TumblerSource/Tumbler_AEVT.c

//  Tumbler_AEVT.c
//
//  Apple Event Routines for the Tumbler App.  Contains AppleEvent Handlers and senders for
//  the Tumbler app.
//      
//  Author:     Nick Thompson, 11/24/94
//
//  Modification History:
//
//  11/26/94        nick        clean up, remove old TE references from dragtext, remove
//                              all other dead code
//  11/24/94        nick        Initial Cut - factored code from Tumbler event, added
//                              Drag related events for debugging (you can't debug the 
//                              handler, but if the handler sends an event you can debug
//                              the AE handler).
//
//  Copyright © 1992-95 Apple Computer, Inc., All Rights Reserved
//
//  To Do:
//      a number of items are "duplicated" in the event we send to ourselves
//      we send the window and the document (the doc reference is stored in the
//      window refcon, window is stored in the doc)
//
 
#include <AppleEvents.h>
#include <Drag.h>
#include <Gestalt.h>
#include <Memory.h>
#include <SegLoad.h>
 
#include "Tumbler_prototypes.h"
#include "Tumbler_resources.h"
#include "Tumbler_offscreen.h"
#include "Tumbler_globals.h"
 
#include "Tumbler_AEVT.h"
#include "Tumbler_Traps.h"
#include "Tumbler_Document.h"
#include "Tumbler_file.h"
#include "Tumbler_PICTImport.h"
#include "Tumbler_camera.h"
#include "Tumbler_file.h"
 
#ifdef PODIUM_APP
#include "Tumbler_Podium.h"
#endif
 
#include "QD3D.h"
#include "QD3DDrawContext.h"
#include "QD3DGroup.h"
#include "QD3DIO.h"
#include "QD3DPick.h"
#include "QD3DShader.h"
#include "QD3DStorage.h"
#include "QD3DTransform.h"
#include "QD3DView.h"
 
 
#define kGestaltTrap    0xA0AD
 
#include "Tumbler_AEVT.h"
 
 
// local variables - to this file
 
static AEAddressDesc        pSelfAddress;           // A self-addressed address descriptor record
static ProcessSerialNumber  pSelfPSN;               // This application's psn
static AEDesc               pnilDesc;               // A nil descriptor record
 
// this defines a suite of events for dispatching drags
static const AEEventClass   kDraggingClass          = 'drag' ;
    static const AEEventID      kDragDrawID             = 'draw' ;
    static const AEEventID      kDragSendID             = 'send' ;
    static const AEEventID      kDragReceiveID          = 'recv' ;
    static const AEEventID      kDragTrackID            = 'trak' ;
    static const AEEventID      kDragDragID             = 'drag' ;
    
//
 
static const AEKeyword  keyPrivateData              = 'priv' ;
 
 
// AppleEvent Error Handling....
//----------------------------------------------------------------------------------
//  If an error has occurred, I check the user interaction level. If I can          
//  interact with the user, I put up a dialog and exit the application; otherwise,
//  I just exit the application.
//
//  ***NOTE: Real applications would not handle errors in this fashion!  If they
//  cannot interact with the user, they should abort the Apple event handler and
// return the error in the reply parameter.
 
void FailIfErr (OSErr  error)
{
    OSErr       interactErr = noErr ;
    if (error != noErr)
    {
        if ((interactErr = AEInteractWithUser(kNoTimeOut, nil, nil)) == noErr) {    
                                    // Can we interact?
            AlertUser(error);       // Yes, so put up the dialog.
            ExitToShell();
        }
    }
}
 
//----------------------------------------------------------------------------------
// Display an alert for the user to indicate that an error has occurred.
// This approach would not really be good for a real app - hard coding 
// strings in this manner would be really hard to localise.  But this approach
// is good for programming because it gives us the error code.  
 
void AlertUser (short  error)
{
    short       itemHit;
    Str255      defaultMessage = "\pAn error was encountered" ;
    Str255      message ;
    Str255      errNo ;
 
    if( error < 0 ) {
        BlockMove( &defaultMessage[1], &message[1], defaultMessage[0] );
        message[0] = defaultMessage[0] ;
    }
    else {
        GetIndString(message, rErrorStringIndex, error);
    }
    
    NumToString( error, errNo ) ;
    
    ParamText(  message,
                (ConstStr255Param)"\p (",
                errNo,
                (ConstStr255Param)"\p).");  // [pwpc]
 
    itemHit = Alert(rUserAlert, nil);
}
 
