How to display a Chooser

This FAQ describes the two Chooser components available in the Library and how to use them. It also describes issues that can arise when using the ASCOM.Com.Chooser component in .NET 9 and later applications, and available mitigations.

Introduction

The Library contains two components for displaying an ASCOM Chooser dialog: ASCOM.Com.ChooserSA and ASCOM.Com.Chooser. These are functionally equivalent but differ in their compatibility and in the technology used to create them:

  • ASCOM.Com.Chooser - This is a thin .NET Standard 2.0 wrapper around the ASCOM Platform's Chooser component, which is compiled as a COM object using .NET Framework 3.5. It is compatible with projects targeting .NET Framework 4.x and .NET 5, 6, 7 and 8.

  • ASCOM.Com.ChooserSA - This is a native .NET component, which is compatible with projects targeting .NET 8 onward.

Recommendation

ASCOM.Com.ChooserSA is the recommended component if you wish to display a Chooser in a .NET 8 or later Windows Forms application.

This is because the ASCOM.Com.Chooser component has been found to cause spontaneous application terminations with run-time 0xC0000409 errors. These have been traced to Microsoft's decision to enable the Intel Control-Flow Technology security feature when compiling applications in .NET 9 and later versions.

All executables compiled in .NET 9 and later are flagged as compatible with Intel Control-Flow Enforcement Technology (CET) by default. This limits the behaviour of DLLs loaded into the application space. The .NET 3.5 compiled Chooser component falls foul of the new protections and this results in the application crashing. There is no known way to compile the ASCOM.Com.Chooser component to be compatible with CET.

In .NET 9 and later applications, two mitigation options are available:

  • Recommended: Use the ASCOM.Com.ChooserSA component instead of ASCOM.Com.Chooser, as shown below.

  • Reduced security: Add the <CETCompat>false</CETCompat> property to your .NET project's project file to disable CET.

How to display a Chooser

To display a Chooser using the ASCOM.Com.ChooserSA component, first add a reference to the ASCOM.Com.ChooserSA NuGet package to your project. Then, create an instance of the ChooserSA class, set the device type and call its Choose method with either:

  • No parameters, to display a list of available drivers

  • A string ProgID parameter, to preselect the provided ProgID in the displayed list.

The following code snippet illustrates how to display a Chooser using the ASCOM.Com.ChooserSA component in a .NET 8 or later Windows Forms application:

Displaying the stand-alone Chooser
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
using ASCOM.Com;
using ASCOM.Common;

namespace HelpExamples
{
    internal class HowtToCreateAChooserClass
    {
        internal void HowToCreateAChooser()
        {
            const string DEVICE_TYPE_NAME = "ObservingConditions";

            // Create a stand-alone Chooser instance to select a telescope driver
            ChooserSA chooserSA = new()
            {
                // Set the device type to Telescope
                DeviceType = DeviceTypes.Telescope
            };

            // Retrieve the selected telescope driver ProgID
            string selectedProgId = chooserSA.Choose("ASCOM.Simulator.Telescope");

            // Display the returned ProgID
            Console.WriteLine($"Selected Telescope ProgID: {selectedProgId}");

            // When implementing ChooserSA you may find the following .ToDeviceType() and .ToDeviceString() Library extension methods useful
            // to convert between string device type names and DeviceTypes enum values.

            // Illustrate the extension method for converting a string device type name to a DeviceTypes enum value.
            DeviceTypes deviceType = DEVICE_TYPE_NAME.ToDeviceType();
            Console.WriteLine($"The DeviceTypes enum value of the string device type name: {DEVICE_TYPE_NAME} is: {deviceType}");

            // Illustrate the extension method for converting a DeviceTypes enum value to a string device type name.
            string deviceTypeString = deviceType.ToDeviceString();
            Console.WriteLine($"The DeviceTypes enum value of the string device type name: {deviceType} is: {deviceTypeString}");

            // Wait for a key press before closing the program
            Console.ReadKey();
        }
    }
}