Unmanaged to managed code return pointers

I have an unmanaged dll that exports the following function:

SomeData* test(); 

Assume SomeData as:

 typedef struct _Data Data; struct _Data{ int a; int b; } 

Now I want to call this function from C # code. I am starting to define the C # Struture needed for custom marshaling as follows:

 [StructLayout(LayoutKind.Sequential)] public class SomeData { public Int32 a; public Int32 b; } 

And now I declare a managed function:

 [DllImport("DynamicLibrary.dll", CharSet=CharSet.Auto)] [return: MarshalAs(UnmanagedType.LPStruct)] public static extern SomeData test(); 

And in the main function, I have:

 IntPtr ptr = test(); 

By doing this, I get a MarchalDirectiveException exception: "Cannot marshal return value": Incorrect combination of managed / unmanaged types (Int / UInt must be mated to SysInt or SysUInt).

I did not allocate memory for SomeData in C #, since I expect this memory to be allocated in the C function, and I will use Marshal.Copy to transfer it to managed memory.

Any ideas? thanks

------------------------ IMAGE AFTER JaredPar ANSWER ------------------- -

Actually, I made a mistake while copying the code to my question. The real managed signature I used was:

[DllImport ("DynamicLibrary.dll", CharSet = CharSet.Auto)]
[return: MarshalAs (UnmanagedType.LPStruct)]
open static extern IntPtr test ();

JaredPar's answer still matters. To get the correct behavior, I have 2 options:

1) Use 'public static extern IntPtr test (),'; (without the MarshalAs attribute) and then access the returned pointer, such as suggested by JaredPar.

2) Use "public static extern SomeData test ()"; (with the MarshalAs attribute) and then just use SomeData sd = test ();

+7
c # marshalling pinvoke
source share
1 answer

When declaring a managed function, you need to map pointer types to reference values ​​or IntPtr values. In this case, the LPStruct modifier will not help. The simplest solution is to convert the return value of the test as IntPtr , not SomeData , since the native method returns the value of the pointer. Then you can write the following shell

 [DllImport("DynamicLibrary.dll", CharSet=CharSet.Auto)] public static extern IntPtr test(); public static SomeData testWrapper() { var ptr = test(); try { return (SomeData)Marshal.PtrToStructure(ptr, typeof(SomeData)); } finally { // Free the pointer here if it allocated memory } } 
+10
source share

All Articles