2

我的主机应用程序有问题,它加载 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.
4

1 回答 1

1

你永远不会分配给Form_DLL. 这意味着当您调用时FreeF,您将执行FreeAndNil(Form_DLL)。因为Form_DLLis nil,所以什么都不做,并且表单仍然存在。

通过更改来解决这个问题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表单关闭。

于 2013-10-07T10:30:16.450 回答