Solved

Form in DLL is Invisible

Posted on 2003-11-25
7
349 Views
Last Modified: 2010-04-05
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.
0
Comment
Question by:gwhite012597
7 Comments
 
LVL 5

Accepted Solution

by:
snehanshu earned 84 total points
ID: 9822598
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
 
LVL 5

Assisted Solution

by:Darth_helge
Darth_helge earned 83 total points
ID: 9824546
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
 

Author Comment

by:gwhite012597
ID: 9833480
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
 

Author Comment

by:gwhite012597
ID: 9833502
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
 
LVL 22

Assisted Solution

by:Mohammed Nasman
Mohammed Nasman earned 83 total points
ID: 9834118
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

Featured Post

Courses: Start Training Online With Pros, Today

Brush up on the basics or master the advanced techniques required to earn essential industry certifications, with Courses. Enroll in a course and start learning today. Training topics range from Android App Dev to the Xen Virtualization Platform.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
This Micro Tutorial hows how you can integrate  Mac OSX to a Windows Active Directory Domain. Apple has made it easy to allow users to bind their macs to a windows domain with relative ease. The following video show how to bind OSX Mavericks to …
Microsoft Active Directory, the widely used IT infrastructure, is known for its high risk of credential theft. The best way to test your Active Directory’s vulnerabilities to pass-the-ticket, pass-the-hash, privilege escalation, and malware attacks …

785 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question