oracle 试图不需要 x86 和 x64 程序的两个单独的解决方案

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4599797/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 22:20:32  来源:igfitidea点击:

Trying to not need two separate solutions for x86 and x64 program

c#visual-studio-2008oracle

提问by Sean Anderson

I have a program which needs to function in both an x86 and an x64 environment. It is using Oracle's ODBC drivers. I have a reference to Oracle.DataAccess.DLL. This DLL is different depending on whether the system is x64 or x86, though.

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

Currently, I have two separate solutions and I am maintaining the code on both. This is atrocious. I was wondering what the proper solution is?

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

I have my platform set to "Any CPU." and it is my understanding that VS should compile the DLL to an intermediary language such that it should not matter if I use the x86 or x64 version. Yet, if I attempt to use the x64 DLL I receive the error "Could not load file or assembly 'Oracle.DataAccess, Version=2.102.3.2, Culture=neutral, PublicKeyToken=89b483f429c47342' or one of its dependencies. An attempt was made to load a program with an incorrect format."

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

I am running on a 32 bit machine, so the error message makes sense, but it leaves me wondering how I am supposed to efficiently develop this program when it needs to work on x64.

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

Thanks.

谢谢。

回答by Hans Passant

This is purely a deployment problem, you should never have to maintain different projects. It is an awkward one though, and boo on Oracle for not taking care of this themselves. Another consideration is that this assembly really should be ngen-ed on the target machine. Some options

这纯粹是一个部署问题,您永远不必维护不同的项目。不过,这是一个尴尬的问题,并且对 Oracle 没有自己解决这个问题表示不满。另一个考虑是这个程序集真的应该在目标机器上生成。一些选项

  • Create two installers, one for x64 and one for x86. The customer picks the right one, based on the operating system she uses. Simple enough, you just copy the right file.
  • Deploy both assemblies to the GAC. Now it is automatic, .NET picks the right one on either type of machine. Big companies should almost always use the GAC so they can deploy security updates, not sure why Oracle doesn't do this.
  • Deploy the assemblies to a x86 and x64 subdirectory of the install directory. You'll need to write an AppDomain.AssemblyResolve event handler that, based on the value of IntPtr.Size, picks the right directory.
  • Change the target platform on your EXE project to x86. Given that your code needs to work on a 32-bit machine as well as on a 64-bit machine, there isn't/shouldn't be a reason to build for AnyCPU.
  • 创建两个安装程序,一个用于 x64,一个用于 x86。客户根据她使用的操作系统选择正确的。很简单,您只需复制正确的文件即可。
  • 将两个程序集部署到 GAC。现在它是自动的,.NET 在任一类型的机器上选择正确的。大公司应该几乎总是使用 GAC 以便他们可以部署安全更新,不知道为什么 Oracle 不这样做。
  • 将程序集部署到安装目录的 x86 和 x64 子目录。您需要编写一个 AppDomain.AssemblyResolve 事件处理程序,该处理程序根据 IntPtr.Size 的值选择正确的目录。
  • 将 EXE 项目上的目标平台更改为 x86。鉴于您的代码需要在 32 位机器和 64 位机器上工作,没有/不应该有理由为 AnyCPU 构建。

回答by Wolf5

This is a working solution for your problem:

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

Add the 2 DLL's (x86 and x64) to your solution in a subfolder. Make them "Copy if newer"

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

Reference the correct DLL you use for development for debugging from the 2 DLL's you added. Make it Copy Local=false.

从您添加的 2 个 DLL 中引用您用于开发的正确 DLL 进行调试。使其复制本地 = 假。

What this does is that when you app starts the DLL is not autoloaded. It will not be loaded until you use a Type from that assembly. Once that happens an event will be triggered in .Net that asks where it can find your assembly.

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

So sometime before the first use of that assembly make sure you attach yourself to that event.

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

AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;

In the content of the handler make sure you load the DLL (x86 or x64) when it asks for it.

在处理程序的内容中,确保在需要时加载 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;
    }

Voila. You can now run your app as both 32 bit and 64 bit.

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

Alternatively to adding the DLLs in a subfolder, you can make them as Embedded Resources, and then load them like this:

除了在子文件夹中添加 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;
    }

This does not work for all assemblies. Some "hybrid" assemblies tends to fail unless they are loaded from disk (can be solved by writing them to disk just before loading).

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

回答by Jim Mischel

If you're running on a 32-bit machine, then you have to load the 32-bit version of the Oracle DLL. A 32-bit program can't reference a 64-bit DLL. And, a 64-bit program can't reference a 32-bit DLL.

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

"Any CPU" is the correct target if you have multiple versions of the external DLL. The trick is making sure that the proper Oracle DLL is located and loaded. Your best bet is to locate the 64-bit version of the DLL on your 32-bit system and rename it so that the runtime can't find it.

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

回答by Alexei Levenkov

You shold be able to configure the same solution to build x86/x64 versions separately. You may also need to add post build steps to copy correct version of DLL to corresponding output folders...

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

At least if you have to build 2 solutions - use the same source (add files as refernce to second solution, not copy into second solution).

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

回答by SilverbackNet

Using AnyCPU with native early bindings is just not going to work, for that you need two separate solutions and builds as you saw. You have to get hold of a 64-bit system to develop or at least test x64 compiled dlls on.

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

However, with late binding, you can use AnyCPU and System properties to figure out what architecture you're running as and link to the correct dll, if you keep the named like Oracle.DataAccess.x86.dll. If they're installed into the GAC, it's even easier, you can bind without even bothering to test for architecture first, but I believe you still have to late bind.

但是,通过后期绑定,您可以使用 AnyCPU 和系统属性来确定您正在运行的架构并链接到正确的 dll,如果您保留像 Oracle.DataAccess.x86.dll 这样的名称。如果将它们安装到 GAC 中,那就更容易了,您可以绑定而无需先测试架构,但我相信您仍然需要延迟绑定。

Note that VMware can run a 64-bit guest on a 32-bit host, if you really can't be bothered to reinstall Windows.

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