Solved

MDI Form in a DLL - Gives error

Posted on 1998-12-02
22
451 Views
Last Modified: 2011-09-20
I am trying to create a MDI form with 3 MDI children in a DLL. There is only one function I can Export and that function must create the MDI form and its children.

When I attemp to create the first child it gives this error 'Cannot Create Form. NO MDI Forms are currently active'.

I have to create the Main MDI form with a NIL as there is no Application in the DLL. ie
Form1 := TForm.Create(NIL);

0
Comment
Question by:ggets
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 9
  • 5
  • 3
  • +3
22 Comments
 
LVL 12

Expert Comment

by:rwilson032697
ID: 1348929
Um... You can't create MDI children from a DLL. A sad limitation I'm afraid (well, thats not strictly true, you can create them but you wont get them to work like MDI children created  in the main app).

Cheers,

Raymond.
0
 

Author Comment

by:ggets
ID: 1348930
I have seen a Dll that does do it, but its written in C V1.5

I suspect that this might be a Delphi restriction?
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1348931
The same question has been asked about 5 times now, and no one actually got a working answer, so I don't know if you'd find an answer for this one :( Sorry )

Cheers,
Viktor†
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
LVL 3

Expert Comment

by:williams2
ID: 1348932
I have had success with creating forms within a DLL, but it worked as I handled the application handle to the DLL at first.
Basically you need an application handle to create a form, or you will have a form without an application, am I wrong?

/Williams
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1348933
well..lets see your code willie :)

Cheers,
Viktor
0
 
LVL 3

Expert Comment

by:williams2
ID: 1348934
Ok Viktor, I have sent an example to your mail account specified in your userprofile.

In time, I will try to make a simplier example to be listed here.

regards
/Williams
0
 
LVL 3

Expert Comment

by:williams2
ID: 1348935
I have done dome further testing. Delphi needs the MDI-application to be the mainform of the application-window, that's why you get the error above.

I'll try some further testing now, where I'll try to create a new application window. Since the MainForm property is readonly, you cannot assign a new form as the mainform, but there might be other ways to trick the OS... I'll be back.

Regards
/Williams
0
 
LVL 3

Expert Comment

by:williams2
ID: 1348936
Ok guys hehehehe... I DID IT!!!!!! ..Limits are to be broken, but it's a HUGE damn hack! ..But it works! ..But I'm afraid you'll have to deal with the following points in seperate methods:

1. Open the window
2. Do some stuff, dataexchange etc.
3. Close the window

I'll have the answer proposed in a couple of hours!

regards
Williams
0
 
LVL 3

Expert Comment

by:williams2
ID: 1348937
Ok guys hehehehe... I DID IT!!!!!! ..Limits are to be broken, but it's a HUGE damn hack! ..But it works! ..But I'm afraid you'll have to deal with the following points in seperate methods:

1. Open the window
2. Do some stuff, dataexchange etc.
3. Close the window

I'll have the answer proposed in a couple of hours!

regards
Williams
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1348938
Williams. I couldn't find where the source was... I didn't open the project with Dlephi but tried to search for source files and couldn't find any .. There was a DLL that has only some stuff with the BItmaps and stuff...

Cheers,
Viktor
0
 
LVL 3

Expert Comment

by:williams2
ID: 1348939
Try again, you should open the program-manager, and select the source from withion the projects. You should also notice the directory 'dll'.


Ok! ..At the current moment I have a bit of a problem. The MDI form is showing and working, but when I exit the whole thing (including the first application) I get a pointer error from the dll..

Hey ggets! You better raise the credits, because this is going to take some time. I think I will need some sleep now Zzzzzzzz...

Cheers,
Williams
Cheers,
Williams
0
 
LVL 3

Expert Comment

by:Ronald Buster
ID: 1348940
I already did this a long time ago, and the source below works
however credit me and I mail you the full source code ready to run, no cut and paste however you can try the below code and you will see that it works.

regards,

Cono

<--------->


unit calldll;

interface

uses forms;

  procedure ini(app : Tapplication;scr : Tscreen);
  procedure doit;
  procedure restoreit;

implementation
 
  procedure doit; external 'dll1.dll' index 1;
  procedure ini; external  'dll1.dll' index 2;
  procedure restoreit; external 'dll1.dll' index 3;
