当前位置: 首页 > news >正文

远程控制项目第四天 功能实现

发送屏幕内容

        

代码详解

1. 创建 CImage 对象并获取屏幕内容

首先,我们创建一个 CImage 对象,用于接收屏幕上的内容。要获取屏幕内容,我们需要先获取当前设备上下文(DC)。调用 ::GetDC(NULL) 函数,参数 NULL 表示我们要获取整个屏幕的设备上下文。

CImage screen;
HDC hScreen = ::GetDC(NULL);
int nBitPerPixel = GetDeviceCaps(hScreen, BITSPIXEL);  // 获取屏幕颜色深度
int nWidth = GetDeviceCaps(hScreen, HORZRES);  // 获取屏幕宽度
int nHeight = GetDeviceCaps(hScreen, VERTRES);  // 获取屏幕高度
screen.Create(nWidth, nHeight, nBitPerPixel);  // 创建 CImage 对象

2. 使用 BitBlt 获取屏幕内容

通过 BitBlt 函数,将当前屏幕的内容复制到 CImage 对象上。BitBlt 的本质就是将源图像的一部分搬运到目标图像的指定位置。

CImage screen;
HDC hScreen = ::GetDC(NULL);
int nBitPerPixel = GetDeviceCaps(hScreen, BITSPIXEL);  // 获取屏幕颜色深度
int nWidth = GetDeviceCaps(hScreen, HORZRES);  // 获取屏幕宽度
int nHeight = GetDeviceCaps(hScreen, VERTRES);  // 获取屏幕高度
screen.Create(nWidth, nHeight, nBitPerPixel);  // 创建 CImage 对象

3. 释放设备上下文

完成屏幕内容复制后,我们需要释放设备上下文,避免内存泄露。调用 ReleaseDC 函数来释放资源。

ReleaseDC(NULL, hScreen);  // 释放设备上下文

4. 创建全局内存块和流对象

接下来,我们创建一个空的全局内存块,使用 GlobalAlloc 分配内存。GMEM_MOVEABLE 标志表示这块内存是可移动的。然后,我们创建一个 IStream 流对象,使用 CreateStreamOnHGlobal 将全局内存块与流对象绑定。

HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, 0);  // 创建全局内存块
if (hMem == NULL) return -1;  // 内存分配失败IStream* pStream = NULL;
HRESULT ret = CreateStreamOnHGlobal(hMem, TRUE, &pStream);  // 创建流对象
if (ret != S_OK) return -1;  // 创建失败

5. 将 CImage 数据保存到流对象

现在,我们可以通过 CImage::Save 方法将图像数据保存到流对象中。保存时,我们指定保存的格式(如 JPEG)。

screen.Save(pStream, Gdiplus::ImageFormatJPEG);  // 将图像保存到流对象中

6. 流指针调整

调用 screen.Save 后,流指针已经指向了数据的末尾。如果不重置指针,接下来的读取操作可能会从流的末尾开始,这样读取到的数据可能为空。为了确保后续可以正确读取数据,我们需要通过 Seek 函数将流指针重置到开头。

LARGE_INTEGER bg = {0};
pStream->Seek(bg, STREAM_SEEK_SET, NULL);  // 将流指针移回开头

7. 锁定内存块并读取数据

接下来,我们通过 GlobalLock 锁定全局内存块,获取指向内存的指针。这允许我们直接操作内存中的数据。在操作完数据后,我们使用 GlobalUnlock 解锁内存。

PBYTE pData = (PBYTE)GlobalLock(hMem);  // 锁定内存并获取指针
SIZE_T nSize = GlobalSize(hMem);  // 获取内存大小

8. 发送数据

使用获取的内存数据,构造数据包并发送。发送完成后,解锁内存。

CPacket packet(6, pData, nSize);
CServerSocket::getInstance()->Send(packet);  // 发送数据GlobalUnlock(hMem);  // 解锁内存

9. 释放资源

最后,我们需要释放流对象、全局内存块以及 CImage 对象的设备上下文。资源的释放顺序应该是先释放流对象,再释放全局内存块,最后释放设备上下文。

pStream->Release();  // 释放流对象
GlobalFree(hMem);  // 释放全局内存块
screen.ReleaseDC();  // 释放 CImage 对象的设备上下文

总结

  • 获取屏幕内容:通过 GetDC 获取设备上下文,使用 BitBlt 将屏幕内容复制到 CImage 对象。
  • 流操作:使用 GlobalAlloc 创建全局内存块,使用 CreateStreamOnHGlobal 将内存块和流绑定。使用 CImage::Save 保存数据到流对象。
  • 内存操作:使用 GlobalLock 锁定内存,获取数据后调用 GlobalUnlock 解锁内存。注意流指针位置,要确保数据从流的起始位置读取。
  • 资源释放:确保按顺序释放资源:先释放流对象,再释放内存块,最后释放设备上下文。

