Migaro. 技術Tips

                       

ミガロ. 製品の技術情報
IBMiの活用に役立つ情報を掲載!


【Delphi】ミューテックスを使った二重起動の防止

Delphiでアプリケーションの二重起動防止を行う際に、
よく使われる方法の一つがWindows Mutex(ミューテックス)です。

Mutex(Mutual Exclusion Object)は、
Windowsが提供する同期オブジェクトです。
同じ名前のミューテックスはシステム内で一意に管理されます。

例えば、Delphiで作成したアプリケーションで
「MyApplicationMutex」という名前のミューテックスを作成しておくと、
同じアプリケーションをもう一度起動した際に、
同じ名前のミューテックスが既に存在するかチェックできます。
それによって、存在する場合には「既に起動中」という判断ができます。

通常は「OpenMutex」「CreateMutex」というWindows APIを使用します。
同名のミューテックスが既に存在する場合、
OpenMutexの戻り値に0以外の値がが返るので、そこから判断できます。

実装時はプロジェクトファイル(*.dpr)内にロジックを追加します。
プロジェクトファイルのソースを編集する場合は、テキストを直接変更するか、
IDE(統合開発環境)の右側のプロジェクトマネージャからEXE名部分を選択して
「Ctrl+V」または「右クリックから『ソースの表示』」を行います。

dprファイルのソースが表示されたら、以下のようにロジックを記述します。
赤字部分が標準からの追加ロジックとなります。)
(uses節に「Winapi.Windows」を追加します。)

program Project1;

uses
  Vcl.Forms,
  Winapi.Windows,
  Unit1 in 'Unit1.pas' {Form1};

{$R *.res}

var
  strMutexName : string;      // ミューテックス名
  hMutex: THandle;            // ミューテックスハンドル

begin
  // 二重起動禁止処理(Mutexを使用し、既に起動中なら新たに起動させない)
  strMutexName := 'MyApplicationMutex'; // 任意のミューテックス名
  hMutex := OpenMutex(MUTEX_ALL_ACCESS, false, PChar(strMutexName)); // ミューテックスオープン
  if hMutex <> 0 then
  begin                                                      // 0以外=すでに起動済み
    CloseHandle(hMutex);                                     // ミューテックスクローズ
  end
  else
  begin                                                      // 起動していない
    hMutex := CreateMutex(nil, False, PChar(strMutexName));  // ミューテックス作成
    Application.Initialize;                                  // 以下、元々の起動処理
    Application.MainFormOnTaskbar := True;
    Application.CreateForm(TForm1, Form1);
    Application.Run;
  end;
end.

 
上記のロジックでは、
起動済みの場合に新たに起動させない(EXE終了させる)だけの処理で、
新たに起動してすぐに終了するEXE側では、見た目上は何も起こりません。

事情を知らないユーザー様からは
「二重に起動したくてもできない」といった問合せがあるかもしれません。

 
そこでもうひと手間ロジックを追加し、
二重起動になっている場合は終了前にダイアログを表示させ、
既に起動しているウインドウを手前に表示させることも可能です。
赤字部分が先ほどのコードからの追加ロジックとなります。)
(uses節に「Winapi.Messages」「Vcl.Dialogs」を追加します。)
(ロジック内の『TForm1』は実際のメインフォーム名に読み替えて下さい。)

program Project1;

uses
  Vcl.Forms,
  Winapi.Windows,
  Winapi.Messages,
  Vcl.Dialogs,
  Unit1 in 'Unit1.pas' {Form1};

{$R *.res}

var
  strMutexName : string;      // ミューテックス名
  hMutex: THandle;            // ミューテックスハンドル
  hWnd, hAppWnd: THandle;     // アプリケーションウィンドウ

begin
  // 二重起動禁止処理(Mutexを使用し、既に起動中ならそれを前面に表示)
  strMutexName := 'MyApplicationMutex'; // 任意のミューテックス名
  hMutex := OpenMutex(MUTEX_ALL_ACCESS, false, PChar(strMutexName)); // ミューテックスオープン
  if hMutex <> 0 then
  begin                                                      // 0以外=すでに起動済み
    ShowMessage('既に起動しています。');
    hWnd := FindWindow('TForm1', nil);                       // 対象のメインフォームを探す
    if hWnd <> 0 then
    begin
      SetForegroundWindow(hWnd);                             // メインフォームを前面に
      hAppWnd := GetWindowLong(hWnd, GWL_HWNDPARENT);        // アプリケーションインスタンスハンドル
      if hAppWnd <> 0 then
        hWnd := hAppWnd;
      if IsIconic(hWnd) then                                 // アイコン状態?
        SendMessage(hAppWnd, WM_SYSCOMMAND, SC_RESTORE, -1); // リストア
    end;
    CloseHandle(hMutex);                                     // ミューテックスクローズ
  end
  else
  begin                                                      // 起動していない
    hMutex := CreateMutex(nil, False, PChar(strMutexName));  // ミューテックス作成
    Application.Initialize;                                  // 以下、元々の起動処理
    Application.MainFormOnTaskbar := True;
    Application.CreateForm(TForm1, Form1);
    Application.Run;
  end;
end.

 

ミューテックスは「起動済みかどうかの判定」に非常に適しており、
二重起動防止の実装として現在でも標準的な方法です。

プログラムの二重起動を防ぎたい場合にぜひご活用ください。