Ищу руководство по поиску перехвата в Win7, чтобы определить, подключен или отключен монитор

#c# #powershell #winapi #monitoring

#c# #powershell #winapi #мониторинг

Вопрос:

Большое количество видеоустройств Win7 распределено по нескольким различным местам в медицинском учреждении. Иногда необходимость острая, и они используются в кратчайшие сроки. Каждое устройство подключается через HDMI к настенному телевизору. Одна из проблем заключается в том, что иногда люди отсоединяют кабель HDMI от компьютера Win7 для подключения к своим персональным устройствам, что нарушает правила. Они не будут повторно подключать кабель, что вызывает проблемы при следующем использовании устройства. Это вызвало задержки в обслуживании. На прошлой неделе я работал над написанием небольшого приложения (предпочтительно службы на системном уровне), которое определит, когда дисплей больше не подключен к ПК, а затем запустит действие (например, запись в журнале событий, отправка оповещения по электронной почте и т.д.). К сожалению, все мои попытки наталкивались на препятствия. Ищу идеи.

Я потратил довольно много времени на изучение способов или «перехватов», которые я мог бы найти в Windows, из которых я мог бы запускать. Я обнаружил, что существуют собственные классы (DeviceWatcher, WindowsDeviceEnumeration и т.д.), Которые могли бы помочь в этой работе, но, к сожалению, они не совместимы с Win7.
Я создал консольное приложение c # с обработчиком событий для SystemEvents.DisplaySettingsChanging и это работает именно так, как я хотел бы! Я могу отключить монитор, и он отправит электронное письмо с предупреждением и запишет запись в журнал событий (которую мы можем отслеживать с помощью сторонних инструментов и оповещений, создавать заявки и т.д.). Хотя это консольное приложение работает отлично, мне нужно, чтобы оно больше работало как скрытый фоновый сервис. Я создал службу Windows с той же функциональностью, но обнаружил, что обработчики событий могут быть сложными в службах Windows. Я никогда не мог заставить EventHandler (SystemEvents_DisplaySettingsChanging) запускаться в режиме службы Windows. С тех пор я обнаружил, что EventHandler DisplaySettingsChanged является событием пользовательского уровня и будет работать только для текущего пользователя, а не на системном уровне, когда запускается как служба.
Я тестировал различные методы отключения монитора и искал способы для Windows сообщать «Нет монитора). Я пробовал класс Win32_PnPEntity, а также классы Win32_Video *, и все они будут сообщать, что состояние монитора в порядке, даже если он не подключен.

Я обнаружил, что могу буквально наблюдать за диспетчером устройств при отключении монитора и видеть, как монитор исчезает со вкладки «Мониторы». Должен быть какой-то способ, которым я могу подключиться к этому.
Я думаю, что могу запустить службу Windows с таймером, который проверит этот перехват. Если монитор подключен, ничего не делайте — если НЕ подключен, выполните действие (отправьте оповещение, запишите запись в журнале событий, создайте заявку и т.д.)

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

Я потратил на это много времени, и я должен представить результаты 3/28.

Любая помощь приветствуется. Спасибо!

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

1. Быстрый поиск по wm_devicechange hdmi в поисковой системе выдал несколько многообещающих результатов.

Ответ №1:

Я исследовал WM_DEVICECHANGE и WM_DISPLAYCHANGE, но я просто не мог заставить ни то, ни другое работать так, как мне было нужно, и у меня заканчивалось время.
Мне нужно больше времени, чтобы разобраться в этом (и перехватывать сообщения Windows в целом) в будущем.
Однако я, наконец, смог найти правильное подключение для достижения своей цели.

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

Покопавшись в PowerShell, я обнаружил, что с помощью WMI и Win32_PnPEntity я могу извлекать информацию об отображении, и если НИКАКИЕ дисплеи не были подключены, DeviceID всегда возвращал бы Display NVD0000 SomeGuid. Когда были подключены 1 или 2 монитора, DeviceID был бы шестнадцатеричным вариантом, заменяющим нули после NVD (например, Display NVD39E4 someGUID).

Зная, что я могу рассчитывать на получение идентификатора устройства Display NVD0000, когда ни один монитор не был подключен, я создаю службу Windows с таймером, используя ManagementObjectSearcher и Win32_PnPEntity. Таймер запускается каждые 10 минут, затем выполняет проверку.
Если обнаружится, что дисплей физически не подключен, появится запись в журнале событий, которую можно отслеживать с помощью внешнего средства мониторинга (Xymon, Nagios и т.д.), И может быть предпринято предупреждение / действие, чтобы убедиться, что оно исправлено.

Я тестировал с монитором HDMI. Тестировался с монитором в выключенном состоянии и с источником монитора, измененным на другое входное состояние (не HDMI), и единственное условие, при котором я мог получить предупреждение для запуска, было, когда кабель был физически отсоединен от ПК, что именно то, что я хотел.

Существует более одного способа снять шкуру с кошки. Я знаю, что есть другие разработчики, которые могли бы создать сложное рабочее решение за считанные минуты. Учитывая количество совокупного экранного времени в C # за мою карьеру (сравнительно немного), я рад этой маленькой победе.

Надеюсь, это может помочь кому-нибудь в будущем.