Solved

MDI Form in a DLL - Gives error

Posted on 1998-12-02
22
443 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
  • 9
  • 5
  • 3
  • +3
22 Comments
 
LVL 12

Expert Comment

by:rwilson032697
Comment Utility
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
Comment Utility
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
Comment Utility
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
 
LVL 3

Expert Comment

by:williams2
Comment Utility
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
Comment Utility
well..lets see your code willie :)

Cheers,
Viktor
0
 
LVL 3

Expert Comment

by:williams2
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 3

Expert Comment

by:Ronald Buster
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
..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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
This also works with Delphi 3 incase anyone was wondering
0
 
LVL 3

Expert Comment

by:williams2
Comment Utility
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

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

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…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
Polish reports in Access so they look terrific. Take yourself to another level. Equations, Back Color, Alternate Back Color. Write easy VBA Code. Tighten space to use less pages. Launch report from a menu, considering criteria only when it is filled…
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.

763 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

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now