How should I pass an array of strings to a C library using P/Invoke?
See the question and my original answer on StackOverflowYou can't use a variable size array in a struct, you have to marshal the whole thing manually, or use arguments which is much easier, especially in the (C# to C)-only way.
If you want to use a struct for some reason, then you can do it like this:
C side (I'm using Windows, you may have to adapt):
struct MyArgs {
int32_t someArg;
char** filesToProcess;
int32_t filesToProcessLength;
};
// I pass struct as reference, not value, but this is not relevant
// I also use __stdcall which is quite standard on Windows
extern "C" {
__declspec(dllexport) bool __stdcall myFunction(struct MyArgs* pargs) {
printf("Files to Process: %i\n", pargs->filesToProcessLength);
for (int i = 0; i < pargs->filesToProcessLength; i++) {
char* str = pargs->filesToProcess[i];
printf("\t%i. %s\n", i, str);
}
return true;
}
}
C# side:
static void Main(string[] args)
{
var files = new List<string>();
files.Add("hello");
files.Add("world!");
var elementSize = IntPtr.Size;
var my = new MyArgs();
my.filesToProcessLength = files.Count;
// allocate the array
my.filesToProcess = Marshal.AllocCoTaskMem(files.Count * elementSize);
try
{
for (var i = 0; i < files.Count; i++)
{
// allocate each file
// I use Ansi as you do although Unicode would be better (at least on Windows)
var filePtr = Marshal.StringToCoTaskMemAnsi(files[i]);
// write the file pointer to the array
Marshal.WriteIntPtr(my.filesToProcess + elementSize * i, filePtr);
}
myFunction(ref my);
}
finally
{
// free each file pointer
for (var i = 0; i < files.Count; i++)
{
var filePtr = Marshal.ReadIntPtr(my.filesToProcess + elementSize * i);
Marshal.FreeCoTaskMem(filePtr);
}
// free the array
Marshal.FreeCoTaskMem(my.filesToProcess);
}
}
[StructLayout(LayoutKind.Sequential)]
struct MyArgs
{
public int someArg;
public IntPtr filesToProcess;
public int filesToProcessLength;
};
// stdcall is the default calling convention
[DllImport("MyProject.dll")]
static extern bool myFunction(ref MyArgs args);