//----------------------------------------------------------------------------------
 
void    FatalError(short error)
{
 
    Str255      message ;
 
    GetIndString(message, rFatalErrorStringIndex, error);
    ParamText(message, (ConstStr255Param)"\p", (ConstStr255Param)"\p", (ConstStr255Param)"\p"); // [pwpc]
    (void)StopAlert( rFatalAlert, nil ) ;
    ExitToShell() ;
}
 
//-----------------------------------------------------------------------
// call this to init the AE stuff in this file
 
void InitAEStuff( void ) 
{
    // Set up the self-addressed descriptor record.
    pSelfPSN.highLongOfPSN = 0;
    pSelfPSN.lowLongOfPSN = kCurrentProcess;        // Use this instead of GetCurrentProcess
    FailIfErr(AECreateDesc(typeProcessSerialNumber,(Ptr)&pSelfPSN,sizeof(ProcessSerialNumber),&pSelfAddress));
    pnilDesc.descriptorType = typeNull;         // Initialize the global nil descriptor record.
    pnilDesc.dataHandle = nil;
    
    RegisterMyEvents() ;                            // and finally register appleEvent handlers
    
}
 
//-----------------------------------------------------------------------
// returns true if the platform supports appleevents - we won't run
// if it doesn't
 
Boolean SupportsAEVT(void)
{
    OSErr err;
    long response;
    
    if (!myTrapAvailable(kGestaltTrap))
        return false;
    
    err = Gestalt(gestaltAppleEventsAttr,&response);
    if (err!=noErr)
        return false;
        
    return (response && (response << gestaltAppleEventsPresent));
}
 
//-----------------------------------------------------------------------
// called to process high level appleevents
 
void DoHighLevelEvent(EventRecord *ev)
{
    OSErr err;
    
    err = AEProcessAppleEvent(ev);  
}
 
//-----------------------------------------------------------------------
// called to register our appleevent handlers
 
void RegisterMyEvents(void)
{
    OSErr err;
    
    if (!SupportsAEVT())
        return;
    
    err = AEInstallEventHandler(kCoreEventClass,kAEOpenApplication,NewAEEventHandlerProc(MyAEHandleOAPP),0L,false);
    if (err!=noErr)
        return;
                
    err = AEInstallEventHandler(kCoreEventClass,kAEOpenDocuments,NewAEEventHandlerProc(MyAEHandleODOC),0L,false);
    if (err!=noErr)
        return;
                
    err = AEInstallEventHandler(kCoreEventClass,kAEPrintDocuments,NewAEEventHandlerProc(MyAEHandlePDOC),0L,false);
    if (err!=noErr)
        return;
                
    err = AEInstallEventHandler(kCoreEventClass,kAEQuitApplication,NewAEEventHandlerProc(MyAEHandleQUIT),0L,false);
    if (err!=noErr)
        return;         
 
 
    // drag stuff handlers
    err = AEInstallEventHandler(kDraggingClass,kDragReceiveID,NewAEEventHandlerProc(MyAEHandleDragRecv),0L,false);
    if (err!=noErr)
        return;         
 
}
 
//-----------------------------------------------------------------------
// open application event handler for the core event suite, 
// by default we just want a blank new document
 
pascal OSErr MyAEHandleOAPP(AppleEvent *theAppleEvent,AppleEvent *reply,long refCon)
{
    OSErr err = noErr ;
 
#ifndef PODIUM_APP
    DoNewDocument();
#endif
    return err;
}
 
 
//-----------------------------------------------------------------------
// handler for the open document appleevent handler
 
