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.
The new ActiveX DocObjects offer this new and powerful capability. They are intended for use in both Internet Explorer 3.0 and in the Office95
Binder for visually editing various file formats. The ActiveX DocObject technology uses a modified menu-sharing technique that more closely resembles the data's own standalone native editing application.
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.
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.
Most businesses maintain a lot of documentation in a variety of
formats. The cost of maintaining, updating, and distributing this information can be astronomical. The Binder delivered with Office95 gives you a way to organize your documents into a sort of three-ring binder, as the name implies. Like the Internet
Explorer, the Binder allows you to visually edit documents that are associated with DocObject-enabled applications. The ActiveX DocObject technology, both for Office95's Binder and Internet Explorer, offers some solutions to these problems. In addition, it
paves the way for better online publishing techniques that haven't
been available in the past.
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.
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.
In this section, I'll let you in on the big secretDocObjects are not really new, just their use on the Internet is new. You'll see where the DocObject concept initially evolved from, then take a look at just what the
DocObject does to make it special before getting into the sample code in the next section. The deeper explanation shows you before and after shots of DocObjects at work to illustrate how they work and what exactly the benefits are.
Originally, the DocObject technology was mentioned in the Concord specification for the next generation of OLE after OLE 2.0. I would have said
OLE 3.0, which was the unofficial name for Concord, but Microsoft decided to stop numbering the various versions of OLE to avoid confusion. It isn't uncommon for a technology leader like Microsoft to look into the next few generations of their software
years in advance of its actual introduction. That is the case with the Concord specification, in which Microsoft actually mentions the Office95 specification. Microsoft's work on the Concord specification paved the way for the Office95 Binder interfaces, presenting some of the ideas used for DocObjects.
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.
Now look at a detailed example of using Office95 DocObjects. Note that you must have Office95 and Internet Explorer 3.0 (or better)
installed. You start out with a click on a hyperlink in Internet Explorer, which references a Microsoft Word document (.doc). Microsoft Word is then activated in the context of the Internet Explorer for editing. Figure 11.4 shows Internet Explorer before
and after Word is activated in-place to illustrate how the menus are merged.
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.
In this example, you write a simple DocObject application; it's a
multidocument (MDI) application called TextView that displays text windows (the CTextView class) for keying in and editing text. The file
can be saved with the .tvi extension and read later to initialize the TextView application. In this example, you will focus only on the DocObject parts, although it can be used equally well as a standalone application, as an
OLE server, or in the Office95 Binder.
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.
There are two main interfaces in the TextView application. For a particular DocObject, or document instance, there is one IOleDocument
object, hence the name Document Object, or DocObject for short. I relate the IOleDocument object to a document, so I will usually refer to it as just "the document" from here on.
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:
Now draw yourself a BIG cup of coffee (with Scribble) and read on about the main interfaces used for this example:
IOleObject This is the main interface used by containers to communicate to all OLE objects. The only interface methods of interest to this discussion are
SetClientSite() and DoVerb().
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.
Let me begin by saying, "Thanks, Microsoft." Once again, they've made life a bit easierrelatively speaking, of course.
There is an example of the Scribble tutorial in the VC++ 4.1 sample code with the DocObject interfaces. The source for the
Scribble-DocObject sample code is in \msdev\samples\mfc\ole\bindscrb, where \msdev\ is the directory where you download VC++. Alternatively, in the VC++ PRoject Workspace window on the InfoView tab, go to Samples\MFC Samples\MFC OLE Samples\BINDSCRB:
Illustrates an MFC Document Binder.
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:
The AppWizard has done quite a bit of the work for you, and the classes you borrow from the Scribble-DocObject sample code essentially do the rest. To use this code,
copy the following files into your project directory:
Binddcmt.cpp
Binddoc.cpp
Binddoc.h
Bindipfw.cpp
Bindipfw.h
Binditem.cpp
Binditem.h
Bindview.cpp
Mfcbind.cpp
Mfcbind.h
Oleobjct.cpp
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 your classes are using the new parent classes which enable the DocObject interfaces. The next step is to use the Find in Files toolbar button and Edit | Replace commands: Replace COleServerDoc with CDocObjectServerDoc, COleServerItem with
CDocObjectServerItem, and COleIPFrameWnd with CDocObjectIPFrameWnd in all the source and header files. Use the Find In Files dialog box with each of the original class names to help find all
instances that must be changed. The only exception is the OnGetEmbeddedItem() method, which requires that you return a COleServerItem.
Now add the required #include files, as follows:
To perform the extra required DocObject
registration, edit the CTextViewApp::InitInstance() method in the TextView.cpp file and change the line
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 units
to
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 here
Change 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.
The project is now ready to run. The TextView.exe executable must run
standalone one time to perform the necessary registration. Once it has registered itself, the TextView application can be used to view its .tvi files in the context of Internet Explorer as a DocObject server.
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.
Your initial example was of an Office95 Word document displaying in the context of Internet Explorer. If you have your own data format viewer or editor, providing DocObject support can make your application much more usable. Using the techniques
outlined in this chapter will make building a DocObject application based on Visual C++ 4.1 MFC very easy. Take a look at another possible implementation to get you thinking the DocObject way.
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.
Making your application Internet and intranet aware is as easy as using the DocObject interfaces and Visual C++ 4.1 MFC classes. This can be a boon to your business by making your formats more accessible. The Office95 Binder and Internet Explorer are
just the first two areas that have applied the DocObject interfaces; more DocObject container and server applications should follow in the near future. These new applications stand to revolutionize how diverse groups of people can easily access the same
data in a standardized, efficient manner. If your business starts considering how to make use of these new interfaces now, it will undoubtedly stand to benefit considerably in the near (and far) future.
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.