第159章 グローバル・アトム その3


マルチタスク環境では、同一のプログラムを複数起動する ことができます。しかし、プログラムの内容によっては重複起動 してほしくないこともあります。 今回は、グローバル・アトムを利用してアプリケーションの 重複起動を防止するプログラムを考えてみます。

この方法は、以前筆者がある人から教わった方法です。

1.プログラムが開始したらすぐにグローバル・アトム・テーブルに   このプログラム特有の文字列がないか確認します。 2.もし、存在すればプログラムを終了します。 3.存在しなければ、GlobalAddAtom関数で特有の文字列を格納します。 4.プログラム終了時に3.のアトムを削除します。

たったこれだけです。自分と同じプログラムがすでに起動されていると 1.の段階で終了してしまいます。偶然他のアプリケーションが自分の アプリケーションと同じ文字列をテーブルに格納していたら、起動する ことができないので、ありそうにない文字列を決めておく必要があります。

では、プログラムを見てみましょう。

// atom03.cpp #ifndef STRICT #define STRICT #endif #define MYATOMSTR "Yasutaka Kumei, atom03, 1998" #include <windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); BOOL IsDuplicate(void); char szClassName[] = "atom03"; //ウィンドウクラス ATOM aMyAtom;

いつもとたいして変わりませんが、MYATOMSTRにこのプログラム 特有の文字列をdefineしておきます。自分の氏名、プログラム名、 日付、電話番号、でたらめな文字列などを組み合わせておくと、 偶然同じ文字列が他のアプリケーションによってグローバル・アトム・テーブルに 格納されている確率は限りなく0に近づきます。

int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; if (IsDuplicate()) return FALSE; if (!InitApp(hCurInst)) return FALSE; if (!InitInstance(hCurInst, nCmdShow)) return FALSE; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; }

WinMain関数が始まったらすぐに重複起動をチェックする 自作関数IsDuplicateを呼びます。もしこの関数がTRUEを返したら WinMain関数から抜けてプログラムを終了します。

//ウィンドウ・クラスの登録 ATOM InitApp(HINSTANCE hInst) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; //プロシージャ名 wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst; //インスタンス wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; //メニュー名 wc.lpszClassName = (LPCSTR)szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); return (RegisterClassEx(&wc)); } //ウィンドウの生成 BOOL InitInstance(HINSTANCE hInst, int nCmdShow) { HWND hWnd; hWnd = CreateWindow(szClassName, "猫でもわかるアトム", //タイトルバーにこの名前が表示されます WS_OVERLAPPEDWINDOW, //ウィンドウの種類 CW_USEDEFAULT, //X座標 CW_USEDEFAULT, //Y座標 CW_USEDEFAULT, //幅 CW_USEDEFAULT, //高さ NULL, //親ウィンドウのハンドル、親を作るときはNULL NULL, //メニューハンドル、クラスメニューを使うときはNULL hInst, //インスタンスハンドル NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } //ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; switch (msg) { case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { if (aMyAtom) { if(!GlobalDeleteAtom(aMyAtom)) MessageBox(hWnd, "グローバルアトムを削除しました", "OK", MB_OK); } DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }

このへんは、いつもとほとんど同じですが、終了時にaMyAtomを削除しています。

BOOL IsDuplicate(void) { if (GlobalFindAtom(MYATOMSTR) == NULL) { MessageBox(NULL, "初回起動です", "初回起動", MB_OK); aMyAtom = GlobalAddAtom(MYATOMSTR); return FALSE; } else { MessageBox(NULL, "重複起動です", "重複起動", MB_OK | MB_ICONEXCLAMATION); return TRUE; } }

プログラムが始まるとすぐにWinMainから呼ばれます。 GlobalFindAtom関数でこのプログラムに特有な文字列が、グローバル・アトム・テーブルに 格納されていないか調べます。この時大文字・小文字の区別はされません。 これが気になる人はあと2、3行プログラムを書き足してください。

さて、このプログラムはちょっと困ったことがおこります。 プログラムが起動してから、何らかのエラーで強制的に終了されてしまった場合 グローバル・アトム・テーブルに文字列が格納されたままになりますので 再度起動することができません。こうなったらコンピュータをリセットする しかありません。

重複起動をチェックする方法はほかにもいろいろあります。 考えてみて下さい。


[SDK第2部 Index] [総合Index] [Previous Chapter] [Next Chapter]

Update 28/Nov/1998 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。