Building the Extensible Windows Forms Application
The final step is to create a new Windows Forms application (
MyExtensibleApp) that allows users to select a snap-in using a standard Windows Open dialog box. Set a reference to the CommonSnappableTypes.dll assembly, but
not the CSharpSnapIn.dll or Vb2005SnapIn.dll code libraries. Remember that the whole goal of this application is to make use of dynamic loading, late binding, and reflection to determine the "snappability" of external binaries created by third-party vendors.
I won't bother to discuss all the details of building the Windows Form discussed in this article. Basically though, place a MenuStrip component onto the Forms designer, and define a topmost menu item named
Tools that provides a single submenu named
Snap In Module. The Windows Form should also contain a descriptive Label for a ListBox (named
lstLoadedSnapIns) that the form uses to display the names of each snap-in loaded by the user.
Figure 1 shows the final GUI design.
 | |
| Figure 1. Sample Windows Form: The figure shows the final design of the sample application used to select and list loaded snap-ins. |
Next, be sure to update your initial C# file with
using directives for the System.Reflection and CommonSnappableTypes namespaces:
using System.Reflection;
using CommonSnappableTypes;
The code that handles the
Click event of the "Tools> Snap In Module" menu item (which you can create by double-clicking the menu item from the menu editor) displays a File Open dialog box and extracts the path to the selected file.
private void snapInModuleToolStripMenuItem_Click(
object sender, EventArgs e)
{
// Allow user to select an assembly to load.
OpenFileDialog dlg = new OpenFileDialog();
if (dlg.ShowDialog() == DialogResult.OK)
{
if (LoadExternalModule(dlg.FileName) == false)
MessageBox.Show(
"Nothing implements IAppFunctionality!");
}
}
The preceding code passes the user-selected assembly path to a helper function named
LoadExternalModule() for processing.
LoadExternalModule() inspects the selected assembly and returns
false when it is unable to find a type implementing IAppFunctionality; therefore, the
Click method handles that possibility by displaying a message to the end user.
The
LoadExternalModule() method performs the following core tasks:
- Dynamically loads the assembly into memory via the Assembly.LoadFrom() method.
- Determines if the assembly contains a type implementing IAppFunctionality by analyzing the type information for each type in the assembly.
When LoadExternalModule finds a type that implements IAppFunctionality, it calls the
DoIt() method and adds the fully qualified name of the type to the ListBox.
private bool LoadExternalModule(string path)
{
bool foundSnapIn = false;
IAppFunctionality itfAppFx = null;
Assembly theSnapInAsm = null;
try
{
// Dynamically load the selected assembly.
theSnapInAsm = Assembly.LoadFrom(path);
}
catch
{
// If any error at all takes place, just
// return false.
return false;
}
// Get all types in assembly.
Type[] theTypes = theSnapInAsm.GetTypes();
// See if the type implements IAppFunctionality.
for (int i = 0; i < theTypes.Length; i++)
{
Type t = theTypes[i].GetInterface(
"IAppFunctionality");
if (t != null)
{
foundSnapIn = true;
// Use late binding to create the type.
object o = theSnapInAsm.CreateInstance(
theTypes[i].FullName);
// Call DoIt() off the extracted interface.
itfAppFx = o as IAppFunctionality;
itfAppFx.DoIt();
lstLoadedSnapIns.Items.Add(
theTypes[i].FullName);
}
}
return foundSnapIn;
}
Note that the
for loop shown above iterates over all types in the assembly to handle the possibility that a single assembly has multiple snap-ins.