home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1998 / MacHack 1998.toast / Papers / C++ Exceptions / µShell / Threads Support / AEThreads.cp next >
Encoding:
Text File  |  1998-05-25  |  4.1 KB  |  190 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        AEThreads.c
  3.                   
  4.     Contains:    Routines for installing threaded AppleEvent handlers
  5.  
  6.     Written by: Steve Sisak
  7.  
  8.      Copyright:    © 1993-94 Steve Sisak
  9.                 License is granted to use, modify, make derivative works, and 
  10.                 duplicate this code at will, so long as this notice remains intact.
  11.  
  12.     Change History (most recent first):
  13.     
  14.          <1>     1/24/95    DRF        First checked in.
  15. */
  16.  
  17. #ifndef __AETHREADS__
  18. #include "AEThreads.h"
  19. #endif
  20. #ifndef __ERRORS__
  21. #include <Errors.h>
  22. #endif
  23. #ifndef __APPLEEVENTS__
  24. #include <AppleEvents.h>
  25. #endif
  26.  
  27. #include "ThreadSupport.h"
  28. #include "Exceptions.h"
  29.  
  30.  
  31. pascal OSErr SpawnAEThread(const AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon);
  32.  
  33. class AEThread : public TThread
  34. {
  35. protected:
  36.     AEEventHandlerUPP    fHandler;    // The real handler
  37.     const AppleEvent*    fEvent;
  38.     AppleEvent*            fReply;
  39.     long                fRefcon;
  40.  
  41. public:
  42.     AEThread(AEEventHandlerUPP handler, const AppleEvent* event, AppleEvent* reply, long refcon, ThreadID id)
  43.     : TThread(id), fHandler(handler), fEvent(event), fReply(reply), fRefcon(refcon) {};
  44.     virtual    ~AEThread() {};
  45.     
  46.     static pascal void*            AEThreadProc(AEThread* context);
  47.  
  48.     friend pascal OSErr SpawnAEThread(const AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon);
  49. };
  50.  
  51. struct AEThreadDesc                    // Kept in the OS refcon
  52. {
  53.     AEEventHandlerUPP    handler;    // The real handler
  54.     long                refcon;        // The real refcon
  55.     Size                stackSize;    // Stack size for handling event
  56.     ThreadOptions        options;    // Thread options for event
  57.     ThreadID            holder;        // used as a semaphore
  58. };
  59.  
  60. AEEventHandlerUPP gSpawnAEThreadUPP = nil;
  61.  
  62. //#pragma segment foobar
  63.  
  64. pascal OSErr AEInstallThreadedEventHandler(
  65.     AEEventClass        theAEEventClass,
  66.     AEEventID            theAEEventID,
  67.     AEEventHandlerUPP    proc,
  68.     long                handlerRefcon,
  69.     ThreadOptions        options,
  70.     Size                stacksize)
  71. {
  72.     AEThreadDesc* desc = (AEThreadDesc*) NewPtr(sizeof(AEThreadDesc));
  73.     OSErr          err  = MemError();
  74.     
  75.     if (gSpawnAEThreadUPP == nil)
  76.     {
  77.         gSpawnAEThreadUPP = NewAEEventHandlerProc(SpawnAEThread);
  78.     }
  79.     
  80.     if (err == noErr)
  81.     {
  82.         desc->handler    = proc;
  83.         desc->refcon    = handlerRefcon;
  84.         desc->stackSize    = stacksize;
  85.         desc->options    = options;
  86.         desc->holder    = kNoThreadID;
  87.  
  88.         err = AEInstallEventHandler(theAEEventClass, theAEEventID, gSpawnAEThreadUPP, (long) desc, false);
  89.     }
  90.     
  91.     return err;
  92. }
  93.  
  94.  
  95. pascal void* AEThread::AEThreadProc(AEThread* context)
  96. {
  97.     OSErr result = noErr;
  98.  
  99.     try
  100.     {
  101.         result = CallAEEventHandlerProc(context->fHandler, context->fEvent, context->fReply, context->fRefcon);
  102.  
  103.         // Since the event was suspended, we need to stuff the error code ourselves    
  104.         // note that there's not much we can do about reporting errors beyond here
  105.     }
  106.     catch (Exception& err)
  107.     {
  108.         err.CopyToAppleEvent(CAppleEvent(context->fReply));
  109.         result = 1;
  110.     }
  111.     catch (...)
  112.     {
  113.         result = eGeneralErr;
  114.     }
  115.  
  116.     OSErr err;
  117.  
  118.     if (result != 1)
  119.     {
  120.         err = AEPutAttributePtr(context->fReply, keyErrorNumber, typeShortInteger, &result, sizeof(result));
  121.  
  122. #if qDebug
  123.         if (err)
  124.             SysBreakStr("\pAEPutAttributePtr failed installing error code - very bad");
  125. #endif
  126.     }
  127.  
  128.     err = AEResumeTheCurrentEvent(context->fEvent, context->fReply, kAENoDispatch, 0);    // This had better work
  129.  
  130. #if qDebug
  131.     if (err)
  132.         SysBreakStr("\pAEResumeTheCurrentEvent failed - very bad");
  133. #endif
  134.  
  135.     delete context;
  136.  
  137.     return nil;
  138. }
  139.  
  140. pascal OSErr AEHandleInThread(
  141.                     const AppleEvent*    event,
  142.                     AppleEvent*            reply,
  143.                     AEEventHandlerUPP    handler,
  144.                     long                handlerRefcon,
  145.                     ThreadOptions        options,
  146.                     Size                stacksize)
  147. {
  148.     OSErr             result;
  149.     AEThread* context = new AEThread(handler, event, reply, handlerRefcon);
  150.     
  151.     try
  152.     {
  153.         FailNil(context);
  154.     
  155.         context->CreateThread(kCooperativeThread, (ThreadEntryProcPtr) AEThread::AEThreadProc, stacksize, options);
  156.  
  157.         result = AESuspendTheCurrentEvent(event);
  158.     }
  159.     catch (TException& err)
  160.     {
  161.         delete context;
  162.         result = err.GetErrorNumber();
  163.     }
  164.     catch (...)
  165.     {
  166.         delete context;
  167.         result = eGeneralErr;
  168.     }
  169.     
  170.     return result;
  171. }
  172.  
  173.  
  174. //#pragma segment Spawn
  175.  
  176. pascal OSErr SpawnAEThread(const AppleEvent *event, AppleEvent *reply, long handlerRefcon)
  177. {
  178.     AEThreadDesc* desc = (AEThreadDesc*) handlerRefcon;
  179.  
  180.      return AEHandleInThread(event, reply,
  181.                             desc->handler,
  182.                             desc->refcon,
  183.                             desc->options,
  184.                             desc->stackSize);
  185. }
  186.  
  187.  
  188.  
  189.  
  190.