最初のアプリケーションインスタンスのウィンドウを最前面に置く

多重起動が防止されたことをユーザに示す手段として、最初のアプリケーションインスタンスのウィンドウを最前面に置くというものがあります。それを実現するには、Windowsが提供するプロパティを利用します。手順は次の通りです。
  1. 最初のインスタンスは、Applicationオブジェクトにプロパティを設定する。
  2. 二番目以降のインスタンスは、EnumWindowsを使ってシステム内のウィンドウを列挙する。
  3. 1で設定したプロパティを持つウィンドウが見つかったら、それをSetForegroundWindowで最前面に置く。
特定のウィンドウを見つけるには、FindWindowではなく、EnumWindowsを使うようにします。ウィンドウハンドルを取得してからウィンドウの操作に移るまでには、時間的な間隔が生じます。FindWindowは、この間にウィンドウハンドルが閉じられて無効になることを防げません。それに対してEnumWindowsは、ウィンドウの列挙中にはウィンドウハンドルが確実に有効であることを保証します。

例えば、次のようにします。

//---------------------------------------------------------------------------
// Project1.cpp
//---------------------------------------------------------------------------
namespace {
//---------------------------------------------------------------------------
// 多重起動防止用ミューテックスの名前
const AnsiString AppInstanceLockName = "ExampleAuthor.ExampleApplication.AppInstanceLock";

// 最初のアプリケーションインスタンスに設定するプロパティの名前
const AnsiString AppInstanceMarkName = "ExampleAuthor.ExampleApplication.AppInstanceMark";

void __fastcall EnsureSingleAppInstance();
BOOL CALLBACK SetFirstAppInstanceForeground(HWND hwnd, LPARAM lParam);
//---------------------------------------------------------------------------
// 多重起動を防止する。もし既にインスタンスがあれば、それを最前面に置く。
void __fastcall EnsureSingleAppInstance()
{
        ::SetLastError(NO_ERROR);
        HANDLE instanceLock = ::CreateMutex(NULL, true, AppInstanceLockName.c_str());
        if(instanceLock == NULL || ::GetLastError() != NO_ERROR) {
                ::EnumWindows(reinterpret_cast<WNDENUMPROC>(SetAppFirstInstanceForeground), NULL);
                Abort();
        }
        if(!::SetProp(Application->Handle, AppInstanceMarkName.c_str(), reinterpret_cast<HANDLE>(1))) {
                Abort();
        }
}
//---------------------------------------------------------------------------
// コールバック関数。多重起動防止後、最初のインスタンスを最前面に置く。lParam
// は使用しない。
BOOL CALLBACK SetFirstAppInstanceForeground(HWND hwnd, LPARAM lParam)
{
        if(::GetProp(hwnd, AppInstanceMarkName.c_str()) != NULL) {
                ::SetForegroundWindow(hwnd);
        }
        return true;
}
//---------------------------------------------------------------------------
} // End of namespace
//---------------------------------------------------------------------------
// ...
//---------------------------------------------------------------------------
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
        try
        {
                EnsureSingleAppInstance();

                Application->Initialize();
                Application->CreateForm(__classid(TForm1), &Form1);
                Application->Run();
        }
        catch(EAbort& e)
        {
                // Do nothing
        }
        catch (Exception &exception)
        {
                // ...
        }
        catch (...)
        {
                // ...
        }
        return 0;
}
//---------------------------------------------------------------------------
最終更新: 2008-11-10

戻る