008 屏幕监控功能

本文详细描述了如何通过CImage类获取屏幕截图,包括获取屏幕信息、使用BitBlt函数复制图像、保存至内存流并最终发送回客户端的过程,涉及GDI+库和内存管理技术。
摘要由CSDN通过智能技术生成

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;
}
  • 10
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值