AEventStuff.c

/*
    File:       AEvents.c
 
    Contains:   This file contains an assortment of functions to deal with
                the Apple Events needed to set the OS 9 desktop.  The majority of
                the functionality below came from MoreAppleEvents, but it was not
                yet carbonized (to my knowledge) when I created this sample, so I could
                not directly link with the library that comes with that example.
                Special thanks to GeoWar for help in this area.                 
 
    Written by:     
 
    Copyright:  Copyright © 1991-1999 by Apple Computer, Inc., All Rights Reserved.
 
                You may incorporate this Apple sample source code into your program(s) without
                restriction. This Apple sample source code has been provided "AS IS" and the
                responsibility for its operation is yours. You are not permitted to redistribute
                this Apple sample source code as "Apple sample source code" after having made
                changes. If you're going to re-distribute the source, we require that you make
                it clear in the source that the code was descended from Apple sample source
                code, but that you've made changes.
            
*/
 
#include "Snapshot.h"
 
static int gNumMonitors = 0;
 
OSErr SetDesktopPict(AEDesc* pAEDesc,SInt32 pIndex)
{
    OSErr anErr = noErr;
    AppleEvent theEvent = {typeNull, nil};  //  always init AEDescs
    ProcessSerialNumber tPSN;
 
    gNumMonitors = 0;   // zero monitor count
    {
        GDHandle tGDHandle = DMGetFirstScreenDevice(true);
        while (tGDHandle)
        {
            gNumMonitors++; // bump count
            tGDHandle = DMGetNextScreenDevice(tGDHandle,true);
        }
    }
    if (gNumMonitors == 0)
        gNumMonitors = 1;
 
    // Launch reciever if it's not already running.
    anErr = LaunchProcessBySignature('APPC', 'apcp',&tPSN);
    if (anErr != noErr)
        return anErr;
 
            //moreisbetter or AEHelpers
    anErr = AEHMakeEventSignatureTarget('APPC', 'apcp', kAECoreSuite, kAESetData, &theEvent);
    if (anErr == noErr) // if it worked
    {
        AEDesc containerObj = {typeNull, nil};      // always init AEDescs
        AEDesc propertyObject = {typeNull, nil};    // always init AEDescs
 
        anErr = MakePictureProperty(pIndex,&containerObj, &propertyObject);
        if (anErr == noErr) // if it worked
        {
            anErr = AEPutParamDesc(&theEvent, keyDirectObject, &propertyObject);
            AEDisposeDesc(&propertyObject);     // Always dispose ASAP
 
            if (anErr == noErr) // if it worked
            {
                AEDesc tAEObject = {typeNull, nil}; // always init AEDescs
 
                anErr = AECoerceDesc(pAEDesc,typeAlias,&tAEObject);    // coerce pAEDesc to type alias
                if (anErr == noErr) // if it worked
                {
                    anErr = AEPutParamDesc(&theEvent, keyAEData, &tAEObject);
                    AEDisposeDesc(&tAEObject);  // Always dispose ASAP
                    if (anErr == noErr) // if it worked
                    {
                        anErr = AEHSendEventNoReturnValue(nil, &theEvent);
                    }
                }
            }
        }
        AEDisposeDesc(&theEvent);   // Always dispose ASAP
    }
    if (anErr != noErr)
        DebugStr("\p|Set_DesktopPict-I-Error;error r30;");
    return anErr;
}
 
OSErr MakePictureProperty(SInt32 pIndex,
                              AEDesc* containerObjPtr,
                              AEDesc* propertyObjPtr)
{
    AEDesc longAEDesc = {typeNull, nil};    // always init AEDescs
    SInt32 index = ((pIndex - 1) % gNumMonitors) + 1;
    OSErr anErr = AECreateDesc(typeSInt32, &index, sizeof(long), &longAEDesc);
 
    if (anErr == noErr) // if it worked
    {
        AEDesc cmonAEDesc = {typeNull, nil};    // always init AEDescs
 
        // 'cmon' is nth (pIndex) color monitor object
        anErr = CreateObjSpecifier('cmon',containerObjPtr,formAbsolutePosition,&longAEDesc,false,&cmonAEDesc);
        AEDisposeDesc(&longAEDesc); // Always dispose ASAP
 
        if (anErr == noErr) // if it worked
        {
            AEDesc dpicDesc = {typeNull, nil};  // always init AEDescs
            OSType dpicOSType = 'dpic';         // Desktop Picture
 
            anErr = AECreateDesc('type', &dpicOSType, sizeof(OSType), &dpicDesc);
            if (anErr == noErr) // if it worked
            {
                anErr = CreateObjSpecifier(typeProperty,&cmonAEDesc,formPropertyID,&dpicDesc,false,propertyObjPtr);
                AEDisposeDesc(&cmonAEDesc); // Always dispose ASAP
            }
        }
    }
    return anErr;
}
 
