「 WinSxS 」一覧

現在のWindowsサイドバイサイドについて-続き2-


前回に引き続きSide-by-Side話で、DLL+exe構成でのお話です。

実はexeと同様にDLLも対処することが出来ます。
exe名.manifestはexeに作用する物でDLLに対して作用させることができません。またWindowsServer2003以降、マニフェストの優先順位がXPのものと逆になったため、外部マニフェストで上書きができません。
XPのころであれば、DLL名+.2.config というファイル名でDLLのマニフェストも置き換えられたのですが・・・。コレに関しては昔に自分で書いた記事がこちらに

よって解決策はほぼ1つで、DLLの中に入っている埋め込みマニフェストを開発環境にあわせたVCランタイムバージョンを使用するように変更するということになります。
これには方法が2つあると思います。

  1. mt.exeを使用し、DLLの埋め込みマニフェストを編集&書き戻す
  2. DLLをビルドする際に、 _BIND_TO_CURRENT_VCLIBS_VERSION を定義しておく

ほぼexeのときの手順と同じですね。
重要なのは、exeが求めるバージョンとDLLが求めるバージョンを一緒にしておくことです。
VC9で同一バージョンを指すように、VC8で同一バージョンを指すようにという感じです。同じVCxxで別々のバージョンを指してはいけません。実際にコレが起こると非常にわかりづらいエラーとして表面化します。。。

今までの全3回をきちんと理解すれば、おそらく目的の挙動を達成できるのではないかと思います。環境に合わせて、それぞれでやる内容は異なってくるかと思いますが、仕組みとツールの挙動が把握できれば思い通りに出来るようになるかと思います。


現在のWindowsサイドバイサイドについて-続き-


前回は、VCランタイムをスタティックリンクして生成させるという話で終了しましたが、今回はその続きに当たるダイナミックリンク版のVCランタイムを使用しつつ前回の条件を満たす、ということを考えてみたいと思います。

前回はこちらに。 現在のWindowsサイドバイサイドについて

ここでは2005,2008と2010,2012での谷間によって、大きく違います。
2010以降で生成されたアプリケーションでは、VCランタイムに関する埋め込みマニフェストがないため、そのまま必要なDLLをexeと同じ場所にコピーしておくことで対処できます。
一方で、2005,2008はカレントに決められた名前でフォルダを作成してその中にDLLを配置する手法をとります。
これはプライベートアセンブリというものに該当します。

図示するとこんな感じです

-- Application.exe
      + Microsoft.VC90.CRT
          + msvc***.dll
          + Microsoft.VC90.CRT.manifest

Microsoft.VC90.CRT というフォルダはVCインストールフォルダでredistというフォルダの中で見つけることが出来ます。

