二重起動を防止するための策は色々ある。
有名なのは以下の3つかな?
1.FindWindowを使う
2.ToolHelp32を使う
3.Mutexを使う
とりあえず1はデバッガが起動出来ないのでボツ。
コメントアウトすればいいらしいが、ミスの元になる。
2は実行中のアプリの一覧を取得し、どうたらこうたらするらしい。
NTだけ動かないらしいが、さして問題でもない。
3は最もメジャーな方法。恐らく多くのソフトがこれを採用しているだろう。
ということでMutexについて触れてみる。
Mutexっていうのはユニークなシステムグローバルなオブジェクトで、
同じ名前のMutexを複数存在させることは出来ない。
これを利用して既にMutexが存在していれば起動を阻止するようにすればいい。
(本来はスレッド間の同期を取る時とかに使うらしいよ)
処理はプロジェクトソースか、initialization部に記述する。
プロジェクトソースを弄るのは見てくれてきに美しくないなので、
今回はinitialization部に記述してみる。
var
MutexName: string;
hMutex: THandle;
initialization
MutexName:= {任意の文字列(※)};
hMutex:= OpenMutex(MUTEX_ALL_ACCESS, False, PChar(MutexName));
if hMutex <> 0 then
begin
CloseHandle(hMutex);
Halt;
end;
hMutex:= CreateMutex(nil, False, PChar(MutexName));
finalization
ReleaseMutex(hMutex);
end.
何が何やらといった感じだが、
MutexNameはMutexの名前に設定する文字列、hMutexはMutexのハンドルを表す変数。
まず最初にMutexNameに重複しそうにない名前を与えてやる。(何を与えてやるべきかは後述)
そしたらOpenMutex関数で既にその名前のMutexが存在するかを調べてやる。
もし仮にhMutexが0、すなわちMutexが存在しなければ、
そのアプリは起動していないと言うことなので、通常通りに起動が出来るわけである。
しかし、ここでMutexが検出されたら既に起動済みなので、
if文内でMutexをCloseしてやってからプログラムを終了させている。
CreateMutex〜の一文は、Mutexが検出されていない時、
すなわち既に起動していない状態の時に二重起動を阻止するためにMutexを作成している。
finalization部はMutexを破棄しているだけ。
さて、Mutexは二重起動を防止するために今回は使っている。
このためMutexに設定する文字列がもし他のアプリと被ると、
当然二重起動と判別されてしまうわけである。
これを防止するためにはできるだけ被らない名前を考えなくてはならない。
1.アプリケーションのタイトル名
被る確率は結構低いと思うが、万が一があるかも知れない。
あと、悪質な嫌がらせとして意図的に同名のMutexを作成されてしまう危険性も考えられる。
(そんなことねーとは思いますけどね)
2.Application.ExeName
ある意味ユニークといえる。
Windowsでは同じフォルダ内に同じファイル名が存在することは出来ないので、
そのアプリの実行名をフルパスで含んでいるApplication.ExeNameは確かにユニークだ。
ただし、これは他のフォルダから起動されてしまうといった恐れがある。
最も、複数のフォルダに同じプログラムをインストールすることはあまり無いと思うが。
3.GUIDを使う
最も確実な方法がこれ。GUIDとは世界中で重複することがなく、
ユニークであることが保証された128bitのランダムな数値のこと。
グローバル一意識別子なんて呼んだりもするらしい。
GUIDは重複することがないと保証されているため、
設定したGUID自体を知られない限り名前が被ることはない。
GUIDの生成はコードエディタ上でShift+Ctrl+Gで即座に生成出来る。
(例:['{F2788EA9-DC89-40B8-B877-5AB62B2AF622}'])
とりあえずGUIDを使えばまず被ることはないだろう。
ちなみにGUIDの生成はいつから出来るのかは知りません。
試したところBDS2006、Delphi7Pro両方とも出来ました。
もし出来ない場合はMicrosoftで公開されているGUID生成ツールを使えばいいだけ。