Supportedos id windows 10

1. Создаем текстовый файл в любом редакторе, например в стандартном «Блокноте».
Я пользуюсь AkelPad, например, но это не принципиально. Содержимое файла
примерно такое:

XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
 
<assembly
  xmlns="urn:schemas-microsoft-com:asm.v1"
  manifestVersion="1.0">
 
  <assemblyIdentity
    type="win32"
    name="MyCompany.ProductName.ComponentName"
    version="1.0.0.0"
    processorArchitecture="*">
  </assemblyIdentity>
 
  <description>Description of the component.</description>
 
  <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}"></supportedOS>
 
      <!-- Windows 8.1 -->
      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"></supportedOS>
 
      <!-- Windows 8 -->
      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"></supportedOS>
 
      <!-- Windows 7 -->
      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"></supportedOS>
 
      <!-- Windows Vista -->
      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"></supportedOS>
 
    </application>
  </compatibility>
 
  <application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
      <dpiAware
          xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware>
    </windowsSettings>
  </application>
 
</assembly>

При сохранении файла следует указать кодировку UTF-8.

Теперь разберем этот манифест по блокам:

<?xml… — стандартная декларация, с которой начинается любой XML-файл.

<assembly> — корневой элемент XML.

<assemblyIdentity> — здесь описаны мета-данные твоей «сборки», такие как название,
архитектура, номер версии и т.д. Есть и другие атрибуты, вся информация
описана в MSDN, в разделе про манифесты.

Строго говоря, exe не является сборкой (assembly) в полном смысле этого слова,
но такая декларация дает пользоваться основными возможностями, которые
дают манифесты.

<description> — описание сборки (опционально).

<trustInfo> — здесь задается уровень прав, с которыми должно быть запущено приложение.
«asInvoker» — запуск без повышения, «requireAdministrator» — запрос администраторских
прав, «highestAvailable» — запрос максимально возможных прав.

<compatibility> — в этом блоке перечисляются GUID-ы соответствующих версий Windows, с
которыми данный exe декларирует себя как совместимый. В настоящее время известны
пять GUID-ов от Vista до Windows 10 включительно. Именно эта секция влияет на то,
будет ли задействован для приложения механизм совместимости или нет.
Например, Windows 8.1 и Windows 10 при отсутствии нужного GUID-а всегда будут
выдавать для GetVersionEx номер версии 6.2., т.е. номер от Windows 8.

<dpiAware> — этот блок аналогичен «compatibility», здесь декларируется совместимость
приложения с High-DPI, т.е. с режимами, когда выставлен размер шрифтов 125%, 150% и выше.
Без «dpiAware» твое приложение на таких настройках будет выглядеть размыто и
слегка неестественно.

Кстати, если приложение графическое и использует визуальные темы оформления, то
следует в блок «assembly» включить также следующий фрагмент:

XML
1
2
3
4
5
6
7
8
9
10
11
12
<dependency>
  <dependentAssembly>
    <assemblyIdentity
      type="win32"
      name="Microsoft.Windows.Common-Controls"
      version="6.0.0.0"
      processorArchitecture="*"
      publicKeyToken="6595b64144ccf1df"
      language="*">
    </assemblyIdentity>
  </dependentAssembly>
</dependency>

2. Созданный XML-файл следует подключить к своему exe как ресурс.
Тип ресурса — 24, ID — 1. Например:

Code
1
1 24 "MyManifest.xml"

При этом следует в настройках компоновщика (Linker Options) отключить генерацию манифеста
(Generate Manifest = No).

Привет, коллеги-разработчики! Сегодня мы погружаемся в мир разработки приложений для Windows 10 и изучаем, как объявить поддержку этой популярной операционной системы в манифесте вашего приложения. Итак, берите чашку кофе, надевайте шляпу программиста и приступаем!

Но подождите секунду, что же такое манифест приложения? Что ж, думайте об этом как о специальном файле, содержащем важные метаданные о вашем приложении. Он предоставляет важную информацию операционной системе, такую ​​как необходимые разрешения, поддерживаемые операционные системы и зависимости. Заявив о поддержке Windows 10 в манифесте приложения, вы гарантируете бесперебойную работу вашего приложения и максимальное удобство работы с пользователем на этой платформе.

Теперь давайте рассмотрим некоторые способы объявления поддержки Windows 10 в манифесте вашего приложения.

Метод 1: использование Visual Studio

Если вы используете Visual Studio в качестве среды разработки, объявить о поддержке Windows 10 очень просто. Выполните следующие действия:

  1. Откройте проект в Visual Studio.
  2. В Обозревателе решений найдите файл манифеста (обычно с именем «app.manifest»).
  3. Дважды щелкните файл манифеста, чтобы открыть его.
  4. В редакторе манифеста перейдите на вкладку «Совместимость».
  5. В разделе «Поддерживаемые операционные системы» установите флажок «Windows 10».

И всё! Visual Studio позаботится об обновлении файла манифеста, обеспечивая совместимость с Windows 10.

Метод 2: редактирование вручную

