做了一下测试:
主窗体(fsMDIForm)单元:
unit CMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Menus;
const
WM_CALLBACK = WM_USER + 100;
type
//Same as DLL Exports
TShowForm = function (App: TApplication; CallProc: Pointer; FormID: Integer; ParentForm: TForm): longint; stdcall;
TActiveForm = function : LongInt; stdcall;
TCloseForm = function : LongInt; stdcall;
TfrmMain = class(TForm)
MainMenu: TMainMenu;
mmFile: TMenuItem;
mmFileOpen: TMenuItem;
mmFileClose: TMenuItem;
procedure mmFileOpenClick(Sender: TObject);
procedure mmFileCloseClick(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
FLibHandle : THandle;
FShowForm : TShowForm;
FActiveForm : TActiveForm;
FCloseForm : TCloseForm;
procedure CallPostMessage(ID:Integer);
procedure BackCallMessage(var Msg: TMessage); message WM_CALLBACK;
public
{ Public declarations }
end;
var
frmMain: TfrmMain;
implementation
{$R *.dfm}
procedure CallBackProc(ID:Integer); stdcall;
begin
frmMain.CallPostMessage(ID);
end;
procedure TfrmMain.CallPostMessage(ID: Integer);
begin
PostMessage(self.Handle, WM_CALLBACK, ID, 0);
end;
procedure TfrmMain.BackCallMessage(var Msg: TMessage);
begin
if Msg.Msg = WM_CALLBACK then
begin
if Msg.WParam = FLibHandle then
begin
FreeLibrary(FLibHandle);
FLibHandle := 0;
end;
end;
end;
procedure TfrmMain.mmFileOpenClick(Sender: TObject);
var
FarPointer : FarProc;
begin
if FLibHandle = 0 then
begin
try
FLibHandle := LoadLibrary('Project2.dll');
except
FLibHandle := 0;
end;
if FLibHandle <> 0 then
begin
FarPointer := GetProcAddress(FLibHandle, 'ShowForm');
FShowForm := FarPointer;
FarPointer := GetProcAddress(FLibHandle, 'ActiveForm');
FActiveForm := FarPointer;
FarPointer := GetProcAddress(FLibHandle, 'CloseForm');
FCloseForm := FarPointer;
if Assigned(FShowForm) then
FShowForm(Application, @CallBackProc, FLibHandle, self);
end;
end
else
begin
if Assigned(FActiveForm) then
begin
FActiveForm;
end;
end;
end;
procedure TfrmMain.mmFileCloseClick(Sender: TObject);
begin
if FLibHandle <> 0 then
FCloseForm;
end;
procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if FLibHandle <> 0 then
FCloseForm;
end;
end.
动态库Library
library Project2;
uses
SysUtils,
Classes,
Forms,
Windows,
Unit2 in 'Unit2.pas' {frmChild};
{$R *.res}
function ShowForm(App: TApplication; CallProc: Pointer; CallID: Integer; ParentForm: TForm): LongInt; stdcall;
begin
Application := App;
@FreeProc := CallProc;
ProcID := CallID;
frmChild := TfrmChild.Create(ParentForm);
Result := Longint(frmChild);
frmChild.Show;
frmChild.BringToFront;
end;
function ActiveForm: LongInt; stdcall;
begin
if Assigned(frmChild) then
begin
frmChild.BringToFront;
frmChild.SetFocus;
end;
Result := 0;
end;
function CloseForm: LongInt;stdcall;
begin
if Assigned(frmChild) then
begin
frmChild.Close;
end;
Result := 0;
end;
exports
ShowForm, ActiveForm, CloseForm;
{Dll Entry Point}
procedure ExitDll(Reason: Integer);
begin
if Reason = DLL_PROCESS_DETACH then // detaching from process
begin
// restore application
Application := DllApp;
end;
end;
begin
// backup application
DllApp := Application;
DllProc := @ExitDll;
end.
动态库中子窗体单元
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TFreeProc = procedure (ProcID: Integer); stdcall;
TfrmChild = class(TForm)
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
frmChild : TfrmChild;
FreeProc : TFreeProc; //if childform is free(close), notify parent process
ProcID : Integer; //handle that is loaded from parent process
DllApp : TApplication; //a copy of dll application
implementation
{$R *.dfm}
procedure TfrmChild.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end;
procedure TfrmChild.FormDestroy(Sender: TObject);
begin
if Assigned(@FreeProc) then
FreeProc(ProcID);
end;
end.