VC被遮挡窗口截图问题的方法分析

GreenXML 2013-08-18 06:11:55
最近有哥们问我后台截图的问题,我研究了几个后台截图的案例,感觉有些疑问。

1)http://blog.csdn.net/VisualEleven/article/details/6202796
这个哥们的窗口截图函数,我试了一下,基本上就是前台截图,一旦有窗口被遮挡,那么截到的图就是包含所有上面窗口的图了。他说的第二种方法prinWindow也不行,所以这个不行。

2)哥们发给我几个游戏截图的插件,我试了一下,感觉很厉害。不过他们都是先BindWindow(Hwnd)或者先Transform(HWND)之类的操作,然后再用一般的截图,就可以了。
就相当于在截图前做了变换,就是不知道什么变换??

3)我也发现有些3D桌面软件也是利用这些原理的实现后台截图,然后做成3D界面的。 就是不知道他们使用什么原理获取的。

有哪位大侠可以指导一下,关于被遮挡截图的问题?
...全文
3135 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
nicksong 2014-05-22
  • 打赏
  • 举报
回复
用OLLYDBG逆向一下就知道怎么做的了呀
pengh_ts 2014-05-15
  • 打赏
  • 举报
回复
32位操作系统(win7)是可以解决截屏被遮挡问题,但64位(win7、windows sever 2008 )还是不行。
shiter 2014-05-15
  • 打赏
  • 举报
回复
顶一下,学习一下啊
GreenXML 2013-08-31
  • 打赏
  • 举报
回复
急需顶啊。。。。
GreenXML 2013-08-30
  • 打赏
  • 举报
回复
引用 14 楼 VisualEleven 的回复:
大佬出现了!! 老大你看看除了PrintWindow外,还有其他什么方法能后台截图呢?? 老大能否看一下,这个插件就可以后台截图,但是他用的不是PrintWIndow,速度很快。。。能否分析分析 http://bbs.anjian.com/thread-107721-1-1.html
GreenXML 2013-08-20
  • 打赏
  • 举报
回复
插件的说明和下载在:http://bbs.anjian.com/thread-107721-1-1.html
GreenXML 2013-08-20
  • 打赏
  • 举报
回复
今天看了一个按键精灵的插件,发现它事先调用一个函数: 函数说明: 1.TransformWindow(窗口句柄) 功能:转换窗口,对要取后台图色数据的窗口使用该函数后才能取后台图色数据。如果是DX图形绘图的窗口,DX绘图区域必须有部分移到屏幕外,否则无法使用。转换窗口后,有些窗口(特别是大多数游戏的)要等待一会儿才能用其它函数可靠地取到后台图色数据,等待的时间要大于画面两次刷新的时间间隔。转换后到取消转换前,可以无限次使用取到后台图色数据的命令,即通常只需要转换一次。 参数:   1)窗口句柄:整型数。 貌似他这个函数速度挺快的,不知道是如何转换的呢???? 谁知道原理详细解释一下呢。。。。。谢谢了
GreenXML 2013-08-20
  • 打赏
  • 举报
回复
不过我测试了一下 发现PrintWindow速度好慢啊。。。。 有无其他速度较快的呢?????? 或者这个PrintWindow函数实现原理是什么? 我们可以代替他?
  • 打赏
  • 举报
回复
我copy过来,大家一起学习

PrintWindow函数是截取在屏幕窗口区域外的函数,即截取“移除到屏幕外的窗口”。比如:mfc中要截取隐藏的一个窗口时,我们可以将这个窗口移除到屏幕外,然后用PrintWindow函数进行截取。

下面这是一个win32控制台程序(给出了PrintWindow函数的用法):
 
#define _WIN32_WINNT 0x0501 //仅XP或以上系统有效
#include <windows.h>
int main()
{
RECT rc;
HWND hwnd = FindWindow(TEXT("Notepad"), NULL); //注意窗口不能最小化
if (hwnd == NULL)
{
cout << "找不到记事本窗口" << endl;
return 0;
}
GetClientRect(hwnd, &rc);

//创建
HDC hdcScreen = GetDC(NULL);
HDC hdc = CreateCompatibleDC(hdcScreen);
HBITMAP hbmp = CreateCompatibleBitmap(hdcScreen, rc.right - rc.left, rc.bottom - rc.top);
SelectObject(hdc, hbmp);

//复制
PrintWindow(hwnd, hdc, PW_CLIENTONLY);
//PW_CLIENTONLY:Only the client area of the window is copied to hdcBlt.
//By default, the entire window is copied.
//PW_CLIENTONLY表示仅仅拷贝窗口的客户区域,而默认情况下,执行printwindow会拷贝整个窗口

//复制到粘贴板
OpenClipboard(NULL);
EmptyClipboard();
SetClipboardData(CF_BITMAP, hbmp);
CloseClipboard();

//释放
DeleteDC(hdc);
DeleteObject(hbmp);
ReleaseDC(NULL, hdcScreen);

cout << "成功把记事本窗口复制到粘贴板,请粘贴到Windows画图工具" << endl;

return 0;
}


Eleven 2013-08-20
  • 打赏
  • 举报
回复
泥鳅不是鱼 2013-08-20
  • 打赏
  • 举报
回复
void SaveHwndToJpgFile(HWND hWnd, LPCTSTR lpszPath) 
{
HDC hDC = ::GetWindowDC(hWnd);
ASSERT(hDC);

HDC hMemDC = ::CreateCompatibleDC(hDC);
ASSERT(hMemDC);

RECT rc;
::GetWindowRect(hWnd, &rc);

HBITMAP hBitmap = ::CreateCompatibleBitmap(hDC, rc.right - rc.left, rc.bottom - rc.top);
ASSERT(hBitmap);

HBITMAP hOldBmp = (HBITMAP)::SelectObject(hMemDC, hBitmap);
::PrintWindow(hWnd, hMemDC, 0);

CImage img;
img.Attach(hBitmap);
HRESULT hResult = img.Save(lpszPath,Gdiplus::ImageFormatPNG);

::SelectObject(hMemDC, hOldBmp);
::DeleteObject(hBitmap);
::DeleteObject(hMemDC);
::ReleaseDC(hWnd, hDC);
}
GreenXML 2013-08-19
  • 打赏
  • 举报
回复
刚才自己又重新试了一下:下面这个函数:
BOOL SaveHwndToBmpFile(HWND hWnd, LPCTSTR lpszPath)
{
HWND hDesktop = ::GetDesktopWindow();
ASSERT(hDesktop);
if(NULL == hWnd)
{
hWnd = hDesktop;
}
RECT rect;
::GetWindowRect(hWnd, &rect);

int nWidht = rect.right - rect.left;
int nHeight = rect.bottom - rect.top;

HDC hSrcDC = ::GetWindowDC(hWnd);
ASSERT(hSrcDC);
HDC hMemDC = ::CreateCompatibleDC(hSrcDC);
ASSERT(hMemDC);
HBITMAP hBitmap = ::CreateCompatibleBitmap(hSrcDC, nWidht, nHeight);
ASSERT(hBitmap);
HBITMAP hOldBitmap = (HBITMAP)::SelectObject(hMemDC, hBitmap);
::BitBlt(hMemDC, 0, 0, nWidht, nHeight, hSrcDC, 0, 0, SRCCOPY);

BITMAP bitmap = {0};
::GetObject(hBitmap, sizeof(BITMAP), &bitmap);
BITMAPINFOHEADER bi = {0};
BITMAPFILEHEADER bf = {0};

CONST int nBitCount = 24;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bitmap.bmWidth;
bi.biHeight = bitmap.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = nBitCount;
bi.biCompression = BI_RGB;
DWORD dwSize = ((bitmap.bmWidth * nBitCount + 31) / 32) * 4 * bitmap.bmHeight;

HANDLE hDib = GlobalAlloc(GHND, dwSize + sizeof(BITMAPINFOHEADER));
LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);
*lpbi = bi;