Если вы предпочитаете редактировать файл манифеста приложения вручную, выполните следующие действия:

  1. Найдите файл манифеста вашего приложения (обычно с именем «app.manifest»).
  2. Откройте файл в любом текстовом редакторе.
  3. Найдите раздел <compatibility>в файле манифеста.
  4. Добавьте следующий фрагмент кода в раздел <compatibility>:
<application>
  <!-- ... -->
  <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
  1. Сохраните изменения в файле манифеста.

Добавляя элемент <supportedOS>с соответствующим идентификатором, вы заявляете о поддержке Windows 10.

Метод 3. Использование PowerShell

Если вы поклонник PowerShell и предпочитаете магию командной строки, вы можете использовать следующий скрипт PowerShell для обновления манифеста приложения:

$manifestPath = "C:\Path\To\Your\App.manifest"
$manifestContent = Get-Content $manifestPath
$manifestContent -replace '<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">', 
    '<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
      <application>
        <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
      </application>'
     | Set-Content $manifestPath

Просто замените "C:\Path\To\Your\App.manifest"фактическим путем к файлу манифеста вашего приложения и запустите скрипт. Он обновит файл манифеста необходимой декларацией совместимости с Windows 10.

Имея в своем распоряжении эти методы, вы можете легко объявить поддержку Windows 10 в манифесте вашего приложения. Помните, что обеспечение совместимости имеет решающее значение для обеспечения бесперебойной работы пользователей в этой широко используемой операционной системе.

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

На этом пока все, ребята. Приятного кодирования!

Solution 1:[1]

GetVersion and GetVersionEx were superseded by various version helper functions. The one you want is IsWindows10OrGreater. They can be found in VersionHelpers.h.

IsWindows10OrGreater is only available in the latest SDK/Visual Studio 2015. You can use IsWindowsVersionOrGreater in the general case however. For example on my 7 box I get TRUE for IsWindowsVersionOrGreater(6, 0, 0).

Remember that the parameters this function takes relate to Windows build number and NOT marketing name. So Windows 8 is build 6.2. Windows 7 is 6.0 etc.

Solution 2:[2]

Starting in Windows 8.1, GetVersion() and GetVersionEx() are subject to application manifestation:

With the release of Windows 8.1, the behavior of the GetVersionEx API has changed in the value it will return for the operating system version. The value returned by the GetVersionEx function now depends on how the application is manifested.

Applications not manifested for Windows 8.1 or Windows 10 will return the Windows 8 OS version value (6.2). Once an application is manifested for a given operating system version, GetVersionEx will always return the version that the application is manifested for in future releases. To manifest your applications for Windows 8.1 or Windows 10, refer to Targeting your application for Windows.

The newer Version Helper functions are simply wrappers for VerifyVersionInfo(). Starting in Windows 10, it is now subject to manifestation as well:

Windows 10: VerifyVersionInfo returns false when called by applications that do not have a compatibility manifest for Windows 8.1 or Windows 10 if the lpVersionInfo parameter is set so that it specifies Windows 8.1 or Windows 10, even when the current operating system version is Windows 8.1 or Windows 10. Specifically, VerifyVersionInfo has the following behavior:

  • If the application has no manifest, VerifyVersionInfo behaves as if the operation system version is Windows 8 (6.2).
  • If the application has a manifest that contains the GUID that corresponds to Windows 8.1, VerifyVersionInfo behaves as if the operation system version is Windows 8.1 (6.3).
  • If the application has a manifest that contains the GUID that corresponds to Windows 10, VerifyVersionInfo behaves as if the operation system version is Windows 10 (10.0).

The Version Helper functions use the VerifyVersionInfo function, so the behavior IsWindows8Point1OrGreater and IsWindows10OrGreater are similarly affected by the presence and content of the manifest.

To manifest your applications for Windows 8.1 or Windows 10, see Targeting your application for Windows.

To get the true OS version regardless of manifestation use RtlGetVersion(), NetServerGetInfo(), or NetWkstaGetInfo() instead. They all report an accurate OS version and are not subject to manifestation (yet?).

(Microsoft used to suggest querying the file version of a system DLL, but they stopped recommending that when Windows didn’t update system DLL versions to match.)

Solution 3:[3]

Use the following function:

double getSysOpType()
{
    double ret = 0.0;
    NTSTATUS(WINAPI *RtlGetVersion)(LPOSVERSIONINFOEXW);
    OSVERSIONINFOEXW osInfo;

    *(FARPROC*)&RtlGetVersion = GetProcAddress(GetModuleHandleA("ntdll"), "RtlGetVersion");

    if (NULL != RtlGetVersion)
    {
        osInfo.dwOSVersionInfoSize = sizeof(osInfo);
        RtlGetVersion(&osInfo);
        ret = (double)osInfo.dwMajorVersion;
    }
    return ret;
}

It will return the Windows version as a double (7, 8, 8.1, 10).

Solution 4:[4]

2021-01-12
https://stackoverflow.com/a/52122386/1923561
Based on Michael Haephrati’s answer, I made adjustments to my code.

enum WindowsOS{
   NotFind,
   Win2000,
   WinXP,
   WinVista,
   Win7,
   Win8,
   Win10
};

