[delphi-users:4329] MUTEXが効かない?

閲覧: 668 回
最初の未読メッセージにスキップ

Quest

未読、
2015/12/15 7:18:292015/12/15
To: delphi...@freeml.com
いつもお世話になっています。

非常に不可解な現象に出くわしたので、皆さんのお知恵を借りたいと思います。

二重起動の防止にはMUTEXがよく使われますが
それを仕込んだのに二重起動してしまう状況が発生しています。

プロジェクトソースに
const
MUTEX_NAME = 'MUTEX_MYAPPLICATION';
var
hMutex: THandle;
begin
hMutex := CreateMutex(nil, True, MUTEX_NAME);
if WaitForSingleObject(hMutex, 0) = WAIT_TIMEOUT then
begin
MessageBox(Application.Handle, '既に起動しています',
'MyApplication', MB_OK);
CloseHandle(hMutex);
end
else
begin
try
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.Title := 'MyApplication';
Application.CreateForm(TDatabaseModule, DatabaseModule);
Application.CreateForm(TAppMainForm, AppMainForm);
Application.Run;
finally
CloseHandle(hMutex);
end;
end;
end.
このように記述しているのですが、TDatabaseModuleのOnCreateイベントで
同時に1プロセスしか開けないファイルを開くところでエラーになります。
(具体的にはFirebirdのEmbeded版でDBを開いています)
何らかの理由でTDatabaseModuleのOnCreateイベントが再度呼ばれたためとも考
えましたが
起動後にプロセスIDを取得しログに書き出してみると、明らかに違うIDが記録さ
れるので
確かに二重起動しているようです。

厄介なことに、開発マシンや手元にある別のPCでは全く再現せず、顧客先のPCで
のみ発生します。
その状況から環境に依存するものと思われますが
MUTEXが環境(や状況)によって効かない場合などあるのでしょうか?
このMUTEXの使い方が間違っているのでしょうか。

皆さんのお知恵をお貸しください。

Quest


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
Powered by freeml -- http://www.freeml.com/ --
------------------------------------------------------[freeml byGMO]--

中村拓男(自宅)

未読、
2015/12/15 7:43:162015/12/15
To: delphi-users

mutex名は頭に 'Global¥' を付けないと、Windowstation
に閉じたローカルなmutexになってしまいます。
サービスとかリモートデスクトップなど、異なる
Windowstationから起動されると、mutexは効きません。

-- Takuo Nakamura, Hino City Tokyo Japan

2015/12/15 21:18 "Quest" <delphi...@freeml.com>:

Quest

未読、
2015/12/15 10:29:202015/12/15
To: delphi...@freeml.com
中村さん、こんばんは。

この問題が発生する端末は業務専用でネットワークには繋がっておらず
PCに登録されているユーザーも管理者の一人だけですが
その状態で「異なるWindowstationから起動される」ということが
起きるのでしょうか。
とりあえずMutex名に 'Global¥' を付ける様にしてみます。

ありがとうございました。

Quest

On 2015/12/15 21:43, 中村拓男(自宅) wrote:
> mutex名は頭に 'Global¥' を付けないと、Windowstation
> に閉じたローカルなmutexになってしまいます。
> サービスとかリモートデスクトップなど、異なる
> Windowstationから起動されると、mutexは効きません。
>
> -- Takuo Nakamura, Hino City Tokyo Japan
>
> 2015/12/15 21:18 "Quest" <delphi...@freeml.com
> <mailto:delphi...@freeml.com>>:

中村拓男(自宅)

未読、
2015/12/15 10:42:472015/12/15
To: delphi-users

思いつくのをあげると

・ロ-カルでりモートディスクトップを使う。
・デスクトップ切替ソフトの使用(Win10ならOS標準)
・サービスからの起動やスケジュール起動

-- Takuo Nakamura, Hino City Tokyo Japan

2015/12/16 0:29 "Quest" <delphi...@freeml.com>:

auemura

未読、
2015/12/16 4:03:462015/12/16
To: delphi...@freeml.com
上村です。
2重起動の防止でWaitForSingleObjectを使うのは初めて見たのですが。
CreateMutexの返り値のチェック(Mutexの作成に失敗した場合NULLが返る)
また、WaitForSingleObjectが失敗した場合の対処をしないと現状だとWaitForSingleObjectが失敗した場合無条件で起動しちゃうんじゃないでしょうか。

中村拓男(自宅)

未読、
2015/12/16 4:25:342015/12/16
To: delphi-users

本当だ、initialOwner=true使っているなら、
排他出来たかはCreateMutexの戻りで
決まるから、見てないのは変。

-- Takuo Nakamura, Hino City Tokyo Japan

2015/12/16 18:03 "auemura" <delphi...@freeml.com>:

中村拓男(自宅)

未読、
2015/12/16 20:25:492015/12/16
To: delphi-users
久しぶりなので、ちゃんと調べてみました(^^;

コードとしてはこんなもので十分なはず。

h := CreateMutex(Nil, False, 'Global\TestTestMutex');

if h = 0 then
begin
ShowMessage('MUTEX作成失敗');
Exit;
end;

if GetLastError() = ERROR_ALREADY_EXISTS then
begin
ShowMessage('二重起動');
Exit;
end;

#「別ユーザで実行」で起動できるようにするには「セキュリティ属性」を
#ちゃんと作らないとだめらしい。

以下はMutexを使って2重起動防止を行う場合の基本

1)  CreateMutex で bInitalOwner を True を指定すると、
CreateMutexを呼んだスレッドがMutexを「作った場合のみ」
オーナ(ロック)を取得する。

bInitalOwner = true は使いにくいので通常は使用しない。
ロックがほしければ WaitForSingleObject で随時取得する方が
柔軟で簡単。

2) CreateMutex で2重起動を検出するには、自スレッドが
Mutexを作成したスレッドであることを確認すれば十分。
ロック(オーナ)の獲得は不要。

3) CreateMutexはセキュリティ関連でエラーになる可能性があるので、
必ず戻り値を見ること。

4) 自身がMutexを作成したスレッドだと確認するには
GetLastError() の戻りが ERROR_ALREADY_EXISTS ではないことを
確認すること

2015年12月16日 18:25 中村拓男(自宅) <delphi...@freeml.com>:
--
----------
Takuo Nakamura from Hino City Tokyo

Quest

未読、
2015/12/16 23:28:532015/12/16
To: delphi...@freeml.com
上村さん、中村さん、ご指摘有難うございます。
サンプルまでご提示いただき助かります。

以前から二重起動の防止はMutexを使っていましたが
詳細をきちんと理解していませんでした。
さっそく、きちんとした処理に変更して検証してみます。

有難うございました。
全員に返信
投稿者に返信
転送
新着メール 0 件