none
ハンドルされていない例外が発生しました

    質問

  • いつもおせわになっています。

    Visual C++ MFCでプログラムを作成しているのですが、OnPaint内でピクチャーボックスのビットマップを更新する時に「MCSP.exe の 0x004033ca でハンドルされていない例外が発生しました: 0xC0000005: 場所 0x00000004 を読み込み中にアクセス違反が発生しました。」というメッセージがでて、処理が中断します。このエラーを回避する方法となぜエラーが発生するのかわかりません。どなたかお教え下さい。

    ソースは以下のように記述しています。

         pDC = m_xcPicLamp[i].GetDC();    // デバイスコンテキスト 取得
         myDC.CreateCompatibleDC(pDC);    // pDCと互換のあるmyDC生成
         oldBMP = myDC.SelectObject(&myBMP);                // 画像選択
         pDC->BitBlt(0, 0, 16, 16, &myDC, 0, 0, SRCCOPY);        // 画像転送  ←この行で発生しています。
         myDC.SelectObject(oldBMP);                        // 元のビットマップに戻す

    2010年3月2日 2:07

回答

  • 例外の発生するのはどの処理をしたタイミングですか?
    CResourceException は、文字通りリソース(システムリソースではなく、.rcに含まれるような情報)にアクセスできない場合や、CGdiObject の派生クラスのハンドルがNULLだった時などに発生します。

    デバッガなどでどこで例外が発生しているか?を確実に抑え、その原因となるものを究明してください。
    このソースだけをみる限り、可能性としtえ問題がありそうなのは。。。

    myBMP くらいですが、もしかしたら m_xcPicLamp[i].GetDC() のなかかもしれませんし。。。

    あと、MFCの例外は、必ずTRYマクロを使ってトラップしてください。状況によって ex->Delete() はしない場合とする場合があります。


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/
    2010年3月2日 6:31
  • pDC は、NULLではない有効な値ですか?

    CDC::BitBlt でアクセス違反が発生しているので、pDC か、 &myDC が怪しいと思われます。
    が、&myDC にクラッシュ要因があるとは思えないため、十中八九 pDC がNULLなどが原因と思われます。


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/
    2010年3月2日 3:28
  • myDCを生成後に破棄するように変更し、IF文はコメントとして実行しましたが、
      pDC->BitBlt(0, 0, 16, 16, &myDC, 0, 0, SRCCOPY);
    の部分でエラーが発生します。
    この時、m_picLamp[i]には値が入っています。pDCの値は見ることができませんでした。
    この場合、IF文というのはpDCの判定文だと思うのですけれど、取得エラーの可能性があるのであればこの文は無いとだめだと思います。
    既にどこかで取得済みの値を保持していてそれがNULLでない事が検査済みで保持されていればなくても良いかもしれませんが、GetDC関数に失敗の可能性があるなら判定はすべきです。m_picLampが何者なのか良く分からないのでCWnd::GetDCの事を指しているのか、オリジナルの関数なのかもわかりませんし。

    解決した時は、参考になったレスポンスの所にある[回答としてマーク]ボタンをクリックしてスレッドを締めましょう。
    2010年3月2日 8:43
  • yominetさん、ありがとうございます。

    1.発生頻度
      発生頻度は、約1400回以上呼ばれたら発生します(30秒間隔で発生)。

    2.崩れるとは
      崩れるとは、デザイナで配置したコントロールの位置がバラバラになり、かつ画面全体が灰色(ダイアログ
      の背景色)になります。この時、ダイアログの枠も消えています。

    3.myDCは、生成だけで破棄していませんでした。
    推測ですが、崩れ方や、1400回未満までは起こらないことから、
    メモリやらGDIオブジェクトやらが解放されずにどんどん溜まり、限界がきたところでおかしくなってると思います。
    このような場合、エラーとして止まった場所・報告がなされた場所に問題があるのではなく
    別の場所に、本当の問題がある場合が多いです。
    ♯1400回呼ばれるのがOnPaintのみであるなら、OnPaint内にあると思いますが…

    ソースからはmyDCのみしか気になりませんでしたが
    myBMPもふくめ、生成したものをきちんと解放・破棄しているかどうか確認しなおすべきだと思います。

    デバッグモードで1400回未満のエラーが出ない段階で終了させてみて、リークがないか確認したり
    タスクマネージャで、メモリ使用量、仮想メモリサイズ、また、GDIオブジェクト数やハンドル数を確認すれば
    解放し忘れなどがあるかわかります。
    2010年3月2日 12:11
  • すんません。すごく大事な部分を見落としていました。

    OnPaint で処理してるってことは、最終的な画面出力先は、CPaintDC を指定すると思うのですが、そうはなってませんよね?

    あと、現状の最新状態がよくわからんのですが...
    GetDC で取り出してきたDCは、ReleaseDC がいるような気がします。

    配列だったやつは今は配列じゃない?という感じで状況がよくわかりません。

    ずるずるとやっていても、B_Wolf さんはちっとも解決できないままなので
    ごく一般的なリソースリークを発生しないようにするための指針を挙げておきます。

    1.CWnd::GetDC で取得したDCは、そのイベントハンドラから戻る前に CWnd::ReleaseDC を呼び出して解放する。
    2.CDC::CreateDC または、CDC::CreateCompatibleDC で作成したDCは、不要になったら DeleteDC をする(デストラクタ呼び出しでもよい)
    3.すでに有効なHDCを保持しているCDCで作成系メンバー関数を呼び出してはならない。
    4.SelectObject して選択したものは、そのDCを解放(削除)する前にもともと選択されていたオブジェクトが選択されるようにする。
    5.SelectObject された状態の CGdiObject(の派生クラスオブジェクト) は、選択を解除してから削除する。
    6.CWnd::OnPaint() のハンドラでは、CPaintDC dc( this ); を行い、再描画用DCを構築する。

    #7個目が思い浮かばなかった...orz


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/
    2010年3月3日 5:06
  • あれ?現行のソースは最初のソースとそれほど変わらないんですよね?
    であれば、myBMP を SelectObject していると思うのですが?

    6 の CPaintDC の利用は、OnPaint がWM_PAINTのイベントハンドラであれば、最初のスケルトンコードに含まれていたはずです。
    そうではないのであれば(名前が OnPaint というだけでイベントハンドラではない)、当てはまらないので関係ありません。

    先にあげたものはごくごく一般的に発生しやすいリソースリークの事例を羅列しただけですので。


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/
    2010年3月4日 2:43

