Object oriented

Method and system for referring to and binding to objects using identifier objects

5581760

Abstract

A method and system for referring to and binding to objects using a moniker object is provided. In a preferred embodiment, a moniker object contains information to identify linked source data and provides methods through which a program can bind to the linked source data. A binding method is provided that returns an instance of an interface through which the linked source data can be accessed. The moniker object can identify source data that is stored persistently or nonpersistently. In addition, moniker objects can be composed to form a composite moniker object. A composite moniker object is used to identify linked source data that is nested in other data. In a preferred embodiment, the moniker object provides other methods including a reducing method that returns a more efficient representation of the moniker object; equality and hash methods for comparing moniker objects; and inverse, common prefix, and relative-path-to methods for comparing and locating moniker objects from other moniker objects. Several implementations of a moniker object are provided including a file moniker, an item moniker, a generic composite moniker, a pointer moniker, and an anti moniker. Each implementation is a moniker class and has a class identifier that identifies code to manage the moniker class.


Claims

We claim:

1. A method in a computer system for binding to a source object, the computer system having a destination object, the method comprising the computer-implemented steps of:

instantiating a moniker object, the instantiated moniker object having a moniker class identifier that identifies binding code that, when invoked, locates and connects to the source object;

storing a reference to the source object in the instantiated moniker object as naming information, the source object associated with server code;

storing in the destination object a reference to the instantiated moniker object having the stored reference to the source object;

when the destination object is accessed,

retrieving the reference stored in the destination object to the instantiated moniker object; and

invoking the binding code identified by the moniker class identifier of the instantiated moniker object referred to by the retrieved reference;

when the binding code is invoked,

locating and invoking the server code associated with the source object referred to by the naming information of the instantiated moniker object referred to by the retrieved reference; and

requesting the server code to connect to the source object referred to by the naming information of the instantiated moniker object referred to by the retrieved reference; and

when the server code is invoked,

instantiating the source object referred to by the naming information of the instantiated moniker object referred to by the retrieved reference;

loading data into the instantiated source object; and

returning to the invoked binding code an indication of the instantiated source object with the loaded data, wherein the loaded data of the instantiated source object is accessed using the returned indication.

2. A method in a computer system of creating an object that refers to a source object, the method comprising the computer-implemented steps of:

creating an instance of an identifier object of an identifier class, the identifier class having a binding member function that, when invoked, binds to the source object by locating and accessing the source object;

storing a reference to the source object in the created identifier object as naming information that is used by the binding member function to bind to the source object; and

storing a reference to the created identifier object having the stored reference to the source object that is used when binding to the source object.

3. The method of claim 2 wherein the binding member function of the created identifier object, when invoked, binds by further instantiating the source object referred to by the naming information of the created identifier object and returning a pointer to the instantiated source object.

4. The method of claim 2, the identifier object having a reducing member function for creating a reduced identifier object that is a canonical form of the identifier object and that identifies the source object.

5. A method for binding to the source object in accordance with the method of claim 4 wherein the binding member function of the identifier object, in response to being invoked, invokes the reducing member function to create the reduced identifier object and then invokes a binding member function of the reduced identifier object to bind to the source object.

6. The method of claim 2, the identifier object having a reducing member function, wherein the reducing member function, when invoked, parses and processes, a script that, when processed, identifies the source object and creates and returns another identifier object that is a reduced form of the identifier object.

7. The method of claim 2, the identifier object having a macro that, when processed, identifies the source object and having a reducing member function that, when invoked, parses and processes the macro to create and return a reduced identifier object that is a reduced form of the identifier object and that refers to the source object.

8. The method of claim 2, the identifier object having a reducing member function that, when invoked, executes a query that, when satisfied, identifies a source object from a plurality of source objects.

9. The method of claim 2, the computer system having client code, the source object associated with server code, wherein the step of creating the instance of the identifier object is performed by executing the server code, the method further comprising the steps of:

terminating the execution of the server code after creating the instance of the identifier object; and

after terminating the execution of the server code, locating and accessing the source object by executing the binding member function of the created identifier object, wherein the binding member function launches the server code to locate and access the source object referred to by the naming information of the created identifier object.

10. A method in a computer system for composing a first identifier object with a second identifier object to create a composite identifier object that refers to a source object, the first identifier object having an internal state that refers to a container object and having a first class identifier that identifies binding code that, when invoked, locates and connects to the container object referred to by the internal state, the second identifier having an internal state that refers to an item and having a second class identifier that identifies binding code that, when invoked, locates and connects to the item referred to by the internal state, the method comprising the computer-implemented steps of:

creating an instance of a composite identifier object, the created composite identifier object having an internal state and having a composite class identifier that identifies binding code that, when invoked, locates and connects to the source object referred to by the internal state of the created composite identifier object;

storing a reference to the first identifier object in the internal state of the created composite identifier object; and

storing a reference to the second identifier object in the internal state of the created composite identifier object, wherein the second identifier object is composed with the first identifier object to refer to the item within the container object as the source object.

11. A method for binding to a source object in accordance with the method of claim 10, further comprising the steps of:

when the binding code identified by the composite class identifier is invoked, invoking the binding code identified by the second class identifier of the second identifier object passing the stored reference to the first identifier object; and

when the binding code identified by the second class identifier of the second identifier object is invoked,

invoking the binding code of the first identifier object to bind to the container object referred to by the internal state of the first identifier object;

receiving a reference to the bound container object referred to by the first identifier object; and

using the received reference to the bound container object to locate and connect to the item referred to by the internal state of the second identifier object, thereby binding to the source object referred to by the composite identifier object.

12. The method of claim 11, the binding code identified by the composite class identifier of the composite identifier object having a bind context that contains indicators to instantiated objects created in the process of binding to the source object, wherein the bind context is passed, when the binding code identified by the class identifier of the second identifier object is invoked and when the binding code identified by the class identifier of the first identifier object is invoked, to prevent unnecessary creation of already existing objects.

13. The method of claim 10, the internal state of the composite identifier object being structured in a composition sequence from left to right such that the reference to the first identifier object is conceptually to the left of the reference to the second identifier object in the composition sequence and such that the reference to the second identifier object is conceptually at the rightmost end of the composition sequence.

14. A computer system for creating an object that refers and binds to source data comprising:

means for instantiating an identifier object having a class identifier that identifies binding code; and

means for storing in the instantiated identifier object a reference to the source data as identifying data, wherein the binding code, when invoked, locates and connects to the source data referred to by the stored identifying data; and

means for storing in the instantiated identifier object a class identifier that identifies the binding code.

15. The system of claim 14, further comprising means for storing the instantiated identifier object in a persistent medium.

16. A method in a computer system for binding to source data, the method comprising the computer-implemented steps of:

creating an instance of an identifier object, the created identifier object having naming information that identifies the source data and having a class identifier that identifies binding code that, when invoked, binds by locating and connecting to the source data identified by the naming information;

invoking the binding code identified by the class identifier of the created identifier object to bind to the source data; and

when the binding code is invoked, returning an indicator of the bound source data.

17. The method of claim 16 wherein the source data is stored in a file, the source data having a data type that indicates associated server code that, when executed, manages the source data, wherein the naming information that identifies the source data is a file name, the file name indicating the data type of the source data stored within the file, and wherein the binding code identified by the class identifier of the identifier object, when executed, invokes the server code associated with the data type indicated by the file name stored as the naming information, requests the invoked server code to load the source data from the file referred to by the file name, and returns a reference to the loaded data.

18. The method of claim 16, further comprising the step of storing the created identifier object in a persistent medium.

19. A method in a computer system of generating an object that refers to source data, the computer system having a destination object, the method comprising the computer-implemented steps of:

creating an instance of a moniker object, the created moniker object having a moniker class identifier that identifies binding code that, when executed, binds to the source data;

storing a reference to the source data in the created moniker object as naming information;

storing the class identifier in the created moniker object; and

storing in the destination object a reference to the created moniker object having the stored reference to the source data.

20. The method of claim 19, further comprising the step of accessing the source data from the destination object by retrieving the reference to the created moniker object that is stored in the destination object, and invoking the binding code identified by the moniker class identifier of the created moniker object referred to by the retrieved reference to resolve the stored reference to the source data into locatable data and to locate and connect to the locatable data.

21. The method of claim 20, the source data having associated server code that, when executed, manages the source data, wherein the step of accessing the source data by invoking the binding code identified by the moniker class identifier of the created moniker object further comprises the substeps of:

locating the server code associated with the source data referred to by the naming information of the created moniker object referred to by the retrieved reference;

invoking the located server code;

requesting the invoked server code to connect to the source data referred to by the naming information; and

when the server code is invoked,

instantiating a source object;

loading the source data referred to by the naming information into the instantiated source object; and

returning an indication of the instantiated source object having the loaded source data.

22. The method of claim 20, the computer system having a computer memory and having a source object that contains the source data, the source object having server code that, when executed, manages the source object, wherein the step of accessing the source data by invoking the binding code identified by the moniker class identifier of the created moniker object further comprises the substeps of:

determining whether an instance of the source object already exists in the computer memory and whether the server code is already launched;

when it is determined that the instance of the source object already exists and the server code is already launched, obtaining an indicator to the instance of the source object; and

returning the indicator.

23. The method of claim 22 wherein the step of determining whether the instance of the source object already exists further comprises the step of determining whether an entry for the created moniker object exists in a running object table.

24. A method in a computer system of binding to source data having associated persistent storage for containing the source data, the method comprising the computer-implemented steps of:

instantiating an identifier object, the instantiated identifier object having a class identifier that identifies binding code that, when executed, binds to the source data;

storing a reference to the source data in the instantiated identifier object as naming information; and

accessing the source data by invoking the binding code identified by the class identifier of the instantiated identifier object to obtain an indicator of the persistent storage associated with the source data.

25. A method in a computer system of locating source data, the computer system having a destination object, the method comprising the computer-implemented steps of:

creating an instance of a link object, the link object having an absolute location reference for referring to the location of the source data relative to an origin location, having a relative location reference for referring to the location of the source data relative to the location of the destination object, and having a link class identifier that identifies binding code that, when executed, locates and connects to the source data; and

locating the source data by invoking the binding code identified by the link class identifier of the created link object, the binding code using one of the absolute location reference and the relative location reference to locate the source data.

26. The method of claim 25, further comprising the step of storing the link object in the destination object.

27. The method of claim 26 wherein the step of locating the source data by invoking the binding code locates the source data using the relative location reference of the stored link object when the source data and the destination object have moved to new locations but have not moved relative to each other.

28. The method of claim 25 wherein the absolute location reference is a moniker object and the relative location reference is a moniker object, each moniker object having a moniker class identifier that identifies binding code that, when executed, binds to the source data, and wherein the binding code identified by the link class identifier of the created link object invokes the binding code identified by the moniker class identifier of one of the moniker objects to locate the source data.

29. A method in a computer system of generating a reduced reference to source data, the method comprising the computer-implemented steps of:

creating an instance of a moniker object, the created moniker object having a moniker class identifier that identifies a reduce member function;

storing a reference to the source data in the created moniker object as naming information; and

reducing the stored reference to the source data to a canonical form by invoking the reduce member function, wherein the reduce member function creates a reduced moniker object, the created reduced moniker object having reduced naming information that refers, in the canonical form, to the source data referred to by the naming information of the created moniker object.

30. The method of claim 29 wherein the step of reducing the stored reference to the source data is repeated using the created reduced moniker object until no further reductions are possible.

31. The method of claim 29, further comprising the steps of:

requesting a number of times to perform the step of reducing; and

repeating, the requested number of times, the step of reducing the stored reference to the source data using the created reduced moniker object for each subsequent step of reducing.

