何回も利用させていただいてます。よろしくお願いします。
開発環境
VS2013 VC++ 共通言語ランタイムを使用しない、スタティックライブラリでMFCを使用
する。
プロジェクトは、コンソールアプリケーションで作成しています。
多重起動の判断について困っています。
同じコマンド引数の場合は多重起動という事でエラーをだして、プログラムの実行はしな
いが、コマンド引数の内容が違う場合は、多重起動とは判断せず、プログラムの実行がで
きるようにしたいのです。
なので、Mutexでは対応できないので困っています。ネットでも探したのですが解決方法
がみつかりません。
【実行例】
>App.exe [ret] …起動
>App.exe 10 20 [ret] …起動OK
>App.exe 20 20 [ret] …起動OK
>App.exe [ret] …多重起動としてエラー出力
>App.exe 10 20 [ret] …多重起動としてエラー出力
>App.exe 10 20 -d [ret] …起動OK
スマートな方法がないとなれば、引数情報をテキストにでも吐きだして、アプリを実行す
るたびに引数情報ファイルの中を確認するしかないかなぁ。と考えております。
それと、テストプログラムでアプリケーション名を取得しようと以下のコードを書いたの
ですが、
printf((Application name is %s\n), AfxGetAppName());
実行すると結果としてNULLが返ってきてしまいます。
AfxGetAppName()はコンソールアプリケーションでは使えないという事なのでしょうか?
初心者な質問で恥ずかしいのですがご回答いただければ助かります。
よろしくお願いします。
> なので、Mutexでは対応できないので困っています。
なぜそう判断したのでしょうか?
試してませんが。
CreateMutex() の第3引数は「ミューテックスオブジェクト名」なんだから、
そこにコマンドライン引数を渡してやれば「Mutexで多重起動」が叶うのでは?
> AfxGetAppName()はコンソールアプリケーションでは使えないという事なのでしょうか?
MFCでないと使えないと思います。
コンソールアプリなら argv[0] とか。
>K様
回答ありがとうございます。
Mutexについては、
if (!CreateMutex(0, TRUE, アプリ名))
printf(多重起動です\n);
}
というようにしか使えないと考えていたのですが、第3引数にアプリ名 引数1 引数2”
と渡せばよいという事なのですね?
試してみます。
AfxGetAppName()についても回答ありがとうございました。
取り急ぎ、以下のようなプログラムを実行したのですが、引数なしで多重起動したのです
が動いてしまいました。
私が使い方を勘違いしていますか?
TCHAR ExecName[MAX_PATH];
ZeroMemory(ExecName, sizeof(ExecName));
if (argc == 1){ //単純実行
_stprintf_s(ExecName, MAX_PATH, _T(%s), argv[0]);
}
if (!CreateMutex(0, TRUE, ExecName)){
printf(起動されています %s\n,ExecName);//コンソール標準出力
AfxMessageBox(_T(起動されています), MB_OK, 0);//メッセージボックス
}
ちなみに、ExecName はフルパス\アプリ名.exe となります。
> 私が使い方を勘違いしていますか?
はい。
| 関数を呼び出す前にすでに名前付きミューテックス オブジェクトが
| 存在している場合、 GetLastError関数はERROR_ALREADY_EXISTSを返します。
の検査が抜けています。
>K様
ミスの指摘ありがとうございます。
以下のようなコードに変えてみました。
CreateMutex(0, TRUE, ExecName);
error_no = GetLastError(); /* エラー番号の取得 */
if (error_no == ERROR_ALREADY_EXISTS){
printf(起動されている %s(err:%d)\n,ExecName,error_no);
AfxMessageBox(_T(起動されています), MB_OK, 0);
}
else
{
printf(起動されていない %s(err:%d)\n, ExecName, error_no);
AfxMessageBox(_T(起動されていない), MB_OK, 0);
}
このコードでargv[0]をExecNameとした単純実行を行ったのですが、
①コマンドプロンプトを二つ立ち上げてexeのディレクトリでexeを実行→2つとも実行でき
てしまう
②エクスプローラーでexeのフォルダにてexeをWクリックして起動→2回目では 起動されて
いると正しく出る。
な状況が起きてしまい、困惑しています。
また、最初に投稿した記述にミスがありました。
>App.exe 10 20 [ret] …起動OK
>App.exe 10 20 [ret] …多重起動としてエラー出力
!!!>App.exe 10 20 -d [ret] …起動OK ←多重起動としてエラー出力
>App.exe [ret] …起動OK
>App.exe /a [ret] …起動NG(App.exeと同様と考える)
引数の数が違うが、第2、第3引数が同じなら多重起動と判断。という方法が知りたいので
すが、sMutexNameを利用した方法だとできない気がしていますがどうでしょうか。
ん?
①の場合は、仮想モードで立ち上がっているからだめでは?
ソフトのつかいかたですね。
>ITO 様
ご回答ありがとうございます。
コマンドラインで実行すると仮想モードになるのですか。
引数を渡すプログラムですから、利用方法としてはコマンドラインでの実行になると思い
ます。
ということは、多重起動の判断はできないってことですね。
> このコードでargv[0]をExecNameとした単純実行を行ったのですが、
argv[0] を持ち出したのは私ですが、それで本当に安全(意図通り)に
なるでしょうか?
foo.cpp として作成し cl foo.cpp でビルドすると foo.exe が生成されますが、
コマンドプロンプトから
> foo
で起動したのと
> FOO
で起動したのと、
> foo.exe
で起動したのと、
> .\foo.exe
で起動したのと、
すべて argv[0] は異なります。
つまり、すべて「起動していません」になります。
少なくともこれは「意図通り」ではないように思いますが、
他に、
・別のフォルダなら「多重起動」とはしないのか?
・別のユーザなら「多重起動」とはしないのか?
・同じフォルダでも実行ファイル名が違えば「多重起動」とはしないのか?
・ファイル名(パス名)の大文字小文字の同一視は?
などなど、仕様次第ですが、検討すべきことはあります。
立ち返って AfxGetAppName() ですが、MFC のソースを調べてみたら
わかりますが、デフォルトでは文字列リソースの AFX_IDS_APP_TITLE が
返されるだけです。
つまり foo だろうが FOO だろうが foo.exe だろうが .\foo だろうが
「すべて同じ」です。
同じフォルダでも別フォルダでも、bar.exe にリネームしても同じです。
# 「別ユーザで起動」は、Mutex による。
なおぞうがやりたいのは何なのでしょうか?
ExecName を argv[0] から取得せず、固定文字列にすれば(とりあえず)
意図通りになったりしないでしょうか?
> また、最初に投稿した記述にミスがありました。
>
> >App.exe 10 20 [ret] …起動OK
> >App.exe 10 20 [ret] …多重起動としてエラー出力
> !!!>App.exe 10 20 -d [ret] …起動OK ←多重起動としてエラー出力
> >App.exe [ret] …起動OK
> >App.exe /a [ret] …起動NG(App.exeと同様と考える)
>
> 引数の数が違うが、第2、第3引数が同じなら多重起動と判断。という方法が知りたいの
で
> すが、sMutexNameを利用した方法だとできない気がしていますがどうでしょうか。
TCHAR szMutexString[MAX_PATH];
::wsprintf( szMutexString, _T(%s %s %s), szAppName, argv[1], argv[2] );
HANDLE hMutex = ::CreateMutex( NULL, FALSE, szMutexString );
みたいな感じでしょうか?
これだけだと最後の例の「/a」が「起動OK」になってしまいますが、
「/から始まる引数は『オプション』として除外する」ような決まりなら、
argv[1] argv[2] と決め打ちするはマズいですね。
先の投稿で、敬称が抜けていました。申し訳ありません。
「仮想モード」というのは私はわかりませんが、
> 引数を渡すプログラムですから、利用方法としてはコマンドラインでの実行になると
> 思います。
「コマンドラインでしか引数を渡せない」と思われているのでしたら
間違いだと思います。
普通の(?)ウィンドウアプリでも引数は渡せます。
> ということは、多重起動の判断はできないってことですね。
そう判断されるならその方がよろしいかもしれません。
>コマンドラインで実行すると仮想モードになるのですか。
「コマンドプロンプトを二つ立ち上げて」がまずいのかと思います。
コマンドラインで実行するのはいいと思います。
>K様
ご返答ありがとうございます。
テストプログラムという事で雑に書いてしまい混乱させてしまったようで申し訳ありません。
記載してくださった、
>TCHAR szMutexString[MAX_PATH];
>::wsprintf( szMutexString, _T(%s %s %s), szAppName, argv[1], argv[2] );
>HANDLE hMutex = ::CreateMutex( NULL, FALSE, szMutexString );
が、一番目的に近いと思います。
1>exe /a 10 20 [ret]
2>exe /a 10 20 finename [ret]
と実行した場合に1と2は同じ(多重起動)というように判定できるのか。
2のケースでプログラム内で、argv[3]は無視して
>::wsprintf( szMutexString, _T(%s %s %s), szAppName, argv[1], argv[2] );
と指定すれば、1と重複していると判断できるのか…など実際にコードを書いて実行しな
くてはいけないと考えています。
>「/から始まる引数は『オプション』として除外する」ような決まりなら、
>argv[1] argv[2] と決め打ちするはマズいですね。
/から始まる引数は除外するではなく、/aの場合のみ引数なしと同じであること。となり
ます。
/a 以外にも”/”が付く動作判断引数があります。
「仮想モード」に関しては、ネットで軽く調べたところ分からなかったのですが…コマン
ドプロンプトで実行すると「仮想モード」というものになってしまい、起動していない状
態になってしまうのか。と理解した次第です。
また、エクスプローラー上でexeをクリックして起動する際に引数を渡す方法についても
調べてはみたのですが見つけることができませんでした。
まだまだ勉強不足なので、情報が載っているサイトなどを紹介していただけると助かります。
よろしくお願いします。
>コマンドラインで実行すると仮想モードになるのですか。
WIN95のころから変わっていないと思いますが、
一つのコマンドプロンプトは一つの仮想DOSマシンになります。
ですので、
二つコマンドプロンプト立ち上げるとそれぞれ別格のコマンドプロンプトの
環境になるのでは?
と思っただけです。
一つのコマンドプロンプト上で2回立ち上げれば多重起動の判断はできると思いますが
だめでしょうか?
>ITO様
追記ありがとうございます。
違うコマンドプロンプトから実行するからダメという事なのですか。ありがとうございます。
現在作成しているWin32コンソールアプリでは、バックグラウンド指定(方法?)に関
してもまだ調べておらず、どうやったら良いのかわからなかったので二つコマンドプロン
プトを立ち上げて重複起動させてみたのでした。
> 1>exe /a 10 20 [ret]
> 2>exe /a 10 20 finename [ret]
>
>
> と実行した場合に1と2は同じ(多重起動)というように判定できるのか。
その引数の
・「10」や「20」は「ファイル名」ではなく
・「filename」は「ファイル名」である
・なので「10」と「20」で判断する
との判断ロジック(仕様)を明確にできるのであれば、判定は可能と思います。
# 「数値」と「それ以外」でしょうか?
# そうすると、「数字だけのファイル名を持つファイル」の扱いは?
> /から始まる引数は除外するではなく、/aの場合のみ引数なしと同じであること。とな
り
ます。
> /a 以外にも”/”が付く動作判断引数があります。
ですから、その判断ロジックを明確にできるかどうか?でしょうね。
# 「/から始まるファイル名」は「無い」としても、「-から始まるファイル名」は
# 存在しえます。
> また、エクスプローラー上でexeをクリックして起動する際に引数を渡す方法について
も
それはエクスプローラの仕様でしょうが…
めんどくさいのでパスします。
> 違うコマンドプロンプトから実行するからダメという事なのですか。
そんなことないです。
ちゃんと「多重起動だ」と判定できます。できないとおかしいです。