안녕하세요 삽잡이입니다.
이번 시간에도 마찬가지로 WinMain함수와 WndProc함수에 대해서 마져 알아보도록 하겠습니다.
WndProc의 매개변수는 어떻게 생겼을까요...
1 | LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) | cs |
이런식으로 생겨먹었습니다...
매개변수를 하나씩 살펴보도록 하겠습니다.
우선 hwnd의 경우 메시지가 발생한 윈도우의 핸들을 뜻합니다.
다음 매개변수인 iMsg는 메시지의 종류를 뜻합니다.
그리고 하위 두개의 매개 변수는 각각 4바이트 짜리 변수를 뜻합니다.
우선 wParam의 w의 경우 2Byte 크기의 WORD를 뜻했었는데 뭐....
현재는 정보도 많아지고... 과거의 잔재로 그냥 w가 붙어 있는 4바이트 짜리를 나타냅니다.
즉, w 글자가 남아있다지만, 4바이트짜리 변수라는 것입니다.
lParam의 경우 Long형이며 4바이트짜리 변수입니다. 이곳에는 부가 정보가 들어있습니다.
고로 wPram, lParam 은 둘 다 합쳐서 8Byte의 정보가 들어있다고 볼 수 있습니다.
iMsg에 만약 WM_LBUTTONDOWN이라는 메시지가 들어오게 된다면,
lParam의 상위 2바이트에는 y 좌표, 하위 2바이트에는 x 좌표가 들어가게 됩니다.
wParam에는 마우스 키(MK), VK등의 정보들이 들어가고 말입니다...
Window 메시지마다 모두 다르기 때문에 굳이 정보들에 대해서 알 필요는 많이 없습니다....
모르면 찾으면 그만이니까요... 하지만 중요한 몇몇 메시지는 외워야 되긴합니다...
아무튼, 메시지가 발생하면 4가지의 정보를 통해 Proc에서 처리하게 됩니다.
hWnd에 메시지가 발생했다는 것을 알리면
MSG구조체인 iMsg 즉, 메시지 정보를 보고 판단을 하게 됩니다.
iMsg에는 기본적으로 6가지의 정보가 들어있는데,
기존의 HWND, MSG, WPARAM, LPARAM을 포함한 시간과 좌표가 포함됩니다.
lParam에는 키에 따른 부가정보가 들어가 있는데,
모든 메시지에는 마우스 Point 좌표와 시간이 들어있게 됩니다.
그러니 굳이 따르면 둘은 다른 것이지요....
MSG의 4가지 정보는 표면적으로 받아가고,
나머지 두 정보는 Get함수로 받아올 수 있게 됩니다.
우리의 프로그래밍은 대부분 Proc에서 하게 되겠지요...
그렇다면 프로그램은 언제 종료될까요...
WinMain 함수의 while문이 거짓이 된다면 종료되지 않겠습니까...
오직 메시지가 WM_QUIT과 같은 경우 while문에 false를 반환하게 됩니다.
나머지 메시지들은 모두 true를 리턴값으로 보내지요...
한마디로 윈도우가 파괴되었어도 WM_QUIT 메시지가 전달되지 않는다면
프로세스는 살아있게 됩니다.
윈도우는 죽어도 어플리케이션은 죽지 않는 문제가 발생하는 것입니다.
왜 안죽느냐 여쭤보신다면,
프로그램은 눈에 보이는 요소와 보이지 않는 요소가 있는데
UI만 죽이고 프로그램을 죽이지 않으니 남아있게 되는 문제가 발생하는 것이지요...
둘중 하나만 죽어봤자 어플리케이션이 아니지 않습니까...
메인창이 닫힐때 프로그램도 죽여아합니다. 아니면 의미가 없지요...
Window 에서는 WM_CLOSE나 Alt+F4버튼을 누르면 WM_DESTORY 메시지가 발생하게 됩니다.
그렇다면 Main window가 파괴되니 더이상 프로그램이 남아있게 되면 안되니까
Message Queue에 WM_QUIT 메시지를 저장시켜줘야 합니다.
오직 while문을 flase 시키는 것은 WM_QUIT입니다!
PostQuitMessage를 사용하는 것도 살펴보면 인수는 종료 코드를 넣게 되있습니다.
종료 코드 값은 결과적으로 wParam을 리턴하게 되고,
최종적으로 프로그램 종료시 wParam 값을 리턴하게 되는 것입니다.
종료 코드는 외부의 프로세스를 위해 존재하는 것입니다.
왜 죽었는지에 대해 사실을 알고 싶을때를 위해 종료코드가 존재하는 것이지요...
지금까지 삽잡이의 수준으로는 아무 의미가 없겠지만... 추후 알게 될 것을 기대합니다...
WM_QUIT 메시지가 발생하면 루프가 종료되고,
종료 코드 값을 wParam이 보관해서 이 값을 날리게 됩니다.
즉, 이 날리는 값은 프로그램이 어떻게 죽었는지에 대해 확인하고 싶은 프로세스를 위해
준비해놓은 것입니다.
1 | return (DefWindowProc(hwnd, iMsg, wParam, lParam)); | cs |
이 부분은 반드시 있어야 합니다.
우리는 모든 메시지를 처리할 수 없습니다.
우리가 모든 메시지를 처리할 수 없으니, 기본적인 메시지 처리 작업을 하는 함수가 있습니다.
그 함수가 바로 위에 있는 함수를 말하는 것입니다.
WndProc 함수를 보게 된다면
switch 문으로 각각 case 별로 메시지를 나누어 처리할 수 있게 만들어 놨습니다.
case문을 마치기 위해서는 break를 사용하지요... 물론 return도 가능합니다.
하지만, 어떤 메시지들은 해당 case를 끝내고 다른 메시지들을 처리해야할 일이 있는데
return 을 하면 case문을 끝내고 바로 반환되는 문제가 있어서
DefWindowProc함수로 접근할 수 없게 됩니다.
break를 하면 다르지만 말이지요...
즉, 일반적으로 return은 잘 쓰지 않습니다.
DefWindowProc이 호출되지 않기 때문이죠...
자... 그렇다면 최종적으로 WinMain 함수와 WndProc은 어떤 순서로 발생되는지 살펴보겠습니다.
우선, Class를 RegisterClass로 등록을 합니다.
그 다음 WM_CREATE 메시지를 처리합니다.
즉, WM_CREATE는 비큐 메시지라는 것입니다.
대부분의 사용자와 관련된 메시지는 큐 메시지이고, 사용자와 관련성 없는 메시지들을 비 큐메시지라고 합니다.
그 중, WM_PAINT는 사용자가 발생 시킬 수 있고/ 시스템도 발생시킬수 있기 때문에
큐메시지입니다.
모든 메시지에는 우선 순위가 있습니다.
먼저 처리되어야 할 메시지가 있을 수 있으니, WM_PAINT는 정말 우선순위가 낮은 메시지입니다...
키보드 및 마우스로 입력한 값이 우선적으로 발생되고
그 다음 WM_PAINT가 발생해야되지 않겠습니까....
우선순위가 낮은 메시지로는 WM_PAINT와 TIMER가 있습니다...
해당 메시지들은 정말 낮은 우선순위를 가지고 있습니다.
WM_CREATE 메시지는 비큐 메시지이고,
CreateWindow가 Return 하기 직전 다 생성해두고 사용자에게 초기화할 것이 있다면
초기화를 하고 문제가 있다면 하지말라는 선택권을 주게 됩니다.
즉, WM_CREATE는 초기화 작업 및 초기화가 잘 되었는지 안되었는지를 알려주는 작업을 하게 됩니다.
따라서 최종적 순서로,
RegisterClass -> WM_CREATE -> CreateWindow ->MW_PAINT로 가게 되있습니다.
아하하.. 너무 재미있군요...
이상 혼자노는 삽잡이였습니다!
'삽질의 현장 > - 윈도우 API' 카테고리의 다른 글
#006_WIndow_API_그리기 (I/O) (2) (0) | 2015.09.09 |
---|---|
#005_WIndow_API_그리기 (I/O) (1) (0) | 2015.09.09 |
#003_WIndow_API_WinMain, WndProc에 대해서 (2) (0) | 2015.09.08 |
#002_WIndow_API_WinMain, WndProc에 대해서 (1) (0) | 2015.09.08 |
#001_WIndow_API_Intro (0) | 2015.09.07 |