CDCクラスのSelectObjectしたものの解放

[戻る]
ナオーバ 2002/12/19(木) 11:14:13
あるDLしたのソースに

 CPaintDC dc(this);
 CDC* pDCMem = new CDC;
 pDCMem->CreateCompatibleDC(&dc);

 HGDIOBJ hOld;
 hOld = pDCMem->SelectObject(m_otOption->GetBoldFont());
 pDCMem->SelectObject(hOld);
とあります(抜粋です)

m_otOption->GetBoldFont()はCFont*が返ってきます

CDCクラスのSelectObjectはクラスのポインタが返ってきますが
このソースでは HGDIOBJ に格納しています

こんな事でいいんでしょうか?

HGDIOBJをやめてCFont*にしてしまうか、
やめないで pDCMem->SelectObject((CFont *)hOld);

こうすべきなんでしょうか?

dairygoods 2002/12/19(木) 11:30:14
> こんな事でいいんでしょうか?
良くありません!!(^^;

typedef void* HGDIOBJ;
なので、CFont*をHGIDOBJへ代入できてしまうんですね。

SelectObject(hOld)のほうは、
不正なハンドルが来たと思ってエラーになっているはずです。


> HGDIOBJをやめてCFont*にしてしまうか、
この方法が良いと思います。


>やめないで pDCMem->SelectObject((CFont *)hOld);
これでも正しく動きますが、
見る人をさらに混乱させます…。

ナオーバ 2002/12/19(木) 12:16:21
ありがとうございます

>不正なハンドルが来たと思ってエラーになっているはずです。
NULLが返ってきていました

ついでにすみません。
このバグによって何が起きるか予想はつかないですよね?

リソースが解放されていなければ、リソース不足になるのかな?

実際DLした物を組み込んで作成したソフトで9x系で終了時に落ちる現象があるのですが
これが直接の原因かどうかは判断できないですよね?

dairygoods 2002/12/19(木) 12:48:55
デバイスコンテキストに選択された状態ではGDIを削除できないので、
m_otOption->GetBoldFont()が毎回新しいフォントを作っているのであれば、
リソースをどんどん消費して、リソース不足になると思います。

リソース不足になるとメニューやアイコンが表示されなくなったりしますが、
終了時に落ちる直接的な原因にはならないと思います。
リソースを当然獲得できると思って書かれているコードで
落ちる可能性はありますね。

ナオーバ 2002/12/19(木) 14:26:12
ありがとうございます

m_otOption->GetBoldFont()は毎回新しいフォントは作成していません
m_otOptionのクラスのメンバのアドレスを返します

>終了時に落ちる直接的な原因にはならないと思います。
そうですか。

でもバグなのでHGDIOBJをやめてCFont*に修正中なんですが、
以下のような場合きちんと解放されているのでしょうか?

 HGDIOBJ hOldBrush = pDCMem->SelectObject(GetSysColorBrush(COLOR_BTNFACE));
 pDCMem->SelectObject(hOldBrush);

MSDN(VC付属の物)には載っていないのですが、
SelectObjectにHGDIOBJを渡せるようです、HGDIOBJが返ってきます

このソースの場合GetSysColorBrushによってHBRUSHを選択させ、HGDIOBJで解放しています
 pDCMem->SelectObject(hOldBrush);
で、エラーはでていませんが解放できているのでしょうか?

 HBRUSH hOldBrush = (HBRUSH)pDCMem->SelectObject(GetSysColorBrush
(COLOR_BTNFACE));
 pDCMem->SelectObject(hOldBrush);
にすべきでしょうか?

何度もすみませんがお願いします。

Bun 2002/12/19(木) 16:21:31
>このソースの場合GetSysColorBrushによってHBRUSHを選択させ、HGDIOBJで解放しています
> pDCMem->SelectObject(hOldBrush);
>で、エラーはでていませんが解放できているのでしょうか?

横から失礼します。m(__)m

上記のコードは「GDIオブジェクトをもとに戻しておく」ということであって
リークとは直接関係ないと思います。

GetSysColorBrush()のヘルプを読むと「ブラシを削除してはいけない」
と書いてありますので、リークの心配はないと思います。

違っていたら、ご指摘をお願いします。

Bun 2002/12/19(木) 16:24:46
>GetSysColorBrush()のヘルプを読むと「ブラシを削除してはいけない」
>と書いてありますので、リークの心配はないと思います。

おそらくブラシを Create() しているわけではないので、削除する必要は
なく、リークの心配はないということですね。

BQ 2002/12/20(金) 00:34:24
はじめまして。

> HBRUSH hOldBrush = (HBRUSH)pDCMem->SelectObject(GetSysColorBrush
>(COLOR_BTNFACE));
> pDCMem->SelectObject(hOldBrush);
>にすべきでしょうか?

正しい動作をしているのであれば、別にこれでも構わないと思いますが、マニュアル掲
載外のものは保証された用法ではないので、個人的には

CBrush* pOldBrush = pDCMem->SelectObject(CBrush::FromHandle(::GetSysColorBrush
(COLOR_BTNFACE)));
pDCMem->SelectObject(pOldBrush);

のようにしておくのが正当なやり方だと思います。

あと、GetSysColorBrush() はウインドウ等を描画するためにシステムが持っているブ
ラシオブジェクトのハンドル(の複製?)を取得するだけなので、Bunさんのおっしゃる
とおり元に戻すだけでよいと思います。

dairygoods 2002/12/20(金) 11:03:13
最初の例のように、オブジェクトのポインタとHGDIOBJが混在すると
バグの元になりますから、MFCを使用している場合は、
MFCのクラスだけ使ったほうが安全だと思います。

CBrush::FromHandle()で良いですが、
CBursh::CreateSysColorBrush()なんてのもありますね。
#古いMSDNの説明は完全に間違ってる…。

CBrush brush;
brush.CreateSysColorBrush(COLOR_BTNFACE);
CBrush* pOldBrush = pDCMem->SelectObject(&brush);
...

ナオーバ 2002/12/20(金) 12:28:15
皆さんありがとうございます。

dairygoodsさんの方法でMFCのクラスだけ使うように変更します

CreateSysColorBrushにCOLOR_BTNFACEを渡すことができるんですね
VC付属のMSDNにはないので、いつのMSDNにのっているのでしょう?
もしかして、他にもこのようにVC付属には無いけど新しいのでは
変更されているのってあるんですかね?

古いスレッドには追加発言できません。