試験運用中なLinux備忘録・旧記事

はてなダイアリーで公開していた2007年5月-2015年3月の記事を保存しています。

.exeファイル(Windows用とMono/.NET用)の識別と関連付けについて

NautilusなどのGUIファイルマネージャやbinfmt_misc(関連記事)ではファイルの種類に応じてそれを開いたときに、関連付けられたアプリケーションに引数としてそのファイルを渡すことができる。しかし、.exeファイルの場合

複数の可能性があるため、直接どちらかに関連付けをしてしまうともう片方では使えない。

fileコマンドでWindows向け実行ファイルとMono/.NETアセンブリを識別可能

ファイルを識別するfileコマンドはファイル先頭にある種類ごとに固有の文字列「マジック」で大まかなファイルの識別をするだけでなく、種類によっては更に深い情報を調べて表示してくれる。
幸いなことに、バージョン4.26の時点のfileコマンドでは、Windows向けの実行ファイルとMono/.NETアセンブリとを識別してくれる。

(Windows向けの実行ファイル)
$ file [.exeファイルの場所]
[.exeファイルの場所]: PE32 executable for MS Windows (GUI) Intel 80386 32-bit
(Mono/.NETアセンブリ)
$ file [.exeファイルの場所]
[.exeファイルの場所]: PE32 executable for MS Windows (console) Intel 80386 32-bit Mono/.Net assembly

種類によって処理を振り分ける

コマンドの出力という形でどちらの形式かが得られるということから、下のようなシェルスクリプトを作成してこれに関連付けを行うことにより、種類に応じたアプリケーション(WineMono)で.exeファイルを開くということが可能になる。
下のコードを使用するにはfileコマンドを使用するのでこれがパッケージ(「file」というパッケージ名が多い)としてインストールされている必要がある。なお、このコードはCC0のもとで公開する。
[任意]ファイル名: exehandler ライセンス:CC0

#! /bin/bash
PATH=/bin:/usr/bin
IFS=
FILE="$(file "${1}")"
[[ "${FILE:${#FILE}-18}" = "Mono/.Net assembly" ]] && CMD=mono || CMD=wine
${CMD} ${@}

fileコマンドでMono/.NETアセンブリを渡したときに出力の最後に出る文字列が「Mono/.Net assembly」であるという前提なので、今後この表記が変われば4行目をそれに合わせて修正する必要が出てくる。「18」の部分はその文字列長となるため、長さが変わったりした場合はそこも変更することになる。
なお、「Windows用の.NET FrameworkWineにインストールしてMonoは使わない」ということもできなくはないかもしれないが、Windowsの機能を呼び出している.NETアプリケーションに対して使用するのを除いておすすめはできない。
下はNautilusに関連付ける例*1。場所は実際の配置場所に合わせる。画像では/usr/local/bin/以下に(管理者権限で)保存した場合となる。

binfmt_miscでの使い方としては

(管理者権限のシェル上)
# echo ':EXE:M::MZ::/usr/local/bin/exehandler:' > /proc/sys/fs/binfmt_misc/register
(一般ユーザでsudoを使用)
$ sudo sh -c "echo ':EXE:M::MZ::/usr/local/bin/exehandler:' > /proc/sys/fs/binfmt_misc/register"

のようになる。こちらもexehandlerの場所は実際の配置場所に合わせる。
C#のテストを兼ねた静的メンバのテスト」で書いているコードをビルドしたアセンブリを下のように実行すると

$ [Hello.exeの場所] AAA BBB CCC
Hello, Work!
arg:AAA
arg:BBB
arg:CCC
TestClass(): cnt=1 str=aaa
(以下略)

となり、引数も渡されていることが分かる。

関連記事:

使用したバージョン:

*1:コンテキストメニュー「別のアプリで開く...」から出るダイアログで設定