● 二重起動を禁止する - その3 ●

VBでは極めてマイナー。ここまで来ると本人の趣味。

さて、ここではミューテックスというものを使おう。私本人も100%理解しているというわけではないが、まあ、やってみましょう。今回の処理の流れを簡単に言うと、メモリー上に任意の名前を持つオブジェクトが存在するかを見て、存在するなら2重起動処理、存在しないなら、オブジェクトを作成した後、通常起動という感じ。

オブジェクトがメモリー上に存在するということは、他プロセスから参照できるということ。簡単に言うと全く違ったアプリケーションどうしで、共通の情報を参照できるってことになるかな。また、ミューテックスオブジェクトは1プロセスに1つしか作れないよ。

ここで注意することが1つある。

やってみて分かたんだけど、Visual Basic 開発環境では、アプリケーションからミューテックスオブジェクトを解放しても駄目であるということ。開発中のアプリケーションを Visual Basic から実行した場合、Visual Basic がアプリケーションのハンドル等を管理する。その結果、ミューテックスオブジェクトを作成しても、Visual Basic もそれを保持してしまいアプリケーションから解放しても解放できないのよ。従って、ミューテックスオブジェクトを削除するには Visual Basic を終了しなければならない。こんな事をすることは非常に面倒なので、実行ファイルから起動していればミューテックスを有効にし、Visual Basic 開発環境なら無効にするというようにする。本来なら GetModuleFileName API関数を使用してするべきなのであろうがここでは Debug.Print の性質を利用することにする。

Debug.Printは、開発環境においては有効だけど、コンパイルすると無視され実行ファイルには反映されない。従って、意図的にエラーを発生させることにより、その2つの判断ができる。簡単である。0で除算すればよい。実際コードで書いてみるとよく分かる。

'---------------------------------------------------------------------------
'  関数名 : IsNotVBProject
'  機能   : Visual Basic の開発環境であるか調べる
'  引数   : なし
'  返り値 : True  … 実行ファイル環境
'              False … Visual Basic の開発環境
'---------------------------------------------------------------------------
Public Function IsNotVBProject() As Boolean

    On Error Resume Next

    Debug.Print 1 \ 0

    IsNotVBProject = CBool(Err.Number = 0)

End Function

さて、ミューテックス関連のAPI関数・定数・外部変数は以下の通り。

Private Declare Function OpenMutex Lib "Kernel32" Alias "OpenMutexA" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal lpName As String) As Long

Private Declare Function CreateMutex Lib "Kernel32" Alias "CreateMutexA" (ByVal lpMutexAttributes As Long, ByVal bInitialOwner As Long, ByVal lpName As String) As Long

Private Declare Function ReleaseMutex Lib "Kernel32" (ByVal hMutex As Long) As Long

Private Declare Function CloseHandle Lib "Kernel32" (ByVal hObject As Long) As Long

Private Const SYNCHRONIZE = &H100000
Private Const STANDARD_RIGHTS_REQUIRED = &HF0000
Private Const MUTANT_QUERY_STATE = &H1
Private Const MUTANT_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED Or SYNCHRONIZE Or MUTANT_QUERY_STATE

'ミューテックスオブジェクトのハンドル
Private hMutex As Long

'メモリー共有する文字
Private Const APPNAME_ON_MEM As String = "MyAppName"

APPNAME_ON_MEM は各自で好きなように変更してね。

'---------------------------------------------------------------------------
' 関数名: IsMutexEntity
' 機  能: ミューテックスオブジェクトが作成されているか調べる
'          作成されていなかったら作成する
' 引  数: なし
' 返り値: True …  ミューテックスオブジェクトが存在する
'          False … ミューテックスオブジェクトが存在しない
' 備  考: 二重起動防止に使用する
'---------------------------------------------------------------------------
Public Function IsMutexEntity() As Boolean

    'ミューテックを開く
    hMutex = OpenMutex(MUTANT_ALL_ACCESS, 0&&, APPNAME_ON_MEM)

    'ミューテックスオブジェクトが存在するならハンドルをクローズし、終了
    If hMutex Then
        Call CloseHandle(hMutex)
        IsMutexEntity = True
        Exit Function
    End If

    'ミューテックスオブジェクトを作成する
    hMutex = CreateMutex(0&, 0&&, APPNAME_ON_MEM)

End Function

'---------------------------------------------------------------------------
' 関数名: ReleaseMyMutex
' 機  能: ミューテックスオブジェクトを解放する
' 引  数: なし
' 返り値: なし
' 備考  : IsMutexEntity を呼び出していたら必ずこの関数を呼ばなければならない
'---------------------------------------------------------------------------
Public Sub ReleaseMyMutex()

    Call ReleaseMutex(hMutex)

End Sub

使用例は以下の通り。

Private Sub Form_Load()
    実行環境が Visual Basic 開発環境ではない
    If IsNotVBProject Then
        If IsMutexEntity Then Call MsgBox("2重起動です"):End
    End If
End Sub

Private Sub Form_Unload(Cancel As Integer)
    Call ReleaseMyMutex
End Sub

戻る