SIMCONNECT_RECV_EVENT_EX1 documentation -- `dwData` is not really an array

Version: SDK 0.23.1

Frequency: Consistently

Severity: High

Context: Current live SDK documentation.

Bug description:
Docs for SIMCONNECT_RECV_EVENT_EX1 show:

struct SIMCONNECT_RECV_EVENT_EX1 : public SIMCONNECT_RECV {
    DWORD  uGroupID;
    DWORD  uEventID;
    DWORD  dwData[5];
};

Definition from SimConnect.h in SDK v0.23.1:

struct SIMCONNECT_RECV_EVENT_EX1 : public SIMCONNECT_RECV {
    DWORD   uGroupID;
    DWORD   uEventID;
    DWORD   dwData0;
    DWORD   dwData1;
    DWORD   dwData2;
    DWORD   dwData3;
    DWORD   dwData4;
};
1 Like

That’s the same thing, really…

In terms of memory layout, since the structs are tightly packed, sure.

But for example

void dispatchMessage(SIMCONNECT_RECV* pData, ...) {
...
    case SIMCONNECT_RECV_ID_EVENT_EX1: {
      SIMCONNECT_RECV_EVENT_EX1* data = (SIMCONNECT_RECV_EVENT_EX1*)pData;
      doSomethingWith(data.dwData[0]);
    }
...
}

might be surprising to someone just following the docs. :person_shrugging:

-Max

1 Like

The address of data.dwData[0] is the same as the address of the dwData0 member of the struct… as such, they’re really entirely equivalent…

It’s possible @Nocturne might want to address this however, just for consistency’s sake.

1 Like

I think the point Max is making is that anybody trying to use dwData0 (or any of the others) as shown in the docs is going to receive some unexpected compilation errors.

1 Like

LOL… “consistency” between documentation and implementation… yes. Old fashioned, I know… :sweat_smile:

I guess the cool kids just use like
doSomethingWith(*(pData + 2 * sizeof(DWORD)))
these days ? :sweat_smile:

Not directly relevant to the original topic, but in case this shows up in searches and/or isn’t obvious to everyone…

If one is just wanting to add support for TransmitClientEvent_EX1() to an existing custom event handler (which would previously have been invoked only via TransmitClientEvent()), one can basically just add a case clause for the new message type ID to the existing handler w/out modifying any casts or accessors (example from actual code in a WASM module):

void dispatchMessage(SIMCONNECT_RECV* pData, ...)
{
	switch (pData->dwID)
	{
		case SIMCONNECT_RECV_ID_EVENT:
		case SIMCONNECT_RECV_ID_EVENT_EX1:  // just add this
		{
			// The difference between SIMCONNECT_RECV_EVENT and SIMCONNECT_RECV_EVENT_EX1 is 4 extra DWORD values tacked onto the end of the latter
			// (dwData is _not_ an array as the SDK docs claim). Since we're only using the first value anyway, this is safe to cast.
			SIMCONNECT_RECV_EVENT* data = (SIMCONNECT_RECV_EVENT*)pData;
			switch (data->uEventID) {
				case CLI_EVENT_PING:
                    // data->dwData is the first passed value in both message types
					returnPingEvent(data->dwData);  
					break;
                ....
			}
			break;
		}  // SIMCONNECT_RECV_ID_EVENT[_EX1]
    ...
    }
}

Sending a TransmitClientEvent_EX1() does not invoke existing SIMCONNECT_RECV_ID_EVENT message handlers since the message’s dwID is different (SIMCONNECT_RECV_ID_EVENT_EX1). So to support both ways of sending events one has to add this to their handler, as far as I can tell.