MSFS 2020 / SimConnect

Has anyone linked in SimConnect.h using SimConnect.lib/dll yet?

If you have, could you share some of the simple “get data” code, please?

I did do a project in C++ and PureBasic, and while it works well it can only process updates once a second. I need to process my window all in memory, in one program so that it is fast enough.

I have not been able to do the SimConnect calls in PB so that is out. Visual Studio? What a joke that is!

If you could show me how to do the calls I would be indebted to you!

An interesting add on.
MSFS - Solved: Where is simconnect.h? | FSDeveloper

I wonder if this is the same SimConnect.h

Sample: SimConnect.h (prepar3d.com)

Which links back to this Lockheed Martin Environment Sim.
Prepar3D Product Overview – Prepar3D

Is this Prepar3D one and the same Flight Simulator?

This looks like its a pertinent structure to watch for input and it suggests there might be quite a few of them.

struct SIMCONNECT_RECV_SIMOBJECT_DATA : public SIMCONNECT_RECV           // when dwID == SIMCONNECT_RECV_ID_SIMOBJECT_DATA
{
    DWORD   dwRequestID;
    DWORD   dwObjectID;
    DWORD   dwDefineID;
    DWORD   dwFlags;            // SIMCONNECT_DATA_REQUEST_FLAG
    DWORD   dwentrynumber;      // if multiple objects returned, this is number <entrynumber> out of <outof>.
    DWORD   dwoutof;            // note: starts with 1, not 0.         
    DWORD   dwDefineCount;      // data count (number of datums, *not* byte count)
    DWORD   dwData;             // data begins here, dwDefineCount data items
};

I assume the below would be found after running the dll through the libmaker, to create a Lib file?

> SIMCONNECTAPI SimConnect_RetrieveString(SIMCONNECT_RECV * pData, DWORD cbData, void * pStringV, char ** pszString, DWORD * pcbString);
> SIMCONNECTAPI SimConnect_GetLastSentPacketID(HANDLE hSimConnect, DWORD * pdwError);
> SIMCONNECTAPI SimConnect_CallDispatch(HANDLE hSimConnect, DispatchProc pfcnDispatch, void * pContext);
> SIMCONNECTAPI SimConnect_GetNextDispatch(HANDLE hSimConnect, SIMCONNECT_RECV ** ppData, DWORD * pcbData);
> SIMCONNECTAPI SimConnect_RequestResponseTimes(HANDLE hSimConnect, DWORD nCount, float * fElapsedSeconds);
> SIMCONNECTAPI SimConnect_InsertString(BYTE * pDest, DWORD cbDest, BYTE ** ppEnd, DWORD * pcbStringV, const char * pSource);
> SIMCONNECTAPI SimConnect_Open(HANDLE * phSimConnect, LPCSTR szName, HWND hWnd, DWORD UserEventWin32, HANDLE hEventHandle, DWORD ConfigIndex);
> SIMCONNECTAPI SimConnect_Close(HANDLE hSimConnect);

