Advanced Search
Apple Developer Connection
Member Login Log In | Not a Member? Contact ADC

Previous Book Contents Book Index Next

Inside Macintosh: Operating System Utilities /
Chapter 8 - Trap Manager


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 the NGetTrapAddress, GetOSTrapAddress, or GetToolboxTrapAddress functions. To write an address to a trap dispatch table, you can use the NGetTrapAddress, GetOSTrapAddress, or GetToolboxTrapAddress procedures.

This section shows how you can use the Trap Manager to

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 these Unimplemented 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 the Unimplemented 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;
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 the InitGraf routine.
You can use the application-defined procedure MySWRoutineAvailable to check for system software routines not supported by the Gestalt Manager. A notable example is the WaitNextEvent function, which has never had Gestalt selectors. Listing 8-2 shows two common uses of the application-defined MySWRoutineAvailable 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. When SysBeep is called, this application-defined patch MySysBeep is executed before transferring control to the original SysBeep 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 original SysBeep procedure), the application-defined MyInstallAPatch procedure (Listing 8-5) uses the application-defined procedure MyFollowDaisyChain, shown in Listing 8-4. The MyFollowDaisyChain duplicates the parameter for the SysBeep procedure and then pushes the address of the SysBeep procedure on the stack.
Listing 8-4 shows the application-defined procedure MyFollowDaisyChain.

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
END
The application-defined procedure MyInstallAPatch in Listing 8-5 installs a patch into the daisy chain (in this example, the MySysBeep patch). First, the procedure calls the NGetTrapAddress 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 the NSetTrapAddress procedure to put the address of the new patch (in this example, the address of MySysBeep 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 the NGetTrapAddress and NSetTrapAddress routines. The NGetTrapAddress and NSetTrapAddress routines both need a parameter that indicates which type of routine is being patched, an Operating System or Toolbox routine.

Previous Book Contents Book Index Next

© Apple Computer, Inc.
6 JUL 1996

Get information on Apple products.
Visit the Apple Store online or at retail locations.
1-800-MY-APPLE

Copyright © 2004 Apple Computer, Inc.
All rights reserved. | Terms of use | Privacy Notice