如何shell到另一个应用程序并让它以delphi形式出现

发布于 2024-07-17 09:46:42 字数 774 浏览 4 评论 0原文

在 Delphi 中,我多年来一直使用 ShellExecute 来启动(并可选择等待)其他应用程序。 但现在,我需要让这些应用程序之一出现在我的 Delphi 应用程序表单之一中。 我尝试使用下面的代码作为一个简单的测试来打开记事本(它会这样做)并在我的表单上的 PAnel1 中显示结果(它不会)。 有好心人能让我走上正轨吗? 谢谢

var
  Rec          : TShellExecuteInfo;
  wnd : HWnd;
const
  AVerb = 'open';
  AParams = '';
  AFileName = 'Notepad.exe';
  ADir = '';
begin
  FillChar(Rec, SizeOf(Rec), #0);

  Rec.cbSize       := SizeOf(Rec);
  Rec.fMask        := SEE_MASK_NOCLOSEPROCESS;
  Rec.lpVerb       := PChar( AVerb );
  Rec.lpFile       := PChar( AfileName );
  Rec.lpParameters := PChar( AParams );
  Rec.lpDirectory  := PChar( Adir );
  Rec.nShow        := sw_Show;

  ShellExecuteEx(@Rec);

  wnd := Windows.FindWindow( 'Notepad', nil );
  Windows.SetParent( Wnd, PAnel1.Handle );

end;

In Delphi I've used ShellExecute for years to launch (and optionally wait for) other applications. Now though, I need to have one of these applications appear in one of my Delphi app forms. I've tried the code below as a simple test to open notepad (which it does) and to display the result within PAnel1 on my form (which it doesnt). Can some kind person put me on the right track?
Thanks

var
  Rec          : TShellExecuteInfo;
  wnd : HWnd;
const
  AVerb = 'open';
  AParams = '';
  AFileName = 'Notepad.exe';
  ADir = '';
begin
  FillChar(Rec, SizeOf(Rec), #0);

  Rec.cbSize       := SizeOf(Rec);
  Rec.fMask        := SEE_MASK_NOCLOSEPROCESS;
  Rec.lpVerb       := PChar( AVerb );
  Rec.lpFile       := PChar( AfileName );
  Rec.lpParameters := PChar( AParams );
  Rec.lpDirectory  := PChar( Adir );
  Rec.nShow        := sw_Show;

  ShellExecuteEx(@Rec);

  wnd := Windows.FindWindow( 'Notepad', nil );
  Windows.SetParent( Wnd, PAnel1.Handle );

end;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

夜清冷一曲。 2024-07-24 09:46:42

省略所有错误检查,但这应该可以帮助您开始:

procedure TForm1.Button1Click(Sender: TObject);
var
  Rec: TShellExecuteInfo;
const
  AVerb = 'open';
  AParams = '';
  AFileName = 'Notepad.exe';
  ADir = '';
begin
  FillChar(Rec, SizeOf(Rec), #0);

  Rec.cbSize       := SizeOf(Rec);
  Rec.fMask        := SEE_MASK_NOCLOSEPROCESS;
  Rec.lpVerb       := PChar( AVerb );
  Rec.lpFile       := PChar( AfileName );
  Rec.lpParameters := PChar( AParams );
  Rec.lpDirectory  := PChar( Adir );
  Rec.nShow        := SW_HIDE;

  ShellExecuteEx(@Rec);
  WaitForInputIdle(Rec.hProcess, 5000);

  fNotepadHandle := Windows.FindWindow( 'Notepad', nil );
  Windows.SetParent( fNotepadHandle, Handle );

  Resize;
  ShowWindow(fNotepadHandle, SW_SHOW);
end;

procedure TForm1.FormResize(Sender: TObject);
begin
  if IsWindow(fNotepadHandle) then begin
    SetWindowPos(fNotepadHandle, 0, 0, 0, ClientWidth, ClientHeight,
      SWP_ASYNCWINDOWPOS);
  end;
end;

您绝对应该做的是枚举新进程的窗口,而不是简单地使用 FindWindow() 返回的任何窗口句柄。

All error checking omitted, but this should get you started:

procedure TForm1.Button1Click(Sender: TObject);
var
  Rec: TShellExecuteInfo;
const
  AVerb = 'open';
  AParams = '';
  AFileName = 'Notepad.exe';
  ADir = '';
begin
  FillChar(Rec, SizeOf(Rec), #0);

  Rec.cbSize       := SizeOf(Rec);
  Rec.fMask        := SEE_MASK_NOCLOSEPROCESS;
  Rec.lpVerb       := PChar( AVerb );
  Rec.lpFile       := PChar( AfileName );
  Rec.lpParameters := PChar( AParams );
  Rec.lpDirectory  := PChar( Adir );
  Rec.nShow        := SW_HIDE;

  ShellExecuteEx(@Rec);
  WaitForInputIdle(Rec.hProcess, 5000);

  fNotepadHandle := Windows.FindWindow( 'Notepad', nil );
  Windows.SetParent( fNotepadHandle, Handle );

  Resize;
  ShowWindow(fNotepadHandle, SW_SHOW);
end;

procedure TForm1.FormResize(Sender: TObject);
begin
  if IsWindow(fNotepadHandle) then begin
    SetWindowPos(fNotepadHandle, 0, 0, 0, ClientWidth, ClientHeight,
      SWP_ASYNCWINDOWPOS);
  end;
end;

What you should definitely do is enumerate the windows of the new process, instead of simply using any window handle that FindWindow() returns.

撧情箌佬 2024-07-24 09:46:42
var
  URL: string;
begin
  URL:= DBMemoURL.Text;
  // ShellExecute(self.WindowHandle,'open', PChar(URL), nil, nil, SW_SHOW); //default browser
     ShellExecute(self.WindowHandle,'open','chrome.exe', PChar(URL), nil, SW_SHOW); 
var
  URL: string;
begin
  URL:= DBMemoURL.Text;
  // ShellExecute(self.WindowHandle,'open', PChar(URL), nil, nil, SW_SHOW); //default browser
     ShellExecute(self.WindowHandle,'open','chrome.exe', PChar(URL), nil, SW_SHOW); 
峩卟喜欢 2024-07-24 09:46:42

如果可能的话,这将是一个棘手的问题。

我见过适用于基于文本的应用程序的方法 - 它们通常捕获流程发生时的标准输出并将其放入文本控件中。

但您所说的是一个成熟的图形应用程序(记事本,尽管处理文本、显示像素,而不是字符代码)。

因此,除非记事本提供了一个接口,您可以:

  • 请求缓冲区中的任意字符; 并向
  • 程序发送任意击键,
    我想说你运气不好。

绝对是一个拼凑,但一个选择是持续监视记事本窗口并确保它始终叠加在您的表单客户区域上。 这非常可怕,因为您必须阻止它移动、调整大小、最小化等等,并保持其 z 顺序位于应用程序的正上方。 我不希望对我最大的敌人提出这些要求。

您是否考虑过使用专为 Delphi 构建的编辑器控件(或可以嵌入的 ActiveX 编辑器)? 这可能是一个更好的方法。

That will be a tricky one, if it's even possible.

I've seen approaches that will work for text-based applications - they generally capture the standard output of the process as it happens and put it into a text control.

But what you're talking about is a fully fledged graphical application (Notepad, despite working on text, display pixels, not character codes).

So, unless Notepad provides an interface where you can:

  • request arbitrary characters in the buffer; and
  • send arbitrary keystrokes to the program,
    I'd say you're flat out of luck.

Definitely a kludge, but one option is to continuously monitor the Notepad windows and ensure it's always superimposed over your forms client area. That's pretty horrible since you have to stop it moving, resizing, minimizing and so on, and maintain its z-order to be just above your applications. I wouldn't wish those requirements on my worst enemy.

Have you thought of using an editor control built specifically for Delphi (or an ActiveX editor that you could embed)? That might be a better approach.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文