您的位置:首页 > 编程语言 > C语言/C++

基于visual c++之windows核心编程代码分析(11)实现屏幕截取

2016-12-08 21:54 926 查看
我们在进行Windows编程的时候,经常需要进行屏幕截取,我们来实现截取屏幕,不依赖MFC来实现屏幕截取。请见代码实现与注释讲解

 

 

 

[cpp] view
plain copy

/* 头文件 */  

#include <windows.h>  

/* 常量定义 */  

#define PALVERSION 0x300  

#define CAP_SHOW_MODE_STRTCH 1  

#define CAP_SHOW_MODE_NOSTRTCH 0  

  

/* 全局变量 */  

HBITMAP ghBitmap = NULL;  

RECT rectShow;  

// 修改这里截取不同的窗口,如果为NULL,则截取屏幕  

LPSTR szCaptureWindowName = "Windows 任务管理器";  

  

/* 函数申明 */  

LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);  

HBITMAP ScreenCapture(LPSTR filename ,WORD BitCount,LPRECT lpRect);  

VOID DoPaint(HWND hWnd, DWORD dwMode);  

  

/************************************* 

* DWORD WINAPI WinMain(HINSTANCE hinstance, 

HINSTANCE hPrevInstance, 

LPSTR lpCmdLine, 

int nCmdShow) 

* 功能 截屏,保存为文件,并显示在窗口上 



**************************************/  

INT WINAPI WinMain(HINSTANCE hinstance,  

                     HINSTANCE hPrevInstance,  

                     LPSTR lpCmdLine,  

                     int nCmdShow)  

{  

    WNDCLASSEX wcx;  

    HWND hwnd;  

    MSG msg;  

    WORD wport = 80;  

    BOOL fGotMessage;  

    HWND hwndCap = NULL;  

  

    // 截取全屏幕还是窗口  

    if(szCaptureWindowName != NULL)  

    {  

        hwndCap = FindWindow(NULL,"Windows 任务管理器");  

        // 获取窗口的RECT,可自行修改,获取屏幕中的任意区域  

        if(!GetWindowRect(hwndCap,&rectShow))  

        {  

            MessageBox(NULL,"Can not find window to capture", "erroe",MB_OK);  

            return 0;  

        }  

    }  

    // 注册窗口类,并创建窗口,用于显示截取的位图  

    wcx.cbSize = sizeof(wcx);  

    wcx.style = CS_HREDRAW | CS_VREDRAW;  

    wcx.lpfnWndProc = MainWndProc;  

    wcx.cbClsExtra = 0;  

    wcx.cbWndExtra = 0;  

    wcx.hInstance = hinstance;  

    wcx.hIcon = LoadIcon(NULL,  MAKEINTRESOURCE(IDI_APPLICATION));  

    wcx.hCursor = LoadCursor(NULL,  IDC_ARROW);  

    wcx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);  

    wcx.lpszMenuName = NULL;  

    wcx.lpszClassName = "MainWClass";  

    wcx.hIconSm = NULL;  

  

    if( !RegisterClassEx(&wcx))  

        return 1;  

    // 创建窗口  

    hwnd = CreateWindow(  

        "MainWClass",  

        "CAP",  

        WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |  

        WS_MAXIMIZE | WS_POPUPWINDOW,  

        CW_USEDEFAULT,  CW_USEDEFAULT,  CW_USEDEFAULT,  CW_USEDEFAULT,  

        (HWND) NULL,    (HMENU) NULL,   hinstance, (LPVOID) NULL);  

  

    if (!hwnd)  

        return 1;  

  

    // 截取屏幕,可根据需要设置不同的参数,这里只演示截取特定窗口。  

    ghBitmap = ScreenCapture("taskmgr.bmp" ,32, &rectShow);  

    // 显示  

    ShowWindow(hwnd, nCmdShow);  

    UpdateWindow(hwnd);  

  

    while ((fGotMessage = GetMessage(&msg, (HWND) NULL, 0, 0)) != 0 && fGotMessage != -1)  

    {  

        TranslateMessage(&msg);  

        DispatchMessage(&msg);  

    }  

    return msg.wParam;  

    UNREFERENCED_PARAMETER(lpCmdLine);  

}  

  

LRESULT CALLBACK MainWndProc(  

                             HWND hwnd,  

                             UINT uMsg,  

                             WPARAM wParam,  

                             LPARAM lParam)  

