ものがたり(旧)

atsushieno.hatenablog.com に続く

minvoke

http://squeedlyspooch.com/blog/2009/06/29/minvoke-forcing-portability/

世の中には、せっかく.NET向けにC#で書かれたプログラムなのに、user32.dllやkernel32.dllをP/InvokeしているせいでMono/Linux環境で実行出来ない残念なアプリケーションが少なからず存在する。そしてこれらのP/Invokeは大したメリットも無く使われていることが多いし、何らかのmanaged codeで代用することも多い。

それならば、そんな邪魔なP/Invokeアセンブリレベルで書き換えて消してしまえ、というのが、最近新しく作られたminvokeというプロジェクトだ。

これはcecilを使って、DllImportされているメンバーへの呼び出しを、minvokeで読み込んだアセンブリの中で対応するクラスのメンバーへの呼び出しに置き換える。現状では、MapDllImportAttributeというのを指定するかたちで使うようだ。minvokeがアセンブリをどう読み込むかは今後変わっていくだろうけど、kernel32やuser32に対応するクラスを含むアセンブリは、いずれmono本体に入ることになると予測されている。

さて。

P/Invokeまわりはややこしい状況なので、少し整理しながらminvokeの位置付けを補足したいと思う。

まず、P/Invokeがあること自体は必ずしも移植性を損なうものではない。呼び出されるライブラリがクロスプラットフォームであれば、ほぼ問題なく実行出来る*1。一番分かりやすい例として、Gtk#はGtk+のライブラリに対するP/Invokeとして書かれている。openglまわりのバインディングクロスプラットフォームだ。

呼び出されるライブラリのファイル名が微妙に違うせいでDllImportAttributeが上手く書けないというのは、大して問題ではない。configファイルに<dllmap>という(.NETには無い)要素を追加すればいい (see mono site)。

問題になるのは、user32.dllやkernel32.dllなど、Windows上にしか存在しないdllをP/Invokeしている場合だ。Wineにはこれらのライブラリが存在するが、これらはあくまでwineの環境を前提としている。Win32メッセージループのエミュレーションもmonoとwineは独立して行うことになるし、wine上でmono on windowsを動かすなんてのはいびつなやり方だ*2

ユーザが自分でwin32 dllに依存しないコードを書くように心がければいいのだけど(FlashDevelopチームなんかは、Monoで動かせるように新バージョンを修正しているという)、誰もがそれをやってくれるとは期待出来ない。

minvokeの解決策は、ユーザによるコードの書き換えはもう期待せずに、必要な範囲でアセンブリを書き換えて、とりあえず実行出来るようにしちゃおう、というものだ。で、これはuser32やkernel32に膨大な関数が含まれていることを考えると、最初から「完成」することは目指していない。でも共通のものは共通のコードで概ね解決できるだろう。いくらでも作業する余地はあるけど、ハッカーが寄ってたかってコードをcontributeできるものでもある。はず。どう進められるか、まだ分からないけれど。

というわけで何か協力してコード書けそうなところがあるという方は協力してやってくらさいw

*1:文字列のマーシャリングなどの扱いが異なる部分はあるけど

*2:wineの箱の中から出られず、ネイティブファイルアクセスやPosixまわりのサポート、さらには将来の世代別GCデバッグサポートなどさまざまなアドバンテージを失う