Introduction
Energy conservation is among the world’s top priority issues.
By profession, I am a software engineer and work for a software firm. I have taken an initiative towards conservation of energy through GreenUtils.
Background
Most of the Information Technology companies have their power policies in place. For example - there is a power policy to turn off display/monitor automatically if PC remains idle for 10 minutes or standby the system if it is idle for 20 minutes. The idle time is configurable through Windows power policies. These settings helps in saving a good amount of power.
As per my observation, there are additional areas where power savings can be implemented, for example – Turn Off monitor immediately when system is locked. Locking machines is the most common practice being followed by almost all the Information Technology firms. Hence there can be a considerable amount of energy saving if we consider this factor.
GreenMonitor
I have named the application as GreenMonitor and can be freely download from GreenUtils.
Through this article, I would like to share my development experience of GreenMonitor.
I have used Windows terminal services to trap system lock and unlock events. You can register to receive Windows terminal service notification using WTSRegisterSessionNotification(). I have not used global keyboard hooks for two reasons:
- Compromise in system’s security
- Compromise on system's performance
Below is the code snippet for the usage of WTSRegisterSessionNotification():
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance;
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
UpdateWindow(hWnd);
WTSRegisterSessionNotification(hWnd,NOTIFY_FOR_THIS_SESSION);
return TRUE;
}
I have used WTSRegisterSessionNotification() in InitInstance()
method, just after my create window succeeds. I have removed ShowWindow()
call from InitInstance()
because the application runs in the background and the user should not see any UI.
Once I register my applications handle to window to terminal services, the system sends the following notifications:
WTS_CONSOLE_CONNECT
WTS_CONSOLE_DISCONNECT
WTS_REMOTE_CONNECT
WTS_REMOTE_DISCONNECT
WTS_SESSION_LOGON
WTS_SESSION_LOGOFF
WTS_SESSION_LOCK
WTS_SESSION_UNLOCK
WTS_SESSION_REMOTE_CONTROL
These notifications are sent to the WndProc
method whose handle has been registered using WTSRegisterSessionNotification().
Once I was able to trap windows lock/unlock notifications, I used simple windows SendMessage () to send system command to shutdown the monitor.
Below is the code snippet on how SendMessage
can be used to turn off the monitor. For more information on how send message can be used for various monitor operations, click here.
SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM) 2);
The below code snippet shows my WndProc
method:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
WTSUnRegisterSessionNotification(hWnd);
PostQuitMessage(0);
break;
case WTS_SESSION_LOCK:
SendMessage(HWND_BROADCAST, WM_SYSCOMMAND,
SC_MONITORPOWER, (LPARAM) 2);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Architecture
Initially I thought of creating the entire application as a service.
My first version of the software was in fact a service, however I started facing complications when I tried to port my service from XP to Vista and Win 7.
From Vista, Microsoft has tightly implemented the concept of session isolation. Every user runs in a separate session. Services run in session zero. Services should ideally not interact with users. Hence, Microsoft has made session zero non interactive. This concept of session isolation already existed in XP, but was not strictly implemented by Microsoft.
There were two reasons for me why my application should not run as a service:
- Sending turn off message to monitor in Windows is per session. Click here to find out more on how to use SendMessage() to turn off the display/monitor.
- Retrieving the last interactive activity on system is again per session. I used GetLastInputInfo() to determine the last time when the user interacted with the system. Finding last input time was important to turn off the monitor if someone accidentally taps the keyboard or moves the mouse when system is in locked state.
Hence I decided to make my application session specific. A separate instance of application runs under each session.
I believe my article would help developers in taking early decisions about complications that could arise if services are made interactive. I have also attached the source code with the article. If you directly wish to download setup, you can download it from here.
Next Article
In my next article, I would like to share my experience of creating an installer for GreenMonitor using Visual Studio 2008.
History
- 25th November, 2009: Initial post