• Which the release of FS2020 we see an explosition of activity on the forun and of course we are very happy to see this. But having all questions about FS2020 in one forum becomes a bit messy. So therefore we would like to ask you all to use the following guidelines when posting your questions:

    • Tag FS2020 specific questions with the MSFS2020 tag.
    • Questions about making 3D assets can be posted in the 3D asset design forum. Either post them in the subforum of the modelling tool you use or in the general forum if they are general.
    • Questions about aircraft design can be posted in the Aircraft design forum
    • Questions about airport design can be posted in the FS2020 airport design forum. Once airport development tools have been updated for FS2020 you can post tool speciifc questions in the subforums of those tools as well of course.
    • Questions about terrain design can be posted in the FS2020 terrain design forum.
    • Questions about SimConnect can be posted in the SimConnect forum.

    Any other question that is not specific to an aspect of development or tool can be posted in the General chat forum.

    By following these guidelines we make sure that the forums remain easy to read for everybody and also that the right people can find your post to answer it.

C# *Console* app?

Messages
112
Country
unitedkingdom
Morning chaps. Long time no visit. Hope you're all surviving lockdown[n].

Please can you give me a nudge in the right direction?
I've previously coded a prototype "application" (=scrappy bit of test code) in VBA that successfully connected to SimConnect and exchanged various bits of flight dynamics data and control events.
I'm now trying to do something similar but thought VBA was perhaps not the greatest idea so thought that maybe C# would be a better choice not least because I've got basic skills in this.

Having read a bunch of examples in the ancient (FSX) SimConnect examples and a few slightly later ones in LM's documentation I took a deep breath and started upsetting Visual Studio.
Given the nature of the application (I want to interface some physical gauges - compass & ADI initially and a control column - not USB joystick) I thought that a Console app would be a good start, but immediately ran into a problem that was beyond my depth of understanding: The sample code I was (ahem) "inspired by", passes a form handle to SimConnect and elsewhere uses Windows forms messaging capabilities to manage update events.

C#:
if (simconnect == null)
            {
                try
                {
                    simconnect = new SimConnect("Managed Data Request", this.Handle, WM_USER_SIMCONNECT, null, 0);
                    //the "this.Handle" is never going to work here. No form=no handle?

                    initDataRequest();

                }
                catch (COMException ex)
                {
                    mLog.LogInformation("Unable to connect to SimConnect:\n\n" + ex.Message);
                }
    ...

and later:

C#:
protected override void DefWndProc(ref Message m)
//No "Message" without a form
...

Is there a way to achieve the same with a CONSOLE app (i.e. no forms)? How do I catch the messages from SImConnect?

I found references to managed code console apps on Beatle's deceased blog page (well the page is there but the sample code isn't), and in a thread on a Delphi port here (which felt like a rabbit hole that was unlikely to help) and have drawn a blank with my web searches.
I suspect I could get it working by giving up and using a form, but I'd rather not if I don't have to.

Thanks in advance,

Z
 
Messages
112
Country
unitedkingdom
Well: Can open, worms everywhere.

While I was waiting, I kept searching and came across this:
https://prepar3d.com/forum/viewtopic.php?t=130820
...which in summary says "Don't try creating a console app. Doesn't work. Use a forms app."

So, realising that all C# apps are pretty much the same but with different template code, I thought I'd have a go at adding the missing references so that I can add an (invisible) form to the project, following what I found here:
https://stackoverflow.com/questions...-application-to-a-winforms-or-wpf-application

...but this doesn't help me because when I add the:
C#:
using System.Windows.Forms;

line into my Program.cs class, I get:
"the type or namespace 'Forms' does not exist in the namespace 'System.Windows' Are you a complete nincompoop?" (or sentiment to that effect)

I suspect the fundamental problem here is my failure to reference the necessary component here (because I don't know what or how). Should I just start again with a Windows Forms project, persist with converting the one I have or hang on to the seemingly daft idea of creating a "simple" console application?

Please put me out of my ignorance and set me on a path in the general direction of competence. All help appreciated. :)

Z
 
