An Example

Imagine that we have a client that wants to maintain a list of links to objects and that the code and data for those objects are located outside the client's own code and storage so that the client maintains only a link or a name in its own storage while the real data exists elsewhere. When an end user gives a command such as View Description, this client would like to:

Let's say the client has in its list a file moniker that manages a simple filename such as C:\DATA\BOOKS\CHALICE.DOC. When the user selects View Description, the client calls IMoniker::BindToObject. The moniker, understanding that it has a filename, calls GetClassFile (as we saw in Chapter 7) to find the CLSID of the code related to this file type. The moniker then calls CoCreateInstance3 with that CLSID, requesting IPersistFile, and then passes its filename to IPersistFile::Load, bringing the file into memory. After this, the moniker calls IPersistFile::QueryInterface(IID_IDescription), returning that IDescription pointer as an out-parameter from IMoniker::BindToObject. The client then calls IDescription::GetText, which returns a string such as "Notes from January 1995 reading of The Chalice and the Blade, by Riane Eisler," which is the sort of thing I might have typed into a Summary Information comments field.

In all of what went on, the client made only two calls in order to retrieve the descriptive text: IMoniker::BindToObject to get the named object's IDescription pointer and IDescription::GetText to get the text. Nowhere did the client know that the moniker actually referred to a file-based object that contained a document. Nowhere does the client actually do any work itself to resolve the name into an interface pointer. All of that is done inside the moniker itself—that's where the intelligence lies. (Keep in mind that the file object probably has more interfaces than the ones this client happens to use. The same moniker could be used by some other client that wanted to do something different with the same object!)

Now let's say the user selects View Description for another name in the client's list. This time it's a hypothetical network connection moniker that contains the name http://www.gardens.com/bunnykins.carrotpatch!eatweeds, where the ! delimiter separates the name of the World Wide Web page from the password needed to access that page. The client, of course, doesn't know this. It simply executes the same code as before, calling IMoniker::BindToObject to get IDescription and then calling IDescription::GetText. This moniker, however, does something completely different from the file moniker we saw before, calling CoCreateInstance with a hypothetical CLSID_WWWBrowser, asking for a hypothetical IWWWPage interface pointer in return. The object here represents the connection itself so that when released it will disconnect from that page. On return from CoCreateInstance, the moniker passes the share name and password to something like IWWWPage::SetConnection, which might store that information but not actually make the connection (until something like IWWWPage::Connect is called).

The moniker then queries the connection object for IDescription and returns to the client. When that client calls IDescription::GetText, the connection object calls functions in the Win32 WinSockets API to connect to the World Wide Web page. The object then grabs the first 512 characters found on the Web page and returns that text to the client as the descriptive text. This might contain something like "Bunnykin's private garden of goodies—raptors not welcome."

It is important to see that in these examples the client, using exactly the same code, retrieved the descriptive text for radically different objects without any specific knowledge of those objects. All that knowledge is hidden in the moniker, encapsulated behind the IMoniker interface. The monikers themselves are not the objects of interest but merely symbols that wrap all the meaning and knowledge of those objects in interchangeable units. As such, monikers are extraordinarily powerful, capable of doing far more than you might think when you first work with them.

3 Moniker::BindToObject calls CoCreateInstance with CLSCTX_ALL meaning that all server types are allowable for moniker binding.