0

我继承了一个用 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# 中的函数进行哪些更改?

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

还是我在叫错树?

4

3 回答 3

2

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

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

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

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

于 2012-11-29T22:18:34.077 回答
1

根据 MSDN 页面(http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.unmanagedtype.aspx),枚举UnmanagedType.I8对应于一个 8 字节有符号整数,或者在 C#System.Int64中具有别名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 位性质(假设两个版本都使用相同的编译器和操作系统),它们都将始终具有相同的大小。

于 2012-11-29T22:08:50.320 回答
0

double将保持为double. 在C# double中是64位实数,R8是64位实数。long在 C# 中是一个Int64所以这也是正确的类型。I8是一个 64 位无符号整数,和 long 一样。但是,没有理由使用I8,因为 C 代码中的值都是 32 位整数(C int == I4 == C# int)。

于 2012-11-29T22:09:51.190 回答