내용 보기

작성자

관리자 (IP : 172.17.0.1)

날짜

2020-07-29 01:43

제목

[C/C++] C/C++ MFC 스레드(Thread) SendMessage PostMessage 관련


  • PostMessage

PostMessage 함수는 Msg 인수로 지정된 메시지를 hWnd 윈도우의 메시지 큐에 집어넣어
윈도우 프로시저에서 이 메시지를 처리하도록 한다. 메시지를 메시지 큐에 넣어 놓기만
하고 곧바로 리턴하므로 메시지는 곧바로 처리되지 않는다. 큐에 붙여진 메시지는
GetMessage 에 의해 읽혀지고 DispatchMessage 에 의해 윈도우 프로시저로 보내져
처리될 것이다.

급하게 처리될 필요가 없거나 또는 지금 하고 있는 작업을 완전히 끝내야만 처리할
수 있는 메시지는 PostMessage 함수로 큐에 붙인다. 이 함수로 붙여진 메시지는
언제 처리될지 정확하게 예측하기 힘들다. 그래서 붙여지는 메시지의 wParam 과
lParam 에는 지역 포인터를 사용하지 않아야 한다. 메시지를 붙일 시점에는
포인터가 존재했더라도 메시지가 처리될 시점에는 포인터가 무효해질 수 있기 때문이다.

PostMessage 는 메시지를 큐에 붙인 후 성공하면 TRUE 를 리턴하며 실패하면
FALSE 를 리턴하는데 이 리턴값은 가급적이면 점검해보는 것이 좋다. 왜냐하면
메시지 큐는 크기가 한정되어 있기 때문에 고속으로 전송되는 모든 메시지를 다 수용하지 못할 수도 있기 때문이다.

PostMessage 의 첫번째 인수인 hWnd 는 이 메시지를 받을 윈도우의 핸들인데 이값은
아주 특수하게 NULL 일 수도 있다. 즉, 메시지를 받는 대상 윈도우가 없는 메시지를
큐에 붙일 수도 있는데 이런 메시지는 특정 윈도우에게 신호를 보내기 위한 것이 아니라 응용 프로그램 전반에 걸친 작업 지시를 보낼때 사용된다.
대상 윈도우가 
없기 때문에 이 메시지는 윈도우 프로시저가 처리할 수 없으며 반드시 메시지 루프에서 직접 처리해주어야 한다.

while(GetMessage(&Message, 000) {
   if (Message.message == WM_SOME ) {
        // 직접 처리
   } else {
       TranslateMessage( &Message );
       DispatchMessage( &Message );
   }
}
cs

GetMessage 로 메시지를 꺼낸 후 곧바로 메시지 ID 를 비교해보고 스레드를 위한 메시지인지 검사해본다.
만약 스레드를 위한 메시지라면 메시지 루프에서 
직접 처리해야 하며 DispatchMessage 함수로 보내서는 안된다.
대상 윈도우가 
지정되지 않은 메시지이기 때문에 이 메시지를 받아줄 윈도우 프로시저가 없기 때문이다.
PostMessage 함수가 메시지를 붙여넣는 큐가 윈도우를 위한 큐가 아니라 
스레드를 위한 큐이기 때문에 이런 기법이 가능하다.
다른 스레드의 메시지 큐에 
메시지를 붙일 때는 다음 함수가 사용된다.

BOOL PostThreadMessage ( DWORD idThread, UINT Msg, WPARAM wParam, LPARAM lParam );

윈도우 핸들 대신 스레드의 ID를 첫 번째 인수로 지정해준다. 이때 이 메시지를 받을 스레드는 반드시 스레드 큐를 가지고 있어야 하는데 큐를 가지지 않는 작업 스레드(Worker Thread)는 메시지를 받지 못한다.


  • SendMessage

메시지를 큐에 넣는 것이 아니라 곧바로 윈도우 프로시저로 보내 즉각 처리하도록
하며 메시지가 완전히 처리되기 전에는 리턴하지 않는다. 즉 블록시킨다. 
그래서
SendMessage는 윈도우간, 특히 부모 윈도우와 차일드 컨트롤간의 통신에 자주 사용된다.

         PostMessage     SendMessage
        ↙            ↙
┏━┓    ┏━┓ 메시지루프    ↙
┃ ┃------→  ┃ ┃-------------→ WndProc
┃ ┃    ┃ ┃
┃ ┃    ┃ ┃
┗━┛    ┗━┛
시스템    스레드
메시지큐   메시지큐


질문2) 함수명앞의 LRESULT , BOOL 의 선언은 function 의 리턴예약어 Result 와 Boolean 명칭하는건가요?
=> BOOL 은 델파이에서의 Boolean 과 같습니다.

그러나, LRESULT 는 Result 와는 다릅니다.
LRESULT 는 Win32 API 에서 쓰이는 리턴값의 한 종류입니다.
Result 는 델파이에서 function 의 마지막에 사용되는 C언어로 따지자면 return 예약어와 같은 것입니다.

PostMessage(Self.Handle, WM_CLOSE, 0, 0);
현재 폼에 종료 메세지를 보낸다.

※ self.Close; 명령과 같은 역할을 합니다.


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 하나를 호출하는 것과 같아요.
극히 책을 참조하여 객관적으로 적었기 때문에 제 주관적인 느낌이나 내용은 극히 없으므로,
틀린 내용이 있다면 지적하여도 무방합니다.

출처1

https://202psj.tistory.com/1069

출처2