在开发软件时,经常需要知道程序运行的操作系统版本和位数,以便进行相应的适配和优化。本文将介绍如何使用C#编写程序来检测Windows操作系统的版本和位数。
在尝试查找检测Windows版本和位数的代码时,发现很多代码都没有更新到Windows 7,并且它们都没有包含所有可用的Windows版本(尤其是缺少“Professional”版本,这是常用的操作系统版本)。此外,它们都没有正确地确定操作系统是32位还是64位。在寻找解决方案的过程中,找到了一篇很好的文章:,认为这是最好的、最新的版本。所以决定修改这篇文章的代码,添加缺失的部分。
添加了对“Windows 7”和“Windows Server 2008 R2”的检测。添加了所有能发现的缺失的Windows版本。完全重写了32/64位检测代码。
创建的类非常容易使用。只需将CS文件包含到项目中(或者将其编译为DLL以在VB项目中使用),然后像这样查询属性:
StringBuilder sb = new StringBuilder(String.Empty);
sb.AppendLine("Operation System Information");
sb.AppendLine("----------------------------");
sb.AppendLine(String.Format("Name = {0}", OSVersionInfo.Name));
sb.AppendLine(String.Format("Edition = {0}", OSVersionInfo.Edition));
if (OSVersionInfo.ServicePack != string.Empty)
sb.AppendLine(String.Format("Service Pack = {0}", OSVersionInfo.ServicePack));
else
sb.AppendLine("Service Pack = None");
sb.AppendLine(String.Format("Version = {0}", OSVersionInfo.VersionString));
sb.AppendLine(String.Format("ProcessorBits = {0}", OSVersionInfo.ProcessorBits));
sb.AppendLine(String.Format("OSBits = {0}", OSVersionInfo.OSBits));
sb.AppendLine(String.Format("ProgramBits = {0}", OSVersionInfo.ProgramBits));
textBox1.Text = sb.ToString();
检测操作系统是32位还是64位实际上是一个很大的问题。发现很多建议的方法都不能正确工作。为了那些感兴趣以及为了学习和分享信息,将在这里列出不同的建议:
最流行的方法似乎是这种方法的变体:
return IntPtr.Size * 8;
但这实际上并没有返回操作系统的位架构,它返回的是运行程序的位值。所以对于在64位Windows上以32位模式运行的程序,上述代码将返回32。
另一种误导性很大的方法是:
string pa = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE");
return ((String.IsNullOrEmpty(pa) || String.Compare(pa, 0, "x86", 0, 3, true) == 0) ? 32 : 64);
实际上,这个结果与版本1完全相同:它没有返回PROCESSOR_ARCHITECTURE名称所说的处理器位架构,而是返回了运行程序的位架构。对于在64位Windows上以32位模式运行的程序,上述代码也将返回32。
请注意:为了保持文章的合理长度,没有包含结构声明和PInvoke API声明……它们可以在源代码中找到。
ProcessorArchitecture pbits = ProcessorArchitecture.Unknown;
try
{
SYSTEM_INFO l_System_Info = new SYSTEM_INFO();
GetSystemInfo(ref l_System_Info);
switch (l_System_Info.uProcessorInfo.wProcessorArchitecture)
{
case 9: // PROCESSOR_ARCHITECTURE_AMD64
pbits = ProcessorArchitecture.Bit64;
break;
case 6: // PROCESSOR_ARCHITECTURE_IA64
pbits = ProcessorArchitecture.Itanium64;
break;
case 0: // PROCESSOR_ARCHITECTURE_INTEL
pbits = ProcessorArchitecture.Bit32;
break;
default: // PROCESSOR_ARCHITECTURE_UNKNOWN
pbits = ProcessorArchitecture.Unknown;
break;
}
}
catch
{
Ignore
}
return pbits;
再次失望。这段代码——尽管有处理器特定的标志——也返回了运行程序的位,而不是操作系统和处理器的位。
在某个地方读到,上述方法不可信(正如已经发现的),应该使用GetNativeSystemInfo API。
代码与上述代码完全相同,但是GetSystemInfo被GetNativeSystemInfo替换,API声明也是如此。
现在又得到了另一个结果。但遗憾的是,这个API似乎返回了处理器本身的位架构。感兴趣的是操作系统的位架构。可以很容易地在64位处理器的机器上运行32位的Windows版本。
所以还没有完成。
经过大量的研究,找到了决定在类中使用的方法:IntPtr.Size和IsWow64Process的组合:
static public SoftwareArchitecture OSBits
{
get
{
SoftwareArchitecture osbits = SoftwareArchitecture.Unknown;
switch (IntPtr.Size * 8)
{
case 64:
osbits = SoftwareArchitecture.Bit64;
break;
case 32:
if (Is32BitProcessOn64BitProcessor())
osbits = SoftwareArchitecture.Bit64;
else
osbits = SoftwareArchitecture.Bit32;
break;
default:
osbits = SoftwareArchitecture.Unknown;
break;
}
return osbits;
}
}
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;
}
如果IntPtr大小是64,则操作系统必须是64位的,因为不能在32位操作系统上运行64位程序。
如果程序以32位运行,则代码检查代码运行的过程以确定那是32位还是64位。
如果是64位,则操作系统将是64位的,但程序以32位运行。如果是32位,则操作系统也是32位的。
最后,将这些方法中的大多数包含在最终的类库中,因为能够区分程序、操作系统和处理器的位架构是很有用的。