title: Marshal struct from C to C#
body: <p>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...</p>
  
  <p>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? </p>
  
  <p>My custom structure:</p>
  
  <pre><code>typedef struct _MY_STRUCT_STRING {
      LPWSTR strMyString1;
      LPWSTR strMyString2;
      LPWSTR strMyString3;
  }MY_STRUCT_STRING, *PMY_STRUCT_STRING;
  </code></pre>
  
  <p>My C function returns an array of pointers to this struct:</p>
  
  <pre><code>bool bEnumerateString(OUT LONG &amp;i_arr_size, OUT PMY_STRUCT_STRING* &amp;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 &lt; i_arr_size; i++) {
      ptr_arr_string[i] = (PMY_STRUCT_STRING)malloc(sizeof(MY_STRUCT_STRING));
      ptr_arr_string[i]-&gt;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]-&gt;strMyString2 = L"String 2";
      ptr_arr_string[i]-&gt;strMyString3 = L"String 3";
  }
  
  pArrStringStruct = ptr_arr_string;
  
  return true;
  }
  </code></pre>
  
  <p>C#:</p>
  
  <pre><code>    //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 &lt; (ulong)lCount; i++)
         {
              pArrStructList[i] = Marshal.ReadIntPtr(pArrStruct, Marshal.SizeOf(typeof(IntPtr)) * (int)i);
         }
  
  
      // Marshal pointers to struct
         var lstMyStringStrct = new List&lt;MY_STRUCT_STRING&gt;(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);
          }
  
      }
  </code></pre>