为啥我在 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_CREATEWNDWH_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 位(长模式)

在 Windows 上从源代码构建 NSIS(VS2012)

Qt 4.8.4 Release 版本不适用于 Windows 7 64 位