|
さて、良く見かけると思うけども1個起動していると、2回目起動しようとすると怒られたり、1回目に起動した奴がアクティブになる奴を実装しようかなと。 今回作っている物も多重起動されると厄介なのだ。ファイルに同時アクセスに行ったり、フォルダ名が変わってたりするし。 ので、やってみた。 |
|
|
|
これもさして難しい実装では無いっす。 まずはApp Classを開きます。今回の場合は PictureAlbum.cpp 普通はアプリ名.h, cpp ってなってると思います。 で、CPictureAlbumApp::InitInstance()内に書きます。
BOOL CPictureAlbumApp::InitInstance()
{
// アプリケーション マニフェストが visual スタイルを有効にするために、
// ComCtl32.dll バージョン 6 以降の使用を指定する場合は、
// Windows XP に InitCommonControls() が必要です。さもなければ、ウィンドウ作成はすべて失敗します。
InitCommonControls();
CWinApp::InitInstance();
/* 2重起動防止 */
HANDLE hMutex;
hMutex = CreateMutex( NULL, TRUE, "PictureAlbum by Antenn-a" );
if ( !hMutex )
return FALSE;
if ( GetLastError() == ERROR_ALREADY_EXISTS ){
HWND hPrevWnd = GetWindow( GetDesktopWindow(), GW_CHILD );
while ( hPrevWnd ){
if( ::GetProp( hPrevWnd, "PictureAlbum by Antenn-a" ) ){
// 同じウィンドウが見つかった場合はそちらにフォーカスを移す
// 小さくなってたらデカくする
if( IsIconic( hPrevWnd ) )
ShowWindow( hPrevWnd, SW_RESTORE );
// ここでフォアグラウンドにする
SetForegroundWindow( ::GetLastActivePopup( hPrevWnd ) );
return FALSE;
}
hPrevWnd = GetWindow( hPrevWnd, GW_HWNDNEXT );
}
return FALSE;
}
// 標準初期化
// これらの機能を使わずに、最終的な実行可能ファイルのサイズを縮小したい場合は、
// 以下から、不要な初期化ルーチンを
// 削除してください。
// 設定が格納されているレジストリ キーを変更します。
// TODO: この文字列を、会社名または組織名などの、
// 適切な文字列に変更してください。
SetRegistryKey(_T("アプリケーション ウィザードで生成されたローカル アプリケーション"));
LoadStdProfileSettings(4); // 標準の INI ファイルのオプションをロードします (MRU を含む)
// アプリケーション用のドキュメント テンプレートを登録します。ドキュメント テンプレート
// はドキュメント、フレーム ウィンドウとビューを結合するために機能します。
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CPictureAlbumDoc),
RUNTIME_CLASS(CMainFrame), // メイン SDI フレーム ウィンドウ
RUNTIME_CLASS(CPictureAlbumView));
AddDocTemplate(pDocTemplate);
// DDE、file open など標準のシェル コマンドのコマンドラインを解析します。
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
// コマンド ラインで指定されたディスパッチ コマンドです。アプリケーションが
// /RegServer、/Register、/Unregserver または /Unregister で起動された場合、 False を返します。
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// メイン ウィンドウが初期化されたので、表示と更新を行います。
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
// 接尾辞が存在する場合にのみ DragAcceptFiles を呼び出してください。
// SDI アプリケーションでは、ProcessShellCommand の直後にこの呼び出しが発生しなければなりません。
// プロパティにセット(消去はMainFrm.cpp内のデストラクタに記述)
::SetProp(m_pMainWnd->GetSafeHwnd(), "PictureAlbum by Antenn-a", (HANDLE)1);
return TRUE;
}
着目点は /* 2重起動防止 */ のコメントアウトの当たりと、returnの直前にある ::SetProp()って奴です。 これらを追記してから、MainFrm.cpp を開きデストラクタで
CMainFrame::~CMainFrame()
{
// プロパティ消去(作成は PictureAlbum.cpp内に記述)
::RemoveProp(GetSafeHwnd(), "PictureAlbum by Antenn-a");
}
こんな感じです。 これで2重起動が防止できます。 |
|
|
|
何をしているかというと、Mutex(相互排他オブジェクト)を作ってるんですね。 で、最初の着目点では CreateMutex しようとしてます。この時ユニークなIDを文字列で定義出来、今回は PictureAlbum by Antenn-aという文字列でした。 その後、1回目の起動の場合は、スルスルと流れて ::SetProp でそのウィンドウのプロパティに PictureAlbum by Antenn-a を書き込みます。 次回起動時は、同じIDでMutexを作ると失敗し、GetLastError に引っかかります。 ここで、return すればアプリケーションが作成されません。 また、一度セットしたプロパティは消さねばならないので、MainFrame のデストラクタでプロパティを消去してます。 これで、アプリケーションは2重起動する事は無く、最小化されていても元に戻ってアクティブウィンドウになります。 出来た出来た、わーい |