我试图在 Delphi 窗体中托管其他应用程序,但我发现获取窗口句柄的例程不一致。
例如,如果我启动notepad.exe,下面的例程找不到任何与进程ID匹配的窗口句柄。然而,其他应用程序(如我自己的 Delphi 内置应用程序)被找到了。这个例程基于我找到的许多示例,但我不知道我遗漏了什么。
function enum_windows_callback(Handle: HWND; LParam: longint): bool; stdcall;
begin
Result := true;
var obj: TfHostApplication := TfHostApplication(Pointer(lParam)^);
var process_id: Cardinal := 0;
GetWindowThreadProcessId(Handle, &process_id);
if (obj.process_id = process_id) and (handle <> 0) then //and is_main_window(handle) then
obj.AppWindowHandles.Add(handle);
end;
procedure TfHostApplication.HostApplication(fn: string);
var
Rec: TShellExecuteInfo;
Title: string;
const
AVerb = 'open';
AParams = '';
ADir = '';
begin
FillChar(Rec, SizeOf(Rec), #0);
Rec.cbSize := SizeOf(Rec);
Rec.fMask := SEE_MASK_NOCLOSEPROCESS;
Rec.lpVerb := PChar( AVerb );
Rec.lpFile := PChar( fn );
Rec.lpParameters := PChar( AParams );
Rec.lpDirectory := PChar( Adir );
Rec.nShow := SW_HIDE;
// Run the application
if ShellExecuteEx(@Rec) then
begin
// Wait for it to become ideal i.e. finished loading
WaitForInputIdle(Rec.hProcess, 5000);
// Get the list of window handles for this process
AppWindowHandles.Clear;
ProcessHandle := Rec.hProcess;
process_id := GetProcessId(Rec.hProcess);
EnumWindows(@enum_windows_callback, integer(@Self));
if AppWindowHandles.Count > 1 then
begin
// if there is more than 1 window then display a list for the user to choose
lbWindows.Items.Clear;
var def := 0;
for var hwd in AppWindowHandles do
begin
var Len := GetWindowTextLength(hwd) + 1;
SetLength(Title, Len);
GetWindowText(hwd, PChar(Title), Len);
Title := Trim(Title);
lbWindows.Items.Add(Title);
end;
PanelSel.Visible := true;
PanelSel.align := alClient;
end
else if AppWindowHandles.Count > 0 then
begin
// if there is only 1 window then just use this.
SelectedWindowHandle := AppWindowHandles[0];
ShowAppInWindow;
end
else
DoCloseView;
end;
end;
procedure TfHostApplication.lbWindowsClick(Sender: TObject);
begin
inherited;
PanelSel.Visible := false;
if lbWindows.ItemIndex < AppWindowHandles.Count then
begin
SelectedWindowHandle := AppWindowHandles[lbWindows.ItemIndex];
SelectedWindowName := lbWindows.Items[lbWindows.ItemIndex];
ShowAppInWindow;
end;
end;
procedure TfHostApplication.ShowAppInWindow;
begin
Windows.SetParent(SelectedWindowHandle, Handle );
var Style := GetWindowLongPtr(SelectedWindowHandle, GWL_STYLE);
Style := Style and (not (WS_BORDER + WS_DLGFRAME + WS_THICKFRAME));
SetWindowLongPtr(SelectedWindowHandle, GWL_STYLE, Style);
Resize;
ShowWindow(SelectedWindowHandle, SW_SHOW);
end;
2条答案
按热度按时间55ooxyrt1#
使用CreateProcess而不是SheelExecute似乎可以解决查找句柄的问题。
cnjp1d6j2#
例如,如果我启动notepad.exe,下面的例程找不到任何与进程ID匹配的窗口句柄
原因是在64位版本的Windows上,默认情况下会启动64位版本的记事本。由于您的程序是32位的,因此您无法从任何64位应用程序/进程访问进程信息。
您需要使用64位版本的应用程序才能从64位应用程序中检索进程信息。
注意:您可以手动启动位于
\Windows\SysWOW64
文件夹中的32位版本的记事本。