Articles   Members Online:
-Article/Tip Search
-News Group Search over 21 Million news group articles.
Member Area
-Account Center
-Top 10 NEW!!
-Submit Article/Tip
-Forums Upgraded!!
-My Articles
-Edit Information
-Become a Member
-Why sign up!
-Chat Online!
-Indexes NEW!!
-Build your resume
-Find a job
-Post a job
-Resume Search
-Link to us
Visit Embarcadero
Embarcadero Community
How to Implement Plug-Ins for Your Delphi Applications Turn on/off line numbers in source code. Switch to Orginial background IDE or DSP color Comment or reply to this aritlce/tip for discussion. Bookmark this article to my favorite article(s). Print this article
Open Tools API / IDE
Delphi 3.x
User Rating
No Votes
# Votes
DSP, Administrator
Reference URL:
			Author: Tim Sullivan

How to Implementing Plug-Ins for Your Delphi Applications


Back in January, 1999, Delphi Informant ran an article on developing plugins for 
your Delphi applications. It covered some of the basics of that plugins are, how to 
make them, exporting fucntions, and so on. I was tremendously inspired, because a 
system I was (and still am) working on could (and did!) benefit greatly from such a 

However, the layout that was described had some pretty big flaws. First, it wasn't 
really OOP. Second, it was a little hairy to pass information back and forth. 
Finally, you had to write a lot of the initialization stuff yourself. There had to 
be a better way. 

A quick overview of what a plugin is: Plugins are DLL files. They contain 
additional commands or other functionality that can add to your system. Often they 
add menu items or toolbuttons to your application. Simply the existance of a file 
can radically enhance your software. 

There was. Step 1 was to create an abstract, base class for a plugin. The plugin 
should know a bit about the application (for example, having a copy of the 
Application variable could be useful). It should know a bit about itself: how many 
"commands" it has, what the name of the plugin was, the author, etc. After some 
fuddling, this is what I came up with:

1   type
2        TuilPlugin = class(TObject)
3          private
4             FHostApplication: TApplication;
5             FFilename       : string;
6             FManager        : TComponent;
7          protected
8               { Protected declarations }
9          public
10              { Public declarations }
11            constructor Create;
12            destructor Destroy; override;
13            function GetAuthor: string; virtual; stdcall;
14            function GetDescription: string; virtual; stdcall;
15            function GetName: string; virtual; stdcall;
16            function Initialize(Manager: TComponent; HostApplication: TApplication;
17        Filename: string): Boolean; virtual; stdcall;
18            function GetNumCommands: Integer; virtual; stdcall;
19            procedure GetCommand(index: integer; var Caption, Hint, Data: string; var
20        Bitmap: HBitmap; var Event: TNotifyEvent); virtual; stdcall;
21            procedure Configure; virtual; stdcall;
23            { properties }
24            property HostApplication: TApplication read FHostApplication;
25            property Filename: string read FFilename;
26            property Manager: TComponent read FManager;
28    end;
29      { TuilPlugin }

Most of the methods and properties are self explanatory. Each plugin publishes a 
number of commands (how many is returned by GetNumCommands). To get information 
about a specific command, a call to GetCommand will give you the command's caption, 
bitmap, hint and event. Notice the stdcall after each of the methods. This is 
required by the dll in order for it to work properly. 

The second thing that needed to be done was to develop a loader component, which 
would take care of all the drudgery of creating, initializing, destroying and 
generally managing the plugins. Here's what I came up with:

