Ryss
Ryss

Reputation:

Accessing Win32 C/C++ struct members from C#

I am intercepting Win32 API calls a native dll or exe is doing from C# using some kind of hooking. In this particular case I am interested in DrawText() in user32.dll. It is declared like this in Win32 API:

INT WINAPI DrawTextW(HDC hdc, LPCWSTR str, INT count, LPRECT rect, UINT flags)

The LPRECT struct has the following signature (also in Win32 API):

typedef struct tagRECT { 
    LONG left;
    LONG top;
    LONG right;
    LONG bottom;
} RECT LPRECT;

LONG is a typedef for 32bit integers on 32bit systems (don't know about 64bit systems, it is irrelevant at this point because I am on 32bit Windows). To be able to access the members of this struct I declared it in my C# code...

[StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct RECT
    {
        public Int32 left;
        public Int32 top;
        public Int32 right;
        public Int32 bottom;
    }

... and wrote the signature of P/Invoke using this RECT struct:

[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);

Since structs are value types in C# as opposed to being reference types like in C/C++, the ref modifier is necessary here.

However when I use rect.top rect.left etc, they almost always return 0. I know for a fact that this is incorrect. But after googling countless hours and trying a lot of different things, I couldn't make this simple stuff work.

Things I've tried:

I am fairly sure that I'm missing something very easy and straightforward but I have no idea what it is...

Any help is appreciated. Thank you.

Upvotes: 6

Views: 7049

Answers (3)

JaredPar
JaredPar

Reputation: 755457

Part of the problem is the use of String where a StringBuilder should be used.

Try this signature (Generated with 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) ;

}

Upvotes: 1

Werg38
Werg38

Reputation: 1130

I notice you say you have tried [MarshallAs] but have you tried [MarshalAs(UnmanagedType.Struct)]?

Upvotes: 2

Related Questions