トップ回答者
DLLの入れ替えについて

質問
-
お世話になっております。
DLLを修正した場合に、EXEファイルごとビルドし直す必要があるのかどうかというところで
悩んでいます。
例えば、A.DLLに記述されているメソッドをB.EXEが使用するとします。
このとき、B.EXEではVisual Studioのソリューションエクスプローラの参照設定→参照の追加→参照から
A.DLLファイルを追加しました。
B.EXEを実行する場合、A.DLLはB.EXEと同じフォルダに入れておくと思います。
ここでA.DLLを修正した場合、B.EXEと同じフォルダのA.DLLを上書きコピーすれば、
B.EXEは再度ビルドする必要なく新しいA.DLLを使用することができるのでしょうか?
ここでの修正は、B.EXEで使っているメソッドの引数等のインターフェースまで
変えるものではないとします。
実際に私自身、単純に戻り値を返すだけのメソッドを含むDLLを作成して、
修正前とあとで戻り値を変える実験をしたところ、
DLLの入れ替えのみで変更が反映されるようなのですが、根拠がわからず、
本番で使用したいアプリケーションでも同様な対処でよいか迷っております。
インターネットでもいくつかDLLの入れ替えについて記述が見られたのですが、
C#についての記述があまりなかった気がします。
MSDNにも以下のような感じで載ってはいたのですが、これのみで判断できるのかわかりません。
(実行時にリンクされるというところ)
http://msdn.microsoft.com/ja-jp/library/3707x96z(VS.80).aspx
結局質問したい内容は、
①上記のように、DLLの修正時はDLLの入れ替えのみで足り、DLLを参照しているEXEファイルのビルドは必要ないのでしょうか。
②①において、DLLの修正の仕方によってEXEのビルドの要不要が変わるのであれば、それはどういう基準でしょうか。
(修正の仕方といっても、インターフェースの変更など明らかに呼び出せない場合は除きます)
最後に今までの流れと全然関係ないのですが
③DLLを参照する場合と、DLL内のコードを直接EXEファイルのソースに直接記述して一緒にビルドする場合で
処理速度に違いは出るのでしょうか。どちらが早いのでしょうか。
だいぶ長くなってしまいましたが、よろしくお願いします。
回答
-
DLLとは「ダイナミックリンクライブラリ」の略で、その名の通り実行時にリンクされるモジュールです。
(逆にEXEファイルにライブラリを組み込む場合は「スタテックリンク」と呼ばれます)
DLLのメリットとしては、共通に使われる処理をDLLとしてひとまとめにして、各EXEファイルの容量を減らしたり、仮にDLLにバグ等があった場合にEXEファイルの修正なしにDLLのみ入れ替えるだけで済むことが挙げられます。
このように、①に関してはEXEファイルのビルドは基本的に不要です。
※「基本的に」と書いたのは、DLLに新たなエントリを追加して、EXEからそのエントリを呼び出す場合はEXEファイルのビルドも必要となります。(これが②の回答になると思います。)
③の処理速度については、厳密に言えばスタティックリンクの方が速いと思いますが、一度DLLを呼び出せばメモリ上にキャッシュされますので、意識する程速度に影響は出ないとおもいます。
※ついでに言えば、Win32APIもDLLの塊ですし。
以上で答えになっていますでしょうか?
-
経験や予想に基づいて記述しています。
参考程度としてお読み頂き、鵜呑みにされないようにご注意下さい。
ハッシュドビーフ さんからの引用 ところでなぜ新しいdlに入れ替えるだけで動作上問題ないのでしょうか。
(というより、一緒にビルドしなかったDLLファイルでも動くことそれ自体がなぞです。)
ここまで来るとそれが気になって仕方ありません。
厳密名を求めていれば、先にそのバージョンや署名等で検証しますが、それが省略された場合は厳密なチェックはないと思います。
型であるとか、メソッドであるとか、DLLに含まれているコードが要求された時点でDLLが読み込まれます。
読み込まれた後、同じ名前等の性質を持つ型を検索します。
見つかればそれを利用しますし、見つからない場合はMissingTypeExceptionだとか、MissingMethodExceptionだとかがスローされます。
そういったようなことで、EXEとDLLの結びつきはあまり強くありません。
名前等の情報(メタデータ)を元に欲しいコードを探すような仕組みであることから、EXEビルド時のDLLと完全一致は必要ありません。
しかし、実際に実行してみるまで、思った通りの動作をするかは分かりません。
# EXEのビルド時と完全に同じDLLを求めていた場合、.NET Frameworkのアップデートで破綻しますよね。(System.Windows.Forms.dllとか)
# .NET Framework 2.0 SP1とかSP2とかこれまで更新されていますし。
ハッシュドビーフ さんからの引用 「DLLを入れ替えるだけで大丈夫です。」と、MSDNライブラリのような公式なところで謳ってくれていればさすがに理論的なところまでわかんなくてもいいんですが、無さそうなのでせめて理論的に…。
「DLLを入れ替えるだけ」ということが、どこまで指しているか分かりにくくありませんか?
DLLを入れ替えるだけといっても、別のDLLをファイル名を変えて入れ替えただけかもしれませんし。
元のDLLと同じ型、インターフェース、メソッドであれば、照合できるとか書いてあれば分かるかも知れませんが。
-
すべての返信
-
DLLとは「ダイナミックリンクライブラリ」の略で、その名の通り実行時にリンクされるモジュールです。
(逆にEXEファイルにライブラリを組み込む場合は「スタテックリンク」と呼ばれます)
DLLのメリットとしては、共通に使われる処理をDLLとしてひとまとめにして、各EXEファイルの容量を減らしたり、仮にDLLにバグ等があった場合にEXEファイルの修正なしにDLLのみ入れ替えるだけで済むことが挙げられます。
このように、①に関してはEXEファイルのビルドは基本的に不要です。
※「基本的に」と書いたのは、DLLに新たなエントリを追加して、EXEからそのエントリを呼び出す場合はEXEファイルのビルドも必要となります。(これが②の回答になると思います。)
③の処理速度については、厳密に言えばスタティックリンクの方が速いと思いますが、一度DLLを呼び出せばメモリ上にキャッシュされますので、意識する程速度に影響は出ないとおもいます。
※ついでに言えば、Win32APIもDLLの塊ですし。
以上で答えになっていますでしょうか?
-
DLLもEXEもC#で作った、.NETのDLLであるという前提で書きます。
(参照設定で追加と書いているので外していないとは思いますが、念のため)
ハッシュドビーフ さんからの引用 ここでA.DLLを修正した場合、B.EXEと同じフォルダのA.DLLを上書きコピーすれば、
B.EXEは再度ビルドする必要なく新しいA.DLLを使用することができるのでしょうか?
その辺はA.DLLが厳密な名前を持つかで変わりそうですね。
http://msdn.microsoft.com/ja-jp/library/51ket42z.aspx
ハッシュドビーフ さんからの引用 ①上記のように、DLLの修正時はDLLの入れ替えのみで足り、DLLを参照しているEXEファイルのビルドは必要ないのでしょうか。
厳密名がないとか、バージョン番号を変えていないとかであれば、多分入れ替えるだけでいけるかもしれませんが、それを言及した資料は見たことがありません。
型が増えたり、減ったりしているとまずいかもしれません。
しかし、.NETのDLLだけ入れ替えるといった手法はあまりお薦めしません。
ハッシュドビーフ さんからの引用 ②①において、DLLの修正の仕方によってEXEのビルドの要不要が変わるのであれば、それはどういう基準でしょうか。
(修正の仕方といっても、インターフェースの変更など明らかに呼び出せない場合は除きます)
DLLが厳密な名前を持つとか、EXE側の参照設定が特定のバージョンに限定しているとか。
CLRのアセンブリの検証の段階で、同一とみなされなかったものはDLLの差し替えだけではこけるので、再ビルドが必要でしょう。
この辺を明確に語っているものはあるのかな…。
ハッシュドビーフ さんからの引用 ③DLLを参照する場合と、DLL内のコードを直接EXEファイルのソースに直接記述して一緒にビルドする場合で
処理速度に違いは出るのでしょうか。どちらが早いのでしょうか。
どの程度のレベルまで意識しているのか分かりませんが、実感できるほどの差はないと思う。
-
CatTailさん Azuleanさん
回答ありがとうございます。
バージョンや厳密名についてはあまり理解していないので、
ちょっと調べてみます。
ところで
Azulean さんからの引用 しかし、.NETのDLLだけ入れ替えるといった手法はあまりお薦めしません。
とのことですが、一般的にはDLLを修正したい場合はどうするのでしょうか。
DLLを参照しているEXEを一個ずつビルドし直すということでしょうか。
1つのソリューションの中にDLLを参照するすべてのEXEのプロジェクトを追加しておき、
一気にビルドするんでしょうか(できるのか試したことないですけど…)。
または基本的に修正しないとか…。
よろしくお願いします。
-
ハッシュドビーフ さんからの引用 DLLを参照しているEXEを一個ずつビルドし直すということでしょうか。
1つのソリューションの中にDLLを参照するすべてのEXEのプロジェクトを追加しておき、
一気にビルドするんでしょうか(できるのか試したことないですけど…)。
または基本的に修正しないとか…。
開発体制によりますが、ほぼ同時に開発・リリースするようなものであれば、1つのソリューションに入れてプロジェクト参照も考えられますが、プロジェクトが巨大すぎてそれが効率的ではないこともあるため、一概には言い切れませんね…。
発言を一部、撤回させて下さい。
バイナリレベルで互換性に問題がないのであれば、可能です。(既存のインターフェースに変更がない等)
ただ、厳密名を設定していると、参照設定をやり直すか、発行者ポリシー等の構成ファイルを用意しなければならないので、単純な入れ替えをする際には、厳密名は設定しない方が良いでしょう。
一般に公開するクラスライブラリであれば、厳密名を設定し、発行者ポリシー等で制御すべきかもしれません。
他に気にかかる点として、配置のソリューションによっては、単純にファイルコピーで済ますと、修復機能が働いたり、VistaのようにProgram Filesに書き込めなかったりするかもしれませんので、ユーザにDLL入れ替えの操作は求めるべきではありません。
-
Azuleanさん
>バイナリレベルで互換性に問題がないのであれば、可能です。(既存のインターフェースに変更がない等)
の部分は、文脈からDLLの上書きコピーでも可能という意味でとらえさせていただきました。
いろいろなサイトを見てみたのですが、主にソフト会社の人がユーザーに対してDLLの新バージョンを配布することを前提にした質問が多かったかなと思いました。
私の場合は、社内で使うだけであり、またDLL名も管理していて重複することはないので厳密名はつけない方向でいます。
よって上書きコピーで良さそうな感じですが、まだちょっと心配なので引き続き回答を募集することにします。
Azuleanさんの回答も大変参考になりました!
-
.NET より前までは、DLL だけを配布することがありました。VC6 の、どの段階でか、DLL だけを配布することはやめようという動きが出始めました。あるいは、DLL だけを配布することが可能なような仕掛けがされ始めました。
.NET では、DLL は共通ディレクトリに置くのではなく、実行ファイルと同じディレクトリに置くことが推奨されています。
この理由は、歴史的背景を知ると、理解しやすいと思います。
Windows 95 の頃は、少ないリソースを有効に使うために、実行時に動的に読み込むことで、多数のアプリケーションから使い回しすることができることが推奨されました。しかし、ご存じのように、Windows 95 の頃は、8.3 ルールでした。このため、ファイル システム上で複数のバージョンの DLL を管理することができませんでした。このため、DLL-HELL と呼ばれる現象が発生します。
いつの頃かよくわかりませんが、DLL にバージョン リソースを持たせて、マニフェスト ファイルにより、バージョン情報を確認することで DLL-HELL を避けるように言われました。しかし、あまり広まっていないようです。
.NET では、さらに進んで、実行ファイルと DLL は同じフォルダに置くことが推奨されます。Windows 95 の頃のような、メモリ的、ハードディスク的な制約はほとんどないからです。
DLL だけ置き換えることは、確かに可能ですが、その実行ファイルとライブラリの組み合わせは、テストされているでしょうか?DLL-HELL を再び招かないためにも、実行ファイルとライブラリは、テストされた組み合わせで使用するのがよいと思います。
-
回答ありがとうございます。
Jitta さんからの引用 .NET では、DLL は共通ディレクトリに置くのではなく、実行ファイルと同じディレクトリに置くことが推奨されています。
私もDLLは実行ファイルと同じフォルダに入れる予定です。
(DLLを参照する実行ファイルが複数あったとして)各実行ファイルのフォルダが違えば、DLLも同様に複数点在することになると思います。
ただ入れ替えるとき、そのdllを使用している実行ファイルをコンパイルせずに、各フォルダ内のdllを入れ替えるだけで大丈夫なのかどうか疑問に思いました。
Jitta さんからの引用 DLL だけ置き換えることは、確かに可能ですが、その実行ファイルとライブラリの組み合わせは、テストされているでしょうか?DLL-HELL を再び招かないためにも、実行ファイルとライブラリは、テストされた組み合わせで使用するのがよいと思います。
確かに、できるできないに関わらず、テストはしたほうが良さそうですね。
テストするようにしたいと思います。でも実行ファイルのビルドし直しはしないかもしれないです。
ところでなぜ新しいdlに入れ替えるだけで動作上問題ないのでしょうか。
(というより、一緒にビルドしなかったDLLファイルでも動くことそれ自体がなぞです。)
ここまで来るとそれが気になって仕方ありません。
経験上というのもあるでしょうが、ある程度理論的に大丈夫だと考えてみなさんそう判断されていると思います。
よろしければそこに至った理論的な背景を教えていただければと思います。
もちろんめっちゃ詳しくなくても、だいたいな説明で構いません。むしろ詳しすぎるとわかんないかもしれませんw
いや、詳しく書いてくださればがんばって理解しますけれども!!!
「DLLを入れ替えるだけで大丈夫です。」と、MSDNライブラリのような公式なところで謳ってくれていればさすがに理論的なところまでわかんなくてもいいんですが、無さそうなのでせめて理論的に…。
この機会にぜひ教えていただければと思います。
今まで回答くださった方だけでなく、たまたまこのスレッドに立ち寄ってくださった熟練の方の回答も大歓迎でございます。
よろしくお願いします。
-
経験や予想に基づいて記述しています。
参考程度としてお読み頂き、鵜呑みにされないようにご注意下さい。
ハッシュドビーフ さんからの引用 ところでなぜ新しいdlに入れ替えるだけで動作上問題ないのでしょうか。
(というより、一緒にビルドしなかったDLLファイルでも動くことそれ自体がなぞです。)
ここまで来るとそれが気になって仕方ありません。
厳密名を求めていれば、先にそのバージョンや署名等で検証しますが、それが省略された場合は厳密なチェックはないと思います。
型であるとか、メソッドであるとか、DLLに含まれているコードが要求された時点でDLLが読み込まれます。
読み込まれた後、同じ名前等の性質を持つ型を検索します。
見つかればそれを利用しますし、見つからない場合はMissingTypeExceptionだとか、MissingMethodExceptionだとかがスローされます。
そういったようなことで、EXEとDLLの結びつきはあまり強くありません。
名前等の情報(メタデータ)を元に欲しいコードを探すような仕組みであることから、EXEビルド時のDLLと完全一致は必要ありません。
しかし、実際に実行してみるまで、思った通りの動作をするかは分かりません。
# EXEのビルド時と完全に同じDLLを求めていた場合、.NET Frameworkのアップデートで破綻しますよね。(System.Windows.Forms.dllとか)
# .NET Framework 2.0 SP1とかSP2とかこれまで更新されていますし。
ハッシュドビーフ さんからの引用 「DLLを入れ替えるだけで大丈夫です。」と、MSDNライブラリのような公式なところで謳ってくれていればさすがに理論的なところまでわかんなくてもいいんですが、無さそうなのでせめて理論的に…。
「DLLを入れ替えるだけ」ということが、どこまで指しているか分かりにくくありませんか?
DLLを入れ替えるだけといっても、別のDLLをファイル名を変えて入れ替えただけかもしれませんし。
元のDLLと同じ型、インターフェース、メソッドであれば、照合できるとか書いてあれば分かるかも知れませんが。
-
-
Azuleanさん KKamegawaさん
回答ありがとうございます。
Azulean さんからの引用 経験や予想に基づいて記述しています。
参考程度としてお読み頂き、鵜呑みにされないようにご注意下さい。
と言われているように、ひとまずAzuleanさんの回答を参考にさせていただきつつ、KKamegawaさんが紹介してくださった本等で調べて自分なりに考えてみたいと思います。
ちなみにですが、C#プログラミングだったか、ちょっと手元に資料がないので正確な名前はわからないのですが、CDが付いてる本にdllの入れ替えるだけで良さそうな感じの文が書いてありました。
ひとまずそれでよしとし、この質問を終わりにしたいと思います。
しかし私の解釈が間違っている可能性もありますので、私と同じくわからない方は、鵜呑みにせずに自分なりに調べてみてくださいm( __ __ )m
今までお付き合いいただきありがとうございました。
今後ともよろしくお願いいたします。