ダイアログ画面を強制的に閉じたときにメモリリーク?

[戻る]
ぽっぽ 2010/06/30(水) 14:46:39
お世話になります。環境はVC++2005 + MFCです。

ダイアログベースでプロジェクトを新規作成し、ビルド、実行してモーダルダイアログ
画面を表示します。ここで、「OK」、「キャンセル」ボタンではなく、画面右上の「×」印を
クリックして画面を閉じると、次のようなメッセージが出て終了します。

ネイティブ' はコード 2 (0x2) で終了しました。

リソースの解放がなされていないようです。WM_DESTROYメッセージに対応したハンドラ
(OnDestroy)でリソースの解放をやろうとしていますが、どうやれば解放できるのかわか
りません。リソースの解放は無理なのか、あるいはできるのならその方法をご教示いた
だければ幸いです。

【追記】
数年前に作成されたアプリケーションが、どういうわけか「OK」、「キャンセル」ボタンを
取り去って、「×」印で終了する仕様になってました。画面にたくさんのコントロールが
配置されているので作り直すのは大変です。せめて、「×」を押したときにメモリリーク
が出ないようにしたいのです。

tetrapod 2010/06/30(水) 15:41:50
終了しているんだからリークしてても何の問題もないのでは?

ぽっぽ 2010/06/30(水) 15:57:45
レスありがとうございます。

>終了しているんだからリークしてても何の問題もないのでは?

まぁ、そうなんですが。。。しかし、爆弾抱えているようで。

tetrapod 2010/06/30(水) 16:11:04
っていうか「本当にリークしているかどうか」はきっちり調べ済みなの?
何をもって「リークしている」と判断したわけ?

ウチの VS2005 で MFC Dialog App をアプリケーションウイザードで新規作成し
一切何の変更も加えずそのままビルド・実行して
・×ボタンで閉じると 終了コード 2
・エスケープキーでキャンセルして閉じると 終了コード 27
・OK/キャンセルボタンをクリックして閉じると 終了コード 0
になる。多分この状態では、なんもリークしていないと思われるわけだが。

PATIO 2010/06/30(水) 16:59:20
ダイアログアプリの終了コードはダイアログの終了時に
操作したボタン等によって変わるので0が返って来るのが
正しいと言う考えでいるのであれば間違いですね。

デバッグモードで動かしている時に終了時にアウトプットウインドウに
メモリリークの表示が出ているのであれば、まだわかりますけれど。
但し、デバッガーに出てくるメモリリークの表示もMFCの終了処理によるもの
なので、STLやらシングルトンインスタンスやらが絡むと実際には問題なくても
出てくる事はあると思います。
(要はチェックした時に確保状態(未開放)なのかという話なので)

ぽっぽ 2010/06/30(水) 17:18:07
[[解決]]
そうですか。。。確認はしていません。

ただ、「終了コード 2 (0x2)が出るのでなんだろう?」とGoogleで検索したら
「メモリリークの可能性」という記述がいくつかヒットしたので、そう思って
しまいました。

よく考えてみれば、新規作成したデフォルトのダイアログ画面の右上にある
「×」印をクリックして画面を閉じたら「メモリリークが生じる」というのなら、
MFCが「×」印のついたダイアログ画面をデフォルトで用意するはずもないと
思います。

tetrapodさんの言われるように、メモリリークの可能性は低いということで
あれば、数年前のプログラムを安心して改良できます(別の爆弾抱えている
可能性もありますが)。

ぽっぽ 2010/06/30(水) 17:21:04
返事が遅れてしまいました。PATIOさん、ありがとうございます。

ロマ 2010/06/30(水) 19:00:32
VC6とVC7.1のMFCをざっと見た感じでは、

1)モーダルダイアログをメインにすると、
 ダイアログはInitInstanceの中で開始され、
 ダイアログ終了時にInitInstanceはFALSEを返す。

2)AfxWinMain中でInitInstanceがFALSEを返すと、
 AfxWinMainはExitInstanceの戻り値を返し、
 プロセスが終了する。

3)ExitInstanceはPeekMessageが最後に処理したメッセージの
 WPARAMを返す(vc7.1ならAfxGetCurrentMessageで取得可)。

ExitInstanceのソースのコメントでは最後のメッセージはWM_QUITなので
普通はPostQuitMessage(0)の引数ゼロが返るはずだが、

モーダルダイアログをメインにした場合、
ESCキーを押した場合はWM_KEYDOWNが最後のメッセージとなる(wParam = 0x1b)。
Xボタンやシステムメニューの"閉じる"の場合は、
PostMessage(WM_COMMAND wParam = 2)が最後のメッセージになる。
こんな感じのようです。

このスレのテーマからは外れますが、
本来WinMainはゼロを返すべきなので、何か工夫が必要と思います。``

ryo 2010/06/30(水) 22:39:31
MS純正のダイアログベースの仕様だってことがわかっていれば、
VSユーザー(うちらプログラマたち)としては
十分なんじゃないかな?
工夫して0を返すようにする必要はないように思えますが・・・

ただ、
この仕様について、MSの公式な文章はあるのか(MSDN内とかに)?
この値をプログラマたちはどう利用することが想定されているのか?
そもそもなんでこんな仕様なのか?
・・・なぞではありますが

仲澤@失業者 2010/07/01(木) 11:15:27
え〜と、一応指摘しておきますが、WinMain()が0を戻すのは

「WinMainがメッセージループの処理をしないで終了する」
ときなので、意味的には「起動の失敗」ですね。

WinMainが戻すのは最終メッセージ(WM_QUIT)のwParam
なので、原理的には

「0以外は全て正常」

です。

仲澤@失業者 2010/07/01(木) 11:23:57
ごめん。まちがった

「0以外は全て正常。0の場合、失敗の可能性がある」

従って、WinMainの戻り値からは一般に

「何も分からない」

ロマ 2010/07/01(木) 19:18:44
病的な例
#define IDC_BUTTON1 259

PostMessage(WM_COMMAND, IDC_BUTTON1);

void OnButton1()
{
 EndDialog(IDCANCEL);
}

終了コードは259
つまり、GetExitCodeProcessの戻り値も259 == STILL_ACTIVE

まぁ、これはこれでいいんですけど。

ロマ 2010/07/02(金) 01:04:07
>「0以外は全て正常。0の場合、失敗の可能性がある」
未処理の例外で終了した場合はGetExceptionCode()が返るようですが。

仲澤@失業者 2010/07/02(金) 11:27:55
>未処理の例外で終了した場合はGetExceptionCode()が返るようですが。

ですか。知りませんでした。
crtのメインまでロングジャンプしているんですかね(う〜む)。

古いスレッドには追加発言できません。