0 注意:
怎么接收到命令,以及如何将结果返回给客户端在2、3、4节以及介绍清楚来,本节只讨论功能实现
屏幕监控的本质就是==》发送屏幕截图
1 参考代码
代码步骤
-
获取屏幕色深,屏幕宽高(以像素为为单位)
-
获取屏幕句柄
-
创建一张图片利用Image对象
-
利用BitBlt函数将屏幕位图信息复制给image对象
-
声明一块全局内存空间global、以及一个流指针pStream
-
将流指针pStream与全局内存空间global绑定
-
利用流指针将图像信息保存在内存里
-
将文件指针指向开头(pStream保存图片后,该指针先处于文件尾)
-
发送数据
-
释放设备上下文、流对象、全局内存
参考代码
#include <atlimage.h> int SendScreen() { CImage screen; // GetDC 函数检索指定窗口的工作区或整个屏幕的设备上下文 (DC) 的句柄 // 通过设备上下文来获取宽高,以及一个像素占多少bit HDC hScreen = ::GetDC(NULL); // GetDeviceCaps 函数检索指定设备的设备特定信息。 // 每个像素的颜色位数。 int nBitPerPixel = GetDeviceCaps(hScreen, BITSPIXEL); // HORZRES:屏幕的宽度,以像素为单位 int nWidth = GetDeviceCaps(hScreen, HORZRES); // VERTRES:屏幕的高度,以像素为单位 int nHeight = GetDeviceCaps(hScreen, VERTRES); // 创建 DIB 节位图并将其附加到先前构造的 CImage 对象 screen.Create(nWidth, nHeight, nBitPerPixel); // 将位图从源设备上下文复制到当前设备上下文。 // 目标Hdc、目标矩形左上角x逻辑坐标,目标矩形左上角y逻辑坐标 // 目标矩形的宽度、目标矩形的高度 // 源hdc、源矩形左上角的逻辑 x 坐标、源矩形左上角的逻辑 y 坐标 BitBlt(screen.GetDC(), 0, 0, 1920, 1080, hScreen, 0, 0, SRCCOPY); // 释放屏幕上下文 ReleaseDC(NULL, hScreen); // 将图像保存到磁盘上的指定流或文件。 /* 权衡点:考虑使用png还是jpeg png 总体要比jpeg小 但是保存一个png所用时间要比jpeg大十几毫秒 这时一个网络应用这个倾向于优化带宽 */ /* ULONGLONG tick = GetTickCount64(); for (int i = 0; i < 10; i++) { tick = GetTickCount64(); screen.Save(_T("test.png"), Gdiplus::ImageFormatPNG); TRACE("png : %ld \r\n", GetTickCount64() - tick); tick = GetTickCount64(); screen.Save(_T("test.jpeg"), Gdiplus::ImageFormatJPEG); TRACE("jpeg : %ld \r\n", GetTickCount64() - tick); } */ // 保存图片到内存里面 // 申请内存,GlobalAlloc从全局堆中分配指定的字节数。 // GMEM_MOVEABLE:分配可移动内存 HGLOBAL hMen = GlobalAlloc(GMEM_MOVEABLE, 0); // 声明一个流指针 IStream* pStream = NULL; // 创建一个流和一个全局内存对象绑定里面,并且自动管理内存 HRESULT ret = CreateStreamOnHGlobal(hMen, TRUE, &pStream); if (hMen == NULL) return -1; if (ret == S_OK) { // 这里保存完了后pStraem指针指向文件尾部了 screen.Save(pStream, Gdiplus::ImageFormatPNG); // 把指针设置到文件首 LARGE_INTEGER begin = { 0 }; // Seek 方法将查找指针更改为新位置。 新位置相对于流的开头、流的末尾或当前查找指针。 // begin 移动到STREAM_SEEK_SET第几个字节 pStream->Seek(begin, STREAM_SEEK_SET, NULL); // 锁定全局内存对象并返回指向对象内存块的第一个字节的指针。递增锁计数 PBYTE pData = (PBYTE)GlobalLock(hMen); size_t nSize = GlobalSize(hMen); if (pData != NULL) { CPacket packet(12, pData, nSize); CServerSocket::getInstance()->Send(packet); } // 递减与使用 GMEM_MOVEABLE 分配的内存对象关联的锁计数 GlobalUnlock(hMen); } // 释放screen 设备上下文 screen.ReleaseDC(); // 释放流 pStream->Release(); // 释放全局堆内存 GlobalFree(hMen); return 0; }