end.

<-------->

library dll1;

uses
  SysUtils,
  Classes,
  forms,
  du1 in 'du1.pas' {Form1};

var
  me  : Tapplication;
  mec : Tscreen;

procedure ini(App : Tapplication;scr : Tscreen);export;
begin
  me := application;
  mec := screen;
  application := App;
  screen := scr;
end;

procedure doit; export;
begin
  Application.CreateForm(TForm1, Form1);
  form1.show;
end;

procedure restoreit; export;
begin
  application := me;
  screen := mec;
end;

exports
 doit index 1,
 Ini index 2,
 Restoreit index 3;

end.

<-------->

unit du1;

interface

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

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

var
  Form1: TForm1;

implementation

{$R *.DFM}

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

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

end.

<-------->

unit p1;

interface

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

type
  Tmdiform1 = class(TForm)
    Panel1: TPanel;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormDestroy(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  mdiform1: Tmdiform1;
implementation

{$R *.DFM}

procedure Tmdiform1.Button1Click(Sender: TObject);
begin
doit;
end;

procedure Tmdiform1.FormClose(Sender: TObject; var Action: TCloseAction);
var i: integer;
begin
 for i := 0 to MDIChildCount-1 do
   MDIChildren[i].Close;
end;

procedure Tmdiform1.FormDestroy(Sender: TObject);
begin
 restoreit;
end;

procedure Tmdiform1.FormCreate(Sender: TObject);
begin
ini(application, screen);
end;

end.

<-------->

program pp1;

uses
  Forms,
  p1 in 'p1.pas' {mdiform1},
  calldll in 'calldll.pas';

{$R *.RES}

begin
  Application.Initialize;
  Application.CreateForm(Tmdiform1, mdiform1);
  Application.Run;
end.


0
 

Author Comment

by:ggets
ID: 1348941
Sorry Cono... Your app creates the MDI form in the main aplication and the childern in the in the Dll.
(I hate rejecting answers - it seems so cold - Thanks anyway)

I need to create the MDI Form AND its children in the DLL.

This MDI form will be called by a middle data layer which only expects One Export function from my DLL. It will only pass info on what data to show, so I cannot add ANY extra export functions
for passing Application info etc.

william2 - I hope you have enough sleep, cos I really need an answer!!

This is a tuffy - so the challenge is on .
0
 
LVL 3

Expert Comment

by:williams2
ID: 1348942
Ha Ha Ha Ha Ha, you are very funny ggets!

Yes I did it and I was not sure that you would reject the answer, but I think I know how to deal with it, just give me some time :-).

If you would please send me your email, so I will know where to  send the project, because I think it will take a couple of hours to post the code. But to everybody else: I will post the answer, because this is a question that has been around for centuries.

Cheers everybody
/Williams
0
 
LVL 3

Expert Comment

by:williams2
ID: 1348943
..By the way. You should send it to williams90@hotmail.com, if you didn't know ..Sorry! :-)

/Williams
0
 
LVL 1

Expert Comment

by:Romanian
ID: 1348944
This code was compiled with Delphi 4 Update Pack 2 and work fine
===DLL CODE ===
library Project2;
uses
  Forms,
  SysUtils,
  Classes,
  Unit1 in 'Unit1.pas' {Form1},
  Unit2 in 'Unit2.pas' {Form2};
var
  SaveApp: TApplication;
procedure MyProc(Reason: Integer);
begin
  if Reason = 0{DLL_PROCESS_DETACH} then begin
    Application := SaveApp;
    SaveApp := Nil;
  end;
end;
procedure CreateAll(App: TApplication);
begin
  If SaveApp = Nil then begin
    SaveApp := Application;
    Application := App;
  end;
  Application.CreateForm(TForm1,Form1);
  TForm2.Create(Application).Panel1.Caption := '1';
  TForm2.Create(Application).Panel1.Caption := '2';
  TForm2.Create(Application).Panel1.Caption := '3';

end;
exports
  CreateAll index 1;
begin
  SaveApp := nil;
  DllProc := @MyProc;
end.
======

TForm1.FormStyle = fsMDIForm (Unit1)
TForm2.FormStyle = fsMDIChild (Unit2)

Tell me if something wrong.
My E-Mail: RomanPetrenko@netscape.net
0
 

