BitBlt函数鼠标闪烁
BitBlt 用于从原设备中复制位图到目标设备,语法格式如下:
BOOL BitBlt(int x,int y,int nWidth,int nHeight,CDC*pSrcDC,int xSrc,int ySrc,DWORDdwRop);
各参数含义:
- x:目标矩形区域的左上角x轴坐标点。
- y:目标矩形区域的左上角y轴坐标点。
- nWidth:在目标设备中绘制位图的宽度。
- nHight:在目标设备中绘制位图的高度。
- pSrcDC:源设备上下文对象指针。
- xSrc:源设备上下文的起点x轴坐标,函数从该起点复制位图到目标设备。
- ySrc:源设备上下文的起点y轴坐标,函数从该起点复制位图到目标设备。
- dwRop:光栅操作代码
其中 dwRop 可以设置的值如下:
BLACKNESS 使用黑色填充目标区域DSTINVERT 目标矩阵区域颜色取反MERGECOPY 使用与运算组合原设备矩形区域的颜色和目标设备的画刷MERGEPAINT 使用或运算将反向的源矩形区域的颜色和目标矩形区域的颜色合并NOTSRCCOPY 复制源设备区域的反色到目标设备中NOTSRCERASE 使用或运算组合源设备区域与目标设备区域的颜色,然后对结果颜色取反PATCOPY 复制源设备当前选中的画刷到目标设备PATINVERT 使用异或运算组合目标设备选中的画刷和目标设备区域的颜色PATPAINT 通过或运算组合目标区域当前选中的画刷和源设备区域反转的颜色SRCAND 使用与运算组合源设备和目标设备区域的颜色SRCCOPY 直接复制源设备区域到目标设备中SRCERASE 使用与运算组合目标设备区域的反色与源设备区域的颜色SRCINVERT 使用异或运算组合源设备区域颜色和目标设备区域颜色SRCPAINT 使用或运算组合源设备区域颜色和目标设备区域颜色WHITENESS 使用白色填充目标区域
但是我们在用BitBlt函数进行屏幕捕捉时,若传递了 CAPTUREBLT (捕捉alpha blending,即半透明窗口)标志,鼠标就会闪烁。
BitBlt(hDCMem,0,0,xScrn,yScrn,hDCSource,0,0,SRCCOPY|CAPTUREBLT);
原因情况博客《windows屏幕捕捉BitBlt函数鼠标闪烁问题》。以防丢失,记录结论:
在windows2000及以后的系统上,鼠标及半透明窗口这两种图形对象是浮于桌面其他图形对象之上的,这里我们称它们为层叠窗口。层叠窗口并不存在于通常的显示场景(具体是在显示的哪一层,我也不清楚,姑且称它为场景M)中,只有在显示到屏幕的最后一刻,Windows才把层叠窗口绘制到屏幕上。
仅使用SRCCOPY标志时,Windows只需要从M中拷贝屏幕图像就行了。而若使用了CAPTUREBLT标志,导致的结果是鼠标及半透明窗口均被捕捉下来。但在设计上,BitBlt函数是不允许捕捉鼠标的。于是,系统只好先隐藏鼠标,然后捕捉图像,再恢复鼠标,结果就导致了鼠标的闪烁。
所以修改这个问题方法是,去除 CAPTUREBLT 参数。
BitBlt(hDCMem,0,0,xScrn,yScrn,hDCSource,0,0,SRCCOPY);
显示鼠标光标
我们在进行屏幕截图时,使用Windows API获取的数据中,是没有鼠标光标的。是因为 鼠标图层位于桌面图层之上。
如图,桌面图层使我们通过 HDC 可以获取的数据部分,如果想要在截图中显示出鼠标图形,需要手动绘制绘制到图层数据上。即先通过鼠标层获取到鼠标位置,然后绘制到数据上。基本实现逻辑如下:
//宽、高仅仅是为了占位置,设置实际参数即可。int width = 0;int heigth = 0;HWND curhWind = GetDesktopWindow();HDC curhDDC = GetDC(curhWind);HDC curhCDC = CreateCompatibleDC(curhDDC); //创建与桌面窗口兼容的DCHBITMAP curBitMap = CreateCompatibleBitmap(curhDDC, width, heigth);SelectObject(curhCDC, curBitMap);if (!BitBlt(curhCDC, 0, 0, width, heigth, curhDDC, width, heigth, SRCCOPY)){return;}CURSORINFO cursinf = { sizeof(cursinf) };GetCursorInfo(&cursinf); //获取鼠标信息if (cursinf.flags == CURSOR_SHOWING){ICONINFO iconinf = { sizeof(iconinf) };GetIconInfo(cursinf.hCursor, &iconinf);int x = cursinf.ptScreenPos.x - iconinf.xHotspot;int y = cursinf.ptScreenPos.y - iconinf.yHotspot;BITMAP bmpCur = { 0 };GetObject(iconinf.hbmColor, sizeof(bmpCur), &bmpCur);DrawIconEx(curhCDC, x, y, cursinf.hCursor, bmpCur.bmWidth, bmpCur.bmHeight, 0, NULL, DI_NORMAL);DeleteObject(iconinf.hbmColor);DeleteObject(iconinf.hbmMask);DestroyCursor(cursinf.hCursor);}
