Как я могу найти название продукта Windows в Windows 11?

#c# #.net #windows #.net-core #windows-11

Вопрос:

Windows 11, выпущенная вчера, сообщает о себе как о Windows 10.0 практически везде — RtlGetVersion говорит 10.0, и если вы спросите VerifyVersionInfo , являетесь ли вы 11.0 или выше, он скажет «нет».

Похоже, что в app.manifest нет нового идентификатора GUID, который можно было бы вставить, чтобы сказать «привет, я поддерживаю Windows 11», как это было для Windows 7, 8, 8.1 и 10.

В настоящее время я полагаюсь на HKLM:SOFTWAREMicrosoftWindows NTCurrentVersionProductName то, чтобы сообщить мне, какова текущая версия Windows, но на моей машине, которую я обновил, по-прежнему написано «Windows 10 Enterprise», а не «Windows 11 Enterprise».

Похоже, в реестре есть только одно место, содержащее текст «Windows 11», и это раздел BCD (конфигурация загрузки), который также можно переименовать, поэтому я не хочу к нему прикасаться.

До сих пор я определил только несколько методов, чтобы определить, работаю ли я в Windows 11:

  1. Вызовите WMI для запроса Win32_OperatingSystem и проверьте свойство Name, в котором просто написано «Windows 11». Это неполное (оно не включает артикул, такой как «Предприятие»), а WMI относительно медленный и немного хрупкий, поэтому это неприемлемое решение для моего варианта использования.
  2. Проверьте номер сборки, чтобы узнать, превышает ли он 21996 (бета-версии) или 22000 (первый публичный релиз). Как и выше, это не будет включать артикул, и для создания полной строки потребуется некоторое ручное перемешивание.
  3. Запустите sysinfo и проанализируйте выходные данные. Это довольно медленно и, возможно, хрупко (я не проверял, но вывод может быть локализован на разных языках).
  4. winver знает, но это приложение с графическим интерфейсом, поэтому я не могу точно запросить его программно.

У кого-нибудь есть какие-либо другие идеи о том, как вывести строку «Windows 11 Enterprise» (или «Windows 11 Pro» и т. Д., В зависимости от обстоятельств) Из моей операционной системы эффективным и полным способом? Откуда WMI, sysinfo и winver получают его?

Мне нужно сделать это из библиотеки .NET, но вызовы функций P/Invokes / native являются приемлемыми решениями.

Комментарии:

1. MS уже давно выступает за то, чтобы вы тестировали функции по мере необходимости, а не проверяли версию ОС. Возможно, они удвоили усилия и теперь вынуждают вас сделать это?

2. Это используется не для принятия решений на компьютере, а для информирования разработчиков об ошибках — я хочу знать, в какой версии Windows мое приложение сломалось.

3. Назвать его Win11 было маркетинговым решением, оно не имеет ничего общего с версией операционной системы. Это просто еще один релиз Win10, среди многих, отличающийся номером сборки. Если это 22000 или больше, то вы знаете, что это Win11.

4. Вы должны зарегистрировать номер сборки, а не маркетинговое название. Это также позволит вам различать различные версии Windows 10 (18363, 19042 и т.д.)

5. Мы также регистрируем это, но я бы предпочел, чтобы мы начали искать правильную сборку Win11 или правильную сборку Win10 в зависимости от обстоятельств, а не разработчики, которые пересекаются на ранней стадии… и я бы предпочел не нести ответственность за поддержание моих собственных сопоставлений версий ОС навсегда.

Ответ №1:

Оставляю это здесь, чтобы я мог найти его позже:

Похоже, что сама Windows (например, winver) получает эту информацию из фирменного стиля Windows — в частности, из таблицы ресурсов в %WinDir%BrandingBasebrden-USbasebrd.dll.mui .

Для доступа к этому можно использовать частные API %WinDir%System32winbrand.dll -интерфейсы . В частности, функция BrandingFormatString , которая принимает широкую строку (LPW[C]STR) и возвращает широкую строку.

например BrandingFormatString("%WINDOWS_LONG%") , возвращается "Windows 11 Pro" на мой домашний компьютер.

Я не знаю семантики жизненного цикла результирующей строки, т. Е. Если/когда/как ее следует освободить.

