疑問
現在MFCでWindowsアプリケーションを開発している者です。
Win32APIの公式ドキュメントで、::DeleteObjectのページに
指定したハンドルが有効でない場合、または現在 DC に選択されている場合、戻り値は 0 です。
描画オブジェクト(ペンまたはブラシ)は、DC で選択されている間は削除しないでください。
と記述がありました。
https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-deleteobject
MFCにおいてもそれは同様と思い、GDIオブジェクトを解放するときはCDC::SelectObject → CGdiObject::DeleteObjectの順番で呼ぶようにしていました(DeleteObjectはCGdiObjectのデストラクタで呼ばれることも認識しています)。
ところが、この順番でなくても正しくGDIオブジェクトは解放されていることに気づき、疑問が生まれ調べましたが、有効な手掛かりが得られず、質問に至っています。
以下に詳細を書いていきます。
実験用のソースコード
C++
1// View.cpp 2 3// MFCのクラスを用いた実験 4void ResourceLeakTest1(CDC& dc); 5 6//Win32APIを用いた実験 7void ResourceLeakTest2(CDC& dc); 8 9static const int penNumber = 5000; 10 11// DeleteObjectを自分で呼ぶためstatic変数 12static CPen pens[penNumber]; 13 14void MyView::OnDraw(CDC* pDC) 15{ 16 ResourceLeakTest1(*pDC); 17 ResourceLeakTest2(*pDC); 18} 19 20void ResourceLeakTest1(CDC& dc) 21{ 22 for (int index = 0; index < penNumber; index++) 23 { 24 pens[index].CreatePen(PS_SOLID, 0, RGB(200, 200, 0)); 25 CPen* oldPen = dc.SelectObject(&pens[index]); 26 27 // 適当にたくさん円を描く 28 dc.Ellipse(CRect(CPoint(10 + index * 2, 10 + index * 2), CPoint(30 + index * 2, 30 + index * 2))); 29 30 // SelectObjectより先にDeleteObjectを呼んでみる。 31 BOOL result = pens[index].DeleteObject(); 32 33 // 予想では、resultはFALSEになり、ASSERTに引っ掛かる。 34 // 仮に引っ掛からなかったとしても、この関数を抜けたときに 35 // 5000個のGDIオブジェクトのリソースリークが起きている。 36 ASSERT(result != FALSE); 37 38 dc.SelectObject(oldPen); 39 } 40} 41 42static HPEN hPens[penNumber]; 43 44void ResourceLeakTest2(CDC& dc) 45{ 46 HDC hdc = dc.GetSafeHdc(); 47 for (int index = 0; index < penNumber; index++) 48 { 49 hPens[index] = ::CreatePen(PS_SOLID, 5, RGB(255, 0, 0)); 50 HPEN hOldPen = (HPEN)::SelectObject(hdc, hPens[index]); 51 52 // 適当に直線をたくさん描く 53 ::MoveToEx(hdc, 100 + index * 2, 10, NULL); 54 ::LineTo(hdc, 10, 100); 55 56 // 先ほどと同様 57 BOOL result = ::DeleteObject(hPens[index]); 58 ASSERT(result != 0); 59 60 ::SelectObject(hdc, hOldPen); 61 } 62} 63 64
実際に起こっていること
GDIオブジェクトのリソースリークは、タスクマネージャーの詳細タブにある「GDIオブジェクト」列で確認しています。
ResourceLeakTest1は、MFCのクラスを用いた実験です。
ソースコード中のコメントに書いた自分の予想に反して、ASSERTに引っ掛からず(DeleteObjectは1を返している)、GDIオブジェクトのリソースリークも起きていませんでした(penNumberの数だけGDIオブジェクトが増えなかった)。
ResourceLeakTest2はWin32APIを使った実験です。こちらも、同様の結果となりました。
なお、ソースコード中のDeleteObjectをコメントアウトすると、当たり前ですがGDIオブジェクトがpenNumberの数だけ(今回は5000個)増えました。
教えていただきたいこと
なぜ、リソースリークが起きないのでしょうか。
また、公式にこのことについて言及している記事があれば教えてください。
よろしくお願いいたします。

回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2022/11/04 06:18
2022/11/04 06:30
2022/11/04 06:47
2022/11/04 07:07