我在C#中使用EasyHook挂钩了QtGui4.dll的非托管函数QPainter::drawTextItem(const QPointF &p, const QTextItem &ti);
。我已将QPointF
和QTextItem
类包装到托管结构中,并可通过编组来获取这些参数中的数据。但是,我想使用托管代码调用非托管QPainter
类的成员函数,因此我尝试将QPainter
类包装到托管类中。我可以访问非托管代码以进行测试,但在生产中无法访问它。我查看了非托管类QPainter
和QPaintDevice
的内存布局。 QPainter
类只是一个指针而QPaintDevice
类只是两个指针(一个用于虚函数表)。我尝试按照 this blog 中的技术进行操作,但是当我调用包装的QPainter::device()
方法只是为了查看是否可以获取指针时,我的目标(非托管,挂钩)应用程序崩溃了具有访问冲突错误(Access violation reading location 0x00000078
)或参数异常错误(EEArgumentException at memory location 0x003786f4
),具体取决于我的包装QPainter
类是否使用顺序布局。我不希望有人纠正所有的源代码,但我希望有人能指出我在我的方法中犯的一些错误。顺便说一句,这是我第一次在Stack Overflow上发布一个问题,因为我通常会从一个或多个现有问题中找到问题的答案。我为这个长期问题道歉,但我试图尽可能地简化问题而不遗漏潜在的相关信息。在此先感谢您的帮助。
记忆转储:
class QPainter (size = 4):
(0) d_ptr
class QPaintDevice (size = 8):
(0) {vfptr}
(4) painters
非托管代码(qpainter.h):
class QPainter
{
QPainter();
explicit QPainter(QPaintDevice *);
~QPainter();
QPaintDevice *device() const; // trying to call this function
void drawTextItem(const QPointF &p, const QTextItem &ti); // hooked function
// class has additional functions, but left out for brevity
}
托管挂钩(hook.cs):
[DllImport("QtGui4.dll", CharSet = CharSet.Unicode, SetLastError = true,
CallingConvention = CallingConvention.ThisCall,
EntryPoint = "?drawTextItem@QPainter@@QAEXABVQPointF@@ABVQTextItem@@@Z")]
public static extern void QPainter_drawTextItem(IntPtr obj, IntPtr pt, IntPtr ti);
[UnmanagedFunctionPointer(CallingConvention.ThisCall, CharSet = CharSet.Unicode,
SetLastError = true)]
delegate void D_QPainter_drawTextItem(IntPtr obj, IntPtr pt, IntPtr ti);
static unsafe void QPainter_drawTextItem_Hooked(IntPtr obj, IntPtr pt, IntPtr ti)
{
QTextItem qti = (QTextItem)Marshal.PtrToStructure(ti, typeof(QTextItem));
QPointF qpt = (QPointF)Marshal.PtrToStructure(pt, typeof(QPointF));
QPainter painter = (QPainter)Marshal.PtrToStructure(obj, typeof(QPainter));
__QPaintDevice* pd = painter.device(); // ERROR
QPainter_drawTextItem(obj, pt, ti);
}
托管包装器(wrap.cs):
[StructLayout(LayoutKind.Sequential, Size=8)]
public unsafe struct __QPaintDevice
{
public IntPtr *vfptr;
public IntPtr painters;
};
[StructLayout(LayoutKind.Sequential, Size=4)]
public unsafe struct __QPainter
{
public IntPtr d_ptr;
};
// When the following line is included, I get this error:
// Access violation reading location 0x00000078.
// When the following line is excluded, I get this error:
// EEArgumentException at memory location 0x003786f4.
[StructLayout(LayoutKind.Sequential)] // is this useful?
public unsafe class QPainter : IDisposable
{
private __QPainter* _this;
private __QPaintDevice* _pd;
[DllImport("QtGui4.dll", EntryPoint = "??0QPainter@@QAE@XZ",
CallingConvention = CallingConvention.ThisCall)]
private static extern int _QPainter_Constructor(__QPainter* ths);
[DllImport("QtGui4.dll",
EntryPoint = "??0QPainter@@QAE@PAVQPaintDevice@@@Z",
CallingConvention = CallingConvention.ThisCall)]
private static extern int _QPainter_Constructor(__QPainter* ths,
__QPaintDevice* pd);
[DllImport("QtGui4.dll", EntryPoint = "??1QPainter@@QAE@XZ",
CallingConvention = CallingConvention.ThisCall)]
private static extern int _QPainter_Destructor(__QPainter* ths);
[DllImport("QtGui4.dll",
EntryPoint = "?device@QPainter@@QBEPAVQPaintDevice@@XZ",
CallingConvention = CallingConvention.ThisCall)]
private static extern __QPaintDevice* _device(__QPainter* ths);
public QPainter()
{
_this = (__QPainter*)Marshal.AllocHGlobal(sizeof(__QPainter));
_QPainter_Constructor(_this);
}
public QPainter(__QPaintDevice* pd)
{
_this = (__QPainter*)Marshal.AllocHGlobal(sizeof(__QPainter));
_pd = (__QPaintDevice*)Marshal.AllocHGlobal(sizeof(__QPaintDevice));
_QPainter_Constructor(_this, pd);
}
public void Dispose()
{
_QPainter_Destructor(_this);
Marshal.FreeHGlobal((IntPtr)_this);
Marshal.FreeHGlobal((IntPtr)_pd);
_this = null;
_pd = null;
}
public __QPaintDevice* device()
{
return _device(_this);
}
};