質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.12%

1つのDLLファイルの参照先をプログラム内で変更する。

解決済

回答 5

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 8,504

nmoki

score 10

Oracle.Data.AccessやExcelCreatorを使用したアプリケーションの開発では、x64とx86のdllファイルが用意されています。
Oracle.Data.AccessやExcelCreatorはx64とx86でフォルダを分け、普段はx64のDll
を参照し、x86の実行環境の場合にx86のDLLを使用するように、参照先を変更することは可能でしょうか。
調べているうちにSetDllDirectoryが挙げられていたのですが、
SetDllDirectoryを使用すると、他のDLLファイルの参照先も変わってしまうのでしょうか。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 5

+1

x86の実行環境ではx86フォルダのDLL、x64ならx64フォルダのDLLを参照先を変えて読み込むとなると、DLLを読み込むホストアプリも当然x86とx64の両方用意することになります。

WindowsのDLLの検索場所と優先度は以下のような感じになっていて、

  1. 実行したexeファイルと同じディレクトリ
  2. プロセスのカレントディレクトリ(ショートカット等で指定されている作業フォルダ)
  3. Systemディレクトリ
  4. windowsディレクトリ
  5. 環境変数PATHで指定されたディレクトリ

SetDllDirectoryはそのうち2番の参照先を変更するAPIになり、
1度変更すると再度設定しない限り、現在のプロセス内でのDLLの呼び出し全てに影響します。
libを使ったDLLの暗黙的リンクとLoadLibrary等の動的リンクでDLLの絶対パスを指定しなかった場合の両方に影響します。

単一のDLLの読み込み場所を指定するとなるとLoadLibraryでDLLの絶対パスを渡して動的リンクし、GetProcAddressで個別にDLL内の関数を呼び出して使う形になると思います。
しかし、LoadLibraryでパスを指定して呼び出したDLLが更に別のDLLに依存している場合も、DLLの検索PATHの影響を受けるのでややこしいことになります。

例えばx64フォルダにlibpng.dllzlib1.dllがあって、libpng.dllzlib1.dllに依存しています。

LoadLibraryでlibpng.dllを読み込もうとすると、libpng.dllが内部で依存しているzlib1.dllを呼び出そうとします。
しかし、DLLの検索PATHにはx64フォルダが含まれていないためlibpng.dllと同じフォルダに存在するにもかかわらず、zlib1.dllが見つからないとエラーが出るのです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/07/12 18:07

    後から気が付いたのですが、AnyCPUが…って事はC#かVB.NETが対象でしょうか?
    C++等のネイティブなアプリケーションを想定していたので、.NETのアプリケーションだとこの回答は当てはまらないかもしれません。

    タグにC# or VB.NET等の対象言語も追加したほうがより良い回答が得られるかもしれません。

    ↓の連載記事が役に立つかも?
    http://www.atmarkit.co.jp/fdotnet/technology/idnfw11_02/idnfw11_02_04.html

    キャンセル

  • 2017/07/13 09:09

    回答、並びにアドバイスありがとうございます。
    連載記事を参考にしてみます。

    キャンセル

checkベストアンサー

0

マネージドアセンブリ自体がx86/x64で分かれていた場合は、Windowsの.NET Framework限定ですが、
AppDomain.AssemblyResolveイベントを使って、DLLを動的に読み出すという方法があります。

  • https://msdn.microsoft.com/en-us/library/system.appdomain.assemblyresolve(v=vs.110).aspx
  • http://d.hatena.ne.jp/masa_m/20130108/1357644226

ただし、PCLモジュールが混ざっている場合は、以下のURLのように一工夫必要です。
https://stackoverflow.com/questions/18793959/filenotfoundexception-when-trying-to-load-autofac-as-an-embedded-assembly

対象がネイティブDLLの場合、DllImportのパラメーターにx64用とx86用のものを指定したクラスをそれぞれ作っておいて、Environment.Is64BitProcessで呼ぶクラスを分けるという手段があります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

x86とx64のDLLを読み替えるということでしょうか。
たぶん無理だったと思います。x86、x64のどちらでビルドしたかで、読み込めるDLLは決まるはずです。
プラットフォームと違うDLLを読んだ時点で例外で落ちると思われます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/07/12 17:24

    回答ありがとうございます。
    AnyCPUでビルドを行い、クライントの環境によってDLLを読み替えることは同じく不可能でしょうか。

    キャンセル

  • 2017/07/13 14:14

    それぞれのクライアントを用意する必要がありますね。

    キャンセル

0

こういうのはどうでしょうか?

Kicker.exe
Main_x86.exe
Main_x86.exe.config
Main_x64.exe
Main_x64.exe.config
その他のdll(Any CPU)
lib_x86/x86ライブラリのdll
lib_x64/x64ライブラリのdll

というようにしてKicker.exeでx86/x64かを判定して対応するEXEを起動する。
Main_x86.exe.configには
<probing privatePath="lib_x86"/>
Main_x64.exe.configには
<probing privatePath="lib_x64"/>
と記載して追加でロードする場所を切り替える。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/07/13 12:07

    回答ありがとうございます。

    キャンセル

0

確か Assembly.LoadFrom で動的ロードができたと思います。私が少し前に作ったアプリは、その方法で Temp ディレクトリに任意の dll を保存してロードして使えてました。

Reflection.Assembly.LoadFrom("C:\Program Files (x86)\Oracle Developer Tools for VS2013\odp.net\managed\" & If(Environment.Is64BitProcess, "x64", "x86") & "\Oracle.ManagedDataAccessDTC.dll")


Oracleは詳しくないので良く分かりませんが、上記コードで適切なアセンブリをロードできているようです。ロードした後、DLLの呼び出し方法は試していませんが、以下のいずれかの方法でできると思います。

<32bitと64bitのアセンブリが同一と認識される場合>
1.読み込める方のDLLを参照設定して New でオブジェクトを作って呼び出す。(普通に使う)

<32bitと64bitのアセンブリが同一と認識されない場合>
1.Object型で遅延バインディングを使う。
2.Reflectionの機能を使って呼び出す。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.12%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる