お世話になります。
以前、Mutex による二重起動防止についてご相談させて戴きました。
Windows 7/8.1 に搭載されている音声読み上げアプリ『ナレーター』の起動中に、自分が
作ったアプリを終了させると、タスクマネージャーのバックグラウンド・プロセスに自分
のアプリが残ったままになり、そのため Mutex が検出されて2回目の起動ができなかっ
たのです。
こちらです。
http://rarara.cafe.coocan.jp/cgi-bin/lng/vc/vclng.cgi?print+201403/14030001.txt
解決策として、二重起動防止に FindWindow() 関数を使うことにしました。
アプリの名称を仮に Gekiatsu とします。
コードは下記の通りです。
BOOL CGekiatsuApp::InitInstance()
{
CWnd *pWnd;
pWnd = CWnd::FindWindow(NULL, _T(Gekiatsu));
if (pWnd != NULL)
{
pWnd->ShowWindow(SW_RESTORE);
pWnd->SetForegroundWindow();
return FALSE;
}
}
これで解決できたと思っていたら、このアプリの実行ファイルを Gekiatsu というフォル
ダの中に置くと、起動しないことが判明しました。(例:D:\MyApp\Gekiatsu)
フォルダも Window ということになるのでしょうか?
D:\Gekiatsu\MyApp というように直前が Gekiatsu でなければ起動します。
何かいい解決策はないでしょうか?
よろしくお願いいたします。
ちょっと語弊がありますが、FindWindow()の第2引き数は、トップレベルのウィンドウ
のキャプション文字列(タイトルバーの文字列)なので、どこかに「Gekiatsu」というタ
イトルバーを持ったアプリケーションが起動しているのだと思います。
具体的には、エクスプローラーで該当フォルダーを開いてんじゃね?と予想しています。
(エクスプローラーはコントロールパネルでタイトルバーのパス表記をどうするか指定
できます)
簡単な方法は2重起動を防止するアプリケーションのタイトルバーにパスで使えない文
字を埋めておく、コッソリスペースを足しておくと原理が分かりやすいでしょう。
次に簡単な方法は、第1引き数を使うことです。
ドキュメント-ビュー構成であると仮定して、PreCreateWindow()に以下の記述でウィン
ドウのクラス名をユニークである事が保証できる文字列に書き換えてしまうとバッティン
グしなくなります。
自前でウィンドウ作っているなら、生成時のクラス名を適当なものにすれば良いです。
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if (cs.lpszName)
WNDCLASS wc;
::GetClassInfo(AfxGetInstanceHandle(), cs.lpszClass, &wc);
wc.lpszClassName = Lなんかユニークになる文字列、GUIDとかお奨め;
AfxRegisterClass(&wc);
cs.lpszClass = wc.lpszClassName;
}
・・・
他にもハンドルからプロセス名を取得して一致を見るとか、逆にプロセス一覧からハン
ドルを求めるとか、親プロセスとの関係から取得するとか、いろんな回避方法があります
ので工夫してみてください。
(ですが、本来はMutexを使うのが王道だと思っています)
SetPropで自身に目印をつけておいて、FindWindowで見つけだした
Windowに対してGetPropして目印つけてるWindowか判断している
って処理を見たことがあります。
AR様、みい様 有り難うございます。
AR様に教えて戴いた、PreCreateWindow()でウィンドウのユニークなクラス名を定義する
方法でクリア出来ました。