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 10 - Scripting Components / Using Scripting Component Routines


Compiling and Executing Source Data

This section describes how you can use scripting component routines to obtain source data from users, compile the source data, and execute the compiled script. To create and execute a script using the Script Editor application, a user can type the script, then click the Run button to execute it. Your application can provide similar capabilities.

To allow users to write a new script and then execute it, your application must use scripting component routines to compile and execute the source data. To compile source data in a new script with a new script ID, pass the constant kOSANullScript (rather than an existing script ID) in the last parameter of the OSACompile function. This causes OSACompile to return a new script ID in the same parameter.

To execute a compiled script, your application must specify, in addition to the script ID for the compiled script, a script context: either the corresponding scripting component's default context or a script ID for the global context created by that scripting component. Script contexts maintain state information for the execution of scripts. Your application can use script contexts to control the binding of variables used in scripts that it executes. For example, if your application saves its own global context and reuses it every time a script is executed, the binding of variables used in the script is maintained after the user restarts the computer. If your application does not specify a script context, the AppleScript component uses a single default context whenever it executes the script. A scripting component's default context binds the variables used in the script only until the user quits the application.

To specify a scripting component's default context, pass the constant kOSANullScript in the third parameter of the OSAExecute function; to specify some other global context, pass its script ID in the third parameter.

The MyDoNewScript procedure in Listing 10-2 allows a user to type a script in the appropriate scripting language, then compiles the script, executes the compiled script using a global context provided by the application, and displays the result to the user.

The MyDoNewScript procedure begins by calling the OSAScriptingComponentName function to obtain the name of the scripting component specified by gScriptingComponent. This name is passed to the application-defined function MyGetUserScriptText.

Note
If you are using the generic scripting component, you can use the OSAGetDefaultComponent function to get the subtype code for the default scripting component (that is, the scripting component used by the generic scripting component for new scripts). You can then get an instance of the default scripting component by passing its subtype code to OSAGetScriptingComponent. Finally, you can pass that instance to OSAScriptingComponentName to obtain the default scripting component's name. For more information about the default scripting component and routines you can use with the generic scripting component, see "Generic Scripting Component Routines," which begins on page 10-83.
The MyGetUserScriptText function displays the name of the scripting language to use in a script-editing window or message box that allows the user to type and execute a new script. After it obtains the source data for the new script, the MyDoNewScript procedure sets the scriptID variable to kOSANullScript. The procedure then passes the source data and scriptID to the OSACompile function. When the script ID passed to OSACompile is kOSANullScript, OSACompile returns, in the same parameter, a new script ID for the resulting compiled script. The MyDoNewScript procedure then passes the new script ID to the OSAExecute function.

In addition to a component instance and the script ID for the compiled script to be executed, OSAExecute takes a script ID for a script context and a parameter that contains the mode flags, if any, for script execution. In Listing 10-2, the script ID passed to OSAExecute for the script context is gContext, a global context provided by the application. The constant kOSAModeNull in the next parameter indicates that no mode flags are set for script execution.

Listing 10-2 A routine that compiles and executes source data

PROCEDURE MyDoNewScript;
VAR
   componentName, scriptText, resultText: AEDesc;
   scriptID, resultID:                    OSAID;
   myOSAErr, ignoreErr:                   OSAError;
