Supportedos id windows 10

Зачем Win32-приложению манифест?

Недавно на руборде в разделе Программирование был задан вопрос: «Зачем 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 появилось еще несколько секций, обо всех о них ниже.

Функции манифеста

    Активация тем оформления (Visual Styles)
    Эта технология появилась в ХР и полностью основана на SxS. Работает просто: вы запрашиваете у системы ComCtl32.dll шестой версии, и — вуаля — все стандартные контролы рисуются согласно с активированной в системе темой. Если же вы не упомянете в манифесте ComCtl32.dll, или манифест вообще будет отсутствовать в приложении, то система по умолчанию загрузит ComCtl32.dll пятой версии, которая отрисовывает контролы в стиле Win95. Кроме поддержки тем оформления, шестая версия ComCtl32.dll содержит кое-какой функционал, которого нету в пятой версии. Поэтому если отключить темы оформления, некоторые приложения будут работать и выглядеть не так, как задумывали их авторы.

Справа тоже самое приложение без манифеста:

Взаимодействие с UAC имеет несколько аспектов:

    Ключ requestedExecutionLevel.level позволяет указать требуемый приложению уровень прав пользователя. К примеру если указать requireAdministrator, то приложению будут предоставлены права администратора (если пользователь разрешит).

Запрос разрешения пользователя:

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

Читайте также:  Windows firewall is preventing

Виртуализация файловой системы в деле:

  • Ключ requestedExecutionLevel.uiAccess позволяет приложениям, запущенным без прав администратора, взаимодействовать с окнами приложений, запущенных с правами администратора. Это может потребоваться экранным клавиатурам, приложениям типа AutoIt, экранным читалкам, тестовым и отладочным тулзам. Чтобы этот ключ сработал, приложение должно быть подписано сертификатом Microsoft Authenticode.
  • Управление 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-дисплеи), поэтому для корректной работы современные приложения должны поддерживать работу на них в полной мере.

    Читайте также:  Чем отличаются windows 64 бит от 32 бит

    Введение

    К 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 загружает изображения двойного разрешения и размещает их на форме.

    Читайте также:  Webdav mail ru windows 10

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

    Заключение

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

    Более того, т.к. мы задали режим 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).

  • Оцените статью