我正在尝试获取C#2.0应用程序之外的窗口的可执行文件的名称。我的应用程序当前使用来自“user32.dll”的GetForegroundWindow()调用获取窗口句柄(hWnd)。
从我能够做的挖掘中,我想我想使用GetModuleFileNameEx()函数(来自PSAPI)来获取名称,但是GetModuleFileNameEx()需要一个Process的句柄,而不是一个Window。
是否可以从窗口句柄获取进程句柄? (我是否需要首先获取窗口的线程句柄?)
编辑第一句话,使我更清楚我要做的事情。
UPDATE!这是我发现为我工作的C#代码。唯一的警告是偶尔它返回一个文件/路径,其中驱动器号是“?”而不是实际的驱动器号(如“C”)。 - 还没弄明白为什么。
[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());
}
答案 0 :(得分:8)
现在一直在努力解决同样的问题,还使用GetModuleFileNameEx将第一个字母替换为?。 最后使用 System.Diagnostics.Process 类提出了这个解决方案。
[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 :(得分:6)
您可以致电GetWindowThreadProcessId,这将返回与该窗口相关联的过程。
由此,您可以致电OpenProcess打开流程并获取流程的句柄。
答案 2 :(得分:2)
如果您在Windows 64位平台上运行,则可能需要使用QueryFullProcessImageName。这将返回一个用户样式路径,与GetProcessImageFileName相比,后者返回需要使用NtQuerySymbolicLinkObject或ZwQuerySymbolicLinkObject转换的系统样式路径。
一个庞大的示例功能 - 建议分解为可用的位。
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();
}
答案 3 :(得分:1)
你到底想要做什么?您可以获取创建具有GetWindowThreadProcessId()的窗口的进程的进程ID,然后获取OpenProcess()以获取进程句柄。但这看起来非常糟糕,我觉得有一种更优雅的方式可以做你想做的事。
答案 4 :(得分:0)
尝试此操作以获取可执行文件的文件名:
C#:
string file = System.Windows.Forms.Application.ExecutablePath;
MFG