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