为啥编译为 x86 的 .NET EXE 会以 x64 运行?

Posted

技术标签:

【中文标题】为啥编译为 x86 的 .NET EXE 会以 x64 运行?【英文标题】:Why would a .NET EXE, compiled as x86, run as x64?为什么编译为 x86 的 .NET EXE 会以 x64 运行? 【发布时间】:2012-05-28 07:41:55 【问题描述】:

我有一个简单的小命令行程序,用 C# 编写,在 .NET 4.0 下运行,并使用 Visual Studio 10.0 编译。

它的作用是从另一个供应商的 Access.mdb 文件中提取数据,并将其插入到 Sql Server 数据库中,以便我们的一个应用程序可以访问数据。

我们使用 .NET 的 OleDbConnection/OleDbCommand/OleDbDataReader 类,使用 Microsoft.Jet.OLEDB.4.0 作为数据提供者。

这对我们来说很好,直到我们尝试在 64 位机器上运行。事实证明,.NET 没有 64 位 OleDb 提供程序。网络上散布着关于这个问题的模糊、半清楚的线索,讨论了不同版本的 Access、MDAC、Office 或其他任何东西,它们以某种方式使某些人工作正常。

我们所做的是将项目配置为以 x86 为目标。问题就消失了。

现在它又回来了,原因我完全不明白。当我在本地机器上构建程序时,它以 x86 运行,但是当我在我们的构建机器上构建它时,它以 x64 运行。

项目文件明确配置为x86:

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>bin\Release\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
    <PlatformTarget>x86</PlatformTarget>
</PropertyGroup>

它是从同一个批处理文件构建的,无论是在我的机器上还是在构建机器上:

msbuild OurApp.sln /property:Configuration=Release

而生成的 exes say 它们是 x86,无论它们是在哪台机器上构建的。如果我在其中一个上运行 dumpbin /headers,我会看到:

FILE HEADER VALUES
         14C machine (x86)
           3 number of sections
    4FBA64C8 time date stamp Mon May 21 10:52:40 2012
           0 file pointer to symbol table
           0 number of symbols
          E0 size of optional header
         102 characteristics
               Executable
               32 bit word machine

在我的机器上构建的 exe 和在构建机器上构建的 exe 转储之间的唯一区别在于时间戳和 .pdb 文件的路径。

但是,奇怪的是,在我的机器上构建的一个 exe 运行得很好,在构建机器上构建的一个 exe 会出现与我们在将其构建为 x64 时看到的相同错误消息。

不仅如此 - 我们的程序从注册表中获取其配置,为了方便用户,如果它没有找到设置,它会创建一个。我们从 HLM\SOFTWARE\OurName\OurApp 中读取并创建它们。但是,当然,由于这是一个在 64 位机器上运行的 32 位应用程序,它确实应该从 HLM\SOFTWARE\WoW6432Node\OurName\OurApp 读取和写入。

使用我的机器上构建的应用程序,它确实如此。但是在构建机器上构建的应用程序,尽管是为 x86 编译的,并且具有指示它们应该作为 x86 运行的标头,从 HLM\SOFTWARE\OurName\OurApp 和 not 读取和写入来自 HLM\SOFTWARE\WoW6432Node\OurName\OurApp。就好像它实际上是作为 64 位应用程序运行一样,尽管如此。

有人知道这是怎么发生的吗?

【问题讨论】:

配置文件是否相同? 查看***.com/questions/8794379 上的第一个答案以获得可能的解决方案。另外,我注意到您正在构建 AnyCPU 配置,该配置与 x64x86 不同,并且可能会引入行为 没有配置文件。直接建立在版本控制之外。 Condition 字符串中的“AnyCPU”表示我们要构建的内容。 设置表明我们正在构建什么。我们的解决方案文件指定即使我们指定 AnyCPU,我们也会构建 x86。 【参考方案1】:

好吧,这只是加重了。

我们在 .csproj 文件中拥有的是:

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>bin\Debug\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
    <PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>bin\Release\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
</PropertyGroup>

这是采用默认配置并将其更改为目标 x86 的结果。

我删除了 AnyCPU 配置,并创建了新的 x86 配置,然后得到:

<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
    <DebugSymbols>true</DebugSymbols>
    <OutputPath>bin\x86\Debug\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <DebugType>full</DebugType>
    <PlatformTarget>x86</PlatformTarget>
    <ErrorReport>prompt</ErrorReport>
    <CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
    <OutputPath>bin\x86\Release\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <Optimize>true</Optimize>
    <DebugType>pdbonly</DebugType>
    <PlatformTarget>x86</PlatformTarget>
    <ErrorReport>prompt</ErrorReport>
    <CodeAnalysisIgnoreBuiltInRuleSets>false</CodeAnalysisIgnoreBuiltInRuleSets>
    <CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules>
</PropertyGroup>

现在我可以发誓,GUI 告诉我,在旧配置中,我在调试和发布时都以 x86 为目标。并且生成的可执行文件作为 x86 转储,并在我的机器上作为 x86 运行。但显然我对在什么条件下构建什么版本的 exe 感到困惑,因为查看 .csproj,很明显我们在构建版本时没有指定 x86。

在任何情况下,使用新配置,exe 构建和运行,无论它们是在什么机器上构建或运行的。

无论如何,很抱歉给您带来麻烦,感谢您提供的帮助,让我以正确的方式看待问题。

【讨论】:

在更改应该同时应用调试和发布配置的项目设置时,很容易忘记选择“所有配置”。我不确定是否有一个很好的可用性修复,因为 IDE 无法知道。我认为我希望 IDE 的行为与现在相反 - 除非您选择“仅当前配置”选项,否则项目设置更改将应用​​于所有配置(我认为我的大部分项目设置更改都适用于配置)。但老实说,我不确定我是否会更喜欢这样。 这只是在 VS2010 中搞砸了,我认为他们没有时间真正解决问题。平台名称对托管项目没有意义,只有项目+属性、编译、目标平台设置重要。这是将 C++ 集成到 msbuild 系统的副作用。所以是的,让 x86 平台生成在 64 位模式下运行的代码是非常有可能的。通过让目标平台设置依赖于配置,将问题的几率提高四倍。适用于 Debug,您的目标平台正确,不适用于 Release,因为您忘记更改该平台。

以上是关于为啥编译为 x86 的 .NET EXE 会以 x64 运行?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Visual Studio 2017 将 .NET Core 应用程序编译为 EXE 文件

使用 Visual Studio 2017 将 .NET Core 应用程序编译为 EXE 文件

为啥我可以在 Mac OS X 上使用 Cython 编译为 C 但不能编译为 C++

如何将 .NET EXE 反编译为可读的 C# 源代码?

尝试在 64 位机器上将 Detours.lib 编译为 32 位:LNK1112:模块机器类型“x86”与目标机器类型“x64”冲突

一次编译为两个 .NET Framework