Многие разработчики, работающие с Delphi и Free Pascal, сталкиваются с проблемой: функция RtlGetNtVersionNumbers из ntdll.dll возвращает для Windows 11 те же значения, что и для Windows 10 (major version = 10, minor version = 0), хотя сборка (build number) отличается. Это связано с тем, что Microsoft продолжает использовать номер версии 10.0 для Windows 11, изменяя только номер сборки.
Решение через номер сборки
Самый простой способ определить Windows 11 - проверить номер сборки:
program DetectWindows11;
{$APPTYPE CONSOLE}
uses
Windows;
procedure RtlGetNtVersionNumbers(out MajorVersion, MinorVersion, BuildNumber: DWORD);
stdcall; external 'ntdll.dll';
function IsWindows11OrNewer: Boolean;
var
Major, Minor, BuildNumber: DWORD;
begin
RtlGetNtVersionNumbers(Major, Minor, BuildNumber);
// Извлекаем номер сборки (младшие 16 бит)
BuildNumber := BuildNumber and $FFFF;
Result := (Major = 10) and (Minor = 0) and (BuildNumber >= 22000);
end;
begin
if IsWindows11OrNewer then
Writeln('Это Windows 11 или новее')
else
Writeln('Это Windows 10 или старше');
Readln;
end.
Альтернативные методы определения версии
1. Использование Win32Proc (Lazarus)
В Lazarus можно использовать модуль Win32Proc из LCL:
uses
Win32Proc;
function GetWindowsVersionName: string;
begin
case WindowsVersion of
wv95: Result := 'Windows 95';
wvNT4: Result := 'Windows NT 4.0';
// ... другие версии
wv10: Result := 'Windows 10';
wv11: Result := 'Windows 11';
else
Result := 'Неизвестная версия Windows';
end;
end;
Важно: Для корректной работы необходимо включить манифест в настройках проекта.
2. Чтение из реестра
Можно получить информацию из реестра:
function GetWindowsVersionFromRegistry: string;
var
Reg: TRegistry;
begin
Result := 'Неизвестная версия';
Reg := TRegistry.Create;
try
Reg.RootKey := HKEY_LOCAL_MACHINE;
if Reg.OpenKeyReadOnly('SOFTWARE\Microsoft\Windows NT\CurrentVersion') then
begin
Result := Reg.ReadString('ProductName');
Reg.CloseKey;
end;
finally
Reg.Free;
end;
end;
3. Использование WMI
Более надежный, но сложный способ через WMI:
uses
ComObj, Variants, SysUtils;
function GetWindowsVersionFromWMI: string;
var
FSWbemLocator: OleVariant;
FWMIService: OleVariant;
FWbemObjectSet: OleVariant;
FWbemObject: OleVariant;
oEnum: IEnumVariant;
iValue: LongWord;
begin
Result := 'Неизвестная версия';
try
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
FWMIService := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
FWbemObjectSet := FWMIService.ExecQuery('SELECT Caption FROM Win32_OperatingSystem', 'WQL', 0);
oEnum := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
if oEnum.Next(1, FWbemObject, iValue) = 0 then
begin
Result := FWbemObject.Caption;
FWbemObject := Unassigned;
end;
except
on E: Exception do
Result := 'Ошибка: ' + E.Message;
end;
end;
Почему RtlGetNtVersionNumbers возвращает Windows 10?
Microsoft решила сохранить совместимость, оставив для Windows 11 тот же основной номер версии (10.0), что и у Windows 10. Различие только в номере сборки:
Windows 10: build number < 22000
Windows 11: build number ≥ 22000
Первая версия Windows 11 имела номер сборки 22000, последующие обновления увеличивают этот номер.
Рекомендации по определению версии Windows
Для простых проверок используйте сравнение номера сборки через RtlGetNtVersionNumbers.
Для точного определения названия версии используйте WMI или чтение из реестра.
В Lazarus-приложениях удобно использовать модуль Win32Proc.
Не полагайтесь только на номер версии для проверки возможностей системы - лучше проверять наличие конкретных API-функций.
Пример полной программы
program WindowsVersionDetector;
{$APPTYPE CONSOLE}
uses
SysUtils, Windows, Registry;
procedure RtlGetNtVersionNumbers(out MajorVersion, MinorVersion, BuildNumber: DWORD);
stdcall; external 'ntdll.dll';
function IsWindows11OrNewer: Boolean;
var
Major, Minor, Build: DWORD;
begin
RtlGetNtVersionNumbers(Major, Minor, Build);
Build := Build and $FFFF;
Result := (Major = 10) and (Minor = 0) and (Build >= 22000);
end;
function GetWindowsVersionFromRegistry: string;
var
Reg: TRegistry;
CurrentBuild: string;
begin
Result := 'Неизвестная версия Windows';
Reg := TRegistry.Create;
try
Reg.RootKey := HKEY_LOCAL_MACHINE;
if Reg.OpenKeyReadOnly('SOFTWARE\Microsoft\Windows NT\CurrentVersion') then
begin
Result := Reg.ReadString('ProductName');
CurrentBuild := Reg.ReadString('CurrentBuild');
Reg.CloseKey;
if Pos('Windows 10', Result) > 0 then
begin
if StrToIntDef(CurrentBuild, 0) >= 22000 then
Result := 'Windows 11 (обнаружено по номеру сборки)';
end;
end;
finally
Reg.Free;
end;
end;
var
Major, Minor, Build: DWORD;
begin
RtlGetNtVersionNumbers(Major, Minor, Build);
Build := Build and $FFFF;
Writeln(Format('Версия ядра: %d.%d.%d', [Major, Minor, Build]));
Writeln('По RtlGetNtVersionNumbers: ',
IfThen(IsWindows11OrNewer, 'Windows 11 или новее', 'Windows 10 или старше'));
Writeln('По реестру: ', GetWindowsVersionFromRegistry);
Readln;
end.
Заключение
Хотя Microsoft изменила подход к нумерации версий Windows, разработчики на Delphi и Free Pascal могут точно определить версию ОС, используя либо номер сборки, либо альтернативные методы. Для большинства случаев достаточно проверки номера сборки через RtlGetNtVersionNumbers, но если требуется точное название продукта, лучше использовать WMI или реестр.
статья описывает методы определения версии Windows 11 в Delphi и Pascal, когда стандартная функция RtlGetNtVersionNumbers возвращает данные для Windows 10.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.