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

如何shell到另一个应用程序并使其以delphi形式出现,delphi,shellexecute,setparent,Delphi,Shellexecute,Setparent,在Delphi中,我多年来一直使用ShellExecute来启动(并可选地等待)其他应用程序。现在,我需要让这些应用程序中的一个出现在我的Delphi应用程序表单中。我已经尝试了下面的代码作为一个简单的测试来打开记事本(它可以)并在我的表单上的PAnel1中显示结果(它不能)。能找个好心人把我带上正轨吗? 谢谢 如果可能的话,这将是一个棘手的问题 我见过一些适用于基于文本的应用程序的方法——它们通常在流程发生时捕获流程的标准输出,并将其放入文本控件中 但您所说的是一个成熟的图形应用程序(记事本,

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


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

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

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

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

  • 请求缓冲区中的任意字符;及
  • 向程序发送任意击键, 我得说你真倒霉
这肯定是一个难题,但其中一个选项是持续监视记事本窗口,并确保它始终叠加在窗体客户端区域上。这是非常可怕的,因为你必须停止它的移动,调整大小,最小化等等,并保持它的z顺序刚好高于你的应用程序。我不希望那些要求发生在我最大的敌人身上


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

省略所有错误检查,但这应该让您开始:

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()返回的任何窗口句柄。

您想对记事本的主菜单做什么?我认为记事本只是其他程序尝试此技术的占位符。虽然我同意你的一般看法,如果有其他方法的话,不要这样做,但简单地设置父HWND并进行定位并不难。ActiveX/OLE控件肯定会更好。但是,当然可以将另一个应用程序的窗口放在您的应用程序中。我在VB中做过类似的事情,但我想我使用了MDI表单。而且,通过子类化捕获击键并将其发送到另一个windows窗体应该相对容易。但我已经有将近十年没有处理过这种事情了。太棒了,谢谢。我只希望我能详细了解正在发生的事情。。。。。!现在关闭以删除一些位,看看会发生什么。再次感谢。BriI很好奇-这能处理最小化、最大化改变z顺序等问题吗?或者应该为此添加更多的TForm1.Form*函数吗?看起来不错。唯一的问题是记事本的标题栏按钮被保留了下来,所以人们仍然可以最小化、最大化或关闭记事本。为了获得合适的解决方案,可能应该删除整个标题栏。根据要求,可能需要更多,但问题中的问题通过上述代码解决。什么是
fNotepadHandle
Windows
类型?@EASI:Windows是单元名称,是正确名称解析所必需的(表单具有相同名称、不同签名的方法)。另一个是
HWND
,但是您可以自己在FindWindow()API函数的文档中查找它。
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;
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);