none
カレントディレクトリ以外でexeを実行するとdllが見つからないエラーになる。 RRS feed

  • 質問

  • いつもお世話になっております。
    VS2008でC#で開発しているツールが正常動作しないので質問させて下さい。

    testA.dll を参照した testB.exeを作成しました。

    出力先ディレクトリは

    release\
     testA.dll
     testB.exe

    のようになります。

    release\の中でB.exeを実行すると正常動作するのですが
    release\にパスを通し、カレント以外のディレクトリでtestB.exeを実行すると

    -----------------------------------------------------------------------------------------
    ハンドルされていない例外: System.IO.FileNotFoundException:
    ファイルまたはアセンブリ 'testA, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'、
    またはその依存関係の 1 つが読み込めませんでした。

    指定されたファイルが見つかりません。
    ファイル名 'testA, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' です。
       場所 testB.Program.Main(String[] args)

    警告: アセンブリ バインドのログ記録がオフにされています。
    アセンブリ バインドのエラー ログを有効にするには、
    レジストリ値 [HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) を 1 に設定してください。
    注意: アセンブリ バインドのエラー ログに関連するパフォーマンス ペナルティがあります。
    この機能をオフにするには、レジストリ値 [HKLM\Software\Microsoft\Fusion!EnableLog] を削除します。
    -----------------------------------------------------------------------------------------

    と言うエラーが出て実行出来ません。
    ただし、カレント以外でも絶対パス指定でexeを実行すると正常動作します。

    一体、何がいけないのでしょうか?

     

    2010年7月9日 8:19

回答

  • バッチファイル内でのPATH設定は、その有効範囲は、そのコマンドプロンプト内だけになります。

    おそらく、以下の流れになってるのではないでしょうか。

    ①バッチ起動

    ②バッチ内でPATHを設定

    ③EXE起動

    ④EXEからはバッチで設定したPATHは見えない

    ⑤DLLが参照できない

     

    試しに、システム環境変数にパスを設定し、バッチから set PATH の記述を削除して実行してみてください。

    • 回答としてマーク zilch_1975 2010年7月9日 11:26
    2010年7月9日 10:07

