title: How to convert c++ QString parameter to c# string
body: <p>I'm trying to hook the <code>QPainter::drawText</code> function in another application by injecting my DLL and detour the <code>QPainter::drawText</code> function to my own application. I'm doing this because the other application does not expose a usable API and I want to do some basic statistical analysis on the data I'm getting.</p>
  
  <p>All is working fine: I see the <code>QPainter::drawText</code> functions being called, but I'm unable to convert the <code>QString</code> parameter to anything useful. All I get is two characters when I Marshall the <code>QString</code> parameter as <code>LPWStr</code>.</p>
  
  <p>I'm no C++ superhero, so I'm a bit lost. I think I'm looking at some pointer or reference because of the two characters I get for each call, but I'm not sure. After a few nights trying to make sense of it I'm close to the point of giving up.</p>
  
  <p>I've demangled the <code>QPainter::drawText</code> function (found using Dependency Walker: <code>?drawText@QPainter@@QAEXABVQRect@@HABVQString@@PAV2@@Z</code>) with <a href="https://demangler.com/" rel="nofollow">https://demangler.com/</a> and it comes up with this function declaration:</p>
  
  <pre class="lang-c prettyprint-override"><code>public: void __thiscall QPainter::drawText(class QRect const &amp;,int,class QString const &amp;,class QRect *)
  </code></pre>
  
  <p>I've converted this into the following DllImport (I substituted the <code>QRect</code> and <code>Qstring</code> classes to <code>IntPtr</code>, because I have no idea how to convert them to C#).</p>
  
  <pre class="lang-cs prettyprint-override"><code>    [DllImport("Qt5Gui.dll", SetLastError = true,  CharSet = CharSet.Unicode, CallingConvention = CallingConvention.ThisCall, EntryPoint = "?drawText@QPainter@@QAEXABVQRect@@HABVQString@@PAV2@@Z")]
      public static extern void QPainter_drawText(IntPtr obj, IntPtr p1, int p2, IntPtr p3, IntPtr p4);
  </code></pre>
  
  <p>This is what I have so far:</p>
  
  <p><strong>Detouring Qt QPainter::drawText</strong></p>
  
  <pre class="lang-cs prettyprint-override"><code>    LocalHook QPainter_drawTextHook;
  
      [DllImport("Qt5Gui.dll", SetLastError = true,  CharSet = CharSet.Unicode, CallingConvention = CallingConvention.ThisCall, EntryPoint = "?drawText@QPainter@@QAEXABVQRect@@HABVQString@@PAV2@@Z")]
      public static extern void QPainter_drawText(IntPtr obj, IntPtr p1, int p2, IntPtr p3, IntPtr p4);
  
      [UnmanagedFunctionPointer(CallingConvention.ThisCall, CharSet = CharSet.Unicode, SetLastError = true)]
      delegate void TQPainter_drawText(IntPtr obj, IntPtr p1, int p2, IntPtr p3, IntPtr p4);
  
      static void QPainter_drawText_Hooked(IntPtr obj, IntPtr p1, int p2, IntPtr p3, IntPtr p4)
      {
          var qs3 = (QString)Marshal.PtrToStructure(p3, typeof(QString));
  
          try
          {
              ((Main)HookRuntimeInfo.Callback).Interface.GotQPainter_drawText(qs3.ToString());
              QPainter_drawText(obj, p1, p2, p3, p4);
          }
          catch (Exception ex)
          {
              ((Main)HookRuntimeInfo.Callback).Interface.ErrorHandler(ex);
          }
      }
  </code></pre>
  
  <p><strong>Create QPainter::drawText detour</strong></p>
  
  <pre class="lang-cs prettyprint-override"><code>            QPainter_drawTextHook = LocalHook.Create(
                                          LocalHook.GetProcAddress("Qt5Gui.dll", "?drawText@QPainter@@QAEXABVQRect@@HABVQString@@PAV2@@Z"),
                                          new TQPainter_drawText(QPainter_drawText_Hooked), 
                                          this);
  
              QPainter_drawTextHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });
  </code></pre>
  
  <p><strong>Update 2016-1-31</strong>
  Thus far I have found this (see <a href="https://github.com/mono/cxxi/blob/master/examples/qt/src/QString.cs" rel="nofollow">https://github.com/mono/cxxi/blob/master/examples/qt/src/QString.cs</a>). But now I'm getting an <code>AccessViolationException</code> on the <code>Marshal.PtrToStringUni</code>.</p>
  
  <pre class="lang-cs prettyprint-override"><code>    [StructLayout(LayoutKind.Sequential)]
      public unsafe struct QString
      {
          [StructLayout(LayoutKind.Sequential)]
          public struct Data
          {
              public int @ref;
              public int alloc, size;
              public IntPtr data;
              public ushort clean;
              public ushort simpletext;
              public ushort righttoleft;
              public ushort asciiCache;
              public ushort capacity;
              public ushort reserved;
              public IntPtr array;
          }
  
          public Data* d;
          #endregion
  
          public override string ToString()
          {
              try
              {
                  return Marshal.PtrToStringUni(d-&gt;array, d-&gt;alloc * 2);
              }
              catch (Exception ex)
              {
                  return ex.Message;
              }
          }
      }
  </code></pre>