home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / macfe / applevnt / ulaunch.cp < prev    next >
Encoding:
Text File  |  1998-04-08  |  14.2 KB  |  488 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. // ulaunch.cp
  20. // Launching of external applications through AppleEvents
  21. // Created by atotic, June 14th, 1994
  22. // Based on Apple's LaunchWithDoc example snippet
  23.  
  24. #include <Folders.h>
  25. #include <AERegistry.h>
  26. #include <Errors.h>
  27.  
  28. #include "BufferStream.h"
  29.  
  30. #include "PascalString.h"
  31.  
  32. #include "macutil.h"
  33. #include "uprefd.h"
  34. #include "ufilemgr.h"
  35. #include "uerrmgr.h"
  36. #include "reserr.h"
  37. #include "ulaunch.h"
  38.  
  39. // ÑÑ PROTOTYPES
  40. OSErr FindAppOnVolume(OSType sig, short vRefNum, FSSpec& thefile);
  41.  
  42. // Sends an ODOC event to creator in fndrInfo,
  43. // with file in fileSpec
  44. OSErr SendODOCEvent(OSType appSig, 
  45.                 LFileBufferStream * inFile);
  46.                 
  47. // Launches the application with the given doc
  48. void LaunchWithDoc(FInfo& fndrInfo, 
  49.                     FSSpec& appSpec,
  50.                     LFileBufferStream * inFile,
  51.                     const FSSpec inFileSpec);
  52.  
  53.  
  54. // Displays a launching error alert.
  55. int LaunchError(ResIDT alertID, OSType creator, const Str63& fileName, OSErr err);
  56.  
  57. // Creates Finder's OpenSelection event
  58. OSErr BuildOpenSelectionEvent(FSSpec & fileSpec, AppleEvent& theEvent);
  59.  
  60. // Sends OpenSelection to Finder
  61. OSErr SendOpenSelectionToFinder(FSSpec & fileSpec);
  62.  
  63. // ÑÑ Implementation
  64.  
  65.  
  66.  
  67. // Builds an ODOC event
  68. OSErr BuildODOCEvent(OSType applSig, 
  69.                     FSSpec fileSpec, 
  70.                     AppleEvent& theEvent)    {
  71. // Builds all the arguments for the event
  72.     AEDesc myAddress;
  73.     AEDesc docDesc;
  74.     AEDescList theList;
  75.     AliasHandle withThis;
  76.     OSErr err;
  77.     
  78. // Anatomy of the event:
  79. // Event class: kCoreEventClass
  80. // Event ID: kAEOpenDocuments
  81. // Event has target description (in the form of typeApplSignature)
  82. // keyDirectObject is a list of aliases
  83.  
  84.       err = AECreateDesc(typeApplSignature,
  85.                           (Ptr)&applSig, sizeof(applSig),
  86.                            &myAddress);
  87.     if (err) return err;
  88.     
  89.     err = AECreateAppleEvent(kCoreEventClass, kAEOpenDocuments, 
  90.                             &myAddress, 
  91.                             kAutoGenerateReturnID, kAnyTransactionID, 
  92.                             &theEvent);
  93.     if (err) return err;
  94.     // create a list for the alaises.  In this case, I only have one, but 
  95.     // you still need a list
  96.  
  97.     err = AECreateList(NULL, 0, FALSE, &theList);
  98.     if (err) return err;
  99.  
  100.     /* create an alias out of the file spec */
  101.     /* I'm not real sure why I did this, since there is a system coercion handler for */
  102.     /* alias to FSSpec, but I'm paranoid */
  103.  
  104.     err = NewAlias(NULL, &fileSpec, &withThis);
  105.     if (err) return err;
  106.  
  107.     HLock((Handle)withThis);
  108.  
  109.     /* now create an alias descriptor */
  110.     err = AECreateDesc(typeAlias, (Ptr) * withThis, GetHandleSize((Handle)withThis), &docDesc);
  111.     if (err) return err;
  112.  
  113.     HUnlock((Handle)withThis);
  114.  
  115.     /* put it in the list */
  116.     err = AEPutDesc(&theList, 0, &docDesc);
  117.     if (err) return err;
  118.     err = AEPutParamDesc(&theEvent, keyDirectObject, &theList);
  119.     err = AEDisposeDesc(&myAddress);
  120.     err = AEDisposeDesc(&docDesc);
  121.     err = AEDisposeDesc(&theList);
  122.     return err;
  123. }
  124.  
  125. // Sends an ODOC event to appliation
  126. OSErr SendODOCEvent(OSType appSig, 
  127.                 LFileBufferStream * inFile)
  128. {
  129.     OSErr err;
  130.     Try_ {
  131.         AppleEvent    openEvent;
  132.         FSSpec inFileSpec;
  133.         inFile->GetSpecifier(inFileSpec);
  134.         err = BuildODOCEvent(appSig, 
  135.                             inFileSpec, 
  136.                             openEvent);
  137.         ThrowIfOSErr_(err);
  138.         AppleEvent result;
  139.         err = AESend(&openEvent, &result, 
  140.                     kAENoReply  + kAECanSwitchLayer,
  141.                     kAENormalPriority, kAEDefaultTimeout,
  142.                     NULL,NULL);
  143.         AEDisposeDesc(&openEvent);
  144.         // err could be memFullErr, app is out of memory
  145.         ThrowIfOSErr_(err);
  146.     }
  147.     Catch_(inErr) {
  148.         return inErr;
  149.     } EndCatch_
  150.     return err;
  151. }
  152.  
  153. #define kDelete 2
  154. #define kSave    1
  155. #define kTryAgain 3
  156. // Displays launch error dialogs with appropriate arguments.
  157. // Alerts used are:
  158. // ALRT_ODOCFailed
  159. // ALRT_AppNotFound
  160. // ALRT_AppMemFull
  161. // ALRT_MiscLaunchError
  162. // Returns: kDelete, kSave, or kTryAgain
  163. int LaunchError(ResIDT alertID, OSType creator, const Str63& fileName, OSErr err)
  164. {
  165.         CMimeMapper * map = CPrefs::sMimeTypes.FindCreator(creator);
  166.         ErrorManager::PrepareToInteract();
  167.         ParamText(map->GetAppName(), CStr255(fileName), ErrorManager::OSNumToStr(err), CStr255(""));
  168.         UDesktop::Deactivate();
  169.         int retVal = ::CautionAlert(alertID, NULL);
  170.         UDesktop::Activate();
  171.         return retVal;
  172. }
  173.  
  174. // Launches an application with a given doc
  175. OSErr StartDocInApp(FSSpec theDocument,  FSSpec theApplication)
  176. {
  177.     FInfo fndrInfo;
  178.     OSErr    err;
  179.     
  180.     HGetFInfo(    theApplication.vRefNum,
  181.                 theApplication.parID,
  182.                 theApplication.name,
  183.                 &fndrInfo);
  184.                 
  185.     FSSpec applSpecTemp;
  186.     ProcessSerialNumber processSN;
  187.     err = FindProcessBySignature(fndrInfo.fdCreator, 'APPL',  processSN, &applSpecTemp);
  188.     if (err == noErr)    // App is running. Send 'odoc'
  189.     {
  190.         Try_ {
  191.             AppleEvent theEvent;
  192.             err = BuildODOCEvent(fndrInfo.fdCreator, theDocument, theEvent);
  193.             ThrowIfOSErr_(err);
  194.             AppleEvent result;
  195.             err = AESend(&theEvent, &result, 
  196.                         kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer,
  197.                         kAENormalPriority, kAEDefaultTimeout,
  198.                         NULL,NULL);
  199.             AEDisposeDesc(&theEvent);
  200.             // err could be memFullErr, app is out of memory
  201.             ThrowIfOSErr_(err);
  202.             if (IsFrontApplication())
  203.                 SetFrontProcess(&processSN);
  204.         }
  205.         Catch_(inErr) {
  206.             return inErr;
  207.         } EndCatch_
  208.         
  209.         return noErr;
  210.     }
  211.  
  212.     Try_    {
  213.         LaunchParamBlockRec launchThis;
  214.         AEDesc launchDesc;
  215.         AppleEvent theEvent;
  216.     
  217.         ThrowIfOSErr_(BuildODOCEvent(fndrInfo.fdCreator, theDocument, theEvent));
  218.         ThrowIfOSErr_(AECoerceDesc(&theEvent, typeAppParameters, &launchDesc));
  219.         
  220.         launchThis.launchAppSpec = (FSSpecPtr)&theApplication;
  221.         launchThis.launchAppParameters = (AppParametersPtr)*(launchDesc.dataHandle);
  222.         launchThis.launchBlockID = extendedBlock;
  223.         launchThis.launchEPBLength = extendedBlockLen;
  224.         launchThis.launchFileFlags = NULL;
  225.         launchThis.launchControlFlags = launchContinue + launchNoFileFlags + launchUseMinimum;
  226.         if (!IsFrontApplication())
  227.             launchThis.launchControlFlags += launchDontSwitch;
  228.         err = LaunchApplication(&launchThis);
  229.         ThrowIfOSErr_(err);
  230.     }
  231.     Catch_(inErr)
  232.     {
  233.     } EndCatch_
  234.     return err;
  235. }
  236.  
  237. // Launches the application with the given doc
  238. void LaunchWithDoc(FInfo& fndrInfo, 
  239.                 FSSpec& appSpec,
  240.                 LFileBufferStream * inFile,
  241.                 const FSSpec inFileSpec)
  242. {
  243.     OSErr err = CFileMgr::FindApplication(fndrInfo.fdCreator, appSpec);
  244.     if (err)    // Application not found error
  245.     {
  246.         int whatToDo = ::LaunchError(ALRT_AppNotFound, fndrInfo.fdCreator, 
  247.                                     inFileSpec.name, err);
  248.         if (whatToDo == kSave)
  249.             CFileMgr::sFileManager.CancelRegister(inFile);        // Save the file
  250.         else    // kDelete
  251.             CFileMgr::sFileManager.CancelAndDelete(inFile);        // Delete the file
  252.         return;
  253.     }
  254.     
  255.     Try_    {
  256.         LaunchParamBlockRec launchThis;
  257.         AEDesc launchDesc;
  258.         AppleEvent theEvent;
  259.     
  260.         ThrowIfOSErr_(BuildODOCEvent(fndrInfo.fdCreator, inFileSpec, theEvent));
  261.         ThrowIfOSErr_(AECoerceDesc(&theEvent, typeAppParameters, &launchDesc));
  262.         
  263.         launchThis.launchAppSpec = (FSSpecPtr)&appSpec;
  264.         launchThis.launchAppParameters = (AppParametersPtr)*(launchDesc.dataHandle);
  265.         /* launch the thing */
  266.         launchThis.launchBlockID = extendedBlock;
  267.         launchThis.launchEPBLength = extendedBlockLen;
  268.         launchThis.launchFileFlags = NULL;
  269.         launchThis.launchControlFlags = launchContinue + launchNoFileFlags + launchUseMinimum;
  270.         if (!IsFrontApplication())
  271.             launchThis.launchControlFlags += launchDontSwitch;
  272.         do        // Launch until we succeed, or user gives up.
  273.         {
  274.             err = LaunchApplication(&launchThis);
  275.             if ((err == memFullErr) || (err == memFragErr))    
  276.             // Launch failed because of low memory
  277.             {
  278.                 int whatToDo = ::LaunchError(ALRT_AppMemFull, fndrInfo.fdCreator, 
  279.                                             inFileSpec.name, err);
  280.                 switch (whatToDo)    {
  281.                 case kSave:
  282.                     CFileMgr::sFileManager.CancelRegister(inFile);        // Save the file
  283.                     err = noErr;
  284.                     break;
  285.                 case kDelete:
  286.                     CFileMgr::sFileManager.CancelAndDelete(inFile);        // Save the file
  287.                     err = noErr;
  288.                     break;
  289.                 case kTryAgain:                                // Loop again
  290.                     break;
  291.                 }
  292.             }
  293.             else    // Unknown launch error
  294.                 ThrowIfOSErr_(err);
  295.         } while (err != noErr);
  296.     }
  297.     Catch_(inErr)
  298.     {
  299.         int whatToDo = ::LaunchError(ALRT_AppMiscError, fndrInfo.fdCreator, 
  300.                                     inFileSpec.name, inErr);
  301.         if (whatToDo == kSave)
  302.             CFileMgr::sFileManager.CancelRegister(inFile);        // Save the file
  303.         else    // kDelete
  304.             CFileMgr::sFileManager.CancelAndDelete(inFile);        // Delete the file
  305.     } EndCatch_
  306. }
  307.  
  308.  
  309. OSErr
  310. CreateFinderAppleEvent(        AEEventID        eventID,
  311.                             SInt16             returnID, 
  312.                             SInt32             transactionID,
  313.                             AppleEvent    &    theEvent)
  314. {
  315.     OSErr                err;
  316.     FSSpec                finder;
  317.     ProcessSerialNumber    psn;
  318.     AEDesc                finderAddress;
  319.     Boolean                validAddress = false;
  320.     
  321.     try
  322.     {
  323.         err = FindProcessBySignature('MACS', 'FNDR', psn, &finder);
  324.         ThrowIfOSErr_(err);
  325.          
  326.          err = ::AECreateDesc(typeProcessSerialNumber, (Ptr)&psn, sizeof(psn), &finderAddress);
  327.         ThrowIfOSErr_(err);
  328.         validAddress = true;
  329.         
  330.         err = ::AECreateAppleEvent(    kAEFinderEvents, 
  331.                                     eventID, 
  332.                                     (const AEAddressDesc *) &finderAddress, 
  333.                                     returnID, 
  334.                                     transactionID, 
  335.                                     &theEvent    );
  336.  
  337.     }
  338.     catch(long tErr)
  339.     {
  340.         if (validAddress) 
  341.             ::AEDisposeDesc(&finderAddress);
  342.     }
  343.  
  344.     return err;
  345. }
  346.  
  347. // Builds an OpenSelection event for Finder
  348. OSErr BuildOpenSelectionEvent(FSSpec & fileSpec, AppleEvent& theEvent)    {
  349.     FSSpec dirSpec, procSpec;
  350.     FSSpecPtr theFileToOpen = nil;
  351.     CStr63 processName;
  352.     AEDesc aeDirDesc, listElem;
  353.     AEDesc fileList;
  354.     ConstStr255Param * dummy  = NULL;
  355. // Create the event
  356.     OSErr err;
  357.     Try_ {
  358.         ProcessInfoRec pir;
  359.         pir.processInfoLength = sizeof(ProcessInfoRec);
  360.         pir.processName = (StringPtr)&processName;
  361.         pir.processAppSpec = &procSpec;
  362.     // Find a Finder, and create its description as an address for an apple event
  363.     
  364.         err = CreateFinderAppleEvent(kAEOpenSelection, kAutoGenerateReturnID, kAnyTransactionID, theEvent);
  365.         ThrowIfOSErr_(err);
  366.         
  367.     // Create a description of the file, and the enclosing folder
  368.     // keyDirectObject is directory description
  369.     //
  370.         err = CFileMgr::FolderSpecFromFolderID(fileSpec.vRefNum, fileSpec.parID, dirSpec);
  371.         ThrowIfOSErr_(err);
  372.         
  373.         err = AECreateList(nil, 0, false, &fileList);
  374.         ThrowIfOSErr_(err);
  375.  
  376.          AliasHandle DirAlias, FileAlias;
  377.         NewAlias(nil, &dirSpec, &DirAlias);
  378.         HLock((Handle)DirAlias);
  379.         err = AECreateDesc(typeAlias, (Ptr)*DirAlias, GetHandleSize((Handle)DirAlias), &aeDirDesc);
  380.         ThrowIfOSErr_(err);
  381.         HUnlock((Handle)DirAlias);
  382.         DisposeHandle((Handle)DirAlias);
  383.         
  384.         err = AEPutParamDesc(&theEvent, keyDirectObject, &aeDirDesc);
  385.         ThrowIfOSErr_(err);
  386.         AEDisposeDesc(&aeDirDesc);
  387.  
  388.         NewAlias(nil, &fileSpec, &FileAlias);
  389.         HLock((Handle)FileAlias);
  390.         err = AECreateDesc(typeAlias, (Ptr)*FileAlias, GetHandleSize((Handle)FileAlias), &listElem);
  391.         ThrowIfOSErr_(err);
  392.         HUnlock((Handle)FileAlias);
  393.         err = AEPutDesc(&fileList, 0, &listElem);
  394.         ThrowIfOSErr_(err);
  395.         DisposeHandle((Handle)FileAlias);
  396.  
  397.         err = AEPutParamDesc( &theEvent, keySelection, &fileList);
  398.         ThrowIfOSErr_(err);        
  399.     }
  400.     Catch_(inErr)
  401.     {
  402.         return inErr;
  403.     } EndCatch_
  404.     return noErr;
  405. }
  406.  
  407. // Sends 'open selection event to Finder
  408. OSErr SendOpenSelectionToFinder(FSSpec & fileSpec)
  409. {
  410.     AppleEvent event;
  411.     AppleEvent result;
  412.     OSErr err = BuildOpenSelectionEvent(fileSpec, event);
  413.     if (err)
  414.         return err;
  415.     err = AESend(&event, &result, 
  416.                     kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer,
  417.                     kAENormalPriority, kAEDefaultTimeout,
  418.                     NULL,NULL);
  419.     AEDisposeDesc(&event);
  420.     return err;
  421. }
  422.  
  423. // A somewhat tricky way of opening a foreign document
  424. // Algorithm: 
  425. //    - if a process is not running, launch it with the document
  426. //  - if a process is running and AE aware, send it an AppleEvent
  427. //  - if a process is running and is not AE aware, send openSelection to the Finder.
  428. void LaunchFile(LFileBufferStream * inFile)
  429. {
  430.     FSSpec applSpec;
  431.     FInfo fndrInfo;
  432.     
  433. // Get file info
  434.     FSSpec inFileSpec;
  435.     inFile->GetSpecifier(inFileSpec);
  436.     
  437.     HGetFInfo(inFileSpec.vRefNum,
  438.                 inFileSpec.parID,
  439.                 inFileSpec.name,
  440.                 &fndrInfo);
  441.  
  442. // Find if the application is already running
  443.     ProcessSerialNumber processSN;
  444.     ProcessInfoRec infoRecToFill;
  445.     Str63 processName;
  446.     infoRecToFill.processInfoLength = sizeof(ProcessInfoRec);
  447.     infoRecToFill.processName = (StringPtr)&processName;
  448.     infoRecToFill.processAppSpec = &applSpec;
  449.     OSErr err = FindProcessBySignature(fndrInfo.fdCreator, 'APPL',  processSN, &applSpec);
  450.     
  451.     if (err == noErr)    // App is running. Send 'odoc'
  452.     {
  453.         err = SendODOCEvent(fndrInfo.fdCreator, inFile);
  454.         if (err == noErr)
  455.         {
  456.             if (IsFrontApplication())
  457.                 SetFrontProcess(&processSN);
  458.         }
  459.         else
  460.         {
  461.             // Application did not accept apple event for some reason (err = connectionInvalid)
  462.             // Send 'odoc' to Finder. Finder can figure out how to fake menu events when
  463.             // it tries to open the file
  464.             err = SendOpenSelectionToFinder(inFileSpec);
  465.             if (err == noErr)
  466.             {        // If finder launched the application successfully, find it and bring it to front
  467.                 err = FindProcessBySignature(fndrInfo.fdCreator, 'APPL',  processSN, &applSpec);
  468.                 if (err == noErr && IsFrontApplication())
  469.                     SetFrontProcess(&processSN);
  470.             }
  471.             else    // Finder launch also failed. Notify the user
  472.             {
  473.                 //Notify the user, try to handle the error
  474.                 int whatToDo = LaunchError(ALRT_ODOCFailed, 
  475.                                             fndrInfo.fdCreator,
  476.                                              inFileSpec.name, err);
  477.                 if (whatToDo == 1)
  478.                     CFileMgr::sFileManager.CancelRegister(inFile);        // Save the file
  479.                 else
  480.                     CFileMgr::sFileManager.CancelAndDelete(inFile);        // Delete the file
  481.             }
  482.         }
  483.     }
  484.     else                // App is not running. Launch it with this file
  485.         LaunchWithDoc(fndrInfo, applSpec, inFile, inFileSpec);
  486. }
  487.  
  488.