すべての返信

  • 基本的に、プロジェクトからDLLを参照している状態でコンパイルすれば、releaseフォルダに

    そのDLLも出力されているはずです。

    .NETはside-by-side実行であるので、その状態で配布するのが当たり前になります。

    http://msdn.microsoft.com/ja-jp/library/8477k21c(VS.80).aspx

    ですので、事情がない限りは、exeとdll群のディレクトリは同一にしてください。

     

    ではexeとdllが同じ階層にない場合にどうするかというと、GACに登録するなり、アプリケーションの設定でパスを

    指定するなりの色々な方法が必要になります。

    GACへの登録はあまりおすすめはしませんので、以下、パスを指定する方法です。

     

    以下のような状態だとします。

    c:\hoge\hoge.dll

    c:\hoge\fuga\piyo.exe

     

    piyo.exeと同じルートに、以下のアプリケーション構成ファイルを作成します。

    ※ファイル名は、piyo.exe.config

    追記:ファイルはUTF-8で保存

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
     <runtime>
     <developmentMode developerInstallation="true"/>
     </runtime>
    </configuration>
    

     

    次に、システムのプロパティにある環境変数を開き、システム環境変数に以下を追加します。

     

    名前:DEVPATH
    値:c:\hoge

     

    これで、実行時にちゃんとDLLを読み込むようになると思います。

    • 編集済み honefai 2010年7月9日 9:20 追記
    2010年7月9日 9:18
  • アセンブリの検索にPATHは使わないからです。下記を参照してどういう検索をするか調べてみてください。

    http://msdn.microsoft.com/ja-jp/library/9h55zhet(v=VS.80).aspx

    ただ、何も考えずに exe と dll を同じディレクトリに入れる方が簡単です。

    2010年7月9日 9:22
  • honefai様

    素早い回答有難う御座います。

    今回、問題が起きている環境はDLLもEXEも同一ディレクトリで配布しております。
    コマンドラインから実行するツールなのですが、EXEがあるディレクトリに移動してからEXEを実行すると問題ないのですが
    EXEがあるディレクトリにパスを通して、EXEがあるディレクトリ以外で実行した時に問題が起こるのです。

    説明が下手で申し訳御座いません。

    2010年7月9日 9:23
  • 説明が曖昧でした。

    問題が起こるのは
    release\にパスを通し、カレント以外のディレクトリでtestB.exeを実行すると・・・
    ではなく
    release\にパスを通し、カレント以外のディレクトリでtestB.exeを呼び出すと・・・
    でした。

    DLLとEXEは同じディレクトリの同じ階層にあります。

     

    2010年7月9日 9:32
  • ちょっと試してみたのですが、どうも再現しません。

    c:\hoge\fuga\bin\Release\hoge.dll

    c:\hoge\fuga\bin\Release\piyo.exe

     

    システム環境変数

    Path = c:\hoge\fuga\bin\Release

     

    コマンドプロンプト

    c:\>

    c:\>piyo.exe

     

    でエラーもなく表示されます。

    確認ですが、上記のような環境及び設定で実行されてるのでしょうか。

    2010年7月9日 9:41
  • DLL、EXEの環境は同じです。
    異なるのは『システム環境変数』は使用しておりません。

    バッチファイルからオープンしたDOS窓だけでPATHが有効になるように(本ツールは環境変数使用禁止環境で動作するツール)

    @setlocal
    @set PATH=%PATH%;%~dp0\..\EXEとDLLのあるパス;
    @cmd
    @endlocal

    のようなバッチを提供し、@cmdで開かれたコマンドプロンプト内で使用しております。

    2010年7月9日 9:47
  • 考えてみると自作アプリをファイル名のみで実行ってやったことないかも…というのはおいといて
    念のため確認ですが testB.exe は本当に release の下のものが実行されているのでしょうか?
    もっとも、UNIX だと which testB.exe で簡単にフルパス表示できるのですが
    Windows だと面倒なようです(?)

    whichコマンドを作る
    http://www.atmarkit.co.jp/fwin2k/win2ktips/319which/which.html

     

    追記:which コマンドとか作らなくても、フルパス実行で同じエラーなら OK ですね。

    • 編集済み anningo 2010年7月9日 10:16 追記
    2010年7月9日 10:06
  • バッチファイル内でのPATH設定は、その有効範囲は、そのコマンドプロンプト内だけになります。

    おそらく、以下の流れになってるのではないでしょうか。

    ①バッチ起動

    ②バッチ内でPATHを設定

    ③EXE起動

    ④EXEからはバッチで設定したPATHは見えない

    ⑤DLLが参照できない

     

    試しに、システム環境変数にパスを設定し、バッチから set PATH の記述を削除して実行してみてください。

    • 回答としてマーク zilch_1975 2010年7月9日 11:26
    2010年7月9日 10:07
  • honefai様

    大変お騒がせ致しました。
    解決致しました。
    C#とは全く関係のない事でした・・・バッチファイルの問題でした。

    @setlocal
     @set PATH=%PATH%;%~dp0\..\EXEとDLLのあるパス;
     @cmd
    @endlocal

    の『%~dp0\』が問題だったようです。
    正しくは『%~dp0』でした。

    %~dp0\だと展開されると
    xxx\\..\EXEとDLLのあるパス;
    となるようで、\\となるのが今回の問題の原因でした。

    \\でもパスは通ってEXEの実行は出来るがDLL検索時に問題になるようです。

    大変お騒がせしました。

    2010年7月9日 11:29
  • anningo様

    そうなんです。
    コマンドラインから実行するツールは滅多に作らないので今回嵌ってしまいました。
    何とか解決出来ました。

    有難う御座いました。

    2010年7月9日 11:31