윈도우에 대한 각종 처리가 진행될 때 운영체제는 응용 프로그램으로 메시지를 보내 윈도우의
변화에 대한 대응을 할 수 있도록 기회를 부여한다.
# 생성
윈도우가 생성될 때, 즉 CreateWindow 함수가 호출될 때 두 개의 메시지가 응용 프로그램으로 차례대로
전달된다. 우선 비작업영역이 생성되고 난 직후에 WM_NCCREATE 메시지가 전달되며 작업영역이 생성되고
난 직후에 WM_CREATE 메시지가 전달된다. WM_NCCREATE는 윈도우로 가장 먼저 전달되는 메시지로
객헤촤를 할때 중요하게 사용되지만 일반적으로 큰 실용성이 없다. 그래서 DefWindowProc으로 넘기는것이
가장 무난하다.
WM_CREATE 메시지는 윈도우 생성과 초기화에 성공했으면 0을 리턴한다. 만약 메모리 할당이나 라이브러리
초기화 등 윈도우가 동작하기 위해 꼭 필요한 초기화에 실패했다면 이때는 -1을 리턴하여 에러를 보고하여야
한다. 그러면 CreateWindow(Ex) 함수는 이미 생성한 윈도우를 파괴하고 NULL을 리턴한다.
# 파괴
사용자가 시스템 메뉴에서 닫기 명령을 선택하거나 타이틀 바의 X 버튼을 누르면 WM_CLOSE 메시지가
전달된다. 이 메시지를 처리하지 않고 DefWindowProc으로 넘기면 디폴트로 DestroyWindow를 호출하므로
윈도우가 파괴되는데 이 메시지를 처리하면 사용자에게 프로그램을 정말 끝낼 것인가를 물어 볼 수도 있다.
저장하지 않은 파일이 있다거나 할 경우는 이 메시지에서 종료를 거부 하면된다.
[메시지 박스로 프로그램 종료 여부 결정]
이 메시지에서 필요한 종료 처리를 하는데 주로 열려져 있는 파일을 닫고 할당된 메모리나 전역 자원을
해제하는 등의처리를 한다. 메인 윈도우일 경우 PostQuitMessage 함수를 호출하여 응용 프로그램을 종료하는
중요한 처리도 해야한다. 종료 확인을 위해 WM_DESTROY 메시지는 사용할 수 없다.
이 메시지를 받았을 때도 미 저장 문서의 존재를 확인한다거나 경고 메시지를 출력하는 것은 가능 하지만
종료를 취소하는 것을 불가능하다. 왜냐하면 WM_DESTROY 메시지를 받았을 때는 이미 윈도우 파괴가 진행중인
상황이므로 파괴를 멈출 수 없기 때문이다.
응용프로그램이 스스로를 종료하는 가장 정상적인 방법은 DestroyWindow 함수로 메인 윈도우를 파괴하는
것이다. 그러나 미저장 문서 확인 기능이 있는 프로그램은 이 함수를 직접 호출하는 것보다 WM_CLOSE 메시지를
경유해서 종료하는 것이 좋다.
[마우스 오른쪽에 종료 기능 추가]
# 크기 변경
윈도우의 크기가 변경될 때는 WM_SIZE 메시지가 전달된다.
wParam으로는 어떤 종류의 크기 변경인가를 나타내는 다음 중 하나의 값이 전달된다.
- SIZE_MAXHIDE : 다른 윈도우가 최대화되었을 때 모든 팝업 윈도우로 전달된다.
- SIZE_MAXIMIZED : 최대화 되었다.
- SIZE_MAXSHOW : 다른 윈도우가 복구되었을 때 모든 팝업 윈도우로 전달된다.
- SIZE_MINIMIZED : 최소화 되었다.
- SIZE_RESTORED : 최소, 최대화가 아닌 크기 변경이다.
wParam 값 중 특히 SIZE_MINIMIZED에 대해서는 다소 특별한 처리가 요구되는 경우가 많은데
최소화 될 때는 작업영역의 폭이 0이 되므로 평상시와는 조금 다르게 처리해야 한다. 예를 들어 부모의 작업영역을
분할하여 차일드를 배치하는 경우 어차피 복구되면 원래 상태로 재배치해야 하므로 최소화될 때는 차일드를 굳이
다시 배치할 필요가 없다. 또 문자열을 윈도우 폭에 맞게 정렬하는 경우는 최소화 상태일 때는 절대로 정렬하지
말아야 하는데 폭이 0인 윈도우에 대해 문서의 길이는 무한대가 되어 버리기 때문이다.그래서 WM_SIZE의 코드는
통상, if (wParam != SIZE_MINIMIZED) { } 인 경우가 많다.
WM_SIZING 메시지는 사용자가 윈도우 크기를 변경하고 있을 때 보내진다. 이 메시지의 wParam에는 사용자가
드래그하고 있는 윈도우의 경계선이 어느쪽인가를 지정하는 WMSZ_BOTTOM,WMSZ_LEFT,WMSZ_TOP 등의
값이 전달되며 lParam에는 현재 윈도우의 영역을 화면 좌표로 가지는 RECT 구조체의 포인터가 전달된다.
이 메시지를 사용하면 윈도우의 크기가 어떻게 변화되고 있는지 살펴볼 수 있으며 RECT 구조체를 직접 변경하여
크기와 위치를 임의로 변경할 수도 있다.
윈도우의 크기와 관련한 또 하나의 메시지는 WM_GETMINMAXINFO 이다. 운영체제는 윈도우의 크기나 위치를
바꾸기 전에 이 메시지를 응용 프로그램으로 보내어 위치와 크기에 대한 제한을 할 수 있는 기회를 준다.
메시징의 의미상 기회 제공에 해당한다고 볼 수 있으며, lParam으로는 다음과 같이 정의된 구조체 포인터가 전달된다.
ptMinTrackSize는 경계선을 드래그하여 지정할 수 있는 윈도우의 최소 크기를 제한하며 ptMaxTrackSize는
경계선을 드래그하여 지정 할 수 있는 윈도우의 최대 크기를 제한한다.
[최소(300,200),최대(600,400)의 윈도우]
# 이동
윈도우가 이동중일 때는 WM_MOVING 메시지가 전달되는데 이 메시지에서 윈도우의 위치나 크기가 어떻게
변하는가를 감시하거나 강제로 변경할 수 있다. 또한 윈도우의 이동이 완료되었을 때는 WM_MOVE 메시지가
전달된다. WM_MOVE 메시지의 lParam의 상,하위 워드에는 각각 새 위치의 x,y 좌표가 전달된다.
이 두 메시지는 WM_SIZE 메시지에 비해서 사용빈도가 극히 낮은데 왜냐하면 위치가 바뀐다고 해서 윈도우의
동작이 바뀌는 경우는 거의 없기 때문이다.
이 두 메시지는 윈도우의 위치가 변할 때만 전달되는데 비해 다음 두 메시지는 위치와 크기뿐만 아니라 Z순서가
변해도 전달된다. 이동중일 때는 WM_WINDOWPOSCHANGING 메시지가 전달되며 이동이 완료 되었을 때는
WM_WINDOWPOSCHANGED 메시지가 전달된다. 이 메시지들이 lParam에는 다음과 같이 정의된 윈도우 구조체
가 전달된다.
[팝업 윈도우가 부모윈도우의 가장자리에 스스로 밀착하는 기능 예제]
# 액티브 상태 변경
화면상의 많은 윈도우중에 사용자의 입력을 받아들일 수 있는 활성화 상태(Active)의 윈도우는 오직 하나만
존재할 수 있다. 사용자는 키보드나 마우스를 통해 수시로 활성 윈도우를 변경할 수 있는데 윈도우의 활성화
상태가 변경될 때는 세 개의 메시지가 차례로 전달된다.
WM_ACTIVATEAPP 메시지는 응용 프로그램이 활성화되거나 비활성화될 때 보내진다.
wParam이 TRUE이면 이 메시지를 받은 프로그램이 활성화되는 것이고 FALSE이면 비활성화되는 것이다.
lParam으로는 활성화 상태가 변경될 때 상대편 윈도우를 소유한 스레드의 ID가 전달된다.
(응용 프로그램이 활성/비활성화될 때 메인 윈도우로 보내지는 메시지)
WM_NCACTIVATE 메시지는 비작업영역의 활성화 상태가 변경될 때 보내지는데 wParam이 TRUE이면 활성화
되는 것이고 FALSE이면 비활성화되는 것이다. 이 메시지는 보통 DefWindowProc으로 그냥 보내주는 것이
무난하며 DefWindowProc은 비작업영역의 활성화 여부에 따라 타이틀바나 아이콘의 색상을 다르게 그리는
디폴트처리를 한다.
(시스템이 내부적으로 사용하는 메시지)
WM_ACTIVATE 메시지는 활성화 상태가 변경되는 개별 윈도우에게 보내는 메시지이다. wParam의 하위워드에는
윈도우의 활성화 여부를 나타내는 다음과 같은 값들이 전달된다.
(같은 프로그램 내의 윈도우끼리 활성/비활성화될 때 보내지는 메시지)
- WM_INACTIVE : 윈도우가 비활성화되었다.
- WM_CLICKACTIVE : 마우스 클릭에 의해 윈도우가 활성화되었다.
_ WM_ACTIVE : 마우스 클릭 이외의 방법, 키보드 또는 SetActiveWindow등의 함수 호출에 의해 활성화되었다.
wParam의 상위 워드에는 윈도우가 최소화 상태인가 아닌가를 전달하는데 상위 워드가 0이외의 값을 가지면
윈도우가 최소화 되어 있는 것이다. lParam은 윈도우의 활성화/비활성화에 따라 활성상태가 변경된 상대편
윈도우의 핸들이 전달된다.
예를 들어 B윈도우가 활성화된 상태에서 사용자가 A윈도우를 클릭해서 활성화시켰다면 A윈도우에는
WA_CLICKACTIVE가 전달되고 이때 비활성화된 B윈도우의 핸들이 lParam으로 전달된다.
WM_INACTIVE가 전달된 경우 새로 활성화된 상대편 윈도우의 핸들이 lParam으로 전달될 것이다.
lParam은 경우에 따라 NULL이 될 수도 있다.
포커스가 변경될 때도 메시지가 전달된다. 포커스(Focus)란 입력 초점이라는 뜻이며 키보드 입력을 받을 수 있는
상태를 의미한다. 한 번에 하나의 윈도우만 포커스를 받을 수 있다. 윈도우의 포커스 상태가 변경될 때는
WM_SETFOCUS, WM_KILLFOCUS 메시지가 전달된다. 이때 wParam으로는 포커스를 잃게 되는 윈도우의 핸들
또는 새로 포커스를 얻게 되는 윈도우의 핸들이 전달된다.
예를 들어 메모장을 사용하다가 탐색기로 포커스를 옮겼다고 하자. 메모장은 WM_KILLFOCUS 메시지를 받으며
이 때 wParam으로는 새로 포커스를 받은 탐색기의 윈도우 핸들이 전달된다.
반대로 탐색기는 WM_SETFOCUS 메시지를 받으며 wParam으로는 이전에 포커스를 가지고 있던 메모장의 핸들이
전달된다.
WM_ACTIVATE는 일반적인 활성화를 의미하며 WM_SETFOCUS는 키보드의 입력을 받을 수 있는 상태를 의미한다.
# 상태 변경
윈도우의 보이기 상태, 사용 가능 여부, 최대, 최소화 상태 등은 사용자나 시스템에 의해, 또는 스스로에 의해
수시로 변화한다. 이런 상태 변화를 조사하는 함수들이 있지만 변화 시점을 정확하게 알아내고 반응하려면
시스템이 보내는 메시지는 받아야 한다.
WM_SHOWINDOW 메시지는 윈도우가 보여지거나 숨겨지기 직전에 보내지는데 wParam이 TRUE이면 윈도우가
보이기 직전이며 FALSE이면 숨겨지기 직전이다. 이때 lParam은 이 메시지가 보내진 이유를 설명하는데
ShowWindow 함수에 의해 이 메시지가 보내졌으면 lParam은 0이 되며 나머지 이유로 이 메시지가 보내졌을 때
lParam은 다음 중 하나의 값이 된다.
- SW_OTHERUNZOOM : 최대화 되어 있던 다른 윈도우가 복구되면서 이 윈도우의 가려졌던 부분이 드러났다.
- SW_OTHERZOOM : 다른 윈도우가 최대화되면서 이 윈도우가 가려졌다.
- SW_PARENTCLOSING : 소유자 윈도우가 최소화 되었다.
- SW_PARENTOPENING : 소유자 윈도우가 복구 되었다.
숨겨진 윈도우는 사용자의 눈에 보이지는 않지만 여전히 존재하고 있다. 사용자의 입력을 처리하지 못할 뿐이지
시스템이나 다른 윈도우로부터 보내지는 메시지는 처리할 수 있다. 만약 숨겨질 때 어떤 처리, 예를 들어 타이머
처리나 백그라운드 작업 등을 중지하고자 한다면 이 메시지를 사용하면 된다.
참고로 윈도우가 최대, 최소화될 때를 알아내야 할 때는 이 메시지 대신 WM_SIZE 메시지를 받아야 하며 wParam
값을 검사함으로써 윈도우의 상태 변화를 알 수 있다.
WM_ENABLE 메시지는 윈도우의 사용 금지/허가 상태가 변경될 때 보내지는데 wParam이 TRUE일 때는 사용
허가되는 상태이며 FALSE일 때는 사용 금지되는 상태이다.
윈도우는 생성할 때 WS_DISABLED 스타일을 주지 않은 한 디폴트로 사용 가능한 상태로 생성되지만 언제든지
EnableWindow 함수로 사용 금지 시킬 수 있다.
사용 금지된 윈도우는 입력은 받을 수 없지만 시스템으로부터 보내지는 메시지는 처리할 수 있다.
사용 금지될 때 모양이 달라지는 그래픽버튼들이 WM_ENABLE 메시지를 처리하여 사용 가능성이 변경될 때마다
자신을 다시 그린다.
# WM_NCHITTEST
시스템은 윈도우의 각 부분에 커서가 어떤 모양이 도어야 할지를 알고 있는데 현재 마우스 커서 위치가 윈도우의
어떤 부분인지를 조사할 때(커서 이동, 마우스 누름) 윈도우에게 WM_NCHITTEST라는 메시지를 먼저 보낸다.
이 메시지의 wParam은 사용되지 않으며 lParam에는 커서의 현재 좌표가 전달된다. 윈도우들은 보통 이 메시지를
처리하지 않고 DefWindowProc으로 전달하는데 이 함수는 lParam의 마우스 위치를 보고 윈도우의 어느 부분에
커서가 있는지를 조사해 다음 값중 하나를 리턴한다.
- HTBORDER In the border of a window that does not have a sizing border.
- HTBOTTOM In the lower-horizontal border of a resizable window
- HTBOTTOMLEFT In the lower-left corner of a border of a resizable window
- HTBOTTOMRIGHT In the lower-right corner of a border of a resizable window
- HTCAPTION In a title bar.
- HTCLIENT In a client area.
- HTCLOSE In a Close button.
- HTERROR On the screen background or on a dividing line between windows
- HTGROWBOX In a size box (same as HTSIZE).
- HTHELP In a Help button.
- HTHSCROLL In a horizontal scroll bar.
- HTLEFT In the left border of a resizable window (the user can click the mouse to resize the window horizontally).
- HTMENU In a menu.
- HTMAXBUTTON In a Maximize button.
- HTMINBUTTON In a Minimize button.
- HTNOWHERE On the screen background or on a dividing line between windows.
- HTREDUCE In a Minimize button.
- HTRIGHT In the right border of a resizable window (the user can click the mouse to resize the window horizontally).
- HTSIZE In a size box (same as HTGROWBOX).
- HTSYSMENU In a window menu or in a Close button in a child window.
- HTTOP In the upper-horizontal border of a window.
- HTTOPLEFT In the upper-left corner of a window border.
- HTTOPRIGHT In the upper-right corner of a window border.
- HTTRANSPARENT In a window currently covered by another window in the same thread
- HTVSCROLL In the vertical scroll bar.
- HTZOOM In a Maximize button.
MSDN : http://msdn.microsoft.com/en-us/library/ms645618(VS.85).aspx
시스템은 DefWindowProc이 리턴하는 이 값을 참조하여 커서를 바꾸고 디폴트 처리를 한다.
예를 들어 HTCAPTION위에서 마우스 버튼을 눌렀으면 윈도우의 이동 처리를 하며 경계선 위에서 마우스 버튼을
눌렀으면 크기를 변경한다.
이 메시지를 처리하지 않으면 모든것이 표준적인 윈도우대로 동작하지만 이 메시지를 가로채면 동작 방식을
변경 할 수 있다.
[윈도우의 작업영역을 타이틀바 처리로 변경하는 예제]
때 DefWindowProc을 호출해 마우스 커서가 윈도우의 어느 부분에 있는지를 조사해본다. 그리고 만약 마우스
커서가 작업영역에 있다면 이를 HTCAPTION 즉, 타이틀 바에 있는 것처럼 바꿔 리턴한다. 시스템이 이 메시지의
리턴값으로 HTCAPTION을 받으면 디폴트 정의된 동작대로 타이틀 바를 드래그해서 윈도우를 이동하려고 할
것이고 그래서 작업 영역을 드래그해서 윈도우의 위치를 옮길 수 있다.
이 메시지는 다른 메시지와 달리 리턴값이 중요한 의미를가진다.
변화에 대한 대응을 할 수 있도록 기회를 부여한다.
# 생성
윈도우가 생성될 때, 즉 CreateWindow 함수가 호출될 때 두 개의 메시지가 응용 프로그램으로 차례대로
전달된다. 우선 비작업영역이 생성되고 난 직후에 WM_NCCREATE 메시지가 전달되며 작업영역이 생성되고
난 직후에 WM_CREATE 메시지가 전달된다. WM_NCCREATE는 윈도우로 가장 먼저 전달되는 메시지로
객헤촤를 할때 중요하게 사용되지만 일반적으로 큰 실용성이 없다. 그래서 DefWindowProc으로 넘기는것이
가장 무난하다.
WM_CREATE 메시지는 윈도우 생성과 초기화에 성공했으면 0을 리턴한다. 만약 메모리 할당이나 라이브러리
초기화 등 윈도우가 동작하기 위해 꼭 필요한 초기화에 실패했다면 이때는 -1을 리턴하여 에러를 보고하여야
한다. 그러면 CreateWindow(Ex) 함수는 이미 생성한 윈도우를 파괴하고 NULL을 리턴한다.
# 파괴
사용자가 시스템 메뉴에서 닫기 명령을 선택하거나 타이틀 바의 X 버튼을 누르면 WM_CLOSE 메시지가
전달된다. 이 메시지를 처리하지 않고 DefWindowProc으로 넘기면 디폴트로 DestroyWindow를 호출하므로
윈도우가 파괴되는데 이 메시지를 처리하면 사용자에게 프로그램을 정말 끝낼 것인가를 물어 볼 수도 있다.
저장하지 않은 파일이 있다거나 할 경우는 이 메시지에서 종료를 거부 하면된다.
[메시지 박스로 프로그램 종료 여부 결정]
EnumWindows(MyEnumWindowsProc,NULL);윈도우가 파괴될 때는 차례대로 WM_DESTROY 메시지와 WM_NCDESTROY 메시지가 전달된다.
BOOL CALLBACK MyEnumWindowsProc(HWND hWnd,LPARAM lParam)
{
TCHAR str[300];
TCHAR Cap[255];
RECT rt;
GetWindowText(hWnd,Cap,255);
GetWindowRect(hWnd,&rt);
wsprintf(str,TEXT("핸들=0x%x(%d), 캡션=%s, 좌표=(%d,%d,%d%d)"),hWnd,hWnd,
Cap,rt.left,rt.top,rt.right,rt.bottom);
SendMessage(hList,LB_ADDSTRING,0,(LPARAM)str);
returnTRUE;
}
이 메시지에서 필요한 종료 처리를 하는데 주로 열려져 있는 파일을 닫고 할당된 메모리나 전역 자원을
해제하는 등의처리를 한다. 메인 윈도우일 경우 PostQuitMessage 함수를 호출하여 응용 프로그램을 종료하는
중요한 처리도 해야한다. 종료 확인을 위해 WM_DESTROY 메시지는 사용할 수 없다.
이 메시지를 받았을 때도 미 저장 문서의 존재를 확인한다거나 경고 메시지를 출력하는 것은 가능 하지만
종료를 취소하는 것을 불가능하다. 왜냐하면 WM_DESTROY 메시지를 받았을 때는 이미 윈도우 파괴가 진행중인
상황이므로 파괴를 멈출 수 없기 때문이다.
응용프로그램이 스스로를 종료하는 가장 정상적인 방법은 DestroyWindow 함수로 메인 윈도우를 파괴하는
것이다. 그러나 미저장 문서 확인 기능이 있는 프로그램은 이 함수를 직접 호출하는 것보다 WM_CLOSE 메시지를
경유해서 종료하는 것이 좋다.
[마우스 오른쪽에 종료 기능 추가]
case WM_RBUTTONDOWN:
//DestroyWindow(hWnd);
SendMessage(hWnd,WM_CLOSE,0,0);
return0;
# 크기 변경
윈도우의 크기가 변경될 때는 WM_SIZE 메시지가 전달된다.
wParam으로는 어떤 종류의 크기 변경인가를 나타내는 다음 중 하나의 값이 전달된다.
- SIZE_MAXHIDE : 다른 윈도우가 최대화되었을 때 모든 팝업 윈도우로 전달된다.
- SIZE_MAXIMIZED : 최대화 되었다.
- SIZE_MAXSHOW : 다른 윈도우가 복구되었을 때 모든 팝업 윈도우로 전달된다.
- SIZE_MINIMIZED : 최소화 되었다.
- SIZE_RESTORED : 최소, 최대화가 아닌 크기 변경이다.
wParam 값 중 특히 SIZE_MINIMIZED에 대해서는 다소 특별한 처리가 요구되는 경우가 많은데
최소화 될 때는 작업영역의 폭이 0이 되므로 평상시와는 조금 다르게 처리해야 한다. 예를 들어 부모의 작업영역을
분할하여 차일드를 배치하는 경우 어차피 복구되면 원래 상태로 재배치해야 하므로 최소화될 때는 차일드를 굳이
다시 배치할 필요가 없다. 또 문자열을 윈도우 폭에 맞게 정렬하는 경우는 최소화 상태일 때는 절대로 정렬하지
말아야 하는데 폭이 0인 윈도우에 대해 문서의 길이는 무한대가 되어 버리기 때문이다.그래서 WM_SIZE의 코드는
통상, if (wParam != SIZE_MINIMIZED) { } 인 경우가 많다.
WM_SIZING 메시지는 사용자가 윈도우 크기를 변경하고 있을 때 보내진다. 이 메시지의 wParam에는 사용자가
드래그하고 있는 윈도우의 경계선이 어느쪽인가를 지정하는 WMSZ_BOTTOM,WMSZ_LEFT,WMSZ_TOP 등의
값이 전달되며 lParam에는 현재 윈도우의 영역을 화면 좌표로 가지는 RECT 구조체의 포인터가 전달된다.
이 메시지를 사용하면 윈도우의 크기가 어떻게 변화되고 있는지 살펴볼 수 있으며 RECT 구조체를 직접 변경하여
크기와 위치를 임의로 변경할 수도 있다.
윈도우의 크기와 관련한 또 하나의 메시지는 WM_GETMINMAXINFO 이다. 운영체제는 윈도우의 크기나 위치를
바꾸기 전에 이 메시지를 응용 프로그램으로 보내어 위치와 크기에 대한 제한을 할 수 있는 기회를 준다.
메시징의 의미상 기회 제공에 해당한다고 볼 수 있으며, lParam으로는 다음과 같이 정의된 구조체 포인터가 전달된다.
typedefstruct tagMINMAXINFO {ptReserved는 사용되지 않으며 ptMaxSize, ptMaxPosition은 최대화 되었을 때의 크기와 위치를 지정한다.
POINT ptReserved;
POINT ptMaxSize;
POINT ptMaxPosition;
POINT ptMinTrackSize;
POINT ptMaxTrackSize;
} MINMAXINFO;
ptMinTrackSize는 경계선을 드래그하여 지정할 수 있는 윈도우의 최소 크기를 제한하며 ptMaxTrackSize는
경계선을 드래그하여 지정 할 수 있는 윈도우의 최대 크기를 제한한다.
[최소(300,200),최대(600,400)의 윈도우]
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)위 메시지를 사용한 프로그램은 윈도우의 그림판을 예로 들 수있다.
{
LPMINMAXINFO pmmi;
switch (iMessage) {
case WM_GETMINMAXINFO:
pmmi=(LPMINMAXINFO)lParam;
pmmi->ptMinTrackSize.x = 300;
pmmi->ptMinTrackSize.y = 200;
pmmi->ptMaxTrackSize.x = 600;
pmmi->ptMaxTrackSize.y = 400;
pmmi->ptMaxSize.x = 500;
pmmi->ptMaxSize.y = 300;
pmmi->ptMaxPosition.x = 100;
pmmi->ptMaxPosition.y = 100;
return0;
case WM_DESTROY:
PostQuitMessage(0);
return0;
}
return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}
# 이동
윈도우가 이동중일 때는 WM_MOVING 메시지가 전달되는데 이 메시지에서 윈도우의 위치나 크기가 어떻게
변하는가를 감시하거나 강제로 변경할 수 있다. 또한 윈도우의 이동이 완료되었을 때는 WM_MOVE 메시지가
전달된다. WM_MOVE 메시지의 lParam의 상,하위 워드에는 각각 새 위치의 x,y 좌표가 전달된다.
이 두 메시지는 WM_SIZE 메시지에 비해서 사용빈도가 극히 낮은데 왜냐하면 위치가 바뀐다고 해서 윈도우의
동작이 바뀌는 경우는 거의 없기 때문이다.
이 두 메시지는 윈도우의 위치가 변할 때만 전달되는데 비해 다음 두 메시지는 위치와 크기뿐만 아니라 Z순서가
변해도 전달된다. 이동중일 때는 WM_WINDOWPOSCHANGING 메시지가 전달되며 이동이 완료 되었을 때는
WM_WINDOWPOSCHANGED 메시지가 전달된다. 이 메시지들이 lParam에는 다음과 같이 정의된 윈도우 구조체
가 전달된다.
typedefstruct tagWINDOWPOS {이 구조체는 윈도우의 크기,위치,Z순서를 변경하는 SetWindowPos함수의 인수와 동일한 멤버를 가지고 있다.
HWND hwnd;
HWND hwndInsertAfter;
int x;
int y;
int cx;
int cy;
UINT flags;
} WINDOWPOS;
[팝업 윈도우가 부모윈도우의 가장자리에 스스로 밀착하는 기능 예제]
case WM_WINDOWPOSCHANGING:
wp=(LPWINDOWPOS)lParam;
GetWindowRect(GetParent(hWnd),&prt);
if(wp->y < prt.bottom && wp->y+wp->cy > prt.top)
{ //부모 윈도우 작업영역 내에 존재하는가?
if(abs(wp->x-prt.right)<30)
{// 현재 윈도우의 x축 값과 부모 윈도우의 작업영역의 right좌표 값이 30 이하인가
wp->x=prt.right;
}
if(abs(wp->x-prt.left)<30)
{// 현재 윈도우의 x축 값과 부모 윈도우의 작업영역의 left좌표 값이 30 이하인가
wp->x=prt.left;
}
if(abs(wp->x+wp->cx-prt.right)<30)
{// 현재 윈도우의 x+cx축 값과 부모 윈도우의 작업영역의 right좌표 값이 30이하인가
wp->x=prt.right-wp->cx;
}
if(abs(wp->x+wp->cx-prt.left)<30)
{// 현재 윈도우의 x+cx축 값과 부모 윈도우의 작업영역의 left좌표 값이 30이하인가
wp->x=prt.left-wp->cx;
}
}
return0;
# 액티브 상태 변경
화면상의 많은 윈도우중에 사용자의 입력을 받아들일 수 있는 활성화 상태(Active)의 윈도우는 오직 하나만
존재할 수 있다. 사용자는 키보드나 마우스를 통해 수시로 활성 윈도우를 변경할 수 있는데 윈도우의 활성화
상태가 변경될 때는 세 개의 메시지가 차례로 전달된다.
WM_ACTIVATEAPP 메시지는 응용 프로그램이 활성화되거나 비활성화될 때 보내진다.
wParam이 TRUE이면 이 메시지를 받은 프로그램이 활성화되는 것이고 FALSE이면 비활성화되는 것이다.
lParam으로는 활성화 상태가 변경될 때 상대편 윈도우를 소유한 스레드의 ID가 전달된다.
(응용 프로그램이 활성/비활성화될 때 메인 윈도우로 보내지는 메시지)
WM_NCACTIVATE 메시지는 비작업영역의 활성화 상태가 변경될 때 보내지는데 wParam이 TRUE이면 활성화
되는 것이고 FALSE이면 비활성화되는 것이다. 이 메시지는 보통 DefWindowProc으로 그냥 보내주는 것이
무난하며 DefWindowProc은 비작업영역의 활성화 여부에 따라 타이틀바나 아이콘의 색상을 다르게 그리는
디폴트처리를 한다.
(시스템이 내부적으로 사용하는 메시지)
WM_ACTIVATE 메시지는 활성화 상태가 변경되는 개별 윈도우에게 보내는 메시지이다. wParam의 하위워드에는
윈도우의 활성화 여부를 나타내는 다음과 같은 값들이 전달된다.
(같은 프로그램 내의 윈도우끼리 활성/비활성화될 때 보내지는 메시지)
- WM_INACTIVE : 윈도우가 비활성화되었다.
- WM_CLICKACTIVE : 마우스 클릭에 의해 윈도우가 활성화되었다.
_ WM_ACTIVE : 마우스 클릭 이외의 방법, 키보드 또는 SetActiveWindow등의 함수 호출에 의해 활성화되었다.
wParam의 상위 워드에는 윈도우가 최소화 상태인가 아닌가를 전달하는데 상위 워드가 0이외의 값을 가지면
윈도우가 최소화 되어 있는 것이다. lParam은 윈도우의 활성화/비활성화에 따라 활성상태가 변경된 상대편
윈도우의 핸들이 전달된다.
예를 들어 B윈도우가 활성화된 상태에서 사용자가 A윈도우를 클릭해서 활성화시켰다면 A윈도우에는
WA_CLICKACTIVE가 전달되고 이때 비활성화된 B윈도우의 핸들이 lParam으로 전달된다.
WM_INACTIVE가 전달된 경우 새로 활성화된 상대편 윈도우의 핸들이 lParam으로 전달될 것이다.
lParam은 경우에 따라 NULL이 될 수도 있다.
포커스가 변경될 때도 메시지가 전달된다. 포커스(Focus)란 입력 초점이라는 뜻이며 키보드 입력을 받을 수 있는
상태를 의미한다. 한 번에 하나의 윈도우만 포커스를 받을 수 있다. 윈도우의 포커스 상태가 변경될 때는
WM_SETFOCUS, WM_KILLFOCUS 메시지가 전달된다. 이때 wParam으로는 포커스를 잃게 되는 윈도우의 핸들
또는 새로 포커스를 얻게 되는 윈도우의 핸들이 전달된다.
예를 들어 메모장을 사용하다가 탐색기로 포커스를 옮겼다고 하자. 메모장은 WM_KILLFOCUS 메시지를 받으며
이 때 wParam으로는 새로 포커스를 받은 탐색기의 윈도우 핸들이 전달된다.
반대로 탐색기는 WM_SETFOCUS 메시지를 받으며 wParam으로는 이전에 포커스를 가지고 있던 메모장의 핸들이
전달된다.
WM_ACTIVATE는 일반적인 활성화를 의미하며 WM_SETFOCUS는 키보드의 입력을 받을 수 있는 상태를 의미한다.
# 상태 변경
윈도우의 보이기 상태, 사용 가능 여부, 최대, 최소화 상태 등은 사용자나 시스템에 의해, 또는 스스로에 의해
수시로 변화한다. 이런 상태 변화를 조사하는 함수들이 있지만 변화 시점을 정확하게 알아내고 반응하려면
시스템이 보내는 메시지는 받아야 한다.
WM_SHOWINDOW 메시지는 윈도우가 보여지거나 숨겨지기 직전에 보내지는데 wParam이 TRUE이면 윈도우가
보이기 직전이며 FALSE이면 숨겨지기 직전이다. 이때 lParam은 이 메시지가 보내진 이유를 설명하는데
ShowWindow 함수에 의해 이 메시지가 보내졌으면 lParam은 0이 되며 나머지 이유로 이 메시지가 보내졌을 때
lParam은 다음 중 하나의 값이 된다.
- SW_OTHERUNZOOM : 최대화 되어 있던 다른 윈도우가 복구되면서 이 윈도우의 가려졌던 부분이 드러났다.
- SW_OTHERZOOM : 다른 윈도우가 최대화되면서 이 윈도우가 가려졌다.
- SW_PARENTCLOSING : 소유자 윈도우가 최소화 되었다.
- SW_PARENTOPENING : 소유자 윈도우가 복구 되었다.
숨겨진 윈도우는 사용자의 눈에 보이지는 않지만 여전히 존재하고 있다. 사용자의 입력을 처리하지 못할 뿐이지
시스템이나 다른 윈도우로부터 보내지는 메시지는 처리할 수 있다. 만약 숨겨질 때 어떤 처리, 예를 들어 타이머
처리나 백그라운드 작업 등을 중지하고자 한다면 이 메시지를 사용하면 된다.
참고로 윈도우가 최대, 최소화될 때를 알아내야 할 때는 이 메시지 대신 WM_SIZE 메시지를 받아야 하며 wParam
값을 검사함으로써 윈도우의 상태 변화를 알 수 있다.
WM_ENABLE 메시지는 윈도우의 사용 금지/허가 상태가 변경될 때 보내지는데 wParam이 TRUE일 때는 사용
허가되는 상태이며 FALSE일 때는 사용 금지되는 상태이다.
윈도우는 생성할 때 WS_DISABLED 스타일을 주지 않은 한 디폴트로 사용 가능한 상태로 생성되지만 언제든지
EnableWindow 함수로 사용 금지 시킬 수 있다.
사용 금지된 윈도우는 입력은 받을 수 없지만 시스템으로부터 보내지는 메시지는 처리할 수 있다.
사용 금지될 때 모양이 달라지는 그래픽버튼들이 WM_ENABLE 메시지를 처리하여 사용 가능성이 변경될 때마다
자신을 다시 그린다.
# WM_NCHITTEST
시스템은 윈도우의 각 부분에 커서가 어떤 모양이 도어야 할지를 알고 있는데 현재 마우스 커서 위치가 윈도우의
어떤 부분인지를 조사할 때(커서 이동, 마우스 누름) 윈도우에게 WM_NCHITTEST라는 메시지를 먼저 보낸다.
이 메시지의 wParam은 사용되지 않으며 lParam에는 커서의 현재 좌표가 전달된다. 윈도우들은 보통 이 메시지를
처리하지 않고 DefWindowProc으로 전달하는데 이 함수는 lParam의 마우스 위치를 보고 윈도우의 어느 부분에
커서가 있는지를 조사해 다음 값중 하나를 리턴한다.
- HTBORDER In the border of a window that does not have a sizing border.
- HTBOTTOM In the lower-horizontal border of a resizable window
- HTBOTTOMLEFT In the lower-left corner of a border of a resizable window
- HTBOTTOMRIGHT In the lower-right corner of a border of a resizable window
- HTCAPTION In a title bar.
- HTCLIENT In a client area.
- HTCLOSE In a Close button.
- HTERROR On the screen background or on a dividing line between windows
- HTGROWBOX In a size box (same as HTSIZE).
- HTHELP In a Help button.
- HTHSCROLL In a horizontal scroll bar.
- HTLEFT In the left border of a resizable window (the user can click the mouse to resize the window horizontally).
- HTMENU In a menu.
- HTMAXBUTTON In a Maximize button.
- HTMINBUTTON In a Minimize button.
- HTNOWHERE On the screen background or on a dividing line between windows.
- HTREDUCE In a Minimize button.
- HTRIGHT In the right border of a resizable window (the user can click the mouse to resize the window horizontally).
- HTSIZE In a size box (same as HTGROWBOX).
- HTSYSMENU In a window menu or in a Close button in a child window.
- HTTOP In the upper-horizontal border of a window.
- HTTOPLEFT In the upper-left corner of a window border.
- HTTOPRIGHT In the upper-right corner of a window border.
- HTTRANSPARENT In a window currently covered by another window in the same thread
- HTVSCROLL In the vertical scroll bar.
- HTZOOM In a Maximize button.
MSDN : http://msdn.microsoft.com/en-us/library/ms645618(VS.85).aspx
시스템은 DefWindowProc이 리턴하는 이 값을 참조하여 커서를 바꾸고 디폴트 처리를 한다.
예를 들어 HTCAPTION위에서 마우스 버튼을 눌렀으면 윈도우의 이동 처리를 하며 경계선 위에서 마우스 버튼을
눌렀으면 크기를 변경한다.
이 메시지를 처리하지 않으면 모든것이 표준적인 윈도우대로 동작하지만 이 메시지를 가로채면 동작 방식을
변경 할 수 있다.
[윈도우의 작업영역을 타이틀바 처리로 변경하는 예제]
case WM_NCHITTEST:시스템은 마우스 커서가 이동하거나 버튼이 눌러질 때 수시로 이 메시지를 보낸다. 윈도우는 이 메시지를 받았을
nHit=DefWindowProc(hWnd,iMessage,wParam,lParam);
if(nHit==HTCLIENT)
nHit==HTCAPTION;
return nHit;
때 DefWindowProc을 호출해 마우스 커서가 윈도우의 어느 부분에 있는지를 조사해본다. 그리고 만약 마우스
커서가 작업영역에 있다면 이를 HTCAPTION 즉, 타이틀 바에 있는 것처럼 바꿔 리턴한다. 시스템이 이 메시지의
리턴값으로 HTCAPTION을 받으면 디폴트 정의된 동작대로 타이틀 바를 드래그해서 윈도우를 이동하려고 할
것이고 그래서 작업 영역을 드래그해서 윈도우의 위치를 옮길 수 있다.
이 메시지는 다른 메시지와 달리 리턴값이 중요한 의미를가진다.
'프로그래밍 > API' 카테고리의 다른 글
API :: DrawBitmap(메모리 DC -> 화면 DC) (0) | 2010.05.28 |
---|---|
API :: 윈도우 관리(5) 윈도우 리전,반투명,애니메이션 (0) | 2010.05.27 |
API :: 윈도우 관리(3) 윈도우 핸들, 열거 (0) | 2010.05.23 |
API :: 윈도우 관리(2) 작업영역,상태조사 및 변경,Z순서 (0) | 2010.05.23 |
API :: 윈도우 관리(1) 소유관계,위치,크기,좌표 (0) | 2010.05.22 |
댓글 로드 중…