7

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...

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
insipid
  • 3,238
  • 3
  • 26
  • 38
  • What is the error message it gives you? –  Jul 13 '10 at 14:54
  • Of course, this should be typeof(double). But I think that SizeOf(typeof(InpPtr)) is always >= SizeOf(typeof(double)), so it may work by some way. Interesting, what is "do stuff with x" part? – Alex F Jul 13 '10 at 15:00

3 Answers3

7

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
  • 40,729
  • 5
  • 57
  • 110
  • +1 the most representative would be to use out instead of ref. The OP didn't ever initialize the pointer. – JaredPar Jul 13 '10 at 16:12
  • @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 Jul 13 '10 at 17:05
  • 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? – Thomas Kjørnes Jul 15 '10 at 15:30
  • @thomask, There is a discussion about that [here](http://stackoverflow.com/questions/1910912/net-interop-intptr-vs-ref) – Mark Wilkins Jul 15 '10 at 16:06
  • @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 Jul 15 '10 at 16:24
5

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));
lsalamon
  • 7,998
  • 6
  • 50
  • 63
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
2

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

IntPtr x = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(double)));
Grzenio
  • 35,875
  • 47
  • 158
  • 240