32. The method of claim 29 wherein the stored reference to the source data contains a query that, when executed, identifies the source data and wherein the step of reducing the stored reference executes the query to create the reduced moniker object.

33. The method of claim 32, the reduced moniker object having a class identifier that identifies a binding member function that, when invoked, uses the reduced naming information to locate the source data, the moniker class identifier identifying a binding member function to locate and connect to the source data referred to by the naming information of the created moniker object, wherein the binding member function of the created moniker object, in response to being invoked, invokes the reduce member function of the created moniker object to obtain the reduced moniker object and then invokes the binding member function identified by the class identifier of the reduced moniker object to locate and connect to the source data.

34. The method of claim 29 wherein the stored reference to the source data contains a macro script that, when processed, identifies the source data and wherein the step of reducing the stored reference parses and processes the macro script to create the reduced moniker object.

35. The method of claim 34, the reduced moniker object having a class identifier that identifies a binding member function that, when invoked, uses the reduced naming information to locate the source data, the moniker class identifier identifying a binding member function to locate and connect to the source data referred to by the naming information of the created moniker object, wherein the binding member function of the created moniker object, in response to being invoked, invokes the reduce member function of the created moniker object to obtain the reduced moniker object and then invokes the binding member function identified by the class identifier of the reduced moniker object to locate and connect to the source data.

36. A method in a computer system of comparing a first object that refers to source data to a second object that refers to source data, the method comprising the computer-implemented steps of:

creating an instance of a moniker object, the created moniker object having naming information that refers to source data and having a moniker class identifier that identifies comparison code that, when executed, determines whether the moniker object is equal to another moniker object; and

invoking the comparison code, passing a requested moniker object, the requested moniker object having naming information that refers to source data, to determine whether the created moniker object is equal to the requested moniker object.

37. The method of claim 36, the moniker class identifier identifying binding code to locate and connect to the source data referred to by the naming information of the created moniker object, wherein the requested moniker object passed to the comparison code is selected from an entry in a running object table, and wherein the step of invoking the comparison code is performed by the binding code, when the binding code is executed, to determine whether the created moniker object refers to source data already referred to by the entry in the running object table.

38. The method of claim 36 wherein the comparison code determines equality based upon whether the created moniker object is a member of a set of moniker objects represented by the requested moniker object.

39. The method of claim 36, wherein the comparison code determines equality based upon whether the structure of the created moniker object naming information is equivalent to the naming information of the requested moniker object.

40. The method of claim 36 wherein the comparison code determines equality based upon when the created moniker object and the requested moniker object refer to the same source data.

41. A method in a computer system for determining a common prefix between a first identifier object and a second identifier object, the method comprising the computer-implemented steps of:

creating an instance of the first identifier object, the created first identifier object having naming information that refers to first source data;

creating an instance of the second identifier object, the created second identifier object having naming information that refers to second source data, the second identifier object having a class identifier that identifies code having a prefix determination member function that, when executed, determines a common prefix between the naming information of the created second identifier object and a requested location; and

invoking the prefix determination member function of the second identifier object, with an indicator to the naming information of the created first identifier object as the requested location, to determine a common prefix between the naming information of the created second identifier object and the naming information of the created first identifier object.

42. The method of claim 41, the first source data having a location, the second source data having a location, the naming information of the first identifier object divisible into a plurality of portions, each portion having a position and identifying a part of the location of the first source data, the naming information of the second identifier object divisible into a plurality of portions, each portion having a position and identifying a part of the location of the second source data, and wherein the step of invoking the prefix determination function member comprises the substeps of:

comparing in order, starting with a first position, each portion of the naming information of the second identifier object with the positionally corresponding portion of the naming information of the first identifier object until one portion of the naming information of the second identifier object compares unequally to the positionally corresponding portion of the naming information of the first identifier object; and

returning an indicator of the portions of the second identifier object that compare equally to the corresponding portions of the first identifier object.

43. The method of claim 42 wherein two portions compare equally only if each portion is in the identical structural position relative to the naming information to which the portion belongs.

44. The method of claim 41 wherein the prefix determination function member determines a common prefix by determining whether the naming information of the second identifier object is identical to the naming information of the first identifier object.

45. The method of claim 41 wherein the prefix determination function member determines a common prefix by determining whether the second identifier object is equal to the first identifier object.

46. The method of claim 41 wherein the naming information of the second identifier object is a path name to a file and wherein the step of determining the common prefix is accomplished by determining a portion of the path name of the naming information of the second identifier object that is equal to a portion of the naming information of the first identifier object.

47. The method of claim 41 wherein the first identifier object and the second identifier object are instances of a composite identifier object, the composite identifier object having naming information with a plurality of ordered components, each component indicating an identifier object, and wherein the step of invoking the prefix determination function member to determine a common prefix further comprises the substeps of:

comparing in order each component of the naming information of the second identifier object with the positionally corresponding component of the naming information of the first identifier object until one component of the naming information of the second identifier object compares unequally to the positionally corresponding component of the naming information of the first identifier object; and

indicating the components of the second identifier object that compare equally to the corresponding portions of the first identifier object.

48. The method of claim 47 wherein the prefix determination function member identified by the class identifier of the second identifier object has no structural knowledge of the identifier objects indicated by the components of the naming information of the second identifier object.

49. The method of claim 41, the code identified by the class identifier of the second identifier object having a relative path function member for determining a relative path to a requested identifier object, wherein the step of invoking the prefix determination function member is performed under the control of the relative path function member.

50. A computer system for binding to source data comprising:

means for generating a moniker object having naming information that identifies source data and having a class identifier that identifies a binding member function that, when executed, binds to the source data identified by the naming information and returns an indicator of the bound source data; and

means for invoking the binding member function of the moniker object.

51. A method in a computer system for binding to a source object, the computer system having a destination object, the method comprising the computer-implemented steps of:

instantiating a first moniker object of a moniker class, the moniker class identified by a moniker class identifier and having binding code that, when invoked, connects to the source object;

storing a source reference to the source object in the instantiated first moniker object as naming information, the source object associated with server code;

storing in the destination object a moniker reference to the instantiated first moniker object having the stored source reference;

storing the destination object in persistent storage including,

accessing the moniker class identifier and the naming information referred to by the moniker reference;

storing in persistent storage the accessed moniker class identifier; and

storing in persistent storage the accessed naming information;

when the destination object is accessed from persistent storage,

retrieving the stored moniker class identifier and naming information from persistent storage;

instantiating a second moniker object of the moniker class identified by the retrieved moniker class identifier;

storing the retrieved naming information in the instantiated second moniker object; and

invoking the binding code of the moniker class;

when the binding code is invoked,

invoking the server code associated with the source object referred to by the naming information stored in the second moniker object; and

requesting the server code to connect to the source object referred to by the naming information stored in the second moniker object; and

when the server code is invoked,

instantiating the source object referred to by the naming information stored in the second moniker object;

loading data into the instantiated source object; and

returning to the invoked binding code an indication of the instantiated source object with the loaded data, wherein the loaded data of the instantiated source object is accessed using the returned indication.


Description

TECHNICAL FIELD

This invention relates generally to a computer method and system for referencing objects and, more specifically, to a method and system for naming objects and binding to objects

BACKGROUND OF THE INVENTION

Current document processing computer systems allow a user to prepare compound documents. A compound document is a document that contains information in various formats. For example, a compound document may contain data in text format, chart format, numerical format, etc. FIG. 1 is an example of a compound document. In this example, the compound document 101 is generated as a report for a certain manufacturing project. The compound document 101 contains scheduling data 102, which is presented in chart format; budgeting data 103, which is presented in spreadsheet format; and explanatory data 104, which is presented in text format. In typical prior systems, a user generates the scheduling data 102 using a project management computer program and the budgeting data 103 using a spreadsheet computer program. After this data has been generated, the user creates the compound document 101, enters the explanatory data 104, and incorporates the scheduling data 102 and budgeting data 103 using a word processing computer program.

FIG. 2 shows a method for incorporating the scheduling data, budgeting data, and explanatory data into the compound document. A user generates scheduling data using the project management program 201 and then stores the data in the clipboard 203. The user also generates budgeting data using the spreadsheet program 204 and then stores the data in the clipboard 203. The clipboard 203 is an area of storage (disk or memory) that is typically accessible by any program and is used to transfer data between programs. The project management program 201 and the spreadsheet program 204 typically store the data into the clipboard in a presentation format. A presentation format is a format in which the data is easily displayed on an output device. For example, the presentation format may be a bitmap that can be displayed with a standard bitmap block transfer operation (BitBlt). The storing of data into a clipboard is referred to as "copying" to the clipboard.

After data has been copied to the clipboard 203, the user starts up the word processing program 206 to create the compound document 101. The user enters the explanatory data 104 and specifies the locations in the compound document 101 to which the scheduling data and budgeting data that are in the clipboard 203 are to be copied. The copying of data from a clipboard to a document is referred to as "pasting" from the clipboard. The word processing program 206 then copies the scheduling data 102 and the budgeting data 103 from the clipboard 203 into the compound document 101 at the specified locations. Data that is copied from the clipboard into a compound document is referred to as "embedded" data. The word processing program 206 treats the embedded data as simple bitmaps that it displays with a BitBlt operation when rendering the compound document 101 on an output device. In some prior systems, a clipboard may only be able to store data for one copy command at a time. In such a system, the scheduling data can be copied to the clipboard and then pasted into the compound document. Then, the budgeting data can be copied to the clipboard and then pasted into the compound document.

Since word processors typically process only text data, users of the word processing program can move or delete embedded data, but cannot modify embedded data, unless the data is in text format. Thus, if a user wants to modify, for example, the budgeting data 103 that is in the compound document 101, the user must start up the spreadsheet program 204, load in the budgeting data 103 from a file, make the modifications, copy the modifications to the clipboard 203, start up the word processing program 206, load in the compound document 101, and paste the modified clipboard data into the compound document 101.

Some prior systems store links to the data to be included in the compound document rather than actually embedding the data. When a word processing program pastes the data from a clipboard into a compound document, a link is stored in the compound document. The link points to the data (typically residing in a file) to be included. These prior systems typically provide links to data in a format that the word processing program recognizes or treats as presentation format. For example, when the word processing program 206 is directed by a user to paste the scheduling data and budgeting data into the compound document by linking, rather than embedding, the names of files in which the scheduling data and budgeting data reside in presentation format are inserted into the document. Several compound documents can contain links to the same data to allow one copy of the data to be shared by several compound documents.

A link is conceptually a path name to the data. Some prior systems store two-level links. A two-level link identifies both a file and an area within the file. For example, the two-level link ".backslash.BUDGET.XLS.backslash.R2C2:R7C4" identifies a spreadsheet file ".backslash.BUDGET.XLS" and the range of cells "R2C2:R7C4." The use of two-level links limits the source of the links to data that is nested one level within a file. If a file contains multiple spreadsheets, then a two-level link could identify the file and a spreadsheet, but could not identify a range within the spreadsheet. It would be desirable to have a method and system of supporting links to an arbitrary level.

Since the present invention is described below using object-oriented programming, an overview of well-known object-oriented programming techniques is provided. Two common characteristics of object-oriented programming languages are support for data encapsulation and data type inheritance. Data encapsulation refers to the binding of functions and data. Inheritance refers to the ability to declare a data type in terms of other data types.

In the C++ language, object-oriented techniques are supported through the use of classes. A class is a user-defined type. A class declaration describes the data members and function members of the class. For example, the following declaration defines data members and a function member of a class named CIRCLE.

    ______________________________________
               class CIRCLE
               {public:
               int x, y;
               int radius;
               void draw();
               };
    ______________________________________


Variables x and y specify the center location of a circle and variable radius specifies the radius of the circle. These variables are referred to as data members of the class CIRCLE. The function draw is a user-defined function that draws the circle of the specified radius at the specified location. The function draw is referred to as a function member of class CIRCLE. The data members and function members of a class are bound together in that the function operates on an instance of the class. An instance of a class is also called an object of the class.

In the syntax of C++, the following statement declares the objects a and b to be of type class CIRCLE.

CIRCLE a, b;

This declaration causes the allocation of memory for the objects a and b. The following statements assign data to the data members of objects a and b.

a.x=2;

a.y=2;

a.radius=1;

b.x=4;

b.y=5;

b.radius=2;

The following statements are used to draw the circles defined by objects a and b.

a.draw( );

b.draw( );

A derived class is a class that inherits the characteristics-data members and function members-of its base classes. For example, the following derived class CIRCLE.sub.-- FILL inherits the characteristics of the base class CIRCLE.

    ______________________________________
           class CIRCLE.sub.-- FILL:CIRCLE
           {public:
           int pattern;
           void fill();
           };
    ______________________________________


This declaration specifies that class CIRCLE.sub.-- FILL includes all the data and function members that are in class CIRCLE in addition to those data and function members introduced in the declaration of class CIRCLE.sub.-- FILL, that is, data member pattern and function member fill. In this example, class CIRCLE.sub.-- FILL has data members x, y, radius, and pattern and function members draw and fill. Class CIRCLE.sub.-- FILL is said to "inherit" the characteristics of class CIRCLE. A class that inherits the characteristics of another class is a derived class (e.g., CIRCLE.sub.-- FILL). A class that does not inherit the characteristics of another class is a primary (root) class (e.g., CIRCLE). A class whose characteristics are inherited by another class is a base class (e.g., CIRCLE is a base class of CIRCLE.sub.-- FILL). A derived class may inherit the characteristics of several classes, that is, a derived class may have several base classes. This is referred to as multiple inheritance.

A derived class may specify that a base class is to be inherited virtually. Virtual inheritance of a base class means that only one instance of the virtual base class exists in the derived class. For example, the following is an example of a derived class with two nonvirtual base classes.

class CIRCLE.sub.-- 1:CIRCLE { . . . };

class CIRCLE.sub.-- 2:CIRCLE { . . . };

class PATTERN: CIRCLE.sub.-- 1, CIRCLE.sub.-- 2 { . . . };

In this declaration class PATTERN inherits class CIRCLE twice nonvirtually through classes CIRCLE.sub.-- 1 and CIRCLE.sub.-- 2. There are two instances of class CIRCLE in class PATTERN.

The following is an example of a derived class with two virtual base classes.

class CIRCLE.sub.-- 1: virtual CIRCLE { . . . };

class CIRCLE.sub.-- 2: virtual CIRCLE { . . . };

class PATTERN: CIRCLE.sub.-- 1, CIRCLE.sub.-- 2 { . . . };

The derived class PATTERN inherits class CIRCLE twice virtually through classes CIRCLE.sub.-- 1 and CIRCLE.sub.-- 2. Since the class CIRCLE is virtually inherited twice, there is only one object of class CIRCLE in the derived class PATTERN. One skilled in the art would appreciate virtual inheritance can be very useful when the class derivation is more complex.

A class may also specify whether its function members are virtual. Declaring that a function member is virtual means that the function can be overridden by a function of the same name and type in a derived class. In the following example, the function draw is declared to be virtual in classes CIRCLE and CIRCLE.sub.-- FILL.

    ______________________________________
           class CIRCLE
           {public:
           int x, y;
           int radius;
           virtual void draw();
           };
           class CIRCLE.sub.-- FILL:CIRCLE
           {public:
           int pattern;
           virtual void draw();
           };
    ______________________________________


The C++ language provides a pointer data type. A pointer holds values that are addresses of objects in memory. Through a pointer, an object can be referenced. The following statement declares variable c.sub.-- ptr to be a pointer on an object of type class CIRCLE and sets variable c.sub.-- ptr to hold the address of object c.

CIRCLE *c.sub.-- ptr;

c.sub.-- ptr=&c;

Continuing with the example, the following statement declares object a to be of type class CIRCLE and object b to be of type class CIRCLE.sub.-- FILL.

CIRCLE a;

CIRCLE.sub.-- FILL b;

The following statement refers to the function draw as defined in class CIRCLE.

a.draw( );

Whereas, the following statement refers to the function draw defined in class CIRCLE.sub.-- FILL.

b.draw( );

Moreover, the following statements type cast object b to an object of type class CIRCLE and invoke the function draw that is defined in class CIRCLE.sub.-- FILL.

    ______________________________________
    CIRCLE *c.sub.-- ptr;
    c.sub.13  = &b;
    c.sub.13 - > draw();
                    // CIRCLE.sub.-- FILL::draw()
    ______________________________________


Thus, the virtual function that is called is function CIRCLE.sub.-- FILL::draw.

FIG. 3 is a block diagram illustrating typical data structures used to represent an object. An object is composed of instance data (data members) and member functions, which implement the behavior of the object. The data structures used to represent an object comprise instance data structure 301, virtual function table 302, and the function members 303, 304, 305. The instance data structure 301 contains a pointer to the virtual function table 302 and contains data members. The virtual function table 302 contains an entry for each virtual function member defined for the object. Each entry contains a reference to the code that implements the corresponding function member. The layout of this sample object conforms to the model defined in U.S. patent application Ser. No. 07/682,537, entitled "A Method for Implementing Virtual Functions and Virtual Bases in a Compiler for an Object Oriented Programming Language," which is hereby incorporated by reference. In the following, an object will be described as an instance of a class as defined by the C++ programming language. One skilled in the art would appreciate that objects can be defined using other programming languages.

An advantage of using object-oriented techniques is that these techniques can be used to facilitate the sharing of objects. In particular, object-oriented techniques facilitate the creation of compound documents. A compound document (as described above) is a document that contains objects generated by various computer programs. (Typically, only the data members of the object and the class type are stored in a compound document.) For example, a word processing document that contains a spreadsheet object generated by a spreadsheet program is a compound document. A word processing program allows a user to embed a spreadsheet object (e.g., a cell) within a word processing document. To allow this embedding, the word processing program is compiled using the class definition of the object to be embedded to access function members of the embedded object. Thus, the word processing program would need to be compiled using the class definition of each class of objects that can be embedded in a word processing document. To embed an object of a new class into a word processing document, the word processing program would need to be recompiled with the new class definition. Thus, only objects of classes selected by the developer of the word processing program can be embedded. Furthermore, new classes can only be supported with a new release of the word processing program.

To allow objects of an arbitrary class to be embedded into compound documents, interfaces are defined through which an object can be accessed without the need for the word processing program to have access to the class definitions at compile time. An abstract class is a class in which a virtual function member has no implementation (pure). An interface is an abstract class with no data members and whose virtual functions are all pure.

