I am implementing a plugin framework, and chse to use an interface
implementation to learn more about interfaces, but cannot figure out how to
expose my host apps menu object to the plugins it loads via an interface. I
want the plugins to be able to adjust the main menu on the host apps main
form. When I load the plugin, I want the plugin to have the oppirtunity to
access the host interface to add an item to the menu the host exposes.
Many thanks,
dion
IHost = Interface
['{7E37854E-137C-47E0-86CD-A99995A58346}']
function GetMenu: TMenu;
property Menu: TMenu read GetMenu;
end;
------------------
IStaffPlugIn = interface(ICustomPlugIn)
['{154FE4DC-617D-4ABB-A6D7-5BA55DA6AA2C}']
function Add(const AName: string): string;
end;
------------------
unit PlugInIntf;
interface
uses
Classes;
type
{ TPlugInClass }
TPlugInClass = class(TComponent);
{ TEvPlugInProc }
TPlugInProc = function(AOwner: TComponent; ForceCreate: Boolean = False):
TPlugInClass; stdcall;
{ ICustomPlugIn }
ICustomPlugIn = interface
['{DBF39F5D-C567-4E6D-987C-B228933399E4}']
function GetAuthor: string;
function GetDescription: string;
function GetVersion: string;
end;
-------------------------
unit StaffImpl;
interface
uses
PlugInIntf, StaffIntf, Classes;
type
{ TStaffPlugIn }
TStaffPlugIn = class(TPlugInClass, ICustomPlugIn, IStaffPlugIn, IHost)
<-------
private
FNameList: TStringList;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function GetAuthor: string;
function GetVersion: string;
function GetDescription: string;
function Add(const AName: string): string;
end;
> I am implementing a plugin framework, and chse to use an interface
> implementation to learn more about interfaces, but cannot figure out
> how to expose my host apps menu object to the plugins it loads via an
> interface. I want the plugins to be able to adjust the main menu on
> the host apps main form. When I load the plugin, I want the plugin to
> have the oppirtunity to access the host interface to add an item to
> the menu the host exposes.
Don't let the plugin access anything in the host directly, that is: do
not hand a TMenuitem or TMainMenu reference to the plugin. Not only may
the plugins get into a fight over who controls the menu, you would also
tie you host app to actually use a plain TMainMenu etc. to implement
the menu bar. Instead have IHost also implement a IMenuManager
interface with methods to add, delete, enable menu entries or tie a
menu entry to a TAction implemented by the plugin (by far the best
option IMO, actions are a brilliant feature of the VCL).
--
Peter Below (TeamB)
Don't be a vampire (http://slash7.com/pages/vampires),
use the newsgroup archives :
http://www.tamaracka.com/search.htm
http://groups.google.com
Thanks,
dion.
You seem to have a mental block here <g>. The interface would expose
whatever methods the plugin needs to perform its menu manipulation.
It's completely up to you. You could have one
type
IMenuManager = interface
{guid here}
procedure AddMenuActionItem(aAction: TAction);
procedure RemoveActionItem(aAction: TAction);
end;
The hosts implementation of AddMenuActionItem, for example, would
create a new TMenuItem tied to a main menu submenu reserved for the
popup menu and assign the passed Action to this menu items Action
property. RemoveActionItem would walk over the submenu to find a
TMenuitem with the action assigned and destroy it.
dion.
> Before I try and implement what Peter has just suggested, how
> would I expose the host apps main menu to a plugin, through
> an interface.
Define an Interface for the plugin to access, and then have the host
implement a class that derives from that interface. The class accesses the
menu internally. You can then pass an instance of the class to the plugin
when needed.
> Just as an example of how to use interfaces. A similar eg would do.
> What would the plugin and host declarations look like?
I suggest you have a look at the following article:
Implementing a Plug-in Framework
http://www.techvanguards.com/com/tutorials/plugin.asp
Gambit
> You may be right about the mental block. I am having difficulty
> figuring out how the plugin will have access to the host application
> through interfaces, in order to make the necessary changes to the
> menu, toolbar etc in order to allow navigation of the added
> functionality offered by the plugin.
Have you decided on a mechanims for the plugins to get the hosts IHost
interface yet? You can design this in a couple of different ways.
For plugins that are loaded explicitely by the host application (by
calling LoadPackage on every package found at a specific location or
named in a registry key, for example) you can either treat the plugins
as you would treat DLLs or you can use a framework with which the
packages would register themselves when they are loaded.
For the DLL approach you would require each plugin package to export a
simple function with a known name and prototype. The host would use
GetProcAddress on the packages module handle (you get that from
LoadPackage) to get the functions entry point and call it. The function
would return an IPlugin interface instance that is implemented by a
singleton object inside the package (created by the function if it does
not already exist). The host would store this in a list of known
packages and the interface would have methods to get the plugin package
to create whatever it has to plug in (a form, for instance, or a frame)
and the method could take the IHost interface of the host as parameter,
so the plugin has it available when needed.
In the framework approach you would have a statically loaded package
that implements a registry (a singleton object) with which each package
can register its IPlugin interface, for example. The host could
register its IHost interface with the registry in this case so the
plugins could ask the registry for it when they need it. Or you could
pass it to the registry method you call to get a specific plugin to
create its frame/form.