Legacy Documentclose button

Important: The information in this document is obsolete and should not be used for new development.

Previous Book Contents Book Index Next

Inside Macintosh: Interapplication Communication /
Chapter 6 - Resolving and Creating Object Specifier Records / Creating Object Specifier Records


Creating a Complex Object Specifier Record

This section describes how to create object specifier records that specify a test or a range. You can specify the object class ID for these object specifier records the same way you would for any other object specifier record. When you create the other three keyword-specified descriptor records, however, you can use additional Apple Event Manager routines and descriptor types to specify any combination of Apple event objects.

Specifying a Test

The key form formTest allows your application to specify key data that identifies one or more elements in the specified container that pass a test. To do so, your application must construct several interconnected descriptor records that specify comparisons and, if necessary, logical expressions.

For example, to specify "the first row in which the First Name column equals 'John' and the Last Name column equals 'Chapman' in the table 'MyAddresses' of the database 'SurfDB,'" your application must construct an object specifier record whose key data describes a logical expression that applies the logical operator AND to two separate comparisons for each row: a comparison of the First Name column to the word "John" and a comparison of the Last Name column to the word "Chapman."

The logical organization of the data for the object specifier record that specifies this test is summarized in Table 6-8 and Table 6-9. (It is also illustrated in Figure 6-3 and Figure 6-4, beginning on page 6-22.) The listings in the remainder of this section demonstrate how to create this object specifier record. For general information about the organization of key data for a test, see "Key Data for a Test," which begins on page 6-16.
Table 6-8 Object specifier record for the first row that meets a test in the table named "MyAddresses"
KeywordDescriptor typeData
keyAEDesiredClasstypeTypecRow
keyAEContainertypeObjectSpecifier(see indented record)
keyAEDesiredClass typeType cRow
keyAEContainer typeObjectSpecifier (see indented record)
keyAEDesiredClass typeType cTable
keyAEContainer typeObjectSpecifier (see indented record)
keyAEDesiredClass typeType cDatabase
keyAEContainer typeNull Data handle is NIL
keyAEKeyForm typeEnumerated formName
keyAEKeyData typeChar "SurfDB"
keyAEKeyForm typeEnumerated formName
keyAEKeyData typeChar "MyAddresses"
keyAEKeyForm typeEnumerated formTest
keyAEKeyData typeLogicalDescriptor (see Table 6-9)
keyAEKeyFormtypeEnumeratedformAbsolutePosition
keyAEKeyDatatypeLongInteger1
Table 6-9 Logical descriptor record that specifies a test
KeywordDescriptor typeData
keyAELogicalOperatortypeEnumeratedkAEAnd
keyAELogicalTermstypeAEList(see indented records)
  typeCompDescriptor (see indented record)
keyAECompOperator typeType kAEEquals
keyAEObject1 typeObjectSpecifier (see indented record)
keyAEDesiredClass typeType cColumn
keyAEContainer typeObjectBeingExamined Data handle is NIL
keyAEKeyForm typeEnumerated formName
keyAEKeyData typeChar "First Name"
keyAEObject2 typeChar "John"
typeCompDescriptor (see indented record)
keyAECompOperator typeType kAEEquals
keyAEObject1 typeObjectSpecifier (see indented record)
keyAEDesiredClass typeType cColumn
keyAEContainer typeObjectBeingExamined Data handle is NIL
keyAEKeyForm typeEnumerated formName
keyAEKeyData typeChar "Last Name"
keyAEObject2 typeChar "Chapman"

Because both the database and the table shown in Table 6-8 are specified by name, it would be convenient to have an application-defined routine that creates an object specifier record that uses the key form formName. The MyCreateFormNameObjSpecifier function shown in Listing 6-16 can be used for this purpose.

Listing 6-16 Creating an object specifier record with the key form formName

FUNCTION MyCreateFormNameObjSpecifier
                        (class: DescType; container: AEDesc; 
                         keyDataName: str255; 
                         VAR resultObjSpecRec: AEDesc): OSErr;
VAR
   keyDataDescRec: AEDesc;
   myErr:          OSErr;
BEGIN
   myErr := AECreateDesc(typeChar, @keyDataName[1], 
                           Length(keyDataName), keyDataDescRec);
   IF myErr = noErr THEN
      myErr := CreateObjSpecifier(class, container, formName,
                                    keyDataDescRec, TRUE,
                                    resultObjSpecRec);
   MyCreateFormNameObjSpecifier := myErr;
END;
The MyCreateFormNameObjSpecifier function shown in Listing 6-16 returns, in the resultObjSpecRec parameter, an object specifier record that describes an Apple event object of the class specified by the class parameter, located in the container specified by the container parameter, with the key form formName and key data specified by the keyDataName parameter. This function is used in Listing 6-19 on page 6-83 to create object specifier records that use the key form formName for the database and the table.

