Reputation: 114
I've followed suggestions in threads like this one
on how to pass arrays of values from c++ to c#. after @CodyGray's comment on my recent question here why I'm using pointers at all i tried to pass values without pointers and marshal code, also following this
and it works too! I'm confused, what's the correct/best way to do it? why use pointers here at all?
here's some code:
consider this exported c++ function
extern "C" { __declspec(dllexport) void PointerTest(char ** text, float* fArray, int * iArray); }
here's what I did until now in c#:
[System.Runtime.InteropServices.DllImport("myTest.dll")]
private static extern void PointerTest(IntPtr text, IntPtr fArray, IntPtr iArray);
public static IntPtr NativeUtf8FromString(string managedString) {
int len = Encoding.UTF8.GetByteCount(managedString);
byte[] buffer = new byte[len + 1];
Encoding.UTF8.GetBytes(managedString, 0, managedString.Length, buffer, 0);
IntPtr nativeUtf8 = Marshal.AllocHGlobal(buffer.Length);
Marshal.Copy(buffer, 0, nativeUtf8, buffer.Length);
return nativeUtf8;
}
public void DoSomething(String text, float[] F, int[] I, int numFloats, int numInts){
IntPtr sPtr = NativeUtf8FromString(text);
IntPtr fPtr = Marshal.AllocHGlobal(numFloats*sizeof(float));
IntPtr iPtr = Marshal.AllocHGlobal(numInts*sizeof(int));
try
{
Marshal.Copy(F, 0, fPtr, numFloats);
Marshal.Copy(I, 0, iPtr, numInts);
PointerTest(sPtr, fPtr, iPtr);
}
finally
{
Marshal.FreeHGlobal(sPtr);
Marshal.FreeHGlobal(fPtr);
Marshal.FreeHGlobal(iPtr);
}
}
this works fine when passing values from c# to c++; however, the only way of passing values back (reliably) using pointers i found was the return value of my function, causing me to stuff all kinds of values in one big array and return that (again by reference).
now consider this code:
[System.Runtime.InteropServices.DllImport("myTest.dll")]
private static extern void PointerTest([In, Out] String text, [In, Out] float[] fArray, [In, Out] int[] iArray);
public void DoSomething(String text, float[] F, int[] I){
PointerTest(text, F, I);
}
This does the same thing as far as I can tell. Plus by using the [In, Out] semantic I can easily access the modified arrays after I've called PointerTest.
Now what am I missing here? Obviously the second approach is much cleaner, easier to understand for beginners like me and still the standard answer online is use pointers/the first approach....which leads me to the conclusion there must be something wrong in the second approach, but then i got it from msdn....
please help me understand this. thanks in advance.
Upvotes: 3
Views: 2046
Reputation: 316
I know almost nothing about C++/C# interop, but according to this documentation on improving interop performance (see the bit about Marshaling), the choice of [In, Out] vs pointers should be based on your marshaling needs. "By declaring parameters and fields as IntPtr," the documentation says, "you can boost performance, albeit at the expense of ease of use, type safety, and maintainability." It also says to "use the [in] and [out] attributes carefully to reduce unnecessary marshaling."
My super-brief-skim-read of the documentation suggests to me that [In, Out] and pointers will both work. It seems the first thing to consider is performance. For the data you're working with, are the two approaches above both sufficiently performant? If so, tis probably best to go with the choice that is cleaner and easier to understand as you suggested. But don't take my word for it, check it out! (The documentation, that is.)
Upvotes: 1