Messages
112
Country
unitedkingdom
VS19 Community. Reasonable sure I did select WinForms, but below is the list from Help/About (many of which I don't recognise as things I want/need).
If the below means the answer to your question is "no", is it Tools/Get Tools and Features to install it?

List of stuff from Help/About:
Microsoft Visual Studio Community 2019
Version 16.4.2
VisualStudio.16.Release/16.4.2+29613.14
Microsoft .NET Framework
Version 4.8.04084

Installed Version: Community

Visual C++ 2019 00435-60000-00000-AA478
Microsoft Visual C++ 2019

ASP.NET and Web Tools 2019 16.4.457.38025
ASP.NET and Web Tools 2019

ASP.NET Web Frameworks and Tools 2019 16.4.457.38025
For additional information, visit https://www.asp.net/

Azure App Service Tools v3.0.0 16.4.457.38025
Azure App Service Tools v3.0.0

Azure Functions and Web Jobs Tools 16.4.457.38025
Azure Functions and Web Jobs Tools

C# Tools 3.4.1-beta4-19610-02+c4e5d138903b899477649a17f197abd2bcb22f9e
C# components used in the IDE. Depending on your project type and settings, a different version of the compiler may be used.

Common Azure Tools 1.10
Provides common services for use by Azure Mobile Services and Microsoft Azure Tools.

Extensibility Message Bus 1.2.0 (d16-2@8b56e20)
Provides common messaging-based MEF services for loosely coupled Visual Studio extension components communication and integration.

GitHub.VisualStudio 2.11.106.19330
A Visual Studio Extension that brings the GitHub Flow into Visual Studio.

IntelliCode Extension 1.0
IntelliCode Visual Studio Extension Detailed Info

Microsoft Azure Tools 2.9
Microsoft Azure Tools for Microsoft Visual Studio 2019 - v2.9.21016.1

Microsoft Continuous Delivery Tools for Visual Studio 0.4
Simplifying the configuration of Azure DevOps pipelines from within the Visual Studio IDE.

Microsoft JVM Debugger 1.0
Provides support for connecting the Visual Studio debugger to JDWP compatible Java Virtual Machines

Microsoft Library Manager 2.0.87+gbb515bf382
Install client-side libraries easily to any web project

Microsoft MI-Based Debugger 1.0
Provides support for connecting Visual Studio to MI compatible debuggers

Microsoft Visual C++ Wizards 1.0
Microsoft Visual C++ Wizards

Microsoft Visual Studio Tools for Containers 1.1
Develop, run, validate your ASP.NET Core applications in the target environment. F5 your application directly into a container with debugging, or CTRL + F5 to edit & refresh your app without having to rebuild the container.

Microsoft Visual Studio VC Package 1.0
Microsoft Visual Studio VC Package

Mono Debugging for Visual Studio 16.5.24 (1fafd7e)
Support for debugging Mono processes with Visual Studio.

NuGet Package Manager 5.4.0
NuGet Package Manager in Visual Studio. For more information about NuGet, visit https://docs.nuget.org/

ProjectServicesPackage Extension 1.0
ProjectServicesPackage Visual Studio Extension Detailed Info

SQL Server Data Tools 16.0.61912.09160
Microsoft SQL Server Data Tools

TypeScript Tools 16.0.11031.2001
TypeScript Tools for Microsoft Visual Studio

Visual Basic Tools 3.4.1-beta4-19610-02+c4e5d138903b899477649a17f197abd2bcb22f9e
Visual Basic components used in the IDE. Depending on your project type and settings, a different version of the compiler may be used.

Visual F# Tools 10.4 for F# 4.6 16.4.0-beta.19556.5+e7597deb7042710a7142bdccabd6f92b0840d354
Microsoft Visual F# Tools 10.4 for F# 4.6

Visual Studio Code Debug Adapter Host Package 1.0
Interop layer for hosting Visual Studio Code debug adapters in Visual Studio

Visual Studio Container Tools Extensions (Preview) 1.0
View, manage, and diagnose containers within Visual Studio.

Visual Studio Tools for Containers 1.0
Visual Studio Tools for Containers

VisualStudio.DeviceLog 1.0
Information about my package

VisualStudio.Foo 1.0
Information about my package

VisualStudio.Mac 1.0
Mac Extension for Visual Studio

Xamarin 16.4.000.307 (d16-4@e031886)
Visual Studio extension to enable development for Xamarin.iOS and Xamarin.Android.

Xamarin Designer 16.4.0.464 (remotes/origin/d16-4@4abf337c3)
Visual Studio extension to enable Xamarin Designer tools in Visual Studio.

Xamarin Templates 16.4.25 (579ee62)
Templates for building iOS, Android, and Windows apps with Xamarin and Xamarin.Forms.

Xamarin.Android SDK 10.1.1.0 (d16-4/f2c9364)
Xamarin.Android Reference Assemblies and MSBuild support.
Mono: bef1e63
Java.Interop: xamarin/java.interop/d16-4@c4e569f
ProGuard: xamarin/proguard/master@905836d
SQLite: xamarin/sqlite/3.28.0@46204c4
Xamarin.Android Tools: xamarin/xamarin-android-tools/master@9f4ed4b


Xamarin.iOS and Xamarin.Mac SDK 13.8.3.0 (0d8fe21)
Xamarin.iOS and Xamarin.Mac Reference Assemblies and MSBuild support.
 

DragonflightDesign

Resource contributor
Messages
1,082
Country
northernireland
Looks loaded to me. Start a new project and see if the WinForms option comes up. If it does, carry on with the new project and copy/paste in as much of the old code as possible. Alternatively, before you go that far, try

Using System
Using System.Windows.Forms

For some reason the stupid IDE occasionally requires the parent import before it will allow you to call the child.
 
Messages
112
Country
unitedkingdom
Thanks DD - appreciate the advice.
I'm actually making some progress omitting forms entirely and will update when I have something more concrete to report.

Z
 
Messages
112
Country
unitedkingdom
OK, so now I'm making progress.
The Forms thing looks like it may be a red herring in that there is no need to pass a form handle when instantiating a SimConnect object. The LM Scenario Controller sample shows that you pass null pointers and zeros, like this:
C#:
SimConnect = new SimConnect("Managed Scenario Controller", IntPtr.Zero, 0, null, 0);
- and that line works just fine.

The next bit to worry about is how to get data and the LM Data Request sample gives an example of how to do this:
1) Create a enums of structs and data requests
2) Create the structs (the sample has title/lat/lon/altitude but I'm interested in pitch/bank/heading initially so I created a second struct)
3) Do a bunch of "AddToDataDefinitions" to point the FSX/P3D/etc simulation variables to the appropriate struct.
4) Declare an event handler for "OnRecvSimObjectDataByType" - aka how to handle incoming data.
5) Periodically issue a request ("SimConnect.RequestDataOnSimObjectType()") for the data specified.

