计算机锁定时关闭显示器






3.63/5 (6投票s)
一个实用工具,用于在锁定机器(Windows)时立即关闭显示器。
引言
几个月前,我公司的“社会活动小组”发起了一项活动,如果发现显示器未使用,则将其关闭。这确实是一项减少公司能源浪费的伟大举措。这激励我编写一个简单的应用程序来完成该小组正在尝试做的事情。关闭显示器的最佳时机是我们锁定计算机的时候。因此,锁定机器后立即将其关闭是有意义的。
解决方案
解决方案很简单。只需按照以下步骤操作
- 捕获“Windows 锁定/解锁”事件。
- 捕获用户交互事件,如鼠标移动、键盘敲击,以便如果由于这些移动导致显示器打开,则可以再次将其关闭。
- 如果计算机已锁定,则发出信号以关闭显示器。
- 重复步骤 2 和 3,直到机器解锁。
步骤 1:捕获 Windows 锁定/解锁事件
有几种方法可以获取 Windows 锁定和解锁的事件,我选择使用 Winlogon 通知包。 Winlogon 通知包是一个 DLL,允许您导出函数来处理 Winlogon.exe 事件。 这些事件消息包括锁定、解锁、注销、登录、启动、关闭、启动屏幕保护程序、停止屏幕保护程序和启动 shell 等。
您所要做的就是编写一个 DLL 导出事件处理程序并进行一些注册表项。 以下是附加项目中的代码片段,该项目具有三个事件句柄:“CompLocked
”、“CompUnlocked
”和“CompLoggedIn
”,这些句柄从“ShutDownMonitor.dll”(随代码一起提供)导出。
HANDLE g_hUnLockEvent = NULL;//An event handle to signal System
//Unlock Event
HANDLE g_hMovementEvent = NULL;//An event handle to signal
//any mouse movement/keboard hit event
VOID CompLocked( PWLX_NOTIFICATION_INFO pInfo )
{
//When the computer gets locked, create two event objects to signal
//Unlock event and Keyboard/Mouse movement event
if( !g_hUnLockEvent )
{
//First lock event
g_hUnLockEvent = CreateEvent( NULL, TRUE, FALSE, _T("MonitorShutDown") );
}
else
{
ResetEvent( g_hUnLockEvent );
}
if( !g_hMovementEvent )
{
//First lock event
g_hMovementEvent = CreateEvent(NULL, TRUE, TRUE, _T("MovementCaptured"));
}
else
{
SetEvent( g_hMovementEvent );
}
// Create a thread “ShutDownMonitor” to monitor systemt lock/unlock state,
// Implementation given in step 3
CreateThread( NULL, 0, ShutDownMonitor, NULL, 0, NULL );
}
VOID CompUnlocked( PWLX_NOTIFICATION_INFO pInfo )
{
if( g_hUnLockEvent )
{
SetEvent( g_hUnLockEvent );
}
}
VOID CompLoggedIn( PWLX_NOTIFICATION_INFO pInfo )
{
if( g_hUnLockEvent )
{
SetEvent( g_hUnLockEvent );
}
}
步骤 2:捕获用户交互事件,如鼠标移动、键盘敲击
这可以使用 SetWindowsHookEx
轻松实现。 您必须为 WH_MOUSE
和 WH_KEYBOARD
设置一个钩子来捕获鼠标和键盘事件。 调用看起来像
SetWindowsHookEx( WH_KEYBOARD, KeyboardProc, hModule, 0 );
SetWindowsHookEx( WH_MOUSE, MouseProc, hModule, 0 );
KeyboardProc
:键盘事件的钩子程序。MouseProc
:鼠标事件的钩子程序。hModule
:实现KeyboardProc
和MouseProc
的模块的句柄。
我在我的 Winlogon 通知包中实现了这些函数,即“ShutDownMonitor.dll”,实现如下所示
LRESULT CALLBACK MouseProc( int nCode, WPARAM wParam, LPARAM lParam )
{
//One weird thing that I observed was, even when i had my systemt left idle,
//My opticle mouse was resulting into a minor displacemets like 3-4 pixels
//So, decided to set the event only if the displacement is considerable
static POINT ptOld = reinterpret_cast<PMOUSEHOOKSTRUCT>( lParam )->pt;
POINT ptNew = reinterpret_cast<PMOUSEHOOKSTRUCT>( lParam )->pt;
//Get the displacement of the mouse position in pixel
int nXDisp = abs( ptNew.x - ptOld.x );
int nYDisp = abs( ptNew.y - ptOld.y );
if( ( WAIT_OBJECT_0 != WaitForSingleObject( g_hMovementEvent, 0 ) ) &&
( nXDisp || nYDisp ) )
{
EnterCriticalSection( &g_csMovement );
SetEvent( g_hMovementEvent );
LeaveCriticalSection( &g_csMovement );
}
//Save the current position of the mouse
ptOld = ptNew;
return CallNextHookEx( g_hMouseHook, nCode, wParam, lParam );
}
LRESULT CALLBACK KeyboardProc( int nCode, WPARAM wParam, LPARAM lParam )
{
if( WAIT_OBJECT_0 != WaitForSingleObject( g_hMovementEvent, 0 ) )
{
//Set the event only when the key is being released(31st bit 1).
if( (lParam & 0x80000000) && (lParam & 0x40000000) )
{
EnterCriticalSection( &g_csMovement );
SetEvent( g_hMovementEvent );
LeaveCriticalSection( &g_csMovement );
}
}
return CallNextHookEx( g_hKBHook, nCode, wParam, lParam );
}
步骤 3:如果计算机已锁定,则发出信号以关闭显示器
可以使用 SendMessage()
打开/关闭显示器
const int ON = -1;
const int OFF = 2;
const int STANBY = 1;
SendMessage( hWnd, WM_SYSCOMMAND, SC_MONITORPOWER, OFF);
其中 hWnd
是最顶层窗口的句柄。当计算机锁定时,最顶层窗口的标题为“计算机已锁定”。因此,我们的任务是找到此窗口并向其发送一条消息以关闭显示器。因此,步骤 1 中使用的“ShutDownMonitor
”线程如下所示
DWORD WINAPI ShutDownMonitor( LPVOID )
{
DWORD dwDisposition = 0;
HKEY hKey = NULL;
DWORD dwSleepTime = 10;
InitializeCriticalSection( &g_csMovement );
//Set the mouse and keyboard hooks
HMODULE hModule = LoadLibrary( _T("ShutDownMonitor.dll") );
typedef LRESULT (CALLBACK *HOOKPROC)( int nCode, WPARAM wParam, LPARAM lParam );
HOOKPROC MouseProc = NULL;
HOOKPROC KeyboardProc = NULL;
if( hModule )
{
MouseProc = (HOOKPROC)GetProcAddress( hModule, "MouseProc" );
KeyboardProc = (HOOKPROC)GetProcAddress( hModule, "KeyboardProc" );
}
if( MouseProc )
{
g_hMouseHook = ::SetWindowsHookEx( WH_MOUSE, MouseProc, hModule, 0 );
}
if( KeyboardProc )
{
g_hKBHook = ::SetWindowsHookEx( WH_KEYBOARD, KeyboardProc, hModule, 0 );
}
HWND hWnd = NULL;
while( WAIT_TIMEOUT == WaitForSingleObject( g_hUnLockEvent, 500 ) )
{
hWnd = FindWindow( NULL, _T("Computer Locked") );
if( hWnd )
{
break;
}
}
do
{
hWnd = FindWindow( NULL, _T("Computer Locked") );
if( hWnd )
{
RECT rectWnd = {0};
GetWindowRect( hWnd, &rectWnd );
int x = rectWnd.left + ( rectWnd.right - rectWnd.left )/2;
int y = rectWnd.top + ( rectWnd.bottom - rectWnd.top )/2;
SetCursorPos( x, y );
//This will put the monitor in sleep mode
::SendMessage( hWnd, WM_SYSCOMMAND, SC_MONITORPOWER, OFF );
}
EnterCriticalSection( &g_csMovement );
ResetEvent( g_hMovementEvent );
LeaveCriticalSection( &g_csMovement );
WaitForSingleObject( g_hMovementEvent, INFINITE );
//This is just to take care that MONITOR POWWER OFF messages
//are not sent very frequently
//One can use his/her own time out values
if( dwSleepTime < 60 )
{
dwSleepTime *= 2;
}
}while( WAIT_TIMEOUT == WaitForSingleObject( g_hUnLockEvent, dwSleepTime*1000 ) );
//Release the hooks
if( g_hKBHook )
{
UnhookWindowsHookEx( g_hKBHook );
g_hKBHook = NULL;
}
if( g_hMouseHook )
{
UnhookWindowsHookEx( g_hMouseHook );
g_hMouseHook = NULL;
}
DeleteCriticalSection( &g_csMovement );
return 0;
}
安装实用程序
为了在机器上安装此实用程序,请将“ShutDownMonitor.dll”复制到 c:\windows\System32 中并进行以下注册表更改
HKEY_LOCAL_MACHINE
\Software
\Microsoft
\Windows NT
\CurrentVersion
\Winlogon
\Notify
\ShutDownMonitor
\Asynchronous REG_DWORD 1
\DllName REG_SZ ShutDownMonitor.dll
\Lock REG_SZ CompLocked
\Logon REG_SZ CompLoggedIn
\Unlock REG_SZ CompUnlocked
完成注册表更改后,您需要重新启动机器才能使该实用程序生效。 就是这样,您已经准备好节省宝贵的能源了:)
并且,如果您想卸载该实用程序,请首先删除注册表更改,重新启动机器,然后从 c:\windows\system32 中删除文件“ShutDownMonitor.dll”。