Blog › ICP guides

Lingo developer on retainer: FileIO Xtra exclusive lock, Macromedia Director developer, Adobe Director developer on monthly retainer

October 9, 2026 · ~15 min read

A Lingo developer was maintaining an interactive visitor kiosk application built in Adobe Director 12 for a natural history museum. The museum operated four self-service kiosk stations on the exhibit floor; each station ran a standalone Director projector (.exe) that let visitors browse exhibit information and take a short quiz. A Lingo handler in the closing screen recorded each visitor’s interaction data to a shared log file on the museum’s server: it used the FileIO Xtra to call fileioObj.openFile("//server/kiosk/logs/visitor_log.txt", 2) (mode 2 = write/append), then fileioObj.writeString(sStationID & "," & sVisitorID & "," & sQuizScore & "," & the systemDate), then fileioObj.closeFile(). The developer had tested the kiosk application with one station at a time and confirmed it recorded every visit correctly. During a busy Saturday afternoon, two visitors on adjacent kiosk stations completed the quiz within the same half-second window. The second station’s fileioObj.openFile received a FileIO Xtra error: “File already open” (the first station held an exclusive OS file lock during its write window). The Lingo on error handler in the projector was not configured to log or display FileIO errors; the error was silently discarded. The second visitor’s interaction record was never written. The museum’s weekly visitor analytics report showed 4 fewer records than the turnstile count for that Saturday afternoon. Silent interaction records lost per busy shift: 4 → 0 after rewriting the handler to use per-station log files consolidated server-side.

The root cause was the FileIO Xtra’s openFile method opening the shared log file in exclusive mode by default. Director’s built-in FileIO Xtra, when openFile is called with mode 1 (read) or mode 2 (write/append), uses the Windows CreateFile API with dwShareMode = 0 — exclusive access, allowing no other process to open the file while the first caller holds it open. On a single kiosk station this is never a problem: only one Director projector session runs at a time, and the openFile → writeString → closeFile sequence completes in a few milliseconds. Across four simultaneous kiosk stations writing to the same shared log file, the probability of two stations attempting openFile within the same window scales with visitor throughput. During a busy afternoon at 40 visitors per hour across 4 stations, the expected collision rate is approximately one per hour — enough to produce measurable discrepancies in analytics without ever generating a visible error on screen. The FileIO Xtra reports the error as a non-zero return value from openFile; if the Lingo handler does not check that return value or does not have an on error handler that catches it, the writeString call is silently skipped (it writes to a nil file object), the closeFile call completes without effect, and the handler returns normally. Fix: replace the shared log file with per-station files (visitor_log_station1.txt, visitor_log_station2.txt, etc.); a server-side batch script consolidates the per-station files nightly. Each station writes only to its own file; no two stations ever contend for the same file.

Director’s FileIO Xtra exposes file I/O operations as a Lingo object interface. The Xtra is instantiated with set fileioObj = new(xtra "FileIO"); the instance is then used to call file operations. openFile(path, mode) opens a file: mode 0 = read/write, mode 1 = read only, mode 2 = write (creates if not present, appends if already present). writeString(str) writes a string to the open file without a newline. writeLine(str) writes a string followed by a platform-appropriate newline. readLine() reads a line. readChar() reads a single character. closeFile() closes the file and releases the OS file lock. getFinderInfo() returns file metadata on macOS. The FileIO Xtra’s status() method returns a numeric error code: 0 for success, non-zero for failure. Common FileIO Xtra error codes: -37 is “Bad filename” (filename or path contains invalid characters); -36 is “I/O error” (network path unavailable or disk error); -43 is “File not found”; the “File already open” error surfaces as a non-zero status corresponding to Windows OS error 32 (sharing violation). A defensive Lingo handler checks fileioObj.status() immediately after openFile before proceeding to writeString; if the status is non-zero, the handler logs the error to a fallback mechanism (a per-station error log, or a Director Lingo put statement to the message window) and exits without writing a corrupt or partial record.

Director’s history spans three corporate owners and nearly three decades of multimedia authoring. Macromedia Corporation released Director 1.0 in 1993 as VideoWorks, positioning it as the professional tool for CD-ROM interactive multimedia. Director’s authoring paradigm centers on the Score: a timeline where sprites (instances of cast members) are placed in channels across frames. The Score is the visual timeline; Lingo is the scripting layer that adds interactivity, file I/O, network access, and data logic. A Director movie (.dir source, .dxr protected, .dcr Shockwave compressed) contains the Score, the Cast library (all media assets), and all Lingo scripts. Director movies are deployed as standalone projectors (.exe on Windows, .app on macOS) that bundle the Director runtime with the movie file; or as Shockwave content (.dcr) delivered via the Shockwave browser plugin for web playback. Macromedia also offered the Director Runtime (a non-authoring runtime installer) for corporate network deployments where the authoring application was not needed on playback machines.

Macromedia Director, Lingo, and the Xtra plugin architecture

Lingo is a dynamically typed, object-based scripting language designed for event-driven multimedia programming. Lingo handlers are defined with the on handlerName syntax and respond to Director events: on mouseUp fires when a mouse button is released; on enterFrame fires when the playback head enters a frame; on exitFrame fires when it exits; on startMovie fires when the movie begins playback; on stopMovie fires on exit. Score scripts are attached to sprite channels in the Score and fire for the frames where the sprite is present. Behavior scripts (introduced in Director 6) are reusable script cast members that can be attached to sprites or frames via drag-and-drop, accepting parameter values per instance. Movie scripts are global handler libraries that respond to movie-level events. Parent scripts define Lingo classes (ancestor objects), instantiated with new(script "ClassName"). Lingo’s property management uses the property of object syntax (e.g., the locH of sprite 3, the text of member "Title"); direct property access was added in Director MX as sprite(3).locH and member("Title").text.

Xtras are Director’s plugin architecture: shared libraries (.x32 on Windows, .xtra on macOS) that extend Director’s built-in capabilities. Xtra types include: Lingo Xtras (expose new Lingo objects and commands, such as FileIO, NetLingo, and Flash Asset); Sprite Xtras (add new sprite types, such as Flash Asset and QuickTime Asset); Tool Xtras (add authoring environment tools); and Transition Xtras (add custom scene transitions). The FileIO Xtra is a built-in Lingo Xtra included with all Director versions since Director 4; it provides cross-platform file I/O via a consistent Lingo object interface regardless of whether the underlying OS is Windows or macOS. Other commonly used Xtras in production Director deployments: NetLingo (HTTP network access, included since Director 7); MUI Xtra (Windows native dialog boxes for file open/save, message boxes, and progress dialogs); V12 Database Xtra (ODBC-based database connectivity to Access, SQL Server, or Oracle from Lingo — a commercial Xtra widely used in kiosk and training deployments as a more robust alternative to FileIO flat-file logging). Director 11.5 and 12.0 added built-in HTML5 canvas export capabilities through the Director HTML5 Canvas feature, but Xtra-dependent movies (those using V12 Database or custom third-party Xtras) could not be exported automatically.

Adobe acquired Macromedia in December 2005, inheriting Director alongside Flash, Dreamweaver, and ColdFusion. Adobe released Director 11.0 (2008), 11.5 (2010), and 12.0 (2013) with improved 3D rendering, enhanced ActionScript-to-Lingo interop, and 64-bit macOS support. Adobe discontinued Shockwave Player in April 2019 (citing security concerns and declining browser plugin support) and ceased active Director development simultaneously. Director 12.0 remains the final shipping version. The consequence for retainer developers: museums, science centers, corporate training departments, and government agencies that deployed Director projectors in the 2000s and early 2010s continue running those projectors on Windows 7, Windows 10, and (with compatibility shims) Windows 11 kiosk machines, but have no path to Director authoring support from Adobe. Third-party Xtras that relied on 32-bit Windows DLL architecture (“x32” Xtras) require 32-bit Director projectors running under the 32-bit WOW64 subsystem on 64-bit Windows; many corporate IT policies require explicit exception approval for 32-bit application deployment. Director 12.0’s .exe projectors are 32-bit on Windows; they run under WOW64 on Windows 10 and 11 without modification, but access to the system file paths used in openFile calls may require adjustments for UAC virtualization and UNC path accessibility from 32-bit processes.

Typical Lingo developer retainer work and what it looks like in a work log

FileIO Xtra exclusive lock collision on shared network log file is the canonical Lingo invisible production kiosk deployment bug. The pattern is consistent: a Lingo handler in the projector’s closing-screen on mouseUp or frame on exitFrame handler calls fileioObj.openFile("//server/kiosk/logs/visitor_log.txt", 2); fileioObj.writeLine(sStationID & "," & sVisitorID & "," & sQuizScore); fileioObj.closeFile(). The developer tests with one kiosk station — no collision possible. In production, four stations run concurrently; two visitors complete the quiz within the same half-second; the second station’s openFile returns a non-zero status (OS error 32 sharing violation); if the handler does not check fileioObj.status() after openFile, the subsequent writeLine is a no-op on a nil file object; closeFile completes without error; the handler exits normally; the interaction record is never written. The museum’s analytics report shows fewer records than expected. Fix: per-station files (visitor_log_station1.txt, visitor_log_station2.txt); a server-side batch script consolidates nightly. Silent interaction records lost per busy shift: 4 → 0. Work log: “Museum kiosk VisitorInteractions.dir; closing-screen on mouseUp handler; openFile("//server/kiosk/logs/visitor_log.txt", 2) exclusive OS lock; 4 concurrent kiosk stations; second concurrent station receives FileIO error (OS error 32 sharing violation); interaction record silently lost; fix: per-station log files (visitor_log_stationID.txt); server-side nightly batch consolidation; silent losses: 4 per busy shift → 0; 2h.”

Director projector load time degradation from over-embedded Cast library is the second most common Lingo retainer pattern in long-running kiosk deployments. A Director 12 movie for a museum’s exhibit floor kiosk has grown over several years to include 600 cast members: every exhibit photograph was imported directly into the Cast library as an embedded bitmap, and every audio narration clip was embedded as an uncompressed WAV file. The .dir source file has reached 340 MB. The Director projector (.exe) bundles the entire movie; when the kiosk station restarts and the projector launches, Director loads the full Cast library into memory before the first frame displays — on the museum’s aging kiosk hardware, loading 340 MB from a network-mapped drive takes 60–90 seconds. Visitors who approach the kiosk during startup see a blank screen. Fix: re-export all embedded bitmaps as externally linked JPEG files (referenced via member("PhotoName").fileName = "//server/kiosk/media/photo001.jpg"); re-export all embedded WAV audio as externally linked MP3 files. The Cast library now contains only script members and a minimal set of UI graphics; the projector shrinks to 8 MB; startup time drops to 4–6 seconds from network. External cast members are loaded on demand (only when the sprite referencing that member enters the visible Score channel). Work log: “Museum kiosk ExhibitBrowser.dir; 340 MB embedded bitmaps + WAV audio; 600 cast members; projector load time 60–90s on network; extracted bitmaps to //server/kiosk/media/*.jpg (linked via member.fileName); WAV to //server/kiosk/audio/*.mp3; .dir Cast library reduced to 8 MB; load time 4–6s; 3h.”

Lingo sprite channel collision from puppetSprite not released is the third common Lingo retainer pattern in interactive quiz applications. A Lingo behavior script uses puppetSprite 5, TRUE to take manual control of sprite channel 5 for an animated feedback sequence; the behavior’s on exitFrame handler moves the sprite, changes its color, and plays a sound. When the feedback sequence completes, the behavior calls go to frame "Menu" to return to the main menu. The developer does not call puppetSprite 5, FALSE before branching away. At the Menu frame, Director’s Score no longer has a sprite in channel 5 at that frame — but the channel remains puppeted (Lingo still controls it, overriding the Score). The sprite from the previous feedback screen remains visible on the Menu screen, overlaid on top of the menu buttons. Clicking that area fires mouse events for the invisible puppeted sprite, not for the menu button underneath. Fix: add puppetSprite 5, FALSE in the behavior’s on stopBehavior handler (fired when the sprite leaves the Stage). Phantom sprite visible on menu: 1 → 0. Work log: “MuseumQuiz.dir; QuizFeedback behavior script on sprite 5; puppetSprite 5, TRUE not released before go to frame “Menu”; sprite channel 5 remains puppeted at Menu frame; phantom sprite visible; menu button clicks intercepted; fix: puppetSprite 5, FALSE in on stopBehavior; phantom: 1 → 0; 1h.”

Track Lingo developer retainer hours without the status emails

When a 2-hour investigation traces 4 silent interaction record losses per busy museum shift to Director’s FileIO Xtra opening a shared network log file in exclusive mode — four concurrent kiosk stations; second-concurrent station’s openFile receives OS error 32 sharing violation; record silently lost; fix: per-station files eliminate all collision risk — the work log must name the projector, the handler, the openFile path, the concurrent station count, and the records lost and recovered. HourTab gives your Lingo retainer client a public dashboard URL they can bookmark: hours used, hours remaining, and a work log naming the per-station-file fix. No client login. No status emails. CSV in, URL out.

See HourTab pricing →

How HourTab tracks Lingo developer retainer hours

Lingo FileIO Xtra exclusive lock bugs are invisible by the same mechanism that makes them impossible to reproduce in single-station development testing: the openFile call succeeds every time when only one Director projector session runs; the writeLine writes the record correctly; the closeFile releases the OS file lock; the Lingo handler completes without error; the kiosk displays the correct feedback screen. The interaction record appears in the log file. The developer confirms the feature works and moves on. The only evidence of the problem surfaces in post-deployment analytics audits when a multi-station kiosk deployment produces fewer log records than visitor turnstile counts — with no visible error on the kiosk screen, no feedback to the visitor, and no Director error log entry (because the unhandled openFile error is silently discarded by Director’s default error behavior). Diagnosing the problem requires correlating the kiosk station activity timestamps (from the partial log records that did write successfully) against the turnstile count, identifying the time windows where two stations completed simultaneously, and then tracing the Lingo handler to confirm the unguarded openFile call.

The work log must name the mechanism to be auditable: which Director movie file (VisitorInteractions.dir), which Lingo handler (closing-screen on mouseUp handler on sprite 3), the openFile path (//server/kiosk/logs/visitor_log.txt), the open mode (mode 2, write/append, exclusive OS lock), the concurrent station count (4 stations), the collision window (same half-second when two visitors complete simultaneously), the interaction records lost per busy shift before fix (4 silent losses), the records lost after fix (0), and the fix (per-station files: visitor_log_stationID.txt; server-side nightly consolidation batch). A log entry that says “fixed logging issue on kiosk, 2h” is not auditable. A log entry that names the movie, the handler, the openFile path, the OS error 32 sharing violation, the silent data loss mechanism, and the per-station-file fix is auditable and defensible to the museum’s analytics team. HourTab gives Lingo developers a public retainer-hours URL they send to clients — museums, science centers, government agencies, corporate training departments, and theme park operators that built interactive kiosk and training applications in Macromedia and Adobe Director in the 1990s and 2000s, maintained today by the original Lingo developer or a successor retainer consultant.

Comparative context: Lingo FileIO Xtra exclusive lock bugs are structurally identical to exclusive-lock patterns in other legacy courseware and interactive deployment environments where the platform’s default file I/O acquires a lock wider than necessary. ToolBook retainers cover the same OpenScript FileOpen exclusive Windows OS file lock pattern — same shared network log file, same concurrent session collision, same silent data loss in group deployments. Authorware retainers cover ADODB.Connection leak from external DLL calls in courseware — a related invisible pattern where the resource is a database connection rather than a file handle, but the root cause is the same: a resource opened for a brief write is not explicitly released, and concurrent sessions exhaust the available resource pool. WinDev retainers cover HFSQL HLock file-system lock not released on failure branch — the same OS file-system lock class where a held exclusive lock blocks concurrent sessions until explicitly released.

FAQ: Lingo developer retainers

What does a Lingo developer on retainer typically do?

A Lingo developer on monthly retainer covers FileIO Xtra exclusive lock audits (reviewing every Lingo handler that calls openFile on a shared network path for concurrent-access safety); FileIO error “File already open” diagnosis (correlating Director error logs and kiosk station timestamps to identify the collision point); Director movie file size optimization (extracting embedded bitmaps and audio to externally linked files to reduce projector load time); Lingo sprite behavior and score scripting audits for interactive kiosk applications; Director projector packaging and Windows deployment support; Xtra plugin compatibility validation for Windows 10 and 11 kiosk environments; and Shockwave-to-HTML5 migration planning for browser-embedded Director content reaching end-of-life.

What Lingo kiosk deployment bug work is most commonly underlogged?

FileIO Xtra exclusive lock collisions on shared network log files — where Director’s FileIO Xtra openFile acquires an exclusive OS file lock, causing a “File already open” error when two concurrent kiosk stations attempt openFile within the same brief window — are the most systematically underlogged Lingo retainer work. The developer who tests with one station at a time never observes the collision; Director silently discards the unhandled FileIO error; the silent interaction record loss surfaces only during post-deployment analytics audits. The work log must name the Director movie file, the Lingo handler, the openFile path, the concurrent station count, and the interaction records lost per session before and after the fix.

What are typical Lingo developer retainer rates?

Entry-level Lingo developers with experience in Director score scripting, basic Lingo handler syntax (on mouseUp, on exitFrame, on startMovie), and cast member management typically bill at $55 to $95 per hour. Mid-level Lingo developers with experience in FileIO Xtra file I/O, Director projector packaging and deployment, Xtra plugin management, and Lingo list operations typically bill at $80 to $150 per hour. Senior Lingo developers with deep knowledge of Director 11.0/11.5/12.0, Shockwave web delivery, MIAW architecture, parent scripts and child objects, Xtra API development, and production forensics on museum kiosk and corporate training deployments typically bill at $120 to $210 per hour. Monthly retainer ranges: $1,200 to $2,500 per month for advisory engagements; $2,000 to $4,000 per month for active kiosk maintenance.

What should a Lingo developer retainer agreement include?

A Lingo developer retainer agreement should specify: Director version (Director MX 2004, Director 11.0, 11.5, or 12.0); deployment model (standalone projector .exe, Shockwave .dcr browser plugin, or Director runtime on a network kiosk drive); whether the retainer developer has access to Director authoring environment source (.dir files — required to edit Lingo handlers and recompile the projector); whether the retainer covers FileIO Xtra shared network log file patterns; concurrent station count (determines whether FileIO collision risk analysis is in scope); Xtra plugin compatibility on current Windows versions; and whether the retainer covers Shockwave-to-HTML5 migration planning.

How should Lingo developer retainer hours be logged?

Log each Lingo retainer session with the Director movie file, the Lingo handler, the FileIO path, and the concurrent station outcome. For FileIO exclusive lock: movie file (VisitorInteractions.dir), handler (on mouseUp on closing-screen sprite), openFile path (//server/kiosk/logs/visitor_log.txt, mode 2), concurrent station count (4), interaction records lost per busy shift before fix (4 silent losses), records lost after fix (0), fix (per-station files: visitor_log_stationID.txt; server-side nightly batch), hours (2h). For Cast library performance: movie file, original size (340 MB), embedded cast members, fix (externally linked JPEG + MP3 files), reduced size (8 MB), projector load time before and after (60s to 4s), hours (3h). For puppetSprite not released: movie file, handler, fix (puppetSprite N, FALSE in on stopBehavior), phantom sprite eliminated, hours (1h).