/* File: SegmentLoaderPatches.c Contains: Routines which patch the segment loader traps. Written by: Erich Ringewald and Phil Goldman Copyright: © 1986-1992 by Apple Computer, Inc., all rights reserved. This file is used in these builds: System Change History (most recent first): <18> 5/21/92 gbm #1030303,: Start using the new (and improved!) 'SIZE'(1) for launching, if itÕs present. <17> 1/14/92 YK Take out <15>,<16> since we found a better way. <16> 1/10/92 YK Oops, I didn't close the comment. <15> 1/10/92 YK Check if the app is the Service Window Manager app (for TSM) in GetSizeInfo, then set the flag. (this is a tentative solution) <14> 7/26/91 stb use HOpenResFile instead of old glue <13> 4/18/91 DFH TED, WS#DFH-910418b : Fixed LaunchApplication to restore the zone in the error patch where the file could not be opened. <12> 4/1/91 DFH (with John Iarocci) Merged in latest AUX support code. NOTE: No AUX support code is referenced unless the build defines the HAS_AUX_PROCESSMGR condition. <11> 3/25/91 DFH JSM,#DFH-910325a: Fix SetAppParameters to deal with the fact that the fabricated AppleEvent is in an unlocked handle. <10> 2/28/91 DFH VL,#83781: Removed 32-bit clean check from LaunchApplication. It is deemed no longer relevant, since Finder always overrode it. <9> 2/21/91 DFH dba,#82504, #82681, #83168, #83182, #83207: Available memory calc in StandardLaunch no longer needs special param for ProcessMgrMaxBlock to be accurate. <8> 1/31/91 DFH NGK,WS#DFH-910131a:Changed SetAppParameters so that launchee gets a saeLaunchedWithoutDocs AppleEvent when the launcher passed launchAppParameters == nil. <7> 1/14/91 DFH (JDR) Conditionalize out AUX support. <5> 12/5/90 DFH Integrated AUX support. <4> 11/26/90 DFH Change trespass() to dbmsg(). <2> 10/30/90 csd Fixed some identifiers to match the newest interfaces. <0> x/xx/86 PYG New Today. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Glue.h" #include "Lomem.h" #include "Data.h" #include "SysMisc.h" #include "Aux.h" #include "Puppet.h" #include "Zone.h" #include "AppleEventExtensions.h" /* Function prototypes internal to this file */ void OpenAppWDs(PEntryPtr); void CopyAppParmHandle(AppParmRecHdl, PCB **); void GetSizeInfo(swParmPtr, short); void SyncSIZEInfo(void); /* Some function prototypes that should be in (yet another) header file */ AppParmRecHdl AEParmToAppParmHandle(AppParametersPtr, PCB **); Handle AppParmHandleToAEParm(AppParmRecHdl); OSErr DecomposeWD(short, short *, unsigned long *); void FPInit(void); void NextAppFile(AppFile **); unsigned long SizeOfThisAppFile(AppFile *); void kill_dce(THz); /* Macros for easy access to the _Launch parameters */ #define IS_EXTENDED_BLOCK(pLaunchBlock) ((pLaunchBlock)->launchBlockID == extendedBlock) #define FIRST_EXTENSION_SIZE (2*sizeof(short)) #define SECOND_EXTENSION_SIZE ( FIRST_EXTENSION_SIZE + sizeof(ProcessSerialNumber) + 5*sizeof(long) ) /* This is roughly the memory overhead to handle an application that will have * half a chance of running. It includes PCBs, HLists, 'lmem' resources, AppleEvents, * etc. that are made in either the system heap or the Process Mgr heap. */ #define APPSIZESLOP (0x1000) /* SyncSIZEInfo. Sync the SIZE information in case a pre-7.1 system has touched the SIZE(0) * information but the SIZE(1) is not yet updated. We would prefer to use the SIZE(1) resource * to do the launch, but only after it is up to date. Data is updated as follows: if the * psize (preferred size) in the SIZE(0) is different from the same field in SIZE(1), then * copy that size into SIZE(1). Then, if the msize (minimum size) in SIZE(1) is greater than * the new psize, set msize the same as psize. If either SIZE(1) or SIZE(0) are * missing, then bail. */ void SyncSIZEInfo() { swParmHdl h0, h1; /* Get the resources */ h0 = Get1Resource('SIZE', 0); h1 = Get1Resource('SIZE', 1); if ( h0 && h1 ) // if we have both handles, then do more stuff { if ( (**h0).psize != (**h1).psize ) { (**h1).psize = (**h0).psize; if ( (**h1).msize > (**h1).psize ) (**h1).msize = (**h1).psize; ChangedResource( (Handle) h1 ); // if this fails, we donÕt care... WriteResource( (Handle) h1 ); // ...the in-memory copy will still be right } } } /* GetSizeInfo. Extract SIZE information from current file. Supplies defaults * in no-find case. The defaults were chosen with the assumption that the app * is capable of running on a MacPlus. We also assume that the sizes (default or * otherwise) were chosen with the MacPlus stack size in mind, and adjust them * according to the stack size we'll actually use for this launch. */ void GetSizeInfo(swParmPtr pSizeInfo, short firstChoice) { swParmHdl h; /* Make sure the SIZE resources are correct */ SyncSIZEInfo(); /* First, try the preferred resource ID. This will either be a 1 for applications or * a weird negative ID for DAs. If itÕs for a DA and itÕs unavailable, give up. If itÕs for * an application and weÕre looking for ID 1 and itÕs unavailable, then try ID 0. If neither * ID 0 or ID 1 (made by Finder) are present, try one more time for ID -1. If ID -1 canÕt be * found, then just give up. */ if ( ((h = Get1Resource('SIZE', firstChoice)) == nil) && (firstChoice == 1) ) if ( (h = Get1Resource('SIZE', 0)) == nil ) h = Get1Resource('SIZE', -1); /* Copy info if available. Otherwise, assume the app has old requirements. */ if (h != nil) BlockMove(*h,pSizeInfo,sizeof(swParms)); else { pSizeInfo->flags = 0; pSizeInfo->psize = (512*1024); pSizeInfo->msize = (512*1024); } /* Normalize to MacPlus stack size if not a daemon */ if (((pSizeInfo->flags & modeOnlyBackground) == 0) && (DEFLTSTACK > MACPLUS_DEFLTSTACK)) { unsigned long normalization; normalization = DEFLTSTACK - MACPLUS_DEFLTSTACK; pSizeInfo->psize += normalization; pSizeInfo->msize += normalization; } } /* StandardLaunch. Subroutinizes most of what it takes to launch an application * into a process. Name and vRefNum specify the application resource file. Assumes * that any necessary working directories have already been opened. * Called internally, we may have extra flags on in the taskMode (such as to * indicate a Desk Accessory launch). * NOTE: Callers should be able to rely on launchResults->pNewProcess == nil if the result != noErr. * NOTE: assumes a5 == PROCESSMGRGLOBALS */ void StandardLaunch(FSSpecPtr pFileSpec, u_short launchFlags, u_long taskMode, Ptr pAppParms, LaunchResultsPtr launchResults, DASpecBlockPtr pDAInfo) { InternalLaunchPB ILParams; swParms sizeInfo; OSErr retVal; short rfn, saveCurMap; u_size appSize; THz saveZone; /* Fill in param block for lower routines */ ILParams.ilAppSpecPtr = pFileSpec; ILParams.ilDAInfoPtr = pDAInfo; ILParams.ilStackSize = DEFLTSTACK; ILParams.ilAppParameters = pAppParms; ILParams.ilAppParamHdl = nil; /* In case of error */ launchResults->pNewProcess = nil; appSize = 0; /* Get access to the application resource file SIZE resource. Switch to the * system heap, since the caller may not have enough room to even create the * resource map when we open the file. */ saveCurMap = CURMAP; SafeSetZone(saveZone, SYSZONE); if ((taskMode & modeDeskAccessory) != 0) { UseResFile(0); GetSizeInfo(&sizeInfo, DAH_SIZE_RESOURCE_ID); } else { SetResLoad(false); rfn = HOpenResFile(pFileSpec->vRefNum, pFileSpec->parID, &pFileSpec->name, ((taskMode & modeMultiLaunch) != 0) ? fsRdPerm : fsCurPerm); launchResults->LaunchError = RESERR; SetResLoad(true); /* Fail if we couldn't open the resource file */ if (rfn == (-1)) { SafeRestoreZone(saveZone); return; } /* Set the taskMode. OR in the MultiLaunch flag, and replace the low word * with control information from the SIZE resource. */ if ((taskMode & FILE_FLAG_MULTILAUNCH) != 0) taskMode |= modeMultiLaunch; GetSizeInfo(&sizeInfo, 1); // <18> /* Don't close yet so that we get opWrErr later on. * NOTE: Closing the app file (we do it here in the non-continue case) * has the potential for screwing up VBLs (and others?) that will still * be running out of its code segments. Mostly a problem only if the * heap moves before the VBLKILL in the launcher's ExitToShell. */ if ( ((launchFlags & launchContinue) == 0) || (rfn != CURAPREFNUM) ) CloseResFile(rfn); } /* Have to restore map, since app file might not have been at top of chain */ SafeRestoreZone(saveZone); CURMAP = saveCurMap; /* Copy the flags into the task mode */ ILParams.ilTaskMode = ((taskMode & 0xFFFF0000) | (u_long) sizeInfo.flags); /* If it's a BG-only app, is that OK? */ if (((sizeInfo.flags & modeOnlyBackground) != 0) && ((launchFlags & launchInhibitDaemon) != 0)) { launchResults->LaunchError = appIsDaemon; return; } /* Try to launch in the preferred size */ ILParams.ilPartitionSize = sizeInfo.psize; retVal = KernelLaunch(&ILParams); /* If launch failed because there was not enough room, retry in smaller space * if the user wants to, and the space is available. Use the largest available * size, as long as it meets the application's minimum size requirement. Try to * leave enough memory in ProcessMgrZone to allocate subordinate structures, like * the PCB, HLists, etc. * NOTE: Assumes that the partition is the next block allocated from the * ProcessMgrZone (otherwise, we are not guaranteed to get full appSize). */ if (retVal == memFullErr) { appSize = ProcessMgrMaxBlock(); if (appSize < APPSIZESLOP) appSize = 0; else appSize -= APPSIZESLOP; /* Do we have enough to retry? * NOTE: Assumes that the first KernelLaunch didn't change anything in ILParams. */ if ( (appSize >= sizeInfo.msize) && ((launchFlags & launchUseMinimum) != 0) ) { ILParams.ilPartitionSize = appSize; retVal = KernelLaunch(&ILParams); appSize = 0; } } if (retVal == noErr) { /* Synchronize count for scrap coercion */ (ILParams.ilResultProc)->p_cutcopycount = cutCopyCount; /* Launching an app cancels an saeQuitAll */ if (pSystemQuitAllMsg != nil) CancelQuitAll(&((ILParams.ilResultProc)->p_serialNumber)); } /* Return output information */ launchResults->pNewProcess = ILParams.ilResultProc; launchResults->AvailableSize = appSize; launchResults->PreferredSize = sizeInfo.psize; launchResults->MinimumSize = sizeInfo.msize; launchResults->LaunchError = retVal; } #pragma segment INIT /* LaunchFacelessTasks. Find and launch all background applications kept in the * "extensions" folder. * NOTE: Theoretically, FindFolder or HOpenResFile could move memory by calling * _GetResource, which is a problem for the rsrc mgr routine CheckLoad(), which * will save and restore TheZone for resources w/ resSysHeap set. Growing the * system heap means moving ProcessMgrZone, so the resource manager save/restore would * restore an obsolete value. * NOTE: assumes a5 == PROCESSMGRGLOBALS * NOTE: assumes THEZONE == ProcessMgrZone since we specifically restore it */ void LaunchFacelessTasks(void) { LaunchResults bgLaunchResults; swParms sizeInfo; short rfn, saveCurMap; FSSpec fileSpec; CInfoPBRec cInfoPBRec; /* Locate the startup folder. */ assert(THEZONE == ProcessMgrZone); THEZONE = SYSZONE; if (FindFolder(kOnSystemDisk, kExtensionFolderType, kDontCreateFolder, &fileSpec.vRefNum, &fileSpec.parID) != noErr) { THEZONE = ProcessMgrZone; return; } /* Now iterate over all the files in the directory */ cInfoPBRec.hFileInfo.ioNamePtr = &fileSpec.name; cInfoPBRec.hFileInfo.ioVRefNum = fileSpec.vRefNum; cInfoPBRec.hFileInfo.ioFDirIndex = 0; cInfoPBRec.hFileInfo.ioCompletion = nil; for(;;) { /* Reset parameters and get next file. Quit if directory went bad. */ cInfoPBRec.hFileInfo.ioDirID = fileSpec.parID; cInfoPBRec.hFileInfo.ioFDirIndex++; if (PBGetCatInfo(&cInfoPBRec, SyncHFS) != noErr) break; /* Don't try launch if file isn't an application */ if ( ((cInfoPBRec.hFileInfo.ioFlAttrib & FILE_ATTRIB_ISDIR) != 0) || (cInfoPBRec.hFileInfo.ioFlFndrInfo.fdType != 'appe') ) continue; /* Don't launch if it is not a background-only system extension */ saveCurMap = CURMAP; SetResLoad(false); rfn = HOpenResFile(fileSpec.vRefNum, fileSpec.parID, &fileSpec.name, fsCurPerm); SetResLoad(true); if (rfn == (-1)) continue; GetSizeInfo(&sizeInfo, 1); // <18> CloseResFile(rfn); CURMAP = saveCurMap; if ((sizeInfo.flags & modeOnlyBackground) == 0) continue; /* Try the launch */ StandardLaunch(&fileSpec, 0, 0, nil, &bgLaunchResults, nil); } THEZONE = ProcessMgrZone; } #pragma segment Main /* c_launch. Our patch to the _Launch trap. It has takes a parameter block that * may be any of three different sizes. To make things worse, there are flag * fields that can tell us to perform optional extra work so that the caller * doesn't have to. Please excuse my GOTOs, but they were the most effective * way to bail out of error conditions without some extremely unwieldy coding. * This is essentially a wrapper for our internal routine StandardLaunch. */ #define APPPARMS_NOT_SPECIFIABLE (-1) pascal long c_launch(LaunchPBPtr pLaunchBlock) { u_short launchOpts, wdRefNumDst; u_long blockLen, olda5; Boolean alreadyLaunched; FInfo fndrInfo; unsigned short fileFlags; Ptr appParms; LaunchResults appLaunchResults; FSSpec fileSpec, *pFileSpec; #define pProc (appLaunchResults.pNewProcess) #define retVal (appLaunchResults.LaunchError) olda5 = ProcessMgrA5SimpleSetup(); /* Clear retVal, pProc, and SIZE information */ MemClear(&appLaunchResults, sizeof(LaunchResults)); /* Fill in default values for parameters that might not be there */ blockLen = 0; pFileSpec = nil; fileFlags = 0; launchOpts = 0; appParms = (Ptr) APPPARMS_NOT_SPECIFIABLE; /* Get the parameters that were given */ blockLen = (IS_EXTENDED_BLOCK(pLaunchBlock)) ? pLaunchBlock->launchEPBLength : 0; if (blockLen >= FIRST_EXTENSION_SIZE) { fileFlags = pLaunchBlock->launchFileFlags; launchOpts = pLaunchBlock->launchControlFlags; } if (blockLen >= SECOND_EXTENSION_SIZE) { pFileSpec = pLaunchBlock->launchAppSpec; pLaunchBlock->launchPreferredSize = 0; pLaunchBlock->launchMinimumSize = 0; pLaunchBlock->launchAvailableSize = 0; if ((appParms = pLaunchBlock->launchAppParameters) == APPPARMS_NOT_SPECIFIABLE) appParms = nil; } else { GetVol(0, &wdRefNumDst); if ((retVal = FSMakeFSSpec(wdRefNumDst, 0, (StringPtr) pLaunchBlock->reserved1, &fileSpec)) != noErr) goto AfterLaunch; pFileSpec = &fileSpec; } /* Launch the application into a process. Relaunch existing application only if * it is the caller himself and he is not trying to get a second copy!. */ alreadyLaunched = ((pProc = PEntryFromFileSpec(pFileSpec, nil)) != nil); if ( (alreadyLaunched == false) || ((pProc == pCurrentProcess) && ((launchOpts & launchContinue) == 0)) ) { /* Get file's flags if the caller wants us to */ if ((launchOpts & launchNoFileFlags) != 0) { if ((retVal = FSpGetFInfo(pFileSpec, &fndrInfo)) != noErr) goto AfterLaunch; fileFlags = fndrInfo.fdFlags; } /* Try the launch */ StandardLaunch(pFileSpec, launchOpts, (u_long) fileFlags, appParms, &appLaunchResults, nil); } /* Return output parameters */ if (blockLen >= SECOND_EXTENSION_SIZE) { if (retVal == noErr) pLaunchBlock->launchProcessSN = pProc->p_serialNumber; else SetPSN(kNoProcess, &pLaunchBlock->launchProcessSN); pLaunchBlock->launchPreferredSize = appLaunchResults.PreferredSize; pLaunchBlock->launchMinimumSize = appLaunchResults.MinimumSize; pLaunchBlock->launchAvailableSize = appLaunchResults.AvailableSize; } AfterLaunch: /* Arrange for the new app layer to be created in front, unless overridden. We then * put the newborn to sleep until fg_resched decides to schedule it. This ensures * that the app gets its first time in the foreground, and when there are no modals * up. A "don't switcher" will be created in the very back (it doesn't matter * whether there's a modal in this case). * If the app was already launched, a simple SetFrontProcess will do. */ if (retVal == noErr) { if ( ((launchOpts & launchDontSwitch) == 0) && ((pProc->p_taskmode & modeOnlyBackground) == 0) ) { if ((SetFrontProcess(&pProc->p_serialNumber) == noErr) && (alreadyLaunched == false)) PutOnSleepQueue(pProc, MAXVALUE); } } /* Old style launch causes the launcher to quit. This is true even if the new * application fails to launch (no error return possible, so just beep). */ if ((launchOpts & launchContinue) == 0) { if (retVal != noErr) SysBeep(20); A5SimpleRestore(olda5); ExitToShell(); dbmsg("ExitToShell in LaunchApplication failed."); } A5SimpleRestore(olda5); /* Return short process descriptor or error to caller */ return ( ((retVal == noErr) && (blockLen < SECOND_EXTENSION_SIZE)) ? pProc->p_mypid : retVal); #undef pProc #undef retVal } #pragma segment kernel_segment /* NewAppParmHandle. Create a blank AppParmRecHdl of the specified size. * NOTE: Locking the AppParmHandle is done explicitly for MacWrite 4.5 (and * 4.6?) and should someday be removed. */ AppParmRecHdl NewAppParmHandle(Size theSize) { AppParmRecHdl retHdl; ResrvMem(theSize); if ((retHdl = (AppParmRecHdl) NewHandleClear(theSize)) != nil) HLock(retHdl); return(retHdl); } /* SizeOfThisAppFile. Figure out the size of the given AppFile structure. Allows * for even alignment. */ unsigned long SizeOfThisAppFile(AppFile *pAppFile) { register unsigned long theSize; theSize = 2*sizeof(short) + sizeof(OSType) + Length(&(pAppFile->fName))+ 1; WORD_ALIGN(theSize); return(theSize); } /* NextAppFile. Moves the specified AppFile pointer past its data. */ void NextAppFile(AppFile **ppAppFile) { AppFile *pAppFile; /* Bump pointer by size of data */ pAppFile = *ppAppFile; (Ptr) pAppFile += SizeOfThisAppFile(pAppFile); *ppAppFile = pAppFile; } /* CopyAppParmHandle. Copy the specified AppParmRecHdl into the current zone, and * set up the p_appWDList for later consumption by OpenAppWDs. */ void CopyAppParmHandle(AppParmRecHdl sourceAPH, PCB **hPCB) { AppWDRecPtr dstLoc; AppWDListPtr pWDList; AppWDListHdl hWDList; AppParmRecPtr pAPH; AppFile *parmLoc; short parmCount = 0, sizeOfStruct; /* In case of error */ (*hPCB)->p_appWDList = nil; /* Copy the APPPARMHANDLE into new zone. Allocate it low so we can lock it. * NOTE: Locking the AppParmHandle is done explicitly for MacWrite 4.5 (and * 4.6?) and should someday be removed. */ ResrvMem(GetHandleSize(sourceAPH)); HandToHand(&sourceAPH); if (MEMERROR != noErr) return; HLock(sourceAPH); APPPARMHANDLE = sourceAPH; pAPH = *sourceAPH; /* See how many files there are. Get out if there are none. */ parmCount = pAPH->count; if (parmCount == 0) return; /* Allocate the list in a relocatable block in the current heap */ sizeOfStruct = sizeof(AppWDList) + (parmCount * sizeof(AppWDRec)); if ( (hWDList = (AppWDListHdl) NewHandleClear(sizeOfStruct)) == nil ) { DisposHandle(sourceAPH); return; } /* Traverse the APPPARMHANDLE to save off the WD information therein */ pWDList = *hWDList; pWDList->wdlCount = parmCount; dstLoc = &(pWDList->wdlDirectories); parmLoc = &(pAPH->appFiles[0]); while (parmCount-- != 0) { (void) DecomposeWD(parmLoc->vRefNum, &dstLoc->awdVolume, &dstLoc->awdDirID); parmLoc->vRefNum = 0; NextAppFile(&parmLoc); dstLoc++; } (*hPCB)->p_appWDList = hWDList; } /* SetAppParameters. Ensures that the new app gets the intended parameters in a * form it can understand. This can mean translating from an AppleEvent to an * APPPARMHANDLE, or vice versa. It definitely means saving the necessary working * directory info. */ void SetAppParameters(PCB **hPCB, unsigned long currentA5, register InternalLaunchPBPtr pParams, Boolean appDoesEppc) { PCB *pPCB; DASpecBlockPtr pDAInfo; AppParmRecHdl aph; struct appparmarea *parm; /* Get the resource file directory. If this is DA Handler being launched, * the resource file directory is the one containing the Desk Accessory file. */ pPCB = *hPCB; if ((pDAInfo = pParams->ilDAInfoPtr) == nil) { pPCB->p_appVolume = (pParams->ilAppSpecPtr)->vRefNum; pPCB->p_appDirID = (pParams->ilAppSpecPtr)->parID; } else { pPCB->p_appVolume = (pDAInfo->daFileSpec)->vRefNum; pPCB->p_appDirID = (pDAInfo->daFileSpec)->parID; } /* Convert DocList to AppParmRecHdl or vice-versa. Do nothing for the thoroughly * modern case of the launcher giving an AppleEvent to an AppleEvent-aware launchee, * except to ensure that the launchee gets an saeLaunchedWithoutDocs ('oapp') in * case ilAppParameters is nil (AppleEvent-aware applications count on seeing an * AppleEvent at startup, knowing that it came from the launcher and not sometime * after they were launched). */ aph = APPPARMHANDLE; APPPARMHANDLE = nil; if (pParams->ilAppParameters != APPPARMS_NOT_SPECIFIABLE) { if (appDoesEppc == false) { APPPARMHANDLE = AEParmToAppParmHandle(pParams->ilAppParameters, hPCB); pParams->ilAppParameters = nil; } else if (pParams->ilAppParameters == nil) pParams->ilAppParamHdl = AppParmHandleToAEParm(nil); } else { pParams->ilAppParameters = nil; if (appDoesEppc) pParams->ilAppParamHdl = AppParmHandleToAEParm(aph); else if ((aph != nil) && (*aph != nil)) CopyAppParmHandle(aph, hPCB); } /* fix up application parameter area */ parm = (struct appparmarea *) ((Ptr)currentA5 + 8); parm->stdin = 0; parm->stdout = 0; parm->physexec = 0; parm->parmhandle = APPPARMHANDLE; } /* OpenAppWDs. Open the working directories needed by a new application. Also * sets CURDIRSTORE and SFSAVEDISK according to the last file in APPPARMHANDLE * (if there is no APPPARMHANDLE, it uses the resource file directory). */ void OpenAppWDs(PEntryPtr pProc) { AppWDListHdl hWDList; AppWDRecPtr pWDInfo; short wdCount; WDPBRec wdpbrec; AppFile *pAppFile; PCB *pPCB; /* Open home working directory */ wdpbrec.ioNamePtr = nil; wdpbrec.ioCompletion = nil; pPCB = *(pProc->p_pcb); wdpbrec.ioVRefNum = pPCB->p_appVolume; wdpbrec.ioWDDirID = pPCB->p_appDirID; wdpbrec.ioWDProcID = 0; PBOpenWD(&wdpbrec, SyncHFS); (*pProc->p_pcb)->p_vrefnum = wdpbrec.ioVRefNum; SetVol(nil, wdpbrec.ioVRefNum); /* Get list of parameter WDs to open, if any. */ if ((hWDList = (*pProc->p_pcb)->p_appWDList) == nil) { SFSAVEDISK = -(pPCB->p_appVolume); CURDIRSTORE = pPCB->p_appDirID; return; } /* Traverse said list, opening a WD from the component info. Note that the * volume/dirid that ultimately get used for SFSAVEDISK and CURDIRSTORE will * be from the last AppFile in APPPARMHANDLE. */ HLock(hWDList); wdCount = (*hWDList)->wdlCount; pWDInfo = &((*hWDList)->wdlDirectories); if (APPPARMHANDLE != nil) pAppFile = &((*(AppParmRecHdl) APPPARMHANDLE)->appFiles[0]); while (wdCount-- != 0) { wdpbrec.ioVRefNum = pWDInfo->awdVolume; wdpbrec.ioWDDirID = pWDInfo->awdDirID; wdpbrec.ioWDProcID = 0; PBOpenWD(&wdpbrec, SyncHFS); pAppFile->vRefNum = wdpbrec.ioVRefNum; SFSAVEDISK = -(pWDInfo->awdVolume); CURDIRSTORE = pWDInfo->awdDirID; NextAppFile(&pAppFile); pWDInfo++; } /* Free the memory */ DisposHandle(hWDList); (*pProc->p_pcb)->p_appWDList = nil; } /* BeginApplication. Code executed by a newborn process after it is switched in for * the very first time. Set up the toolbox and OS worlds. */ void BeginApplication(void) { #ifdef HAS_AUX_PROCESSMGR void (*auxidleprocptr)(); #endif HAS_AUX_PROCESSMGR unsigned long olda5; olda5 = ProcessMgrA5SimpleSetup(); if (MachineHasFPU) FPInit(); /* Fix up working directories for home directory and files in APPPARMHANDLE */ OpenAppWDs(pCurrentProcess); #ifdef HAS_AUX_PROCESSMGR auxidleprocptr = ((pCurrentProcess->p_taskmode & COFF_BINARY) != 0) ? AUX_IdleProc : nil; #endif HAS_AUX_PROCESSMGR A5SimpleRestore(olda5); /* now call toolbox/system initializing trap */ InitApplication(); #ifdef HAS_AUX_PROCESSMGR /* Let coff binary be initialized and scheduled by AUX. * NOTE: AUX context switch will probably occur hereÉ */ if (auxidleprocptr != nil) (*auxidleprocptr)(); #endif HAS_AUX_PROCESSMGR } #pragma segment kernel_segment /* c_rdrvrinstall. Fix up the unit table when the application zone is nuked. * NOTE: Also, gives appropriate GBKisses to drivers, which is not done in the ROM * routine (Done inline in _ExitToShell/_Launch) but no one except _ExitToShell should * be calling this anyway. * NOTE: Needs to be same segment as kill_dce. */ pascal void c_rdrvrinstall(void) { kill_dce(APPLZONE); }