GDI:原始 DC 位图更改,无法恢复
Posted
技术标签:
【中文标题】GDI:原始 DC 位图更改,无法恢复【英文标题】:GDI: Original DC bitmap changes, and can't restore 【发布时间】:2018-01-15 12:36:10 【问题描述】:我看到一个问题,我无法在 DC 上重新选择原始位图,从而导致内存泄漏。指向原始位图的指针在整个程序中保持不变,但数据(来自 CBitmap::GetBitmap)从单色变为其他内容。我不知道位图何时真正改变,但系统中的某些东西导致了它。
CBitmap* cMyClass::mpOldBitmap;
CDC cMyClass::mCanvasDc;
CBitmap cMyClass::mCanvasBmp;
void cMyClass::Init()
// One-time initialization
CDC* pDc = GetDC();
mCanvasDc.CreateCompatibleDC(pDc);
mCanvasBmp.CreateCompatibleBitmap(pDc, 10, 10);
mpOldBitmap = mCanvasDc.SelectObject(&mCanvasBmp);
ReleaseDC(pDc);
BITMAP bitmap;
mpOldBitmap->GetBitmap(&bitmap); // A monochrome bitmap, as expected.
void cMyClass::Recreate(int newW, int newH)
// 1. Delete existing bitmap:
if (mpOldBitmap)
BITMAP bitmap;
mpOldBitmap->GetBitmap(&bitmap); // This is no longer the monochrome bitmap. It is 8bpp, with random size.
CBitmap* pCurrBmp = mCanvasDc.SelectObject(mpOldBitmap); // This fails (NULL). I can't de-select my bitmap.
mCanvasBmp.DeleteObject(); // This fails too, causing memory leak. Actually, it fails in CE6, but not in Win32. Regardless, both platforms will have a memory leak.
// 2. Recreate the bitmap with new size:
CDC* pDc = GetDC();
mCanvasBmp.CreateCompatibleBitmap(pDc, newW, newH);
ReleaseDC(pDc);
// 3. Finalize
mpOldBitmap = mCanvasDc.SelectObject(&mCanvasBmp);
-
任何已知的可能发生这种情况的场景?
位图数据发生变化时有什么调试技巧可以破解?
注意:在代码中,我提到了“这失败了”。我删除了返回值上的断言以使代码可读。
编辑:我用来修复它的解决方案是使用 CDC:SaveDC 和 CDC::RestoreDC 而不是存储指针。内存泄漏消失了,每个 GDI 调用都通过了。但是我还是很好奇为什么原始代码会泄露。据我所知,指向默认位图的指针应该是默认的单色位图,在 GDI 世界中可能是全局的
【问题讨论】:
minimal reproducible example 必填。 我认为你的问题是你不能像这样操作(重新创建)一个实例变量。您需要一个指向 CBitmap 的指针,即 CBitmap* mCanvasBmp 并“删除”它并像 mCanvasBmp = new CBitmap 每次一样重新创建它。 【参考方案1】:让我们看看 OP 的代码。
mpOldBitmap = mCanvasDc.SelectObject(mCanvasBmp);
因为 mCanvasBmp 是一个 CBitmap 对象(不是指向 CBitmap 的指针),所以首先调用 HGDIOBJ 运算符,然后是返回 HGDIOBJ 的 CDC::SelectObject(HGDIOBJ) 和不是 CBitmap*。这应该会产生转换编译器错误。如果将返回值转换为 CBitmap* 也是错误的。
摆脱问题的正确方法是传递指针。
mpOldBitmap = mCanvasDc.SelectObject(& mCanvasBmp);
这种情况将被称为 CDC::SelectObject(CBitmap* pBitmap),它返回一个 CBitmap*。
// 我希望它很清楚。 :)
【讨论】:
对不起,这是我在尝试简化 SO 代码时的拼写错误。我已经更正了描述。我还添加了我找到的解决方案,但我仍然很好奇为什么原来的解决方案不起作用。以上是关于GDI:原始 DC 位图更改,无法恢复的主要内容,如果未能解决你的问题,请参考以下文章
什么是,为什么我必须在清理时将位图 hdc 或内存 dc 恢复到默认状态? [复制]
如何使用 Powershell 更改 Windows 10 中的电源计划并在长脚本后恢复为原始设置?