API-게임 메시지 구조(GetMessage,PeekMessage)


1.GetMessage 와 PeekMessage의 차이
 

GetMessage
는 메시지가 없으면 메시지가 생길떄까지 기다린다.

하지만 게임에서는 역동적이어야 하기때문에 GetMessage를 사용하는것이 좋은선택은아니다.

사용자가 어떤입력을 줄떄까지 조용히 있는 게임을 바라는 사람은없을것이다.

사용자가 입력이 없으면 애니메이션도 안될것이다.

이런것을 하려면 다른종류의
메시지 펌프가 필요하다.

즉, 처리함 메시지가 있으면 그것을 처리하되 그렇지 않는 시간에는 게임을 위한 다른코드를 처리할 수 있어야한다.

PeekMessage가 이런 목적에 맞다.

  

BOOL PeekMessage {

    LPMSG lpMsg;

    HWND   hWnd;

    UINT     wMsgFilterMin;

    UINT     wMsgFilterMax;

    UINT     wRemoveMsg;

};
  

PeekMessage함수는 GetMessage와 비슷하다. 한가지 다른점은 wRemoveMsg 이다.

제거플래그는 PM_NOREMOVE, PM_REMOVE이 있는데 PM_NOREMOVE  메시지 큐에서 메시지를 제거하지 않는다.

PM_REMOVE이   메시지 큐에서 메시지를 제거 대부분의 경우는 메시지큐에서 메시지를 제거한다.

 

PeekMessage는 메시지가 있으면 true를 리턴하고, 그렇지 않으면  false 를 리턴합니다.

실시간 메시지 펌프를 만드는 것은 전보다 다소 복잡합니다.

단순희 GetMessage를 PeekMessage로 바꾸었다고생각해보면

메시지 큐에 메시지가 없을때 PeekMessage는 false 를 리턴할것이고
 
프로그램은 바로종료되버릴것이다.

 

While(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))

{

   TranslateMessage(&msg);

   DispatchMessage(&msg);

}

 

실행해보면 윈도우가 나타났다가 바로사라진다.

 

//메시지루프로

bool bDone = false;

MSG msg;

 

while(!iDone)

{

  while(PeekMessage(&msg, NUL,  0, 0, PM_REMOVE))

  {

      if(msg,message == WM_QUIT)

      {

           bDone = true;

      }

      else

      {

           TransLateMessage(&msg);

           DispatchMessage(&msg);

      }

  }

   InvalidateRect(hwnd, NULL, TRUE);

   updatewindow(hwnd);

}

 

메시지 펌프는 bDone이 false 동안 계속루프를 실행

루프를 실행할 떄마다 Peekmessage메시지 큐를 검사

처리할 메시지가 있으면 그것이 WM_QUIT인가 검사를하고 
 
WM_QUIT가 맞다면 bDone를 TRUE로 만들고

프로그램을 종료
 

만약 WM_QUIT 이외에 메시지가 메시지 큐에 있었다면 메시지를

처리하고 큐에서 제거함.
 

더이상 처리할 메시지가 없으면 윈도우를 다시 그리기위해서

InvalidateRect와 updatewindow를 호출



2.윈도우즈 API에서의 게임 구조
 

즉! 게임같이 메시지가 없어도 계속적으로 처리해야되는것이 있으면,
PeekMassage를 사용하여 false 일때(Idle Tile 또는 Death Time) 렌더링을 해주는 식으로 쓰는 것이다.


 MSG msg;

  bool done = FALSE;

 //Message Loop
 while(!done)
 {
  if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
  {
   if(msg.message==WM_QUIT)
    done=TRUE;
   else
   { 
    TranslateMessage(&msg);
    DispatchMessage(&msg);
   }
  }
  else          
   RenderTest();  //메세지가 없는 경우는 backbone형태로 이 함수가 수행됨.
 }



3. 사용된 함수들

혹시나 해서 함수들에대해서 정리해보았다. 
 

1. PeekMessage()

