5

I have this

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;

On windows 7 32 bit no problems. On Win 8 x64 i have this:

enter image description here

where last 3 entries should be explorer.exe, i guess. Thanks for help.

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
mca64
  • 534
  • 1
  • 5
  • 17
  • The `GetModuleFileNameEx` returns the file name for modules of the same bitness as your application is. – TLama Jul 31 '14 at 15:54
  • It's likely that you can see into WOW64 processes from an x64 process, but not the other way. @user, is your process 64 bit? And why are you neglecting to check for errors? – David Heffernan Jul 31 '14 at 15:55
  • if you are Delphi user you can use the code from answer on the similar question: http://stackoverflow.com/questions/22285024/how-to-get-a-systems-process-path-from-pid-in-a-64-bit-system/22286210#22286210 – Denis Anisimov Jul 31 '14 at 19:55

3 Answers3

10

As far as I am aware, this approach will fail to retrieve 64 bit process information when the code is executed in a 32 bit process. This sort of problem is common when running inside the WOW64 emulator and the cleanest way to avoid such issues is to run the code outside of the WOW64 emulator. That is, run your code in a 64 bit process.

Other possible ways to work around this, if you cannot re-compile as 64 bit are:

  1. Use a separate 64 bit process, and some IPC, to retrieve the information.
  2. Use WMI to get the module file name.
  3. Use QueryFullProcessImageName.

Another point that I always like to stress, is that error checking is important. You fail to check for errors when you call GetModuleFileNameEx. The calls are clearly failing which is why you end up with an uninitialized text buffer. Always check Windows API calls for errors.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Thanks. I have another question, but will make another topic. – mca64 Jul 31 '14 at 16:18
  • or i post here: Delphi gettin notification from Windows about created/destroyed global window. Is this possible with WINAPI? Im using EnumWindows and want to update this only when is change. – mca64 Jul 31 '14 at 16:23
  • @user3188855, I think you might use the [`WH_SHELL`](http://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx#WH_SHELL) hook and wait for the [`HSHELL_WINDOWCREATED`](http://msdn.microsoft.com/en-us/library/windows/desktop/ms644991(v=vs.85).aspx#HSHELL_WINDOWCREATED) code to monitor top level windows creation (`HCBT_CREATEWND` of the `WH_CBT` hook would be too early for you). – TLama Jul 31 '14 at 17:22
  • @TLama thanks, but this work only for my window. I check "HSHELL_WINDOWACTIVATED" and i must click on window from my app. What im doin wrong? – mca64 Jul 31 '14 at 17:59
  • @user Comments to an answer is not the place to ask a new question – David Heffernan Jul 31 '14 at 18:00
3

After modifications:

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;

enter image description here

mca64
  • 534
  • 1
  • 5
  • 17
0

I ended up going for a completely different workaround. This answer about PE headers mentions the PE headers among 32 and 64 bit Windows executables. You can completely circumvent the WinAPI checking, and have your target executable checked via reading it in the Binary mode and checking if it matches the PE signature.

Sadly, there isn't much info on the problem online. I remember seeing this problem on some forum, where is was clearly listed as bug, but this was about ~10 years ago. I hope as we discuss this problem, more people become aware of it.

TAbdiukov
  • 1,185
  • 3
  • 12
  • 25