How Union Works

Most of Win32 functions are user friendly. Not as user friendly as .NET framework, but once you see specification, everything is clear. There is no problem translating it to P/Interop call.

But there is one issue that may be problematic - unions. They are used in C++ programs in order to force multiple variables to use same memory space. We will use INPUT structure as example here:

typedef struct tagINPUT {
DWORD type;
union {
MOUSEINPUT mi;
KEYBDINPUT ki;
HARDWAREINPUT hi;
};
} INPUT, *PINPUT;
typedef struct tagMOUSEINPUT {
LONG dx;
LONG dy;
DWORD mouseData;
DWORD dwFlags;
DWORD time;
ULONG_PTR dwExtraInfo;
} MOUSEINPUT, *PMOUSEINPUT;
typedef struct tagKEYBDINPUT {
WORD wVk;
WORD wScan;
DWORD dwFlags;
DWORD time;
ULONG_PTR dwExtraInfo;
} KEYBDINPUT, *PKEYBDINPUT;
typedef struct tagHARDWAREINPUT {
DWORD uMsg;
WORD wParamL;
WORD wParamH;
} HARDWAREINPUT, *PHARDWAREINPUT;

Although this code is little bit messy, it should be mostly clear to C# developer:

public struct MOUSEINPUT {
public Int32 dx;
public Int32 dy;
public Int32 mouseData;
public Int32 dwFlags;
public Int32 time;
public UInt32 dwExtraInfo;
}
public struct KEYBDINPUT {
public Int16 wVk;
public Int16 wScan;
public Int32 dwFlags;
public Int32 time;
public UInt32 dwExtraInfo;
}
public struct HARDWAREINPUT {
public Int32 uMsg;
public Int16 wParamL;
public Int16 wParamH;
}

While this conversion is clear, what is not so clear is what to do with tagINPUT.
Solution in C# could look like this:

public struct tagHARDWAREINPUT {
[FieldOffset(0)]
public MOUSEINPUT mi;
[FieldOffset(0)]
public KEYBDINPUT ki;
[FieldOffset(0)]
public HARDWAREINPUT hi;
}

This makes all fields aligned on first byte and thus they behave identically to C++ structure union.

Leave a Reply

Your email address will not be published. Required fields are marked *