home *** CD-ROM | disk | FTP | other *** search
- /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * The contents of this file are subject to the Netscape Public License
- * Version 1.0 (the "NPL"); you may not use this file except in
- * compliance with the NPL. You may obtain a copy of the NPL at
- * http://www.mozilla.org/NPL/
- *
- * Software distributed under the NPL is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
- * for the specific language governing rights and limitations under the
- * NPL.
- *
- * The Initial Developer of this code under the NPL is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1998 Netscape Communications Corporation. All Rights
- * Reserved.
- */
-
- // ulaunch.cp
- // Launching of external applications through AppleEvents
- // Created by atotic, June 14th, 1994
- // Based on Apple's LaunchWithDoc example snippet
-
- #include <Folders.h>
- #include <AERegistry.h>
- #include <Errors.h>
-
- #include "BufferStream.h"
-
- #include "PascalString.h"
-
- #include "macutil.h"
- #include "uprefd.h"
- #include "ufilemgr.h"
- #include "uerrmgr.h"
- #include "reserr.h"
- #include "ulaunch.h"
-
- // ÑÑ PROTOTYPES
- OSErr FindAppOnVolume(OSType sig, short vRefNum, FSSpec& thefile);
-
- // Sends an ODOC event to creator in fndrInfo,
- // with file in fileSpec
- OSErr SendODOCEvent(OSType appSig,
- LFileBufferStream * inFile);
-
- // Launches the application with the given doc
- void LaunchWithDoc(FInfo& fndrInfo,
- FSSpec& appSpec,
- LFileBufferStream * inFile,
- const FSSpec inFileSpec);
-
-
- // Displays a launching error alert.
- int LaunchError(ResIDT alertID, OSType creator, const Str63& fileName, OSErr err);
-
- // Creates Finder's OpenSelection event
- OSErr BuildOpenSelectionEvent(FSSpec & fileSpec, AppleEvent& theEvent);
-
- // Sends OpenSelection to Finder
- OSErr SendOpenSelectionToFinder(FSSpec & fileSpec);
-
- // ÑÑ Implementation
-
-
-
- // Builds an ODOC event
- OSErr BuildODOCEvent(OSType applSig,
- FSSpec fileSpec,
- AppleEvent& theEvent) {
- // Builds all the arguments for the event
- AEDesc myAddress;
- AEDesc docDesc;
- AEDescList theList;
- AliasHandle withThis;
- OSErr err;
-
- // Anatomy of the event:
- // Event class: kCoreEventClass
- // Event ID: kAEOpenDocuments
- // Event has target description (in the form of typeApplSignature)
- // keyDirectObject is a list of aliases
-
- err = AECreateDesc(typeApplSignature,
- (Ptr)&applSig, sizeof(applSig),
- &myAddress);
- if (err) return err;
-
- err = AECreateAppleEvent(kCoreEventClass, kAEOpenDocuments,
- &myAddress,
- kAutoGenerateReturnID, kAnyTransactionID,
- &theEvent);
- if (err) return err;
- // create a list for the alaises. In this case, I only have one, but
- // you still need a list
-
- err = AECreateList(NULL, 0, FALSE, &theList);
- if (err) return err;
-
- /* create an alias out of the file spec */
- /* I'm not real sure why I did this, since there is a system coercion handler for */
- /* alias to FSSpec, but I'm paranoid */
-
- err = NewAlias(NULL, &fileSpec, &withThis);
- if (err) return err;
-
- HLock((Handle)withThis);
-
- /* now create an alias descriptor */
- err = AECreateDesc(typeAlias, (Ptr) * withThis, GetHandleSize((Handle)withThis), &docDesc);
- if (err) return err;
-
- HUnlock((Handle)withThis);
-
- /* put it in the list */
- err = AEPutDesc(&theList, 0, &docDesc);
- if (err) return err;
- err = AEPutParamDesc(&theEvent, keyDirectObject, &theList);
- err = AEDisposeDesc(&myAddress);
- err = AEDisposeDesc(&docDesc);
- err = AEDisposeDesc(&theList);
- return err;
- }
-
- // Sends an ODOC event to appliation
- OSErr SendODOCEvent(OSType appSig,
- LFileBufferStream * inFile)
- {
- OSErr err;
- Try_ {
- AppleEvent openEvent;
- FSSpec inFileSpec;
- inFile->GetSpecifier(inFileSpec);
- err = BuildODOCEvent(appSig,
- inFileSpec,
- openEvent);
- ThrowIfOSErr_(err);
- AppleEvent result;
- err = AESend(&openEvent, &result,
- kAENoReply + kAECanSwitchLayer,
- kAENormalPriority, kAEDefaultTimeout,
- NULL,NULL);
- AEDisposeDesc(&openEvent);
- // err could be memFullErr, app is out of memory
- ThrowIfOSErr_(err);
- }
- Catch_(inErr) {
- return inErr;
- } EndCatch_
- return err;
- }
-
- #define kDelete 2
- #define kSave 1
- #define kTryAgain 3
- // Displays launch error dialogs with appropriate arguments.
- // Alerts used are:
- // ALRT_ODOCFailed
- // ALRT_AppNotFound
- // ALRT_AppMemFull
- // ALRT_MiscLaunchError
- // Returns: kDelete, kSave, or kTryAgain
- int LaunchError(ResIDT alertID, OSType creator, const Str63& fileName, OSErr err)
- {
- CMimeMapper * map = CPrefs::sMimeTypes.FindCreator(creator);
- ErrorManager::PrepareToInteract();
- ParamText(map->GetAppName(), CStr255(fileName), ErrorManager::OSNumToStr(err), CStr255(""));
- UDesktop::Deactivate();
- int retVal = ::CautionAlert(alertID, NULL);
- UDesktop::Activate();
- return retVal;
- }
-
- // Launches an application with a given doc
- OSErr StartDocInApp(FSSpec theDocument, FSSpec theApplication)
- {
- FInfo fndrInfo;
- OSErr err;
-
- HGetFInfo( theApplication.vRefNum,
- theApplication.parID,
- theApplication.name,
- &fndrInfo);
-
- FSSpec applSpecTemp;
- ProcessSerialNumber processSN;
- err = FindProcessBySignature(fndrInfo.fdCreator, 'APPL', processSN, &applSpecTemp);
- if (err == noErr) // App is running. Send 'odoc'
- {
- Try_ {
- AppleEvent theEvent;
- err = BuildODOCEvent(fndrInfo.fdCreator, theDocument, theEvent);
- ThrowIfOSErr_(err);
- AppleEvent result;
- err = AESend(&theEvent, &result,
- kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer,
- kAENormalPriority, kAEDefaultTimeout,
- NULL,NULL);
- AEDisposeDesc(&theEvent);
- // err could be memFullErr, app is out of memory
- ThrowIfOSErr_(err);
- if (IsFrontApplication())
- SetFrontProcess(&processSN);
- }
- Catch_(inErr) {
- return inErr;
- } EndCatch_
-
- return noErr;
- }
-
- Try_ {
- LaunchParamBlockRec launchThis;
- AEDesc launchDesc;
- AppleEvent theEvent;
-
- ThrowIfOSErr_(BuildODOCEvent(fndrInfo.fdCreator, theDocument, theEvent));
- ThrowIfOSErr_(AECoerceDesc(&theEvent, typeAppParameters, &launchDesc));
-
- launchThis.launchAppSpec = (FSSpecPtr)&theApplication;
- launchThis.launchAppParameters = (AppParametersPtr)*(launchDesc.dataHandle);
- launchThis.launchBlockID = extendedBlock;
- launchThis.launchEPBLength = extendedBlockLen;
- launchThis.launchFileFlags = NULL;
- launchThis.launchControlFlags = launchContinue + launchNoFileFlags + launchUseMinimum;
- if (!IsFrontApplication())
- launchThis.launchControlFlags += launchDontSwitch;
- err = LaunchApplication(&launchThis);
- ThrowIfOSErr_(err);
- }
- Catch_(inErr)
- {
- } EndCatch_
- return err;
- }
-
- // Launches the application with the given doc
- void LaunchWithDoc(FInfo& fndrInfo,
- FSSpec& appSpec,
- LFileBufferStream * inFile,
- const FSSpec inFileSpec)
- {
- OSErr err = CFileMgr::FindApplication(fndrInfo.fdCreator, appSpec);
- if (err) // Application not found error
- {
- int whatToDo = ::LaunchError(ALRT_AppNotFound, fndrInfo.fdCreator,
- inFileSpec.name, err);
- if (whatToDo == kSave)
- CFileMgr::sFileManager.CancelRegister(inFile); // Save the file
- else // kDelete
- CFileMgr::sFileManager.CancelAndDelete(inFile); // Delete the file
- return;
- }
-
- Try_ {
- LaunchParamBlockRec launchThis;
- AEDesc launchDesc;
- AppleEvent theEvent;
-
- ThrowIfOSErr_(BuildODOCEvent(fndrInfo.fdCreator, inFileSpec, theEvent));
- ThrowIfOSErr_(AECoerceDesc(&theEvent, typeAppParameters, &launchDesc));
-
- launchThis.launchAppSpec = (FSSpecPtr)&appSpec;
- launchThis.launchAppParameters = (AppParametersPtr)*(launchDesc.dataHandle);
- /* launch the thing */
- launchThis.launchBlockID = extendedBlock;
- launchThis.launchEPBLength = extendedBlockLen;
- launchThis.launchFileFlags = NULL;
- launchThis.launchControlFlags = launchContinue + launchNoFileFlags + launchUseMinimum;
- if (!IsFrontApplication())
- launchThis.launchControlFlags += launchDontSwitch;
- do // Launch until we succeed, or user gives up.
- {
- err = LaunchApplication(&launchThis);
- if ((err == memFullErr) || (err == memFragErr))
- // Launch failed because of low memory
- {
- int whatToDo = ::LaunchError(ALRT_AppMemFull, fndrInfo.fdCreator,
- inFileSpec.name, err);
- switch (whatToDo) {
- case kSave:
- CFileMgr::sFileManager.CancelRegister(inFile); // Save the file
- err = noErr;
- break;
- case kDelete:
- CFileMgr::sFileManager.CancelAndDelete(inFile); // Save the file
- err = noErr;
- break;
- case kTryAgain: // Loop again
- break;
- }
- }
- else // Unknown launch error
- ThrowIfOSErr_(err);
- } while (err != noErr);
- }
- Catch_(inErr)
- {
- int whatToDo = ::LaunchError(ALRT_AppMiscError, fndrInfo.fdCreator,
- inFileSpec.name, inErr);
- if (whatToDo == kSave)
- CFileMgr::sFileManager.CancelRegister(inFile); // Save the file
- else // kDelete
- CFileMgr::sFileManager.CancelAndDelete(inFile); // Delete the file
- } EndCatch_
- }
-
-
- OSErr
- CreateFinderAppleEvent( AEEventID eventID,
- SInt16 returnID,
- SInt32 transactionID,
- AppleEvent & theEvent)
- {
- OSErr err;
- FSSpec finder;
- ProcessSerialNumber psn;
- AEDesc finderAddress;
- Boolean validAddress = false;
-
- try
- {
- err = FindProcessBySignature('MACS', 'FNDR', psn, &finder);
- ThrowIfOSErr_(err);
-
- err = ::AECreateDesc(typeProcessSerialNumber, (Ptr)&psn, sizeof(psn), &finderAddress);
- ThrowIfOSErr_(err);
- validAddress = true;
-
- err = ::AECreateAppleEvent( kAEFinderEvents,
- eventID,
- (const AEAddressDesc *) &finderAddress,
- returnID,
- transactionID,
- &theEvent );
-
- }
- catch(long tErr)
- {
- if (validAddress)
- ::AEDisposeDesc(&finderAddress);
- }
-
- return err;
- }
-
- // Builds an OpenSelection event for Finder
- OSErr BuildOpenSelectionEvent(FSSpec & fileSpec, AppleEvent& theEvent) {
- FSSpec dirSpec, procSpec;
- FSSpecPtr theFileToOpen = nil;
- CStr63 processName;
- AEDesc aeDirDesc, listElem;
- AEDesc fileList;
- ConstStr255Param * dummy = NULL;
- // Create the event
- OSErr err;
- Try_ {
- ProcessInfoRec pir;
- pir.processInfoLength = sizeof(ProcessInfoRec);
- pir.processName = (StringPtr)&processName;
- pir.processAppSpec = &procSpec;
- // Find a Finder, and create its description as an address for an apple event
-
- err = CreateFinderAppleEvent(kAEOpenSelection, kAutoGenerateReturnID, kAnyTransactionID, theEvent);
- ThrowIfOSErr_(err);
-
- // Create a description of the file, and the enclosing folder
- // keyDirectObject is directory description
- //
- err = CFileMgr::FolderSpecFromFolderID(fileSpec.vRefNum, fileSpec.parID, dirSpec);
- ThrowIfOSErr_(err);
-
- err = AECreateList(nil, 0, false, &fileList);
- ThrowIfOSErr_(err);
-
- AliasHandle DirAlias, FileAlias;
- NewAlias(nil, &dirSpec, &DirAlias);
- HLock((Handle)DirAlias);
- err = AECreateDesc(typeAlias, (Ptr)*DirAlias, GetHandleSize((Handle)DirAlias), &aeDirDesc);
- ThrowIfOSErr_(err);
- HUnlock((Handle)DirAlias);
- DisposeHandle((Handle)DirAlias);
-
- err = AEPutParamDesc(&theEvent, keyDirectObject, &aeDirDesc);
- ThrowIfOSErr_(err);
- AEDisposeDesc(&aeDirDesc);
-
- NewAlias(nil, &fileSpec, &FileAlias);
- HLock((Handle)FileAlias);
- err = AECreateDesc(typeAlias, (Ptr)*FileAlias, GetHandleSize((Handle)FileAlias), &listElem);
- ThrowIfOSErr_(err);
- HUnlock((Handle)FileAlias);
- err = AEPutDesc(&fileList, 0, &listElem);
- ThrowIfOSErr_(err);
- DisposeHandle((Handle)FileAlias);
-
- err = AEPutParamDesc( &theEvent, keySelection, &fileList);
- ThrowIfOSErr_(err);
- }
- Catch_(inErr)
- {
- return inErr;
- } EndCatch_
- return noErr;
- }
-
- // Sends 'open selection event to Finder
- OSErr SendOpenSelectionToFinder(FSSpec & fileSpec)
- {
- AppleEvent event;
- AppleEvent result;
- OSErr err = BuildOpenSelectionEvent(fileSpec, event);
- if (err)
- return err;
- err = AESend(&event, &result,
- kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer,
- kAENormalPriority, kAEDefaultTimeout,
- NULL,NULL);
- AEDisposeDesc(&event);
- return err;
- }
-
- // A somewhat tricky way of opening a foreign document
- // Algorithm:
- // - if a process is not running, launch it with the document
- // - if a process is running and AE aware, send it an AppleEvent
- // - if a process is running and is not AE aware, send openSelection to the Finder.
- void LaunchFile(LFileBufferStream * inFile)
- {
- FSSpec applSpec;
- FInfo fndrInfo;
-
- // Get file info
- FSSpec inFileSpec;
- inFile->GetSpecifier(inFileSpec);
-
- HGetFInfo(inFileSpec.vRefNum,
- inFileSpec.parID,
- inFileSpec.name,
- &fndrInfo);
-
- // Find if the application is already running
- ProcessSerialNumber processSN;
- ProcessInfoRec infoRecToFill;
- Str63 processName;
- infoRecToFill.processInfoLength = sizeof(ProcessInfoRec);
- infoRecToFill.processName = (StringPtr)&processName;
- infoRecToFill.processAppSpec = &applSpec;
- OSErr err = FindProcessBySignature(fndrInfo.fdCreator, 'APPL', processSN, &applSpec);
-
- if (err == noErr) // App is running. Send 'odoc'
- {
- err = SendODOCEvent(fndrInfo.fdCreator, inFile);
- if (err == noErr)
- {
- if (IsFrontApplication())
- SetFrontProcess(&processSN);
- }
- else
- {
- // Application did not accept apple event for some reason (err = connectionInvalid)
- // Send 'odoc' to Finder. Finder can figure out how to fake menu events when
- // it tries to open the file
- err = SendOpenSelectionToFinder(inFileSpec);
- if (err == noErr)
- { // If finder launched the application successfully, find it and bring it to front
- err = FindProcessBySignature(fndrInfo.fdCreator, 'APPL', processSN, &applSpec);
- if (err == noErr && IsFrontApplication())
- SetFrontProcess(&processSN);
- }
- else // Finder launch also failed. Notify the user
- {
- //Notify the user, try to handle the error
- int whatToDo = LaunchError(ALRT_ODOCFailed,
- fndrInfo.fdCreator,
- inFileSpec.name, err);
- if (whatToDo == 1)
- CFileMgr::sFileManager.CancelRegister(inFile); // Save the file
- else
- CFileMgr::sFileManager.CancelAndDelete(inFile); // Delete the file
- }
- }
- }
- else // App is not running. Launch it with this file
- LaunchWithDoc(fndrInfo, applSpec, inFile, inFileSpec);
- }
-
-