这样就能确保屏幕截图数据能够被正确保存、读取和发送,同时避免资源泄露。

锁机

        通过_beginthreadex(NULL, 0, threadLockDlg, NULL, 0, &threatid);创建一个新线程来处理锁机逻辑,同时判断dlg.m_hWnd==NULL,dlg.m_hWnd==INVALID_HANDLE_VALUE要不要起新线程。线程函数threadLockDlg的逻辑是先通过Create(IDD_DIALOG_INFO,NULL);来创建对话框,NULL表示对话框没有父窗口,属于顶级窗口,然后ShowWindow显示窗口,再创建一个矩形对象,通过GetSyetemMetrics(SM_CYSCREEN);获取到屏幕大小,dlg.MoveWindow(rect);把对话框填满整个屏幕,还要dlg.SetWindowPos(&dlg.wndTopMost, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);使其对话框置顶,同时要让用户无法操控鼠标ShowCursor(false);::ShowWindow(::FindWindow(_T("Shell_TrayWnd"), NULL), SW_HIDE);的作用是查找任务栏窗口并隐藏它。FindWindow 查找 Shell_TrayWnd 类的窗口句柄,这通常是任务栏的窗口类,然后通过 ShowWindow(SW_HIDE) 隐藏任务栏。然后还要将光标限制在对话框内,通过调用ClipCursor(rect);后面就开始最重要的消息循环机制
 

  • 作用:这是标准的 Windows 消息循环,用于处理来自操作系统的消息。
    • GetMessage(&msg, NULL, 0, 0):从消息队列中检索消息,直到收到退出消息(如关闭窗口)。返回 FALSE 时退出消息循环。
    • TranslateMessage:翻译消息,通常是键盘消息,转换为字符消息。
    • DispatchMessage:分发消息,交给对应的窗口过程进行处理。
    • if (msg.message == WM_KEYDOWN):检查是否是按键按下事件(WM_KEYDOWN)。
    • if (msg.wParam == 0x1B):判断按下的键是不是 ESC 键(0x1BESC 键的虚拟键代码)。
  • 意识:通过消息循环,程序可以响应用户的输入,处理键盘事件或其他消息。这里实现了用户按 ESC 键退出对话框。

当退出循环,就要恢复鼠标,恢复任务栏,销毁对话框,并结束线程。
 

解锁

这里有个很重要的知识,每个线程都有自己独立的消息循环和消息处理,每个线程发出的消息只能被自己线程的消息循环接收到,所以我们要通过特定的函数来进行跨线程发送消息

PostThreadMessage(threatid, WM_KEYDOWN, 0x1B, 0);

这个函数可以把消息类型消息内容发送给指定的(threatid)线程,这样的话我们就可以把消息发给处理锁机逻辑的线程中,来解锁。


http://www.mrgr.cn/news/68037.html

相关文章:

  • 基于YOLO11/v10/v8/v5深度学习的维修工具检测识别系统设计与实现【python源码+Pyqt5界面+数据集+训练代码】
  • 全面解析:网络协议及其应用
  • 梧桐数据库SQL高级查询技巧之计算用户每月登录次数及其变化
  • aspose如何获取PPT放映页“切换”的“持续时间”值
  • 贝叶斯定理
  • 虚幻引擎5(UE5)学习教程
  • Claude Prompt:博弈天平|缘起自李继刚老师的提示词
  • 使用PyQt5设计一个简易计算器
  • 【测试】【Debug】pytest运行后print没有输出
  • CPU Study-Multi-Port Cache
  • golang函数
  • 使用开源Embedding模型嵌入高维空间向量
  • Linux命令--paste
  • 【大模型系列】Grounded-VideoLLM(2024.10)
  • Java学习篇之JVM 调优
  • linux进程的状态之环境变量
  • 【贪心算法】No.1---贪心算法(1)
  • linux 进程调度学习笔记
  • 迭代解法:Jacobi、Gauss-Seidel、SOR
  • CPU Study - Branch Prediction
  • java单例模式
  • 使用LoRA 对千问70B模型进行微调
  • R7:糖尿病预测模型优化探索
  • MinGW-w64_10.0.0 + GCC12_x86_64-12.2.0-release-posix-seh-msvcrt-rt_v10-rev2.zip
  • 怎么快速区分金媒10.3和10.4旗舰版小程序,如果只看数字你就out了表面被忽悠教新手几招!
  • lua入门教程:随机数