VC进行屏幕截取编程
潘小龙 顾时明

屏幕截取是令人比较感兴趣的事情.虽然现在有不少应用程序如HYPERSNAP等可以用来截取你所喜欢的屏幕画面,但是如果能把这个功能加到自己的程序中,就更能利用它强大的作用.

下面用VC来逐步介绍在Windows95下的实现过程.首先我们要确定屏幕截取的区域,LPRECT结构来定义.可以截取一个窗口,或整个屏幕.以下代码把选定的屏幕区域拷贝到位图中.

HBITMAP CopyScreenToBitmap(LPRECT lpRect)

 

 //lpRect 代表选定区域

 

{

 

HDC       hScrDC, hMemDC;     

 

 // 屏幕和内存设备描述表

 

HBITMAP    hBitmap, hOldBitmap;  

 

 // 位图句柄

 

int       nX, nY, nX2, nY2;     

 

// 选定区域坐标

 

int       nWidth, nHeight;     

 

// 位图宽度和高度

 

int       xScrn, yScrn;        

 

// 屏幕分辨率

 

 

 

   // 确保选定区域不为空矩形

 

   if (IsRectEmpty(lpRect))

 

     return NULL;

 

   //为屏幕创建设备描述表

 

   hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL);

 

   //为屏幕设备描述表创建兼容的内存设备描述表

 

   hMemDC = CreateCompatibleDC(hScrDC);

 

   // 获得选定区域坐标

 

   nX = lpRect- >left;

 

   nY = lpRect- >top;

 

   nX2 = lpRect- >right;

 

   nY2 = lpRect- >bottom;

 

   // 获得屏幕分辨率

 

   xScrn = GetDeviceCaps(hScrDC, HORZRES);

 

   yScrn = GetDeviceCaps(hScrDC, VERTRES);

 

   //确保选定区域是可见的

 

   if (nX < 0)

 

      nX = 0;

 

   if (nY < 0)

 

      nY = 0;

 

   if (nX2 > xScrn)

 

      nX2 = xScrn;

 

   if (nY2 > yScrn)

 

      nY2 = yScrn;

 

   nWidth = nX2 - nX;

 

   nHeight = nY2 - nY;

 

   // 创建一个与屏幕设备描述表兼容的位图

 

hBitmap = CreateCompatibleBitmap

 

 (hScrDC, nWidth, nHeight);

 

   // 把新位图选到内存设备描述表中

 

   hOldBitmap = SelectObject(hMemDC, hBitmap);

 

   // 把屏幕设备描述表拷贝到内存设备描述表中

 

BitBlt(hMemDC, 0, 0, nWidth, nHeight,

 

 hScrDC, nX, nY, SRCCOPY);

 

   //得到屏幕位图的句柄

 

   hBitmap = SelectObject(hMemDC, hOldBitmap);

 

   //清除

 

   DeleteDC(hScrDC);

 

   DeleteDC(hMemDC);

 

   // 返回位图句柄

 

   return hBitmap;

 

}

 

  

 

得到屏幕位图句柄以后,我们

 

可以把屏幕内容粘贴到剪贴板上.

 

    if (OpenClipboard(hWnd))

 

     //hWnd为程序窗口句柄

 

      {

 

        //清空剪贴板

 

        EmptyClipboard();

 

        //把屏幕内容粘贴到剪贴板上,

 

        hBitmap 为刚才的屏幕位图句柄

 

        SetClipboardData(CF_BITMAP, hBitmap);

 

        //关闭剪贴板

 

        CloseClipboard();

 

      }

 

   我们也可以把屏幕内容以位图格式存到磁盘文件上.

 

     

 

int SaveBitmapToFile(HBITMAP hBitmap ,

 

        LPSTR lpFileName) //hBitmap 为刚才的屏幕位图句柄

 

{        //lpFileName 为位图文件名

 

        HDC            hDC;        

 

         //设备描述表

 

      int            iBits;      

 

        //当前显示分辨率下每个像素所占字节数

 

        WORD            wBitCount;  

 

        //位图中每个像素所占字节数

 

      //定义调色板大小, 位图中像素字节大小 ,

 

      位图文件大小 , 写入文件字节数

 

        DWORD           dwPaletteSize=0,

 

                               dwBmBitsSize,

 

                                dwDIBSize, dwWritten;

 

        BITMAP          Bitmap;       

 

        //位图属性结构

 

        BITMAPFILEHEADER   bmfHdr;       

 

        //位图文件头结构

 

      BITMAPINFOHEADER   bi;           

 

        //位图信息头结构

 

        LPBITMAPINFOHEADER lpbi;         

 

        //指向位图信息头结构

 

      HANDLE          fh, hDib, hPal,hOldPal=NULL;

 

        //定义文件,分配内存句柄,调色板句柄

 

 

 

   //计算位图文件每个像素所占字节数

 

   hDC = CreateDC("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 if (iBits < = 24)

 

      wBitCount = 24;

 

   //计算调色板大小

 

   if (wBitCount < = 8)

 

      dwPaletteSize = (1 < <  wBitCount) *

 

      sizeof(RGBQUAD);

 

  

 

   //设置位图信息头结构

 

   GetObject(hBitmap, 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.biClrUsed         = 0;

 

   bi.biClrImportant      = 0;

 

 

 

   dwBmBitsSize = ((Bitmap.bmWidth *

 

    wBitCount+31)/32)* 4

 

         *Bitmap.bmHeight ;

 

   //为位图内容分配内存

 

   hDib  = GlobalAlloc(GHND,dwBmBitsSize+

 

        dwPaletteSize+sizeof(BITMAPINFOHEADER));

 

   lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);

 

   *lpbi = bi;

 

   // 处理调色板  

 

   hPal = GetStockObject(DEFAULT_PALETTE);

 

   if (hPal)

 

   {

 

      hDC  = GetDC(NULL);

 

      hOldPal = SelectPalette(hDC, hPal, FALSE);

 

      RealizePalette(hDC);

 

   }

 

   // 获取该调色板下新的像素值

 

   GetDIBits(hDC, hBitmap, 0, (UINT) Bitmap.bmHeight,

 

         (LPSTR)lpbi + sizeof(BITMAPINFOHEADER)

 

    +dwPaletteSize,

 

         (BITMAPINFOHEADER *)

 

    lpbi, DIB_RGB_COLORS);

 

   //恢复调色板  

 

   if (hOldPal)

 

   {

 

      SelectPalette(hDC, 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);

 

}