Rick Hodder
Rick Hodder

Reputation: 2252

Managed Type equivalent of [MarshalAs(UnmanagedType.I8)]

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

Answers (3)

evanmcdonnal
evanmcdonnal

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

David Heffernan
David Heffernan

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

Dai
Dai

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

Related Questions