2016-01-31 194 views
1

我試圖通過注入我的DLL並將QPainter::drawText函數繞到我自己的應用程序中來掛鉤另一個應用程序中的QPainter::drawText函數。我這樣做是因爲其他應用程序沒有公開可用的API,我想對我得到的數據做一些基本的統計分析。如何將C++ QString參數轉換爲C#字符串

所有工作正常:我看到QPainter::drawText函數被調用,但我無法將QString參數轉換爲任何有用的參數。當我將Marshall的QString參數設爲LPWStr時,我得到的只有兩個字符。

我不是C++的超級英雄,所以我有點失落。我想我正在看一些指針或參考,因爲每次打電話都會收到兩個字符,但我不確定。經過幾個晚上試圖理解它,我接近放棄的地步。

我demangled的QPainter::drawText功能(發現使用依賴沃克:[email protected]@@[email protected]@[email protected]@[email protected]@Z)與https://demangler.com/並將其與該函數聲明出現:

public: void __thiscall QPainter::drawText(class QRect const &,int,class QString const &,class QRect *) 

我已經轉換成以下的DllImport這個(I取代的QRectQstring類到IntPtr,因爲我不知道如何將它們轉換爲C#)。

[DllImport("Qt5Gui.dll", SetLastError = true, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.ThisCall, EntryPoint = "[email protected]@@[email protected]@HABVQSt[email protected]@[email protected]@Z")] 
    public static extern void QPainter_drawText(IntPtr obj, IntPtr p1, int p2, IntPtr p3, IntPtr p4); 

這是我到目前爲止有:

迂迴的Qt的QPainter ::的drawText

LocalHook QPainter_drawTextHook; 

    [DllImport("Qt5Gui.dll", SetLastError = true, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.ThisCall, EntryPoint = "[email protected]@@[email protected]@[email protected]@[email protected]@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); 
     } 
    } 

創建的QPainter ::繞道的drawText

  QPainter_drawTextHook = LocalHook.Create(
             LocalHook.GetProcAddress("Qt5Gui.dll", "[email protected]@@[email protected]@[email protected]@[email protected]@Z"), 
             new TQPainter_drawText(QPainter_drawText_Hooked), 
             this); 

      QPainter_drawTextHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 }); 

更新2016-1-31 到目前爲止我找到了這個(見https://github.com/mono/cxxi/blob/master/examples/qt/src/QString.cs)。但現在我在Marshal.PtrToStringUni上獲得AccessViolationException

[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->array, d->alloc * 2); 
      } 
      catch (Exception ex) 
      { 
       return ex.Message; 
      } 
     } 
    } 
+0

另外,我知道我在尋找的方向是正確的,因爲在鉤省略了原來'drawText'函數調用導致無在目標應用程序中渲染文本。它可能是我之前發佈的結構的一些重新配置,以獲取字符串存儲的內存地址。 QPoint.d.alloc包含字符串在屏幕上顯示的字符數。 –

回答

0

歸功於很有幫助文章https://woboq.com/blog/qstringliteral.html,這也解釋了QString的數據結構在QT5我已經成功地得到了鉤工作:

[StructLayout(LayoutKind.Sequential)] 
    public unsafe struct QString 
    { 
     [StructLayout(LayoutKind.Sequential)] 
     public struct QStringData 
     { 
      public int @ref; 
      public int size; 
      public uint alloc; 
      public uint capacityReserved; 
      public fixed byte data[128]; 
     } 

     public QStringData* data; 

     public override string ToString() 
     { 
      try 
      { 
       var bytes = new byte[data->size * 2]; 
       Marshal.Copy((IntPtr)data->data, bytes, 0, data->size * 2); 
       return Encoding.Unicode.GetString(bytes); 
      } 
      catch (Exception ex) 
      { 
       return ex.Message; 
      } 
     } 
    } 
0

QString是複雜類型。 你可以嘗試導入QString::FromUtf16用於創建的QString和傳遞的IntPtr給你的函數

string str = "Test"; 
var p2 = new IntPtr(QString.Utf16(str,str.Length)); 

編輯:另外,你可以嘗試https://github.com/ddobrev/QtSharp這個

+0

我正在尋找做另一種方式:我不調用QPainter :: drawText函數,我鉤它並獲取IntPtr。我想將IntPtr轉換爲QString c#結構來獲取字符串。 –

相關問題