CDCクラスのSelectObjectしたものの解放 – プログラミング – Home

通知
すべてクリア

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


ナオーバ
 ナオーバ
(@ナオーバ)
ゲスト
結合: 23年前
投稿: 187
Topic starter  

ある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
 dairygoods
(@dairygoods)
ゲスト
結合: 23年前
投稿: 1421
 

> こんな事でいいんでしょうか?
良くありません!!(^^;

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

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

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

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


返信引用
ナオーバ
 ナオーバ
(@ナオーバ)
ゲスト
結合: 23年前
投稿: 187
Topic starter  

ありがとうございます

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

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

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

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


返信引用
dairygoods
 dairygoods
(@dairygoods)
ゲスト
結合: 23年前
投稿: 1421
 

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

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


返信引用
ナオーバ
 ナオーバ
(@ナオーバ)
ゲスト
結合: 23年前
投稿: 187
Topic starter  

ありがとうございます

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
 Bun
(@Bun)
ゲスト
結合: 24年前
投稿: 761
 

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

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

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

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

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


返信引用
Bun
 Bun
(@Bun)
ゲスト
結合: 24年前
投稿: 761
 

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

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


返信引用
BQ
 BQ
(@BQ)
ゲスト
結合: 22年前
投稿: 2
 

はじめまして。

> 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
 dairygoods
(@dairygoods)
ゲスト
結合: 23年前
投稿: 1421
 

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

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

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


返信引用
ナオーバ
 ナオーバ
(@ナオーバ)
ゲスト
結合: 23年前
投稿: 187
Topic starter  

皆さんありがとうございます。

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

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


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました