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!
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?
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.
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:
#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!
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?
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
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?
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?
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.
__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.
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:
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).
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
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?
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.
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.