.NET Frameworkでは、実行可能ファイル・アセンブリにビットマップやアイコンなどの画像ファイル、マルチメディアファイル、テキストファイルなどをリソースとして埋め込むことができます。 これによって単体で存在する外部ファイルを実行可能ファイルやアセンブリに含めてひとまとめにすることができます。 ここではリソースを埋め込むための方法と、埋め込んだリソースの読み込み方法について解説します。

§1 Visual Studioでのリソースの埋め込みと読み込み

ここではVisual Studio 2008を使った場合を例としてリソースの埋め込みと読み込みの方法を見ていきます。 なお、2008以外の他のバージョンでもメニュー等が若干異なる程度で基本的な手順は同じです。

§1.1 リソースファイルの追加 (新しく作成する)

まずは、リソースを新しく作成して埋め込む方法です。 新しくリソースを作成するには、ソリューションエクスプローラでプロジェクトを右クリックして[追加]メニューの[新しい項目の追加]をクリックします。

続いて、追加したいリソースの種類とファイル名を設定します。 ここではビットマップファイルを追加することにします。 ファイル名は後で変更することもできるので、デフォルトのままでも構いません。 種類とファイル名を決定したら[追加]をクリックします。

すると、リソースがプロジェクトに追加されます。 あとは、生成されたリソースを編集します。

§1.2 リソースファイルの追加 (既存のファイルを使う)

Visual Studioで用意されている画像・アイコンエディタなどはあまり使い勝手が良くないため、画像などのリソースは外部のアプリケーションを用いて編集することになると思います。 そういった場合には、別のアプリケーションで作成したファイルをプロジェクトに追加することでリソースとして埋め込みます。 既存のファイルを埋め込む場合は、リソースを新規作成する場合と同じように[追加]メニューを開き、[既存の項目]をクリックします。

続いて、追加したいリソースとなるファイルを選択します。 このダイアログではどのようなファイルも追加することができますが、ファイルがプロジェクトのフォルダ外にある場合などは、ファイルをプロジェクトフォルダにコピーして追加するか、コピーはせず元のファイルへリンクするかを選択することが出来ます。 リソースファイルの管理方法に応じて適切なものを選んでください。

[追加]ボタンをクリックするとファイルがプロジェクトに追加されます。

§1.3 ファイルを埋め込みリソースとして設定する

上記の手順で追加したファイルをリソースとして埋め込むためには、ファイルのプロパティを忘れずに変更しておく必要があります。 ファイルを右クリックして[プロパティ]を開き、「ビルドアクション」が「埋め込まれたリソース」になっていることを確認します。

このようにして埋め込みリソースとして追加されたファイルは、ビルド時に実行可能ファイル(アセンブリ)に埋め込まれることになります。

§1.4 リソースの読み込み

続いて埋め込まれたリソースを実行時に読み込む方法について見ていきます。 リソースを実行時に読み込むには、Assembly.GetManifestResourceStreamメソッドを使います。 このメソッドは、埋め込まれたリソースをStreamクラスとして取得するためのメソッドです。

より具体的には、以下の手順でリソースを読み込むことになります。

  1. Assembly.GetExecutingAssembly等のメソッドを使い目的のリソースが埋め込まれているアセンブリを取得する
  2. 取得したアセンブリに対して、目的のリソース名を指定してAssembly.GetManifestResourceStream()を呼び出し、リソースのストリームを取得する
  3. 取得できたストリームからデータを読み込む

では早速、ここまでの手順で埋め込んだリソースを読み込んでみます。 以下の例では、リソースとして埋め込まれている画像ファイルsample.bmpを読み込み、ウィンドウの中央に表示しています。

リソースとして埋め込んだ画像ファイルを読み込み、フォームの背景に設定する
using System;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Windows.Forms;

namespace Sample {
  public partial class Form1 : Form {
    public Form1()
    {
      InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
      // 現在実行中のアセンブリを取得
      var assm = Assembly.GetExecutingAssembly();

      // リソースとして埋め込んだ画像ファイルのストリームを取得
      using (var stream = assm.GetManifestResourceStream("Sample.sample.bmp")) {
        // ストリームの内容をMemoryStreamにコピー
        var length = (int)stream.Length;
        var reader = new BinaryReader(stream);
        var memoryStream = new MemoryStream(length);

        memoryStream.Write(reader.ReadBytes(length), 0, length);

        // コピーしたMemoryStreamからBitmapを作成し、背景に設定
        this.BackgroundImage = Bitmap.FromStream(memoryStream);
        this.BackgroundImageLayout = ImageLayout.Center;
      }
    }
  }
}

