Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why would a .NET EXE, compiled as x86, run as x64?

I have a simple little command-line program, written in C#, running under .NET 4.0, and compiled with Visual Studio 10.0.

What it does is pull data out of another vendor's Access.mdb file, and insert it into a Sql Server database, so one of our apps can access the data.

We're using .NET's OleDbConnection/OleDbCommand/OleDbDataReader classes, using Microsoft.Jet.OLEDB.4.0 as the data provider.

This worked fine, for us, until we tried to run in on 64-bit machines. It turns out that there is no 64-bit OleDb provider for .NET. There are vague, half-clear threads on the problem scattered all over the web, with discussions of different versions of Access, or MDAC, or Office, or whatever, that somehow made things work for some people.

What we did was configure the project to target x86. And the problem went away.

Now it's back, for reasons I simply don't understand. When I build the program on my local machine, it runs as x86, but when I build it on our build machine, it runs as x64.

The project file is clearly configured to target 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>

It's built from the same batchfile, whether on my machine or on the build machine:

msbuild OurApp.sln /property:Configuration=Release

And the generated exes say they are x86, regardless of which machine they are built on. If I run dumpbin /headers on either, I see:

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

The only difference between the dumps of an exe built on my machine and an exe built on the build machine is the timestamp and the path to the .pdb file.

But, and here's the odd thing, an exe built on my machine runs just fine, one built on the build machine errors out with the same error message we had seen when we'd built it as x64.

More than that - our program gets its configuration from the registry, and for the convenience of the user, if it doesn't find a setting, it creates one. We read them from, and create them in, HLM\SOFTWARE\OurName\OurApp. But, of course, since this is a 32-bit app running on a 64-bit machine, it really should be reading to and writing from HLM\SOFTWARE\WoW6432Node\OurName\OurApp.

And with the apps built on my machine, it does. But the apps that are built on the build machine, despite being compiled for x86, and having headers that indicate that they should be run as x86, read and write from HLM\SOFTWARE\OurName\OurApp and not from HLM\SOFTWARE\WoW6432Node\OurName\OurApp. As if it was actually running as a 64-bit app, despite everything.

Does anyone have any idea how this could be happening?

like image 396
Jeff Dege Avatar asked May 21 '12 19:05

Jeff Dege


1 Answers

OK, this is just aggravating.

What we had had, in the .csproj file, was this:

<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>

It's what resulted from taking the default configuration, and changing it to target x86.

I removed the AnyCPU configurations, and created new x86 configurations, and got:

<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>

Now I could have sworn that the GUI was telling me I was targeting x86 both in debug and in release, in the old configuration. And that the resulting executables dumped as being x86, and ran as x86 on my machine. But apparently I was getting confused about what versions of the exe were being built under what conditions, because looking at the .csproj, it's clear that we were not specifying x86, when building release.

In any case, with the new config the exes build and run, regardless of what machine they're built on, or which they're run on.

In any case, sorry to have troubled you, and thanks for providing the ear that got me to look at the problem in the right way.

like image 175
Jeff Dege Avatar answered Oct 14 '22 12:10

Jeff Dege