Post by NYCDaveThe 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