GetManifestResourceStreamメソッドでリソースのストリームを取得する際に使用するリソース名は、「プロジェクト名.ファイル名」となります。 この例ではプロジェクト名が"Sample"、リソースのファイル名が"sample.bmp"なので、このリソースを参照する場合のリソース名は"Sample.sample.bmp"となります。 なお、このメソッドは指定するリソース名の大文字小文字の違いを意識する点に注意が必要です。 大文字小文字の違い含めてリソース名が一致しない場合は、見つからないものとして扱われます。

またこのメソッドでは、指定された名前のリソースが見つからない場合null/Nothingが返されます。 リソースが見つからなくても例外がスローされることはありません。

なお、このサンプルではリソースのストリームをMemoryStreamにコピーしてからBitmapのインスタンスを作成しています。 これは、Bitmapを作成したあとにGetManifestResourceStream()で取得したストリームを閉じてしまうと例外がスローされるためです。 GetManifestResourceStream()で取得したストリームから直接画像を作成する場合は、ストリームを閉じないようにする必要があります。

ここではリソースから画像を読み込む方法を紹介しましたが、テキストファイルや音声ファイルなども同様に読み込むことが出来ます。 テキストファイルならStreamReaderなど、音声ファイルならSoundPlayerなどと組み合わせて使うことで読み込むことが出来ます。

また、この例では実行可能ファイルに含まれているリソースを取得しましたが、Assembly.LoadメソッドAssembly.GetAssemblyメソッドなどを使うことでDLLのアセンブリからリソースを取得するようにすることも出来ます。



§2 MonoDevelopでのリソースの埋め込みと読み込み

ここではリソースの埋め込みと読み込みの方法をMonoDevelop 3.0を使った場合を例にとって解説します。

§2.1 リソースの埋め込み

まずはリソースとして埋め込みたいファイルを選択します。 プロジェクトを右クリックし、[追加]メニューから[ファイルを追加]を選択します。 なお、[新しいファイル]を選択すると、追加するリソースファイルを新規に作成出来ます。

次に、ファイルを選択します。 このとき、[開く]ボタンを押す前に、「デフォルトビルドアクションをオーバーライドします」にチェックを入れ、追加しようとするファイルが埋め込みリソースであることを指定するため「EmbeddedResource」を選択します。

追加するファイルがプロジェクトのディレクトリ外にある場合は、追加するファイルをプロジェクトのディレクトリにコピーもしくは移動するか、リンクとして追加するかを問われます。 リソースファイルの管理方法に応じて適切なものを選んでください。

これでプロジェクトにリソースとして埋め込まれるファイルが追加されます。

§2.2 リソースの読み込み

プロジェクトに追加したリソースを実行時に読み込むには、先に解説したGetManifestResourceStreamメソッドを使って読み込みます。

まず、リソースファイルを読み込むためのリソースIDを確認しておきます。 プロジェクトに追加したリソースファイルを右クリックし、[プロパティ]を表示します。 ここでリソースIDを確認します。 デフォルトでは、「プロジェクト名.ファイル名」がリソースIDとなっています。 このタブでは、必要に応じてリソースIDを変更することも出来ます。

あとは、このリソースIDをGetManifestResourceStreamメソッドの引数で指定してリソースのStreamを取得し、読み込むだけです。

リソースからテキストファイルを読み込み、内容を表示する
using System;
using System.IO;
using System.Reflection;

namespace Sample {
  class MainClass {
    static void Main(string[] args)
    {
      var assm = Assembly.GetExecutingAssembly();

      using (var stream = assm.GetManifestResourceStream("Sample.sample.txt")) {
        var reader = new StreamReader(stream);

        Console.WriteLine(reader.ReadToEnd());
      }
    }
  }
}
sample.txtの内容
sample.txt
これはリソースとして埋め込まれたテキストファイルです。

