Two earlier reports left the problem of driving an arbitrary front application’s menus unresolved. The journaling driver reaches only the daemon’s own menus, because MenuSelect uses the calling process’s menu list. The jGNE filter could read a foreign application’s menu structure but crashed the host when used to drive one. This report closes the problem with the third mechanism the literature pointed to — a global MenuSelect trap patch installed at startup from a system extension — and records two findings that the closing required: that a patch installed by a running application is process-local, and that a trap patch’s presence must be verified by scanning memory rather than by reading the trap vector.

The mechanism

MenuSelect is a Toolbox trap. Patching it replaces the routine every application calls when a menu-bar mouse-down arrives. The patch here is a head patch with two behaviours, chosen per call by a flag a controller sets. Disarmed, it is transparent: it jumps to the saved original routine with the stack frame untouched, so ordinary menu tracking proceeds unchanged. Armed with a target menu and item, it does not enter the tracking loop at all — it writes that result into the caller’s Pascal return slot and returns immediately. The calling application then dispatches the chosen command itself, exactly as if the user had pulled the menu down and released on the item.

This is the property the earlier approaches lacked. The journaling driver can feed a synthesized mouse path into a tracking loop, but only in the process that owns the loop. The jGNE drive attempt injected a menu-bar event and armed playback, which made a background daemon perform a window reorder that tripped an illegal-instruction fault in the host’s window manager. The trap patch avoids both traps: there is no journal, no injected tracking, and no window activity — the front application, already frontmost, simply receives a menu result and acts on it.

A patch installed by an application is process-local

The first finding emerged from trying to install the patch from the running daemon rather than at boot. The install succeeded and persisted, and the daemon’s own calls to MenuSelect were intercepted correctly. The front application’s calls were not. A menu-bar click that demonstrably reached the Finder — it entered the real tracking loop and starved the background daemon — never passed through the patch.

The behaviour is precisely what Inside Macintosh describes. A patch installed into an application’s heap applies only to that application; a patch installed from a system extension during startup is placed in the system heap and applies to every application. The daemon, however resident, is still an application, and its trap patch is local to it. A second, independent obstacle reinforced the same conclusion: the MPW tool server snapshots and restores the trap dispatch table around each tool it runs, so a patch made by a command-line tool is silently reverted the moment the tool exits. Only a patch installed at boot, before the applications it must serve are launched, is both global and durable. The system extension was therefore not the tidy deliverable form of the mechanism — it was a requirement.

Verify by scanning, not by reading the trap

The extension was built as a self-contained startup INIT: it embeds the patch bytes and, when the system runs it at boot, copies them into the system heap and points the MenuSelect trap at the copy. It was modelled byte-for-byte on an existing, known-good extension in the same project, down to the resource identifier and the system-heap and locked attributes.

After the first boot with the extension in place, the obvious check — does the MenuSelect trap now point at our patch? — reported that it did not. Read literally, that said the extension had not run. It had. MenuSelect is a heavily contended trap: the system itself patches it, and other extensions that load later patch it again, each chaining to the previous routine. Our patch had been installed at boot and then displaced from the head of the chain by a later patch that now sits above it. Reading the trap vector returns only the topmost patch, so a head comparison cannot see a patch that has been chained over.

Scanning the system heap for the patch’s own signature found it immediately, resident and intact, with its saved link to the routine it had chained onto. The lesson generalises: the presence of a trap patch must be established by finding the patch in memory, not by asking the trap manager for the current head. The contrast with the reference extension is instructive. That one patches a quiet trap nobody else touches, and its effect — an indicator drawn in the menu bar — is directly visible; it appears to work because you can see it and because it remains the head. The two extensions are built by identical machinery. Only the method of verifying them differed, and the difference was entirely an artifact of the trap’s contention.

The title image shows the scan and the resulting interception, read back live over the bridge from the daemon’s own monitor window: a hit at address 412C (the patch is resident, so the boot extension ran), two calls and two interceptions with the last returned value 03780005 — the menu and item that had been armed — and a report that the current trap head belongs to a later patch, confirming that our patch is chained rather than absent.

flowchart TD
  A["front app calls MenuSelect"] --> B["later patch (chain head)"]
  B --> C["our boot-INIT patch (armed?)"]
  C -->|armed| D["return target menuID+item, no tracking"]
  C -->|disarmed| E["chain to real MenuSelect (tracks normally)"]
  D --> F["app dispatches the chosen command"]
  G["verify presence: scan heap for the patch — NOT the trap head"] -.-> C

The result

With the patch located, the test was direct. A controller armed the resident block with a chosen menu and item, brought the Finder to the front, and pressed one of its menu titles. The block’s counters advanced — one call, one interception — and it recorded the exact value that had been armed. A foreign front application’s MenuSelect had been intercepted and made to return an injected menu selection, with no tracking loop entered and the background daemon remaining responsive throughout. The emulator did not fault; it ran without error for the duration of the exercise and well beyond.

This is the capability the two earlier mechanisms could not provide. Journaling drives only the daemon’s own menus. The jGNE filter reads a foreign application’s menus safely but cannot drive them without crashing the host. The startup trap patch drives them, and does so stably, because it removes rather than adds the two things that made the alternatives fragile: the mouse-tracking loop and any perturbation of window ordering.

Where it stands

The patch, the boot extension, the command-line harness that verified each stage, and the controller verbs are all in place and exercised live. Two refinements remain. The controller should locate the resident patch by scanning for its signature — the same technique that diagnosed the head-of-chain displacement — so that arming it does not depend on the patch being the current trap head. And the whole path deserves a single high-level tool call, so that selecting a named menu item in the front application becomes one instruction rather than a sequence of low-level steps. Neither is a research question; both are finishing work on a mechanism that is now demonstrated.