Linux – Why is Ubuntu trying to open the Mono app with Wine instead of Mono

file associationlinuxmono-framework

So, I have compiled a C# program on Linux using MonoDevelop. When I try to execute the resulting binary, my system tries and fails to run it as a windows executable, with wine. Wine gives me the following message:

$ ~/bin/MyMonoApp
wine: Install the Windows version of Mono to run .NET executables
~/bin/MyMonoApp: command not found

I can only convince it to run by explicitly calling mono:

$ mono ~/bin/MyMonoApp

So, how can I make this the default, so I don't have to explicitly call mono every time?

Best Answer

Execution of binaries in the Linux kernel is controlled via the binfmt_misc module (short for “miscellaneous binary formats”). The way it works is that the kernel looks at the first few bytes of the file and sees if there is a “magic number” that characterizes a known file format. The idea is that if the kernel sees the magic number of a .NET executable, it calls mono; if it sees the magic number of a jar (Java virtual machine binary), it calls a JRE; etc.

The problem with Mono and Wine is that the magic number is the same — a .NET executable is a Windows executable. If both formats are registered with binfmt_misc, whichever is registered last wins. Oops.

On a Debian-derived system, the magic number for Windows executables doesn't invoke wine or mono directly: it goes via a script that performs additional tests to decide which environment to use. The script in question was initially written for Debian; it could be used by other distributions (for instance Ubuntu has kept it).

Apparently your distribution (which one? you don't say!) doesn't use it. The first thing to check would be if some updates you haven't applied includes something similar. If you'd like to port the mechanism, here's where to find the bits; it's a small programming task. The script is /usr/share/binfmt-support/run-detectors in the binfmt-support package (you need the libraries in /usr/share/perl5/Binfmt as well); for mono, the detector is /usr/lib/cli/binfmt-detector-cli in the mono-common or mono-runtime package.

If your distribution has no special support, and you don't care about wine binaries, a more manual route would be easier. The binfmt_misc module is controlled via the /proc/sys/fs/binfmt_misc directory. You can register a format by writing to /proc/sys/fs/binfmt_misc/register; each file in this directory other than register and status represents a registered format. Be careful when writing to register: if you accidentally register a magic number that matches Linux native executables (ELF), you're likely to hose your system with no remedy other than rebooting. To unregister the wine format, echo -1 to /proc/sys/fs/binfmt_misc/wine. The binfmt_misc module is documented in Documentation/binfmt_misc.txt.gz in the Linux kernel documentation.

One solution to your problem would be to unregister the wine format; you'd have to do that after whichever boot script registers binary formats. An alternative solution is to figure out where in the boot process the wine format is registered and skip this part. A third solution is to find a way to distinguish .NET executables from other Windows executable and register the .NET magic number after the generic Windows magic number.

Related Question