30     TuilPluginManager = class(TComponent)
31       private
32            // Private declarations
33          FExtension      : string;
34          FPlugins        : TList;
35          FOnBeforeLoading: TNotifyEvent;
36          FOnAfterLoading : TNotifyEvent;
37          FOnBeforeLoad   : TuilBeforeLoadEvent;
38          FOnAfterLoad    : TuilAfterLoadEvent;
39          FOnNewCommand   : TNewCommandEvent;
40       protected
41        [...]
42         public
43            // Public declarations
44          constructor Create(AOwner: TComponent); override;
45          destructor Destroy; override;
46          procedure LoadPlugin(Filename: string); virtual;
47          procedure LoadPlugins; virtual;
48          procedure UnloadPlugin(index: integer); virtual;
49          procedure GetLoadedPlugins(PluginList: TStrings); virtual;
50          property Plugins[index: integer]: TuilPlugin read GetPlugins; default;
51      // Public
52          property PluginCount: integer read GetPluginCount;
53       published
54            // Published properties and events
55          property Extension: string read GetExtension write SetExtension;
56      // Published
57          property Version: string read GetVersion write SetVersion;
58          property OnBeforeLoading: TNotifyEvent read FOnBeforeLoading write
59      FOnBeforeLoading;
60          property OnAfterLoading: TNotifyEvent read FOnAfterLoading write
61      FOnAfterLoading;
62          property OnBeforeLoad: TuilBeforeLoadEvent read FOnBeforeLoad write
63      FOnBeforeLoad;
64          property OnAfterLoad: TuilAfterLoadEvent read FOnAfterLoad write 
65  FOnAfterLoad;
66          property OnNewCommand: TNewCommandEvent read FOnNewCommand write
67      FOnNewCommand;
69  end;
70    // TuilPluginManager

The main meat procedure here is LoadPlugin. It handles the actual loading and 
initialization of a plugin. LoadPlugins is useful as well, since it globally loads 
all the plugins in the application's folder. 

All this is well and good, but how the heck do we make our OWN plugins? Actually, 
it's really simple. 

First, you want to create a descendant of the TuilPlugin class. Include (private) 
event handlers for each of the commands you want to export.

71  type
72       TMyPlugin = class(TuilMyPlugin)
73            procedure Command1(Sender: TObject);
74            procedure Command2(Sender: TObject);
75         public
76              function GetAuthor: string; override; stdcall;
77            function GetDescription: string; override; stdcall;
78            function GetName: string; override; stdcall;
79            function Initialize(Manager: TComponent; HostApplication: TApplication;
80        Filename: string): Boolean; override; stdcall;
81            function GetNumCommands: Integer; override; stdcall;
82            procedure GetCommand(index: integer; var Caption, Hint, Data: string; var
83        Bitmap: HBitmap; var Event: TNotifyEvent); override; stdcall;
84            procedure Configure; override; stdcall;
86    end;

The two most important methods you override are GetNumCommands and GetCommand. 
GetNumCommands is easy. In this case, we've got 2 commands we're exporting:

87  function TMyPlugin.GetNumCommands: integer;
88  begin
89       Result := 2;
90  end;

GetCommand is a little trickier. You need to determine what command number you're 
getting, and return the appropriate information and event handler:
92  procedure TupSamplePlugin.GetCommand(index: integer; var Caption, Hint, Data: 
93  string;
94    var Bitmap: HBitmap; var Event: TNotifyEvent);
95  begin
96      Caption := '';
97      Event := nil;
98      case index of
99          0:
100       begin
101                    Caption := 'Command One';
102                    Hint := 'Command One';
103                    Data := '';
104                    Event := CommandOne;
105                            Bitmap := 0;
107       end;
108         1:
109       begin
110                    Caption := 'Command Two';
111                    Hint := 'Command Two';
112                    Data := '';
113                    Event := CommandTwo;
114                            Bitmap := 0;
116       end;
118   end;
119 end;

That's most of it, believe it or not. We have to export a RegisterPlugin procedure 
with our dll, and include ShareMem as the first unit in both the DLL and our 
application's .DPR files. 

Because there is so much to make sure you do (Sharemem, stdcall, RegisterPlugin, 
and so on), I put together a Wizard that would make things a lot easier. 

I've included the complete source code for the 
system, including the wizard, available for free. If you are using Delphi 3, there 
is different code which you can get by clicking 
here Feel free to play with it and let me 
know what you think. I'm hoping that we can continue to improve the system as a 
community. Comments are welcome!

Vote: How useful do you find this Article/Tip?
Bad Excellent
1 2 3 4 5 6 7 8 9 10


Share this page
Download from Google

Copyright © Mendozi Enterprises LLC