Optional: Implement IPersistFile and Register as Running

You might want to add the IPersistFile interface to your document object, associate your file type (through extension or a CLSID in a compound file) with your document object's CLSID, and register a file moniker for any loaded document in the running object table. This allows controllers to access an object that represents the contents of the file instead of a new document, whether or not the document is already loaded. For example, Visual Basic supports an object-creation function that can take a filename as an argument:


Dim doc as Object
set doc = CreateObject("sample.doc")

The CreateObject function takes the filename in the argument, creates a file moniker with it, and then calls that moniker's BindToObject(IID_IDispatch) to get the IDispatch pointer for an object that has that document loaded. To support this construct, you have to support the binding action of a file moniker, as we've seen in Chapter 9. This means implementing IPersistFile right next to your document's IDispatch. Without this sort of support, you would require controllers to first create an instance of your application object, then get the documents collection, and then ask that collection to open the same file:


Dim app as Object
Dim doc as Object
set app = CreateObject("Name.Application")
set doc = app.Documents.Open("sample.doc")

Granted, this isn't much more code, but it is more confusing to the controller's user because it is much more indirect. Users like to specify their intentions as directly as possible, and getting at a document through the application ® collection ® document sequence is not as direct as asking for the document in the first place.

When you do load a document, you should create a file moniker for the name with CreateFileMoniker and register that moniker along with your document object's IUnknown in the running object table. This allows a controller to support some syntax that would allow run-time connection to a running instance. Visual Basic supports this through the GetObject function, which creates a moniker based on the arguments given to the function and checks whether that moniker is in the running object table. If so, it connects immediately. If not, it binds that moniker, which will launch your application and work with your IPersistFile interface to get the document loaded.

Of course, you might want to support binding to more than just the document as a whole, which involves composite monikers and implementations of other interfaces such as IOleItemContainer to support binding to item monikers in the composite. This is great when you have a deep hierarchy. If you have addressable objects within a document, it makes sense to allow a controller to access these objects directly, without having to navigate the hierarchy.