Delphi调用DLL中的接口

最近很少上论坛,这几次发现好几个问题都是围绕如何使用DLL中的接口而展开的。

问题描述:

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

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

解决方法:

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

错误调用代码为:

 

[delphi]  view plain copy
  1. var  
  2.   libHandle: THandle;  
  3.   GetDllObject: TGetDllObject;  
  4.   ADllObj: ICustomDLL;  
  5. begin  
  6.   libHandle := LoadLibrary(PChar(ExtractFilePath(ParamStr(0)) + edtDLLFileName.Text));  
  7.   try  
  8.     if (libHandle = 0then raise Exception.Create('载入DLL失败!');  
  9.     @GetDllObject := GetProcAddress(libHandle, 'GetDllObject');  
  10.     if (@GetDllObject <> nilthen  
  11.     begin  
  12.       ADllObj := GetDllObject() AS ICustomDLL; //GetDllObject()    
  13.       ADllObj.OwnerAppHandle := Application.Handle;  
  14.       edtDLLName.Text := ADllObj.DLLName;  
  15.       ADllObj.Execute;  
  16.     end  
  17.     else RaiseLastOSError();  
  18.   finally  
  19.     FreeLibrary(libHandle); //***前面正常,到这里就报错***  
  20.   end;  
  21. end;  

正确的全过程为:

 

[c-sharp]  view plain copy
  1. //DLL部分  
  2. 1.接口定义  
  3. unit DLLInf;  
  4. interface  
  5. type  
  6.   ITest = interface  
  7.   ['{623008B1-5E8C-463C-9048-821C14FB20C1}']  
  8.    
  9.     function ShowMSG(ParamStr:Widestring):Widestring;  
  10.  end;  
  11. implementation  
  12. end.  
  13. 2.接口实现  
  14. unit DLLImpl;  
  15. interface  
  16. uses  
  17.   DLLInf  ;  
  18. type  
  19.  TTest=class(TinterfacedObject,ITest)  
  20.   public  
  21.     function ShowMSG(ParamStr:Widestring):Widestring;  
  22.   end;  
  23. implementation  
  24. function TTest.ShowMSG(ParamStr: Widestring): Widestring;  
  25. begin  
  26.    result:=result+ ParamStr;  
  27. end;  
  28. end.  
  29. 3.导出类单元  
  30. function TestObj:ITest;stdcall;  
  31. begin  
  32.   result := TTest.create;  
  33.    
  34. end;  
  35. exports        
  36.   TestObj;  

[delphi]  view plain copy
  1. //前端调用  
  2. unit Unit1;  
  3. interface  
  4. uses  
  5.   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,  
  6.   Dialogs, StdCtrls,DLLInf;  
  7. type  
  8.   TTestObj=function:ITest;stdcall;  
  9.   TForm1 = class(TForm)  
  10.     btn1: TButton;  
  11.     edt1: TEdit;  
  12.     procedure btn1Click(Sender: TObject);  
  13.   private  
  14.     { Private declarations }  
  15.     TestObj: TTestObj;  
  16.     myDLLHandle: THandle;  
  17.     procedure  getDLLObject;  
  18.   public  
  19.     { Public declarations }  
  20.   end;  
  21. var  
  22.   Form1: TForm1;  
  23. implementation  
  24. {$R *.dfm}  
  25. procedure TForm1.getDLLObject;  
  26. var  
  27.   testStr:Widestring;  
  28. begin  
  29.     testStr:='Test String';  
  30.     @TestObj:= GetProcAddress(myDLLHandle, 'TestObj');  
  31.     if @TestObj<>nil then  
  32.         TestObj.ShowMSG(testStr) //调用DLL中的对象并执行相关方法  
  33.     else  
  34.        Application.MessageBox('在Dll动态链接库中加载方法失败!','提示',mb_ok);  
  35. end;  
  36. procedure TForm1.btn1Click(Sender: TObject);  
  37. begin  
  38.   myDLLHandle:=loadlibrary('DLLDemo.dll');  
  39.   try  
  40.    if myDLLHandle>0 then  
  41.      getDLLObject;  
  42.   finally  
  43.     FreeLibrary(myDLLHandle);  
  44.   End ;  
  45. end;  
  46. end.  

你可能感兴趣的:(Delphi,接口)