Ryukalice

C++Builder で二重起動を防止する

2013-11-05

TDoubleStartingGuard.h

/**
 * @file    TDoubleStartingGuard.h
 * @brief   二重起動防止クラス定義
 */

#ifndef TDoubleStartingGuardH
#define TDoubleStartingGuardH

#include <vcl.h>
#pragma hdrstop


namespace Common {


/**
 *  二重起動防止クラス
 *
 *  エントリーポイント(_tWinMain)で初期化処理を開始する前にguard()メソッドをコールする。
 *  この時の戻り値で、今回の起動が二重起動か否かを確認できる。
 */
class TDoubleStartingGuard {
    public:
        /**
         *  @brief    デフォルトコンストラクター
         */
        __fastcall TDoubleStartingGuard();

        /**
         *  @brief    デフォルトデストラクター
         */
        virtual __fastcall ~TDoubleStartingGuard();

        /**
         *  @brief    二重起動防止開始
         *  @return   正常時true。今回の起動が二重起動であればfalse。
         */
        bool __fastcall guard();

        /**
         *  @brief    二重起動防止用のミューテックスを破棄。
         *  @return    なし。
         */
        void __fastcall release();

    private:
        //! ミューテックスのハンドル
        HANDLE mMutexHandle;
};

}    // Common

#endif

TDoubleStartingGuard.cpp

/**
 * @file    TDoubleStartingGuard.cpp
 * @brief   二重起動防止クラスの実装
 */

#include "TDoubleStartingGuard.h"

#pragma package(smart_init)

namespace Common {


//------------------------------------------------------------------------------
// デフォルトコンストラクター
//------------------------------------------------------------------------------
__fastcall TDoubleStartingGuard::TDoubleStartingGuard() : mMutexHandle(NULL) {
    // DO NOTHING
}

//------------------------------------------------------------------------------
// デフォルトデストラクター
//------------------------------------------------------------------------------
__fastcall TDoubleStartingGuard::~TDoubleStartingGuard() {
    release();
}

//------------------------------------------------------------------------------
// 二重起動防止開始
//    実行ファイル名でミューテックスを作成しておく。
//    そのため、まずミューテックスをオープンしようとして成功した場合は、二重起動である。
//------------------------------------------------------------------------------
bool __fastcall TDoubleStartingGuard::guard() {
    const UnicodeString mutexName = ExtractFileName(ChangeFileExt(Application->ExeName, ""));

    mMutexHandle = OpenMutex(MUTEX_ALL_ACCESS, false, mutexName.c_str());
    if (mMutexHandle) {
        return false;
    }

    CreateMutexW(NULL, true, mutexName.c_str());

    return true;
}

//------------------------------------------------------------------------------
// 二重起動防止解除
//    gurad()で作成したミューテックスを破棄。
//------------------------------------------------------------------------------
void __fastcall TDoubleStartingGuard::release() {
    if (!mMutexHandle) {
        return;
    }

    CloseHandle(mMutexHandle);
    mMutexHandle = NULL;
}


}    // namespace Common

エントリーポイント

#include <vcl.h>
#pragma hdrstop

#include <tchar.h>
#include "TDoubleStartingGuard.h"

static Common::TDoubleStartingGuard DoubleStartingGuard;

//---------------------------------------------------------------------------
WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int) {
    try {
        // 二重起動防止
        if (!DoubleStartingGuard.guard()) {
            MessageBox(Application->Handle, L"アプリケーションは既に起動しています。", L"エラー", (MB_OK | MB_ICONERROR));
            return 0;
        }

        Application->Initialize();
        Application->CreateForm(__classid(TForm_Main), &Form_Main);
        Application->Run();

        // 二重起動防止解除
        DoubleStartingGuard.release();
    }
    catch (Exception &exception) {
        Application->ShowException(&exception);
    }
    catch (...) {
        try {
            throw Exception("");
        }
        catch (Exception &exception) {
            Application->ShowException(&exception);
        }
    }
    return 0;
}