So then it becomes a case of match the MS Data Types to Clarion Data Types
[ Windows Data Types (BaseTsd.h) - Win32 apps | Microsoft Docs

If you need more info, sometimes looking in the WinDef.h can give more info on a MS Data Type and then marry up to a Clarion data Type. You can get WinDef.h from downloading and installing the latest copy of the free version of VisualStudio unless you have your own already. I find VS search facility quite good for looking up info which is lacking in the online Web API’s like these.
API Index - Win32 apps | Microsoft Docs
Windows API index - Win32 apps | Microsoft Docs

Things I usually find using Visual studio are the data structures and the enumerates which are like clarion equates.

Where the MS Data Types & WinDef.h are both lacking in info, sometimes you can get the info from looking at other defined data types, this Visual Basic example also conveys info more suited to a database and Clarion is a database tool.

Data type summary | Microsoft Docs

So eventually you would have in your MAP structure something which looks like this:

SIMCONNECTAPI SimConnect_GetLastSentPacketID(HANDLE hSimConnect, DWORD * pdwError);

becomes in Clarion

MAP
SimConnect_GetLastSentPacketID( long hSimConnect, long pdwError )
End

Both Flight Sim and the Prepar3d look interesting. I wonder if the Military are going to open up their flight sims for others to go head to head, like EA, NeedForSpeed and others do with online competitions.

Sorry about the formatting, it seems somewhat variable as to what it chooses to do.

Thanks for the quick reply, Richard! Much appreciated.

The SimConnect library is very complex to use and understand. The version you have prepared (PrePar3D!) has most of the library calls in it that match the MSFS version. MSFS/Asobo will be making tweaks to the SDK as they go along, but your versions are 95% accurate.

I have never been good at understanding linked in libraries and their usage. It is a mental block that I cannot seem to overcome. I have tried for many years now.

These are all of the prototypes required to get SimVars out of the MSFS engine:

SimConnect_Open(phSimConnect.l, szName.s, hwnd.l, UserEventWin32.l, hEventHandle.l, ConfigIndex.l)
SimConnect_AddToDataDefinition(hSimConnect.l, DefineID.l, DatumName.s, UnitsName.s, DatumType = #SIMCONNECT_DATATYPE_FLOAT64, fEpsilon.f=0.0, DatumID.l=#SIMCONNECT_UNUSED)
SimConnect_RequestDataOnSimObject(hSimConnect.l, RequestID.l, DefineID.l, ObjectID.l, Period.l, flags.l, origin.l, interval.l, limit.l)
SimConnect_GetNextDispatch(hSimConnect.l, *ppData.SIMCONNECT_RECV, pcbData.l)
SimConnect_Close(hSimConnect.l)

This is a sample “get’ur done” C++ example:

#include <Windows.h>
#include "SimConnect.h"
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

using namespace std;
HANDLE hSimConnect = NULL;
enum DATA_DEFINE_ID   { DEFINITION_ID_AP, };
enum DATA_REQUEST_ID   { REQUEST_AP_SETTINGS, };

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct AutopilotData {
   public:double ALTITUDE;
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ PWSTR pCmdLine, _In_ int nCmdShow)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{
  HRESULT hr;
  SIMCONNECT_RECV_SIMOBJECT_DATA* pObjData = NULL;
  SIMCONNECT_RECV* pData = NULL;
  DWORD cbData = 0;
  AutopilotData* pAutopilotData   = NULL;
  bool bDone = false;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

  // Connect to MSFS
  if (FAILED(SimConnect_Open(&hSimConnect, "MSFS Info", NULL, 0, 0, 0))) {
    return false;
  }

  // Add data to return
  hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_ID_AP, "INDICATED ALTITUDE", "Feet");
 
  // Request data call to return data
  hr = SimConnect_RequestDataOnSimObject(hSimConnect, REQUEST_AP_SETTINGS, DEFINITION_ID_AP, SIMCONNECT_OBJECT_ID_USER, SIMCONNECT_CLIENT_DATA_PERIOD_VISUAL_FRAME);

  bDone = false;
  while (bDone == false)
  {
      // Get next set of data
    hr = SimConnect_GetNextDispatch(hSimConnect, &pData, &cbData);
    if (SUCCEEDED(hr))
    {
      // Assign data to structure
      pObjData = (SIMCONNECT_RECV_SIMOBJECT_DATA*)pData;
      if (pData->dwID == SIMCONNECT_RECV_ID_SIMOBJECT_DATA && pObjData->dwRequestID == REQUEST_AP_SETTINGS)
      {
        pAutopilotData = (AutopilotData*)&pObjData->dwData;

        // Display Altitude data here

        // Not the most efficient. A call-back function should be used instead, but this works if Sleep(16) is used. I have tested this logic using Task Manager observations of very-low CPU usage.
        Sleep(16);   // Basically, 60fps (1000ms / 60fps = 16ms)
      }
    }
  }
  // Close
  hr = SimConnect_Close(hSimConnect);
  return true;
}

If I could get this code above to be done in Clarion I would be tickled pink!

Maybe contact Mark Watney here

1 Like

This is completely wrong.

Whats wrong with it?

Well, your prototype lost return value, lost parameter passing convention (Pascal or C), has incorrect pdwError type, and is declared in MAP instead of MODULE.

Some question, if you dont mind? :grinning:
Whats the return value?
Does this need C or Pascal to be stated?
What is the correct pdwError data type?
Why declare in a Module instead of the MAP?

The return value is of HRESULT (long) type. Parameter passing convention is Pascal, the type of pdwError is *ULONG, external prototypes must be declared in the MODULE clause. So if I’m correct the prototype should be

MAP
  MODULE('SIMCONNECT API')
    SimConnect_GetLastSentPacketID(long hSimConnect, *ulong pdwError), long, pascal
  END
END

Where are you getting the HRESULT from?

I just performed a search for SIMCONNECTAPI and found this:

#define SIMCONNECTAPI extern "C" HRESULT __stdcall

I didnt kook at this in my first post, so yes there is a hresult but the rest is still correct because Clarion defaults to C if C or Pascal is not specified according to the docs?

#if !defined(SIMCONNECTAPI)
#define SIMCONNECTAPI extern “C” HRESULT __stdcall
#endif

The address of pdwError is still a long in Clarion. Address() uses a long so I can take the address from the debugger and then go to the memory address in the debugger to read the actual value, cant I?

Doesnt LoadLibrary let me get around the problem of using modules?
LoadLibraryA function (libloaderapi.h) - Win32 apps | Microsoft Docs

Default Clarion calling convention is not C nor Pascal, from the help:

the default calling convention is the internal, register-based parameter passing convention used by all the TopSpeed compilers.

extern “C” has nothing to do with calling conventions, but stdcall does and means PASCAL in Clarion.

Well, yes, you indeed can use LONG as pdwError argument and pass an address, but this is unnecessary complication of the code and I can’t understand why it should be used in this case.

So using this link
c++ - What is the meaning and usage of __stdcall? - Stack Overflow

  • __stdcall , Pushes parameters on the stack, in reverse order (right to left)
  • __cdecl , Pushes parameters on the stack, in reverse order (right to left)
  • __clrcall , Load parameters onto CLR expression stack in order (left to right).
  • __fastcall , Stored in registers, then pushed on stack
  • __thiscall , Pushed on stack; this pointer stored in ECX

So Clarion help doc page “C, PASCAL (parameter passing conventions)” suggests:
C read the parameter list from Right to Left, then push onto the stack.
Pascal read the parameter list from Left to Right, then push onto the stack.

but it says in the link above stdcall is right to left. Another source which suggests the same thing is
x86 calling conventions - Wikipedia

The stdcall[5] calling convention is a variation on the Pascal calling convention in which the callee is responsible for cleaning up the stack, but the parameters are pushed onto the stack in right-to-left order, as in the _cdecl calling convention.
Prototyping Functions in Clarion, Pascal

So the stdcall doesnt tell me it should be Pascal, but C, and stdcall tells me (the caller) I do not need to clean the stack, but (the callee) Simconnect code will clean it.

If C or Pascal is not specified, a clarion app defaults to the internal register-based parameter passing which from the wiki link reads:

TopSpeed / Clarion / JPI[edit]

The first four integer parameters are passed in registers eax, ebx, ecx and edx. Floating point parameters are passed on the floating point stack – registers st0, st1, st2, st3, st4, st5 and st6. Structure parameters are always passed on the stack. Additional parameters are passed on the stack after registers are exhausted. Integer values are returned in eax, pointers in edx and floating point types in st0.

So in this case I think the hresult would be in the EAX register automatically but something would need to be done to get the value out of the EAX register either by prototyping it and have the clarion runtime do the work (easy) or by reading it direct using GetThreadContext and the EAX value in the 32bit of _context.h (havent looked in the 64bit updated version of _context).

GetThreadContext function (processthreadsapi.h) - Win32 apps | Microsoft Docs

typedef struct _CONTEXT
{
DWORD ContextFlags;

DWORD   Dr0;
DWORD   Dr1;
DWORD   Dr2;
DWORD   Dr3;
DWORD   Dr6;
DWORD   Dr7;

FLOATING_SAVE_AREA FloatSave;

DWORD   SegGs;
DWORD   SegFs;
DWORD   SegEs;
DWORD   SegDs;

DWORD   Edi;
DWORD   Esi;
DWORD   Ebx;
DWORD   Edx;
DWORD   Ecx;
DWORD   Eax;

Edit.
Re unnecessary complication of the code and I can’t understand why it should be used in this case.
Defensive programming reasons. Performing additional checks not afforded to us by the runtime and language commands. eg loading a dll will fail if not found, but its possible to use loadlibrary to search multiple folders for the dll, in case someone has moved dll’s for some reason, and there is the windows Side by Side (SxS) folder which can be used to hunt for missing dlls.
Side-by-side assembly - Wikipedia

Edit2:
This is a bit of history on the registers
EAX x86 Register: Meaning and History (keleshev.com)

and these registers are memory mapped i/o but dont technically have a memory address in the normal programming sense.
Memory-mapped I/O - Wikipedia

I don’t know where you got this quote, C11 help file says:

The C and PASCAL attributes of a PROCEDURE prototype specifies that parameters are always passed on the stack. In 32-bit programs, both C and PASCAL conventions pass the parameters to the stack from right to left. The difference is in who (callee ( C ) or caller(PASCAL)) is cleaning the stack on return.

You can see the C11 help page on the left of the screen shot, thats where I have got it from. Maybe there is a mistake with the docs because of what is said in the links I posted earlier?

hmm… I can’t find your quote on your screenshot.

Its the C11 help document visible on left hand part of the screensho, with all the words hilighted in blue.

Found it, this was the other help page I had open yesterday or whenever.

Prototyping C/C++ Functions in Clarion
Prototyping Functions in Clarion

Most non-SoftVelocity C and C++ compilers use a calling convention where parameters are pushed onto the stack from right to left (as read from the parameter list). The Clarion C attribute specifies this convention.

Many C and C++ compilers also offer a Pascal calling convention where parameters are pushed left to right from the parameter list. Most other languages on the PC also use this convention. The Clarion PASCAL attribute generates calls using this convention.

Edit. It could be a help documentation issue, its hard enough tracking down the right info sometimes. :grinning:

I leave you guys alone for a few hours and… Wham! Thanks for all the posts while I was gone.

While I was away, I was able to pipe the output out of the sim, using a hidden C++ console program. Using the std::out from the console app, my PureBasic program is now able to read that data - real-time with hits of data at 15ms. The PB program opens the console app hidden and lets the C++ program perform all of the heavy work. Both programs have a “very-low” to “low” CPU status in task manager so I don’t think I need to do anything else at this time.

It just would be nice to have another language other than C/C++/C#/VB.net being used for MSFS. I hit up the PureBasic forum and got no responses there.

The MSFS SDK can be found here: https://docs.flightsimulator.com/html/index.htm if you should want to pursue it further or it can help to answer any questions I have created for you.

I may still consider trying to understand what you guys were talking about but… Dang! I am a K.I.S.S. kind of guy.