「 2013年06月 」一覧

現在の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についてですが、これについては次回に続く、ということで。この話は長くなりそうです。


VRAMの使用量を取得するライブラリ


先日公開したVRAMの使用状況をグラフ化するツールで使用しているDLL部分について、ヘッダとライブラリの形式でまとめた物を公開します。
純粋にCインターフェースで作成しているため、C#からの呼出も割と楽に実現できます。
(通常のWin32APIの呼出手続きと同じように記述が可能です)

ダウンロード

VRAMSpaceLib ver 1.00 をダウンロード
VRAMSpaceLib ver 1.01 をダウンロード
VRAMSpaceLib ver 1.02 をダウンロード

コード使用例

以下のような感じで使います。

使ってみて動いたor動かない、改良案、感想などありましたらコメントでお願い致します。


VRAMの使用状況を取得するアプリ


先日からやっているVRAMの使用状況についてですが、別の手法で実装してみました。
取得コードはネイティブで、GUI部分をC#で作ってみました。
これはWindows7以降の環境で動作します。
意外とWindow操作で使用量が変動するので見ていてもおもしろいです。

DirectXやOpenGLなどの描画APIによって左右されずに、システム全体での使用量がわかります。

ViewVRAM_v100 のダウンロード
ViewVRAM v1.01 のダウンロード

これのDLL部分は後日ヘッダ+DLLで別途公開予定です。

追記

こちらのほうでDLLらを公開しました。


VRAM情報の取得(AMD編)


最近AMDドライバを更新したらVRAM情報用の拡張がなくなっているじゃないか、の続きの話です。
関連する話は、OpenGLでVRAM情報を得る – AMDや、OpenGLでVRAM使用状況を取得…出来なくなった?!などになります。

結局のところ、ドライバを更新して Catalyst 13.4で RADEON 6850 を使用している状況では、ATI_meminfo エクステンションがやっぱり消えてしまっているようです。そこで一応強引に、VBO_FREE_MEMORY_ATI,TEXTURE_FREE_MEMORY_ATI を試してみたところ、なんと値が返ってきました。値の内容もそれなりに正しいようです。

こんな感じです。

VBO_FREE_MEMORY_ATI  1036288, 774144, 2096128, 2096128

4つの値がある理由はパラメータ1つで4つの値が返ってくるためです。詳しくはATI_meminfoの仕様を参照してください。

1GBの搭載メモリなので、1036288 という値が返ってきているところは正常そうです。ただ、元々のAPIの仕様からか現在使用中もしくは空きメモリをトータルで返す機能はないようです。これではモニタリングという点では厳しそうです。

また、GL_TOTAL_PHYSICAL_MEMORY_ATI で搭載している物理メモリ分もとれるよ!と過去の日記では書いたのですが、どうやらこれは現在使えないようです。この定義はどうやら Undocumented extension 的な扱いだったようです・・・。

話を戻して、他のアプリケーションの起動によって使用可能領域に関するパラメータが変動するかを調べてみます。
↑では第2パラメータの部分がアロケーションの最大ブロックなので、これが変動するかを確認してみようとおもいます。複数のアプリケーションを起動した後、取得したら値が変わるかどうか。
試してみた結果は、変動無し。まだまだ使用量が足りなかったのかもしれません。小ブロックでも消費した分がわかるAPI拡張だったら安心できるのにと思うのですが・・・OpenGLだとVRAMのメモリ使用量を気にするな、という意志を継いでいるのでしょうか。

以上の点により、とりあえずはなんとなく値はとれるようだけど、NVIDIAに比べて、信用ならない印象です。
どの環境でもそれなりにというのであればProcessExplorerが搭載している機能と同じ方法でやるしかなさそうです。Intelの場合はAMD以上に拡張そのものが使えないですし。


VRAM情報の取得(NVIDIA編)


前回AMDのドライバでVRAM情報取得が出来なくなった状態だったのと、Vista以降でVRAM情報が正しくとれなくなったのとのコンボで再度ちょっと実験してみました。

NVIDIAのドライバでは、GL_NVX_gpu_memory_info という拡張がOpenGLで使える可能性があります。
これを用いてみて、どのような挙動になるか確かめてみたいと思います。AMDも本来なら実験したいのですが、先日の通りなぜか使えなくなっている状態でしたのでここでは諦めておきます・・・。

NVIDIAの拡張のほうで、搭載メモリを取得するのには、GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX を用い、使用可能メモリを取得するのに、GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX を用いて値を得ます。これらの詳しい説明はこちらに

自分の環境は以下の通りです。

  • Windows7SP1
  • NVIDIA GeForce650Ti
  • NVIDIAドライバ 314.07
  • 1920×1200モニタ

これで値の取得を試みたところこうなりました。

  • 搭載メモリ 1023MB
  • 使用可能メモリ 805352 KB

