Windows实现屏幕截取

我们在进行Windows编程的时候,经常需要进行屏幕截取,我们来实现截取屏幕,不依赖MFC来实现屏幕截取。请见代码实现与注释讲解

源自: http://blog.csdn.net/yincheng01/article/details/7079602 

 view plainprint?

  1. /* 头文件 */  
  2. #include <windows.h>  
  3. /* 常量定义 */  
  4. #define PALVERSION 0x300  
  5. #define CAP_SHOW_MODE_STRTCH 1  
  6. #define CAP_SHOW_MODE_NOSTRTCH 0  
  7.   
  8. /* 全局变量 */  
  9. HBITMAP ghBitmap = NULL;  
  10. RECT rectShow;  
  11. // 修改这里截取不同的窗口,如果为NULL,则截取屏幕  
  12. LPSTR szCaptureWindowName = "Windows 任务管理器";  
  13.   
  14. /* 函数申明 */  
  15. LRESULT CALLBACK MainWndProc(HWNDUINTWPARAMLPARAM);  
  16. HBITMAP ScreenCapture(LPSTR filename ,WORD BitCount,LPRECT lpRect);  
  17. VOID DoPaint(HWND hWnd, DWORD dwMode);  
  18.   
  19. /************************************* 
  20. * DWORD WINAPI WinMain(HINSTANCE hinstance, 
  21. HINSTANCE hPrevInstance, 
  22. LPSTR lpCmdLine, 
  23. int nCmdShow) 
  24. * 功能 截屏,保存为文件,并显示在窗口上 
  25. * 
  26. **************************************/  
  27. INT WINAPI WinMain(HINSTANCE hinstance,  
  28.                      HINSTANCE hPrevInstance,  
  29.                      LPSTR lpCmdLine,  
  30.                      int nCmdShow)  
  31. {  
  32.     WNDCLASSEX wcx;  
  33.     HWND hwnd;  
  34.     MSG msg;  
  35.     WORD wport = 80;  
  36.     BOOL fGotMessage;  
  37.     HWND hwndCap = NULL;  
  38.   
  39.     // 截取全屏幕还是窗口  
  40.     if(szCaptureWindowName != NULL)  
  41.     {  
  42.         hwndCap = FindWindow(NULL,"Windows 任务管理器");  
  43.         // 获取窗口的RECT,可自行修改,获取屏幕中的任意区域  
  44.         if(!GetWindowRect(hwndCap,&rectShow))  
  45.         {  
  46.             MessageBox(NULL,"Can not find window to capture""erroe",MB_OK);  
  47.             return 0;  
  48.         }  
  49.     }  
  50.     // 注册窗口类,并创建窗口,用于显示截取的位图  
  51.     wcx.cbSize = sizeof(wcx);  
  52.     wcx.style = CS_HREDRAW | CS_VREDRAW;  
  53.     wcx.lpfnWndProc = MainWndProc;  
  54.     wcx.cbClsExtra = 0;  
  55.     wcx.cbWndExtra = 0;  
  56.     wcx.hInstance = hinstance;  
  57.     wcx.hIcon = LoadIcon(NULL,  MAKEINTRESOURCE(IDI_APPLICATION));  
  58.     wcx.hCursor = LoadCursor(NULL,  IDC_ARROW);  
  59.     wcx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);  
  60.     wcx.lpszMenuName = NULL;  
  61.     wcx.lpszClassName = "MainWClass";  
  62.     wcx.hIconSm = NULL;  
  63.   
  64.     if( !RegisterClassEx(&wcx))  
  65.         return 1;  
  66.     // 创建窗口  
  67.     hwnd = CreateWindow(  
  68.         "MainWClass",  
  69.         "CAP",  
  70.         WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |  
  71.         WS_MAXIMIZE | WS_POPUPWINDOW,  
  72.         CW_USEDEFAULT,  CW_USEDEFAULT,  CW_USEDEFAULT,  CW_USEDEFAULT,  
  73.         (HWND) NULL,    (HMENU) NULL,   hinstance, (LPVOID) NULL);  
  74.   
  75.     if (!hwnd)  
  76.         return 1;  
  77.   
  78.     // 截取屏幕,可根据需要设置不同的参数,这里只演示截取特定窗口。  
  79.     ghBitmap = ScreenCapture("taskmgr.bmp" ,32, &rectShow);  
  80.     // 显示  
  81.     ShowWindow(hwnd, nCmdShow);  
  82.     UpdateWindow(hwnd);  
  83.   
  84.     while ((fGotMessage = GetMessage(&msg, (HWND) NULL, 0, 0)) != 0 && fGotMessage != -1)  
  85.     {  
  86.         TranslateMessage(&msg);  
  87.         DispatchMessage(&msg);  
  88.     }  
  89.     return msg.wParam;  
  90.     UNREFERENCED_PARAMETER(lpCmdLine);  
  91. }  
  92.   
  93. LRESULT CALLBACK MainWndProc(  
  94.                              HWND hwnd,  
  95.                              UINT uMsg,  
  96.                              WPARAM wParam,  
  97.                              LPARAM lParam)  
  98. {  
  99.     switch (uMsg)  
  100.     {  
  101.     case WM_PAINT:  
  102.         // 显示截取的屏幕  
  103.         DoPaint(hwnd,CAP_SHOW_MODE_STRTCH);  
  104.         break;  
  105.     case WM_DESTROY:  
  106.         // 创建的BITMAP对象需要删除,以释放资源  
  107.         DeleteObject(ghBitmap);  
  108.         ExitProcess(0);  
  109.         break;  
  110.     default:  
  111.         break;  
  112.     }  
  113.     return DefWindowProc(hwnd, uMsg, wParam, lParam);  
  114. }  
  115.   
  116. /************************************* 
  117. * VOID DoPaint(HWND hWnd, DWORD dwMode) 
  118. * 功能 将位图(全局变量ghBitmap)显示在界面上 
  119. * 
  120. * 参数 HWND hWnd,用于显示位图的窗口 
  121. * DWORD dwMode,模式,是否拉申 
  122. * 
  123. * 无返回值 
  124. **************************************/  
  125. VOID DoPaint(HWND hWnd, DWORD dwMode)  
  126. {  
  127.     PAINTSTRUCT ps;  
  128.     RECT rect;  
  129.     HDC hdcMem;  
  130.     BITMAP bm;  
  131.     // BeginPaint  
  132.     HDC hDC = BeginPaint(hWnd, &ps);  
  133.     // 获取窗口的Client区域,用于显示位图  
  134.     GetClientRect(hWnd, &rect);  
  135.   
  136.     // 设置拉申模式  
  137.     SetStretchBltMode(hDC, HALFTONE);  
  138.     // 将BITMAP对象选择入内存DC  
  139.     hdcMem = CreateCompatibleDC(hDC);  
  140.     SelectObject(hdcMem, ghBitmap);  
  141.     if (ghBitmap)  
  142.     {  
  143.         // 获取DIB属性  
  144.         if (GetObject(ghBitmap, sizeof(BITMAP), &bm))  
  145.         {  
  146.             // 判断参数示:是否根据显示窗口大小拉申位图  
  147.             // 采用不同的方面将内存DC StretchBl t至窗口Client区域DC  
  148.             if(dwMode == CAP_SHOW_MODE_STRTCH)  
  149.             {  
  150.                 StretchBlt(hDC, 0, 0, rect.right, rect.bottom,  
  151.                     hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);  
  152.             }  
  153.             else  
  154.             {  
  155.                 // 不拉伸,计算显示的位置,将其显示在Client的中央  
  156.                 INT ixStart = (rect.right - rect.left - bm.bmWidth)/2;  
  157.                 INT iyStart = (rect.bottom - rect.top - bm.bmHeight)/2;  
  158.                 ixStart = ixStart < 0 ? 0 : ixStart;  
  159.                 iyStart = iyStart < 0 ? 0 : iyStart;  
  160.                 BitBlt(hDC, 0, 0, rect.right, rect.bottom,  
  161.                     hdcMem,-ixStart,-iyStart, SRCCOPY);  
  162.             }  
  163.             DeleteDC(hdcMem);  
  164.         }  
  165.     }  
  166.     // 如果没有位图,则使用Brush填充  
  167.     else  
  168.     {  
  169.         PatBlt(hDC, 0, 0, rect.right, rect.bottom, BLACKNESS);  
  170.     }  
  171.     // EndPaint  
  172.     EndPaint(hWnd, &ps);  
  173. }  
  174.   
  175. /************************************* 
  176. * BITMAP ScreenCapture(LPSTR filename ,WORD BitCount,LPRECT lpRect); 
  177. * 功能 截取指定区域的屏幕,并保存为文件 
  178. * 
  179. * 参数    LPSTR filename 保存位图文件的文件路径,如果为NULL,则不保存 
  180. *       WORD BitCount Bit深度,用于表示一个像素点所使用的数据长度 
  181. *       LPRECT lpRect 所需截取的屏幕区域,如果为NULL,则获取全屏幕 
  182. * 
  183. * 返回 HBITMAP 所截取的位图对象 
  184. **************************************/  
  185. HBITMAP ScreenCapture(LPSTR filename ,WORD BitCount,LPRECT lpRect)  
  186. {  
  187.     HBITMAP hBitmap;  
  188.     // 显示器屏幕DC  
  189.     HDC hScreenDC = CreateDC("DISPLAY", NULL, NULL, NULL);  
  190.     HDC hmemDC = CreateCompatibleDC(hScreenDC);  
  191.     // 显示器屏幕的宽和高  
  192.     int ScreenWidth = GetDeviceCaps(hScreenDC, HORZRES);  
  193.     int ScreenHeight = GetDeviceCaps(hScreenDC, VERTRES);  
  194.     // 旧的BITMAP,用于与所需截取的位置交换  
  195.     HBITMAP hOldBM;  
  196.     // 保存位图数据  
  197.     PVOID lpvpxldata;  
  198.     // 截屏获取的长宽及起点  
  199.     INT ixStart;  
  200.     INT iyStart;  
  201.     INT iX;  
  202.     INT iY;  
  203.     // 位图数据大小  
  204.     DWORD dwBitmapArraySize;  
  205.     // 几个大小  
  206.     DWORD nBitsOffset;  
  207.     DWORD lImageSize ;  
  208.     DWORD lFileSize ;  
  209.     // 位图信息头  
  210.     BITMAPINFO bmInfo;  
  211.     // 位图文件头  
  212.     BITMAPFILEHEADER bmFileHeader;  
  213.     // 写文件用  
  214.     HANDLE hbmfile;  
  215.     DWORD dwWritten;  
  216.   
  217.     // 如果LPRECT 为NULL 截取整个屏幕  
  218.     if(lpRect == NULL)  
  219.     {  
  220.         ixStart = iyStart = 0;  
  221.         iX = ScreenWidth;  
  222.         iY =ScreenHeight;  
  223.     }  
  224.     else  
  225.     {  
  226.         ixStart = lpRect->left;  
  227.         iyStart = lpRect->top;  
  228.         iX = lpRect->right - lpRect->left;  
  229.         iY = lpRect->bottom - lpRect->top;  
  230.     }  
  231.     // 创建BTIMAP  
  232.     hBitmap = CreateCompatibleBitmap(hScreenDC, iX, iY);  
  233.     // 将BITMAP选择入内存DC。  
  234.     hOldBM = (HBITMAP)SelectObject(hmemDC, hBitmap);  
  235.     // BitBlt屏幕DC到内存DC,根据所需截取的获取设置参数  
  236.     BitBlt(hmemDC, 0, 0, iX, iY, hScreenDC, ixStart, iyStart, SRCCOPY);  
  237.     // 将旧的BITMAP对象选择回内存DC,返回值为被替换的对象,既所截取的位图  
  238.     hBitmap = (HBITMAP)SelectObject(hmemDC, hOldBM);  
  239.     if(filename == NULL)  
  240.     {  
  241.         DeleteDC( hScreenDC);  
  242.         DeleteDC(hmemDC);  
  243.         return hBitmap;  
  244.     }  
  245.     // 为位图数据申请内存空间  
  246.     dwBitmapArraySize = ((((iX*32) + 31) & ~31)>> 3)* iY;  
  247.     lpvpxldata = HeapAlloc(GetProcessHeap(),HEAP_NO_SERIALIZE,dwBitmapArraySize);  
  248.     ZeroMemory(lpvpxldata,dwBitmapArraySize);  
  249.   
  250.     // 添充 BITMAPINFO 结构  
  251.     ZeroMemory(&bmInfo,sizeof(BITMAPINFO));  
  252.     bmInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);  
  253.     bmInfo.bmiHeader.biWidth = iX;  
  254.     bmInfo.bmiHeader.biHeight = iY;  
  255.     bmInfo.bmiHeader.biPlanes = 1;  
  256.     bmInfo.bmiHeader.biBitCount = BitCount;  
  257.     bmInfo.bmiHeader.biCompression = BI_RGB;  
  258.   
  259.     // 添充 BITMAPFILEHEADER 结构  
  260.     ZeroMemory(&bmFileHeader,sizeof(BITMAPFILEHEADER));  
  261.     nBitsOffset = sizeof(BITMAPFILEHEADER) + bmInfo.bmiHeader.biSize;  
  262.     lImageSize =  
  263.         ((((bmInfo.bmiHeader.biWidth * bmInfo.bmiHeader.biBitCount) + 31) & ~31)>> 3)  
  264.         * bmInfo.bmiHeader.biHeight;  
  265.     lFileSize = nBitsOffset + lImageSize;  
  266.     bmFileHeader.bfType = 'B'+('M'<<8);  
  267.     bmFileHeader.bfSize = lFileSize;  
  268.     bmFileHeader.bfOffBits = nBitsOffset;  
  269.   
  270.     // 获取DIB用于写入到文件  
  271.     GetDIBits(hmemDC, hBitmap, 0, bmInfo.bmiHeader.biHeight,  
  272.         lpvpxldata, &bmInfo, DIB_RGB_COLORS);  
  273.     // 写文件  
  274.     hbmfile = CreateFile(filename,  
  275.         GENERIC_WRITE,  
  276.         FILE_SHARE_WRITE,  
  277.         NULL,  
  278.         CREATE_ALWAYS,  
  279.         FILE_ATTRIBUTE_NORMAL,  
  280.         NULL);  
  281.   
  282.     if(hbmfile == INVALID_HANDLE_VALUE)  
  283.     {  
  284.         MessageBox(NULL,"create file error","error",MB_OK);  
  285.     }  
  286.   
  287.     WriteFile(hbmfile,&bmFileHeader,sizeof(BITMAPFILEHEADER),&dwWritten,NULL);  
  288.     WriteFile(hbmfile,&bmInfo,sizeof(BITMAPINFO),&dwWritten,NULL);  
  289.     WriteFile(hbmfile,lpvpxldata,lImageSize,&dwWritten,NULL);  
  290.     CloseHandle(hbmfile);  
  291.   
  292.     // 释放内存,清除不同的DC。  
  293.     // 这里没有删除BITMAP对象,需在显示完成后删除  
  294.     HeapFree(GetProcessHeap(),HEAP_NO_SERIALIZE,lpvpxldata);  
  295.     ReleaseDC(0, hScreenDC);  
  296.     DeleteDC(hmemDC);     
  297.     return hBitmap;  
  298. }

你可能感兴趣的:(屏幕截取)