На хабре есть статья как сделать это из Linux: ссылка Полезная вещь, но не все используют Linux, поэтому я решил написать что-то подобное для Windows. В Windows есть несколько способов добраться до I2C шины монитора, но самый простой из них появился в Windows Vista, его и будем использовать.

Ссылка на соответствующий раздел 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 и включает мониторы, а при завершении работы – выключает, и/или управляет питанием по горячей клавише – тут много можно чего придумать.

Комментарии (8)


  1. slon4ik
    09.07.2026 16:51

    Статья пролежала в песочнице с 2011 года. Актуальность, может, и не самая горячая, но авторов таких статей на хабре надо поощрять. ИМХО.


    1. Squoworode
      09.07.2026 16:51

      Месье знает толк в некропостинге, там уж и автор-то десять лет как перестал на Хабре появляться... ;)


  1. dky
    09.07.2026 16:51

    Я выключаю моник горячей клавишей в автохоткей, моник самсунг, в десятке работает:

    #noEnv
    #persistent
    #singleInstance force

    #m::gotoSleep() ; Win+M hotkey

    gotoSleep() {
    sleep, 500
    sendMessage, 0x112, 0xF170, 2, Program Manager
    }


    1. PereslavlFoto
      09.07.2026 16:51

      Но ведь горячая клавиша есть на самом же мониторе? Зачем ещё другая?


      1. iDuran
        09.07.2026 16:51

        А тут не все так однозначно. У меня лыжа из верхнего сегмента - там одна кнопка, она же стик. Есть еще, конечно, пульт, но его постоянно держать рядом тоже не прям удобно. Так вот, нужно сначала на этот стик нажать, а потом ещё раз нажать и подержать, чтоб монитор отключить. Хоткеем с клавы гораздо удобнее.


  1. lkik
    09.07.2026 16:51

    https://www.nirsoft.net/utils/nircmd.html

    вырубать из консоли все мониторы - nircmd.exe monitor off

    или выборочно из gui или консоли

    https://www.nirsoft.net/articles/turn-off-monitor.html

    https://www.nirsoft.net/utils/multi_monitor_tool.html

    https://www.nirsoft.net/utils/control_my_monitor.html

    и тд.. там полно разного


  1. Arhammon
    09.07.2026 16:51

    А зачем? Дежурка блока питания обычно потребляет столько же, сколько спящий монитор...


    1. Denis_Chernyshev
      09.07.2026 16:51

      Например, чтобы не светить экран при работе с удаленного подключения.