Rom*_*098 5 windows winapi gdi
我正在研究一些传统的Win32/MFC项目.
我发现了以下(伪代码):
HDC hDC = ::CreateCompatibleDC(hDCWnd);
HANDLE hFileMap = ::CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, dwSize, FileMapName);
HBITMAP hBmp = ::CreateDIBSection(hDCWnd, &zBI, DIB_RGB_COLORS, &pvNull, hFileMap, 0);
::SelectObject(hDC, hBmp);
::DeleteObject(hBmp);
::CloseHandle(hFileMap);
// .. do something with hDC ..
::DeleteDC(hDC);
Run Code Online (Sandbox Code Playgroud)
这对我来说很奇怪.任何人都可以解释一下,在我对DC做某事之前删除位图和/或关闭文件句柄是否正确?
谢谢.
不,这不对.代码调用SelectObject()将位图选择到设备上下文中,然后调用DeleteObject()以尝试删除位图,同时仍在设备上下文中选择该位图.在这种情况下,DeleteObject()将失败,因此位图泄露.
http://msdn.microsoft.com/en-us/library/dd183539(v=vs.85).aspx
"当它仍然被选择到设备上下文中时,不要删除绘图对象(笔或画笔)."
编辑:
嗯,这很有趣.我尝试DeleteObject()在设备上下文中选择位图时调用,它也为我返回1.有趣的是,此时实际上并未删除位图; 调用GetObject()"已删除"位图成功!但是,只要从设备上下文中选择了删除的位图,就会将其删除; 此时呼叫GetObject()失败.我还通过观察任务管理器中的GDI句柄计数来验证.因此,DeleteObject()如果位图当前被选择到设备上下文中,显然会推迟删除,尽管我不认为这在任何地方都有记录.
HDC hdc = CreateCompatibleDC(NULL);
if (hdc != NULL) {
HBITMAP hBitmap = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_SAMPLE));
BITMAP bm = { 0 };
int numBytes;
// this succeeds as expected
numBytes = GetObject(hBitmap, sizeof(BITMAP), &bm);
HBITMAP hOldBitmap = SelectBitmap(hdc, hBitmap);
DeleteObject(hBitmap);
// this succeeds -- NOT expected!
numBytes = GetObject(hBitmap, sizeof(BITMAP), &bm);
SelectBitmap(hdc, hOldBitmap);
// this fails as expected
numBytes = GetObject(hBitmap, sizeof(BITMAP), &bm);
DeleteDC(hdc);
}
Run Code Online (Sandbox Code Playgroud)
最重要的是,您发布的代码似乎有效,但依赖于未记录的行为.我倾向于安全地发挥它并消除这种依赖性.
Raymond Chen的The Old New Thing中有一篇相关文章解释了这种行为:
GDI人员发现很多人陷入困境并试图摧毁对象,而他们仍被选入DC.未通过电话会导致两类问题:一些应用程序只是泄漏了资源(因为他们认为它们正在销毁对象,但却没有).其他应用程序检查了返回值,如果他们发现DeleteObject实际上没有删除该对象,则会吓坏.
为了让这两种类型的应用程序都满意,GDI有时(并非总是)说谎,"当然,我删除了你的对象." 它实际上并没有删除它,因为它仍然被选中为DC,但它也会在其手指上绑一个字符串,当最终取消选择对象时,GDI会说:"哦,等等,我应该删除这个对象,"并执行删除.因此,GDI所做的谎言不是谎言,而是对未来的"乐观预测".
http://blogs.msdn.com/b/oldnewthing/archive/2013/03/06/10399678.aspx