BOOL PostMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam);
LRESULT SendMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
두 함수의 인수는 완전히 동일하다.
여기서 Post라는 말은 순수 우리 말로는 "붙인다~"라고 번역되며
"Send"라는 말은 보낸다.라고 번역된다.
PostMessage 함수는 Msg인수로 지정된 메세지를 hWnd 윈도우의 메세지 큐에
집어넣어 윈도우 프로시져에서 이 메세지를 처리하도록 한다. 메세지를 큐에 넣기만하고
바로 리턴하므로 메세지를 붙인 수 즉시 다른 작업을 할 수 있지만
큐에 대기하고 있는 다른 메세지가 있으면 뒤에 붙인 메세지는 곧바로 처리되지 않는다.
큐에 붙여진 메세지는 GetMessage에 의해 읽혀지고
DispatchMessage에 의해 윈도우 프로시져로 보내져 처리될 것이다.
급하게 처리할 필요가 없거나 또는 지금 하고 있는 작업을 완전히 끝내야만 처리할 수 있는 메세지는
PostMessage 함수로 큐에 붙인다. 이 함수로 붙여진 메세지는 언제 처리될지 정확하게
예측하기 힘들고 그래서 붙여지는 메세지는 wParam과 lParam에는 지역 포인터를 사용하지 말아야 한다.
메세지를 붙일 시점에는 포인터가 존재했더라도 메세지가 처리될 시점에는 포인터가 무효해질 수 있기
때문이다.PostMessage는 메세지를 큐에 붙인 후 성공하면 TRUE를 리턴하며,
실패하면 FALSE를 리턴하는데 메세지 큐는 크기가 한정되어 있기 때문에 고속으로 전송되는 모든
메세지를 다 수용하지 못할 수도 있다.다행히 Win32 환경에서는 큐 크기가 대폭 늘어나면서 왠만해서는
큐가 부족한 상황이 잘 발생하지 않는다.
SendMessage는 메세지를 큐에 넣는 것이 아니라,
곧바로 윈도우 프로시져로 보내 즉각 처리하도록 하며,
메세지가 완전히 처리되기 전에는 리턴하지 않는다.
즉, 블록시켜서 SendMessage는 윈도우간 특히 부모 윈도우와 차일드 컨트롤간의 통신에 자주 사용된다.
예를 들어 리스트 박으세요~ 라는 LB_ADDSTRING 이라는 메세지를 보내면 이는 리스트 박스에게
문자열 항목을 추가하라는 명령이 되며, 항목이 완전히 추가되고 난 후에 SendMessage가 리턴된다.
윈도우간에 메세지를 교환할 때 어떤 함수를 사용할 것인가는,
신중하게 결정해야 하는데 대부분의 경우는 SendMessage로 보내는 것이 정석이며,
또 효율적이다. 또 WM_COPYDATA 같은 메세지는 그 특성상 반드시
SendMessage로만 보내야 하며, PostMessage로 붙여서는 안된다.
다시, 간략히 정리하자면
SendMessage는 당장 어떤 일을 하라는 명령이며, PostMessage는 한가해질 때 어떤 일을 하라는 신호다.
라고 생각하면 쉬울 것이다.
부가적으로,
PostMessage는 큐에 넣고, SendMessage는 WndProc의 case 하나를 호출하는 것과 같다.
출처:윈도우즈 API 정복(한빛미디어,김상형)
=====================================================================================================
SendMessage()의 응용 방법...
LRESULT SendMessage(
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam
);
윈도우가 다른 두 객체에서 데이타 전달 또는 명령 실행에 유용하게 쓰일 수 있다.
보통 Msg에 동작의 구분 값이 들어가고
wParam과 lParam에 전달할 데이타를 넣는다.
그런데 데이타의 전달 뿐만 아니라,
호출 한 부분에서 데이타를 받을 때도 쓸 수 있다.
즉 A에서 B로 SendMessage를 보낼때 값을 wParam과 lParam에 넣어서 전달을 하고,
다시 B에서 A로 LRESULT에 값을 담아서 A로 다시 보낼 수 있는 것이다.
ClassB::sendData(){
...
::SendMessage(ClassA Windows, WM_COMMAND, (LPARAM)nInt1, (WPARAM)nInt2);
...
}
struct SData{
int n1;
int n2;
};
IMPLEMENT_MESSAGE_HANDLER(ClassA, OnCommand){
int nValue1 = (int)wParam ;
int nValue2 = (int)lParam
...
SData data;
...
pResult = (void * )&data;
return (LRESULT)pResult ;
}
이때 주의해야 할 점은..
B에서 A로 보낼때는 값을 stack에 들어가서 전달 과정에서 사라지지 않게 하는 것이 중요하다.
즉 void * pResult 가 함수내에 선언되어있다면 함수가 리턴되면서 사라질 수 있기 때문에
멤버 변수로 선언하거나, static으로 선언해서 사라지지 않도록 해야 한다.
================================================================================================
WPARAM과 LPARAM의 역할 API 2006/05/24 12:19 |
LPARAM과 WPARAM은 메세지에 대한 추가적인 정보를 가지고 있다.
예를 들어 키보드를 눌렀을 경우 메세지가 발생하는데
무슨 키를 눌렀는지 2개의 키를 동시에 눌렀는지등등..
마우스를 클릭햇을 경우도 메세지가 발생하는데
어느 위치에 눌렀는지 등등
LPARAM은 보통 위치정보,
WPARAM은 보통 어떤키를 눌렀는지 중복키를 눌렀는지 정보, resource의 발생정보
(표1) 기본적인 마우스 메시지
메시지 | 내용 | lParam | wParam |
WM_LBUTTONDOWN | 좌측 마우스 버튼을 눌렀을때 | 마우스 위치 | 키상태정보 |
WM_LBUTTONUP | 좌측 마우스 버튼을 띄었을때 | 마우스 위치 | 키상태정보 |
WM_RBUTTONDOWN | 우측 마우스 버튼을 눌렀을때 | 마우스 위치 | 키상태정보 |
WM_RBUTTONUP | 우측 마우스 버튼을 띄었을때 | 마우스 위치 | 키상태정보 |
WM_MOUSEMOVE | 마우스가 움직일때 | 마우스 위치 | 키상태정보 |
마우스가 클릭하였을 때 마우스에 대한 메시지가 발생되는데 클라이언트 영역과 비 클라이언트 영역에 분리되어 다르게 나타난다.
클라이언트 영역이란 윈도우 타이틀바와 외곽선을 제외한 즉 실제로 WM_PAINT메시지에 의해서 그래픽을 출력하는 영역을 말한다.
마우스가 눌려졌을 경우에는 어느 부분이 눌려졌다는 정보를 보내주어야 한다.
이 정보를 lParam에 기록한다.
lParam은 32비트 LONG형이다.
이 형에 마우스 정보를 입력하여 알려주게 된다.
우리는 보통 위치 좌표를 사용할 경우 2차 평면에서는 (X,Y)를 사용한다.
즉 정보값이 최소 2개라는 의미이다. 헌데 lParam은 한 개의 정보 저장 장소이다.
이 저장장소에 두 개의 값을 저장하기 위해서 lParam을 16비트씩 잘라서 상위 16비트에는 Y좌표를 하위 16비트에는 X좌표값을 넣어서 보내준다.
lParam안에 X,Y의 자표값이 나누어져 들어가 있기 때문에 우리는 이 값을 분리해야 한다.
다행히도 윈도우 lParam의 값에서 상위 16비트를 얻고자 한다면 HIWORD함수를 사용해야 한다.
int y = HIWORD(lParam) int x = LOWORD(lParam)
좌측 마우스 버튼의 클릭 메시지 처럼 우측 마우스 버튼 클릭 메시지도 같은 방법으로 lParam에 위좌표를 넣어서 전송한다.
마우스 더블클릭메시지
더블 클릭이란 연속적으로 빠르게 마우스 버튼을 두번 클릭하는 것이다.
이 메시지를 이벤트를 받기 위해서는 WNDCLASSEX의 멤버변수 style안에 CS_DBCLKS 삽입시킴으로서 이벤트를 받을수 있다.
이 값을 대입하기전 CS_DBLKS라는 값을 대입하면 연속적으로 두번 눌렀을 경우 WM_LBUTTONDOWN이 연속적으로 들어오는 것과 동시에 WM_LBUTTONDBLCKS가 발생
이 더블 클릭 메시지는 사실 시스템에서 발생하는 메시지가 아니라 어플리케이션에서 조합하여 만든 메시지이다.
어느 일정한 시간 구간안에서 WM_LBUTTONDOWN이 발생하면 이것을 WM_BUTTONDBLCKS로 바꾸어서 메시지 큐에 삽입하기 때문이다.
이때 사용하는 함수가 GetMessageTime인데 이 함수는 현재 메시지 큐에서 가장 최근에 얻은 메시지의 시간을 얻는 함수이다.
이 함수를 통해서 어느 시간 사이에 WM_LBUTTONDOWN 메시지가 연속적으로 발생하였을때 이 메시지와 함께 WM_BLUTTONDDBLCLK로 발생하게 되는것이다.
이런 이유로 더블클릭 메시지는 WM_LBUTTONDOWN이나 WM_RBUTTONDOWN과 같이 lParam과 wParam에 저장되는 정보의 값은 같다.
어플리케이션을 만들 경우 좌측 마우스 버튼을 눌렀을때와 더블 클릭을 했을 경우 이 두개를 분리하여 처리할 경우가 있다.
그러나 메시지는 더블 클릭했을 경우 두개의 메시지가 동시적으로 발생하기 때문에 이것을 막기는 어렵다.
비클라이언트 영역
메시지 | 내용 | lParam | wParam |
WM_NCLBUTTONDOWN | 좌측 마우스 버튼을 눌렀을때 | 마우스 위치 | Hit-test정보 |
WM_NCLBUTTONUP | 좌측 마우스 버튼을 띄었을때 | 마우스 위치 | Hit-test정보 |
WM_NCRBUTTONDOWN | 우측 마우스 버튼을 눌렀을때 | 마우스 위치 | Hit-test정보 |
WM_NCRBUTTONUP | 우측 마우스 버튼을 띄었을때 | 마우스 위치 | Hit-test정보 |
WM_NCMOUSEMOVE | 마우스가 움직일때 | 마우스 위치 | Hit-test정보 |
[출처] WPARAM과 LPARAM의 역할|작성자 동키
'프로그래밍(Programming) > c++, 11, 14 , 17, 20' 카테고리의 다른 글
SHFILEOPSTRUCT와 폴더를 이동시킬 때 주의점 (0) | 2012.11.01 |
---|---|
다시 수행했을때 중복되지 않는 난수발생 CryptGenRandom (0) | 2012.11.01 |
HRESULT / LRESULT 의 정리 ,HRESULT 리턴값 요약 (0) | 2012.11.01 |
경로 설정 GetCurrentDirectory() / SetCurrentDirectory() (0) | 2012.11.01 |
inline keyword 와 inl file (0) | 2012.11.01 |