Home > other >  Calculating window handle from module file path gets wrong results
Calculating window handle from module file path gets wrong results

Time:02-26

In a 32-bit VCL Application in Windows 10 in Delphi 11 Alexandria, I am trying to get the window handle of a running main task from the task's module path:

type
  TFindWindowRec = record
  ModuleToFind: string;
  FoundHWnd: HWND;
end;

function EnumWindowsCallBack(aHandle: HWND; var FindWindowRec: TFindWindowRec): BOOL; stdcall;
const
  C_FileNameLength = 256;
var
  WinFileName: string;
  PID, hProcess: DWORD;
  Len: Byte;
begin
  Result := True;

  SetLength(WinFileName, C_FileNameLength);
  GetWindowThreadProcessId(aHandle, PID);
  hProcess := OpenProcess(PROCESS_ALL_ACCESS, False, PID);
  Len := GetModuleFileNameEx(hProcess, 0, PChar(WinFileName), C_FileNameLength);
  if Len > 0 then
  begin
    SetLength(WinFileName, Len);
    if SameText(WinFileName, FindWindowRec.ModuleToFind) then
    begin
      Result := False;
      FindWindowRec.FoundHWnd := aHandle;
    end;
  end;
end;

var
  FindWindowRec: TFindWindowRec;

function TformMain.GetmainWindowHandleFRomProcessPath(aProcessPath: string): HWND;
begin
  Result := 0;
  CodeSite.Send('TformMain.GetmainWindowHandleFRomProcessPath: aProcessPath', aProcessPath);
  FindWindowRec.ModuleToFind := aProcessPath;
  FindWindowRec.FoundHWnd := 0;
  EnumWindows(@EnumWindowsCallback, Integer(@FindWindowRec));
  if FindWindowRec.FoundHWnd <> 0 then
  begin
    Result := FindWindowRec.FoundHWnd;
    CodeSite.Send('TformMain.GetmainWindowHandleFRomProcessPath: Result', Result);
  end;
end;

When I do this with:

GetmainWindowHandleFRomProcessPath('c:\windows\system32\notepad.exe');

... then I get the correct window handle.

When I do this with:

GetmainWindowHandleFRomProcessPath('C:\Program Files (x86)\Embarcadero\Studio\22.0\bin\bds.exe');

... then I get a WRONG (non-existing) window handle!

Why is this happening? How do I get the correct window handle?

CodePudding user response:

The discussion with Remy and Andreas lead me to this successful working answer:

type
  TFindWindowRec = record
  ModuleToFind: string;
  FoundHWnd: HWND;
end;

// The `RzShellUtils` unit is from Ray Konopka's Signature Library available from GetIt:
function PathsAreSamePIDL(const Path1, Path2: string): Boolean;
begin
  var AIL1: PItemIdList;
  var AIL2: PItemIdList;
  RzShellUtils.ShellGetIdListFromPath(Path1, AIL1);
  RzShellUtils.ShellGetIdListFromPath(Path2, AIL2);
  var CompResult:= RzShellUtils.CompareAbsIdLists(AIL1, AIL2);
  Result := CompResult = 0;
end;

function EnumWindowsCallBack(aHandle: HWND; var FindWindowRec: TFindWindowRec): BOOL; stdcall;
const
  C_FileNameLength = MAX_PATH;
  PROCESS_QUERY_LIMITED_INFORMATION = $1000;
var
  WinFileName: string;
  PID, hProcess: DWORD;
  Len: Byte;
begin
  Result := True;

  SetLength(WinFileName, C_FileNameLength);
  GetWindowThreadProcessId(aHandle, PID);
  hProcess := OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, PID);
  Len := GetModuleFileNameEx(hProcess, 0, PChar(WinFileName), C_FileNameLength);
  CloseHandle(hProcess);
  if Len > 0 then
  begin
    SetLength(WinFileName, Len);
    //if SameText(WinFileName, FindWindowRec.ModuleToFind) then
    if PathsAreSamePIDL(WinFileName, FindWindowRec.ModuleToFind) then
    begin
      var IsVisible := IsWindowVisible(aHandle);
      if not IsVisible then EXIT;
      var IsOwned := GetWindow(aHandle, GW_OWNER) <> 0;
      if IsOwned then EXIT;
      var IsAppWindow := GetWindowLongPtr(aHandle, GWL_EXSTYLE) and WS_EX_APPWINDOW <> 0;
      if not IsAppWindow then EXIT;

      Result := False;
      FindWindowRec.FoundHWnd := aHandle;
    end;
  end;
end;

function TformMain.GetMainWindowHandleFromProcessPath(aProcessPath: string): HWND;
var
  FindWindowRec: TFindWindowRec;
begin
  Result := 0;
  FindWindowRec.ModuleToFind := aProcessPath;
  FindWindowRec.FoundHWnd := 0;
  EnumWindows(@EnumWindowsCallback, LPARAM(@FindWindowRec));
  if FindWindowRec.FoundHWnd <> 0 then
  begin
    Result := FindWindowRec.FoundHWnd;
  end;
end;

I don't understand why the person who moved the discussion to another page deleted the latest comments. Was there anything forbidden in those deleted comments?

Again: Thank you to Remy and Andreas!

  • Related