none
環境変数を定義したバッチファイルから起動したVisualBasicのデバッグ実行時、定義した環境変数を見ていない? RRS feed

  • 質問

  • VS2008です。あるソリューション中に次の二つのプロジェクトがあります。

    library.dll (C++/CLI)
    testapp.exe (VB.NET)

    testapp.exe は library.dll を参照しており、library.dll はソリューション外にあるサードパーティ製 DLL 3rdparty.dll にダイナミックリンクしています。
    このソリューションファイルを開く際以下のようなバッチファイルを書いて、それを実行しています。


    set MYLIB="E:\path\to\lib"
    set PATH="%MYLIB%\..\bin;%PATH%"

    start "C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\devenv.exe" このソリューションファイル.sln


    library.dll がリンクしている 3rdpary.dll のヘッダなどは MYLIB として定義されており、3rdparty.dll 本体は E:\path\to\bin に設置されています。
    library.dll は正常にビルドすることができ、testapp.exe もビルドまでは正常にいくのですが、デバッグ実行を行うと、どうも環境変数 PATH を見ていないらしく、FileNotFound 例外が出てしまいます。
    testapp.exe のバイナリと同じ位置( このソリューション/testapp/bin/Debug 配下 )に library.dll が吐かれているので、3rdparty.dll の方が見えていないようです。
    3rdparty.dll を testapp.exe および library.dll が吐かれたディレクトリに配置してやれば、正常に実行できます。

    そこで、testapp.exe のプロパティ>デバッグ>作業ディレクトリを 3rdparty.dll がある E:\path\to\bin に設定してやると、正常に実行できましたが、複数の環境で開発をしているソリューションなので
    プロジェクトファイルに個人の作業マシンのパスを入力することができません。

    作業ディレクトリを $(MYLIB)\..\bin と設定しても、「入力したディレクトリは存在しません」と環境変数を解釈してくれていないようです。

    1) 開発者の作業マシンの環境変数はいじれないので、バッチファイルから環境変数付きで devenv.exe を起動している。
    2) 例に上げた 3rdparty.dll は、実際には一つのファイルではなく、さらに数百 MB もあるので、(例で言う)E:\path\to\bin から testapp/bin/Debug にそれらをコピーしてくる、という事はしたくない。
    3) 例で言う E:\path\to\bin および MYLIB として定義されている E:\path\to\lib は、作業マシンによって違う場所を差している。統一することも出来ない。

    という条件の許、何かスマートな解決方法はないでしょうか。
    2012年6月4日 3:01

回答

  • 環境変数アプローチで海外のネタを調べましたが、正攻法としては用意されていないようですね。
    VS2010 で濃ゆいことをやっている事例があったくらいでした。

    前述のように作業フォルダーの設定で済ませられるのであれば、それが一番楽そうに見えます。

    • 回答の候補に設定 山本春海 2012年6月25日 8:46
    • 回答としてマーク 山本春海 2012年6月28日 8:45
    2012年6月4日 15:19
    モデレータ
  • DEVPATH環境変数を使われてはどうでしょう。PATH環境変数はアセンブリの検索に使えなかったと思います。

    http://msdn.microsoft.com/ja-jp/library/cskzh7h6%28v=vs.100%29.aspx

    この方法はアセンブリ構成ファイルを変更する必要がありますが開発環境であればDLLの位置にかかわらずどのマシンでも同じ設定になります。

    リリースの時には消す必要があります。

    subversionのブランチが使えるのであれば、開発用、リリース用を用意しておくと良いと思います。



    http://systemartlaboratory.com/

    • 回答の候補に設定 山本春海 2012年6月25日 8:45
    • 回答としてマーク 山本春海 2012年6月28日 8:45
    2012年6月5日 0:22

