繁体   English   中英

如何使用 Delphi 启动应用程序并获取它的句柄?

[英]How to Start an application and obtain a handle to it with Delphi?

我想从 Delphi 启动一个应用程序,并获得它的句柄,这样我就可以将所述应用程序的主窗口嵌入到 TFrame 类型的框架中。 到目前为止,我已经尝试过:

Function TFrmEmbeddedExe.StartNewApplication : Boolean;
var
  SEInfo: TShellExecuteInfo;
  ExitCode : DWORD;
begin

  FillChar(SEInfo, SizeOf(SEInfo), 0) ;
  SEInfo.cbSize := SizeOf(TShellExecuteInfo) ;
  with SEInfo do
  begin
    fMask := SEE_MASK_NOCLOSEPROCESS;
    Wnd := self.Handle;
    lpFile := PChar(self.fexecuteFileName) ;//  Example could be 'C:\Windows\Notepad.exe'
    nShow := SW_SHOWNORMAL;//SW_HIDE;
  end;

  if ShellExecuteEx(@SEInfo) then
  begin
    sleep(1500);
    self.fAppWnd := FindWindow(nil, PChar(self.fWindowCaption)); //Example : 'Untitled - Notepad'
    if self.fAppWnd <> 0 then
    begin
      Windows.SetParent(self.fAppWnd, SEInfo.Wnd);
      ShowWindow(self.fAppWnd, SW_SHOWMAXIMIZED);
      result := true;
    end
    else
      result := false;

  end

  else
    result := false;
end ;

上面的代码实际上有效,但 findWindow 会找到我启动的应用程序的任何给定实例。 我想嵌入我 Shell 执行的确切实例。 因此,如果记事本已经启动了几次,我就无法使用 FindWindow 获得正确的记事本。

我试过了:

Function TfrmEmbeddedExe.CreateProcessNewApplication : Boolean;
var
zAppName: array[0..512] of char;
StartupInfo: TStartupInfo;
ProcessInfo: TProcessInformation;
Res : DWORD;
DoWait : Boolean;
begin
  DoWait := False;
  StrPCopy(zAppName, self.fexecuteFileName);  //'C:\Windows\Notepad.exe'
  FillChar(StartupInfo, Sizeof(StartupInfo), #0);
  StartupInfo.cb := Sizeof(StartupInfo);
  StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
  StartupInfo.wShowWindow := SW_SHOWNORMAL;

  if CreateProcess (zAppName,
  nil, { pointer to command line string }
  nil, { pointer to process security attributes }
  nil, { pointer to thread security attributes }
  false, { handle inheritance flag }
  CREATE_NEW_CONSOLE or { creation flags }
  NORMAL_PRIORITY_CLASS,
  nil, { pointer to new environment block }
  nil, { pointer to current directory name }
  StartupInfo, { pointer to STARTUPINFO }
  ProcessInfo) then   { pointer to PROCESS_INF }
  begin
    if DoWait then  //just set it to false... so it will never enter here
    begin
      WaitforSingleObject(ProcessInfo.hProcess, INFINITE);
      GetExitCodeProcess(ProcessInfo.hProcess, Res);
    end
    else
    begin
      self.fAppWnd := ProcessInfo.hProcess;

      Windows.SetParent(self.fAppWnd, self.Handle);
      ShowWindow(self.fAppWnd, SW_SHOWMAXIMIZED);
      CloseHandle(ProcessInfo.hProcess);
      CloseHandle(ProcessInfo.hThread);


    end;

    result := true;
  end
  else begin
    Result := false;
  end;
end;

请不要在代码之上运行! 它会产生奇怪的结果,包括在所有正在运行的应用程序中的任何地方选择一个看似随机的窗口并嵌入它(甚至是 Windows 开始菜单中的菜单项......)

所以基本上我需要的是如何启动应用程序,并获取应用程序主窗口的句柄。

任何帮助都受到高度赞赏

问候

延斯·福吉

这是您需要做的大致轮廓。 我会把编码留给你:

  1. 使用ShellExecuteExCreateProcess启动您的流程。 这将产生一个进程句柄。
  2. 在进程句柄上调用WaitForInputIdle 这使进程有机会加载并启动其消息循环。
  3. 将进程句柄传递给GetProcessId以获取进程ID。
  4. 使用EnumWindows枚举顶级窗口。
  5. 将每个窗口传递给GetWindowThreadProcessId以检查是否找到了目标进程的顶级窗口。
  6. 找到一个进程ID与目标进程匹配的窗口后,您就完成了!

完成后,不要忘记关闭进程句柄。

当按下按钮时,我的程序“Master”最多可打开(运行)4 个其他程序(“Slaves”)。 当按下“Close-All”- 按钮时,所有“Slaves”再次关闭。 所以我遇到了同样的问题,即找到以 ShellExecute 启动的程序的窗口句柄。 我意识到,当你运行一个程序时,它会打开一个带有新窗口句柄的新窗口(有焦点),所以为什么不这样做:

  1. 获取当前聚焦窗口的句柄

  2. 使用 ShellExecute 打开新窗口

  3. 运行一个 Repeat-Until- 循环,读取当前聚焦的窗口句柄,直到它改变

  4. 这就是你想要的手柄。 所以这是执行此操作的函数 >>

    函数 TfmSWSM.RunProgramAndReturnHandle(ProgName : string): HWND; var PrevH, NewH : HWND; iSE : 整数; 开始结果:= 0; // Handle = 0 表示:无法打开程序 PrevH := GetForegroundWindow; // 保存之前的句柄以与新打开的窗口进行比较 iSE := ShellExecute(Handle, 'open', PChar(ProgName), nil,nil, SW_SHOWNORMAL); if (iSE > 32) then // 程序打开成功 >> 找到新窗口的句柄 >> 开始重复 // 等待新窗口变为活动状态 NewH := GetForegroundWindow; 直到 (NewH <> PrevH); // 新句柄意味着新窗口 Result := NewH; // Slave的句柄-程序结束; 结尾;

要打开记事本,你可以这样:

Slave1H := RunProgramAndReturnHandle('Notepad.exe');  // Slave1H is the handle to the program window

要再次关闭它,你可以这样:

if Slave1H <> 0 then  PostMessage(Slave1H, WM_CLOSE, 0, 0);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM