ISWIX, LLC View Christopher Painter's profile on LinkedIn profile for Christopher Painter at Stack Overflow, Q&A for professional and enthusiast programmers

July 07, 2010

.NET Bitness Pain

One of the really cool things about .NET is the ability to write platform independent code. You can build an EXE as "AnyCPU" and on an x86 windows machine it will run as a 32bit process and on an x64 windows machine it will run as a 64bit process. It's that simple; you don't have to worry about 'bitness'! Well, that's the sales pitch anyways.

In practice I'm noticing it's far from that simple, especially considering that Windows Installer cares very, very much about bitness. If your code uses less then 100% pure managed classes you will find yourself falling into a number of traps that are important for developers and setup developers to understand. Sadly I've yet to find a comprehensive list of these issues.

So let's start with a simple example. Let's go back 10 years in time and pretend we are writing an x86 application and x86 installer with no concern for x64. Someone hands you a vb6 EXE and a regfile ( HKLM\SOFTWARE\Company\Product type entries ) and says this is what needs to be deployed. You go off and create an MSI that writes the registry values, deploys the EXE and creates a shortcut. Now let's come back to present. You take that MSI and throw it on a modern Windows 7 x64 box and it works just fine.

But now let's pretend that the EXE was a .NET application. If it was compiled as x86 it would behave the same way. But if that application was built as AnyCPU ( the default for all versions of Visual Studio prior to VS2010 ) we are going to land in one of those traps. Here's why:

The MSI is marked as an x86 package so it writes the registry data to the Wow6432Node of the registry so the expected x86 application can find it. While the EXE gets installed to ProgramFiles(x86) it will actually JIT as a 64 bit process. This process will fail to find it's registry resource at runtime and crash. This is because the .NET BCL Win32.Registry class cares about bitness.

These traps are all over the place. For example if you P/Invoke a C++ DLL you'll need to have the correct x86 or x64 dll and the same goes for things in WinSxS and the GAC.

I recently read a .NET MVP blogging about these issues and he wrote a comment "to have the installer deploy both."

There's just one big problem with that: MSI doesn't support that. The Windows Installer team seriously expects you to build two MSI's for the two platforms. This goes against what the .NET team encourages.

This is a huge problem and I'm somewhat suprised that I'm not hearing more about it considering the huge uproar when Vista was released and the break neck speed x64 machines are entering the market.

I'm not sure exactly where to wrap this up other then I'm trying to gether up what all these traps are because most developers I speak with seem suprised when I mention this. Be sure to test your apps on both x86 and x64 to look for problems and seriously consider doing what Visual Studio has done: Compile your .NET apps for x86 instead of AnyCPU. I wouldn't use Any CPU until you are really ready to support x86 and x64 deployments.


Pranav said...

Nice Article.
Thank you!

ShadowWolf said...

Yeah, this 'feature' was not a very well thought-out one. Fortunately, they learned from the mistake and VC2010 moves away from AnyCPU as a default:

It's kind of a bummer when this stuff doesn't work, though. I like automatic!

HoweBoutArden said...

I feel your pain…
Why is it that the MSI architects do not trust installation engineers to configure our application correctly? They make every effort to prevent engineers from managing multiplatform applications with one msi package even going so far as to alter any property that contains “program files” in it.
My product managers do not want a separate installation for each platform any more. So now I have to build two msi files per product and an elaborate boot strapper application just to bypass a completely pointless limitation of the MSI service.
What if the Windows Installer could just allow an installation package that contains both 32 and 64 bit components to install only the 32-bit components on a 32-bit OS? With this one concession I could simplify my product installation and leverage just the functionality Windows Installer provides to deploy my application. We may need to add some kind of flag to identify a mixed platform package to maintain backwards compatibility. This simple change in behavior reflects the reality that installation engineers have an increasing need to support applications that straddle both 32 and 64 bit platforms.