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

时间:2008-10-14 23:18:18

标签: c# c++ winapi interop struct

我正在拦截Win32 API调用本机dll或exe使用某种挂钩从C#执行。在这种特殊情况下,我对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.left等时,它们几乎总是返回0.我知道这是不正确的。但是经过无数小时的谷歌搜索并尝试了很多不同的事情,我无法让这些简单的东西发挥作用。

我尝试过的事情:

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

我很确定我错过了一些非常简单明了的内容,但我不知道它是什么......

感谢任何帮助。谢谢。

3 个答案:

答案 0 :(得分:3)

答案 1 :(得分:2)

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

答案 2 :(得分:1)

部分问题是使用String,其中应使用StringBuilder。

尝试此签名(使用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) ;

}