[英]Trying to not need two separate solutions for x86 and x64 program
我有一个程序需要在x86和x64环境中运行。 它使用的是Oracle的ODBC驱动程序。 我有一个Oracle.DataAccess.DLL的引用。 但是,根据系统是x64还是x86,此DLL会有所不同。
目前,我有两个独立的解决方案,我维护两者的代码。 这太残忍了。 我想知道什么是正确的解决方案?
我的平台设置为“任何CPU”。 并且我的理解是VS应该将DLL编译为中间语言,这样如果我使用x86或x64版本则无关紧要。 然而,如果我尝试使用x64 DLL,我收到错误“无法加载文件或程序集'Oracle.DataAccess,Version = 2.102.3.2,Culture = neutral,PublicKeyToken = 89b483f429c47342'或其中一个依赖项。加载格式不正确的程序。“
我在32位机器上运行,所以错误信息是有意义的,但它让我想知道当我需要在x64上工作时我应该如何有效地开发这个程序。
谢谢。
这是解决您问题的有效方法:
将2 DLL(x86和x64)添加到子文件夹中的解决方案中。 让他们“复制如果更新”
从您添加的2 DLL中引用用于开发调试的正确DLL。 使其复制Local = false。
这样做是因为当你启动应用程序时,DLL不会自动加载。 在使用该程序集中的Type之前,不会加载它。 一旦发生这种情况,将在.Net中触发事件,询问它可以在何处找到您的程序集。
因此,在第一次使用该程序集之前的某个时间,请确保将自己附加到该事件。
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
在处理程序的内容中,确保在请求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;
}
瞧。 您现在可以将应用程序作为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;
}
这不适用于所有程序集。 一些“混合”程序集往往会失败,除非它们是从磁盘加载的(可以通过在加载之前将它们写入磁盘来解决)。
这纯粹是一个部署问题,您永远不应该维护不同的项目。 虽然这是一个尴尬的问题,并且甲骨文因为没有自己照顾这个问题而嘘声。 另一个考虑因素是该组件确实应该在目标机器上使用。 一些选择
如果您在32位计算机上运行,则必须加载32位版本的Oracle DLL。 32位程序无法引用64位DLL。 并且,64位程序不能引用32位DLL。
如果您有多个版本的外部DLL,“任何CPU”都是正确的目标。 诀窍是确保找到并加载正确的Oracle DLL。 最好的办法是在32位系统上找到64位版本的DLL并重命名,以便运行时找不到它。
使用具有本机早期绑定的AnyCPU是行不通的,因为您需要两个单独的解决方案和构建,如您所见。 你必须得到一个64位系统来开发或至少测试x64编译的dll。
但是,使用后期绑定,您可以使用AnyCPU和系统属性来确定您正在运行的体系结构并链接到正确的dll,如果保留命名为Oracle.DataAccess.x86.dll。 如果它们被安装到GAC中,它甚至更容易,你可以绑定而不用费心去测试架构,但我相信你还是要迟到绑定。
请注意,如果您真的无法重新安装Windows,VMware可以在32位主机上运行64位guest虚拟机。
您可以配置相同的解决方案来单独构建x86 / x64版本。 您可能还需要添加后期构建步骤以将正确版本的DLL复制到相应的输出文件夹...
至少如果你必须构建2个解决方案 - 使用相同的源(添加文件作为参考第二个解决方案,而不是复制到第二个解决方案)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.