home *** CD-ROM | disk | FTP | other *** search
- // DoBatchEvt.c
- // Copyright © Michael D. Crawford. All Rights Reserved.
- // mail bug reports and enhancement suggestions to crawford@scruznet.com
- // get updates from:
- // http://www.scruznet.com/~crawford/WordServices/wdsvindex.html
- // DoBatchEvt creatorCode [ fieldNumber ] [ cardNumber ]
- // Optional params default to 1.
- //
- // Version history
- // 1.0d2 MDC Added params for card and field number
- // 1.0d1 MDC First release
-
- #include <HyperXCMD.h>
- #include <Aliases.h>
- #include <Processes.h>
- #include <AppleEvents.h>
- #include <AEObjects.h>
- #include <AEPackObject.h>
- #include <AERegistry.h>
-
- #include "TestBedPrefix.h"
- #include "FindProcess.h"
- #include "Gripe.h"
- #include "WordServices.h"
-
- OSErr DoBatchCheck( AEAddressDesc *spellerAddrPtr, long fieldNumber, long cardNumber );
- OSErr CreateTextSpecifier( long windowNumber, long textNumber, AEDesc *specPtr );
- OSErr BuildWindowSpecifier( AEDesc *specPtr, long whichWindow );
- OSErr CreateFieldSpecifier( long cardNumber, long fieldNumber, AEDesc *specPtr );
- OSErr BuildCardSpecifier( AEDesc *specPtr, long whichWindow );
- void HandleStrToPStr( Handle h, StringPtr str );
-
- #define kBatchTimeout 600
-
- #ifdef XCMD_TESTBED
- void CallXCmd( XCmdPtr pBPtr )
- #else
- void main( XCmdPtr pBPtr )
- #endif
- {
- OSType signature;
- ProcessSerialNumber psn;
- ProcessInfoRec pInfo;
- OSErr err;
- AEAddressDesc spellerAddr;
- long cardNumber;
- long fieldNumber;
- Str255 strBuf;
-
- if ( pBPtr->paramCount < 1 || pBPtr->paramCount > 3 ){
- pBPtr->returnValue = NewHandle( 9 );
- if ( pBPtr->returnValue )
- BlockMoveData( "paramErr", *( pBPtr->returnValue ), 9 );
- }
-
- BlockMove( *( pBPtr->params[ 0 ] ), &signature, 4 );
-
- // Defaults
-
- cardNumber = 1;
- fieldNumber = 1;
-
- if ( pBPtr->paramCount > 1 ){
- HandleStrToPStr( pBPtr->params[ 1 ], strBuf );
- StringToNum( strBuf, &fieldNumber );
- }
-
- if ( pBPtr->paramCount > 2 ){
- HandleStrToPStr( pBPtr->params[ 2 ], strBuf );
- StringToNum( strBuf, &cardNumber );
-
- }
- // Check if the speller is already running
-
- if ( !FindAProcess( signature, &psn, &pInfo, (FSSpecPtr)NULL, (StringPtr)NULL ) ){
-
- // err = LaunchSpeller( aliasHdl );
- // if ( err ){
- // Gripe( "\pUnable to launch Word Services server" );
- // return err;
- // }
- }
-
- err = AECreateDesc( typeApplSignature,
- (Ptr)&signature,
- sizeof( signature ),
- &spellerAddr );
- if ( err ){
- Gripe( "\pAECreateDesc failed" );
- return;
- }
-
- err = DoBatchCheck( &spellerAddr, fieldNumber, cardNumber );
- if ( err ){
- DebugStr( "\pDoBatchCheck failed" );
- return;
- }
-
- return;
- }
-
- OSErr DoBatchCheck( AEAddressDesc *spellerAddrPtr, long fieldNumber, long cardNumber )
- {
- OSErr err;
- // AEDesc textSpecifier;
- AEDesc fieldSpecifier;
- AppleEvent btchEvent;
- AppleEvent replyEvent;
- // WWJrPrefsHdl prefHdl;
- AEDescList textSpecList; /* 1.0d7 */
- long index; /* 1.0d7 */
-
- /* We make an object specifier that refers to _our_own_ window
- */
-
- // err = CreateTextSpecifier( 1L, 1L, &textSpecifier );
- err = CreateFieldSpecifier( cardNumber, fieldNumber, &fieldSpecifier );
-
- if ( err ){
- Gripe( "\pCreateFieldSpecifier failed" );
- return err;
- }
-
- // prefHdl = GetPrefHandle();
- // if ( !prefHdl ){
- // Gripe( "\pCannot get preferences handle" );
- // return resNotFound;
- // }
- //
- // if ( (*prefHdl)->checkSel ){
- // /* Make a formRange descriptor that gives the selection range */
- //
- // Gripe( "\pSelection-only checking is not yet implemented" );
- // return noErr;
- // }
-
- /* Create the event to send to the speller */
-
- err = AECreateAppleEvent( kWordServicesClass,
- kWSBatchCheckMe,
- spellerAddrPtr,
- kAutoGenerateReturnID,
- kAnyTransactionID,
- &btchEvent );
-
- if ( err ){
- Gripe( "\pcreate btch event failed" );
- return err;
- }
- err = AEDisposeDesc( spellerAddrPtr );
- if ( err ){
- Gripe( "\pAEDisposeDesc failed" );
- return err;
- }
-
-
- /* 1.0d7 This is the new way to do it - use a list of object specifiers (even if
- * only one of them
- */
-
- err = AECreateList( (Ptr)NULL, (Size)0, false, &textSpecList );
- if ( err ){
- Gripe( "\pAECreateList failed" );
- return err;
- }
-
- /* Put our specifier into it. If we had multiple text blocks to check, we would
- * put specifiers for each into it in turn.
- * Note that we use AEPutDesc, not AEPutParamDesc, to put items into an indexed
- * list.
- */
-
- #define N_TEXT_SPECS 1L /*3L */ /* Define this to be 1 for normal checking */
-
- for ( index = 1L; index <= N_TEXT_SPECS; index++ ){
- err = AEPutDesc( &textSpecList,
- index,
- &fieldSpecifier );
- if ( err ){
- Gripe( "\pAEPutDesc failed to put text specifier into textSpecList" );
- return err;
- }
- }
-
- err = AEDisposeDesc( &fieldSpecifier );
- if ( err ){
- Gripe( "\pAEDisposeDesc failed" );
- return err;
- }
-
- /* Insert the list of object specifiers as the direct object of the batch event */
-
- err = AEPutParamDesc( &btchEvent,
- keyDirectObject,
- &textSpecList );
- if ( err ){
- Gripe( "\pAEPutParamDesc failed to put direct object on batch event" );
- return err;
- }
-
- /* 1.0.3 MDC fixed a bug in which we disposed of textSpecifier a second
- * time, instead of properly disposing of textSpecList
- */
-
- err = AEDisposeDesc( &textSpecList );
- if ( err ){
- Gripe( "\pAEDisposeDesc failed" );
- return err;
- }
-
- /* Send the event. We await the reply, so that if there is a failure of some
- * sort in the initial connection, we can alert the user right away. The timeout
- * value to use here should be as long as one would care to have a user wait for
- * the completion of a menu command. Since we expect that the speller is on a local
- * machine in this case, and should be able to respond immediately, we just give
- * a few seconds for the timeout.
- *
- * We should assign an idle proc to spin the cursor. Even better would be a progress
- * dialog that says "Contacting speller" or some such, with an animated display that
- * shows the time elapsed relative to the total timeout, so the user will know how
- * long she may have to wait
- */
-
- err = AESend( &btchEvent,
- &replyEvent,
- kAEWaitReply + kAECanInteract + kAECanSwitchLayer,
- kAENormalPriority,
- kBatchTimeout,
- (AEIdleUPP)NULL,
- (AEFilterUPP)NULL );
-
- if ( err ){
- Gripe( "\psend batch event failed" );
- return err;
- }
- err = AEDisposeDesc( &btchEvent );
- if ( err ){
- Gripe( "\pAEDisposeDesc failed" );
- return err;
- }
-
- /* MDC 1.1.1 fix a memory leak */
-
- err = AEDisposeDesc( &replyEvent );
- if ( err ){
- Gripe( "\pAEDisposeDesc failed" );
- return err;
- }
-
- /* Now the event has been sent. There is nothing more that we have to actually do
- * on our own initiative to accomplish the spelling; we just sit back and respond
- * to events. In particular, we don't remember that spelling is taking place - once
- * the spelling is done, we will just start seeing events from the user (mouse and
- * key clicks and so on
- */
-
- return noErr;
- }
-
- /*
- * Descriptor packing routines
- */
-
- /* Create a formAbsolutePosition window descriptor */
-
- OSErr BuildCardSpecifier( AEDesc *specPtr, long whichWindow )
- {
- AEDesc nullDesc;
- AEDesc nullSpec;
- AEDesc whichDesc;
- OSErr err;
-
- /* Create the descriptor for the container (the application, or null) */
-
- err = AECreateDesc( typeNull, (Ptr)NULL, (Size)0, &nullDesc );
- if ( err )
- return err;
-
- /* Create the key data, which gives the window number */
-
- err = CreateOffsetDescriptor( whichWindow, &whichDesc );
- if ( err )
- return err;
-
- /* Create the Object Specifier for the window */
-
- err = CreateObjSpecifier( 'cCRD',
- &nullDesc,
- formAbsolutePosition,
- &whichDesc,
- true, /* Dispose of input descriptors */
- specPtr ); /* specPtr is the value we return */
- return err;
- }
-
- #ifdef NEVER
- OSErr CreateTextSpecifier( long windowNumber, long textNumber, AEDesc *specPtr )
- {
- AEDesc docSpecifier;
- AEDesc textDescriptor;
- OSErr err;
-
- /* Create an object specifier for a particular text field within a particular
- * window. In each case use formAbsolutePosition.
- */
-
- err = BuildWindowSpecifier( &docSpecifier, windowNumber );
- if ( err ){
- Gripe( "\pBuildWindowDescriptor failed" );
- return err;
- }
-
- err = CreateOffsetDescriptor( textNumber, &textDescriptor );
- if ( err ){
- Gripe( "\pCreateOffsetDescriptor failed" );
- return err;
- }
-
- err = CreateObjSpecifier( cText,
- &docSpecifier,
- formAbsolutePosition,
- &textDescriptor,
- true, /* Dispose input descriptors */
- specPtr );
- if ( err ){
- Gripe( "\pCreateObjSpecifer failed" );
- return err;
- }
-
- return noErr;
- }
- #endif
-
- OSErr CreateFieldSpecifier( long cardNumber, long fieldNumber, AEDesc *specPtr )
- {
- AEDesc docSpecifier;
- AEDesc fieldDescriptor;
- AEDesc nullDesc;
- OSErr err;
-
- /* Create an object specifier for a particular text field within a particular
- * window. In each case use formAbsolutePosition.
- */
-
- err = BuildCardSpecifier( &docSpecifier, cardNumber );
- if ( err ){
- Gripe( "\pBuildWindowDescriptor failed" );
- return err;
- }
-
-
- // err = AECreateDesc( typeNull, (Ptr)NULL, (Size)0, &nullDesc );
- // if ( err )
- // return err;
-
- err = CreateOffsetDescriptor( fieldNumber, &fieldDescriptor );
- if ( err ){
- Gripe( "\pCreateOffsetDescriptor failed" );
- return err;
- }
-
- err = CreateObjSpecifier( 'cCFD',
- &docSpecifier,
- formAbsolutePosition,
- &fieldDescriptor,
- true, /* Dispose input descriptors */
- specPtr );
-
- // err = CreateObjSpecifier( 'cCFD',
- // &nullDesc,
- // formAbsolutePosition,
- // &fieldDescriptor,
- // true, /* Dispose input descriptors */
- // specPtr );
- if ( err ){
- Gripe( "\pCreateObjSpecifer failed" );
- return err;
- }
-
- return noErr;
- }
-
- void HandleStrToPStr( Handle h, StringPtr str )
- {
- short size;
- char *p;
-
- // Convert a handle to a C string into a Pascal string
-
- p = *h;
- size = 0;
-
- while ( *p++ )
- size++;
-
- if ( size > 255 )
- size = 255;
-
- str[ 0 ] = (unsigned char)size;
-
- BlockMove( *h, &str[ 1 ], size );
-
- return;
- }