EDIT: I oversimplified my example... In the real code I was assigning values to strMyStringx without correctly using wcscpy_s, so instead of assigning the values I was just passing the pointer, which was out of scope by the time the values were being marshaled into managed code...
I'm trying to marshal a struct with three string properties from C to C#, but I can't get the definition of the struct right in C#. All of the properties print as garbage. Am I marshaling wrong or do my properties have the wrong type?
My custom structure:
typedef struct _MY_STRUCT_STRING { LPWSTR strMyString1; LPWSTR strMyString2; LPWSTR strMyString3; }MY_STRUCT_STRING, *PMY_STRUCT_STRING; My C function returns an array of pointers to this struct:
bool bEnumerateString(OUT LONG &i_arr_size, OUT PMY_STRUCT_STRING* &pArrStringStruct) { // [...] function simplified to demonstrate building a pointer to an array of struct* long i_arr_size = 3 PMY_STRUCT_STRING *ptr_arr_string = (PMY_STRUCT_STRING *)malloc(sizeof(PMY_STRUCT_STRING)* i_arr_size); for (int i = 0; i < i_arr_size; i++) { ptr_arr_string[i] = (PMY_STRUCT_STRING)malloc(sizeof(MY_STRUCT_STRING)); ptr_arr_string[i]->strMyString1 = L"String 1"; // This would work. In the real code I was assigning values from another array and mistakenly passed the pointer rather than doing wcscpy_s ptr_arr_string[i]->strMyString2 = L"String 2"; ptr_arr_string[i]->strMyString3 = L"String 3"; } pArrStringStruct = ptr_arr_string; return true; } C#:
//Import the DLL with my function [DllImport("My.dll", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "bEnumerateString")] internal static extern bool bEnumerateString(out long count, out IntPtr pArrStringStruct); // Define the C# equivalent of the C struct [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] internal struct MY_STRUCT_STRING { [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 8)] public string strMyString1; [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 8)] public string strMyString1; [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 8)] public string strMyString1; } [...] // Code to marshal (try... catch etc removed for succinctness) IntPtr pArrStruct = IntPtr.Zero; long lCount = 0; bool bResult = false; bResult = bEnumerateString(out lCount, out pArrStruct); if (!bResult) { // Marshal to deref pointer IntPtr[] pArrStructList = new IntPtr[lCount]; for (ulong i = 0; i < (ulong)lCount; i++) { pArrStructList[i] = Marshal.ReadIntPtr(pArrStruct, Marshal.SizeOf(typeof(IntPtr)) * (int)i); } // Marshal pointers to struct var lstMyStringStrct = new List<MY_STRUCT_STRING>(pArrStructList.Length); foreach (IntPtr ptr in pArrStructList) { lstMyStringStrct.Add((MY_STRUCT_STRING)Marshal.PtrToStructure(ptr, typeof(MY_STRUCT_STRING))); } // Enumerate struct foreach (MY_STRUCT_STRING myStr in lstMyStringStrct) { // All of these outputs are garbage Console.WriteLine("strMyString1: " + myStr.strMyString1); Console.WriteLine("strMyString2: " + myStr.strMyString2); Console.WriteLine("strMyString3: " + myStr.strMyString3); } }