Form in DLL is Invisible

Hi all,

I've got a problem when creating a form from within a DLL. I want my host application to call the DLL to provide a form, and the host should then display the returned form as a child of the host applications main form.

I've had a look at the examples offered in the following question:
http://www.experts-exchange.com/Programming/Programming_Languages/Delphi/Q_20081197.html

and am now passing through the host applications handle through to the DLL. I've got everything pretty much working (ie: no AV's), EXCEPT that if I set the parent property of the DLL-provided form to be the Main form the child form remains invisble after calling show. Not setting the parent property allows the child form to become visible, but it is no longer a child of the main form which is what I require. I suspect that there is more going on than just the child form not being visible, because scrollbars appear on the main form and they don't respond as expected.

ie:
  NewForm := MyDLL.GenerateForm(Application.Handle);
  NewForm.Parent := MainForm;   // <---- Commenting this out makes the form visible
  NewForm.Top := 10;
  NewForm.Left := 10;
  NewForm.Show;


If the child form is provided by the host application instead of a DLL, there is no problem with making the child form a child of the main form, so I figure that the problem must have something to do with using a DLL.

If anyone has got any suggestions, I'd really like to hear them,

Cheers,
Greg

PS. I'm using Delphi 7 personal ed.
gwhite012597Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

snehanshuCommented:
Have you done what ITugay suggested in the link:
http://www.gnomehome.demon.nl/uddf/pages/dll.htm#dll3
i.e. dynamically loading the DLL, changing the DLL's APPlication Handle etc.?
Pls provide your DLL code here.
...Shu
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Darth_helgeCommented:
this is what's inside my DLL with a form:

function ShowDllIRForm(hApp: THandle): TCustomForm; stdcall;
begin
 Application.Handle := hApp;
  if not assigned(IRForm) then
    IRForm := TIRForm.Create(Application);
  result := IRForm;
end;

and this is what that calls my dllform from the mainform:

ShowDllIRForm(MainForm.Handle).ParentWindow := MainPanel.Handle;
ShowDllIRForm(MainForm.Handle).Show;
SetForegroundWindow(ShowDllIRForm(MainForm.Handle).Handle);

and this works just fine!
0
gwhite012597Author Commented:
Hi guys,

Thanks for the input... I've written a basic app to test this functionality before implementing it in my main project. Below is the code from this test app...

----------------------------------------------
 here is the DLL code:
----------------------------------------------
library formlibrary;

uses
  forms,
  ULibraryForm in 'ULibraryForm.pas' {Form1};

function CreateForm : TForm; stdcall;
begin
  result := TForm1.Create(nil);
end;

exports
  CreateForm;

begin
end.

----------------------------------------------
 here is the child form unit - there is nothing special about this form. The only property changed after creation by the IDE was the visible property to false. This is so the form doesn't become visible until after
I assign the parent property:
----------------------------------------------
unit ULibraryForm;

interface

uses
  Classes, Forms;

type
  TForm1 = class(TForm)
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  end;

implementation

{$R *.DFM}

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;


----------------------------------------------
 here is my test app's main form:
----------------------------------------------
unit UMainForm;

interface

uses
  Controls, Forms, StdCtrls, Classes;

type
  TMainForm = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  end;

  function CreateForm : TForm; stdcall; external 'FormLibrary.DLL';
var
  MainForm: TMainForm;

implementation

{$R *.DFM}

procedure TMainForm.Button1Click(Sender: TObject);
var
  NewForm : TForm;
begin
  NewForm := CreateForm;
  NewForm.Caption := 'DLL Form';
  NewForm.Parent := self;
  NewForm.Top := 60;
  NewForm.Left := 10;
  NewForm.Show;
  {At this point NewForm should now be visible as a child of the main form - unfortunately it is not}
end;

procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  while(ControlCount > 0) do
    Controls[0].Free;
end;
end.


Cheers,
Greg

0
gwhite012597Author Commented:
Hi again,

I've now come up with a solution to the problem.... calling the UpdateControlState method of the mainform makes the child form visible. I'm guessing that when the NewForms parent property is set, Delphi adds the NewForm to the list of child controls of the MainForm - and calling the UpdateControlState method forces it to refresh the child control - of course I'm only guessing. The main thing is I've now got a work around for this behaviour.

----------------------------------------------
 Calling the UpdateControlState makes the form visible
----------------------------------------------
procedure TMainForm.Button1Click(Sender: TObject);
var
  NewForm : TForm;
begin
  NewForm := CreateForm;
  NewForm.Caption := 'DLL Form';
  NewForm.Parent := self;
  NewForm.Top := 60;
  NewForm.Left := 10;
  NewForm.Show;

  UpdateControlState;
end;


Thanks again for your time,

Cheers,
Greg

0
Mohammed NasmanSoftware DeveloperCommented:
Hello

  I think you need to pass the application and screen variables

and you Application.CreateForm to create the MDIForm

here's a sample

// dll libaray

library MyDll;
uses
  SysUtils,
  Classes,forms, windows,
   MyForm in 'MyForm.pas' {Form1};

{$R *.res}
var
  oApp : TApplication;
  oScr : TScreen;

procedure MyDLLProc(Reason: Integer);
begin
  if Reason = DLL_PROCESS_DETACH then
  begin
    Application := oApp;
    Screen := oScr;
  end;
end;

procedure ShowFrm(App:TApplication; Scr : TScreen); stdcall;
begin
  Application := App;
  Screen := Scr;
  App.CreateForm(TMyChildFrm, MyChildFrm);
  MyChildFrm.Show;
end;

exports
  ShowFrm;

begin
  oApp := Application;
  oScr := Screen;
  DLLProc := @MyDLLProc;
end.

==================

// test form

procedure ShowFrm(App: TApplication;Scr: TScreen); stdcall;

var
  Form2: TForm2;

implementation

procedure ShowFrm(App: TApplication;Scr: TScreen); external 'MyDll.dll' name 'ShowFrm';

{$R *.dfm}

procedure TForm2.NewForm1Click(Sender: TObject);
begin
    ShowFrm(Application, Screen);
end;

you can look for these question for more info
http://www.experts-exchange.com/Programming/Programming_Languages/Delphi/Q_20653308.html
http://www.experts-exchange.com/Programming/Programming_Languages/Delphi/Q_20665112.html
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.