web-dev-qa-db-ja.com

プロセスIDからメインウィンドウハンドルを取得する方法は?

プロセスIDからメインウィンドウハンドルを取得する方法は?

このウィンドウを前面に表示したいです。

「Process Explorer」でうまく機能します。

55
Alexey Malistov

.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);
}
53
Hiale

Windowsは(.NETとは対照的に)それを実現する直接的な方法を提供するとは思わない。

私が知っている唯一の方法は、EnumWindows()を使用してすべてのトップレベルウィンドウを列挙し、それぞれがGetWindowThreadProcessID()に属するプロセスを見つけることです。これは間接的で非効率に聞こえますが、期待するほど悪くはありません。典型的なケースでは、1ダースのトップレベルウィンドウを通り抜けることができます。

37
Jerry Coffin

ここで誤解の可能性があります。 .NetのWinFormsフレームワークは、作成された最初のウィンドウ(たとえば、Application.Run(new SomeForm()))をMainWindowとして自動的に指定します。ただし、win32 APIは、プロセスごとの「メインウィンドウ」の概念を認識しません。メッセージループは、システムおよびプロセスのリソースで作成できる数の「メイン」ウィンドウを完全に処理できます。そのため、プロセスには「メインウィンドウ」がありません。一般的な場合にできる最善の方法は、EnumWindows()を使用して、特定のプロセスで子以外のすべてのウィンドウをアクティブにし、いくつかのヒューリスティックを使用して、どちらが望ましいかを判断することです。幸いなことに、ほとんどのプロセスでは、ほとんどの場合、単一の「メイン」ウィンドウが実行されるだけなので、ほとんどの場合、良好な結果が得られます。

11
Dathan

これは、トップアンサーに基づいて純粋な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)&params);

    if (!bResult && GetLastError() == -1 && params.first)
    {
        return params.first;
    }

    return 0;
}
7
Benj

質問とは無関係かもしれませんが、 GetGUIThreadInfo Function をご覧ください。

2
AntonK

Tid(スレッドID)とpid(プロセスID)を混同しないようにするためだけに:

DWORD pid;
DWORD tid = GetWindowThreadProcessId( this->m_hWnd, &pid);
0
Oliver Zendel

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;
}
0
Class Skeleton