Author Comment

by:ggets
ID: 1348945
Unfortunalty your app also requires that you send the DLL the application. The export function is fixed - I cannot change the arguments.
0
 
LVL 1

Expert Comment

by:Romanian
ID: 1348946
If export function doesn't receive any argument you can leave only function CreateAll like this:
====
procedure CreateAll;
begin
  Application.Initialize;
  Application.CreateForm(TForm1,Form1);
  TForm2.Create(Application).Panel1.Caption := '1';
  TForm2.Create(Application).Panel1.Caption := '2';
  TForm2.Create(Application).Panel1.Caption := '3';
  Application.Run;
end;
===
You must remove MyProc and startup dll code too.

PS: You can try change your code and you must create mainform with uses
  Forms,...
.....
Application.CreateForm(TYourFormClass,YourForm);

0
 

Author Comment

by:ggets
ID: 1348947
Romanian - Please submit you solution as a proposed answer-

You are a genius - Its simple, quick and easy.

Well Done!
0
 
LVL 1

Accepted Solution

by:
Romanian earned 600 total points
ID: 1348948
Thanks. It's pleasure for me.
So that is the answer:
If export function doesn't receive any argument you can leave only function CreateAll like this:
      ====
      procedure CreateAll;
      begin
        Application.Initialize;
        Application.CreateForm(TForm1,Form1);
        TForm2.Create(Application).Panel1.Caption := '1';
        TForm2.Create(Application).Panel1.Caption := '2';
        TForm2.Create(Application).Panel1.Caption := '3';
        Application.Run;
      end;
      ===
PS: You can try change your code and you must create mainform with
uses
     Forms,...
      .....
      Application.CreateForm(TYourFormClass,YourForm);
0
 

Author Comment

by:ggets
ID: 1348949
This also works with Delphi 3 incase anyone was wondering
0
 
LVL 3

Expert Comment

by:williams2
ID: 1348950
To Romanian and ggets:

Your example apparently works, but actually you may consider some bugs which is very nasty to get rid of.

It's not because I have hard feelings about this, but I just was in a situation, where I needed this feature, and I discovered the misbehavior and realized that some errors appeared.

1) When you close your MDI application, you will discover, that you'll have to close it twice before it terminates due to a  message error.
2) You should be aware of the application instance you have created creates a nasty stack error.

Romanians first example from Saturday, December 05 1998 - 01:26AM
has a huge error, you cannot pass the application object through a dll, only handles are allowed.

Romanians last answer just overrides the existing application object, which also is invalid though it's handle = 0.

Instead of solving the problem, you have generated a new application instance which makes the MDI-form act very weird, but as long as ggets is happy with this, everything is allright.

But I think you should know, that this was the exact problem I was having problems with when I wrote the last comment above and sent ggets the answer.

I have just solved this problem at the moment writing, and I will not share the answer, because I think you should figure out for yourself, as you obviously didn't realize the problem was there in the first place, I have used a 2 weeks figuring this application thing and most of all ggets accepted the answer from Romanian which makes him a happy guy.

but I can give you a hint:

You will notice, that the MDI-application got it's own icon in the start-menubar, but that's easy to remove :-)

But when you figure this out, you will also discover, that a MDI-application can actually be inside another MDI-child asswell.

So I hope you guys won't be just happy with what you have achieved this far, but don't consider reposting this question, since I realize that this practice will get you to better understanding of the subject, and I think we could use some more people who is willing not to give up at a first try.

Merry X-mas everybody :-)

Regards,
Williams
0

Featured Post

Want Experts Exchange at your fingertips?

With Experts Exchange’s latest app release, you can now experience our most recent features, updates, and the same community interface while on-the-go. Download our latest app release at the Android or Apple stores today!

Question has a verified solution.

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

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Michael from AdRem Software outlines event notifications and Automatic Corrective Actions in network monitoring. Automatic Corrective Actions are scripts, which can automatically run upon discovery of a certain undesirable condition in your network.…
Sometimes it takes a new vantage point, apart from our everyday security practices, to truly see our Active Directory (AD) vulnerabilities. We get used to implementing the same techniques and checking the same areas for a breach. This pattern can re…
Suggested Courses
Course of the Month8 days, 3 hours left to enroll

617 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