winAPI

윈도우 프로그래밍 기본적인 구조?

루실리드 2012. 1. 30. 12:24

메시지 루프 돌리기

○ 윈도우는 이벤트 처리 방식이다.
윈도우에 어떤 입력이라든지 어떤 것이 "발생"하기만 하면 튀어 나온다.
키보드를 입력하거나 마우스를 입력하거나 뭐 기타등등등....

뭐 이해 안되면, 하자.


LPWSTR lpszClass = L"클래스이름";

int APIENTRY WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance , LPSTR lpszCmdParam , int nCmdShow )
{
 HWND hWnd;
 MSG Message;

 WNDCLASS WndClass;

 /* 구조체에 내용 집어 넣는 내용 */
 WndClass.cbClsExtra = 0;                                    // 1. 뭐 그냥 0. 클래스 여분 바이트
 WndClass.cbWndExtra = 0;                                 // 2. 이것도 그냥 0. 구조체 여분 바이트
 WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);

                                                                          // 3. 전경색 = 흰색..
 WndClass.hCursor = LoadCursor( NULL , IDC_ARROW );

                                                                           // 4. 커서는 일반 화살표 커서
 WndClass.hInstance = hInstance;                        // 5. 요거는 실행될 핸들?이 뭔지
 WndClass.lpfnWndProc = (WNDPROC) WndProc; // 6. 이벤트 발생시 메시지 호출할 함수명
 WndClass.lpszClassName = lpszClass;                  // 7. 클래스 이름
 WndClass.lpszMenuName = NULL;                       // 8. 보통 NULL, 여러개의 윈도우 발생시 쓰인다 한다
 WndClass.style = CS_HREDRAW | CS_VREDRAW; // 9. 윈도우 옵션들. 사이드바 있는지 없는지 등등
 /* 구조체 끝 */

 RegisterClass(&WndClass);
 // 명시적인 구조체 등록. 이방법이 아니라면 MFC에서 이것이 사용 되어져야 한다.

 /* 윈도우를 만들고 */
 hWnd =
    CreateWindow(
           lpszClass,
           lpszClass,
           WS_OVERLAPPEDWINDOW,
           CW_USEDEFAULT,
           CW_USEDEFAULT,
           CW_USEDEFAULT,
           CW_USEDEFAULT,
           NULL,
           (HMENU) NULL,
           hInstance,
           NULL
     );

 /* 윈도우를 띄운다 */
 ShowWindow(hWnd, nCmdShow);

 /* ㅅㅂ 이게 머야!
  응? 메시지 리스너?
 */
 while( GetMessage( &Messge, 0, 0, 0 ) )
 {
  TranslateMessage(&Message);  
  DispatchMessage(&Message);
 }
 
}
// 윈도우main 함수 종료. 리턴따윈 없는 것이다!

 

/* 문제의 이벤트 처리 호출 함수 부분 */
LRESULT CALLBACK WndProc(
                 HWND hWnd ,           // 이벤트가 발생한 핸들no
                 UINT iMessage ,        // 발생한 메시지
                 WPARAM wParam ,  // 메시지에 추가된 내용들1
                 LPARAM lParam      // 메시지에 추가된 내용들2
                 )
{
 HDC hdc;
 PAINTSTRUCT ps;
 switch( iMessage )
 {
  // 윈도우가 생성된다는 메세지인경우 0을 리턴해주자
  case WM_CREATE:
   return 0;
  // 윈도우가 표시되었다는 메세지인 경우,
     // 해당 윈도우에 그려준다? 아마도 이전의 화면 표시된 내용을 저장하고
     // 해당 그릴 내용을 변경 시켜 준다음 그것을 다시 저장 시킨다.
     // 그리고 0을 리턴
  case WM_PAINT:
   hdc = BeginPaint( hWnd,&ps );
   EndPaint( hWnd, &ps );
   return 0;
  // 윈도우가 사라진다는 메시지인 경우
     // 메시지 큐에 0을 넣어주고
     // 0을 리턴 한다
  case WM_DESTROY:
   PostQuitMessage( 0 );
   return 0;
 }

 // 마지막으로 처리 못한 것들은 라이브러리에 있는 DefWindowProc가 처리하게 넘기자
 return( DefWindowProc( hWnd, iMessage , wParam , lParam ) );
}
// 예제 끝

윈도우 프로그래밍은 전부 쓰래드에서 시작해서 쓰래드로 끝난다고 해도 과언이 아니라고 생각한다.
그래서 생각을 쓰래드적으로 생각하기로 해보자.

윈도우Main쓰레드 AAAAAAAAAAAA AAAAAAAAAAA => 코드 흐름
                                               BBBBBBB        => 이벤트 리스너 동작! 쓰래드 생성


뭐 쓰래드를 명시적으로 종료 하거나 그런 내용은 없었다. 예제로 나온 코드로 보자면,

윈도우Main쓰레드 AAAAAAAAAA AAAAAAAAAAAA...무제한 => 코드 흐름
                                            BBBBBBBBBBB...무제한 => 이벤트 리스너 동작

이런 형식이다. 물론 WM_QUIT 메시지를 이용해서 프로그램은 종료 될것이다.
조금 불만족 스럽지만, 예제는 예제...

여기서 설명한 개념에 대해 보자.

시스템 큐 : OS가 가지고 있는 메시지 저장소로서 저장된 이벤트 메시지를 APP 큐로 넘긴다.
APP 큐 : APP 큐는 실행 중인 응용 프로그램마다 하나씩 가지고 있는 메시지 저장소

요는 OS에도 이벤트 처리 큐가 있고, 프로그램에도 이벤트 처리 큐가 있다고 보라는 것이다.

......으음...일단 메시지 흐름을 만들어 보자면,
1. WM_KEYDOWN <==발생
2. GetMessage 에서 해당 메시지 접수 리턴 으로 1을 발생했으니까 아래로 넘어가겠지......
3. TranslateMessage 에서 눌러진 key가 문자인지 판단해서 WM_CHAR 메시지 발생
4. 만약 문자가 아닐 경우 DispatchMessage 함수로 넘어감
5. DispatchMessage는 메시지를 처리하는 함수로 보내어진다.
6. 메시지를 처리하는 함수는 WndProc 이다.
7. 예제에서는 WM_CREATE , WM_PAINT , WM_DESTORY 를 처리
8. 나머지는 DefWindowProc에서 처리하게 한다.
9. 발생한 메시지는 WM_KEYDOWN이므로, DefWindowProc가 처리
10. 별 내용 없으므로 다시 돌아온다.0을 리턴하겠지

11. 그다음은? 그다음은? 몰라...

 

일단은 GetMessage에 대해 알아보는게 순서겠지...

 

우선적으로 기본 구조는 이런 형식이다...

WinMain()

{

 while( GetMesaage( ... ) )

 {

 ...

 }

}

 

LRESULT WndProc( ... )

{

 return ( DefWindowProc( ... ) );

}

 

.... 이정도로 정리해 두자.

 

'winAPI' 카테고리의 다른 글

MessageBox 함수   (0) 2012.02.08
WM_PAINT 메시지에 대해  (0) 2012.02.05
GetDC와 ReleseDC 간략 정리  (0) 2012.02.04