Click here to Skip to main content
15,867,568 members
Articles / Programming Languages / C#

Plugin Architecture using C#

Rate me:
Please Sign up or sign in to vote.
3.71/5 (71 votes)
3 Aug 2003CPOL2 min read 447K   16.1K   265   38
How to make plugins to work with .NET

Sample Image - Plugins.jpg

Introduction

This article demonstrates to you how to incorporate a single module, as a plugin for another application or use it as a standalone application. The article will demonstrate how a minimal change is required to obtain the above result.

Background

The basic idea for this article has been adopted from the net, I don't remember the original author, but I found the code as a console application, while what I was searching was a method to use one of my windows application module in another application and run it standalone as well with as minimal changes a possible. A little changes to the console application, and this article is what the final result looks like.

Using the code

The key to a plugin architecture is the implementation of a minimal set of methods by the plugins. These methods are used by the main (incorporating) application to find and recognize the plugins. This minimal set of method is achieved by making an interface, which would declare the methods, that are to be implemented by the plugins. This interface has been defined as follows:

C#
public interface IPlugin
{
    string Name{get;set;}
    IPluginHost Host{get;set;}
    void Show();
}

The interface define a few methods. Name is used to get the name of the plugin to be shown on the main application in the menu. IPluginHost is used to let the plugin know who is hosting the plugin. Show will show the main form of the plugin application.

We now make our first plugin in form of a windows application like this.

C#
using System;
using PlugIn;

namespace Dynamic
{
    class PlugIn : IPlugin
    {
        private string m_strName;
        private IPluginHost m_Host;
        
        public PlugIn()
        {
            m_strName = "Dynamic"; 
        }
        
        public string Name
        {
            get{return m_strName;}
            set{m_strName=value;}
        }
        
        public void Show()
        { 
            Main1 mn = new Main1();
            mn.ShowDialog();
        }

        public IPluginHost Host
        {
            get{return m_Host;}
            set
            {
                m_Host=value;
                m_Host.Register(this);
            }
        }
    }
}

public class Main1 : System.Windows.Forms.Form 
{ 
    //Your original code goes here...

    [STAThread]
    static void Main() 
    {
        Application.Run(new Main1());
    }
}

The above code declare the a plugin class so that the parent application could recognize it as a plugin. The application also declare a form class, which is the startup form.

Now compile the plugin as an executable file. Run it, it should run as a normal standalone exe. Copy the exe into the main applications executable directory, and rename it as a DLL instead of a exe.

Now we move to our main application:

for that we have to interface, which is implemented by our application so that it registers with the plugins.

C#
public interface IPluginHost
{
    bool Register(IPlugin ipi);
}

The main application is implemented as windows form.

C#
public class Form1 : System.Windows.Forms.Form, IPluginHost 
{
    private System.Windows.Forms.MainMenu mainMenu1;
    private System.Windows.Forms.MenuItem menuItem1; private IPlugin[] ipi;

