AEUtilities.c

/*------------------------------------------------------------------------------
*
*  Apple Developer Technical Support
*
*  AppleEvent utility routines
*
*  Program:AEObject-Edition Sample
*  File:   AEUtilityRoutines.c - C Source
*
*  by: C.K. Haun <TR>
*
*  Copyright © 1991-1992 Apple Computer, Inc.
*  All rights reserved.
*
*------------------------------------------------------------------------------
* This file contains some generic and specific utility routines I wrote
* to help with the AppleEvent manager.  The prime motivation for this file
* is to NOT have to type in all the fields needed for many of the
* AEM parameter accessing routines, since I do them so often.  
* There aren't all that many calls here yet, this will grow as the AEM world grows
*----------------------------------------------------------------------------*/
 
 
#define __AEMU__
 
#include "Sampdefines.h"
 
#pragma segment AEUtils
/* A little routine that returns a short from a descriptor */
OSErr ShortFromDesc(short *theData, const AppleEvent *theDesc)
{
    OSErr myErr = noErr;
    AEDesc tempDesc;
    long temp;
    if (theDesc->descriptorType == typeShortInteger) {
        
        temp = *((short *)*(theDesc->dataHandle));
        *theData = temp;
    } else {
    /* if it wasn't a short to begin with, try and coerce it into a short */
        myErr = AECoerceDesc(theDesc, typeShortInteger, &tempDesc);
        if (!myErr) {
            /* it coerced.  grab it */
            temp = *((short *)*(tempDesc.dataHandle));
            *theData = temp;
            AEDisposeDesc(&tempDesc);
        }
    }
    return(myErr);
    
}
/* this has been replaced by my coercion handler, see AppleEventCore.c  */
void PStringFromTextDesc(Str255 theString, const AEDesc *theDesc)
{
    theString[0] = GetHandleSize(theDesc->dataHandle);
    BlockMove((Ptr)*theDesc->dataHandle, (Ptr)&theString[1], theString[0]);
    
}
 
/* Puts up the PPCBrowser, and creates a target address */
/* based on the user selection */
OSErr BrowseForTarget(AEDesc *theAddress)
{
    Str32 prompt1;
    Str32 prompt2;
    LocationNameRec theLoc;
    PortInfoRec theRec;
    OSErr myErr = noErr;
    TargetID theID;
    GetIndString(prompt1,kGeneralStrings,kPPCPrompt1);
    GetIndString(prompt2,kGeneralStrings,kPPCPrompt2);
    myErr = PPCBrowser(prompt1, prompt2, false, &theLoc, &theRec, nil, nil);
    if (!myErr) {
        /* make a target descriptor */
        BlockMove(theRec.name.name, targetName, theRec.name.name[0] + 1);
        ParamText(&targetName, "", "", "");
        theID.name = theRec.name;
        theID.location = theLoc;
        myErr = AECreateDesc(typeTargetID, (Ptr)&theID, sizeof(theID), theAddress);
        
    }
    mAEErrorDisplay("\pBrowser Error", myErr)
    return(myErr);
}
 
/* Makes an AppleEvent address descriptor based on the settings in the Dialog Box */
/* in AppleEventCore.c */
OSErr MakeAddress(AEDesc *theAddress)
{
    OSErr myErr = noErr;
    ProcessSerialNumber myNumber;
    switch (gAddressMode) {
    /* Remember, if you use this case (using the PSN of kCurrentProcess) the  */
    /* AppleEvent Manager will bypass the event loop and directly call (like a normal */
    /* subroutine call) your handler, the event will _not_ come through */
    /* WaitNextEvent */
        case kSelfCur:
            myNumber.highLongOfPSN = 0;
            myNumber.lowLongOfPSN = kCurrentProcess;
            myErr = AECreateDesc(typeProcessSerialNumber, (Ptr)&myNumber, sizeof(ProcessSerialNumber), theAddress);
            break;
    /* If you use your real PSN, then the event will come through WNE */        
        case kSelfPSN:
            myErr = AECreateDesc(typeProcessSerialNumber, (Ptr)&gOurSN, sizeof(ProcessSerialNumber), theAddress);
            break;
        case kOtherApp:
            if (gTargetAddress.dataHandle == nil) {
                myErr = BrowseForTarget(theAddress);
            } else {
            /* If I already have one, duplicate it and pass it back */
                myErr = AEDuplicateDesc(&gTargetAddress, theAddress);
            }
            break;
    }
    mAEErrorDisplay("\pMakeAddress ", myErr)
    return(myErr);
}
 
