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
, orGetToolboxTrapAddress
functions. To write an address to a trap dispatch table, you can use theNGetTrapAddress
,GetOSTrapAddress
, orGetToolboxTrapAddress
procedures.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
Unimplemented
procedure 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 theseUnimplemented
addresses 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 theUnimplemented
procedure.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
GetToolboxTrapAddress
function so that the address of A-line instruction $AA6E (whether implemented or not) would be the same as A-line instruction $A86E, which invokes theInitGraf
routine.Available
to check for system software routines not supported by the Gestalt Manager. A notable example is theWaitNextEvent
function, which has never hadGestalt
selectors. Listing 8-2 shows two common uses of the application-definedMySWRoutineAvailable
procedure.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
SysBeep
Operating System procedure. WhenSysBeep
is called, this application-defined patchMySysBeep
is executed before transferring control to the originalSysBeep
procedure.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 originalSysBeep
procedure), the application-definedMyInstallAPatch
procedure (Listing 8-5) uses the application-defined procedureMyFollowDaisyChain
, shown in Listing 8-4. TheMyFollowDaisyChain
duplicates the parameter for theSysBeep
procedure and then pushes the address of theSysBeep
procedure 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 procedureMyInstallAPatch
in Listing 8-5 installs a patch into the daisy chain (in this example, theMySysBeep
patch). First, the procedure calls theNGetTrapAddress
function 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,MyInstallAPatch
calls theNSetTrapAddress
procedure to put the address of the new patch (in this example, the address ofMySysBeep
patch) 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
MyInstallAPatch
procedure used in this example was designed to install both Operating System and Toolbox patches; it uses theNGetTrapAddress
andNSetTrapAddress
routines. TheNGetTrapAddress
andNSetTrapAddress
routines both need a parameter that indicates which type of routine is being patched, an Operating System or Toolbox routine.