pascal OSErr MyAEHandleODOC(AppleEvent *theAppleEvent,AppleEvent *reply,long refCon)
{
    FSSpec      myFSS;
    AEDescList  docList;
    OSErr       err,
                ignoreErr;
    long        index,
                itemsInList;
    Size        actualSize;
    AEKeyword   keywd;
    DescType    returnedType;
 
    
    err = AEGetParamDesc(theAppleEvent,keyDirectObject,typeAEList,&docList);
    if (err == noErr) {
    
        // see how many descriptor items are in the list
        // this is the number of documents we want to open
        err = AECountItems(&docList,&itemsInList);
 
        // now get each descriptor record from the list
        // coerce the returned data to an FSSpec record, and
        // open the asoociated file
        
        for (index=1; index <= itemsInList && err == noErr; index++) {
        
            err = AEGetNthPtr(  &docList, 
                                index,
                                typeFSS,
                                &keywd,
                                &returnedType,
                                (Ptr)&myFSS,
                                sizeof(myFSS),
                                &actualSize);
    
            if (err == noErr)   {
            
                FInfo       fndrInfo ;
                
                // we now have a valid FSSpec to reference the file, we need to know 
                // what type the file is to determine which file open function to call
                // we can determine this from the finder info for the file
                
                err = FSpGetFInfo( &myFSS, &fndrInfo ); 
                
                // if we got that ok, then we switch on the file  
                // type (we don't care about the creator type)  
                        
                if (err == noErr)   {
                
                    switch( fndrInfo.fdType ) {
                        case 'PICT':
                            break ;
                            
                        case 'TEXT':
                        case '3DMF':
                            err = DoOpenFile(&myFSS);
                            break ;
                        
                        default:
                            break ;
                    }
                }
            }
        }
        ignoreErr = AEDisposeDesc(&docList);
    }
    return err ;
}
 
//-----------------------------------------------------------------------
// handler for the print document event handler
 
pascal OSErr MyAEHandlePDOC(AppleEvent *theAppleEvent,AppleEvent *reply,long refCon)
{
    FSSpec      myFSS;
    AEDescList  docList;
    OSErr       err;
    long        index,
                itemsInList;
    Size        actualSize;
    AEKeyword   keywd;
    DescType    returnedType;
 
    
    err = AEGetParamDesc(theAppleEvent,keyDirectObject,typeAEList,&docList);
    if (err == noErr) {
    
        // see how many descriptor items are in the list
        // this is the number of documents we want to open
        err = AECountItems(&docList,&itemsInList);
 
        // now get each descriptor record from the list
        // coerce the returned data to an FSSpec record, and
        // open the asoociated file
        
        for (index=1; index <= itemsInList && err == noErr; index++) {
        
            err = AEGetNthPtr(  &docList, 
                                index,
                                typeFSS,
                                &keywd,
                                &returnedType,
                                (Ptr)&myFSS,
                                sizeof(myFSS),
                                &actualSize);
    
            if (err == noErr)   {                   
                // err = HandlePrintDoc( &myFSS );
                err = errAEEventNotHandled ;        // we don't do this yet...
            }
        }
        err = AEDisposeDesc(&docList);
    }
    return err ;
}
 
//-----------------------------------------------------------------------
// quit appleevent handler
 
pascal OSErr MyAEHandleQUIT(AppleEvent *theAppleEvent,AppleEvent *reply,long refCon)
{
    OSErr           err = noErr ;       // used as return value
 
    
    // close all windows and signal to Quit
 
    gQuitting = true;
        
    // attempt to close all documents
    if( CloseAllDocuments() == false )
        return userCanceledErr ;    // couldn't close them, so indicate the user cancelled
        
 
    // if we closed everything up successfully, we can return noErr, otherwise
    // indicate to sender of the 'quit' aevt that we canceled
    
    if (gQuitting) {
        gQuit = true;                       // user didn't cancel
        err = AEDisposeDesc(&pSelfAddress); // Dispose of my self-addressed descriptor.
    }
    else {
        err = userCanceledErr ;
    }
            
    return err ;
}
 
//-----------------------------------------------------------------------
// drag receive appleevent handler
 
pascal OSErr MyAEHandleDragRecv(AppleEvent *theAppleEvent,AppleEvent *reply,long refCon)
{
 
    AEDesc              myDesc;
    OSErr               err;
    OSErr               ignoreErr ;
    TQ3Object           objects = nil;
 
 
    err = AEGetParamDesc(theAppleEvent,keyPrivateData,typeChar,&myDesc);
    if (err == noErr) {
    
        // try to load all of the items we stuffed into the apple event
        myPrivateDataHdl        thePrivateData = (myPrivateDataHdl)myDesc.dataHandle ;
        OSType                  theDragType = (**thePrivateData).myTypeOfData ;
        DocumentPtr             theDocument = (**thePrivateData).myDocument ;
        long                    dataSize = (**thePrivateData).myDataSize ;
        WindowPtr               theWindow = (**thePrivateData).myWindow  ;
        Point                   theLocation = (**thePrivateData).myLocation ;
        Handle                  dataHdl = NewHandle( dataSize ) ;
        
        // sanity check
        if( dataSize > GetHandleSize( myDesc.dataHandle )) {
            ignoreErr = AEDisposeDesc(&myDesc);
            return paramErr ;
        }
        
        // check we could create the data handle OK
        if( dataHdl == nil ) {
            ignoreErr = AEDisposeDesc(&myDesc);
            return MemError() ;
        }
 
        // copy the data from the descriptor to our handle
        BlockMove( &(**thePrivateData).myData, *dataHdl, dataSize );
        
        // we need to get rid of the descriptor, to save on memory
        err = AEDisposeDesc(&myDesc);
        
        // process the information from the drag
        if( theDragType == '3DMF' ) {
        
            TQ3SharedObject viewHints ;
        
            // do this on receipt of a drag of type 3DMF    
 
            TQ3FileObject       fd;
            TQ3StorageObject        storage;
 
            // Lock and load
            MoveHHi( dataHdl ) ;
            HLock(  dataHdl ) ;
            
            storage = Q3MemoryStorage_New((const unsigned char *) *dataHdl,
                (unsigned long) dataSize );
                
            HUnlock( dataHdl ) ;
            
            if (storage == nil)
                goto bail;
            
            fd = Q3File_New();
            Q3File_SetStorage(fd, storage);
            Q3Object_Dispose(storage);
            
            if (fd == nil)
                goto bail;
 
            Tumbler_ReadScene(
                fd,
                false,
                &viewHints,
                &theDocument->documentGroup) ;
                
            TumblerDocument_UpdateView( theDocument,  viewHints ) ;
 
#ifdef PODIUM_APP
            {
            // we really want the obect to be centered about the 
            // drop location.
            GrafPtr     savedPort ;
            
            extern void Podium_UpdateDrawContextFromDropRect( DocumentPtr theDocument ) ;
 
            GetPort( &savedPort ) ;
            SetPort( theWindow ) ;
            GlobalToLocal(&theLocation) ;
            
            // make the droprect be located top left at (0, 0)
            OffsetRect( &theDocument->dropArea, -theDocument->dropArea.left,  -theDocument->dropArea.top );
            OffsetRect( &theDocument->dropArea, 
                            (theLocation.h - ((theDocument->dropArea.right - theDocument->dropArea.left)/2)), 
                            (theLocation.v - ((theDocument->dropArea.bottom - theDocument->dropArea.top)/2)) );
            Podium_UpdateDrawContextFromDropRect( theDocument ) ;
            SetPort(savedPort) ;
            }
#endif
            
            TumblerDocument_UpdateView( theDocument, viewHints ) ;
            
            AdjustLightsPositions(theDocument) ;
        
            if (viewHints)
                Q3Object_Dispose(viewHints);
        
            Q3Object_Dispose(fd);
        }       
        else if( theDragType == 'PICT' ){
 
            // do this on receipt of a drag of type PICT
 
            TQ3StoragePixmap textureImage;
            PicHandle       thePicture = (PicHandle)dataHdl ;
 
            //Create a texture pixmap
            MoveHHi((Handle) thePicture );
            HLock((Handle) thePicture );
 
            if( TextureFromPICT((PicHandle) thePicture, &textureImage) == kQ3False ) {
                Alert(130, 0L);
                goto bail;
            }
            
            if( AddTextureToDocument( theDocument, &textureImage) != kQ3Success ) {
                Alert(130, 0L);
                goto bail;
            }
            HUnlock((Handle)thePicture);
            
        }       
        else if( theDragType == flavorTypeHFS ){
        
            // do this on receipt of an HFS flavor (a file from the finder)
            HFSFlavor       theHFSFlavor ;
 
            // lock down the handle
            MoveHHi( dataHdl ) ;
            HLock( dataHdl ) ;
            
            theHFSFlavor = *((HFSFlavor *)*dataHdl) ;
 
            
            if( theHFSFlavor.fileType == 'TEXT' || theHFSFlavor.fileType == '3DMF') {
            
                OSErr               result;
                short               refNum;
                DocumentPtr         theDocument;
                FInfo               fndrInfo ;
                TQ3Boolean          isText ;
            
                // we assume the FSSpec passed in was valid, get the file information
                // we need to know the file type, this routine may get called by an appleEvent
                // handler, so we can't assume a type, we need to get it from the fsspec.
                
                FSpGetFInfo( &theHFSFlavor.fileSpec, &fndrInfo ) ;
                
                // pull out the file type
                
                isText = ( fndrInfo.fdType == 'TEXT') ;
                
                if ((result = FSpOpenDF(&theHFSFlavor.fileSpec, fsRdWrPerm, &refNum)) != noErr)
                    return(result);
        
                theDocument->fRefNum = refNum;
                theDocument->theFileSpec = theHFSFlavor.fileSpec ;
                SetCursor(*GetCursor(watchCursor));
                ReadDocumentFile( theDocument, isText ) ;
                SetCursor(&qd.arrow);
            
            } else if( theHFSFlavor.fileType == 'PICT' && theDocument && theDocument->documentGroup) {
 
                PicHandle       thePict;
                TQ3StoragePixmap textureImage;
                
                // get the picture from the file
                thePict = OpenPICTFile(&theHFSFlavor.fileSpec);
                
                // make a texture
                TextureFromPICT( thePict, &textureImage);
                AddTextureToDocument( theDocument, &textureImage);
                
                // and free the space occupied by the picture
                KillPicture(thePict) ;
            
            }
            else
                dataSize = 0;   // need better handling here...
        
        
        }
 
        // we can free up the memory now...
        DisposeHandle( dataHdl ) ;
        dataHdl = nil ;
        
        //  If we actually received something, insert it into the destination.
    
        if (dataSize != 0) {
    
            theDocument->dirty = true;
                AdjustLightsPositions( theDocument);
                
                AdjustCamera(theDocument,
                    theWindow->portRect.right - theWindow->portRect.left,
                    theWindow->portRect.bottom - theWindow->portRect.top);
 
            //  Draw everything into offscreen pixmap.
            if (DrawOffscreen(theDocument)) {
                SetPort( theWindow ) ;
                InvalRect( &theWindow->portRect ) ;
                DrawOnscreen(theDocument);
            } 
        }   
    }
    return err ;
    
bail:
    return(memFullErr);
}
 
