DeleteD会自动取消选择对象吗?

时间:2014-12-11 12:26:14

标签: winapi

我是否总是需要调用SelectObject将原始对象恢复为DC(并使我的对象可以删除),即使我即将删除DC ...?

e.g。

  // Create DC
  HBITMAP hBitmap = CreateCompatibleBitmap (hDC, rect.Width(), rect.Height());
  HGDIOBJ hOldBitmap = SelectObject(hMemDC, hBitmap);


  // ... Do some other stuff with the DC

  // DO I NEED THIS LINE HERE???
  SelectObject(hMemDC, hOldBitmap);

  // Tidy up
  DeleteDC(hMemDC);
  DeleteObject(hBitmap);  // This DOES return TRUE even without the SelectObject line...

'DeleteDC'是否会自动取消选择其中的对象,因此删除DC后可以删除它们?

由于

2 个答案:

答案 0 :(得分:3)

DC不会保留所选对象的历史记录。例如,考虑如果在绘制内容时多次SelectObject()使用不同的字体或画笔会发生什么。 DC仅知道当前对象,而不知道任何先前的对象。这就是为什么在释放DC之前,必须总是使用SelectObject()来恢复您替换的任何对象。 DeleteDC()不会为你做那次修复。

文档中明确说明了这一点:

SelectObject function

  

此函数返回先前选定的指定类型的对象。 在使用新对象完成绘制后,应用程序应始终使用原始默认对象替换新对象。

Operations on Graphic Objects

  

这些函数中的每一个都返回一个标识新对象的句柄。在应用程序检索句柄后,它必须调用SelectObject函数来替换默认对象。但是,应用程序应保存标识默认对象的句柄,并在不再需要时使用此句柄替换新对象。 当应用程序使用新对象完成绘制时,它必须通过调用SelectObject函数来恢复默认对象,然后通过调用DeleteObject函数删除新对象。未能删除对象会导致严重的性能问题。

DC拥有最初创建的对象。因此,它将在释放时释放所有当前选定对象,因为它期望原始对象。无法恢复原始对象将导致代码中的泄漏和可能的其他故障。

如果您要在绘图时替换/恢复多个对象,请考虑使用SaveDC()RestoreDC()来简化原始对象的恢复:

Saving, Restoring, and Resetting a Device Context

答案 1 :(得分:0)

我已经对这个主题进行了自己的调查。根据他们的说法,标记的答案是不准确的,至少在这个声明中是这样的:

<块引用>

A DC ... 将在释放时相应地释放任何当前选定的对象,因为它期待原始对象。

当你选择一个刚刚创建的内存位图到一个刚刚创建的内存 DC 时,内存 DC 并不拥有这个位图(至少,在内存管理的意义上) ) - 它将它标记为“已使用”,因此它不能被 DeleteObject 调用删除(可能,通过增加位图的一种引用计数)。如果您先删除内存 DC - 它不会删除内存位图:GetGuiResources(GR_GDIOBJECTS) 返回的对象计数减 1,即仅针对 DC 本身,而不是减 2(对于DC 和位图)。随后的 DeleteObject(hMemBitmap) 调用相应地减少了 GDI 对象计数。

至于 in this comment 中提到的“默认 1x1 位图泄漏”,似乎也是错误的:这个位图不是为每个内存 DC 单独创建的。相反,它是Raymond Chen很好解释的所谓“stock bitmap”:根据his "The mysterious stock bitmap" article,这个位图是GDI用于各种目的的单例,它是唯一可以选择到许多DC中的位图。除了将其选入 DC 之外,您无法删除它或以任何方式使用它。尽管 DeleteObject 在此位图的句柄上返回 TRUE,但它不影响 GDI 对象计数。在删除那个 DC 之前选择这个位图回到内存 DC 只是一种好习惯,实际上不是必需的:选择它会增加它的使用引用计数,然后删除 DC 会减少引用计数,这导致没有增益(参考值与从内存 DC 中“取消选择”库存位图后的值保持不变)。

我制作了一个 PoC 测试程序,并在各种版本的 Windows(从 WinXP SP3 到最新的 Win10 更新)中进行了检查 - 结果非常一致。

总结:

  • 原始问题的答案是“是的,确实如此”

  • // DO I NEED THIS LINE HERE??? 问题的答案是“不,您不知道 - 前提是您确定旧位图的句柄是库存位图的句柄”