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.

HOST アプリ コード

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 に答える