如何强制.NET应用程序以32位模式运行

12
我正在尝试在Win7 x64上运行我的.NET 3.5 WinForms应用程序。该应用程序使用NHibernate和System.Data.OracleClient访问Oracle数据库,而Oracle客户端是32位的。启动应用程序时,我收到以下错误消息:
“尝试加载Oracle客户端库时抛出BadImageFormatException异常。当以64位模式运行且安装了32位Oracle客户端组件时,将出现此问题。”
为解决这个问题,我将构建目标定向为x86平台。

Screenshot of the Build settings

令我惊讶的是,在尝试在Win7平台上执行该新构建时,出现了完全相同的错误消息

NHibernate程序集通过Assembly.Load("...");在运行时加载。

可能是NHibernate DLL仍在64位模式下运行,而主机exe在32位模式下运行。这对我来说听起来很奇怪。或者可能是由于某种原因,我的应用程序在64位模式下运行,即使它是针对x86目标的也是如此?


更新:

我使用 CorFlags 检查了我的二进制文件,发现它标记为 32 位:

Microsoft (R) .NET Framework CorFlags Conversion Tool.  Version  4.0.30319.1
Copyright (c) Microsoft Corporation.  All rights reserved.

Version   : v2.0.50727
CLR Header: 2.5
PE        : PE32
CorFlags  : 3
ILONLY    : 1
32BIT     : 1
Signed    : 0

我还在任务管理器中检查了它,发现它有一个*32的后缀。
我还尝试使用CorFlags为我的应用程序中的所有程序集添加32位标志。但仍然出现相同的错误信息。
我很困惑...很困惑...很困惑...

1
你是否通过任务管理器检查程序在崩溃时是以32位还是64位模式运行的?如果进程名称后面有“*32”,则表示它是32位,否则为64位(假设操作系统和系统为64位)。 - Lasse V. Karlsen
2
你是将x86作为目标吗?是针对你的类库还是你的程序?还是两者都是? - Lasse V. Karlsen
1
@Lasse:更详细地说,该应用程序由3个层、2个DLL和1个EXE组成,其中一个DLL引用了NHibernate。我已将所有这些目标定为x86,并确保EXE项目在编译时使用DLL项目的x86二进制文件。唯一无法控制的是NHibernate DLL本身。 - chiccodoro
你确定 NHibernate 的程序集是 Any CPU,而不是 64 位的吗? - Lasse V. Karlsen
@Lasse:是的,因为该应用程序在Windows XP 32位上运行顺畅。我可能需要尝试下载源代码并自行编译,但这会使构建和部署过程更加复杂,而且我几乎无法相信加载到EXE进程中的程序集可以以不同于EXE本身的模式运行。然而,我不是.NET的专家... - chiccodoro
6个回答

6

32位进程无法加载64位DLL,反之亦然(详见此处)。这意味着,如果您的进程成功加载了一个64位DLL,则它绝对是一个64位进程。您可以通过任务管理器(如Lasse所建议的)或其他手段(在这里描述)验证这一点。该文章还提供了有关Windows x64上.NET的更多信息。


嗨,Helge,感谢您的回复。那就是我所想的(即DLL必须在与其宿主进程相同的模式下运行)。我在任务管理器和使用 CorFlags 进行了检查,我的 EXE 是 32 位的。(请参阅我问题的更新)。 - chiccodoro

3

没错,看起来 NHibernate 组件是使用 AnyCPU 作为其平台目标进行构建的。你需要一个专门针对 x86 构建的 NHibernate 组件。


嗨,sixlettervariables。这是否意味着当EXE以32位模式运行时,加载到同一进程中的DLL仍然可以以64位模式运行?你确定吗?如果是这样的话,那将是非常不幸的,因为我无法控制NHibernate构建... - chiccodoro
不可以,正如我在答案中所写的,32位进程无法加载64位DLL。 - Helge Klein
@Helge:我的意思是它加载了一个AnyCPU DLL,然后请求一个64位的DLL。 - user7116
@sixlettervariables:我编译的EXE标记为32位。我认为Helge的观点是,由于它是32位的,NHibernate也必须以32位模式运行,即使它是为“AnyCPU”构建的。 - chiccodoro
@chiccodoro:我无法通过在 x86 可执行文件上使用 Assembly.Load 和混合 AnyCPU DLL 的方式使任何测试应用程序出现相同的错误。 - user7116
@sixlettervariables:非常奇怪,不是吗?非常感谢您的努力!我们将看看如何处理此问题。我们还尝试运行Oracle 64位客户端(与32位客户端并行),并使应用程序使用它。当然,留下这个问题是不令人满意的。也许我以后会回来解决它。 - chiccodoro

2
你可以尝试使用RunAsx86工具。
我使用这个工具从命令行启动.NET应用程序,以x86模式运行它们。

0

我在我的C++ Oracle应用程序中遇到了相同的错误,需要在32位机器上构建64位机器运行。坏映像错误是由于32位和64位dll混合使用造成的,因此我使用依赖项查找器查找哪些dll被混合使用。在该应用程序中,我发现oci.dll是64位的,因为我安装了64位的Oracle客户端,但所有其他dll都是32位的。因此,我在64位机器上安装了32位的Oracle客户端,并解决了这个错误。


0

我之前遇到过类似的问题。我有一个使用Crystal Reports的Windows服务,在我的64位机器上一切都很好,我调整了一切 - 该项目被构建为使用x86架构。

当部署到不同的机器上时,出现了问题,因为Crystal Reports引擎无法加载log4net.dll 1.2.10程序集而导致服务失败。我检查了目录 - 那里的版本是1.2.11,我的本地目录包含相同的版本。但是bindingRedirect没有起作用。

然后我检查了GAC - CR dlls已由安装程序签名并添加到GAC中,log4net 1.2.10在那里,但处理器架构不是x86。在为x86架构添加log4net 1.2.10后,它就像魔术般地工作了。


我想分享我的故事,并展示最终一切都是关于将正确的版本安装到GAC中。 - Karel Frajták

0
如果有帮助的话,我也遇到了在Oracle 64位和Windows 7 64位上出现相同症状的问题。我没有改变任何项目设置,而是简单地安装了32位的Oracle,这解决了问题。请确保更新您的环境变量(即ORACLE_HOME、PATH)以指向32位版本。

有趣的是,我遇到了32位的问题,最终安装64位解决了它! - chiccodoro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接