Link to home
Start Free TrialLog in
Avatar of tdk_man
tdk_man

asked on

Program Within A Program

Bit of a strange one this...

Is it possible at all to create a window in a Delphi program so that an external exe (not written in Delphi) can be run and it's output directed to that window?

I'm writing a Delphi app which let's you create the data for a 3D terrain for use in a DirectX programming environment. Once the terrain has been created I'd like to be able to view a 3D rendering of the scene in the Delphi app.

Rather than installing a DirectX component in Delphi and having to learn how to use it, I could write a small exe in the 3D programming language which simply accepts the terrain data from the Delphi app and will display the 3D view in say a 320x200 window.

Is there any way I could 'lock' this window to my delphi app's screen to make it look like it isn't a separate exe?

Or is there a better way (if it's possible at all).

TDK_Man
Avatar of TheBigBadWolfGang
TheBigBadWolfGang

Hi

Do you think of something like that? (not tested)

your program is at c:\theprogram.exe
and is viewed in maincontrol (eg. a TPanel)

.....

var client : THandle;

   wtitle := 'ProgramCaption';
   chdir('c:\');
 
   if winexec('theprogram.exe',SW_SHOW)> 32 then
    begin
      client:=FindWindow(nil,wTitle);
    end;
   
  if client=0 then showmessage('Can't start the application')
  else begin
   setparent(client,maincontrol.Handle);    
    showwindow(client,sw_hide);
    SetWindowLong(client,GWL_STYLE,GetWindowLong( Handle, GWL_STYLE ) and not WS_CAPTION );
    showwindow(client,sw_show);
    setForegroundwindow(client);
    maincontrol.Invalidate;
    self.Invalidate;
    repaint;
    movewindow(client,0,0,clientwidth,clientheight,true);
    RedrawWindow(client,0,0,RDW_INVALIDATE+RDW_INTERNALPAINT+RDW_UPDATENOW+RDW_ALLCHILDREN);
    UpdateWindow(client);

....

wolf
Avatar of tdk_man

ASKER

Thanks for that, but I'm having problems with the

setparent(client,maincontrol.Handle);

line.

The help files say it only has one parameter - the handle of the new window (Panel1).

However, the Panel1.Handle property should be a TWinControl which  is incompatible with the type required by SetParent() and I can't figure out how to set the new value.

I put the code into  FormShow BTW.

TDK_Man
try using Windows.SetParent instead
or :

function sp(hwnd,parent:THandle):integer;
begin
  result:=setparent(hwnd,parent);
end;

note that there is no TForm1.sp(...)

wolf
Avatar of tdk_man

ASKER

I've got it working... sort of.

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    procedure FormShow(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  Client: THandle;

implementation

{$R *.DFM}

procedure TForm1.FormShow(Sender: TObject);
begin
  if winexec('c:\rotate.exe',sw_show) > 32 then
    Begin
      Sleep(2000);
      Client:=FindWindow(nil,PChar('Rotate'));
      Windows.SetParent(Client,Panel1.Handle);
      showwindow(client,sw_hide);
      SetWindowLong(client,GWL_STYLE,GetWindowLong( Handle, GWL_STYLE ) and not WS_CAPTION );
      showwindow(client,sw_show);
      setForegroundwindow(client);
      Panel1.Invalidate;
      Self.Invalidate;
      Repaint;
      movewindow(client,0,0,clientwidth,clientheight,true);
      RedrawWindow(client,0,0,RDW_INVALIDATE+RDW_INTERNALPAINT+RDW_UPDATENOW+RDW_ALLCHILDREN);
      UpdateWindow(client);
    End
  Else
    ShowMessage('Winexec Returns Less Than 32!');
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  CloseWindow(client);
end;

end.

But, the strange thing is that it will only work if the apps main form is only slightly larger than the TPanel itself.

As soon as you make the main form any larger, the display seems to move away from the top left corner of the Panel - as if it's anchored to the main form instead of the TPanel.

If anyone wants to check it out, the above code is just an empty form with a single TPanel on it and I've uploaded Rotate.exe that I've made for putting on the root of drive C: to http://www.matedit.com/rotate.zip.

TDK_Man


ASKER CERTIFIED SOLUTION
Avatar of Member_2_248744
Member_2_248744
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of tdk_man

ASKER

Slick812:

The main form of the Delphi application will contain all the options and buttons for the landscape generator and the window (TPanel) on the form will simply display a 3D view of the terrain being created.

I could save the terrain data to disk and then run a program written in the 3D language which would load the terrain data and show the landscape. However it wouldn't be very user-friendly if you had to load another program to see the results every time you changed something!

A better way would be to have the 3D exe running at the same time - accepting data from the Delphi application when data changes and updating the 3D display in real time.

Using this method, to the user, it would look like they were seeing a 3D window in the Delphi application.

As I said before, the only real alternative is something like the WDX8 or DelphiX components and having to learn how to use them from scratch.

TDK_Man
OK, I read your last comment and I agree with  your statements, as far as I can understand it, ,  I do not really follow your thoughts or your intent to say something about code or methods, at least for the code in my comment?
   In that I had hoped that your landscape program could run on your delphi programs form as a child window at the same time, , maybe with the code I gave, which seems to work with a notepad. . ., but I may have been off target, sorry about that
Avatar of tdk_man

ASKER

Sorry, I misunderstood you.

When you said "another window is not nesary (TPanel)" I thought you were suggesting that the TPanel wasn't needed and the whole Form should be used to display the 3D view.  It didn't click that you were actually suggesting a 'child' window which actually is a nice idea!

My comments in the last post were based on my incorrect asssumption of what you meant. :)

"I do not really follow your thoughts or your intent to say something about code or methods"

Sorry, I don't know what you are referring to here. I haven't mentioned either.

Now I know what you are suggesting, I'll try your method and see what happens.

Thanks for the help...

TDK_Man
Avatar of tdk_man

ASKER

Thanks for that Slick812 - it worked perfectly! :)

I modified my exe to create a 320x240 window without a title bar and altered the MoveWindow line to:

MoveWindow(RotateApp, Panel1.Left+1,Panel1.Top+1, 318, 238, True);

and the exe display appears to exactly fit in the TPanel on the main form!

I'm very impressed and very thankful. You deserve the points.

TDK_Man