Go Premium for a chance to win a PS4. Enter to Win

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

MDI Form in a DLL - Gives error

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
ggets
Asked:
ggets
  • 9
  • 5
  • 3
  • +3
1 Solution
 
rwilson032697Commented:
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
 
ggetsAuthor Commented:
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
 
viktornetCommented:
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
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
williams2Commented:
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
 
viktornetCommented:
well..lets see your code willie :)

Cheers,
Viktor
0
 
williams2Commented:
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
 
williams2Commented:
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
 
williams2Commented:
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
 
williams2Commented:
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
 
viktornetCommented:
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
 
williams2Commented:
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
 
Ronald BusterCommented:
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
 
ggetsAuthor Commented:
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
 
williams2Commented:
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
 
williams2Commented:
..By the way. You should send it to williams90@hotmail.com, if you didn't know ..Sorry! :-)

/Williams
0
 
RomanianCommented:
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
 
ggetsAuthor Commented:
Unfortunalty your app also requires that you send the DLL the application. The export function is fixed - I cannot change the arguments.
0
 
RomanianCommented:
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
 
ggetsAuthor Commented:
Romanian - Please submit you solution as a proposed answer-

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

Well Done!
0
 
RomanianCommented:
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
 
ggetsAuthor Commented:
This also works with Delphi 3 incase anyone was wondering
0
 
williams2Commented:
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

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

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