Creating a Plugin
Aim: Create a .Net plugin DLL that is dynamically loaded at application start-up.
NOTE: Mini SQL Query is now hosted as open source at http://www.codeplex.com/MiniSqlQuery.
The short how-to: Create a DLL ending with “.Plugin.dll” in the filename, implement the IPlugin interface and use 1 or more ICommand classes to perform an action within the application via a button or menu click.
Notes
I have written all plugins to target .net v2. The test projects can target higher and there is no limitation on v2 its just a choice for broad coverage.
Unzip the SDK to a sub directory of the Mini SQL Query directory (it‘s a good idea to work with a copy of the application for plugin development).
Grab a copy of the VS.NET plugin project item file (MiniSqlQuery.PlugIn.ProjectTemplate.zip) from the SDK and dump in in the right directory - probably “(my docs)\Visual Studio 2008\Templates\ProjectTemplates\Visual C#”- you will only need to do this once or when the template is updated.
Creating the PlugIn Project
This details creating a plugin using the project template. You can do the same manually if desired, its just a DLL with some references and some default files. The project template assumes that you create a new solution directory.
Create a new project calling it “MyCompany.Foo.PlugIn”. The output DLL name is what matters, not so much the namespace but keep them in sync. As long as the DLL ends with “.plugin.dll” it will get picked up. This is simply to reduce the number of files scanned at application startup.
You should see the following files created under the :
- Solution
- Project
- Loader.cs
- Form1.cs
- Commands\SampleCommand.cs
The project should reference (in addition to System etc):
- PKSoftware.MiniSqlQuery.Core.dll
- ICSharpCode.TextEditor.dll
- WeifenLuo.WinFormsUI.Docking.dll
If you build this immediately the DLL should get built in the application directory (assuming the above setup.) Run the application and it should find the DLL, there should be a new button on the toolbar and a new menu option called “Descriptive Name”. Invoking this will display the form (Form1) and will be able to see the plugin details in the about form list of loaded plugins.
Making the plugin do something
Start with the “Loader.cs” file and change the name and description as required. An instance of the loader class is created after the assembly is loaded at application start-up time. The plugin itself should not “do” anything until the “InitializePlugIn” method is called. There is an abstract helper class called “PluginLoaderBase” that should cover most situations, all you need to do is inherit from it and implement the “InitializePlugIn” method.
Note that you only need to mess around with the RequestedLoadOrder value if you are depending on 1 or more other plugins being initialized before yours (e.g. you are writing agroup of interacting plugins or relying on another core 3rd party plugin). The default is 1000, keep custom values above this.
using System;
using MyCompany.Foo.PlugIn.Commands;
using MiniSqlQuery.Core;
namespace MyCompany.Foo.PlugIn
{
public class Loader : PluginLoaderBase
{
public Loader()
: base(
"My Plugin Name",
"My Plugin Description.")
{
}
public override void InitializePlugIn()
{
Services.HostWindow.AddPluginCommand<SampleCommand>();
Services.HostWindow.AddToolStripCommand<SampleCommand>(null);
}
}
}
The above code adds “SampleCommand” to the “Plugins” menu and also to the toolbar (a null index argument just puts it on the end in no specific order). Functionality will be added to add new menus and also to allow sub-menus. Note that you can do this currently, its just a manual process.
The InitializePlugIn method is where the plugin attaches commands to menus, toolbars or context menus. A single command instance is created for the lifetime of the application from this point. If you need instance style commands, wrap them in another command to control that lifetime (i.e. a factory).
Implementing Commands
The command pattern is a good, well known way to handle separation of concerns. This in turn makes the application more extendable and easier to test because it changes how you write an application. It’s the opposite of double-clicking a control on a form and adding code to the “control_click” event handler. I call that “OO Spaghetti Coding” ;-) It’s fine in small doses or simple applications but can quickly get out of hand.
In short you need to implement the ICommand interface but there is a base class to cover most of it. Inherit from CommandBase and you can optionally supply a “SmallImage” and “ShortcutKeys” but the Name is the essential part. These values are used by the application to create menu items and buttons (e.g. the call to HostWindow.AddPluginCommand<SampleCommand>() in the PlugIn.InitializePlugIn method.
using System;
using MiniSqlQuery.Core;
using MiniSqlQuery.Core.Commands;
namespace MyCompany.Foo.PlugIn.Commands
{
public class SampleCommand : CommandBase
{
public SampleCommand()
: base("&Descriptive Name")
{
SmallImage = ImageResource.database_edit;
}
public override void Execute()
{
Form1 frm = new Form1();
frm.ShowDialog(Services.HostWindow.Instance);
}
}
}
The “Execute” method is where it all happens. This gets called each time the commands menu item or button is clicked (you can also execute the commands through code, or composite commands).
Running the plugin in Debug mode
There are two main ways to do this, attach to the Mini SQL Query application after startup, or set the project to start the application as an external program.