X-Master is freeware by LinkeSOFT. You can distribute X-Master with your freeware, shareware, or commercial application free of charge, provided that the X-Master program is not altered in any way. Users can install X-Master over an already existing version w/o problems. Migrating from Hackmaster is easy: X-Master detects Hackmaster, takes over its settings and removes it.
At a Glance
Writing a system extension (Hack)
You should have a working knowledge of Palm programming before you write our first Palm OS system extension (Hack). Access to the Palm OS source (available from Palm after signing an NDA) is invaluable. You can use either prc-tools or CodeWarrior.
Unlike normal applications, system extensions do not have a PilotMain() routine. They consist of various code resources that contain replacement or enhancement code for the system functions they want to patch. You can call the original function from your code resource.
A system extension:
- must have one or more 'TRAP' resources starting from ID 1000
The value of the TRAP resource is the 32 bit number of the trap you want to patch. You can find all trap numbers in the Palm OS system header CoreTraps.h
- must contain corresponding 'code' resources starting from ID 1000
These code resources contain your replacements for the traps above. The first routine in this code resource will be called. It must have the same signature as the corresponding OS function. You can define helper functions after the main patch function. The address of the original function is stored in a feature with the same ID. Note: no global variables are allowed!
- should have an info form resource with ID 3000
This form is displayed with FrmDoDialog, i.e. no custom event handler can be provided.
- can have configuration form resources with IDs 2000-2999 and corresponding 'code' resources with ID 2000-2999
The code resources are set as event handlers for the respective forms. Note: no global variables are allowed!
- should have an icon name (tAIN) resource with ID 1000 or 3000 that contains the extension name as it is displayed in the X-Master extension list. If no icon name is found, the database name will be displayed. Note the original HackMaster required tAIN 3000 resource. X-Master will also look for a tAIN 1000 resource to be more compatible with standard applications.
- should have a standard version (tver) resource with ID 1 or 1000 that will be displayed in the X-Master details form.
X-Master opens your extension database when displaying the info or configuration form, i.e. all resources are available via DmGetResource. X-Master uses resource IDs 9000-9999 internally. For robustness, it is suggested that your extension uses only resource IDs less than 9000.
Have a look at the PLZ-Hack sources for a simple example of a system extension that reverses the order of zip and town in the built-in address book. To achieve this effect, it patches the trap for DmGetResource(). The archive contains both a falch.net project for use with prc-tools and a CodeWarrior 7 project.
Because system extensions are called in another applications stack frame, you cannot use global variables. Use features as a replacement. Static strings (
"foo") and trace functions will not work in most cases (even if PC-relative strings is selected). Use string resources (don't forget to open your own application database first) and alerts or character drawing for debugging.
The original HackMaster author Edward Keyes has an introduction to Hack programming on his web site.
German developers can read an article about Hack programming in computer magazine c't 16/2001 page 180.
Using UIs in Hacks
When you want to display a user interface (forms and controls) from your running hack, you have to keep in mind that your code runs in the currently active application, just as if it were a part of it. Every form id you use in your hack may already be loaded in the active app. This makes displaying your own form resources from a running hack pretty difficult, if not impossible.
One solution (see the McPhling source for an example) would be to dynamically create the form and controls at runtime. Unfortunately, all dynamic control creation calls are thoroughly broken in all OS versions below 4.0 so you can only use FrmNewForm, CtlNewControl etc. on devices with PalmOS 4.0+.
X-Master fully supports the standard Hack API defined by Edward Keyes' Hackmaster in 1997. It offers some extensions to developers, namely launch codes for interaction with regular applications and support for activation/deactivation notification. You can test for the presence and version of X-Master by including xminterface.h and calling
If the call is successfull, X-Master is active and
xmasterversion contains the version of X-Master (e.g. 0x10400 for X-Master Version 1.4).
X-Master creator ID: ExtM
X-Master application database name: X-Master
X-Master launch codes and stand-alone applications
Some Palm developers will prefer writing system extensions as stand-alone applications because of
- increased usability and visibility (user sees application in launcher, just like any other application)
- use of globals in configuration forms
X-Master supports registering system extensions by stand-alone applications via launch codes. Stand-alone system extension applications can be configured and activated by starting them directly in the launcher.
To have a stand-alone application that is X-Master aware, just develop a standard system extension as described above. Instead of providing the configuration forms with ID 2000+ and event handlers with code resources 2000+, simply write a standard PilotMain() application and link it together with the system extension. To activate/deactivate your system extension from your main application, use launch codes.
Notification of extension activation/deactivation via code 999 resource
Some extensions need to perform special initialization or cleanup when they are activated/deactivated. Currently, such applications usually catch FtrRegister and FtrUnregister which is used by X-Master to create/release the original trap addresses. While this works with both HackMaster and X-Master, it is, of course, not a very clean solution as it depends on implementation details.
X-Master 1.4 and later contain the following extension of the original HackMaster API. Extensions that want to get notified about activation/deactivation provide a code 999 resource (regular trap code resources start at 1000).
The function for activation/deactivation should be in the code resource 999 and must have the following signature
Boolean ExtOnActivateDeactivate(Boolean activate);
Before an extension is activated, X-Master checks the existence of a code 999 resource. If such a code resource exists in the extension, it is locked, called with activate=true, and unlocked. If the return value is true, the extension is activated. If the return value is false, the extension is not activated. You must display your own alert in the notification handler.
After an extension is deactivated, X-Master performs the same check for the code 999 resource, locks it, calls it with activate=false, and unlocks it. The return value is ignored.
Multiple applications patching the same trap or why is a central trap management so important?
Consider the following scenario: Two applications A and B patch the same system trap, say SysHandleEvent (trap ID 0xA0A9). The user installs and activates application A.
Application A stores the original trap 0xA0A9 address that points to SysHandleEvent in a private variable (usually in a feature), and calls SysSetTrapAddress(0xA0A9,ASysHandleEvent). When the special processing is done, ASysHandleEvent will eventually call the original handler SysHandleEvent.
The user now installs and activates application B. Application B retrieves the address for trap 0xA0A9 via SysGetTrapAddress (which is now the address of ASysHandleEvent) and stores it in a private feature. It then calls SysSetTrapAddress(0xA0A9,BSysHandleEvent). When BSysHandleEvent is finished, it will call the original handler, ASysHandleEvent().
The chain of calls is now
and everything works fine as long as the user doesn't change anything.
Now consider the case that the user decides to remove or deactivate application A.
Upon deactivation, application A will happily restore the trap 0xA0A9 address (which currently points to BSysHandleEvent) with the original trap handler SysHandleEvent. In effect, application B will no longer work. The user will probably complain to application vendor B. Or maybe the user first opens application B (which still assumes it is active). When trying to deactivate itself, application B will restore the SysHandleEvent trap address with the value of ASysHandleEvent and in turn crash the device, since ASysHandleEvent now points to void memory.
Conclusion: applications should never call SysSetTrapAddress() directly. This applies to all trap patching extensions, hardware drivers and even vendor supplied Palm OS extension. Instead of calling SysSetTrapAddress, applications should register their trap routines with a central management application that keeps track of all patched traps and restores the function chains correctly. X-Master provides such a management application.