- ベストアンサー
スレッド一覧の取得
こんにちわ。 VC6.0でWindowsNT4.0上で動作しているプロセス一覧及びスレッド 一覧を取得するツールを作成したいのですが、アドバイス下さい。 プロセス一覧に関しては、EnumProcessesを使用すればいいのかな? とめぼしはついたのですが、スレッド一覧の取得で壁に当たって います。 NT5.0以降であればCreateToolhelp32Snapshotなんかを使用して いけそうな感じもするのですが。 よろしくお願いします。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
- ベストアンサー
実行中スレッド監視という処理概念で定義しますね。 1.SetWindowsHookEx()で、ForegroundIdleProc を渡す つまり、システム上の全スレッドを監視します。 2.任意スレッドが実行されたらフックプロシージャが 呼び出されるのでここで、GetCurrentThreadId() 関数を 使います。 プロシージャからチェインする前に共有変数 <例>(DWORD th[65535]と定義)にスレッドIDをストア。 <例> for (int i=0;i<=インデックス;i++) if (th[i]==スレッドID) break; if (インデックス^i-1) th[インデックス++]=スレッドID 3.2の処理をTSR処理(常駐)させます。 4.メインアプリケーションでは共有変数を参照してIDを列挙します。 複雑で申し訳ないのですが一例としてどうでしょうか・・?
その他の回答 (3)
別スレッドが属するウインドウがアクティブにならない限り 自己スレッドのままになりますね・・・。 ブロードキャストでアクティブにすることもできますが、 処理がグズグスになるためフックは避けたほうがよさそうです。 スレッドIDを引数として取るAPI関数などでエラー(無効ID) 検出を使って0からスレッド最大個数整数値のループから拾う こともできるかもしれませんが・・。 あとはキー名はわかりませんが、レジストリ参照とか・・。 (結局参考にならず、すみません・・・)
#1です。 "pEnd"変数は無視してください、未定義ゴミ変数です。
お礼
度々のフォローありがとうございます。 再度、質問させてください。 SetWindowsHookExなどをいろいろと調べて、私が望んでいる仕様に するには、システムフックにする必要があること。そうするには DLL化する必要があることなどは分かりました。 で、自分なりにコーディングしてみて、デバッカで確認しました。 SetWindowsHookExで指定したプロシージャが頻繁に呼ばれている ようですが、GetCurrentThreadIdの値が毎回同じになります。 ちなみに、このIdはDLL関数を呼び出す、メイン側のスレッドIdと 同じことも確認しました。 このような現象に関してなにか知識をお持ちでないでしょうか? 参考までにソースです ///// Cppファイル ///// #include "MyHooker.h" int WINAPI DllMain(HINSTANCE hInstance , DWORD dwReason , PVOID pvReserved) { ghDllInst = hInstance; memset(gdwThreadIds, NULL, MAXWORD); return(TRUE); } BOOL Hook() { ghHook = SetWindowsHookEx(WH_FOREGROUNDIDLE, (HOOKPROC)Procedure, ghDllInst, 0); if(ghHook) return(TRUE); return(FALSE); } BOOL UnHook() { if(ghHook) UnhookWindowsHookEx(ghHook); ghHook = NULL; return(TRUE); } LRESULT CALLBACK Procedure(int nCode, WPARAM wParam, LPARAM lParam) { if(nCode < 0) return(CallNextHookEx(ghHook, nCode, wParam, lParam)); DWORD dwThreadId = GetCurrentThreadId(); for(int i = 0; i < MAXWORD; i++) { if(gdwThreadIds[i] == dwThreadId) break; if(gdwThreadIds[i] == NULL) { gdwThreadIds[i] = dwThreadId; break; } } return CallNextHookEx(ghHook, nCode, wParam, lParam); } ///// ヘッダーファイル ///// #define DLL_EXPORT __declspec (dllexport) #include "windows.h" #pragma data_seg(".ShareData") HHOOK ghHook = NULL; #pragma data_seg() HINSTANCE ghDllInst = NULL; DLL_EXPORT BOOL Hook(); DLL_EXPORT BOOL UnHook(); DLL_EXPORT LRESULT CALLBACK Procedure(int nCode, WPARAM wParam, LPARAM lParam); ///// Defファイル ///// LIBRARY SECTIONS .ShareData READ WRITE SHARED
<定義> typedef BOOL (WINAPI *_EnumProcesses)(DWORD*,DWORD,DWORD*); typedef BOOL (WINAPI *_EnumProcessModules)(HANDLE,HMODULE*,DWORD,LPDWORD); typedef DWORD (WINAPI *_GetModuleBaseName)(HANDLE,HMODULE,LPTSTR,DWORD); _EnumProcesses EnumProcesses; _EnumProcessModules EnumProcessModules; _GetModuleBaseName GetModuleBaseName; <処理> HMODULE hDll,hModule[1]; HANDLE hToken, hProcess; TOKEN_PRIVILEGES tp; LUID luid; CHAR pBuf[256]; DWORD pID[255],pNum=0,pNum2=0,i; OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken); LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&luid); tp.PrivilegeCount=1; tp.Privileges[0].Luid=luid; tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED; AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),NULL,NULL); hDll=LoadLibrary("psapi.dll"); EnumProcesses=(_EnumProcesses)GetProcAddress(hDll,"EnumProcesses"); EnumProcessModules=(_EnumProcessModules)GetProcAddress(hDll,"EnumProcessModules"); GetModuleBaseName=(_GetModuleBaseName)GetProcAddress(hDll,"GetModuleBaseNameA"); i=(EnumProcesses)(pID,sizeof(pID),&pNum); pNum/=sizeof(DWORD); for (i=0,pEnd=true;i<pNum;i++) { hProcess=OpenProcess(PROCESS_ALL_ACCESS,0,pID[i]); if (!hProcess) {CloseHandle(hProcess);continue;} (EnumProcessModules)(hProcess,hModule,sizeof(hModule),&pNum2); (GetModuleBaseName)(hProcess,hModule[0],pBuf,sizeof(pBuf)); // pBuf=プロセス名 CloseHandle(hProcess); } CloseHandle(hToken); FreeLibrary(hDll); がシステムプロセス(WinLogon.exe など)も列挙する一例ですが、 スレッド名はEnumWindowsを使います。 そもそもスレッドは名目実体がないため、列挙トップウインドウの ハンドルからタイトルとスレッドID(GetWindowThreadProcessId) を取得して、列挙終了後に昇順に並べたスレッドIDごとに ID一致するタイトル名をツリー階層表示するのが良いと思いますよ。 参考にしてみてください。
お礼
ご回答ありがとうございます。 おっしゃっている意味は大体理解できました。 ただ、GetWindowThreadProcessIdだと、トップレベルウィンドウを 作成したスレッドのIDを取得する感じですよね。 例えば、マルチスレッドのアプリケーションなどの場合は複数の スレッドが生成されていると思うのですが、その複数のスレッド すべてのIDを取得するのは難しいのですかね? 質問ばかりで申し訳ありません。
お礼
ありがとうございました。 完全に満足するものは作成できませんでしたが、それなりのものは作成することが出来ました。何より、いろいろとフック関係の勉強になりました。