ここから計算すると、約200MB ほど使用中という感じになります。他にもいくつかのアプリケーションが動いていたため、それらで消費されている分も考慮されているということでしょう。
 そこでこの値の変動を、他のアプリケーションの起動によって変動するかを確かめてみます。エクスプローラーを他にも立ち上げたり、画像処理系のプログラムを動かしてみたりと。これで値が変動するのを確認できました。つまりここで取得される値というのはシステムトータルの使用量を考慮の上ということのようです。

ここから、このOpenGL APIによる値取得でVRAMの使用量をモニタリングするアプリケーションが作れそうです。

気になる点

ただ気になる点が1つあります。最新のProcessExplorerではGPUのメモリ使用量もグラフ化することができるのですが、ここと結構値が違います。特に搭載メモリ量の部分で違うところからちょっと驚きです。(1023 vs 950 MB) ここが違うためか、使用中メモリ量を計算するとずれてきます。この差分を考慮して下駄を履かせると両者で同じくらいにはなりそうですが・・・この差異が出てくる理由はちょっとわかりません。


Windows8のBitLocker


BitLockerがWindows8 Proエディションで使用できることを知った!Enterprise版しかダメかと思い込んでいたので。
一応見てみたらWindows7のProからも実は使用できたようで・・・意外でした。

そしてWindows8のBitLockerは少し進化してるようです。

  • 使用済み領域だけの暗号化
  • 回復キーをMicrosoftアカウントへ保存
  • ネットワーク・ロック解除

などなど。個人的にはこれらのものがいい!と感じたので特にあげてみました。

回復キーをアカウントに紐づけてネットワーク向こうに保存できるのはいいですね。流出しない前提ならば、ローカルに保存することもないので安心です。それになくさないし。
また、ネットワークロック解除っていうのもすごい。調べてみるとWindowsServer2012がないと駄目なようですが、会社等ではかなり使えそうに思えました。いざっていうときのデコードに使える・・・。
アカウントへ保存って実際のところはSkyDrive上に保存されるって意味だそうですが。

個人的にはHDDよりもUSBメモリに適用して落としても安心、って感じに使っていきたいかも。


WindowsVistaとVisualStudio2012の罠


先日VisualStudio 2012自体の動作環境を調べてみましたが、それ以外にもまだ罠が潜んでおりました。
WindowsXPをターゲットとするリモートデバッグが出来ないのはよく知られた事実ですが、なんとWindowsVistaも同様にリモートデバッグが出来ない対象となっていました!

これに気付かずに、がんばってVistaでリモートデバッグを出来るようにと試行錯誤してました。
Update1以降を適用したとしても、XPがリモートデバッグできない対象であるようにVistaもダメなんでしょう。
Vista,XPをリモートデバッグの対象として使うなら、VisualStudio 2010はまだまだ手放せないようです。


Wow64のリダイレクトに悩まされたら


Windowsも64bitが割と定番になってきた今日この頃ですが、相変わらずUAC関連に悩まされることも多いです。これVistaのころから導入されているのに、意外と仕組みをきちんと知らない人が多いようです(自分も含めて)。

ここでいうUAC関連による悩みとは以下の事柄に代表されるかと思います。

  • 権限昇格の問題(管理者権限付与ユーザーでも管理者として実行が必要なときがある)
  • フォルダのリダイレクト
  • レジストリのリダイレクト

これらに悩まされることが面倒で、UACをオフにして常に管理者権限付与したユーザーで操作するという手は言語道断、非常に不味いです。

どうしても管理者として実行させたいプログラムを作るときには、埋め込みマニフェストにて、asInvokerではなく、requireAdministrator を実行レベルに設定しておきましょう。これを適用しておくと常に管理者として実行されます。ただし実行するタイミングで暗転して確認が求められたりしますが・・・。それでもFAQのように、管理者として実行でお願いします、と毎回答えるよりはマシかと思います。

続いてリダイレクトについて。
フォルダがリダイレクトされ、レジストリもリダイレクトされ・・・これらは調査するときには非常に厄介だったりします。
レジストリについては、実はフラグ(KEY_WOW64_32KEYやKEY_WOW64_64KEY)で参照する場所を特定できるようですし、常に意識するようにすればそのうち慣れます。
64bitのレジストリエディタならば、全領域を参照することが出来ますし不具合調査の時にはコレを用いればいいでしょう。

フォルダのリダイレクトについて。
これが個人的には厄介だなと思いました。たとえば64bitのメモ帳を起動したいとき、32bitのプログラムからは普通にやると32bitのメモ帳しか起動出来ないのです。フルバス指定するにしても、C:\Windows\System32\notepad.exe が64bitのメモ帳を指すのですが、これがリダイレクトの対象になって、実際は C:\Windows\SysWow64/notepad.exe になってしまうわけで。

これを断ち切って動かすには、次のようなAPIを用います。

これらは見ての通り、リダイレクションを有効・元に戻すという機能を持つAPIです。詳しくはMSDNのヘルプを参照してください。

コレを使って一時的にリダイレクトをオフにしてフルパス指定すれば、多くの場合には32bitプロセスから64bitプロセスを起動するといってことも割と楽に出来るのではないでしょうか。