How to Run a Windows Executable from Wsl (Ubuntu) Bash

How can I run a Windows executable from WSL (Ubuntu) Bash


Native solution

The official solution provided with Windows 10 Insider Preview Update (14951) is based on the almost forgotten binfmt_msc Linux facility for launching binaries. The registration command for the binfmt_misc would be like this (where /init is the provisional binfmt_misc "interpreter" for the win-executables):

sudo echo ":WSLInterop:M::MZ::/init:" > /proc/sys/fs/binfmt_misc/register

And then win-executable would be launched like regular programs:

$ export PATH=$PATH:/mnt/c/Windows/System32
$ notepad.exe
$ ipconfig.exe | grep IPv4 | cut -d: -f2
$ ls -la | findstr.exe foo.txt
$ cmd.exe /c dir

Not that any win-executable must reside in the windows (DrvFs) file-system - not on the Linux's file-system (VolFs) - in order to inherit a proper Windows working-directory.

The cbwin alternative

Untill you get the latest build, project cbwin offers a workaround, by installing 3 new linux commands inside WSL:

  • wcmd: call a win-executable through cmd.exe.
  • wrun: call a win-executable synchronously with CreateProcess, and wait to die (not using cmd.exe).
  • wstart: launch a detached (asynchronously) command (with the use of cmd.exe).

In order to use them, you must:

  1. Install cbwin:

    • a new outbash.exe will be installed in your regular Windows filesystem (somewhere in your %PATH%), plus
    • the 3 linux-commands in the WSL filesystem.
  2. Use this outbash.exe (wherever you installed it) to start WSL, NOT C:\Windows\System32\bash.exe!
  3. Prefix any win-executables with one of those commands, e.g. wrun notepad.

Tip: If the executable launched with wcmd or wrun spawns any children, these survive only for as long that executable remains alive.

In other words, trying to start notepad.exe with wcmd won't work, because notepad will be killed just after having been launched -- Use wrun (synchronously) or wstart (asynchronously) in this case.

Why is Windows Subsystem for Linux able to run Windows *.exe programs?


How is WSL2 able to run Windows executables?

The Windows executable (PE binary) is added as a binfmt_misc entry in WSL2.
In simple words, binfmt_misc is a Linux kernel feature which allows
arbitrary executable file formats to be recognized and passed to certain programs.

In WSL2, the init binary (from which every process is forked) register the
Windows PE binary as a executable and make it executable by itself (i.e. the init).
Here is a output of the PE binfmt entry:

cat /proc/sys/fs/binfmt_misc/WSLInterop
enabled
interpreter /tools/init
flags: F
offset 0
magic 4d5a

WSLInterop is just a name for the entry. The magic number 4d5a is MZ which
is first two bytes of Windows PE executable. Assume this is a fingerprint with
which init (the interpreter) recognizes PE binary.

Users can disable the registry with this command:

echo 0 | sudo tee /proc/sys/fs/binfmt_misc/WSLInterop

Further readings:

  • Windows Subsystem for Linux interoperability with Windows
  • Wikipedia: binfmt_misc
  • Kernel Support for miscellaneous (your favourite) Binary Formats v1.1

Run windows apps (like VSCode) in wsl

Personally i find WSL awesome (Im using WSL 1), it integrates really well with windows 10 and ubuntu. I spend most of my day in there.

I have set up alias to a few windows applications that i use a lot. Inside your ~/.bashrc or ~/.zshrc you need to add something like these to the top:

alias webstorm="/mnt/c/Program\ Files/JetBrains/WebStorm/bin/webstorm64.exe"
alias subl="/mnt/c/Program\ Files/Sublime\ Text\ 3/subl.exe"
alias chrome="/mnt/c/Program\ Files\ \(x86\)/Google/Chrome/Application/chrome.exe"

Following this pattern vs code would be something like:

alias code="/mnt/c/Program\ Files/Microsoft\ VS\ Code/Code.exe" 

OR

alias code="/mnt/c/Users/damo/AppData/Local/Programs/Microsoft\ VS Code/bin/code.exe

Depending on your install location. Check your alias with alias from within wsl.

The alternative is to ensure that your path contains the directory of the application in question. Check your path with echo $PATH

But when i installed VS code it actually put itself in the WSL path, have you tried just typing code . does that not open vs code in your current location?

Can't launch exe file from WSL2

Did you try this ?

 ./testFlatScan.exe 

WSL run linux from windows without spawning a cmd-window

Here's a simpler solution, which, however, requires a WSH-based helper script, runHidden.vbs (see bottom section):

wscript .\runHidden.vbs bash -c "DISPLAY=:0 xmessage 'hello, world'"

To apply @davv's own launch-in-background technique to avoid creating a new bash instance every time:

One-time action (e.g., at boot time): launch a hidden, stay-open bash window. This spawns 2 bash processes: the Windows bash.exe process that owns the console window, and the WSL bash process (owned by the WSL init singleton), which is then available for servicing background commands.

wscript .\runHidden.vbs bash # hidden helper instance for servicing background commands

For every X Window-launching command: Terminate each command with & to have it be run by the hidden WSL bash instance asynchronously, without keeping the invoking bash instance alive:

wscript .\runHidden.vbs bash -c "DISPLAY=:0 xmessage 'hello, world' &"


runHidden.vbs source code:

' Simple command-line help.
select case WScript.Arguments(0)
case "-?", "/?", "-h", "--help"
WScript.echo "Usage: runHidden executable [...]" & vbNewLine & vbNewLine & "Runs the specified command hidden (without a visible window)."
WScript.Quit(0)
end select

' Separate the arguments into the executable name
' and a single string containing all arguments.
exe = WScript.Arguments(0)
sep = ""
for i = 1 to WScript.Arguments.Count -1
' Enclose arguments in "..." to preserve their original partitioning, if necessary.
if Instr(WScript.Arguments(i), " ") > 0 then
args = args & sep & """" & WScript.Arguments(i) & """"
else
args = args & sep & WScript.Arguments(i)
end if
sep = " "
next

' Execute the command with its window *hidden* (0)
WScript.CreateObject("Shell.Application").ShellExecute exe, args, "", "open", 0

Even when launched from a GUI app (such as via the Run dialog invoked with Win+R), this will not show a console window.

If your system is configured to execute .vbs scripts with wscript.exe by default (wscript //h:wscript /s, which, I think, is the default configuration), you can invoke runHidden.vbs directly, and if you put it in your %PATH%, by filename (root) only: runHidden ....

Note that use of the script is not limited to console applications: even GUI applications can be run hidden with it.



Related Topics



Leave a reply



Submit