0

C#のWindowsアプリケーション(Framework 2.0)からアクセスするCで記述されたdllを継承しました。最近、一部のマシンが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);

関数をそのままにしてCdllを64ビットdllとしてコンパイルする場合、C#の関数にどのような変更を加える必要がありますか?

I4をI8に変更する必要があると思いますが、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ビットの両方で互いに一致します。

Windowsの64ビットコードでは、Cintの幅は8バイトだと思われるかもしれません。そうではない。幅は4バイトです。

すべてのMarshalAs属性は、デフォルトのマーシャリングを再記述しているだけなので、削除できます。

32ビットOSから64ビットOSへの切り替えが実際に不一致の原因である可能性は非常に低いようです。

于 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。私の個人的な好みは、エイリアスの代わりに常に構造体タイプ名を使用することです。これは、32ビットまたは64ビット整数を意味する可能Int64性のあるポータブルC89での不適切なプログラミングを思い起こさせるためです。long

同様に、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ビットの性質に関係なく、パラメーターは常に同じサイズになります(両方のビルドで同じコンパイラーとOSが使用されていると想定)。

于 2012-11-29T22:08:50.320 に答える
0

double残りますdouble。C# doubleでは64ビットの実数でR8あり、64ビットの実数です。longC#では、Int64これも正しいタイプになります。I8longと同様に、64ビットの符号なし整数です。I8ただし、 Cコードの値はすべて32ビット整数(C int == I4 == C#int)であるため、使用する必要がある理由はありません。

于 2012-11-29T22:09:51.190 に答える