
Introduction
I recently needed to be able to create new document/view's that were
contained within a DLL. After an initial search on developer sites, I didn't
find any article which covered this subject. So I went ahead and tried to do it
myself.
It comes down to overriding two classes which MFC uses to create and manage
the document templates used. These are CDocManager
and
CMultiDocTemplate
(I am doing this in an MDI app).
The CDocManager
class was inherited from, to add the
functionality to open a given document type without having to display the MFC
"Select document type" dialog which is used when more than one document template
exists in the project. The CMultiDocTemplate
was inherited from and
virtual functions re-written to allow the new class to load the resources from
the DLL instance and not the EXEs.
Ok, so how do we go about doing this? First you need to create your DLL, and
add a document/view class which will be your exported document/view. Create a
class inheriting from CView
, CScrollView
or
CFormView
etc. Do the same for a class inheriting from
CDocument
. You will have to write the GetDocument()
function for the view, it's just a copy of what you see in a regular .EXE file
doc/view class but with the DLL class names.
#ifdef _DEBUG
void CDLLDocument::AssertValid() const
{
CDocument::AssertValid();
}
void CDLLDocument::Dump(CDumpContext& dc) const
{
CDocument::Dump(dc);
}
#endif
You also have to add an exported function from the DLL as follows:
CMyMultiDocTemplate* DLLNewDocTemplate()
{
CMyMultiDocTemplate *pTemplate = NULL ;
pTemplate = new CMyMultiDocTemplate(
theApp.m_hInstance,
IDR_DLL_TYPE,
RUNTIME_CLASS(CMyDLLDoc),
RUNTIME_CLASS(CChildFrame),
RUNTIME_CLASS(CMyDLLView));
return pTemplate ;
}
When you call this procedure, it returns a pointer to a
CMyMultiDocTemplate
object which can be added to the list of
available document types in your main exe's InitInstance
procedure.
Your DLL must have the following resources defined with the ID of
IDR_DLL_TYPE
:
- Menu - The menu that gets switched to when the doc/view type is open and
selected.
- Dialog - A
CFormView
dialog template if your class inherits
from CFormView
.
- String table - Document type names in the same format as the type used in a
.exe file. Example: "\nDLL\nDLL\n\n\nDLL.Document\nDLL Document".
- Icon - The icon that appears on the window's title bar
What code goes in your InitInstance?
In your app's InitInstance
, there will be some code to add the
single document template that your app will currently support. You need to do
some minor modification to this as follows:
m_pDocManager = new CMyDocManager ;
CMyMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMyMultiDocTemplate(
theApp.m_hInstance,
IDR_SOMECLASSTYPE,
RUNTIME_CLASS(CSomeClassDoc),
RUNTIME_CLASS(CChildFrame),
RUNTIME_CLASS(CSomeClassView));
AddDocTemplate(pDocTemplate);
for (int i = 0 ;i < number_of_dlls ; i++)
{
pTemplate = SomeDLL.DLLNewDocTemplate() ;
if (pTemplate != NULL)
AddDocTemplate(pDocTemplate) ;
}
You also have to modify your ExitInstance
to deal with the
inherited CMyDocManager
. If you don't do this, MFC will fail to
deallocate correctly.
Add these lines:
delete (CMyDocManager*)m_pDocManager ;
m_pDocManager = NULL ;
This must be done before the call to CWinApp::ExitInstance
and
before your DLLs are unloaded!
Ok, that's the big work out of the way. How do you open a document of these
new types? For your regular EXE doc/view type, the current mechanism will work
as normal except that you will get the MFC "select document type" dialog. If you
don't want this, change your app's OnFileNew
as follows:
((CMyDocManager*)m_pDocManager)->CreateNewDocument(0) ;
This command holds for any of the given document types that have been added.
To create the 2nd document type:
((CMyDocManager*)m_pDocManager)->CreateNewDocument(1) ;
So that's it basically. You just need to put the regular doc/view code
handling stuff in your DLL and add the .h and .cpp files to your
projects as required. You also have to export your CChildFrame
classes to your DLLs as well, to make the class accessible there.
Word of warning
Your menus could be the biggest problem after this point. If you have
standard menu options like those in the default menu displayed when no documents
are open, I recommend that you copy this menu across into your DLL as a base
menu from which to build the menu used by your new document type(s), that way
the IDs for all the original menu options will work without any problems. You
should also check for possible clashes between any new menu items you add to the
DLL menu to make sure they are not used by any in the menus used by the exe's
document.