• 締切済み

VC++6.0 異常終了の調査方法

環境:VC++6.0 MFC使用 ダイアログベースアプリケーション 使用PC:同一ソースをWin2000またはWinXPでリビルドして使用 です。 メインダイアログにメニューを実装し、あるメニュー項目を 選ぶと別のダイアログをDoModalで表示し、別のダイアログで「OK」を 押すとメインダイアログに処理が戻るようなソフトを作成しています。 別のダイアログは数種類あり、EDITボックスやコンボボックスなどを 配置しています。 ダイアログ切り替えの運用試験として、 あるダイアログを表示→閉じるを繰り返す試験を行っていると、 数時間でこのソフトが異常終了してしまいます。 (タイマ処理内で、現在日時分秒を出力しています) 「あるダイアログを表示」は、ソフトのタイマ処理で5秒おきにDoModalしています。 「閉じる」は、「OK」ボタンを押す別アプリを作成しています。 別アプリでは、「IsWindowVisible()の戻り値がTRUE」かつ 「FindWindowExを使用してlpszWindow(ウインドウ名)が「OK」」 のコントロールを探し出し、見つかればSendMessageなどで 「OK」ボタンを押す処理を代行させています。 何が原因で異常終了してしまうかを調べたいのですが、 具体的な良い方法はありませんでしょうか。 わかっている現象として、 1.タスクマネージャのプロセスタブで このソフトのメモリ使用量を見ていると、 時間とともに少しずつ増加しています。 よろしくお願いいたします。

みんなの回答

  • MrBan
  • ベストアンサー率53% (331/615)
回答No.2

> CRTとは_CrtSetDbgFlag ... でしょうか? 御意。 > 異常の検出は無いようです。入れる場所が悪いのでしょうか。 悪いです。_CrtSetDbgFlagは起動直後など最初にやるものですので、 その位置でやっても恐らく結果が出てません。 最初に設定をしておいて、_CrtDumpMemoryLeaks等で結果を得ます。 # BoundsCheckerをお使いなら、近しい機能ともいえますが。 尚、デバッグ版実行時や上記設定時などはメモリがチェックの為に内部的に解放されず、 メモリが増え続けるように見えることがあります。 メモリ消費が増え続ける云々は、最低限リリース版で確認する必要があります。 # リリース版でもキャッシュのために解放されないものもありえますが。 また、staticなインスタンス内などで動的確保しても誤検出がありえます。 確証に至る情報はないのですが、何か漏らしてるとしたら、 DoModalで起動されるダイアログの中身の方じゃないですか? 再現コードがあるといいのですが、徐々に処理を削って公開できる ものは作れませんか?(この過程で原因が分かることも多いので、 最小限の再現コードを作るのは王道ですが)

ewqewq
質問者

補足

MrBan様 ご回答いただきありがとうございます。 >悪いです。_CrtSetDbgFlagは起動直後など最初にやるものですので、 >その位置でやっても恐らく結果が出てません。 >最初に設定をしておいて、_CrtDumpMemoryLeaks等で結果を得ます。 初めて使用したこともあり、勉強不足でした。 ご指摘ありがとうございます。 MSDNで調べてみましたが、コードの記述位置について教えていただけませんでしょうか。 1. #define _CRTDBG_MAP_ALLOC #include <stdlib.h> #include <crtdbg.h> は、 BOOL CxxxApp::InitInstance() のあるファイルの #include の行の後に記述 2. _CrtDumpMemoryLeaks は、 BOOL CVisionSoftApp::InitInstance() の一番最後に記述 3. _CrtSetDbgFlag は BOOL CVisionSoftApp::InitInstance() の一番最初に記述 でよいのでしょうか。 質問が増えてしまいますがすみません。 新たに新規プロジェクト(ダイアログベース)を作成し、上記の3つのコードのみを追加し 実行したところ、 「プロジェクト」メニュー→「設定」→「一般」タブ「Microsoft Foudation Class」で 「共有DLLでMFCを使用」にした場合、実行してすぐに「OK」を押してもリークが発生し、 「MFCのスタティックライブラリを使用」に設定した場合、実行してすぐに「OK」を押してもリークは 発生しませんでした。 これは、「共有DLLでMFCを使用」にした場合、DLLに問題がありリークが発生している と考えてよいのでしょうか。 >メモリ消費が増え続ける云々は、最低限リリース版で確認する必要があります。 ># リリース版でもキャッシュのために解放されないものもありえますが。 これは、「タスクマネージャ」の「メモリ使用量」の値に惑わされてはいけないということでしょうか。 メモリ消費が増加しても、延々と増加する場合は問題ですが、 起動後増加していても、ある地点で安定していれば問題ないということでしょうか。 >確証に至る情報はないのですが、何か漏らしてるとしたら、 >DoModalで起動されるダイアログの中身の方じゃないですか? >再現コードがあるといいのですが、徐々に処理を削って公開できる >ものは作れませんか?(この過程で原因が分かることも多いので、 >最小限の再現コードを作るのは王道ですが) はい、メイン画面(起動後初期表示される画面)を表示したままであれば 「メモリ使用量」は増えませんが、DoModalでダイアログを表示すると 「メモリ使用量」が増えていくことがあります。 おそらく、DoModalで起動されるダイアログの方に問題があると思っています。 機能を削ったコードを用意しますので申し訳ありませんが、 少し時間をいただけませんでしょうか。 頼ってばかりで申し訳ありませんが、もう少しの間ご指導お願いいたします。

  • MrBan
  • ベストアンサー率53% (331/615)