/* generic sender, so I don't have to duplicate the various conditional code */
/* (for replies, interactions, or whatever) all over */
OSErr DoSend(AppleEvent *theEvent, AEDesc *reply)
{
    AEDesc *replyPointer = nil;
    short response = 2;
    OSErr myErr;
    long timeOut = kAEDefaultTimeout;
    if (gReplyMode)
        replyPointer = reply;
    if (gReplyMode == 1 && gAddressMode == 1) {
        ModalFilterUPP upp = NewModalFilterProc(standardAlertFilter);
        timeOut = 0;
        response = CautionAlert(kBadMix, upp);
        DisposeRoutineDescriptor(upp);
    }
    if (response == 2) {
        myErr = AESend(theEvent, replyPointer,
                       (gSendInteractArray[gAESendInteraction] + gAESwitchLayer) + gReplyLevels[gReplyMode], kAENormalPriority,
                       timeOut, gCommonIdleFunctionUPP, nil);
        
        mAEErrorDisplay("\pAESend in DoSend ", myErr)
    } else {
        myErr = userCanceledErr;
    }
    return(myErr);
}
 
/* lil routine that will print out actual error text for AEM errors, since I */
/* got real tired of trying to remeber what -1723 was. */
/* revised to reflect the new error codes, and to use my ERST <ckh 1.0.2>*/
/* resource <ckh 1.0.2>*/
void AEErrorText(OSErr theError)
{
    Str63 theWords;
    Ptr theErrors;
    OSErr tempError;
    register qq;
    short errCount;
    Byte stringLen;
    /* get my errors <ckh 1.0.2>*/
    Handle scratch = GetResource(kErrorStringResourceType,kTheErrorStrings);
    theWords[0] = 0;
    if(scratch){
        /* if I got it, lock it and deref <ckh 1.0.2>*/
        HLock(scratch);
        theErrors = *scratch;
        errCount =  *((short *)theErrors);
        /* position to the first error code <ckh 1.0.2>*/
        theErrors = theErrors+sizeof(short);
        errCount--;
        for(qq = 0;qq<errCount;qq++){
            tempError =  *((short *)theErrors);
            theErrors = theErrors + sizeof (OSErr);
            /* get the string count, we'll need this whatever we do <ckh 1.0.2>*/
            stringLen = *theErrors;
            stringLen ++;   
            if(tempError == theError){
                /* it's this one, theErrors points to the string <ckh 1.0.2>*/
                BlockMove(theErrors,(Ptr)&theWords,stringLen);
                break;
                
                } else {
                /* next errror please <ckh 1.0.2>*/
                theErrors = theErrors + stringLen;
                }
            }
        if(theWords[0] == 0){
            GetIndString(theWords,kGeneralStrings,kUnknownError);
            }   
        AddAEText(theWords);
        HUnlock(scratch);
        ReleaseResource(scratch);
        }
}
 