pascal  OSErr   OHMakeAliasDescFromFSSpec( const FSSpecPtr fssPtr,
                                                  AEDesc *aliasDescPtr )
{
    OSErr           anErr = noErr;
    AliasHandle     aliasHandle;
    
    anErr = NewAlias( nil, fssPtr, &aliasHandle);
    if ( anErr == noErr  &&  aliasHandle == nil )
    {
        anErr = paramErr;
    }
 
    if ( anErr == noErr )
    {
        anErr = OHMakeAliasDesc( aliasHandle, aliasDescPtr );
        DisposeHandle( (Handle)aliasHandle );
    }
        
    return anErr;
}//end MakeAliasObject
 
pascal  OSErr   OHMakeAliasDesc( const AliasHandle aliasHandle,
                                        AEDesc *aliasDescPtr )
{
    OSErr   anErr = noErr;
    
    char    handleState = HGetState( (Handle)aliasHandle );
    HLock( (Handle)aliasHandle );
    
    anErr = AECreateDesc( typeAlias, *aliasHandle, GetHandleSize( (Handle)aliasHandle ), aliasDescPtr );
    
    HSetState( (Handle)aliasHandle, handleState );
    
    return anErr;
}//end MakeAliasObject
 
pascal  OSErr   AEHMakeEventSignatureTarget( const OSType targetType,
                                                  const OSType targetCreator,
                                                  const AEEventClass eventClass,
                                                  const AEEventID eventID,
                                                        AppleEvent *theEventPtr )
{
    OSErr   anErr = noErr;
    
    ProcessSerialNumber     psn = { kNoProcess, kNoProcess };
    
    anErr = FindProcessBySignature( targetType, targetCreator, &psn );
    if ( anErr == noErr )
    {
        anErr = AEHMakeEventProcessTarget( &psn, eventClass, eventID, theEventPtr );
    }
    return anErr;
}//end AEHMakeEventSignatureTarget
 
pascal  OSErr   AEHMakeEventProcessTarget( const ProcessSerialNumberPtr psnPtr,
                                           const AEEventClass eventClass,
                                           const AEEventID eventID,
                                                 AppleEvent *theEventPtr )
{
    OSErr   anErr = noErr;
    AEDesc  targetAppDesc = { typeNull, nil };
    
    anErr = AECreateDesc (typeProcessSerialNumber, psnPtr, sizeof( ProcessSerialNumber ), &targetAppDesc);
 
    if ( anErr == noErr )
    {
        anErr = AECreateAppleEvent( eventClass, eventID, &targetAppDesc,
                                    kAutoGenerateReturnID, kAnyTransactionID, theEventPtr);
    }
    
    AEDisposeDesc( &targetAppDesc );
    
    return anErr;
}//end AEHMakeEventProcessTarget
 
pascal  OSErr   AEHSendEventNoReturnValue( const AEIdleUPP idleProcUPP,
                                           const AppleEvent *theEvent )
{
    OSErr       anErr = noErr;
    AppleEvent  theReply = { typeNull, nil };
    AESendMode  sendMode;
    
    if ( idleProcUPP == nil )
        sendMode = kAENoReply;
    else
        sendMode = kAEWaitReply;
 
    anErr = AESend( theEvent, &theReply, sendMode, kAENormalPriority, kNoTimeOut, idleProcUPP, nil );
    if ( anErr == noErr  &&  sendMode == kAEWaitReply )
    {
        anErr =  AEHGetHandlerError( &theReply );
    }
    (void) AEDisposeDesc( &theReply );
    
    return anErr;
}//end AEHSendEventNoReturnValue
 
