[.NET] VS2005/2008 で別プロジェクトの埋め込みリソースを設計時に参照する方法

Visual Studio の埋め込みリソースの機能はよく出来ているが、複数のプロジェクトに分割された時の設計時サポートは微妙にかゆいところがある。ところが、ちょっとした工夫で設計時にも実行時にも上手く扱えるようになる。
2月頃に下書きをまとめておいて、超書いた気分になって放置されていたかわいそうな記事。MSDN Forum を眺めていて、書いたつもりの記事を紹介しようとして検索してびっくりした(笑
VS2010 でリソース選択機能がパワーアップしているかどうかは未確認なので、この Tips が VS2010 に必要なのか、有効なのかについては、未確認です。

設計時に埋め込みリソースを利用する

おそらく、ほとんどの人はわかってると思いますが、Visual Studio では、設計時に画像を読み込む場合のリソース選択において、埋め込みリソースを格納した resx ファイルを選択することができる。

さて、ここで選択できる resx ファイルの一覧だが、おそらく

  • プロジェクトの Properties ディレクトリに格納された Resources*.resx
  • プロジェクトのルートディレクトリに格納された *.resx

の2つのファイル群が対象になっている。また、画像ファイルを選択した際にフォームのデザインファイル (Form1.Designer.cs 等) には、Visual Studio の ResXFileCodeGenerator によって生成された埋め込みリソースの参照用リソースクラスが使用されるため、ここで選択する resx ファイルはリソースクラスが生成されていなければならない。

別プロジェクトへリソースを公開する

単純に、別のプロジェクトで使用している画像等のリソースを取り込むと、まったく同じ画像が自プロジェクトと別プロジェクトに二重に登録されてしまう。これは、ビルドされたアセンブリにおいても同様で、Project1 と Project2 の両方で 100MB の A.bmp を使用していたら、両方のアセンブリサイズが 100MB 増えてしまうことになる。当然、画像を変更する場合は Project1 も Project2 も再構築しなければならなくなる。これを防ぐために、Project1 では Project2 に格納された A.bmp を使用したいと思うのは普通の考えだろう。
リソースを公開するためには、*.resx を開くなどして表示されるリソースエディタのツールバーにある「アクセス識別子」を「Internal」から「Public」に変更する。もしくは、プロパティウィンドウから、カスタムツールを「ResXFileCodeGenerator 」から「PublicResXFileCodeGenerator」に変更すればよい。Project2 の resx を公開設定することで、Project1 は参照設定に Project2 を追加するだけでコーディング上から Project2 のリソースにアクセスすることができるようになる。

// Project1 から Project2 の A.bmp にアクセスできる
var a_bmp = Project2.Properties.Resources.A;

しかし、これだけではリソースの選択ダイアログに Project2 の画像は出てこないし、Form1.Designer.cs を手作業で編集してリソースの参照先を Project2 に変更しておいても、フォームデザイナを使用して編集操作をした時点で、Visual Studio は Project2 のリソースへの参照を Project1 への参照へと書き換えてしまう

リンクファイルを使って Visual Studio を騙そう


この2つの問題を解決するためには、リンクファイルを使って *.resx を間接的に参照する必要がある。まず、リソースにアクセスできなければどうにもならないので、Project2 のリソースを公開設定にし、Project2 を Project1 の参照設定に追加するところまでは一緒だ。
次に、Project1 のルートディレクトリに対して「項目の追加」を行い Project2 にある共有したい *.resx を「リンクとして追加」を行う。*1注意点として、デフォルトの Resources.resx という名前のままだと Project1 と Project2 のどっちのリソースなのか区別がつかなくなるため、共有するリソースはできれば Resources.resx とは違う名前で用意しておくほうがよいというところ。
リンクとして *.resx を追加したら、そのプロパティを以下のように設定しよう

カスタムツール PublicResXFileCodeGenerator
カスタムツールの名前空間 参照元名前空間*2
ビルドアクション なし

設定しおえたら右クリックメニュー等から「カスタムツールを実行」を行うと対応した *.Designer.cs がリンクファイルとして生成されるはずなので、次はそのリンクファイルのプロパティを開き、

カスタムツール (空欄)
カスタムツールの名前空間 (空欄)
ビルドアクション なし

と設定する。これで準備は完了だ。

別プロジェクトのリソースを使う

上記の設定が終わった後、リソースの選択ダイアログを開くと、追加したリンクファイルの resx が選択肢に出てきて、その画像が利用できるようになっている。
また、参照先アセンブリにリソースが複製されることも、Visual Studio によって勝手に参照が書き変わることもない。

元プロジェクトの .Designer.cs の復元を行う

最後に、参照元となっている(リンクファイルではない)*.resx を右クリックして「カスタムツールを実行」を行います。これは、カスタムツールが読み込み元アセンブリの名前を埋め込んじゃう都合で、参照元の *.Designer.cs が不正なアセンブリを指しているものを修正するためです。(実行時にリソースファイルが見つからないという例外が出たら、この設定を忘れています)

*1:追加→既存の項目→ファイルを選択→追加ボタンを押さずに、ドロップダウンからリンクとして追加

*2:たとえば、ClassLibrary1 の PubResources.resx であれば、ClassLibrary1 というネームスペースになる