为什么一个以x86编译的.NET可执行文件会以x64方式运行?

10

我有一个简单的命令行程序,使用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

生成的可执行文件会“说”它们是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读取和写入,而不是从HLM\SOFTWARE\WoW6432Node\OurName\OurApp读取和写入。看起来好像一切都像运行为64位应用程序一样。

有人知道这可能是如何发生的吗?


1
配置文件是否相同? - Oded
1
请参考https://dev59.com/kWoy5IYBdhLWcg3wEJ9n上的第一个答案,以获取可能的解决方案。此外,我注意到您正在构建“AnyCPU”配置,该配置与“x64”和“x86”不同,并且可能会引入行为。 - skarmats
没有配置文件。直接从版本控制构建。 - Jeff Dege
“AnyCPU”在条件字符串中表示我们要构建的内容。它是<PlatformTarget>设置,指示我们正在构建什么。我们的解决方案文件指定即使我们指定了AnyCPU,我们也将构建x86。 - Jeff Dege
1个回答

6

好的,这真是令人恼火。

在.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 告诉我在 debug 和 release 中都是 x86,而且生成的可执行文件也显示为 x86 并在我的电脑上以 x86 运行。但显然我混淆了在什么条件下建立哪个版本的可执行文件,因为看 .csproj 文件时,很明显我们在建立 release 时没有指定 x86。

无论如何,在新的配置中,这些可执行文件可以在任何机器上建立和运行。

无论如何,很抱歉给你添麻烦了,感谢提供正确方向的耳朵。


更改应该适用于调试和发布配置的项目设置时,很容易忘记选择“所有配置”。我不确定是否有一个良好的可用性解决方案,因为IDE无法知道。我认为我更喜欢IDE的行为与现在相反 - 项目设置更改将适用于所有配置,除非您选择“仅当前配置”选项(我认为我的大多数项目设置更改都适用于各种配置)。但是,老实说,我真的不确定我是否会更喜欢那个。 - Michael Burr
3
这个问题在VS2010中出了点问题,我认为他们没有足够的时间来真正解决这个问题。对于托管项目,平台名称是无意义的,只有项目+属性、编译、目标平台设置才重要。这是将C++集成到msbuild系统的副作用。因此,是的,使用x86平台生成在64位模式下运行的代码是完全可能的。如果目标平台设置依赖于配置,那么问题的机会将增加四倍。对于Debug,你设置了正确的目标平台,但对于Release却忘记改变了目标平台设置,所以无法正常工作。 - Hans Passant

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