Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用并排程序集加载x64或x32版本的DLL 我们有两个版本的托管C++程序集,一个是x86,一个是x64。此程序集由为AnyCPU编写的.net应用程序调用。我们正在通过文件副本安装部署代码,并希望继续这样做_C#_.net_64 Bit - Fatal编程技术网

C# 使用并排程序集加载x64或x32版本的DLL 我们有两个版本的托管C++程序集,一个是x86,一个是x64。此程序集由为AnyCPU编写的.net应用程序调用。我们正在通过文件副本安装部署代码,并希望继续这样做

C# 使用并排程序集加载x64或x32版本的DLL 我们有两个版本的托管C++程序集,一个是x86,一个是x64。此程序集由为AnyCPU编写的.net应用程序调用。我们正在通过文件副本安装部署代码,并希望继续这样做,c#,.net,64-bit,C#,.net,64 Bit,当应用程序动态选择其处理器体系结构时,是否可以使用并行程序集清单分别加载x86或x64程序集?或者是否有其他方法在文件副本部署中完成此操作(例如,不使用GAC)?您可以使用该实用程序强制将AnyCPU exe加载为x86或x64可执行文件,但是,除非您根据目标选择要复制的exe,否则这并不完全满足文件复制部署要求。我创建了一个简单的解决方案,能够从编译为AnyCPU的可执行文件加载特定于平台的程序集。使用的技术可总结如下: (C:\TEMP\CrossPlatformTest, root dir

当应用程序动态选择其处理器体系结构时,是否可以使用并行程序集清单分别加载x86或x64程序集?或者是否有其他方法在文件副本部署中完成此操作(例如,不使用GAC)?

您可以使用该实用程序强制将AnyCPU exe加载为x86或x64可执行文件,但是,除非您根据目标选择要复制的exe,否则这并不完全满足文件复制部署要求。

我创建了一个简单的解决方案,能够从编译为AnyCPU的可执行文件加载特定于平台的程序集。使用的技术可总结如下:

(C:\TEMP\CrossPlatformTest, root dir)
    platform (dir)
        amd64 (dir)
            library.dll
        x86 (dir)
            library.dll
    program.exe
    *.cs (source files)
  • 确保默认的.NET程序集加载机制(“Fusion”引擎)找不到平台特定程序集的x86或x64版本
  • 在主应用程序尝试加载特定于平台的程序集之前,请在当前AppDomain中安装自定义程序集解析器
  • 现在,当主应用程序需要特定于平台的程序集时,Fusion engine将放弃(因为步骤1)并调用我们的自定义解析器(因为步骤2);在自定义解析器中,我们确定当前平台并使用基于目录的查找来加载适当的DLL
  • 为了演示这项技术,我附加了一个简短的、基于命令行的教程。我在WindowsXPx86和Vista SP1x64上测试了生成的二进制文件(通过复制二进制文件,就像您的部署一样)

    注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:主程序分为两部分。“引导程序”包含可执行文件的主入口点,并在当前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;
            }
        }
    }
    
    “Program”是应用程序的“真实”实现(请注意,App.Run是在Bootstrapper.Main末尾调用的):

    步骤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调试器附加到进程以查看调用堆栈等


    当program.exe运行时,我们的自定义程序集解析器将连接到当前appdomain。一旦.NET开始加载程序类,它就会看到对“library”程序集的依赖,因此它会尝试加载它。但是,找不到这样的程序集(因为我们将其隐藏在platform/*子目录中)。幸运的是,我们的自定义解析器知道我们的诡计,并且基于当前平台,它尝试从相应的platform/*子目录加载程序集。

    我的版本,类似于@Milan,但有几个重要更改:

    • 适用于所有未找到的DLL
    • 可以打开和关闭
    • 使用
      AppDomain.CurrentDomain.SetupInformation.ApplicationBase
      而不是
      Path.GetFullPath()
      ,因为当前目录可能不同,例如在托管场景中,Excel可能会加载插件,但当前目录不会设置为DLL


    • 环境。使用IS64位进程
      而不是
      处理器体系结构
      ,因为我们不应该依赖于操作系统是什么,而是取决于此进程是如何启动的-它可能是x64操作系统上的x86进程。在.NET4之前,请改用
      IntPtr.Size==8

    在某个主类的静态构造函数中调用此代码,该构造函数在所有其他类之前加载

    public static class MultiplatformDllLoader
    {
        private static bool _isEnabled;
    
        public static bool Enable
        {
            get { return _isEnabled; }
            set
            {
                lock (typeof (MultiplatformDllLoader))
                {
                    if (_isEnabled != value)
                    {
                        if (value)
                            AppDomain.CurrentDomain.AssemblyResolve += Resolver;
                        else
                            AppDomain.CurrentDomain.AssemblyResolve -= Resolver;
                        _isEnabled = value;
                    }
                }
            }
        }
    
        /// Will attempt to load missing assembly from either x86 or x64 subdir
        private static Assembly Resolver(object sender, ResolveEventArgs args)
        {
            string assemblyName = args.Name.Split(new[] {','}, 2)[0] + ".dll";
            string archSpecificPath = Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
                                                   Environment.Is64BitProcess ? "x64" : "x86",
                                                   assemblyName);
    
            return File.Exists(archSpecificPath)
                       ? Assembly.LoadFile(archSpecificPath)
                       : null;
        }
    }
    

    看看SetDllDirectory。我在动态加载x64和x86的IBMSPSS程序集时使用了它。它还解决了由程序集加载的非程序集支持dll的路径问题。在我的例子中,spss dll就是这样


    此解决方案也适用于非托管程序集。我创建了一个简单的例子,类似米兰·加迪安的伟大例子。我创建的示例动态地将托管C++ DLL加载到任何CPU平台编译的C*yDLL中。该解决方案利用InjectModuleInitializer nuget包在加载程序集的依赖项之前订阅AssemblyResolve事件


    我们使用类似的方法,但事件附加在静态构造函数中-在某些情况下,这种附加发生在.NET尝试加载另一个程序集之前。请更新为使用Environment.Is64BitProcess,因为它可能与计算机上的CPU不同。否则-回答得很好-我们使用的是类似的东西。
    处理器体系结构
    是正确的-它实际上反映的是进程而不是机器。有人知道这是否适用于非托管程序集吗?我似乎无法为非托管程序集触发
    AssemblyResolve
    事件。
    PROCESSOR\u架构实际上反映的是进程,而不是机器;尝试
    Start->Run
    ing