ASCOM LocalServer (singleton) Host

V1.0.2 Feb 2010

You have just created a local server (singleton) host for one or more ASCOM driver classes.


This project implements an ASCOM host server for one or more driver classes in a single-instance executable. It can be used to serve multiple instances of a single driver class (hub) or for providing driver services for multiple devices (e.g., Telescope and Focuser) to multiple applications. In the latter scenario, the multiple driver classes will often share one or more resources such as the serial connection and a microcontroller in the combined device. From the client's perspective, using the drivers served by the local server is exactly the same as if the drivers are loaded into the client's process space (in-proc servers).

NOTE: Unless you are prepared to handle all of the timing issues that arise when multiple clients are accessing the properties and methods of your driver(s), stop now. Just because the local server serializes the calls to your driver(s)' properties and methods does not mean that there will be no timing or concurrency issues. Local server drivers are tricky to get right. There is no such thing as "ignorance is bliss" here.

This gets even more tricky if you decide to turn your local server into a "control panel" with the main form showing all the time and itself providing controls for your device. The UI messaging loop and thread, plus timed actions to refresh your displays, plus the events generated by user actions, plus the incoming calls from clients of your drivers all can add up to a nightmare unless you have the skills and patience to get it right.

You're probably anxious to get going, but you really should read through the Theory of Operation and Detailed Use and Deployment below.

You must do the following in order to complete your local server:

  1. In the local server's project properties, Application tab, change BOTH the AssemblyName and the default namespace to ASCOM.$safeprojectname$.
  2. Add one or more driver skeleton projects using the in-proc templates. You may use either the C# or VB templates. Project name is not important (not used in ProgID) choose something like TelescopeDriver. You will be changing the substituted project name in these projects below.
  3. Build the LocalServer
  4. Set a reference to the local server project in each of the driver skeleton projects
  5. In each skeleton driver project:
    1. Do a Find In Files for the project name of the skeleton driver (e.g., TelescopeDriver) and change it to match the project name of your local server ($safeprojectname$). You don't have to do this in the ReadMe.html file. Everywhere else, however, is IMPORTANT. This sets the correct namespace, progID, etc. If you're a bit more brave, you can use Replace in Files.
    2. In project properties, Application tab, change the assembly name to ASCOM.$safeprojectname$.drivertype, (e.g., ASCOM.$safeprojectname$.Telescope).
    3. In project properties, Application tab, click Assembly Information...
      • Assure that Make assembly COM visible is on (it should aready be on).
      • Edit the Product Name to be the "friendly name" of your driver as will be shown in the Chooser.
    4. In project properties, Build tab, turn off Register for COM Interop.
    5. Modify the driver class declaration to inherit from ReferenceCountedBase. Examples:
      C#:
          public class Telescope :
              ReferenceCountedObjectBase,
              ITelescope
      VB:
          Public Class Telescope
              '==================================
              Inherits ReferenceCountedObjectBase
              Implements ITelescope
              '==================================
    6. In driver.cs/driver.vb, remove the entire ASCOM Registration region
    7. In driver.cs/driver.vb, remove the private strings for driver ID and driver description
  6. Unless you're writing a single-driver hub, you will have two or more driver types (e.g. Telescope and Focuser) and thus two or more skeleton driver assembly projects added. Presumably, these drivers need to share some resources (e.g. a single COM port via Helper.Serial). Put shared resources into the SharedResources class provided.

    A shared serial port is already provided (see SharedResources.cs) as SharedResources.SharedSerial and it is an ASCOM Helper Serial object. You may wish to define additional shared resources in static member variables with public static accessor properties as is already done for the SharedSerial. Unfortunately, if you are a Visual Basic programmer, you will have to make these additions in C#.
  7. If you are writing a hub and don't need the serial port, in SharedResources.cs you can remove the public static SharedSerial property, the m_SharedSerial member in the private data region, and the line in main that initializes it. If you don't need any other shared resources for your hub, then you can remove the SharedResources.cs file completely.
  8. If you modified the LocalServer in (6) or (7), build it again now. This will refresh the stuff that's visible to the driver skeletons.
  9. Build the driver skeletons to verify that you got all of the namespace and other variable changes in (5a).
  10. The local server dynamically loads the driver assemblies from a subdirectory called localservernameServedClasses (e.g. SuperScopeServedClasses) which must be a sub-folder of the local server executable.

    The local server is smart enough to detect that it is running in the Visual Studio IDE and look for this folder just below its solution folder in that case. It is assumed that the local server project and each served driver assembly project, are in subfolders below the solution folder.

    Once deployed, the subfolder will need to be just under the local server executable. At any rate, during development, you'll need to add a post-build task to each your driver assembly projects which puts a copy of the driver assembly into that subfolder. Here is an example:
        copy "$(TargetPath)" "..\..\..\$safeprojectname$ServedClasses\$(TargetName).dll"
    Note the quotes for possible path elements with spaces in them.
  11. IMPORTANT: With a local server based driver (or hub) it is possible for multiple clients to control the device(s). It is up to you to safeguard against abuse.
  12. You may want to add controls and/or status information to the main form frmMain of the local server. Please resist the temptation to turn the local server's main form into a graphical device control panel. Instead, make a separate application that uses the served driver(s). A driver is not a program!

