In the last part we talked about how the Zero Install Bootstrapper bundles a subset of Zero Install’s functionality into a single EXE in order to download a full version of Zero Install. Today we’ll have a look at how the Bootstrapper manages to be a GUI app and a command-line tool at the same time.
Most of Zero Install’s functionality is available in both a GUI and a command-line form. Windows executables declare their intended subsystem (e.g. graphical or command-line) in their PE metadata. This determines whether a console window is shown on startup. Therefore, Zero Install for Windows comes with 0install.exe
and 0install-win.exe
. Both take the same command-line arguments, but the first outputs to the command-line while the second displays a graphical progress bar, message boxes, etc.
The Bootstrapper, however, is a hybrid. It declares itself as using the graphical subsystem, preventing a console window from popping up when you double-click it. But when you launch the Bootstrapper from the command-line or within a batch script it detects its parent console and uses it for output instead of showing its own window. It does using the AttachConsole Win32 API.
Unfortunately, these hybrid EXEs behave slightly different than true command-line applications. When you execute a command like cmd.exe
checks whether this is a command-line command (built-in or external EXE) or a GUI executable. In the first case cmd.exe
runs the command and waits for it to complete before printing a new command-line prompt awaiting further input. In the latter case the executable runs asynchronously and the next command-line prompt is printed right away without waiting for the application to exit.
Since Windows assumes our hybrid EXE to be a GUI app it does not wait for the execution to complete. The EXE can detect the console window it was launched from and attach to it, but cmd.exe
has already printed the next prompt line and is waiting for input. What does this mean? cmd.exe
and the Bootstrapper are now running concurrently and competing for console input rather than one waiting for the other to complete. You might see a prompt printed by either cmd.exe
or the Bootstrapper but can’t be sure which of the two will receive any input you make.
The Bootstrapper is designed to perform most operations based on command-line arguments rather than requesting additional input at runtime to mitigate this issue. Once you enter your command and press ENTER
you either get prompted to rerun the command with additional arguments or to sit back and enjoy the fireworks. When using batch files the whole “two commands running at the same time” issue does not apply: cmd.exe
waits for both GUI and non-GUI commands to complete before executing the next command when executing a .bat
or .cmd
script.