Delphi调用DLL中的接口

问题描述:

具体问题就是在隐式使用接口变量后,在FreeLibrary执行后,就会出现一个非法访址的错误。

这个错误的原因就是在FreeLibrary后,DLL以的代码均为不可用状态,而在代码执行完整个过程后,VCL要对RTL类型的数据进行清理。而在清理过程中肯定要对接口进行减1并进行释放相关对象。而对象代码已从进程空间卸载,故报非法访址错误!

解决方法:

所以要想解决该问题,就应该把DLL调用过程放到一个单独的过程中,其目的就是让调用完毕后,让VCL来清理接口。清理完毕后返回后,再调用FreeLibrary来从进程空间中卸载DLL。

错误调用代码为:

 

var

  libHandle: THandle;

  GetDllObject: TGetDllObject;

  ADllObj: ICustomDLL;

begin

  libHandle := LoadLibrary(PChar(ExtractFilePath(ParamStr(0)) + edtDLLFileName.Text));

  try

    if (libHandle = 0) then raise Exception.Create('载入DLL失败!');

    @GetDllObject := GetProcAddress(libHandle, 'GetDllObject');

    if (@GetDllObject <> nil) then

    begin

      ADllObj := GetDllObject() AS ICustomDLL; //GetDllObject()  

      ADllObj.OwnerAppHandle := Application.Handle;

      edtDLLName.Text := ADllObj.DLLName;

      ADllObj.Execute;

    end

    else RaiseLastOSError();

  finally

    FreeLibrary(libHandle); //***前面正常,到这里就报错***

  end;

end;
View Code

正确的全过程为:

//DLL部分

1.接口定义

unit DLLInf;

interface

type

  ITest = interface

  ['{623008B1-5E8C-463C-9048-821C14FB20C1}']

 

    function ShowMSG(ParamStr:Widestring):Widestring;

 end;

implementation

end.

2.接口实现

unit DLLImpl;

interface

uses

  DLLInf  ;

type

 TTest=class(TinterfacedObject,ITest)

  public

    function ShowMSG(ParamStr:Widestring):Widestring;

  end;

implementation

function TTest.ShowMSG(ParamStr: Widestring): Widestring;

begin

   result:=result+ ParamStr;

end;

end.

3.导出类单元

function TestObj:ITest;stdcall;

begin

  result := TTest.create;

 

end;

exports      

  TestObj;
View Code
//前端调用

unit Unit1;

interface

uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, StdCtrls,DLLInf;

type

  TTestObj=function:ITest;stdcall;

  TForm1 = class(TForm)

    btn1: TButton;

    edt1: TEdit;

    procedure btn1Click(Sender: TObject);

  private

    { Private declarations }

    TestObj: TTestObj;

    myDLLHandle: THandle;

    procedure  getDLLObject;

  public

    { Public declarations }

  end;

var

  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.getDLLObject;

var

  testStr:Widestring;

begin

    testStr:='Test String';

    @TestObj:= GetProcAddress(myDLLHandle, 'TestObj');

    if @TestObj<>nil then

        TestObj.ShowMSG(testStr) //调用DLL中的对象并执行相关方法

    else

       Application.MessageBox('在Dll动态链接库中加载方法失败!','提示',mb_ok);

end;

procedure TForm1.btn1Click(Sender: TObject);

begin

  myDLLHandle:=loadlibrary('DLLDemo.dll');

  try

   if myDLLHandle>0 then

     getDLLObject;

  finally

    FreeLibrary(myDLLHandle);

  End ;

end;

end.
View Code

 

你可能感兴趣的:(Delphi)