WindowsOS GetOsVersionQuick()
{
   using namespace std;
   double ret = 0.0;
   NTSTATUS(WINAPI *RtlGetVersion)(LPOSVERSIONINFOEXW);
   OSVERSIONINFOEXW osInfo;

   *(FARPROC*)&RtlGetVersion = GetProcAddress(GetModuleHandleA("ntdll"), 
   "RtlGetVersion");

   if (NULL != RtlGetVersion)
   {
      osInfo.dwOSVersionInfoSize = sizeof(osInfo);
      RtlGetVersion(&osInfo);
      ret = (double)osInfo.dwMajorVersion;
   }

   if (osInfo.dwMajorVersion == 10 && osInfo.dwMinorVersion == 0)
   {
      cout << "this is windows 10\n";
      return Win10;
   }
   else if (osInfo.dwMajorVersion == 6 && osInfo.dwMinorVersion == 3)
   {
      cout << "this is windows 8.1\n";
      return Win8;
   }
   else if (osInfo.dwMajorVersion == 6 && osInfo.dwMinorVersion == 2)
   {
      cout << "this is windows 8\n";
      return Win8;
   }
   else if (osInfo.dwMajorVersion == 6 && osInfo.dwMinorVersion == 1)
   {
      cout << "this is windows 7 or Windows Server 2008 R2\n";
      return Win7;
   }

   return NotFind;
}

2020-06-14

#include <iostream>
#include <windows.h>
#pragma comment(lib, "Version.lib" )

BOOL GetOsVersion()
{
    wchar_t path[200] = L"C:\\Windows\\System32\\kernel32.dll";
    DWORD dwDummy;
    DWORD dwFVISize = GetFileVersionInfoSize(path, &dwDummy);
    LPBYTE lpVersionInfo = new BYTE[dwFVISize];
    if (GetFileVersionInfo(path, 0, dwFVISize, lpVersionInfo) == 0)
    {
        return FALSE;
    }

    UINT uLen;
    VS_FIXEDFILEINFO* lpFfi;
    BOOL bVer = VerQueryValue(lpVersionInfo, L"\\", (LPVOID*)&lpFfi, &uLen);

    if (!bVer || uLen == 0)
    {
        return FALSE;
    }
    DWORD dwProductVersionMS = lpFfi->dwProductVersionMS;
    if (HIWORD(dwProductVersionMS) == 10 && LOWORD(dwProductVersionMS) == 0)
    {
        cout << "this is windows 10\n";
    }
    else if (HIWORD(dwProductVersionMS) == 6 && LOWORD(dwProductVersionMS) == 3)
    {
        cout << "this is windows 8.1\n";
    }
    else if (HIWORD(dwProductVersionMS) == 6 && LOWORD(dwProductVersionMS) == 2)
    {
        cout << "this is windows 8\n";
    }
    else if (HIWORD(dwProductVersionMS) == 6 && LOWORD(dwProductVersionMS) == 1)
    {
        cout << "this is windows 7 or Windows Server 2008 R2\n";
    }
    else if (HIWORD(dwProductVersionMS) == 6 && LOWORD(dwProductVersionMS) == 0)
    {
        cout << "this is windows Vista or Windows Server 2008\n";
    }
    else if (HIWORD(dwProductVersionMS) == 5 && LOWORD(dwProductVersionMS) == 2)
    {
        cout << "this is windows Server 2003\n";
    }
    else if (HIWORD(dwProductVersionMS) == 5 && LOWORD(dwProductVersionMS) == 1)
    {
        cout << "this is windows Server XP\n";
    }
    else if (HIWORD(dwProductVersionMS) == 5 && LOWORD(dwProductVersionMS) == 0)
    {
        cout << "this is windows 2000\n";
    }
    //else if (lpFfi->dwFileVersionMS == 4 && lpFfi->dwFileVersionLS == 90)
    //{
    //    cout << "this is windows  Me\n";
    //}
    //else if (lpFfi->dwFileVersionMS == 4 && lpFfi->dwFileVersionLS == 10)
    //{
    //    cout << "this is windows  98\n";
    //}
    //else if (lpFfi->dwFileVersionMS == 4 && lpFfi->dwFileVersionLS == 0)
    //{
    //    cout << "this is windows  95\n";
    //}
    return TRUE;
}

After testing the code used to detect win10.

I speculate that this api error, IsWindows10OrGreater, is because the wrong FileVersionMS version is set for kernel32.dll. Use ProductVersionMS version query to get it normally.

https://docs.microsoft.com/en-us/windows/win32/api/versionhelpers/nf-versionhelpers-iswindows10orgreater

Hope it could help everyone!

Solution 5:[5]

I needed this to work on an older version of the VS compiler, and more over within a Qt framework. Here’s how I accomplished that.

Add this file GetWinVersion.h to your Qt project:

#ifndef GETWINVERSION
#define GETWINVERSION

#include <QtGlobal>

#ifdef Q_OS_WIN

#include <windows.h>
#include <stdio.h>

float GetWinVersion()
{
    OSVERSIONINFO osvi;
    ZeroMemory( &osvi, sizeof(OSVERSIONINFO) );
    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    return GetVersionEx( &osvi ) ?
           (float)osvi.dwMajorVersion +
           ((float)osvi.dwMinorVersion/10) :
           0.0 ;
}

