我正在尝试通过注入我的DLL并将QPainter::drawText
函数绕道到我自己的应用程序来将QPainter::drawText
函数挂钩到另一个应用程序中。我这样做是因为其他应用程序没有公开可用的API,我想对我得到的数据做一些基本的统计分析。
一切正常:我看到QPainter::drawText
函数被调用,但我无法将QString
参数转换为有用的参数。当我将QString
参数设置为LPWStr
时,我得到的只有两个字符。
我不是C ++超级英雄,所以我有点失落。我想我正在看一些指针或引用,因为我为每次调用得到两个字符,但我不确定。几个晚上试图理解它之后,我已经接近放弃了。
我已经使用https://demangler.com/将QPainter::drawText
函数(使用Dependency Walker:?drawText@QPainter@@QAEXABVQRect@@HABVQString@@PAV2@@Z
找到)解除了它,并且它出现了这个函数声明:
public: void __thiscall QPainter::drawText(class QRect const &,int,class QString const &,class QRect *)
我已将此转换为以下DllImport(我将QRect
和Qstring
类替换为IntPtr
,因为我不知道如何将它们转换为C#)。
[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);
这是我到目前为止所做的:
绕道Qt QPainter :: drawText
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);
}
}
创建QPainter :: drawText绕行
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 });
更新2016-1-31
到目前为止,我已经找到了这个(见https://github.com/mono/cxxi/blob/master/examples/qt/src/QString.cs)。但现在我在AccessViolationException
上获得Marshal.PtrToStringUni
。
[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 :(得分:0)
QString是复杂类型。
您可以尝试导入QString::FromUtf16
以创建QString并将IntPtr传递给您的函数
string str = "Test";
var p2 = new IntPtr(QString.Utf16(str,str.Length));
编辑:此外,您可以尝试使用https://github.com/ddobrev/QtSharp
答案 1 :(得分:0)
感谢有用的文章https://woboq.com/blog/qstringliteral.html,它解释了Qt5中的QString数据结构,我设法让钩子工作:
[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;
}
}
}