我现在正在经历一些非常奇怪的事情.
当我将结构从C传递给Delphi DLL作为参数时,一切正常.
但是,一旦我想收到一条记录,我就会得到错误的值或异常.
我停用了记录的对齐方式,这样传递它们就可以了!
继承人的代码!
当我将结构从C传递给Delphi DLL作为参数时,一切正常.
但是,一旦我想收到一条记录,我就会得到错误的值或异常.
我停用了记录的对齐方式,这样传递它们就可以了!
继承人的代码!
Delphi DLL:
TSimpleRecord = packed record Nr1 : Integer; Nr2 : Integer; end; //... function TTest() : TSimpleRecord; cdecl; begin Result.Nr1 := 1; Result.Nr2 := 201; ShowMessage(IntToStr(SizeOf(Result))); end;
C电话:
#pragma pack(1) struct TSimpleRecord { int Nr1; int Nr2; }; //... typedef TSimpleRecord (__cdecl TestFunc)(void); TestFunc* Function; HINSTANCE hInstLibrary = LoadLibrary("Reactions.dll"); if (hInstLibrary) { Function = (TestFunc*)GetProcAddress(hInstLibrary,"TTest"); if (Function) { TSimpleRecord Result = {0}; Result = Function(); printf("%d - %d - %d",sizeof(Result),Result.Nr1,Result.Nr2); cin.get(); } }
我不知道为什么将此记录作为参数传递但不是作为函数的结果!?
有人能帮帮我吗?
谢谢
PS:正如我所说,C和Delphi都表明该记录大8字节.
解决方法
一些编译器将在寄存器中返回结构类型(可能取决于大小),其他编译器将添加一个隐藏的额外参数,其中应存储结果.不幸的是,看起来你正在处理两个不同意如何返回它们的编译器.
您应该能够通过显式使用out参数来避免此问题.
procedure TTest(out Result: TSimpleRecord); cdecl; begin Result.Nr1 := 1; Result.Nr2 := 201; end;
不要忘记相应地更新C代码.
Rudy Velthuis has written about this:
This showed me that the ABCVar struct was returned in the registers EDX:EAX (EDX with the top 32 bits,and EAX with the lower ones). This is not what Delphi does with records at all,not even with records of this size. Delphi treats such return types as extra var parameters,and does not return anything (so the function is actually a procedure).
[…]
The only type which Delphi returns as EDX:EAX combination is Int64.
这表明避免这个问题的另一种方法是
function TTest() : Int64; cdecl; begin TSimpleRecord(Result).Nr1 := 1; TSimpleRecord(Result).Nr2 := 201; end;
请注意,即使在C中未定义行为的情况下,Delphi也允许这种类型惩罚.