托管类型相当于[MarshalAs(UnmanagedType.I8)]

时间:2012-11-29 22:02:40

标签: c# pinvoke

我继承了一个用C语言编写的dll,我从C#中的Windows应用程序(Framework 2.0)访问。最近有些机器已升级到64位Windows 7,并且dll不再在这些机器上返回正确的值。我相信这是因为C函数具有预期为64位的参数类型。

这是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)

这是从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#中的函数进行哪些更改?

我会假设我必须将I4更改为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,

还是我在错误的树上吠叫?

3 个答案:

答案 0 :(得分:2)

编译64位时,根本不需要进行任何更改。 C和C#版本在32位和64位上相互匹配。

您似乎认为C int在Windows上的64位代码中是8字节宽。它不是。它是4个字节宽。

您可以删除所有MarshalAs属性,因为它们只是重新声明了默认的编组。

从32位操作系统切换到64位操作系统似乎不太可能是造成这种差异的原因。

答案 1 :(得分: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位性质(假设两个构建使用相同的编译器和操作系统)

答案 2 :(得分:0)

double仍为double。在C#double中是64位实数,R8是64位实数。 C#中的longInt64,因此也是正确的类型。 I8是一个64位无符号整数,因为它很长。但是,您没有理由使用I8,因为C代码中的值都是32位整数(C int == I4 == C#int)。