为什么这个BitBlt示例不再起作用?

我现在正在使用Petzold的书(第5版)回到一些Windows编程。 我使用BitBlt编译了以下示例 ,它不能正常工作。

它应该复制Window的(CxSource,CySource)大小的图标并在整个窗口的表面上复制它。 实际上,使用Windows 7会发生什么,窗口下方的位图会被获取并复制到绘图表面,即hdcClient。

我不明白为什么它表现得像这样知道很明显传递给BitBlt的DC是hdcWindow,它指的是通过当前应用程序的GetWindowDC(hwnd)获得的设备上下文。

我首先想到的是,默认情况下启用了透明度模式,但是停用它并不会改变任何东西。 BitBlt似乎总是占据应用程序窗口下方的表面! 我不明白! :)任何人都知道为什么它的工作原理以及如何修复它?

自添加DWM(桌面窗口管理器,又称Aero)以来,使用BitBlt()制作屏幕截图并没有那么容易。 Petzold的示例代码存在一个微妙的计时问题,它很快就会截屏。 它是这样做的,而Aero仍然忙于动画框架,将其淡入视图。 因此,您可以看到窗口后面的内容,可能已经部分褪色,具体取决于生成第一个WM_PAINT消息的速度。

您可以通过禁用效果轻松修复它:

 #include  #include  #pragma comment(lib, "dwmapi.lib") 

在CreateWindow()调用之后:

 BOOL disabled = TRUE; DwmSetWindowAttribute(hwnd, DWMWA_TRANSITIONS_FORCEDISABLED, &disabled, sizeof(disabled)); 

另一个棘手的细节是第一个 BitBlt很重要,DWM之后返回一个缓存的副本,这个副本没有被动画正确地无效。

当您需要属于另一个进程的窗口的屏幕截图时,这会变得更加粗糙。 但这在Aero之前已经是一个问题,你必须等待足够长的时间以确保窗口完全涂漆。 值得注意的可能是BitBlt()的性能,它必须通过从窗口后缓冲区编写最终图像来明显陷入困境。 关于那个问题的很多问题,没有快乐的答案。

它不应该复制Windows图标,它应该复制图标所在的窗口标题栏部分。

这有一些问题(现在是20岁的代码):

  • 由于GetSystemMetrics返回经典大小而不是视觉样式大小,因此GetSystemMetrics值不能再用于与窗口相关的维度。

  • 根据Windows版本的不同, DWM可能会将窗口大小定义为大于窗口的大小(它绘制窗口阴影和其他效果的位置)。

您的示例在XP上正常工作:

XP

(有一个小问题,因为标题栏不是正方形(与此示例设计的Windows 98/2000不同),因此您在左上角看到一个问题,它只是白色。我还稍微修改了示例,因此它会改变HDC源位置)

在现代版本的Windows上,似乎DWM或其他东西无法正确模拟简单的窗口DC,阴影/边框/效果区域的一部分是DC的一部分:

Windows 8

我不知道如何解决这个问题,但无论如何这个例子都是无用的,如果你想绘制窗口图标,你应该用DrawIconEx绘制HICON。 如果你想绘制自定义非客户区域的东西,那么你需要找到更新的例子,而不是只支持经典主题的东西。