如何获取窗口的可执行文件名

Posted

技术标签:

【中文标题】如何获取窗口的可执行文件名【英文标题】:How to get the Executable name of a window 【发布时间】:2021-10-04 13:08:35 【问题描述】:

我尝试获取所有已启动窗口的可执行文件名称,但我的问题是:

我用方法

UINT GetWindowModuleFileName(      
HWND hwnd,
LPTSTR lpszFileName,
UINT cchFileNameMax);

我不明白为什么它不起作用。

关于窗口的数据是:-HWND AND PROCESSID

错误是: 例如:

HWND: 00170628 
ProcessId: 2336        
WindowTitle: C:\test.cpp - Notepad++
GetWindowModuleFileName():  C:\test.exe

HWND: 00172138 
ProcessId: 2543        
WindowTitle: Firefox
GetWindowModuleFileName():  C:\test.exe

HWND: 00120358 
ProcessId: 2436        
WindowTitle: Mozilla Thunderbird
GetWindowModuleFileName():  C:\test.exe

注意:test.exe 是我的可执行文件的名称,但它不是 Notepad++ 的完整路径...而且它也适用于 Mozilla Thunderbird... 我不明白为什么

我使用这样的功能:

char filenameBuffer[4000];
if (GetWindowModuleFileName(hWnd, filenameBuffer, 4000) > 0)

    std::cout << "GetWindowModuleFileName(): " << filenameBuffer << std::endl;

感谢您的回复。

【问题讨论】:

【参考方案1】:

GetWindowModuleFileName 函数仅适用于当前进程中的窗口。

您必须执行以下操作:

    使用GetWindowThreadProcessId检索窗口的进程。 使用OpenProcess 打开具有PROCESS_QUERY_INFORMATIONPROCESS_VM_READ 访问权限的进程。 在进程句柄上使用GetModuleFileNameEx

如果你真的想获取注册窗口的模块的名称(而不是进程可执行文件),你可以通过GetWindowLongPtrGWLP_HINSTANCE 获取模块句柄。然后可以将模块句柄传递给前面提到的GetModuleFileNameEx

示例:

TCHAR buffer[MAX_PATH] = 0;
DWORD dwProcId = 0; 

GetWindowThreadProcessId(hWnd, &dwProcId);   

HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ , FALSE, dwProcId);    
GetModuleFileName((HMODULE)hProc, buffer, MAX_PATH);
CloseHandle(hProc);

【讨论】:

msdn.microsoft.com/en-us/library/windows/desktop/… @MartinBa,请注意它带来了对 oleacc.dll 的依赖。 是的。我只是在阅读您的答案,并认为我也会放弃该功能,因为这是我在搜索引擎上的第一次点击。 请注意,PROCESS_VM_READ 要求 SeDebugPrivilege 在用户令牌中存在并启用。 正确的方法!但是,如果您以其他用户身份运行可执行文件并尝试使用“OpenProcess”获取进程名称,则会抛出“拒绝访问”。在这种情况下还有其他方法可以实现这一点吗?【参考方案2】:

啊啊。我阅读了底部的 MSDN 页面。

来自http://support.microsoft.com/?id=228469

GetWindowModuleFileName 和 GetModuleFileName 正确检索 信息... GetWindowModuleFileName 和 GetModuleFileName 正确检索 关于窗口和模块的信息 在调用过程中。在 Windows 95 中 和 98,他们返回有关信息 其他中的窗口和模块 过程。然而,在 Windows NT 4.0 和 Windows 2000,因为模块句柄 不再由所有进程共享 就像在 Windows 95 和 98 上一样, 这些 API 不返回信息 关于其他中的窗口和模块 进程。

获取有关 Windows 的更多信息 2000,使用进程状态助手 一组 API(称为 PSAPI,请参阅 Psapi.h 包含文件),自 视窗 NT 4.0。 API,例如 GetModuleFileNameEx 和 GetModuleBaseName 提供等价物 功能。

尝试改用GetModuleFileNameEx。

【讨论】:

@Ninefingers:谢谢你的帮助!【参考方案3】:

http://support.microsoft.com/?id=228469

执行摘要是,GetWindowModuleFileName 不适用于基于 NT 的 Windows 中其他进程中的窗口。

相反,您可以使用QueryFullProcessImageName 处理进程。您可以使用OpenProcess 获取进程的句柄,一旦您拥有进程ID,就可以使用它。您可以使用 GetWindowThreadProcessId 从 HWND 获取进程 ID

【讨论】:

第一个链接不再适用于此。我尝试了几次搜索,但没有成功。【参考方案4】:

根据MSDN page 的GetWindowModuleFileName,您似乎正确地调用了它,并且如果您的可执行文件位于C 的根目录中:它返回正确的值:

GetWindowModuleFileName 函数检索与指定窗口句柄关联的模块的完整路径和文件名。

你希望得到什么?

【讨论】:

@ChrisF: 看看我的例子,我添加了三个程序,分别是记事本、firefox 和 Thunderbird……我的可执行文件名称是这些程序的 text.exe ???是黑暗面的力量吗? @Jaguar - 我不确定发生了什么。 MSDN 页面暗示您可以为任何窗口句柄调用此函数,但它似乎只返回正在运行的程序的模块名称。 @Ninefingers:没错,我尝试获取 firefox.exe,正如您在我的示例中看到的那样,我的 HWND 打印了良好的 WindowTitle,但 GetWindowModuleFileName 函数没有这样做!!!【参考方案5】:

这是一个如何获取创建窗口的可执行文件名称的例子,希望它能给你一些想法:

    while(true)
    
    Sleep(250);//reduce cpu usage
    CHAR __name[MAX_PATH];//name buffer
    HWND hwnd;//window handle
    DWORD pid;//process pid
    hwnd=FindWindow(NULL,NULL);//find any window
    PROCESSENTRY32 entry;//process structure containing info about processes
    entry.dwSize=sizeof(PROCESSENTRY32);
    HANDLE snapshot=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);//get processes
    if(hwnd!=0)
    
        GetWindowThreadProcessId(hwnd,&pid);//get found window pid
    
    if (Process32First(snapshot,&entry)==TRUE)//start listing processes
    
        while (Process32Next(snapshot,&entry)==TRUE)
        
            if (stricmp(entry.szExeFile,"explorer.exe")==0)
            
                if(pid!=entry.th32ProcessID)//if found window pid is explorers one, skip it
                
                    HANDLE hProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid);//open processusing PROCESS_ALL_ACCESS to get handle
                    if(hProcess!=NULL)
                    
                        GetModuleFileNameEx(hProcess,NULL,__name,MAX_PATH);//get executable path
                        cout<<"Found: "<<__name<<endl;
                    
                
            
        
    

要使用 GetModuleFileNameEx(),您可能需要设置链接器设置以链接库 psapi。还包括 psapi.h。

【讨论】:

+1 到 CreateToolhelp32Snapshot,这是我发现的唯一一种可以轻松返回所有活动进程的 exe 文件名的方法,不像 OpenProcess 通常需要额外的访问权限。

以上是关于如何获取窗口的可执行文件名的主要内容,如果未能解决你的问题,请参考以下文章

如何在 linux 系统的可执行文件上设置图标(或 .ico 文件)?

如何在同一部 iPhone 中获取两个不同版本的可执行文件?使用 Xcode

已安装的 Java 程序提交批处理文件但它不执行。从命令窗口执行相同的可执行文件有效

从 C++ 中的可执行路径(或从 hWnd,或从 pid)获取程序名称

如何在c ++中的可执行文件附近的文件夹中打开图像

获取 AIX 上正在运行的进程的可执行文件的完整路径