All of which I've implemented (combining approaches from both samples so that the requests run in a separate background thread), but I never seem to get any data back in response to (5) above. In debug I can see the request being made and not throwing any exception but my event handler is never hit.

Any suggestions? I can't see why it would be Forms biting back or else LMs console example wouldn't work (albeit that it is requesting a SimConnect message rather than data) .

Z
Edit: I wasn't calling ReceiveMessage() (since I wrongly assumed that it was only required to get the "mission complete" message), so now I'm getting data, although not for the Struct I created. I suspect that there may be an error in (2) or (3) above.
 
Last edited:
Messages
112
Country
unitedkingdom
Right - I think I know that the problem is with my Struct, but I can't figure out what I'm doing wrong.
I have:
C#:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        struct Struct1
        {
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public String title;
            public double latitude;
            public double longitude;
            public double altitude;
        };
        //End insert

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        struct Struct2
        {
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public double pitch;
            public double bank;
            public double heading;
            public double magHeading;
        };

I'm actually only interested in Struct2 - Struct1 was from LM's example. I then have:
C#:
                // define a data structure
                SimConnect.AddToDataDefinition(DEFINITIONS.Struct1, "title", null, SIMCONNECT_DATATYPE.STRING256, 0.0f, SimConnect.SIMCONNECT_UNUSED);
                SimConnect.AddToDataDefinition(DEFINITIONS.Struct1, "Plane Latitude", "degrees", SIMCONNECT_DATATYPE.FLOAT64, 0.0f, SimConnect.SIMCONNECT_UNUSED);
                SimConnect.AddToDataDefinition(DEFINITIONS.Struct1, "Plane Longitude", "degrees", SIMCONNECT_DATATYPE.FLOAT64, 0.0f, SimConnect.SIMCONNECT_UNUSED);
                SimConnect.AddToDataDefinition(DEFINITIONS.Struct1, "Plane Altitude", "feet", SIMCONNECT_DATATYPE.FLOAT64, 0.0f, SimConnect.SIMCONNECT_UNUSED);

                SimConnect.AddToDataDefinition(DEFINITIONS.Struct2, "Plane Pitch Degrees", "radians", SIMCONNECT_DATATYPE.FLOAT64, 0.0f, SimConnect.SIMCONNECT_UNUSED);
                SimConnect.AddToDataDefinition(DEFINITIONS.Struct2, "Plane bank degrees", "radians", SIMCONNECT_DATATYPE.FLOAT64, 0.0f, SimConnect.SIMCONNECT_UNUSED);
                SimConnect.AddToDataDefinition(DEFINITIONS.Struct2, "Plane heading degrees true", "radians", SIMCONNECT_DATATYPE.FLOAT64, 0.0f, SimConnect.SIMCONNECT_UNUSED);
                SimConnect.AddToDataDefinition(DEFINITIONS.Struct2, "Plane heading degrees magnetic", "radians", SIMCONNECT_DATATYPE.FLOAT64, 0.0f, SimConnect.SIMCONNECT_UNUSED);

                // IMPORTANT: register it with the SimConnect managed wrapper marshaller
                SimConnect.RegisterDataDefineStruct<Struct1>(DEFINITIONS.Struct1);
                SimConnect.RegisterDataDefineStruct<Struct2>(DEFINITIONS.Struct2);

