为啥我在 64 位 Windows 8 上从 GetModuleFileNameEx 得到废话?
Posted
技术标签:
【中文标题】为啥我在 64 位 Windows 8 上从 GetModuleFileNameEx 得到废话?【英文标题】:Why do I get nonsense from GetModuleFileNameEx on 64-bit Windows 8?为什么我在 64 位 Windows 8 上从 GetModuleFileNameEx 得到废话? 【发布时间】:2014-09-23 16:06:51 【问题描述】:我有这个
function NazwaProcesu(const uchwyt: Thandle): string;
var
pid: DWORD;
hProcess: Thandle;
sciezka: array [0..MAX_PATH - 1] of char;
begin
GetWindowThreadProcessId(uchwyt, pid);
hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, FALSE, pid);
if hProcess <> 0 then
try
GetModuleFileNameEx(hProcess, 0, sciezka, MAX_PATH)
finally
Result := sciezka;
CloseHandle(hProcess);
end;
end;
在 windows 7 32 位上没有问题。在 Win 8 x64 我有这个:
我猜最后 3 个条目应该是 explorer.exe。感谢您的帮助。
【问题讨论】:
GetModuleFileNameEx
返回与您的应用程序相同位数的模块的文件名。
您很可能可以从 x64 进程查看 WOW64 进程,但反之则不行。 @user,您的进程是 64 位的吗?你为什么忽略检查错误?
如果您是 Delphi 用户,您可以使用类似问题的答案中的代码:***.com/questions/22285024/…
【参考方案1】:
据我所知,当代码在 32 位进程中执行时,这种方法将无法检索 64 位进程信息。在 WOW64 模拟器中运行时,此类问题很常见,避免此类问题的最简单方法是在 WOW64 模拟器之外运行代码。也就是说,在 64 位进程中运行您的代码。
如果您无法重新编译为 64 位,其他可能的解决方法是:
-
使用单独的 64 位进程和一些 IPC 来检索信息。
使用 WMI 获取模块文件名。
使用
QueryFullProcessImageName
。
我总是想强调的另一点是错误检查很重要。当您调用GetModuleFileNameEx
时,您无法检查错误。调用显然失败了,这就是为什么你最终得到一个未初始化的文本缓冲区的原因。始终检查 Windows API 调用是否有错误。
【讨论】:
谢谢。我还有一个问题,但会提出另一个话题。 或者我在这里发布:Delphi gettin notification from Windows about created/destroyed global window。这可能与 WINAPI 吗?我正在使用 EnumWindows,并且只想在更改时更新它。 @user3188855,我想你可能会使用WH_SHELL
钩子并等待HSHELL_WINDOWCREATED
代码来监视***窗口的创建(HCBT_CREATEWND
的WH_CBT
钩子对于你)。
@TLama 谢谢,但这仅适用于我的窗口。我检查了“HSHELL_WINDOWACTIVATED”,我必须从我的应用程序中单击窗口。我做错了什么?
@user 对答案的评论不是提出新问题的地方【参考方案2】:
修改后:
function NazwaProcesu(const uchwyt: Thandle): string;
type
TQueryFullProcessImageName = function(hProcess: Thandle; dwFlags: DWORD; lpExeName: PChar; nSize: PDWORD): BOOL; stdcall;
var
pid: DWORD;
hProcess: Thandle;
sciezka: array [0 .. MAX_PATH - 1] of Char;
QueryFullProcessImageName: TQueryFullProcessImageName;
nSize: cardinal;
begin
Result := '';
GetWindowThreadProcessId(uchwyt, pid);
hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, false, pid);
if hProcess <> 0 then
try
if GetModuleFileNameEX(hProcess, 0, sciezka, MAX_PATH) <> 0 then Result := sciezka
else if Win32MajorVersion >= 6 then
begin
nSize := MAX_PATH;
ZeroMemory(@sciezka, MAX_PATH);
@QueryFullProcessImageName := GetProcAddress(GetModuleHandle('kernel32'), 'QueryFullProcessImageNameW');
if Assigned(QueryFullProcessImageName) then
if QueryFullProcessImageName(hProcess, 0, sciezka, @nSize) then Result := sciezka
end;
finally
CloseHandle(hProcess);
end;
end;
【讨论】:
【参考方案3】:我最终选择了一个完全不同的解决方法。 This answer about PE headers 提到了 32 位和 64 位 Windows 可执行文件中的 PE 标头。您可以完全绕过 WinAPI 检查,并通过以二进制模式读取目标可执行文件并检查它是否与 PE 签名匹配来检查目标可执行文件。
遗憾的是,网上没有太多关于这个问题的信息。我记得在某个论坛上看到过这个问题,其中很明显被列为错误,但这是大约 10 年前的事了。我希望当我们讨论这个问题时,更多的人会意识到它。
【讨论】:
以上是关于为啥我在 64 位 Windows 8 上从 GetModuleFileNameEx 得到废话?的主要内容,如果未能解决你的问题,请参考以下文章
PyQt5 5.8.2 在 Windows 10 上从源代码构建
为啥我在 IA32_LSTAR MSR 上使用内核调试器在 64 位 Windows 上为 SYSCALL 设置断点时会出现 DoubleFault? (KVASCODE 部分)
为啥 Windows Vista 64 位默认使用 32 位 cmd.exe? (特定于机器)
在 64 位 linux 上从 32 位模式切换到 64 位(长模式)