2012-11-29 71 views
0

我繼承了一個用C語言編寫的dll,可以從C#中的windows應用程序(Framework 2.0)訪問。最近有些機器已升級到64位Windows 7,並且dll不再在這些機器上返回正確的值。我相信這是因爲C函數具有預期爲64位的參數類型。Managed Type equivalent [MarshalAs(UnmanagedType.I8)]

這裏的C函數

int doFlightCalc_S(double LatA, 
        double LonA, 
        double LatB, 
        double LonB, 
        int month, 
        int aircraftCd, 
        int nbrPsgrs, 
        int taxiInTm, 
        int taxiOutTm, 
        int fuelStopTime, 
        int *results) 

這裏的Signature的,雖然離開從C#

[DllImport("doFlightCalc.dll", CallingConvention = CallingConvention.Cdecl)] 
     private static extern int doFlightCalc_S(
      [MarshalAs(UnmanagedType.R8)] double latA, 
      [MarshalAs(UnmanagedType.R8)] double lonA, 
      [MarshalAs(UnmanagedType.R8)] double latB, 
      [MarshalAs(UnmanagedType.R8)] double lonB, 
      [MarshalAs(UnmanagedType.I4)] int month, 
      [MarshalAs(UnmanagedType.I4)] int aircraftCd, 
      [MarshalAs(UnmanagedType.I4)] int nbrPsgrs, 
      [MarshalAs(UnmanagedType.I4)] int taxiInTm, 
      [MarshalAs(UnmanagedType.I4)] int taxiOutTm, 
      [MarshalAs(UnmanagedType.I4)] int fuelStopTime, 
      [MarshalAs(UnmanagedType.LPArray)] [Out] int[] results); 

如果我編譯C DLL作爲一個64位的DLL訪問函數的定義函數是這樣的,我需要對C#中的函數做些什麼改變?

我會假設我必須將I4s更改爲I8s,但是我會用什麼類型替換int和double?將以下內容:

   [MarshalAs(UnmanagedType.R8)] double lonB, 
      [MarshalAs(UnmanagedType.I4)] int month, 

改爲:

   [MarshalAs(UnmanagedType.R8)] (what would go here?) lonB, 
      [MarshalAs(UnmanagedType.I8)] long (is long correct here?) month, 

還是我找錯了樹?

+0

不知道更多的細節,我想你可能會過早跳到無根據的結論。例如,有沒有人*重新編譯這個C .dll?作爲一個64位的二進制文件?你知道嗎?這是事實嗎? – paulsm4

+0

不,那不是。你也不會意外地創建了該DLL的64位版本。使用調試器。 –

+0

我通過將可執行文件的生成平臺從AnyCPU更改爲x86來實現它。 –

回答

2

當您編譯64位時,您不需要做任何更改。 C和C#版本在32位和64位上相互匹配。

您似乎認爲C int在Windows上的64位代碼中是8個字節寬。不是這樣。它是4個字節寬。

您可以刪除所有MarshalAs屬性,因爲它們只是重新聲明默認編組。

從32位操作系統切換到64位操作系統似乎不太可能導致差異。

+0

我通過將可執行文件的生成平臺從AnyCPU更改爲x86來實現它。 –

+1

在AnyCPU下,您的託管代碼將作爲64位進程運行。哪些將無法加載本地32位DLL。 –

+0

+1,如果僅用於「刪除所有MarshalAs,因爲它們是多餘的」...無需過度複雜! – JerKimball

1

按照MSDN頁(http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.unmanagedtype.aspx)枚舉UnmanagedType.I8對應於一個8字節符號整數,或System.Int64其在C#別名爲long。我的個人偏好是始終使用結構類型名稱Int64而不是別名,因爲它只是讓我想到便攜式C89中的糟糕編程,其中long可以表示32位或64位整數。

同樣,R8是一個8字節的浮點數。類型System.Double對應於該成員。

[MarshalAs(UnmanagedType.R8)] Double lonB, 
[MarshalAs(UnmanagedType.I8)] Int64 month, 

或這,這取決於你的編碼風格偏好

[MarshalAs(UnmanagedType.R8)] double lonB, 
[MarshalAs(UnmanagedType.I8)] long month, 

但是我不明白的是,爲什麼64位會有所作爲,除非參數需要一個指針類型(如本是32位和64位系統之間唯一不同的基本類型)。

編輯:無視我的答案:我沒有完全讀你的問題。如果C函數定義了參數int,那麼無論編譯的平臺是32位還是64位(假設兩個版本都使用相同的編譯器和操作系統),它們的大小始終相同。

0

double仍然是double。在C#中double是一個64位實數,R8是一個64位實數。 C#中的longInt64,所以這也是正確的類型。 I8是一個64位無符號整數,因爲很長。但是,沒有理由應該使用I8,因爲C代碼中的值都是32位整數(C int == I4 == C#int)。

+0

我在C代碼中看不到64位整數。 –

+0

@DavidHeffernan我同意,我只是回答了C#中'I8'的等效類型。根據發佈的示例代碼,似乎沒有任何理由使用'I8'而不是'I4'。 – evanmcdonnal