このように配置してアプリケーションを動かしたいということは、その環境ではランタイムが入っていないわけですので、
Application.exe が要求するバージョンの Microsoft.VC90.CRT を配置しなくてはなりません。
ここがくせ者でして、VisualStudio2005,2008にはそれぞれで違った挙動を示してくれます(涙

  • 2005の場合
    • ビルド環境の最新状態のVCランタイムバージョンにバインドされる
  • 2008の場合
    • ビルド環境の最新状態のVCランタイムバージョンではなく、2008RTM版のランタイムバージョンにバインドされる

つまり、2005のこの挙動であれば、ビルド環境のredistフォルダからコピーして配置で問題なく動くようになるわけです。
一方、2008のこの挙動ではビルド環境のVCインストールフォルダのredistも最新状態のランタイムに更新されているため、redistフォルダからのコピーではバージョン違いにより動作させることが出来ない状態となります。

これらの挙動を修正するのに、exeが要求するランタイムバージョンを変更するという方法が1つあげられます。それが外部マニフェストです。
exeと同じ場所に、exe名(拡張子含む).manifestというファイルを作成することで、処理されるマニフェストを上書きする形で制御できます。ここにredist内で見つかったバージョンを要求するように書き換えてしまえばうまく動くという考えです。

この方法はXPまでであれば考え通りに動きますが、2003以降マニフェストの処理優先順が変わりました。そのため現在主流となっているWindows7周辺のバージョンでは埋め込みマニフェストが優先されてしまうため、動かない状態となります。

この状態でとれる案として以下のものが考えられます。

  1. 2008の場合において、ビルド時に
    _BIND_TO_VCLIBS_CURRENT_VERSION=1 (プリプロセッサ定義で指定する)
  2. 生成されたexeの埋め込みマニフェストを編集する

(1)の場合、ビルド時のVCランタイムバージョンにバインドされるようになります。
依存するライブラリ全てにおいてこのプリプロセッサ定義を行いexeを生成できれば、ビルド環境のredistからランタイムをコピーだけで動くようになります。
(2)の場合、mt.exe というツールを用いて、manifest取り出し → 編集 → 再度埋め込み という手順を行います。

具体的には、下記のような感じになります。

取り出し
mt.exe -inputresource:Application.exe;#1 -out:result.manifest

取り出したマニフェストファイルを開き、要求しているバージョンを変更します。

埋め込み
mt.exe -manifest result.manifest -outputresource:Application.exe;#1

以上で、exe単体で動かす場合の話は終了です。
しかし、オープンソースのライブラリや自作の他ライブラリを用いており、それがDLL版だったりすると話はまだ続きます。
これについてはまた次回に。


現在のWindowsサイドバイサイドについて


以前にまとめてから随分と時間が経って、VisualStudioも2012となっているし、Windowsも8.1がプレビューとなっている現在、そろそろWinSxSについても情報更新しておくべきじゃないかと思ったので、この記事を書いています。

以前の記事は、WinSxS問題(2009年)VisualStudio2010でのWinSxS(2010年)というものを自分で書いたようです。

まず、VisualStudioによる大きな逆目が2010になります。

  • VisualStudio2010,2012は、生成されるexeにVCランタイムに関するマニフェストが含まれません。
  • VisualStudio2005,2008は、生成されるexeにVCランタイムに関するマニフェストが含まれます。

この挙動に注意する必要があります(2005,2008間でも挙動違いますが…)。

次に、OSについてですが、Windows XPまでは、外部マニフェストが有効です。
それ以降のOS WindowsServer2003からは、外部マニフェストよりも内部マニフェスト(埋め込みマニフェスト)が優先されるため、外部による変更ができません。
(情報元:http://msdn2.microsoft.com/ja-jp/library/ms235342(VS.80).aspx

このような変更点・注意点がありますが、マイクロソフトからダウンロードできる再頒布ランタイムをインストールすれば、どのOS環境でも気にすることなく配布したexeを実行することが出来ると思います。

しかし!この再頒布ランタイムをインストールしたくない場面というものはあるもので、
例えば以下のシチュエーションでしょうか。

  • 開発環境なので恒久的に更新されてしまうVC再頒布ランタイムは入れたくない
  • そもそもユーザー権限しかないので、VC再頒布ランタイムをインストールできない
  • 一時的に実行したいだけなので、VC再頒布ランタイムをインストールするなどして環境を汚したくない

企業のPCだと実は2が該当したりして、この環境でも動くアプリケーションにしておくのは便利だったりします。
一番簡単な解決方法は自分が作成するアプリケーションを、VCランタイムをスタティックリンクして生成する方法です。

VCでプロジェクト設定を開いて、コード生成の項目で、ランタイムライブラリをマルチスレッド(もしくはマルチスレッドデバッグ)を設定すること、です。これらで統一してexe,dllを作成して配布すれば上記の実行条件を満たすことが出来ます。

続いてマルチスレッドDLLやマルチスレッドデバッグDLLについてですが、これについては次回に続く、ということで。この話は長くなりそうです。


VisualStudio2010でのWinSxS


VisualStudio2010では、またサイドバイサイド(Side by Side:SxS)の状況が変わっていた。どうやら、WinSxSを使っていないようです!
C:WindowsWinSxs の中を見ても vc100用のランタイムは入っていませんでしたし、
VS2010インストールフォルダ内のdll群をチェックしてみても、
埋め込みマニフェストすら入っていませんでした。

さらには、2010で作成されるexeの中の埋め込みマニフェストをみてみても
ランタイムのバージョンに関するものは記載がありませんでした。

ちなみに、VS2005/2008では、世間で有名になっているとおり
サイドバイサイドが使用されており、ランタイムの単純コピーでは動作しないようになっていました(一般的には)。
ユーザーはマイクロソフトより再配布ランタイムのパッケージをダウンロードして、インストールする必要がありました。

今回の2010での変更は、従来のdll単純コピーで済ますことが出来るという点では手軽になったと思います。
しかし、懸念されるのは一昔前のDLL-HELLです。また同じ状況が起こる可能性があります。

所感

WinSxSがそうとう厄介問題だったのは知っていましたが、
新バージョンで取りやめるほどとは思いませんでした。

以前のランタイムもマイナーバージョン間では単なるリダイレクトになっていたし、
全て新バージョンのランタイムで置き換えてきた現実からこのような方法に変更になったのかもしれません。
「今までも全て新しいものに置き換えてきた。今後も大丈夫だろう。
VCではWinSxSを廃止して、dll直配置を認めた方がサポートも楽になる。」
というような思惑だったりするのかも、と思ってます。

昔のようなバージョン依存は現在となっては低そうということでしょうか。


WinSxS問題 その2


基本的事項

まずは知っておかなくてはいけないこと。

外部マニフェストの挙動

  • 外部マニフェストはexeのみに適用される。
    • そのexeが必要とするdllらには適用されない点に注意
  • WindowsXP環境では、外部マニフェストのほうが埋め込みマニフェストよりも優先される
    • 2003より優先順序が逆転した。

症状

再頒布ランタイムパッケージがインストールできない環境で発生した。
インストールできない環境とは、ユーザーがゲスト権限くらいしかない場合を指す。
あるいはどうしても事情により入れられないとか。

このときに、exeとdllと同フォルダにおいて、
そのプライベートアセンブリとして、VCランタイムを配置した。
このときに、最近のWindowsUpdateが適用されたバージョンを置いた。
(VC90.30729.4148バージョン)

そして、exeがこのバージョンのランタイムを使うように、外部マニフェストファイルを作成して
実行をさせようとした。

この結果が、昨日のエラーを引き起こしていた。
理由は、dllにはこのマニフェストの影響が及ばないからである。
故にdllは埋め込みマニフェストに従い、21022.8のランタイムを要求しているし、
exeは外部マニフェストによって強制された 320729.4148バージョンを要求する。

ここで同一のアセンブリ名であるためにdllがロードされてチェック機構が働いた段階で、
不整合がおこり、ローダーの段階で失敗してしまう。
その結果、exeが実行されることなく強制終了されてしまう。
試した環境ではエラーダイアログすら出ない。

解決策

簡単に解決する方法がある。
ひとつは、VisualStudio2008,およびSP1環境のデフォルト動作では、
RTM版のランタイムにバインドされる。
これは、9.0.21022.8 のバージョンである。
これに対応するランタイムを入手し、それをプライベートアセンブリとして使用する。

ただし、セキュリティ関係で問題になりそうな気もするが仕方ない.

もう一つは、最初から埋め込みマニフェストで最新バージョンを使うように
全部アプリケーションをリビルドする。
これには、まずプロジェクト設定の、プリプロセッサ定義で、
_BIND_TO_CURRENT_VCLIBS_VERSION を定義しておく。

これを行うとビルドした環境の最新のバージョンへバインドされる。
よって、最近のやつであれば 30729.4148にバインドされる。
リビルドにより dllからexeまでがこれに依存するようになるため、
VisualStudioのインストールディレクトリから再配布ランタイムをコピーして使用すればよい。

最後の方法は、exeでやったように、dllに対しても依存するアセンブリ情報を強制変更する方法である。
これには、hogehoge.dll.2.config というファイルを作成する。
ポイントは”2″という部分。

このファイルにより、目的のバージョンへバインドがリダイレクトするように設定すれば、
dllとexeのバージョン要求不一致を解決できる。
この方法は一応海外のMS CONNECTで記述があったためおそらく正式な方法だと思う。

しかし、日本語での情報が見つからなかったためここに書いてみた。