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

Embedding Application

91 views
Skip to first unread message

Rolando M. Casumpang

unread,
Dec 7, 1999, 3:00:00 AM12/7/99
to
I want to run an application inside, say, a panel. This panel acts as the
desktop. I also want to trigger an event if it is closing (or trap it before
it closes).

Olan
--------------------------------------------
Rolando M. Casumpang
System Analyst/Programmer
E-mail: rcasu...@irri.cgiar.org
--------------------------------------------
"IRRI is one of 16 centers supported by the Consultative Group on
International Agricultural Research (CGIAR)"
http://www.cgiar.org


Peter Below (TeamB)

unread,
Dec 7, 1999, 3:00:00 AM12/7/99
to
In article <82i88n$fh...@forums.borland.com>, Rolando M. Casumpang wrote:
> I want to run an application inside, say, a panel. This panel acts as the
> desktop. I also want to trigger an event if it is closing (or trap it before
> it closes).
>

You can parent an external window to one of your own using Windows.Setparent
but it does not work as well as parenting a form in your own application to
another form. Here is an older thread on a related topic that may give you
some ideas:

<quote>
> I was wondering if someone can offer assistance with this application.
> Basically the application is for configuring our system. At present it is a
> MDI where child windows are various functions (security, report options,
> ect), the number of functions are growing, currently around 15, which means
> an increase in different child forms and, overall, a growing exe. I would
> like the child forms to be standalone programs or dlls which can appear in
> the control program as child windows and also execute by themselves. Only
> one child form is displayed at a time and always maximised within the parent
> window.
> I did see some code about that provided for a dll as a child form, but this
> would not help as a standalone execution.
> I think I need to do something fairly simplistically but I'm not too sure
> what. Grateful for any advice.


David,

this is an interesting problem. As it happens it is possible in Win32 to make
another processes window appear like a child window in ones own windows. It
does not work quite as well as a true child in your own process but takes care
about moving the pseudo-child with your menu app.

The general design is this: the main/menu app has a form with menu, perhaps
tool and status bars, and a client-aligned panel that will serve as the host
for the child windows. It reads the available child apps from INI file or
registry key and builds a menu or selection list from this info. On user
request it launches the appropriate child app and passes the panels window
handle on the commandline. The child app checks the command line, if there are
no parameters it rans as designed, if there is a parameter it reads it,
removes its border and bordericon, parents itself to the passed window handle
and sizes itself to its client area. It also sends a message with *its* window
handle to the panels parent (the main app form) to register itself. The main
app can close the child with this handle and also resize it when the user
resizes the main app.

For space reasons i will not give the form resources of main and child here.

Main app: has a menu with two entries (OpenMenu, CloseMenu), a toolbar with
two buttons attached to the same events as the two menus, a statusbar, a
client-aliged panel.

unit MenuApp;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Menus, ExtCtrls, ComCtrls, ToolWin;

const
UM_CHILDREGISTER = WM_USER + 111;
UM_CHILDUNREGISTER = WM_USER + 112;

type
TUmChildRegister = packed record
msg: Cardinal;
childwnd: HWND;
unused: Integer;
result: Integer;
end;
TUmChildUnregister = TUmChildregister;