すべての返信

  • スマートな解決方法という表現が気にはなりますが、
    基本的には環境を統一する1択だと思います。

    なぜ参照パスを絶対パス前提で会話されているのかはわかりませんが、
    ライブラリの参照は相対パスも可能です。
    ※vbprojファイルのHintPathって所をご確認下さい。

    というか、参照パスはアプリの内部情報ですので、
    これを可変にするってのは構成管理なんかの面においてもいかがなものかと・・・

    2012年6月4日 3:17
  • 私ならという方法でしかありませんが、

    リポジトリに3rdparty.dllを含めてしまい、ビルド時に相対パス指定で出力ディレクトリにコピーします。

    2012年6月4日 3:43
  • リプライありがとうございます。

    > 基本的には環境を統一する1択だと思います。

    オープンソースプロジェクトなど、不特定多数の開発者が任意の開発環境で開発を行うプロジェクトをご存じならご理解頂けると思いますが、開発環境をすべて統一することができないプロジェクトも実際には存在します。特に大規模なシステムを開発することになると、プロジェクトをモジュール単位で個々の開発者(社内とは限りません。例えば外注など)に割り振って開発することも珍しくありません。 aviator___ さんがおっしゃっている「基本的」は、何を基本とされているか存じませんが、条件に「統一はできない」と名言している以上、それに従った回答を頂けると幸いです。

    > なぜ参照パスを絶対パス前提で会話されているのか

    絶対パスを前提として会話しているつもりはありません。事実、例として提示しているバッチファイルでは、パス中に相対パス「..」を盛り込んでいますが・・・。

    > vbprojファイルのHintPathって所をご確認下さい。

    ありがとうございます。確認いたします。

    > 参照パスはアプリの内部情報

    「Makefile のような柔軟な開発ができるものではない、VisualStudio でブラックボックス化されている部分は、手を加えずに諦めた方が良い」ということでしょうか。確かに、私も VisualStudio、特に VB.NET の開発環境周りにそこまでの柔軟かつ高度な開発ができるとは考えていません。


    総じてこちらの質問の仕方が悪かったようです。申し訳ございません。

    バッチファイルから起動した開発環境 Visual Studio は、そのバッチファイル中で定義した環境変数を利用できるというのが私の認識です。(事実、バッチファイル中で定義したライブラリパスを VisualStudio のビルド時に使用することができました)
    しかし、いざ VB.NET プロジェクトで「デバッグ実行」を実行した際、testapp.exe はバッチファイル中で定義した環境変数 PATH を読んでいない模様です。
    どうしたら VB.NET でデバッグ実行したプロセスから環境変数を利用できるようになるのでしょうか。

    という質問にするべきでした。

    2012年6月4日 4:14
  • リプライありがとうございます。

    先の質問文にもございますが、

    2) 例に上げた 3rdparty.dll は、実際には一つのファイルではなく、さらに数百 MB もあるので、(例で言う)E:\path\to\bin から testapp/bin/Debug にそれらをコピーしてくる、という事はしたくない。

    ということです。

    せっかくご提案頂いたのに、申し訳ございません。

    2012年6月4日 4:17
  • とりあえず、*.vbproj、*.csprojなどの.projファイルはdevenvではなくMSBuildが処理しています。Visual Studio 2010からは.vcxprojによりC++に関してもMSBuildが処理するようになりました。リンク先にもありますが、書式や処理内容は公開されていて自由に編集できます。

    コピーしたくなくて環境がバラバラと言われるとどうしたものやら…? 開発中とは別にリリース?時にはどうするのでしょうか? 開発中もリリースに合わせて処理すればいいような。例えばリリース形態によってはLoadLibraryで読み込めるよう設定してしまうとか。

    2012年6月4日 5:08
  • 佐祐理様

    何度もリプライを頂き、申し訳ありません。

    >devenvではなくMSBuildが処理しています

    なるほど、MSBuild が一環して環境を提供しているのですね。
    VS2008 環境ですが、これから勉強してみます。

    > コピーしたくなくて

    もう少し具体的にコピーしたくない理由を申しますと、

    1) 開発者が作業環境として利用している Windows の「一部」は仮想環境で、システムを終了したらまっさらな状態に戻る。ネイティブ環境の開発者もある。
    2) 基本的にまっさらな状態から、Subversion で作業コピーをチェックアウトしてきて、作業を行う。例外もある。
    3) コミット後、またまっさらな状態に戻す。ただし、3rdparty.dll はネットワークドライブ上にあるので、作業環境からダイナミックにアクセス可能。
    4) パスを通すか実行時リンク LoadLibrary さえすれば、動的リンクが可能なのが DLL なので、わざわざ作業の度にローカルの出力フォルダに持ってくるのは本末転倒のような・・・。

    という考えがありました。
    リリース版は、VisualStudio の機能を利用しない独自のスクリプトで配布形式を作成しますので、特に問題にはなっておりません。
    また、名前のとおり 3rdparty.dll は別の組織で開発されているものです。

    > 環境がバラバラ

    昔の Windows アプリケーションのように「Cドライブの直下に決め打ちでインストールさせる!」みたいな力技ができなくなっている昨今ですので、ファイル構造の差異くらいだったら環境変数に定義させておいて、開発者ごとに切り替えて使うのがスマートなんじゃないかなあ、と思いました。

    UNIX 風に言うと、

    PATH=/path/to/bin cgdb testapp
    

    のようにデバッグ実行時に環境変数を指定できればな、と思っただけなんですが、私の質問も的を得ていませんでした。申し訳ありません。

    2012年6月4日 5:57
  • 質問したかったのは、リリース版ではどのように配布形式を作成するのか、ではなく、配布後(インストール後)にどのように3rdparty.dllを参照するのか、です。
    リリース時には同じディレクトリに配置されているのであれば、デバッグ時にもリリース時と同じ環境つまりDLLも同じディレクトリに配置した方がデバッグにも適しているでしょう。

    デバッグ実行時に環境変数を指定する点については、要はdevenv起動前に環境変数を設定するBATを書けばいいのでは?

    2012年6月4日 6:48
  • オープンソースプロジェクトなど、不特定多数の開発者が任意の開発環境で開発を行うプロジェクトをご存じならご理解頂けると思いますが

     だからこそ、リポジトリ一つダウンロード(チェックアウト)すれば全ての環境が整うように、リポジトリを構成します。FA


    Jitta@わんくま同盟

    2012年6月4日 12:10
  • ピンポイントだけで申し訳ないのですが、勘違いされているようなので指摘しておきます。

    そこで、testapp.exe のプロパティ>デバッグ>作業ディレクトリを 3rdparty.dll がある E:\path\to\bin に設定してやると、正常に実行できましたが、複数の環境で開発をしているソリューションなので
    プロジェクトファイルに個人の作業マシンのパスを入力することができません。

    この設定値は、vbproj ではなく、vbproj.user といったプロジェクトファイルとは別のユーザー設定ファイルに保存されます。
    通常、*.user ファイルはレポジトリにチェックインせずに管理するはずなので、個人の作業マシンのパスを入れても支障がないはずなのですが、どうなっていますか?

    // これでうまくいっても、ばっさり消える環境では毎回設定が必要ですが…。

    2012年6月4日 13:52
    モデレータ
  • 環境変数アプローチで海外のネタを調べましたが、正攻法としては用意されていないようですね。
    VS2010 で濃ゆいことをやっている事例があったくらいでした。

    前述のように作業フォルダーの設定で済ませられるのであれば、それが一番楽そうに見えます。

    • 回答の候補に設定 山本春海 2012年6月25日 8:46
    • 回答としてマーク 山本春海 2012年6月28日 8:45
    2012年6月4日 15:19
    モデレータ
  • DEVPATH環境変数を使われてはどうでしょう。PATH環境変数はアセンブリの検索に使えなかったと思います。

    http://msdn.microsoft.com/ja-jp/library/cskzh7h6%28v=vs.100%29.aspx

    この方法はアセンブリ構成ファイルを変更する必要がありますが開発環境であればDLLの位置にかかわらずどのマシンでも同じ設定になります。

    リリースの時には消す必要があります。

    subversionのブランチが使えるのであれば、開発用、リリース用を用意しておくと良いと思います。



    http://systemartlaboratory.com/

    • 回答の候補に設定 山本春海 2012年6月25日 8:45
    • 回答としてマーク 山本春海 2012年6月28日 8:45
    2012年6月5日 0:22
  • リプライありがとうございます。

    3rdparty.dll の配置を含めた構成が、完成していれば良いのですが、こちらも外部で開発途中である為、暫定的な構成でのみ提供されているのが現状です。

    もちろん、最終的な配布形態と同じ状態でデバッグするのがベターだとは理解しています。ただ、本題から少し離れた内容になるので、この話題に関するこれ以上の議論は求めていません。

    > デバッグ実行時に環境変数を指定する点については、要はdevenv起動前に環境変数を設定するBATを書けばいいのでは?

    おっしゃる事と同じ事を最初に考え、それが上手くいかないから、こうして質問をしているわけであります。

    要は、バッチファイル中でdevenvを起動する前に設定した環境変数が、VB.NETのデバッグ実行時に設定が読めない、と・・・。

    2012年6月5日 0:46
  • 本題とかけはなれたリプライは、他の方にも迷惑ですので撤回してください。

    # あなたは Ruby を使ったツールのリポジトリに Ruby 本体を入れるタイプですか?
    # それなら反論の余地もないですね ;P

    2012年6月5日 0:48
  • 同等の構成でテストしましたが環境変数は反映されていました。

    アセンブリを探せないのはPATH環境変数がアセンブリの検索に使われないからではないかと思います。


    http://systemartlaboratory.com/

    2012年6月5日 2:03
  • Azulean 様

    リプライありがとうございます。

    > この設定値は、vbproj ではなく、vbproj.user といったプロジェクトファイルとは別のユーザー設定ファイルに保存されます。

    そのとおりです。申し訳ありません。少し混同しておりました。

    > 通常、*.user ファイルはレポジトリにチェックインせずに管理するはずなので、個人の作業マシンのパスを入れても支障がないはずなのですが、どうなっていますか?
    > // これでうまくいっても、ばっさり消える環境では毎回設定が必要ですが…。

    ご指摘のとおりです。やはり、少しいびつな形態での開発ですので、変なことをせずに毎回設定してやる方がいいのかもしれませんね。

    大変参考になりました。

    2012年6月5日 2:13
  • Azulean 様

    何度もリプライ、ありがとうございます。

    UNIX 環境での開発と二足草鞋で作業をする事が多く、「パスでも何でも環境変数で定義しておけばいいのでは?」という考えが先立ってしまっていました。
    (そのような用途の為にあるのが環境変数ですし :)

    ただ、薄々は気付いていましたが Windows での環境変数の取り扱いはちょっと感覚が違っているようで

    > 正攻法としては用意されていないようですね。

    というご指摘にひどく共感いたしました。

    ご提示頂きましたページも参考にさせて頂きます。ありがとうございました。

    2012年6月5日 2:18
  • 暫定だろうがリリース時と同じ環境にすることに変わりはありません。

    リリース時にも環境変数を参照するのであれば、デバッグ環境でも環境変数を設定すべきですし、リリース時に同一ディレクトリに配置されるのであれば、デバッグ環境でも同一ディレクトリに配置すべきです。
    例えばMSBuildのCopyタスクにはSkipUnchangedFilesフラグがあり不用意なコピーを削減することもできます。

    # 別枝ですが、製品にRuby本体が含まれるのであれば、リポジトリにも含めます。含まれないのであれば、Visual Studioのように同じパスにインストールするか環境変数から参照できるようにします。
    ## Visual Studioも環境変数VS90COMNTOOLS辺りの値を使ってインストール場所になるべく依存しないようにできます。

    2012年6月5日 2:21
  • 今更感もあるかもしれませんが。3rdparty.dllも構成管理対象の1つとして考えるなら、リポジトリ構成をこんな感じにしておいて

    $/Project
        +--Trunc
             +-- Source
             +-- Lib
    

    Lib配下には、3rdparty.dllやプロジェクトのビルドに必要な全てのDLLをチェックインしておき、各プロジェクトは、$Project/Trunc/Lib配下のDLLを参照するっていうのはよくやるような気もします。毎回開発環境がまっさらな状態になるというなら、たまたま古いDLLでビルドしてしまいI/Fが変わってしまうってのも防げますし。。。


    2012年6月5日 2:31
  •  まぁ、あなたの問題なので、あなたがかけ離れたと判断されるならかけ離れたものなんでしょう。
     少なくともうちでは、Ruby は触ってないので Ruby が入っているわけではありませんが、あるプロジェクトにて OSS パッケージを3つ、リポジトリに入れています。他のプロジェクトでも、必要な複数の、不変の DLL をリポジトリに登録しています。たかだか開発環境を整える事に、工数を割きたくありませんから。共通の環境を作ってもらうか、共通の環境になるようにするか、二つに一つだと思っています。


    Jitta@わんくま同盟

    2012年6月5日 13:23
  • ただ、薄々は気付いていましたが Windows での環境変数の取り扱いはちょっと感覚が違っているようで

    CreateProcess という API の説明 を見てもらえればわかるかと思いますが、親プロセスの環境変数を引き継がないプロセスの立ち上げ方ができます。
    なので、そういった立ち上げ方をしている部分がある場合、その処理の中で環境変数を指定する手段が用意されていないと、正攻法としては「なし」となります。

    // デバッグは一種のプロセス起動である。

    2012年6月5日 13:42
    モデレータ
  • CreateProcess という API の説明 を見てもらえればわかるかと思いますが、親プロセスの環境変数を引き継がないプロセスの立ち上げ方ができます。
    なので、そういった立ち上げ方をしている部分がある場合、その処理の中で環境変数を指定する手段が用意されていないと、正攻法としては「なし」となります。

    // デバッグは一種のプロセス起動である。

      プロセスに対して環境変数が渡るかということと、プロセスが渡された文字列に環境変数が含まれるか検査するというのは、別の問題だと思います。

     VisualStudio の「ビルド イベント」などに設定できるパスを入力する箇所は、「マクロ」が利用できます。その代わり、環境変数は解釈しないようです。作業ディレクトリは、マクロも設定できないようです。

    補足

     コマンドプロンプトで環境変数「MYLIB」を「C:\」と定義します。C:\ 以外へ移動してから devenv を起動します(.sln ファイルを start コマンドで起動)。プロジェクト プロパティの「デバッグ」タブで、「作業ディレクトリ」に「%MYLIB%」を入力した場合、『入力した作業ディレクトリは存在しません。…』となりますが、「...」ボタンをクリックして表示される「作業ディレクトリの選択」ウィンドウに「%MYLIB%」を入力すると、C:\ に移動します。また、プロジェクトのコードに「Environment.GetEnvironmentVariable("MYLIB")」を入れると、デバッグ実行したときでも環境変数を取ることは出来ます。これらのことから、コマンドプロンプト(バッチファイル)から環境変数の受け渡しはできていますが、プロセスが「環境変数を表す文字列」を解釈していないと言えると思います。

     これは Linux でも同じで、C 言語で chdir("$MYLIB") とコードを書いても、環境変数 MYLIB に定義したディレクトリに移動したりしません。Unix でも同じだったと思います。


    Jitta@わんくま同盟


    • 編集済み Jitta 2012年6月6日 13:44
    2012年6月5日 14:41
  • こんにちは、矢矧 さん。

    MSDN フォーラムのご利用ありがとうございます。オペレーターの山本です。

    参考になる情報をいただいているように思われましたので、勝手ながら私の方で回答としてマークさせていただきました。
    アドバイスくださったみなさん、情報ありがとうございます。

    いただいた情報の中で、解決に役立った投稿や、参考になる情報など有効な情報には回答としてマークすることをお願いしています。
    今後、同じ問題でこのスレッドを参照される方にも、有効な情報を活用いただけるかと思いますので、ご協力よろしくお願いいたします。

    今後とも MSDN フォーラムをよろしくお願いいたします。
    _____________________
    日本マイクロソフト株式会社 フォーラム オペレーター 山本 春海

    2012年6月28日 8:45
  •  この件、その後も「DllImport が DLL を探す場所」を調べてみたのですが、Win32API の LoadLibrary 関数が探すのと同じディレクトリであるという情報がありました。ここ(MSDN  フォーラム)や他の掲示板での回答としてあるだけで、正式なドキュメントには見つけることはできなかったので、URL は示しません。

     ところで、最近「exeと同じフォルダにdllを配置しても「指定されたモジュールが見つかりません」のエラーになる。」という質問が上がっています。また、私自身、やはり exe と同じフォルダに dll を配置したにもかかわらず、DLL が読み込めない現象が出ました。「exeと同じ・・・」は、C++ Runtime がインストールされていなかったようです。私の方も、C++ Runtime ではありませんが、使用しているコンポーネントが足りていませんでした(見つからないと言われている DLL ではありません)。このことから、必要な何かが足りないのだけれど、本当に足りていないものとは違うものに対して「ない」というメッセージが出ているのではないかと疑います。


    Jitta@わんくま同盟

    2012年6月28日 14:46