#endif //Q_OS_WIN

#endif // GETWINVERSION

Add the required linkage in your pro or pri qmake file:

msvc: LIBS += -lKernel32

Implement the helper function like so (note SystemInfo used here is a custom class of mine, but you get the idea…):

#include "GetWinVersion.h"

SystemInfo info;

#ifdef Q_OS_WIN
    info.setPlatform( SystemInfo::WINDOWS );
    switch(QSysInfo::windowsVersion())
    {
    case QSysInfo::WV_32s:        info.setOsName( L"3.1" );     info.setOsVersion( 3.1 ); break;
    case QSysInfo::WV_95:         info.setOsName( L"95" );      info.setOsVersion( 4.0 ); break;
    case QSysInfo::WV_98:         info.setOsName( L"98" );      info.setOsVersion( 4.1 ); break;
    case QSysInfo::WV_Me:         info.setOsName( L"Me" );      info.setOsVersion( 4.9 ); break;
    case QSysInfo::WV_NT:         info.setOsName( L"NT" );      info.setOsVersion( 4.0 ); break;
    case QSysInfo::WV_2000:       info.setOsName( L"2000" );    info.setOsVersion( 5.0 ); break;
    case QSysInfo::WV_XP:         info.setOsName( L"XP" );      info.setOsVersion( 5.1 ); break;
    case QSysInfo::WV_2003:       info.setOsName( L"2003" );    info.setOsVersion( 5.2 ); break;  // Windows Server 2003, Windows Server 2003 R2, Windows Home Server, Windows XP Professional x64 Edition
    case QSysInfo::WV_VISTA:      info.setOsName( L"Vista" );   info.setOsVersion( 6.0 ); break;  // Windows Vista, Windows Server 2008
    case QSysInfo::WV_WINDOWS7:   info.setOsName( L"7" );       info.setOsVersion( 6.1 ); break;  // Windows 7, Windows Server 2008 R2
    case QSysInfo::WV_WINDOWS8:   info.setOsName( L"8" );       info.setOsVersion( 6.2 ); break;  // Windows 8, Windows Server 2012
  // These cases are never reached due to Windows api changes
  // As of Qt 5.5, this not accounted for by QSysInfo::windowsVersion()
  //case QSysInfo::WV_WINDOWS8_1: info.setOsName( L"8.1" );     info.setOsVersion( 6.3 ); break;  // Windows 8.1, Windows Server 2012 R2
  //case QSysInfo::WV_WINDOWS10:  info.setOsName( L"10" );      info.setOsVersion( 10.0 ); break; // Windows 10, Windows Server 2016
    default:
        // On Windows 8.1 & 10, this will only work when the exe
        // contains a manifest which targets the specific OS's
        // you wish to detect.  Else 6.2 (ie. Win 8.0 is returned)
        info.setOsVersion( GetWinVersion() );
        if(      info.osVersion() == 6.3f )  // Windows 8.1, Windows Server 2012 R2
            info.setOsName( L"8.1" );
        else if( info.osVersion() == 10.0f ) // Windows 10, Windows Server 2016
            info.setOsName( L"10" );
        else
            info.setOsName( L"UNKNOWN" );
    }
    info.setOsBits( IsWow64() ? 64 : 32 );
#else
...

Now here’s the real key. You need to attach a manifest file to your exe which will «target» the recent Windows versions, else you can’t detect them (see the MS docs: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724451%28v=vs.85%29.aspx). Here’s an example manifest to do this:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <assemblyIdentity 
        name="MyOrg.MyDept.MyAppName" 
        version="1.0.0.0" 
        processorArchitecture="x86" 
        type="win32" />
    <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 8 -->
            <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
            <!-- Windows 7 -->
            <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>      
            <!-- Windows Vista -->
            <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>          
        </application> 
    </compatibility>
</assembly>

And here’s some batch to attach the manifest:

set exeFile=MyApp.exe
set manifestFile=MyApp.manifest
set manifestExe=C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin\x64\mt.exe

"%manifestExe%" -manifest "%manifestFile%" -outputresource:"%exeFile%"

In theory, you can use qmake to run that last bit attaching the manifest. I didn’t have luck with the examples I found, and just «cheated» with this batch for now…

Solution 6:[6]

Do not use VersionHelpers.h! It’s buggy!

It ignores the user’s application compatibility settings.

Instead, use the older Kernel32.dll functions like GetVersion, e.g.:

bool IsWindowsVersionOrGreater(unsigned short version)
{
    return _byteswap_ushort((unsigned short)GetVersion()) >= version;
}

// Usage: IsWindowsVersionOrGreater(_WIN32_WINNT_WINTHRESHOLD)

Solution 7:[7]

FWIW, the LibreOffice project gives the version string via getOSVersion()

