WM_SYSCOMMAND

인수

wParam : 시스템 명령의 종류가 전달되며 사용자가 시스템 메뉴에서 어떤 항목을 선택했는지를 알 수 있다. 이 값의 하위 4비트는 시스템이 내부적으로 사용하는 값이므로 명령의 종류를 알고 싶으면 wParam을 0xFFF0와 AND연산해야 한다. 연산한 결과는 다음값 중의 하나가 된다.

상수

설명

SC_CLOSE

0xF060

윈도우를 닫는다.

SC_CONTEXTHELP

0xF180

상황별 도움말 출력 상태가 되며 커서에 ?표시를 출력하고 사용자가 대화상자 컨트롤을 클릭하면 WM_HELP 메시지를 보낸다.

SC_DEFAULT

0xF160

디폴트 메뉴 항목을 선택했거나 시스템 메뉴를 더블클릭했다.

SC_HOTKEY

0xF150

응용 프로그램이 정의한 핫키로 윈도우를 활성화였다.

SC_HSCROLL

0xF080 수평으로 스크롤한다.

SC_KEYMENU

0xF100

키보드 입력으로 시스템 메뉴를 호출하였다. 보통 Alt+Space가 시스템 메뉴 출력키이다. 또는 Alt키와 단축키를 같이 누를 때도 이 명령이 전달되는데 이때 lParam은 단축키 문자값이 전달된다. 예를 들어 Alt+H를 누르면 lParam에는 'h'가 전달된다.

SC_MAXIMIZE

0xF030 윈도우를 최대화하였다.

SC_MINIMIZE

0xF020 윈도우를 최소화하였다.

SC_MONITORPOWER

0xF170 출력장치의 상태를 설정한다. 이 명령은 전원 절약 기능이 있는 컴퓨터의 전원 절약 기능을 지원한다. lParam이 1이면 저전력 상태가 된 것이며 2이면 전원이 차단된 것이다.

SC_MOUSEMENU

0xF090 마우스 클릭으로 시스템 메뉴를 출력하였다.

SC_MOVE

0xF010 이동 항목을 선택하여 윈도우를 이동시킨다.

SC_NEXTWINDOW

0xF040 다음 윈도우로 이동하였다.

SC_PREVWINDOW

0xF050 이전 윈도우로 이동하였다.

SC_RESTORE

0xF120 원래 위치로 복구하였다.

SC_SCREENSAVE

0xF140 시스템에 등록된 스크린 세이버를 실행한다.

SC_SIZE

0xF000 윈도우의 크기를 조정한다.

SC_TASKLIST

0xF130 시작 메뉴를 활성화한다.

SC_VSCROLL

0xF070 수직으로 스크롤한다.

각 값들은 해당 명령이 선택되었다는 뜻이지 이미 실행되었다는 뜻이 아니다. 예를 들어 사용자가 시스템 메뉴에서 '이동'항목을 선택하면 SC_MOVE가 전달되는데 이때는 아직 이동을 시작하지 않은 상태이다.

lParam : 마우스로 윈도우 메뉴를 선택한 경우 커서의 좌표가 전달된다. 하위 워드에는 수평 좌표, 상위 워드에는 수직 좌표가 전달되는데 이 좌표는 화면 기준 좌표이다. 액셀러레이터에 의해 명령이 선택되었으면 -1이 되며 니모닉에 의해 선택되었으면 0이 된다.

설명

시스템 메뉴에 있는 메뉴 항목을 선택하면 WM_COMMAND 메시지 대신 이 메시지가 전달된다. 시스템 메뉴를 직접 선택하는 동작 외에도 타이틀 바에 있는 최대, 최소, 닫기 버튼 등의 명령들도 이 메시지를 발생시킨다. 시스템 메뉴에 있는 명령들은 윈도우를 관리하기 위한 기본적인 명령이므로 응용 프로그램은 이 메시지를 직접 처리하지 않고 보통 DefWindowProc으로 그냥 보내 준다.

DefWindowProc은 wParam값에 따라 시스템에 미리 정의되어 있는 동작을 수행한다. 예를 들어 SC_MINIMIZE 시스템 명령이 전달되었으면 윈도우를 최소화하고 SC_CLOSE 명령이 전달되었으면 윈도우를 닫는다. 응용 프로그램이 직접 이 시스템 명령을 프로그래밍 하고 싶다면 이 메시지를 처리하며 자신이 처리한 시스템 명령은 DefWindowProc으로 보내지 말아야 한다. 그외의 시스템 명령은 모두 DefWindowProc으로 보내 주어 디폴트 처리를 하도록 해야 한다.

