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.




Комментариев нет:
Отправить комментарий