回答No.1

症状からみて、メモリリーク(バグ)してる可能性もありそうです。 異常終了はメモリ確保失敗の結果、不正参照とかですかね…? もしくは、タイミング問題のバグとか。 いずれにせよ、ちゃんとデバッグしてください。 VCならCRT(C Runtime)にメモリリークチェック機能がありますので、 多少は役に立つかもしれません。調べてみてください。 市販のメモリチェッカなども販売されてますが、今更VC6版があるかどうか…。

ewqewq
質問者

補足

チェックツールは、BoundsCheckerを使用していますが、 ソフト動作中は異常の検出は無いようです。 CRTとは _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); でしょうか? 各ダイアログのOnOKの最後に入れていますが、 異常の検出は無いようです。入れる場所が悪いのでしょうか。 「タイミング問題」については、なんともいえませんが、 void CVisionSoftDlg::OnTimer(UINT nIDEvent) { static long lDlgCount = 0; switch( nIDEvent ) { case ID_TIMER_1 : KillTimer( ID_TIMER_1 ); switch( lDlgCount ) { case 0 : // ダイアログ1 DoModal() break; ・・・ case 9 : // ダイアログ10 DoModal() break; } lDlgCount++; if( 10 < lDlgCount ) { lDlgCount = 0; } SetTimer( ID_TIMER_1, ID_TIMER_1_INTERVAL, NULL ); break; default : break; } CDialog::OnTimer(nIDEvent); } のようにして、前のダイアログの終了処理が終わる前に 次のダイアログが表示されないようにはしているつもりです。 私としては、 >1.タスクマネージャのプロセスタブで >このソフトのメモリ使用量を見ていると、 >時間とともに少しずつ増加しています。 が気になっています。 上の現象=リークと考えてよいものでしょうか。 他に気にする点がありましたらご指摘お願いいたします。

関連するQ&A

  • ダイアログを終了させてもハンドルが1つ増加したまま。。。

    VC++のMFCを使ってダイアログベースのEXEを造っています。 ハンドルのリークが発生し、困っています。 <動作内容> メインのダイアログで、ボタン押下により別のダイアログを表示します。 DoModal()でモーダルダイアログを作成します。 別のプロセスからブロードキャストされるメッセージを処理したいため、 ボタン押下のルーチンで DoModal() せずに、スレッドを作成し、 そのスレッドで DoModal() を実行しています。 スレッド作成は AfxBeginThread() を使用しています。 <サンプルソース> ●メインダイアログ // ボタン押下のルーチン void CTestModalDlg::OnButton1() { AfxBeginThread( TestDlgThread, (LPVOID)this, THREAD_PRIORITY_NORMAL ); } // スレッド static UINT TestDlgThread(LPVOID pThis) { CTestDlg1 Dlg; Dlg.DoModal(); } ●DoModal() で表示されるダイアログ 何も手を加えてない、デフォルトのまま。 <結果> DoModal() で表示されたダイアログを CDialog::OnCancel() で終了させ、 メインのスレッドが終了しても、ハンドルカウントが1つ増加しています。 Sleep() を入れて値をみてみると、 ・スレッド作成:2増加 ・DoModal() でダイアログ表示:1増加 ・OnCancel() で終了:増減なし ・スレッド終了:2減少 =>結果、1増加となっていました。 以下のパターンでは問題ありませんでした。 ・スレッドを作成+終了(ダイアログ表示しない) ・スレッドを作成せずに、ボタン押下ルーチンから DoModal() でダイアログ表示+終了 ということで、AfxBeginThread()、DoModal() 自体は問題ないのですが、 スレッドを作成して DoModal() するとリークが発生します。 識者の方、原因、対策など、ご教授願います。

  • VCで処理中ダイアログボックスを表示する方法

    VC++6.0を使用してアプリを作成しています。 処理に長い時間(10秒程度)がかかる時に 処理中を知らせるダイアログボックスを表示して 親画面にあるほかのボタンを 触れないようにし、処理が終わったら自動で処理中ダイアログボックス を閉じるのを実現したいのですが、どのように すればよいのでしょうか? よろしくお願いいたします。

  • VC++.NET DLLからのダイアログの表示

    こんばんは。 VC++.NETでDLLを作成しました。 内容はダイアログを表示させるだけの単純なもので DLLの種類はMFC拡張DLLで作成しました。 (CDIALOGを継承したクラスTESTDIALOGのコンストラクタ、デストラクタがあるだけのもの) これをテスト用の単純なMFCアプリケーションで呼び出したところ ダイアログを表示させることができましたが 別の複雑なアプリケーション(DLLからDLLを呼ぶなどしている)で 呼び出したところダイアログが表示されません。 コンパイルエラーなどもでないし 何がいけないのか分かりません。 呼び出し側ではメニューにイベントハンドラを作ってそこで TESTDIALOG dlg; dlg.DoModal(); としているだけなのですが・・・ (デバッガで追ったところMFCのdlgcore.cppのCDialog::DoModalの m_lpDialogTemplateNameが不適切なptrとなる辺りに原因はありそうなのですが何故そうなるのかわかりません。) どなたかダイアログが表示されない原因がお分かりになる方 よろしくお願いします。

  • VC++ スレッドからDoModalへ

    いまさらですがVC++6.0でつまづいています MFCです AdlgクラスのダイアログのOnButtonA() からXXXスレッドを起動し そのXXXスレッドではcountを+1しつづけます。 そして別のダイアログ DDD10をDoModalで起動しそのDDD10 内のTextBoxの値にcount値を反映させて表示しようとしました 下記ソース内のAfxMessageBox(tmp);ではcount値は 更新されますが DDD10ダイアログ内のテキストボックス の値が変更されません m_gui_xfr_totalはDDD10のテキストボックスにつけた メンバー名です どなたかアドバイスをお願いします void ADlg::OnButtonA() { DDD10 dlg10 ; CWinThread *pThread = AfxBeginThread(XXX_thread_entry,(LPVOID *)this); dlg10.DoModal() ; } void XXX_Thread(){ CString tmp; unsigned int count=0; DDD10 dlg10; while(1){ count++; tmp.Format("%d",count); dlg10.m_gui_xfr_total.Format(tmp); AfxMessageBox(tmp); Sleep(1000); } }

  • ビジュアルベーシックでは、 AddHandlerステートメントがありましたが・・・・・

    ビジュアルベーシックを学んでから、 今度は、Visual C++を勉強していますが・・・ 困っています、 たとえば、ダイアログの上に OK と、Cancel のボタンがあるとします、 ダイアログを表示させて、 OK ボタンを押したら A の処理 Cancel ボタンを押したら B の処理 そして、どちらかの処理が終わったら 続く C の処理を続けてゆく この様にするためには、どうしたらよいのでしょうか? ビジュアルベーシックでは、 AddHandlerステートメントを 使うことができたのですが・・・・ BOOL CXXXDoc::OnNewDocument() { Cfailsettei cf; // 作成したダイアログボックスのクラスです nRet=cf.DoModal();  //モーダルでダイアログを表示     // cf.buttonOK オーケーボタンを押した処理     // cf.buttonCancel キャンセルボタンを押した処理          //処理を続けてゆく if (!CDocument::OnNewDocument()) return FALSE; // TODO: この位置に再初期化処理を追加してください。 // (SDI ドキュメントはこのドキュメントを再利用します。) return TRUE; } どうすれば、良いのでしょうか? よろしくお願いします。

  • VC++ タブコントロールについて

    以下の環境にてタブコントロールを実装しようとしています。 ・VisualStudio2008 VC++ ・ネイティブ(.NET未使用) ・ダイアログベース、スタティックライブラリ タブを表示させるメインダイアログと他に、子ダイアログ3つを用意して タブが押されたときに表示をON/OFF(ShowWindow使用)させるものを作ったのですが、 以下の問題が出ています。 うまい対策または、タブコントロールの文献で参考になるサイトを教えてください。 [現象と質問] ・メインダイアログを移動させると子ダイアログが追従しない。  → OnPaint()にてOnTcnSelchangeSelectTab()を呼ぶようにしたら追従しましたが、    すばやくダイアログを動かすと、子ダイアログが遅れてついてくるように見えてしまいます。    子ダイアログを追従させるうまい方法(本来のやりかた)はどうすればよいでしょうか。 ・子ダイアログをクリックすると、メインダイアログのタイトルが薄くなる(裏に隠れるような感じ)。  → メインダイアログと子ダイアログのプロパティの組み合わせでなんとかなると思っていますが、    どのようにしたらいいのか、てこずっています。    アドバイスをいただけたらと思います。

  • Win98の終了オプションで終了できなくなりました!

    Windowsを終了させる時は、スタート→Windowsの終了→電源を切れる状態にする→OKで今まで問題なく終了していたのですが、2、3日前からOKを押すと、別のダイアログボックスが出るようになりました。ダイアログボックスの上部には---このプログラムからの応答がありません。ビジー状態か、入力待ちか、または停止しています。---と表示されていて下部には、左から「待機」「終了」「キャンセル」のボタンがあります(フリーズした時にCtrl+Alt+Delを押すと出るあのダイアログボックスと同じものです)。ここで「終了」を押すと終了は出来るのですが、一々面倒です。何故こうなったのでしょう? スタート→Windowsの終了→電源を切れる状態にする→OKで終了させるにはどうしたらいいのでしょう? よろしくお願い致します。

  • 終了していない文字列型の定数です・・・と出ます。

    javaScript使用可能・不可能の表示 ↓ 「OK」「キャンセル」ボタン付きのダイアログボックスの表示 ↓ OK→次のページへ キャンセル→ダイアログボックスを閉じる というようなスクリプトを作ったのですが、最初は上手く動いたのですが、すこしダイアログボックスの文字を変更すると、終了していない文字列型の定数です・・・ というエラーを吐いてきます。 どうやらここの文字が多すぎるとエラーを吐くのですがどうなのでしょうか。 http://mekipedia.cocolog-nifty.com/test.txt これがタグのデータです。 このテキストデータでは表示できるようなので、文字コードか何かでしょうか・・・。 では、よろしくお願いします。

  • VC++でダイアログボックスを表示させるプログラム

    VC++のプログラミングで、実行できない原因が 判らないので、ヒントをいただけないでしょうか。 現在VC++の勉強中で、ダイアログボックスを 表示するプロジェクトを作成しています。 ビルドエラーは出ないのですが、実行しても 何も表示されません。 メニューを持った親ウインドウを表示し、 メニューから「加算」を選択すると 計算用のダイアログボックスが表示されるプログラムです。 ダイアログボックスは三個のテキストボックスと 二個のボタンがあり、数字を二箇所入れ ボタンを押すと計算結果を表示します。 長くなる為ソースは書けないのですが、 こういう場合まず何からチェックすればいいでしょうか? 初心者なのでちょっとしたことで間違えているかも しれません。どなたかアドバイス下さい。

  • 子ウィンドウの操作について(VC++)

    Windows98 Visual C++6.0 雛型でMDIを作成して、アクティブな子ウィンドウに記述されている文字列を操作したいと思っています。 ダイアログボックスを表示して、その中のボタンを押したら、アクティブな子ウィンドウから文字列を取得しある処理した結果をダイアログボックスのtextに表示したいと考えています。 今のところダイアログボックスを表示する所まで出来ています。 問題点は 1.アクティブな子ウィンドウのハンドルはどのようすれば取得できるのでしょうか? 使用すべき関数名等を教えてください。 2.アクティブな子ウィンドウに記述されているデータを取得するには、GetWindowTextやsendMessageで出来るのでしょうか?(なるべくならSJISで処理をしたいと考えているのですが。) わかりずらい質問かも知れませんが宜しくお願いします。