The nested object specifier records shown in Table 6-9 specify "the rows in which the First Name column equals 'John' and the Last Name column equals 'Chapman.'" To identify the rows that pass this test, the Apple Event Manager needs to evaluate two comparisons: the comparison of each row of the First Name column to the word "John," and the comparison of each row of the Last Name column to the word "Chapman."

The Apple Event Manager uses the information in comparison descriptor records to compare the specified elements in a container, one at a time, either to another Apple event object or to the data associated with a descriptor record. The two comparison descriptor records you need to create for this example are summarized in Table 6-9 on page 6-79.

You can use the CreateCompDescriptor function to create a comparison descriptor record, or you can create an AE record and use AECoerceDesc to coerce it to a comparison descriptor record. Listing 6-17 shows an example of an application-defined routine that creates an object specifier record and a descriptor record of typeChar, then uses the CreateCompDescriptor function to add them to a comparison descriptor record.

Listing 6-17 Creating a comparison descriptor record

FUNCTION MyCreateComparisonDescRec (VAR compDesc: AEDesc;
                                    colName: str255; 
                                    name: str255): OSErr;
VAR
   logicalContainer, colNameDesc, nameDesc:  AEDesc;
   myObjectExaminedContainer:                AEDesc;
   myErr:                                    OSErr;
BEGIN
   {create the object specifier record for keyAEObject1; }
   { first create container}
   myErr := AECreateDesc(typeObjectBeingExamined, NIL, 0,
                           myObjectExaminedContainer);
   {create key data}
   IF myErr = noErr THEN
      myErr := AECreateDesc(typeChar, @colName[1],
                            Length(colName), colNameDesc);
   {now create the object specifier record}
   IF myErr = noErr THEN
      myErr := CreateObjSpecifier(cColumn,
                                  myObjectExaminedContainer, 
                                  formName, colNameDesc, TRUE,
                                  logicalContainer);
   {create the descriptor record for keyAEObject2}
   IF myErr = noErr THEN
      myErr := AECreateDesc(typeChar, @name[1], Length(name), 
                            nameDesc);
   {create the first logical term (comp descriptor record)}
   IF myErr = noErr THEN
      myErr := CreateCompDescriptor(kAEEquals, logicalContainer,
                                    nameDesc, TRUE, compDesc);
   MyCreateComparisonDescRec := myErr;
END; 
The MyCreateComparisonDescRec function takes two strings and uses them to create a comparison descriptor record. The string passed in the second parameter specifies the name of the column whose contents should be compared to the string passed in the third parameter. First, the MyCreateComparisonDescRec function uses AECreateDesc to create a descriptor record of typeObjectBeingExamined, which is returned in the variable myObjectExaminedContainer. Next, AECreateDesc creates a descriptor record of descriptor type typeChar, whose data consists of the string in the variable colName, and which is returned in the variable colNameDesc. The code then passes the variables myObjectExaminedContainer and colNameDesc to the CreateObjSpecifier function, which uses them to create an object specifier record, returned in the logicalContainer variable, that becomes the keyword-specified descriptor record with the keyword keyAEObject1.

Next, the MyCreateComparisonDescRec function uses AECreateDesc and the name parameter to create the descriptor record for keyAEObject2, which AECreateDesc returns in the nameDesc variable. Finally, the code passes the constant kAEEquals, the variable logicalContainer, and the variable nameDesc to the CreateCompDescriptor function, which creates a comparison descriptor record that allows the Apple Event Manager (with the help of object-comparison functions provided by the server application) to determine whether the specified column in the row currently being checked equals the specified string.

You can use the MyCreateComparisonDescRec function to create both the descriptor records of type typeCompDescriptor shown in Table 6-9 on page 6-79. These descriptor records provide two logical terms for a logical descriptor record. The entire logical descriptor record corresponds to the logical expression "the First Name column equals 'John' AND the Last Name column equals 'Chapman.'"

You can use the CreateLogicalDescriptor function to create a logical descriptor record, or you can create an AE record and use the AECoerceDesc function to coerce it to a comparison descriptor record. Listing 6-18 shows an application-defined function that adds two comparison descriptor records to a descriptor list, then uses the CreateLogicalDescriptor function to create a logical descriptor record whose logical terms are the two comparison descriptor records.

Listing 6-18 Creating a logical descriptor record

FUNCTION MyCreateLogicalDescRec (VAR compDesc1, compDesc2: AEDesc;
                                 logicalOperator: DescType;
                                 VAR logicalDesc: AEDesc): OSErr;
VAR
   logicalTermsList: AEDescList;
   myErr:            OSErr;
