윈도우 시스템은, 메시지구동 시스템으로 모든 이벤트는 메세지의 발생에 의해서 처리된다.


#define MY_USER 1000 
이렇게 선언할 경우 이미 1000이라는 값은 시스템이 내부적으로 예약해서 사용하는 상수일 수 있다.
그래서 이러한 현상을 막는 방법으로 WM_USER와 같은 사용자가 정의 할 수 있는 상수공간을 마련해두었다.


설명 - 이 메시지는 실제로 정의되어 있는 시스템 메시지가 아니며 사용자 정의 메시지의 시작 범위를 지정하는 상수값이다. 메시지는 정수값 하나로 표현되는데 윈도우즈는 메시지의 범위를 다음과 같이 정의하고 있다.



<범위 설명>

0~WM_USER-1
운영체제가 정의하는 시스템 메시지. WM_PAINT, WM_TIMER 등의 메시지들이 모두 이 범위에 속한다.

WM_USER~WM_APP-1
윈도우 클래스가 정의하는 사용자 정의 메시지
WM_APP~0xBFFF
응용 프로그램이 정의하는 사용자 정의 메시지

0xC000~0XFFFF
문자열로 등록되는 메시지

0x10000~ 이후의 사용을 위해 예약된 영역이며 현재는 사용되지 않는다.


WM_USER

WM_USER는 한 윈도우 클래스를 위한 고유의 메시지를 정의하기 위한 상수값이며 이 범위 이후부터 윈도우 클래스의 사용자 정의 메시지를 만들 수 있다. 이 값은 0x400으로 정의되어 있으며 보통 WM_USER+n으로 사용자 정의 메시지를 정의한다. 이때 n은 1보다 큰 정수이며 사용자 정의 메시지간의 구분을 위해 사용된다. 여러 개의 사용자 정의 메시지가 필요하다면 WM_USER+1, WM_USER+2, WM_USER+3,... 식으로 계속 n을 증가시켜 가며 메시지를 정의할 수 있다. 윈도우즈는 WM_USER이후 0x8000까지 사용자 정의 메시지 영역으로 정의하고 있으므로 n은 최대 0x7c00까지 가능하다. WM_USER+n을 곧바로 사용할 수도 있으며 자주 사용할 경우 다음과 같이 매크로를 정의하여 별도의 메시지를 만들 수 있다.

#define WM_MYMESSAGE WM_USER+1

이렇게 매크로를 정의해 놓고 이후부터 WM_MYMESSAGE라는 명칭을 대신 사용하면 된다.

주의
- 표준 컨트롤 중 일부는 자신만의 사용자 정의 메시지를 정의하여 사용하고 있다. 따라서 WM_USER+n은 가급적이면 한 윈도우 클래스내에서만 정의하여 사용해야 하며 응용 프로그램간의 통신에는 사용하지 않는 것이 바람직하다.
- 표준 컨트롤을 서브클래싱했을 경우 함부로 WM_USER+n을 사용하면 표준 컨트롤 고유의 메시지와 충돌이 발생할 수 있다.



예제
 
다음 예제는 사용자 정의 메시지로 윈도우를 이동시킨다.

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
        HDC hdc;
        PAINTSTRUCT ps;
        RECT wrt;
        TCHAR Mes[]="왼쪽 마우스 버튼을 누르면 이동합니다";

        switch(iMessage) {
        case WM_USER+1:
                GetWindowRect(hWnd,&wrt);
                wrt.left+=wParam;
                wrt.right+=wParam;
                wrt.top+=lParam;
                wrt.bottom+=lParam;
                MoveWindow(hWnd,wrt.left,wrt.top,wrt.right-wrt.left,wrt.bottom-wrt.top,TRUE);
                return 0;
        case WM_LBUTTONDOWN:
                SendMessage(hWnd,WM_USER+1,(WPARAM)-3,(LPARAM)5);
                return 0;
        case WM_PAINT:
                hdc=BeginPaint(hWnd, &ps);
                TextOut(hdc,10,10,Mes,lstrlen(Mes));
                EndPaint(hWnd, &ps);
                return 0;
        case WM_DESTROY:
                PostQuitMessage(0);
                return 0;
        }
        return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

이 예제에서 WM_USER+1은 윈도우를 이동하라는 뜻이며 wParam은 수평 이동 거리, lParam은 수직 이동 거리로 정의하였다. WM_USER+1을 받으면 이 인수들이 지정하는 거리만큼 윈도우를 이동시킨다.

WM_APP

#define WM_MYMESSAGE WM_APP+1

이렇게 매크로를 정의해 놓고 이후부터 WM_MYMESSAGE라는 명칭을 대신 사용하면 된다. WM_USER도 사용자 정의 메시지를 정의하는 용도로 사용되지만 표준 컨트롤중에 이미 WM_USER를 사용하는 컨트롤이 있으므로 중복될 위험성이 있다. 반면 WM_APP는 시스템이 전혀 이 영역을 사용하지 않고 있으므로 중복될 위험이 전혀 없으며 응용 프로그램간의 통신에 사용하기에 적합하다. 두 응용 프로그램의 약속에 의해 WM_APP+n 메시지를 정의하여 사용하면 된다.

WM_USER는 윈도우 클래스를 위한 사용자 정의 메시지이며 WM_APP는 응용 프로그램을 위한 사용자 정의 메시지라는 점이 다르다. 그러나 이 구분은 어디까지나 권장 사항일 뿐이지 강제 사항은 아니다. WM_USER를 응용 프로그램간의 통신에 사용하더라도 충돌이 없다는 확신만 있다면 가능하다. 다만 잠재적인 충돌 가능성이 있을 수 있다는 것을 고려할 때 바람직하지는 않다.

정리

이런 상황을 고려해 보자. MyApp에서 Con1이라는 커스텀 컨트롤을 사용하는데 이 컨트롤은 자신에게 변화가 있을 때 WM_USER+1이라는 통지 메시지를 부모 윈도우로 보내도록 되어 있다. 이런 상황에서 MyApp가 자신의 고유 용도로 WM_USER+1을 다시 정의한다면 메시지간의 충돌이 발생하게 된다. 이런 상황을 방지하기 위해 운영체제는 WM_USER를 내부적인 용도로 WM_APP를 응용 프로그램간의 통신에 사용하도록 권장하는 것이다. 하지만 WM_APP도 여전히 충돌이 발생할 가능성이 있으므로 좀 더 안전한 방법으로 메시지를 정의하고자 한다면 RegisterWindowMessage 함수로 문자열 메시지를 등록하여 사용하는 것이 좋다.


 

리턴값의 의미는 정해져 있다. 응용 프로그램이 의미를 정해서 사용할 수 있다. 이 메시지로 어떤 질문을 하고자할 때는 리턴값을 정의하며 그렇지 않을 경우는 통상 리턴값을 사용하지 않는다.



출처 http://www.winapi.co.kr/reference/Message/WM_USER.htm


'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

간단한 DLL 예제  (1) 2010.02.03
리스트뷰  (0) 2010.02.03
레지스트리  (0) 2010.02.02
o/s의 role  (0) 2010.01.28
파일매핑예제  (0) 2010.01.25
Posted by 아몰라