5

我正在使用某种挂钩从 C# 拦截 Win32 API 调用本机 dll 或 exe。在这种特殊情况下,我对 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# 中的值类型,而不是 C/C++ 中的引用类型,因此此处需要 ref 修饰符。

但是,当我使用rect.top rect.leftetc 时,它们几乎总是返回 0。我知道这是不正确的事实。但是在谷歌搜索了无数小时并尝试了很多不同的东西之后,我无法让这个简单的东西发挥作用。

我尝试过的事情:

  • 对 RECT 成员使用不同的原语(int、long、short、UInt32...)。实际上很明显这不是类型问题,因为无论如何我应该看到一些乱码,而不是 0。
  • 删除 ref 修饰符。这也是愚蠢的(绝望的时候,绝望的措施),因为 rect.left 正确地返回指向 rect 的指针而不是它的值。
  • 尝试过unsafe的代码块。没用,但我可能在实现中犯了一个错误(我不记得我做了什么)。除了这种方法通常保留用于 COM 和 Win32 中棘手的指针情况,无论如何,这对我的情况来说是多余的。
  • 尝试[MarshallAs]在 RECT 成员之前添加。没区别。
  • 玩弄Pack价值观。没有不同。

我相当确定我错过了一些非常简单直接的东西,但我不知道它是什么......

任何帮助表示赞赏。谢谢你。

4

3 回答 3

4

http://www.pinvoke.net/default.aspx/user32.DrawText

于 2008-10-14T23:40:07.087 回答
2

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

于 2008-10-14T23:43:34.257 回答
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) ;

}
于 2008-10-15T08:16:43.533 回答