【问题标题】:Trying to not need two separate solutions for x86 and x64 program试图不需要 x86 和 x64 程序的两个单独的解决方案
【发布时间】:2011-01-05 00:20:54
【问题描述】:

我有一个程序需要在 x86 和 x64 环境中运行。它使用 Oracle 的 ODBC 驱动程序。我参考了 Oracle.DataAccess.DLL。不过,这个 DLL 会根据系统是 x64 还是 x86 而有所不同。

目前,我有两个单独的解决方案,我正在维护这两个解决方案的代码。这太残暴了。我想知道正确的解决方案是什么?

我的平台设置为“任何 CPU”。我的理解是 VS 应该将 DLL 编译为一种中间语言,这样我使用 x86 或 x64 版本就无关紧要了。但是,如果我尝试使用 x64 DLL,我会收到错误消息“无法加载文件或程序集 'Oracle.DataAccess, Version=2.102.3.2, Culture=neutral, PublicKeyToken=89b483f429c47342' 或其依赖项之一。已尝试加载格式不正确的程序。”

我在 32 位机器上运行,所以错误消息是有道理的,但它让我想知道当它需要在 x64 上运行时,我应该如何有效地开发这个程序。

谢谢。

【问题讨论】:

  • 如果您要开发 32/64 位应用程序,您应该使用 64 位操作系统。至少对于 Windows,32 位操作系统无法运行 64 位程序,但 64 位操作系统可以运行 32 位程序。
  • 另一个需要思考的问题是“我的应用真的需要以 64 位运行吗?” WOW 在 x64 上运行 32 位应用程序做得非常出色。

标签: c# visual-studio-2008 oracle


【解决方案1】:

这纯粹是一个部署问题,您永远不必维护不同的项目。虽然这是一个尴尬的问题,而且甲骨文自己没有处理好这个问题。另一个考虑因素是这个程序集确实应该在目标机器上进行生成。一些选项

  • 创建两个安装程序,一个用于 x64,一个用于 x86。客户根据她使用的操作系统选择正确的。很简单,您只需复制正确的文件即可。
  • 将这两个程序集部署到 GAC。现在它是自动的,.NET 在任何一种类型的机器上都可以选择正确的。大公司应该几乎总是使用 GAC,以便他们可以部署安全更新,不知道甲骨文为什么不这样做。
  • 将程序集部署到安装目录的 x86 和 x64 子目录。您需要编写一个 AppDomain.AssemblyResolve 事件处理程序,它根据 IntPtr.Size 的值选择正确的目录。
  • 将 EXE 项目上的目标平台更改为 x86。鉴于您的代码需要在 32 位机器和 64 位机器上运行,因此没有/不应该为 AnyCPU 构建代码。

【讨论】:

    【解决方案2】:

    这是解决您问题的有效解决方案:

    将 2 个 DLL(x86 和 x64)添加到您的解决方案的子文件夹中。让它们“如果更新则复制”

    参考您用于开发的正确 DLL,以便从您添加的 2 个 DLL 中进行调试。使其 Copy Local=false。

    这样做是当您的应用程序启动时,DLL 不会自动加载。在您使用该程序集中的类型之前,它不会被加载。一旦发生这种情况,将在 .Net 中触发一个事件,询问它在哪里可以找到您的程序集。

    因此,在第一次使用该程序集之前,请确保您将自己附加到该事件中。

    AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
    

    在处理程序的内容中,确保您在请求时加载 DLL(x86 或 x64)。

        static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) {
            if (args.Name.Equals("MyFullAssemblyName")) {
                var path = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
                if (IntPtr.Size > 4) {
                    var dll = System.IO.Path.Combine(path, @"MySubDir\MyDLL_x64.dll");
                    return System.Reflection.Assembly.LoadFile(dll);
                }
                else {
                    var dll = System.IO.Path.Combine(path, @"MySubDir\MyDLL.dll");
                    return System.Reflection.Assembly.LoadFile(dll);
                }
            }
            return null;
        }
    

    瞧。您现在可以以 32 位和 64 位的方式运行您的应用程序。

    除了在子文件夹中添加 DLL 之外,您还可以将它们作为嵌入式资源,然后像这样加载它们:

        static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) {
            if (args.Name.Equals("MyFullAssemblyName")) {
                var ass = Assembly.GetExecutingAssembly();
    
                if (IntPtr.Size > 4) {
                    var strm = ass.GetManifestResourceStream("the.resource.name.for.MyDLL_x64.dll");
                    var data = new byte[strm.Length];
                    strm.Read(data, 0, data.Length);
                    return Assembly.Load(data);
                }
                else {
                    var strm = ass.GetManifestResourceStream("the.resource.name.for.MyDLL.dll");
                    var data = new byte[strm.Length];
                    strm.Read(data, 0, data.Length);
                    return Assembly.Load(data);
                }
            }
            return null;
        }
    

    这不适用于所有程序集。一些“混合”程序集往往会失败,除非它们是从磁盘加载的(可以通过在加载之前将它们写入磁盘来解决)。

    【讨论】:

      【解决方案3】:

      如果您在 32 位计算机上运行,​​则必须加载 32 位版本的 Oracle DLL。 32 位程序不能引用 64 位 DLL。而且,64 位程序不能引用 32 位 DLL。

      如果您有多个版本的外部 DLL,“任何 CPU”是正确的目标。诀窍是确保找到并加载了正确的 Oracle DLL。最好的办法是在 32 位系统上找到 64 位版本的 DLL 并重命名它,以便运行时找不到它。

      【讨论】:

      • 我认为我们在同一个球场,但我的想法并没有被完全正确地传达。我在“32 位解决方案”中手动包含了正确的 32 位 dll,在“64 位解决方案”中包含了 64 位 dll。当我需要生成可执行文件时,我会构建两个单独的解决方案。当我开发时,我只在 32 位中工作,当我完成代码更改时,我必须在 64 位解决方案上复制这些更改。我想只使用一种解决方案而不是两种,但结果相同。
      【解决方案4】:

      将 AnyCPU 与本机早期绑定一起使用是行不通的,因为您需要两个单独的解决方案并如您所见那样构建。您必须掌握 64 位系统才能开发或至少测试 x64 编译的 dll。

      但是,通过后期绑定,您可以使用 AnyCPU 和 System 属性来确定您正在运行的架构并链接到正确的 dll,前提是您保持命名为 Oracle.DataAccess.x86.dll。如果将它们安装到 GAC 中,那就更容易了,您可以绑定,甚至无需先测试架构,但我相信您仍然需要后期绑定。

      请注意,如果您实在懒得重新安装 Windows,VMware 可以在 32 位主机上运行 64 位客户机。

      【讨论】:

        【解决方案5】:

        您应该能够配置相同的解决方案来分别构建 x86/x64 版本。您可能还需要添加构建后步骤以将正确版本的 DLL 复制到相应的输出文件夹...

        至少如果您必须构建 2 个解决方案 - 使用相同的源(添加文件作为对第二个解决方案的引用,而不是复制到第二个解决方案中)。

        【讨论】:

          猜你喜欢
          • 2011-02-05
          • 2010-12-07
          • 2020-08-19
          • 1970-01-01
          • 2011-07-01
          • 1970-01-01
          • 2013-08-02
          • 1970-01-01
          • 2015-01-05
          相关资源
          最近更新 更多