views:

3704

answers:

5

I'm trying to get the name of the executable of a window that is outside my C# 2.0 application. My app currently gets a window handle (hWnd) using the GetForegroundWindow() call from "user32.dll".

From the digging that I've been able to do, I think I want to use the GetModuleFileNameEx() function (from PSAPI) to obtain the name, but GetModuleFileNameEx() requires a handle to a Process, not a Window.

Is it possible to get a process handle from a window handle? (Do I need to get the thread handle of the window first?)

EDITED the first sentence to make it clearer what I'm trying to do.

UPDATE! Here's the C# code that I found worked for me. The only caveat is occasionally it returns a file/path where the drive letter is a "?" instead of the actual drive letter (like "C"). -- Haven't figured out why yet.

[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

[DllImport("kernel32.dll")]
static extern IntPtr OpenProcess(UInt32 dwDesiredAccess, Int32 bInheritHandle, UInt32 dwProcessId);

[DllImport("psapi.dll")]
static extern uint GetModuleFileNameEx(IntPtr hProcess, IntPtr hModule, [Out] StringBuilder lpBaseName, [In] [MarshalAs(UnmanagedType.U4)] int nSize);

[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);

private string GetWindowModuleFileName(IntPtr hWnd)
{
    uint processId = 0;
    const int nChars = 1024;
    StringBuilder filename = new StringBuilder(nChars);
    GetWindowThreadProcessId(hWnd, out processId);
    IntPtr hProcess = OpenProcess(1040, 0, processId);
    GetModuleFileNameEx(hProcess,IntPtr.Zero,filename,nChars);
    CloseHandle(hProcess);
    return (filename.ToString());
}
+3  A: 

You can call GetWindowThreadProcessId and that will return you the process associated with the window.

From that, you can call OpenProcess to open the process and get the handle to the process.

Hey welcome to stack overflow - I've been a long time reader of yours
1800 INFORMATION
+1  A: 

What exactly is it that you're trying to do? You can get the process ID of the the process which created a window with GetWindowThreadProcessId(), followed by OpenProcess() to get the process handle. But this seems very kludgy, and I feel like there's a more elegant way to do what you want to do.

Adam Rosenfield
Maybe it seems kludgy to you, but someone with reputation of 1 gave the exact same answer just 1 minute before you, and I don't think his reputation is going to stay at 1 for very long.
Windows programmer
Yes, it feels kludgy to me, too. I'm trying to track which window has focus. Naturally, window handles and title bar names change, but the application exe name doesn't.
Pretzel
OK, but anyway Larry Osterman gave the same answer so it's probably less klugy than all of the alternatives. And his reputation isn't 1 any more.
Windows programmer
Larry Osterman's lifetime reputation in windows programming is right up there with Raymond Chen's
1800 INFORMATION
Larry Osterman's answer has just been accepted so now his reputation is 46. His lifetime prior to SO doesn't count.
Windows programmer
A: 

Been struggling with the same problem for an hour now, also got the first letter replaced by a ? by using GetModuleFileNameEx. Finaly came up with this solution using the System.Diagnostics.Process class.

[DllImport("user32.dll")]
public static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);

void GetProcessPathFromWindowHandle(IntPtr hwnd)
{
   uint pid = 0;
   Win32.GetWindowThreadProcessId(hwnd, out pid);
   Process p = Process.GetProcessById((int)pid);
   return p.MainModule.FileName;
}
+1  A: 

If you are running on a windows 64 bit platform, you may need to use QueryFullProcessImageName instead. This returns a user style path, compared to GetProcessImageFileName which returns a system style path that would need to be converted using NtQuerySymbolicLinkObject or ZwQuerySymbolicLinkObject.

One mammoth example function - recommend breaking up into re usable bits.

typedef DWORD (__stdcall *PfnQueryFullProcessImageName)(HANDLE hProcess, DWORD dwFlags, LPTSTR lpImageFileName, PDWORD nSize);
typedef DWORD (__stdcall *PfnGetModuleFileNameEx)(HANDLE hProcess, HMODULE hModule, LPTSTR lpImageFileName, DWORD nSize);

std::wstring GetExeName( HWND hWnd ){
// Convert from Window to Process ID
DWORD dwProcessID = 0;
::GetWindowThreadProcessId(hWnd, &dwProcessID);

// Get a handle to the process from the Process ID
HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcessID);

// Get the process name
if (NULL != hProcess) {
 TCHAR szEXEName[MAX_PATH*2] = {L'\0'};
 DWORD nExeName = sizeof(szEXEName)/sizeof(TCHAR);

    //  the QueryFullProcessImageNameW does not exist on W2K
 HINSTANCE hKernal32dll = LoadLibrary(L"kernel32.dll");
 PfnQueryFullProcessImageName pfnQueryFullProcessImageName = NULL;
 if(hKernal32dll != NULL) {
  pfnQueryFullProcessImageName = (PfnQueryFullProcessImageName)GetProcAddress(hKernal32dll, "QueryFullProcessImageNameW");
  if (pfnQueryFullProcessImageName != NULL) 
   pfnQueryFullProcessImageName(hProcess, 0, szEXEName, &nExeName);
  ::FreeLibrary(hKernal32dll);
 } 

    // The following was not working from 32 querying of 64 bit processes
    // Use as backup for when function above is not available 
 if( pfnQueryFullProcessImageName == NULL ){ 
  HINSTANCE hPsapidll = LoadLibrary(L"Psapi.dll");
  PfnGetModuleFileNameEx pfnGetModuleFileNameEx = (PfnGetModuleFileNameEx)GetProcAddress(hPsapidll, "GetModuleFileNameExW");
  if( pfnGetModuleFileNameEx != NULL ) 
   pfnGetModuleFileNameEx(hProcess, NULL, szEXEName, sizeof(szEXEName)/sizeof(TCHAR));
  ::FreeLibrary(hPsapidll);
 }

 ::CloseHandle(hProcess);

 return( szEXEName );
} 
return std::wstring();
}
Greg Domjan
A: 

try this to get the file name of the executable :

C#:

string file = System.Windows.Forms.Application.ExecutablePath;

mfg

muh
@muh: This is a bit of an old question now, but at the time, I was trying to get the EXE name of *another* process based on process ID. (Not the one that was running.) So this isn't helpful answer in this context.
Pretzel