我是不是需要调用 SelectObject() 来恢复使用 GetStockObject() 检索的对象?

Posted

技术标签:

【中文标题】我是不是需要调用 SelectObject() 来恢复使用 GetStockObject() 检索的对象?【英文标题】:Do I need to call SelectObject() to restore a object retreived with GetStockObject()?我是否需要调用 SelectObject() 来恢复使用 GetStockObject() 检索的对象? 【发布时间】:2020-07-21 06:12:09 【问题描述】:

我正在使用 MFC...

当我创建一个新画笔时,我知道我需要使用 SelectObject 恢复旧灌木:

CBrush brushFill;
brushFill.CreateSolidBrush(colorFill);
CBrush *oldBrush = pDC->SelectObject(&brushFill);
// Draw something here.
pDC->SelectObject(oldBrush);

但是,如果我使用 GetStockObject() 获取画笔,是否也需要恢复它?

CBrush *oldBrush = (CBrush *)pDC->SelectObject(GetStockObject(HOLLOW_BRUSH));
// Draw something here.
pDC->SelectObject(oldBrush);

我问,因为该代码偶尔会崩溃。我不确定这是否是因为我不应该保存/恢复库存物品,或者我的类型转换为 CBrush*。如果是后者,我想我应该保存/恢复一个 HGDIOBJ 句柄:

HGDIOBJ oldBrush = pDC->SelectObject(GetStockObject(HOLLOW_BRUSH));
// Draw something here.
pDC->SelectObject(oldBrush);

如果是前者,我不会保存/恢复之前的对象。

【问题讨论】:

【参考方案1】:

您应该始终使用CDC 对象的SaveDC()RestoreDC() 成员函数将设备上下文上的任何操作“括起来”:

int DCsave = pDC->SaveDC(); // Saves all (or most) settings and object selections
// ... Do your drawing operations, etc.
pDC->RestoreDC(DCsave);     // Restores the saved state and all selected objects

另外,仅供参考,您可能会发现SelectStockObject() 成员更易于使用:

pDC->SelectStockObject(HOLLOW_BRUSH);

注意(来自IInspectable 的评论):尽管取消选择 GDI 'Stock Objects' 可能似乎 不必要(毕竟,默认情况下会选择其中的几个),其他代码可能依赖于选择前一个对象(在您的情况下为画笔);因此,未能恢复此选择可能会导致该代码以几乎无法追踪的方式失败。

【讨论】:

那里有危险的建议。每个SelectObject 调用涉及两个对象:当前选择到设备上下文中的对象和即将选择的对象。在将设备上下文返回给您之前,总是需要将设备上下文恢复到它被交给您的状态。其他代码将对选择到此设备上下文中的对象的所有权和生命周期做出假设。未能恢复设备上下文将导致完全有效的代码失败。 @IInspectable 好点——而且我不能(也不会)与之争论!我已经编辑了我的答案以反映 需要(而不仅仅是 首选项)来保存/恢复设备上下文。我希望你同意。 这表达了更简洁的陈述。不过,我很好奇,评论的 "(or most)" 部分指的是什么?是否存在SaveDC/RestoreDC 不考虑的客户端控制资源? @IInspectable 好吧,没有那么多 resources,但是,例如,当前位置(MoveTo(x,y) 使用的)是否被保存?我不知道,TBO,这就是我添加“最”的原因。

以上是关于我是不是需要调用 SelectObject() 来恢复使用 GetStockObject() 检索的对象?的主要内容,如果未能解决你的问题,请参考以下文章

Windows API一日一练 29 SelectObject和DeleteObject函数

SelectObject

SelectObject()函数

删除CreateFont创建的字体

PHP:扩展类是不是需要另一个“使用”来调用命名空间?

使用 Moq 来验证调用是不是以正确的顺序进行