I know this can be done by mallocing in C, passing malloced pointer to delegate with parameter type IntPtr, marshalling to string[] and then freeing malloced memory with separate, exported C-function from managed code.
My question is: Can this be done simpler way? E.g. :
- C# delegate parameter is of type string[]?
- no separate free function to call from managed code
EDIT: I tried with delegate signature:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
MyManagedDelegate(string[] values, int valueCount)
and fucntion in C:
void NativeCallDelegate(char *pStringValues[], int nValues)
{
if (gSetStringValuesCB)
gSetStringValuesCB(pStringValues, nValues);
}
calling it in C:
char *Values[]= {"One", "Two", "Three"};
NativeCallDelegate(Values, 3);
This results in that i can use only 1st string in array.
I came up with far from optimal solution:
This is not working if called like this:
I could have fixed size 10 array where the values are copied and that is always passed to delegate. This is not what I want. I wonder if there is good solution to this...
Here's how to do it properly, I'll give a full example so it's reproductible.
The C side
Nothing fancy here, I just added the necessary glue code and left the rest alone.
The C# side
The trick lies in the marshaling part:
The
MarshalAs
attribute tells the .NET marshaler the following:UnmanagedType.LPArray
You're getting an array...ArraySubType = UnmanagedType.LPStr
...of standard C strings...SizeParamIndex = 1
...and the size of that array is specified by the second parameter.The C strings are copied and converted to
System.String
instances by the .NET marshaler before the invocation of your C# method. So if you need to pass dynamically generated strings to C#, youmalloc
them, then you callgSetStringValuesCB
, and you canfree
them immediately afterwards, all from the C code, as .NET has its own copy of the data.You can refer to the docs: