Part 1 — the Old School Launcher

The usual way to work around the no-targetengine-in-jsxbin rule is to use a separate ‘launcher’ written in human-readable JavaScript. The JS launcher creates the persistent engine (#targetengine 'myScriptSession'), then it loads and runs the encrypted jsxbin file through app.doScript(File(jsxBinFilePath)). Beforehand, you must make sure that the jsxbin file exists at the desired location. (And of course you have to distribute two files.)

Note. — The separate launcher approach is demonstrated in a technical document provided by Adobe: “Feature Development with Scripting” (PDF). It does not work in CS3. Prior to CS4, any script loaded via doScript was executed in the main engine —unless it contained a #targetengine directive,— so it was not possible to load a binary script in a specific engine using doScript. The solution then was to pass the entire script within a string and to invoke eval. . . Alas, it's well known by JavaScript gurus that “eval is evil.”

Part 2 - the Bastard Pop Launcher

What Adobe did not tell us, though, is that a jsxbin file is nothing but a serialized ASCII string that we can directly pass to doScript! Well, almost.

Let's study a stupid JavaScript:

var msg = "Hello, World!";
try {
    app.selection[0].contents = msg;
    }
catch(_)
    {
    alert( msg );
    }
 

Now, paste the JS in ESTK and export it as binary. You get something like this:

What a simple script looks like in jsxbin format.

The only important thing to note is that the encrypted string contains line breaks. OK, this can be annoying if we intend to use such a string as a literal within a script. But what Adobe did not say either is that the jsxbin line breaks are optional.

Then, open the jsxbin file in your favorite text editor and remove all the line breaks. (Use find/replace on ^p, \n, and/or \r, depending on your application.)

Finally, create a simple JS file and try this:

//-----------------------------
// 'Bastard Pop' JSXBIN Launcher
//-----------------------------
 
// 1. Create your persistent engine (if needed)
#targetengine 'MySessionScript'
 
// 2. Paste the jsxbin code as a literal string in doScript
app.doScript("@JSXBIN@ES@2.0@MyBbyBn0ACJAnASzDjNjTjHByBneNiIjFjMjMjPhMhAiXjPjSjMjEhBftgBbyBn0ABJCnABXzIjDjPjOjUjFjOjUjTCfXzBhQDfXzJjTjFjMjFjDjUjJjPjOEfjzDjBjQjQFfVBfyBnfABnzBifGnbyBn0ABJGnAEjzFjBjMjFjSjUHfRBVBfyBffABB40BiAABAzAIByB");
 

The #targetengine directive and the jsxbin code are now mixed in a single file, and the inner code is actually executed in the specified engine!

(Works in InDesign CS4 and CS5. In CS3, you can still use eval on a binary string, it works too —preserving the session engine!)

• See also: “Can InDesign Script Rewrite Itself”