BOOL PeekMessage(
LPMSG lpMsg, 
HWND hWnd, 
UINT wMsgFilterMin, 
UINT wMsgFilterMax, 
UINT wRemoveMsg 
);

- Nonzero 리턴은 성공, Zero 리턴은 실패(메세지 큐에 아무런 메시지도 없는 경우).

- PeekMassage()는 GetMessage()와는 다르게 return하기전에 큐에 메세지가 들어오기를 기다리지 않음.

- PeekMassage()는 hWnd파라미터에 정의된 윈도우와 그 자식윈도우와 관련된 메세지만 보게된다.

- hWnd가 NULL이면, 현재의 thread를 호출한 윈도우와 관련된 메시지를 보게된다.

- 보게되는 메시지는  wMsgFilterMin ~ wMsgFilterMax 사이의 메세지이다. (winuser.h 참조)

- wMsgFilterMin, wMsgFilterMax가 모두 0이면, 모든 메세지를 보게된다.

- PeekMassage()sms WM_PAINT는 메세지 큐에서 제거하지 않는다. WM_PAINT는 처리될때까지 큐에 남아있게 된다.

 

2. GetMessage()

BOOL GetMessage(
LPMSG lpMsg, 
HWND hWnd, 
UINT wMsgFilterMin, 
UINT wMsgFilterMax 
);

- GetMessage()는 메세지 큐에 메세지가 들어올때 까지 block됨.

- Nonzero return : WM_QUIT 이외의 메세지를 받은경우.

- zero return : WM_QUIT 메세지를 받은경우.

- 다른 내용은 PeekMessage()와 동일함.

 

3. TranslateMessage()

BOOL TranslateMessage(
const MSG *lpMsg 
);

This function translates virtual-key messages into character messages. The character messages are posted to the calling thread's message queue, to be read the next time the thread calls the GetMessage or PeekMessage function.

키보드를 누르면, 메세지 큐에 WM_KEYDOWN이 들어가게 된다. 이 메세지를 통해 어떤 키가 눌려졌는지만 알 수 있다.

추가적인 정보, 예를들어 caps, ctrl, alt키등이 동시에 눌려졌는지, char 값이 무엇인지는 모른다.

이를 위해 또 다른 메세지가 필요하고,, 그것이 WM_CHAR이다.

TranslateMessage()는 키보드와 관련된 메세지(WM_KEYDOWN 등)로 부터 WM_CHAR를 만들어 낸다. 

키보드와 관련된 메세지가 아니면 아무런 일도 하지 않는다.

Nonzero indicates that the message is translated, that is, a character message is posted to the thread's message queue.

The TranslateMessage function does not modify the message pointed to by the lpMsg parameter.

TranslateMessage produces WM_CHAR messages only for keys that are mapped to ASCII characters by the keyboard driver.

TranslateMessage can only be used to translate messages received from calls to GetMessage or PeekMessage.

If applications process virtual-key messages for some other purpose, they should not call TranslateMessage. For instance, an application should not call TranslateMessage if the TranslateAccelerator function returns a nonzero value.

 

4. DispatchMessage()

LONG DispatchMessage(
  const MSG* lpmsg 
);

This function dispatches a message to a window procedure. It is typically used to dispatch a message retrieved by the GetMessagefunction.

The return value specifies the value returned by the window procedure. Although its meaning depends on the message being dispatched, the return value generally is ignored.

The MSG structure must contain valid message values. If the lpmsg parameter points to a WM_TIMER message and the lParamparameter of the WM_TIMER message is not NULL, lParam points to a function that is called instead of the window procedure.

 

//----------------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 switch (message) 
 {  
  case WM_PAINT: 
   ValidateRect(hWnd,NULL); //Needed to avoid new WM_PAINT messages
   return 0;

  case WM_DESTROY:
   PostQuitMessage(0);
   return 0;  
 };
 return DefWindowProc(hWnd, message, wParam, lParam);   
}

[출처] Message Management|작성자 kri7001


이 글을 공유하기

댓글

Designed by JB FACTORY