home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / FakeStart 1.0 / FS_Source / FakeStart.c next >
Encoding:
C/C++ Source or Header  |  1996-04-16  |  25.3 KB  |  871 lines  |  [TEXT/CWIE]

  1. /****
  2.     File.....:     FakeStart.c
  3.     Date.....:     Thursday, April 04 1996
  4.     By.......:     Ken Earle. No rights reserved.
  5.     Status...:     tested.
  6.     Spec.....:     "main" for the Fake Start project.
  7.                  Fake app to start up a "real" application, forcing it low in memory.
  8.                  Which application is determined by the "creator" code in
  9.                      STR# 1001, string 1.
  10.                  User double-clicks us or drags documents onto us.
  11.                  On Startup:
  12.                  -grab any opening Apple Event
  13.                  -check if the "real" application is open yet: if not,
  14.                      -allocate big chunks of system memory, locked and high
  15.                      -open the real application low in memory
  16.                  -pass any documents from opening AE along to real application
  17.                  -free system memory if allocated (not really needed)
  18.                  -Quit.
  19.                  This app has no interface, except for error Alerts.
  20. ****/
  21.  
  22. #include <Traps.h>
  23. #include <GestaltEqu.h>
  24.  
  25. #define _GestaltDispatch                0xA0AD
  26.  
  27. #include "FakeStart.h"
  28. #include "MultiFnder.h"
  29. #include "FS_Memory.h"
  30.  
  31. // Globals for system 7
  32. SysDetails     gSysDetails;
  33. SysEnvRec    gMac;
  34.  
  35. // AE handling globals
  36. FSSpecElementPtr    gSpecElementP = NULL;    // for documents to open
  37. Boolean                gWasOpenAE = FALSE;        // received odoc event here
  38. Boolean                gWasPrintAE = FALSE;    // received pdoc event here
  39.  
  40.  
  41. // Functions in this file
  42. void main(void);
  43. void GetOut
  44.     (short         alertID,                // eg ALRT 1000
  45.     ErrorIndex     theErrorMessageIndex,    // into a STR# rsrc
  46.     OSType        realApplicationCreator    // eg 'JAGO', app to launch
  47.     );
  48. void DoMostStandardMacInits(void);
  49. OSType GetRealApplicationCreator(void);
  50. OSErr GrabStartupAppleEvent(void);
  51. OSErr OpenDocumentsInRunningApp
  52.     (ProcessSerialNumber    *serialNumP,    // ->PSN of application
  53.     FSSpecElementPtr        specElementP    // ->list of doc file specs
  54.     );
  55. OSErr OpenItemInFinder(FSSpecElementPtr specElementP); // ->list of doc file specs
  56. // Utility functions
  57. // Gestalt and trap support
  58. static void InitGestaltGlobals(void);
  59. Boolean HasGestaltAbility
  60.     (OSType        selector,    // eg gestaltFSAttr
  61.     short        bitNumber    // eg gestaltHasFSSpecCalls
  62.     );
  63. static Boolean System7Available(void);
  64. Boolean TrapIsAvailable(short theTrap);
  65. // AppleEvent handlers: we just remember any file specs passed along.
  66. void AEInstallEventHandlers(void);
  67. pascal OSErr Handle_aevt_oapp(AppleEvent *theAppleEventP, AppleEvent *reply,
  68.     long myRefCon);
  69. pascal OSErr Handle_aevt_odoc(AppleEvent *theAppleEventP, AppleEvent *reply,
  70.     long myRefCon);
  71. pascal OSErr Handle_aevt_pdoc(AppleEvent *theAppleEventP, AppleEvent *reply,
  72.     long myRefCon);
  73. pascal OSErr Handle_aevt_quit(AppleEvent *theAppleEventP, AppleEvent *reply,
  74.     long myRefCon);
  75. static OSErr ExtractFSSpecListFromAE(AppleEvent *theAppleEventP); // typ. 'odoc'
  76. OSErr AddFSSToAEList
  77.     (AEDescList     *aeDescListP,    // <->becomes direct object of event
  78.     short             index,             // 0 means add at end
  79.     FSSpec             *fsspecFileP    // ->the document spec to add
  80.     );
  81. // Process handling
  82. OSErr FindAProcess
  83.     (OSType                    typeToFind,        // eg 'APPL' or 'FNDR'
  84.     OSType                    creatorToFind,    // eg 'JAGO' or 'MACS'
  85.     ProcessSerialNumberPtr    processSN        // <- PSN of process
  86.     );
  87. // File handling
  88. static void GetErrorMessage
  89.     (StringPtr     messageP,                // Str255 for ParamText
  90.     ErrorIndex     theErrorMessageIndex    // into a STR# rsrc
  91.     );
  92. static void GetGeneralMessage
  93.     (StringPtr         messageP,                // Str255 for ParamText
  94.     GeneralIndex     theGeneralMessageIndex    // into a STR# rsrc
  95.     );
  96. OSErr LocateFileByTypeCreator
  97.     (OSType        fdType,                // eg 'APPL'
  98.     OSType        fdCreator,            // eg 'JAGO'
  99.     short        vRefNum,            // 0 for default drive
  100.     FSSpec        *spec                // <- file spec
  101.     );
  102. OSErr LaunchIt
  103.     (FSSpec                *theAppP,    // ->Specs which application to launch
  104.     ProcessSerialNumber *serialNumP    // <-filled in if we succeed
  105.     );
  106. static OSErr AddSpecElement
  107.     (FSSpecPtr            theSpecP,        // ->a document file spec
  108.     FSSpecElementPtr    *specElementPP    // <->head of spec list or NULL first time
  109.     );
  110.  
  111.  
  112. /* Do it all and quit, see spec at top.
  113. */
  114. void main(void)
  115.     {
  116.     EventRecord                event;                         // used at end
  117.     FSSpec                    realApplicationSpec;         // for real Application
  118.     ProcessSerialNumber        realApplicationPSN;             // ditto
  119.     Handle                    bigChunkHA[NUM_HANDLES_TOP]; // to seize hi mem
  120.     OSType                    realApplicationCreator;         // eg 'JAGO', app to launch
  121.     short                    i;
  122.     OSErr                    theErr = noErr;
  123.     Boolean                    realAppIsRunning = FALSE;    // !avoid launching twice!
  124.     
  125.     // Clear system handles to be allocated
  126.     for (i = 0; i < NUM_HANDLES_TOP; ++i)
  127.         bigChunkHA[i] = NULL;
  128.     
  129.     // Do standard Mac inits.
  130.     DoMostStandardMacInits();
  131.     
  132.     // Can we proceed? If not, alert and exit.
  133.     if (gMac.machineType < 0)        //does not have 128K ROMS
  134.         GetOut(kCannotFunctionAlertID, eMachineTooOld_ErrorIndex, 0);
  135.     if (!gSysDetails.hasSystem7 )    // too primitive
  136.         GetOut(kCannotFunctionAlertID, ePreSystem7_ErrorIndex, 0);
  137.     if (!gSysDetails.hasAE)            // Can't start real app
  138.         GetOut(kCannotFunctionAlertID, eNoAppleEvents_ErrorIndex, 0);
  139.     
  140.     // Get real Application Creator (eg 'JAGO') from our resources, or use default.
  141.     realApplicationCreator = GetRealApplicationCreator();
  142.     
  143.     // Grab any startup Apple Event.
  144.     theErr = GrabStartupAppleEvent(); // fills in global list gSpecElementP
  145.     if (theErr != noErr)
  146.         gSpecElementP = NULL;
  147.     
  148.     // Find real Application on disk, or get out.
  149.     theErr = LocateFileByTypeCreator(realApplication_type, realApplicationCreator,
  150.                                     0, &realApplicationSpec);
  151.     if (theErr != noErr)
  152.         {
  153.         GetOut( kCannotFunctionAlertID, eApplicationNotFound_ErrorIndex,
  154.                 realApplicationCreator );
  155.         }
  156.     
  157.     // See if the real app is running.
  158.     theErr = FindAProcess( realApplication_type, realApplicationCreator,
  159.                           &realApplicationPSN );
  160.     if (theErr == noErr)
  161.         realAppIsRunning = TRUE;
  162.     
  163.     // If not running, will need to grab upper memory to force app low.
  164.     // If we can't grab the memory, get out.
  165.     if (!realAppIsRunning)
  166.         {
  167.         // Leave just a piece of low system memory free for the real app.
  168.         theErr = 
  169.             GrabUpperSystemMemory(&realApplicationSpec, bigChunkHA, NUM_HANDLES_TOP);
  170.         if (theErr != noErr)
  171.             {
  172.             GetOut(kCannotFunctionAlertID, eMemoryOut_ErrorIndex, 0);
  173.             }
  174.         }
  175.     
  176.     // Launch real Application if it isn't running yet.
  177.     if (!realAppIsRunning)
  178.         {
  179.         // Case with documents is the tricky one: if app understand AEs, then
  180.         // launch app and send odoc; else ask Finder to do the open.
  181.         if (gSpecElementP != NULL)
  182.             {
  183.             if (APP_IS_AE_AWARE)// see FakeStart.h
  184.                 {
  185.                 theErr = LaunchIt(&realApplicationSpec, &realApplicationPSN);
  186.                 if (theErr == noErr)
  187.                     theErr = OpenDocumentsInRunningApp( &realApplicationPSN,
  188.                                                          gSpecElementP );
  189.                 }
  190.             else                // old dumb thing, ask Finder to do the open
  191.                 theErr = OpenItemInFinder(gSpecElementP);
  192.             }
  193.         else                    // no document, just do a simple LaunchApplication
  194.             theErr = LaunchIt(&realApplicationSpec, &realApplicationPSN);
  195.         }
  196.     else                        // already open, just pass the documents along
  197.         {
  198.         // Pass list of docs to real Application.
  199.         if (gSpecElementP != NULL && theErr == noErr)
  200.             theErr = OpenDocumentsInRunningApp(&realApplicationPSN, gSpecElementP);
  201.         }
  202.     
  203.     // Deallocate system memory.
  204.     if (bigChunkHA[0] != NULL)
  205.         ReleaseUpperSystemMemory(bigChunkHA, NUM_HANDLES_TOP);
  206.     
  207.     // Spend a couple of events to start app.
  208.     for (i = 0; i < 2; ++i)
  209.         {
  210.         (void)WaitNextEvent(everyEvent, &event, 2, NULL);
  211.         }
  212.     // Exit, all done.
  213.     }
  214.  
  215. /* Show alert and exit.
  216. */
  217. void GetOut
  218.     (short         alertID,                // eg ALRT 1000
  219.     ErrorIndex     theErrorMessageIndex,    // into a STR# rsrc
  220.     OSType        realApplicationCreator    // eg 'JAGO', app to launch
  221.     )
  222.     {
  223.     Str255    messageP;    // put into param text
  224.     
  225.     // Read error message from STR# resource, put in param text.
  226.     GetErrorMessage(messageP, theErrorMessageIndex);
  227.     
  228.     if (theErrorMessageIndex == eApplicationNotFound_ErrorIndex)
  229.         {
  230.         Str31    creatorString;
  231.         
  232.         // Put creator in front, followed by resource message
  233.         BlockMove( &realApplicationCreator, creatorString + 1,
  234.                     sizeof(realApplicationCreator) );
  235.         creatorString[0] = sizeof(realApplicationCreator);
  236.         ParamText("\pCreator ", creatorString, messageP, "\p");
  237.         }
  238.     else
  239.         {
  240.         ParamText(messageP, "\p", "\p", "\p");
  241.         }
  242.     // Show a stop alert.
  243.     StopAlert(alertID, NULL);
  244.     
  245.     // Die.
  246.     ExitToShell();
  247.     }
  248.  
  249. /* Routine stuff, plus do SysEnv and a few Gestalt calls.
  250. */
  251. void DoMostStandardMacInits(void)
  252.     {
  253.     
  254.     MaxApplZone();
  255.     MoreMasters();
  256.     
  257.     InitGraf(&qd.thePort);
  258.     InitCursor();
  259.     InitFonts();
  260.     InitWindows();
  261.     InitMenus();
  262.     InitDialogs(NULL);
  263.     TEInit();
  264.     
  265.     // See if we have system 7 etc
  266.     InitGestaltGlobals();
  267.     
  268.     // Finish AppleEvent init, object handling
  269.     if (gSysDetails.hasAE)
  270.         {
  271.         AEObjectInit();
  272.         }
  273.     // Get standard environment information, complements gestalt info
  274.     SysEnvirons(kSysEnvironsVersion, &gMac);
  275.     // note the "blessed folder" is gMac.sysVRefNum
  276.     
  277.     // Can we do color? Hey, I was just curious....
  278.     gSysDetails.hasColor = gMac.hasColorQD;
  279.     
  280.     // Install AE handlers
  281.     if (gSysDetails.hasAE)
  282.         AEInstallEventHandlers();
  283.     }
  284.  
  285. /* Grab STR# that holds real app's creator--if not found, use a default.
  286. */
  287. OSType GetRealApplicationCreator(void)
  288.     {
  289.     Str255        rawString;                // big enough to hold any string
  290.     OSType        realApplicationCreator;    // eg 'JAGO', returned value
  291.     
  292.     // Get raw string, using a large holder to be safe.
  293.     GetGeneralMessage(rawString, eAppCreator_GeneralIndex);
  294.     
  295.     // If string "looks" like an OSType, use it, else use a default
  296.     if (rawString[0] == 4)
  297.         realApplicationCreator = *( (OSType *)(rawString + 1) );
  298.     else
  299.         realApplicationCreator = kDefaultAppCreator;
  300.     
  301.     return realApplicationCreator;
  302.     }
  303.  
  304. /* Do a few WNE's, waiting for an AE. If get an AE, collect file specs
  305. and return (handling of events done in Handle_aevt functions).
  306. */
  307. OSErr GrabStartupAppleEvent(void)
  308.     {
  309.     EventRecord    event;                // we wait for a hi-level event
  310.     short        i;
  311.     Boolean        gotEvent;
  312.     Boolean        receivedAE = FALSE;    // what we're waiting for
  313.     OSErr        theErr = noErr;
  314.     
  315.     for (i = 0; i < 3 && !receivedAE; ++i)
  316.         {
  317.         gotEvent = WaitNextEvent(everyEvent, &event, 2, NULL);
  318.         if (gotEvent)
  319.             {
  320.             switch (event.what)
  321.                 {
  322.             case kHighLevelEvent:
  323.                 theErr = AEProcessAppleEvent(&event);
  324.                 receivedAE = TRUE;
  325.             break;
  326.                 }
  327.             }
  328.         }
  329.     return theErr;
  330.     }
  331.  
  332. /* Pass AE to a running app asking it to open some documents. Call ONLY
  333. if specElementP != NULL. Well it won't crash, but it also won't do much.
  334. */
  335. OSErr OpenDocumentsInRunningApp
  336.     (ProcessSerialNumber    *serialNumP,    // ->PSN of application
  337.     FSSpecElementPtr        specElementP    // ->list of doc file specs
  338.     )
  339.     {
  340.     AEDesc             target              = {typeNull, NULL};
  341.     AppleEvent         aeEvent          = {typeNull, NULL};
  342.     AppleEvent         aeReply          = {typeNull, NULL};
  343.     AEDescList         aeDescFileList   = {typeNull, NULL};
  344.     AEEventID        theAEEventID;
  345.     AESendMode         sendMode;
  346.     OSErr             theErr = noErr;
  347.     
  348.     // Sanity check
  349.     if (specElementP == NULL)
  350.         return noErr;
  351.     
  352.     // Which event, open or print?
  353.     if (gWasOpenAE)
  354.         theAEEventID = kAEOpenDocuments;
  355.     else if (gWasPrintAE)
  356.         theAEEventID = kAEPrintDocuments;
  357.     else
  358.         return noErr;
  359.     
  360.     // Create AE for target application.
  361.     theErr = AECreateDesc(typeProcessSerialNumber, serialNumP, 
  362.                             sizeof(*serialNumP), &target);
  363.     if (theErr == noErr)
  364.         theErr = AECreateAppleEvent(kCoreEventClass, theAEEventID,
  365.                          &target, kAutoGenerateReturnID,
  366.                          kAnyTransactionID, &aeEvent);
  367.     
  368.     // Prepare AEDesc for doc(s) to be launched.
  369.     if (theErr == noErr)
  370.         theErr = AECreateList(NULL, 0, FALSE, &aeDescFileList);
  371.     while ( specElementP != NULL
  372.         &&  theErr == noErr )
  373.         {
  374.         theErr = AddFSSToAEList(&aeDescFileList, 0, &specElementP->fss);
  375.         specElementP = specElementP->next;
  376.         }
  377.     // Put list of docs in as direct object of the event.
  378.     if (theErr == noErr)
  379.         theErr = AEPutParamDesc(&aeEvent, keyDirectObject, &aeDescFileList);
  380.     
  381.     // Send 'odoc' or 'pdoc' AE to application, waiting for reply.
  382.     sendMode = kAEWaitReply + kAECanSwitchLayer + kAENeverInteract;
  383.     if (theErr == noErr)
  384.         theErr = AESend(&aeEvent, &aeReply,
  385.                      sendMode, kAEHighPriority,
  386.                      kNoTimeOut, NULL, NULL);
  387.     // Clean up.
  388.     (void)AEDisposeDesc(&target);
  389.      (void)AEDisposeDesc(&aeEvent);
  390.      (void)AEDisposeDesc(&aeReply);
  391.      (void)AEDisposeDesc(&aeDescFileList);
  392.     
  393.     return theErr;
  394.     }
  395.  
  396. /* Send in a list of FSSpec of items you wish the Finder to launch.
  397. */
  398. OSErr OpenItemInFinder(FSSpecElementPtr specElementP) // ->list of doc file specs
  399.     {
  400.     AEDesc                target             = {typeNull, NULL};
  401.     AEDescList            aeDescFileList     = {typeNull, NULL};
  402.     AppleEvent            aeEvent         = {typeNull, NULL},
  403.                         aeReply         = {typeNull, NULL};
  404.     AESendMode            sendMode;
  405.     ProcessSerialNumber    psnOfFinder;
  406.     OSErr                theErr = noErr;
  407.     
  408.     // Use Gestalt to check for OSL compliance
  409.     if (!HasGestaltAbility(gestaltFinderAttr, gestaltOSLCompliantFinder))
  410.         {
  411.         return 1; // codeword for OSL not supported here
  412.         }
  413.     
  414.     // Grab process for finder
  415.     theErr = FindAProcess(kostypeFinder, kostypeCreatorMac, &psnOfFinder);
  416.     if (theErr == noErr)
  417.         {
  418.         // Prepare 'odoc' AE for finder
  419.         theErr = AECreateDesc(typeProcessSerialNumber, &psnOfFinder,
  420.                     sizeof(ProcessSerialNumber), &target);
  421.         if (theErr == noErr)
  422.             theErr = AECreateAppleEvent(kCoreEventClass, kAEOpenDocuments,
  423.                                     &target, kAutoGenerateReturnID,
  424.                                     kAnyTransactionID, &aeEvent);
  425.         
  426.         // Prepare FSSpec(s) to send to finder
  427.         if (theErr == noErr)
  428.             theErr = AECreateList(NULL, 0, FALSE, &aeDescFileList);
  429.         while ( specElementP != NULL
  430.             &&  theErr == noErr )
  431.             {
  432.             theErr = AddFSSToAEList(&aeDescFileList, 0, &specElementP->fss);
  433.             specElementP = specElementP->next;
  434.             }
  435.         // Put list of docs in as direct object of the event.
  436.         if (theErr == noErr)
  437.             theErr = AEPutParamDesc(&aeEvent, keyDirectObject, &aeDescFileList);
  438.             
  439.         // Send AE to Finder
  440.         if (theErr == noErr) 
  441.             {
  442.             // Set AE switches, wait for reply etc.
  443.             sendMode = kAEWaitReply + kAECanSwitchLayer + kAENeverInteract;
  444.             theErr = AESend(&aeEvent, &aeReply, sendMode,
  445.                             kAEHighPriority, kAEDefaultTimeout,
  446.                             NULL, NULL);
  447.             }
  448.         // Tidy up
  449.         AEDisposeDesc(&aeEvent);
  450.         AEDisposeDesc(&aeReply);
  451.         AEDisposeDesc(&aeDescFileList);
  452.         AEDisposeDesc(&target);            
  453.         }
  454.     return theErr;
  455.     }
  456.  
  457. // Utility functions
  458.  
  459. /* See if we have system 7 etc, fill in gSysDetails.
  460. */
  461. static void InitGestaltGlobals(void)
  462.     {
  463.     long    response;    // bits (flags) from Gestalt call
  464.     
  465.     // Do we have Gestalt? If not, don't do anything.
  466.     gSysDetails.hasGestalt = TrapIsAvailable(_GestaltDispatch);
  467.     if (!gSysDetails.hasGestalt)
  468.         return;
  469.     // Do we have system 7? Do nothing if not.
  470.     gSysDetails.hasSystem7 = System7Available();
  471.     if (!gSysDetails.hasSystem7)
  472.         return;
  473.     // Do we have the "new" file system?
  474.     gSysDetails.hasFSS = HasGestaltAbility(gestaltFSAttr, gestaltHasFSSpecCalls);
  475.     //...and certain standard new features?
  476.     if (gSysDetails.hasFSS)
  477.         gSysDetails.hasFSS =
  478.                     HasGestaltAbility(gestaltStandardFileAttr, gestaltStandardFile58);
  479.     // Are Apple Events possible?
  480.     if ( !Gestalt(gestaltAppleEventsAttr, &response)
  481.       && !Gestalt(gestaltPPCToolboxAttr, &response) )
  482.         {
  483.         // Init communications
  484.         gSysDetails.hasAE = (PPCInit() == noErr);
  485.         }
  486.     }
  487.  
  488. /* Note call this only after setting global gSysDetails.hasGestalt.
  489. */
  490. Boolean HasGestaltAbility
  491.     (OSType        selector,    // eg gestaltFSAttr
  492.     short        bitNumber    // eg gestaltHasFSSpecCalls
  493.     )
  494.     {
  495.     long    response;            // bits (flags) from Gestalt call
  496.     Boolean    hasThing = FALSE;    // return value
  497.     
  498.     if (!gSysDetails.hasGestalt)
  499.         return FALSE;
  500.     if (!Gestalt(selector, &response))
  501.         hasThing = (response & (1<<bitNumber));
  502.     return hasThing;
  503.     }
  504.  
  505. /* See if we have at least system 7.
  506. */
  507. static Boolean System7Available(void)
  508.     {
  509.     long    sysVersion;
  510.     
  511.     if (!Gestalt(gestaltSystemVersion,&sysVersion))
  512.         {
  513.         if (sysVersion >= 0x700)
  514.             return TRUE;
  515.         }
  516.     return FALSE;
  517.     }
  518.  
  519. /* Determine if a particular call is available.
  520. */
  521. Boolean TrapIsAvailable(short theTrap)
  522.     {
  523.     TrapType     theTrapType;        // ToolTrap or OSTrap
  524.     short         numToolboxTraps;
  525.     
  526.     if ( (theTrap & 0x0800) > 0 )
  527.         theTrapType = ToolTrap;
  528.     else
  529.         theTrapType = OSTrap;
  530.  
  531.     if (theTrapType == ToolTrap)
  532.         {
  533.         theTrap = theTrap & 0x07ff;
  534.         if (NGetTrapAddress(_InitGraf, ToolTrap) == NGetTrapAddress(0xaa6e, ToolTrap))
  535.             numToolboxTraps = 0x0200;
  536.         else
  537.             numToolboxTraps = 0x0400;
  538.         if (theTrap >= numToolboxTraps)
  539.             theTrap = _Unimplemented;
  540.         }
  541.  
  542.     return (NGetTrapAddress(theTrap, theTrapType)
  543.         != NGetTrapAddress(_Unimplemented, ToolTrap));
  544.     }
  545.  
  546. /* Install standard AE handlers.
  547. */
  548. void AEInstallEventHandlers(void)
  549.     {
  550.     AEEventHandlerUPP aHandler;
  551.     
  552.     aHandler = NewAEEventHandlerProc(Handle_aevt_oapp);
  553.     (void)AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
  554.         aHandler, 0L, FALSE);
  555.     aHandler = NewAEEventHandlerProc(Handle_aevt_odoc);
  556.     (void)AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
  557.         aHandler, 0L, FALSE);
  558.     aHandler = NewAEEventHandlerProc(Handle_aevt_pdoc);
  559.     (void)AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
  560.         aHandler, 0L, FALSE);
  561.     aHandler = NewAEEventHandlerProc(Handle_aevt_quit);
  562.     (void)AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
  563.         aHandler, 0L, FALSE);
  564.     }
  565.  
  566.  
  567. // AppleEvent handler functions
  568.  
  569. /* Open the application (without documents).
  570. */
  571. pascal OSErr Handle_aevt_oapp(AppleEvent *theAppleEventP, AppleEvent *reply,
  572.     long myRefCon)
  573.     {
  574. #pragma unused(theAppleEventP, reply, myRefCon)
  575.     return noErr;
  576.     }
  577.  
  578. /* Open app with a list of documents: we just grab the list to gSpecElementP.
  579. */
  580. pascal OSErr Handle_aevt_odoc(AppleEvent *theAppleEventP, AppleEvent *reply,
  581.     long myRefCon)
  582.     {
  583.     OSErr        theErr;
  584.  
  585. #pragma unused(reply, myRefCon)
  586.     // Remember the event type, for resending to real Application
  587.     gWasOpenAE = TRUE;
  588.     theErr = ExtractFSSpecListFromAE(theAppleEventP);
  589.     return theErr;
  590.     }
  591.  
  592. /* Print a list of documents.
  593. */
  594. pascal OSErr Handle_aevt_pdoc(AppleEvent *theAppleEventP, AppleEvent *reply,
  595.     long myRefCon)
  596.     {
  597.     OSErr        theErr;
  598.  
  599. #pragma unused(reply, myRefCon)
  600.     // Remember the event type, for resending to real Application
  601.     gWasPrintAE = TRUE;
  602.     theErr = ExtractFSSpecListFromAE(theAppleEventP);
  603.     return theErr;
  604.     }
  605.  
  606. /* Quit--we quit immediately anyway.
  607. */
  608. pascal OSErr Handle_aevt_quit(AppleEvent *theAppleEventP, AppleEvent *reply,
  609.     long myRefCon)
  610.     {
  611. #pragma unused(theAppleEventP, reply, myRefCon)
  612.     return noErr;
  613.     }
  614.  
  615. /* Common to open and print, grab list of files to gSpecElementP.
  616. */
  617. static OSErr ExtractFSSpecListFromAE(AppleEvent *theAppleEventP)  // typ. 'odoc'
  618.     {
  619.     AEDescList    theAEDescList     = { typeNull, NULL };
  620.     AEKeyword    theAEKeyword;    // value not used
  621.     FSSpec        theSpec;        // extracted from direct object of event
  622.     DescType    typeCode;        // value not used
  623.     Size        actualSize;        // value not used
  624.     long        i;
  625.     long        count;            // count of file specs in direct object
  626.     OSErr        theErr = noErr;
  627.     
  628.     // Get direct object, containing file list.
  629.     theErr = AEGetParamDesc( theAppleEventP, keyDirectObject,
  630.                              typeAEList, &theAEDescList );
  631.     // Count the file items
  632.     if (theErr == noErr)
  633.         theErr = AECountItems(&theAEDescList, &count);
  634.     
  635.     // Loop over list, add FSSpecs to linked list gSpecElementP
  636.     if (theErr == noErr)
  637.         {
  638.         for (i = 1; i <= count && theErr == noErr; ++i)
  639.             {
  640.             theErr = AEGetNthPtr(&theAEDescList, i, typeFSS, &theAEKeyword, &typeCode,
  641.                         &theSpec, sizeof(FSSpec), &actualSize);
  642.             if (theErr == noErr)
  643.                 {
  644.                 theErr = AddSpecElement(&theSpec, &gSpecElementP);
  645.                 }
  646.             }
  647.         }
  648.         
  649.     // Clean up and return error result.
  650.     AEDisposeDesc(&theAEDescList);
  651.     return theErr;
  652.     }
  653.  
  654. /* Add one FSSpec as an alias to an AEDescList at position "index".
  655. To add at end, pass index = 0.
  656. */
  657. OSErr AddFSSToAEList
  658.     (AEDescList     *aeDescListP,    // <->becomes direct object of event
  659.     short             index,             // 0 means add at end
  660.     FSSpec             *fsspecFileP    // ->the document spec to add
  661.     )
  662.     {
  663.     AliasHandle    hAliasFile;
  664.     OSErr        theErr = noErr;
  665.     
  666.     // create alias handle & insert into AEDescList
  667.     theErr = NewAlias(NULL, fsspecFileP, &hAliasFile);
  668.     if (theErr == noErr) 
  669.         {
  670.         HLock( (Handle) hAliasFile );
  671.         theErr = AEPutPtr(aeDescListP, index, typeAlias,
  672.                         *hAliasFile, (*hAliasFile)->aliasSize);
  673.         DisposeHandle( (Handle)hAliasFile );
  674.         }
  675.     return theErr;
  676.     }
  677.  
  678.  
  679. // Process handling
  680.  
  681. /* This runs through the process list looking for the indicated thing,
  682. based on type and creator.
  683. */
  684. OSErr FindAProcess
  685.     (OSType                    typeToFind,        // eg 'APPL' or 'FNDR'
  686.     OSType                    creatorToFind,    // eg 'JAGO' or 'MACS'
  687.     ProcessSerialNumberPtr    processSN        // <- PSN of process
  688.     )
  689.     {
  690.     ProcessInfoRec tempInfo;    // to check type/creator
  691.     FSSpec procSpec;            // value not used
  692.     Str31 processName;            // value not used
  693.     OSErr theErr = noErr;
  694.     
  695.     // nul out the PSN so we're starting at the beginning of the list 
  696.     processSN->lowLongOfPSN = kNoProcess;
  697.     processSN->highLongOfPSN = kNoProcess;
  698.     // initialize the process information record
  699.     tempInfo.processInfoLength = sizeof(ProcessInfoRec);
  700.     tempInfo.processName = processName;
  701.     tempInfo.processAppSpec = &procSpec;
  702.     
  703.     // loop through all the processes until we
  704.     // 1) find the process we want, or
  705.     // 2) error out because of some reason (usually, no more processes)
  706.     // (NOTE this loop, stolen originally i think from THINK Ref, is wrong
  707.     // in many published versions, having "...|| theErr != noErr...".
  708.     do
  709.         {
  710.         theErr = GetNextProcess(processSN);
  711.         if (theErr == noErr)
  712.             GetProcessInformation(processSN, &tempInfo);
  713.         } while ( (tempInfo.processSignature != creatorToFind
  714.                 || tempInfo.processType != typeToFind)
  715.                 && theErr == noErr);
  716.     return theErr;
  717.     }
  718.  
  719.  
  720. // File handling
  721.  
  722. /* Retrieve indexed string from STR# resource.
  723. */
  724. static void GetErrorMessage
  725.     (StringPtr     messageP,                // Str255 for ParamText
  726.     ErrorIndex     theErrorMessageIndex    // into a STR# rsrc
  727.     )
  728.     {
  729.     GetIndString(messageP, kErrorStringID, (short)theErrorMessageIndex);
  730.     }
  731.  
  732. /* Retrieve indexed string from STR# resource.
  733. */
  734. static void GetGeneralMessage
  735.     (StringPtr         messageP,                // Str255 for ParamText
  736.     GeneralIndex     theGeneralMessageIndex    // into a STR# rsrc
  737.     )
  738.     {
  739.     GetIndString(messageP, kGeneralStringID, (short)theGeneralMessageIndex);
  740.     }
  741.  
  742. /* Locate file (app) based on type, creator. If found, fill in the spec. Borrowed
  743. with changes from Paul Celestin's InterLaunch (check the "Apprentice 4" CD from
  744. Celestin Co.).
  745. */
  746. OSErr LocateFileByTypeCreator
  747.     (OSType        fdType,                // eg 'APPL'
  748.     OSType        fdCreator,            // eg 'JAGO'
  749.     short        vRefNum,            // 0 for default drive
  750.     FSSpec        *spec                // <- file spec
  751.     )
  752.     {
  753.     CSParam            cs;        // for PBCatSearch
  754.     HFileInfo        spec1;    // start criteria for PBCatSearch
  755.     HFileInfo        spec2;    // stop criteria for PBCatSearch
  756.     Ptr                buffer;    // to speed things up, optional
  757.     OSErr            theErr;
  758.     
  759.     // Use buffer for speed, but proceed if memory not available.
  760.     buffer = NewPtr(16384L);
  761.     if (MemError() != noErr)
  762.         buffer = NewPtr(8192L);
  763.     if (MemError() != noErr)
  764.         buffer = NULL;
  765.  
  766.     cs.ioNamePtr = NULL;                // name of volume, we don't need it
  767.     cs.ioVRefNum = vRefNum;                // volume number
  768.     cs.ioMatchPtr = spec;                // spec for first match (if any)
  769.     cs.ioReqMatchCount = 1;                // we want at most one spec
  770.     cs.ioSearchBits = fsSBFlFndrInfo;     // We are searching for Finder info
  771.     cs.ioSearchInfo1 = (CInfoPBPtr)&spec1;
  772.     cs.ioSearchInfo2 = (CInfoPBPtr)&spec2;
  773.     cs.ioSearchTime = 0;                // no timeout on search
  774.     cs.ioCatPosition.initialize = 0;    // start at beginning of catalog
  775.     // Use the buffer if we have one.
  776.     cs.ioOptBuffer = buffer;
  777.     if (buffer != NULL)
  778.         cs.ioOptBufSize = GetPtrSize(buffer);
  779.     else
  780.         cs.ioOptBufSize = 0;
  781.     
  782.     // Set values and lower bounds in spec1
  783.     spec1.ioFlFndrInfo.fdType = fdType;
  784.     spec1.ioFlFndrInfo.fdCreator = fdCreator;
  785.     spec1.ioFlFndrInfo.fdFlags = 0;
  786.     *(long *)&spec1.ioFlFndrInfo.fdLocation = 0L;
  787.     spec1.ioFlFndrInfo.fdFldr = 0;
  788.     
  789.     // Set masks and upper bounds in spec2
  790.     spec2.ioFlFndrInfo.fdType = (ResType)0xffffffff;    // match type
  791.     spec2.ioFlFndrInfo.fdCreator = (ResType)0xffffffff;    // match creator
  792.     spec2.ioFlFndrInfo.fdFlags = 0x4000; // require file to be visible
  793.     *(long *)&spec2.ioFlFndrInfo.fdLocation = 0; // ignore icon position
  794.     spec2.ioFlFndrInfo.fdFldr = 0;                 // obsolete field, ignore
  795.  
  796.     // Whew, do the actual search...result if any goes in "spec"
  797.     theErr = PBCatSearch(&cs,FALSE);
  798.     // Clean up and return result
  799.     if (buffer != NULL)
  800.         DisposePtr(buffer);
  801.     return theErr;
  802.     }
  803.  
  804. /* Launch an application, without files, using preferred size.
  805. */
  806. OSErr LaunchIt
  807.     (FSSpec                *theAppP,        // ->Specs which application to launch
  808.     ProcessSerialNumber *serialNumP        // <-filled in if we succeed
  809.     )
  810.     {
  811.     LaunchParamBlockRec        launchParams;    // See Processes.h
  812.     OSErr                    theErr = noErr;
  813.  
  814.     launchParams.launchBlockID = extendedBlock;
  815.     launchParams.launchEPBLength = extendedBlockLen;
  816.     launchParams.launchFileFlags = 0;    // ignored due to launchNoFileFlags below
  817.     launchParams.launchControlFlags = launchContinue +    launchNoFileFlags;
  818.     launchParams.launchAppSpec = theAppP;
  819.     launchParams.launchAppParameters = NULL; // no high-level event
  820.     
  821.     // Launch app without docs, using preferred size.
  822.     theErr = LaunchApplication(&launchParams);
  823.     
  824.     // Set serial number of running process if we succeeded.
  825.     if (theErr == noErr)
  826.         *serialNumP = launchParams.launchProcessSN;
  827.     return theErr;
  828.     }
  829.  
  830.  
  831. /* Make new FSSpecElement, fill in and add to tail of *specElementPP list.
  832.     *specElementPP->secondInList->...currentLastInList->newElement->NULL.
  833. Error only if out of memory.
  834. */
  835. static OSErr AddSpecElement
  836.     (FSSpecPtr            theSpecP,        // ->a document file spec
  837.     FSSpecElementPtr    *specElementPP    // <->head of spec list or NULL first time
  838.     )
  839.     {
  840.     FSSpecElementPtr    lastElemP;        // last element in current list
  841.     FSSpecElementPtr    newElemP;        // created here
  842.     OSErr                theErr = noErr;
  843.     
  844.     // Make a new element for the linked list
  845.     newElemP = (FSSpecElementPtr)NewPtr( sizeof(FSSpecElement) );
  846.     theErr = MemError();
  847.     
  848.     // Add it to the list (set *specElementPP if it's the first one).
  849.     if (theErr == noErr)
  850.         {    
  851.         // Fill in the values for the new element, add to end of list.
  852.         newElemP->fss = *theSpecP;
  853.         newElemP->next = NULL;
  854.         // First one is special, goes in *specElementPP.
  855.         if (*specElementPP == NULL)
  856.             {
  857.             *specElementPP = newElemP;
  858.             }
  859.         else
  860.             {
  861.             // Walk list and add new one at end.
  862.             lastElemP = *specElementPP;
  863.             while (lastElemP->next != NULL)
  864.                 lastElemP = lastElemP->next;
  865.             lastElemP->next = newElemP;
  866.             }
  867.         }
  868.     return theErr;
  869.     }
  870.  
  871.