BEGIN
   {get the scripting component's name so you can show }
   { the user which scripting language to use}
   myOSAErr := OSAScriptingComponentName(gScriptingComponent, 
                                          componentName);
   IF myOSAErr = noErr THEN
   BEGIN       {get the user's script text, then compile it}
      MyGetUserScriptText(componentName, scriptText);
      {to create a new compiled script using the user's script }
      { text, pass kOSANullScript to OSACompile as the script ID }
      { for the script to be compiled}
      scriptID := kOSANullScript;
      myOSAErr := OSACompile(gScriptingComponent, scriptText, 
                              kOSAModeNull, scriptID);
      ignoreErr := AEDisposeDesc(scriptText);
   END;
   IF myOSAErr = noErr THEN
   BEGIN
      {execute the script in a global context}
      myOSAErr := OSAExecute(gScriptingComponent, scriptID, 
                              gContext, kOSAModeNull, resultID);
      ignoreErr := OSADispose(gScriptingComponent, scriptID);
      IF myOSAErr = noErr THEN
      BEGIN
         {convert the script value returned by OSAExecute to }
         { text that can be displayed to the user}
         myOSAErr := OSADisplay(gScriptingComponent, resultID, 
                              typeChar, kOSAModeNull, resultText);
         ignoreErr := OSADispose(gScriptingComponent, resultID);
         {show result to user}
         MyShowUserResult(resultText);
         ignoreErr := AEDisposeDesc(resultText);
      END;
   END;
   IF myOSAErr = errOSAScriptError THEN 
      MyGetScriptErrorInfo;
END;  
If script execution is successful, the MyDoNewScript procedure passes the script ID for the resulting script value to the OSADisplay function and calls the MyShowUserResult procedure to display the script value to the user. It also disposes of the script data for the compiled script. If OSAExecute or OSACompile returns the result code errOSAScriptError, the MyDoNewScript procedure calls the MyGetScriptErrorInfo procedure shown in Listing 10-3, which uses the OSAScriptError function to obtain more information about the error.

Whenever a scripting component routine returns the result code errOSAScriptError, you can use OSAScriptError to obtain more information about the error. The second parameter of the OSAScriptError function is a constant that specifies the kind of error information to be returned, and the third parameter is the descriptor type for the descriptor record in which the additional error information will be returned.

The MyGetScriptErrorInfo procedure in Listing 10-3 calls OSAScriptError three times: once to obtain an error number for either a system error or a scripting component error, once to obtain a text description of the error, and once to obtain error-range information. (For more information about specifying descriptor types for OSAScriptError, see page 10-36.) Finally, the MyGetScriptErrorInfo procedure extracts the starting and ending positions of the error range in the source data and calls the application-defined procedure MyIndicateError to display the error information to the user. Note that your application is responsible for disposing of any descriptor records that are created.

You should use the OSACompile and OSAExecute functions as shown in Listing 10-2 if you expect the user to execute the compiled script several times or manipulate it in some other way. If you want to compile and execute a script just one time and don't need to keep the compiled script in memory after it has been executed, you can use either OSACompileExecute or OSADoScript if these functions are supported by the scripting component you specify.

The OSACompileExecute function takes a component instance, a descriptor record for the source data to be compiled and executed, a context ID, and a modeFlags parameter. It executes the resulting compiled script, disposes of the compiled script, and returns the script ID for the resulting script value.

The OSADoScript function takes a component instance, a descriptor record for source data, a context ID, a text descriptor type, and a modeFlags parameter. It compiles and executes the script, returns a descriptor record for the text that corresponds to the resulting script value, and disposes of both the compiled script and the script value.

Listing 10-3 A procedure that uses OSAScriptError to get information about an execution error

PROCEDURE MyGetScriptErrorInfo; 
TYPE
   OSErrPtr       = ^OSErr;
   OSErrHandle    = ^OSErrPtr;
VAR
   errorMessage:                 Handle;
   startPos, endPos:             Integer;
   desc, recordDesc:             AEDesc;
   actualType:                   DescType;
   actualSize:                   Size;
   scriptErr, myErr, ignoreErr:  OSErr;
   myOSAErr:                     OSAError; 
BEGIN
   myOSAErr := OSAScriptError(gScriptingComponent, 
                           kOSAErrorNumber, typeShortInteger, 
                           desc);
   scriptErr := OSErrHandle(desc.dataHandle)^^;
   ignoreErr := AEDisposeDesc(desc);
   myOSAErr := OSAScriptError(gScriptingComponent, 
                           kOSAErrorMessage, typeChar, desc);
   errorMessage := desc.dataHandle;
   myOSAErr := OSAScriptError(gScriptingComponent, 
                           kOSAErrorRange, typeOSAErrorRange, 
                           desc);
   myErr := AECoerceDesc (desc, typeAERecord, recordDesc);
   ignoreErr := AEDisposeDesc(desc);
   myErr := AEGetKeyPtr(recordDesc, keySourceStart, 
                        typeShortInteger, actualType,
                        Ptr(@startPos), sizeOf(startPos),
                        actualSize);
   myErr := AEGetKeyPtr(recordDesc, keySourceEnd, 
                        typeShortInteger, actualType,
                        Ptr(@endPos), sizeOf(endPos),
                        actualSize);
   ignoreErr := AEDisposeDesc(recordDesc);
   MyIndicateError(scriptErr, errorMessage, startPos, endPos);
   {add your own error checking}
END;  

Previous Book Contents Book Index Next

© Apple Computer, Inc.
7 JUL 1996