简体   繁体   English

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

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

I have a program which needs to function in both an x86 and an x64 environment. 我有一个程序需要在x86和x64环境中运行。 It is using Oracle's ODBC drivers. 它使用的是Oracle的ODBC驱动程序。 I have a reference to Oracle.DataAccess.DLL. 我有一个Oracle.DataAccess.DLL的引用。 This DLL is different depending on whether the system is x64 or x86, though. 但是,根据系统是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." 我的平台设置为“任何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. 并且我的理解是VS应该将DLL编译为中间语言,这样如果我使用x86或x64版本则无关紧要。 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." 然而,如果我尝试使用x64 DLL,我收到错误“无法加载文件或程序集'Oracle.DataAccess,Version = 2.102.3.2,Culture = neutral,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. 谢谢。

This is a working solution for your problem: 这是解决您问题的有效方法:

Add the 2 DLL's (x86 and x64) to your solution in a subfolder. 将2 DLL(x86和x64)添加到子文件夹中的解决方案中。 Make them "Copy if newer" 让他们“复制如果更新”

Reference the correct DLL you use for development for debugging from the 2 DLL's you added. 从您添加的2 DLL中引用用于开发调试的正确DLL。 Make it Copy Local=false. 使其复制Local = false。

What this does is that when you app starts the DLL is not autoloaded. 这样做是因为当你启动应用程序时,DLL不会自动加载。 It will not be loaded until you use a Type from that assembly. 在使用该程序集中的Type之前,不会加载它。 Once that happens an event will be triggered in .Net that asks where it can find your assembly. 一旦发生这种情况,将在.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时加载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). 一些“混合”程序集往往会失败,除非它们是从磁盘加载的(可以通过在加载之前将它们写入磁盘来解决)。

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 一些选择

  • Create two installers, one for x64 and one for x86. 创建两个安装程序,一个用于x64,另一个用于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. 将两个程序集部署到GAC。 Now it is automatic, .NET picks the right one on either type of machine. 现在它是自动的,.NET在任何一种类型的机器上选择正确的。 Big companies should almost always use the GAC so they can deploy security updates, not sure why Oracle doesn't do this. 大公司应该几乎总是使用GAC,以便他们可以部署安全更新,而不确定Oracle为什么不这样做。
  • Deploy the assemblies to a x86 and x64 subdirectory of the install directory. 将程序集部署到安装目录的x86和x64子目录。 You'll need to write an AppDomain.AssemblyResolve event handler that, based on the value of IntPtr.Size, picks the right directory. 您需要编写一个AppDomain.AssemblyResolve事件处理程序,该处理程序根据IntPtr.Size的值选择正确的目录。
  • Change the target platform on your EXE project to x86. 将EXE项目中的目标平台更改为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. 鉴于您的代码需要在32位计算机上以及在64位计算机上运行,​​因此没有/不应该是为AnyCPU构建的原因。

If you're running on a 32-bit machine, then you have to load the 32-bit version of the Oracle DLL. 如果您在32位计算机上运行,​​则必须加载32位版本的Oracle DLL。 A 32-bit program can't reference a 64-bit DLL. 32位程序无法引用64位DLL。 And, a 64-bit program can't reference a 32-bit DLL. 并且,64位程序不能引用32位DLL。

"Any CPU" is the correct target if you have multiple versions of the external DLL. 如果您有多个版本的外部DLL,“任何CPU”都是正确的目标。 The trick is making sure that the proper Oracle DLL is located and loaded. 诀窍是确保找到并加载正确的Oracle DLL。 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. 最好的办法是在32位系统上找到64位版本的DLL并重命名,以便运行时找不到它。

Using AnyCPU with native early bindings is just not going to work, for that you need two separate solutions and builds as you saw. 使用具有本机早期绑定的AnyCPU是行不通的,因为您需要两个单独的解决方案和构建,如您所见。 You have to get hold of a 64-bit system to develop or at least test x64 compiled dlls on. 你必须得到一个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. 但是,使用后期绑定,您可以使用AnyCPU和系统属性来确定您正在运行的体系结构并链接到正确的dll,如果保留命名为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. 如果它们被安装到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位guest虚拟机。

You shold be able to configure the same solution to build x86/x64 versions separately. 您可以配置相同的解决方案来单独构建x86 / x64版本。 You may also need to add post build steps to copy correct version of DLL to corresponding output folders... 您可能还需要添加后期构建步骤以将正确版本的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个解决方案 - 使用相同的源(添加文件作为参考第二个解决方案,而不是复制到第二个解决方案)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM