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

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

У меня есть приложение vcl, которое имеет событие show формы, которое получает детали операционной системы и отображает их в поле 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.

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

Ответ 1

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

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

Так получилось, что обновление XE8 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;

Ответ 2

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

Я использую XE8 и не имею проблем с TOSVersion, распознающим Windows 10 при использовании файла манифеста, который предназначен для 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)