На хабре есть статья как сделать это из Linux: ссылка Полезная вещь, но не все используют Linux, поэтому я решил написать что-то подобное для Windows. В Windows есть несколько способов добраться до I2C шины монитора, но самый простой из них появился в Windows Vista, его и будем использовать.
Ссылка на соответствующий раздел MSDN: ссылка
Итак, алгоритм управления питанием всеми подключёнными мониторами:
К сожалению, есть два неприятных нюанса. Во-первых, всё это будет работать только в Windows Vista или Windows 7. А во-вторых, и это самое неприятное, всё это будет работать не со всеми мониторами, так как некоторые производители мониторов не слишком заботятся о корректной поддержке стандарта DDC-CI. А бывает вообще про него забывают, а только поддерживают чтение EDID, чтобы Windows знала какие разрешения поддерживает монитор. Samsung же вообще использует свой собственный DDC-CI код для управления питанием.
Тем не менее, на большинстве современных мониторов данный подход будет работать.
Код консольной утилиты получился совсем небольшим:
Параметр «-off» выключает все подключённые мониторы, любой другой параметр их включает. Исходный код для VS2008 и готовый EXE можно скачать тут: ссылка
Возможно в будущем дойдут руки сделать полноценную утилиту, которая запускается при старте Windows и включает мониторы, а при завершении работы – выключает, и/или управляет питанием по горячей клавише – тут много можно чего придумать.
Ссылка на соответствующий раздел MSDN: ссылка
Итак, алгоритм управления питанием всеми подключёнными мониторами:
- Перебираем все логические мониторы в системе, вызывая функцию EnumDisplayMonitors, в ней указываем свою callback функцию которая будет получать описатель для каждого логического монитора – HMONITOR
- Зная HMONITOR-описатель монитора получаем соответствующий описатель физического монитора — HANDLE, для этого используем GetPhysicalMonitorsFromHMONITOR. Один логический монитор в Windows может включать в себя несколько физических мониторов, поэтому потребуется еще функция GetNumberOfPhysicalMonitorsFromHMONITOR
- Найденные неповторяющиеся описатели физических мониторов сохраняем в отдельном списке
- Посылаем команду мониторам, используя функцию SetVCPFeature
К сожалению, есть два неприятных нюанса. Во-первых, всё это будет работать только в Windows Vista или Windows 7. А во-вторых, и это самое неприятное, всё это будет работать не со всеми мониторами, так как некоторые производители мониторов не слишком заботятся о корректной поддержке стандарта DDC-CI. А бывает вообще про него забывают, а только поддерживают чтение EDID, чтобы Windows знала какие разрешения поддерживает монитор. Samsung же вообще использует свой собственный DDC-CI код для управления питанием.
Тем не менее, на большинстве современных мониторов данный подход будет работать.
Код консольной утилиты получился совсем небольшим:
<code> // код команды управлением питания 0xD6 //константы для этой команды: #define POWER_ON 0x01 #define POWER_STANDBY 0x02 #define POWER_SUSPEND 0x03 #define POWER_OFF 0x04 //список для описателей физических мониторов std::vector<HANDLE> MonHandles; void AddToMonHandles(HANDLE h) { int i, cnt; cnt = MonHandles.size(); for (i = 0; i < cnt; i++) if (MonHandles[i] == h) return; MonHandles.push_back(h); } //callback функция для EnumDisplayMonitors BOOL CALLBACK EnumProc( HMONITOR hMonitor, // описатель логического монитора HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData ) { LPPHYSICAL_MONITOR pMons = NULL; DWORD i, mcnt; if (!GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor, &mcnt)) return TRUE; pMons = (LPPHYSICAL_MONITOR)malloc(mcnt * sizeof(PHYSICAL_MONITOR)); if (GetPhysicalMonitorsFromHMONITOR(hMonitor, mcnt, pMons)) for (i = 0; i < mcnt; i++) AddToMonHandles(pMons[i].hPhysicalMonitor); free(pMons); return TRUE; } int _tmain(int argc, _TCHAR* argv[]) { if (argc < 2) return 0; bool IsOn = _wcsicmp(argv[1], L"-off") != 0; EnumDisplayMonitors(NULL, NULL, EnumProc, NULL); int i, cnt; cnt = MonHandles.size(); for (i = 0; i < cnt; i++) { //посылаем команду управления питанием SetVCPFeature(MonHandles[i], 0xD6, IsOn ? POWER_ON : POWER_OFF); //а это специально для мониторов Samsung SetVCPFeature(MonHandles[i], 0xE1, IsOn ? 1 : 0); //разобравшись, что работает на вашем мониторе, одну из строчек можно удалить } return 0; } </code>
Параметр «-off» выключает все подключённые мониторы, любой другой параметр их включает. Исходный код для VS2008 и готовый EXE можно скачать тут: ссылка
Возможно в будущем дойдут руки сделать полноценную утилиту, которая запускается при старте Windows и включает мониторы, а при завершении работы – выключает, и/или управляет питанием по горячей клавише – тут много можно чего придумать.