/* this just pumps out the returned data to the AEWindow */
/* just a utility for this sample */
void DisplayReturnedData(AEDesc *reply)
{
    AEDesc theData;
    OSErr myErr;
    long errorCode = 0;
    DescType returnedType;
    Size returnedSize;
    Str255 returnedText;
    /* I can do most of this by asking for typeChar and getting the desc. */
    /* this is because the AEM can coerce any numeric data to typeChar */
    /* (as described in the AEM chapter of IM VI) */
    /* For things that the AEM _doesn't_ know about, I will install */
    /* coercion handlers! */
    /* if the coercion completely fails, because I got something I no nothing about, I bail */
    mVerboseOutput("\p\n Returned Data was : ")
    myErr = AEGetParamDesc(reply, keyDirectObject, typeChar, &theData);
    if (!myErr) {
        long size = GetHandleSize(theData.dataHandle);
        HLock(theData.dataHandle);
        
        AddToAEWindow((Ptr)*(theData.dataHandle), size);
        
    } else {
        /* get it as a wildcard, and just show me the descType */
        myErr = AEGetParamDesc(reply, keyDirectObject, typeWildCard, &theData);
        AddToAEWindow((Ptr)&theData.descriptorType, kFour);
    }
    /* I got a desc, I need to dispose a desc */
    if (!myErr)
        AEDisposeDesc(&theData);
    else
        AddAEText("\p not available");
    /* see if there was an 'errs' or 'errn' added */
    myErr = AEGetParamPtr(reply, keyErrorNumber, typeLongInteger, &returnedType, (Ptr)&errorCode, sizeof(long), &returnedSize);
    if (myErr && myErr != errAEDescNotFound) {
        
        mVerboseOutput("\p\n Had an error descriptor, but I can't access it")
    }
    if (!myErr) {
        mVerboseOutput("\p\n Error number (errn) returned, was: ")
        AddAENum(errorCode);
        AEErrorText(errorCode);
    }
    /* try for the error string */
    myErr = AEGetParamPtr(reply, keyErrorString, typeMyPString, &returnedType, (Ptr)&returnedText, 255, &returnedSize);
    if (!myErr) {
        mVerboseOutput("\p\n Error string (errs) returned, was: ")
        AddAEText(&returnedText);
    }
}
 
 
/* DoObjectDefinition drives the dialog that sets up the default containers */
/* for this sample, boring dialog stuff */
void DoObjectDefinition(short which)
{
    DialogPtr tdial;
    short hitItem = 0;
    Boolean r5, r6;
    Str32 tempNum;
    register qq;
    long realNum;
    DescType shapeTypes[] =  {
       cGraphicLine, cRectangle, cOval
    };
    tdial = SetUpObjectDialog(which);
    ShowWindow(tdial);
    
    {
        ModalFilterUPP upp = NewModalFilterProc(standardDialogFilter);
 
        while (hitItem != ok && hitItem != cancel) {
            ModalDialog(upp, &hitItem);
            switch (which) {
                case kSetWindowObject:
                    switch (hitItem) {
                        case kWByIndex:
                        case kWByName:
                            if (hitItem == kWByIndex) {
                                r5 = true;
                                r6 = false;
                            } else {
                                r5 = false;
                                r6 = true;
                            }
                            SetControlValue(SnatchHandle(tdial, kWByIndex), r5);
                            SetControlValue(SnatchHandle(tdial, kWByName), r6);
                            
                            break;
                    }
                    break;
                case kSetTextObject:
                    switch (hitItem) {
                        case kWordIndex:                        /* checkbox only to worry about */
                            SetControlValue(SnatchHandle(tdial, kWordIndex), (GetControlValue(SnatchHandle(tdial, kWordIndex)) ? 0 : 1));
                    }
                    break;
                case kSetShapeObject:
                    switch (hitItem) {
                        case kLineRadio:
                        case kRectangleRadio:
                        case kOvalRadio:
                            /* find out which one is true */
                            for (qq = kLineRadio; qq < kOvalRadio + 1; qq++) {
                                if (GetControlValue(SnatchHandle(tdial, qq))) {
                                    if (!(qq == hitItem)) {
                                        SetControlValue(SnatchHandle(tdial, qq), false);
                                        SetControlValue(SnatchHandle(tdial, hitItem), true);
                                    }
                                }
                            }
                            break;
                    }
                    break;
            }
        }
        DisposeRoutineDescriptor(upp);
    }
    /* make the changes permenent */
    if (hitItem == ok) {
        gPreferences.prefsChanged = true;
        switch (which) {
            case kSetWindowObject:
                HLock((Handle)gWindObjSpecHandle);
                if (GetControlValue(SnatchHandle(tdial, kWByIndex))) {
                    /* going by absolute position */
                    (*gWindObjSpecHandle)->form = formAbsolutePosition;
                    GetDialogItemText((Handle)SnatchHandle(tdial, kWIndexNum), tempNum);
                    StringToNum(tempNum, &realNum);
                    (*gWindObjSpecHandle)->u.index = realNum;
                } else {
                    /* going by name */
                    (*gWindObjSpecHandle)->form = formName;
                    /* put the name where it belongs */
                    GetDialogItemText((Handle)SnatchHandle(tdial, kWIndexName), (*gWindObjSpecHandle)->u.name);
                    
                }
                HUnlock((Handle)gWindObjSpecHandle);
                break;
            case kSetTextObject:
                
                HLock((Handle)gTextObjSpecHandle);
                /* fewer choices here */
                GetDialogItemText((Handle)SnatchHandle(tdial, kTextONumber), tempNum);
                
                StringToNum(tempNum, &realNum);
                (*gTextObjSpecHandle)->u.index = realNum;
                (*gTextObjSpecHandle)->andWord = GetControlValue(SnatchHandle(tdial, kWordIndex));
                /* see if word is being asked for */
                if ((*gTextObjSpecHandle)->andWord) {
                    GetDialogItemText((Handle)SnatchHandle(tdial, kWordIndexString), tempNum);
                    StringToNum(tempNum, &realNum);
                    (*gTextObjSpecHandle)->wordNumber = realNum;
                    
                }
                HUnlock((Handle)gTextObjSpecHandle);
                break;
            case kSetShapeObject:
                HLock((Handle)gShapeObjSpecHandle);
                for (qq = kLineRadio; qq < kOvalRadio + 1; qq++) {
                    if (GetControlValue(SnatchHandle(tdial, qq))) {
                        (*gShapeObjSpecHandle)->type = qq - kLineRadio;
                        (*gShapeObjSpecHandle)->form = shapeTypes[qq - kLineRadio];
                        break;
                    }
                }
                /* and the index number */
                GetDialogItemText((Handle)SnatchHandle(tdial, kSIEditLine), tempNum);
                StringToNum(tempNum, &realNum);
                (*gShapeObjSpecHandle)->u.index = realNum;
                HUnlock((Handle)gShapeObjSpecHandle);
                break;
        }
    }
    DisposeDialog(tdial);
}
 
