views:

71

answers:

3

Suppose there is a c++ method int NativeMethod(double, double *) in a Native.dll. My first attempt at calling this method from managed code was (assuming I don't need to specify the entry point)

[DllImport("Native.dll")]
private static extern int NativeMethod(double inD, IntPtr outD);

Then to use the DLL I did

IntPtr x = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)));
NativeMethod(2.0, x);

//do stuff with x

Marshal.FreeHGlobal(x);  //crash

I would like to understand why this crashes here. My first guess is that it's a heap problem due to the fact that the DLL and my application could be using a different CRT. But if that were the case why wouldn't the call to the NativeMethod crash instead? The method returned an x that I could successfully extract the double from.

I am able to get the import to work by passing the double by reference

[DllImport("Native.dll")]
private static extern int NativeMethod(double inD, IntPtr outD);

Why does the FreeHGlobal crash in the first attempt, and what is the recommended way to pass pointers to native methods? The out keyword may work fine this situation, but what if I needed to Marshal a string? I don't think I can get around AllocH and FreeH...

+2  A: 

I am not an expert, but shouldn't it be:

IntPtr x = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(double)));
Grzenio
+3  A: 

The problem is that the method takes a double* which is a pointer to a double. You are passing in a pointer which is pointing to an IntPtr. This is important only in that there is a size difference between double (8 bytes) and IntPtr which is variable sized (either 4 or 8 bytes). You need to allocate the pointer to a double

IntPtr x = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(double));
JaredPar
Ah, many thanks.. I missed the part about the platform-specific size in the msdn reference.
insipid
+3  A: 

I might be misunderstanding your goal, but it seems you are making it more complicated than is necessary. Just pass it by reference and let the marshalling underneath take care of it.

[DllImport("Native.dll")]
private static extern int NativeMethod(double inD, ref double outD);

double x;

x = 1;
NativeMethod( 2.0, ref x );
Mark Wilkins
+1 the most representative would be to use out instead of ref. The OP didn't ever initialize the pointer.
JaredPar
@JaredPar, that is true. I was unsure if the OP was desiring ref or out behavior, but I failed to recognize that obvious clue (the fact that he didn't initialize it in the example).
Mark Wilkins
Exactly what are the implications of using out/ref vs. AllocHGlobal to get to unmanged memory? Can the GC rearrange memory and change pointer references before the method/function returns?
thomask
@thomask, There is a discussion about that [here](http://stackoverflow.com/questions/1910912/net-interop-intptr-vs-ref)
Mark Wilkins
@thomask - One other point about it. I believe that using out/ref for [blittable](http://msdn.microsoft.com/en-us/library/75dwhxf7.aspx) will be more efficient. I think that the address of the simple variable will be passed directly to the unmanaged DLL for modification, so it does not involve extra allocations.
Mark Wilkins