Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 296
  • Last Modified:

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
0
tdk_man
Asked:
tdk_man
  • 5
  • 2
  • 2
  • +1
1 Solution
 
TheBigBadWolfGangCommented:
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
0
 
tdk_manAuthor Commented:
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
0
 
DragonSlayerCommented:
try using Windows.SetParent instead
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
TheBigBadWolfGangCommented:
or :

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

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

wolf
0
 
tdk_manAuthor Commented:
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


0
 
Slick812Commented:
hello  tdk_man , , for me I think it would be nessary to set the Style bit for WS_CHILD for the main window of program . . . as below, another window is not nesary (TPanel) but may be usefull for other effects, but you do not say anything about other masking or movements effects. .


procedure TForm1.but_GetNotePadClick(Sender: TObject);
var
hNotePad, Style: Cardinal;
begin
// button click event
hNotePad := FindWindow(nil, 'Untitled - NotePad');
if hNotePad = 0 then
  begin
  ShowMessage('NotePad is NOT Running');
  Exit;
  end;
ShowWindow(hNotePad, SW_HIDE);
Style := GetWindowLong(hNotePad, GWL_STYLE);
if Style = 0 then
  begin
  ShowMessage('System can NOT access Style');
  Exit;
  end;
Style := Style  or WS_CHILD; // to be attatched to another window I think u need a ws_child
SetWindowLong(hNotePad, GWL_STYLE, Style);
windows.SetParent(hNotePad, Handle);
MoveWindow(hNotePad, 2,2, Width-10, Height - 56, True);
ShowWindow(hNotePad, SW_SHOW);
end;

 - - - - - - - - - - - - - - - - - - - - - - - - - - -  - - -
you can also change some of the other "Style" bits, but not all style changes work as you would expect. . .
0
 
tdk_manAuthor Commented:
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
0
 
Slick812Commented:
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
0
 
tdk_manAuthor Commented:
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
0
 
tdk_manAuthor Commented:
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
0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

  • 5
  • 2
  • 2
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now