Reputation: 2252
I have inherited a dll written in C that I access from a windows application (Framework 2.0) in C#. Recently some machines have been upgraded to 64-bit Windows 7, and the dll is no longer returning the correct values on those machines. I believe this is because the C function has parameter types that are expected to be 64-bit.
Here's the signature of the C function
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)
Here's the definition that accesses the function from 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);
If I were to compile the C dll as a 64-bit dll while leaving the function as is, what changes would I need to make to the function in C#?
I would assume that I have to change the I4s to I8s but what type would I replace the int and double with? Would the following :
[MarshalAs(UnmanagedType.R8)] double lonB,
[MarshalAs(UnmanagedType.I4)] int month,
be changed to:
[MarshalAs(UnmanagedType.R8)] (what would go here?) lonB,
[MarshalAs(UnmanagedType.I8)] long (is long correct here?) month,
Or am I barking up the wrong tree?
Upvotes: 0
Views: 6815
Reputation: 48114
double
would remain a double
. In C# double
is a 64-bit real number, R8
is a 64-bit real number. long
in C# is an Int64
so that would also be the correct type. I8
is a 64-bit unsigned integer, as is long. However, there's no reason you should be using I8
because the the values in the C code are all 32-bit integers (C int == I4 == C# int).
Upvotes: 0
Reputation: 613302
You don't need to make any changes at all when you compile for 64 bit. The C and C# versions match each other on both 32 and 64 bit.
You seem to think that C int is 8 bytes wide in 64 bit code on Windows. It is not. It is 4 bytes wide.
You can remove all the MarshalAs attributes since they merely re-state the default marshalling.
It seems highly unlikely that the switch from 32 bit OS to 64 bit OS is really the cause of the discrepancy.
Upvotes: 2
Reputation: 155443
According to the MSDN page ( http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.unmanagedtype.aspx ) the enum UnmanagedType.I8
corresponds to an 8-byte signed integer, or System.Int64
which is aliased as long
in C#. My personal preference is to always use the struct type name Int64
instead of the alias because it just makes me think of bad programming in portable C89 where long
can mean either a 32-bit or 64-bit integer.
Similarly, R8
is an 8-byte floating number. The type System.Double
corresponds to this member.
[MarshalAs(UnmanagedType.R8)] Double lonB,
[MarshalAs(UnmanagedType.I8)] Int64 month,
or this, depending on your coding style preferences
[MarshalAs(UnmanagedType.R8)] double lonB,
[MarshalAs(UnmanagedType.I8)] long month,
However what I don't understand is why 64-bit would make a difference, unless the parameter expects a pointer type (as this is the only primitive type that should be different between 32-bit and 64-bit systems).
EDIT: Disregard my answer: I didn't read your question fully. If the C function defines int
parameters then they will always be the same size regardless of the 32-bit or 64-bit nature of the platform it was compiled for (assuming the same compiler and OS was used for both builds).
Upvotes: 1