Notes

  • The local server handles all of the registration and unregistration for each of its served driver classes, including the ASCOM Chooser info and the DCOM/AppID info needed for activation from TheSky. By running the server from a command line and giving /register or /unregister as the command line option, it will register or unregister all served classes (respectively). Never use REGASM on the local server executable!
  • When you make the installer for your local server based driver/hub, do not let it register the executable for COM. Instead, have it activate the installed local server with the /register option.
  • The ASCOM registration uses the driver assembly info AssemblyProduct attribute as the friendly name that will show in the chooser.

Theory of Operation

The local server is an executable which can provide multiple instances of multiple drivers to multiple clients. This capability is needed for two applications:

  • A hub, which allows multiple clients to chare a single device
  • A device which provides multiple services, such as a telescope which has a focuser built-in where both the telescope and focuser are controlled by the same serial connection and different client programs need to control to the focuser and telescope.

By simply dropping suitably developed driver assemblies into a known folder, the local server will register them for COM and ASCOM and serve any number of instances of the drivers' interfaces to any number of client programs. It does this by locating and loading the driver assemblies, analyzing them to detect their classes and interfaces, and implementing a class factory that can create instances of them for clients.

A driver is an assembly which contains a class that implements one of the ASCOM standard driver interfaces and inherits the ReferenceCountedObjectBase class of the local server. Apart from that, driver assemblies are identical to those that are used in-process (DLL-type). The instructions above detail the steps needed to convert an in-process driver into one that can be served by the local server.

The name of the local server is important, so we provide it as a template from which you can create a local server for your produce. To make this clear, let's assume that your company AlphaTech produces a telescope system which contains a microcontroller that is able to control not only the telescope mount, but also a focuser and a camera rotator. The mount, focuser, and rotator are all controlled via commands sent through a common serial line connecting the computer to the microcontroller, so you need a local server. In ASCOM, then, you probably want your system to appear as AlphaTech.Telescope, AlphaTech.Focuser, and AlphaTech.Rotator. Then you would name the local server AlphaTech. Be sure to give this due consideration before creating the template, the project name is the name of your local server.

The fact that driver classes inherit from the local server's ReferenceCountedObjectBase class allows the local server to maintain a reference count on the driver class. If a client creates an instance of a served driver, the local server automatically starts up and provides an instance of the class to the client. Once started the local server can provide additional instances of any of its served driver classes. If the reference count of all served classes drops to zero as a result of clients releasing their instances, the local server will automatically exit.

Registration services provided include not only the basic COM class registration, but also DCOM/AppID info needed to use the served classes from outbound connections from Software Bisque's TheSky. It also registers the served classes for the ASCOM Chooser. The "friendly" name of each served driver that appears in the chooser comes from the driver classes' assembly information ProductName. The COM ProgID for each served driver is ASCOM.localservername.drivertype, for example, ASCOM.AlphaTech.Telescope, where AlphaTech is the local server name and Telescope is the type of the driver. Unregistering removes all of this information from the operating system.

Detailed Use and Deployment

Once you have built your local server and the served driver class assemblies, here's how to use it. To register the served classes, activate the local server from a shell command line with the option /register (or /regserver, for VB6 compatibility):

C:\xxx> ASCOM.$safeprojectname$.exe /register

To unregister the local server and its drivers, activate the local server from a shell command line with the option /unregister (or /unregserver for VB6 compatibility):

C:\xxx> ASCOM.$safeprojectname$.exe /unregister

When the operating system starts the local server in response to a client creating one of it's served driver classes, the command option /embedding is included. The local server's code detects this and sets a variable that you can use.

NOTE: On Vista and Windows 7, registering and unregistering require elevated privileges. When the local server is run as above, an Elevation Dialog will appear, requiring the user to either approve the operation, or if the user is not an administrator, to supply administrator credentials.

When deploying a hub or set of drivers with the local server, you'll have to arrange for the driver assemblies to be placed in a subfolder under the local server called $safeprojectname$ServedClasses. That's all you need to do, though, the local server will find them.

ASCOM Initiative

logo

The ASCOM Initiative consists of a group of astronomy software developers and instrument vendors whose goals are to promote the driver/client model and scripting automation.

See the ASCOM web site for more information. Please participate in the ASCOM-Talk Yahoo Group.

 
V1.0.2 - Added logic to self-elevate privileges (with Elevation Dialog) for register and unregister operations, as required for Vista and Windows 7 User Account Control.