Metamorphing Machine I rather be this walking metamorphosis
than having that old formed opinion about everything!

How to deal with unions, the VB6 way

Union is a C artifact unknown to VB6.
It allows to have different things in a struct/Type, but all those different things share the same space - the space occupied by the largest of them.
There's no way we can replicate it in VB6.

If you're interested in only one of those different things, then it is a no-brainer: Build up your Type with that thing alone.
But make sure any padding space needed is still there.

Let's see an example:

Const INPUT_MOUSE = 0
Const INPUT_KEYBOARD = 1
Const INPUT_HARDWARE = 2

typedef struct tagINPUT {
DWORD type;
union {
MOUSEINPUT mi;
KEYBDINPUT ki;
HARDWAREINPUT hi;
} DUMMYUNIONNAME;
} INPUT, *PINPUT, *LPINPUT;

// ---------------- Size: 24 bytes ----------------
typedef struct tagMOUSEINPUT {
LONG dx;
LONG dy;
DWORD mouseData;
DWORD dwFlags;
DWORD time;
ULONG_PTR dwExtraInfo;
} MOUSEINPUT, *PMOUSEINPUT, *LPMOUSEINPUT;

Type MOUSEINPUT
dx As Long
dy As Long
mouseData As Long
dwFlags As Long
time As Long
dwExtraInfo As LongPtr
End Type

// ---------------- Size: 16 bytes ----------------
typedef struct tagKEYBDINPUT {
WORD wVk;
WORD wScan;
DWORD dwFlags;
DWORD time;
ULONG_PTR dwExtraInfo;
} KEYBDINPUT, *PKEYBDINPUT, *LPKEYBDINPUT;

Type KEYBDINPUT
wVk As Integer
wScan As Integer
dwFlags As Long
time As Long
dwExtraInfo As LongPtr
End Type

// ---------------- Size: 8 bytes -----------------
typedef struct tagHARDWAREINPUT {
DWORD uMsg;
WORD wParamL;
WORD wParamH;
} HARDWAREINPUT, *PHARDWAREINPUT, *LPHARDWAREINPUT;

Type HARDWAREINPUT
uMsg As Long
wParamL As Integer
wParamH As Integer
End Type

When I was trying to mimic VB's SendKeys, I was only interested in the KEYBDINPUT, so my Type ended up being:

Type GeneralInput
Type As Long
ki As KEYBDINPUT
Dummy As Currency 'Needed to complete 24 bytes
End Type

(Input is a reserved keyword, so I had to change it to GeneralInput.)

Now suppose you're providing it to some API but do not know what you'll get in return.
My tip: Declare three different Types:

Type InputForMouse
Type As Long
ki As MOUSEINPUT
End Type

Type InputForKeyboard
Type As Long
ki As KEYBDINPUT
Dummy As Currency
End Type

Type InputForHardware
Type As Long
ki As HARDWAREINPUT
Dummy1 As Currency
Dummy2 As Currency
End Type

Have available one variable for each:

Dim Mouse As InputForMouse
Dim Keyboard As InputForKeyboard
Dim Hardware As InputForHardware

Pass any of them to the API. On return, check which one you got and then use LSet to adjust the type:

Select Case Mouse.Type
Case INPUT_MOUSE
Rem Use Mouse variable

Case INPUT_KEYBOARD
LSet Keyboard = Mouse
Rem Use Keyboard variable

Case INPUT_HARDWARE
LSet Hardware = Mouse
Rem Use Hardware variable
End Select

If you have a better suggestion, please, let me know.
Next week we'll have one more WTF VB6!

Andrej Biasic
2021-09-29