OUString WinSalInstance::getOSVersion()
{
    OUStringBuffer aVer(50); // capacity for string like "Windows 6.1 Service Pack 1 build 7601"
    aVer.append("Windows ");
    // GetVersion(Ex) and VersionHelpers (based on VerifyVersionInfo) API are
    // subject to manifest-based behavior since Windows 8.1, so give wrong results.
    // Another approach would be to use NetWkstaGetInfo, but that has some small
    // reported delays (some milliseconds), and might get slower in domains with
    // poor network connections.
    // So go with a solution described at https://web.archive.org/web/20090228100958/http://msdn.microsoft.com/en-us/library/ms724429.aspx
    bool bHaveVerFromKernel32 = false;
    if (HMODULE h_kernel32 = GetModuleHandleW(L"kernel32.dll"))
    {
        wchar_t szPath[MAX_PATH];
        DWORD dwCount = GetModuleFileNameW(h_kernel32, szPath, SAL_N_ELEMENTS(szPath));
        if (dwCount != 0 && dwCount < SAL_N_ELEMENTS(szPath))
        {
            dwCount = GetFileVersionInfoSizeW(szPath, nullptr);
            if (dwCount != 0)
            {
                std::unique_ptr<char[]> ver(new char[dwCount]);
                if (GetFileVersionInfoW(szPath, 0, dwCount, ver.get()) != FALSE)
                {
                    void* pBlock = nullptr;
                    UINT dwBlockSz = 0;
                    if (VerQueryValueW(ver.get(), L"\\", &pBlock, &dwBlockSz) != FALSE && dwBlockSz >= sizeof(VS_FIXEDFILEINFO))
                    {
                        VS_FIXEDFILEINFO* vi1 = static_cast<VS_FIXEDFILEINFO*>(pBlock);
                        aVer.append(OUString::number(HIWORD(vi1->dwProductVersionMS)) + "."
                                    + OUString::number(LOWORD(vi1->dwProductVersionMS)));
                        bHaveVerFromKernel32 = true;
                    }
                }
            }
        }
    }
    // Now use RtlGetVersion (which is not subject to deprecation for GetVersion(Ex) API)
    // to get build number and SP info
    bool bHaveVerFromRtlGetVersion = false;
    if (HMODULE h_ntdll = GetModuleHandleW(L"ntdll.dll"))
    {
        if (auto RtlGetVersion
            = reinterpret_cast<RtlGetVersion_t>(GetProcAddress(h_ntdll, "RtlGetVersion")))
        {
            RTL_OSVERSIONINFOW vi2{}; // initialize with zeroes - a better alternative to memset
            vi2.dwOSVersionInfoSize = sizeof(vi2);
            if (STATUS_SUCCESS == RtlGetVersion(&vi2))
            {
                if (!bHaveVerFromKernel32) // we failed above; let's hope this would be useful
                    aVer.append(OUString::number(vi2.dwMajorVersion) + "."
                                + OUString::number(vi2.dwMinorVersion));
                aVer.append(" ");
                if (vi2.szCSDVersion[0])
                    aVer.append(OUString::Concat(o3tl::toU(vi2.szCSDVersion)) + " ");
                aVer.append("Build " + OUString::number(vi2.dwBuildNumber));
                bHaveVerFromRtlGetVersion = true;
            }
        }
    }
    if (!bHaveVerFromKernel32 && !bHaveVerFromRtlGetVersion)
        aVer.append("unknown");
    return aVer.makeStringAndClear();
}

Windows 10 aware app.manifest

OSVersion

In windows 8.1 Environment.OSVersion underlying Win32 GetVersionEx function changed to for compatibility reasons report latest version app is compiled for.

The code

Console.WriteLine(
    System.Environment.OSVersion
    );
  • Without 8.1 ID on 8.1
    • Microsoft Windows NT 6.2.9200.0
  • Without 10 ID on 10
    • Microsoft Windows NT 6.3.9600.0
  • With 10 ID on 10
    • Microsoft Windows NT 10.0.10049.0

Usage

If you have an app.manifest just add the <supportedOS Id/> you are missing.
Otherwise just Add new item to the project, search for manifest and choose Application Manifest File with file name app.manifest

Basically your .csproj should include (should just work if you add an Application Manifest File with file name app.manifest)

  <PropertyGroup>
    <ApplicationManifest>app.manifest</ApplicationManifest>
  </PropertyGroup>

and

  <ItemGroup>
    <None Include="app.manifest" />
  </ItemGroup>


This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters

Show hidden characters

<?xml version=«1.0« encoding=«utf-8«?>
<asmv1:assembly manifestVersion=«1.0« xmlns=«urn:schemas-microsoft-com:asm.v1« xmlns:asmv1=«urn:schemas-microsoft-com:asm.v1« xmlns:asmv2=«urn:schemas-microsoft-com:asm.v2« xmlns:xsi=«http://www.w3.org/2001/XMLSchema-instance«>
<assemblyIdentity version=«1.0.0.0« name=«MyApplication.app«/>
<trustInfo xmlns=«urn:schemas-microsoft-com:asm.v2«>
<security>
<requestedPrivileges xmlns=«urn:schemas-microsoft-com:asm.v3«>
<requestedExecutionLevel level=«asInvoker« uiAccess=«false« />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns=«urn:schemas-microsoft-com:compatibility.v1«>
<application>
<!— Windows Vista and Windows Server 2008 —>
<supportedOS Id=«{e2011457-1546-43c5-a5fe-008deee3d3f0}«></supportedOS>
<!— Windows 7 and Windows Server 2008 R2 —>
<supportedOS Id=«{35138b9a-5d96-4fbd-8e2d-a2440225f93a}«/>
<!— Windows 8 and Windows Server 2012 —>
<supportedOS Id=«{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}«></supportedOS>
<!— Windows 8.1 and Windows Server 2012 R2 —>
<supportedOS Id=«{1f676c76-80e1-4239-95bb-83d0f6d0da78}«/>
<!— Windows 10 —>
<supportedOS Id=«{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}«/>
</application>
</compatibility>
</asmv1:assembly>

Недавно на руборде в разделе Программирование был задан вопрос: «Зачем Win32-приложению манифест? На что он влияет?». Первое, что сразу приходит в голову большинству программистов — это темы оформления. Но на самом деле в современных виндах манифест нужен не только для этого. Я подумал и написал пять ключевых аспектов, на которые влияет манифест или его отсутствие. После этого сразу несколько человек попросили оформить этот пост в виде более развернутой статьи.

Для начала предлагаю вспомнить, как вообще в Windows появились манифесты, и как они развивались.

В древние времена в мире Win95/98 царил ад, точнее DLL hell. Возник он из-за того, что Windows задумывалась как идеальная система. Все приложения в ней всегда должны были писаться с использованием самых свежих версий системных библиотек. А различные версии самих библиотек должны были быть взаимозаменяемыми. Реальность быстро доказала всем, что для популярной операционки это несбыточная мечта, так и возник ад. Каждое второе приложение во время инсталляции перезаписывало системные библиотеки нужными ему версиями. В результате после установки приложения X установленное ранее приложение Y начинало глючить. А после переустановки приложения Y глючить начинало приложение X. В общем юзерам жилось весело.

Для решения этой проблемы в Windows XP появилась технология Side-by-side Assembly (SxS). Суть ее заключалась в том, что приложение могло явно указать, с какой версией библиотеки оно желает работать. Эта информация могла указываться либо в специальном файле .manifest, либо в ресурсах приложения в разделе Manifest. В самой ХР на основе новой технологии реализовали одну из самых заметных новых фишек системы — темы оформления.

Всем был хорош SxS кроме одного — он был ужасно неудобен для программиста. В 99% случаев манифест применялся только для включения тех самых тем оформления, и ни для чего больше. Разработчикам винды стало ясно, что нужен новый, более простой в использовании способ указать поддерживаемые версии системных библиотек. Тогда они придумали простое правило: в пределах одной версии системы интерфейс и поведение этих библиотек не изменяется. Нужно было только каким то образом научится определять какая их версия требуется конкретному приложению. Так в Windows 7 в манифесте появилась секция Compatibility, где можно указать с какими версиями ОС тестировалось приложение.
Также в манифесте начиная с Windows Vista появилось еще несколько секций, обо всех о них ниже.

Если вся секция по взаимодействию с UAC отсутствует в манифесте, к приложению будет применена виртуализация файловой системы и реестра. Если такое приложение попытается записать что то в защищенные папки типа «Program files», оно будет перенаправлено в папку “%userprofile%\AppData\Local\VirtualStore\Program files». Аналогично, попытки записи в раздел реестра HKEY_LOCAL_MACHINE будут перенаправлены в «HKEY_CURRENT_USER\Software\Classes\VirtualStore\MACHINE». Естественно, сделанные таким образом изменения будут видны только приложениям, запущенным в режиме виртуализации.

Управление DPI-масштабированием
С древнейших времен винда имеет механизм масштабирования интерфейса в зависимости от DPI монитора (тут говорится, что все началось в XP, но мне кажется, что раньше). В те времена эта настройка выставлялась только вручную, наверное из-за отсутствия EDID. Популярностью она не пользовалась, возможно потому, что запрятана была далеко, а возможно потому, что мониторов с большим разрешением было очень-очень мало. Кроме того, большая часть работы, необходимой для поддержки масштабирования, была отдана на откуп самим приложениям и их авторам. А программисты, как известно, люди весьма ленивые, поэтому куча софта для винды писалась в предположении, что DPI всегда равен стандартному значению 96. Очень часто встречалась ситуация, когда в приложении использовались библиотеки поддерживающие нестандартный DPI, в то время как код самого приложения его не поддерживал. Это приводило к появлению ужасных артефактов в интерфейсе приложения, стоило пользователю выставить DPI, к примеру, в значение 120 (масштабирование 125%):

Разработчики Висты не стерпели подобного безобразия, и заложили в DWM возможность производить масштабирование самостоятельно, а приложениям врать, что DPI по прежнему равен 96. Причем зависящие от него системные настройки, разрешение монитора и даже положение мыши, также пересчитываются. К сожалению разработчики Висты небыли волшебниками, поэтому масштабирование DWM производит с помощью простых алгоритмов растягивания изображений. И если интерфейс приложения нужно увеличить, то происходит замыливание картинки. Представьте что было бы, если бы разработчики Фотошопа не могли это отключить. Таких бунтов на корабле никто не хотел, поэтому появилась возможность указать в манифесте, что ваше приложение таки умеет нормально масштабировать свой интерфейс, и помощь DWM ему не нужна. За это отвечает параметр dpiAware. Тут правда следует отметить, что по умолчанию масштабирование силами DWM включается при увеличении 150% и выше. Видимо в Microsoft посчитали, что при масштабировании 125% артефакты как на скриншоте выше вполне терпимы.

