Delphi DLL called from C++ crashes when showing a form
EDIT: Dumb question, already fixed. Form1
was nil
because I didn't assign it a new TForm1
, I forgot Delphi doesn't do that for you like C++.
I have a Delphi DLL that I want to use for the GUI of my C++ program, so just for starters, I created a form, and have a function that will show the form which is exported so that C++ can call it. However, the program crashes when it calls the function. Here is my code. (I am using Delphi 2010)
The delphi part:
unit Main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Tabs, ComCtrls;
type
TForm1 = class(TForm)
TabControl1: TTabControl;
TabSet1: TTabSet;
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
function ShowForm(i: Integer) : Integer; export; cdecl;
exports
ShowForm name 'ShowForm';
implementation
{$R *.dfm}
function ShowForm(i: Integer) : Integer; export; cdecl;
begin
Form1.Show();
Result := 3; // random value, doesn't mean anything
end;
end.
And here is the C++ code:
HMODULE h 开发者_开发技巧= LoadLibrary("delphidll.dll");
if (!h) {
printf("Failed LoadLibrary (GetLastError: %i)\n", GetLastError());
return 0;
}
FARPROC p = GetProcAddress(h, "ShowForm");
if (p)
printf("Found it @ %p\n", p);
else
printf("Didn't find it\n");
((int(__cdecl *)(int))p)(34);
system("PAUSE");
return 0;
The program prints "Found it @ " and then crashes. If I comment out Form1.Show()
in the Delphi DLL, it doesn't crash, and the function returns 3 (tested by printf). Am I missing some initialization or something? Thanks.
The reason it crases is that the var Form1: TForm1;
is not initialized.
The reason that the var Form1: TForm1;
is not initialized, is most likely because you put the unit Main
into a DLL project, but it originally came from a Delphi VCL project where you had Form1
on the auto-creation list.
The auto-creation list means that the Delphi .dpr will initialize the form.
Now you need to manually create the form, so you need to export these 3 new routines from your DLL, and have the C++ DLL call them:
function CreateForm() : Integer; export; cdecl;
begin
try
Application.CreateForm(TForm1, Form1);
Result := 0;
except
Result := -1;
end;
end;
function DestroyForm() : Integer; export; cdecl;
begin
try
if Assigned(Form1) then
begin
FreeAndNil(Form1);
Application.ProcessMessages();
end;
Result := 0;
except
Result := -1;
end;
end;
function DestroyApplication() : Integer; export; cdecl;
begin
try
FreeAndNil(Application);
Result := 0;
except
Result := -1;
end;
end;
In addition, you should put a try...except
block around the implementation of your ShowForm
function implementation, as exceptions and other language dependent run-time features should not cross DLL boundaries.
You probably should do similar things for releasing other potentially allocated pieces of dynamic memory too.
--jeroen
精彩评论