Search code examples
delphishellexecutesetparent

How to shell to another app and have it appear in a delphi form


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;

Solution

  • 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.