//-----------------------------------------------------------------------
// A P P L E E V E N T   S E N D E R   R O U T I N E S . . .
//-----------------------------------------------------------------------
// These routines are used to send ourselves AppleEvents, this is useful 
// for a number of reasons, ultimately it would help make us scriptable if
// we implemented some of the OSL, also it's a big help for debugging drags.
//
// Its not really easy to do source level debugging of drag handlers and 
// trackers.  By packaging up the information into an appleevent and sending
// it to ourselves, we can to source level debugging of the drag in the AE 
// handler.
 
 
//----------------------------------------------------------------------------------//
//  Send a Quit Application Apple Event to myself to terminate this app.        
 
void SendQuitApp( void )
{
    AppleEvent  myAppleEvent, reply;
    
    //  Create the Apple Event.
    FailIfErr(AECreateAppleEvent( kCoreEventClass, 
                                  kAEQuitApplication, 
                                  &pSelfAddress,
                                  kAutoGenerateReturnID, 
                                  kAnyTransactionID, 
                                  &myAppleEvent));
                                  
    //  Send the Apple Event.
    FailIfErr(AESend( &myAppleEvent, 
                      &reply, 
                      kAENoReply+kAENeverInteract, 
                      kAENormalPriority,
                      kAEDefaultTimeout, 
                      nil, 
                      nil));
                      
    AEDisposeDesc(&myAppleEvent);               // Dispose of the Apple Event.
} // SendQuitApp
 
//----------------------------------------------------------------------------------//
//  Send a Open Document Application Apple Event to myself to open a document.      
 
void SendOpenDoc(FSSpec *myFSSpec)
{
    AppleEvent    myAppleEvent;
    AppleEvent    defReply;
    AEDescList    docList;
 
    OSErr         ignoreErr;
    
    myAppleEvent.dataHandle = nil;
    docList.dataHandle  = nil;
    defReply.dataHandle = nil;
        
    // Create empty list and add one file spec
    FailIfErr(AECreateList(nil,0,false, &docList));
    
    FailIfErr(AEPutPtr(&docList,1,typeFSS,(Ptr)myFSSpec,sizeof(FSSpec)));
        
    FailIfErr(AECreateAppleEvent(   kCoreEventClass,
                                    kAEOpenDocuments,
                                    &pSelfAddress,
                                    kAutoGenerateReturnID,
                                    kAnyTransactionID,
                                    &myAppleEvent));
 
    // Put Params into our event and send it
 
    FailIfErr(AEPutParamDesc( &myAppleEvent,
                              keyDirectObject,
                              &docList));
 
    FailIfErr(AESend( &myAppleEvent,
                      &defReply,
                      kAENoReply+kAENeverInteract,
                      kAENormalPriority,
                      kAEDefaultTimeout,
                      nil,
                      nil));
        
        
    if (myAppleEvent.dataHandle) 
        ignoreErr = AEDisposeDesc(&myAppleEvent);
        
    if (docList.dataHandle) 
        ignoreErr = AEDisposeDesc(&docList);
            
}   // SendOpenDoc 
 
