Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
Sources/MSASSubroutines.c
// MSASSubroutines.c |
// |
// Original version by Jon Lansdell and Nigel Humphreys. |
// 4.0 and 3.1 updates by Greg Sutton. |
// Human Interface changes and GX Printing by Don Swatman |
// ©Apple Computer Inc 1996, all rights reserved. |
#include "MSASSubroutines.h" |
#include <AppleScript.h> |
#include <Resources.h> |
#include <AERegistry.h> |
#include <ASRegistry.h> |
#include <TextUtils.h> |
#ifdef THINK_C |
#include "PLStrs.h" |
#else |
#include <PLStringFuncs.h> |
#endif |
#include "MSAppleEvents.h" |
#include "MSAEUtils.h" |
#include "MSGlobals.h" |
#include "MSWindow.h" |
const short kSEScriptID = 128; |
extern ComponentInstance gScriptingComponent; |
#ifdef THINK_C |
extern pascal StringPtr PLstrcpy(StringPtr str1, StringPtr str2); |
extern pascal StringPtr PLstrcat(StringPtr str1, StringPtr str2); |
#endif |
AEIdleUPP gAEIdleUPP; |
OSAID gScript1ID; |
OSAID gScript2ID; |
// Script 3 targets a script application - its script is not loaded |
OSAID gScript4ID; |
OSAID gScript5ID; |
// Variables to target script application |
ProcessSerialNumber gScriptAppPSN; |
AEDesc gScriptAppAddress; |
Str31 gScript1Name = "\pscript shift"; |
Str31 gScript2Name = "\pscript datestring"; |
Str31 gScript3Name = "\pscript topseeturvee"; |
Str31 gScript4Name = "\pscript changecreator"; |
Str31 gScript5Name = "\pscript get/set selection"; |
// Launch an application into the background given an FSSpec |
OSErr FSSpecLaunchApplication(const FSSpec *fileSpec, ProcessSerialNumber *PSN) |
{ |
LaunchParamBlockRec launchRec; |
OSErr err; |
launchRec.launchBlockID = extendedBlock; |
launchRec.launchEPBLength = extendedBlockLen; |
launchRec.launchFileFlags = 0; |
launchRec.launchControlFlags = launchContinue + launchNoFileFlags + launchDontSwitch; |
launchRec.launchAppSpec = (FSSpecPtr)fileSpec; |
launchRec.launchAppParameters = nil; |
err = LaunchApplication(&launchRec); |
if (err == noErr) |
*PSN = launchRec.launchProcessSN; |
return(err); |
} |
// Set up the scripts we can send AppleEvents to them. |
// Launch the script application. |
void SetUpScripts( void ) |
{ |
FSSpec aSpec; |
OSErr err; |
aSpec.vRefNum = gAppRec.theSpec.vRefNum; |
aSpec.parID = gAppRec.theSpec.parID; |
gAEIdleUPP = NewAEIdleProc(IdleProc); // Universal Procedure - only used in here |
PLstrcpy( aSpec.name, gScript1Name ); |
(void)LoadScriptFromResFile( &aSpec, kSEScriptID, &gScript1ID ); |
PLstrcpy( aSpec.name, gScript2Name ); |
(void)LoadScriptFromResFile( &aSpec, kSEScriptID, &gScript2ID ); |
PLstrcpy( aSpec.name, gScript3Name ); |
err = FSSpecLaunchApplication( &aSpec, &gScriptAppPSN ); |
if (err == noErr) |
AECreateDesc( typeProcessSerialNumber,(Ptr)&gScriptAppPSN, |
sizeof( ProcessSerialNumber ), &gScriptAppAddress ); |
else |
gScriptAppAddress.dataHandle = NULL; |
PLstrcpy( aSpec.name, gScript4Name ); |
(void)LoadScriptFromResFile( &aSpec, kSEScriptID, &gScript4ID ); |
PLstrcpy( aSpec.name, gScript5Name ); |
(void)LoadScriptFromResFile( &aSpec, kSEScriptID, &gScript5ID ); |
} |
// Given a FileSpec open the resource fork and Load the script resource of resID. |
// The resource file will be closed afterwards. |
OSErr LoadScriptFromResFile( FSSpec *theSpec, short theResID, OSAID *theScriptID ) |
{ |
short aFileRef; |
OSErr err; |
*theScriptID = kOSANullScript; |
aFileRef = FSpOpenResFile( theSpec, fsRdPerm ); |
err = ResError( ); |
if ( noErr == err && aFileRef > 0 ) |
{ |
err = LoadScriptFromResFileRef( aFileRef, theResID, theScriptID ); |
CloseResFile( aFileRef ); |
} |
return err; |
} |
// Given a file reference number for a resource file, and a resource ID |
// for a 'scpt' resource, this routine loads the already compiled script |
// and sets theScriptID to the components reference for it. |
OSErr LoadScriptFromResFileRef( short theRefNum, short theResID, OSAID *theScriptID ) |
{ |
short saveRefNum = CurResFile(); // save current resource |
AEDesc aScriptDesc = { typeNull, NULL }; |
Handle aHandle; |
OSErr err; |
*theScriptID = kOSANullScript; // NULL before we do anything |
if ( ! theRefNum ) |
return errAENoSuchObject; |
UseResFile( theRefNum ); // set this resource to be current |
aHandle = (Handle)Get1Resource( kOSAScriptResourceType, theResID ); |
err = ResError( ); |
if ( noErr != err ) goto done; |
HLock(aHandle); |
err = AECreateDesc( typeOSAGenericStorage, (Ptr)*aHandle, |
GetHandleSize( aHandle ), &aScriptDesc ); |
HUnlock(aHandle); |
if ( noErr != err ) goto done; |
err = OSALoad( gScriptingComponent, &aScriptDesc, |
kOSAModeNull, theScriptID ); |
done: |
if ( aHandle ) |
ReleaseResource( aHandle ); |
UseResFile( saveRefNum ); // reset back to resource previously set |
(void)AEDisposeDesc( &aScriptDesc ); |
return err; |
} |
// Store the scipt ID as a 'scpt' resource, in file given, with the ID given. |
OSErr StoreScriptToResFile(FSSpec *theSpec, short theResID, OSAID theScriptID, StringPtr theResName ) |
{ |
short aFileRef; |
OSErr err; |
if ( theScriptID == kOSANullScript ) |
return errAENoSuchObject; |
aFileRef = FSpOpenResFile( theSpec, fsWrPerm ); |
err = ResError( ); |
if ( noErr == err && aFileRef > 0 ) |
{ |
err = StoreScriptToResFileRef( aFileRef, theResID, theScriptID, theResName ); |
CloseResFile( aFileRef ); |
} |
return err; |
} |
OSErr StoreScriptToResFileRef( short theFileRef, short theResID, OSAID theScriptID, StringPtr theResName ) |
{ |
short saveRefNum = CurResFile(); // save current resource file |
AEDesc scriptData = { typeNull,NULL }; |
Handle aHandle; |
OSErr err; |
if ( kOSANullScript == theScriptID ) |
return noErr; // No script to store so that's okay |
if ( ! theFileRef ) |
return fnfErr; |
UseResFile( theFileRef ); // set this resource to be current |
err = (OSErr)OSAStore( gScriptingComponent, theScriptID, |
typeOSAGenericStorage, kOSAModeNull, &scriptData ); |
if ( noErr != err ) goto done; |
// Write over current script |
aHandle = Get1Resource( kOSAScriptResourceType, theResID ); |
if ( aHandle ) |
{ |
RemoveResource( aHandle ); // Disposed of in current resource file |
err = ResError( ); |
if ( noErr != err ) goto done; |
} |
aHandle = scriptData.dataHandle; |
HLock( aHandle ); |
HandToHand( &aHandle ); |
AddResource( aHandle, typeOSAGenericStorage, theResID, theResName ); |
HUnlock( aHandle ); |
err = ResError( ); |
done: |
UpdateResFile( saveRefNum ); |
(void)AEDisposeDesc( &scriptData ); |
return err; |
} |
// Quit the script application, store changes to scripts and dispose of scripts. |
OSErr CleanUpAEScripts(void) |
{ |
AppleEvent myAppleEvent = {typeNull,NULL}, |
ignoreReply = {typeNull,NULL}; |
FSSpec fileSpec; |
OSErr err; |
// Quit the script application we launched |
if (gScriptAppAddress.dataHandle) |
{ |
err = AECreateAppleEvent(kCoreEventClass, kAEQuitApplication, &gScriptAppAddress, |
0, 0, &myAppleEvent); |
if (err == noErr) |
err = AESend(&myAppleEvent, &ignoreReply, kAENoReply + kAEAlwaysInteract, |
kAENormalPriority, kAEDefaultTimeout, NULL, NULL); |
AEDisposeDesc(&myAppleEvent); |
} |
// Store the scripts used - this saves any changed properties and aliases |
fileSpec.vRefNum = gAppRec.theSpec.vRefNum; |
fileSpec.parID = gAppRec.theSpec.parID; |
PLstrcpy( fileSpec.name, gScript1Name ); |
StoreScriptToResFile( &fileSpec, kSEScriptID, gScript1ID, gScript1Name ); |
PLstrcpy( fileSpec.name, gScript2Name ); |
StoreScriptToResFile( &fileSpec, kSEScriptID, gScript2ID, gScript2Name ); |
PLstrcpy( fileSpec.name, gScript4Name ); |
StoreScriptToResFile( &fileSpec, kSEScriptID, gScript4ID, gScript4Name ); |
PLstrcpy( fileSpec.name, gScript5Name ); |
StoreScriptToResFile( &fileSpec, kSEScriptID, gScript5ID, gScript5Name ); |
(void)OSADispose( gScriptingComponent, gScript1ID ); |
(void)OSADispose( gScriptingComponent, gScript2ID ); |
(void)OSADispose( gScriptingComponent, gScript4ID ); |
(void)OSADispose( gScriptingComponent, gScript5ID ); |
return(err); |
} |
// Calls a script subroutine that takes two window names or numbers. |
// If a window doesn't exist then it is created, one window is then |
// moved below the other. |
// Uses predefined label parameters. |
// on shift around winMove below winStay |
OSErr ExecuteScript1(DPtr theDoc) |
{ |
#ifdef __MWERKS__ |
#pragma unused (theDoc) |
#endif |
AppleEvent myAppleEvent = {typeNull,NULL}, |
ignoreReply = {typeNull,NULL}; |
AEDesc selfAddress; |
OSErr myErr; |
Str255 handlerName = "\pshift", |
below = "\pBelow", |
above = "\pAbove"; |
if (gScript1ID == kOSANullScript) |
return(noErr); |
myErr = MakeSelfAddress(&selfAddress); |
if (myErr != noErr) return noErr; |
// Set up a subroutine AppleEvent |
myErr = AECreateAppleEvent(kASAppleScriptSuite, kASSubroutineEvent, &selfAddress, |
kAutoGenerateReturnID, kAnyTransactionID, &myAppleEvent); |
// Add the name of the subroutine |
if (myErr == noErr) |
myErr = AEPutParamPtr(&myAppleEvent, keyASSubroutineName, typeChar, |
(Ptr)&handlerName[1], handlerName[0]); |
// Add the first predefined label parameter |
if (myErr == noErr) |
myErr = AEPutParamPtr(&myAppleEvent, keyASPrepositionAround, typeChar, |
(Ptr)&below[1], below[0]); |
// Add the second predefined label parameter |
if (myErr == noErr) |
myErr = AEPutParamPtr(&myAppleEvent, keyASPrepositionBelow, typeChar, |
(Ptr)&above[1], above[0]); |
if (myErr == noErr) |
myErr = OSADoEvent(gScriptingComponent, &myAppleEvent, gScript1ID, |
kOSAModeAlwaysInteract, &ignoreReply); |
(void)AEDisposeDesc( &selfAddress ); |
(void)AEDisposeDesc( &myAppleEvent ); |
(void)AEDisposeDesc( &ignoreReply ); |
return(myErr); |
} |
// Calls a subroutine that returns the date and/or time depending |
// on parameters sent. |
// Uses subroutine defined label parameters. |
// on datestring given wDate:fDate, wTime:fTime |
OSErr ExecuteScript2(DPtr theDoc) |
{ |
#ifdef __MWERKS__ |
#pragma unused (theDoc) |
#endif |
AppleEvent myAppleEvent = {typeNull,NULL}, |
myReply = {typeNull,NULL}; // Need to NULL for OSADoEvent() routine |
AEDesc selfAddress, |
textDesc; |
AEDescList paramList = {typeNull,NULL}; |
OSErr myErr; |
Str255 pStr = "\pdatestring"; |
if (gScript2ID == kOSANullScript) |
return(noErr); |
myErr = MakeSelfAddress(&selfAddress); |
if (myErr != noErr) return noErr; |
// Create an AppleScript subroutine AppleEvent |
myErr = AECreateAppleEvent(kASAppleScriptSuite, kASSubroutineEvent, &selfAddress, |
kAutoGenerateReturnID, kAnyTransactionID, &myAppleEvent); |
// Specify the routine by it's name |
if (myErr == noErr) |
myErr = AEPutParamPtr(&myAppleEvent, keyASSubroutineName, typeChar, |
(Ptr)&pStr[1], pStr[0]); |
// Create list for user defined label parameters |
if (myErr == noErr) |
myErr = AECreateList(NULL, 0 , false, ¶mList); |
if (myErr == noErr) |
{ // Make sure label name is in lower case |
PLstrcpy(pStr,"\pwdate"); |
myErr = AEPutPtr(¶mList, 0 ,typeChar ,(Ptr)&pStr[1], pStr[0]); |
if (myErr == noErr) myErr = AEPutPtr(¶mList, 0, typeTrue , NULL, 0); |
} |
if (myErr == noErr) |
{ |
PLstrcpy(pStr,"\pwtime"); |
myErr = AEPutPtr(¶mList, 0 ,typeChar ,(Ptr)&pStr[1], pStr[0]); |
if (myErr == noErr) AEPutPtr(¶mList, 0, typeFalse , NULL, 0); |
} |
// Add list to AppleEvent |
if (myErr == noErr) |
myErr = AEPutParamDesc(&myAppleEvent, keyASUserRecordFields, ¶mList); |
if (myErr == noErr) |
myErr = OSADoEvent(gScriptingComponent, &myAppleEvent, gScript2ID, |
kOSAModeAlwaysInteract, &myReply); |
AEDisposeDesc(&selfAddress); |
AEDisposeDesc(&myAppleEvent); |
AEDisposeDesc(¶mList); |
if (myErr == noErr) |
myErr = GetTextDescFromReply(&myReply, &textDesc); |
if (myErr == noErr) |
myErr = SetSelection(&textDesc); |
AEDisposeDesc(&textDesc); |
AEDisposeDesc(&myReply); |
return(myErr); |
} |
// First of all gets the current selection. Then calls a script application |
// subroutine to twist the text in the selection. Finally it sets the selection |
// with the result. |
// Uses a positional parameter. |
// on topseeturvee(someText) |
OSErr ExecuteScript3(DPtr theDoc) |
{ |
#ifdef __MWERKS__ |
#pragma unused (theDoc) |
#endif |
AppleEvent myAppleEvent = {typeNull,NULL}, |
myReply = {typeNull,NULL}; |
AEDescList paramList = {typeNull,NULL}, |
textDesc; |
OSErr myErr; |
Str255 pStr = "\ptopseeturvee"; |
if (! gScriptAppAddress.dataHandle) |
return(noErr); |
// Get the current selection of the front window |
myErr = GetSelection(&textDesc); |
// Create a subroutine AppleEvent |
if (myErr == noErr) |
myErr = AECreateAppleEvent(kASAppleScriptSuite, kASSubroutineEvent, &gScriptAppAddress, |
kAutoGenerateReturnID, kAnyTransactionID, &myAppleEvent); |
// Add the name of the subroutine |
if (myErr == noErr) |
myErr = AEPutParamPtr(&myAppleEvent, keyASSubroutineName, typeChar, |
(Ptr)&pStr[1], pStr[0]); |
// Create positional parameter list |
if (myErr == noErr) |
myErr = AECreateList(NULL, 0 ,false, ¶mList); |
// Add textDesc as positional parameter |
if (myErr == noErr) |
myErr = AEPutDesc(¶mList, 0, &textDesc); |
// Add positional parameter list |
if (myErr == noErr) |
myErr = AEPutParamDesc(&myAppleEvent, keyDirectObject, ¶mList); |
if (myErr == noErr) |
myErr = AESend(&myAppleEvent, &myReply, kAEWaitReply + kAEAlwaysInteract, |
kAENormalPriority, kAEDefaultTimeout, gAEIdleUPP, NULL); |
AEDisposeDesc(&myAppleEvent); |
AEDisposeDesc(¶mList); |
// Dispose of textDesc before we get one in reply |
AEDisposeDesc(&textDesc); |
if (myErr == noErr) |
myErr = GetTextDescFromReply(&myReply, &textDesc); |
if (myErr == noErr) |
{ |
myErr = SetSelection(&textDesc); |
AEDisposeDesc(&textDesc); |
} |
AEDisposeDesc(&myReply); |
return(myErr); |
} |
// Calls script subroutine that changes a given file's creator |
// to the creator specified. |
// Uses direct and predefined label parameters. |
// on changecreator of aSpec into aCreator |
OSErr ExecuteScript4(DPtr theDoc) |
{ |
AppleEvent myAppleEvent = {typeNull,NULL}, |
ignoreReply = {typeNull,NULL}; |
AEDesc selfAddress; |
AEDescList paramList = {typeNull,NULL}; |
OSErr myErr; |
Str255 pStr = "\pchangecreator"; |
if (gScript4ID == kOSANullScript) |
return(noErr); |
myErr = MakeSelfAddress(&selfAddress); |
if (myErr != noErr) return myErr; |
// Create a subroutine AppleEvent |
myErr = AECreateAppleEvent(kASAppleScriptSuite, kASSubroutineEvent, &selfAddress, |
kAutoGenerateReturnID, kAnyTransactionID, &myAppleEvent); |
// Add the name of the subroutine |
if (myErr == noErr) |
myErr = AEPutParamPtr(&myAppleEvent, keyASSubroutineName, typeChar, |
(Ptr)&pStr[1], pStr[0]); |
// Add the direct parameter |
if (myErr == noErr) |
myErr = AEPutParamPtr(&myAppleEvent, keyDirectObject, typeFSS, |
(Ptr)&(theDoc->theFSSpec), sizeof(FSSpec)); |
// Add the subroutine parameter label |
if (myErr == noErr) |
{ |
PLstrcpy(pStr, "\pToyS"); |
myErr = AEPutParamPtr(&myAppleEvent, keyASPrepositionInto, typeChar, |
(Ptr)&pStr[1], pStr[0]); |
} |
if (myErr == noErr) |
myErr = OSADoEvent(gScriptingComponent, &myAppleEvent, gScript4ID, |
kOSAModeAlwaysInteract, &ignoreReply); |
AEDisposeDesc(&selfAddress); |
AEDisposeDesc(&myAppleEvent); |
AEDisposeDesc(&ignoreReply); |
return(myErr); |
} |
// Calls script subroutine to get this application's selection. |
// Uses no parameters except for subroutine name. |
// on getselection() |
OSErr GetSelection(AEDesc *textDesc) |
{ |
AppleEvent myAppleEvent = {typeNull,NULL}, |
myReply = {typeNull,NULL}; |
AEDesc selfAddress; |
OSErr myErr; |
Str255 pStr = "\pgetselection"; |
if (gScript5ID == kOSANullScript) |
return(noErr); |
myErr = MakeSelfAddress(&selfAddress); |
if (myErr != noErr) return myErr; |
// Create an AppleScript subroutine AppleEvent |
myErr = AECreateAppleEvent(kASAppleScriptSuite, kASSubroutineEvent, &selfAddress, |
kAutoGenerateReturnID, kAnyTransactionID, &myAppleEvent); |
// Specify the routine by it's name |
if (myErr == noErr) |
myErr = AEPutParamPtr(&myAppleEvent, keyASSubroutineName, typeChar, |
(Ptr)&pStr[1], pStr[0]); |
if (myErr == noErr) |
myErr = OSADoEvent(gScriptingComponent, &myAppleEvent, gScript5ID, |
kOSAModeAlwaysInteract, &myReply); |
myErr = GetTextDescFromReply(&myReply, textDesc); |
AEDisposeDesc(&selfAddress); |
AEDisposeDesc(&myAppleEvent); |
AEDisposeDesc(&myReply); |
return(myErr); |
} |
// Calls script subroutine to set this application's selection. |
// Uses a positional parameter. |
// setselection(aString) |
OSErr SetSelection(AEDesc *textDesc) |
{ |
AppleEvent myAppleEvent = {typeNull,NULL}, |
myReply = {typeNull,NULL}; |
AEDesc selfAddress; |
AEDescList paramList = {typeNull,NULL}; |
OSErr myErr; |
Str255 pStr = "\psetselection"; |
if (gScript5ID == kOSANullScript) |
return(noErr); |
myErr = MakeSelfAddress(&selfAddress); |
if (myErr != noErr) return myErr; |
// Create an AppleScript subroutine AppleEvent |
myErr = AECreateAppleEvent(kASAppleScriptSuite, kASSubroutineEvent, &selfAddress, |
kAutoGenerateReturnID, kAnyTransactionID, &myAppleEvent); |
// Specify the routine by it's name |
if (myErr == noErr) |
myErr = AEPutParamPtr(&myAppleEvent, keyASSubroutineName, typeChar, |
(Ptr)&pStr[1], pStr[0]); |
// Create positional parameter list |
if (myErr == noErr) |
myErr = AECreateList(NULL, 0 ,false, ¶mList); |
// Add textDesc as positional parameter |
if (myErr == noErr) |
myErr = AEPutDesc(¶mList, 0, textDesc); |
// Add positional parameter list |
if (myErr == noErr) |
myErr = AEPutParamDesc(&myAppleEvent, keyDirectObject, ¶mList); |
if (myErr == noErr) |
myErr = OSADoEvent(gScriptingComponent, &myAppleEvent, gScript5ID, |
kOSAModeAlwaysInteract, &myReply); |
AEDisposeDesc(&selfAddress); |
AEDisposeDesc(&myAppleEvent); |
AEDisposeDesc(¶mList); |
AEDisposeDesc(&myReply); |
return(myErr); |
} |
// Takes a reply and tries to get a text descriptor from it. |
OSErr GetTextDescFromReply(AEDesc *aReply, AEDesc *textDesc) |
{ |
OSErr myErr; |
textDesc->descriptorType = typeNull; |
textDesc->dataHandle = NULL; |
myErr = AEGetParamDesc(aReply, keyAEResult, typeChar, textDesc); |
return(myErr); |
} |
void EnableAEScriptItems(Boolean fEnable) |
{ |
SetMenuItemState ( (fEnable && kOSANullScript != gScript1ID), myMenus[subroutineM], cScript1); |
SetMenuItemState ( (fEnable && kOSANullScript != gScript2ID), myMenus[subroutineM], cScript2); |
SetMenuItemState ( (fEnable && gScriptAppAddress.dataHandle), myMenus[subroutineM], cScript3); |
SetMenuItemState ( (fEnable && kOSANullScript != gScript4ID), myMenus[subroutineM], cScript4); |
} |
// IdleProc for AESend |
pascal Boolean IdleProc(EventRecord *myEvent, long *sleep, RgnHandle *mouseRgn) |
{ |
WindowPtr theWindow; |
Boolean activate; |
switch ( myEvent->what ) |
{ |
case nullEvent: |
*sleep = 0; // no null processing in this sample |
mouseRgn = nil; |
break; |
case activateEvt: |
activate = ((myEvent->modifiers & activeFlag) != 0); |
theWindow = (WindowPtr)myEvent->message; |
DoActivate(theWindow, activate); |
break; |
case updateEvt: |
DoUpdate( (WindowPtr)myEvent->message ); |
break; |
case osEvt: |
if ( ( myEvent->message >> 24 ) & suspendResumeMessage ) // suspend or resume |
{ |
gInBackground = ((myEvent->message & resumeFlag) == 0); |
DoActivate(FrontWindow(), ! gInBackground); |
} |
break; |
default: |
SysBeep( 1 ); |
break; |
} |
return false; // I'll wait forever |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14