从C#访问Win32 C/C++结构成员

6

我正在使用某种钩子从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值。没有区别。
我相当肯定我错过了一些非常简单和直接的东西,但我不知道它是什么...
感谢任何帮助。谢谢。
3个回答


2

我注意到你说过尝试过 [MarshallAs],但是你尝试过 [MarshalAs(UnmanagedType.Struct)] 吗?


1
问题的一部分是在应该使用 StringBuilder 的地方使用了 String。
尝试使用此签名(使用 PInvoke Interop Assistant 生成)。

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct tagRECT {

    /// LONG->int
    public int left;

    /// LONG->int
    public int top;

    /// LONG->int
    public int right;

    /// LONG->int
    public int bottom;
}

public partial class NativeMethods {

    /// Return Type: int
    ///hdc: HDC->HDC__*
    ///lpchText: LPCWSTR->WCHAR*
    ///cchText: int
    ///lprc: LPRECT->tagRECT*
    ///format: UINT->unsigned int
    [System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint="DrawTextW")]
public static extern  int DrawTextW([System.Runtime.InteropServices.InAttribute()] System.IntPtr hdc, [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPWStr)] System.Text.StringBuilder lpchText, int cchText, ref tagRECT lprc, uint format) ;

}

为什么PInvoke Interop助手将结构体命名为tagRECT而不是RECT? - xx77aBs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接