如何使用.NET检测Windows 64位平台?

296
在一个.NET 2.0 C# 应用程序中,我使用以下代码来检测操作系统平台:
string os_platform = System.Environment.OSVersion.Platform.ToString();

这将返回"Win32NT"。问题是,即使在Windows Vista 64位上运行时,它仍会返回"Win32NT"。

是否有其他方法可以知道正确的平台(32位或64位)?

请注意,它还应在以32位应用程序形式在Windows 64位上运行时检测到64位。

31个回答

260

.NET 4在Environment类中增加了两个新属性:Is64BitProcessIs64BitOperatingSystem。有趣的是,如果您使用Reflector工具,您会发现它们在32位和64位版本的mscorlib中实现方式不同。32位版本对于Is64BitProcess返回false,并通过P/Invoke调用IsWow64Process来处理Is64BitOperatingSystem。而64位版本对这两个属性都返回true。


5
为什么不直接下载源代码,而要用反编译工具?这样你就可以获得注释和其他“笔记”。 - AMissico
3
根据参考来源,它执行类似以下的操作:if (IntPtr.Size == 8) return true; if(!DoesWin32MethodExist(...,"IsWow64Process")) return false; return IsWow64Process(GetCurrentProcess());(伪代码) - Polynomial
5
好的,如果用户使用的是.NET 4.0,那么这绝对是正确答案(即Environment.Is64BitOperatingSystem)。顺便提一下,在.NET 3.5中似乎没有这个属性。 - BrainSlugs83
5
这并没有回答问题,该问题特别指出了.Net 2.0。 - abbottdev
.NET Core已经发布在MIT许可下,这意味着您可以阅读Is64BitProcessIs64BitOperatingSystem的源代码(版本2.0的链接)。 - Cristian Ciupitu

236

更新: 正如Joel Coehoorn和其他人所建议的,从.NET Framework 4.0开始,您可以直接检查Environment.Is64BitOperatingSystem


如果在64位Windows上运行32位.NET Framework 2.0,则IntPtr.Size将不会返回正确的值(它将返回32位)。

正如微软的Raymond Chen所描述的那样,您必须首先检查是否在64位进程中运行(我认为在.NET中您可以通过检查IntPtr.Size来实现),如果您正在运行32位进程,则仍然必须调用Win API函数IsWow64Process。 如果返回true,则表示您正在64位Windows上运行的32位进程中。

微软的Raymond Chen: 如何以编程方式检测您是否在64位Windows上运行

我的解决方案:

static bool is64BitProcess = (IntPtr.Size == 8);
static bool is64BitOperatingSystem = is64BitProcess || InternalCheckIsWow64();

[DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool IsWow64Process(
    [In] IntPtr hProcess,
    [Out] out bool wow64Process
);

public static bool InternalCheckIsWow64()
{
    if ((Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor >= 1) ||
        Environment.OSVersion.Version.Major >= 6)
    {
        using (Process p = Process.GetCurrentProcess())
        {
            bool retVal;
            if (!IsWow64Process(p.Handle, out retVal))
            {
                return false;
            }
            return retVal;
        }
    }
    else
    {
        return false;
    }
}

8
在运行于32位操作系统时,任何对IsWow64Process的调用都会抛出异常,因为该条目在kernel32.dll中不存在。你应该检查来自codeplex的解决方案,网址为http://1code.codeplex.com/SourceControl/changeset/view/39074#842775。我还有一个基于该代码的解决方案列在本页面底部,如果您关心重用代码,它使用扩展方法。 - dmihailescu
8
IsWow64Process是在Win XP SP2中引入的。如果您需要XP SP2或更新版本,则此代码可以正常工作。 - Marc
3
@dmihailescu,您可以在调用IsWow64Process之前使用DoesWin32MethodExist,这是.net 4.0实现is64BitOperatingSystem的方法。 - noobish
4
您的解决方案在一台搭载Intel i7-3720QM微处理器、运行Bootcamp并使用Windows 7 Ultimate分区的MacBook Pro上返回了正确的值。+1 - Mark Kram
14
FYI:从.NET 4.0开始,您可以只检查System.Environment.Is64BitOperatingSystem。您是否可以编辑此内容到您的回答中,或者给我编辑权限以将其编辑到您的回答中? - Joel Coehoorn
显示剩余3条评论

105

2
对于极客而言,使用IsWow64Process(...)的内部实现 http://referencesource.microsoft.com/#mscorlib/system/environment.cs,75feca36cdd83149 - Zyo

51

这只是对Bruno Lopez上面建议的实现方式的一个实现,但可用于Win2k及其所有WinXP服务包。我想我应该把它发布出来,这样其他人就不需要手动滚动它了。(本来可以发布为评论,但我是新用户!)

[DllImport("kernel32", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
public extern static IntPtr LoadLibrary(string libraryName);

[DllImport("kernel32", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
public extern static IntPtr GetProcAddress(IntPtr hwnd, string procedureName);

private delegate bool IsWow64ProcessDelegate([In] IntPtr handle, [Out] out bool isWow64Process);

public static bool IsOS64Bit()
{
    if (IntPtr.Size == 8 || (IntPtr.Size == 4 && Is32BitProcessOn64BitProcessor()))
    {
        return true;
    }
    else
    {
        return false;
    }
}

private static IsWow64ProcessDelegate GetIsWow64ProcessDelegate()
{
  IntPtr handle = LoadLibrary("kernel32");

  if ( handle != IntPtr.Zero)
  {
    IntPtr fnPtr = GetProcAddress(handle, "IsWow64Process");

    if (fnPtr != IntPtr.Zero)
    {
      return (IsWow64ProcessDelegate)Marshal.GetDelegateForFunctionPointer((IntPtr)fnPtr, typeof(IsWow64ProcessDelegate));
    }
  }

  return null;
}

private static bool Is32BitProcessOn64BitProcessor()
{
  IsWow64ProcessDelegate fnDelegate = GetIsWow64ProcessDelegate();

  if (fnDelegate == null)
  {
    return false;
  }

  bool isWow64;
  bool retVal = fnDelegate.Invoke(Process.GetCurrentProcess().Handle, out isWow64);

  if (retVal == false)
  {
    return false;
  }

  return isWow64;
}

49

完整的答案如下(摘自stefan-mg、ripper234和BobbyShaftoe的回答):

    [DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool IsWow64Process([In] IntPtr hProcess, [Out] out bool lpSystemInfo);

    private bool Is64Bit()
    {
        if (IntPtr.Size == 8 || (IntPtr.Size == 4 && Is32BitProcessOn64BitProcessor()))
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    private bool Is32BitProcessOn64BitProcessor()
    {
        bool retVal;

        IsWow64Process(Process.GetCurrentProcess().Handle, out retVal);

        return retVal;
    } 

首先检查当前进程是否为64位进程。如果不是,再检查32位进程是否为Wow64Process。


13
这段代码在Win2000和WinXP SP1及更早版本中将无法运行。在调用IsWow64Process()函数之前,您需要检查它是否存在,因为它仅在XP SP2、Vista/Win7中引入。 - user9876
2
@user9876,还有人(或曾经)针对那些古老的系统吗? - CMircea
5
这个示例没有正确处理由Process.GetCurrentProcess()返回的Process实例的释放问题。 - Joe

43

微软提供了一个代码示例:

http://1code.codeplex.com/SourceControl/changeset/view/39074#842775

它看起来像这样:

    /// <summary>
    /// The function determines whether the current operating system is a 
    /// 64-bit operating system.
    /// </summary>
    /// <returns>
    /// The function returns true if the operating system is 64-bit; 
    /// otherwise, it returns false.
    /// </returns>
    public static bool Is64BitOperatingSystem()
    {
        if (IntPtr.Size == 8)  // 64-bit programs run only on Win64
        {
            return true;
        }
        else  // 32-bit programs run on both 32-bit and 64-bit Windows
        {
            // Detect whether the current process is a 32-bit process 
            // running on a 64-bit system.
            bool flag;
            return ((DoesWin32MethodExist("kernel32.dll", "IsWow64Process") &&
                IsWow64Process(GetCurrentProcess(), out flag)) && flag);
        }
    }

    /// <summary>
    /// The function determins whether a method exists in the export 
    /// table of a certain module.
    /// </summary>
    /// <param name="moduleName">The name of the module</param>
    /// <param name="methodName">The name of the method</param>
    /// <returns>
    /// The function returns true if the method specified by methodName 
    /// exists in the export table of the module specified by moduleName.
    /// </returns>
    static bool DoesWin32MethodExist(string moduleName, string methodName)
    {
        IntPtr moduleHandle = GetModuleHandle(moduleName);
        if (moduleHandle == IntPtr.Zero)
        {
            return false;
        }
        return (GetProcAddress(moduleHandle, methodName) != IntPtr.Zero);
    }

    [DllImport("kernel32.dll")]
    static extern IntPtr GetCurrentProcess();

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    static extern IntPtr GetModuleHandle(string moduleName);

    [DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
    static extern IntPtr GetProcAddress(IntPtr hModule,
        [MarshalAs(UnmanagedType.LPStr)]string procName);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool IsWow64Process(IntPtr hProcess, out bool wow64Process);

还有一个可用的 WMI 版本(用于测试远程机器)。


1
请注意,此代码已根据Microsoft Public License获得许可。 - ladenedge
没有使用托管的.NET,如何查看WMI版本?我想看看它,但迄今为止还没有找到。 - JohnZaj

17

您还可以检查 PROCESSOR_ARCHITECTURE 环境变量。

在32位Windows上,它要么不存在,要么设置为"x86"。

private int GetOSArchitecture()
{
    string pa = 
        Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE");
    return ((String.IsNullOrEmpty(pa) || 
             String.Compare(pa, 0, "x86", 0, 3, true) == 0) ? 32 : 64);
}

1
仅仅因为你拥有一颗64位处理器并不意味着你拥有一个64位操作系统。 - David
2
@David 这个报告了Windows的处理器架构,而不是CPU。请参见此页面上从“The Code”开始的详细说明:http://andrewensley.com/2009/06/c-detect-windows-os-part-1/ - Andrew Ensley
1
只是补充一下,当你运行此代码时,如果你的应用程序配置为“优先使用32位”且“平台目标”为“任何CPU”,那么你将得到“x86”,但是如果你取消选中“优先使用32位”,那么你将得到“AMD64”。 - XAMlMAX

17

来自 Chriz Yuen 博客

C# .Net 4.0 引入了两个新的环境属性 Environment.Is64BitOperatingSystem; Environment.Is64BitProcess;

在使用这两个属性时请小心。 在 Windows 7 64 位机器上进行测试。

//Workspace: Target Platform x86
Environment.Is64BitOperatingSystem True
Environment.Is64BitProcess False

//Workspace: Target Platform x64
Environment.Is64BitOperatingSystem True
Environment.Is64BitProcess True

//Workspace: Target Platform Any
Environment.Is64BitOperatingSystem True
Environment.Is64BitProcess True

16

最快的方法:

if(IntPtr.Size == 8) {
    // 64 bit machine
} else if(IntPtr.Size == 4)  {
    // 32 bit machine
} 

注意:这种方法非常直接,只有在程序不强制作为32位进程执行时才能在64位上正常工作(例如通过项目设置中的<Prefer32Bit>true</Prefer32Bit>)。


32
如果在64位的Windows上运行32位的.NET Framework 2.0,这种方法行不通,因为它将返回32位。 - Stefan Schultze
对不起,我忘记了这种情况。我已经编辑了问题并提到了这一点。谢谢stefan-mg。 - Marc
1
这不是正确的,平台可能是64位,但您仍然在32位模式下运行。 - Sebastian Good

11

试一试这个:

Environment.Is64BitOperatingSystem

Environment.Is64BitProcess

5
感谢您的回复,但请在发帖之前阅读已有的答案,因为这个解决方案已经给出。另外请注意,原问题是关于 .net 2 的,而这两个属性是仅在 .net 4 中引入的。 - Marc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接