Imagine editing
a Microsoft Word document by selecting a hyperlink displayed by Internet
Explorer. After clicking on a hyperlink to a Microsoft Word document, the
document is displayed in Internet Explorer's window. The Word menus and
toolbars are displayed along with those from Internet Explorer, as shown
in Figure 11.1.

Figure 11.1. Editing a Word document in Internet Explorer.
This is known as visual editing; Word becomes activated in Internet Explorer's window. The editing functions of both applications (Word and Internet Explorer) are coexisting on the Internet completely intact.
You can benefit greatly from this type of "online" document management
and editing. It gives you a much greater maintenance capability, which
doesn't exist for most file formats. The problem of distributing your documentation
is also alleviated merely
by putting the documents on the Web.
To try this on your
own, you need Office95 and Internet Explorer 3.0; you can get the beta
version of Internet Explorer
3.0 directly from Microsoft's Web site (http://www.microsoft.com/ie
The Internet Explorer Home Page).
This chapter discusses how businesses can benefit from DocObject technology
and gives a broader understanding of what the DocObject interfaces are.
A sample DocObject OLE server, with source code, is presented to illustrate
how this new ActiveX technology works. The chapter winds up by discussing
ways ActiveX DocObject OLE servers could be used.
The source code for all this chapter's
examples can be found on this book's CD-ROM.
Using this technology allows you to manage your company's documentation
through the Internet. This is illustrated in Figure 11.2, which shows many
users accessing documents over the network.
Figure 11.2. Users accessing documents on a central HTTP server.
By using DocObjects, a business can develop better viewing and editing applications for its various data formats. They will be better because DocObjects work in the context of the binder they're embedded in. As an added bonus to your business, Internet Explorer understands how to use DocObjects. That is, all DocObject applications display in the context of their binder complete with their usual menusin this case, Internet Explorer.
For example, your business could give users of their data and documents a DocObject server. Some users, such as the author or maintenance person, could be given either write access to the document or an editing-enabled DocObject application. Other users of the information might be allowed only view access to it or given a viewing-only DocObject application.
In either case, all your business information can be made more accessible
through HTML pages with hyperlink references to the data files. When the
hyperlinks are activated, the DocObject application for that data format
will activate inside the browser. All the data format's application menus will
be merged with Internet Explorer's menus.
At present, only Internet Explorer
has integrated ActiveX DocObject technology. However, Microsoft has agreed
to provide an ActiveX plug-in for Netscape's browser in the near future.
Other applications for DocObjects will undoubtedly soon follow.
The visual editing capabilities of ActiveX DocObject technology provides users with a consistent desktop, even while surfing the Internet. The familiar menus users are already comfortable with are displayed in the context of Internet Explorer's window, requiring less training time and encouraging higher productivity, something all businesses must be concerned with.
Another advantage of the DocObject's
visual editing is that the documents can be stored in a central location.
Your business could put all its documents on a central HTTP server, with
massive data storage for speed, reliability, and centralized security.
All users and maintenance personnel could then easily access the information
stored there through their Internet Explorer browser. This is beneficial
since the information can be easily found and either edited or viewed without
moving or copying the actual files around. Figure 11.3 shows a sample configuration
of an HTTP server.

Figure
11.3. HTTP server configuration for a business intranet.
The Binder interfaces in Office95 were created to allow for the binder-container (Binder.EXE) delivered with Office95. This useful container allows you to organize various documents into the equivalent of a three-ring binderthus, the term "binder." Each of the DocObjects in the binder are embedded into distinct (OLE) storages. As the objects are activated for visual editing in the Office95 Binder, their DocObject application is activated in the context of the Office95 Binder. The menu sharing, as discussed earlier, allows the DocObject to display its entire menu along with the Office95 Binder's menu. This menu merging was originally called in-place activation in OLE 2.0 terminologyMicrosoft coined the phrase "visual editing" as a more descriptive term for in-place activation. Another reason for this choice in terminology is that the menu choice for in-place activation in an OLE 2.0 container is "Edit." You see the same kind of in-place activation, or visual editing, in Internet Explorer.
Once again, Microsoft used well-planned, well-designed, existing technology
to pave the way for the future into other areas of computing. They borrowed
the visual editing model from the Office95 Binder, which improved on the
generic in-place activation model of OLE 2.0. Now your existing OLE applications
can be retrofitted or redesigned to use the Binder-now-DocObject technology.
Adding DocObject interfaces to your application instantly turns them into
intranet/Internet applicationsa significant but inexpensive added value.
If you do, then Internet Explorer can use a hyperlinked document's application
to perform visual editing.
Microsoft has hinted
that Visual C++ 4.2 will support DocObject classes in Microsoft Foundation
Classes, so they will probably either offer a DocObject Wizard or integrate
the DocObject classes with their MFC AppWizard.

