最近在编写.net应用程序时,发现某些平台下无法加载SQLite DLL的问题。
症状表现为:
a. 本地Windows 7/8 64bit开发环境完全正常。
b. 某些Windows 7 64bit用户的计算机无法加载System.Data.SQLite.DLL。
c. 极个别Windows XP的计算机无法加载该DLL。
无法加载DLL时,均报BadImageFormatException异常,甚至直接被Windows关闭而无法采集异常信息。奇怪的是在当前目录包含了这个DLL文件,所以理应能成功加载才是。
由于各种场景的组合在一起,一时很难判断问题出于何处。起初笔者努力尝试各种方法试图在本机重现,也均告失败。在偶然的机会,笔者删除了本机所有与SQLite相关的组件,问题成功重现。
绝望之中燃起了一点希望。我发现自己曾经安装了三个与SQLite相关的组件:
SQLite-1.0.66.0-setup.exe
sqlite-netFx35-setup-bundle-x64-2008-1.0.82.0.exe
sqlite-netFx35-setup-bundle-x86-2008-1.0.82.0.exe
反复多次后确认了以下内容:
SQLite-1.0.66.0-setup.exe - 无效果
sqlite-netFx35-setup-bundle-x86-2008-1.0.82.0.exe - 无效果
sqlite-netFx35-setup-bundle-x64-2008-1.0.82.0.exe - 成功
看来,用户系统上没有sqlite-netFx35-setup-bundle-x64-2008-1.0.82.0.exe,所以导致运行失败。经仔细检查,这个包在系统GAC中安装了64位DLL,而之前我发布的目录中包含的是32位DLL文件。一切真相大白,将64位版本与32位版本分开发布,问题解决!
到这里,本该可以松口气了,但我心中仍然充满疑惑:
(1) 在64位系统上,我的.net应用到底算是32位的还是64位的?
(2) 32位应用程序照理可以在64位系统上正常运行,为什么当前目录的DLL没有加载成功?
(3) 为何以前调用的第三方DLL从没有发生32/64位的问题,只有这个DLL如此特别?
(4) .net的加载DLL的顺序是什么,到底以哪个优先?
经过一番认真的Google,上述迷团一一破解。
(1) 在64位系统上,.net程序是通常以64位程序运行的。Windows不会启用Wow。这可以从任务管理器中看到(在64位系统中运行的32位程序将以*32或“32位”标记)。
然后事情并非还如此简单。.net程序目前有以下几种处理器架构:
Any CPU(处理器无关的纯MSIL代码)
x64(仅64位处理器,又称AMD64)
x86(仅32位处理器)
IA64(仅IA64位处理器)
之前所说的“通常”,即指Any CPU。这样的程序在32位系统上以32位模式运行,在64位系统上以64位模式运行。这时,而标识为特定处理器的,只能在相应的模式上运行。
更详细地,使用corflags工具可以看到以下信息:
D:\Lib\x64\>corflags System.Data.SQLite.DLL
Microsoft (R) .NET Framework CorFlags Conversion Tool. Version 2.0.50727.42
Copyright (c) Microsoft Corporation. All rights reserved.
Version : v2.0.50727
CLR Header: 2.5
PE : PE32+
CorFlags : 24
ILONLY : 0
32BIT : 0
Signed : 1
D:\Lib\x86\>corflags System.Data.SQLite.DLL
Microsoft (R) .NET Framework CorFlags Conversion Tool. Version 2.0.50727.42
Copyright (c) Microsoft Corporation. All rights reserved.
Version : v2.0.50727
CLR Header: 2.5
PE : PE32
CorFlags : 24
ILONLY : 0
32BIT : 0
Signed : 1
ILONLY: 在映像中是否只包含了IL代码。1表示纯IL代码,0表示包含了Native代码。
32BIT: 即使是纯IL代码,在32位与64位环境中运行还是有区别的。这个标记用于区分x86与Any CPU。
PE: 32位为PE32,64位为PE32+。这个用于区分32位与64位映象。
Any CPU:PE = PE32 and 32BIT = 0
x86: PE = PE32 and 32BIT = 1
x64: PE = PE32+ and 32BIT = 0
由于之前我们试图在64位进程上加载的32位DLL,其ILONLY=0,即包含平台相关代码,因此无法加载而抛出错误。【注:通过现象推测,需要跟踪.net Framework代码证实】
(2) 这个问题通过上述剖析,已经很清楚了。要说明的是,如果想绕过64位DLL带来的麻烦,将主程序也编译成x86而不是Any CPU,也是可以在64位系统上运行的。这时,操作系统将启用Wow模式启动这个进程。
(3) 这个SQLite的DLL混合了IL和Native代码,必须严格地对应平台调用。
(4) .net加载程序集的顺序:
1、 在GAC(Global Assembly Cache)中搜索相应版本的DLL;
2、 配置文件(web.config或app.config);
3、 应用程序(.exe)当前目录下;
但事实上有可能比这个顺序更为复杂,详见:
http://msdn.microsoft.com/en-us/library/aa720133.aspx 及参考文献7。
之前,在我开发环境中,由于本地GAC中已经包含了正确的x64版本,所以能正确运行。但复制到别人的64位机器上时就出问题了。而有些XP机器上安装了错误的小版本,因此也出现加载失败的现象。
最后,补充说明一下GAC的位置:\Windows\assembly。使用“我的电脑”打开这个目录时,看到的是所有.net全局程序集的列表,这是Windows特殊处理后的结果。只有通过命令行才能看到这个目录中分成了GAC_32, GAC_64, GAC_MSIL等几个子目录。这几个目录正是前文所述不同处理器架构的几种DLL。
补充:
关于之前[c]的问题的解决方案:
后来发现,System.Data.SQLite.DLL版本1.0.66均能正常工作,但1.0.82在某些Windows XP上无法工作。由于官方网站对1.0.82的解释大多关注在x86与x64的区别,我一度仍然以为是处理器架构造成的。最后,通过depends工具查看发现,1.0.82版的DLL引用了MSVCR90.DLL。而出问题的机器上未安装VC2008 Runtime,自然无法找到该DLL了。
解决的办法有两个:使用1.0.66版,或在XP上安装VC2008运行包:
http://www.microsoft.com/zh-cn/download/details.aspx?id=29
由于之前对64位平台应用的理解有限,文中很多内容通过实验推测,有可能和Microsoft官方表述有不一致或者错误的地方。欢迎大家指正!
参考文献:
1、
http://msdn.microsoft.com/en-us/magazine/dd727509.aspx
2、
http://blogs.msdn.com/b/gauravseth/archive/2006/03/07/545104.aspx
3、
http://blogs.msdn.com/b/junfeng/archive/2004/08/11/212555.aspx
4、
http://blogs.msdn.com/b/junfeng/archive/2004/09/12/228635.aspx
5、
http://blog.csdn.net/cstod/article/details/4887049
6、
http://stackoverflow.com/questions/6507675/gac-32bit-vs-64bit
7、
http://blog.csdn.net/wangjunhe/article/details/6692194
分享到:
相关推荐
Microsoft .NET Framework 4.0运行库是微软公司推出的一款重要的软件开发框架,它为开发者提供了构建、部署和运行各种Windows应用程序所需的环境。这个运行库是与Visual Studio 2012紧密配合的一个组件,主要服务于...
.NET Framework是微软公司开发的一个全面且开放的编程框架,它为开发者提供了构建、部署和运行应用程序所需的环境。本文将深入探讨.NET Framework 4.5(版本号4.5.50709),以及它如何解决安装问题和与其他版本的...
在本文中,我们将深入探讨.NET Framework 4.5.2的主要特性、安装问题以及解决方法。 1. **主要特性**: - **异步编程模型**:引入了`async`和`await`关键字,使得编写异步代码更加简洁,提高了应用的响应性。 - *...
.NET Framework 3.0是微软开发的一个重要软件框架,它为开发者提供了构建、运行Windows应用程序所需的环境。这个框架是.NET Framework 2.0的扩展,引入了新的技术栈,包括Windows Presentation Foundation (WPF),...
.NET Framework 2.0 Configuration配置安装程序是微软为了帮助开发者和系统管理员管理.NET Framework 2.0环境而设计的一个重要工具。此安装包包含了用于调整和优化.NET Framework 2.0运行时性能、安全性和其他关键...
本篇文章将深入探讨.NET Framework的源代码,尤其是System命名空间下的内容,帮助读者更好地理解其内部机制。 1. **CLR(Common Language Runtime)** .NET Framework的核心是CLR,它是.NET应用程序的运行环境。...
.NET Framework 类库是微软开发的一个全面的开发框架,它为构建和运行基于Windows的应用程序提供了必要的基础设施。这个类库包含了丰富的API集合,涵盖了各种编程任务,从基础数据类型到高级网络通信,再到图形绘制...
1. **ASP.NET架构**:介绍ASP.NET的运行时环境,包括ASP.NET应用程序的生命周期、请求处理流程、页面生命周期及事件模型。 2. **Web Forms**:讲解ASP.NET Web Forms,这是一种基于控件的开发模型,允许开发者通过...
本教程基于一位曾在微软工作过的资深讲师的PPT,将深入探讨.NET Framework的核心概念和技术,旨在帮助初学者和进阶者更好地理解和运用这一平台。 一、.NET Framework基础 .NET Framework包含两大部分:公共语言运行...
以上是.NET Framework的初步介绍,每份PPT将深入探讨一个或多个主题,结合实际代码示例,帮助读者逐步掌握.NET Framework的精髓。通过学习这些材料,你将能够更好地理解和应用.NET Framework进行软件开发。
本文将深入探讨SXS文件以及其在.NET Framework安装中的作用。 首先,理解SXS文件:SXS是“Side-by-Side”(并行)的缩写,它是微软Windows操作系统中用于处理组件版本冲突的一种机制。在Windows中,多个版本的相同...
.NET Framework 4.7.2 是微软开发的一个重要的软件开发框架,它为Windows操作系统上的应用程序提供了运行环境。这个离线安装程序是专为那些没有网络连接或者需要在多台计算机上快速部署.NET Framework的用户设计的。...
.NET框架是微软推出的一个用于构建和运行应用程序的全面开发平台,它包括公共语言运行时(CLR)和类库,为开发者提供了跨语言的编程环境和丰富的API。本书首先会介绍.NET框架的基础,包括CLR的工作原理、垃圾回收...
.NET Framework包含了Common Language Runtime(CLR)和类库,为各种编程语言提供了一致的运行环境。CLR执行代码并提供了内存管理、异常处理和类型安全等服务。类库则包含了大量的预定义类,如System、System.Web等...
这篇内容将深入探讨如何在WIN2003上的IIS中安装和配置ASP.NET插件,以及.NET Framework 2.0的相关知识点。 首先,我们需要了解.NET Framework 2.0。这是一个由Microsoft开发的软件框架,它提供了运行ASP.NET应用...
在Part I中,作者会首先探讨.NET Framework的架构,包括编译源代码成托管模块的过程,以及如何将这些模块组合成可执行的.NET应用程序。这一部分还将涉及类型系统、垃圾收集机制、异常处理和多线程编程等关键主题,...
### 如何在Win8.1 Update系统中安装.NET Framework 3.5与2.0 ...通过以上两种方法,用户可以在Windows 8.1 Update系统中成功安装.NET Framework 3.5,从而确保需要该环境支持的应用程序能够正常运行。
CLR中的垃圾回收机制是.NET Framework的一大特色,它自动管理内存,消除了程序员手动释放内存的需要。当对象不再被引用时,垃圾回收器会识别并释放这些内存,防止内存泄漏。 3. **CIL与元数据** .NET源代码会被...
.NET Framework是微软开发的一款用于构建、部署和运行应用程序的强大平台,它包含了丰富的类库、编译器、垃圾收集器和托管执行环境。本教程将深入探讨.NET Framework的高级开发技术,旨在通过实例和易于理解的方式,...