Apple IIgs #101
Patching the Toolbox

Revised by Dave Lyons (May 1992)
Written by Dave Lyons (May 1991)

This Technical Note presents guidelines on when and how to patch Apple IIgs Toolbox functions.

Added a note about patching the Tool Locator and Desk Manager, and corrected a spelling error.


There is normally no need to patch the toolbox; avoid patching whenever you can. If you must patch a toolbox function, be sure to have a good understanding of the call you're patching and how it interacts with the whole system.

No toolbox patch is risk-free. Future versions of the toolbox could change in ways that make your patch less useful. (For example, if you patched NewControl to have some global effect on controls being created, your patch became less useful when NewControl2 was introduced in System Software 5.0.)

For better compatibility, patch with care! If any parameters passed are outside the range that was allowed when you wrote your patch, just pass the call straight through; the new toolbox probably knows something your patch doesn't.

Patching the Toolbox from an Application

An application can easily patch a function for the duration of that application.

After starting up the tools, construct a Function Pointer Table (FPT) the same size as the existing FPT (call GetTSPtr and examine the first word of the table; multiply it by four to get the size of the FPT in bytes). The first longword of your FPT is the number of functions in the tool set; do not hard-code this value! Get it from the existing FPT on the fly. Fill the rest of your FPT with zeroes, except for the functions you want to patch. You must always patch the BootInit function (the first function) to return no error. Remember that the function pointer values are one less than the addresses of your replacement functions.

On exit, when you call TLShutDown your patch will be automatically removed. (If you're using ShutDownTools, you should call MMShutDown and TLShutDown after you call ShutDownTools.)

Note: In the description of SetTSPtr on page 24-19 of Apple IIgs Toolbox Reference, Volume 2, there are several references to the TPT. Keep in mind that the TPT is the Toolset Pointer Table, not the Function Table Pointer you pass to SetTSPtr. While SetTSPtr copies the TPT to RAM if necessary, it does not make a copy of the FPT. After you call SetTSPtr, the FPT you passed is being used, and any zero values in your table were filled in.

Patching the Toolbox from a Desk Accessory of Setup File

A permanent initialization file or Desk Accessory can patch toolbox functions at boot time by constructing an FPT for SetTSPtr, as described for an application, but there is an extra step to make the patch "stick."

Call LoadOneTool and then SetTSPtr; then call SetDefaultTPT (see Apple IIgs Toolbox Reference Volume 3, page 51-16).

It is not safe to call SetDefaultTPT while an application is running (temporary application patches would be made permanent, and later the application would go away). Since there are desk accessories that install other desk accessories while applications are running, desk accessory that wants to install a tool patch should make the class-one GS/OS GetName call; if the null string is returned, no application is executing yet, so it is safe to make the patch. (Otherwise the desk accessory should ask the user to put the desk accessory file in the System:Desk.Accs folder and restart the system.)

Patching the Tool Locator or Desk Manager

On ROM 3 systems, the SetTSPtr call treats toolsets 1 (Tool Locator) and 5 (Desk Manager) specially, for compatibility with system software versions earlier than 5.0.

You must pass a systemOrUser value of $0001 (not $0000) when patching one of these toolsets, or the SetTSPtr call will have no effect. Passing this special systemOrUser value works for other ROM versions, too -- you don't have to check the ROM version.

Avoid Tail Patching

The best kind of patch is a pre-patch or head patch: it does some extra work and then jumps to the original function (as found in the FPT before applying the patch). Make sure the A, X, and Y registers contain the same values when you jump to the original function as they did when the patch got control.

A "tail patch" which calls the original function and then regains control is much more of a compatibility risk, because there are several instances where System Software patches examine return addresses to fix problems in large toolbox calls which call small ones (by patching the small one to realize it's being called from the big one, many K of RAM remain available to your application).

If you tail patch a function which the system already patched, you may prevent the toolbox from working correctly.

Patching the Tool Dispatcher

If you need to patch a large number of functions, especially for a general purpose utility like a debugger, it may make more sense to patch the tool dispatcher vectors instead of patching individual functions. See Apple IIgs Technical Note #87, Patching the Tool Dispatcher.

Further Reference

This and all of the other Apple II Technical Notes have been converted to HTML by Aaron Heiss as a public service to the Apple II community, with permission by Apple Computer, Inc. Any and all trademarks, registered and otherwise, are properties of their owners.