ローカルで開いているMSWord文書のテキストを読むという問題の声明があります。私が理解していることは、次のアプローチを使用すると、ドキュメントのパスが与えられれば、ドキュメント内の任意の操作を実行できます。
しかし、私の場合、ローカルに開かれたwordオブジェクトへのハンドル(WinDef.HWND)があります。そして、そこからローカルパスを取得できません。私が試しているコードを指定しましたが、私が探しているものを達成できません。上記の解決策をどのようにして達成できるかをポインタで教えてください。
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);
}
}
あなたがあなたが望むことを達成できるかどうかはよくわかりませんが、私はあなたの質問に答えてあなたが目標に近づくようにできる限りのことをします。
ファイル情報を取得する方法は2つあります。1つはJava / JNAを使用する一般的な方法、もう1つはプロセスのメモリ空間内をピアリングする必要がある方法です。最初の問題を取り上げます。
ウィンドウハンドルを処理するのではなく、後で使いやすいプロセスIDを取得しましょう。それは比較的簡単です:
IntByReference pidPtr = new IntByReference();
com.sun.jna.platform.win32.User32.INSTANCE.GetWindowThreadProcessId(hWnd, pidPtr);
int pid = pidPtr.getValue();
(注目すべきは、おそらくUser32
上記の1つを拡張する独自のインターフェースを用意して、1つのクラスを使用するだけで、私が行ったようにJNAバージョンを完全に修飾する必要がないことです。)
PIDで武装した今、パスを取得しようとするいくつかのオプションがあります。
運が良ければ、ユーザーが([ファイル]> [開く]を使用するのではなく)ファイルを直接開いた場合は、ユーザーが使用したコマンドラインを回復でき、パスが表示される可能性があります。これはWMIクラスから取得できますWin32_Process
。WindowsOperatingSystemクラスの私のプロジェクトOSHI で見つけることができる完全なコード、またはRuntime.getRuntime().exec()
コマンドラインWMIバージョンを使用wmic path Win32_Process where ProcessID=1234 get CommandLine
して、結果をキャプチャすることができますBufferedReader
(または実装のOSHIのExecutingCommand
クラスを参照してください)。
コマンドラインチェックが失敗した場合は、そのプロセスによって開かれているファイルハンドルを検索できます。これを行う最も簡単な方法は、ハンドルユーティリティをダウンロードして(ただし、すべてのユーザーがこれを行う必要があります)、コマンドラインを実行することhandle -p 1234
です。これにより、そのプロセスによって保持されている開いているファイルが一覧表示されます。
ユーザーがHandleをダウンロードすることに依存できない場合は、同じコードを自分で実装してみることができます。これは、を使用した文書化されていないAPI NtQuerySystemInformation
です。オペレーティングシステムのすべてのハンドルを反復処理してファイルを確認できるサンプルコードについては、JNAプロジェクトの問題657を参照してください。すでにPIDを知っている場合、pidと一致しSYSTEM_HANDLE sh = info.Handles[i];
ない限り、コードの残りの部分をスキップすることで、反復を短縮できsh.ProcessID
ます。その問題で述べられているように、リストされているコードはほとんどサポートされておらず危険です。Windowsの将来のバージョンで動作するという保証はありません。
最後に、プロセスメモリで何ができるかを確認できます。PIDで武装すると、プロセスを開いてハンドルを取得できます。
HANDLE pHandle = Kernel32.INSTANCE.OpenProcess(WinNT.PROCESS_QUERY_INFORMATION, false, pid);
次に、EnumProcessModulesを使用してそのモジュールを列挙できます。モジュールごとにGetModuleInformationを使用してMODULEINFO構造を取得します。これは、あなたがあなたの心の内容に探求することができるメモリへのポインタを提供します。もちろん、どのオフセットでどの情報を見つけるかを正確に知るには、探索している実行可能ファイル(Word、ワードパッドなど)のAPIと、適切なバージョンが必要です。また、管理者権限が必要です。この調査は、読者のための演習として残されています。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加