::GetDIBits(hMemDC, hBitmap, 0, bitmap.bmHeight, (BYTE*)lpbi + sizeof(BITMAPINFOHEADER), (BITMAPINFO*)lpbi, DIB_RGB_COLORS);

try
{
CFile file;
file.Open(lpszPath, CFile::modeCreate | CFile::modeWrite);
bf.bfType = 0x4d42;
dwSize += sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
bf.bfSize = dwSize;
bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

file.Write((BYTE*)&bf, sizeof(BITMAPFILEHEADER));
file.Write((BYTE*)lpbi, dwSize);
file.Close();
}
catch(CFileException* e)
{
e->ReportError();
e->Delete();
}

GlobalUnlock(hDib);
GlobalFree(hDib);

::SelectObject(hMemDC, hOldBitmap);
::DeleteObject(hBitmap);
::DeleteDC(hMemDC);
::ReleaseDC(hWnd, hSrcDC);

return TRUE;
}

// 调用方法
HWND hWnd = ::FindWindow(NULL, _T("XXX"));
if(hWnd)
{
SaveHwndToBmpFile(hWnd, _T("F://12.bmp"));
}

在WIN7下面可以使用,即使目标窗口上面有遮挡,也是可以截取全部图形的。
但是Windowxp就不行,如果目标窗口上面有遮挡的话,就只能截取部分图形。

很奇怪啊。。。。
GreenXML 2013-08-19
  • 打赏
  • 举报
回复
今天找了一天,终于解决了问题。 原来用PrintWindow可以解决啊!!
schlafenhamster 2013-08-19
  • 打赏
  • 举报
回复
“在WIN7下面可以使用,即使目标窗口上面有遮挡,” 太好了, 我没有 win7. 微软就是 问题多。
GreenXML 2013-08-18
  • 打赏
  • 举报
回复
刚看到了@lh15871815717 的一个函数,能否也帮忙看看???谢谢了
GreenXML 2013-08-18
  • 打赏
  • 举报
回复
刚又搜索了一下,发现有人说:【在WIN7下面按窗口句柄的HDC是正常的。但是在XP系统下面,如果有窗口在要取的窗口句柄前面的话,那这个截图就不全是内容句柄的图,还有在它之上的窗口图。】 我想问一下,关于GetWindowDC 在Winxp和Win7是否是不一样呢?
schlafenhamster 2013-08-18
  • 打赏
  • 举报
回复
memDC 创建 不难。即: CDC memDC; memDC.CreateCompatibleDC(pDC); 问题在于, 窗口 不 使用 你给的这个 memDC ,他 直接 取 自己的 DC 即 CPaintDC (this);
GreenXML 2013-08-18
  • 打赏
  • 举报
回复
引用 1 楼 schlafenhamster 的回复:
如果给 窗口 一个 memDC , 他 就可以 把 窗口 绘制 在 这个 memDC 上,那就是 没 问题 了。 可惜 不是 所有 窗口 都 支持 该 技术 (大部分 微软 控件支持)。 被自绘的 控件 基本上 不行,(因为 OnPaint 没有 查 有没有 另外给 了一个 DC)
如果能找到窗口对应的memDC呢???? 这个是关键,或者如何创建?
schlafenhamster 2013-08-18
  • 打赏
  • 举报
