没有一种通用方法可以获取应用程序的“该”窗口句柄,因为不能保证任何程序都有一个窗口句柄。一个程序可能有许多顶级句柄(例如,Microsoft Word,每个文档一个),或者它可能根本没有窗口。您可能会问您真正需要窗口句柄的目的是什么?可能有更好的方法来做你想做的事情,不需要任何特定的窗口句柄。
WinExec
(它已经被弃用近 15 年了,所以你应该认真考虑不再使用它)和ShellExecute
如果他们确实启动了任何程序,则绝对不会返回有关他们启动的程序的信息。 (ShellExecute
可能使用 DDE 向应用程序的已运行实例发送命令。)并且如果他们启动应用程序,它可能会在您的程序开始运行之前完成运行。
您可以使用CreateProcess http://msdn.microsoft.com/en-us/library/ms682425.aspx or ShellExecuteEx http://msdn.microsoft.com/en-us/library/bb762154.aspx反而。如果他们启动一个程序,他们会给您一个代表他们启动的程序的进程句柄。您可以使用它来帮助您获取有关该程序的其他信息,例如其窗口列表。别打扰FindWindow
;标题和窗口类不保证是唯一的;一个程序可能会对许多不同的窗口使用相同的类名,并且一个程序的多个实例将使用相同的类名,而没有太多方法可以选择您真正想要的类名。
EnumWindows
是一个可用于获取候选窗口句柄列表的函数。您给它一个函数指针,它将为桌面上的每个顶级窗口调用该函数一次。您需要一种方法来告诉它您对哪个进程感兴趣,以及一种让它返回结果列表的方法。该函数只接受一个参数,因此该参数必须是指向包含更多信息的结构的指针:
type
PWindowSearch = ^TWindowSearch;
TWindowSearch = record
TargetProcessID: DWord;
ResultList: TWndList;
end;
TWndList
是我创建的用于保存列表的类型HWnd
价值观。如果您有 Delphi 2009 或更高版本,您可以使用TList<HWnd>
;对于早期版本,您可以使用TList
后代或任何你选择的其他东西。
CreateProcess
会告诉你新的进程IDdwProcessID
的成员TProcessInformation
记录它填满;ShellExecuteEx
只返回一个进程句柄,所以使用GetProcessID http://msdn.microsoft.com/en-us/library/ms683215.aspx关于这一点。窗口枚举函数需要一个与此签名匹配的回调函数:
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
以便操作系统可以清理进程的簿记信息。