Creating The Driver

The QuickSharp platform is contained within the QuickSharp.Core.dll library assembly and the supporting docking window manager in WeifenLuo.WinFormsUI.Docking.dll. Together these provide the basic functionality required to create a Windows application. As these are both libraries they require a third component to launch the application; this is the driver program and every QuickSharp application must have one.

Loading the platform

The driver program is responsible for loading the core platform and to do so it must first define the platform startup or 'bootstrap' parameters. These define the basic behaviour of the core and provide the location of resources such as branding required to present the application to the user.

The driver is actually a simple Windows Forms application. Here is an example.

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;
using System.Reflection;
using QuickSharp.Core;

namespace QuickSharp
{
    public static class Program
    {
        [STAThread]
        public static void Main(string[] args)
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.ThreadException +=
                new ThreadExceptionEventHandler(ThreadException);

            ClientProfile profile = new ClientProfile();

            profile.ClientName = "QuickSharpApp";
            profile.ClientTitle = "QuickSharp Application";
            profile.ClientIcon = Resources.MainFormIcon;
            profile.AboutBoxImage = Resources.AboutBoxImage;
            profile.AboutBoxTextColor = Color.Black;
            profile.PersistenceKey = "QuickSharpApp";
            profile.CommandLineArgs = args;

            ApplicationManager applicationManager =
                ApplicationManager.GetInstance();

            applicationManager.ClientProfile = profile;

            try
            {
                Application.Run(new MainForm());
            }
            catch (Exception ex)
            {
                ErrorForm ef = new ErrorForm(ex, false);
                ef.ShowDialog();
            }
        }

        private static void ThreadException(object sender,
            System.Threading.ThreadExceptionEventArgs e)
        {
            ErrorForm ef = new ErrorForm(e.Exception, true);
            if (ef.ShowDialog() == DialogResult.OK)
                Application.Exit();
        }
    }
}

Aside from the normal Windows Forms initialization the driver program is required to define the application's 'ClientProfile', pass it to the 'ApplicationManager' and then instantiate the 'MainForm' through which the QuickSharp.Core platform is loaded. It also defines application-level exception handling and installs the standard platform error message box to present any errors that appear at the global level.

The client profile stores the bootstrap parameters for the application and is made available for the lifetime of the application by assigning it to a property of the application manager. The application manager manages most of the core platform's functions and is available throughout the application. It controls various subsystems such as document handling, user settings management and themes.

For more information on the members of the ApplicationManager and ClientProfile classes see the QuickSharp.Core API documentation in the SDK.

Branding

A QuickSharp application requires a number of customizable elements to be defined in order to create a unique appearance. These include the main form title text, the application and main form icon, and about box text and background graphic. Additional resources such as a help file and update checking can also be controlled by setting properties in the client profile.

The main form icon and about box background are binary resources; they can be loaded from an embedded resource file or directly from the file system, for example:

profile.ClientIcon = new Icon("MainFormIcon.ico");
profile.AboutBoxImage = Image.FromFile("AboutBackgroundImage.png");

Other important properties are the main form title text and the about box copyright text:

profile.ClientTitle = "QuickSharp Application";
profile.CopyrightText = String.Format("{0} {1}\r\n{2}\r\n{3}",
    "QuickSharp Application Version",
    Application.ProductVersion,
    "Copyright © 2011",
    "http://website.com");

The text values can be provided as literals or better still from resources. Use the assembly information attributes to set the application version:

[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

External storage

Managing user settings requires a backing store to persist data between sessions. By default a QuickSharp application will use the Windows registry and requires the name of the registry key to be provided via the client profile.

profile.PersistenceKey = "QuickSharpApp";

This defines a unique storage location for the application settings and is combined with 'HKEY_CURRENT_USER\Software' to create the full storage key: do not run a QuickSharp application without defining this key.

The ClientName profile property is used to define the location of the local application data folder used by the application. This contains user-specific content items such as templates, snippets and theme data.

Client Flags

An important aspect of the modular architecture of a QuickSharp application is that the driver program is unaware of the plugins loaded by the core. Plugins are designed to be discoverable at runtime and for any given session may or may not be present. It is desirable that there is minimal coupling between plugins; the design of QuickSharp strives to reduce the dependencies between application components wherever possible. Coding references to plugins within the driver would create unnecessary dependencies and limit the runtime flexibility of the application. A mechanism is required to allow the driver to suggest certain behaviour from plugins without explicitly requesting it.

Client flags provide this mechanism and allow arbitrary text values to be made available for reading anywhere in the application. A plugin which can respond to a particular flag will look for it when loaded and if found will modify its behaviour accordingly. If the plugin is not loaded the flag will simply be ignored.

Generally speaking flags should be defined and queried as literal text values. Using a typed constant in the driver and then having a plugin look for a flag using the same typed constant would clearly create a type dependency between them. An exception to this is in the core which is by definition always available to any plugin. The core defines client flags for the standard IDE plugins and these may be safely referenced as typed constants.

To 'raise' a flag in the driver add it to the client profile using the AddFlag() method. For example, the QuickSharp IDE hides the explorer window by default. This is achieved by setting a client flag in the driver:

profile.AddFlag(ClientFlags.ExplorerHideByDefault);

The explorer plugin 'sees' this flag when it loads and hides the explorer window. In this case the flag is defined using the ClientFlags helper class. For custom plugins new flags must be referenced literally.