    private void Form1_Load(object sender, System.EventArgs e)
    {
        string path = Application.StartupPath;
        string[] pluginFiles = Directory.GetFiles(path, "*.DLL");
        ipi = new IPlugin[pluginFiles.Length];

        for(int i= 0; i<pluginFiles.Length; i++)
        {
            string args = pluginFiles[i].Substring(
                pluginFiles[i].LastIndexOf("\\")+1,
                pluginFiles[i].IndexOf(".DLL")-
                pluginFiles[i].LastIndexOf("\\")-1);

            Type ObjType = null;
            try
            {
                // load it
                Assembly ass = null;
                ass = Assembly.Load(args);
                if (ass != null)
                {
                    ObjType = ass.GetType(args+".PlugIn");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            try
            {
                // OK Lets create the object as we have the Report Type
                if (ObjType != null)
                {
                    ipi[i] = (IPlugin)Activator.CreateInstance(ObjType);
                    ipi[i].Host = this;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }

}

In OnLoad(), we check for all the DLLs present in the application directory, and scan if any implement the plugin interface. If it does we store it and register the plugin with us. This plugin in turn calls the register method on the main application. The register method add the plugin name with out menu.

C#
public bool Register(IPlugin ipi)
{
    MenuItem mn = new MenuItem(ipi.Name,new EventHandler(NewLoad));

    Console.WriteLine("Registered: " + ipi.Name);
    menuItem1.MenuItems.Add(mn);
    return true;
}

The next time the plugin menu is click, we check for the respective plugin name and call the appropriate plugin.

C#
private void NewLoad(object sender, System.EventArgs e) {
    
    MenuItem mn = (MenuItem)sender; for(int

    i=0; i < ipi.Length; i++)
    {
        string strType = mn.Text;
        if(ipi[i]!=null)
        {
            if(ipi[i].Name==strType)
            {
                ipi[i].Show();
                break;
            }
        }
    }            
}    

Now compile and run the application, with the plugin DLL in the application path, the plugin name would show in the menu. Click the menu and the plugin pops up. Hope you find the code useful.

History

  • This is the initial release 1.0.0R.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Team Leader
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralRe: Proof read proof read proof read!!!!! Pin
justapgmr14-Jan-09 5:23
justapgmr14-Jan-09 5:23 
GeneralRe: Proof read proof read proof read!!!!! Pin
Steve_28-Jan-09 1:22
Steve_28-Jan-09 1:22 
GeneralRe: Proof read proof read proof read!!!!! Pin
Baeltazor12-Jul-09 5:04
Baeltazor12-Jul-09 5:04 
GeneralA little bit code optimization Pin
Alexander Batishchev11-Apr-06 0:13
Alexander Batishchev11-Apr-06 0:13 
GeneralRe: A little bit code optimization Pin
Alexander Batishchev11-Apr-06 12:47
Alexander Batishchev11-Apr-06 12:47 
GeneralRe: A little bit code optimization PinPopular
David30019-Dec-06 7:48
David30019-Dec-06 7:48 
GeneralRe: A little bit code optimization Pin
Alexander Batishchev3-Apr-07 4:21
Alexander Batishchev3-Apr-07 4:21 
GeneralRe: A little bit code optimization Pin
Henk Burgstra4-Aug-07 15:21
Henk Burgstra4-Aug-07 15:21 
GeneralRe: A little bit code optimization Pin
BZZR14-Nov-07 19:49
BZZR14-Nov-07 19:49 
GeneralRe: A little bit code optimization Pin
Member 20530069-Sep-09 0:30
Member 20530069-Sep-09 0:30 
Questionother directory than app path?? Pin
Badscher14-Feb-06 23:42
Badscher14-Feb-06 23:42 
AnswerRe: other directory than app path?? Pin
Alexander Batishchev12-Apr-06 1:15
Alexander Batishchev12-Apr-06 1:15 
GeneralReflection in VB2005 Pin
hrgy846-Jan-06 7:53
hrgy846-Jan-06 7:53 
It's a very good and useful article, and I adapted it for VB.NET in VS2005.

If others would use it, I share my knowledge.

I don't understand the problem correctly, but the VB can't use this code:
ObjType = ass.GetType(args+".PlugIn")
Confused | :confused:
I tested the correct version. Here:
<br />
Dim ObjType As Type = Nothing<br />
<br />
                If ass IsNot Nothing And ass.FullName.StartsWith("PEFilter.") Then<br />
                    assname = plFile.Name.Substring(0, plFile.Name.LastIndexOf(".")).Replace("PEFilter.", "")<br />
                    For Each ObjType In ass.GetTypes<br />
                        If ObjType.Name = assname Then Exit For<br />
                    Next<br />


Comments:

I get the name of assembly from the filename. And I start a search, and I stop it when i found the correct ObjType. It's dont have a very different from the directly request but it works correctly.

I hope, I can help for people, who would use the reflection.

And i very-very thanks this article for Shoki! It was a tutorial for me to use a reflection.

PS: Sorry, i dont's speak english very well... Frown | :(
GeneralSecurity concerns Pin
Biju P K17-May-05 0:13
Biju P K17-May-05 0:13 
GeneralRe: Security concerns Pin
Valer BOCAN26-Sep-05 2:44
Valer BOCAN26-Sep-05 2:44 
GeneralRe: Security concerns Pin
111vvv16-Oct-05 19:07
111vvv16-Oct-05 19:07 
GeneralRe: Security concerns Pin
Edward Moemeka8-Jun-06 7:12
Edward Moemeka8-Jun-06 7:12 
GeneralChild Forms Pin
irungu4-May-05 0:22
irungu4-May-05 0:22 
GeneralPerformance of this Plugin Architecture Pin
Member 119551211-Aug-04 1:27
Member 119551211-Aug-04 1:27 
GeneralImplemention Problem with Pocket PC application. Pin
kirankumart10-Jul-04 18:40
kirankumart10-Jul-04 18:40 
GeneralRe: Implemention Problem with Pocket PC application. Pin
Turlingdrobe12-Jun-07 0:18
Turlingdrobe12-Jun-07 0:18 
GeneralGood start, more resources here... Pin
charleswoerner28-Apr-04 11:00
charleswoerner28-Apr-04 11:00 
GeneralRe: Good start, more resources here... Pin
111vvv16-Oct-05 19:05
111vvv16-Oct-05 19:05 
GeneralNicely adapted Pin
OwenCliftonHines4-Dec-03 0:49
OwenCliftonHines4-Dec-03 0:49 
GeneralHave bug when a assemply contain an interface that defined an event Pin
Member 1649039-Sep-03 16:51
Member 1649039-Sep-03 16:51 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.