시스템 메뉴에는 이동, 최소화, 최대화, 크기 조정, 닫기 등의 표준 윈도우 관리 명령들만 들어 있다. GetSystemMenu, AppendMenu 등의 메뉴 관련 명령을 사용하면 시스템 메뉴에도 응용 프로그램 고유의 메뉴 항목을 추가할 수 있다. 이렇게 만들어진 메뉴 항목을 선택할 때는 WM_COMMAND 대신 WM_SYSCOMMAND 메시지가 대신 전달되므로 반드시 이 메시지를 처리해야 한다. 이 경우 직접 추가한 메뉴 항목 외의 시스템 명령은 모두 DefWindowProc으로 전달해 주어야 한다.

응용 프로그램이 시스템 명령을 직접 실행할 필요가 있다면 wParam에 원하는 시스템 명령을 대입하고 DefWindowProc으로 WM_SYSCOMMAND를 보내 준다. 예를 들어 윈도우를 닫고 싶으면 SendMessage(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0); 명령을 보내 주면 된다.

리턴

이 메시지를 처리했으면 0을 리턴한다.

예제

예제 1

다음 예제는 시스템 명령이 언제 호출되는지를 보여 준다. WM_SYSCOMMAND 메시지를 받았을 때마다 어떤 메시지를 받았는지 기록하고 작업 영역에 보여 줌으로써 시스템 명령 방생 시기를 학습하기 위해 제작하였다.

int y=40;
TCHAR buf[10000];
void PrintMessage(TCHAR *str)
{
	lstrcat(buf,str);
	lstrcat(buf,"\r\n");
	InvalidateRect(hWndMain,NULL,TRUE);
	y+=20;
}

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;
	TCHAR str[128];
	TCHAR Mes[]="시스템 명령 메시지를 보여 줍니다";
	RECT crt;

	switch(iMessage) {
	case WM_SYSCOMMAND:
		switch (wParam & 0xFFF0) {
		case SC_CLOSE:
			PrintMessage("SC_CLOSE");
			break;
		case SC_KEYMENU:
			PrintMessage("SC_KEYMENU");
			break;
		case SC_MOVE:
			PrintMessage("SC_MOVE");
			break;
		case SC_MAXIMIZE:
			PrintMessage("SC_MAXIMIZE");
			break;
		case SC_MINIMIZE:
			PrintMessage("SC_MINIMIZE");
			break;
		case SC_MOUSEMENU:
			PrintMessage("SC_MOUSEMENU");
			break;
		case SC_NEXTWINDOW:
			PrintMessage("SC_NEXTWINDOW");
			break;
		case SC_PREVWINDOW:
			PrintMessage("SC_PREVWINDOW");
			break;
		case SC_RESTORE:
			PrintMessage("SC_RESTORE");
			break;
		case SC_SIZE:
			PrintMessage("SC_SIZE");
			break;
		default:
			wsprintf(str, "그외의 시스템 명령. wParam=%X", wParam);
			PrintMessage(str);
			break;
		}
		break;
	case WM_PAINT:
		hdc=BeginPaint(hWnd, &ps);
		TextOut(hdc,10,10,Mes,lstrlen(Mes));
		GetClientRect(hWnd,&crt);
		crt.top=40;
		crt.left=200;
		DrawText(hdc,buf,-1,&crt,0);
		EndPaint(hWnd, &ps);
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

실행중의 모습은 다음과 같다.

키보드 및 마우스 등으로 시스템 메뉴를 열어 보고 타이틀 바의 각 버튼을 눌러 보면 언제 시스템 명령이 발생하는지 알 수 있다. 모든 시스템 명령은 DefWindowProc으로 보내 주어 디폴트 처리를 할 수 있도록 하였다. 만약 위 소스에서 SC_MOVE를 받았을 때 return 0; 해 버리면 윈도우 이동이 불가능해진다.

예제 2

다음 예제는 시스템 메뉴에 메뉴 항목을 추가하고 이 항목이 선택되었을 때를 처리한다.

#define IDM_SYS_TEST 41000
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	HMENU hSysMenu;

	switch(iMessage) {
	case WM_CREATE:
		hSysMenu=GetSystemMenu(hWnd, FALSE);
		AppendMenu(hSysMenu, MF_STRING, IDM_SYS_TEST, "테스트 항목");
		return 0;
	case WM_SYSCOMMAND:
		switch (LOWORD(wParam)) {
		case IDM_SYS_TEST:
			MessageBox(hWnd, "시스템 메뉴에 있는 테스트 항목을 선택했네요.","알림",MB_OK);
			return 0;
		}
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

시스템 메뉴의 항목은 WM_COMMND 메시지 대신 WM_SYSCOMMAND 메시지가 발생하므로 반드시 이 메시지에서 처리해야 한다. IDM_SYS_TEST 항목 이외의 시스템 명령에 대해서는 break하여 DefWindowProc으로 넘겨 주어 디폴트 처리를 하도록 해 주었다. 직접 처리하지 않는 시스템 명령은 반드시 DefWindowProc으로 넘겨 주어야 한다.

플랫폼

95이상

참조

WM_COMMAND


written by http://www.winapi.co.kr