Black Blade Associates Logo A Black Blade Associates blog. Struggling with SharePoint? We can help.




Blog moved: This blog has moved to http://thingsthatshouldbeeasy.wordpress.com. Go there now to see the new posts.


Tuesday, August 04, 2009

AnyCPU, x86, x64 – What’s the Difference?

A colleague of mine recently posed an interesting question: Why would you ever want to specifically target an assembly compilation to x86 or x64? Wouldn’t you always want to use the AnyCPU option?

What are the options?

Here’s a bit of background on what each option does:

  • AnyCPU – The assembly is compiled in a CPU-independent manner. If you are compiling an EXE, the EXE will run as an x64 processes when loaded by an x64 version of the .Net Framework on an x64 operating system. Otherwise the EXE will run as an x86 process. When you’re compiling a DLL, the DLL will load as an x64 DLL when loaded from an x64 process. Otherwise, the DLL will load as an x86 DLL.
  • x86 – The assembly will always load as an x86 assembly, regardless of the operating system or .Net Framework version. The assembly will not load from an x64 process.
  • x64 – The assembly will always load as an x64 assembly, regardless of the operating system or .Net Framework version. The assembly will not load on an x86 operating system or from an x86 process.

Well, it looks like the AnyCPU option is definitely the way to go. You get the most flexibility with the least amount of headaches due to platform and process differences. In most cases (99 out of 100) that is true.

Subtleties of assembly loading

However, there is one subtlety to how assemblies load into processes. A process can only load assemblies that are of the same architecture at runtime as the process itself. An x64 process can only load x64 assemblies, and x86 processes can only load x86 assemblies. This restriction still applies to assemblies compiled with the AnyCPU option. Even though assemblies compiled with the AnyCPU option are processor architecture-independent at compile-time, the assemblies do get tied to a particular processor architecture when they are loaded for execution. If a process tries to load an assembly with an incompatible architecture, a BadImageFormatException will be thrown.

Why does that matter? Wouldn’t all of this be irrelevant if all assemblies were compiled with the AnyCPU option? Yes. Except, that not all code your assembly needs to load or that will be loading your assembly is processor architecture-independent. In particular, this is most apparent when you need to interoperate with un-managed code, such as COM.

So what? I only use managed code

Many .Net developers believe that all of .Net is a brand new, shiny framework that frees them from the headaches or working with legacy runtimes and unmanaged binaries. This is not true. In fact, a large portion of the .Net Framework simply wraps existing un-managed operating system components, such as the EnterpriseServices and DirectoryServices namespaces. Here’s a screenshot of a COM+ component EnterpriseServices uses to extend transaction support into the .Net Framework:

.Net in Component Services

There are also many components and products that are based on un-managed code and only wraps this code for interoperability with .Net assemblies. Many Microsoft applications fall into this category as well, such as Microsoft Office, even if you are using the Office primary interop assemblies.

When do I need to specify x86 or x64 target for my assembly?

Given what we now know about how assemblies are loaded, we can now see that when we need to interoperate with un-managed code, even code that has .Net wrappers, we may need to target our assemblies, particularly when our process or assembly is likely to be loaded as a 64-bit (x64) architecture but the unmanaged code is of 32-bit (x86) architecture.

For example, say we need to automate a Microsoft Office application and our assembly is running on an x64 operating system. We need to have a 32-bit process, since Office is strictly a 32-bit application (that is until Office 2010 is released), but because our process is running on an x64 operating system, the process will be loaded in x64 mode. In this case, we want to specify that our assembly should always be targeted to x86 architecture, even when running on an x64 operating system.