回复
如果给 窗口 一个 memDC , 他 就可以 把 窗口 绘制 在 这个 memDC 上,那就是 没 问题 了。 可惜 不是 所有 窗口 都 支持 该 技术 (大部分 微软 控件支持)。 被自绘的 控件 基本上 不行,(因为 OnPaint 没有 查 有没有 另外给 了一个 DC)
可以作为课程设计的程序,实现简单的绘图,移动图形的功能。 使用vc框架实现。 GHpaint程序的几个重点 程序的基本功能: 程序提供绘图、删除已绘图形、移动已绘图形。 可以选择绘图颜色、形状、线粗。 重点问题: 1、 程序设计基于面向对象。 程序中所有图形都从基类CShapebase派生,大部分工作(例如:删除、移动等)都在这个基类中完成。此类中的两个纯需函数: //纯需函数DrawShape,每个基类都必须实现的函数。 //指定不同图形的绘制方法。 virtual void DrawShape(CDC* pdc) = 0; //橡皮筋效果的算法函数 virtual void ZoomShape(CDC *pdc) = 0; 这两个函数需要在派生类中重载。这两个函数中主要实现不同图形的绘制方法。 也就是说,不同图形的不同点只有绘制方法不同,其他所有属性和行为都可以统一处理。 这里的继承体现了面向对象的设计,论文中可以体现这一点。 2、 动态模板库对象CPtList的使用,动态模板库基础知识。 CPtList是动态模板库的一个实例化类。功能是以链表形式保存指针,至于指针类型不做要求,需要程序员自己设计。 本程序CPtList对象中保存所有图形对象指针,由于所有图形都从CShapebase派生,所以所有图形指针都可以转化为基类CShapebase指针后保存在CPtList中。以后再遍历列表,调用图形对象函数时出现了多态调用。这里体现面向对象程序的多态,论文中可以说明。 至于CPtList的使用,可以在网上查查,可以看看程序代码,比较简单。 多态:是一种函数调用形式。出现在类继承情况下。详细的多态定义到网上查查。 程序中的多态体现在CShapebase类的虚函数,在使用CShapebase指针调用这两个虚函数,实际调用的使子类的重载函数体。这里实际上是不知道函数怎样工作,但是知道函数功能。 例如:使用CShapebase指针调用DrawShape函数,因为不知道子类是什么图形,所以不知道DrawShape怎样画这个图,但是直到DrawShape函数会把这个图画好,这就达到了要求。 3、 Windows窗口绘图基本知识。 3.1 Windows GUI绘图基本知识。使用MFC类库之后,每个窗口都有一个CDC指针量。这个变量提供图形绘制。CDC类说明查查网络,内容比较多。CDC及提供图形绘制算法,也提供各种绘制模式(单色、异或色等),提供画笔和画刷的功能。 3.2 窗口绘图基本思想: 图形绘制在窗口中,windows不会帮助程序员让图形“长在”窗口上,当窗口遮挡,最小化后,图形绘消失。程序需要在合适的时机把图形重新画在窗口上。所以窗口上画的内容需要程序员自己思考怎样保存。在本程序中所有图形保存在CPtList对象中。 3.2 Windows为窗口提供了一个重绘消息:OnPaint,在winxp系统中,这个消息会在窗口遮挡部分从新出现、窗口从最小化恢复时调用。在win7种只有窗口从屏幕外移动进屏幕时调用。具体情况可以查查网络,这里是我的发现,并不是主要内容。 在OnPaint消息中重新绘制所有图形是一个保证图形不消失的好办法。 4、 Windows颜色控制基本知识。 4.1 windows使用RGB三原色(红绿蓝)提供颜色控制,本程序使用24位颜色,在内存中占用4字节,所以用int型表示,但是int型的最高位字节不使用,这样每一种颜色就有一个字节表示,每种颜色级别从0-255。系统提供RGB宏帮助定义颜色,例如:RGB(255,0,0)是红色,RGB(0,0,0)黑色,RGB(255,255,255)白色。 4.2 windows绘图提供多种颜色混合模式,本程序中使用异或模式实现图形的“橡皮筋”效果和移动效果,使用纯色模式定位图形。

19,468

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 图形处理/算法
社区管理员
  • 图形处理/算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