あるフリーソフトをネット上に公開しています。ダウンロード数は延べ10万回くらい
のオーダーになっています。
最近ある一人のユーザー(OSはXP)から、「起動→終了したあと、また起動すると二重
起動の警告が出て立ち上がらない」と指摘がありました。この指摘ははじめてです。
自分のOS(98SE, XP, Vista)では問題ありません。
このユーザーに協力して貰って調べた結果を以下に述べますので、お気づきのことがあ
りましたらご教授ください。よろしくお願いいたします。
VS2005, VC++, MFC, SDI, CFormView で作っています。
二重起動防止のため Mutex を使っています。
最初、これに問題があるのではないかと思って調べたら、Mutex の問題ではなく、この
ユーザーの場合「このアプリを終了してもタスクマネージャーのプロセスタブに残って
いる」ことが判明しました。
このアプリでは、フォームビューに139個のコントロールを配置しています。
コントロールは、リソースファイルに記述しています。
種類は、押しボタン、ラジオボタン、チェックボタン、エディット、コンボボックス、
スピンおよびテキストです。
139個を3通りのメニュー(A,B,C)で切り替えています。
切り替えは、ShowWindow(SW_HIDE) および ShowWindow(SW_SHOW) で行っています。
メニューAのとき使うのは60個、Bのとき57個、Cのとき22個です。
このユーザーに5通りのプログラムをテストして貰った結果は、次の通りです。
(スケルトンにコントロールを配置しただけのプログラムで、コードは一切書いていな
い)
①Aに使う60個のみをリソースファイルに記述
②Bに使う57個のみをリソースファイルに記述
③Cに使う22個のみをリソースファイルに記述
④A+Bの117個をリソースファイルに記述
⑤A+B+Cの139個をリソースファイルに記述
【テスト結果】
①②③の場合は、起動→終了でタスクマネージャーのプロセスタブから消える。
④⑤の場合は、起動→終了してもプロセスタブに残る。
すなわち、このユーザーの場合「リソースファイルに記述してあるコントロールの数
が、ある程度以上多いと、終了してもプロセスタブから消えない」ということです。
1.どうしてこういうことが起きるのでしょうか? OS側(または環境)でこうなる
ことがあるでしょうか?
2.対策として、リソースに最初から139個のコントロールを記述するのではなく、コー
ド(Create / Delete)で各メニューに必要な数だけ記述する方法を試みましたが、面倒
過ぎて途中でやめています。何かよい方法はないでしょうか?
(他の質問コーナーでお尋ねしていましたが、スパムにやられているので、こちらでも
お世話になります。)
>(他の質問コーナーでお尋ねしていましたが、スパムにやられているので、こちらでも
お世話になります。)
http://hpcgi1.nifty.com/MADIA/Vcbbs/wwwlng.cgi?print+200806/08060008.txt
> あるフリーソフトをネット上に公開しています。
ソフト名、掲載サイト名(Vector,窓の社等)を示したほうがいいと思います。
>ダウンロード数は延べ10万回くらい
ここの利用者も使っているかも知れません。
ソフトのアルゴリズム等から原因を探るのも大事ですが、
実際の症状を探るのも大切ですね。
たとえば、
「ある一定の操作を行うと必ずプロセスが残る。」
というのを探して
(こんだけユーザーがいるんだから見つけてもらうのも手ですね。
フリーソフトだし、見つかった直ればまた進展もあるだろうし。
ユーザーも作者もお互いに助かる。
シェアソフト だとそうはいかないだろうけど。)
そこから原因を探す手もあります。
本題ですね
スレッドを使っていないですか?
スレッド終了を確認後にソフトを終了していますか?
ソフト上できちんと行っていても実際に処理されていない可能性が多々あります。
ブレークポイントなしでデバッグ実行・終了でスレッドのリ-クがないか
調べるのを手ですね。
スレッドを使っていない場合で、同様の症状を経験しました。
私のケースは、
・数分以上かかるかなり重い処理(ゲーム木の探索のようなもの)をするが、
横着してスレッドは分けていない。
・処理中にも画面の更新がされるように、適当なタイミングで
PeekMessageでメッセージを処理している。
・処理中にwindowを終了するとプロセスが残る。
↓
WM_DESTROYで、グローバルの終了フラグを立て、重い計算部分でたまに
終了フラグをチェックし、フラグが立っていたら中断するように変更して解決。
私の場合ですと、別スレッドで適切に処理するのが正しい解決方法でしょうが、
個人的な使用なので横着しています。
そう考えると、多分参考になりませんね。
ITO さん、有り難うございます。
ソフト名を言うのはなんとなく恥ずかしです。
ここの利用者が特に興味を持ちやすいという種類のものではありません。
スレッドは使っていません。
MFC SDI CFormView でスケルトンを作り、リソースにコントロールを配置しただけのテ
ストプログラムで、このユーザーにテストして貰った結果、コントロールの数だけが関
係する、という状況です。操作は何も出来ないテストプログラムです。起動して終了し
て、プロセスタブに残っているかどうかだけを調べて貰いました。
たいちう さん、有り難うございます。
同様の症状を経験されたとのことで、ドキッとしましたが、少し違うようですね。
コントロール139個というのは多すぎるのでしょうか?
WM_DESTROY の前の WM_CLOSE でコントロールを消す(m_edit○○○.DestroyWindow())
のはどうだろうと考えたのですが、CFormView では WM_CLOSE が発生しないようです。
ボタンをコピーで200個ほど貼り付けたCFromViewをつくってみても
再現しないですねぇ
>コントロール139個というのは多すぎるのでしょうか?
いいえ。
>1.どうしてこういうことが起きるのでしょうか? OS側(または環境)でこうなる
>ことがあるでしょうか?
ありえてもおかしいことではない。
ただ、そのユーザーさんの環境を直接みてみるか、
同様の現象がおきるユーザーさんがいないか探してみて情報を集めないと
対応するのは難しいですね
>2.対策として、リソースに最初から139個のコントロールを記述するのではなく、コ
ー
>ド(Create / Delete)で各メニューに必要な数だけ記述する方法を試みましたが、面
倒
>過ぎて途中でやめています。何かよい方法はないでしょうか?
1つのFormに全部貼り付けるのではなく、複数のFormを切り替えるのはどうでしょう
か?
切り替えは、表示・非表示ではなく、生成・破棄するように
rin さん、有り難うございます。
> 1つのFormに全部貼り付けるのではなく、複数のFormを切り替えるのはどうでしょう
か?
これはいい考えだと思います。
しかし、未熟者でやり方が判らず、ネット上を探しました。
幾つか見つかりましたが、いずれも基本はこれのようです。
http://support.microsoft.com/default.aspx?scid=kb;ja;JP141334
これは、表示・非表示ですよね。
生成・破棄ってどうやればいいか。
リソースファイルを複数用意して、読み込んだり、リリースしたり・・・
なんてことでしょうか?
MFC では無理かなー。
もう少し調べます。
自分としてはFormViewを使ってるなら
Viewの切り替えより
Aのリソースを使うダイアログ
Bのリソースを使うダイアログ
Cのリソースを使うダイアログ
を必要に応じて作成・削除するとかがお手軽かなと思います。
ちょっと気になったんですが、
使っているコントロールと言うのは全て標準でMFCで提供されているものでしょうか?
特殊なコントロールや改造が入ったものの場合は必ずしもボタンを貼り付けた物と
同じ結果にならないのではと言う気もしますけれど。
あと確認するとしたら使っているコントロールの種類かなぁと。
特定のコントロールが絡むと現象が起きるのか?
というのも糸口にはなりそうです。
てんてく さん、有り難うございます。
モーダルダイアログだと、閉じるまでは親ウインドウを操作できないので支障があるん
です。
モードレスダイアログならいいでしょうが、既に1個は常時出しているので、ちょっと
ややこしいかと思って踏み切れません。
PATIO さん
> 使っているコントロールと言うのは全て標準でMFCで提供されているものでしょうか?
すべて標準でMFCで提供されているものばかりです。
種類は、押しボタン、ラジオボタン、チェックボタン、エディット、コンボボックス、
スピンおよびテキストの7種類です。
最初の書き込みに書きませんでしたが、この7種類を各1個ずつ配置したテストプログ
ラムもこのユーザーにテストして貰いました。結果はOK(プロセスタブに残らない)
でした。
http://wg-web.ics.teikyo-u.ac.jp/usage/VC/vwchange.html
ここを参考に、ビューを切り替える(生成・破棄ではないが)テストテストプログラム
を作って、このユーザーにテストして貰おうと思っています。
話の流れを読んでいて思ったんですが、
何処で止まっているのかと言うのはある程度特定できたんでしょうか?
現状上がっている情報は、どうもコントロールの個数が関係するらしいという
話とコントロールの種類は関係無いらしいと言う話ですよね。
結局、前のプロセスが終了しきれないでいるから複数起動チェックに引っかかって
しまうと言う話ですから、前のプロセスが何処でとまっているのかと言うのも
切り口の一つではと思うのですけれど。
ログを仕込んで何処で止まっているか特定できない物ですかねぇ。
ダイアログはポップアップするだけでなく
各種コントロールと同様の感覚で貼り付けることが出来ます。
ダイアログのスタイルを子、ボーダーをなし
でCreateすればいい感じに出来ると思いますよ。
ちょっと作ってみた
void CMainFrame::OnViewChange()
{
CView* pNewView;
CView* pOldView = GetActiveView();
if( pOldView == NULL )return;
if( !id ){
pNewView = new CForm2View; //コンストラクタをPublicにしておく
}else{
pNewView = new CStudy061View;//コンストラクタをPublicにしてお
く
}
if( !pNewView )return; //確認
// 現在のVIEWから、ドキュメントをゲット
CCreateContext context;
context.m_pCurrentDoc = pOldView->GetDocument();
pNewView->Create(NULL,NULL,WS_VISIBLE|WS_CHILD|WS_BORDER,
CFrameWnd::rectDefault,this,NULL,&context);
//ドキュメントをセットしつつ生成
pNewView->OnInitialUpdate();
SetActiveView( pNewView );
pNewView->ShowWindow(SW_SHOW);
pOldView->ShowWindow(SW_HIDE);
pNewView->SetDlgCtrlID( AFX_IDW_PANE_FIRST );//トップレベルのViewには
AFX_IDW_PANE_FIRSTを
RecalcLayout(); //レイアウト変更
pOldView->DestroyWindow(); //古いものを消す
id = !id;
//ID入れ替え
}
デフォルトと追加のVIEWの切り替えです。
rin さん、サンプルまで作って戴いてありがとうございました。
やっと、大体同じと思われるものを作って、一応動作を確認しました。
これは、起動のときは元々の CFormView が表示され、その後、OnViewChange() を発生
するメニューをクリックするたびに CForm2View または CStudy061View が切り替わって
表示される・・・ということでしょうか?
① この方式の場合、自分としては、CFormView は空っぽにしておき、起動と同時に
CForm2View が表示されるようにしたいのですが、CMainFrame には OnInitialUpdate()
は作れないし、どうしたらいいいか思案しています。
② また、終了のとき、表示されている CForm2View または CStudy061View を Destroy
した方がいいかと思うのですが、やり方が判りません。
お助けください。よろしくお願いいたします。
釈迦に説法かもしれませんけれど。
原因を特定しないままに話がすすでいるような気がして
対処療法だけに陥ってしまわないかが気になります。
問題のプログラムが何処で止まってしまっているのかが
わかっていて対処方法を検討しているのであれば、
良いとは思うのですけれど。