文章目录
- Windows反截屏开发实现
-
- [1. SetWindowDisplayAffinity](#1. SetWindowDisplayAffinity)
- [2. 反截屏系统](#2. 反截屏系统)
- [3. 总结](#3. 总结)
Windows反截屏开发实现
最近在我们云桌面中需要做到反截屏能力,所谓反截屏就是我们无法通过截图软件(微信,QQ,截图等程序)截取桌面的内容。在Windows下面我们通过如下步骤来截图:
- 通过
GetDC
或者CreateDC
来获取DC。 - 通过
CreateCompatibleDC
创建内存DC。 - 通过
BitBlt
/StretchBlt
将屏幕DC的内容拷贝到内存DC中。 - 我们将DC的位图提取出来,就完成了截图。
要做到反截屏,一般有两种方式来实现:
- 通过设置属性,是的第三方软件无法获取到窗口的内容。
- 对截图的行为进行拦截,例如
CreateCompatibleDC
或者BitBlt
/StretchBlt
等。
接下来分别对两种情况来进行处理。
1. SetWindowDisplayAffinity
SetWindowDisplayAffinity
该函数设置窗口的显示属性,该函数如下:
cpp
BOOL SetWindowDisplayAffinity(
HWND hWnd,
DWORD dwAffinity
);
对于dwAffinity
可以取值如下:
WDA_MONITOR
设置窗口只在显示器上面显示,我们从内存DC中那窗口的内容的话得到的是空的。WDA_NONE
移除只在显示器上面显示的标记属性。
其实还有一个标记WDA_EXCLUDEFROMCAPTURE
专门是为截图设计的,当设置这个标记的时候,就会导致该窗口截图的时候透明。
该函数是在DWM窗口合成中完成的,因此需要在DWM开启的情况下才能生效;我们可以大致实现如下:
cpp
void CWindowAffinityDlg::OnBnClickedButtonWdaMonitor()
{
WCHAR wszWndName[MAX_PATH] = { 0 };
GetDlgItemTextW(IDC_EDIT_WND_NAME, wszWndName, _countof(wszWndName));
HWND hWnd = ::FindWindowW(NULL, wszWndName);
if (hWnd == NULL)
{
return;
}
SetWindowDisplayAffinity(hWnd, WDA_MONITOR);
}
在正常的情况下,我们看到的截图效果如下:
设置WDA_MONITOR
之后,我们的效果如下:
如果设置WDA_EXCLUDEFROMCAPTURE
,截图的效果如下:
可以看到,通过SetWindowDisplayAffinity
可以对当前窗口进行处理,防止被别人截图。但是SetWindowDisplayAffinity
有一个限制,只能够设置本进程的窗口,无法设置其他进程窗口,例如我们无法做到防止截图软件去截取桌面其他窗口的内容。
但是这对于我们的云桌面客户端来说是不影响的,因为云桌面客户端只要禁止我们的窗口被其他程序截屏就行了。
2. 反截屏系统
如果我们需要对其他窗口也进行拦截那么上面的方案就不行了,例如我们需要做到禁止微信截取所有图片,防止信息泄露,那么就需要使用另外方案了。
我们需要对CreateCompatibleDC
或者BitBlt
/StretchBlt
做处理,例如:
cpp
BOOL BitBlt(
HDC hdc,
int x,
int y,
int cx,
int cy,
HDC hdcSrc,
int x1,
int y1,
DWORD rop
);
BitBlt
函数中,我们hdcSrc
表示了原DC的内容,因此我们只需要将原DC的内容进行清理就可以了,如下:
cpp
HBRUSH hBrush = CreateSolidBrush(0);
if (hBrush != NULL)
{
GetWindowRect(hWnd, &Rect);
FillRect(hdc, &Rect, hBrush);
DeleteObject(hBrush);
}
我们可以看到实现效果,针对Windows自带的截图如下,截图如下:
微信截图如下(截取到的整个桌面为黑色):
QQ截图效果如下(截取到的整个桌面为黑色):
3. 总结
上面我们提供了两种反截屏的方式:
- 如果我们仅仅需要对自己的窗口进行反截屏,那么使用
SetWindowDisplayAffinity
设置好窗口的属性就可以了。 - 如果我们需要对系统桌面进行反截屏,这种情况一般是防止桌面内容通过截屏被泄露,这样就需要使用我们对截屏行为进行拦截和处理了。