Figure
11.4. Internet Explorer before and after Word menus are merged.
Internet Explorer then looks in the registry
to see what application is associated with (.doc) Word documentsnamely
Microsoft Word (the Word.Document.6 registry key for Word 6.0). Since Microsoft
Word has registry entries indicating it supports DocObjects (the DocObject
registry key), Internet Explorer knows it can activate the document. The
Internet Explorer then uses Word's
"class id" (the CLSID registry key) to creates a Microsoft Word OLE server
object to handle the document. After the initial Microsoft Word OLE server
object creation, Internet Explorer tries to activate Word
as an ActiveX Document by querying for Word's DocObject. Microsoft Word
is then activated inside Internet Explorer's window with its usual complete
set of commands and toolbars, just as though you were running Microsoft
Word standalone. Figure 11.5 compares the menu and toolbars of Word running standalone
and activated in Internet Explorer.

Figure
11.5. Comparing Word's menus and toolbars running standalone and in
Internet Explorer.
That's the magic of Microsoft's new ActiveX DocObject technologyyour application runs in the context of the container it's activated in. This is similar to OLE's Edit verb, which equates to, in OLE 2.0 terms, "in-place activation", or "visual editing" in DocObject terminology. Another OLE verb, Open, equates to running the native application standalone.
However, there is a difference between DocObject activation and OLE's in-place activation. With OLE's in-place activation, the menu is shared with the container the object is activated in. With DocObject activation, the menu is virtually taken over by the object. Some menu sharing still occurs, but the entire native application's menus are "embedded" in the container's menu. Also, the Help menu item is shared between the two applications, with both container and DocObject applications providing submenus.
With the MFC Scribble tutorial/example from Visual C++ 4.1, Microsoft has added the DocObject interfaces (look in \msdev\samples\mfc\ole\bindscrb where \msdev is the directory where you downloaded VC++). In fact, the sample code discussed in the next section uses the code from the Scribble example as a basis for its DocObject interfaces. The Scribble application is a simple drawing tool. It lets you draw lines of various thickness and save the lines to a file as a list of strokes (the CStroke class). The saved file (.osc) may be read to initialize Scribble as a standalone application, an OLE server, or a DocObject server. The file can be used by the standalone Scribble application, it can be inserted into an OLE container, or it can be activated in the Internet Explorer from a hyperlink. The OLE container can be an OLE 2.0 container or a Binder container, such as Office95 Binder. Scribble can run by itself in its own window, as a linked or embedded OLE Object in any OLE container (Microsoft Word for example), as a DocObject in any Office95 Bindercompliant application, or as a DocObject in Internet Explorer 3.0. The following lists the running scenarios for Scribble; Figures 11.6 through 11.9 illustrate all four cases:

Figure
11.6. Scribble running standalone.

Figure
11.7. Scribble running in Word.

Figure
11.8. Scribble running in Binder.

Figure
11.9. Scribble running in Internet Explorer.
A typical application can easily be written to run in these four different ways. The real power here comes from using the MFC framework from Visual C++ 4.1; it makes building your own DocObject application very easy. Other methods are time-consuming, at best. The next section explains in more detail how to use the MFC framework to build an ActiveX Document server application.
The major features of the interfaces used are discussed first as a brief overview of how the TextView application was created and written. Next, the main interfaces are presented, introducing you to the DocObject interfaces. Following this is a presentation on the sequence of events that occur during initialization, activation and deactivation, and, finally, saving and termination. Next is the implementation details of crucial interface methods pertinent to writing a DocObject application. After all this, you can finally deal with the setup and usage instructions, followed by a few notes on testing and debugging your DocObject application.
Each document has one or more
IOleDocumentView interfaces. Each one of
these objects represents one view; each of these views is merely a different
representation of the data in the document. Perhaps the document can be
viewed with different levels of detail, like zooming in on a drawing or
looking at your town from the street and then from the rooftop. At any
rate, the different views are your DocObject's different views of its data
or document. Figure 11.10 illustrates the ActiveX Document/View architecture.

