VC编程实现交互式截屏的MFC DLL(一)

2012-03-19 20:42:56|?次阅读|上传:wustguangh【已有?条评论】发表评论

关键词:C/C++, MFC, 操作系统, 图形/图像|来源:唯设编程网

在实际项目中,经常会用到截屏的功能,于是自己使用VC编写了一个实现截屏功能的MFC DLL,以备随时可以使用。该项目实现了屏幕指定区域截图、全屏用户交互式截图、保存截图结果到位图(BMP)文件等功能,下面分步骤详细介绍具体的设计方案和实现代码。

首先显示程序的运行效果:

VC实现交互式屏幕截图

1. 创建一个名称为ScreenSnap的MFC DLL项目到解决方案中,DLL类型选择MFC扩展DLL;

2. 在项目ScreenSnap中创建类ScreenShutter,用于提供用户调用屏幕截图操作的接口。该类主要实现屏幕截图的基本功能:保存屏幕截图到位图(BMP)文件、返回指定范围的截图、返回截图的完整区域位图。

2.1 屏幕截图导出类CScreenShutter类的申明:

示例:

class AFX_EXT_CLASS CScreenShutter
{
private:    
    CDC ScrDC;    //显示器DC    
public:
    CBitmap* m_pBitmap;//存储背景图片(成员变量)
public:
    CScreenShutter(void);
    ~CScreenShutter(void);
    // 保存m_pBackBitmap中储存的位图数据到磁盘文件中
    BOOL SaveBitmapToFile(LPCWSTR lpFileName);
    // 截图屏幕指定区域
    // 结果保存在成员变量m_pBackBitmap中
    CScreenShutter* getScreenBitmap(POINT pt1,POINT pt2);
    // 截图屏幕完整区域
    // 结果保存在成员变量m_pBackBitmap中
    CScreenShutter* getScreenBitmap();
};

备注:在CScreenShutter前面增加AFX_EXT_CLASS使该类为DLL的导出类。

2.2 首先定义屏幕截图导出类CScreenShutter的构造和析构函数:

示例:

CScreenShutter::CScreenShutter(void)
:m_pBitmap(NULL)
{    
            
}

CScreenShutter::~CScreenShutter(void)
{
    //清除位图资源
    if (m_pBitmap != NULL)
    {
        delete m_pBitmap;
        m_pBitmap = NULL;
    }    
}

2.3 保存截图数据到磁盘位图(BMP)文件的成员函数SaveBitmapToFile定义:

示例:

// 把Cbitmap对象保存到文件中
// lpFileName       为位图文件名
BOOL CScreenShutter::SaveBitmapToFile(LPCWSTR lpFileName)    
{                        
    //设备描述表
    HDC hDC;
    //当前分辨率下每象素所占字节数
    int iBits;
    //位图中每象素所占字节数
    WORD wBitCount;
    //定义调色板大小, 位图中像素字节大小 ,位图文件大小 , 写入文件字节数
    DWORD dwPaletteSize=0, dwBmBitsSize=0, dwDIBSize=0, dwWritten=0;
    //位图属性结构
    BITMAP Bitmap;  
    //位图文件头结构
    BITMAPFILEHEADER bmfHdr;  
    //位图信息头结构
    BITMAPINFOHEADER bi;  
    //指向位图信息头结构  
    LPBITMAPINFOHEADER lpbi;  
    //定义文件,分配内存句柄,调色板句柄
    HANDLE fh, hDib, hPal,hOldPal=NULL;

    //计算位图文件每个像素所占字节数
    hDC = CreateDC(_T("DISPLAY"), NULL, NULL, NULL);
    iBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES);
    DeleteDC(hDC);
    if (iBits <= 1) wBitCount = 1;
    else if (iBits <= 4) wBitCount = 4;
    else if (iBits <= 8) wBitCount = 8;
    else wBitCount = 24;

    GetObject(*m_pBitmap, sizeof(Bitmap), (LPSTR)&Bitmap);
    bi.biSize = sizeof(BITMAPINFOHEADER);
    bi.biWidth = Bitmap.bmWidth;
    bi.biHeight = Bitmap.bmHeight;
    bi.biPlanes = 1;
    bi.biBitCount = wBitCount;
    bi.biCompression = BI_RGB;
    bi.biSizeImage = 0;
    bi.biXPelsPerMeter = 0;
    bi.biYPelsPerMeter = 0;
    bi.biClrImportant = 0;
    bi.biClrUsed = 0;

    dwBmBitsSize = ((Bitmap.bmWidth * wBitCount + 31) / 32) * 4 * Bitmap.bmHeight;

    //为位图内容分配内存
    hDib = GlobalAlloc(GHND,dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER));
    if(hDib==NULL)
        return false;
    lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);
    *lpbi = bi;

    // 处理调色板  
    hPal = GetStockObject(DEFAULT_PALETTE);
    if (hPal)
    {
        hDC = ::GetDC(NULL);
        hOldPal = ::SelectPalette(hDC, (HPALETTE)hPal, FALSE);
        RealizePalette(hDC);
    }

    // 获取该调色板下新的像素值
    GetDIBits(hDC, *m_pBitmap, 0, (UINT) Bitmap.bmHeight, (LPSTR)lpbi + sizeof(BITMAPINFOHEADER)
        +dwPaletteSize, (BITMAPINFO *)lpbi, DIB_RGB_COLORS);

    //恢复调色板  
    if (hOldPal)
    {
        ::SelectPalette(hDC, (HPALETTE)hOldPal, TRUE);
        RealizePalette(hDC);
        ::ReleaseDC(NULL, hDC);
    }

    //创建位图文件  
    fh = CreateFile(lpFileName, GENERIC_WRITE,0, NULL, CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);

    if (fh == INVALID_HANDLE_VALUE)   return FALSE;

    // 设置位图文件头
    bmfHdr.bfType = 0x4D42; // "BM"
    dwDIBSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmBitsSize;  
    bmfHdr.bfSize = dwDIBSize;
    bmfHdr.bfReserved1 = 0;
    bmfHdr.bfReserved2 = 0;
    bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER) + dwPaletteSize;
    // 写入位图文件头
    WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);
    // 写入位图文件其余内容
    WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &dwWritten, NULL);
    //清除  
    GlobalUnlock(hDib);
    GlobalFree(hDib);
    CloseHandle(fh);

    return TRUE;    
}

