请教 C++屏幕截图

时间:2021-02-03 15:23:05
// pmjt.cpp : 定义应用程序的入口点。
//

#include "stdafx.h"
#include <Windows.h>






int APIENTRY _tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)
{
HDC hDC,hMemDC;
int x,y;
HBITMAP hbmp,holdbmp;
DWORD err;

BOOL b;

    //获取屏幕DC
hDC=::GetDC(NULL);
err=::GetLastError();
//创建一个内存DC
hMemDC=::CreateCompatibleDC(hDC);
err=::GetLastError();
//获取屏幕大小
x=::GetDeviceCaps(hDC,HORZRES);
y=::GetDeviceCaps(hDC,VERTRES);
//x = ::GetSystemMetrics(SM_CXSCREEN);
//y = ::GetSystemMetrics(SM_CYSCREEN);
//创建一个和屏幕DC相同的位图
hbmp = ::CreateCompatibleBitmap(hDC,x,y);
err=::GetLastError();
//把位图选到内存DC中
holdbmp=(HBITMAP)::SelectObject(hMemDC,hbmp);
//把屏幕DC拷贝到内存DC中
b=BitBlt(hMemDC,0,0,x,y,hDC,x,y,SRCCOPY);
//得到位图句柄
hbmp=(HBITMAP)::SelectObject(hMemDC,holdbmp);
      //计算每个像数所占字节数
int ibits;
WORD bitcount;
ibits=GetDeviceCaps(hDC,BITSPIXEL)*GetDeviceCaps(hDC,PLANES);

if (ibits <= 1)
bitcount = 1;
else if (ibits <= 4)
bitcount = 4;
else if (ibits <= 8)
bitcount = 8;
else if (ibits <= 16)
bitcount = 16;
else if (ibits <= 24)
bitcount = 24;
else 
bitcount = 32;
DWORD dwtsbsize=0,dwwritten;//调色板
//计算调色板大小
if (bitcount <= 8)
dwtsbsize = (1 << bitcount) * sizeof(RGBQUAD);


BITMAP bmp; //位图属性结构
BITMAPFILEHEADER bmfhdr; //位图文件头结构
BITMAPINFOHEADER bi; //位图信息头结构
LPBITMAPINFOHEADER lpbi; //指向位图信息头结构
GetObject(hbmp,sizeof(bmp),(LPVOID)&bmp);
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bmp.bmWidth;
bi.biHeight= bmp.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = bitcount;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;

    //位图大小
DWORD dwbitsize;
dwbitsize = ((bmp.bmWidth*bitcount+31)/32)*4*bmp.bmHeight;
//为位图分配内存
HANDLE fh,hdib,hpal,holdpal=NULL;
hdib=VirtualAlloc(NULL,dwbitsize+dwtsbsize+sizeof(BITMAPINFOHEADER),MEM_COMMIT,PAGE_READWRITE);
    lpbi=(LPBITMAPINFOHEADER)hdib;
*lpbi=bi;
// 处理调色板 
hpal=GetStockObject(DEFAULT_PALETTE);
if (hpal)
{
holdpal = SelectPalette(hDC, (HPALETTE)hpal, false);
RealizePalette(hDC);
}
// 获取该调色板下新的像素值
GetDIBits(hDC, hbmp, 0, (UINT) bmp.bmHeight,(LPSTR)lpbi + 
sizeof(BITMAPINFOHEADER)+dwtsbsize,(BITMAPINFO*)lpbi, DIB_RGB_COLORS);
//恢复调色板 
if (holdpal)
{
SelectPalette(hDC, (HPALETTE)holdpal, true);
RealizePalette(hDC);
}

//创建位图文件 
fh = CreateFile("C:\\1.bmp", GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL|
FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (fh == INVALID_HANDLE_VALUE)
return 0;

// 设置位图文件头
bmfhdr.bfType=0x4d42; //"bm"
//位图大小
DWORD dwbmpsize=sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)+ 
dwtsbsize + dwbitsize;
bmfhdr.bfSize=dwbmpsize;
bmfhdr.bfReserved1 = 0;
bmfhdr.bfReserved2 = 0;
bmfhdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + 
(DWORD)sizeof(BITMAPINFOHEADER)+ dwtsbsize;

// 写入位图文件头
WriteFile(fh, (LPSTR)&bmfhdr, sizeof(BITMAPFILEHEADER), &dwwritten, NULL);

// 写入位图文件其余内容
WriteFile(fh, (LPSTR)lpbi, dwbitsize, &dwwritten, NULL);
//清除 
VirtualFree(hdib,dwbitsize+dwtsbsize+sizeof(BITMAPINFOHEADER),MEM_DECOMMIT);


CloseHandle(fh);













MSG msg;
// 主消息循环:
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
 
return 0;
}


