views:

1752

answers:

3

How do I declare in C# a C function that returns a pointer to a structure?

I believe following is one way to do that, followed by Marshal.PtrToStructure to get actual structure value.

// C-function
SimpleStruct * Function(void);

// C# import
[DllImport("MyDll.dll")]
public static extern IntPtr Function();
  1. Am I correct about that?
  2. Are there other ways to accomplish the same? (It would be OK to get struct back by value)
+1  A: 

I am not an expert here at all, but I happened to be looking at a piece of code (that i don't understand completely mind you) that is doing this same thing.

Here is what they are doing

[DllImport("")]
private static extern short MethodName([In,Out] ref StructureName variable);

and then on the structure they have the following attribute

[StructLayout(LayoutKind.Sequential, Size = #)]
public struct StructureName {}

I think the part you are looking for is the [In,Out] part, and since it's being passed via ref, you should be getting the same data back.

marked as community wiki so people can fix this if wrong.

Darren Kopp
That is an import for following signature: short MethodName(StructureName * struct);I am pretty shure I'll get "ESP is screwed up" exception here.
+3  A: 

Since the function returns a pointer (hopefully not a locally allocated one?) your best bet is to manually marshal it (via Marshal.PtrToStructure).

If it were a parameter you could create a managed version of the structure using the PInvoke Interop Assistant then pass it via ref or out.

Arnshea
Manually marshalling pointers is almost never needed. Usually you can work with structs directly.
Jonathan Allen
I believe you are mistaken. There are a number of large classes of interop problems that require manual marshaling of pointers. Variable sized structures and structures containing arrays of structures are just two of the more common ones.
Stephen Martin
I put up an example of marshaling a struct containing an array of structs at http://arnshea.blogspot.com/2009/04/interop-with-struct-that-contains-array.html . It's pretty rare that you have to manually marshal data for interop...
Arnshea
what if I have a function that returns a pointer to a struct allocated locally?
Meidan Alon
@Meidan: Then your function has a bug. You shouldn't give out invalid pointers, and a pointer to a local variable is invalid as soon as the function exits.
Ben Voigt
+2  A: 

Caveat: this will only work if the pointer returned is to memory already managed by the CLR

I believe what you are looking for is

// C# import
[DllImport("MyDll.dll")]
[return : MarshalAs(UnmanagedType.LPStruct)]
public static extern StructureName Function();

[StructLayout(LayoutKind.Sequential)]
public class StructureName {}

This should eliminate the need for any manual Marshal.PtrToStructure calls. Depending on what your structure contains, you may need to tag some fields with MarshalAs attributes as appropriate. MSDN has a good example of this.

Eric Burnett
+1, Hmm, I'm not 100% sure about the class version though. class in invoke is typically treated as a pointer type while struct is a value. I'm not sure if combining a class type with LPStruct will work in all scenarios.
JaredPar
**MarshalAs(LPStruct)** most accurately describes what I want. Though LPStruct on return is P/Invoke incompatible: "Cannot marshal 'return value': Invalid managed/unmanaged type combination ..."
I did a bit of testing, and its a struct marshaled as `LPStruct` that doesn't work - I'll edit the post appropriately. Additionally, there is one more (fairly major) caveat: The memory pointed to (the SimpleStruct* in C code) needs to have been allocated by the CLR, since it adds a reference to it and will try to garbage collect it. I'll add this to the post as well. So it looks like you will have to go with the IntPtr approach.
Eric Burnett