すべての返信

  • pDC は、NULLではない有効な値ですか?

    CDC::BitBlt でアクセス違反が発生しているので、pDC か、 &myDC が怪しいと思われます。
    が、&myDC にクラッシュ要因があるとは思えないため、十中八九 pDC がNULLなどが原因と思われます。


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/
    2010年3月2日 3:28
  • とっちゃんさん、ありがとうございます。

    try
    {
         pDC = m_xcPicLamp[i].GetDC();    // デバイスコンテキスト 取得
        if ( pDC !=NULL)
        {     
             myDC.CreateCompatibleDC(pDC);    // pDCと互換のあるmyDC生成
             oldBMP = myDC.SelectObject(&myBMP);                // 画像選択
             pDC->BitBlt(0, 0, 16, 16, &myDC, 0, 0, SRCCOPY);        // 画像転送
             myDC.SelectObject(oldBMP);
         }
    }
    catch (CException* ex)
    {  
        GetLocalTime(&datNow);        // 現在日時 取得
        strTemp = _T("画像転送に失敗しました。");   // エラーメッセージ 取得
        LogListInsertItem(datNow, _T(""), _T(""), strTemp); // ログリストに追加
        ex->Delete();
    }

    上記のように、変更したのですが、今度は「Microsoft C++ の例外: CResourceException (メモリの場所 0x0012c9d0)」というエラーが発生して、画面が崩れてしまうようになりました。

    回避策は上記変更ではできないのでしょうか。

    2010年3月2日 4:46
  • 1:発生頻度は?(OnPaint一回目からとか、何回か呼ばれたときからとか)

    2:崩れるとはどういう現象?

    3:OnPaintのたびにmyDCを生成してるが、そのたびに破棄してる?
    2010年3月2日 6:16
  • 例外の発生するのはどの処理をしたタイミングですか?
    CResourceException は、文字通りリソース(システムリソースではなく、.rcに含まれるような情報)にアクセスできない場合や、CGdiObject の派生クラスのハンドルがNULLだった時などに発生します。

    デバッガなどでどこで例外が発生しているか?を確実に抑え、その原因となるものを究明してください。
    このソースだけをみる限り、可能性としtえ問題がありそうなのは。。。

    myBMP くらいですが、もしかしたら m_xcPicLamp[i].GetDC() のなかかもしれませんし。。。

    あと、MFCの例外は、必ずTRYマクロを使ってトラップしてください。状況によって ex->Delete() はしない場合とする場合があります。


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/
    2010年3月2日 6:31
  • yominetさん、ありがとうございます。

    1.発生頻度
      発生頻度は、約1400回以上呼ばれたら発生します(30秒間隔で発生)。

    2.崩れるとは
      崩れるとは、デザイナで配置したコントロールの位置がバラバラになり、かつ画面全体が灰色(ダイアログ
      の背景色)になります。この時、ダイアログの枠も消えています。

    3.myDCは、生成だけで破棄していませんでした。
    2010年3月2日 7:05
  • yominetさん


    myDCを生成後に破棄するように変更し、IF文はコメントとして実行しましたが、
      pDC->BitBlt(0, 0, 16, 16, &myDC, 0, 0, SRCCOPY);
    の部分でエラーが発生します。
    この時、m_picLamp[i]には値が入っています。pDCの値は見ることができませんでした。

    2010年3月2日 7:29
  • myDCを生成後に破棄するように変更し、IF文はコメントとして実行しましたが、
      pDC->BitBlt(0, 0, 16, 16, &myDC, 0, 0, SRCCOPY);
    の部分でエラーが発生します。
    この時、m_picLamp[i]には値が入っています。pDCの値は見ることができませんでした。
    この場合、IF文というのはpDCの判定文だと思うのですけれど、取得エラーの可能性があるのであればこの文は無いとだめだと思います。
    既にどこかで取得済みの値を保持していてそれがNULLでない事が検査済みで保持されていればなくても良いかもしれませんが、GetDC関数に失敗の可能性があるなら判定はすべきです。m_picLampが何者なのか良く分からないのでCWnd::GetDCの事を指しているのか、オリジナルの関数なのかもわかりませんし。

    解決した時は、参考になったレスポンスの所にある[回答としてマーク]ボタンをクリックしてスレッドを締めましょう。
    2010年3月2日 8:43
  • PATIOさん

    m_picLampはピクチャーボックスの変数です。
    やはり、if (pDL != NULL)を戻してみます。
    2010年3月2日 9:13
  • yominetさん、ありがとうございます。

    1.発生頻度
      発生頻度は、約1400回以上呼ばれたら発生します(30秒間隔で発生)。

    2.崩れるとは
      崩れるとは、デザイナで配置したコントロールの位置がバラバラになり、かつ画面全体が灰色(ダイアログ
      の背景色)になります。この時、ダイアログの枠も消えています。

    3.myDCは、生成だけで破棄していませんでした。
    推測ですが、崩れ方や、1400回未満までは起こらないことから、
    メモリやらGDIオブジェクトやらが解放されずにどんどん溜まり、限界がきたところでおかしくなってると思います。
    このような場合、エラーとして止まった場所・報告がなされた場所に問題があるのではなく
    別の場所に、本当の問題がある場合が多いです。
    ♯1400回呼ばれるのがOnPaintのみであるなら、OnPaint内にあると思いますが…

    ソースからはmyDCのみしか気になりませんでしたが
    myBMPもふくめ、生成したものをきちんと解放・破棄しているかどうか確認しなおすべきだと思います。

    デバッグモードで1400回未満のエラーが出ない段階で終了させてみて、リークがないか確認したり
    タスクマネージャで、メモリ使用量、仮想メモリサイズ、また、GDIオブジェクト数やハンドル数を確認すれば
    解放し忘れなどがあるかわかります。
    2010年3月2日 12:11
  • yominetさん

    OnPaint内で生成したものは、全て解放・破棄するように変更しました。また、「if (pDC != NULL)」文も追加しました。

    この状態でプログラムを稼動すると、一応エラーは発生しないのですが、スクリーンセーバからの復帰時等で同様のエラーがCMCSPApp::InitInstance()内の最終行「// ダイアログは閉じられました。アプリケーションのメッセージ ポンプを開始しないで
     //  アプリケーションを終了するために FALSE を返してください。
     return FALSE;」で発生します。
    また、何もしない状態で1400回を越えたあたりで終了ボタンをクリックしたときも同様のことが発生します。

    何が悪いのかわかりません。ご教授下さい。
    ハンドルは増減はしますが、増えているようには見えません。メモリまでは確認できていません。
    2010年3月3日 0:41
  • すんません。すごく大事な部分を見落としていました。

    OnPaint で処理してるってことは、最終的な画面出力先は、CPaintDC を指定すると思うのですが、そうはなってませんよね?

    あと、現状の最新状態がよくわからんのですが...
    GetDC で取り出してきたDCは、ReleaseDC がいるような気がします。

    配列だったやつは今は配列じゃない?という感じで状況がよくわかりません。

    ずるずるとやっていても、B_Wolf さんはちっとも解決できないままなので
    ごく一般的なリソースリークを発生しないようにするための指針を挙げておきます。

    1.CWnd::GetDC で取得したDCは、そのイベントハンドラから戻る前に CWnd::ReleaseDC を呼び出して解放する。
    2.CDC::CreateDC または、CDC::CreateCompatibleDC で作成したDCは、不要になったら DeleteDC をする(デストラクタ呼び出しでもよい)
    3.すでに有効なHDCを保持しているCDCで作成系メンバー関数を呼び出してはならない。
    4.SelectObject して選択したものは、そのDCを解放(削除)する前にもともと選択されていたオブジェクトが選択されるようにする。
    5.SelectObject された状態の CGdiObject(の派生クラスオブジェクト) は、選択を解除してから削除する。
    6.CWnd::OnPaint() のハンドラでは、CPaintDC dc( this ); を行い、再描画用DCを構築する。

    #7個目が思い浮かばなかった...orz


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/
    2010年3月3日 5:06
  • とっちゃんさん

    1,2に関しては実行するようにしました。
    今回は、SelectOblectは使用していないので必要は無いと思います。
    6のCPあいんtDC(this);の使い方がよくわかりません。

    1,2項を実施することによって、現状ではエラーが発生しなくなりました。

    ご教授、ありがとうございます。

    2010年3月3日 23:03
  • あれ?現行のソースは最初のソースとそれほど変わらないんですよね?
    であれば、myBMP を SelectObject していると思うのですが?

    6 の CPaintDC の利用は、OnPaint がWM_PAINTのイベントハンドラであれば、最初のスケルトンコードに含まれていたはずです。
    そうではないのであれば(名前が OnPaint というだけでイベントハンドラではない)、当てはまらないので関係ありません。

    先にあげたものはごくごく一般的に発生しやすいリソースリークの事例を羅列しただけですので。


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/
    2010年3月4日 2:43
  • とっちゃんさん

    6項ですが、OnPaint()の最初の方で実行していました。
    SelectObjectも行っていました。参考資料を基にソースを書いているので、ピンときていなかったです。

    ありがとうございます。

    2010年3月4日 23:07
  • こんにちは。フォーラムオペレーターの高橋春樹です。

    とっちゃんさん、yominetさん、PATIOさん
    アドバイスの投稿有難うございました。

    B_Wolfさん
    MSDNフォーラムのご利用ありがとうございます。
    今回、皆様からのアドバイスが問題解決に繋がったようなので
    アドバイスをくれた皆様からの投稿に、回答マークを付けさせてもらいました。

    今後ともMSDNフォーラムを宜しくお願いします。


    マイクロソフト株式会社 フォーラム オペレーター 高橋春樹
    2010年3月10日 8:19