Introduction
I was looking for a way to determine the version of the operating system my program was running under. When I Googled it, I got a lot of code hits, but they all had the same problem: They were not updated for Windows 7.
Also, all of them had the same two shortcomings:
- They didn't include all available Windows editions (especially the absence of "Professional" bothered me as that is the operating system edition I normally use)
- I wanted to know if the operating system was 32 bit or 64 bit, and none of the solutions I found correctly determined that. Much more on that later...
Background
I found this article http://www.csharp411.com/determine-windows-version-and-edition-with-c/ and that was in my opinion the best and most updated version. So I decided to simply amend that code and add the things that were missing.
Please note: ALL CREDIT FOR THE ORIGINAL CODE GOES TO "TIMM", THE AUTHOR OF THE ABOVEMENTIONED ARTICLE...
Changes Made By Me
- I added "Windows 7" and "Windows Server 2008 R2" to the detection scheme.
- I added all the missing Windows editions I could find.
- Completely rewrote the 32/64 bit detection code.
Using the Code
The class I came up with is very easy to use. Just include the CS file in your project (or compile it to a DLL for use in your VB project), and query the properties like this:
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();
Points of Interest
The big problem with this was actually the detection of whether or not your OPERATING SYSTEM is 32 or 64 bits. As mentioned, I found a lot of suggestions to how this could be detected, but none of them worked properly. For those who are interested and for the sake of learning/sharing information, I'll list the different suggestions here:
- Using the
IntPtr
size
The most popular method seems to be variations on this:
return IntPtr.Size * 8;
But this doesn't actually return the Bit architecture of the OS, it returns the bit value for the running program. So for programs running in 32 bit mode on 64 bit Windows, the above code will return 32.
- Using the '
PROCESSOR_ARCHITECTURE
' Environment variable:
string pa = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE");
return ((String.IsNullOrEmpty(pa) || String.Compare(pa, 0,
"x86", 0, 3, true) == 0) ? 32 : 64);
This is actually very misleading, because the result of this is exactly the same as version 1: It doesn't return the PROCESSOR bit architecture as the name says, but the bit architecture of the running program. For programs running in 32 bit mode on 64 bit Windows, the above code will ALSO return 32.
- Using
PInvoke
and GetSystemInfo
Please note: To keep the article at a reasonable length, I'm not including the Structure declarations and the PInvoke API declarations... They can be found in the source code.
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: pbits = ProcessorArchitecture.Bit64;
break;
case 6: pbits = ProcessorArchitecture.Itanium64;
break;
case 0: pbits = ProcessorArchitecture.Bit32;
break;
default: pbits = ProcessorArchitecture.Unknown;
break;
}
}
catch
{
Ignore
}
return pbits;
Once again, I was disappointed. This code - despite the presence of the processor specific flags - ALSO returned the bits of the running program, not the OS and not the processor.
- Using
PInvoke
and GetNativeSystemInfo
I read somewhere that the above was not to be trusted (as I had already discovered), and that you should use the GetNativeSystemInfo
API instead.
The code is exactly the same as the above, but GetSystemInfo
is replaced by GetNativeSystemInfo
, and the same in the API declaration.
NOW I got another result. But alas, it seemed that this API actually returns the bit architecture of the processor itself. And I was interested in the OS bit architecture. You can easily have a 32 bit windows version running on a 64 bit processored machine.
So I was still not done.
After A LOT of research, I found the method I decided to use in the class:
- A combination of
IntPtr.Size
and 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;
}
If the IntPtr
size is 64
, then the OS MUST be 64 bits as well because you can't run a 64 bit program on a 32 bit OS.
If the program is running as 32 bits, then the code checks the process the code runs in to determine if that's 32 or 64 bits.
If it is 64, then the OS will be 64 bits, but the program is running as 32 bits. And if it's 32 then the OS is also 32 bits.
In the end, I included most of these methods in the final class lib, because it can be nice to be able to distinguish between the bit architecture of the Program, the OS and the Processor.
Acknowledgements
Thanks to Member 7861383, Scott Vickery for the Windows 8.1 update and workaround.
Thanks to Brisingr Aerowing for help with the Windows 10 adaptation.
History
- 2016-02-11 - Version 3.0, Added code for Windows 8.1 & Windows 10
- 2012-11-21 - Version 2.0, Added version numbers for Windows 8 & Windows Server 2012
- 2010-04-15 - Version 1.0, Initial release