//----------------------------------------------------------------------------------//
//  Send a Print Document Application Apple Event to myself to open a document.     
 
 
 
 
void SendPrintDoc(FSSpec *myFSSpec)
{
    AppleEvent    myAppleEvent;
    AppleEvent    defReply;
    AEDescList    docList;
 
    OSErr         ignoreErr;
    
    myAppleEvent.dataHandle = nil;
    docList.dataHandle  = nil;
    defReply.dataHandle = nil;
        
    // Create empty list and add one file spec
    FailIfErr(AECreateList(nil,0,false, &docList));
    
    FailIfErr(AEPutPtr(&docList,1,typeFSS,(Ptr)myFSSpec,sizeof(FSSpec)));
        
    FailIfErr(AECreateAppleEvent(   kCoreEventClass,
                                    kAEPrintDocuments,
                                    &pSelfAddress,
                                    kAutoGenerateReturnID,
                                    kAnyTransactionID,
                                    &myAppleEvent));
 
    // Put Params into our event and send it
 
    FailIfErr(AEPutParamDesc( &myAppleEvent,
                              keyDirectObject,
                              &docList));
 
    FailIfErr(AESend( &myAppleEvent,
                      &defReply,
                      kAENoReply+kAENeverInteract,
                      kAENormalPriority,
                      kAEDefaultTimeout,
                      nil,
                      nil));
        
        
    if (myAppleEvent.dataHandle) 
        ignoreErr = AEDisposeDesc(&myAppleEvent);
        
    if (docList.dataHandle) 
        ignoreErr = AEDisposeDesc(&docList);
            
}   // SendOpenDoc 
 
 
 
//----------------------------------------------------------------------------------
//  Send a drag receive Apple Event to myself to handle the receipt of a drag.      
 
 
void SendDragRecv( myPrivateDataHdl privateHdl )
{
    AppleEvent    myAppleEvent;
    AppleEvent    defReply;
 
    OSErr         ignoreErr;
    
    ProcessSerialNumber     myPSN ;
    
    AEDesc          myAddress ;
    char            cMemTags = HGetState((Handle)privateHdl);   // save the state of the handle in case
                                                                // it was already locked before we were
                                                                // called
    
    myAppleEvent.dataHandle = nil;
    defReply.dataHandle = nil;
 
    // the static pSelfAddress that we create an usually use will cause the 
    // AE handler to be caused directly (less overhead).  We DON'T WANT THAT
    // to happen here.  The reason being that the handler for this event needs
    // to be called in our main event loop, not directly at the send.  Doing things
    // this way lets us get out of the Drag Managers context, back into our own.
    // that in turn lets us use a high level debugger.
    
    
    FailIfErr(GetCurrentProcess(&myPSN)) ;
    FailIfErr(AECreateDesc(typeProcessSerialNumber,(Ptr)&myPSN,sizeof(ProcessSerialNumber),&myAddress));
 
    FailIfErr(AECreateAppleEvent(   kDraggingClass,
                                    kDragReceiveID,
                                    &myAddress,
                                    kAutoGenerateReturnID,
                                    kAnyTransactionID,
                                    &myAppleEvent));
 
    // lock down the handle
    MoveHHi( (Handle)privateHdl );
    HLock( (Handle)privateHdl );
    
    // Put Params into our event and send it
 
    FailIfErr(AEPutParamPtr( &myAppleEvent,
                             keyPrivateData,
                             typeChar,
                             *privateHdl,
                             GetHandleSize( (Handle)privateHdl )));
 
    // restore the state of the handle (effectively the same as HUnlock)
    HSetState((Handle)privateHdl, cMemTags) ;
 
    FailIfErr(AESend( &myAppleEvent,
                      &defReply,
                      kAENoReply+kAENeverInteract,
                      kAENormalPriority,
                      kAEDefaultTimeout,
                      nil,
                      nil));
        
        
    if (myAddress.dataHandle) 
        ignoreErr = AEDisposeDesc(&myAddress);
 
    if (myAppleEvent.dataHandle) 
        ignoreErr = AEDisposeDesc(&myAppleEvent);
}