You have no idea how helpful your information is.
Thanks so much.
the application saying for example, AddItem, to add an item to the tree.
command items (M I right?).
Janiv Ratson.
Post by Joseph M. NewcomerSee below...
Post by Janiv RatsonThanks Joe for the great help.
I have some further questions regarding your solution.
You said that the plugin cannot handle GUI events (for example, context
menu -> remove).
You also said that the events must be translated and converted to anstract
operation.
However, I must pass concrete GUI controls to the plugin, which means that
my interface include concrete GUI controls in it. For example.
User right click on a tree control item and a context menu is poped up: how
do I make the popup menu displayed from within the specific item's plugin?.
*****
I'm a little confused about context here. A plugin should know NOTHING about the
implementation of the controls in the main application. If a right-click on the control
needs to pop up a context menu, and the plugin is providing part of the context menu, then
the main app might send a message UWM_QUERY_POPUP_ADDINS to the plugin, or call an
abstract method of the plugin superclass,
CWhateverIsTheSuperclass::QueryPopupAddins,
which causes the plugin to return, for example, a CMenu * object which is the set of items
to pop up in addition to the default behavior (if any). If one of these CMenu items is
selected, the approach would be to send a message UWM_POPUP_SELECTED with the menu ID, or
call an abstract method of the plugin superclass,
CWhateverIsTheSuperclass::PopupItemSelected passing in the item ID. You translate back
and forth between concrete implementations (maintained by the application) and abstract
queries, actions, and notifications (maintained in the plugin). Then, if you decide to
rework the app, the interface remains constant. I've done this successfully many times,
so I know it works well. So there is no reason for the plugin to have the slightest clue
as to how the application interface works. It presents options, it reacts to events, but
it doesn't actually know what invoked the operations, or how its requests or replies are
actually implemented
*****
Post by Janiv RatsonUser chooses to Remove the item using the Remove menu item: how do I enable
the plugin to handle the Remove commnad (is it necessary to handle the
remove command within the plugin, or should I handle it within my
application GUI handler?).
*****
Is the plugin supplying the actual controls? In that case, you would simply have a
reserved area of the screen with coordinates provided (I tend to do this by creating an
invisible frame control, changing its ID from IDC_STATIC to
IDC_WHATEVER_I_WANT, and
creating a CStatic frame control for it. Then, when time comes for the plugin to provide
its control, I would most likely have the plugin create a child CDialog-derived class in
the rectangle provided, and then it would handle all events within that dialog. So in my
plugin-load sequence, I'd call an abstract method of the plugin superclass, for example,
CWhateverIsTheSuperClass::InstallHere(CRect & r) where r is the
GetWindowRect/ScreenToClient transformation of the frame control. I'd make my plugin
"smart" about geometry so it could adjust its control layout (if necessary) within the
child dialog. Then the parent app doesn't even see the control notifications, which are
handled entirely within the child dialog subclass in the plugin, but if one of these
operations requires notification to the parent, a GetParent()->SendMessage can be used to
notify the parent.
Example: I have a set of plugins that provide for keyboard, musical staff, and fretted
instrument layouts. They each manage their own components of the dialog they control, and
occasionally do a GetParent()->SendMessage to notify the parent that something interesting
should happen, such as sending a note-on or note-off command, or all-notes-off, or making
a query about some aspect of the enclosing environment. If someone came to me and wanted
the image of a recorder complete with fingering options, I could write it in a couple days
and if I put it on the Web site, every existing user could download it and add it to their
app, even though we have several different versions of the app out there (they all use the
same interface to the plugins). So while the plugins manage "concrete" controls, they are
entirely self-contained and have no direct interaction with the parent (I use separate
dialogs, but the notion of embedding a child dialog in the parent is an idea I'm thinking
about for another app that we're working one which requires plugins)
*****
Post by Janiv RatsonWhether the app or the plugin handle the event, somehow the item icon should
be removed (and maybe some more changes should be made to the tree control),
hence, the plugin must accept somehow (How?) the concrete CTReeCtrl object
as a funnction parameter, which break encapsulation.
*****
Think of the abstract operations. If the tree control is owned by the application (not
the plugin, as just described above), then any operation on the tree control must be
transmitted abstractly to the plugin, and the plugin will respond with appropriate
requests (e.g., UWM_REMOVE_ICON). If a later implementation uses a different
representation, perhaps the implementation of this message changes, but the abstract
concept of removing an icon remains the same. So I don't see any reason the plugin needs
to see the CTreeCtrl, or care that it *is* a CTreeCtrl. You could consider passing an
abstract LPARAM value to the plugin, which the plugin passes back via the message (perhaps
pointing to a structure that contains it). If, this week, the LPARAM is an HTREEITEM,
fine; if next week it is something else, that's fine also. The plugin shouldn't care.
*****
Post by Janiv RatsonIf I understand it correctly, you suggest that the app GUI will update the
GUI controls (CTReeCtrl for example), and the plugin will use an abstract
interface to made the required changes.
*****
Yes.
****
Post by Janiv RatsonHowever, there might be a case in which, the plugin will need to make some
special GUI care to the control (for example, while most of the plugins will
add an icon to the tree, on an Add command, one plugin, may add an item to
the tree control which has some more sub items, and also would need to
update some other items within the tree control). I will never be able to
anticipate any GUI updates on every GUI control I have. I must let the
plugin handle the GUI controls ,on one hand, and on the other hand, I want
to keep encapsulation.
*****
If the concept is a tree of objects, then express things in terms of a tree of objects. If
this tree of objects is, this week implemented as a CTreeCtrl, fine. If next week it is
done by some other means, the plugin should not have to change. It expresses what it is
doing in terms of tree operations; someone else (the app) maps those to an implementaiton
of a CTreeCtrl
****
Post by Janiv RatsonAlso, how do I make sure that resources will not be ambiguous (dialog names,
control ids, registered event names, etc.) ?
*****
Dialog names never escape the plugin, so they doesn't matter. If you are registering
Window classes, use GUIDGEN to create a unique name, likewise for Registered Window
Messages, etc. See my essay on Message Management to see how I use GUIDs to avoid any
ambiguities in this regard. I tend to do names like
HUMAN_READABLE-{long-guid-here} so I
can tell what is going on using various tools. I would only care about the guid if
someone else invented a HUMAN_READABLE-{other-long-guid-here} for some different purpose
and I happened to be using their module in my code. Also, these are much more readable in
Spy++ than names that are based on WM_USER or WM_APP.
****
****
Post by Janiv RatsonThanks again,
Janiv Ratson.
First, ActiveX is worth thinking about here. It is ideal for supporting
plugins, and
abstracts concepts such as what kind of control vs. what kind of
operation.
You will have to design an abstract interface that says "what do I want to
do" and in the
code you implement the details of how this is done. You might use a tree
control this
week and some weird custom control next week, but the ability to create
elements and
assign icons is what you are after.
My own preference on this is to use Registered Window Messages; the
plugins with either
export methods (and be careful: you can't really export C++ methods
because of name
mangling issues, since you usually want to define an interface class and
let the plugins
derive subclasses to implement their features. I usually just send
messages to the
plugin, either via an explicit window it produces or a hidden window
created for that
purpose; these then invoke virtual methods of the parent class which the
plugin
implementor has written in a subclass).
As to how to make a plugin "handle GUI events", in effect, it cannot.
The
events have to
be translated from your GUI to the abstract operations you want the plugin
to perform.
The way to "update GUI controls" is to figure out what the abstract
interface is that your
GUI presents to the plugin (the complementary problem of the abstract
interface the plugin
presents to the application), and let the plugin send messages that ask
for operations to
be done to the GUI (such as updating a control), and the details of how
that abstraction
is implemented this week are subject to change without notice. So your
responsibility as
app designer is to make sure that in all future releases, the abstractions
you told the
plugin writers to use continue to make sense.
This is not a trivial design issue, but there is no simple "one answer
fits all" model,
either.
joe
Post by Janiv RatsonHi,
I'm writing a plug in application.
The GUI is managed in my application, and each plug in should be able to
update the GUI.
For example, I have a tree control and a list view that represent a home
network.
There are some plug ins (thay may be developed by 3rd parties) that add
their own items to the tree view and to the list view. I want them to handle
the tree update (adding their own icons, items, menu items, command handlers
etc).
I think I want to avoid creating an interface that accepts CTReeView and
CListView objects, it seems not so well designed, buy maybe this is the only
way to do it.
Anyway, I need your help on how to design my system.
How do I make the plugins (separate dllz) handle GUI events?
How do I enable plugin developers to updates the GUI control that in my
application?
How do I set the appropriate context menu to be poped up when user right
clicks on a tree item?
Thanks,
Janiv Ratson.
Joseph M. Newcomer [MVP]
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
--
NewsGuy.Com 30Gb $9.95 Carry Forward and On Demand Bandwidth
Joseph M. Newcomer [MVP]
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
--
NewsGuy.Com 30Gb $9.95 Carry Forward and On Demand Bandwidth