C# - How to determine if a Program, Process or File, is 32-bit or 64-bit

The specific technique that you will use depends upon whether the file under consideration is:
  1. A Native program. A DLL, EXE, OCX, etc. that contains Intel machine code and runs directly on the CPU instruction set, or
  2. An IL program. A DLL or EXE that is contains Intermediate Langugage code, that is run not on the CPU directly, but in a custom runtime environment that subsequently compiles the IL to native executable machine code.

We present 9 different techniques, plus one that doesn't work, despite popular opinion to the contrary. Some console, some code (C#), some GUI. Doubtless, there are many more.

What doesn't work.

You can use Microsoft corflags.exe
Usage: corflags.exe filename

Any CPU

PE        : PE32
CorFlags  : 0x1
ILONLY    : 1
32BITREQ  : 0
32BITPREF : 0

Any CPU - Prefer 32-bit

PE        : PE32
CorFlags  : 0x20003
ILONLY    : 1
32BITREQ  : 0
32BITPREF : 1

x86

PE        : PE32
CorFlags  : 0x3
ILONLY    : 1
32BITREQ  : 1
32BITPREF : 0

x64

PE        : PE32+
CorFlags  : 0x1
ILONLY    : 1
32BITREQ  : 0
32BITPREF : 0

The table below displays the corflags values for the processor build configurations supported by Visual Studio.

PE
32BITREQ
32BITPREF
Any CPU
PE32
0
0
Any CPU - Prefer 32-bit
PE32
0
1
x86
PE32
1
0
x64
PE32+
0
0

You can use dumpbin.exe
Dumpbin is a Microsoft utility and is part of Visual Studio.

Usage: dumpbin.exe filename /headers

Look for: 8664 machine (x64) or 14C machine (x86)

Dumpbin output:

dumpbin c:\windows\notepad.exe /headers
 
Microsoft (R) COFF/PE Dumper Version 14.12.25835.0
Copyright (C) Microsoft Corporation.  All rights reserved.
 
 
Dump of file c:\windows\notepad.exe
 
PE signature found
 
File Type: EXECUTABLE IMAGE
 
FILE HEADER VALUES
            8664 machine (x64)
               6 number of sections
        A0C4CEAB time date stamp
               0 file pointer to symbol table
               0 number of symbols
              F0 size of optional header
              22 characteristics
                   Executable
                   Application can handle large (>2GB) addresses
You can use Cygwin file.exe
Usage: file.exe filename

64-bit notepad.exe

file c:\windows\notepad.exe
 
PE32+ executable (GUI) x86-64, for MS Windows

32-Bit notepad.exe

file c:\windows\syswow64\notepad.exe
 
PE32 executable (GUI) Intel 80386, for MS Windows
You can use SysInternals sigcheck.exe
Usage: sigcheck.exe filename

64-bit notepad.exe

sigcheck c:\windows\notepad.exe
 
Sigcheck v2.54 - File version and signature viewer
Copyright (C) 2004-2016 Mark Russinovich
Sysinternals - www.sysinternals.com
 
c:\windows\notepad.exe:
        Verified:       Signed
        Signing date:   7:29 AM 9/29/2017
        Publisher:      Microsoft Windows
        Company:        Microsoft Corporation
        Description:    Notepad
        Product:        Microsoft� Windows� Operating System
        Prod version:   10.0.16299.15
        File version:   10.0.16299.15 (WinBuild.160101.0800)
        MachineType:    64-bit

32-Bit notepad.exe

sigcheck c:\windows\syswow64\notepad.exe
 
Sigcheck v2.54 - File version and signature viewer
Copyright (C) 2004-2016 Mark Russinovich
Sysinternals - www.sysinternals.com
 
c:\windows\syswow64\notepad.exe:
        Verified:       Signed
        Signing date:   7:25 AM 9/29/2017
        Publisher:      Microsoft Windows
        Company:        Microsoft Corporation
        Description:    Notepad
        Product:        Microsoft� Windows� Operating System
        Prod version:   10.0.16299.15
        File version:   10.0.16299.15 (WinBuild.160101.0800)
        MachineType:    32-bit
You can use Environment.Is64BitProcess
using System;
 
namespace Zuga.net
{
    class Program
    {
        public static void Main(string[] args)
        {
            var is64 = Environment.Is64BitProcess;
            Console.WriteLine($"Environment.Is64BitProcess: {is64}");
        }
    }
}

Program output:

Environment.Is64BitProcess: True
You can check IntPtr.Size
using System;
 
namespace Zuga.net
{
    class Program
    {
        public static void Main(string[] args)
        {
            if (IntPtr.Size == 4)
            {
                // 32-bit
                Console.WriteLine("Pointer size is 4. A 32-bit operating system uses 4-byte pointers.");
            }
            else if (IntPtr.Size == 8)
            {
                // 64-bit
                Console.WriteLine("Pointer size is 8. A 64-bit operating system uses 8-byte pointers.");
            }
        }
    }
}

Program output:

Pointer size is 8. A 64-bit operating system uses 8-byte pointers.
You can use Assembly.GetBinaryType()
using System;
using System.Reflection;
using System.Runtime.InteropServices;
 
namespace Zuga.net
{
    public enum BinaryType : uint
    {
        SCS_32BIT_BINARY = 0,   // A 32-bit Windows-based application
        SCS_64BIT_BINARY = 6,   // A 64-bit Windows-based application.
        SCS_DOS_BINARY = 1,     // An MS-DOS � based application
        SCS_OS216_BINARY = 5,   // A 16-bit OS/2-based application
        SCS_PIF_BINARY = 3,     // A PIF file that executes an MS-DOS � based application
        SCS_POSIX_BINARY = 4,   // A POSIX � based application
        SCS_WOW_BINARY = 2      // A 16-bit Windows-based application
    }
 
    class Program
    {
        [DllImport("kernel32.dll")]
        static extern bool GetBinaryType(string lpApplicationName, out BinaryType lpBinaryType);
 
        static void Main(string[] args)
        {
            var exePath = Assembly.GetExecutingAssembly().Location;
 
            BinaryType bt;
            if (GetBinaryType(exePath, out bt))
            {
                Console.WriteLine(bt);
            }
        }
    }
}

Any CPU

SCS_64BIT_BINARY

Any CPU - Prefer 32-bit

SCS_32BIT_BINARY

x86

SCS_32BIT_BINARY

x64

SCS_64BIT_BINARY
You can use Assembly.GetPEKind()
using System;
using System.Reflection;
 
namespace Zuga.net
{
    class Program
    {
        static void Main(string[] args)
        {
            Assembly asm = Assembly.GetExecutingAssembly();
 
            PortableExecutableKinds peKind;
            ImageFileMachine machine;
 
            asm.ManifestModule.GetPEKind(out peKind, out machine);
 
            Console.WriteLine($"PE kind: {peKind}");
            Console.WriteLine($"Machine: {machine}");
        }
    }
}

Any CPU

PE kind: ILOnly
Machine: I386

Any CPU - Prefer 32-bit

PE kind: ILOnly, Preferred32Bit
Machine: I386

x86

PE kind: ILOnly, Required32Bit
Machine: I386

x64

PE kind: ILOnly, PE32Plus
Machine: AMD64
You can use Task Manager

[taskmanager.gif]
You should not use IsWow64Process()
This function will not tell you whether a process is 64-bit.
It will return true if the process is a 32-bit process running on a 64-bit operating system in a compatibility layer called Wow64 (Windows-32-on-Windows-64).
IsWow64Process
32-bit on 32-bit
False
32-bit on 64-bit
True
64-bit on 64-bit
False
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
 
namespace Zuga.net
{
    class Program
    {
        [DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool IsWow64Process([In] IntPtr hProcess, [Out] out bool wow64Process);
 
        static void Main(string[] args)
        {
            bool iswow64;
            var handle = Process.GetCurrentProcess().Handle;
            var ret = IsWow64Process(handle, out iswow64);
            if (ret)
            {
                Console.WriteLine($"IsWow64Process: {iswow64}");
            }
        }
    }
}

Ads by Google


Ask a question, send a comment, or report a problem - click here to contact me.

© Richard McGrath