24 comments:

  1. Terrible explanation. Makes people even more confused...

    ReplyDelete
    Replies
    1. i agree.
      what I am more confused now with is if we have our x64 wrapper assembly around a x86 un-managed code and if we should now compile our dlls to target x86 architecture to overcome? Does this mean that we are going to have a x86 assembly that contains x86 managed and unmanaged code targeted at only x86?

      Delete
    2. If you are using x86 un-managed DLLs, you will need to compile your application using x86, not AnyCPU. You will have a 32-bit application. Simple enough?

      Delete
    3. >When you’re compiling a DLL, the DLL will load...

      Your explanation is ambiguous then, since you didn't make that distinction under the AnyCPU bullet for unmanaged x86 dlls (until that last reply).

      Delete
    4. True, I did not mention un-managed code in the first bullet. You would have had to read into the next section of this post, "Subtleties of assembly loading," in order to get info on that topic. After that section, the discussion of un-managed code permeates this post.

      Delete
  2. Multi-platform computing can be complex, especially when those platforms coexist within the same machine as 32-bit and 64-bit process do on Windows machines. Throw interop with unmanaged code into the mix, and life becomes even more interesting.

    If you're looking for the simple answer, here it is: Compile your code with the AnyCPU setting, and don't think about it unless you get a BadImageFormatException. This post was intended for those who want a slightly deeper understanding of what's happening under the covers. If you want to learn more, there are plenty of resources that go into more depth on 32/64 bit coding.

    Look at the bright side though: at least we don't have to worry about 16-bit code anymore :)

    ReplyDelete
  3. Nice article on target platfarm... Thanks :)

    ReplyDelete
  4. thank´s!
    there is on more item important.
    when trying to access registry-keys, that were writen by a 32 Bit application on a 64 Bit machine.
    All 32 Bit entries are stored under a special subkey!
    so when you run with any cpu on a 64 bit machine you will not find these registry keys as long as not compiled as 32 bit.

    ReplyDelete
  5. Anonymous, if you found this article confusing, maybe you should find another line of work.

    In fact, this is good article ... explains this as well as any other I've read. Thanks.

    ReplyDelete
  6. Ha, nice comment, Peter. I didn't want to be the one to say it :)

    ReplyDelete
  7. Very helpful article! Thanks!

    ReplyDelete
  8. **Terrible explanation** are you nuts??.. its decent explanation.. Jezz I hate folks to pass poor comment like that.. take something away for the post..

    ReplyDelete
  9. Thanks....I like Peter's response to that comment, "if you found this article confusing, maybe you should find another line of work."

    ReplyDelete
  10. prolly his cube mate!

    ReplyDelete
  11. Nice article. I just ran into this problem. A program written in 2001 (but updated to c# in 2008) suddenly wouldn't work on 64 bit. The problem was, it was using Jet 4.0 to communicate w/ an old Access DB, and I had selected AnyCPU. A simple re-compile with x86 resolved it.

    ReplyDelete
  12. Very nice article.

    I have the same problem with my assembly. I was compiling my code with x86 dlls on a x64 machine using Any CPU option. When you access the dll, your solution crashes.

    I was using an approach to compiling specific versions, x64 and x86. But it's hard to manage 2 kings of codes, with different dlls.

    ReplyDelete
    Replies
    1. Hello Evone,
      even i am facing he same problem.I have used Microsoft.jet.oledb.4.0 in my code and it workls fine on 32 bit machine and crashed on 64 bit.Can somebody guide me what i must do.

      Delete
    2. Sounds like you need to set the target platform for your application to x86, NOT AnyCPU.

      Delete
  13. Bad article.

    ReplyDelete
  14. Nice article..very well explained !

    ReplyDelete
  15. Nice to find an article about this. My question what the best solution to when you want to deploy to two different servers - one x86 and the other x64 and you have two different vendor supplied assemblies for each platform (e.g. Oracle ODP.NET supplies x64 and x32 versions)? Is there an easy way to configure build options for both these scenarios? I presume if referenced the x64 vendor supplied assembly its still fine to build for All CPUs.

    ReplyDelete
  16. What build option would you use if want to deploy an app to x64 server but it references both x86 assemblies (interop. Excel) as well as x64 vendor supplied assemblies?

    ReplyDelete
    Replies
    1. As far as I know you can't reference x86 assemblies from an x64 process. We ran into that issue when creating a 64 bit process a while ago. Maybe that changed since newer versions of the .Net Framework can support multiple versions of the framework in the same process concurrently.

      Delete