0

我用来创建一个自定义函数,如 winexec(...):Hwnd ,它将重新调整已执行应用程序的句柄。

我确实使用了 findwindow() 但如果它更改窗口标题会出现问题。

4

3 回答 3

8

没有通用的方法来获取应用程序的“窗口句柄”,因为不能保证任何程序都有一个窗口句柄。一个程序可能有许多顶级句柄(即,Microsoft Word,每个文档一个),或者它可能根本没有窗口。您可能会质疑您真正需要窗口句柄的目的是什么;可能有更好的方法来做你想做的任何事情,不需要任何特定的窗口句柄。

WinExec(它已被弃用近 15 年,因此您应该认真考虑不再使用它)并且ShellExecute绝对不返回有关它们启动的程序的信息,如果它们确实启动了任何程序。(ShellExecute可能使用 DDE 向应用程序的已运行实例发送命令。)如果他们启动应用程序,它可能会在您的程序运行之前完成运行。

您可以使用CreateProcessorShellExecuteEx代替。如果他们启动一个程序,他们会给你一个代表他们启动的程序的进程句柄。您可以使用它来帮助您获取有关该程序的其他信息,例如其窗口列表。不要打扰FindWindow; 不保证标题和窗口类是唯一的;一个程序可能对许多不同的窗口使用相同的类名,并且一个程序的多个实例将使用相同的类名,而没有太多方法可以选择您真正想要的。

EnumWindows是一个可用于获取候选窗口句柄列表的函数。你给它一个函数指针,它会为桌面上的每个顶级窗口调用一次该函数。您需要一种方法来告诉它您对哪个进程感兴趣,以及一种方法让它返回结果列表。该函数只接受一个参数,因此参数必须是指向包含更多信息的结构的指针:

type
  PWindowSearch = ^TWindowSearch;
  TWindowSearch = record
    TargetProcessID: DWord;
    ResultList: TWndList;
  end;

TWndList是我组成的用于保存HWnd值列表的类型。如果您有 Delphi 2009 或更高版本,您可以使用TList<HWnd>; 对于早期版本,您可以使用TList后代或您选择的任何其他内容。

CreateProcess将在它填写dwProcessID的记录成员中告诉您新的进程 ID ;只返回一个进程句柄,所以使用它。窗口枚举函数需要一个与此签名匹配的回调函数:TProcessInformationShellExecuteExGetProcessID

function SelectWindowByProcessID(Wnd: HWnd; Param: LParam): Bool; stdcall;

您可以使用EnumWindows以下方式获取句柄列表:

function GetWindowListByProcessID(pid: DWord): TWndList;
var
  SearchRec: TWindowSearch;
begin
  Result := TWndList.Create;
  try
    SearchRec.TargetProcessID := pid;
    SearchRec.ResultList := Result;
    Win32Check(EnumWindows(SelectWindowByProcessID, LParam(@SearchRec)));
  except
    Result.Free;
    raise;
  end;
end;

您将像这样实现回调函数:

function SelectWindowByProcessID(Wnd: HWnd; Param: LParam): Bool; stdcall;
var
  SearchRec: PWindowSearch;
  WindowPid: DWord;
begin
  SearchRec := PWindowSearch(Param);
  Assert(Assigned(SearchRec));
  GetWindowThreadProcessID(Wnd, WindowPid);
  if WindowPid = SearchRec.TargetProcessID then
    SearchRec.ResultList.Add(Wnd);
  Result := True;
end;

获得列表后,您可以检查窗口的其他属性以确定哪些是您真正想要的。您可以通过窗口标题或类名来确定它,或者通过属于该窗口的其他控件来确定它。

使用完进程句柄后,请确保调用CloseHandle它,以便操作系统可以清理进程的簿记信息。

于 2010-06-15T14:56:50.483 回答
2

有一个名为 EnumWindows 的函数。我想这对你会有用。

检查以下链接以获取更多信息

http://delphi.about.com/od/windowsshellapi/l/aa080304a.htm

http://www.swissdelphicenter.ch/torry/showcode.php?id=327

于 2010-06-15T06:58:27.780 回答
0

试试这个页面 ( http://delphidabbler.com/tips/134 ) 中的示例 6,然后稍微修改一下。这就是我所做的。

如果您想拆分检查的位置和查看结果的位置,您可以执行类似的操作

var
  //...
  runNext : Boolean;
  //...

begin
{ startup code from other sample here }

// but instead of if
runNext := ShellExecuteEx(@SEInfo);

{ some more code here }

    // need delay before running next process
    // run loop until window with Handle is closed
if runNext then
    with SEInfo do
     repeat
      GetExitCodeProcess(SEInfo.hProcess, ExitCode);
      Sleep(20);
      Application.ProcessMessages;
      CheckSynchronize();
    until (ExitCode <> STILL_ACTIVE) or Application.Terminated;

{ next process code here }
end;

我意识到你们中的一些人会因为抛出 Sleep() 而放弃仇恨邮件,但我宁愿在处理大量内容并等待时执行完成之前不锁定窗口。

于 2016-07-26T22:28:35.243 回答