Monoに関するTips

§1 使用しているランタイムがMonoかどうか調べる

Monoのmscorlib.dllにはMono.Runtimeクラスが含まれているので、この型の情報が取得できるかどうかでランタイムがMonoかそうでないかを調べることが出来る。 ちなみに、Mono.Runtimeクラスはinternalなのでインスタンスは作成できない。

using System;

class runtime {
  static void Main() {
    Console.WriteLine("runtime: {0}", Type.GetType("Mono.Runtime") == null ? ".NET Framework?" : "Mono");
    Console.WriteLine("version: {0}", Environment.Version);
  }
}
Monoで実行した場合
runtime: Mono
version: 2.0.50727.1433
.NET Frameworkで実行した場合
runtime: .NET Framework?
version: 2.0.50727.3082

§2 実行しているプラットフォームがUnixかどうか調べる

.NET Framework 2.0以降を使用する場合は、Environment.OSVersion.Platformの値がPlatformID.Unixかどうかで判断できる。 Monoの場合も同様に、2.0以降ではPlatformID.Unixかどうかで判断できる。 一方1.xの場合にはPlatformID.Unixは存在せず、Monoでは代わりに128が割り当てられていたため、ランタイムのバージョンを問わず判断するためにはEnvironment.OSVersion.Platformの値がPlatformID.Unixまたは128かどうかで判断すればよい。

以下のサンプルにおいて、

  • 4は.NET Framework 2.0以降のPlatformID.Unixの値
  • 6は.NET Framework 2.0 SP2以降のPlatformID.MacOSXの値

を表す。

using System;

class platform {
  static void Main() {
    var p = (int)Environment.OSVersion.Platform;

    //Console.WriteLine("unix? {0}", Environment.OSVersion.Platform == PlatformID.Unix);
    Console.WriteLine("unix? {0}", (p == 4) || (p == 6) || (p == 128));
    Console.WriteLine("version: {0}", Environment.OSVersion);
  }
}
Ubuntu 9.04上のMonoで実行した場合
unix? True
version: Unix 2.6.28.11
Windows XP上の.NET Frameworkで実行した場合
unix? False
version: Microsoft Windows NT 5.1.2600 Service Pack 3

§3 名前付きミューテックスを使用する

Linux上で動作するMonoでは、名前付きミューテックスなどプロセス間で共有されるハンドルをエミュレートするために共有メモリを使用している。 2.8以降のMonoではデフォルトで共有ハンドルの使用が無効化されている。 有効にするには環境変数MONO_ENABLE_SHMをセットする。

名前付きミューテックスを使用する例
using System;
using System.Threading;

class Sample {
  static void Main()
  {
    bool createdNew;

    using (var mutex = new Mutex(false, "my-named-mutex", out createdNew)) {
      Console.WriteLine("createdNew: {0}", createdNew);
      Thread.Sleep(1000);
    }
  }
}
実行結果
$ mcs test.cs && for i in `seq 1 5` ; do mono test.exe & done 
createdNew: True
createdNew: True
createdNew: True
createdNew: True
createdNew: True

$ mcs test.cs && for i in `seq 1 5` ; do MONO_ENABLE_SHM=1 mono test.exe & done 
createdNew: True
createdNew: False
createdNew: False
createdNew: False
createdNew: False

MONO_ENABLE_SHMが設定されているか(共有ハンドルを使用できるか)どうかを実行時に知る方法は、Environment.GetEnvironmentVariableを使う以外には特に用意されていない模様。

§4 gdiplus.dllでSystem.DllNotFoundExceptionとなる

Fedora 8で起きた問題。 System.Windows.Forms等を使ったアプリケーションを起動するとgdiplus.dllが原因でSystem.DllNotFoundExceptionが発生する。 これは$LD_LIBRARY_PATH(yumでインストールした場合は/usr/lib)にlibgdiplus.soが存在せず、動的リンクに失敗することが原因で起きる。

yumでMonoをインストールした場合は/usr/libにはlibgdiplus.so.0というファイル名でインストールされるので、シンボリックリンクを貼ればリンク出来るようになり、System.DllNotFoundExceptionは発生しなくなる。

cd /usr/lib
ln -s libgdiplus.so.0 libgdiplus.so