1170177249 (環境VC++6)下記描画処理を繰返行った時に

LoadImageでhBitmapにNULLが入る場合があります。
この場合は再度LoadImageを呼ぶようにしていますが
またhBitmapにNULLが入ってしまい、BMPが読めません。
どのような原因でこのような症状が発生するのか
教えていただきたくお願いします。

<補足>
・BMP連続描画を行うことができるが、なんらかの条件により失敗している。
 (原因は不明。描画回数or描画間隔が原因かも)
・10回以上描画した後にメモリリークなし
・デバッグmodeで確認したとき問題発生後に、添付画像の警告が出た。

<ソース>
HBITMAP hBitmap = (HBITMAP)::LoadImage(AfxGetInstanceHandle(),(LPCSTR)csBmpName,IMAGE_BITMAP,0,0,LR_LOADFROMFILE | LR_CREATEDIBSECTION);
static BITMAP bmpBack;
if(hBitmap == NULL)return FALSE;
GraphicMap.Attach(hBitmap);
GetObject(hBitmap , sizeof(BITMAP) , &bmpBack);
CDC cdcSubDC;
cdcSubDC.CreateCompatibleDC(pDC);
CBitmap* oldBMP=cdcSubDC.SelectObject(&GraphicMap);
cdcMain->SetStretchBltMode(COLORONCOLOR) ;

if(0==cdcMain->StretchBlt(iXzahyou,iYzahyou,iMainYoko,iMainTate,
&cdcSubDC,iXzahyou*bmpBack.bmWidth/iMainYoko,iYzahyou*bmpBack.bmHeight/iMainTate,
iMainYoko*bmpBack.bmWidth/iMainYoko,iMainTate*bmpBack.bmHeight/iMainTate,SRCCOPY)){
iReturnValue=FALSE;
}
cdcSubDC.SelectObject(oldBMP);

回答の条件
  • URL必須
  • 1人5回まで
  • 登録:
  • 終了:2007/02/04 10:02:13
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

ベストアンサー

id:SevenS No.2

回答回数51ベストアンサー獲得回数3

ポイント50pt

読み込まれたhBitmapは、StretchBltの後再利用されていないので、DeleteObjectで削除すべきではないでしょうか?

頭にHのつくハンドルと呼ばれるものはWindowsサイドで管理しているものなので、メモリリークとしては現れなかったような気もします。

念のため、LoadImageの結果がNULLのとき、GetLastErrorを取得することをオススメします(FormatMessageと併用するとなおGood)。

もしかすると解決の糸口が見つかるかもしれません。

それと、お節介かも知れませんがいくつか。

  1. cdcSubDC.CreateCompatibleDCの引数は、pDCではなくcdcMainがふさわしいのでは?
  2. 読み込みは、HBITMAP LoadBitmap( LPCTSTR lpszFileName )のような関数に処理をまとめた方が楽

ただ、この部分の処理は重いので、OnPaintなどには使わない方がいいかもしれませんね。

備考: VC++7.0以降なら、MFCのCImageクラスを使って、

LPCTSTR lpszFileName = TEXT( "bitmap.bmp" );
CImage image;
image.Load( lpszFileName );
image.StretchBlt(
    cdcMain->GetSafeDC(),
    iXzahyou, iYzahyou,
    iMainYoko, iMainTate,
    iXzahyou * image.GetWidth() / iMainYoko,
    iYzahyou * image.GetHeight() / iMainTate,
    image.GetWidth(), image.GetHeight() );

とできるようです。

http://www.geocities.jp/chiakifujimon/makesoft2/proc4.html

id:harunoharuno

いろいろと、教えていただきありがとうございます。

GetLastErrorとFormatMessageを併用したところ

『このコマンドを実行するのに十分な記憶域がありません』とでていました。

やはり、ご指摘いただいているhbitmap等のリソース開放処理がないためかな?

>>cdcSubDC.CreateCompatibleDCの引数は、pDCではなくcdcMainがふさわしいのでは?

pDCはcdcMainのアドレスが入っているので、cdcMainと同じです。

>>読み込みは、HBITMAP LoadBitmap( LPCTSTR lpszFileName )のような関数に

>>処理をまとめた方が楽

確かにそうしたほうがソースも読みやすいですね。

コーディングに対する指摘も参考になり大変ありがたいです。

他にまた気になる点などありましたらまた、ご指摘いただきたくよろしくお願いします。


>>頭にHのつくハンドルと呼ばれるものはWindowsサイドで管理しているものなので、メモリリークとしては現れなかったような気もします。

あれっっ

ひょっとしてHICONなども開放する必要がありますか?

2007/01/31 18:52:20

その他の回答2件)

id:TONTON3 No.1

回答回数212ベストアンサー獲得回数4

ポイント40pt

http://rararahp.cool.ne.jp/cgi-bin/lng/vc/vclng.cgi?print+200607...

oldBMPのDeleteObject

cdcSubDCのDeleteDc

が抜けてませんか?

id:harunoharuno

回答ありがとうございます。試してみても改善しませんでしたが

そこに問題があるのかもしれませんね。

私が用いている教科書(新VisualC++6.0入門ビギナー編)には、oldBMPや

cdcSubDCを削除するように書かれていませんでしたので

教えていただいたコードを追加する必要性について説明していただきたくよろしくお願いします。

それと、下記のように私の理解に基づきコメントを追加しました。

