WinAPI – это огромный монстр с неисчислимым количеством функций, которые запросто могут дублировать функционал друг друга. Это позволяет решить одну задачу различными способами. Так и для определения версии установленной на компьютере операционной системы существует несколько путей. Давайте посмотрим на сколько они эффективны.
"Классикой жанра" для определения версии Windows является функция GetVersion. Ее старший товарищ, функция GetVersionEx, используется Delphi в TOSVersion из System.SysUtils. Она возвращает структуру OSVERSIONINFOEXW, которая содержит информацию об операционной системе.
Для проверки версии операционной системы из драйвера Windows SDK предоставляет эквивалент функции GetVersionEx – RtlGetVersion. Хоть в ее описании и написано "kernel-mode", но никто не запрещает использовать ее вместо GetVersionEx в обычной программе ("user-mode"):
Усложним задачу и запустим тестовую программу в режиме совместимости с Windows 7. Картина печальная. Функции GetVersionEx (TOSVersion) и RtlGetVersion вернули информацию, не о установленной на компьютер операционной системе, а о выбранной для совместимости. Но это не ошибка, так задумано их разработчиками. Чтение из регистра вернуло смесь Windows 7 и Windows 10. Реальную версию Windows из режима совместимости удалось получить с помощью WMI и функций управления сетью. У функций GetVersion и GetVersionEx, а значит и у TOSVersion, есть еще одна проблема. Если программа скомпилирована без манифеста или в ее манифесте не указана поддержка Windows 10, то они работают не корректно.
Давайте запустим эту тестовую программу на Windows 11. Итак, на сегодня мы имеем Windows 10.0.22000. Правильно недавно сказал мой сын: "Windows 11 – это Windows 10 с новой красивой графической оболочкой". Надеюсь, что перед релизом Windows 11 в Microsoft не забудут поменять ее номер версии на 11.
"Классикой жанра" для определения версии Windows является функция GetVersion. Ее старший товарищ, функция GetVersionEx, используется Delphi в TOSVersion из System.SysUtils. Она возвращает структуру OSVERSIONINFOEXW, которая содержит информацию об операционной системе.
procedure TMainForm.CheckTOSVersion; begin mInfo.Lines.Add('* TOSVersion'); mInfo.Lines.Add(TOSVersion.ToString); mInfo.Lines.Add('Name: ' + TOSVersion.Name); mInfo.Lines.Add(Format('Version: %d.%d.%d', [TOSVersion.Major, TOSVersion.Minor, TOSVersion.Build])); mInfo.Lines.Add('Build: ' + TOSVersion.Build.ToString); end;Самый простой способ определить версию Windows – это прочитать ее из реестра Windows.
procedure TMainForm.CheckRegistry; var reg: TRegistry; begin mInfo.Lines.Add('* Registry'); reg := TRegistry.Create(KEY_READ); try reg.RootKey := HKEY_LOCAL_MACHINE; if reg.OpenKey('SOFTWARE\Microsoft\Windows NT\CurrentVersion', False) then begin mInfo.Lines.Add('Name: ' + reg.ReadString('ProductName')); mInfo.Lines.Add(Format('Version: %d.%d.%s', [reg.ReadInteger('CurrentMajorVersionNumber'), reg.ReadInteger('CurrentMinorVersionNumber'), reg.ReadString('CurrentBuildNumber')])); mInfo.Lines.Add('Build: ' + reg.ReadString('CurrentBuildNumber')); end; finally reg.Free; end; end;Windows Management Instrumentation (WMI) имеет множество объектов из которых можно получить информацию об аппаратном обеспечении и операционной системе компьютера. WMI-класс Win32_OperatingSystem представляет доступ к почти 70 параметрам, описывающим операционную систему. Среди которых есть и информация о ее версии.
procedure TMainForm.CheckWMI; const wbemFlagForwardOnly = $00000020; var SWbemLocator : OleVariant; SWbemService : OleVariant; SWbemObjectSet: OleVariant; SWbemObject : OleVariant; Enum : IEnumVariant; pceltFetched : LongWord; begin mInfo.Lines.Add('* Windows Management Instrumentation (WMI)'); CoInitialize(nil); try SWbemLocator := CreateOleObject('WbemScripting.SWbemLocator'); SWbemService := SWbemLocator.ConnectServer('', 'root\CIMV2'); SWbemObjectSet := SWbemService.ExecQuery('SELECT Caption, Version, BuildNumber FROM Win32_OperatingSystem', 'WQL', wbemFlagForwardOnly); Enum := IUnknown(SWbemObjectSet._NewEnum) as IEnumVariant; if Enum.Next(1, SWbemObject, pceltFetched) = S_OK then begin mInfo.Lines.Add('Name: ' + SWbemObject.Caption); mInfo.Lines.Add('Version: ' + SWbemObject.Version); mInfo.Lines.Add('Build: ' + SWbemObject.BuildNumber); SWbemObject := Unassigned; end; finally CoUninitialize; end; end;Используя этот способ можно получить информацию не только о компьютере, на котором запущена программа, но и о другом компьютере. Для подключения к удаленному компьютеру в метод ConnectServer необходимо передать имя компьютера, имя пользователя и его пароль.
Для проверки версии операционной системы из драйвера Windows SDK предоставляет эквивалент функции GetVersionEx – RtlGetVersion. Хоть в ее описании и написано "kernel-mode", но никто не запрещает использовать ее вместо GetVersionEx в обычной программе ("user-mode"):
procedure TMainForm.CheckRtlGetVersion; const STATUS_SUCCESS = $00000000; type TFuncRtlGetVersion = function(var RTL_OSVERSIONINFOEXW): DWORD; stdcall; var RtlGetVersion: TFuncRtlGetVersion; VerInfo: TOSVersionInfoExW; begin mInfo.Lines.Add('* RtlGetVersion'); @RtlGetVersion := GetProcAddress(GetModuleHandle('ntdll.dll'), 'RtlGetVersion'); if Assigned(RtlGetVersion) then begin ZeroMemory(@VerInfo, SizeOf(VerInfo)); VerInfo.dwOSVersionInfoSize := SizeOf(VerInfo); if RtlGetVersion(VerInfo) = STATUS_SUCCESS then begin mInfo.Lines.Add(Format('Version: %d.%d.%d', [VerInfo.dwMajorVersion, VerInfo.dwMinorVersion, VerInfo.dwBuildNumber])); mInfo.Lines.Add('Build: ' + VerInfo.dwBuildNumber.ToString); end; end end;И последний вариант, который я хочу рассмотреть – это использование для определения версии Windows функций управления сетью. Среди них есть две функции: NetWkstaGetInfo – возвращает информацию о конфигурации рабочей станции и NetServerGetInfo – возвращает информацию о конфигурации сервера. Эти функции предназначены для работы с удаленным компьютером, но если вместо имени компьютера в первом параметре передать nil, то они возвращают информацию о локальном компьютере. Они идентичны, поэтому я приведу пример только с NetWkstaGetInfo.
procedure TMainForm.CheckNetWkstaGetInfo; const NetApiDll = 'netapi32.dll'; NERR_SUCCESS = 0; type NET_API_STATUS = DWORD; TFuncNetWkstaGetInfo = function(ServerName: LPWSTR; Level: DWORD; var BufPtr: Pointer): NET_API_STATUS; stdcall; TFuncNetApiBufferFree = function (BufPtr: Pointer): NET_API_STATUS; stdcall; WKSTA_INFO_100 = record wki100_platform_id: DWORD; wki100_computername: LPWSTR; wki100_langroup: LPWSTR; wki100_ver_major: DWORD; wki100_ver_minor: DWORD; end; PWKSTA_INFO_100 = ^WKSTA_INFO_100 ; var NetWkstaGetInfo : TFuncNetWkstaGetInfo; NetApiBufferFree: TFuncNetApiBufferFree; BufPtr: Pointer; begin mInfo.Lines.Add('* NetWkstaGetInfo'); @NetWkstaGetInfo := GetProcAddress(GetModuleHandle(NetApiDll), 'NetWkstaGetInfo'); @NetApiBufferFree := GetProcAddress(GetModuleHandle(NetApiDll), 'NetApiBufferFree'); if Assigned(NetWkstaGetInfo) and Assigned(NetApiBufferFree) then begin BufPtr := nil; if NetWkstaGetInfo(nil, 100, BufPtr) = NERR_SUCCESS then with PWKSTA_INFO_100(BufPtr)^ do mInfo.Lines.Add(Format('Version: %d.%d', [wki100_ver_major, wki100_ver_minor])); if Assigned(BufPtr) then NetApiBufferFree(BufPtr); end; end;При запуске 64-х битной версии программы мы видим, что все функции указали одинаковый номер версии Windows. А вот в результатах работы 32-х битной версии программы есть небольшой глюк – из реестра в "Name" вместо "Windows 10 Pro" читается "Windows 10 Enterprise".
Усложним задачу и запустим тестовую программу в режиме совместимости с Windows 7. Картина печальная. Функции GetVersionEx (TOSVersion) и RtlGetVersion вернули информацию, не о установленной на компьютер операционной системе, а о выбранной для совместимости. Но это не ошибка, так задумано их разработчиками. Чтение из регистра вернуло смесь Windows 7 и Windows 10. Реальную версию Windows из режима совместимости удалось получить с помощью WMI и функций управления сетью. У функций GetVersion и GetVersionEx, а значит и у TOSVersion, есть еще одна проблема. Если программа скомпилирована без манифеста или в ее манифесте не указана поддержка Windows 10, то они работают не корректно.
Давайте запустим эту тестовую программу на Windows 11. Итак, на сегодня мы имеем Windows 10.0.22000. Правильно недавно сказал мой сын: "Windows 11 – это Windows 10 с новой красивой графической оболочкой". Надеюсь, что перед релизом Windows 11 в Microsoft не забудут поменять ее номер версии на 11.
Комментариев нет:
Отправить комментарий