Then after requesting like this:
C#:
if (SimConnect != null)
                {
                    while (!mQuit)
                    {
                        try
                        {
                            SimConnect.ReceiveMessage();
                            SimConnect.RequestDataOnSimObjectType(DATA_REQUESTS.REQUEST_1, DEFINITIONS.Struct1, 0, SIMCONNECT_SIMOBJECT_TYPE.USER);
                            SimConnect.RequestDataOnSimObjectType(DATA_REQUESTS.REQUEST_2, DEFINITIONS.Struct2, 0, SIMCONNECT_SIMOBJECT_TYPE.USER);
                        }
                        catch (Exception ex)
                        {
                             //This is being thrown for Struct2
                            Console.WriteLine("Exception during data request: \n" + ex.Message);
                        }

                        Thread.Sleep(500);
                    }

                    if (mQuit)
                    {
                        SimConnect.Dispose();
                        SimConnect = null;
                    }
                }

I have this:
C#:
void SimConnect_OnRecvSimObjectDataByType(SimConnect sender, SIMCONNECT_RECV_SIMOBJECT_DATA_BYTYPE data)
        {
            Console.WriteLine("Receiving data...");

            switch ((DATA_REQUESTS)data.dwRequestID)
            {
                case DATA_REQUESTS.REQUEST_1:
                    Struct1 s1 = (Struct1)data.dwData[0];

                    Console.WriteLine("title: " + s1.title);
                    Console.WriteLine("Lat:   " + s1.latitude);
                    Console.WriteLine("Lon:   " + s1.longitude);
                    Console.WriteLine("Alt:   " + s1.altitude);
                    break;

                case DATA_REQUESTS.REQUEST_2:
                    Struct2 s2 = (Struct2)data.dwData[0];

                    Console.WriteLine("Pitch:       " + s2.pitch);
                    Console.WriteLine("Bank:        " + s2.bank);
                    Console.WriteLine("Heading:     " + s2.heading);
                    Console.WriteLine("Mag Heading: " + s2.magHeading);
                    break;

                default:
                    Console.WriteLine("Unknown request ID: " + data.dwRequestID);
                    break;
            }
        }

I get the Struct1 data back, but it throws an exception "no meaningful size or offset can be computed" for Struct2. It is almost certainly relevant that I get SimConnect errors "7" and "3" (twice each) before it starts returning data. I'm not 100% sure what these mean (can't find documentation) other than making me think every "AddToDataDefinition" line is wrong.

Help!!! (please) :)

Z
 
Last edited:
Messages
112
Country
unitedkingdom
Bingo! You beauty!
(There was another error in the switch statement where I pointed at element[1], but that did the trick.)
So the [MarshallAs()] only needs to precede a string value that I'm requesting? I didn't understand what it was doing so blindly copied from the LM example - which started with a string.

Many thanks WarpD. Now I can get on with turning the values into serial messages to drive my Arduino-powered instruments.
 
Messages
108
Country
us-newmexico
Can you post the corrected code? I just tonight found the lptr zero thing that (finally) allowed me to open simconnect in console. I'm very much interested in getting events from simconnect in console to hit the serial line to my Uno...but all this events stuff is beyond me. hwndprocprefboombangouch... but you seem to have a way for the client app to FETCH data rather than waiting for event pushes... can I see it?
 