何か不自然なところなどありましたらご指摘いただけると嬉しいです。

よろしくお願いします。

HBITMAP hBitmap = (HBITMAP)::LoadImage(ファイル名等)  //ビットマップロード

if(hBitmap == NULL)return FALSE;            //ロードできなかったらReturn

GraphicMap.Attach(hBitmap);               //GraphicMapとビットマップの関連付け

GetObject(hBitmap , sizeof(BITMAP) , &bmpBack);

CDC cdcSubDC;                      //裏画面作成

cdcSubDC.CreateCompatibleDC(pDC);            //裏画面にメイン画面(pDC)との互換性を持たせる

CBitmap* oldBMP=cdcSubDC.SelectObject(&GraphicMap);   //裏画面とGraphicMapの関連付け

cdcMain->SetStretchBltMode(COLORONCOLOR);        //

//メイン画面に裏画面の画像を描画

if(0==cdcMain->StretchBlt(iXzahyou,iYzahyou,iMainYoko,iMainTate,

&cdcSubDC,iXzahyou*bmpBack.bmWidth/iMainYoko,iYzahyou*bmpBack.bmHeight/iMainTate,

iMainYoko*bmpBack.bmWidth/iMainYoko,iMainTate*bmpBack.bmHeight/iMainTate,SRCCOPY)){

iReturnValue=FALSE;

}

cdcSubDC.SelectObject(oldBMP); //なぜそうするのか

                            //理解していない参考書どおり

  • <追加>---------------------------------------------------------------------

cdcSubDC.DeleteDC();

oldBMP->DeleteObject();

2007/01/31 11:22:52
id:SevenS No.2

回答回数51ベストアンサー獲得回数3ここでベストアンサー

ポイント50pt

読み込まれたhBitmapは、StretchBltの後再利用されていないので、DeleteObjectで削除すべきではないでしょうか?

頭にHのつくハンドルと呼ばれるものはWindowsサイドで管理しているものなので、メモリリークとしては現れなかったような気もします。

念のため、LoadImageの結果がNULLのとき、GetLastErrorを取得することをオススメします(FormatMessageと併用するとなおGood)。

もしかすると解決の糸口が見つかるかもしれません。

それと、お節介かも知れませんがいくつか。

  1. cdcSubDC.CreateCompatibleDCの引数は、pDCではなくcdcMainがふさわしいのでは?
  2. 読み込みは、HBITMAP LoadBitmap( LPCTSTR lpszFileName )のような関数に処理をまとめた方が楽

ただ、この部分の処理は重いので、OnPaintなどには使わない方がいいかもしれませんね。

備考: VC++7.0以降なら、MFCのCImageクラスを使って、

LPCTSTR lpszFileName = TEXT( "bitmap.bmp" );
CImage image;
image.Load( lpszFileName );
image.StretchBlt(
    cdcMain->GetSafeDC(),
    iXzahyou, iYzahyou,
    iMainYoko, iMainTate,
    iXzahyou * image.GetWidth() / iMainYoko,
    iYzahyou * image.GetHeight() / iMainTate,
    image.GetWidth(), image.GetHeight() );

とできるようです。

http://www.geocities.jp/chiakifujimon/makesoft2/proc4.html

id:harunoharuno

いろいろと、教えていただきありがとうございます。

GetLastErrorとFormatMessageを併用したところ

『このコマンドを実行するのに十分な記憶域がありません』とでていました。

やはり、ご指摘いただいているhbitmap等のリソース開放処理がないためかな?

>>cdcSubDC.CreateCompatibleDCの引数は、pDCではなくcdcMainがふさわしいのでは?

pDCはcdcMainのアドレスが入っているので、cdcMainと同じです。

>>読み込みは、HBITMAP LoadBitmap( LPCTSTR lpszFileName )のような関数に

>>処理をまとめた方が楽

確かにそうしたほうがソースも読みやすいですね。

コーディングに対する指摘も参考になり大変ありがたいです。

他にまた気になる点などありましたらまた、ご指摘いただきたくよろしくお願いします。


>>頭にHのつくハンドルと呼ばれるものはWindowsサイドで管理しているものなので、メモリリークとしては現れなかったような気もします。

あれっっ

ひょっとしてHICONなども開放する必要がありますか?

2007/01/31 18:52:20
id:SevenS No.3

回答回数51ベストアンサー獲得回数3

ポイント50pt

自信はありませんが…

HICONがプログラムモジュール内のリソースをロードするだけなら、リリースする必要はないと思います。

無論、ハンドルやポインタは、ちゃんと解放する癖をつけておくのは正しいことだと思います。

http://support.microsoft.com/kb/87976/ja

id:harunoharuno

回答ありがとうございます。

WindowsタスクマネージャのPF使用量を見ながら

メモリリークしている処理を探したのですが、

SHGetFileInfo関数でHICONを受け取るときに

PF使用量が増加していることがわかりました。

そこでネットで検索したDestroyIcon関数の

開放処理を追加したところ、

SHGetFileInfo関数を呼び出すごとに

増加していたPF使用量が増加しなくなり、

BMP描画関数でこけることもなくなりました!!

裏づけが信頼性の高い資料などで確認取れていませんが、

SHGetFileInfo関数で取得した

HICONをDestroyIcon関数で

開放していなかったため、アイコンを再描画するたびに

メモリリークが発生し、

その影響からBMPファイル読み込みに支障がでたようです。

2007/01/31 23:52:27

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません