首页 > 代码精文 > C/C++ > C++模拟QQ截图的实现
2015
08-08

C++模拟QQ截图的实现

很多时候登QQ只是为了截图..虽然系统有截屏键,浏览器什么的都有截屏插件,但总觉得QQ是做的做好的。只此一家别无分号。但有时候断网就悲催了。

于是周六周末摸索着自己实现了一下它的两个基本功能,截屏到剪切板和保存到文件。参考了两个版本的代码 。一个是VC 驿站上的QQ2008版本的截屏。它采用了橡皮筋类。一种是之前CSDN上一个牛人放出的模拟ipad效果的源代码里面的截屏功能。        1  先说QQ2008版本的       在程序启动后,鼠标会变成一个彩色的箭头。拖动后就会显示一个虚线框。这是通过 CRectTracker 派生的一个橡皮筋类 。之所以不直接使用基类,源代码的注释中说是 更新窗口,消除TRACK时的虚线框     接下来就是在程序中对橡皮筋类的初始化

//初始化像皮筋类
    m_RectTracker.m_nStyle=CRectTracker::resizeInside|CRectTracker::dottedLine;
    m_RectTracker.m_rect.SetRect(-1,-1,-1,-1);
/cpp]

获取屏幕分辨率  截取屏幕到位图中 获取要更新的区域 和设置鼠标为彩色等一系列活动。具体看源代码。

最核心的一个函数就是拷贝屏幕 源代码如下



HBITMAP CScreenSpyDlg::CopyScreenToBitmap(LPRECT lpRect,BOOL bSave)
//lpRect 代表选定区域
{
    HDC       hScrDC, hMemDC;      
    // 屏幕和内存设备描述表
    HBITMAP    hBitmap, hOldBitmap;   
    // 位图句柄
    int       nX, nY, nX2, nY2;      
    // 选定区域坐标
    int       nWidth, nHeight;
    
    // 确保选定区域不为空矩形
    if (IsRectEmpty(lpRect))
        return NULL;
    //为屏幕创建设备描述表
    hScrDC = CreateDC(L"DISPLAY", NULL, NULL, NULL);


    //为屏幕设备描述表创建兼容的内存设备描述表
    hMemDC = CreateCompatibleDC(hScrDC);
    // 获得选定区域坐标
    nX = lpRect->left;
    nY = lpRect->top;
    nX2 = lpRect->right;
    nY2 = lpRect->bottom;


    //确保选定区域是可见的
    if (nX < 0)
        nX = 0;
    if (nY < 0)
        nY = 0;
    if (nX2 > m_xScreen)
        nX2 = m_xScreen;
    if (nY2 > m_yScreen)
        nY2 = m_yScreen;
    nWidth = nX2 - nX;
    nHeight = nY2 - nY;
    // 创建一个与屏幕设备描述表兼容的位图
    hBitmap = CreateCompatibleBitmap
        (hScrDC, nWidth, nHeight);
    // 把新位图选到内存设备描述表中
    hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);
    // 把屏幕设备描述表拷贝到内存设备描述表中
    if(bSave)
    {
        CDC dcCompatible;
        dcCompatible.CreateCompatibleDC(CDC::FromHandle(hMemDC));
        dcCompatible.SelectObject(m_pBitmap);
        
        BitBlt(hMemDC, 0, 0, nWidth, nHeight,
            dcCompatible, nX, nY, SRCCOPY);
    }
    else
    {
        BitBlt(hMemDC, 0, 0, nWidth, nHeight,
            hScrDC, nX, nY, SRCCOPY);
    }
    hBitmap = (HBITMAP)SelectObject(hMemDC, hOldBitmap);
    //得到屏幕位图的句柄
    //清除 
    DeleteDC(hScrDC);
    DeleteDC(hMemDC);
    // 返回位图句柄
    if(bSave)
    {
                
        if (OpenClipboard()) 
        {
        //清空剪贴板
        EmptyClipboard();
        //把屏幕内容粘贴到剪贴板上,
        //hBitmap 为刚才的屏幕位图句柄
        SetClipboardData(CF_BITMAP, hBitmap);
        //关闭剪贴板
        CloseClipboard();
      }
    }
    return hBitmap;
}

这里就完成了截取屏幕到剪切板的操作。
还有一点可能是我们这种菜鸟犯晕的地方,就是它如何做到在屏幕上画出一个虚线框的。这一点,实际上它是通过设置透明窗体实现的。所以看上去像是直接在桌面上画图。这个方法是一开始初始化就调用

CopyScreenToBitmap 这个函数 获取整个屏幕//截取屏幕到位图中

然后处理 WM_ERASEBKGND 消息 将获取到的屏幕设置为背景。所以看上去似乎是在桌面绘图。

m_pBitmap=CBitmap::FromHandle(CopyScreenToBitmap(&rect));
BOOL CScreenSpyDlg::OnEraseBkgnd(CDC* pDC) 
{
    BITMAP bmp;
    m_pBitmap->GetBitmap(&bmp);


    CDC dcCompatible;
    dcCompatible.CreateCompatibleDC(pDC);


    dcCompatible.SelectObject(m_pBitmap);


    CRect rect;
    GetClientRect(&rect);
    pDC->BitBlt(0,0,rect.Width(),rect.Height(),&dcCompatible,0,0,SRCCOPY);


    return TRUE;
}

模仿QQ2012截屏工具 QQScrSpy 2012_05_10

最后编辑:
作者:leehom
leehom
本博客主要是把自己的经验记录于此,方便自己以后查阅及其他遇到类似问题的朋友参考。如果你有觉得不错的文章,可以注册会员发布文章或者邮箱发给我文章地址,谢谢!
捐 赠如果觉得文章还不错,请麻烦点下广告,算是赞助下本站服务器费用,谢谢!

留下一个回复