The following class definition is an example definition of an interface. In this example, for simplicity of explanation, rather than allowing any class of object to be embedded in its documents, a word processing program allows spreadsheet objects to be embedded. Any spreadsheet object that provides this interface can be embedded, regardless of how the object is implemented. Moreover, any spreadsheet object, whether implemented before or after the word processing program is compiled, can be embedded.

    ______________________________________
    class ISpreadSheet
    {virtual void File() = 0;
    virtual void Edit() = 0;
    virtual void Formula() = 0;
    virtual void Format() = 0;
    virtual void GetCell (string RC, cell *pCell) = 0;
    virtual void Data() = 0;
    ______________________________________


The developer of a spreadsheet program would need to provide an implementation of the interface to allow the spreadsheet objects to be embedded in a word processing document. When the word processing program embeds a spreadsheet object, the program needs access to the code that implements the interface for the spreadsheet object. To access the code, each implementation is given a unique class identifier. For example, a spreadsheet object developed by Microsoft Corporation may have a class identifier of "MSSpreadsheet," while a spreadsheet object developed by another corporation may have a class identifier of "LTSSpreadsheet." A persistent registry in each computer system is maintained that maps each class identifier to the code that implements the class. Typically, when a spreadsheet program is installed on a computer system, the persistent registry is updated to reflect the availability of that class of spreadsheet objects. So long as a spreadsheet developer implements each function member defined by the interface and the persistent registry is maintained, the word processing program can embed the developer's spreadsheet objects into a word processing document.

Various spreadsheet developers may wish, however, to implement only certain function members. For example, a spreadsheet developer may not want to implement database support, but may want to support all other function members. To allow a spreadsheet developer to support only some of the function members, while still allowing the objects to be embedded, multiple interfaces for spreadsheet objects are defined. For example, the interfaces IDatabase and IBasic may be defined for a spreadsheet object as follows.

    ______________________________________
    class IBasic
    {virtual void File() = 0;
    virtual void Edit() = 0;
    virtual void Formula() = 0;
    virtual void Format() = 0;
    virtual void GetCell (string RC, cell *pCell) = 0;
    class IDatabase
    {virtual void Data() = 0;
    }
    ______________________________________


Each spreadsheet developer would implement the IBasic interface and, optionally, the IDatabase interface.

At run time, the word processing program would need to determine whether a spreadsheet object to be embedded supports the IDatabase interface. To make this determination, another interface is defined (that every spreadsheet object implements) with a function member that indicates which interfaces are implemented for the object. This interface is named IUnknown (and referred to as the unknown interface or the object management interface) and is defined as follows.

    ______________________________________
    class IUnknown
    {virtual HRESULT QueryInterface (REFIID iid, void
    **ppv) = 0;
    virtual ULONG AddRef() = 0;
    virtual ULONG Release() = 0;
    ______________________________________


The IUnknown interface defines the function member (method) QueryInterface. The method QueryInterface is passed an interface identifier (e.g., "IDatabase") in parameter iid (of type REFIID) and returns a pointer to the implementation of the identified interface for the object for which the method is invoked in parameter ppv. If the object does not support the interface, then the method returns a false. (The type HRESULT indicates a predefined status, and the type ULONG indicates an unsigned long integer.)

                  CODE TABLE 1
    ______________________________________
    HRESULT XX::QueryInterface(REFIID iid, void **ppv)
    ret = TRUE;
    switch (iid)
    {case IID.sub.-- IBasic:
    *ppv = *pIBasic;
    break;
    case IID.sub.-- IDatabase:
    *ppv = *pIDatabase;
    break;
    case IID.sub.-- IUnknown:
    *ppv = this;
    break;
    default:
    ret = FALSE;
    if (ret == TRUE)(AddRef();};
    return ret;
    }
    ______________________________________


Code Table 1 contains C++ pseudocode for a typical implementation of the method QueryInterface for class XX, which inherits the class IUnknown. If the spreadsheet object supports the IDatabase interface, then the method QueryInterface includes the appropriate case label within the switch statement. The variables pIBasic and pIDatabase point to a pointer to the virtual function tables of the IBasic and IDatabase interfaces, respectively. The method QueryInterface invokes the method AddRef (described below) to increment a reference count for the object of class XX when a pointer to an interface is returned.

                  CODE TABLE 2
    ______________________________________
    void XX:: AddRef() {refcount ++;}
    void XX:: Release() {if(--refcount == 0) delete this;}
    ______________________________________


The interface IUnknown also defines the methods AddRef and Release, which are used to implement reference counting. Whenever a new reference to an interface is created, the method AddRef is invoked to increment a reference count of the object. Whenever a reference is no longer needed, the method Release is invoked to decrement the reference count of the object and, when the reference count goes to zero, to deallocate the object. Code Table 2 contains C++ pseudocode for a typical implementation of the methods AddRef and Release for class XX, which inherits the class IUnknown.

The IDatabase interface and IBasic interface inherit the IUnknown interface. The following definitions illustrate the use of the IUnknown interface.

    ______________________________________
    class IDatabase: public IUnknown
    {public:
    virtual void Data() = 0;
    class IBasic: public IUnknown
    {public:
    virtual void File() = 0;
    virtual void Edit() = 0;
    virtual void Formula() = 0;
    virtual void Format() = 0;
    virtual void GetCell (string RC, cell *pCell) = 0;
    }
    ______________________________________


FIG. 4 is a block diagram illustrating a sample data structure of a spreadsheet object. The spreadsheet object comprises object data structure 401, IBasic interface data structure 403, IDatabase interface data structure 404, the virtual function tables 402, 405, 406 and methods 407 through 421. The object data structure 401 contains a pointer to the virtual function table 402 and pointers to the IBasic and IDatabase interface. Each entry in the virtual function table 402 contains a pointer to a method of the IUnknown interface. The IBasic interface data structure 403 contains a pointer to the virtual function table 405. Each entry in the virtual function table 405 contains a pointer to a method of the IBasic interface. The IDatabase interface data structure 404 contains a pointer to the virtual function table 406. Each entry in the virtual function table 406 contains a pointer to a method of the IDatabase interface. Since the IBasic and IDatabase interfaces inherit the IUnknown interface, each virtual function table 405 and 406 contains a pointer to the methods QueryInterface, AddRef, and Release. In the following, an object data structure is represented by the shape 422 labeled with the interfaces through which the object may be accessed.

The following pseudocode illustrates how a word processing program determines whether a spreadsheet object supports the IDatabase interface.

    ______________________________________
    if (pSpreadsheet- > QueryInterface("IDatabase",
    &pIDatabase) == S.sub.-- OK)
    // IDatabase supported
    else
    // IDatabase not supported
    ______________________________________


The pointer pSpreadsheet is a pointer to the IBasic interface of the object. If the object supports the IDatabase interface, the method QueryInterface sets the pointer pIDatabase to point to the IDatabase data structure and returns the value S.sub.-- OK.

Normally, an object can be instantiated (an instance of the object created in memory) by a variable declaration or by the "new" operator. However, both techniques of instantiation need the class definition at compile time. A different technique is needed to allow a word processing program to instantiate a spreadsheet object at run time. One technique provides a global function CreateInstanceXX, which is defined in the following.

static void CreateInstanceXX (REFIID iid, void **ppv)=0;

The method CreateInstanceXX (known as a class factory) instantiates an object of class XX and returns a pointer ppv to the interface of the object designated by parameter iid.

SUMMARY OF THE INVENTION

It is an object of the present invention to provide a method and system for generating links to source data incorporated within a compound document.

It is another object of the present invention for binding links to source data.

It is another object of the present invention for interfacing with these links in a manner that is independent of the underlying source data.

It is another object of the present invention for linking to data nested to an arbitrary level within a compound document.

These and other objects, which will become apparent as the invention is more fully described below, are provided by a method and system for naming and binding data objects. In a preferred embodiment, a link to an object incorporated is stored as a moniker. A moniker is an identifier object that encapsulates the information needed to access the incorporated data and provides methods which bind to the incorporated data.

BRIEF DESCRIPTION OF THE DRAWINGS

FIG. 1 is a block diagram of an example of a compound document.

FIG. 2 is a block diagram illustrating scheduling data, budgeting data, and explanatory data.

FIG. 3 is a block diagram illustrating typical data structures used to represent an object.

FIG. 4 is a block diagram illustrating a sample data structure of a spreadsheet object.

FIG. 5 is a block diagram showing a sample compound document.

FIGS. 6, 7, and 8 are block diagrams illustrating the use of a moniker by a word processing program.

FIG. 9 is a block diagram of a generic composite moniker.

FIGS. 10A, 10B, and 10C are block diagrams illustrating moniker composition.

FIG. 11 is a flow diagram of the method BindToObject of the class CFileMoniker.

FIG. 12 is a flow diagram of the function FileBindToObject.

FIG. 13 is a flow diagram of the method BindToObject of the class CItemMoniker.

FIG. 14 is a flow diagram of the method BindToObject of the class CCompositeMoniker.

FIGS. 15A, 15B, 15C, 15D, 15E and 15G are block diagrams illustrating the binding to an object identified by a generic composite moniker.

FIG. 16 is a flow diagram illustrating the overall behavior of implementations of the method ComposeWith.

FIG. 17 is a flow diagram of the method ComposeWith of the class CCompositeMoniker.

FIGS. 18, 19A, 19B, 19C, 20A, 20B, 20C, 21A, 21B, and 21C are block diagrams illustrating sample generic composite monikers.

FIG. 22 is a block diagram illustrating moniker reduction.

FIG. 23 is a flow diagram of the method Reduce of the class CCompositeMoniker.

FIG. 24 is a flow diagram of the method Reduce of the sample class CAliasMoniker.

FIG. 25 is a flow diagram of the method IsEqual of the class CFileMoniker.

FIG. 26 is a flow diagram of the method IsEqual of the class CCompositeMoniker.

FIG. 27 is a flow diagram of the method Hash of the class CCompositeMoniker.

FIGS. 28A, 28B, and 28C are block diagrams illustrating composition with inverse monikers.

FIG. 29 is a flow diagram of the method Inverse of the class CCompositeMoniker.

FIG. 30 is a flow diagram of the method Inverse of the class CItemMoniker.

FIG. 31 is a flow diagram of the method ComposeWith of the class CItemMoniker.

FIG. 32 is a flow diagram of the method AnnihilateOne of the class CAntiMoniker.

FIG. 33 is flow diagram of the method ComposeWith of the class CAntiMoniker.

FIG. 34 is a block diagram illustrating a common prefix of generic composite monikers.

FIG. 35 is a flow diagram of the method CommonPrefixWith of the class CCompositeMoniker.

FIG. 36 is a flow diagram of the method CommonPrefixWith of the class CFileMoniker.

FIG. 37 is a flow diagram of the method CommonPrefixWith of the class CItemMoniker.

FIG. 38 is a flow diagram of the method CommonPrefixWith of the class CAntiMoniker.

FIG. 39 is a flow diagram of the function MonikerCommonPrefixWith.

FIG. 40 is a block diagram illustrating a relative path to moniker.

FIGS. 41A and 41B, are block diagrams illustrating a usage of the method RelativePathTo.

FIGS. 42A, 42B, 42C, and 42D comprise a flow diagram of the method RelativePathTo of the class CCompositeMoniker.

FIG. 43 is a flow diagram of the function MonikerRelativePathTo.

FIG. 44 is a flow diagram of the method Enum of the class CCompositeMoniker.

FIG. 45 is a flow diagram of the method GetNext of the class CCompositeMonikerEnum.

FIG. 46 is a flow diagram of the method Next of the class CCompositeMonikerEnum.

FIG. 47 is a flow diagram of the method Create of the class CPointerMoniker.

FIG. 48 is a flow diagram of the method BindToObject of the class CPointerMoniker.

FIG. 49 is a block diagram illustrating a pointer moniker.

DETAILED DESCRIPTION OF THE INVENTION

The present invention provides a computer implemented method and system for naming and binding to linked data. In a preferred embodiment, a compound document that incorporates linked data stores a persistent data handle, called a "moniker," which is a reference to the link source. A moniker is an identifier object that contains information to identify the linked data and provides methods through which a program can bind to the linked data. A binding method returns an instance of an interface through which the linked data can be accessed. A moniker may link to data that is itself embedded data within another compound document. For example, a moniker may link to a range of cells within a spreadsheet table that is contained in a word processing document. A moniker may link to data at any level within a compound document. During execution of the binding method, several applications may be invoked to locate the link data. For example, to bind to the range of cells within a spreadsheet table that is within a word processing document, the word processing program may be invoked to locate the embedded spreadsheet table and the spreadsheet program may be invoked to bind to the range of cells. The present invention defines an interface through which a moniker is accessed. A moniker can identify source data that is stored persistently or non-persistently.

In a preferred embodiment, monikers can be composed to form a composite moniker. A composite moniker is conceptually a path to a source object that is identified by the concatenation of the monikers. For example, if a moniker specifying a certain path (e.g., "c:.backslash.reports") is composed with a moniker specifying a certain file name (e.g., "Q3.doc") then the result is the complete path name to the file (e.g., "c:.backslash.reports.backslash.Q3.doc"). Each composite moniker comprises a plurality of component monikers. The present invention provides a method and system for decomposing a composite moniker. In a preferred embodiment, each moniker provides a method that is used to retrieve each component moniker.

In a preferred embodiment, a moniker provides a reducing method which returns another moniker that is a more efficient representation of a moniker to the same source object. The reducing method may interpret a macro script that identifies the source object. Alternatively, the reducing method may evaluate a query request that identifies the source object.

In a preferred embodiment, a moniker provides an equality method and a hash method. The equality method determines whether two monikers identify the same source object. The hash method provides a hash value for a moniker. The equality method and hash method are used to implement hash tables indexed by monikers.

In a preferred embodiment, a moniker provides an inverse method that generates another moniker that is the inverse of the moniker. When a moniker is composed with its inverse, the result is NULL. The inverse moniker is said to annihilate the moniker. An inverse moniker may be used, for example, to remove portions of a path and is analogous to the ".." functionality of traditional file systems.

In a preferred embodiment, a moniker provides a common prefix with method and a relative path to method. The common prefix with method determines the common prefix portion of two monikers. For example, if one moniker identifies the object "c:.backslash.reports.backslash.Q3.doc" and another moniker identifies the object "c:.backslash.reports.backslash.data.backslash.Q3.xls" the common prefix is "c:.backslash.reports". The relative path to method generates relative path to moniker that when composed with one moniker results in specified moniker. For example, the moniker specifying the path that is the inverse of a moniker identifying object "Q3.doc" composed with a moniker specifying the path "data.backslash.Q3.xls" is a relative path to moniker from the moniker "c:.backslash.reports.backslash.Q3.doc" to the moniker "c:.backslash.reports.backslash.data.backslash.Q3.xls". Relative path to monikers are preferably used when identifying objects by relative paths from another object.

In a preferred embodiment, the present invention provides several implementation monikers including a file moniker, an item moniker, a generic composite moniker, a pointer moniker, and an anti moniker. Each implementation is referred to as a moniker class and has a class identifier. A file moniker provides a moniker that conceptually is a path name in a file system. An item moniker provides a moniker that conceptually identifies a portion of an object. A generic composite moniker provides a mechanism for composing monikers with arbitrary implementations. For example, a file moniker can be composed with an item moniker to specify a portion of a file. A generic composite moniker is preferably created by the composing method of the file moniker. A pointer moniker is a moniker that wraps an instantiated source object in a moniker. A pointer moniker contains a pointer to the instantiated source object and when a pointer moniker is bound, it returns the pointer. An anti moniker is a moniker that is the inverse of other monikers. When a moniker is composed with an anti moniker, the result is NULL. If a generic composite moniker is composed with an anti moniker, the result is a moniker comprising all but the last component moniker. The anti moniker annihilates the last component moniker of a generic composite moniker.

In a preferred embodiment of the present invention, an application program that creates a compound document controls the manipulation of linked or embedded data generated by another application. In object-oriented parlance, this data is referred to as an object. (The reference Budd, T., "An Introduction to Object-Oriented Programming," Addison-Wesley Publishing Co., Inc., 1991, provides an introduction to object-oriented concepts and terminology.) An object that is either linked or embedded into a compound document is "contained" within the document. Also, a compound document is referred to as a "container" object and the objects contained within a compound document are referred to as "containee" objects. Referring to FIGS. 1 and 2, the scheduling data 102 and budgeting data 103 are containee objects and the compound document 101 is a container object. The user can indicate to the word processor that the user wants to edit a containee object, such as the budgeting data 103. When the user indicates that the budgeting data 103 is to be edited, the word processing program determines which application should be used to edit the budgeting data (e.g., the spreadsheet program) and launches (starts up) that application. The user can then manipulate the budgeting data using the launched application, and changes are reflected in the compound document. The same procedure is used whether the budgeting data is stored as an embedded or linked object.

FIG. 5 is a block diagram showing a sample compound document. The weekly project report 501 is the same compound document of FIG. 1. The executive summary report 503, contains a budgeting chart 505 that is linked to the weekly project 501. The weekly project 501 contains an embedded spreadsheet 502. The embedded spreadsheet 502 was created by the spreadsheet program 204 in FIG. 2. The data for this spreadsheet, the budget for the project, is stored within the storage of the weekly project report 501 because it is an embedded object. The executive summary document 503 is a compound document which contains native text 504 and a contained object, the budget chart 505. The budget chart 505 is linked to the data contained within in the spreadsheet 502 which is embedded in the compound document 501.

In a preferred embodiment, application programs ("applications") cooperate using object linking and embedding facilities to create and manipulate compound documents. An application that creates a compound document is referred to as a client application, and an application that creates and manipulates containee objects are referred to as server applications. An application can behave as both a client and a server. Referring to FIG. 2, the project management program 201 and the spreadsheet program 204 are server applications, and the word processing program 206 is a client application. A client application is responsible for selection of the various objects within the container object and for invoking the proper server application to manipulate the selected containee object. A server application is responsible for manipulating the contents of the containee objects.

In a preferred embodiment, applications are provided with an implementation-independent Application Programming Interface (API) that provides the object linking and embedding functionality. The section entitled "Details of Moniker Related Interfaces" contains a detailed description of several functions within a preferred object linking and embedding system. contains a detailed description of a preferred object linking and embedding system. The API is a set of functions that are invoked by client and server applications. These functions manage, among other things, the setup and initialization necessary for client applications to send and receive messages and data to and from server applications. The API provides functions to invoke the correct server application to act upon a particular containee object and to manipulate containee objects.

In addition, the object linking and embedding API defines "interfaces" through which client applications can communicate with their contained objects. An interface is a set of methods which abide by certain input, output, and behavior rules. If a contained object supports a particular interface, the client application can invoke the methods of that interface to effect the defined behavior. In a preferred embodiment, the client application is not allowed direct access to the object data; it manipulates the object using the supported interfaces. A client application is bound to a contained object through a pointer to an interface. The client application accesses the object by invoking the methods of the interface. To access the object data, the methods may send messages to the server application requesting the specified access. In a preferred embodiment, messages are sent between clients and servers using interprocess communications mechanisms provided by the underlying operating system.

An example will help illustrate the relationship between a client process and a server process. Referring again to FIG. 1, if a user wants to edit the budgeting data 103 of the compound document 101, then the following sequence of events occurs. First, the user starts up the word processor program, which is dynamically linked to the object linking and embedding API. Second, the user opens the compound document for editing. Third, the user selects the budgeting data, which is a containee object, and indicates that the selected object is to be edited. Fourth, the client application invokes a client API routine for performing an action on an object passing the routine a handle (which uniquely identifies the selected object) to the object and an indicator that the action is edit. Fifth, the client API routine determines that the spreadsheet program provides the actions for the budgeting dam. Sixth, the client API code starts up the spreadsheet program as a server process, if it is not already started. Seventh, the word processor application sends a message to the spreadsheet program that it should edit the budgeting data. Eighth, the server API code receives the request to edit and invokes a routine in the spreadsheet program for editing the data. When editing is complete, the spreadsheet routine returns to the server API code. The server API code sends a message to the word processor application to indicate that editing is complete. The client API code receives the message and returns from its invocation. Upon return from the invocation, the word processor application knows that the editing is complete.

In addition to the client and server API, the object linking and embedding facilities of the present invention provide information to client and server applications through a persistent global "registry." This registry is a database of information such as (1) for each type of object, the server application that implements the object type, (2) the actions that the each server application provides to client applications, (3) where the executable files for each server application are located, and (4) whether each server application has an associated object handler. An object handler is a collection of functions in a dynamic link library. An object handler can be used to provide certain functions without launching the server.

FIGS. 6, 7, and 8 are block diagrams illustrating the use of a moniker by a word processing program. In FIG. 6, the document "RPT.DOC" 601 contains a link 602 to the chart file 603. The link 602 is a moniker that is persistently stored in the document 601. The persistent storage of the moniker includes the class identifier "CLSID.sub.-- FileMoniker" and the name of the chart file 603 ("Q3.CHT"). When the word processing program displays the chart of chart file 603, it first instantiates a moniker object of type CLSID.sub.-- FileMoniker, requests the moniker to load its persistent data (e.g., "Q3.CHT"), and then requests the moniker to bind to the file indicated by the loaded data. FIG. 7 is a block diagram illustrating the instantiation of a moniker object. The word processing program first reads in the class identifier of link 602. To determine how to instantiate an object of that class, the program accesses the global registry 704. The global registry includes a mapping from class identifiers to the location of a class factory to create an instance of that class. For example, table 704B indicates that the class factory for the moniker class identified by CLSID.sub.-- FileMoniker is contained in the dynamic link library named "FileMkr.DLL." The program links to the class factory code within the dynamic link library 706. The program invokes the function CreateInstance to create an instance of an object of class CFileMoniker 702 (a file moniker). The program then requests the IPersistStream interface of the file moniker. The IPersistStream interface (described in detail in the section entitled "Details of the Moniker Related Interfaces") provides methods the section entitled "Details of the Moniker Interfaces through which the internal state (e.g., "Q3.CHT") of a moniker can be saved to persistent storage and then loaded into memory from the persistent storage. Using the methods of the IPersistStream interface, the program loads the moniker internal state persistently stored in link 602 into the file moniker 702. The program then requests the IMoniker interface to the file moniker 702. The pointer to the IMoniker interface is stored in pointer 701. FIG. 8 is a block diagram illustrating the binding of the file moniker 702 to the chart file 603. When a binding method of the file moniker 702 is invoked, the method determines the class identifier for the file identified by the file moniker by accessing the global registry table 704A. The class identifier for files with suffix "CHT" is CLSID.sub.-- Chart. The program then retrieves the class factory for the class CLSID.sub.-- Chart from the registry table 704B. The program links to the dynamic link library "CHART.DLL" 806. The program then invokes the CreateInstance method within the dynamic link library 806, which creates an instance of a chart object 807 and returns a pointer to the IDataObject interface. The IDataObject interface (described in detail in the section entitled "Details of the Moniker Related Interfaces") provides methods to pass data to and from an object (e.g., methods GetData and SetData). Through the chart object 807, the program can access the chart file 603 through the chart server 808.

In a preferred embodiment, a moniker is an object that supports the IMoniker interface of Code Table 3. The IMoniker interface inherits 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 new classes of monikers can be created transparently to clients.

The IMoniker interface provides for binding to the object to which it points, which is supported by the method BindToObject. This method 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. Each moniker class can store arbitrary data 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 the method BindToStorage can be used to access it. Many objects have such identifiable storage (e.g., a file), but some, such as the objects which are the ranges in a spreadsheet do not.

In a preferred embodiment, a particular moniker class is designed to be one step along the path (a component) to a data source. These components can be composed together to form a moniker which represents the complete path to the data source. For example, the moniker stored inside the chart of FIG. 5 might be a generic composite moniker formed from three component as illustrated in FIG. 9. This composite is itself a moniker; it is a moniker which is a sequenced collection of other composite monikers. The composition is generic in that it has no knowledge of the component monikers involved other than that they are monikers.

                                      Code TABLE 3
    __________________________________________________________________________
    class IMoniker: IPersistStream{
    virtual
          HRESULT
                BindToObject(pbc, pmkToLeft, iidResult, ppvResult) = 0;
    virtual
          HRESULT
                BindToStorage(pbc, pmkToLeft, iid, ppvObj) = 0;
    virtual
          HRESULT
                Reduce(pbc, dwReduceHowFar, ppmkToLeft, ppmkReduced) = 0;
    virtual
          HRESULT
                ComposeWith(pmkRight, fOnlyIfNotGeneric, ppmkComposite)
    virtual
          HRESULT
                Enum(fForward, ppenmMoniker) = 0;
    virtual
          HRESULT
                IsEqual(pmkOtherMoniker) = 0;
    virtual
          HRESULT
                Hash(pdwHash) = 0;
    virtual
          HRESULT
                IsRunning(pbc, pmkToLeft, pmkNewlyRunning) = 0;
    virtual
          HRESULT
                GetTimeOfILastChange(pbc, pmkToLeft, pfiletime) = 0;
    virtual
          HRESULT
                Inverse(ppmk) = 0;
    virtual
          HRESULT
                CommonPrefixWith(pmkOther, ppmkPrefix) = 0;
    virtual
          HRESULT
                RelativePathTo(pmkOther, ppmkRelPath);
    virtual
          HRESULT
                GetDisplayName(pbc, pmkToLeft, lplpszDisplayName) = 0;
    virtual
          HRESULT
                ParseDisplayName(pbe, pmkToLeft, lpszDisplayName, pcchEaten,
                ppmkOut) = 0;
    virtual
          HRESULT
                IsSysternMoniker(pdwMksys);
    };
    __________________________________________________________________________


The example of FIGS. 6, 7, and 8 illustrate the use of a moniker that identifies a file. The present invention allows moniker to be combined (composed) to an arbitrary level. FIGS. 10A, 10B, and 10C illustrate moniker composition. For example, if the chart file 603 contained multiple charts, it would be useful to designate a specific chart to be the source of a link. In one embodiment of the present invention, a moniker class named "CChartMoniker" could be implemented by the developer of the chart program. A chart moniker 1001 would contain a name of a chart file ("Q3.CHT") and an indication of a chart within the file ("CHART2"). The methods of the class CChartMoniker would have a behavior similar to that provided by the class CFileMoniker plus behavior needed to bind to the identified chart. As described above, the present invention allows two monikers to be composed to form a third moniker. By composing monikers, a developer can use an implementation developed by someone else. For example, the developer of the chart program could define and implement the class CChartMoniker to contain only an indication of a chart within a file. The class CChartMoniker can be developed assuming that an instance of chart moniker 1003 will be composed with a file moniker (e.g., file moniker 1002). In a preferred embodiment, to facilitate the composing of monikers, a moniker of class CCompositeMoniker is defined and implemented. The class CCompositeMoniker encapsulates any two monikers into single generic composite moniker. The generic composite moniker 1004 encapsulates the file moniker 1002 and the chart moniker 1003. A link to a chart is stored as a generic composite moniker which encapsulates a file moniker and a chart moniker. The client of the link need only know that the moniker supports the IMoniker interface.

In the following, each method of the IMoniker interface is defined. In addition, several implementations of various methods are described. In particular, implementations of methods of the classes CFileMoniker, CCompositeMoniker, and CItemMoniker are described. The class CFileMoniker (a file moniker) is a moniker class that identifies a path name in a file system. When a file moniker is bound to, it determines the class of the file by using the persistent global registry, ensures that the appropriate class server is running, and then requests the server to open the file. The class CCompositeMoniker (a generic composite moniker) is a moniker class that identifies a composition of two monikers (a left and a right moniker). When a generic composite moniker is bound to, it invokes the binding method of the right moniker indicating that the left moniker is composed with the right moniker. The right moniker performs its binding behavior, which may include invoking the binding method of the left moniker. The class CItemMoniker (an item moniker) is a moniker class that implements behavior common to the identification of containee objects. An item moniker can be used to identify, for example, a chart contained within a chart file or a range within a spreadsheet. An item moniker uses the IOleItemContainer interface (described in detail in the section entitled "Details of the Moniker Related Interfaces") to interact with the container. Code Table 4 contains the class definitions for a file moniker, a generic composite moniker, an item moniker, an anti moniker, and a pointer moniker. An anti moniker and a pointer moniker are described below in detail. A file moniker contains a string (m.sub.-- szPath) indicating a path name and a count of anti monikers (m.sub.-- cAnti). A generic composite moniker contains a pointer to the left moniker (m.sub.-- pmkLeft) and a pointer to the right moniker (m.sub.-- pmkRight) of the generic composite and a flag (m.sub.-- fReduced) indicating whether the composite is reduced. An item moniker contains a pointer to a string (m.sub.-- lpszItem) that defines the item.

                  CODE TABLE 4
    ______________________________________
    class CFileMoniker: IMoniker
    {char FAR* m.sub.-- szPath;
    UINT m.sub.-- cAnti;
    class CCompositeMoniker: IMoniker
    {LPMONIKER m.sub.-- pmkLeft;
    LPMONIKER m.sub.-- pmkRight;
    BOOL m.sub.-- fReduced;
    }
    class CItemMoniker: IMoniker
    {char FAR* m.sub.-- lpszItem;
    }
    class CAntiMoniker: IMoniker
    {ULONG m.sub.-- count;
    }
    class CPointerMoniker: IMoniker
    {LPUNKNOWN m.sub.-- punk;
    }
    ______________________________________


IMoniker::BindToObject HRESULT IMoniker::BindToObject(pbc, pmkToLeft, iidResult, ppvResult)

The method BindToObject locates and loads the object semantically referred to by this moniker according to the interface specified by iidResult and returns a pointer to the object through ppvResult. In the following, the term "this moniker" refers to the moniker for which a method is invoked. In general, each class of moniker is designed to be used as one component in a generic composite moniker which gives the complete path to the referenced object. In a generic composite, any component moniker has a certain prefix of the generic composite to its left, and a certain suffix to its right. If the method BindToObject is invoked on a component moniker, then the implementation of BindToObject typically requires certain services of the object indicated by the prefix to its left. Item monikers, for example, require the IOleItemContainer interface of the object to their left. The Item Moniker implementation of the method BindToObject (as described below) recursively calls pmkToLeft->BindToObject in order to obtain this interface. If the moniker does not need services of the object to its left, yet one is provided by the caller nevertheless, no error occurs. Rather, the moniker ignores the object to its left. If the object indicated by the moniker does not exist, then the error MK.sub.-- E.sub.-- NOOBJECT is returned.

In general, binding a moniker can be a complicated process, since it may need to launch servers, open files, etc. This may involve binding to other objects, and the binding components of a generic composite to the right of certain components will require the same other objects. In order to avoid loading the object, releasing it, then having it loaded again later, the method BindToObject can use the bind context passed through the pbc parameter to defer releasing objects until the binding process overall is complete. The bind context is described in detail in section entitled "Details of the Moniker Related Interfaces".

Binding to a moniker a second time typically returns the same running object as binding the first time, rather than reloading it again from storage. This functionality is supported with a running object table. The running object table is a lookup table keyed by a moniker whose values are pointers to the corresponding now-running object. As objects become running, they register themselves in this table. Implementations of the method BindToObject uses this table to determine if the object to which they point is already running. More precisely, if the passed pmkToLeft parameter is NULL (and this is not an error; that is, the moniker does not require something to its left), then the moniker fully reduces itself, then looks itself up in the running object table, and returns the pointer to the object found there. The running object table is described in detail in the section entitled "Details of the Moniker Related Interfaces".

The following table describes the parameters of the method BindToObject:

    ______________________________________
    Argument Type      Description
    ______________________________________
    pbc      IBindCtx* the bind context to be used for this
                       binding operation.
    pmkToLeft
             IMoniker* the moniker of the object to the left
                       of this moniker.
    iidResult
             IID       the requested interface by which the
                       caller wishes to connect to the object.
    ppvResult
             void**    on successful return, a pointer to the
                       instantiated object is placed here,
                       unless BINDFLAGS.sub.-- JUSTTEST-
                       EXISTENCE was specified in the
                       binding options, in which case NULL
                       may be returned instead.
    return value
             HRESULT   S.sub.-- OK, MK.sub.-- E.sub.-- NOOBJECT,
                       STG.sub.-- E.sub.-- ACCESSDENIED,
                       MK.sub.-- E.sub.-- EXCEEDEDDEADLINE,
                       MK.sub.-- E.sub.-- CONNECTMANUALLY,
                       MK.sub.-- E.sub.-- INTERMEDIATE-
                       INTERFACENOTSUPPORTED,
                       E.sub.-- OUTOFMEMORY,
                       E.sub.-- NOINTERFACE
    ______________________________________


FIG. 11 is a flow diagram of the method BindToObject of the class CFileMoniker. This method determines the class identifier of the file, determines the server for that file, launches the server (if necessary), and requests the server to open and bind to the file. In step 1101, if a moniker to the left of this moniker is specified, then the method continues at step 1105, else the method continues at step 1102. In steps 1102 through 1104, the method determines whether the object identified by the moniker to the left is in the running object table. If the object to the left is in the running object table, then the requested interface (iidResult) is retrieved from that object and returned. In step 1102, if the object to the left is in the running object table, then the method continues at step 1103, else the method continues at step 1105. In step 1103, the method retrieves a pointer to the object to the left from the running object table. In step 1104, the method retrieves the requested interface from the object to the left by invoking the method QueryInterface of the object to the left and then returns. In step 1105, the method retrieves the class identifier corresponding to the path (m.sub.-- szPath) of this moniker. The class identifier is preferably retrieved from a persistent global registry that maps file name suffixes to class identifiers. In step 1106, the method invokes the function FileBindToObject to bind to the file and returns the requested interface. The method then returns.

FIG. 12 is a flow diagram of the function FileBindToObject. This function is passed a class identifier and a requested interface. This function instantiates an object of the passed class identifier and returns a pointer to the requested interface. In step 1201, the function creates an instance of an object of the passed class identifier and retrieves the IUnknown interface. In step 1202, the function retrieves the IPersistFile interface from the instantiated object. The IPersistFile interface provides methods to load and save files and is described in detail in the section entitled "Details of the Moniker Related Interfaces". In step 1203, the function initializes binding options, which are described in detail in the section entitled "Details of the Moniker Related Interfaces". In step 1204, the function invokes the method Load of the IPersistFile interface to load the data for the created object. In step 1205, the function retrieves the requested interface from the created object and returns.

FIG. 13 is a flow diagram of the method BindToObject of the class CItemMoniker. In step 1301, if no moniker to the left of this moniker is specified, then the method returns an error, else the method continues at 1302. An item moniker identifies a containee object and requires a moniker to a container object to its left. In step 1302, the method invokes the method BindToObject of the moniker of the object to the left. The method requests the IOleItemContainer interface from the object to the left. In step 1303, the method invokes the method GetObject of the IOleItemContainer interface and passes the item name (m.sub.-- lpszItem) and the requested interface. The method then returns with the interface retrieved by the method GetObject.

FIG. 14 is a flow diagram of the method BindToObject of the class CCompositeMoniker. The method binds to a generic composite moniker in a right-to-left manner. Conceptually, a generic composite moniker forwards the bind request to its last component moniker informing the last component moniker of the moniker to its left in the composite. The last component moniker, if it needs to, recursively binds to the object to its left. In step 1401, if no moniker to the left of this moniker is specified, the method continues at step 1402, else the method continues at step 1405. In step 1402, if this moniker is in the running object table, then the method continues at step 1403, else the method continues at step 1405. In step 1403, the method retrieves a pointer to the object from the running object table. In step 1404, the method retrieves the requested interface of the object by invoking the method QueryInterface of the object and returns. In steps 1405 through 1408, the method invokes the method BindToObject of the last component moniker of this moniker passing a moniker comprising the prefix component monikers as the moniker to the left. In step 1405, if no monikers to the left of this moniker is specified, then the method continues at step 1406, else the method continues at step 1407. In step 1406, the method creates a new left moniker that contains all but the last component moniker of this moniker. The method then invokes the method BindToObject of the last component moniker of this moniker passing it the newly-created left moniker and the requested interface in step 1408 and returns. In step 1407, the method composes the moniker to the left with all but the last component moniker of this moniker by invoking the method ComposeWith of the moniker to the left. The method then invokes the method BindToObject of the last component moniker of this moniker passing it the newly-created composed moniker and the identifier of the requested interface in step 1408 and returns.

FIGS. 15A through 15G are block diagrams illustrating the binding to an object identified by a generic composite moniker. FIG. 15A illustrates the generic composite moniker that is to be bound. The generic composite moniker comprises components 1501, 1502, and 1503. The component monikers 1501, 1502, and 1503 represent a reference to an object identified by "C:.backslash.Q3RPT.DOC.backslash.SALESTBL.backslash.R2C2:R7C4". The component moniker 1501 is the first component moniker of the generic composite moniker, and the component moniker 1503 is the last component moniker of the generic composite moniker. The component monikers 1502 and 1503 are all but the first component monikers of the generic composite moniker, and the component monikers 1501 and 1502 are all but the last component monikers of the generic composite moniker. These component monikers are composed using generic composite monikers 1504 and 1505. To bind to the object identified by the generic composite moniker 1504, the method BindToObject is invoked indicating that there is no moniker to the left and indicating the identifier of a requested interface. Since moniker 1504 is a generic composite moniker, the method represented by the flow diagram of FIG. 14 is executed. Since there is no moniker to the left and since for this example the generic composite moniker 1504 is not in the running object table, the method continues at step 1406. In step 1406, the method creates the generic composite moniker 1506 that contains all but the last component moniker of the generic composite moniker 1504. In step 1408, the method invokes the method BindToObject of the last component moniker 1503 passing the generic composite moniker 1506 as the moniker to the left and the identifier of the requested interface. Since the component moniker 1503 is an item moniker, the method represented by the flow diagram of FIG. 13 is executed. Since a moniker to the left is specified, step 1302 is executed. In step 1302, the method invokes the method BindToObject of the moniker to the left (generic composite moniker 1506) passing no moniker to the left and requesting the IOleItemContainer interface. Since the generic composite moniker 1506 is a generic composite moniker, the method represented by the flow diagram of FIG. 14 is executed. Since no moniker to the left is specified, the method continues at step 1406. In step 1406, the method sets the new left moniker to the moniker 1501. In step 1408, the method invokes the method BindToObject of the item moniker 1502 passing the new left moniker 1501 and requesting the passed interface, which is the interface to the IOleItemContainer. Since the item moniker 1502 is an item moniker, the method represented by the flow diagram of FIG. 13 is executed. Since there is a moniker to the left is specified, step 1302 is executed. In step 1302, the method invokes the method BindToObject of the moniker to the left (file moniker 1501). Since the file moniker 1501 is a file moniker, the method represented by the flow diagram of FIG. 11 is executed. Since no moniker to the left is specified, the method continues at step 1105. In steps 1105 and 1106, the method binds to the file object and returns the requested interface as shown in FIG. 15G. The invocation of the method BindToObject of the item moniker 1503 eventually in step 1303 invokes the method GetObject of the IOleItemContainer interface returned in step 1302 to retrieve the requested interface.

IMoniker::ComposeWith RESULT IMoniker::ComposeWith(pmkRight, fOnlyIfNotGeneric, ppmkComposite)

This method ComposeWith returns a new moniker which is a composite formed with this moniker on the left and the passed moniker (pmkRight) on the right. There are two kinds of composite monikers: those composite monikers that know nothing about their component monikers other than that they are monikers (a generic composite moniker), and those composite monikers that know more (a special composite moniker). For example, a file moniker containing a relative path may be composed on to the end of another file moniker. The resulting composite moniker could be a new file moniker containing the complete path. The new file moniker is a special composition. A special composition is useful for monikers that are capable of collapsing a path within a storage domain to a more efficient representation in a subsequent reduction.

Each moniker class may have a set of other kinds of special monikers that can be composed onto the end of it in a non-generic way. Each implementation of the method ComposeWith examines the passed moniker on the right (pmkRight) to see if it is such a special moniker for the implementation. If the specified moniker on the right is special, then the implementation does whatever is appropriate for that special case. If it is not, then the passed flag fOnlyIfNotGeneric controls what occurs. If flag fOnlyIfNotGeneric is true, then NULL is passed back through parameter ppmkComposite and the status MK.sub.-- E.sub.-- NEEDGENERIC returned; if fOnlyIfNotGeneric is false, then a generic composite moniker is created using the function CreateGenericComposite and returned.

If the specified moniker on the fight (pmkRight) completely annihilates this moniker, the resulting composite is empty and the parameter ppmkComposite is set to NULL and the status S.sub.-- OK returned.

Composition of monikers is an associative operation. That is, if A, B, and C are monikers, then

(A.smallcircle.B).smallcircle.C

is always equal to

A.smallcircle.(B.smallcircle.C)

where .smallcircle. represents the composition operation.

The following table describes the parameters of the method ComposeWith:

    ______________________________________
    Argument    Type      Description
    ______________________________________
    pmkRight    IMoniker* the moniker to compose onto
                          the end of the receiver.
    fOnlyIfNotGeneric
                BOOL      controls whether a composite
                          moniker should be returned
                          when the right moniker is not a
                          special moniker for this
                          moniker.
    ppmkComposite
                IMoniker* on exit, the resulting composite
                          moniker. Possibly NULL.
    return value
                HRESULT   S.sub.-- OK,
                          MK.sub.-- E.sub.-- NEEDGENERIC
    ______________________________________


FIG. 16 is a flow diagram illustrating the overall behavior of implementations of the method ComposeWith. In step 1601, if the moniker to the right (pmkRight) is special, then the method continues at step 1602, else the method continues at step 1603. In step 1602, the method performs a composition associated with the special moniker and returns. In step 1603, if the caller wants a generic composition when no special composition occurs (fOnlyIfNotGeneric==FALSE), then the method continues at step 1604, else the method continues at step 1605. In step 1604, the method creates a generic composite moniker by invoking the function CreateGenericMoniker and returns. In step 1605, the method returns an indication that composite moniker is NULL and sets the return flag to indicate that no special or generic composition occurred.

FIG. 17 is a flow diagram of the method ComposeWith of the class CCompositeMoniker. The method invokes the function CreateGenericComposite (described below) and returns.

                                      CODE TABLE 4
    __________________________________________________________________________
    CreateGenericComposite(pmkFirst, pmkRest, ppmkComposite)
    Case 1:
    pmkFirst- > ComposeWith(pmkRest, TRUE, ppmkComposite)
    if (no composition occurred)
    CCompositeMoniker::Create(pmkFirst, pmkRest,
    ppmkComposite)
    Case 2:
    pmkFirst- > ComposeWith(pffdcFirstOfRest, TRUE, &pmk)
    if (no composition occurred)
    CCompositeMoniker::Create(pmkFirst, pmkRest, ppmkComposite)
    else
    if (pmk! = NULL)
    CreateGenericComposte (pmk, pmkAllButFirstOfRest, ppmkComposite)
    else
    *ppmkComposite = pmkAllButFirstOfRest
    Case 3:
    pmkLastOfFirst- > ComposeWith(pmkRest, TRUE, &pmk);
    if (no composition occurred)
    CCompositeMoniker::Create(pmkFirst, pmkRest, ppmkComposite)
    else
    if (pmk! = NULL)
    CreateGenericComposite(pmkAllButLastOfFirst, pmk, ppmkComposite)
    else
    *ppmkComposite = pmkAllButLastOfFirst
    Case 4:
    pmkLastOfFirst- > ComposeWith(pmkFirstOfRest, TRUE, &pmk)
    if(no composition occurred)
    CCompositeMoniker::Create(pmkFirst, pmkRest, ppmkComposite)
    else
    if(pmk! = NULL)
    CreateGenericComposite(pmkAllButLastOfFirst, pmk, &pmk2)
    CreateGenericComposite(pmk2, pmkAllButFirstOfRest, ppmkComposite)
    else
    CreateGenericComposite(pmkAllButLastOfFirst, pmkAllButFirstOfRest,
    ppmkComposite)
    }
    __________________________________________________________________________


CreateGenericComposite HRESULT CreateGenericComposite(pmkFirst, pmkRest, ppmkComposite)

The function CreateGenericComposite allocates and returns a new generic composite moniker. The parameters pmkFirst and pmkRest point to the first and trailing monikers that are to comprise the generic composite monikers, respectively. Either pmkFirst or pmkRest may be a generic composite moniker, or another kind of moniker. The following table describes the parameters of the function CreateGenericComposite:

    ______________________________________
    Argument  Type      Description
    ______________________________________
    pmkFirst  IMoniker* the first moniker in the new
                        composite.
    pmkRest   IMoniker* the trailing (rest) moniker in the
                        new composite.
    ppmkComposite
              IMoniker* a pointer to the new composite.
    return value
              HRESULT   S.sub.-- OK, E.sub.-- OUTOFMEMORY
    ______________________________________


Code Table 4 contains C++ pseudocode for the function CreateGenericComposite. The function handles four specific cases. The first case occurs when neither the first moniker (pmkFirst) nor the rest moniker (pmkRest) are generic composite monikers. The second case occurs when the first moniker is not a generic composite moniker, but the rest moniker is a generic composite moniker. The third case occurs when the first moniker is a generic composite moniker, but the rest moniker is not a generic composite moniker. The fourth case occurs when both the first moniker and the rest moniker are generic composite monikers.

In the first case, the function CreateGenericComposite invokes the method ComposeWith of the first moniker passing the rest moniker and specifying that a composition should occur only if not generic. If the rest moniker is not a special moniker for the first moniker, then no composition occurs and the function creates a composite moniker by invoking the method Create of the class CCompositeMoniker passing the first moniker and the rest moniker. The method Create of the class CCompositeMoniker creates a generic composite moniker that points to the specified monikers and returns a pointer to the created moniker. FIG. 18 illustrates the resulting generic composite moniker 1803 of the first case when the rest moniker 1802 is not a special moniker of the first moniker 1801. In the second case, the function CreateGenericComposite invokes the method ComposeWith of the first moniker passing the first component moniker of the rest moniker. If the first component moniker of the rest moniker is not a special moniker for the first moniker, then no composition occurs and the method creates a composite moniker by invoking the method Create of the class CCompositeMoniker passing the first moniker and the rest moniker. FIG. 19A illustrates a representative resulting generic composite moniker 1905 when the first component moniker 1903 of the rest moniker 1902 is not a special moniker of the first moniker 1901. If, however, a composition of the first moniker and the first component of the rest moniker occurs and a moniker is returned, then the function recursively calls the function CreateGenericComposite to compose the moniker returned with all but the first component moniker of the rest moniker. FIG. 19B illustrates the resulting generic composite moniker 1907 that contains the composite moniker 1906, which is the composition of the first moniker and the first component moniker of the rest moniker, and contains the moniker 1904, which includes all but the first component moniker of the rest moniker. If the composition of the first moniker and the first component moniker of the rest moniker resulted in an annihilation of the monikers (pmk==NULL), then the function returns a pointer to a moniker formed by all but the first component moniker of the rest moniker as illustrated in FIG. 19C. In the third case, the function CreateGenericComposite invokes the method ComposeWith of the last component moniker of the first moniker passing the rest moniker. If the rest moniker is not a special moniker for the last component moniker of the first moniker, then no composition occurs and the function creates a composite moniker by invoking the method Create of the class CCompositeMoniker passing the first moniker and the rest moniker as illustrated by the representative generic composite moniker in FIG. 20A. If, however, a composition occurs, and a moniker is returned, then the method recursively invokes the function CreateGenericComposite passing all but the last component moniker of the first component moniker and the returned moniker as indicated in FIG. 20B. If, however, the composition of the first moniker with the first component moniker of the rest moniker resulted in an annihilation of the monikers, then the function returns a moniker comprising all but the last component moniker of the first moniker as the composite moniker as illustrated by FIG. 20C. In the fourth case, the function CreateGenericComposite invokes the method ComposeWith of the last component moniker of the first moniker passing the first component moniker of the rest moniker. If the first component moniker of the rest moniker is not a special moniker for the last component moniker of the first moniker, then no composition occurs and the function invokes the method Create of the class CCompositeMoniker passing the first moniker and the rest moniker resulting in the sample generic composite moniker of FIG. 21A. If, however, a composition does occur without annihilation, then the function recursively invokes the function CreateGenericComposite passing the composed moniker and all but the last component moniker of the first moniker. The function then recursively invokes the function CreateGenericComposite passing the resulting composite moniker and all but the first component moniker of the rest moniker resulting in the representative composite moniker of FIG. 21B. If the composition results in annihilation of the last component moniker of the first moniker and the first component moniker of the rest moniker, then the function recursively invokes the function CreateGenericComposite passing all but the last component moniker of the first moniker and all but the first component moniker of the rest moniker resulting in the representative generic composite moniker of FIG. 21C.

IMoniker::Reduce HRESULT IMoniker::Reduce(pbc, dwReduceHowFar, ppmkToLeft, ppmkReduced)

The method Reduce requests a moniker to re-write itself into another equivalent moniker. This method 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 certain file systems which support an ID-based method of accessing files that is independent of file names, a file moniker could be reduced to a moniker which contains one of these IDs.

FIG. 22 shows an example of moniker reduction. This example 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. (Note that the particular classes of monikers used here are for illustrative purposes only.) Several 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 ".backslash..backslash.server.backslash.share.backslash.fred". Monikers may reduce to themselves, when they cannot be rewritten any further. A moniker which reduces to itself indicates this by returning itself through parameter ppmkReduced and the returning status code MK.sub.-- S.sub.-- REDUCED.sub.-- TO.sub.-- SELF. A moniker which reduces to nothing returns NULL in parameter ppmkReduced and the status code S.sub.-- OK. If a moniker does not reduce to itself, then this method does not reduce this moniker in-place; instead, it returns a new moniker.

The reduction of a moniker which is a composite of other monikers repeatedly reduces the component monikers of which it is composed until they all reduce to themselves, and then returns the composite of the reduced components. The parameter dwReduceHowFar controls the stopping point of the reduction process. It controls to what extent the reduction should be carried out. It has the following values.

    ______________________________________
    typedef enum tagMKRREDUCE {
    MKRREDUCE.sub.-- ONE = 3 << 16,
    MKRREDUCE.sub.-- TOUSER = 2 << 16,
    MKRREDUCE.sub.-- THROUGUSER = 1 << 16,
    MKRREDUCE.sub.-- ALL = 0
    }MKRREDUCE;
    ______________________________________


These values have the following semantics.

    __________________________________________________________________________
    Value            Description
    __________________________________________________________________________
    MKRREDUCE.sub.-- ONE
                     Perform only one step of reduction on this moniker. In
                     general, the
                     caller will have to have specific knowledge as to the
                     particular kind of
                     moniker in question in order to be able to usefully take
                     advantage of this
                     option.
    MKRREDUCE.sub.-- TOUSER
                     Reduce this moniker to the first point where it first is
                     of the form where
                     it represents something that the user conceptualizes as
                     being the identity
                     of a persistent object. For example, a file name would
                     qualify, but a
                     macro or an alias would not. If no such point exists,
                     then this option
                     should be treated as MKRREDUCE.sub.-- ALL.
    MKRREDUCE.sub.-- THROUGUSER
                     Reduce this moniker to the point where any further
                     reduction would
                     reduce it to a form which the user does not
                     conceptualize as being the
                     identity of a persistent object. Often, this is the same
                     stage as
                     MKRREDUCE.sub.-- TOUSER.
    MKRREDUCE.sub.-- ALL
                     Reduce the entire moniker, then, if needed reduce it
                     again and again
                     to the point where it reduces to simply
    __________________________________________________________________________
                     itself.


The following table describes the parameters of the method Reduce:

    __________________________________________________________________________
    Argument  Type  Description
    __________________________________________________________________________
    pbc       IBindCtx*
                    The bind context to use in this operation.
    dwReduceHowFar
              DWORD Indicates to what degree this moniker should be reduced.
    ppmkToLeft
              IMoniker**
                    On entry, the moniker which is the prefix of this one in
                    the
                    composite in which it is found. On exit, the pointer is
                    either NULL
                    or non-NULL. Non-NULL indicates that what was previously
                    thought of as the prefix should be disregarded and the
                    moniker
                    returned through ppmkToLeft considered the prefix in its
                    place.
                    NULL indicates that the prefix should not be so replaced.
                    Thus,
                    most monikers will NULL out this parameter before
                    returning.
    ppmkReduced
              IMoniker**
                    On exit, the reduced form of this moniker. Possibly
                    NULL.
    return value
              HRESULT
                    S.sub.-- OK, MK.sub.-- S.sub.-- REDUCED.sub.-- TO.sub.--
                    SELF,
                    MK.sub.-- E.sub.-- EXCEEDEDDEADLINE.
    __________________________________________________________________________


FIG. 23 is a flow diagram of the method Reduce of the class CCompositeMoniker. The method reduces each of the component monikers in a left-to-right manner and creates a composite of the result. If any of the component monikers do not reduce to themselves (and thus, the generic composite moniker overall does not reduce to itself), then the process of reduction is repeated. In an alternate embodiment, the method tracks component monikers that reduce to themselves and suppresses their re-reduction. In step 2301, if this moniker is already reduced as indicated by the data member m.sub.-- fReduced, then the method continues at step 2302, else the method continues at step 2303. In step 2302, the method sets the pointer to the reduced moniker to point to this moniker and returns indicating that the moniker reduced to itself. In step 2303, if the left moniker is NULL, then the method continues at step 2306, else the method continues at step 2304. In step 2304, the method invokes the method Reduce of the left moniker passing the moniker to the left of this moniker and returning a left reduced moniker (pmkLeftReduced). In step 2305, if no error occurred or the left moniker reduced to itself, then the method continues at step 2306, else the method returns an error. If this moniker has no right moniker (m.sub.-- pmkRight), then the method continues at step 2309, else the method continues at step 2307. In step 2307, the method invokes the method Reduce of the right moniker passing an indicator of a NULL moniker to the left and returning a right reduced moniker (pmkRightReduced). In step 2308, if no error occurred or the right moniker reduced to itself, then the method continues at step 2309, else the method returns an error. In step 2309, if both the left and right monikers reduced to themselves, then the method continues at step 2310, else the method continues at step 2312. In step 2310, the method sets the state of this moniker to reduced (m.sub.-- fReduced). In step 2311, the method sets the pointer to the reduced moniker to point to this moniker and the method returns with an indication that this moniker reduced to itself. In step 2312, the method invokes the method Create of the class CCompositeMoniker passing the left reduced moniker and the right reduced moniker and returning the result as a composite reduced moniker (pmkCompositeReduced). In step 2313, the method sets the state of the composite reduced moniker to reduced (m.sub.-- fReduced). In step 2314, the method sets the pointer to the reduced moniker to point to the composite reduced moniker and returns.

FIG. 24 is a flow diagram of the method Reduce of the sample class CAliasMoniker. The reduction of an alias moniker is illustrated in FIG. 22. In step 2401, if the alias moniker indicates the home directory, then the method continues at step 2402, else the method tests for other types of alias indicated by the ellipsis. In step 2402, the method retrieves the network volume associated with the user. In step 2403, the method retrieves the home directory for the user. In step 2404, the method creates a net volume moniker passing it the name of the network volume. In step 2405, the method creates a file moniker passing it the name of the user's home directory. In step 2406, the method creates a generic composite moniker passing it the net volume moniker and the file moniker. In step 2407, the method sets the generic composite moniker to indicate that it is reduced. In step 2408, the method sets the pointer to the reduced moniker to the composite moniker (pmkCompositeReduced) and returns.

                  CODE TABLE 5
    ______________________________________
    {   A = CreateMoniker (cFileMoniker, "c:.backslash.reports.backslash.expen
        ses.backslash.
        weekly")
        B = CreateMoniker (cFileMoniker, getcurrentusemame)
        C = CreateMoniker (cFileMoniker, dayofweek
        (getcurrentdate-oneday))
        Result = A.smallcircle.B.smallcircle.C
    ______________________________________


CODE TABLE 6 ______________________________________ { A = CreateMoniker (cFileMoniker, "c:/taxes") Prompt "Enter year:", year B = CreateMoniker (cFileMoniker, year) C = CreateMoniker (cFileMoniker, ".backslash.1040.XLS") D = CreateMoniker (cItemMoniker, "R1C1:R10C10") Result A.smallcircle.B.smallcircle.C.smallcircle.D ______________________________________


In a preferred embodiment, a macro moniker allows for arbitrary moniker creation. A macro moniker contains a macro script that controls the reduction of a macro moniker to another moniker. During reduction, the script is parsed and processed by the method Reduce. One skilled in the art would appreciate that parsing and processing macro scripts are well known. The result of the processing is another moniker that is returned as the reduced moniker. For example, Code Table 5 contains a script that directs the macro moniker to reduce to a moniker referencing the directory "c:.backslash.reports.backslash.expenses.backslash.weekly.backslash.user.b ackslash.dayofweek", where user is the current user name (e.g., "Smith") and dayofweek is the day of week of yesterday (e.g., "Thursday"). The macro moniker with the script of Code Table 5 may reduce to a file moniker with a path name of "c:.backslash.reports.backslash.expenses.backslash.weekly.backslash.smith. backslash.thursday". The macro moniker may contain a pointer to the reduced moniker. The method BindToObject of a macro moniker would typically invoke the method Reduce and then invoke the method BindToObject of the reduced moniker. Code Table 6 contains a macro script that directs the macro moniker to reduce to a moniker and in the process prompts the user for a portion of the path.

    ______________________________________
    CODE TABLE 7
    ______________________________________
    { SELECT FIRST printer.name
    FROM CampusPrinter
    WHERE      (printerType = = PostScript OR
               printerType = = PCL)
               AND
               printerLocation
               INCLUDES "Building1"
    ORDER BY printQueueLength
    ______________________________________


In a preferred embodiment, a query moniker allows for arbitrary reduction to a moniker identified by a query. A query moniker contains a query that controls the reduction. The query is evaluated to produce a file moniker that satisfies the query. For example, Code Table 7 contains a query (in a structured query language) that may reduce to the file moniker with path name ".backslash..backslash.printserver10.backslash.printer2". The query evaluates to a list of printers that can accommodate either PostScript or PCL documents and that is in a certain building. The list is sorted by the length of the print queue, and the printer with the shortest print queue is selected.

IMoniker::IsEqual HRESULT IMoniker::IsEqual(pmkOtherMoniker)

This method determines whether this moniker and the specified other moniker (pmkOtherMoniker) reference the same object. This method is used in a preferred implementation of a running object table. The following table describes the parameters of the method IsEqual:

    ______________________________________
    Argument    Type      Description
    ______________________________________
    pmkOuterMoniker
                IMoniker* the other moniker with whom
                          this moniker is compared.
    return value
                HRESULT   S.sub.-- OK, S.sub.-- FALSE
    ______________________________________


FIG. 25 is a flow diagram of the method IsEqual of the class CFileMoniker. In step 2501, if the other moniker (pmkOtherMoniker) is a file moniker, then the method continues at step 2502, else the monikers are not equal and the method returns a false. In step 2502, if the count of anti-monikers for this moniker (m.sub.-- cAnti) is equal to the count of anti-monikers for the other moniker, then the method continues at step 2503, else the monikers are not equal and the method returns a false. In step 2503, if the path for this moniker (m.sub.-- lpszPath) is equal to the path for the other moniker, then the method returns indicating that the monikers are equal, else the method returns indicating that the monikers are not equal.

FIG. 26 is a flow diagram of the method IsEqual of the class CCompositeMoniker. In step 2601, if the other moniker is a composite moniker, then the method continues at step 2602, the method returns indicating that the monikers are not equal. In step 2602, if the left moniker of this moniker (m.sub.-- pmkLeft) is equal to the left moniker of the other moniker, then the method continues at step 2603, else the method returns an indication that the monikers are not equal. In step 2603, if the right moniker of this moniker (m.sub.-- pmkRight) is equal to the right moniker of the other moniker, then the method returns an indication that the monikers are equal, else the method returns an indication that the monikers are not equal. In an alternate embodiment of the method IsEqual, the method checks each component moniker of this moniker and the other moniker to determine if the monikers are equal.

IMoniker::Hash HRESULT IMoniker::Hash(pdwHash)

This method returns a 32-bit integer associated with this moniker. This integer is used for maintaining tables of monikers: the moniker can be hashed to determine a hash bucket in the table, then compared with the method IsEqual against all the monikers presently in that hash bucket. Two monikers that compare as equal have the same hash value. The following table describes the parameters of the method Hash:

    ______________________________________
    Argument Type      Description
    ______________________________________
    pdwHash  DWORD*    the place in which to put the returned
                       hash value.
    return value
             HRESULT   S.sub.-- OK
    ______________________________________


FIG. 27 is a flow diagram of the method Hash of the class CCompositeMoniker. In step 2701, the method invokes the method Hash of the left moniker. In step 2702, the method invokes the method hash of the right component moniker. In step 2703, the method generates the exclusive-or of the left hash value and the right hash value and returns that as the hash value of the method. The method Hash of the class CItemMoniker performs a hash function on the item name and returns the value.

IMoniker::Inverse HRESULT IMoniker::Inverse(ppmk)

The method Inverse returns a moniker that when composed onto the end of this moniker or one of similar structure annihilates it; that is, composes to NULL. The method Inverse is an abstract generalization of the ".." operation in traditional file systems. For example, a file moniker that represents the path "a.backslash.b.backslash.c.backslash.d" has as its inverse a moniker containing the path "...backslash....backslash....backslash...", since "a.backslash.b.backslash.c.backslash.d" composed with "...backslash....backslash....backslash..." yields nothing. The inverse of a moniker does not annihilate just that particular moniker, but all monikers with a similar structure. Thus, the inverse of a generic composite moniker is the reverse composite of the inverse of its component monikers. Certain classes of monikers may have trivial inverses. If a moniker adds one more component moniker to an existing structure, its inverse is a moniker that removes the last component of the existing structure. A moniker that when composed