BEGIN
   {create a logical descriptor record that contains two }
   { comparison descriptor records}
   {first create a list}
   myErr := AECreateList(NIL, 0, FALSE, logicalTermsList);
   IF myErr = noErr THEN
      myErr := AEPutDesc(logicalTermsList, 1, compDesc1);
   IF myErr = noErr THEN
      myErr := AEPutDesc(logicalTermsList, 2, compDesc2);
   IF myErr = noErr THEN
      myErr := AEDisposeDesc(compDesc1);
   IF myErr = noErr THEN
      myErr := AEDisposeDesc(compDesc2);
   IF myErr = noErr THEN
      myErr := CreateLogicalDescriptor(logicalTermsList,
                                       logicalOperator, TRUE,
                                       logicalDesc);
   MyCreateLogicalDescRec := myErr;
END;
Listing 6-19 uses the application-defined functions shown in Listing 6-16, Listing 6-17, and Listing 6-18 to build the object specifier record illustrated in Table 6-8 and Table 6-9.

Listing 6-19 Creating a complex object specifier record

FUNCTION MyCreateObjSpecRec (VAR theResultObj: AEDesc): OSErr;
VAR
   nullContainer, databaseContainer, tableContainer:  AEDesc;
   compDesc1, compDesc2:                              AEDesc;
   logicalTestDesc, rowTestContainer, rowOffset:      AEDesc;
   myErr:                                             OSErr;




BEGIN
   {create a null container}
   myErr := AECreateDesc(typeNull, NIL, 0, nullContainer);
   {create a container for the database}
   IF myErr = noErr THEN
      myErr := MyCreateFormNameObjSpecifier(cDatabase, nullContainer,
                                            'SurfDB', databaseContainer);
   {create a container for the table}
   IF myErr = noErr THEN
      myErr := MyCreateFormNameObjSpecifier(cTable, databaseContainer, 
                                            'MyAddresses', tableContainer);
   {create a container for the row--an object specifier record that }
   { specifies a test (the row whose First Name column = 'John' and }
   { Last Name column = 'Chapman')}

   {create the first comparison descriptor record}
   IF myErr = noErr THEN
      myErr := MyCreateComparisonDescRec(compDesc1, 'First Name', 'John'); 
   {create the second comparison descriptor record}
   IF myErr = noErr THEN
      myErr := MyCreateComparisonDescRec(compDesc2, 'Last Name', 'Chapman'); 

   {create the logical descriptor record}
   IF myErr = noErr THEN
      myErr := MyCreateLogicalDescRec(compDesc1, compDesc2, kAEAND, 
                                       logicalTestDesc);

   {now create the object specifier record that specifies the test}
   IF myErr = noErr THEN
      myErr := CreateObjSpecifier(cRow, tableContainer, formTest,
                                  logicalTestDesc, TRUE, rowTestContainer);

   {create the object specifier record for the Apple event object}
   {first, create the descriptor record for the key data}
   IF myErr = noErr THEN
      myErr := CreateOffsetDescriptor (1, rowOffset);
   {now create the object specifier record}
   IF myErr = noErr THEN
      myErr := CreateObjSpecifier (cRow, rowTestContainer, 
                                    formAbsolutePosition, rowOffset, 
                                    TRUE, theResultObj);
   MyCreateObjSpecRec := myErr;
END;
The MyCreateObjSpecRec function shown in Listing 6-19 begins by using AECreateDesc to create a null descriptor record, then uses the MyCreateFormNameObjSpecifier function (shown in Listing 6-16) to specify the default container for the database named "SurfDB." The code then calls the MyCreateFormNameObjSpecifier function again, this time passing the object specifier record for SurfDB to specify the container for the table "MyAddresses." The next two calls are both to the MyCreateComparisonDescRec function (shown in Listing 6-17), which creates the comparison descriptor records that allow the Apple Event Manager to compare the First Name column and Last Name column to the names "John" and "Chapman," respectively. The next call passes these two comparison descriptor records to the MyCreateLogicalDescRec function (shown in Listing 6-18) in the compDesc1 and compDesc2 variables.

Now all the components of the logical descriptor record are ready to assemble. The next call, to CreateObjSpecifier, specifies the logical descriptor record in the logicalTestDesc variable as the key data for the object specifier record that specifies the test. A call to the Apple Event Manager routine CreateOffsetDescriptor then creates an offset descriptor record that contains the integer 1. Finally, the code passes the offset descriptor record to the CreateObjSpecifier function in the rowOffset variable to create the final object specifier record, which describes the requested row as the first row that passes the test.

The CreateOffsetDescriptor function creates a descriptor record of type typeLongInteger that can be used as the key data with a key form of formAbsolutePosition to indicate an element's offset within its container. A positive integer indicates an offset from the beginning of the container (the first element has an offset of 1), and a negative integer indicates an offset from the end of the container (the last element has an offset of -1). Using CreateOffsetDescriptor accomplishes the same thing as setting a variable to an integer and passing the variable to AECreateDesc to create a descriptor record of type typeLongInteger.