pascal  OSErr   AEHGetHandlerError( const AppleEvent *reply )
{
    OSErr       anErr = noErr;
    OSErr       handlerErr;
    
    DescType    actualType;
    long        actualSize;
    
    if ( reply->descriptorType != typeNull )    // there's a reply, so there may be an error
    {
        OSErr   getErrErr = noErr;
        
        getErrErr = AEGetParamPtr( reply, keyErrorNumber, typeShortInteger, &actualType,
                                    &handlerErr, sizeof( OSErr ), &actualSize );
        
        if ( getErrErr != errAEDescNotFound )   // found an errorNumber parameter
        {
            anErr = handlerErr;                 // so return it's value
        }
    }
    return anErr;
}//end AEHGetHandlerError
 
pascal  OSErr   FindProcessBySignature( const OSType targetType,
                                        const OSType targetCreator,
                                              ProcessSerialNumberPtr psnPtr )
{
    OSErr       anErr = noErr;
    Boolean     lookingForProcess = true;
    
    ProcessInfoRec  infoRec;
    
    infoRec.processInfoLength = sizeof( ProcessInfoRec );
    infoRec.processName = nil;
    infoRec.processAppSpec = nil;
    
    psnPtr->lowLongOfPSN = kNoProcess;
    psnPtr->highLongOfPSN = kNoProcess;
 
    while ( lookingForProcess )
    {
        anErr = GetNextProcess( psnPtr );
        if ( anErr != noErr )
        {
            lookingForProcess = false;
        }
        else
        {
            anErr = GetProcessInformation( psnPtr, &infoRec );
            if ( ( anErr == noErr )
                 && ( infoRec.processType == targetType )
                 && ( infoRec.processSignature == targetCreator ) )
            {
                lookingForProcess = false;
            }
        }
    }
    
    return anErr;
}//end FindProcessBySignature
 
OSErr LaunchProcessBySignature(
    const OSType pTargetType,const OSType pTargetCreator,ProcessSerialNumberPtr psnPtr)
{
    FSSpec appFSSpec;
    OSErr anErr = FindProcessBySignature(pTargetType, pTargetCreator, psnPtr);
 
    if (anErr == noErr) // already running
        return anErr;
 
    // It's not already running, so look for it (as an APPL) in the desktop database
    if (pTargetType == 'APPL')
        anErr = Find_DTDB_APPL(pTargetCreator,&appFSSpec);
 
    // If we haven't found it yet, search all the volumes
    if (anErr != noErr)
        anErr = Search_Volumes(pTargetType,pTargetCreator,&appFSSpec);
 
    // we found it, so try to launch it
    if (anErr == noErr)
    {
        LaunchParamBlockRec tLaunchPB;
 
        tLaunchPB.launchBlockID = extendedBlock;
        tLaunchPB.launchEPBLength = extendedBlockLen;
        tLaunchPB.launchFileFlags = nil;
        tLaunchPB.launchControlFlags = launchContinue + launchNoFileFlags + launchDontSwitch;
        tLaunchPB.launchAppSpec = &appFSSpec;
 
        anErr = LaunchApplication(&tLaunchPB);
        if (anErr == noErr)
            *psnPtr = tLaunchPB.launchProcessSN;
    }
    return anErr;
}
 
OSErr Search_Volumes(const OSType pTargetType,const OSType pTargetCreator,FSSpec* pFSSpecPtr)
{
    SInt16  index;
    OSErr   anErr = noErr;
 
    for (index = 1;;index++)    // for each volume...
    {
        XVolumeParam    tXVPV;
 
        tXVPV.ioCompletion = nil;
        tXVPV.ioNamePtr = nil;
        tXVPV.ioVolIndex = index;
 
        anErr = PBXGetVolInfoSync(&tXVPV);  // get its ioVRefNum
        if (anErr == nsvErr)            // if no such volume...
            anErr = afpItemNotFound;    // ...return application information not found
        if (anErr != noErr)             // on error...
            break;                      // ...break
 
        anErr = Search_Volume(tXVPV.ioVRefNum,pTargetType,pTargetCreator,pFSSpecPtr);
        if (anErr == noErr)             // if we found it...
            break;                      // ...break
    }
    return anErr;
}
 
