Как узнать модель и серийный номер монитора
Как узнать модель и серийный номер монитора
EDID - Extended Display Identification Data - стандарт формата данных VESA, расширенные данные идентификации дисплея. Эта информация передается монитором или телевизором на устройство, которое генерирует видео сигнал. EDID содержит базовую информацию о мониторе и его возможностях, включая информацию о производителе, максимальном размере, цветовых характеристиках, заводских таймингах, границах частотного диапазона и другие технические данные. Кроме этого в EDID записаны строки, содержащие модель монитора и его серийный номер. Вот они-то нас и интересуют.
После подключения и установки драйверов монитора в систему, в реестре для него формируется соответствующая запись. Нам остается только ее найти, прочитать и извлечь нужные данные. В интернетах можно найти официальный мануал VESA по стандарту EDID.
В документе почти сотня страниц, много теории и всякой технической заумности, поскольку применение EDID очень широкое. Быстро найти нужную информацию, мягко говоря, проблематично. В английском варианте статьи на Википедии эта информация разложена более понятным образом. Итак, в структуре EDID в байтах 54-125 должны быть записаны 4 блока идентификаторов. Структура каждого идентификатора описана там же. Забегая вперед отмечу, что слово "должны" некоторые производители понимают по-своему. Например, для моего маленького китайского монитора серийный номер вообще не узнать, так как в EDID записаны два блока таймингов, диапазоны работы монитора и название модели. При парсинге такие ситуации придется учитывать.
Переходим к программированию. Несколько структур, часть из которых вы уже видели в статье про выключение мониторов. Там же описан и принцип работы с мониторами, как получить их список, как получить хэндл и прочее. Настоятельно рекомендую ознакомиться, чтобы у вас не возникало вопросов, а мне не пришлось дублировать теоретические выкладки.
Code (Assembler) : Убрать нумерацию
- struct PHYSICAL_MONITOR
- hPhysicalMonitor dd ?
- szPhysicalMonitorDescription rw 128
- ends
- struct MONITORINFOEX
- cbSize dd ?
- rcMonitor RECT
- rcWork RECT
- dwFlags dd ?
- szDevice rb 32
- ends
- struct DISPLAY_DEVICE
- cb dd ?
- DeviceName rb 32
- DeviceString rb 128
- StateFlags dd ?
- DeviceID rb 128
- DeviceKey rb 128
- ends
Code (Assembler) : Убрать нумерацию
- ;--------------------------------------------------------
- ; Callback-функция перебора мониторов
- ;--------------------------------------------------------
- proc MonitorEnumProc hMonitor:DWORD,hdc:DWORD,lpRect:DWORD,lParam:DWORD
- locals
- ; Количество мониторов
- num dd ?
- ; Массив PHYSICAL_MONITOR
- hMonArray dd ?
- MonArray dd ?
- Manufacturer dd ?
- CurrentValue dd ?
- MaximumValue dd ?
- CurrentS dd ?
- MaximumS dd ?
- ResS dd ?
- endl
- ; Получить количество физических мониторов
- lea eax,[num]
- invoke GetNumberOfPhysicalMonitorsFromHMONITOR,[hMonitor],eax
- ; Физических мониторов нет
- cmp [num],0
- je .loc_ret
- ; Зарезервировать память под массив PHYSICAL_MONITOR
- mov eax,[num]
- imul eax,sizeof.PHYSICAL_MONITOR
- invoke GlobalAlloc,GMEM_MOVEABLE+GMEM_DDESHARE,eax
- mov [hMonArray],eax
- invoke GlobalLock,[hMonArray]
- mov [MonArray],eax
- ; Получить информацию о всех физических мониторах
- invoke GetPhysicalMonitorsFromHMONITOR,[hMonitor],[num],[MonArray]
- ; Выключить все мониторы поочередно
- mov ecx,[num]
- mov esi,[MonArray]
- .loc_monitors_loop:
- push ecx
- push esi
- ; Информация о мониторе
- mov [minfo.cbSize],sizeof.MONITORINFOEX
- invoke GetMonitorInfo,[hMonitor],minfo
- mov [dds.cb],sizeof.DISPLAY_DEVICE
- invoke EnumDisplayDevices,minfo.szDevice,NULL,dds,0
- invoke RtlZeroMemory,edidmodel,256
- invoke RtlZeroMemory,edidsn,256
- invoke RtlZeroMemory,regstr,256
- ; Сформировать название ключа реестра
- ; SYSTEM\CurrentControlSet\Enum\DISPLAY\
- invoke lstrcpy,regstr,szReg0
- mov edi,regstr
- invoke lstrlen,edi
- add edi,eax
- ; Дописать к нему подстроку из DeviceID
- mov esi,dds.DeviceID
- @@:
- lodsb
- or al,al
- jz .loc_no_devid
- cmp al,'\'
- jne @b
- @@:
- lodsb
- or al,al
- jz .loc_no_devid
- stosb
- cmp al,'\'
- jne @b
- ; Открыть ветку реестра
- ; HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\DISPLAY\PHL0904\
- invoke RegOpenKey,HKEY_LOCAL_MACHINE,regstr,hKey
- or eax,eax
- ; Открыть ключ не получилось, пропускаем
- jnz .loc_no_devid
- ; Перебрать все дочерние ключи, начиная с 0
- mov [dKeysIndex],0
- .loc_scan_keys_monitor:
- ; Просканировать все ключи
- invoke RegEnumKey,[hKey],[dKeysIndex],buff,tmp
- or eax,eax
- jnz .loc_no_more_keys
- ; Сформировать название ключа реестра
- ; SYSTEM\CurrentControlSet\Enum\DISPLAY\PHL0904\
- invoke lstrcpy,buff2,regstr
- ; 5&217f22ba&0&UID1048848
- invoke lstrcat,buff2,buff
- ; \Device Parameters
- invoke lstrcat,buff2,szReg1
- ; Открыть параметр EDID в ключе реестра
- ; HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\DISPLAY\PHL0904\
- ; 5&217f22ba&0&UID1048848\Device Parameters
- invoke RegOpenKeyEx,HKEY_LOCAL_MACHINE,buff2,0,KEY_READ,hSubKey
- or eax,eax
- ; Такого параметра нет, проверить следующий ключ
- jnz .loc_next_key
- ; Прочитать EDID
- invoke RtlZeroMemory,edid,500h
- mov [tmp],500h
- invoke RegQueryValueEx,[hSubKey],szReg2,0,0,edid,tmp
- or eax,eax
- jnz .loc_no_edid
- ; Найти в EDID строки Serial Number и Model
- xor ecx,ecx
- ; Начинаем разбор с 72-го байта
- mov ebx,48h
- .loc_scan_edid:
- mov esi,ebx
- add esi,edid
- mov byte[esi+18],0
- ; Serial Number
- cmp dword[esi],0xFF000000
- jne .loc_not_edidsn
- add esi,5
- mov edi,edidsn
- .loc_move_edidsn:
- lodsb
- cmp al,20h
- jb .loc_next_edid
- stosb
- jmp .loc_move_edidsn
- .loc_not_edidsn:
- ; Model
- cmp dword[esi],0xFC000000
- jne .loc_next_edid
- add esi,5
- mov edi,edidmodel
- .loc_move_edidmodel:
- lodsb
- cmp al,20h
- jb .loc_next_edid
- stosb
- jmp .loc_move_edidmodel
- .loc_next_edid:
- add ebx,18
- inc ecx
- cmp ecx,2
- jbe .loc_scan_edid
- .loc_no_edid:
- ; Закрыть ключ
- invoke RegCloseKey,[hSubKey]
- .loc_next_key:
- ; Следующий индекс
- inc [dKeysIndex]
- jmp .loc_scan_keys_monitor
- .loc_no_more_keys:
- invoke RegCloseKey,[hKey]
- .loc_no_devid:
- ; edidsn -> Serial Number, если есть
- ; edidmodel -> Model
- ; или пустые строки, если записи о мониторе в реестре нет
- invoke wsprintf,buff,mask,edidmodel,edidsn
- add esp,16
- invoke MessageBox,0,buff,dds.DeviceName,0
- .loc_next_monitor:
- ; Следующая запись из массива PHYSICAL_MONITOR
- pop esi
- add esi,sizeof.PHYSICAL_MONITOR
- pop ecx
- sub ecx,1
- jnz .loc_monitors_loop
- ; Прибраться за собой
- invoke DestroyPhysicalMonitors,[num],[MonArray]
- ; Освободить память
- invoke GlobalUnlock,[hMonArray]
- invoke GlobalFree,[hMonArray]
- .loc_ret:
- ; Продолжаем обработку
- mov eax,TRUE
- ret
- endp
Прочитав из реестра значение параметра EDID, мы получим EDID монитора. Он хранится в бинарном виде, так что приступаем к парсингу. В соответствии со стандартом, четыре 18-байтных идентификатора находятся в EDID с 54-го байта. Последовательность и назначение блоков ничем не регламентировано, поэтому надо проверять все четыре. Структура текстовых блоков простейшая: три нулевых байта, байт описания идентификатора, снова нулевой байт и затем ASCII-строка, которая заканчивается или на последнем байте идентификатора, или на любом непечатном символе с кодом меньше 20h. Таким образом максимальная длина строки серийного номера или названия модели монитора может быть 13 символов. Байт описания идентификатора 0FFh соответствует серийному номеру монитора, байт 0FCh - названию модели.
Как я говорил выше, в зависимости от производителя монитора, искомых строк в EDID может вообще не оказаться, или может быть только название модели, с этим я уже столкнулся на практике. Также выяснилось, что при подключении одного и того же монитора к разным компьютерам, получаемые значения его серийного номера могут отличаться. Я не могу даже предположить, с чем это связано. Ну и теоретически, раз уж EDID хранится локально в реестре, то его можно модифицировать, изменив какие-нибудь байты и подкорректировав контрольную сумму. Так что безоговорочно доверять данным EDID не надо.
Скриншот программы Phoenix EDID Designer
Для более детального изучения структуры EDID, а также для редактирования имеющихся значений, можно воспользоваться малюсенькой утилитой Phoenix EDID Designer. Ее разработка прекращена, офсайт недоступен, последнюю версию я выложил сюда.
В приложении пример программы с исходным текстом, которая выводит название модели и серийный номер для каждого подключенного монитора.
Просмотров: 7644 | Комментариев: 2
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
ManHunter
(10.12.2023 в 18:24):
Программа сама ничего не придумывает, только отображает информацию, которую ей отдает система. Так что вопросы не к программе, а к системе.
Maxim
(10.12.2023 в 16:51):
Интересно. У меня монитор выпущен в двух модификациях, которые отличаются по разъёмам. И есть монитор, но у него две разные матрицы. В обоих случаях программа выводит только первые буквы и цифры без модификации.
Например SX202. А ведь эта модель идёт как SX202H и SX202HQ.
Например SX202. А ведь эта модель идёт как SX202H и SX202HQ.
Добавить комментарий
Заполните форму для добавления комментария