MFC截图程序的实现(五)

来源:互联网 发布:盐与避难所mac版 编辑:程序博客网 时间:2024/06/05 23:52

  上篇所讲的程序,造成截图不正确的原因显然是CopyBitmapToClipboard这个函数。关于这个函数这里就先不提了,

后面会具体讲。

  现在的问题是:如果要使用许多截图,必须一一将截图先存成文件。原因有二,一是有的地方不支持直接Ctrl+V从

剪切板复制图像,二是不剪切板是一个公用的临时的存储区,如果有多幅截图,或是其他程序调用了剪切板,截图就丢

失了。

  那么要实现的功能就是讲截取的图像,转换为可存储的格式,最后存成文件。

1、首先,确定格式,最优先的当然是位图了。

2、其次,考虑到前面小程序截图效果的不足,这里提供一种解决方法:那就是获得待截图的窗口句柄后只提取它的位

置信息,而不直接复制图像。

3、复制图像的功能由另一个函数:CopyScreenToBitmap完成。看名字就知道这是讲屏幕的一个部分复制到位图对象

中。这就是我要介绍的第二个函数:

///////////////////////////////////////////////////////////////////////// 功能:将屏幕的某个矩形区域的图像复制到一个位图对象中// 参数:输入一个确定矩形范围的LPRECT型数据// 返回:一个存储了截图的bitmap句柄///////////////////////////////////////////////////////////////////////HBITMAP CopyScreenToBitmap(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(_T("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 = (HBITMAP)SelectObject(hMemDC, hBitmap); // 把屏幕设备描述表拷贝到内存设备描述表中 BitBlt(hMemDC, 0, 0, nWidth, nHeight, hScrDC, nX, nY, SRCCOPY); //得到屏幕位图的句柄 hBitmap = (HBITMAP)SelectObject(hMemDC, hOldBitmap); //清除 DeleteDC(hScrDC); DeleteDC(hMemDC); // 返回位图句柄 return hBitmap; }


4、既然得到了截图的HBITMAP对象,那么就可以重写CopyBitmapToClipboard方法了:

/////////////////////////////////////////////////////////////// 功能:将HBITMAP对象复制到剪切板// 参数:要复制的HBITMAP对象////////////////////////////////////////////////////////////void CMy123Dlg::CopyBitmapToClipboard(HBITMAP hBitmap){OpenClipboard();EmptyClipboard();SetClipboardData(CF_BITMAP, hBitmap);CloseClipboard();}


5、这样运行后的效果如下:




与上一篇文章的截图对比,可以看到,黑色的背景不产生了。似乎效果不错。

但是,细心的朋友发现了,截取资源管理器的同时还将在其之上的程序窗口也截进去了。

所以,结论是:这样的截图方法想要截取完整的图像,必须保证窗口前无遮挡。


6、最后,贴出完整的代码:

MyPic.cpp不变, 123Dlg.cpp如下:

