Native Runtime Architecture
The binaries behind Director MX 2004 and Shockwave - Dirapi.dll, Iml32.dll, Proj.dll - plus the reverse-engineering methodology and evidence standards used in this section.
What this section is
The pages under Native Internals document original reverse-engineering research into the Director MX 2004 / Shockwave native runtime, conducted with Ghidra against the retail binaries. Where the manuals describe what an API does, these pages record how the engine actually implements it: symbol tables, property descriptors, dispatch routes, compositor callbacks, and presentation logic.
Function names are Ghidra-style addresses (FUN_680c8c3e = function at that virtual address in Dirapi.dll). They are stable identifiers for the analyzed binaries, not official names.
Evidence levels
Every claim in this section carries an implicit strength grade:
| Level | Meaning |
|---|---|
manual | Stated in official MX 2004 documentation. |
native table | Name/symbol/string table found in the binaries: proves a surface exists, not its behavior. |
native code | Decompiled implementation path: proves mechanics of that path. |
microtest | Verified against a real Director runtime with a fixture movie. |
implemented | Reproduced in an emulator and confirmed by test/screenshot. |
Rule of thumb: native code and microtests outrank guesses, other emulators' behavior, and AI review. A table slot proves a name exists; only tracing the consumer proves what it does.
The binaries
| Binary | Size (MX 2004) | Role |
|---|---|---|
Director.exe | 5.4 MB | Authoring app; contains authoring-side Lingo and API truth. |
Dirapi.dll | 1.5 MB | The core runtime: Lingo VM, symbol registry, property descriptors, score engine, event dispatch, sprite channels. |
Iml32.dll | 630 KB | Imaging/media layer: bitmap import, palettes, rects, windows (ImlWinCls), blitting, final compositor callbacks. |
Proj.dll | 151 KB | Projector shell: window creation, flag parsing, message loop, bridging to Dirapi ordinals. |
Shockwave 10 dirapiX.dll / iml32X.dll | 1.7 MB / 611 KB | The browser player's equivalents; closest comparison layer for Habbo-era (2000-2005) behavior. |
Shockwave 12 dirapi.dll / iml32.dll | 1.8 MB / 1.0 MB | Late players; useful for spotting changed semantics. |
*.x32 Xtras | varies | Native plugins (TextXtra, Multiusr, NetLingo, Sound Control...). |
Division of labor, as recovered:
Proj.dllparses projector settings, creates the stage window through IML32, and drives the runtime through a small set of Dirapi ordinals (idle pump, status readback, window rebinding).Dirapi.dllowns everything scripting-visible: the symbol/descriptor machinery (Native Lingo internals), channels and their dirty flags, event routes.Iml32.dllowns pixels and windows: rect helpers, DIB/palette Windows API usage, the final per-pixel compositor callback families (Native rendering).
Methodology
The workflow that produced these findings, reusable for further research:
- Define the question in Director terms (e.g. "what does ink 8 do to 4-bit sources?").
- String probe: locate API name strings and their addresses in the target binary.
- Table probe: follow references to those strings; Director API names sit in dense pointer tables, and the table neighborhood reveals the API family grouping.
- Decompile the consumers: never decompile a data table slot itself; find the code that reads the table and decompile that.
- Registry/descriptor dumps: for scripting symbols, decode the registrar call sites to get symbol ID -> descriptor pointer mappings (arguments often travel through callee-saved registers, so instruction-context dumps are the ground truth for missing immediates).
- Classify and trace: descriptor first-word distributions, branch classification in the shared executor, callback family mapping.
- Microtest: build a minimal fixture movie in real Director that exercises exactly one behavior, and log/compare.
Headless Ghidra automation ran each step; probe outputs (Markdown + JSON) are kept as evidence artifacts separate from conclusions, and conclusions link back to the artifact and address ranges.
Failure modes to avoid
Documented mistakes from this research, so others skip them:
- Treating a table slot as code: decompiling data produces garbage; failure to decompile does not mean "no behavior".
- Assuming neighboring names share a handler: table adjacency is organizational, not semantic.
- Treating a string reference as the implementation: the reference is usually a registry row; the implementation is behind a dispatcher.
- Trusting a fan emulator as ground truth: emulators encode their authors' guesses; verify against native code or a real runtime.
- Row number = symbol ID assumptions: Director's symbol interner reuses IDs for duplicate names, so table position and ID diverge after the first duplicate (details in Native Lingo internals).
- Changing runtime behavior in an emulator before the native owner is known: symptom-level patches (per-room, per-window offsets) always regress somewhere else.
Map of the findings
| Page | Covers |
|---|---|
| Native Lingo internals | Symbol bootstrap and interning, the 169-row API registry, descriptor record layout, the descriptor executor's branch families, emitted opcodes, native error codes. |
| Native rendering | The IML32 blit route, operation state, final compositor callback families (keyed copy, blends, arithmetic, color filter), matte/mask coverage streams, the sprite property to compositor bridge. |
| Native stage, input, and timing | Projector flags and ordinals, presentation rect recompute (CenterStage/ResizeStage), window rebinding and channel rebuild, the input pipeline contract, score/timing table surfaces. |