Слева масштабирование силами DWM, а справа — самого приложения:

В Windows 8.1 появилась возможность указывать разный масштаб разным мониторам, если подключено сразу несколько. Соответственно у ключа dpiAware появилось новое значение «True/PM». Оно означает, что приложение умеет динамически изменять масштаб своего интерфейса при переносе окон с одного монитора на другой.

Декларирование совместимости
Работает очень просто: программист тестирует свое приложение в определенной версии винды, и если все работает как надо, добавляет GUID этой версии в манифест.

Наиболее интересен вопрос: «На что влияют эти GUID-ы?» Пока что список различий в поведении системных библиотек невелик. Наиболее интересно упоминание об оптимизации RPC. Получается что приложения, задекларировавшие совместимость с семеркой, будут работать быстрее.
В будущем этот раздел манифеста наверняка будет играть большую роль чем сейчас. Ведь в винде полно разных хаков призванных обеспечивать совместимость. И теперь есть возможность оградить от них нормальные приложения.

Если GUID-ы полностью отсутствуют в манифесте, то к приложению применяются правила как к совместимому с Вистой:

Добавляем поддержку HiDPI в приложения на WinForms

В настоящее время всё больше людей приобретают мониторы, либо ноутбуки, оснащённые дисплеями с большой плотностью пикселей (HiDPI-дисплеи), поэтому для корректной работы современные приложения должны поддерживать работу на них в полной мере.

Введение

К HiDPI относятся любые дисплеи со значением PPI (пикселей на дюйм) 144 и выше (при стандартном значении 96).

В большинстве фреймворков для построения приложений с графическим интерфейсом поддержка масштабирования в зависимости от размеров DPI экрана, на котором отображается окно, реализована «из коробки». Microsoft же предлагали всем использовать исключительно универсальные приложения Windows (UWP), либо WPF, заявляя, что лишь они полностью поддерживают данную технологию. Многих это по понятным причинам не устраивало ибо существует огромное количество уже написанных и прекрасно функционирующих программ, использующих Windows Forms, которые переписывать практически с нуля никто не собирается.

В итоге поддержка полноценного автоматического масштабирования элементов управления для экранов с высокой плотностью пикселей на Windows Forms появилась в пакете .NET Framework лишь начиная с версии 4.7.1, однако она является не полной и требующей ручной доработки.

Активируем стандартную поддержку

Полная поддержка экранов с высокой плотностью пикселей присутствует в ОС Microsoft Windows 10. В более старых её либо нет вовсе, либо она реализована лишь частично.

В главном манифесте приложения, в compatibility::application::supportedOS, явно укажем поддержку всех современных версий системы (в противном случае приложение будет считать, что запущено в Windows 8.1 из-за слоя совместимости Win32 API и не сможет использовать поддержку данной технологии):

Теперь для активации HiDPI в режиме per monitor добавим в главный конфигурационный файл приложения app.config следующие строки:

В свойствах проекта изменим тулчейн сборки на Microsoft .NET Framework 4.7.1 или более позднюю версию, согласимся с предложением Visual Studio на конвертацию и подтвердим осуществление данного действия, согласившись с возможными последствиями.

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

Масштабируем составные элементы управления

Как мы и говорили в самом начале статьи, поддержка автоматического масштабирования в Windows Forms получилась не полной и некоторые сложные элементы управления, а именно ListView , DataGridView , StatusBar и некоторые другие, не будут корректно изменять свои размеры в зависимости от установленного на текущем экране значения DPI, поэтому нам придётся исправить это самостоятельно.

Создадим новый файл с исходным кодом и добавим его корректное в пространство имён проекта. Добавим отдельный статический класс с перегруженным методом ScaleControlElements:

Этот метод изменяет размеры колонок внутри таких контролов, как ListView и DataGridView, в зависимости от текущего значения ScaleFactor, которое, в свою очередь, зависит от DPI текущего дисплея.

Теперь на каждой форме, содержащей проблемные элементы управления, переопределим метод ScaleControl:

Сначала мы вызываем базовый метод base.ScaleControl, чтобы произвести автоматическое масштабирование средствами среды, а затем произведём собственное для составных контролов (ControlName).

Масштабируем графику

Другая серьёзная проблема — это любая растровая графика. При изменении DPI, изображения будут либо растянуты до новых размеров элемента управления и станут мыльными, либо сильно уменьшатся в размере, что приведёт к некорректному отображению формы.

Таким образом, нам необходимо иметь несколько версий каждого растрового изображения на форме. В настоящее время это:

  • 1x — стандартное изображение;
  • 2x — двойное разрешение;
  • 3x — тройное разрешение.

Например если у нас есть файл foo-bar.png с разрешением 100*100 пикселей, то мы должны создать также foo-barx2.png (200*200 px), а также foo-barx3.png (300*300 px).

