如何使用.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个回答

10

@foobar: 你是对的,这太容易了 ;)

在99%的情况下,背景薄弱的开发人员最终未能意识到微软一直为任何人枚举Windows提供的强大功能。

当涉及到这样的问题时,系统管理员将始终编写更好、更简单的代码。

不过,需要注意的一点是,在此环境变量返回正确值的正确系统上,构建配置必须是 AnyCPU

System.Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE")

这将在32位Windows上返回"X86",在64位Windows上返回"AMD64"。


4
你的解决方案在一台搭载Intel i7-3720QM微处理器、运行Bootcamp并分区为Windows 7 Ultimate的MacBook Pro上返回了x86。Stefan Schultze的解决方案正确地将该处理器识别为64位。我相信你的解决方案适用于99%的基于Windows的个人电脑。加1分鼓励。 - Mark Kram
1
不行,在我的 Windows 7 Pro,64 位操作系统上返回了 "x86"。 - Hagai L

8

使用dotPeek可以帮助我们理解框架是如何实现的。有了这个想法,下面是我想到的:

public static class EnvironmentHelper
{
    [DllImport("kernel32.dll")]
    static extern IntPtr GetCurrentProcess();

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

    [DllImport("kernel32")]
    static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

    [DllImport("kernel32.dll")]
    static extern bool IsWow64Process(IntPtr hProcess, out bool wow64Process);

    public static bool Is64BitOperatingSystem()
    {
        // Check if this process is natively an x64 process. If it is, it will only run on x64 environments, thus, the environment must be x64.
        if (IntPtr.Size == 8)
            return true;
        // Check if this process is an x86 process running on an x64 environment.
        IntPtr moduleHandle = GetModuleHandle("kernel32");
        if (moduleHandle != IntPtr.Zero)
        {
            IntPtr processAddress = GetProcAddress(moduleHandle, "IsWow64Process");
            if (processAddress != IntPtr.Zero)
            {
                bool result;
                if (IsWow64Process(GetCurrentProcess(), out result) && result)
                    return true;
            }
        }
        // The environment must be an x86 environment.
        return false;
    }
}

使用示例:

EnvironmentHelper.Is64BitOperatingSystem();

6
请使用以下两个环境变量(伪代码):
if (PROCESSOR_ARCHITECTURE = x86 &&
    isDefined(PROCESSOR_ARCHITEW6432) &&
    PROCESSOR_ARCHITEW6432 = AMD64) {

    //64 bit OS
}
else
    if (PROCESSOR_ARCHITECTURE = AMD64) {
        //64 bit OS
    }
    else
        if (PROCESSOR_ARCHITECTURE = x86) {
            //32 bit OS
        }

请参考博客文章 HOWTO: 检测进程位数


你看到这个问题是关于.NET而不是C/C++的部分了吗?而且这是一个编译时与运行时检查的区别。另外,该代码正在执行赋值而不是比较操作。 - dvallejo
这段代码适用于.NET(已在2.0上测试)。可以通过以下方式访问环境变量:Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE"); Environment.GetEnvironmentVariable("PROCESSOR_ARCHITEW6432"); - andrew.fox

5

我在许多操作系统上都成功地使用了这个检查:

private bool Is64BitSystem
{
   get
   {
      return Directory.Exists(Environment.ExpandEnvironmentVariables(@"%windir%\SysWOW64"));
   }
}

无论操作系统的语言如何,此文件夹始终命名为“SysWOW64”。这适用于.NET Framework 1.1或更高版本。


作为一个拥有管理员权限的用户,我为什么不能在32位操作系统的%windir%上创建一个名为SysWOW64的文件夹呢?文件夹的存在意味着它确实存在。 - cogumel0
用户有意创建这样的文件夹的几率有多大?这只是一种检查操作系统是否为x64的不同方法。 - Alexandru Dicu
你的电脑可能会感染病毒的概率有多大呢?既然机率相当低,那么最好不要安装任何保护措施。编程不是关于创造一些有着很低“明知会失败”的几率的东西,而是关于创造一些有着很低“无意中失败”的几率的东西——然后修复它。前者被称为糟糕的编程/实现,后者被称为 bug。 - cogumel0
@AlexandruDicu,您应该在答案中提到,这种方法并不是100%准确的,如果文件夹被任何第三方应用程序或用户手动创建,仍然存在给出错误输出的风险。 - Rajesh Mishra

4

我需要做这个,但也需要作为管理员远程操作它,无论哪种情况,这对我来说似乎非常有效:

    public static bool is64bit(String host)
    {
        using (var reg = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, host))
        using (var key = reg.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\"))
        {
            return key.GetValue("ProgramFilesDir (x86)") !=null;
        }
    }

4
这是一个基于微软代码http://1code.codeplex.com/SourceControl/changeset/view/39074#842775的解决方案。它使用扩展方法来方便地重用代码。
以下是一些可能的用法示例:
bool bIs64BitOS = System.Environment.OSVersion.IsWin64BitOS();

bool bIs64BitProc = System.Diagnostics.Process.GetCurrentProcess().Is64BitProc();

//Hosts the extension methods  
public static class OSHelperTools  
{  
    /// <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 IsWin64BitOS(this OperatingSystem os)  
    {  
        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.               
            return Process.GetCurrentProcess().Is64BitProc();  
        }  
    }  

    /// <summary>  
    /// Checks if the process is 64 bit  
    /// </summary>  
    /// <param name="os"></param>  
    /// <returns>  
    /// The function returns true if the process is 64-bit;        
    /// otherwise, it returns false.  
    /// </returns>    
    public static bool Is64BitProc(this System.Diagnostics.Process p)  
    {  
        // 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 result;  
        return ((DoesWin32MethodExist("kernel32.dll", "IsWow64Process") && IsWow64Process(p.Handle, out result)) && result);  
    }  

    /// <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);  
}

1
CodePlex的链接似乎已经失效了。 - Peter Mortensen

3

以下是使用C#中的DllImport直接方法来实现,参考此页面

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

public static bool Is64Bit() 
{ 
    bool retVal; 

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

    return retVal; 
} 

你仍然需要先检查指针大小,否则它只会检查在 64 位系统上是否为 32 位进程。 - Bruno Lopes
1
也会在旧操作系统上崩溃,因为“IsWow64Process”不存在。 - Polynomial

3
我正在使用以下代码。注意:它是为一个AnyCPU项目制作的。
    public static bool Is32bitProcess(Process proc) {
        if (!IsThis64bitProcess()) return true; // We're in 32-bit mode, so all are 32-bit.

        foreach (ProcessModule module in proc.Modules) {
            try {
                string fname = Path.GetFileName(module.FileName).ToLowerInvariant();
                if (fname.Contains("wow64")) {
                    return true;
                }
            } catch {
                // What on earth is going on here?
            }
        }
        return false;
    }

    public static bool Is64bitProcess(Process proc) {
        return !Is32bitProcess(proc);
    }

    public static bool IsThis64bitProcess() {
        return (IntPtr.Size == 8);
    }

2

一切都很好,但这也应该从env中起作用:

PROCESSOR_ARCHITECTURE=x86

..

PROCESSOR_ARCHITECTURE=AMD64

可能太简单了 ;-)



2
这是一种使用Windows管理规范 (WMI) 的方法:
string _osVersion = "";
string _osServicePack = "";
string _osArchitecture = "";

ManagementObjectSearcher searcher = new ManagementObjectSearcher("select * from Win32_OperatingSystem");
ManagementObjectCollection collection = searcher.Get();

foreach (ManagementObject mbo in collection)
{
    _osVersion = mbo.GetPropertyValue("Caption").ToString();
    _osServicePack = string.Format("{0}.{1}", mbo.GetPropertyValue("ServicePackMajorVersion").ToString(), mbo.GetPropertyValue("ServicePackMinorVersion").ToString());

    try
    {
        _osArchitecture = mbo.GetPropertyValue("OSArchitecture").ToString();
    }
    catch
    {
        // OSArchitecture only supported on Windows 7/Windows Server 2008
    }
}

Console.WriteLine("osVersion     : " + _osVersion);
Console.WriteLine("osServicePack : " + _osServicePack);
Console.WriteLine("osArchitecture: " + _osArchitecture);

/////////////////////////////////////////
// Test on Windows 7 64-bit
//
// osVersion     : Microsoft Windows 7 Professional
// osservicePack : 1.0
// osArchitecture: 64-bit

/////////////////////////////////////////
// Test on Windows Server 2008 64-bit
//    --The extra r's come from the registered trademark
//
// osVersion     : Microsoftr Windows Serverr 2008 Standard
// osServicePack : 1.0
// osArchitecture: 64-bit

/////////////////////////////////////////
// Test on Windows Server 2003 32-bit
//    --OSArchitecture property not supported on W2K3
//
// osVersion     : Microsoft(R) Windows(R) Server 2003, Standard Edition
// osServicePack : 2.0
// osArchitecture:

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