//问题:
为什么我保存的图象 是黑屏啊。。。。 没想通  
另外 怎么才能保存成 jpeg格式呢? 现在我保存一张bmp的图 是3M 太大了
如果 我想保存成录象 又该怎么办呢?  现在最主要的是 保存的图象不是黑屏
请各位大虾指点哦。。。。。。

16 个解决方案

#1


holdbmp=(HBITMAP)::SelectObject(hMemDC,hbmp); 
//把屏幕DC拷贝到内存DC中 
b=BitBlt(hMemDC,0,0,x,y,hDC,x,y,SRCCOPY); 
//得到位图句柄 
hbmp=(HBITMAP)::SelectObject(hMemDC,holdbmp);

// 我看了一下 这里会不会有什么问题 我也想不出来 
麻烦各位大虾指点一下啦。。。。

#2


在头文件添加
CBitmap * m_pBitmap;            //背景位图



holdbmp=(HBITMAP)::SelectObject(hMemDC,hbmp);
//把屏幕DC拷贝到内存DC中
b=BitBlt(hMemDC,0,0,x,y,hDC,x,y,SRCCOPY);

//得到位图句柄
hbmp=(HBITMAP)::SelectObject(hMemDC,holdbmp); 

改为

//创建军兼容DC,当bSave为中时把开始保存的全屏位图,按截取矩形大小保存
CDC dcCompatible;
dcCompatible.CreateCompatibleDC(CDC::FromHandle(hMemDC));
dcCompatible.SelectObject(m_pBitmap);   
b=BitBlt(hMemDC, 0, 0, x, y,dcCompatible, x, y, SRCCOPY);

保存m_pBitmap即可!

#3


我没用MFC类库耶。。。。 用CDC的话 就要加 MFC类的头文件啦  程序体积就大啦。。。。

我想用API实现

#4


各位帅歌美女 帮我顶顶贴吧。。。。 别让它沉啦。。。。。。。。

#5


帮顶.

#6


谢谢 兄弟  不过还是希望有高手解决  这样顶也不是办法。。。。。。。。

#7


bi.biSizeImage = 0; 
这个字段没设置。

#8


http://www.handytech.cn/main/ArticleShow_12_2.htm 自己写bmp图的格式很麻烦,用这个方法吧。
http://topic.csdn.net/t/20030517/19/1798130.html 4楼和7楼。

http://topic.csdn.net/t/20050120/10/3739972.html
http://topic.csdn.net/t/20000529/20/10122.html 这两个也可以参考一下。

#9


// 写入位图文件其余内容 
WriteFile(fh, (LPSTR)lpbi, dwbitsize, &dwwritten, NULL); 
=======================================================
dwbitsize没有包含信息头的大小,应该为:
WriteFile(fh, (LPSTR)lpbi, dwbmpsize-sizeof(BITMAPFILEHEADER), &dwwritten, NULL);

WriteFile(fh,(LPSTR)lpbi,sizeof(BITMAPINFOHEADER)+dwtsbsize+dwbitsize,&dwwritten,NULL);

#10


现在的问题是
GetDIBits(hDC, hbmp, 0, (UINT) bmp.bmHeight,(LPSTR)lpbi + 
sizeof(BITMAPINFOHEADER)+dwtsbsize,(BITMAPINFO*)lpbi, DIB_RGB_COLORS); 
得到的数据都是0.

#11


//把屏幕DC拷贝到内存DC中 
b=BitBlt(hMemDC,0,0,x,y,hDC,x,y,SRCCOPY); 
=================================================
问题在这。
BitBlt第7,8两个参数设错了。改为:b=BitBlt(hMemDC,0,0,x,y,hDC,0,0,SRCCOPY);就正确了。

BitBlt原型:
BOOL BitBlt(HDC hdcDest,int nXDest,int nYDest,int nWidth,int nHeight,HDC hdcSrc,int nXSrc,int nYSrc,DWORD dwRop);
//int nXSrc,int nYSrc是源起始坐标。

#12


帮顶起

#13


谢谢

#14


  谢谢 dongpy 你照你说的 改了 就对了  非常感谢 
另外 我还想存成jpeg格式  bmp太大了 有没有思路和方法呢? 还请各位帮助 