{  

    switch (uMsg)  

    {  

    case WM_PAINT:  

        // 显示截取的屏幕  

        DoPaint(hwnd,CAP_SHOW_MODE_STRTCH);  

        break;  

    case WM_DESTROY:  

        // 创建的BITMAP对象需要删除,以释放资源  

        DeleteObject(ghBitmap);  

        ExitProcess(0);  

        break;  

    default:  

        break;  

    }  

    return DefWindowProc(hwnd, uMsg, wParam, lParam);  

}  

  

/************************************* 

* VOID DoPaint(HWND hWnd, DWORD dwMode) 

* 功能 将位图(全局变量ghBitmap)显示在界面上 



* 参数 HWND hWnd,用于显示位图的窗口 

* DWORD dwMode,模式,是否拉申 



* 无返回值 

**************************************/  

VOID DoPaint(HWND hWnd, DWORD dwMode)  

{  

    PAINTSTRUCT ps;  

    RECT rect;  

    HDC hdcMem;  

    BITMAP bm;  

    // BeginPaint  

    HDC hDC = BeginPaint(hWnd, &ps);  

    // 获取窗口的Client区域,用于显示位图  

    GetClientRect(hWnd, &rect);  

  

    // 设置拉申模式  

    SetStretchBltMode(hDC, HALFTONE);  

    // 将BITMAP对象选择入内存DC  

    hdcMem = CreateCompatibleDC(hDC);  

    SelectObject(hdcMem, ghBitmap);  

    if (ghBitmap)  

    {  

        // 获取DIB属性  

        if (GetObject(ghBitmap, sizeof(BITMAP), &bm))  

        {  

            // 判断参数示:是否根据显示窗口大小拉申位图  

            // 采用不同的方面将内存DC StretchBl t至窗口Client区域DC  

            if(dwMode == CAP_SHOW_MODE_STRTCH)  

            {  

                StretchBlt(hDC, 0, 0, rect.right, rect.bottom,  

                    hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);  

            }  

            else  

            {  

                // 不拉伸,计算显示的位置,将其显示在Client的中央  

                INT ixStart = (rect.right - rect.left - bm.bmWidth)/2;  

                INT iyStart = (rect.bottom - rect.top - bm.bmHeight)/2;  

                ixStart = ixStart < 0 ? 0 : ixStart;  

                iyStart = iyStart < 0 ? 0 : iyStart;  

                BitBlt(hDC, 0, 0, rect.right, rect.bottom,  

                    hdcMem,-ixStart,-iyStart, SRCCOPY);  

            }  

            DeleteDC(hdcMem);  

        }  

    }  

    // 如果没有位图,则使用Brush填充  

    else  

    {  

        PatBlt(hDC, 0, 0, rect.right, rect.bottom, BLACKNESS);  

    }  

    // EndPaint  

    EndPaint(hWnd, &ps);  

}  

  

/************************************* 

* BITMAP ScreenCapture(LPSTR filename ,WORD BitCount,LPRECT lpRect); 

* 功能 截取指定区域的屏幕,并保存为文件 



* 参数    LPSTR filename 保存位图文件的文件路径,如果为NULL,则不保存 

*       WORD BitCount Bit深度,用于表示一个像素点所使用的数据长度 

*       LPRECT lpRect 所需截取的屏幕区域,如果为NULL,则获取全屏幕 



* 返回 HBITMAP 所截取的位图对象 

**************************************/  

HBITMAP ScreenCapture(LPSTR filename ,WORD BitCount,LPRECT lpRect)  