TForm1 = class(TForm)
MainMenu1: TMainMenu;
OpenMenu: TMenuItem;
StatusBar1: TStatusBar;
ToolBar1: TToolBar;
ToolButton1: TToolButton;
CloseMenu: TMenuItem;
ToolButton2: TToolButton;
Panel1: TPanel;
procedure OpenMenuClick(Sender: TObject);
procedure CloseMenuClick(Sender: TObject);
procedure Panel1Resize(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
FChildAppHandle: HWND;

Procedure UMChildRegister( Var msg: TUmChildRegister );
message UM_CHILDREGISTER;
Procedure UMChildUnRegister( Var msg: TUmChildUnRegister );
message UM_CHILDUNREGISTER;
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation
uses shellapi;

{$R *.DFM}

procedure TForm1.OpenMenuClick(Sender: TObject);
var
path, param: String;
begin
If FChildAppHandle = 0 Then begin
path := ExtractFilePath( Application.Exename )+ 'childAppProj.exe';
param := '$'+IntTohex( panel1.handle, 8 );
ShellExecute( handle, 'open', pchar(path), pchar(param), nil,
SW_SHOWNORMAL );
end
else
ShowMessage('Child already loaded');
end;

procedure TForm1.CloseMenuClick(Sender: TObject);
begin
If FChildAppHandle <> 0 Then
SendMessage( FchildApphandle, WM_CLOSE, 0, 0 );
end;

procedure TForm1.Panel1Resize(Sender: TObject);
begin
If FChildAppHandle <> 0 Then
MoveWindow( FchildAppHandle, 0, 0,
Panel1.ClientWidth, Panel1.ClientHeight, true );
end;

procedure TForm1.UMChildRegister(var msg: TUmChildRegister);
begin
FChildAppHandle := msg.childwnd;
end;

procedure TForm1.UMChildUnRegister(var msg: TUmChildUnRegister);
begin
If FChildAppHandle = msg.childwnd Then
FChildAppHandle := 0;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
If FChildAppHandle <> 0 Then
SendMessage( FchildApphandle, WM_CLOSE, 0, 0 );
end;

end.

Child app has a couple of edits, two buttons, a memo.

unit ChildApp;

interface

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

type
TForm2 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Button1: TButton;
Memo1: TMemo;
Button2: TButton;
ApplicationEvents1: TApplicationEvents;
procedure Button1Click(Sender: TObject);
procedure ApplicationEvents1Activate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormResize(Sender: TObject);
private
{ Private declarations }
FMenuAppWnd: HWND;
FParentPanelWnd: HWND;
public
{ Public declarations }
Constructor Create( aOwner: TComponent ); override;
Procedure CreateWnd; override;
Procedure DestroyWnd; override;
end;

var
Form2: TForm2;

implementation

{$R *.DFM}
const
UM_CHILDREGISTER = WM_USER + 111;
UM_CHILDUNREGISTER = WM_USER + 112;

procedure TForm2.Button1Click(Sender: TObject);
begin
close;
end;

procedure TForm2.ApplicationEvents1Activate(Sender: TObject);
begin
If FMenuAppWnd <> 0 Then
SendMessage( FMenuAppWnd, WM_NCACTIVATE, 1, 0 );
memo1.lines.add( 'Activated');
end;

constructor TForm2.Create(aOwner: TComponent);
begin
If ParamCount > 0 Then Begin
FParentPanelWnd := StrToInt( ParamStr(1));
FMenuAppWnd := Windows.GetParent( FParentPanelWnd );
End;
inherited;
If FParentPanelWnd <> 0 Then Begin
Borderstyle := bsNone;
BorderIcons := [];
// remove taskbar button for the child app.
SetWindowLong( Application.Handle, GWL_EXSTYLE,
GetWindowLong( Application.Handle, GWL_EXSTYLE )
and not WS_EX_APPWINDOW or WS_EX_TOOLWINDOW );
End;
end;

procedure TForm2.CreateWnd;
var
r: Trect;
begin
inherited;
If FMenuAppWnd <> 0 Then Begin
SendMessage( FMenuAppWnd, UM_CHILDREGISTER, handle, 0 );
Windows.SetPArent( handle, FParentPanelWnd );
Windows.GetClientRect( FParentPanelWnd, r );
SetBounds( r.left, r.top, r.right-r.left, r.bottom-r.top );
End;
end;

procedure TForm2.DestroyWnd;
begin
If FMenuAppWnd <> 0 Then
SendMessage( FMenuAppWnd, UM_CHILDUNREGISTER, handle, 0 );
inherited;
end;

procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
// Closing the main form does not fire DestroyWnd for some reason
If FMenuAppWnd <> 0 Then
SendMessage( FMenuAppWnd, UM_CHILDUNREGISTER, handle, 0 );
end;

procedure TForm2.FormResize(Sender: TObject);
begin
memo1.width := clientwidth - memo1.Left - 10;
memo1.height := clientheight - memo1.Top - 10;
end;

end.

One problem i noted is that sometimes the main app caption will loose the
active look when switching between main and child despite the action taken in
the childs Application.OnActivate handler. Needs more work, but not from me
<G>.

</quote>

Peter Below (TeamB) 10011...@compuserve.com)
No replies in private e-mail, please, unless explicitly requested!


