接口DLL表单应用程序崩溃

时间:2013-10-07 07:59:51

标签: delphi plugins dll interface

我的主机应用程序有问题,它加载DLL表单并连接一些功能和属性。

目的是加载一个dll,显示名称作为模块名称,设置与ADOTable组件的连接并显示带有数据的表单。一切都很好。但在关闭主机应用程序后,主机应用程序崩溃,我得到了hostapp.exe停止工作的窗口。

我不知道是通过释放库还是为接口设置nil。

你有解决方案吗?感谢。

接口代码

unit u_baseplugin_intf;

interface

uses Data.Win.ADODB, Data.DB;

type
  IBaseModuleInterface = interface
  ['{060A9C46-B3CF-4BA4-B025-2DC1D9F45076}']
  function GetModuleName: Ansistring;stdcall;
  procedure SetConn(sConn:TAdoConnection);stdcall;
  procedure showF;stdcall;
  procedure freeF;stdcall;

  property ModuleName: Ansistring read GetModuleName;
  property Connection : TAdoConnection write SetConn;
  end;

implementation

end.

DLL代码

library profileslist;

uses
  System.SysUtils,
  System.Classes,
  u_baseplugin_intf,
  u_profileslist in 'u_profileslist.pas' {Form_DLL};

{$R *.res}

function LoadModule:IBaseModuleInterface;stdcall;
begin
  result:=TForm_DLL.Create(nil);
end;

exports
  LoadModule;

begin
end.

DLL表单代码

unit u_profileslist;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Grids, Vcl.DBGrids,  Vcl.StdCtrls,
  u_baseplugin_intf, Data.DB,Data.Win.ADODB;

type
  TForm_DLL = class(TForm, IBaseModuleInterface)
    DBGrid1: TDBGrid;
    ADOTable1: TADOTable;
    DataSource1: TDataSource;
    procedure FormShow(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
    {Interface methods implementation}
    function GetModuleName: AnsiString;stdcall;
    procedure SetConn(sConn:TAdoConnection);stdcall;
  public
    { Public declarations }
    {Interface methods implementation}
    procedure ShowF;stdcall;
    procedure FreeF;stdcall;
  end;

var
  Form_DLL: TForm_DLL;

implementation

{$R *.dfm}

{Interface methods implementation}
function TForm_DLL.GetModuleName;
begin
  Result := 'Profiles list';
end;

procedure TForm_DLL.SetConn(sConn: TAdoConnection);
begin
  AdoTable1.Connection:=sConn;
end;

procedure TForm_DLL.ShowF;
begin
  ShowModal;
end;

procedure TForm_DLL.FreeF;
begin
  FreeAndNil(Form_DLL);
end;

{Form_DLL methods implementation}
procedure TForm_DLL.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  AdoTable1.Active:=false;
end;

procedure TForm_DLL.FormShow(Sender: TObject);
begin
  AdoTable1.Active:=true;
end;

end.

主机应用代码

program hostapp;

uses
  Vcl.Forms,
  u_hostapp in 'u_hostapp.pas' {Form1},
  u_baseplugin_intf in 'u_baseplugin_intf.pas';

{$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

主机应用FORM代码

unit u_hostapp;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls,

  u_baseplugin_intf,
  Data.Win.ADODB, Data.DB;

type
  TForm1 = class(TForm)
    ADOConnection1: TADOConnection;
    Button1: TButton;
    Label1: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

type
  TModuleInterface = function:IBaseModuleInterface; stdcall;

var
  Form1: TForm1;

implementation

{$R *.dfm}
var
  aModuleIntf : IBaseModuleInterface;
  dllHandle : cardinal;

procedure LoadModule( aLibName : pWideChar );
var
   lModule : TModuleInterface;
 begin
   dllHandle := LoadLibrary(aLibName) ;
   if dllHandle <> 0 then
   begin
     @lModule := GetProcAddress(dllHandle, 'LoadModule') ;
     if Assigned (lModule) then
       aModuleIntf := lModule //call the function
     else
      begin
        ShowMessage('GetModuleIntf not found.') ;
        FreeLibrary(dllHandle) ;
      end;
   end
   else
   begin
     ShowMessage(aLibName+' not found.') ;
   end;
 end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  aModuleIntf.Connection:=AdoConnection1;
  aModuleIntf.ShowF;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  aModuleIntf.Connection:=nil;
  aModuleIntf.freeF;
  aModuleIntf:=nil;
  FreeLibrary(dllHandle);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  LoadModule('profileslist.dll');
  Label1.Caption:=aModuleIntf.ModuleName;
end;

end.

1 个答案:

答案 0 :(得分:1)

您永远不会分配到Form_DLL。这意味着当您致电FreeF时,您就会执行FreeAndNil(Form_DLL)。由于Form_DLLnil,因此无效,表单仍然存在。

通过更改LoadModule

来解决此问题
function LoadModule:IBaseModuleInterface;stdcall;
begin
  Assert(not Assigned(Form_DLL));
  Form_DLL:=TForm_DLL.Create(nil);
  result:=Form_DLL;
end;

虽然,我可能会完全删除Form_DLL来完全改变设计。主机应用程序维护对表单的引用,可以在该表单上调用Free。换句话说,请删除Form_DLL并实施FreeF,如下所示:

procedure TForm_DLL.FreeF;
begin
  Free; // or Destroy
end;

或者甚至更好,在实现对象上使用引用计数接口,让aModuleIntf:=nil将表单缩小。