views:

75

answers:

2

I want to use PInvoke to bring to managed side something this:

(C code)

typedef struct{
//some fields...
} A;

type struct{
A* a;
} B;

int getB(B* destination){ //destionation will be an output parameter to C#
//puts an B in 'destination'
return 0;
}

Now, i need a way to tell managed side how to marshalling B from C to C# structure or class. I've tryed many things such as IntPtr fields, MarchalAs atributes, but with no success. I will not expose here the code that i've tryed to keep the question simple. However i could do it as long answers arrive.

Thanks

A: 

If it were me, I would just use unsafe code and use pointers on the C# side:

public unsafe class UnmanagedStuff {

    public struct A {
        // some fields
    }

    public struct B {
        public A* a;
    }

    // Add appropriate PInvoke attribute here
    public static extern int getB(B* destination);

    public static void UseBForSomething() {

        B b;
        getB(&b);

        // Do something with b

    }

}
nonoitall
That's right. This is (almost) the code i need to C# side. Almost because the UseBForSomething body could not be soo simple since we are working with both managed and unmaneged memory. But you have to provide the A and B struct with the apropriate atributes to "teach" the CLR marshalling the structures. And my question is what atributes do i need..
Zé Carlos
We'd need to know the contents of the structs to know any specifics. Assuming they just contain basic value types and you represent them equivalently in C#, the default handling should be fine.
nonoitall
A* (content of struct B) is not a value type. And that's the problem.. If i have A insted of A* the solution would be very easy.
Zé Carlos
Pointers can be passed to unmanaged functions without any special handling, just like ints or floats.
nonoitall
A: 

You can do that using the Marshal class.

// Define a C# struct to match the unmanaged one
struct B
{
    IntPtr a;
}

[DllImport("dllName")]
extern int getB(IntPtr destination);

B GetB()
{
    IntPtr ptrToB = IntPtr.Zero;
    getB(ptrToB);
    return (B)Marshal.PtrToStructure(ptrToB, typeof(B));
}
Zach Johnson
You are not allocating the managed memory to B. It must be IntPtr ptrToB = Marchal.AllocHGlobal(Marchal.sizeof(B)); Even so, doing this only brings to me the value of pointer A. I don't want the value, i need the pointed data.
Zé Carlos
@Zé Carlos: You can then call `Marshal.PtrToStructure(b.a, typeof(A));` to get the pointed data (assuming you have defined the corresponding 'A' structure);
Zach Johnson