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界面的。 就是不知道他们使用什么原理获取的。

有哪位大侠可以指导一下,关于被遮挡截图的问题?
...全文
3259 19 打赏 收藏 转发到动态 举报
AI 作业
写回复
用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)

19,472

社区成员

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

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