Passing objects between C# and C
My application consist of C# code with unmanaged C dll calls. In my C#开发者_如何学Go code I have an object/class where its properties are both system types such as string and int and other objects I have defined.
I would like to pass this complex (Graph.cs) object to my C (dll) code, what implementation would you suggest here?
I have tried moving structs but I fail to do so with anything other then string and int.
Thanks.
Code:
public Class Grpah {
TupleCollection m_TupleCollection;
int m_nGeneralIndex;
bool m_bPrintWRF;
string m_sLink;
}
public Class TupleCollection {
IList<Tuple> _collection;
}
public Class Tuple {
Globals.TupleType m_ToppleType;
ArrayList m_Parameters;
}
public class TupleArgs {
public string Value { get; set; }
public Globals.PAS PAS;
public RefCollection RefCollection { get; set; }
public int Time{ get; set; }
}
public class RefCollection {
public List<int> SynSet{ get; set; }
public Globals.PAS PAS;
}
Try:
How to: Marshal Structures Using PInvoke
I think the easiest way for you to make progress is to modify the native code, giving it the ability to work with CLR types.
Now, you're almost certainly using Visual Studio, and hopefully it's VS2005 or later. This means that although your existing native code is in C, you have the option to delve into a little C++. And not only that - you also have C++/CLI.
So I would make a new C++/CLI DLL, and link your C library to it, so that it can call into the C code. Then write a thin translation layer in the C++/CLI library: it will expose true CLR classes (written with ref class
) and will call onto the native C code.
e.g. in a C header:
void do_something_with_foo_data(int a, int b, int c);
In C++/CLI:
public ref class FooWrapper
{
static void DoSomethingWithFoo(Foo ^foo)
{
// pick apart the Foo class and pass the pieces on to the C function
do_something_with_foo_data(foo->A, foo->B, foo->C);
}
};
In C#:
public class Foo
{
public int A { get; set; }
public int B { get; set; }
public int C { get; set; }
}
...
var foo = new Foo { A = 1, B = 2, C = 3 };
FooWrapper.DoSomethingWithFoo(foo);
When I did this I used Marshal exclusively. This was with standard C for the native code. I did not want to convert my C code to "managed C++" or whatever they call it :-)
The hard and tedious part is that you have to manually marshal your data structure into something that maps directly to the receiving C function. In my case, I had to create separate structs for each data bearing C#-class I wanted to send. In essence, you should convert your nice C# object hierarchy into a more basic form consisting of structs which you then marshal into a memory chunk which you then use as an argument in your native call.
You should use the method Marshal.AllocHGlobal
for allocing memory and Marshal.StructureToPtr
for copying your C# struct to that memory and then Marshal.FreeHGlobal
to free it.
Once you have your IntPtr (from StructureToPtr
), you should be able to simply call your C-dll with that pointer as argument. Note that the struct you are sending to your C function must have the same layout as the native C struct, or you will get very odd results.
Returning data is pretty much the same thing, but you are using the opposite functions (PtrToStructure
etc) instead.
Thats the basic of it anyway.
Your model looks pretty complicated, and incomplete: Tuple.m_parameters is an ArrayList, so it can contain just about anything, and the Globals.PAS type is not defined here.
Perhaps you should think of a different strategy: in your DLL, make a small model that contains whatever you need in your C code, and make it as simple as possible (but not simpler!).
Then, learn whatever you need to marshal that C model from your managed code, and fill in the model from your Graph.cs class. Preferably, Graph.cs shouldn't be responsible to do this, your marshalling code should be.
精彩评论