/* Anther case of not wanting to type dialog code all over the sample */
DialogPtr SetUpObjectDialog(short which)
{
    DialogPtr tdial = CommonDStart(which, nil, nil);
    short tempItem;
    Str63 tempString;
    switch (which) {
        
        case kSetWindowObject:
            HLock((Handle)gWindObjSpecHandle);
            if ((*gWindObjSpecHandle)->form == 0) {
                tempItem = kWPosRadio;                               /* default for the first time the app is run */
            } else {
                
                if ((*gWindObjSpecHandle)->form == formAbsolutePosition) {
                    
                    tempItem = kWPosRadio;
                    NumToString((*gWindObjSpecHandle)->u.index, tempString);
                    SetDialogItemText((Handle)SnatchHandle(tdial, kWPosNum), tempString);
                } else {
                    tempItem = kWTitleRadioSet;
                    SetDialogItemText((Handle)SnatchHandle(tdial, kWTitleELine), (*gWindObjSpecHandle)->u.name);
                }
            }
            SetControlValue(SnatchHandle(tdial, tempItem), true);
            HUnlock((Handle)gWindObjSpecHandle);
            break;
        case kSetTextObject:
            HLock((Handle)gTextObjSpecHandle);
            /* fewer choices here */
            NumToString((*gTextObjSpecHandle)->u.index, tempString);
            SetDialogItemText((Handle)SnatchHandle(tdial, kWPosRadio), tempString);
            /* see if word is being asked for */
            if ((*gTextObjSpecHandle)->andWord) {
                SetControlValue(SnatchHandle(tdial, kWTitleRadioSet), true);
                NumToString((*gTextObjSpecHandle)->wordNumber, tempString);
                SetDialogItemText((Handle)SnatchHandle(tdial, kWPosNum), tempString);
                
            }
            HUnlock((Handle)gTextObjSpecHandle);
            break;
        case kSetShapeObject:
            HLock((Handle)gShapeObjSpecHandle);
            if (!(*gShapeObjSpecHandle)->u.index)
                (*gShapeObjSpecHandle)->u.index = 1;
            NumToString((*gShapeObjSpecHandle)->u.index, tempString);
            SetDialogItemText((Handle)SnatchHandle(tdial, kSIEditLine), tempString);
            SetControlValue(SnatchHandle(tdial, ((*gShapeObjSpecHandle)->type) + kLineRadio), true);
            /* byIndex defaults to on for now */
            SetControlValue(SnatchHandle(tdial, kSByIndexRadio), true);
            
            break;
        default:
            break;
    }
    return(tdial);
}
 
 
 
 
 
