我正在使用某种钩子从C#拦截本地dll或exe执行的Win32 API调用。在这个特定的案例中,我对user32.dll中的DrawText()感兴趣。它在Win32 API中声明如下:
INT WINAPI DrawTextW(HDC hdc, LPCWSTR str, INT count, LPRECT rect, UINT flags)
LPRECT结构体具有以下签名(也适用于Win32 API):
typedef struct tagRECT {
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT LPRECT;
LONG是32位系统中32位整数的typedef(关于64位系统我不清楚,但在这个问题上无关紧要,因为我使用的是32位Windows)。为了能够访问此结构的成员,我在我的C#代码中声明了它...
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct RECT
{
public Int32 left;
public Int32 top;
public Int32 right;
public Int32 bottom;
}
...并使用此RECT结构编写了P/Invoke的签名:
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
static extern IntPtr DrawText(IntPtr HDC, String str, Int32 count, ref RECT rect, UInt32 flags, IntPtr dtp);
由于在C#中,structs是值类型,而不像C/C++中的引用类型,因此在这里需要使用ref修饰符。
然而,当我使用rect.top rect.left等时,它们几乎总是返回0。我知道这是不正确的。但是在经过无数个小时的谷歌和尝试了许多不同的方法后,我无法使这个简单的东西工作。
我尝试过的事情:
- 使用不同的基元来表示RECT成员(int、long、short、UInt32...)。实际上,这很明显不是一个类型问题,因为在任何情况下,我应该看到一些乱码数字,而不是0。 - 移除ref修饰符。这也很愚蠢(绝望的时候,绝望的措施),因为rect.left正确地返回指向rect而不是其值的指针。 - 尝试了unsafe代码块。没有起作用,但我可能在实现上犯了一个错误(我不记得我做了什么)。此外,这种方法通常是为COM和Win32中棘手的指针情况保留的,对于我的情况来说,它是过度设计的。 - 在RECT的成员前添加[MarshallAs]。没有任何区别。 - 调整Pack值。没有区别。
我相当肯定我错过了一些非常简单和直接的东西,但我不知道它是什么...
感谢任何帮助。谢谢。