How to map and marshal a C array into a C# code
I am writing C# code that call a C library and something it is not quite clear in my mind.
The C function has this signature:
double* DoSomeStuff(double* input,int numberOfElements);
I have mapped the function as:
[System.Runtime.InteropServices.DllImportAttribute("myDll.dll", EntryPoint="DoSomeStuff")]
public static extern System.IntPtr DoSomeStuff(ref double input, int numberOfElements) ;
The input value is an array, so the C function will expect a contiguous memory layout. I am more familiar with C++ than C#. In C++ I'd used a std::vector to store the data and then I would use the data() method to get the pointer and exchange the information with C code. std::vector guarantees a con开发者_StackOverflowtiguous layout memory.
Which data structure can I used in C#? Is there anything like std::vector in C#?
I have faced before the same problem for a string (In C++ std::string is just a std::vector with some make up). And I have solve the problem using:
System.IntPtr stringExample = Marshal.StringToHGlobalAnsi("StringExample");
The static function does the job for me. There is anything like this function for other types?
I have asked already too many questions, I think the most important one is: what is the best practise to solve this kind of problem?
Thanks
1)
Define the input as IntPtr:
[System.Runtime.InteropServices.DllImportAttribute("myDll.dll", EntryPoint="DoSomeStuff")]
public static extern System.IntPtr DoSomeStuff(IntPtr input, int numberOfElements) ;
2)
Create an array in a fixed block, then create an IntPtr from the Pointer and then pass it to DoSomeStuff
.
double[] input = new double[20];
IntPtr result = IntPtr.Zero;
fixed(double* d = &input[0])
{
result = DoSomeStuff(new InptPtr(d), 20);
}
...
Reason for the fixed
block is so that GC does not move the array while unmanaged code is populating it.
To make your example work you should define the siganture of the extern function as follows:
[System.Runtime.InteropServices.DllImportAttribute("myDll.dll", EntryPoint="DoSomeStuff")]
public static extern System.IntPtr DoSomeStuff([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)], int numberOfElements);
The second (named) parameter of MarshalAs attaribute tells to the marshaller where the size of the array stored.
Regarding the second question, C# has List<Type>
class that behaves similary to std:vector<Type>
. However, I don't think you can directly provide it to the marshaller. What you can do is to use ToArray()
methor of the List
class, to get an array.
精彩评论