システムメニュー


システムメニューを操作する

ウィンドウには、メニューバーやポップアップ以外にもう一つメニューがある
それが、システムメニューと呼ばれるメニューです
システムメニューは、ウィンドウメニュー、コントロールメニューと呼ばれることもあります

このメニューは CreateWindow() 関数のウィンドウスタイルで WS_SYSMENU を指定すると
ウィンドウに付加されるシステムよりのメニューです
//WS_OVERLAPPEDWINDOW は、WS_SYSMENU を含んでいます

このメニューは、ウィンドウのタイトルバーの左端にあるアイコンをクリックすると表示され
内容はデフォルトで移動やサイズ変更、閉じるなどの項目があります
これらの項目を選択すると、WM_SYSCOMMAND メッセージが発行されます
//このメッセージは、「閉じないウィンドウ」の章で少しだけ紹介した

WPARAM には、システムコマンドの要求された命令が格納されています
すなわち、これはメニューで言う ID にあたるものです
デフォルトで用意されているものでは、次のものがあります

定数解説
SC_CLOSE ウィンドウを閉じる
SC_CONTEXTHELP ポインターによってカーソルを疑問符に変更する
この状態でダイアログボックスをユーザーがクリックすると WM_HELP を受け取る
SC_DEFAULT デフォルトのアイテムを選択
SC_HOTKEY アプリケーション指定のホット キーに関連するウィンドウをアクティブにする
lParam の下位ワードでアクティブになるウィンドウの HWND を識別できる
SC_HSCROLL 水平スクロール
SC_KEYMENU キー操作によりメニューを取得します
SC_MAXIMIZE ウィンドウを最大化
SC_MINIMIZE ウィンドウを最小化
SC_MONITORPOWER ディスプレイの状態を設定する
パワーセーブ機能を持つコンピュータなどをサポートする

LPARAM は次の値になる
1 = ディスプレイのパワーが低い
2 = ディスプレイが停止している
SC_MOUSEMENU マウスクリックによってウィンドウメニューを取得
SC_MOVE ウィンドウを移動
SC_NEXTWINDOW 次のウィンドウへ移転
SC_PREVWINDOW 前のウィンドウ移転
SC_RESTORE ウィンドウを元の位置とサイズに戻す
SC_SCREENSAVE SYSTEM.INI ファイルの [boot] セクションで指定された
スクリーン セーバー アプリケーションを実行
SC_SIZE ウィンドウの大きさを設定
SC_TASKLIST スタートメニューをアクティブにする
SC_VSCROLL 垂直スクロール

これらのメッセージは、基本的に DefWindowProc() 関数で処理されます
そうしなければ、基本的なウィンドウの動作が行えません

LPARAM には、マウスカーソルの位置が格納されています
下位ワードに X 座標、上位ワードに Y 座標がそれぞれスクリーン座標で格納されています
このメッセージを処理した場合は 0 を返さなければいけません

実は、InsertMenu() 関数を使ってユーザー定義の項目を
このシステムメニューに対して追加することができます
しかし、そのためにはシステムメニューのハンドルが必要となります
システムメニューのハンドルを取得するには GetSystemMenu() 関数を使います

HMENU GetSystemMenu(HWND hWnd , BOOL bRevert);

hWnd はシステムメニューを持つウィンドウのハンドルを
bRevert が FALSE ならばこの関数はシステムメニューのハンドルを返します
しかし、bRevert を TRUE にした場合はデフォルトのメニューに戻します

戻り値は、bRevert が FALSE ならばシステムメニューのハンドル
TRUE であった場合、NULL が返ります

これで、システムメニューにユーザー定義の項目を追加できます
ただし、定義済みのシステム項目の ID と重複しない様に注意する必要があり
ユーザー定義の ID は 0xF000 以下 でなければなりません
#include <windows.h>
#define IDM_KITTY 1

LRESULT CALLBACK WndProc(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp) {
	HMENU sysMenu;
	MENUITEMINFO mii;

	switch (msg) {
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_CREATE:
		sysMenu = GetSystemMenu(hwnd , FALSE);

		mii.cbSize 		= sizeof (MENUITEMINFO);
		mii.fMask 		= MIIM_TYPE | MIIM_ID;
		mii.wID 		= IDM_KITTY;
		mii.fType 		= MFT_STRING;
		mii.dwTypeData 	= TEXT("Kitty on your lap");

		InsertMenuItem(sysMenu , 0 , TRUE , &mii);
		return 0;
	case WM_SYSCOMMAND:
		if (LOWORD(wp) == IDM_KITTY)
			GetSystemMenu(hwnd , TRUE);
	}
	return DefWindowProc(hwnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
			PSTR lpCmdLine , int nCmdShow ) {
	HWND hwnd;
	MSG msg;
	WNDCLASS winc;

	winc.style		= CS_HREDRAW | CS_VREDRAW;
	winc.lpfnWndProc	= WndProc;
	winc.cbClsExtra	= winc.cbWndExtra	= 0;
	winc.hInstance		= hInstance;
	winc.hIcon		= LoadIcon(NULL , IDI_APPLICATION);
	winc.hCursor		= LoadCursor(NULL , IDC_ARROW);
	winc.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	winc.lpszMenuName	= NULL;
	winc.lpszClassName	= TEXT("KITTY");

	if (!RegisterClass(&winc)) return -1;

	hwnd = CreateWindow(
			TEXT("KITTY") , TEXT("Kitty on your lap") ,
			WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			NULL , NULL ,
			hInstance , NULL
	);

	if (hwnd == NULL) return -1;

	while(GetMessage(&msg , NULL , 0 , 0)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}


システムメニューに追加した、ユーザー定義のメニュー項目です
これを選択すると、デフォルトのシステムメニューに戻ります
このように、GetSystemMenu() から取得したハンドルからシステムメニューを操作できます

WM_SYSCOMMAND をウィンドウプロシージャで処理していますが
IDM_KITTY でなかった場合はそのまま DefWindowProc() に渡しています
そうしなければ、基本的な動作を失ってしまいます


GetSystemMenu()

HMENU GetSystemMenu(HWND hWnd , BOOL bRevert);

システムメニューのハンドルを取得します

hWnd - ウィンドウメニューのコピーを持つウィンドウのハンドルを指定します
bRevert - FALSE だとシステムメニューのハンドルを返す。TRUE だとデフォルトの状態に戻す

戻り値 - bRecert が FALSE ならシステムメニューのハンドル、そうでなければ NULL



前のページへ戻る次のページへ