// 123Dlg.cpp : implementation file//#include "stdafx.h"#include "123.h"#include "123Dlg.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endifHWND My123Hwnd;HWND cutWnd;CRect cutRc;/////////////////////////////////////////////////////////////////////////////// CMy123Dlg dialogCMy123Dlg::CMy123Dlg(CWnd* pParent /*=NULL*/): CDialog(CMy123Dlg::IDD, pParent){//{{AFX_DATA_INIT(CMy123Dlg)// NOTE: the ClassWizard will add member initialization here//}}AFX_DATA_INIT// Note that LoadIcon does not require a subsequent DestroyIcon in Win32m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);}void CMy123Dlg::DoDataExchange(CDataExchange* pDX){CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CMy123Dlg)// NOTE: the ClassWizard will add DDX and DDV calls here//}}AFX_DATA_MAP}BEGIN_MESSAGE_MAP(CMy123Dlg, CDialog)//{{AFX_MSG_MAP(CMy123Dlg)ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_WM_TIMER()//}}AFX_MSG_MAPEND_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////// CMy123Dlg message handlersBOOL CMy123Dlg::OnInitDialog(){CDialog::OnInitDialog();// Set the icon for this dialog.  The framework does this automatically//  when the application's main window is not a dialogSetIcon(m_hIcon, TRUE);// Set big iconSetIcon(m_hIcon, FALSE);// Set small icon// TODO: Add extra initialization herem_pic.SubclassDlgItem(IDC_PIC,this);  // 关联控件    My123Hwnd = m_hWnd;  // 赋值return TRUE;  // return TRUE  unless you set the focus to a control}// If you add a minimize button to your dialog, you will need the code below//  to draw the icon.  For MFC applications using the document/view model,//  this is automatically done for you by the framework.void CMy123Dlg::OnPaint() {if (IsIconic()){CPaintDC dc(this); // device context for paintingSendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);// Center icon in client rectangleint cxIcon = GetSystemMetrics(SM_CXICON);int cyIcon = GetSystemMetrics(SM_CYICON);CRect rect;GetClientRect(&rect);int x = (rect.Width() - cxIcon + 1) / 2;int y = (rect.Height() - cyIcon + 1) / 2;// Draw the icondc.DrawIcon(x, y, m_hIcon);}else{CDialog::OnPaint();}}// The system calls this to obtain the cursor to display while the user drags//  the minimized window.HCURSOR CMy123Dlg::OnQueryDragIcon(){return (HCURSOR) m_hIcon;}void CMy123Dlg::OnTimer(UINT nIDEvent) {// TODO: Add your message handler code here and/or call defaultif (1 == nIDEvent) {POINT pnt;RECT rc;HWND DeskHwnd = ::GetDesktopWindow(); //取得桌面句柄HDC DeskDC = ::GetWindowDC(DeskHwnd); //取得桌面设备场景int oldRop2 = SetROP2(DeskDC, R2_NOTXORPEN);::GetCursorPos(&pnt); //取得鼠标坐标HWND UnHwnd = ::WindowFromPoint(pnt) ; //取得鼠标指针处窗口句柄::GetWindowRect(UnHwnd, &rc); //获得窗口矩形cutWnd = UnHwnd;cutRc = rc;if( rc.left < 0 ) rc.left = 0;if (rc.top < 0 ) rc.top = 0;HPEN newPen = ::CreatePen(PS_SOLID, 3, RGB(255, 0, 0)); //建立新画笔,载入DeskDCHGDIOBJ oldPen = ::SelectObject(DeskDC, newPen);::Rectangle(DeskDC, rc.left, rc.top, rc.right, rc.bottom); //在窗口周围显示闪烁矩形Sleep(400); //设置闪烁时间间隔::Rectangle( DeskDC, rc.left, rc.top, rc.right, rc.bottom);::SetROP2(DeskDC, oldRop2);::SelectObject( DeskDC, oldPen);::DeleteObject(newPen);::ReleaseDC( DeskHwnd, DeskDC);DeskDC = NULL;}if (2 == nIDEvent) {if (m_pic.GetIsFinshed()) {//CopyBitmapToClipboard(FromHandle(cutWnd), TRUE);CopyBitmapToClipboard(CopyScreenToBitmap((LPRECT)&cutRc));}}CDialog::OnTimer(nIDEvent);}void CMy123Dlg::CopyBitmapToClipboard(CWnd *wnd, BOOL FullWnd){CDC *dc;if(FullWnd){ /* 抓取整个窗口*/dc = new CWindowDC(wnd);}      else{ /* 仅抓取客户区时*/dc = new CClientDC(wnd);} CDC memDC;memDC.CreateCompatibleDC(dc);CBitmap bm;CRect r;if(FullWnd)wnd->GetWindowRect(&r);elsewnd->GetClientRect(&r);CString s;wnd->GetWindowText(s);CSize sz(r.Width(), r.Height());bm.CreateCompatibleBitmap(dc, sz.cx, sz.cy);CBitmap * oldbm = memDC.SelectObject(&bm);memDC.BitBlt(0, 0, sz.cx, sz.cy, dc, 0, 0, SRCCOPY);//直接调用OpenClipboard(),而不用wnd->GetParent()->OpenClipboard();wnd->OpenClipboard();::EmptyClipboard();::SetClipboardData(CF_BITMAP, bm.m_hObject);CloseClipboard();//恢复原始环境memDC.SelectObject(oldbm);bm.Detach();  delete dc;KillTimer(2);// 加一句提示MessageBox(_T("复制完成"));}/////////////////////////////////////////////////////////////// 功能:将HBITMAP对象复制到剪切板// 参数:要复制的HBITMAP对象////////////////////////////////////////////////////////////void CMy123Dlg::CopyBitmapToClipboard(HBITMAP hBitmap){KillTimer(2);OpenClipboard();EmptyClipboard();SetClipboardData(CF_BITMAP, hBitmap);CloseClipboard();// 加一句提示MessageBox(_T("复制完成"));}///////////////////////////////////////////////////////////////////////// 功能:将屏幕的某个矩形区域的图像复制到一个位图对象中// 参数:输入一个确定矩形范围的LPRECT型数据// 返回:一个存储了截图的bitmap句柄///////////////////////////////////////////////////////////////////////HBITMAP CMy123Dlg::CopyScreenToBitmap(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(_T("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 = (HBITMAP)SelectObject(hMemDC, hBitmap); // 把屏幕设备描述表拷贝到内存设备描述表中 BitBlt(hMemDC, 0, 0, nWidth, nHeight, hScrDC, nX, nY, SRCCOPY); //得到屏幕位图的句柄 hBitmap = (HBITMAP)SelectObject(hMemDC, hOldBitmap); //清除 DeleteDC(hScrDC); DeleteDC(hMemDC);// 返回位图句柄 return hBitmap; }


7、完整源代码:http://download.csdn.net/detail/wwkaven/7488351



0 0
原创粉丝点击