2012-11-29 96 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