Re: MFC "Plug-In" Design
 
Joseph M. Newcomer wrote:
I have done this several times.  What you have to do is create virtual
methods in the superclass, and then create the subclasses that
implement them.  Note that the dialog templates would be in the .dll
file as well.
After a few days more of tinkering, it does seem to be working.
Just in case someone else is equally hard headed (about ActiveX) and 
wants to do this same thing, I'll outline what it took to make it work.
1) There is an MFC application.  It does an #include of the WidgetWindow 
base class header, and links (normal C++ compile and link) to the source 
file for that class.  This is slightly different from what I originally 
described -- having this class reside in a DLL.  I changed it to just a 
regular, static link just to remove that one extra layer of complexity.
2) The base WidgetWindow class defines the functionality that all 
WidgetWindow objects need to have.  It is derived from CDialog.  One 
important thing here is that the WidgetWindow base class DOES NOT have a 
"resource.h" and does not use any resource IDs.  Usually, a class 
derived from CDialog would have a member that looks something like this:
   enum { IDD = IDD_DIALOG1 };
Instead, this is left up to the derived class that the plug-in developer 
creates.
3) The plug-in itself is an MFC extension DLL.  It contains all its own 
resources, including the dialog.  It also #includes the WidgetWindow 
header file and links to the source.  The result here is that the 
WidgetWindow code is probably duplicated, wasting space.  I say 
"probably" because I guess it's a possiblity that the MSVC linker is 
smart enough to optimize out the duplicate copies, but it seems pretty 
unlikely.
The plug-in only needs to define two things:  A) the WidgetWindow 
derived class and b) an function called CreateWidgetWindow that is 
exported via the .DEF file and looks something like this:
  WidgetWindow *CreateWidgetWindow(CWnd *parent)
  {
    HINSTANCE h_old = AfxGetResourceHandle();
    AfxSetResourceHandle(WidgetWindowDLL.hModule);
    MyWidget *ww = new WidgetWindow;
    ww->Create(parent);
    ww->ShowWindow(SW_SHOW);
    AfxSetResourceHandle(h_old);
    return ww;
  }
There's no DoModal() there because these windows are all run modelessly.  
And I found that I couldn't omit the resource handle management, even 
though this is an extension DLL.  Without it, I saw strange behavior, 
like plug-ins loading resources from the wrong DLL.
Another thing to notice is the "new" that happens there.  It's tricky to 
know when to do the corresponding "delete."  I guess it depends on how 
your application uses these windows, but I went with a very convenient 
method that I found suggested elsewhere.  In 
WidgetWindow::PostNcDestroy, the modeless dialog can "delete this" 
safely.  It seems unusual, but it's much cleaner than building some sort 
of dialog memory manager that deletes the memory when the windows are 
closed, etc...
With all this in place, the windows can be created and destroyed freely, 
and can communicate with the application using messages, or the 
application can even directly call overloaded virtual functions of the 
Widget Window class.
Thanks for all the suggestions.