{  

    HBITMAP hBitmap;  

    // 显示器屏幕DC  

    HDC hScreenDC = CreateDC("DISPLAY", NULL, NULL, NULL);  

    HDC hmemDC = CreateCompatibleDC(hScreenDC);  

    // 显示器屏幕的宽和高  

    int ScreenWidth = GetDeviceCaps(hScreenDC, HORZRES);  

    int ScreenHeight = GetDeviceCaps(hScreenDC, VERTRES);  

    // 旧的BITMAP,用于与所需截取的位置交换  

    HBITMAP hOldBM;  

    // 保存位图数据  

    PVOID lpvpxldata;  

    // 截屏获取的长宽及起点  

    INT ixStart;  

    INT iyStart;  

    INT iX;  

    INT iY;  

    // 位图数据大小  

    DWORD dwBitmapArraySize;  

    // 几个大小  

    DWORD nBitsOffset;  

    DWORD lImageSize ;  

    DWORD lFileSize ;  

    // 位图信息头  

    BITMAPINFO bmInfo;  

    // 位图文件头  

    BITMAPFILEHEADER bmFileHeader;  

    // 写文件用  

    HANDLE hbmfile;  

    DWORD dwWritten;  

  

    // 如果LPRECT 为NULL 截取整个屏幕  

    if(lpRect == NULL)  

    {  

        ixStart = iyStart = 0;  

        iX = ScreenWidth;  

        iY =ScreenHeight;  

    }  

    else  

    {  

        ixStart = lpRect->left;  

        iyStart = lpRect->top;  

        iX = lpRect->right - lpRect->left;  

        iY = lpRect->bottom - lpRect->top;  

    }  

    // 创建BTIMAP  

    hBitmap = CreateCompatibleBitmap(hScreenDC, iX, iY);  

    // 将BITMAP选择入内存DC。  

    hOldBM = (HBITMAP)SelectObject(hmemDC, hBitmap);  

    // BitBlt屏幕DC到内存DC,根据所需截取的获取设置参数  

    BitBlt(hmemDC, 0, 0, iX, iY, hScreenDC, ixStart, iyStart, SRCCOPY);  

    // 将旧的BITMAP对象选择回内存DC,返回值为被替换的对象,既所截取的位图  

    hBitmap = (HBITMAP)SelectObject(hmemDC, hOldBM);  

    if(filename == NULL)  

    {  

        DeleteDC( hScreenDC);  

        DeleteDC(hmemDC);  

        return hBitmap;  

    }  

    // 为位图数据申请内存空间  

    dwBitmapArraySize = ((((iX*32) + 31) & ~31)>> 3)* iY;  

    lpvpxldata = HeapAlloc(GetProcessHeap(),HEAP_NO_SERIALIZE,dwBitmapArraySize);  

    ZeroMemory(lpvpxldata,dwBitmapArraySize);  

  

    // 添充 BITMAPINFO 结构  

    ZeroMemory(&bmInfo,sizeof(BITMAPINFO));  

    bmInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);  

    bmInfo.bmiHeader.biWidth = iX;  

    bmInfo.bmiHeader.biHeight = iY;  

    bmInfo.bmiHeader.biPlanes = 1;  

    bmInfo.bmiHeader.biBitCount = BitCount;  

    bmInfo.bmiHeader.biCompression = BI_RGB;  

  

    // 添充 BITMAPFILEHEADER 结构  

    ZeroMemory(&bmFileHeader,sizeof(BITMAPFILEHEADER));  

    nBitsOffset = sizeof(BITMAPFILEHEADER) + bmInfo.bmiHeader.biSize;  

    lImageSize =  

        ((((bmInfo.bmiHeader.biWidth * bmInfo.bmiHeader.biBitCount) + 31) & ~31)>> 3)  

        * bmInfo.bmiHeader.biHeight;  

    lFileSize = nBitsOffset + lImageSize;  

    bmFileHeader.bfType = 'B'+('M'<<8);  

    bmFileHeader.bfSize = lFileSize;  

    bmFileHeader.bfOffBits = nBitsOffset;  

  

    // 获取DIB用于写入到文件  

    GetDIBits(hmemDC, hBitmap, 0, bmInfo.bmiHeader.biHeight,  

        lpvpxldata, &bmInfo, DIB_RGB_COLORS);  

    // 写文件  

    hbmfile = CreateFile(filename,  

        GENERIC_WRITE,  

        FILE_SHARE_WRITE,  

        NULL,  

        CREATE_ALWAYS,  

        FILE_ATTRIBUTE_NORMAL,  

        NULL);  

  

    if(hbmfile == INVALID_HANDLE_VALUE)  

    {  

        MessageBox(NULL,"create file error","error",MB_OK);  

    }  

  

    WriteFile(hbmfile,&bmFileHeader,sizeof(BITMAPFILEHEADER),&dwWritten,NULL);  

    WriteFile(hbmfile,&bmInfo,sizeof(BITMAPINFO),&dwWritten,NULL);  

    WriteFile(hbmfile,lpvpxldata,lImageSize,&dwWritten,NULL);  

    CloseHandle(hbmfile);  

  

    // 释放内存,清除不同的DC。  

    // 这里没有删除BITMAP对象,需在显示完成后删除  

    HeapFree(GetProcessHeap(),HEAP_NO_SERIALIZE,lpvpxldata);  

    ReleaseDC(0, hScreenDC);  

    DeleteDC(hmemDC);     

    return hBitmap;  

}  



 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