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

时间:2018-01-02 22:23:31

标签: c windows winapi

我现在正在使用Petzold的书(第5版)回到一些Windows编程。 我使用BitBlt编译了following example并且它不能正常工作。

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

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

我首先认为这是由于默认情况下启用了透明度模式,但是停用它并不会改变任何内容。 BitBlt似乎总是占据应用程序窗口下方的表面! 我不明白! :) 任何人都知道它为什么会这样运作以及如何解决它?

2 个答案:

答案 0 :(得分:7)

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

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

#include <windows.h>
#include <dwmapi.h>
#pragma comment(lib, "dwmapi.lib")

在CreateWindow()调用之后:

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

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

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

答案 1 :(得分:4)

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

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

  • GetSystemMetrics值不能再用于与窗口相关的维度,因为GetSystemMetrics会返回经典尺寸,而不是视觉样式尺寸。

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

您的示例在XP上运行正常:

XP

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

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

Windows 8

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