Figure
11.10. ActiveX Document/View architecture.
A good example of multiple views might be an Excel spreadsheet. One set of views of the Excel spreadsheet could be of the database with various options set, such as gridlines off and a background displayed. This would essentially just be a set of rows and columns with numbers, words, and other data in each slot. Another view may be a diagram view, or a picture of the data in the spreadsheet. For instance, the author can create a pie chart from the data in the Excel spreadsheet.
On the client sidethe containerthere is an interface called IOleDocumentSite. It's just what it sounds like: the server's "view site" within the container. This interface represents where the server's ActiveX Document will "live" in the client's application, or where the DocObject will be placed. The IOleDocumentSite isn't really used in that manner, but rather tells your DocObject application that it's supposed to act like a DocObject and not like the typical OLE 2.0 server object. This makes a difference when the container asks your ActiveX Document to activate; you can tell the container to activate with a particularfavorite or defaultview.
Most applications in the examples and tutorials from both the VC+ 4.1 samples and the ActiveX SDK samples provide only one view. If your DocObject server is an MDI application, then the implementation of the one view is fairly straightforward.. However, if you do or can have multiple views (as in the preceding Excel example), there is an IEnumOleDocumentViews interface that you can support. The client may initially ask your document for a status flag that indicates, among other things, whether your DocObject supports multiple views. The client may also ask your document to return this document view enumeration, which is essentially a standardized list interface (or enumeration) of the views you support. If your DocObject has only one view, then it returns that view and NULL for the enumeration. In the sample code for this chapter, there is only one view, so this interface isn't supported.
There are a few other important ActiveX Document interfaces. Though not required, they are important parts of the ActiveX DocObject specification. The following is a brief description of each interface:
CreateView() Returns a view object (IOleDocumentView), possibly pre-initializing it with a saved view state stored in a stream (IStream) passed in. Also the "view site" (IOleInPlaceSite) may be passed in.
Parameters
(input) IOleInPlaceSite *pIPSite
(input) IStream *pstm
(input) DWORD dwReserved
(output) IOleDocumentView **ppView
GetDocMiscStatus() Returns a status flag, duplicated in the objects registry under the "DocObject" key. The client is responsible for using this status to determine how to communicate with the DocObject. The values are listed in Table 11.1.
Parameters
(output) DWORD *pdwStatus
EnumViews() Returns either an enumeration of view objects (IEnumOleDocumentViews) if your DocObject supports multiple views, or a single-view object (IOleDocumentView) if not.
Parameters
(output) IEnumOleDocumentViews **ppEnum
(output) IOleDocumentView **ppView
IOleDocumentView Represents a single view of your document. If your DocObject supports multiple views, there is a many-to-one relationship of views to document; otherwise, it's a one-to-one relationship. According to the specification in the ActiveX SDK, "this interface provides all the necessary operations for a container to manipulate, manage, and activate a view."
SetInPlaceSite() Saves the view site's (IOleInPlaceSite) interface pointer in the container.
Parameter
(input) IOleInPlaceSite *pIPSite
GetInPlaceSite() Returns the view site's (IOleInPlaceSite) interface pointer in the container.
Parameter
(output) IOleInPlaceSite **ppIPSite
GetDocument() Returns an (IUnknown) interface pointer to the DocObject.
Parameter
(output) IUnknown **ppunk
SetRect() Sets the view's rectangle for display inside the container or client.
Parameter
(input) LPRECT prcView
GetRect() Returns the view's rectangle for display inside the container or client. An error (E_UNEXPECTED) is returned if no view rectangle has been set yet.
Parameter
(output) LPRECT prcView
SetRectComplex() Same as SetRect() with additional rectangles for vertical and horizontal scrollbars.
Parameters
(input) LPRECT prcView
(input) LPRECT prcHScroll
(input) LPRECT prcVScroll
(input) LPRECT prcSizeBox
Show() Either "Show" or "Hide." This is the same idea as OLE's "Show" and "Hide" verbs. To "Show" means to in-place activate the view without a user-interface (UI) activation and to show, or display, the view window. To "Hide" means to deactivate the user interface and hide the view.
Parameter
(input) BOOL fShow
UIActivate() Activate or deactivate the user interface. Activating involves the menu merging/sharing, setting up the toolbar and accelerators, and so forth.
Parameter
(input) BOOL fUIActivate
Open() Same as OLE's "Open" verb. Invokes the native application as a separate process or in a pop-up window.
Parameter
void; no parameters
CloseView() Close down the view by hiding the view and user interface by calling Show(FALSE) and release the view site's (IOleInPlaceSite) interface pointer in the container by calling SetInPlaceSite(NULL).
Parameter
(input) DWORD dwReserved
SaveViewState() Save view-specific data to a stream for use in reinitializing the view at a later time by ApplyViewState(). According to the DocObject specification, this interface "instructs the view to save its state into the given stream, where the state includes properties like the view type, zoom factor, insertion point, and so on."
Parameter
(input) IStream *pstm
ApplyViewState() Reinitialize the view from data in a stream previously saved by SaveViewState(). According to the DocObject specification, this interface "instructs a view to reinitialize itself according to the data in a stream that was previously written through IOleDocumentView::SaveViewState."
Parameter
(input) IStream *pstm
Clone() Create and return another view object exactly like itself.
Parameters
(input) IOleInPlaceSite *pIPSiteNew
(output) IOleDocumentView **ppViewNew
SetClientSite() This interface method is called by the container to set up the "view site" interface pointer. If the "view site" passed in has the IOleDocumentSite interface, then the server is supposed to act like a DocObject as opposed to an ordinary OLE server.
DoVerb() For an ActiveX Document server, this interface method is called by the container to allow your document to specify which view to use. This view would typically be the default or favorite view.
What is exceptional is that this sample code is built by using the AppWizard and has just added an extra parent class for DocObject interfaces. This extra level of parent classes in turn has the respective standard MFC classes you normally get from AppWizard as parent classes. In other words, they just slipped in an extra level of parent classes to enable the DocObject interfaces. Therefore, if you create an AppWizard project, all you have to do is change your classes to use these new parent classes supplied with the Scribble-DocObject sample code, instead of the standard MFC classes.
That is, the Scribble-DocObject extensions are subclasses from the classes used to create a project with the VC++ 4.1 AppWizard. When I looked at the new DocObject classes, it instantly occurred to me that they will probably be added to MFC in VC++ 4.2. The classes are meant to accommodate the DocObject/Binder interfaces that Internet Explorer 3.0 and Office95 introduce. In addition, they also seamlessly integrate with the class structure created through the AppWizard.
Whether I'm right or wrong about these classes, all I can say is that
using these subclasses made writing a DocObject application a snap! Until
VC++ 4.2 makes its long-awaited appearance, however, you're better off
using this sample code as a basis. All I had to do was change the parent
class that AppWizard sets up for you (of COleServerDoc, COleServerItem,
and COleIPFrameWnd) and make global replacements for the parent class name
in most places. The new parent classes are
CDocObjectServerDoc, CDocObjectServerItem, and
CDocObjectIPFrameWnd. The
details are explained in the following numbered stepsthe actual AppWizard
process. Figure 11.8 shows where in the class structure these classes fit,
illustrating what Microsoft has done in the Scribble-DocObject
sample code.

