How to get main window handle from process id?

C++WindowsWinapiWindows 7

C++ Problem Overview


How to get main window handle from process id?

I want to bring this window to the front.

It works well in "Process Explorer".

C++ Solutions


Solution 1 - C++

I checked how .NET determines the main window.

My finding showed that it also uses EnumWindows().

This code should do it similarly to the .NET way:

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);
}

Solution 2 - C++

I don't believe Windows (as opposed to .NET) provides a direct way to get that.

The only way I know of is to enumerate all the top level windows with EnumWindows() and then find what process each belongs to GetWindowThreadProcessID(). This sounds indirect and inefficient, but it's not as bad as you might expect -- in a typical case, you might have a dozen top level windows to walk through...

Solution 3 - C++

There's the possibility of a mis-understanding here. The WinForms framework in .Net automatically designates the first window created (e.g., Application.Run(new SomeForm())) as the MainWindow. The win32 API, however, doesn't recognize the idea of a "main window" per process. The message loop is entirely capable of handling as many "main" windows as system and process resources will let you create. So, your process doesn't have a "main window". The best you can do in the general case is use EnumWindows() to get all the non-child windows active on a given process and try to use some heuristics to figure out which one is the one you want. Luckily, most processes are only likely to have a single "main" window running most of the time, so you should get good results in most cases.

Solution 4 - C++

This is my solution using pure Win32/C++ based on the top answer. The idea is to wrap everything required into one function without the need for external callback functions or structures:

#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;
}

Solution 5 - C++

Though it may be unrelated to your question, take a look at GetGUIThreadInfo Function.

Solution 6 - C++

As an extension to Hiale's solution, you could provide a different or modified version that supports processes that have multiple main windows.

First, amend the structure to allow storing of multiple handles:

struct handle_data {
    unsigned long process_id;
    std::vector<HWND> handles;
};

Second, amend the callback function:

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;   
 }

Finally, amend the returns on the main function:

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;
}

Solution 7 - C++

Just to make sure you are not confusing the tid (thread id) and the pid (process id):

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAlexey MalistovView Question on Stackoverflow
Solution 1 - C++HialeView Answer on Stackoverflow
Solution 2 - C++Jerry CoffinView Answer on Stackoverflow
Solution 3 - C++DathanView Answer on Stackoverflow
Solution 4 - C++BenjView Answer on Stackoverflow
Solution 5 - C++AntonKView Answer on Stackoverflow
Solution 6 - C++Class SkeletonView Answer on Stackoverflow
Solution 7 - C++Oliver ZendelView Answer on Stackoverflow