Следующий код служит функциональным доказательством концепции (C# 9.0):

 using System;
using System.Runtime.InteropServices;

[DllImport("winbrand.dll", CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
static extern string BrandingFormatString(string format);

Console.WriteLine(BrandingFormatString("Hello World from %WINDOWS_LONG%!"));

 

Ответ №2:

Я создал инструмент удаленной поддержки для администраторов настольных компьютеров (см. http://www.appslife-rdt.appspot.com) В VB.Dot.Net я использовал вызов Win32_OperatingSystem пространства WMI и вернул значение «Имя». Затем это нужно разделить, чтобы получить первый объект, который вам нужен. т. е.

 Dim query2 As New SelectQuery("SELECT * FROM Win32_OperatingSystem")
Dim searcher2 As New ManagementObjectSearcher(objManagementScope2, query2, QueryOptions)
        For Each mo As ManagementObject In searcher2.[Get]()
                           OSname = mo("Name")
        Next

        Dim array1 As Array = Nothing
        array1 = Split(OSname, "|")
        OSname = array1(0).ToString
 

Затем имя операционной системы указывает вам «Windows 11 Pro» или «Windows XP Professional», которые вам требуются.

Я также получаю версию операционной системы с последней информацией об обновлении патча из реестра, если это необходимо, следующим образом…

ЭТО ДЛЯ КЛИЕНТСКИХ ВЕРСИЙ 10/11 :-

.Значение setProperty («Имя sSubKeyName», «ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕMicrosoftWindows NTТекущая версияОбновлениеTargetingInfoУстановленоКлиент.OS.rs2.amd64») .Значение setProperty(«Имя файла», «Версия»)

ЭТО ДЛЯ СЕРВЕРНЫХ ВЕРСИЙ 2019 :-

.Значение setProperty(«Имя sSubKeyName», «ПРОГРАММНОЕ обеспечениеMicrosoftWindows NTТекущая версияОбновлениеTargetingInfoУстановленоСервер.OS.amd64») .Значение setProperty(«Имя файла», «Версия»)

Надеюсь, это поможет.

Ответ №3:

tldr — Использование EditionID и CurrentBuild из CurrentVersion реестра, по-видимому, является надежным способом определения Win10 против Win11 и «выпуска» программного обеспечения. EditionID является «Профессиональным» в Windows 10 Pro и Windows 11 Pro и CurrentBuild >= ~22000 сообщает вам, 10 или 11.

Коллекция значений реестра в разделе HKLMSOFTWAREMicrosoftWindows NTCurrentVersion показывает, что похоже на отсутствие планирования со стороны Microsoft. Есть ReleaseId , это число, которое менялось с каждым выпуском Windows 10 (например, 1903 , 1909 , 2004 ,…) до последнего изменения для Windows 10 20H2, где оно изменилось на 2009 . В то же время DisplayVersion было добавлено и установлено значение 20H2 .

Затем Windows 10 21H1 вышла и ReleaseId необъяснимо осталась 2009 .

Тот факт, что как текущие версии Windows 10, так и Windows 11 могут иметь одинаковое DisplayVersion значение (например, 21H2 когда скоро выйдет Windows 10 21H2) и ProductName (например Windows 10 Pro ), действительно вызывает головокружение. (Спасибо @yaakov за то, что уловил мою ошибку, сказав, что это было 21Ч1.)

Комментарии:

1. В Windows 11 есть DisplayVersion = 21H2 , что, по-видимому, правильно, и это то, что показано WinVer.

2. Дох, ты совершенно прав. Я пытался подчеркнуть, что также будет Windows 10 21H2 — она еще не выпущена, и будет странно иметь как 10, так и 11 21H2. Спасибо за поправку.

Ответ №4:

Следующий код был протестирован на Windows XP, 7, 10, 11. Он работает на 32-разрядных и 64-разрядных операционных системах. Он работает внутри 32-разрядных и 64-разрядных приложений.

Будут сгенерированы следующие строки:

  • «Microsoft Windows XP, сборка 2600, 32 бит»
  • «Windows 7 Ultimate, сборка 7601, 64-разрядная»
  • «Windows 10 Enterprise LTSC 2019, версия 1809, сборка 17763, 64-разрядная версия»
  • «Windows 10 Pro, версия 1909, Сборка 18362, 64-разрядная версия»
  • «Windows 11 Professional, версия 21H2, Сборка 22000, 64-разрядная»

Поместите код в статический конструктор, чтобы он выполнялся только один раз и записывал версию в статическую переменную.

 static String ms_OperatingSystem;

static Constructor()
{
    try
    {
        String s_KernelPath = Path.Combine(Environment.SystemDirectory,"Kernel32.dll");
        FileVersionInfo k_Kernel = FileVersionInfo.GetVersionInfo(s_KernelPath);

        // on 32 bit Windows this will read the 32 bit hive instead
        using (RegistryKey i_HKLM = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64))
        {
            using (RegistryKey i_RegVer = i_HKLM.OpenSubKey(@"SoftwareMicrosoftWindows NTCurrentVersion", false))
            {
                // Kernel32.dll on Windows 11 has Product Version 10.0.22000.120
                if (k_Kernel.ProductMajorPart == 10 amp;amp; k_Kernel.ProductBuildPart >= 22000)
                {
                    ms_OperatingSystem = "Windows 11";

                    Object o_Edition = i_RegVer.GetValue("EditionID"); // "Professional"
                    if (o_Edition is String)
                        ms_OperatingSystem  = " "   o_Edition;
                }
                else
                {
                    // "Microsoft Windows XP"
                    // "Windows 7 Ultimate"
                    // "Windows 10 Pro"  (same string on Windows 11. Microsoft SUCKS!)
                    ms_OperatingSystem = (String)i_RegVer.GetValue("ProductName");
                }

                // See: https://en.wikipedia.org/wiki/Windows_10_version_history
                // Windows 10 older releases --> "2009" (invalid if DisplayVersion exists)
                Object o_ReleaseID = i_RegVer.GetValue("ReleaseId");

                // Windows 10 latest release --> "21H1"
                // Windows 11 first  release --> "21H2"
                Object o_DispVer = i_RegVer.GetValue("DisplayVersion");

                // Use ReleaseID ONLY if DisplayVersion does not exist in registry!
                     if (o_DispVer   is String) ms_OperatingSystem  = ", Version "   o_DispVer;
                else if (o_ReleaseID is String) ms_OperatingSystem  = ", Version "   o_ReleaseID;

                ms_OperatingSystem  = ", Build "   k_Kernel.ProductBuildPart;

                if (Environment.Is64BitOperatingSystem) ms_OperatingSystem  = ", 64 bit";
                else                                    ms_OperatingSystem  = ", 32 bit";
            }
        }
     }
     catch (Exception Ex)
     {
        ms_OperatingSystem = Ex.Message;
     }
}