Windows 화면보호기/절전모드 방지하기



Intro

 미디어 플레이어와 같은 프로그램을 개발하다보면, 고려해야 하는 것이 있습니다.
바로 '미디어 재생중 화면보호기 끄기' 라는 것이죠.
동영상을 열심히 보고 있는데, 화면보호기가 갑자기 동작하여 모니터가 꺼지면 곤란하겠죠?
그렇다고 매번 미디어를 재생하기 전에 윈도우 옵션에 들어가서 '화면보호기' / '절전모드' 를 일일이 껐다 켰다 할 수는 없는 노릇입니다.

그래서 곰플레이어를 포함하여 몇몇 미디어 플레이어에서는 '미디어 재생 중 화면보호기 차단' 이라는 옵션을 제공하지요.
이 기능을 구현하려면 어떻게 해야 하는지 알아보도록 하겠습니다.


Contents

이 기능을 구현하는 방법은 크게 두가지 정도로 볼 수 있습니다.
p
첫째, 윈도우의 '전원관리' 에서 화면보호기/절전모드 설정값을 변경하는 방법.
둘째, 주기적으로 윈도우의 Idel Time 을 Reset 하는 방법.


1. 윈도우 설정을 이용하기

첫번째 방법에 대해서 살펴보도록 하겠습니다.
방법은 간단합니다. 윈도우에는 전원관리 설정을 위한 프롬프트 명령을 지원하고 있습니다.

powercfg.exe 파일이 바로 그것입니다.
만약 절전모드를 '사용안함'으로 변경하려면 다음과 같이 하면 됩니다.

C:\>powercfg.exe /change /standby-timeout-ac 0
C:\>powercfg.exe /change /standby-timeout-dc 0

눈치가 빠르신 분들은 눈치 채셨을 겁니다.
위는 ac 이고, 아래는 dc 입니다.
즉 데스크탑처럼 ac 전원인 경우와 노트북처럼 dc 전원인 경우에 대해서 각각 설정을 해 주는 것이지요.

모니터 화면보호기 등 각종 자세한 옵션은 아래 링크를 참고해 주시기 바랍니다.
http://msdn.microsoft.com/en-us/library/ff794903(v=winembedded.1001).aspx

이 방법에는 단점이 있습니다.

프로그램이 종료할 때, 다시 본래 설정값으로 일일이 복원을 해 주어야 한다는 것입니다.
만약 프로그램 실행중에 오류가 나서 갑자기 종료된다면, 기존 값으로 복원을 할 수도 없습니다.
즉, 설정 자체를 변경하는 일은 다소 위험한 방법입니다.


2. Idle Time 을 Reset 하는 방법

 앞서 말씀 드린데로, 윈도우의 Idle Time 을 주기적으로(1분 이내 간격) rest 함으로써, 계속 입력을 하고 있는 것 처럼 보이는 것입니다.

 만약 화면보호기 설정값이 3분이고, 30초 간격으로 Idle Time 을 0으로 reset 해 버리면 어떻게 될까요?
시스템은 내부적으로 Idle Time 을 체크하다가 3분이 되면 화면보호기를 띄우도록 되어 있습니다.
그런데 이 시간값을 30초 간격으로 0으로 만들어 버리니, 절대 화면보호기가 뜨는 일이 발생하지 않을 것입니다.

 이 역할을 위해서 제공되는 Win32 API 가 바로 SystemIdleTimerReset() 입니다. 주기적으로 이 API 를 호출해 주면, 대기모드로 빠지는 것을 방지할 수 있습니다.


3. Windows Proc Message 를 이용하는 방법

 또 다른 방법은 대기/최대 절전모드로 진입시 발생하는 Windows 메세지를 이용하는 것입니다.
대기/최대 절전모드 진입시 WM_POWERBROADCAST  메세지가 각기 다른 wParam 값으로 두 번 발생합니다.


1. WM_POWERBROADCAST 메세지 발생(Message)

  a. PBT_APMQUERYSUSPEND 발생(wParam)
   - 대기/절전 모드로 들어가기 위한 권한을 요청(모든 Application / Device 가 True 를 리턴하면 다음 메세지인 PBT_APMSUSPEND 발생)

  b. PBT_APMSUSPEND 발생(wParam)
   - 대기모드 진입


즉, 방지하기 위해서는 PMT_AMPQUERYSUSPEND 메세지를 전달 받았을 때, BROADCAST_QUERY_DENY 를 리턴하면, 대기모드로 진입하는 프로세스는 중단되게 됩니다.


간략한 코드는 아래와 같습니다.(나머지 기본적인 윈도우 메세지 처리 루틴은 제거하였습니다.)



LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc;

	switch (message)
	{
	case WM_POWERBROADCAST:
		{
		switch(wParam) {
			case PBT_APMQUERYSUSPEND:
				return BROADCAST_QUERY_DENY;
				
			case PBT_APMSUSPEND:
				return DefWindowProc(hWnd, message, wParam, lParam);
		}
		break;
		}
	}

	return 0;
} 




4. SetThreadExecutionState 를 이용하는 방법

 개인적으로 이 방법이 가장 확실하고, 편하다고 생각합니다. :)
윈도우에서 제공하는 이 API 는 특성 Thread 가 실행(Run)되고 있는 동안 '시스템 대기' 모드 및 화면보호기 작동을 중지시킬 수 있습니다. 엄밀히 말하자면 내부적으로 SystemIdleTimerReset() 를 일정시간마다 호출해 주는 듯 합니다.
즉, System 의 Idle Time 을 강제로 리셋해 주는 것이죠.

함수 원형은 아래와 같습니다.


EXECUTION_STATE WINAPI SetThreadExecutionState(
  __in  EXECUTION_STATE esFlags
); 



함수가 매우 간단하므로, 아래 링크를 참고하시기 바랍니다.
http://msdn.microsoft.com/en-us/library/aa373208%28VS.85%29.aspx
http://support.microsoft.com/kb/601067/ko

.NET 으로 만든 샘플코드를 보시면 쉽게 이해하실 수 있을 것입니다.
PowerSavingMode.zip


Result

 대기모드의 진입을 방지하는 방법은 여러가지가 있습니다.
각 상황에 맞게 사용하면 될 것 같네요.
오랜만에 포스팅 하니 힘드네요 ㅎㅎ;


'Microsoft > C++' 카테고리의 다른 글

[MFC] UTF8 / UTF16 Convert  (0) 2011.04.05
Video 썸네일 추출하기  (0) 2011.03.18