Hi all,
I’ve scoured google for this, but can’t find a good answer. We want a struct that looks like this to be passed into unity:
[StructLayout(LayoutKind.Sequential)]
public struct MyPluginInterop
{
int numOfThings;
[MarshalAs (UnmanagedType.LPStr)]
public string someData;
[MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPStr, SizeParamIndex=0)]
public string[ ] things;
}
And the C++ version is:
struct MyPluginInterop
{
int numOfThings;
char* someData;
char** things;
};
I can easily pass strings and ints, but an array of strings is a no go. I’ve spent some time in the C# marshalling docs, yet cannot discern if this is possible or not. I am using SizeParamIndex to tell C# that my array’s size is the numOfThings, and other metadata, but Unity just immediately crashes.
In the past I have been able to use structs within structs, and use Marshal.PtrToStructure() to create structs with the strings inside them. We are also thinking about using one string and a delimiter as an alternative.
Thanks in advance!
So many years later after your question, I figure out how to marshal an array of strings from C++ in C# safe code.
Post that answer to help others Unity3D colleagues.
I simplify my sample many as I could.
I am not sure which platforms working that approach yet. Tested only on Windows Editor
Unity version tested: 2019.1.14f1
Use Callbacks to send C# calls to C++ and return a result
The trick is to use IntPtr and cast pointers to strings.
C++
struct UserEffect
{
const char* StringParams[4];
};
C#
[StructLayout(LayoutKind.Sequential, Size = 32)]
public struct Params
{
// ByValArray is the right way to call String array. LPArray doesn't work
// SizeConst is the length of the array.
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public IntPtr[] StringParams;
}
C++ assign and send the data
p.Params[0] = "Parameter 1";
p.Params[1] = "Parameter 2";
p.Params[2] = "Parameter 3";
p.Params[3] = "Parameter 4";
SendParams(p);
C# get data from C++
private static void ExecuteRendering(Params p)
{
Debug.Log(Marshal.PtrToStringAnsi(p.Params[0]));
Debug.Log(Marshal.PtrToStringAnsi(p.Params[1]));
Debug.Log(Marshal.PtrToStringAnsi(p.Params[2]));
Debug.Log(Marshal.PtrToStringAnsi(p.Params[3]));
}