VC++屏幕捕获并保存成图片(附源码)
Posted dvlinker
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VC++屏幕捕获并保存成图片(附源码)相关的知识,希望对你有一定的参考价值。
目录
我们可以将当前电脑屏幕上显示的内容截屏,并保存成图片文件。在视频会议软件中,桌面共享功能就是通过定时地捕获屏幕,经过视频编码后发出去的。
1、屏幕捕获(截取桌面)
我们先获取桌面窗口句柄,桌面窗口中显示的内容,就是屏幕看到的内容。我们将桌面窗口中的内容拷贝到内存位图(用位图句柄标识)中,代码如下:
HBITMAP CopyScreenToBitmap( )
CString strLog;
HWND hWndDeskTop = ::GetDesktopWindow();
//HDC hScrDC = ::CreateDC( _T("DISPLAY"), NULL, NULL, NULL );
HDC hScrDC = ::GetDC( hWndDeskTop ); // 为屏幕创建设备描述表
if ( hScrDC == NULL )
strLog.Format( _T("[CopyScreenToBitmap] 创建DISPLAY失败, GetLastError: %d"),
GetLastError() );
WriteLog( strLog );
return NULL;
HDC hMemDC = ::CreateCompatibleDC( hScrDC ); // 为屏幕设备描述表创建兼容的内存设备描述表
if ( hMemDC == NULL )
strLog.Format( _T("[CopyScreenToBitmap]创建与hScrDC兼容的hMemDC失败, GetLastError: %d"),
GetLastError() );
WriteLog( strLog );
//::DeleteDC( hScrDC );
::ReleaseDC( hWndDeskTop, hScrDC );
return NULL;
int nX = 0;
int nY = 0;
int nX2 = 0;
int nY2 = 0;
int nWidth = 0;
int nHeight = 0;
// 保证left小于right,top小于bottom
CDirectRect rc = *lpRect;
rc.Normalize();
// 获得选定区域坐标
nX = rc.left;
nY = rc.top;
nX2 = rc.right;
nY2 = rc.bottom;
// 确保选定区域是可见的
if ( nX < 0 )
nX = 0;
if ( nY < 0 )
nY = 0;
if ( nX2 > m_xScreen )
nX2 = m_xScreen;
if ( nY2 > m_yScreen )
nY2 = m_yScreen;
nWidth = nX2 - nX;
nHeight = nY2 - nY;
HBITMAP hBitmap = ::CreateCompatibleBitmap( hScrDC, nWidth, nHeight ); // 创建一个与屏幕设备描述表兼容的位图
::SelectObject( hMemDC, hBitmap ); // 把新位图选到内存设备描述表中
BOOL bRet = ::BitBlt( hMemDC, 0, 0, nWidth, nHeight, hScrDC, nX, nY, SRCCOPY | CAPTUREBLT ); // CAPTUREBLT - 该参数保证能够截到透明窗口
if ( !bRet )
strLog.Format( _T("[CopyScreenToBitmap]将hScrDC拷贝到hMemDC失败, GetLastError: %d"),
GetLastError() );
WriteLog( strLog );
//::DeleteDC( hScrDC );
::ReleaseDC( hWndDeskTop, hScrDC );
::DeleteDC( hMemDC );
::DeleteObject( hBitmap );
return NULL;
if ( hScrDC != NULL )
//::DeleteDC( hScrDC );
::ReleaseDC( hWndDeskTop, hScrDC );
if ( hMemDC != NULL )
::DeleteDC( hMemDC );
return hBitmap; // hBitmap资源不能释放,因为函数外部要使用
2、将内存中的位图保存成图片文件
上面的CopyScreenToBitmap接口将捕获到的屏幕内容保存到hBitmap位图中,我们将该内存中的位图保存成图片:(接口中使用GDI+对象实现保存成图片文件的功能,支持多种图片类型)
// 获取jpeg等编码Clsid
int GetEncoderClsid( const WCHAR* format, CLSID* pClsid )
UINT num = 0; // number of image encoders
UINT size = 0; // size of the image encoder array in bytes
ImageCodecInfo* pImageCodecInfo = NULL;
GetImageEncodersSize( &num, &size );
if( size == 0 )
return -1;
pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
if( pImageCodecInfo == NULL )
return -1;
GetImageEncoders( num, size, pImageCodecInfo );
for( UINT j = 0; j < num; ++j )
if( wcscmp( pImageCodecInfo[j].MimeType, format ) == 0 )
*pClsid = pImageCodecInfo[j].Clsid;
free(pImageCodecInfo);
return j;
free( pImageCodecInfo );
return -1;
// 使用gdi+将HBITMAP位图句柄图片资源保存成图片文件,图片文件的类型包括bmp、jpg、png、gif和tiff
// 根据lpfilename中包含的扩展名来判断是保存到哪个类型的文件中
BOOL SaveHBitmapToFile( HBITMAP hBmp, LPCTSTR lpfilename )
if ( hBmp == NULL || lpfilename == NULL )
WriteLog( _T("[SaveHBitmapToFile]hBmp或lpfilename为空,return") );
return FALSE;
CUIString strLog;
int nLastErrCode = 0;
Bitmap *pSrcBmp = Bitmap::FromHBITMAP( hBmp, NULL );
if ( pSrcBmp == NULL )
nLastErrCode = ::GetLastError();
strLog.Format( _T("[SaveHBitmapToFile]Bitmap::FromHBITMAP失败,GetLastError: %d"),
nLastErrCode );
WriteLog( strLog );
return FALSE;
// 获取文件的扩展名
CUIString strExtName = _T("");
CUIString strFilePatch = lpfilename;
int nPos = strFilePatch.ReverseFind(_T('.'));
if ( nPos != -1)
strExtName = strFilePatch.Right( strFilePatch.GetLength() - nPos - 1 );
// GDI+中有五种编码:bmp、jpeg、gif、tiff和png,下面根据
// 文件名的扩展部分来获取对应的编码CLSID
CLSID encoderClsid;
if ( strExtName == _T("bmp") )
GetEncoderClsid( L"image/bmp", &encoderClsid );
else if ( strExtName == _T("jpg") )
GetEncoderClsid( L"image/jpeg", &encoderClsid );
else if ( strExtName == _T("png") )
GetEncoderClsid( L"image/png", &encoderClsid );
else if ( strExtName == _T("gif") )
GetEncoderClsid( L"image/gif", &encoderClsid );
else if ( strExtName == _T("tiff") )
GetEncoderClsid( L"image/tiff", &encoderClsid );
else // 没有指定类型的扩展名,则默认使用png
GetEncoderClsid( L"image/png", &encoderClsid );
LPWSTR lpWStrFileName = NULL; // 注意:Bitmap::Save接口第一个参数是宽字节参数
#ifdef _UNICODE
lpWStrFileName = const_cast<LPTSTR>(lpfilename); // 如果是_UNICODE模式,直接使用
#else
WCHAR wchFileName[MAX_PATH*2] = 0;
MultiByteToWideChar( CP_ACP, 0, lpfilename, -1, wchFileName, sizeof(wchFileName)/sizeof(WCHAR) ); // 将窄字符转化为宽字符
lpWStrFileName = wchFileName;
#endif
Gdiplus::Status statusRet = pSrcBmp->Save( lpWStrFileName, &encoderClsid );
if ( statusRet != Gdiplus::Ok )
nLastErrCode = ::GetLastError();
strLog.Format( _T("[SaveHBitmapToFile]Bitmap::FromHBITMAP失败,,Gdiplus错误码:%d, GetLastError: %d"),
statusRet, nLastErrCode );
WriteLog( strLog );
// 释放内存
delete pSrcBmp;
return FALSE;
// 释放内存
delete pSrcBmp;
return TRUE;
3、完整功能的屏幕截图
类似IM聊天软件中的完整功能的屏幕截图(包括桌面灰化、窗口自动套索、区域放大、绘制矩形等多个图元、输入文字等功能),可以查看本人的博文,
以上是关于VC++屏幕捕获并保存成图片(附源码)的主要内容,如果未能解决你的问题,请参考以下文章
VC++如何将rc资源中的图片加载到MFC的CImage对象中(附源码)