61

マネージC++アセンブリには2つのバージョンがあります。1つはx86用、もう1つはx64用です。このアセンブリは、AnyCPU用に準拠した.netアプリケーションによって呼び出されます。私たちはファイルコピーインストールを介してコードをデプロイしており、これを継続したいと考えています。

アプリケーションがプロセッサアーキテクチャを動的に選択しているときに、サイドバイサイドアセンブリマニフェストを使用してx86またはx64アセンブリをそれぞれロードすることは可能ですか?または、ファイルコピーの展開でこれを行う別の方法はありますか(GACを使用しないなど)?

4

5 に答える 5

66

AnyCPU としてコンパイルされた実行可能ファイルからプラットフォーム固有のアセンブリをロードできる単純なソリューションを作成しました。使用される技術は次のように要約できます。

  1. デフォルトの .NET アセンブリ ロード メカニズム (「Fusion」エンジン) が、プラットフォーム固有のアセンブリの x86 または x64 バージョンを検出できないことを確認します。
  2. メイン アプリケーションがプラットフォーム固有のアセンブリの読み込みを試みる前に、現在の AppDomain にカスタム アセンブリ リゾルバーをインストールします。
  3. メイン アプリケーションがプラットフォーム固有のアセンブリを必要とする場合、Fusion エンジンは (ステップ 1 のため) あきらめ、カスタム リゾルバーを呼び出します (ステップ 2 のため)。カスタム リゾルバーでは、現在のプラットフォームを特定し、ディレクトリ ベースのルックアップを使用して適切な DLL をロードします。

この手法を実演するために、コマンドライン ベースの短いチュートリアルを添付します。結果のバイナリを Windows XP x86 でテストし、次に Vista SP1 x64 でテストしました (展開と同じように、バイナリをコピーして)。

注 1 : 「csc.exe」は C-sharp コンパイラです。このチュートリアルでは、それがパスにあることを前提としています (私のテストでは "C:\WINDOWS\Microsoft.NET\Framework\v3.5\csc.exe" を使用していました)

注 2 : テスト用の一時フォルダーを作成し、現在の作業ディレクトリがこの場所に設定されているコマンド ライン (または PowerShell) を実行することをお勧めします。

(cmd.exe)
C:
mkdir \TEMP\CrossPlatformTest
cd \TEMP\CrossPlatformTest

ステップ 1 : プラットフォーム固有のアセンブリは、単純な C# クラス ライブラリによって表されます。

// file 'library.cs' in C:\TEMP\CrossPlatformTest
namespace Cross.Platform.Library
{
    public static class Worker
    {
        public static void Run()
        {
            System.Console.WriteLine("Worker is running");
            System.Console.WriteLine("(Enter to continue)");
            System.Console.ReadLine();
        }
    }
}

ステップ 2 : 簡単なコマンドライン コマンドを使用して、プラットフォーム固有のアセンブリをコンパイルします。

(cmd.exe from Note 2)
mkdir platform\x86
csc /out:platform\x86\library.dll /target:library /platform:x86 library.cs
mkdir platform\amd64
csc /out:platform\amd64\library.dll /target:library /platform:x64 library.cs

ステップ 3 : メイン プログラムは 2 つの部分に分割されます。「Bootstrapper」には、実行可能ファイルのメイン エントリ ポイントが含まれており、現在の appdomain にカスタム アセンブリ リゾルバーを登録します。

// file 'bootstrapper.cs' in C:\TEMP\CrossPlatformTest
namespace Cross.Platform.Program
{
    public static class Bootstrapper
    {
        public static void Main()
        {
            System.AppDomain.CurrentDomain.AssemblyResolve += CustomResolve;
            App.Run();
        }

        private static System.Reflection.Assembly CustomResolve(
            object sender,
            System.ResolveEventArgs args)
        {
            if (args.Name.StartsWith("library"))
            {
                string fileName = System.IO.Path.GetFullPath(
                    "platform\\"
                    + System.Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE")
                    + "\\library.dll");
                System.Console.WriteLine(fileName);
                if (System.IO.File.Exists(fileName))
                {
                    return System.Reflection.Assembly.LoadFile(fileName);
                }
            }
            return null;
        }
    }
}

「プログラム」は、アプリケーションの「実際の」実装です (App.Run は Bootstrapper.Main の最後で呼び出されたことに注意してください)。

// file 'program.cs' in C:\TEMP\CrossPlatformTest
namespace Cross.Platform.Program
{
    public static class App
    {
        public static void Run()
        {
            Cross.Platform.Library.Worker.Run();
        }
    }
}

ステップ 4 : コマンド ラインでメイン アプリケーションをコンパイルします。

(cmd.exe from Note 2)
csc /reference:platform\x86\library.dll /out:program.exe program.cs bootstrapper.cs

ステップ 5 : これで完了です。作成したディレクトリの構造は次のようになります。

(C:\TEMP\CrossPlatformTest, root dir)
    platform (dir)
        amd64 (dir)
            library.dll
        x86 (dir)
            library.dll
    program.exe
    *.cs (source files)

32 ビット プラットフォームで program.exe を実行すると、platform\x86\library.dll が読み込まれます。64 ビット プラットフォームで program.exe を実行すると、platform\amd64\library.dll が読み込まれます。Worker.Run メソッドの最後に Console.ReadLine() を追加したことに注意してください。これにより、タスク マネージャー/プロセス エクスプローラーを使用して読み込まれた DLL を調査したり、Visual Studio/Windows Debugger を使用してプロセスにアタッチして、コールスタックなど

program.exe が実行されると、カスタム アセンブリ リゾルバーが現在の appdomain にアタッチされます。.NET が Program クラスのロードを開始するとすぐに、'library' アセンブリへの依存関係が検出されるため、それをロードしようとします。ただし、そのようなアセンブリは見つかりません (platform/* サブディレクトリに隠しているため)。幸いなことに、私たちのカスタム リゾルバーは私たちの策略を知っており、現在のプラットフォームに基づいて、適切な platform/* サブディレクトリからアセンブリを読み込もうとします。

于 2008-10-01T02:42:21.687 に答える
4

SetDllDirectory を見てください。x64 と x86 の両方で、IBM spss アセンブリを動的にロードする際に使用しました。また、アセンブリによってロードされた非アセンブリ サポート dll のパスも解決しました。私の場合は、spss dll の場合でした。

http://msdn.microsoft.com/en-us/library/ms686203%28VS.85%29.aspx

于 2012-06-04T12:16:44.237 に答える
2

corflagsユーティリティを使用して、AnyCPU exe を x86 または x64 実行可能ファイルとして強制的に読み込むことができますが、ターゲットに基づいてコピーする exe を選択しない限り、ファイル コピーの展開要件を完全には満たすことはできません。

于 2008-09-20T18:56:17.797 に答える
1

このソリューションは、管理されていないアセンブリでも機能します。Milan Gardian のすばらしい例に似た簡単な例を作成しました。私が作成した例では、Managed C++ dll を Any CPU プラットフォーム用にコンパイルされた C# dll に動的に読み込みます。このソリューションでは、アセンブリの依存関係が読み込まれる前に、InjectModuleInitializer nuget パッケージを使用して AssemblyResolve イベントをサブスクライブします。

https://github.com/kevin-marshall/Managed.AnyCPU.git

于 2016-11-21T19:14:12.850 に答える