Поиск на сайте
Главная Журнал Форум Wiki DRKB Страны мира

Определение версии и разрядности операционной системы

Версия и разрядность Windows

Один из частых вопросов, возникающих у программистов, как определить версию операционной системы, под которой запущена программа. Большинство примеров в сети не позволяют детектить Windows 7, а так же не умеют определять редакцию операционной системы "Professional". Кроме того эти примеры, как правило, не содержат кода для определения разрядности системы. Поэтому за образец был взят наиболее продвинутый исходник с http://www.csharp411.com/determine-windows-version-and-edition-with-c/, в который был добавлен недостающий функционал.

Какие изменения были внесены:
1. Добавлены "Windows 7" и "Windows Server 2008 R2".
2. Добавлены все редакции Windows.
3. Полностью переписан код определения 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 бита). Как уже упоминалось выше, множество примеров из интернета не делали это должным образом. Вот некоторые варианты того как это можно сделать:

1.Использование размера IntPtr. Это самый распространённый метод:

return IntPtr.Size * 8;

На самом деле такой вызов возвращает разрядность указателя для запущенного приложения, а не разрядность операционной системы. Поэтому для программ, работающих в 32-битном режиме на 64-битных Windows, вышеприведённый код вернет 32.

2. Использование переменной окружения PROCESSOR_ARCHITECTURE:

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

Этот пример, как и предыдущий, возвращает разрядность окружения для запущенной программы и точно также вернёт 32 в программе запущенной в 32-битном режиме под 64-битной ОС.

3. Использование PInvoke и GetSystemInfo

Для сохранения разумных размеров статьи не будем здесь приводить объявление структуры и PInvoke. Это можно найти в исходнике в конце статьи ...

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;

Как оказалось этот код, несмотря на наличие флагов процессора, возвращает только разрядность среды в которой запущено приложение, но никак не разрядность ОС или процессора.

4. Использование PInvoke и GetNativeSystemInfo

В некоторых примерах вместо GetSystemInfo используется GetNativeSystemInfo с таким же объявлением структуры и API. Такой способ позволяет действительно узнать разрядность процессора. Однако, существует масса примеров, когда 32-битная версия Windows работает на 64 битном процессоре.

После долгих поисков однозначный метод всё-таки был найден - это сочетание 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-битной, потому что запустить 64-битные программы под 32-битной операционкой не получится. Если программа работает в 32-битном режиме, то проверка процесса в котором запущен код позволяет определить 32 или 64 бита. Если он равен 64, то ОС будет 64-битной, но программа работает в 32-битном режиме. А если 32, то и ОС тоже 32-битная.

В конце концов, в библиотеку было включено большинство этих методов, чтобы можно было однозначно определять разрядность процессора, операционной системы и среды в которой работает программа.

Скачать демо-проект с исходниками - 32 кб

Скачать библиотеку - 20 кб




Основные разделы сайта


 

Реклама