How to Get Main Window Handle from Process Id

C++: Best way to get Window Handle of the only window from a process by process id, process handle and title name

Using FindWindow requires that you either know the window class or the window title. Both of these are not necessarily unique. Since you alread have the process handle (and its ID) you can implement a robust solution using EnumWindows.

First, declare a structure used for communication. It passes a process ID to the enumeration procedure and returns the window handle back.

// Structure used to communicate data from and to enumeration procedure
struct EnumData {
DWORD dwProcessId;
HWND hWnd;
};

Next, we need a callback procedure that retrieves the process ID (GetWindowThreadProcessId) for any given window and compares it to the one we are looking for:

// Application-defined callback for EnumWindows
BOOL CALLBACK EnumProc( HWND hWnd, LPARAM lParam ) {
// Retrieve storage location for communication data
EnumData& ed = *(EnumData*)lParam;
DWORD dwProcessId = 0x0;
// Query process ID for hWnd
GetWindowThreadProcessId( hWnd, &dwProcessId );
// Apply filter - if you want to implement additional restrictions,
// this is the place to do so.
if ( ed.dwProcessId == dwProcessId ) {
// Found a window matching the process ID
ed.hWnd = hWnd;
// Report success
SetLastError( ERROR_SUCCESS );
// Stop enumeration
return FALSE;
}
// Continue enumeration
return TRUE;
}

What's left is the public interface. It populates the structure used for communication with the process ID, triggers the enumeration of top-level windows, and returns the window handle. The calls to SetLastError and GetLastError are required, since EnumWindows returns FALSE for both error and success in this case:

// Main entry
HWND FindWindowFromProcessId( DWORD dwProcessId ) {
EnumData ed = { dwProcessId };
if ( !EnumWindows( EnumProc, (LPARAM)&ed ) &&
( GetLastError() == ERROR_SUCCESS ) ) {
return ed.hWnd;
}
return NULL;
}

// Helper method for convenience
HWND FindWindowFromProcess( HANDLE hProcess ) {
return FindWindowFromProcessId( GetProcessId( hProcess ) );
}

This will retrieve the first top-level window that matches a given process ID. Since the requirements state that there will only ever be a single window for the given process, the first one that matches is the correct window.

If additional restrictions exist, EnumProc can be expanded to include those. I have marked the spot in the implementation above, where additional filters can be applied.

Get hwnd by process id c++

HWND g_HWND=NULL;
BOOL CALLBACK EnumWindowsProcMy(HWND hwnd,LPARAM lParam)
{
DWORD lpdwProcessId;
GetWindowThreadProcessId(hwnd,&lpdwProcessId);
if(lpdwProcessId==lParam)
{
g_HWND=hwnd;
return FALSE;
}
return TRUE;
}
EnumWindows(EnumWindowsProcMy,m_ProcessId);

Get main window hwnd from process ID

You can't use a non-static member function as a C language callback, because the member function has a hidden this argument.

In Windows you can use a static member function, but note that that is not a portable solution.

The most portable and safest is a namespace scope function.

pywin32: how to get window handle from process handle and vice versa

Enumerate windows and then get the process handle for each window

You need these APIs:

  • win32gui.EnumWindows() to enumerate all top-level windows (that is no child windows aka controls)
  • win32process.GetWindowThreadProcessId() to get process ID from window handle
  • win32api.OpenProcess() to get process handle from process ID

Enumerate processes and then get the main application window handle
for each process

You need these APIs:

  • win32process.EnumProcesses() to enumerate all processes
  • win32api.GetWindowLong() with arguent GWL_STYLE to get window styles and GWL_EXSTYLE to get extended window styles
  • win32gui.GetParent() to determine unowned windows

By filtering the result of EnumWindows() using GetWindowThreadProcessId() you can get all windows that belong to a given process.

Determining the main window can be tricky as there is no single window style that would designate a window as the main window. After all, an application might have multiple main windows.

Best you could do is to use the same rules that the taskbar uses to determine application windows, because that's what the user perceives as main windows:

The Shell places a button on the taskbar whenever an application
creates an unowned window—that is, a window that does not have a
parent and that has the appropriate extended style bits.

To ensure that the window button is
placed on the taskbar, create an unowned window with the
WS_EX_APPWINDOW extended style. To prevent the window button from
being placed on the taskbar, create the unowned window with the
WS_EX_TOOLWINDOW extended style. As an alternative, you can create a
hidden window and make this hidden window the owner of your visible
window.

Use GetParent() and GetWindowLong() to determine the unowned windows that have the right window styles according to these rules.

Main window Handle by process name

I agree with Petesh that you would need to enumerate the top level windows and check the module file name of the process that created it. To help you get started on enumerating top level windows here is a delphi implementation of doing it.

First you need some way of communicating with the EnumWindows method when it calls back to you. Declare a record for that, which will hold the file name of the module you want to find and a handle to the process when it is found:

TFindWindowRec = record
ModuleToFind: string;
FoundHWnd: HWND;
end;

Then you need to declare and implement the call back function that the EnumWindows method is going to call for each top level window:

function EnumWindowsCallBack(Handle: hWnd; var FindWindowRec: TFindWindowRec): BOOL; stdcall;

Please note the stdcall; at the end of the declaration. This specifies the calling convention which is important because Delphi's default calling convention is different from the Windows API's calling convention.

The implementation of your call back function could look like:

function EnumWindowsCallBack(Handle: hWnd; var FindWindowRec: TFindWindowRec): BOOL; stdcall;
const
C_FileNameLength = 256;
var
WinFileName: string;
PID, hProcess: DWORD;
Len: Byte;
begin
Result := True;
SetLength(WinFileName, C_FileNameLength);
GetWindowThreadProcessId(Handle, PID);
hProcess := OpenProcess(PROCESS_ALL_ACCESS, False, PID);
Len := GetModuleFileNameEx(hProcess, 0, PChar(WinFileName), C_FileNameLength);
if Len > 0 then
begin
SetLength(WinFileName, Len);
if SameText(WinFileName, FindWindowRec.ModuleToFind) then
begin
Result := False;
FindWindowRec.FoundHWnd := Handle;
end;
end;
end;

Handle is the handle of the top level window currently being processed by EnumWindows. You use it to get the module's file name of that window. The result of the call back determines whether EnumWindows should continue enumerating windows or not. Return false when you have found what you are looking for.

Of course you still need to set the whole enumeration operation in motion:

var
FindWindowRec: TFindWindowRec;

function IsNotePadOpen: Boolean;
begin
FindWindowRec.ModuleToFind := 'c:\windows\system32\notepad.exe';
FindWindowRec.FoundHWnd := 0;
EnumWindows(@EnumWindowsCallback, integer(@FindWindowRec));
Result := FindWindowRec.FoundHWnd <> 0;
end;

Please note that the above code will find the first notepad window enumerated by the EnumWindows method, there may be more, there may be none. It's up to you to decide how to handle those situations.

The Main window can be invisible so you could add and (IsWindowInvisble(Handle)) after If (Len > 0) in the call back function.

How to I get the window handle by giving the process name that is running?

You can use the Process class.

Process[] processes = Process.GetProcessesByName("someName");

foreach (Process p in processes)
{
IntPtr windowHandle = p.MainWindowHandle;

// do something with windowHandle
}

Find process id by window's handle

You can use the following Windows API:

[DllImport("user32.dll", SetLastError=true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId);

You pass in the HWND and use the out parameter to return the PID.

You can read more on this function here on MSDN.

how do you find what window(Handle) takes process ownership? And get the handle for that..?

how do you find what window takes process ownership?

That's a misconception, surely the reason you are getting stuck. A window doesn't own a process, it is the other way around. And more subtly, a thread owns a window. And a process owns a thread.

When you use Process.GetProcesses() then you'll enumerate a lot of processes that do not have any window at all. Like all of the services that run on the machine, having dozens of them is not unusual. You can use Task Manager to see them in the Processes tab, be sure to click the option that shows processes owned by all users. SysInternals' Process Explorer is also a very nice tool to see what is running.

So don't be surprised that Process.MainWindowHandle returns IntPtr.Zero. And also keep in mind that it is a guess. A process can easily own multiple top-level windows. Which one of them is the "main" window isn't always obvious. The Process class uses a simple rule, it assumes that the first top-level window that it finds that doesn't have an owner and is visible is the main window.

To reliably get the top-level windows for a process you must first enumerate the threads in the process. Easy to do with Process.Threads. Then for each thread, you iterate the windows it owns by pinvoking EnumThreadWindows(). Exact same idea as EnumWindows() but limited to the specific thread and without the firehose problem and lower odds that it falls apart because a new window got created while you were iterating. You'll get the top-level windows owned by the thread, what you want, enumerating the child windows owned by each top-level window requires EnumChildWindows().

Some notable bad news: do note that some filtering is required to get decent results. A thread very commonly owns a window that's not visible at all. Commonly used to take care of inter-thread communication, particularly common for code that uses COM. So you probably also want to pinvoke IsWindowVisible(). And always check for errors on these pinvoked functions, failure is common when your program isn't running with admin privileges and/or is not UAC elevated. Always double-check your results by what you see from the Spy++ utility.



Related Topics



Leave a reply



Submit