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

标签 windows delphi winapi

我想从 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 与目标进程匹配的窗口,就大功告成了!

不要忘记在完成处理后关闭进程句柄。

关于windows - 如何使用 Delphi 启动应用程序并获取它的句柄?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12282952/

相关文章:

c - NtFsControlFile函数错误

windows - 如何在 GUI 应用程序中写入控制台

windows - 在 Windows 10 的 Ubuntu Bash shell 中,如何使用默认程序打开文件或目录?

delphi - 启动进程并监听退出事件

delphi - delphi中枚举注册表子项

delphi - 如何在FireMonkey TTreeView的某个位置添加节点?

c++ - 如何将 native (NT) 路径名转换为 Win32 路径名?

Windows 批处理文件 - 嵌套 FOR 循环中的变量

windows - 如何为未注册的文件扩展名显示 "open with"对话框?

用于分离辅助监视器的 C++ 应用程序