Figure
11.11. Scribble-DocObject MFC extensions.
To start with, bring up Visual C++, choose File | New (or Ctrl+N), and select the Project Workspace option from the New dialog box. This will bring up the New Project Workspace dialog box. Select MFC AppWizard (exe), enter the name TextView, and click the Create button to start the MFC AppWizard. The following list explains what to do for each of the six "step" dialog boxes:
Doc type name = TxView
File new name (OLE short name) = TxVw
Main frame caption = Text Viewer
Filter name = Text View Files (*.tvi)
File type name (OLE long name) = TextView Document
Now click the Close button to close the Advanced Options dialog box, then click the Next button.
Binddcmt.cpp
Binddoc.cpp
Binddoc.h
Bindipfw.cpp
Bindipfw.h
Binditem.cpp
Binditem.h
Bindview.cpp
Mfcbind.cpp
Mfcbind.h
Oleobjct.cpp
An alternative to just
copying files from the Scribble-DocObject sample code into each project
is creating a dynamic-link library or a static library (using the New Project
Workspace dialog box) from this code and using the library in multiple
projects.
To include these files in your project, choose Insert | Files into Project. . . from the menu to bring up the Insert Files into Project dialog box. Select the following files (note only the .cpp files):
Binddcmt.cpp
Binddoc.cpp
Bindipfw.cpp
Binditem.cpp
Bindview.cpp
Mfcbind.cpp
Oleobjct.cpp
Print.cpp
To change the class hierarchy so you can use these DocObject MFC classes, edit and change the parent classes as indicated in the following files:
Now add the required #include files, as follows:
#include "binddoc.h"
#include "binditem.h"
#include "bindipfw.h"
#include "mfcbind.h"
#include "binddoc.h"
#include "bindipfw.h"
#include "binddoc.h"
m_server.UpdateRegistry(OAT_INPLACE_SERVER);to
MfcBinderUpdateRegistry(pDocTemplate, OAT_INPLACE_SERVER);Modify the CTextViewSrvrItem::OnGetExtent()method in the SrvrItem.cpp file to return the correct extents by changing the line
rSize = CSize(3000, 3000); // 3000 x 3000 HIMETRIC unitsto
rSize = pDoc->GetDocSize(); CClientDC dc(NULL); // set a MM_LOENGLISH based on logical inches // (we can't use MM_LOENGLISH because MM_LOENGLISH uses physical inches) dc.SetMapMode(MM_ANISOTROPIC); dc.SetViewportExt(dc.GetDeviceCaps(LOGPIXELSX), dc.GetDeviceCaps(LOGPIXELSY)); dc.SetWindowExt(100, -100); dc.LPtoHIMETRIC(&rSize);Now add a few things to the document class (CTextViewDoc) to initialize and provide the correct size. Add the following to the TxtVwDoc.h file:
protected:
CSize m_sizeDoc;
public:
CSize GetDocSize() { return m_sizeDoc; }
protected:
void InitDocument();
The InitDocument() method has
only one line, used to initialize the document size:
m_sizeDoc = CSize(200,200);The OnOpenDocument() method should be added to the document class (CTextViewDoc) through the built-in Class Wizard; you also add a call to the InitDocument() method to set the size. Open the TxtVwDoc.cpp file, and you'll notice that it has a built-in Class Wizard on the window's title bar. Select the OnOpenDocument method from the Messages pull-down menu, and a Microsoft Developer Studio dialog box prompts you to add this method: OnOpenDocument is not handled. Do you want to add a handler? Click the Yes button, and the method is "magically" added (that's why it's called a Class Wizard!). Your cursor is placed at the following line:
// TODO: Add your specialized creation code hereChange this to a call to the following:
InitDocument();Then add a call to the InitDocument() method in the document's constructor (CTextViewDoc::CTextViewDoc()) and in the document's OnNewDocument() method.
A string must be added to the Resource file's String Table for the MfcBinderUpdateRegistry() function. Select ResourceView from the Project Workspace window, and add the BIND_IDP_FAILED_TO_AUTO_REGISTER ID with the associated string: Unable to add Binder-Compatible entries to registry.
Before you try to compile and link the code, you must add the uuid3.lib library to the "Object/library modules" field in the Link option tab on the Project Settings dialog box to get the DocObject GUIDs. Choose Build | Settings from the menu to bring up the Project Settings dialog box, then select the Link tab. After adding the uuid3.lib, click in the "Project Options" field and enter the /nodefaultlib:"LIBC" option to avoid a link error.
Now you can compile and link your project.
First, run TextView standalone, and create and save a .tvi file with some text in it. Next, create an HTML file with a hyperlink reference to the .tvi file. The HTML file contains the following line, which references your new DocObj.tvi file:
<A HREF="DocObj.tvi">Text View DocObject test</a>When you select this hyperlink in Internet Explorer, the TextView DocObject is invoked to display in-place activation in the context of Internet Explorer. Figure 11.9 shows TextView running both standalone and serving as a DocObject in Internet Explorer.

Figure
11.12. The TextView application running standalone and as a DocObject
server in Internet Explorer.
The TextView application
can also be used as an OLE server in
the Office95 Binder.
One area that I see as a good candidate, outside of Office95, is the CAD/CAM market. The various CAD/CAM formats, such as AutoCAD, MicroStation, Imagineer, and Solid Edge, to name but a few, could really benefit by providing viewer/editor DocObject applications. This would enable their viewing through Internet Explorer. Could this lead to groupware applications? Imagine providing the capability to people at remote places to view or edit data for a group design. It's evident that this market stands a lot to gain from the evolving and expanding DocObject approach.
The next two chapters deal with ISAPI extensions. Chapter 12, "Controlling the Internet Information Server Through ActiveX ISAPI Filters," discusses how your business can use ISAPI filters to help manage their Internet site. Chapter 13, "Developing Web Applications Using ISAPI Extensions," discusses the efficiency advantages of using ISAPI extensions to service CGI requests.