该函数将CBitmap类型的成员指针m_pBitmap所指的位图数据保存到磁盘文件,实现了CBitmap保存到磁盘文件的通用方法,实现过程比较麻烦,读者可以在其它项目直接重用该段代码。

2.4 截取屏幕指定区域的位图数据:

// 截图屏幕指定区域
// 结果保存在成员变量m_pBackBitmap中
CScreenShutter* CScreenShutter::getScreenBitmap(POINT pt1,POINT pt2){        
    //NEW资源(调用一次重新拷贝一次)
    if (m_pBitmap != NULL)
    {
        delete m_pBitmap;
        m_pBitmap = NULL;
    }

    m_pBitmap = new CBitmap();

    CDC ScrDC,MemDC;

    ScrDC.CreateDC(_T("DISPLAY"), NULL, NULL, NULL);
    MemDC.CreateCompatibleDC(&ScrDC);

    //创建位图
    m_pBitmap->CreateCompatibleBitmap(&ScrDC,abs(pt1.x-pt2.x),abs(pt1.y-pt2.y));
    
    MemDC.SelectObject(m_pBitmap);
    //拷贝屏幕的区域到创建的位图中
    int minX=pt1.x<pt2.x?pt1.x:pt2.x;
    int minY=pt1.y<pt2.y?pt1.y:pt2.y;
    MemDC.BitBlt(0, 0, abs(pt1.x-pt2.x), abs(pt1.y-pt2.y),&ScrDC,minX, minY,SRCCOPY);

    ScrDC.DeleteDC();
    MemDC.DeleteDC();
    return this;
}

该函数使用设备描述表CDC实现屏幕截图,并将截图结果保存在pBitmap所指的位图存储空间中。调用CreateDC创建一个特定的设备描述表,调用CBitmap的成员函数CreateCompatibleBitmap初始化与对应设备描述表兼容的位图到m_pBitmap所指的位图空间。最后调用BitBlt实现将ScrDC设备描述表指定区域的位图拷贝到MemDC设备描述表。

2.5 实现用户交互式全屏截图

// 交互式截图
// 结果保存在成员变量m_pBackBitmap中
CScreenShutter* CScreenShutter::getScreenBitmap(){    
    //显示位图
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    CScreenSnapDlg dlg(m_pBitmap);
    dlg.DoModal();    
    return this;
}

特别注意:由于在MFC扩展DLL中使用了自定义的对话框类,在调用前请添加语句

AFX_MANAGE_STATE(AfxGetStaticModuleState());

该类调用屏幕截图对话框CScreenSnapDlg实现全屏用户交互式截图,限于篇幅,CScreenSnapDlg类我们将在下一篇文章中进行介绍。

发表评论0条 】
网友评论(共?条评论)..
VC编程实现交互式截屏的MFC DLL(一)