11 августа 2018 г.

Получение установленных компонентов Windows через Dism.

https://bitbucket.org/sergey_vaulin/windowsfeatures/src/default/

Про что статья?


  1. Получение списка установленных компонентов Windows используя Microsoft.Dism - Nuget сборку.
  2. Альтернативный способ получения через работу с утилитой dism.exe.


Что бы сразу уяснить про какие компоненты идёт речь - необходимо зайти в "Установка удаление программ" нажать на кнопку "Установка компонентов Windows" и увидите окно с настройкой (см. картинку). 






Данные о компонентах будем получать через DismApi, а вся информация об API есть на сайте msdn Deployment Image Servicing and Management (DISM) API. Так же, есть приложение dism.exe - консольная утилита, для работы с этим API.

Способ 1. Используем Microsoft.Dism.dll сборку.


Для этого нам понадобится подключить Microsoft.Dism сборку из Nuget.



После чего простейший код для вывода всех компонентов выглядит так:

DismApi.Initialize(DismLogLevel.LogErrors);
using (var session = DismApi.OpenOnlineSession())
{ 
    foreach (DismFeature feature in DismApi.GetFeatures(session))
    {
        Console.WriteLine($"[Feature Name] {feature.FeatureName}");
        Console.WriteLine($"[State] {feature.State}");
        Console.WriteLine();
    }
}
 
DismApi.Shutdown();

Данный пример можно проверить скачав его по ссылке в верху страницы. Либо отрыв на Bitbacket: DismWrapperExample.cs

Внимание! Данный способ работает, если есть гарантия, что битность вашего приложения будет ВСЕГДА совпадать с битность операционной системы (Если ваше приложение AnyCPU тогда у вас проблем быть не может). В противном случае следует изучить способ 2.

Способ 2. Парсинг вывода dism.exe.


Теперь представим ситуацию:

  • Ваш процесс становится 32 битный (собран под х86 архитектура).
  • Операционная система Windows имеет 64 битную разрядность.

В результате чего используя способ 1 мы получим исключение

An unhandled exception of type 'Microsoft.Dism.DismException' occurred in Microsoft.Dism.dll Additional information: An attempt was made to load a program with an incorrect format.

Иными словами мы получили BadImageFormatException исключение, говорящее о невозможности загрузить сборку. Чаще всего возникает, когда пытаются использовать "битую" сборку, либо из под 32 битного процесса пытаются загрузиться сборку скомпилированную под 64 бита. В данном случае подгружается неверная сборка:



В 32 битный процесс подгружается сборка из SysWOW64 (где сборки 64 битные), что приводит к этому эффекту. При этом если сделать процесс 64 битным, тогда под-грузится сборки 32 битные. А как известно 64 битный процесс корректно работает как с 64 битными сборками так и с 32 битными.



Поэтому, что бы решить проблему сборки, можно использовать альтернативный способ получения информации, через парсинг результата вывода утилиты dism.exe.

Утилита умеет выводить в английском языке названия, вне зависимости от языка системы, тем самым можно сделать универсальный распарсиватель и отказаться от использования Microsoft.Dism. Пример вывода:



Исходный код примера на C# можно увидеть по ссылке: Dism32under64CmdExample.cs

Внимание! Если вы скачали мой пример, тогда для демонстрации 2го способа необходима поменять конфигурацию на x86.

Запуск 64 битной командной строки из под 32 битного процесса.


В коде файла Dism32under64CmdExample.cs, есть нюанс работы. Когда мы пытаемся принудительно запустить cmd64.exe вместо cmd.exe, находясь в 32 битном процессе, операционная система сама принудительно будет выбирать cmd в зависимости от битности текущего процесса, а значит выберет 32 битную файл. Для этого можно использовать трюк с mklink для создания символической ссылки на файл, после чего операционная система будет обязана использовать именно тот файл, на который указывает ссылка.

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

Отправить комментарий