二重起動を防止するには?


えみ  2004-11-25 19:33:19  No: 11906

二重起動防止について過去ログを調べたのですが、わからなかったので教えてください。

BefCalc.exeとMainCalc.exeという2つのexeを作成しました。
このexeのアプリケーションタイトルは同じ「計算システム」という名前です。
MainCalc.exeは単独でも起動でき、BefCalc.exeからも起動させるシステムとなります。

他システムでGlobalFindAtomを使用して二重起動防止をしていたので
参考にして以下のようなプログラムを作成しました。

==========================
var
  Atm1:         TAtom;
  Atm2:         TAtom;
  ActiveHandle: THandle;
  Basepath : string;

const
  SYSTEM_TITLE = '計算システム';

begin

//GlobalFindAtomにプログラム名を渡してすでに登録済みかどうかを調べる
Atm1 := GlobalFindAtom(PChar(ExtractFileName(Application.ExeName)));  //起動EXE

BasePath := ExtractFilePath(Application.ExeName);
BasePath := BasePath + 'BefCalc.exe';      //別EXE
Atm2 := GlobalFindAtom(PChar(BasePath));

try

  //戻り値が0以外の時はすでに登録済み
  if (Atm1 <> 0) or (Atm2 <> 0) then
  begin
    //メインウィンドウの名前でアプリケーションのハンドルを検索
    ActiveHandle := FindWindow(nil, SYSTEM_TITLE);

    //すでに起動しているので、前面に出すなどの処理を行う
    if ActiveHandle <> 0 then
    begin
      showmessage('すでに起動しています。');

      //アイコン状態なら元に戻す
      if IsIconic(ActiveHandle) then
        SendMessage(ActiveHandle, WM_SYSCOMMAND, SC_RESTORE, -1);

      //見つかったアプリケーションを前面に表示
      SetForeGroundWindow(ActiveHandle);

      Exit;
    end
    else
      GlobalDeleteAtom(Atm);

  //プログラム実行
  Atm := GlobalAddAtom(PChar(ExtractFileName(Application.ExeName)));

==========================

MainCalc.exeが起動しているときはMainCalc.exeが起動できない、
BefCalc.exeが起動しているときはBefCalc.exeが起動できないように
ということは出来ました。

しかし、MainCalc.exeが起動しているときはBefCalc.exeが起動しないように、
BefCalc.exeが起動しているときはMainCalc.exeは起動しないようにさせることが出来ません。
(Atm2が0で返ってくるため)

ちなみに、システム名が同じなのでFindWindowをtryの前に持ってきてハンドルを取得したのですが、
この方法ではうまくいかない場合があります。
例えば、システムと同じ名前のフォルダ名(計算システムというフォルダ)を作成し、
そのフォルダを開いていたらEXEを起動していなくても起動している状態となってしまいました。

このような場合はどのようにして二重起動防止をしたらよろしいですか?
よろしくお願いします。


LupinⅢ  URL  2004-11-25 20:30:32  No: 11907

こんな感じでしょうか

var
  HWND,HAPP:THandle;
begin
  Application.Initialize;

  HWND := FindWindow(nil,'アプリタイトル');
  if (HWND <> 0) then begin
     //メインウィンドウがある場合、アプリケーションのハンドルを取得する
     HAPP := GetWindow(HWND,GW_OWNER);
     if (IsIconic(HAPP)) then
        //アプリケーションがアイコン化されていた場合、元サイズにする
        OpenIcon(HAPP);
     //前面に移動させる
     SetForegroundWindow(HAPP);
  end else begin

     Application.Title := 'アプリタイトル';
     Application.CreateForm(TMainForm, MainForm);
     Application.Run;
  end;


えみ  2004-11-25 23:08:16  No: 11908

返信ありがとうございます。

その方法では以下の場合におかしくなってしまいます。

>ちなみに、システム名が同じなのでFindWindowをtryの前に持ってきてハンドルを取得したのですが、
>この方法ではうまくいかない場合があります。
>例えば、システムと同じ名前のフォルダ名(計算システムというフォルダ)を作成し、
>そのフォルダを開いていたらEXEを起動していなくても起動している状態となってしまいました。

他に何か方法はないでしょうか?


ミュータント  2004-11-25 23:38:55  No: 11909

Mutex をつかった方法のコンポがいっぱいありますよ。検索してみたらいかがですか。


LupinⅢ  URL  2004-11-26 00:20:13  No: 11910

Mutexバージョンです

■使用するAPI関数 

OpenMutex(既存の名前付きミューテックスオブジェクトのハンドルを取得する) 
CloseHandle(オブジェクトのハンドルをクローズする) 
CreateMutex(ミューテックスオブジェクトを作成する) 
ReleaseMutex(ミューテックスオブジェクトの所有権を解放する) 

■アプリケーションの二重起動を防止する処理 
program Project1;

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

{$R *.RES}

