WinXP(SP2) VC++2003 MFC
はじめまして独学でVCを勉強している yuki といいます。
このサイトを見てスクロールビューにて裏画面と背景の塗りつぶしをなくして
ちらつきをなくして描画を行うことに成功したのですが、フレームサイズを変更した
場合に最初のサイズのまま描画サイズを変更できないためOnSizeとOnInitialUpdate()
にMDCの初期化を分散させて解決しようとしています。
このときOnSize内で作成したbitmapのメモリが開放できずリークしてしまいます。
独力でいろいろ考えましたがどうしてもよい案が浮かびません、ご助力願えたらと思い
書き込みさせていただきました。
以下ソース**
OnInitialUpdate()内
CDC *pDC;//通常のデバイスコンテキストを格納するポインタ
pDC=GetDC();
dcMem.CreateCompatibleDC(pDC);
ReleaseDC(pDC);
flag_Init = 1;//OnInitialUpdate()以前にOnSizeが呼ばれるのを避ける
OnSize(0,0,0);
***OnSize()内
if(flag_Init == 1)
{
// 描画領域をクライアント領域に従って変更
CDealingRoomApp *mainInf = (CDealingRoomApp*)AfxGetApp();
CSize sizeTotal;
CRect lpRect;
GetClientRect(lpRect);//クライアント領域
sizeTotal.cx = mainInf->Date.GetCount() * (ViewSizeRousokuWidth +
ViewSizeRousokuSplit * 2);
sizeTotal.cy = lpRect.Height();
//TRACE(scWidth : %d scHeight : %d\n,sizeTotal.cx, sizeTotal.cy);
SetScrollSizes(MM_TEXT, sizeTotal);
//メモリーデバイスコンテキストの準備
CDC *pDC;//通常のデバイスコンテキストを格納するポインタ
CRect cClient;//クライアント領域
CBrush cBrush;//ブラシ
// ビットマップオブジェクトの動的確保
//pBitmap->DeleteObject();
pBitmap = new CBitmap();
// クライアント領域の取得
GetClientRect(&cClient);
// 現在のDCのポインタを取得
pDC=GetDC();
// 通常のDCとメモリDCに互換性をつける
//dcMem.DeleteDC();//反復処理のための削除
//dcMem.CreateCompatibleDC(pDC);
// 通常のDCの互換性のあるビットマップをメモリ上に作成
//DeleteObject(pBitmap);//pBitmap->DeleteObject();//
pBitmap->CreateDiscardableBitmap(pDC,cClient.Width(),cClient.Height());
//※※※↑これのせいでリークが起こっているようです。※※※
//ビットマップとメモリDCの関連付け
pOldBitmap = dcMem.SelectObject(pBitmap);
//白のBrushを作成
cBrush.CreateSolidBrush(RGB(255,255,255));
//現在のbrushのポインタをpOldBrushとして残しておく
pOldBrush=dcMem.SelectObject(&cBrush);
// クライアント領域でbitmapをコピー
dcMem.PatBlt(0,0,cClient.Width(),cClient.Height(),PATCOPY);
//昔のBrushに戻す
dcMem.SelectObject(pOldBrush);
//DCを解放
ReleaseDC(pDC);
}
ソース終わり*****
CreateDiscardableBitmapで確保したメモリが開放できていないのが理由だと
思うのですが開放する方法がわかりませんでした。
初心者な質問かもしれませんがよろしくお願いします。
CreateDiscardableBitmapを使っている意図は何なんでしょう?
普通にCreateCompatibleBitmapではいけないのでしょうか?
CreateDiscardableBitmapはDCに選択されていなければ、
Windows OSが勝手に破棄してしまうようです。
既に破棄されている物を破棄しようとして失敗しているだけではないですか?
使用している関数の意味を良く調べてみる事をお勧めします。
もしその関数を使っている意味が理解できないのであれば、
きちんと理解できるまで調べましょう。
追記:
pBitmapという変数について全く説明がありません。
書かれている内容から察するに多分メンバー変数なんだと思いますが、
上の例からはそれが読み取れる記述がありません。
もしメンバー変数でないのであれば、確保したビットマップクラスの
ポインタはどこかに消失してしまうと思いますが、
どうなんでしょう。
早速の返信ありがとうございます。
ヘッダー内の記述が足りませんでした。
ヘッダ内で大域変数として以下のものを用意しています。
BOOL flag_Init;//初期化が行われるまでOnSize等を呼び出さないためのフラグ
CDC dcMem; // メモリデバイスコンテキスト
CBrush *pOldBrush;//ブラシのストック変数
CBitmap* pOldBitmap; // ストックビットマップ
CBitmap* pBitmap; // ビットマップ
最初はPATIOさんの言うように
CreateCompatibleBitmap
でも、やはり同じようにリークが起こります。
WEBで検索をしていると
「CreateDiscardableBitmap関数は、 廃棄可能ビットマップを作成します。
CreateBitmap関数、 CreateCompatibleBitmap関数、 CreateBitmapIndirect関数は、
廃棄不可能ビットマップを作成します。」
参照元(Googleキャッシュ): http://66.102.7.104/search?
q=cache:FpNlSNgLel4J:www.topposystem.co.jp/prog/dl/Win32API/GUI/BITMAP.html+Cre
ateDiscardableBitmap+CreateCompatibleBitmap&hl=ja&ct=clnk&cd=2&lr=lang_ja
という記述がありましたのでCreateCompatibleBitmapではメモリ開放ができないのかと
思い
CreateDiscardableBitmap
を使用した次第です。
CreateCompatibleBitmap
で再度検証してみましたがやはり結果は変わりません。
なにか他の原因は考えられないでしょうか?
> pBitmap = new CBitmap();
↑これに対応する delete は…?
// ビットマップオブジェクトの動的確保
//pBitmap->DeleteObject();
pBitmap = new CBitmap();
ここで、古いのを delete し忘れているということではないですか?
確かにnewしているのにdeleteしてませんね。
他のところでdeleteしているとも思えないから多分これでしょうね。
pBitmap->DeleteObject();は、GDIリソースを削除するのであって
CBitmapクラスのインスタンスを破棄するわけではないですからね。
CBitmapクラスのインスタンスをdeleteで破棄すれば、
CBitmapクラスのデストラクタが走ってDeleteObjectもやってくれたと思います。
あまりにメモリに関して無知なのをあらためて思い知りました。
delete pBitmap;を挿入して解決できました。
PATIOさん、Kerryさん、dairygoodsさん
ありがとうございました。