Matt Pietrek is the author of Windows 95 System Programming Secrets (IDG Books, 1995). He works at NuMega Technologies Inc., and can be reached at firstname.lastname@example.org.
QI noticed the Microsoft® Office for Windows® 95 installation installed a program called FASTBOOT in my startup group. Since it was put there without my permission, I took a look at it. It seems to do a small bit of OLE, then ends. What is FASTBOOT really doing, and why?
AThe short answer seems to be that FASTBOOT does nothing. But it must be there for some reason, and I think we can deduce what it tries to accomplish. Since the code certainly goes through a lot of OLE gyrations, I'll assume that you're at least passingly familiar with basic OLE concepts.
Figure 1 gives a pseudocode version of FASTBOOT, which was most likely written in C++ without MFC. Normally, programs that use OLE are written with MFC. However, since the name FASTBOOT implies that it gets things running quickly, the program shouldn't have to load and initialize the MFC framework.
In the following description I'm assuming that each API or OLE method call succeeds. However, at any point, a call could fail and FASTBOOT would handle it gracefully. All of the code is within conditional blocks that execute only if everything has gone OK so far. That's why the listing has so much indentation in it. By assuming that each API or OLE method call succeeds, I can keep the explanation relatively simple.
At the start of WinMain, FASTBOOT calls a function that registers a windows class named OleInit, then creates a window of that class. This window will be used later by some drag-and-drop related code. Interestingly, no messages are ever pumped for this window, nor does it ever appear on the screen. There's no GetMessage or PeekMessage loop anywhere in the FASTBOOT code; this is the first clue that FASTBOOT isn't your typical program. After creating the window, WinMain calls OleInitialize. Nothing too exciting here.
Next, WinMain creates a structured storage file called "c:\temp\~oleapp.doc". Within ~oleapp.doc, FASTBOOT creates a "data" stream via IStorage::CreateStream. Strangely, nothing is ever written to this stream-yet another clue that FASTBOOT is an unusual program. Once the ~oleapp.doc stream is present, WinMain calls CreateFileMoniker to create an IMoniker instance that identifies the stream.
Putting the ~oleapp.doc stream aside for a moment, WinMain continues by using GetRunningObjectTable to obtain an IRunningObjectTable interface pointer. Next, the code uses operator new to create a DropTarget object that it refers to using the IDropTarget interface. All of the IDropTarget interface methods are implemented immediately following WinMain in the FASTBOOT code.
The IDropTarget methods are very simple dummy stub functions. FASTBOOT's WinMain has three things planned for it. First, the code registers the IDropTarget pointer with the running object table via IRunningObjectTable::Register. To label the registered interface, WinMain uses the previously obtained IMoniker object that refers to ~oleapp.doc. Second, WinMain gives the IDropTarget object to CoRegisterClassObject. This theoretically makes FASTBOOT an OLE local server, ready to serve up IDropTarget objects to anybody who wants one. Third, the IDropTarget object becomes a parameter to RegisterDragDrop, which associates the window created at the beginning of WinMain with the IDropTarget object.
At this point in the FASTBOOT code, there's quite a bit of OLE cranked up. WinMain has pointers to instances of IStream, IStorage, IMoniker, IRunningObjectTable, and IDropTarget interfaces.
The rest of the WinMain code simply reverses everything that's been done so far. You heard right! WinMain calls RevokeDragDrop, follows it with a call to CoRevokeClassObject, then invokes IRunningObjectTable::Revoke. These three actions have the cumulative effect of removing the IDropTarget object from memory. The rest of WinMain includes calls to the Release methods for IRunningObjectTable, IMoniker, IStream, and IStorage, removing all these object instances from memory. WinMain calls OleUninitialize, indicating that it's finished playing with OLE, destroys the window created earlier, and unregisters the OleInit window class. So much for WinMain.
The next section of code implements a dummy IDropTarget interface. It's obvious that this IDropTarget was never intended to be used as a true drop target; all but one of the non-IUnknown methods tell the caller that they can't accept dropped data.
Two functions that deal with window classes and windows follow IDropTarget. One registers a window class and creates a window of that class, the other reverses the process. Pretty standard stuff.
The remainder of the FASTBOOT pseudocode is an elementary window procedure. The only message not handled by DefWindowProc is WM_DESTROY. Its handler simply invokes PostQuitMessage-a typical thing to do. It shouldn't be surprising that this window procedure is so simple once you remember that FASTBOOT never shows the window or pumps any messages through it (other than standard messages generated inside the CreateWindow and DestroyWindow functions).
Two places in the code warrant further discussion. The first thing that caught my eye was the call to StgCreateDocFile. FASTBOOT passes the literal Unicode string
as the first parameter. Obviously, there's going to be some sort of problem if you don't have a c:\temp directory on your system. Specifically, the StgCreateDocFile call should fail, and the rest of the code I described would be skipped. To test this, I temporarily renamed my c:\temp directory and stepped through FASTBOOT in a debugger. As I expected, FASTBOOT bailed out early. This is most likely just a coding error, as the code could easily create the ~oleapp.doc storage file in the location specified by the TEMP= environment variable.
The other anomaly in FASTBOOT is the call to CoRegisterClassObject. Usually, an application using OLE would register an IClassFactory or IClassFactory2 interface. It's hard to fathom why FASTBOOT registers an IDropTarget interface instead. After all, registering an IClassFactory interface allows client applications to create new OLE object instances, which you can't do with IDropTarget. On the other hand, this is a moot point since FASTBOOT revokes IDropTarget shortly after registering it.
So what exactly is FASTBOOT doing? I checked with several OLE experts, including Bernard McCoy (formerly of GE Fanuc), and our general impression is this: all of the OLE functions and interfaces that FASTBOOT uses are similar to those used by a typical Microsoft Office application. For instance, Word uses IStorage and IStream interfaces to create its DOC files. Likewise, Microsoft Excel registers objects with the running object table. In a sense, FASTBOOT resembles a miniature Office application that does nothing. When FASTBOOT terminates, both FASTBOOT.EXE and OLE32.DLL are unloaded from memory. However, as FASTBOOT quickly dances through its various OLE calls and interface methods, it causes various portions of the OLE DLLs to be paged in from disk (if they're not already present). Thus, at the simplest level, FASTBOOT seems to be priming the disk cache in Windows 95 or the file cache in Windows NT®.
To better understand the effect FASTBOOT has on priming OLE32.DLL, I ran the Windows NT PFMON program that comes with the Win32® SDK. PFMON monitors the number of hard and soft page faults that occur during a running process. A hard page fault is a regular page fault where the system must do things like find physical memory for the new page and possibly read the page in from a disk file. A soft fault is a page fault where Windows NT remembers that it recently had a given page of memory loaded, and that the page might still be present in physical memory. If so, the system simply moves the page back into the in-use list without much overhead. For instance, the hard disk won't be hit for a soft fault.
The first time I ran FASTBOOT, there were 16 hard page faults in OLE32.DLL and 38 soft faults. After running FASTBOOT again, there were 5 hard faults and 49 soft faults. This means 11 hard page faults were converted to soft faults. Soft faults are handled much faster than hard faults, so you can see how OLE32.DLL executes faster the second time it's used. Typically, OLE32.DLL will be used the second time when you load an Office 95 program or any other OLE-intensive application.
The fact that FASTBOOT is placed in the startup group indicates that it acts as an OLE pump primer. You can remove FASTBOOT without affecting the Office applications. If you combine the time that it takes to run FASTBOOT with the time to start up an Office program, like Word, you won't see any net decrease in load time. However, FASTBOOT takes some of the time needed to fire up OLE and tacks it onto the initial Windows boot time. The result is that, when you actually run an Office application (or any OLE-intensive application), it loads faster than if FASTBOOT hadn't already touched various portions of OLE.
Have a question about programming in Windows? You can mail it directly to Under The Hood, Microsoft Systems Journal, 825 Eighth Avenue, 18th Floor, New York, New York 10019, or send it to MSJ (re: Under The Hood) via:
From the June 1996 issue of Microsoft Systems Journal.