#15


MARK

#16


引用 14 楼 pcie7777 的回复:
  谢谢 dongpy 你照你说的 改了 就对了  非常感谢
另外 我还想存成jpeg格式  bmp太大了 有没有思路和方法呢? 还请各位帮助

去sourceforge.net上找个jpeg开源库。

#1


holdbmp=(HBITMAP)::SelectObject(hMemDC,hbmp); 
//把屏幕DC拷贝到内存DC中 
b=BitBlt(hMemDC,0,0,x,y,hDC,x,y,SRCCOPY); 
//得到位图句柄 
hbmp=(HBITMAP)::SelectObject(hMemDC,holdbmp);

// 我看了一下 这里会不会有什么问题 我也想不出来 
麻烦各位大虾指点一下啦。。。。

#2


在头文件添加
CBitmap * m_pBitmap;            //背景位图



holdbmp=(HBITMAP)::SelectObject(hMemDC,hbmp);
//把屏幕DC拷贝到内存DC中
b=BitBlt(hMemDC,0,0,x,y,hDC,x,y,SRCCOPY);

//得到位图句柄
hbmp=(HBITMAP)::SelectObject(hMemDC,holdbmp); 

改为

//创建军兼容DC,当bSave为中时把开始保存的全屏位图,按截取矩形大小保存
CDC dcCompatible;
dcCompatible.CreateCompatibleDC(CDC::FromHandle(hMemDC));
dcCompatible.SelectObject(m_pBitmap);   
b=BitBlt(hMemDC, 0, 0, x, y,dcCompatible, x, y, SRCCOPY);

保存m_pBitmap即可!

#3


我没用MFC类库耶。。。。 用CDC的话 就要加 MFC类的头文件啦  程序体积就大啦。。。。

我想用API实现

#4


各位帅歌美女 帮我顶顶贴吧。。。。 别让它沉啦。。。。。。。。

#5


帮顶.

#6


谢谢 兄弟  不过还是希望有高手解决  这样顶也不是办法。。。。。。。。

#7


bi.biSizeImage = 0; 
这个字段没设置。

#8


http://www.handytech.cn/main/ArticleShow_12_2.htm 自己写bmp图的格式很麻烦,用这个方法吧。
http://topic.csdn.net/t/20030517/19/1798130.html 4楼和7楼。

http://topic.csdn.net/t/20050120/10/3739972.html
http://topic.csdn.net/t/20000529/20/10122.html 这两个也可以参考一下。

#9


// 写入位图文件其余内容 
WriteFile(fh, (LPSTR)lpbi, dwbitsize, &dwwritten, NULL); 
=======================================================
dwbitsize没有包含信息头的大小,应该为:
WriteFile(fh, (LPSTR)lpbi, dwbmpsize-sizeof(BITMAPFILEHEADER), &dwwritten, NULL);

WriteFile(fh,(LPSTR)lpbi,sizeof(BITMAPINFOHEADER)+dwtsbsize+dwbitsize,&dwwritten,NULL);

#10


现在的问题是
GetDIBits(hDC, hbmp, 0, (UINT) bmp.bmHeight,(LPSTR)lpbi + 
sizeof(BITMAPINFOHEADER)+dwtsbsize,(BITMAPINFO*)lpbi, DIB_RGB_COLORS); 
得到的数据都是0.

#11


//把屏幕DC拷贝到内存DC中 
b=BitBlt(hMemDC,0,0,x,y,hDC,x,y,SRCCOPY); 
=================================================
问题在这。
BitBlt第7,8两个参数设错了。改为:b=BitBlt(hMemDC,0,0,x,y,hDC,0,0,SRCCOPY);就正确了。

BitBlt原型:
BOOL BitBlt(HDC hdcDest,int nXDest,int nYDest,int nWidth,int nHeight,HDC hdcSrc,int nXSrc,int nYSrc,DWORD dwRop);
//int nXSrc,int nYSrc是源起始坐标。

#12


帮顶起

#13


谢谢

#14


  谢谢 dongpy 你照你说的 改了 就对了  非常感谢 
另外 我还想存成jpeg格式  bmp太大了 有没有思路和方法呢? 还请各位帮助 

#15


MARK

#16


引用 14 楼 pcie7777 的回复:
  谢谢 dongpy 你照你说的 改了 就对了  非常感谢
另外 我还想存成jpeg格式  bmp太大了 有没有思路和方法呢? 还请各位帮助

去sourceforge.net上找个jpeg开源库。