我今天写出了返回GDI+的Bitmap的屏幕捕捉方法,供需要者参考。(记得前几天看到有人问这个问题)代码如下:
enum ScreenType
{
FullScreen,
WorkArea,
ActiveWindow
};Bitmap* CaptureScreen(ScreenType type)
{
HWND wnd;
HDC hDC;
if (type == ActiveWindow) {
wnd = ::GetActiveWindow();
hDC = ::GetWindowDC(wnd);
}
else {
wnd = ::GetDesktopWindow();
hDC = ::GetDC(NULL);
} ATLASSERT(::IsWindow(wnd)); CRect rect; if(type==WorkArea )
{
::SystemParametersInfo(SPI_GETWORKAREA,0,&rect,0);
}
else
{
::GetWindowRect(wnd, &rect);
} HDC hMemDC = ::CreateCompatibleDC(hDC); //most of the remaining code is normal GDI stuff
HBITMAP hBitmap = ::CreateCompatibleBitmap(hDC, rect.Width(), rect.Height());
if (hBitmap)
{
HBITMAP hOld = (HBITMAP) ::SelectObject(hMemDC, hBitmap);
BitBlt(hMemDC, 0, 0, rect.Width(), rect.Height(), hDC, 0, 0, SRCCOPY);
SelectObject(hMemDC, hOld);
DeleteDC(hMemDC);
ReleaseDC(NULL, hDC);
} return Bitmap::FromHBITMAP(hBitmap, NULL);
}这个方法在大多数情况下是有效的。存在的问题:
如果屏幕上有半透明窗口,在取得Desktop的时候无法取到。半透明窗口就像完全透明了一下。而键盘上的「Print Screen」却可以正确取到。如果你有正确的办法请告知。
enum ScreenType
{
FullScreen,
WorkArea,
ActiveWindow
};Bitmap* CaptureScreen(ScreenType type)
{
HWND wnd;
HDC hDC;
if (type == ActiveWindow) {
wnd = ::GetActiveWindow();
hDC = ::GetWindowDC(wnd);
}
else {
wnd = ::GetDesktopWindow();
hDC = ::GetDC(NULL);
} ATLASSERT(::IsWindow(wnd)); CRect rect; if(type==WorkArea )
{
::SystemParametersInfo(SPI_GETWORKAREA,0,&rect,0);
}
else
{
::GetWindowRect(wnd, &rect);
} HDC hMemDC = ::CreateCompatibleDC(hDC); //most of the remaining code is normal GDI stuff
HBITMAP hBitmap = ::CreateCompatibleBitmap(hDC, rect.Width(), rect.Height());
if (hBitmap)
{
HBITMAP hOld = (HBITMAP) ::SelectObject(hMemDC, hBitmap);
BitBlt(hMemDC, 0, 0, rect.Width(), rect.Height(), hDC, 0, 0, SRCCOPY);
SelectObject(hMemDC, hOld);
DeleteDC(hMemDC);
ReleaseDC(NULL, hDC);
} return Bitmap::FromHBITMAP(hBitmap, NULL);
}这个方法在大多数情况下是有效的。存在的问题:
如果屏幕上有半透明窗口,在取得Desktop的时候无法取到。半透明窗口就像完全透明了一下。而键盘上的「Print Screen」却可以正确取到。如果你有正确的办法请告知。
解决方案 »
- 求一个vs2005用自带数据库编写的一个程序 能连接运行查看就行
- win7 对话框重绘问题
- 关于STDAFX.H中添加别的头文件出现LNK2005错误的问题,请高手出招,谢谢!
- 在activex 控件中获取容器(网页)的客户区大小,并且在客户区画图,而不是在窗体上画图的???
- 计算机考研
- 请教数字签名,在<安全设置警告>中为什么总显示我的.cab包的文件路径~,郁闷
- 用什么方法能实现判断当前屏幕中焦点所在的位置是否可以输入???
- 执行钩子安装时的奇怪问题,请大家帮忙看看
- 上海地区的高程考试结果什么时候公布?
- Dialog框中设置单选效果
- 关于模板的问题,能够编译通过,却不能正常链接.
- 请问各位,怎mo为sql表加自动编号
{
HWND wnd;
HDC hDC;
Bitmap* pBitmap = NULL; if (type == ActiveWindow) {
wnd = ::GetActiveWindow();
hDC = ::GetWindowDC(wnd);
}
else {
wnd = ::GetDesktopWindow();
hDC = ::GetDC(NULL);
} ATLASSERT(::IsWindow(wnd)); CRect rect; if(type==WorkArea )
{
::SystemParametersInfo(SPI_GETWORKAREA,0,&rect,0);
}
else
{
::GetWindowRect(wnd, &rect);
} //most of the remaining code is normal GDI stuff
HDC hMemDC = ::CreateCompatibleDC(hDC);
HBITMAP hBitmap = ::CreateCompatibleBitmap(hDC, rect.Width(), rect.Height()); if (hBitmap)
{
HBITMAP hOld = (HBITMAP) ::SelectObject(hMemDC, hBitmap);
BitBlt(hMemDC, 0, 0, rect.Width(), rect.Height(), hDC, 0, 0, SRCCOPY);
SelectObject(hMemDC, hOld);
//Create GDI+ Bitmap from HBITMAP
pBitmap = Bitmap::FromHBITMAP(hBitmap, NULL);
pBitmap = Bitmap::FromHBITMAP(hBitmap, NULL); DeleteObject(hBitmap);
} DeleteDC(hMemDC);
ReleaseDC(wnd,hDC); return pBitmap;
}
谢谢你教会我这么重要的知识。我尝试了去生成DIB,发现完美的实现还是需要做好多工作的。我在后面的实现里使用了CImage封装类来帮助我作这个工作。3) Bitmap::FromHBITMAP is called twice. Typo?
这是贴代码是时的失误。4) Are you sure you can call DeleteObject(hBitmap)? Double check GDI+ documentation. Add a comment if it's safe to delete the HBITMAP.
Thanks again。确是如你所说,我做了危险的工作。在后面的代码里我使用了Clone来解决这个问题。5) Design issue: seperate into two functions, first capture window into HBITMAP, and then the second one convert HBITMAP into GDI+ bitmap, for better reusability.
因为必须考虑资源泄漏等问题,如果我分成不同的函数,那么何时进行资源释放必须谨慎小心。我还是考虑相对安全的实现,返回Bitmap指针。下面是我修改过的代码,如有问题请指正,谢谢
Bitmap* CGdiPlusHelper::CaptureScreen(ScreenType type)
{
HWND wnd;
if (type == ActiveWindow) {
wnd = ::GetActiveWindow();
}
else {
wnd = ::GetDesktopWindow();
} ATLASSERT(::IsWindow(wnd)); CRect rect;
if(type==WorkArea )
{
::SystemParametersInfo(SPI_GETWORKAREA,0,&rect,0);
}
else
{
::GetWindowRect(wnd, &rect);
} CWindowDC winDC(NULL);
CImage image; int nBPP = winDC.GetDeviceCaps(BITSPIXEL) * winDC.GetDeviceCaps(PLANES);
if (nBPP < 24)
nBPP = 24; BOOL bStat = image.Create(rect.Width(), rect.Height(), nBPP);
ATLASSERT(bStat); if (!bStat)
return NULL; CImageDC imageDC(image);
::BitBlt(imageDC, 0, 0, rect.Width(), rect.Height(), winDC, 0, 0, SRCCOPY); Bitmap* pBitmap;
{
Bitmap bmpTemp((HBITMAP)image, NULL);
pBitmap = bmpTemp.Clone(0, 0, rect.Width(), rect.Height(), PixelFormat32bppARGB);
} return pBitmap;
}
难道::GetDC(NULL); 取到的DC里面就没有半透明的图像?
还是根本就不能用GDI方法呢?
或者BitBlt无法正确拷贝半透明图像????
错:CWindowDC winDC(NULL);
正:CWindowDC winDC(wnd);
无效。无法解决带有透明窗口的Desktop问题。
代码重新修改如下,注意多层大括号的使用技巧,它影响了自动变量的生存期间。Bitmap* CGdiPlusHelper::CaptureScreen(ScreenType type)
{
HWND wnd;
if (type == ActiveWindow) {
wnd = ::GetActiveWindow();
}
else {
wnd = ::GetDesktopWindow();
} ATLASSERT(::IsWindow(wnd)); CRect rect;
if(type==WorkArea )
{
::SystemParametersInfo(SPI_GETWORKAREA,0,&rect,0);
}
else
{
::GetWindowRect(wnd, &rect);
} CWindowDC winDC(wnd);
CImage image; int nBPP;
nBPP = winDC.GetDeviceCaps(BITSPIXEL) * winDC.GetDeviceCaps(PLANES);
if (nBPP < 24)
nBPP = 24; BOOL bStat = image.Create(rect.Width(), rect.Height(), nBPP);
ATLASSERT(bStat); if (!bStat)
return NULL; Bitmap* pBitmap = NULL;
{
CImageDC imageDC(image);
::BitBlt(imageDC, 0, 0, rect.Width(), rect.Height(), winDC, rect.left, rect.top, SRCCOPY);
{
Bitmap bmpTemp((HBITMAP)image, NULL);
pBitmap = bmpTemp.Clone(0, 0, rect.Width(), rect.Height(), PixelFormat32bppARGB);
if (bmpTemp.GetLastStatus() != Gdiplus::Ok)
{
pBitmap = NULL;
}
}
} return pBitmap;
}取得带有透明窗口的Desktop另有办法解决,上面的方法仍然无法解决这个问题。