Using the SimConnect SDK - A SimVar Request handler (and potential SDK replacement)

Similar to how we retrieve a SimVar value, setting a SimVar is also a two stage process, reserving a block of memory within SimConnect then assigning values when we want to change it.

Let’s take a peek under the hood.

For reserving the block of memory, we can re-use the same code we developed for fetching SimVar values. This basically tells SimConnect the type of SimVar we’re using followed by the type of data we’re expecting back.

// Submit the SimVar request to SimConnect
simConnect.AddToDataDefinition(simReq.DefID, request.Name, unit, simReq.SimType, 0.0f, SimConnect.SIMCONNECT_UNUSED);

Strangely, SimConnect expects references to SimVars and their expected Data Type to be defined using ENUMs - Normally, when coding an ENUM is a static list of pre-defined values, obviously, we don’t know in advance which SimVars will be used, and we don’t know which values we’d expect back, so why ENUMs?

The first parameter in the method call above is an ENUM.

Luckily ENUM values can be faked at runtime by supplying an integer cast into an ENUM.

The second part is defining the data type we’re expecting this SimVar to return, to identify this correctly, you will need to refer to the documentation, but the method to do this is fairly straightforward:

simConnect.RegisterDataDefineStruct<double>(simReq.DefID);

Change the <double> above to reflect the Data Type you require to be returned.

There is one slightly unusual Data Type, <string> won’t work, even though the value you’re expecting to be returned is a text string (such as for the “Title” SimVar).

Instead, SimConnect will require a struct to be supplied, like this:

simConnect.RegisterDataDefineStruct<SimVarString>(simReq.DefID);

SimVarString is a structure:

internal struct SimVarString
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
    public string Value;
}

This allows SimConnect to populate the Value property of the struct, which you can then reference in the returned value.

The documentation (see link above) relating to which variables can be set is not complete. Many variables have not been updated to indicate if they can be set, some are incorrectly defined as readonly or state they can be set. Others have the wrong units defined.

The basic rule is, if you want to set a specific SimVar value, try it. If it doesn’t work, then it’s likely not settable. Having said that, there are some values that can be set, but not with the units you might expect.

For example, I recently tested 2 SimVars defined as settable, with a unit of BOOL (e.g. TRUE/FALSE). One actually required me to supply the text “TRUE” as the submitted value, the other required me to submit the integer “1”, which SimConnect then returned as “true”.

So, some trial and error is needed when experimenting with editing SimVars.

Once we have defined the SimVar we want to set and the Data Type we expect to be returned, next we’ll pass in the value to set it to. This is achieved with the following:

// Data area reserved, now set the value
simConnect.SetDataOnSimObject((SIMVARDEFINITION)reqId, SimConnect.SIMCONNECT_OBJECT_ID_USER, SIMCONNECT_DATA_SET_FLAG.DEFAULT, simVarValue.Value);

In the code above, reqId is the ENUM value we set in the previous code to reserve the memory block above. simVarValue.Value is an object. This is because it can contain any number of Data Types, so the object base class is used to allow any to be passed.

Since we’ve defined a memory block in the same way we reserve it for Get’ting a SimVar, the value we submit will be returned as a raised event. Most likely, we want a fire-and-forget solution, where we simply don’t care if MSFS 2020 has implemented the value we sent, we’ll just assume it has.

So, we now know how to set SimVar values. Next we’ll look at how we can ask SimConnect to forget about a SimVar request, as we like to tidy up after ourselves when we don’t need something any more.

2 Likes