将记录作为函数结果从Delphi DLL传递给C ++

时间:2013-04-20 10:11:50

标签: 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字节。

2 个答案:

答案 0 :(得分:5)

某些编译器将在寄存器中返回struct类型(可能取决于大小),其他编译器将添加隐藏的额外参数,其中应存储结果。不幸的是,看起来你正在处理两个不同意如何返回它们的编译器。

您应该可以通过明确使用out参数来避免此问题。

procedure TTest(out Result: TSimpleRecord); cdecl;
begin
  Result.Nr1 := 1;
  Result.Nr2 := 201;
end;

不要忘记相应地更新C ++代码。

Rudy Velthuis has written about this

  

这向我展示了ABCVar结构在寄存器EDX:EAX(具有前32位的EDX和具有较低位的EAX)中返回。这不是Delphi所做的记录,甚至不是这个尺寸的记录。 Delphi将这些返回类型视为额外的var参数,并且不返回任何内容(因此该函数实际上是一个过程)。

     

[...]

     

Delphi作为EDX返回的唯一类型:EAX组合是Int64。

这表明避免问题的另一种方法是

function TTest() : Int64; cdecl;
begin
  TSimpleRecord(Result).Nr1 := 1;
  TSimpleRecord(Result).Nr2 := 201;
end;

请注意,即使在C ++中未定义行为的情况下,Delphi也允许这种类型的惩罚。

答案 1 :(得分:1)

Delphi不遵循平台标准ABI的返回值。标准ABI按值将返回值传递给调用者。 Delphi将返回值视为隐式额外var参数,在所有其他参数之后传递。 documentation描述了规则。

您可以更改您的主叫代码以匹配该代码。在C ++函数中传递对struct参数的额外引用。

typedef void (__cdecl TestFunc)(TSimpleRecord&);     

如果你打算在C ++方面做这件事,那么为了清晰起见,你最好在Delphi方面做同样的改变。

由于Delphi不遵循返回值的平台标准,我建议您将自己限制为与其他工具兼容的类型。这意味着最多32位的整数值,指针和浮点值。

作为一般经验法则,请勿打包记录。如果这样做,您将会出现错误对齐,从而影响性能。对于问题中的记录,无论如何都没有填充,因为两个字段的大小相同。