Click here to Skip to main content
15,867,568 members
Articles / Programming Languages / ASM

Which Platform to Target your .NET Applications?

Rate me:
Please Sign up or sign in to vote.
4.81/5 (22 votes)
4 Jun 2016CPOL8 min read 34.6K   779   27   3
An intensive research is given on this topic. A handy utility tool is built to check if an assembly unmanaged or managed, built for 32-bit or 64-bit Windows.

Introduction

From the surface, this question may be as simple as clicking one button to select build for any CPU inside Visual Studio 2012 to 2015 project property=>Build tab. Actually, it is not that simple. After intensive research, I share my understanding here with you.

Besides theoretic results, I integrate all scattered code snippets from the Internet into an easy and useful tool. It can tell an assembly if it is managed, or unmanaged; built for 32-bit or 64-bit platform.

After we build software and are ready to deploy our software to customers machines, we have one question coming up: is customer machine 32-bit Windows, or 64-bit Windows? Should we build our application to target any CPU? I hope this post will help you on this question.

Alternatives can refer to posting [8]-[14].

Disclaimer: I do not write and own these pieces of logic. I just integrate these pieces of code into a useful tool for you to use. These code snippets come from reference [2]-[7]. Particularly, CorFlagsReader.cs is under Apache License.

Visual Studio 2015 Default Build Configuration

When a .NET application is built inside Visual Studio 2012 and up, the default setting is AnyCPU with an additional sub-type of AnyCPU, “Any CPU 32-bit preferred”.[20] It implies the following:

  1. If the process runs on a 32-bit Windows system, it runs as a 32-bit process. IL is compiled to x86 machine code.
  2. If the process runs on a 64-bit Windows system, it runs as a 32-bit process. IL is compiled to x86 machine code.
  3. If the process runs on an ARM Windows system, it runs as a 32-bit process. IL is compiled to ARM machine code.

Another subtle observation is in [21].

Case Study

If a managed application is built for 32-bit OS, then it will run on 32-bit OS. If this application is built for 64-bit OS, and it references 32-bit unmanaged assembly, then it will not work on 64-bit OS.

SQLite ADO.NET installation is a real example for it. If you want to build a C# application to target 64-bit Windows, you need to install SQLite ADO.NET 64-bit DLLs.

Please refer to [23] for more information.

Overview on .NET Application Target Platforms

As we build .NET application in Visual Studio, we need to select target to a specific architecture.

"If you have 100% type safe managed code, then you really can just copy it to the 64-bit platform and run it successfully under the 64-bit CLR."

From [18], we know the following:

Consider a .NET application that is 100% type safe code. In this scenario it is possible to take your .NET executable that you run on your 32-bit machine and move it to the 64-bit system and have it run successfully. Why does this work? Since the assembly is 100% type safe we know that there are no dependencies on native code or COM objects and that there is no 'unsafe' code which means that the application runs entirely under the control of the CLR. The CLR guarantees that while the binary code that is generated as the result of Just-in-time (JIT) compilation will be different between 32-bit and 64-bit, the code that executes will both be semantically the same.

Therefore, if our application is 100% type safe managed code, then we have the following scenarios:

If we select to target x86 architecture, our application will run on any Windows-based computer that supports the targeted .NET framework version. More specifically, it will always run in a 32-bit process, even on a 64-bit operating system.

If we select to target x64 architecture, our application will require a 64-bit process and will not run on 32-bit operating systems.

Both the x86 and x64 options can be useful when we are using third party DLLs, particularly those that use unmanaged code, which require either a 32-bit or a 64-bit process. For example, when a third-party DLL is compiled for x86, a 64-bit process cannot use it.

If we select to target "Any CPU", our application will execute on any supported operating system and the process will use the most appropriate architecture option. Specifically, on 32-bit operating systems, it will run as 32-bit. On 64-bit operating systems, it will execute in a 64-bit process. A possibility comes out that our application may need to behave differently according to its process type. We then need to detect the type of process at run time.

Reference [1] is good to read.

Potential Barriers

If our managed applications have the following circumstances, then they will keep the application targeting to x64 from working well:

  • Invoking platform APIs via p/invoke
  • Invoking COM objects
  • Making use of a mechanism for sharing information
  • Using serialization as a way unsafe code (Please note: This is minor in terms of usage.)
  • Using marshaling as of persisting state

No matter what our application is doing, we need to know our application source code and its dependent assemblies, is it managed or unmanaged, 32-bit or 64-bit? We can have the following choices:

  • Migrate the code with no changes
  • Make changes to your code to handle 64-bit pointers correctly
  • Work with other vendors, etc., to provide 64-bit versions of their products
  • Make changes to your logic to handle marshaling and/or serialization

In my projects, I am only concerned about unsafe code. But from [18], we see that: using unsafe code in your managed application does not mean that migrating to the 64-bit platform will not be possible. Nor does it mean that there will be problems. What it does mean is that you must review all of the unsafe code your managed application has and determine if there will be any issues.

CorFlag Values and their Applications

To know which platform a .NET assembly is built for, we can use CorFlag Values. Reference[19] is the specification on PE file format. Reference[3] is a useful code to get all CorFlag values. The following two tables contain the rule to know all related information about the assembly. Most recent information is updated in [25] for .NET framework 4.5.

CorFlag Information

CLR Header.NET framework it targets for
PE

PE header type:

PE32 = 32-bit

PE32+ = 64 bit

CorFlagsvarious flags for endian type, ILONLY, etc.
ILONLYthe file contains IL only (i.e., no unsafe code)
32BIT

1=x86 target

0=any CPU

Signed

1=Assembly signed

0=Assembly not signed

Rules to Decide Platform

Any CPUPE32 and 32BIT=0
x86PE32 and 32BIT=1
x64/Itanium(IA-64)PE32+ and 32BIT=0

Refined Rules for .NET framework 4.5.1

CPU ArchitecturePE32BITREQ32BITPREF
x86(32-bit)PE3210
x64(64-bit)PE32+00
any CPUPE3200
any CPU 32-bit preferredPE3201

Code Highlights

Thanks to Kirill Osenkov in reference[25], we get this precious details for CorFlags values:

C#
    [Flags]
public enum CorFlags
{
    ILOnly           = 0x00000001,
    Requires32Bit    = 0x00000002,
    ILLibrary        = 0x00000004,
    StrongNameSigned = 0x00000008,
    NativeEntryPoint = 0x00000010,
    TrackDebugData   = 0x00010000,
    Prefers32Bit     = 0x00020000,
}

Based on these details, I add the following properties to CorFlagsReader class in CorFlagsReader.cs file:

C#
  public bool Is32BITREQ
{
    get
    {
        return (corflags & CorFlags.Requires32Bit) == CorFlags.Requires32Bit;
    }
}

public bool Is32BITPREF
{
    get
    {
        return (corflags & CorFlags.Prefers32Bit) == CorFlags.Prefers32Bit;
    }
}
public bool IsPE32
{
    get
    {
        return (peFormat == PEFormat.PE32);
    }
}

public bool IsPE32Plus
{
    get
    {
        return (peFormat == PEFormat.PE32Plus);
    }
}

In the case of managed assembly, I code rules as follows in the openAnAssemblyToolStripMenuItem_Click event:

C#
if(isManagedAssembly)
{
    textBox1.Text = fileName +" is a managed assembly.\n";
    CorFlagsReader corFlags= CorFlagsReader.ReadAssemblyMetadata(fileName);

    if (corFlags.IsPE32 & corFlags.Is32BITREQ & (!corFlags.Is32BITPREF))
    {
        textBox1.Text += "Target CPU architecture: x86";
    }
    if (corFlags.IsPE32 & (!corFlags.Is32BITREQ) & (!corFlags.Is32BITPREF))
    {
        textBox1.Text += "Target CPU architecture: anyCPU";
    }
    if ((corFlags.IsPE32 & (!corFlags.Is32BITREQ) & corFlags.Is32BITPREF) || 
    (corFlags.IsPE32 & corFlags.Is32BITREQ & corFlags.Is32BITPREF))
    {
        textBox1.Text += "Target CPU architecture: anyCPU 32-bit preferred";
    }
    if (corFlags.IsPE32Plus & (!corFlags.Is32BITREQ) & (!corFlags.Is32BITPREF))
    {
        textBox1.Text += "Target CPU archtecture:x64";
    }
}

Assembly Checker

This assembly checker can be used to check any assembly type. It has an easy GUI:

Please load any DLL or EXE file into it and let me know if you have any questions.

Source code files are uploaded here. An executable is ready for you to use.

A .NET Assembly Contains Unmanaged Code?

A good discussion in [26] is worthy reading. corflags tool from Microsoft can tell if it is purely IL or contains mixed unmanaged code, but PEVerify tool can tell if it is 100% type safe.

Feedback

If you have good ideas and thoughts, please give your precious feedback. I hope this tool is useful and saves you more time.

References

  1. Back to Basics: 32-bit and 64-bit confusion around x86 and x64 and the .NET Framework and CLR
  2. How to determine whether a DLL is a managed assembly or native (prevent loading a native dll)?
  3. CorFlagsReader.cs content
  4. Check if unmanaged DLL is 32-bit or 64-bit?
  5. How to find if a native DLL file is compiled as x64 or x86?
  6. How to determine if a .NET assembly was built for x86 or x64?
  7. How do I determine if a .NET application is 32 or 64 bit?
  8. How do I tell if my application is running as a 32-bit or 64-bit application?
  9. 3 Ways to Learn Whether a Windows Program is 64-bit or 32-bit
  10. How to check if a binary is 32 or 64 bit on Windows?
  11. Quick way to tell if an installed application is 64-bit or 32-bit
  12. How to tell if a .exe file is a 32-bit or 64-bit application using dumpbin
  13. Migrating 32-bit Managed Code to 64-bit
  14. Determining Which Version of the .NET Framework Is Installed
  15. How can I tell if my .NET application is running in 64bit on the 64bit server?
  16. Checking if the Current Process is 64-bit
  17. x64 Development with .NET
  18. Migrating 32-bit Managed Code to 64-bit
  19. Microsoft PE and COFF Specification
  20. What AnyCPU Really Means As Of .NET 4.5 and Visual Studio 11
  21. Why does 'Any CPU (prefer 32-bit)' allow me to allocate more memory than x86 under .NET 4.5?
  22. 32bitness and 64bitness and migrating DasBlog on IIS7 and ASP.NET under Vista64
  23. SQLite configuration for C# application targeting any CPU - Part 1
  24. Moving from 32-bit to 64-bit application development on .NET Framework
  25. How to interpret the CorFlags flags?
  26. How do I find out if a .NET assembly contains unmanaged code?

History

  • 07/05/16: Initialized this article

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
United States United States
turns good thoughts into actions...


Comments and Discussions

 
PraiseGreat article, thank you, M{r/s} Southmountain! Pin
sch1166-Jun-16 13:59
professionalsch1166-Jun-16 13:59 
GeneralMy vote of 4 Pin
Muhammad Shahid Farooq4-Jun-16 19:31
professionalMuhammad Shahid Farooq4-Jun-16 19:31 
GeneralRe: My vote of 4 Pin
Southmountain5-Jun-16 16:30
Southmountain5-Jun-16 16:30 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.