Rolando M. Casumpang

unread,
Dec 9, 1999, 3:00:00 AM12/9/99
to
Peter Below (TeamB) <10011...@compuXXserve.com> wrote in message
news:VA.0000434e.015421da@petersnewbox...

> In article <82i88n$fh...@forums.borland.com>, Rolando M. Casumpang wrote:
> > I want to run an application inside, say, a panel. This panel acts as
the
> > desktop. I also want to trigger an event if it is closing (or trap it
before
> > it closes).
> >
>
> You can parent an external window to one of your own using
Windows.Setparent
> but it does not work as well as parenting a form in your own application
to
> another form. Here is an older thread on a related topic that may give you
> some ideas:

This is a good stuff you gave me. Thanks.
But what if the application I would like to contain is not written by me! So
the Message passing is not applicable.

The code you gave me gives me an idea. The problem now is, say, I have the
process instance (say sei.hInstApp), :

1. How can I get the application Handle?
2. Delphi creates a hidden window (TApplication). How can I get the
corresponding form handle (say Form1) so that I could manipulate it?

Thanks

-Olan

Peter Below (TeamB)

unread,
Dec 9, 1999, 3:00:00 AM12/9/99
to
> But what if the application I would like to contain is not written by me! So
> the Message passing is not applicable.

Well, one could retrofit it, at least partially, by subclassing the "child"
apps main window API style. This is complicated for windows in another process
and i would not recommend it unless you have already a fairly good
understanding of API-level programming. Without that you are limited to
parenting the window to your own and sizing it to your client area. You have
to live with its caption and border.

> The code you gave me gives me an idea. The problem now is, say, I have the
> process instance (say sei.hInstApp), :
> 1. How can I get the application Handle?

You cannot, not from the instance handle, that is worthless in Win32. You can
from the process handle, but that is awkward. The best option would be to
launch the program with CreateProcess, that gives you a threadID for its main
thead and that you can use with EnumThreadWindows to find its main window.
That would work basically with any process, even if it can be a bit tricky to
identify the main window if the thread has several.

If you know the apps you have to deal with up front it would be easier, since
you could use WinSight to figure out the main windows classname and use
FindWindow to get at its handle.

> 2. Delphi creates a hidden window (TApplication). How can I get the
> corresponding form handle (say Form1) so that I could manipulate it?

If you have the application windows handle you can use
GetWindowThreadProcessID to get a threadID from it, that again can be used
with EnumThreadWindows. Look for a visible window (IsWindowVisible(wnd)) with
a width and height > 0 (GetWindowRect( wnd, rect )).

Rolando M. Casumpang

unread,
Dec 13, 1999, 3:00:00 AM12/13/99
to
Thanks

I Will try and. If I succeeded I will post it here!

-Olan

Rolando M. Casumpang

unread,
Dec 14, 1999, 3:00:00 AM12/14/99
to
Ok a new problem arises. Ise the following code snippet:

SetWindowLong(FApplication,GWL_EXSTYLE,
GetWindowLong(FApplication,GWL_EXSTYLE) AND NOT
WS_EX_APPWINDOW OR
WS_EX_TOOLWINDOW);
// Change Client's Parent
Windows.SetParent(FMainWindow,Panel1.Handle);
// Show Client
ShowWindow(FMainWindow,SW_MAXIMIZE);
// Set Client's Bounds
Windows.GetClientRect(Panel1.Handle,r);
SetWindowPos(FMainWindow, 0,
r.Left, r.Top, r.right-r.left, r.bottom-r.top,SWP_NOZORDER +
SWP_NOACTIVATE);

SetWindowLong only hide the icon from the taskbar and not the whole button.
What's left is the caption. I search the help and found the following:

"The window button typically contains the application icon and title.
However, if the application does not contain a window menu, the window
button is created without the icon. "

This is tough!

-Olan


Michael Cessna

unread,
Dec 14, 1999, 3:00:00 AM12/14/99
to
I didn't see the beginning of the thread, but this may work:

Application.ShowMainForm := False;

Rolando M. Casumpang <rcasu...@yahoo.com> wrote in message
news:8345v6$f8...@forums.borland.com...

0 new messages