実行時に 32 ビット/64 ビット ライブラリを遅延バインドする方法

StackOverflow https://stackoverflow.com/questions/22322

  •  09-06-2019
  •  | 
  •  

質問

説明されているものと似ていますが、微妙に異なる問題があります ここ (アセンブリとその依存関係の読み込み)。

私は 3D レンダリング用の C++ DLL を持っており、これを顧客に販売しています。.NET ユーザーのために、CLR ラッパーを用意します。C++ DLL は 32 ビット バージョンと 64 ビット バージョンの両方でビルドできますが、CLR は特定の DLL にバインドされるため、2 つの CLR ラッパーが必要になるということだと思いますか?

ここで、お客様が 32 ビットまたは 64 ビットのいずれかの .NET アプリを持っており、それが純粋な .NET アプリであるため、CLR に単一のアセンブリ セットからの処理を任せているとします。問題は、アプリ コードが実行時に 32 ビットと 64 ビットの CLR/DLL の組み合わせをどのように動的に選択できるかということです。

さらに具体的に言えば、前述の質問に対する提案された回答はここにも当てはまりますか (すなわち、ResolveEvent ハンドラーを作成します)?

役に立ちましたか?

解決

ようやくこれに対する答えが得られ、機能すると思われます。

32 ビットと 64 ビットの両方のバージョン (マネージド版とアンマネージド版の両方) を別々のフォルダーにコンパイルします。次に、.NET アプリが実行時にアセンブリをロードするディレクトリを選択します。

ResolveEvent の使用に関する問題は、アセンブリが見つからない場合にのみ呼び出されるため、誤って 32 ビット バージョンを使用してしまう可能性があることです。代わりに、正しいフォルダーを指すように ApplicationBase プロパティを変更できる 2 番目の AppDomain オブジェクトを使用します。したがって、次のようなコードになります。

static void Main(String[] argv)
  {
     // Create a new AppDomain, but with the base directory set to either the 32-bit or 64-bit
     // sub-directories.

     AppDomainSetup objADS = new AppDomainSetup();

     System.String assemblyDir = System.IO.Path.GetDirectoryName(Application.ExecutablePath);
     switch (System.IntPtr.Size)
     {
        case (4): assemblyDir += "\\win32\\";
           break;
        case (8): assemblyDir += "\\x64\\";
           break;
     }

     objADS.ApplicationBase = assemblyDir;

     // We set the PrivateBinPath to the application directory, so that we can still
     // load the platform neutral assemblies from the app directory.
     objADS.PrivateBinPath = System.IO.Path.GetDirectoryName(Application.ExecutablePath);

     AppDomain objAD = AppDomain.CreateDomain("", null, objADS);
     if (argv.Length > 0)
        objAD.ExecuteAssembly(argv[0]);
     else
        objAD.ExecuteAssembly("MyApplication.exe");

     AppDomain.Unload(objAD);

  }

最終的には、通常のアプリと、ロードするビットを選択する 2 番目の切り替えアプリの 2 つの exe が作成されます。注 - この詳細については私自身の功績として認められません。私の同僚の一人は、私の最初の指摘を踏まえて、それを推測しました。彼が StackOverflow にサインアップしたら、私が答えを彼に割り当てます

他のヒント

1年ほど前にこれを行うことができましたが、詳細はもう覚えていません。基本的に、IntPtr.Size を使用してロードする DLL を決定し、p/Invoke を通じて実際の LoadLibrary を実行できます。この時点で、モジュールはメモリ内にあり、その内部から関数を p/Invoke できるはずです。同じモジュール名が再びリロードされるべきではありません。

ただし、私のアプリケーションでは実際に C++ DLL 自体を COM サーバーとして登録し、生成された .NET ラッパーを通じてその機能にアクセスしたと思います。そのため、p/Invoking を直接テストしたことがあるかどうかはわかりません。

しばらく前に同様のシナリオに遭遇しました。私が使用していたツールキットは 64 ビット環境では適切に動作せず、アセンブリを動的に 32 ビットとしてバインドする方法を見つけることができませんでした。

アセンブリを強制的に 32 ビット モードで動作させることは可能ですが、これには CLR ヘッダーにパッチを適用する必要があり (フレームワークにはそれを行うツールがあります)、アセンブリに厳密な名前が付けられている場合、これは機能しません。

32 ビット プラットフォームと 64 ビット プラットフォーム用に 2 セットのバイナリをビルドして公開する必要があると思います。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top