2013-04-20 50 views
7

我現在正在經歷一些非常奇怪的事情。 當我從C++傳遞一個結構爲Delphi DLL作爲參數時,一切正常。 但是,只要我想要收到一條記錄,我就會得到錯誤的值或異常。 我停用記錄的對齊方式,以便傳遞它們應該可以工作!這裏是代碼!將記錄作爲函數結果從Delphi DLL傳遞到C++

德爾福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個字節大。

+0

你是否真的在Delphi函數中設置了返回值? – Angew 2013-04-20 10:16:31

+0

Result.Nr1:= 1; Result.Nr2:= 201;這應該做 – Henry 2013-04-20 10:16:59

+0

對不起,當我最後一次與Delphi交互時,'Result'仍然使用了函數標識符IIRR。 – Angew 2013-04-20 10:19:32

回答

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(EDX與頂部32位,和EAX與下部的)。這不是德爾福所做的記錄,甚至沒有記錄這種大小。 Delphi將這種返回類型視爲額外的var參數,並且不返回任何東西(所以函數實際上是一個過程)。

[...]

其中的Delphi返回作爲EDX的唯一類型:EAX組合的Int64。

這表明另一種方法來避免此問題是

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

注意的Delphi允許這種類型雙關即使在行爲將在C未定義情況++。

+0

謝謝,正是我在找的!即使使用Int64的示例對我無效 – Henry 2013-04-20 10:47:43

+0

@Henry它不起作用的方式?它會給你一個錯誤信息,還是你仍然得到不正確的行爲?我問,因爲我已經驗證了結果是在獨立應用程序中返回寄存器(如預期的那樣)。很高興,避免這個問題的另一種方法是工作,無論如何:) – hvd 2013-04-20 10:56:14

+0

雖然我同意Int64技巧應該工作。這就是我閱讀所有文檔的方式。 – 2013-04-20 11:41:30

1

德爾福不遵循平臺標準ABI的返回值。標準ABI按值將返回值傳遞給調用者。 Delphi將返回值視爲隱式額外的var參數,並在所有其他參數之後傳遞。 documentation描述了規則。

您可以更改您的呼叫代碼以匹配該代碼。在你的C++函數中傳遞一個額外的參考給struct參數。

typedef void (__cdecl TestFunc)(TSimpleRecord&);  

如果你要做到這一點對C++的一面,你最好做的德爾福側爲清楚起見,相同的變化。

由於Delphi不遵循返回值的平臺標準,所以我建議您將自己限制爲與其他工具兼容的類型。這意味着高達32位的整數值,指針和浮點值。

作爲一般的經驗法則,不要打包記錄。如果你這樣做,你會有失調,影響性能。對於問題中的記錄,由於兩個字段的大小相同,因此不會有填充。

相關問題