Messages
108
Country
us-newmexico
So I wrote up some code based on this and stuff by max... Everything seems to be working (no errors), but the SimConnect_OnRecv... function doesn't seem to be called. I'm guessing this is supposed to be called by oSimConnect.ReceiveMessage? I wrote some stub code just to see if it's firing...

And yeah, I used some more descriptive struct names to help me understand all this... sort of.

From Main, I call GetData (which gets to the cw without any errors, so I guess it's working.)

One small difference between mine and yours - I'm trying SimObjectData, not SimObjectDataByType... but that's all working.

Code:
public static void GetData(SimConnect oSimConnect)
        {
            oSimConnect.ReceiveMessage();
            oSimConnect.RequestDataOnSimObject(DATA_REQUESTS.REQUEST_ONE, DATA_DEFINITIONS.sWeatherValues, SimConnect.SIMCONNECT_OBJECT_ID_USER, SIMCONNECT_PERIOD.ONCE, 0, 0, 0, 0);
            Console.WriteLine("We did the request...");
            Console.ReadKey();
            //
        }
        void SimConnect_OnRecvSimObjectData(SimConnect sender, SIMCONNECT_RECV_SIMOBJECT_DATA data)
        {
            Console.Write("data.dwData is ");
            Console.WriteLine(data.dwRequestID);
            Console.ReadKey();
        }
 
Last edited:
Messages
108
Country
us-newmexico
OK, going to answer my own question here, but go ahead and leave it up in case it's useful to somebody else.
So, even though we're not doing "event handling" with forms or any kind of handle, we still need to subscribe to the delegate. This event stuff makes my head hurt, but here's what works. I modified my RegisterDefinitions method by adding a subscription line.

Code:
public static void RegisterDefinitions(SimConnect oSimConnect)
        {
            oSimConnect.RegisterDataDefineStruct<sWeatherValues>(DATA_DEFINITIONS.sWeatherValues);
            Console.WriteLine("I guess we registered a data definitinon");
            Console.ReadKey();
            Console.WriteLine("And now we will subscribe to the event handler");
            oSimConnect.OnRecvSimobjectData += new SimConnect.RecvSimobjectDataEventHandler(SimConnect_OnRecvSimobjectData);
            Console.WriteLine("Subscribed");

But wait, there's more. I found a little thing that makes sense once you do it, but is NOT explained in the docs. The SimConnect_OnRecvSimobjectData object MUST be defined as static if you want to write it that way in the subscriber. I'm guessing you could instantiate it and go from there, but I like statics for these functions that really aren't going to change or morph (not yet anyway.) So, declare the event handler like so (If I'm using the term "event handler" incorrectly, please and by all means correct me. Like I said, it makes my head hurt.



Code:
private static void SimConnect_OnRecvSimobjectData(SimConnect sender, SIMCONNECT_RECV_SIMOBJECT_DATA data)           
        {
            Console.Write("data.dwData is ");
            Console.WriteLine(data.dwRequestID);
            Console.ReadKey();
        }

You will notice I made it private, too. I'm an old VB hacker from way back when, but am still real macho about encapsulation. set/get will ensue... :)

And, here is some tasty output:

1662438609178.png
 
Messages
112
Country
unitedkingdom
Can you post the corrected code? I just tonight found the lptr zero thing that (finally) allowed me to open simconnect in console. I'm very much interested in getting events from simconnect in console to hit the serial line to my Uno...but all this events stuff is beyond me. hwndprocprefboombangouch... but you seem to have a way for the client app to FETCH data rather than waiting for event pushes... can I see it?
Sorry - been doing other things for a while now. Do you still need me to dig out the working code?
 
Messages
98
Country
us-newyork
While I was waiting, I kept searching and came across this:
https://prepar3d.com/forum/viewtopic.php?t=130820
...which in summary says "Don't try creating a console app. Doesn't work. Use a forms app."
I realize this is an old post (though not as old as me... lol). But since it bubbled up, I hope no one reading it takes this part seriously. It is most certainly possible, practical, and not unusual to have a console-based SimConnect client. In any "C variant" or other language for that matter. The article suggesting to "fake it" with a windows form app is... well... let's just say "not correct" and leave it at that. ;-)

Cheers,
-Max
 
Messages
112
Country
unitedkingdom
I'll second that. The documentation took me down an unwanted forms rabbit hole until I figured out that I was wasting my time...
 
Top