Introduction
What is an Active Document? It�s a COM (Component Object Model) component that shows some data (charts, sheets, text documents, bitmaps) which is given by Active Document Server. An Active Document has to be put into an app (Container). For example, when you put a
Paintbrush bitmap into the Wordpad, the Paintbrush is an Active Document Server and the Wordpad is a Container. If you want to put an object into a Container, choose the "Insert/Object..." item from its menu. Despite being COM component, creating your own simple MFC Active Document Server doesn't need any COM knowledge.
There are two types of servers:
- Mini-server - It is compiled into exe file, but you can't execute it. You can only put it into a Container.
- Full-server - You can use it both as an Active Document Server and as an ordinary SDI or MDI application.
Of course your app can be both Full-server and Container.
Remember! Your Active Document Server has to be registrated in the Windows registry. Without it, you won't find it on "Insert object" list. Your app can register itself! You just have to execute it. If it's a Mini-server it will register itself before showing message "This server can only be run from a container application."
Creating a simple MFC Active Document Mini-Server
It isn't difficult to create your own MFC Active Document Server. AppWizard will create basic code for you! Select "New..." from "File" menu. Select "MFC AppWizard (exe)". Give a name to your project and click OK button.
Step 1: Select SDI or MDI app. I think for Mini-server SDI will be better.
Step 2: Any database support? It isn't necessary.
Step 3: It's the most important step. You can select compound document support. Container, server, active document? Anything you want! Choose "Mini-server". Select "Active document server". Think about "ActiveX Controls". Do you need it?
Step 4: Click "Advanced" button. In "Advanced Options" type the file extension. Even if your mini-server won't use files, the AppWizard wants it and won't continue without it.
Step 5: Nothing interesting!
Step 6: Select base class. It's important!
As you can see, AppWizard has created some code. It provides basic funcionallity. It will a�so register your app in the Registry (see Introduction). You can see two more classes: CInPlaceFrame
and CAppnameSrvItem
("Appname" is of course a name of your application).
Server item and metafile device context
It is very important to understand how an Active Document works. When it isn't activated, what you can see in a Container is just a drawing. You can just resize it, copy it (of course with all stored data), but it isn't interactive. To edit it, you have to double-click on it.
CAppnameSrvItem
is responsible for drawing it. It hasn't got any advanced funtions. Its most important function is OnDraw()
. It draws what you can see in a Container. It receives a pointer to the metafile device context, on which unactivated Active Document is drawn. You don't have to worry about resizeing, creating, getting windows handles... You just have to draw what you want on device context given by the Container. It's very comfortable. For example, you don't have to write separate function for printing. A Container will just print the matafile DC. Remember that CAppnameSrvItem object is created by the document class.
Take a look at the following code:
BOOL CAppnameSrvrItem::OnDraw(CDC* pDC, CSize& rSize)
{
UNREFERENCED_PARAMETER(rSize);
CFaceDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowOrg(0,0);
pDC->SetWindowExt(3000, 3000);
pDC->Ellipse(500,1000,2500,2500);
return TRUE;
}
It was created by the AppWizard (except ellipse drawing line). pDC is of course the pointer to the metafile device context. What is important, you don't draw in pixel units! You draw in a rectangle which size is 3000x3000 HIMETRIC units. If you put something (line, rectange, text, bitmap) at x=3000 it will be always at the right edge of your Acctive Document.
Take a look at this code (put it into CAppnameSrvrItem::OnDraw
function just before return TRUE;
line). In a Container it will be represented like this (normal and after resizeing):
pDC->Rectangle(500,500,2500,2000);
pDC->LineTo(1500, 1500);
Remember to create a large font, when usuing text functions (like TextOut()
).
In-place activation
And what's a View class for? I've already written that you have to double click on an Active Document to edit it. After double click the Container changes. Look at this two pictures:
The menu and the toolbar has changed. It's called In-place activation. Our app is run "inside" a Container. It has our toolbar and menu (combined with the Container's one!). The AppWizard has created the
IDR_SRVR_INPLACE
toolbar and menu (take a look at Resources in your project). The Container's menu (of course not all) is added between two separators. The rectangle in the center of the screen isn't a Server item. It's the View! You can use it just like an ordinary View class (its derived from CView
).
MFC AppWizard has created one more class: CInPlaceFrame
. What's this? Look at the second picture in this paragraph. It's responsible for creating the frame around view. To deactivete an Active Document (after In-place activation), you just have to click outside that frame.
If you use some Document's data while drawing in Server Item, after deactivating an Active Document, nothing will change in a Container. For example, if you put a chart into a Container and change some data in it (In-place, after double-click), after returning to the Container, you won't see any changes in your chart unless you will refresh the Server Item. To refresh your data, just put the following code to the Document class (for example in function that changes some data):
UpdateAllItems(NULL);
But there are some situations, when your Mini-server will be shown as an usual app. When you put the Active Document as an icon (you can choose that in "Insert Object" dialog), and you double click on it, it won't activate in-place! It will be shown in separate Window. It will have other menu and toolbar
(IDR_MAINFRAME
). Remember about it!
Storing data
And how about storing data? When you put an Active Document to an other document, you would like the Active Document data to be saved with the document data, when user choose "Save" from the Container's menu. All you have to do is to serialize data, which is stored in the Document class. The App Wizard has created the Serialize()
function.
Take a look at this example:
void CSDCDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
ar << m_someData;
ar << m_otherData;
}
else
{
ar >> m_someData;
ar >> m_otherData;
}
}
And that's all! Take a look at the examples, it will help you to understand MFC Active Document Servers. If you want to wirte to me, my email address is hepico@cz.onet.pl. Thank you!