Проверка версии Windows на W10

Кто-нибудь знает, работает ли TOSVersion.Name на Windows 10?

У меня есть приложение vcl, которое имеет событие показа формы, которое получает сведения об операционной системе и отображает их в окне TMemo, используя запись TOSVersion из SysUtils.

with mmoOSInfo.Lines do 
 begin
    Clear;
    Add(TOSVersion.ToString);
    Add('');
    Add('Architecture: ' + OSArchitectureToStr(TOSVersion.Architecture));
    Add('Platform: ' + OSPlatformToStr(TOSVersion.Platform) +
     IntToStr(PlatformFromPointer));
    Add('Build: ' + IntToStr(TOSVersion.Build));
    Add('Major: ' + IntToStr(TOSVersion.Major));
    Add('Minor: ' + IntToStr(TOSVersion.Minor));
    Add('Name: ' + TOSVersion.Name);
    Add('Service Pack - Major: ' + IntToStr(TOSVersion.ServicePackMajor));
    Add('Service Pack - Minor: ' + IntToStr(TOSVersion.ServicePackMinor));
 end;

Код выполняется без проблем в XP (да, мы все еще используем его (зависает от стыда)), Vista, Windows 7, Windows 8.1, настольных ПК, ноутбуков и Surface Pro, но не при установке в Windows 10.

Когда я отлаживаю с помощью paserver, TOSVersion.Name возвращается как:= 'Windows 8'. Я делаю что-то не так или ожидаю, что TOSVersion обнаружит Windows 10 слишком много? Не исключение срабатывает. Из двух машин с Windows 10, к которым у меня есть доступ, один путь перехода был из Windows 8.1, а другой из Windows 7.

Большое спасибо

2 ответа

Две вещи мешают вашему коду возвращать правильную версию:

  1. Используемая вами RTL-версия XE8 предшествует Windows 10 и поэтому не знает Windows 10.
  2. Ваш исполняемый файл не проявляет себя как поддерживающий Windows 10, и поэтому GetVersionEx, который TOSVersion опирается, будет врать о версии.

Так получилось, что XE8 update 1, полагаю, меняет определение версии на использование NetWkstaGetInfo который не подлежит этой версии лжи. Хотя призыв к NetWkstaGetInfo теряет память, но это, вероятно, не важно, так как он вызывается только один раз.

Некоторые ссылки, относящиеся к этой теме:

Если вам абсолютно необходимо сообщить о версии пользователю, у вас есть множество вариантов:

  • Добавить supportedOS вариант вашего манифеста и включить GUID для Windows 10. Это останавливает GetVersionEx от лжи. Затем используйте модифицированную версию TOSVersion или каким-либо другим способом, чтобы получить версию.
  • Используйте запрос WMI.
  • Вызов NetServerGetInfo,
  • Вызов NetWkstaGetInfo,
  • Вызов RtlGetVersion,

Подробнее в этом вопросе: Как определить истинную версию Windows? Хотя учтите, что принятый ответ там устарел.

В качестве примера подхода WMI вы можете использовать этот код:

function OperatingSystemDisplayName: string;

  function GetWMIObject(const objectName: string): IDispatch;
  var
    chEaten: Integer;
    BindCtx: IBindCtx;
    Moniker: IMoniker;
  begin
    OleCheck(CreateBindCtx(0, bindCtx));
    OleCheck(MkParseDisplayName(BindCtx, PChar(objectName), chEaten, Moniker));
    OleCheck(Moniker.BindToObject(BindCtx, nil, IDispatch, Result));
  end;

  function VarToString(const Value: OleVariant): string;
  begin
    if VarIsStr(Value) then begin
      Result := Trim(Value);
    end else begin
      Result := '';
    end;
  end;

  function FullVersionString(const Item: OleVariant): string;
  var
    Caption, ServicePack, Version, Architecture: string;
  begin
    Caption := VarToString(Item.Caption);
    ServicePack := VarToString(Item.CSDVersion);
    Version := VarToString(Item.Version);
    Architecture := ArchitectureDisplayName(SystemArchitecture);
    Result := Caption;
    if ServicePack <> '' then begin
      Result := Result + ' ' + ServicePack;
    end;
    Result := Result + ', version ' + Version + ', ' + Architecture;
  end;

var
  objWMIService: OleVariant;
  colItems: OleVariant;
  Item: OleVariant;
  oEnum: IEnumvariant;
  iValue: LongWord;

begin
  Try
    objWMIService := GetWMIObject('winmgmts:\\localhost\root\cimv2');
    colItems := objWMIService.ExecQuery('SELECT Caption, CSDVersion, Version FROM Win32_OperatingSystem', 'WQL', 0);
    oEnum := IUnknown(colItems._NewEnum) as IEnumVariant;
    if oEnum.Next(1, Item, iValue)=0 then begin
      Result := FullVersionString(Item);
      exit;
    end;
  Except
    // yes, I know this is nasty, but come what may I want to use the fallback code below should the WMI code fail
  End;

  (* Fallback, relies on the deprecated function GetVersionEx, reports erroneous values
     when manifest does not contain supportedOS matching the executing system *)
  Result := TOSVersion.ToString;
end;

Вы пытались использовать пользовательский манифест?

Я использую XE8 и не испытываю проблем с распознаванием Windows 10 TOSVersion при использовании файла манифеста, предназначенного для Windows 8.1 и Windows 10.

Мой пользовательский манифест сделан, чтобы мое приложение "Windows 10" знало.

Это следующее:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity
    type="win32"
    name="MrTheV Dev"
    version="11.0.2804.9245"
    processorArchitecture="*"/>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel
          level="asInvoker"
          uiAccess="False"/>
        </requestedPrivileges>
    </security>
  </trustInfo>
  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> 
        <application> 
            <!-- Windows 10 --> 
            <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
            <!-- Windows 8.1 -->
            <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
            <!-- Windows Vista -->
            <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> 
            <!-- Windows 7 -->
            <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
            <!-- Windows 8 -->
            <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
        </application> 
    </compatibility>
</assembly>

Я получил это по этой ссылке: https://msdn.microsoft.com/fr-fr/library/windows/desktop/dn481241(v=vs.85).aspx

И TOSVersion.Tostring на Windows 10 1607 отображает:

Windows (Version 10.0, Build 14393, 64-bit Edition)
Другие вопросы по тегам