このコードを実行すると、以下のようにリソースとして追加したテキストファイルの内容が表示されるはずです。

テキストファイル以外のものも、同様の手順で埋め込み・読み込みすることが出来ます。

§3 コマンドラインコンパイラでのリソースの埋め込み

ここではコマンドラインコンパイラでのリソースの埋め込み方法を解説します。 MicrosoftのC#コンパイラであるcsc.exeとVisual Basicコンパイラvbc.exe、およびMonoのC#コンパイラmcs、同Visual Basicコンパイラvbncはいずれも同じ方法でリソースを埋め込むことが出来ます。

リソースを埋め込むためにはコンパイルオプション/resourceを使います。 /resourceオプションの省略形である/resを使うことも出来ます。 /resourceオプションは以下の形式で指定します。

/resource:ファイル名
ファイル名で指定されたファイルをリソースとして埋め込む。 参照する際のリソース名は"ファイル名"となる。
/resource:ファイル名,リソース名
ファイル名で指定されたファイルをリソースとして埋め込む。 参照する際のリソース名は、ここで指定した"リソース名"となる。

これを埋め込みたいリソースの数だけ指定します。 リソース名を省略した場合は埋め込むファイルの名前がリソース名となります。 プロジェクトファイルに追加する場合とは異なり、/resourceオプションでリソース名を省略した場合では、リソース名にはプロジェクト名やexe名などのプレフィックスは前置されません。

例として、コンパイル時にテキストファイルsample.txtをリソースとして埋め込むには次のようにします。 なお、このファイルに与えるリソース名は"message"としています。

cscでsample.txtをリソースとして埋め込む
csc sample.cs /resource:sample.txt,message

これを次のようなコードとともにコンパイル・実行すると、埋め込んだテキストファイルの内容が表示されるはずです。

sample.txtの内容
sample.txt
これはリソースとして埋め込まれたテキストファイルです。
sample.cs (リソースに埋め込まれたテキストファイルを読み込んで表示するプログラム)
using System;
using System.IO;
using System.Reflection;

class Sample {
  static void Main()
  {
    var assm = Assembly.GetExecutingAssembly();

    using (var stream = assm.GetManifestResourceStream("message")) {
      var reader = new StreamReader(stream);

      Console.WriteLine(reader.ReadToEnd());
    }
  }
}
実行結果
sample.txt
これはリソースとして埋め込まれたテキストファイルです。

§4 すべてのリソースの取得・リソース情報の取得

Assembly.GetManifestResourceNamesメソッドを使うとアセンブリに含まれているすべてのリソースの名前を取得することが出来ます。 リソースの名前が予め決まっていない・予測できない場合や、名前からリソースを検索したい場合などはこのメソッドを使うことが出来ます。

また、Assembly.GetManifestResourceInfoメソッドを使うとリソースに関する情報を取得することが出来ます。 リソースの情報はManifestResourceInfoとして取得され、このクラスを通してファイル名(リソースがマニフェストファイル以外に格納されている場合)やリソースが格納されている場所・アセンブリなどを知ることが出来ます。

次の例では、アセンブリに含まれている全てのリソースの名前を取得し、個々のリソースに対してを取得してリソースの情報を表示しています。

sample.cs (アセンブリに含まれるすべてのリソースの名前を取得して表示するプログラム)
using System;
using System.IO;
using System.Reflection;

class Sample {
  static void Main()
  {
    // 現在実行中のアセンブリに含まれるすべてのリソースの名前を取得する
    var assm = Assembly.GetExecutingAssembly();

    foreach (var name in assm.GetManifestResourceNames()) {
      // リソース名からリソースに関する情報を取得する
      var info = assm.GetManifestResourceInfo(name);

      Console.WriteLine("{0}: {1}, {2}", name, info.FileName, info.ResourceLocation);
    }
  }
}
cscで複数リソースを埋め込んだ実行可能ファイルを作成
csc sample.cs /resource:message1.txt,msg1 /resource:message2.txt,msg2 /resource:message3.txt,errmsg
実行結果の例
msg1: , Embedded, ContainedInManifestFile
msg2: , Embedded, ContainedInManifestFile
errmsg: , Embedded, ContainedInManifestFile