OSErr Search_Volume(const SInt16 pVRefNum,const OSType pTargetType,const OSType pTargetCreator,FSSpec* pFSSpecPtr)
{
    CSParamPtr tCSParamPtr;
    OSErr anErr;
 
    if (!pFSSpecPtr)
        return paramErr;
 
    tCSParamPtr = (CSParamPtr) NewPtrClear(sizeof(CSParam));
    if (tCSParamPtr == nil)
        return MemError();
 
    // initialize the parameter block
    tCSParamPtr->ioVRefNum = pVRefNum;
    tCSParamPtr->ioMatchPtr = pFSSpecPtr;
    tCSParamPtr->ioSearchBits = fsSBFlFndrInfo;
 
    tCSParamPtr->ioReqMatchCount = 1;   // only looking for 1
    tCSParamPtr->ioSearchTime = 0;      // no timeout
 
    tCSParamPtr->ioSearchInfo1 = (CInfoPBPtr) NewPtrClear(sizeof(CInfoPBRec));
    tCSParamPtr->ioSearchInfo2 = (CInfoPBPtr) NewPtrClear(sizeof(CInfoPBRec));
 
    if (tCSParamPtr->ioSearchInfo1 && tCSParamPtr->ioSearchInfo2)
    {
        // Now see if we can create an 2K optimization buffer
        tCSParamPtr->ioOptBuffer = NewPtr(2048);
        if (tCSParamPtr->ioOptBuffer)
            tCSParamPtr->ioOptBufSize = 2048;
        else
            tCSParamPtr->ioOptBufSize = 0;  // no buffer, sorry
 
        tCSParamPtr->ioSearchInfo1->hFileInfo.ioNamePtr = nil;
        tCSParamPtr->ioSearchInfo2->hFileInfo.ioNamePtr = nil;
        tCSParamPtr->ioSearchInfo1->hFileInfo.ioFlFndrInfo.fdType = pTargetType;
        tCSParamPtr->ioSearchInfo1->hFileInfo.ioFlFndrInfo.fdCreator = pTargetCreator;
 
        tCSParamPtr->ioSearchInfo2->hFileInfo.ioFlFndrInfo.fdCreator = 0xFFFFFFFF;
        tCSParamPtr->ioSearchInfo2->hFileInfo.ioFlFndrInfo.fdType = 0xFFFFFFFF;
        
        anErr = PBCatSearchSync(tCSParamPtr);       // search sync
//      if ((anErr != noErr) || (tCSParamPtr->ioActMatchCount == 0))
    }
    else
        anErr = MemError();
 
    // no matter what happened, kill all the memory we allocated
    if (tCSParamPtr->ioSearchInfo1)
        DisposePtr((Ptr)tCSParamPtr->ioSearchInfo1);
 
    if (tCSParamPtr->ioSearchInfo2)
        DisposePtr((Ptr)tCSParamPtr->ioSearchInfo2);
 
    if (tCSParamPtr->ioOptBuffer)
        DisposePtr((Ptr)tCSParamPtr->ioOptBuffer);
 
    DisposePtr((Ptr)tCSParamPtr);
 
    return(anErr);
}
 
OSErr Find_DTDB_APPL(const OSType pTargetCreator,FSSpec* pFSSpecPtr)
{
    SInt16  index;
    OSErr   anErr = noErr;
 
    for (index = 1;;index++)    // for each volume...
    {
        XVolumeParam    tXVPV;
        DTPBRec deskTopDBRec;
 
        tXVPV.ioCompletion = nil;
        tXVPV.ioNamePtr = nil;
        tXVPV.ioVolIndex = index;
 
        anErr = PBXGetVolInfoSync(&tXVPV);  // get its ioVRefNum
        if (anErr == nsvErr)            // if no such volume...
            anErr = afpItemNotFound;    // ...return application information not found
        if (anErr != noErr)             // on error...
            break;                      // ...break
 
        // now get the DTDB for this volume
        deskTopDBRec.ioNamePtr = nil;
        deskTopDBRec.ioVRefNum = tXVPV.ioVRefNum;
        anErr = PBDTGetPath( &deskTopDBRec );
        if (anErr != noErr)
            break;
 
        // look in this DTDB for the app with this creator
        deskTopDBRec.ioCompletion = nil;
        deskTopDBRec.ioNamePtr = pFSSpecPtr->name;
        deskTopDBRec.ioIndex = 0;
        deskTopDBRec.ioFileCreator = pTargetCreator;
 
        anErr = PBDTGetAPPLSync( &deskTopDBRec );
        if (anErr == noErr) // found it
        {   // stuff our FSSpec
            pFSSpecPtr->vRefNum = deskTopDBRec.ioVRefNum;
            pFSSpecPtr->parID = deskTopDBRec.ioAPPLParID;
            break;
        }
    }
    return anErr;
}