1

Starting in December 2020, Windows supports x64 emulation on ARM64 devices. How can a program determine if the current version of Windows supports running x64 applications?

Prior to x64 emulation on ARM64, we could use RuntimeInformation.OSArchitecture == Architecture.X64 for this.

Vegard Larsen
  • 12,827
  • 14
  • 59
  • 102
  • This is not a window issue. It is an issue if your apps support x64. Many apps have multiple versions (x86,x32,x64). Depending on what version of app you installed will determine version. The reason for vendor supplying multiple version is the app has to work with other apps that may not support all the versions. – jdweng Jul 28 '21 at 09:02
  • 1
    Since this is tagged with .net, why do you care about emulation? The jitter should compile to arm directly. – JonasH Jul 28 '21 at 09:59
  • The software in question has to run "natively" as all supported architectures to be able to set global CBTHooks, which requires me to compile it for all the architectures on the machine. The question goes to how we can detect which process architectures can be run on the machine. – Vegard Larsen Jul 28 '21 at 14:06
  • Are you looking for this: https://learn.microsoft.com/en-us/windows/win32/api/wow64apiset/nf-wow64apiset-iswow64process2 ? – Simon Mourier Jul 28 '21 at 15:29
  • @SimonMourier Not really. That checks if a specific running process is ARM64/x64/x86. What I am looking for is a way to determine if the system is capable of executing x64, or ARM64, or x86. – Vegard Larsen Jul 31 '21 at 09:56
  • Have you read the link in detail? – Simon Mourier Jul 31 '21 at 10:25
  • I have and I didn't find anything in this API that would allow you to query whether the system can emulate non-native ISAs. It's taking a process handle as the first argument. That doesn't suggest that it were querying a system property. – IInspectable Aug 01 '21 at 09:23

1 Answers1

2

You can use GetMachineTypeAttributes (https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getmachinetypeattributes) to check if Windows supports running x64 code.

For example:

using System;
using System.Runtime.InteropServices;

public class Program
{
    [Flags]
    enum MachineAttributes
    {
        None = 0,
        UserEnabled = 0x00000001,
        KernelEnabled = 0x00000002,
        Wow64Container = 0x00000004,
    }

    [DllImport("kernel32.dll", PreserveSig = false)]
    static extern MachineAttributes GetMachineTypeAttributes(ushort WowGuestMachine);
    const ushort IMAGE_FILE_MACHINE_AMD64 = 0x8664;
    const ushort IMAGE_FILE_MACHINE_I386 = 0x014c;
    const ushort IMAGE_FILE_MACHINE_ARM64 = 0xAA64;

    public static void Main()
    {
        var x64Support = GetMachineTypeAttributes(IMAGE_FILE_MACHINE_AMD64);
        Console.WriteLine("x64 support: {0}", x64Support);
        var x86Support = GetMachineTypeAttributes(IMAGE_FILE_MACHINE_I386);
        Console.WriteLine("x86 support: {0}", x86Support);
        var arm64Support = GetMachineTypeAttributes(IMAGE_FILE_MACHINE_ARM64);
        Console.WriteLine("Arm64 support: {0}", arm64Support);

    }
}

Running this on an x64 device produces:

x64 support: UserEnabled, KernelEnabled
x86 support: UserEnabled, Wow64Container
Arm64 support: None

And on an Arm64 Win11 device produces:

x64 support: UserEnabled
x86 support: UserEnabled, Wow64Container
Arm64 support: UserEnabled, KernelEnabled

So to detect if x64 code can be run, check if the returned value is not MachineAttributes.None:

public static bool SupportsX64()
{
    return GetMachineTypeAttributes(IMAGE_FILE_MACHINE_AMD64) != MachineAttributes.None;
}

Updated

Looks like GetMachineTypeAttributes was added in Win11, so if attempting to P/Invoke it throws EntryPointNotFoundException then you know that you're running on pre-Win11 and can use your older detection logic:

public static bool SupportsX64()
{
    try
    {
        // Win11+: Ask the OS if we can run AMD64 code.
        return GetMachineTypeAttributes(IMAGE_FILE_MACHINE_AMD64) != MachineAttributes.None;
    }
    catch (EntryPointNotFoundException)
    {
        // Pre-Win11: Only x64 machines can run x64 code.
        return RuntimeInformation.OSArchitecture == Architecture.X64;
    }
}