Overview
A moniker is simply an object that supports the IMoniker interface. IMoniker interface includes the IPersistStream interface; thus, monikers can be saved to and loaded from streams. The persistent form of a moniker contains the class identifier (CLSID) of its implementation which is used during the loading process, and so new kinds of monikers can be created transparently to clients.
The most basic operation in IMoniker interface is that of binding to the object to which it points, which is supported by IMoniker::BindToObject. This function takes as a parameter the interface identifier by which the caller wishes to talk to the object, runs whatever algorithm is necessary in order to locate the object, then returns a pointer of that interface type to the caller.1. Each moniker class can store arbitrary data [in] its persistent representation, and can run arbitrary code at binding time.
If there is an identifiable piece of persistent storage in which the object referenced by the moniker is stored, then IMoniker::BindToStorage can be used to gain access to it. Many objects have such identifiable storage, but some, such as the objects which are the ranges on a Microsoft Excel spreadsheet do not. (These ranges exist only as a part of Microsoft® Excel's data structures; they are in effect a figment of Microsoft Excel's imagination and are only reified on demand for clients.)
In most cases, a particular moniker class is designed to be one step along the path to the information source in question. These pieces can be composed together to form a moniker which represents the complete path. For example, the moniker stored inside a chart that refers to its underlying data in a spreadsheet might be a composite moniker formed from three pieces:
Figure 1. Moniker in a chart referring to a spreadsheet from which it extracts data.
This composite is itself a moniker; it just happens to be a moniker which is a sequenced collection of other monikers. The composition here is generic in that it has no knowledge of the pieces involved other than that they are monikers.
Most monikers have a textual representation which is meaningful to the user; this can be retrieved with IMoniker::GetDisplayName. The API function MkParseDisplayName goes the other direction: it can turn a textual display name into the appropriate moniker, though beware that in general this is operation is as expensive as actually binding to the object.
Monikers can compare themselves to other monikers using IMoniker::IsEqual. A hash value useful for storing monikers in lookup tables is available through IMoniker::Hash. Monikers are not a total order or even a partial order; therefore, monikers cannot be stored in tables that rely on sorting for retrieval; use hashing instead (it is inappropriate to use the display name of a moniker for sorting, since the display name may not reflect the totality of internal state of the moniker).
The earliest time after which the object to which the moniker points is known not to have changed can be obtained with IMoniker::GetTimeOfLastChange. This is not necessarily the time of last change of the object; rather, it is the best cheaply available approximation thereto.
A moniker can be asked to re-write itself into another equivalent moniker by calling IMoniker::Reduce. This function returns a new moniker that will bind to the same object, but does so in a more efficient way. This capability has several uses:
- It enables the construction of user-defined macros or aliases as new kinds of moniker classes. When reduced, the moniker to which the macro evaluates is returned.
- It enables the construction of a kind of moniker which tracks data as it moves about. When reduced, the moniker of the data in its current location is returned.
- On file systems (such as Apple® Macintosh® System 7) which support an ID-based method of accessing files, which is independent of file names, a File Moniker could be reduced to a moniker which contains one of these IDs.
Figure 2 shows a (somewhat contrived) example of moniker reduction. It illustrates the reduction of a moniker which names the net income entry for this year's report in the Projects directory of the current user's home directory.
Figure 2. Reduction of a moniker showing the objects connected to during reduction.
(Note that the particular classes of monikers used here are for illustrative purposes only.) As we can see, many monikers in this example are reduced to something completely different, and some bind to something during their reduction, but some do not. For example, to reduce the alias Home, the reduction must access the information that Home was an alias for \\server\share\fred.
The process of moniker reduction may also be tied to a global table called the Running Object Table. The Running Object Table serves as the place where monikers in the process of binding look to see if they are already running or not.
Pointers to instances of IMoniker interface can be marshaled to other processes, just as any other interface pointer can. Many monikers are of the nature that they are immutable once created and that they maintain no object state outside themselves. Item Monikers are an example of a class of such monikers. These monikers, which can be replicated at will, will usually want to support custom marshaling (see IMarshal interface) so as to simply serialize themselves and de-serialize themselves in the destination context (see IPersistStream regarding serialization). This is referred to as marshaling an object by value.