[Delphi] アプリケーションの多重起動を防止する(.Net)

アプリケーションの多重起動を防止したい場面は結構あるのではないでしょうか? 処理結果を特定のファイルに出力するケースなどがあった場合、複数のアプリケーションがその処理を行うと、最悪そのファイルが壊れるケースが出てきそうですし、ファイルが壊れなくても、内容が変になる危険性が高いと思います。 多重起動防止方法にはいくつか方法があると思いますが、ここではもっとも実装が一般的だと思われる Mutex を使った方法をご紹介します。
Mutex に付いての詳細は、@ITにわかりやすい解説があったのでそちらを参照してもらえれば、くろねこの下手な文章よりわかりやすいと思います。
ただ、@IT では Delphi のサンプルが無かったので、Delphi での多重起動防止についてサンプルを作ってみました。
Delphi で .Net 対応アプリを作るのは大きく分けて2とおりの方法があります。VCL.Net を使う方法と、 Windows Form を使用する方法です。VCL.Net で Mutex を実装する際にまた2とおりの方法に分かれます。2とおりの方法とは、VCL.Net (SyncObjs ユニット) にある TMutex クラスを使う方法と、.Net Framework (System.Threading) にある Mutex クラスを使う方法です。くろねこ的には、.Net Framework を使用する方が美しいかと思います。

以下のサンプルをダウンロードできるようにしました。3つのサンプルがまとめてアーカイブしてあります。プロジェクトグループでそれぞれを確認するとわかりやすいと思います。プロジェクトグループでの順番はこのぺージの順番と同じにしてあります。

Delphi VCL.Net で .Net Framework の Mutex クラスを使って多重起動防止を実現

Delphi で一番使うケースになるのではないでしょうか?@IT の記事と同じくWindiws 2000 以降ではグローバル Mutex を使用しています。

const 
  sAppconstName = 'MutexSample'; 
var 
  sMutexName: String; 
  mutexObject: Mutex; 
[STAThread] 
begin 
  if (Win32Platform = VER_PLATFORM_WIN32_NT) and (Win32MajorVersion >= 5) then 
    sMutexName := 'Global' + sAppconstName 
  else 
    sMutexName := sAppconstName; 
 
  try 
    // ミューテックスを生成する 
    mutexObject := Mutex.Create(false, sMutexName); 
  except 
    on E: Exception {ApplicationException} do 
    begin 
      // グローバル・ミューテックスによる多重起動禁止 
      Application.MessageBox('すでに起動しています。2つ同時には起動できません。', '多重起動禁止'); 
      exit; 
    end; 
  end; 
 
  // ミューテックスを取得する 
  if (mutexObject.WaitOne(0, false)) then 
  begin 
    // アプリケーションを実行 
    Application.Initialize; 
    Application.CreateForm(TForm12, Form12); 
    Application.Run; 
 
    // ミューテックスを解放する 
    mutexObject.ReleaseMutex(); 
  end 
  else 
  begin 
    //  警告を表示して終了 
    Application.MessageBox('すでに起動しています。2つ同時には起動できません。', '多重起動禁止'); 
  end; 
 
  // ミューテックスを破棄する 
  mutexObject.Close(); 
end.

Delphi VCL.Net で SyncObjs の TMutex クラスを使って多重起動防止を実現 さきほどと同じ VCL.Net です。ただ SyncObjs の TMutex クラスを利用しています。mutexObject.ReleaseMutex(); に相当する記述がわからず、とりあえず Free しています。もしかするとメモリリークが発生しているかもしれません。 P/Invoke を多用しているようで、美しさで先ほどの例の方が良いかと思います。

const
  sAppconstName = 'MutexSample';
var
  sMutexName: String;
  Mutex: TMutex;
  MutexAttributes: TSecurityAttributes;
[STAThread]
begin
  if (Win32Platform = VER_PLATFORM_WIN32_NT) and (Win32MajorVersion >= 5) then     sMutexName := 'Global' + sAppconstName   else     sMutexName := sAppconstName;
  try
    // ミューテックスを生成する
    Mutex := TMutex.Create(MutexAttributes, false, sMutexName);
  except
    on E: Exception {ApplicationException} do
    begin
      // グローバル・ミューテックスによる多重起動禁止
      Application.MessageBox('すでに起動しています。2つ同時には起動できません。', '多重起動禁止');
      exit;
    end;
  end;

  // ミューテックスを取得する
  if (Mutex.WaitFor(0) = wrSignaled) then
  begin
    // アプリケーションを実行
    Application.Initialize;
    Application.CreateForm(TForm12, Form12);
    Application.Run;
    // ミューテックスを解放する
    Mutex.Release;
  end
  else
  begin
    //  警告を表示して終了
    Application.MessageBox('すでに起動しています。2つ同時には起動できません。', '多重起動禁止');
  end;

  // ミューテックスを破棄する
  FreeAndNil(Mutex);
end.

Delphi Windows Form で .Net Framework の Mutex クラスを使って多重起動防止を実現 Windows Form での実装例です。Windows Form を利用してプログラムを作成するなら、C# で作成した方が良いかもしれませんね。コードもほとんど変わらないと思います。

// アプリケーション固定名
const
  sAppconstName: String = 'MutexSample';

// 多重起動を禁止するミューテックス
var
  sMutexName: String;
  mutexObject: Mutex;
  os: OperatingSystem;
[STAThread]
begin
  // Windows 2000(NT 5.0)以降のみグローバル・ミューテックス利用可
  os := Environment.OSVersion;
  if ((os.Platform = PlatformID.Win32NT) and (os.Version.Major >= 5)) then
    sMutexName := 'Global' + sAppconstName
  else
    sMutexName := sAppconstName;

  try
    // ミューテックスを生成する
    mutexObject := Mutex.Create(false, sMutexName);
  except
    on E: Exception {ApplicationException} do
    begin
      // グローバル・ミューテックスによる多重起動禁止
      MessageBox.Show('すでに起動しています。2つ同時には起動できません。', '多重起動禁止');
      exit;
    end;
  end;

  // ミューテックスを取得する
  if (mutexObject.WaitOne(0, false)) then
  begin
    // アプリケーションを実行
    Application.Run(TWinForm.Create);

    // ミューテックスを解放する
    mutexObject.ReleaseMutex();
  end
  else
  begin
    //  警告を表示して終了
    MessageBox.Show('すでに起動しています。2つ同時には起動できません。', '多重起動禁止');
  end;

  // ミューテックスを破棄する
  mutexObject.Close();
end.

サンプルプログラムのダウンロードは→[Delphi FAQ用サンプル] Ini ファイルの読み書き

コメント (0件)


くろねこ研究所
https://www.blackcat.xyz/article.php/ProgramingFAQ_del0054