var
Mutex: Integer;

begin

  //ミューテックスオブジェクトのハンドルを取得する
  Mutex := OpenMutex(MUTEX_ALL_ACCESS, False, 'EX_Mutex');

  if Mutex <> 0 then  begin
    // オブジェクトのハンドルをクローズする
    CloseHandle(Mutex);
    Exit;
  end;

  //ミューテックスオブジェクトを作成する
  Mutex := CreateMutex(nil, False, 'EX_Mutex');

  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;

  //ミューテックスオブジェクトの所有権を解放する
  ReleaseMutex(Mutex);

end.


ミュータント  2004-11-26 02:55:58  No: 11911

OpenMutex()としてからCreateMutex()とするというのは、割り込める余地があるので間違いです。

http://techtips.belution.com/ja/vc/0025/


LupinⅢ  URL  2004-11-26 18:54:32  No: 11912

なるほど!!勉強になりました。


Fusa  2004-11-27 20:34:39  No: 11913

こうなるかな。

program Project1;

uses
  Windows,
  Forms,
  Unit1 in 'Unit1.pas' ;

{$R *.res}

const
  MutexName = 'myMutex';
  WindowClass = 'TForm1';
var
  hMutex: THANDLE;
  Wnd: HWnd;
  AppWnd: HWND;
  WindowTitle: String;
begin
  WindowTitle := 'myMainFormTitle';

  hMutex := CreateMutex(nil, False, MutexName);
  if hMutex = 0 then Exit;

  if GetLastError() = ERROR_ALREADY_EXISTS then
  begin

    Wnd := FindWindow(PChar(WindowClass), PChar(WindowTitle));
    if Wnd <> 0 then
    begin
      AppWnd := GetWindowLong(Wnd, GWL_HWNDPARENT);
      if AppWnd = 0 then AppWnd := Wnd;

      {二重起動時の動作}
    end;
    Exit;
  end;

  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;

  ReleaseMutex(hMutex);
end.


えみ  2004-11-30 19:23:20  No: 11914

お返事が遅くなり、すみませんでした。
たくさんの返信ありがとうございます。

Mutexを使ったやり方で試しましたが起動出来てしまいます。
失敗です・・・。

皆さんの返信を見ていると「同じEXEを起動出来ないようにする」という
方法を教えていただいてるような気がします。
私の表現が悪かったのではないかと思いますので、もう1度まとめます。

私がやりたいのは「このEXEが起動している時は別EXEを起動させない」
という方法を教えてほしいと思い、書き込みをしました。
例えば、EXE1が起動している時はEXE2は起動出来ないようにしたいのです。
この場合は、EXE2のプロジェクトファイル(dpr)に
「EXE1が起動していれば終了する。
  EXE1が起動していなければ自身を起動する。」
という処理を書いてあげればいいと思っています。
しかし、どのようにEXE1が起動しているかを確認すればいいのかわかりません。
方法を教えてください。
よろしくお願いします。


りおりお  2004-11-30 19:35:57  No: 11915

> 皆さんの返信を見ていると「同じEXEを起動出来ないようにする」という
> 方法を教えていただいてるような気がします。

違います。同じ名前の Mutex はひとつしか作れない、ってことを利用しています。
ですから、えみさんの要望を満たしています。Exe1 も Exe2 も同じ名前の Mutex
を作れるかどうかで判断できます。


AY  2004-12-15 02:33:27  No: 11916

>BefCalc.exeとMainCalc.exeという2つのexeを作成しました。
>このexeのアプリケーションタイトルは同じ「計算システム」という名前です。
>MainCalc.exeは単独でも起動でき、BefCalc.exeからも起動させるシステムとなります。

>MainCalc.exeが起動しているときはMainCalc.exeが起動できない、
>BefCalc.exeが起動しているときはBefCalc.exeが起動できないように
>ということは出来ました。

>しかし、MainCalc.exeが起動しているときはBefCalc.exeが起動しないように、
>BefCalc.exeが起動しているときはMainCalc.exeは起動しないようにさせることが出来ません。

この要件を、起動時に制御するには  仕様的に無理が無いですか・・
BefCalc.exeの中から、起動する(単独起動ではない)MainCalc.exeは
別なEXE名にするとかしないと・・


jok  2004-12-15 02:43:48  No: 11917

>BefCalc.exeの中から、起動する(単独起動ではない)MainCalc.exeは
>別なEXE名にするとかしないと・・

そのときは、特別な起動パラメータ渡して、二重起動抑止ロジックの実行を迂回すると。どちらもプログラム可能なら簡単です。


AY  2004-12-15 03:11:44  No: 11918

jokさん、考えてみれば、そうですね。
組み合わせパターンばかりに頭が行っていました。
>BefCalc.exeとMainCalc.exeという2つのexeを作成しました。
と書かれているので、どちらも御自身で触れそうなので、OKでしょう。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加