如何使用Java或Java Native Access读取本地打开的MS Word文档的文本

问题描述 投票:1回答:1

我有一个阅读本地打开的MSWord文档文本的问题陈述。我了解到,使用以下方法,给定文档的路径,我可以在文档中执行任何操作。

https://github.com/java-native-access/jna/blob/master/contrib/msoffice/src/com/sun/jna/platform/win32/COM/util/office/Wordautomation_KB_313193_Mod.java

但是在我的情况下,我有一个本地打开的单词对象的句柄(WinDef.HWND)。而且我无法从中获取local path。我已经给出了正在尝试的代码,但是我无法实现我想要的。请给我任何指示,我如何才能实现上述解决方案。

[请注意,以下给出了WINWORD.EXE的路径。和System.out.println("File Path: "+desktop.getFilePath());


import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.DesktopWindow;
import com.sun.jna.platform.FileUtils;
import com.sun.jna.platform.WindowUtils;
import com.sun.jna.platform.WindowUtils.NativeWindowUtils;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.Kernel32Util;
import com.sun.jna.platform.win32.WinUser;
import com.sun.jna.win32.StdCallLibrary;

import java.util.List;

public class NativeWordpadExtractor {
    public static void main(String ar[]){
        executeNativeCommands();
    }
    public static void executeNativeCommands(){
        NativeExtractor.User32 user32 = NativeExtractor.User32.INSTANCE;
        user32.EnumWindows(new WinUser.WNDENUMPROC() {
            int count = 0;
            @Override
            public boolean callback(WinDef.HWND hWnd, Pointer arg1) {
                byte[] windowText = new byte[512];
                user32.GetWindowTextA(hWnd, windowText, 512);
                String wText = Native.toString(windowText);

                // get rid of this if block if you want all windows regardless of whether
                // or not they have text
                if (wText.isEmpty()) {
                    return true;
                }
                if("SampleTextForScreenScrapping_Word - WordPad".equals(wText)){
                    System.out.println("Got the 'Wordpad'" + hWnd + ", class " + hWnd.getClass() +"getPointer"+ hWnd.getPointer()+ " Text: " + wText);
                    //WinDef.HWND notePadHwnd = user32.FindWindowA("Wordpad",null  );
                    byte[] fileText = new byte[1024];

                    System.out.println("fileText : " + WindowUtils.getWindowTitle(hWnd));
                    List<DesktopWindow> desktops=WindowUtils.getAllWindows(true);
                    // Approach 1) For getting a handle to the Desktop object . I am not able to achieve result with this.
                    for(DesktopWindow desktop:desktops){
                        System.out.println("File Path: "+desktop.getFilePath());
                        System.out.println("Title : "+desktop.getTitle());
                    }
                    System.out.println("fileText : " + WindowUtils.getAllWindows(true));
                    // Approach 2) For getting a handle to the native object .
                    // This is also not working 
                    WinDef.HWND editHwnd = user32.FindWindowExA(hWnd, null, null, null);
                    byte[] lParamStr = new byte[512];
                    WinDef.LRESULT resultBool = user32.SendMessageA(editHwnd, NativeExtractor.User32.WM_GETTEXT, 512, lParamStr);
                    System.out.println("The content of the file is : " + Native.toString(lParamStr));
                    return false;
                }
                System.out.println("Found window with text " + hWnd + ", total " + ++count + " Text: " + wText);
                return true;
            }
        }, null);

    }
    interface User32 extends StdCallLibrary {
        NativeExtractor.User32 INSTANCE = (NativeExtractor.User32) Native.loadLibrary("user32", NativeExtractor.User32.class);
        int WM_SETTEXT = 0x000c;
        int WM_GETTEXT = 0x000D;
        int GetWindowTextA(WinDef.HWND hWnd, byte[] lpString, int nMaxCount);
        boolean EnumWindows(WinUser.WNDENUMPROC lpEnumFunc, Pointer arg);
        WinDef.HWND FindWindowA(String lpClassName, String lpWindowName);
        WinDef.HWND FindWindowExA(WinDef.HWND hwndParent, WinDef.HWND hwndChildAfter, String lpClassName, String lpWindowName);
        WinDef.LRESULT SendMessageA(WinDef.HWND paramHWND, int paramInt, WinDef.WPARAM paramWPARAM, WinDef.LPARAM paramLPARAM);
        WinDef.LRESULT SendMessageA(WinDef.HWND editHwnd, int wmGettext, long l, byte[] lParamStr);
        int GetClassNameA(WinDef.HWND hWnd, byte[] lpString, int maxCount);
    }
}


java jna
1个回答
0
投票

我不太确定你能实现你想要的,但是我会尽我所能回答你的问题,使你更接近目标。

有两种获取文件信息的方法:一种是Java / JNA的通用方法,另一种是您需要在进程内存空间中进行查看。我将处理第一个。

而不是处理窗口句柄,我们来获取进程ID,该ID在以后更易于使用。这是相对简单的:

IntByReference pidPtr = new IntByReference();
com.sun.jna.platform.win32.User32.INSTANCE.GetWindowThreadProcessId(hWnd, pidPtr);
int pid = pidPtr.getValue();

((请注意,您可能应该拥有自己的User32接口来扩展上面的接口,因此您可以只使用一个接口,而不必像我一样完全限定JNA版本。)

现在,有了PID,有了一些尝试获取路径的选项。

  1. 如果您很幸运,并且用户直接打开了文件(而不是使用File> Open),则可以恢复他们使用的命令行,并且可能会有路径。您可以从WMI类Win32_Process中检索它。您可以在我的项目OSHI in the WindowsOperatingSystem class中找到完整的代码,也可以尝试使用Runtime.getRuntime().exec()使用命令行WMI版本:wmic path Win32_Process where ProcessID=1234 get CommandLine,将结果捕获到BufferedReader中(或查看OSHI的ExecutingCommand class获得实现)。 )

  2. 如果命令行检查失败,则可以搜索该进程打开了哪些文件句柄。最简单的方法是下载ExecutingCommand实用程序(但所有用户都必须这样做),然后只需执行命令行Handle。这将列出该进程保存的打开文件。

  3. 如果您不能依赖用户下载Handle,则可以尝试自己实现相同的代码。这是使用handle -p 1234的未公开API。请参阅JNA项目NtQuerySystemInformation以获取示例代码,该示例代码将迭代所有操作系统的句柄,使您可以查看文件。既然您已经知道PID,则可以跳过Issue 657之后通过跳过其余代码来简化迭代,除非SYSTEM_HANDLE sh = info.Handles[i];与您的pid匹配。如该问题所述,列出的代码是大多不受支持和危险。无法保证它将在将来的Windows版本中运行。

最后,您可以看到使用过程存储器可以做什么。有了PID,您可以打开Process以获得一个句柄:

sh.ProcessID

然后您可以使用HANDLE pHandle = Kernel32.INSTANCE.OpenProcess(WinNT.PROCESS_QUERY_INFORMATION, false, pid); 枚举其模块;对于每个模块,请使用EnumProcessModules检索GetModuleInformation结构。这为您提供了一个记忆的指针,您可以探索自己内心的满足感。当然,准确地知道在什么偏移量处查找哪些信息需要您正在探索的可执行文件(Word,WordPad等,以及适当的版本)的API。并且您需要管理员权限。这项探索留给读者练习。

© www.soinside.com 2019 - 2024. All rights reserved.