So you're thinking about writing 64-bit software. You've reviewed the catalogue of 64-bit software currently available at 64xsoft.com, read the pros and cons arguments on Wikipedia, and decided that now's the time to dive in. Where do you begin? Why not begin by learning about some of its nuances? That way, you make an informed decision. In this article, I'll walk through some pitfalls of developing software for 64-bit architectures. I'll end by giving you some guidelines.
64-bit architectures have been available for some years now, as far back as the 1960s. However, 64-bit consumer application software is just now beginning to emerge as a serious contender. If you go by Wikipedia's timeline, Microsoft first introduced Windows XP 64-bit in 2001 for the Itanium architecture. Although non-Windows versions existed at least a decade before that, the drive to produce 64-bit consumer software would gain no traction for a few more years. This is because consumer software on personal computers revolved around the Windows OS since it controlled the lion's share of the PC market. Added to this, the flagship tool (Visual Studio .NET) for developing that software did not include the ability to target 64-bit platforms until Visual Studio 2005 shipped.
Visual Studio .NET
Starting from VS 2005, developers were able to compile their applications for either 32-bit or 64-bit architectures. In fact, the default option for compilation from Visual Studio 2005 and later is Any CPU, as Figure 1 shows.
Figure 1: Visual Studio compilation options
That default option allows the runtime to match the bit count of the application to the OS bit count.
Platform Target Option in Visual Studio.NET 2010
Prior versions of Visual Studio could only target 32-bit architectures. I'll discuss a way to force these types of applications to run in 64-bit mode later in the guidelines section of this article. But for now, that's pretty much all you need to do if you are building a run-of-the-mill managed application. If you're using unsafe code, mucking around with COM objects or creating macros, you'll need to read on some more.
It's interesting to note that even today, no version of Visual Studio .NET is 64-bit; all versions are 32-bit. Microsoft is not interested in releasing a 64-bit version either! That's not a serious hindrance either because all versions of Visual Studio .NET will install and run on both 32-bit and 64-bit architectures. Visual Studio Team System can even target Itanium architectures.
To provide maximum build flexibility, Visual Studio .NET may be installed with a native compiler and a cross compiler. On a 64-bit OS, the (64-bit) native compiler is installed by default and contains some key 64-bit modules, such as tooling and a 64-bit version of the Common Language Runtime (CLR). On a 32-bit OS, you get what you always had!
The job of the cross compiler is to compile code for other architectures that may not be on the machine where the compiler is running. As an example, you can develop 64-bit software on the 32-bit version of Windows OS. In that case, Visual Studio simply uses the cross compiler to produce the 64-bit code.
Since you don't have the 64-bit target OS, you won't be able to execute the code successfully; at runtime, the OS will examine the PE Header for the 64-bit image and attempt to spawn a 64-bit process on a 32-bit OS, as you can see in Figure 2.
Figure 2: Incorrect platform target execution--64-bit application running on 32-bit OS
Microsoft Application Nuances
The recent OSs, Windows 7 and Windows Server 2008 R2, are available in 64-bit flavors. However, some of the software running on these versions isn't necessarily 64-bit. There's no easy way to eyeball this situation, and it does have quite a significant impact! Consider Internet Explorer (IE) 8 available from the Windows taskbar on Windows 7 (64-bit), as Figure 3 shows.
Figure 3: Internet Explorer 32-bit version
This flavor of IE is actually the 32-bit version, not the 64-bit version! On Windows 7 64-bit version, when you launch IE from the taskbar, it will actually run in 32-bit emulation mode using Windows On Windows (WOW64). If you want to run 64-bit IE, you will need to select Internet Explorer (64-bit) from the Start menu.
The sleight-of-hand magic trick has a profound impact on testing. For instance, did you just certify your Silverlight application for 64-bit Windows 7 using IE 32-bit? Or did you confirm that your Flash plug-in works on IE64 testing via IE on the taskbar and not via the Start menu? At the time of this writing, neither Silverlight nor Adobe Flash supports 64-bit. It means that those types of applications may pass your QA testing (albeit using an "inappropriate" version of IE) but fail to start depending on which version of IE was used by your clients. That can be a software support nightmare because you do not control the end user's preferences!
Mixing Bitted Assemblies
Let's go a bit deeper. Since applications are made up of several moving parts often located inside compiled assemblies, you need to make sure that each dependent assembly as well as the application as a whole is compiled to the same bit count. The reason for this rule has to do with the way in which processes are loaded at runtime. When a process is spawned by the OS, usually in response to some user request, the OS loader evaluates and assigns the appropriate bitness to the process as a whole. (I am trivializing and skipping a lot of details here so you get the general idea). Once the process initializes as a 32-bit, nothing 64-bit is going to load in there. Period! End of story! Vice-versa is true as well.
If you develop a 64-bit application, it helps to understand one thing: Is your process running in emulation mode or native to the platform? Native execution is pretty straightforward to understand; what you see is what you get. Emulation mode is a bit different. WOW64 runs applications as if they were running under a 32-bit process. It does so by forming a 32-bit bubble around your application and its dependencies. Inside that bubble, everything is true 32-bit. WOW64 handles the ugly math between the 32-bit bubble and the 64-bit OS. Your application cannot pierce this bubble.
You can determine whether you're in emulation mode at runtime using code like the example in Figure 4. You'll need to add logic to figure out if you are in emulation mode based on the flag you used to compile your application.
Here is where things start to fall apart. Consider this:
If your 64-bit application has a dependent assembly that is compiled using the x64 flag (as opposed to the default Any CPU flag), your application will fail in emulation mode. To avoid this issue, make sure that your assembly and all its dependencies are built against a matching bit count. Or, compile each dependency with the Any CPU flag.
By default COM objects, add-ins , and plug-ins are 32-bit. Your 64-bit application running native cannot load these types and will result in a BadImageFormatException exception. WOW64 programs should work just fine since they are run inside the 32-bit bubble.
Microsoft Office is another special case. There aren't yet any 64-bit flavors of add-ins or components for Office. But, as you know, Microsoft Office ships in a 64-bit flavor. This means that when you build add-ins or macros for the 64-bit version of Office, you need to pay special attention to bit count.
There are a couple of ways to ease this pain. Either abandon the Office 64-bit adventure or prefer to run your Office-based applications in emulation mode on 64-bit OSs. Basically, install Office 32-bit on the 64-bit OS. For this and other reasons, Microsoft indicates that Office 64-bit should not be adopted as the default version. True to tune, the Office install shell is designed to look for any excuse to load the 32-bit version of Microsoft Office during installation. So for instance, if you are installing 64-bit Office and the installation finds an Office plug-in, it simply installs Microsoft Office 32-bit.
Some 64-Bit Guidelines
Obviously, as vendors start to create and distribute 64-bit versions of their software, it will become increasingly difficult to prevent mixing models. You can start now by observing a few guidelines while you develop 64-bit software today.
- Test at runtime to find out whether your 64-bit application is being run native or emulated.
- Test your applications with the correct version of Internet Explorer if you are developing web applications.
- Handle the case of BadImageFormatException exceptions gracefully for all dynamically loaded modules.
- 64-bit applications designed to run native should not attempt to load COM modules or plug-ins because these types of assemblies are inherently 32-bit.
- Office applications that use MAPI must include the correct MAPI header file. That header file enables MAPI applications to load correctly into 64-bit processes.
- Understand that Windows does not allow you to mix and match applications in the same process that differ by bit count.
- Use the CoreFlags.exe utility to force applications to run as a specific bitted process. The CoreFlags utility updates the PE header for the image, essentially signaling to the loader that this image must be loaded into a process with a particular bit count.
- Applications that manipulate pointers need to be updated and tested to make sure they work correctly.
- Visual Basic for Applications (VBA) and Macro type programs must be updated and tested to make sure they work correctly.
- Make use of the IIS 7x application pool to run 64-bit applications in their own 64-bit application pool. Each pool can run independent of each other as 32-bit or 64-bit.
- 32-bit device drivers will not work on a 64-bit version of Windows and vice-versa.
- All hardware devices require 64-bit drivers for the 64-bit version of Windows.
There's one caveat to all of this. While a 32-bit process cannot load into a 64-bit process (and vice-versa), the 32-bit process can communicate with the 64-bit process via a remote procedure call. Since these processes are separated via a well-defined process boundary, the Windows bit count requirement is not violated. A real-world example would go something like this: Your 64-bit application will not be able to load a Visual Basic 6 DLL via COM Interop. However, it will run just fine if you install the same VB 6 DLL into the COM+ catalog, then call it from your 64-bit application!
If you find all this somewhat confusing, I won't hold that against you. Remember that Windows emulation is your friend; it is designed to just work by forcing your application to run in a 32-bit bubble. And sometimes, this is the path of least resistance.
Alvin Bruney is a longtime ASP.NET MVP and author of five books. His current book, ASP.NET 4 by Example, is currently available for $20 on www.lulu.com/owc.