这篇文章的主要目的实现了一个锁机和解锁的功能,首先是实现锁机,锁机主要通过三方面实现:启动一个新的窗口,将其覆盖整个屏幕实现屏幕的锁定;隐藏任务栏,防止用户切换到其他应用;限制鼠标移动范围,阻止鼠标操作。同时留下解锁按键A,实现解锁功能。
详细分析:
1. LockMachine()
该函数用于启动 threadLockDlg
线程,并发送一个数据包。
2. threadLockDlg(void* arg)
该函数是 LockMachine()
启动的线程入口点,主要执行锁屏操作。
3. UnlockMachine()
该函数用于解锁屏幕。
为什么使用线程函数?
在 LockMachine()
中,我们使用了 _beginthreadex()
来创建一个新的线程运行 threadLockDlg()
,原因如下:
1. 避免 UI 线程阻塞
如果 threadLockDlg()
在主线程(UI 线程)中运行,它会创建一个模态对话框 dlg
,并进入 while (GetMessage(&msg, NULL, 0, 0))
消息循环,导致主线程无法处理其他任务。
2. 让 LockMachine()
迅速返回
如果 threadLockDlg()
在主线程执行:
LockMachine()
会卡在dlg.Create()
之后,直到窗口销毁。- 这样,
LockMachine()
无法立即返回,程序执行效率降低。
通过子线程运行 threadLockDlg()
:
LockMachine()
不会等待 窗口运行完毕,而是立刻返回,让程序继续执行其他任务。
3.兼容多线程架构
在实际开发中:
LockMachine()
可能由其他线程调用(例如:网络接收线程)。- 使用线程封装
dlg
,使其成为独立的可控组件,不会影响主程序逻辑。
此外,如果需要在多个地方调用 LockMachine()
,独立线程方式更易维护,且不会干扰主线程。
具体操作如下:
1. threadLockDlg(void* arg)
创建并显示对话框
dlg.Create(IDD_DIALOG_INFO,NULL);
dlg.ShowWindow(SW_SHOW);
-
IDD_DIALOG_INFO
是一个对话框资源,dlg
作为CLockDialog
实例被创建并显示. -
全屏遮盖后台窗口
CRect rect;
rect.left = 0;
rect.top = 0;
rect.right = GetSystemMetrics(SM_CXFULLSCREEN);
rect.bottom = GetSystemMetrics(SM_CYFULLSCREEN);
rect.bottom *= 1.03;
dlg.MoveWindow(rect);
-
这段代码获取全屏分辨率,并设置窗口大小比屏幕稍大(1.03 倍)。
-
鼠标控制
ShowCursor(false); // 隐藏鼠标
rect.left = 0;
rect.top = 0;
rect.right = 1;
rect.bottom = 1;
ClipCursor(rect); // 限制鼠标活动范围
这里将鼠标位置限制在 (0,0) 到 (1,1),相当于禁用鼠标。
隐藏任务栏
::ShowWindow(::FindWindow(_T("Shell_TrayWnd"), NULL), SW_HIDE);
-
这行代码隐藏了 Windows 任务栏。
-
消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
if (msg.message == WM_KEYDOWN) {
TRACE("msg:%08X wparam:%08X lparam:%08X\r\n", msg.message, msg.wParam, msg.lParam);
if (msg.wParam == 0x41) { // 'A' 键退出
break;
}
}
}
- 监听键盘输入,按下
A
(0x41
) 退出。 -
恢复鼠标、任务栏,并销毁窗口
ShowCursor(true);
::ShowWindow(::FindWindow(_T("Shell_TrayWnd"), NULL), SW_SHOW);
dlg.DestroyWindow();
恢复鼠标指针。
- 显示任务栏。
- 关闭
dlg
窗口,解除锁屏。
2. LockMachine()
该函数用于启动 threadLockDlg
线程,并发送一个数据包。
if ((dlg.m_hWnd == NULL) || (dlg.m_hWnd == INVALID_HANDLE_VALUE)) {
_beginthreadex(NULL, 0, threadLockDlg, NULL, 0, &threadid);
TRACE("THREADID=%d\r\n", threadid);
}
dlg.m_hWnd == NULL
表示窗口未创建,INVALID_HANDLE_VALUE
额外检查句柄无效。- 使用
_beginthreadex()
启动threadLockDlg
线程,并存储线程 ID 到threadid
。
CPacket pack(7, NULL, 0);
CServerSocket::getInstance()->Send(pack);
CPacket
是一个数据包类,构造函数参数(7, NULL, 0)
表示发送一个类型为7
的消息。CServerSocket::getInstance()->Send(pack);
发送数据。
3. UnlockMachine()
该函数用于解锁屏幕。
PostThreadMessage(threadid, WM_KEYDOWN, 0x41, 0);
PostThreadMessage(threadid, WM_KEYDOWN, 0x41, 0);
- 向
threadid
线程发送WM_KEYDOWN
消息,模拟按下A
键,使threadLockDlg
退出。
CPacket pack(7, NULL, 0);
CServerSocket::getInstance()->Send(pack);
- 再次发送数据包,可能是通知服务器解锁完成。