2011-11-23 105 views
2

另一個德爾福互操作問題中返回結構......C#調用DLL德爾福該結構

我有這樣的Delphi代碼:

library DelphiDll; 

uses 
    Dialogs, 
    SysUtils, 
    Classes; 

    type 
    TestEnum = (teOne, teTwo); 

    TTestRecord = record 
    end; 

    TTestType = record 
     MyTestRecords: array [1..255] of TTestRecord; 
     MyTestEnum: TestEnum; 
    end; 

    {$R *.res} 

    function DllFunction(var testType: TTestType): Boolean stdcall; export; 

    begin 
    testType.MyTestEnum := teTwo; 

    Result := True; 
    end; 

    exports DllFunction; 

    begin 
    end. 

而這個C#代碼:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Runtime.InteropServices; 

namespace DelpiDllTester 
{ 
    public enum TestEnum 
    { 
     One, 
     Two 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    public struct TestType 
    { 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 255)] 
     public TestRecord[] MyTestRecords; 
     public TestEnum MyTestEnum; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    public struct TestRecord 
    { 
    } 

    class Program 
    { 
     [DllImport("DelphiDll.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)] 
     public static extern bool DllFunction(ref TestType testType); 

     static void Main(string[] args) 
     { 
      TestType testType = new TestType(); 
      bool dllFunctionResult = DllFunction(ref testType); 

      Console.WriteLine(dllFunctionResult); 
      Console.WriteLine(testType.MyTestEnum); 

      Console.ReadLine(); 
     } 
    } 
} 

當我運行C#代碼時,testType.MyTestEnum的控制檯輸出始終是枚舉值One,即使它在Delphi代碼中明確設置爲Two。

現在,如果我只是簡單地將TestType結構中的TestRecord結構數組改爲使用簡單的整數數組,那麼一切都很好。

爲什麼整數數組工作,但結構數組沒有?

回答

3

主要問題是TTestRecord中沒有定義內容。 C#代碼編組爲1的字段.Delphi編譯器認爲它的大小爲0.因此兩個結構之間存在不匹配。 C#代碼爲Marshal.SizeOf(typeof(TestType))返回260,而Delphi編譯器爲SizeOf(TTestType)返回8。

在真實的代碼中,大概會在該記錄中包含一些實際內容,當您這樣做時,一切都將開始起作用。

請注意@JMarsch和@Ken White也提供了有效點。您需要確保枚舉正確編組並且佈局匹配。由於結構體被填充的方式,你可能在沒有對枚舉編組做任何事情的情況下離開,但是你也可能不幸運!

+0

Doh!你曾經有過這樣的一段時間,你只是陷入了一種思考,似乎無法擺脫。我提供的代碼是真實代碼的一個修剪過的示例,但我沒有注意到這樣一個事實,即我的裁剪代碼和空記錄會導致這樣的問題。再次感謝所有的評論。下次我會更加關注。 – meyousikmann

2

自從我使用Delphi(如'98)以來,這已經是整個其他生命週期了,但是,據我所知,Delphi中的枚舉是1個字節的數字。在c#中的枚舉是整數(32位)。

所以,你可以嘗試定義你的C#枚舉作爲

enum TestEnum: byte {One, Two} 

這並不能說明問題是它如何與一個int數組工作。關於唯一可以想到的其他事情是確保c#enum的值與Delphi Enum的值完全匹配(所以使用teOne,teTwo),但由於我們實際上是在討論整數/字節,我不明白這怎麼重要。

+0

我也在想,都必須有如何枚舉類型在C#中處理,而不是德爾福的問題。它實際上最終成爲一個我忽略的更簡單的問題。空記錄一直是罪魁禍首。不過,感謝您的幫助。 – meyousikmann

2

您需要在Delphi代碼中設置枚舉大小。德爾福將盡可能小,但.NET方面預計int。以下添加到您的代碼枚舉聲明之前:

{$MINENUMSIZE 4} // can also use {$Z4} but it's not clear later when 
        // you're trying to maintain the code. 
        // Or you can use {$Z-} and {$Z+}, for 
        // {$Z1} and {$Z4} respectively 

// Your enum declaration 

{$MINENUMSIZE 1} 
+0

看到我的答案。雖然這個問題是相關的,但房間裏有一個更大的大象。 –

+0

我正在假設海報知道沒有內容的記錄不會起作用,並且這是用於解釋目的的嘲弄代碼。事實上,如果不是,海報試圖在實際代碼中使用無內容記錄,那將是一個更大的大象。 (其實,重新閱讀帖子下方的文字,我想你已經明白了 - 我認爲它可能是**真實的代碼,正如「改變...使用簡單的整數數組」所表明的那樣。趕上,並+1您的答案。) –

+0

我其實已經知道這一點,但我有這樣的隧道視覺關於枚舉,我看不到什麼是坐在我的臉前。然而,我和你一樣思考,由於空記錄問題,這並沒有解決我的問題。我無法擺脫我的思路。不過,感謝您的幫助。 – meyousikmann