I have App.exe applications created in Delphi XE2, then the DLL is created in Delphi 10 Seattle. When I pass an Application.Handle to a DLL after calling a DLL I get an error "Exception class .... 'floating point stack check ...'". When I remove the Application.Handle from EXE assignment, the DLL is ok. I noticed this is related to the TAction action that is hooked to controlek. Eg to MainMenu. I'll also add that when a DLL is called from an EXE that is written in Delphi 10 Seattle it's all ok.
Thank you for your help.
Below I attach some code
Code Delphi XE2
unit Form_MainApp;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Buttons;
type
TfrmMainApp = class(TForm)
btnRunDLL: TBitBtn;
procedure btnRunDLLClick(Sender: TObject);
private
public
end;
var
frmMainApp: TfrmMainApp;
implementation
{$R *.dfm}
procedure TfrmMainApp.btnRunDLLClick(Sender: TObject);
const
LibraryFolder = '\Library\';
DLLName = LibraryFolder + 'TestDLL.dll';
type
TDLLProc = Function(pAppHandle:HWND; pAppTitle:PChar; pId:Integer; var pOUTId:Integer): TModalResult; StdCall;
var
DLLHandle: THandle;
DLLProc: TDLLProc;
DLLResult: TModalResult;
OUTId: Integer;
LibraryName: String;
begin
LibraryName:=ExtractFileDir(Application.ExeName) + DLLName;
DLLHandle:=Winapi.Windows.LoadLibrary(PChar(LibraryName));
try
if DLLHandle <> 0 then
begin
@DLLProc:=Winapi.Windows.GetProcAddress(DLLHandle, PChar('Run_TestDLL'));
if (@DLLProc <> nil) then
DLLResult:=DLLProc(Application.Handle, PChar(Application.Title), 0, OUTId);
end;
finally
if DLLHandle <> 0 then
Winapi.Windows.FreeLibrary(DLLHandle);
end;
end;
end.
Code Delphi 10 Seattle
library TestDLL;
uses
System.SysUtils,
System.Classes,
Controls,
Forms,
Dialogs,
Windows,
Form_MainDLL in 'Form_MainDLL.pas' {frmMainDLL};
{$R *.res}
Function Run_TestDLL(pAppHandle:HWND; pAppTitle:PChar; pId:Integer; var pOUTId:Integer):TModalResult; StdCall;
begin
Application.Handle:=pAppHandle;
Result:=mrNone;
try
frmMainDLL:=TfrmMainDLL.Create('Test');
frmMainDLL.ShowModal;
finally
FreeAndNil(frmMainDLL);
Result:=mrOk;
end;
end;
exports
Run_TestDLL;
begin
ReportMemoryLeaksOnShutdown:=True;
Randomize;
end.
FORM in DLL
unit Form_MainDLL;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
cxEdit, dxBar, Vcl.ExtCtrls, System.Actions,
Vcl.ActnList, Vcl.Menus, Vcl.StdCtrls;
type
TfrmMainDLL = class(TForm)
mmMain: TMainMenu;
mmEdit: TMenuItem;
mmAdd: TMenuItem;
mmData: TMenuItem;
mmClose: TMenuItem;
mmOpen: TMenuItem;
btnSetAction: TButton;
alMain: TActionList;
acAdd: TAction;
procedure acAddExecute(Sender: TObject);
procedure btnSetActionClick(Sender: TObject);
private
fName: String;
public
constructor Create(pName:String);reintroduce; virtual;
destructor Destroy; Override;
end;
var
frmMainDLL: TfrmMainDLL;
implementation
{$R *.dfm}
constructor TfrmMainDLL.Create(pName:String);
begin
inherited Create(Nil);
fName:=pName;
end;
destructor TfrmMainDLL.Destroy;
begin
inherited;
end;
procedure TfrmMainDLL.acAddExecute(Sender: TObject);
begin
ShowMessage('TEST');
end;
procedure TfrmMainDLL.btnSetActionClick(Sender: TObject);
begin
mmAdd.Action:=acAdd;
mmAdd.OnClick:=acAddExecute;
end;
end.
You need to ensure that messages CM_ACTIONEXECUTE
and CM_ACTIONUPDATE
will not be sent from VCL code in DLL to VCL code in EXE (because they have different runtime, and different TAction objects).
There are several ways:
Also, you need to catch all exceptions in Run_TestDLL.