Important: The information in this document is obsolete and should not be used for new development.
Using the Trap Manager
You can use the Trap Manger to read from and write to a trap dispatch table. To read an address from a trap dispatch table, you can call theNGetTrapAddress,GetOSTrapAddress, orGetToolboxTrapAddressfunctions. To write an address to a trap dispatch table, you can use theNGetTrapAddress,GetOSTrapAddress, orGetToolboxTrapAddressprocedures.This section shows how you can use the Trap Manager to
- determine if a system software routine is available
- patch a system software routine
Determining If a System Software Routine is Available
You can use the Trap Manager to determine the availability of system software routines.The Gestalt Manager, introduced in System 6.0.4 and discussed in the chapter "Gestalt Manager" in this book, is the primary tool for querying the system about its features. But if you expect your application to run on a system older than System 6.0.4, the Gestalt Manager may not be available.
The example in this section shows how you can use the Trap Manager to check whether a particular system software routine is available on the installed system.
At startup time, system software places the address of the
Unimplementedprocedure into all entries of each trap dispatch table that do not contain an address of a Toolbox or Operating System routine (or the address of a come-from patch). Listing 8-1 illustrates how you can use theseUnimplementedaddresses to determine whether a particular system software routine is available on the user's system. If a system software routine is available, its address differs from the address of theUnimplementedprocedure.Listing 8-1 Determining if a system software routine is available
FUNCTION MySWRoutineAvailable (trapWord: Integer): Boolean; VAR trType: TrapType; BEGIN {first determine whether it is an Operating System or Toolbox routine} IF ORD(BAND(trapWord, $0800)) = 0 THEN trType := OSTrap ELSE trType := ToolTrap; {filter cases where older systems mask with $1FF rather than $3FF} IF (trType = ToolTrap) AND (ORD(BAND(trapWord, $03FF)) >= $200) AND (GetToolboxTrapAddress($A86E) = GetToolboxTrapAddress($AA6E)) THEN MySWRoutineAvailable := FALSE ELSE MySWRoutineAvailable := (NGetTrapAddress(trapWord, trType) <> GetToolboxTrapAddress(_Unimplemented)); END;You can use the application-defined procedure MySWRoutine
- Note
- Macintosh Plus and Macintosh SE computers with system software prior to System 7 masked their trap numbers with $1FF in the
GetToolboxTrapAddressfunction so that the address of A-line instruction $AA6E (whether implemented or not) would be the same as A-line instruction $A86E, which invokes theInitGrafroutine.![]()
Availableto check for system software routines not supported by the Gestalt Manager. A notable example is theWaitNextEventfunction, which has never hadGestaltselectors. Listing 8-2 shows two common uses of the application-definedMySWRoutineAvailableprocedure.Listing 8-2 Determining whether WaitNextEvent and Gestalt are available
VAR gHasWNE, gHasGestalt: Boolean; {check for the availability of WaitNextEvent} gHasWNE := MySWRoutineAvailable(_WaitNextEvent); {check for the availability of Getstalt} gHasGestalt := MySWRoutineAvailable(_Gestalt);Patching a System Software Routine
Although this chapter describes patching in some depth, you should rarely, if ever, find a need to use patches in an application. The primary purposes of patches, as their name suggests, are to fix problems and augment routines in ROM code. The examples in this section are only included for the sake of completeness.Listing 8-3 illustrates a patch for the
SysBeepOperating System procedure. WhenSysBeepis called, this application-defined patchMySysBeepis executed before transferring control to the originalSysBeepprocedure.Listing 8-3 Patching the SysBeep Operating System procedure
PROCEDURE MySysBeep (duration: Integer); VAR oldPort: GrafPtr; wMgrPort: GrafPtr; i: Integer; BEGIN GetPort(oldPort); GetWMgrPort(wMgrPort); SetPort(wMgrPort); FOR := 3 DOWNTO 0 DO BEGIN InvertRect(wMgrPort^.portBits.bounds); END; SetPort(oldPort); END; {of MySysBeep}To transfer control to the next routine in the daisy chain (in this example the originalSysBeepprocedure), the application-definedMyInstallAPatchprocedure (Listing 8-5) uses the application-defined procedureMyFollowDaisyChain, shown in Listing 8-4. TheMyFollowDaisyChainduplicates the parameter for theSysBeepprocedure and then pushes the address of theSysBeepprocedure on the stack.
Listing 8-4 shows the application-defined procedureMyFollowDaisyChain.Listing 8-4 Jumping to the next routine in the daisy chain
MyFollowDaisyChain PROC EXPORT IMPORT MYSYSBEEP BRA.S @2 @1 DC.L $50FFC001 @2 MOVE.W $4(A7),-(A7) ;duplicate the parameters MOVE.L @1,-(A7) ; and push the chain link BRA.S MYSYSBEEP NOP ENDPROC ENDThe application-defined procedureMyInstallAPatchin Listing 8-5 installs a patch into the daisy chain (in this example, theMySysBeeppatch). First, the procedure calls theNGetTrapAddressfunction to get the address of the next routine in the daisy chain. This address could be the address of another patch or the system software routine. Next,MyInstallAPatchcalls theNSetTrapAddressprocedure to put the address of the new patch (in this example, the address ofMySysBeeppatch) into the trap dispatch table.Listing 8-5 Installing a patch
PROGRAM MyPatchInstaller; USES Memory, ToolIntf, OSIntf, OSUtils,Windows, ToolUtils, Traps, Resources, SamplePatch; TYPE PatchCodeHandle = ^PatchCodePtr; PatchCodePtr = ^PatchCodeHeader; PatchCodeHeader = RECORD branch: Integer; oldTrapAddress: LongInt; END; PROCEDURE MyFollowDaisyChain (duration: Integer); EXTERNAL; PROCEDURE MyInstallAPatch (trapNumber: Integer; tType: TrapType; pPatchCode: PatchCodePtr); BEGIN pPatchCode^.oldTrapAddress := NGetTrapAddress(trapNumber, tType); NSetTrapAddress (ORD4(pPatchCode), trapNumber, tType); END; {of MyInstallAPAtch} BEGIN InitGraf (@qd.thePort); InitFonts; InitWindows; MyInstallAPatch(_SysBeep, ToolTrap, PatchCodePtr(@MyFollowDaisyChain)); SysBeep(1); END. {of MyPatchInstaller}
- Note
- The
MyInstallAPatchprocedure used in this example was designed to install both Operating System and Toolbox patches; it uses theNGetTrapAddressandNSetTrapAddressroutines. TheNGetTrapAddressandNSetTrapAddressroutines both need a parameter that indicates which type of routine is being patched, an Operating System or Toolbox routine.![]()