プロセスIDからメインウィンドウハンドルを取得する方法は?
このウィンドウを前面に表示したいです。
「Process Explorer」でうまく機能します。
.NETがメインウィンドウを決定する方法を確認しました。
私の発見は、EnumWindows()
も使用することを示しました。
このコードは、.NETの方法と同様に実行する必要があります。
struct handle_data {
unsigned long process_id;
HWND window_handle;
};
HWND find_main_window(unsigned long process_id)
{
handle_data data;
data.process_id = process_id;
data.window_handle = 0;
EnumWindows(enum_windows_callback, (LPARAM)&data);
return data.window_handle;
}
BOOL CALLBACK enum_windows_callback(HWND handle, LPARAM lParam)
{
handle_data& data = *(handle_data*)lParam;
unsigned long process_id = 0;
GetWindowThreadProcessId(handle, &process_id);
if (data.process_id != process_id || !is_main_window(handle))
return TRUE;
data.window_handle = handle;
return FALSE;
}
BOOL is_main_window(HWND handle)
{
return GetWindow(handle, GW_OWNER) == (HWND)0 && IsWindowVisible(handle);
}
Windowsは(.NETとは対照的に)それを実現する直接的な方法を提供するとは思わない。
私が知っている唯一の方法は、EnumWindows()
を使用してすべてのトップレベルウィンドウを列挙し、それぞれがGetWindowThreadProcessID()
に属するプロセスを見つけることです。これは間接的で非効率に聞こえますが、期待するほど悪くはありません。典型的なケースでは、1ダースのトップレベルウィンドウを通り抜けることができます。
ここで誤解の可能性があります。 .NetのWinFormsフレームワークは、作成された最初のウィンドウ(たとえば、Application.Run(new SomeForm())
)をMainWindow
として自動的に指定します。ただし、win32 APIは、プロセスごとの「メインウィンドウ」の概念を認識しません。メッセージループは、システムおよびプロセスのリソースで作成できる数の「メイン」ウィンドウを完全に処理できます。そのため、プロセスには「メインウィンドウ」がありません。一般的な場合にできる最善の方法は、EnumWindows()
を使用して、特定のプロセスで子以外のすべてのウィンドウをアクティブにし、いくつかのヒューリスティックを使用して、どちらが望ましいかを判断することです。幸いなことに、ほとんどのプロセスでは、ほとんどの場合、単一の「メイン」ウィンドウが実行されるだけなので、ほとんどの場合、良好な結果が得られます。
これは、トップアンサーに基づいて純粋なWin32/C++を使用する私のソリューションです。アイデアは、外部コールバック関数または構造を必要とせずに、必要なものをすべて1つの関数にラップすることです。
#include <utility>
HWND FindTopWindow(DWORD pid)
{
std::pair<HWND, DWORD> params = { 0, pid };
// Enumerate the windows using a lambda to process each window
BOOL bResult = EnumWindows([](HWND hwnd, LPARAM lParam) -> BOOL
{
auto pParams = (std::pair<HWND, DWORD>*)(lParam);
DWORD processId;
if (GetWindowThreadProcessId(hwnd, &processId) && processId == pParams->second)
{
// Stop enumerating
SetLastError(-1);
pParams->first = hwnd;
return FALSE;
}
// Continue enumerating
return TRUE;
}, (LPARAM)¶ms);
if (!bResult && GetLastError() == -1 && params.first)
{
return params.first;
}
return 0;
}
質問とは無関係かもしれませんが、 GetGUIThreadInfo Function をご覧ください。
Tid(スレッドID)とpid(プロセスID)を混同しないようにするためだけに:
DWORD pid;
DWORD tid = GetWindowThreadProcessId( this->m_hWnd, &pid);
Hialeのソリューションの拡張機能として、複数のメインウィンドウを持つプロセスをサポートする異なるバージョンまたは修正バージョンを提供できます。
まず、複数のハンドルを保存できるように構造を修正します。
struct handle_data {
unsigned long process_id;
std::vector<HWND> handles;
};
次に、コールバック関数を修正します。
BOOL CALLBACK enum_windows_callback(HWND handle, LPARAM lParam)
{
handle_data& data = *(handle_data*)lParam;
unsigned long process_id = 0;
GetWindowThreadProcessId(handle, &process_id);
if (data.process_id != process_id || !is_main_window(handle)) {
return TRUE;
}
// change these 2 lines to allow storing of handle and loop again
data.handles.Push_back(handle);
return TRUE;
}
最後に、メイン関数の戻り値を修正します。
std::vector<HWD> find_main_window(unsigned long process_id)
{
handle_data data;
data.process_id = process_id;
EnumWindows(enum_windows_callback, (LPARAM)&data);
return data.handles;
}