/* this is a central point to add keyErrorText and keyErrorNumber  */
/* parameters to a reply */
/* just a handy thing to do. */
/* It first checks to see if an error is already recorded, if there is one */
/* (for an earlier stage in the process) they we exit, since the user will have to */
/* deal with the ealier problem before they tackle the one we've just been called  */
/* to add */
/* ¥¥¥¥ BE SURE that you null out the gCurrentReply (or whatever you use) pointer */
/* when you exit from your handler, or you could end up writing to a desc that isn't  */
/* there.  And of course, if you send events to yourself from within a handler */
/* you're going to have to use a differrent method than this.  It's a sample, see? */
void AddToReply(ConstStr255Param theWords, long theError)
{
    OSErr myErr = noErr;
    long errNo;
    DescType returnedType;
    Size returnedSize;
    
    /* First, is therre a reply hanging out? */
    if (gCurrentReply) {
        /* test to see if there is one already*/
        myErr = AEGetParamPtr(gCurrentReply, keyErrorNumber, typeLongInteger, &returnedType, (Ptr)&errNo, sizeof(long),
                              &returnedSize);
        
        if (myErr == errAEDescNotFound) {
            /* cool, press on.  */
            myErr = AEPutParamPtr(gCurrentReply, keyErrorNumber, typeLongInteger, (Ptr)&theError, sizeof(long));
            if (!myErr)
                myErr = AEPutParamPtr(gCurrentReply, keyErrorString, typeChar, (Ptr)&theWords[1], theWords[0]);
            
        }
    }
}
 
OSErr MakeTypeRect(CShapeObjHandle theShape, AEDesc *theValue)
{
    OSErr myErr = noErr;
    AEDesc pixDesc;
    AEDescList theList;
    RGBColor black =  {
        0, 0, 0
    };
    RGBColor white =  {
        0xffff, 0xffff, 0xffff
    };
    short penSize = 1;
    long copyWord = kAEQDCopy;
    ShapesHandle theRealShape = (*theShape)->theShape;
    HLock((Handle)theRealShape);
    /* Now, a typeRectangle is a bunch of stuff, and as the AE Registry so clearly says... */
    /* "Note that the Apple Event Manager can coerce any Apple event record into any 
    other descriptor type. A special coercion handler is not required."
    */
    /* If you always wondered what that meant (I know I did) then watch */
    /* create a list that is a record */
    myErr = AECreateList(nil, nil, true, &theList);
    /* now start adding all the junk I have lying around, rectangle, color, kitchen sink.... */
    if (!myErr)
        myErr = MakeSinglePixelMap(&pixDesc, &(*theRealShape)->theColor);
    /* jeeez don't try and write code while the Finder is doing a copy across LocalTalk in the background Like I'm trying to now.... */
    if (!myErr)
        myErr = AEPutParamDesc(&theList, keyAEPenPattern, &pixDesc);
    if (!myErr)
        myErr = AEPutParamDesc(&theList, keyAEFillPattern, &pixDesc);
    AEDisposeDesc(&pixDesc);
    if (!myErr)
        myErr = MakeSinglePixelMap(&pixDesc, &white);
    if (!myErr)
        myErr = AEPutParamDesc(&theList, keyAEFillColor, &pixDesc);
    AEDisposeDesc(&pixDesc);
    if (!myErr)
        myErr = AEPutParamPtr(&theList, keyAEPenWidth, typeShortInteger, (Ptr)&penSize, sizeof(short));
    if (!myErr)
        myErr = AEPutParamPtr(&theList, keyAETransferMode, typeEnumeration, (Ptr)&copyWord, sizeof(long));
    
    if (!myErr)
        myErr = AEPutParamPtr(&theList, keyAEBounds, typeQDRectangle, (Ptr)&(*theRealShape)->theRect, sizeof(Rect));
    if (!myErr)
        myErr = AEPutParamPtr(&theList, keyAEDefinitionRect, typeQDRectangle, (Ptr)&(*theRealShape)->theRect, sizeof(Rect));
    HUnlock((Handle)theRealShape);
    /* and coerce it into what we want */
    if (!myErr)
        myErr = AECoerceDesc(&theList, typeRectangle, theValue);
    AEDisposeDesc(&theList);
    mAEErrorDisplay("\p\n Error creating typeRectangle", myErr)
    return(myErr);
}
 
/* MakeGraphicLine is similar to making a typeRectangle */
 