Specifying a Range

The key form formRange allows your application to specify key data that identifies a range of elements in the specified container. To do so, your application must first create a range descriptor record. The Apple Event Manager uses a range descriptor record to identify the two Apple event objects that specify the beginning and end of a range of elements.

For example, an object specifier record for a range of text in a document could specify the table named "Summary of Sales" as the first boundary object and the figure named "Best-Selling Widgets for 1991" as the second boundary object for a range that consists of all the text between the table and the figure. Any word processor that keeps track of the relative positions of text, tables, and figures should be capable of supporting such a request.

Table 6-10 summarizes the logical organization of the data for the object specifier record that specifies this range. For general information about the organization of data within a range descriptor record, see "Key Data for a Range" on page 6-23.
Table 6-10 A range descriptor record
KeywordDescriptor typeData
keyAERangeStarttypeObjectSpecifier(see indented record)
keyAEDesiredClass typeType cTable
keyAEContainer typeCurrentContainer Data handle is NIL
keyAEKeyForm typeEnumerated formName
keyAEKeyData typeChar "Summary of Sales"
keyAERangeStoptypeObjectSpecifier(see indented record)
keyAEDesiredClass typeType cFigure
keyAEContainer typeCurrentContainer Data handle is NIL
keyAEKeyForm typeEnumerated formName
keyAEKeyData typeChar "Best-Selling Widgets
for 1991"

You can use the CreateRangeDescriptor function to create a range descriptor record, or you can create an AE record and use AECoerceDesc to coerce it to a range descriptor record. Listing 6-20 provides an example of an application-defined routine that creates two object specifier records, then uses the CreateRangeDescriptor function to add them to a range descriptor record.

The container for the boundary objects in the range descriptor record created by
Listing 6-20 is the same as the container for the range itself. The object specifier record for the range's container is added to an object specifier record of key form formRange at the same time that the range descriptor record is added as key data. The container for the two boundary objects can therefore be specified in the range descriptor record by a descriptor record of type typeCurrentContainer whose data handle has the value NIL. The Apple Event Manager interprets this as a placeholder for the range's container when it is resolving the range descriptor record.

Listing 6-20 Creating a range descriptor record

FUNCTION MyCreateRangeDescriptor (VAR rangeDescRec: AEDesc): OSErr;
VAR
   rangeStart:          AEDesc;
   rangeEnd:            AEDesc;
   currentContainer:    AEDesc;
   tableNameDescRec:    AEDesc;
   figureNameDescRec:   AEDesc;
   myErr:               OSErr;
BEGIN
{create the object specifier record for the start of the range }
{ (the table named 'Summary of Sales' in 'MyDoc' document)}

   {create a descriptor record of type typeCurrentContainer}
   myErr := AECreateDesc(typeCurrentContainer, NIL, 0, currentContainer);

   {create the object specifier record}
   IF myErr = noErr THEN
      myErr := MyCreateNameDescRec(tableNameDescRec, 
                                    'Summary of Sales');
   IF myErr = noErr THEN
   myErr := CreateObjSpecifier(cTable, currentContainer, formName,
                                 tableNameDescRec, FALSE, rangeStart);
   
   myErr := AEDisposeDesc(tableNameDescRec);
   {create the object specifier record for the end of the range }
   { (the figure named 'Best-Selling Widgets...' in 'MyDoc') }
   IF myErr = noErr THEN
      myErr := MyCreateNameDescRec(figureNameDescRec, 
                                    'Best-Selling Widgets for 1991');

   IF myErr = noErr THEN
      myErr := CreateObjSpecifier(cFigure, currentContainer, formName,
                                 figureNameDescRec, TRUE, rangeEnd);

   {now create the range descriptor record}
   IF myErr = noErr THEN
      myErr := CreateRangeDescriptor(rangeStart, rangeEnd, TRUE, 
                                       rangeDescRec);
   MyCreateRangeDescriptor := myErr;
END;
After creating a descriptor record of type typeCurrentContainer and a descriptor record for the first table's name, Listing 6-20 uses the CreateObjSpecifier function to create an object specifier record that identifies the beginning of the range. The parameters to CreateObjSpecifier specify that the beginning of the range is an Apple event object of the object class cTable in the current container, with a key form of formName and key data that identifies the table by name. A second call to CreateObjSpecifier creates the object specifier record that identifies the end of the range--an Apple event object of the cFigure object class in the current container, with a key form of formName and key data that identifies the figure by name. Finally, the code in Listing 6-20 uses the CreateRangeDescriptor function to create the range descriptor record, using the two previously created object specifier records to specify the beginning and end of the range.


Previous Book Contents Book Index Next

© Apple Computer, Inc.
7 JUL 1996