【问题标题】:What happens if you release an unclean device context?如果释放不干净的设备上下文会发生什么?
【发布时间】:2014-04-12 08:25:18
【问题描述】:

通常,如果程序将对象选择到设备上下文中,或更改其属性,则应在释放设备上下文之前将其更改回来。如果不这样做会怎样?

假设我这样做:

HDC hdc = GetDC(some_window);
SelectObject(hdc, some_font);
SetTextColor(hdc, 0x123456);
SetBkColor(hdc, 0xFEDCBA);
SetROP2(hdc, R2_XORPEN);
ReleaseDC(some_window, hdc);

并且some_window 的窗口类没有CS_OWNDCCS_CLASSDC 标志。会发生什么?

【问题讨论】:

标签: c winapi gdi


【解决方案1】:

在您列出的函数中,SelectObject 是唯一一个如果未取消选择对象(通过选择原始对象)会导致问题的函数。这将导致 some_font 资源被泄露,因为 DC 在它被释放时会持有一个打开的句柄。

你应该这样做:

HDC hdc = GetDC(some_window);
HGDIOBJ hOldObj = SelectObject(hdc, some_font);

// ... 

SelectObject(hdc, hOldObj);
ReleaseDC(some_window, hdc);

或者这样:

HDC hdc = GetDC(some_window);
int nSaved = SaveDC(hdc);
SelectObject(hdc, some_font);

// ... 

RestoreDC(nSaved);
ReleaseDC(some_window, hdc);

作为MSDN notes

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

【讨论】:

  • 如果字体没有被销毁怎么办? (直到程序终止)
  • @immibis 如果字体没有用DeleteObject 销毁,实际上是资源泄漏。 DeleteObject 如果在对象仍被选入 DC 时调用它(可能)会失败。然而,在程序结束时,这可能无关紧要——但这不是一个好的做法。
  • 删除它的正确时间是程序结束时。是什么让操作系统删除它而不是显式删除它是一种不好的做法?但这与最初的问题相去甚远。
  • @immibis 明确删除意味着您知道自己在做什么,而不是依赖默认行为来进行整理。如果您的代码随后发生更改,则默认行为可能不再适用,并且不再需要您分配的资源的地点和时间将不明显。
【解决方案2】:

无法恢复原始字体对象会导致句柄泄漏。操作系统将保留 some_font 的句柄。如果重复执行此代码,则每次都会泄漏另一个句柄。您将看到任务管理器中的句柄计数正在增加。如果这种情况持续很长时间,最终会出现显示为垃圾的绘画失败。

【讨论】:

    猜你喜欢
    • 2021-12-31
    • 2011-03-19
    • 1970-01-01
    • 2011-01-03
    • 1970-01-01
    • 2018-02-10
    • 2022-01-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多