如何将 C++ QString 参数转换为 C# 字符串
How to convert c++ QString parameter to c# string
我试图通过注入我的 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)。但是现在我在 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;
}
}
}
QString 是复杂类型。
您可以尝试导入 QString::FromUtf16
以创建 QString 并将 IntPtr 传递给您的函数
string str = "Test";
var p2 = new IntPtr(QString.Utf16(str,str.Length));
编辑:此外,您可以为此尝试 https://github.com/ddobrev/QtSharp
感谢有用的文章 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;
}
}
}
我试图通过注入我的 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)。但是现在我在 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;
}
}
}
QString 是复杂类型。
您可以尝试导入 QString::FromUtf16
以创建 QString 并将 IntPtr 传递给您的函数
string str = "Test";
var p2 = new IntPtr(QString.Utf16(str,str.Length));
编辑:此外,您可以为此尝试 https://github.com/ddobrev/QtSharp
感谢有用的文章 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;
}
}
}