Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

External Application from within a Delphi Form

849 views
Skip to first unread message

NYCDave

unread,
Jun 23, 2004, 6:47:46 PM6/23/04
to
I know how to run an external application from within Delphi.. what I need
to know is it possible to have an external program run inside a Delphi
form?

I use this very cumbersome application at work. Its a mainfraim emulator.
There are at least 12 different screens I access numerous times a day. I
thought that I could write a simple shell program with tabs so I could run
the mainframe emulator within the shell and have different instances of
the program for each tab. Is this possible with Delphi?

Thanks,
Dave

J French

unread,
Jun 24, 2004, 3:42:28 AM6/24/04
to
On Wed, 23 Jun 2004 18:47:46 -0400, "NYCDave" <nycd...@yahoo.com>
wrote:

I've never done it with Delphi, but have in VB - just experimentally

You can 're-parent' another process inside a Delphi Form

Are these emulators DOS, Console or Windows based ?

NYCDave

unread,
Jun 24, 2004, 11:03:55 AM6/24/04
to
The mainframe emulator I use is a Windows based application. You mentioned
"re-parent". I'll look through my books to see if Delphi has anything
like that. Thanks

Zakath

unread,
Jun 24, 2004, 11:28:55 AM6/24/04
to

I think you'll have to use Windows API for this... Check out the
SetParent function on msdn or whatever, it's in the Windows unit.

J French

unread,
Jun 25, 2004, 4:58:43 AM6/25/04
to
On Thu, 24 Jun 2004 11:03:55 -0400, "NYCDave" <nycd...@yahoo.com>
wrote:

>The mainframe emulator I use is a Windows based application. You mentioned
>"re-parent". I'll look through my books to see if Delphi has anything
>like that. Thanks
>

Just out of curiousity I have ported the routine to Delphi

It seems to work quite nicely.
Here is a Demo
- Followed by a few comments.

unit Unit1;

// Launch App and Re-Parent in a Panel
// 25th June 2004 - J French

// Add Two Buttons and One Large Panel

interface

uses
Windows, Messages, SysUtils, Classes,
Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls;

type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Panel1: TPanel;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
mHWnd :HWND; // hWnd of Slave App
public
{ Public declarations }
Constructor Create( AOwner:TComponent );Override;
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

constructor TForm1.Create(AOwner: TComponent);
begin
Inherited;
Button1.Caption := 'Launch Notepad';
Button2.Caption := 'Terminate Notepad';
end;

{
Get hWnd from a Process ID
}
Function InstanceToWnd( Const TgtPID:DWORD):HWND;
Var
ThisHWnd :HWND;
ThisPID :DWORD;
Begin
Result := 0;
ThisPID := 0;
// Find the first window
ThisHWnd := FindWindow( Nil, Nil);
While ThisHWnd <> 0 Do
Begin
//Check if the window isn't a child
If GetParent( ThisHWnd ) = 0 Then
Begin
//Get the window's thread & ProcessId
GetWindowThreadProcessId( ThisHWnd, Addr(ThisPID) );
If ThisPID = TgtPID Then
Begin
Result := ThisHWnd;
Break;
End;
End;
// 'retrieve the next window
ThisHWnd := GetWindow( ThisHWnd, GW_HWNDNEXT );
End;

End;{InstanceToWnd}

{
Launch App and return hWnd
}
Function ExecCmd( Const cmdline:String):HWND;
Var
PI :PROCESS_INFORMATION;
SI :STARTUPINFO;
Ret :LONGBOOL;
Begin;
Result := 0;
ZeroMemory( Addr(PI), SizeOf(PI) );
ZeroMemory( Addr(SI), SizeOf(SI) );
// Initialize the STARTUPINFO structure
SI.cb := SizeOf(SI);

// Start the shelled application:
Ret := CreateProcessA( Nil, PChar( cmdline ),
Nil, Nil, True,
NORMAL_PRIORITY_CLASS,
Nil, Nil,
SI, PI);
// --- let it start - this seems important
WaitForSingleObject( PI.hProcess, 500 );
If Ret Then
Begin
Result := InstanceToWnd( PI.dwProcessID );
CloseHandle( PI.hThread );
CloseHandle( PI.hProcess );
End;

End;{ExecCmd}


procedure TForm1.Button1Click(Sender: TObject);
begin
// Lock the window update - prevent flashing
// Does not work under XP
LockWindowUpdate( GetDesktopWindow );

// Execute notepad.Exe - Get its hWnd
mHWnd := ExecCmd( 'notepad.exe' );
If mHWnd = 0 Then
ShowMessage( 'Error starting the app' );

// Set the notepad's parent
If mHWnd <> 0 Then
Begin
Windows.SetParent( mHWnd, Panel1.Handle );
Windows.MoveWindow(mHWnd, 0, 0,
Panel1.ClientWidth,
Panel1.ClientHeight, True);
// Put the focus on notepad
Windows.SetFocus( mHWnd );
End;

// Unlock window update
LockWindowUpdate( 0 );
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
SendMessage(mHWnd, WM_CLOSE, 0, 0);
end;

end.

==== End of Code ====

Under Win95 the LockWindowUpdate() prevents the App showing up as
'normal' just before it is Re-Parented

This does not work under XP
A workaround would be to start it minimized and then resize it

WHILE DEBUGGING comment out the LockWindowUpdate

Notice that the Slave App does not appear in the Taskbar
- this may or may not be a problem

Slave Apps do appear in the Task Manager under Win95
Under XP they appear in the list of Processes not Running Apps

I have only (so far) tested this under Delphi using NotePad as the
slave App.

Also notice that the Delphi 'Host' loses focus when the Slave has
focus. This can be spoofed by trapping WM_ACTIVATEAPP

It would be an idea for someone else to give this code a once over,
just in case I've slipped up somewhere.

Hope this is useful

NYCDave

unread,
Jun 25, 2004, 11:38:42 AM6/25/04
to
Thanks!!! I'll give this a try when I get back from my vacation.

NYCDave

unread,
Jul 6, 2004, 4:11:08 PM7/6/04
to
The code works great. Thanks!!!

0 new messages