![](/img/trans.png)
[英]How do I get the Hwnd / Process Id for a Word Application, and set as Foreground Window
[英]How do I GetModuleFileName() if I only have a window handle (hWnd)?
我正在嘗試獲取 C# 2.0 應用程序之外的窗口的可執行文件的名稱。 我的應用程序當前使用來自“user32.dll”的 GetForegroundWindow() 調用獲取窗口句柄 (hWnd)。
從我已經能夠做的挖掘來看,我想我想使用 GetModuleFileNameEx() 函數(來自 PSAPI)來獲取名稱,但是 GetModuleFileNameEx() 需要一個進程的句柄,而不是一個窗口。
是否可以從窗口句柄獲取進程句柄? (是否需要先獲取窗口的線程句柄?)
編輯第一句話以更清楚地說明我要做什么。
更新! 這是我發現對我有用的 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());
}
一個小時以來一直在為同樣的問題苦苦掙扎,第一個字母也被替換為? 通過使用 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;
}
您可以調用GetWindowThreadProcessId並返回與窗口關聯的進程。
由此,您可以調用OpenProcess來打開進程並獲取進程的句柄。
如果您在 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();
}
你到底想做什么? 您可以使用GetWindowThreadProcessId()獲取創建窗口的進程的進程 ID,然后使用OpenProcess()獲取進程句柄。 但這似乎很笨拙,我覺得有一種更優雅的方式來做你想做的事。
試試這個來獲取可執行文件的文件名:
C#:
string file = System.Windows.Forms.Application.ExecutablePath;
制造
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.