代码之家  ›  专栏  ›  技术社区  ›  Brian Frost

如何Shell到另一个应用程序并使其以Delphi形式显示

  •  11
  • Brian Frost  · 技术社区  · 16 年前

    在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;
    
    3 回复  |  直到 13 年前
        1
  •  15
  •   mghie    16 年前

    忽略了所有错误检查,但这应该可以让您开始:

    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;
    

    您应该明确地做的是枚举新进程的窗口,而不是简单地使用 查找窗口() 返回。

        2
  •  2
  •   chown    13 年前
    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); 
    
        3
  •  0
  •   paxdiablo    16 年前

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

    我已经看到了适用于基于文本的应用程序的方法——它们通常捕获过程的标准输出,并将其放入文本控件中。

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

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

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

    当然是一个拼凑,但有一个选择是不断地监视记事本窗口,并确保它总是叠加在您的窗体工作区上。这太可怕了,因为你必须阻止它移动、调整大小、最小化等等, 保持其z顺序刚好在应用程序之上。我不希望这些要求对我最坏的敌人。

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