Delphi与DLL的接口

Delphi与DLL的接口,delphi,dll,interface,loadlibrary,Delphi,Dll,Interface,Loadlibrary,使用delphixe 当尝试从DLL访问Delphi接口对象时,如果尝试动态访问而不是静态访问,则会失败 dll中的接口单元实现返回接口实例的函数。静态链接时,输入函数时结果为零,一切正常。动态加载时,结果是非nil的,因此当对结果进行赋值时,IntFCopy代码将其视为非nil,因此尝试在赋值之前释放它,这会引发异常 如有任何见解,将不胜感激 DLL包括TestInterface加载和导出测试: library testinterfaceload; uses SimpleShareMem

使用delphixe

当尝试从DLL访问Delphi接口对象时,如果尝试动态访问而不是静态访问,则会失败

dll中的接口单元实现返回接口实例的函数。静态链接时,输入函数时结果为零,一切正常。动态加载时,结果是非nil的,因此当对结果进行赋值时,IntFCopy代码将其视为非nil,因此尝试在赋值之前释放它,这会引发异常

如有任何见解,将不胜感激

DLL包括TestInterface加载和导出测试:

library testinterfaceload;

uses
  SimpleShareMem,
  SysUtils,
  Classes,
  testinterfaceload_u in 'testinterfaceload_u.pas';

{$R *.res}
exports testInt;

begin
end.
testinterfaceload_是定义接口和简单类实现的单元:

unit testinterfaceload_u;

interface

type ITestInt = interface
 procedure Test;
end;

{this function returns an instance of the interface}
function testInt : ITestInt; stdcall; export;

type

TTestInt = class(TInterfacedObject,ITestInt)
 procedure Test;
end;



implementation

function testInt : ITestInt;
begin
//debugger shows result as non-nil ITestInt even before this assignment, when dynamic
  result := TTestInt.Create;  
end;

procedure TTestInt.Test;
var
  i : integer;
begin
  i := 0;
end;



end.
下面是一个控制台应用程序,它加载dll并调用testInt函数返回接口:

program testload_console;

{$APPTYPE CONSOLE}

uses

SysUtils,
  Windows,
  testinterfaceload_u in 'testinterfaceload_u.pas';

type
  TTestInt = function() : ITestInt;

var
   TestInt: TTestInt;
   NewTestInt : ITestInt;
   DLLHandle: THandle;
begin
  DLLHandle := LoadLibrary('testinterfaceload.dll');
  if (DLLHandle < HINSTANCE_ERROR) then
       raise Exception.Create('testinterfaceload.dll can not be loaded or not found. ' +     SysErrorMessage(GetLastError));
  @TestInt := GetProcAddress(DLLHandle, 'testInt');
  try
    if Assigned(TestInt) then
      NewTestInt := TestInt;
  except on e:Exception do
    WriteLn(Output,e.Message);
  end;
end.
程序测试加载\u控制台;
{$APPTYPE控制台}
使用
SysUtils,
窗户,
“testinterfaceload_.pas”中的testinterfaceload_u;
类型
TTestInt=函数():ITestInt;
变量
试验:T染色;
新测试:ITestInt;
德尔汉德尔:坦德尔;
开始
DLLHandle:=LoadLibrary('testinterfaceload.dll');
如果(DLLHandle
尝试一下:尝试向控制台应用程序中dll的testInt函数和TTestInt fnction类型的声明中添加一个调用方法(stdcall、pascal等)

TTestInt
需要在导入DLL的代码中声明为
stdcall

接口定义应包含GUID,每个函数都需要“stdcall”声明。没有它,你可能会遇到问题

type ITestInt = interface
  ['{AA286610-E3E1-4E6F-B631-F54BC6B31150}']
  procedure Test; stdcall
end;
发布模式打开

function testInt : ITestInt;
begin
//debugger shows result as non-nil ITestInt even before this assignment, when dynamic
  result := TTestInt.Create;  
end;
应该是这样的程序

procedure testInt(out intf: ITestInt); stdcall;
begin
 intf := TTestInt.Create;  
end;

为什么要使用显式LoadLibrary而不是隐式链接?我在尝试运行调用另一个dll的其中一个dll时遇到了InstallAware问题。如果加载了第二个dll,则尝试卸载库时InstallAware似乎会阻塞,因此我尝试在第一个dll中处理它的寿命。
如果(DLLHandle
不正确
LoadLibrary
在出现错误时返回0(即
NULL
)。另外,
export
是不需要的,只是会混淆。删除它。t着色函数类型上的stdcall。不幸的是,它没有解决我的InstallAware问题。那显然是另外一回事。一旦你有了一系列的调用约定,那么你上面给出的代码就可以了。调用对流不匹配完美地解释了“调试器在这个赋值之前显示结果为非nil ITestInt,当它是动态的”嗯,有趣,我不知道。如果你没有异议的话,你愿意提供一个关于这个的文档链接吗?我的目标是学习一些新的东西,而不仅仅是空闲参数:对于字符串、动态数组、方法指针或变量结果,效果与函数结果声明为声明参数后的附加var参数相同。换句话说,调用者传递一个额外的32位指针,指向要返回函数结果的变量。