Как и в прошлый раз, на каждой форме, содержащей растровые изображения, переопределим метод ScaleControl:

Здесь CompareFloats — это метод, используемый для сравнения двух чисел одинарной точности с плавающей точкой, а Load2xImages загружает изображения двойного разрешения и размещает их на форме.

Написание этих методов выходит за рамки данной статьи.

Заключение

Теперь после доработки и пересборки нашего приложения, оно будет выглядеть корректно на любых конфигурациях оборудования.

Более того, т.к. мы задали режим per monitor, при наличии нескольких экранов с разным значением PPI и перемещении окон между данными ними, они будут автоматически масштабироваться в большую, либо меньшую сторону.

Литература

При написании данной статьи использовалась литература из следующих источников:

notidealrunner

пятница, 21 июня 2019 г.

Задействуем UAC в приложениях написанных на Delphi 7

UAC – это Контроль Учетных Записей (Wikipedia), используется для повышения привилегий в том случае если вашему приложению это необходимо. Появился в Windows Vista и присутствует Windows 7, 8, 10. Необходимо убедится в том, что UAC включен. В Windows 7 это можно проверить, открыв «Панель управления» — «Учетные записи пользователей» — «Изменение параметров контроля учетных записей» — убедится, что установлен уровень «По умолчанию» (Смотрите рисунок 1).

Основным, важным моментом в файле манифеста является строчка кода:

Параметр level со значением requireAdministrator указывает на то, что нашему приложению для работы требуются права администратора. Следующими строчками кода мы указываем с какими операционными системами наше приложение будет совместимо:

Далее нам необходимо в каталоге проекта создать файл ресурсов компиляции с именем Win7UAC.rc. Содержимое файла компиляции будет следующее:

1 24 «Win7UAC.manifest»

То есть мы в качестве ресурсов нашего приложения указываем наш файл манифеста.

Файл ресурсов компиляции Win7UAC.rc необходимо скомпилировать при помощи компилятора ресурсов brcc32.exe, этот компилятор ресурсов расположен в каталоге, где расположены бинарные файлы Delphi, у меня это каталог D:\Programs\Delphi7\Files\Delphi7\Bin. Убедитесь, что данный каталог добавлен в переменную окружения Path. Запустите командную строку Windows, перейдите в каталог проекта и выполните команду компиляции ресурсов (Смотрите рисунок 2).

В качестве результата в каталоге проекта вы получите файл ресурсов Win7UAC.RES, который необходимо в файле проекта p12.dpr подключить. Смотрите код ниже:

Вынесите на форму с именем Form1 одну кнопку Button1 и один список ComboBox1 (Смотрите рисунок 3).

Добавьте в свойства Items списка ComboBox1 две строки DOMAIN\User1 и DOMAIN\User2 (Смотрите рисунок 4). Эти строки у нас будут выбираться в ComboBox1. Также поменяйте свойства Style для списка ComboBox1 на csOwnerDraw.

В данном обработчике мы присваиваем списку ComboBox1 значение по умолчанию значение DOMAIN\User1.

Рассмотрим обработчик нажатия кнопки Button1, это следующий код:

В данном обработчике мы указываем путь в реестре Windows куда будем писать значения, это переменная типа String c именем SubKey. Смотрите код:

SubKey : String = ‘SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI’;

Далее берем выбранное значение ComboBox1 и присваиваем его переменной strSetRegValue. Смотрите код:

Если переменная strSetRegValue не пуста, то начинаем писать в реестр Windows. Работать будем в корневом разделе HKEY_LOCAL_MACHINE. Смотрите код:

if (strSetRegValue <> ») then
begin
R := TRegistry.Create(KEY_READ);
R.RootKey := HKEY_LOCAL_MACHINE;

Далее проверяем существует ли путь в реестре SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI. Также открываем подраздел реестра на запись для Windows 7 32 bit и 64 bit, следующая строчка:

Access := KEY_WRITE OR $0100;

Смотрите следующий код:

if (R.KeyExists(SubKey)) then
begin
With R do
begin
Access := KEY_WRITE OR $0100;
openResult := OpenKey(SubKey, False);
if (not openResult = True) Then
begin
MessageDlg(‘Unable to create key! Exiting.’, mtError, mbOKCancel, 0);
end;

Далее пишем в реестр параметры LastLoggedOnSAMUser, LastLoggedOnUser и закрываем ветку реестра и освобождаем память. Следующие строчки:

WriteString(‘LastLoggedOnSAMUser’, strSetRegValue);
WriteString(‘LastLoggedOnUser’, strSetRegValue);

Ниже показан снимок рабочей программы (Смотрите рисунок 5) и код полностью. При запуске приложения, оно спросит повышения привилегий, если вы имеете права админа (Смотрите рисунок 6) или повышения привилегий путем ввода логина и пароля администратора (Смотрите рисунок 7).

Понравилась статья? Поделить с друзьями:
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
  • Update for windows 7 for x64 based systems kb2966583
  • Как взломать профиль в windows 7
  • Музыка входа в windows xp
  • Утечка памяти windows server 2012 r2
  • Как подключиться к удаленному рабочему столу windows 10 без пароля