从模块文件路径计算窗口句柄得到错误的结果

发布于 2025-01-09 14:36:11 字数 1758 浏览 1 评论 0原文

在 Delphi 11 Alexandria 的 Windows 10 中的 32 位 VCL 应用程序中,我试图从任务的模块路径获取正在运行的主任务的窗口句柄:

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;

当我执行此操作时:

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

...然后我得到正确的窗口句柄。

当我这样做时:

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

...然后我得到一个错误的(不存在的)窗口句柄!

为什么会发生这种情况?如何获得正确的窗口句柄?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

听你说爱我 2025-01-16 14:36:11

与雷米和安德烈亚斯的讨论使我得到了这个成功的工作答案:

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;

我不明白为什么将讨论移至另一个页面的人删除了最新评论。那些被删除的评论里有什么禁止的内容吗?

再次感谢雷米和安德烈亚斯!

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!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文