OSErr MakeGraphicLine(CShapeObjHandle theShape, AEDesc *theValue)
{
    OSErr myErr = noErr;
    AEDesc emptyList;
    AEDesc pixDesc;
    AEDescList theList;
    RGBColor black =  {
        0, 0, 0
    };
    RGBColor white =  {
        0xffff, 0xffff, 0xffff
    };
    short penSize = 1;
    long copyWord = kAEQDCopy;
    DescType noArr = kAENoArrow;
    ShapesHandle theRealShape = (*theShape)->theShape;
    HLock((Handle)theRealShape);
    myErr = AECreateList(nil, nil, true, &theList);
    /* now start adding all the junk I have lying around, rectangle, color, kitchen sink.... */
    if (!myErr)
        myErr = MakeSinglePixelMap(&pixDesc, &(*theRealShape)->theColor);
    /* jeeez don't try and write code while the Finder is doing a copy across LocalTalk in the background Like I'm trying to now.... */
    if (!myErr)
        myErr = AEPutParamDesc(&theList, keyAEPenPattern, &pixDesc);
    if (!myErr)
        myErr = AEPutParamDesc(&theList, keyAEPenColor, &pixDesc);
    AEDisposeDesc(&pixDesc);
    if (!myErr)
        myErr = AEPutParamPtr(&theList, keyAEPenWidth, typeShortInteger, (Ptr)&penSize, sizeof(short));
    if (!myErr)
        myErr = AEPutParamPtr(&theList, keyAETransferMode, typeEnumeration, (Ptr)&copyWord, sizeof(long));
    
    if (!myErr)
        myErr = AEPutParamPtr(&theList, keyAEBounds, typeQDRectangle, (Ptr)&(*theRealShape)->theRect, sizeof(Rect));
    if (!myErr)
        myErr = AEPutParamPtr(&theList, keyAELineArrow, typeEnumeration, (Ptr)&noArr, sizeof(DescType));
    /* we have no dash styles, so add an empty list */
    myErr = AECreateList(nil, nil, false, &emptyList);
    if (!myErr)
        myErr = AEPutParamDesc(&theList, keyAEDashStyle, &emptyList);
    AEDisposeDesc(&emptyList);
    if (!myErr)
        myErr = AEPutParamPtr(&theList, keyAEStartPoint, typeQDRectangle, (Ptr)&(*theRealShape)->theRect, sizeof(Point));
    if (!myErr)
        myErr = AEPutParamPtr(&theList, keyAEStartPoint, typeQDRectangle, (Ptr)&(*theRealShape)->theRect.bottom, sizeof(Point));
    
    HUnlock((Handle)theRealShape);
    /* and coerce it into what we want */
    if (!myErr)
        myErr = AECoerceDesc(&theList, typeGraphicLine, theValue);
    AEDisposeDesc(&theList);
    mAEErrorDisplay("\p\n Error creating typeGraphicLine", myErr)
    return(myErr);
}
 
/* Now some of the definitions in the AE Registry are rather broad, but they */
/* really need to be.  SO you'll want little routines like this */
OSErr MakeSinglePixelMap(AEDesc *thePlace, RGBColor *theColor)
{
    OSErr myErr = noErr;
    AEDescList thePixelList, tempList;
    AEDesc scratchDesc;
    long copyWord = kAEQDCopy;
    Rect miniRect =  {
        0, 0, 1, 1
    };
    myErr = AECreateList(nil, nil, false, &thePixelList);
    if (!myErr)
        myErr = AECreateDesc(typeRGBColor, (Ptr)theColor, sizeof(RGBColor), &scratchDesc);
    if (!myErr)
        myErr = AEPutDesc(&thePixelList, 0, &scratchDesc);
    if (!myErr)
        myErr = AEDisposeDesc(&scratchDesc);
    /* now create the other list */
    if (!myErr)
        myErr = AECreateList(nil, nil, true, &tempList);
    /* add the pixels */
    if (!myErr)
        myErr = AEPutParamDesc(&tempList, typePixMapMinus, &thePixelList);
    if (!myErr)
        myErr = AEDisposeDesc(&thePixelList);
    if (!myErr)
        myErr = AECreateDesc(typeQDRectangle, (Ptr)&miniRect, sizeof(Rect), &scratchDesc);
    /* add it */
    if (!myErr)
        myErr = AEPutParamDesc(&tempList, keyAEBounds, &scratchDesc);
    if (!myErr)
        myErr = AEDisposeDesc(&scratchDesc);
    /* and the transfer mode, I'm using Copy for all of these */
    if (!myErr)
        myErr = AECreateDesc(typeEnumeration, (Ptr)&copyWord, sizeof(long), &scratchDesc);
    /* add it */
    if (!myErr)
        myErr = AEPutParamDesc(&tempList, keyAETransferMode, &scratchDesc);
    if (!myErr)
        myErr = AEDisposeDesc(&scratchDesc);
    /* and coerce thePlace into a typePixelMap */
    if (!myErr)
        myErr = AECoerceDesc(&tempList, typePixelMap, thePlace);
    
    /* See?  Simplicity itself */
    mAEErrorDisplay("\p\n Error creating pixMap", myErr)
    return(myErr);
}
 
 
#undef __AEMU__