=
4-1-라. TranslateMessage
while (GetMessage(&Message, 0, 0, 0)) { // 윈도우가 보내는 메시지를 받는 함수 (메시지 큐에서 제일 오래된 것을 들고옴 - 원형 연결리스트 ) // 창 닫으면 GetMessage는 0을 반환 => while문 종료 TranslateMessage(&Message); // 키보드 DispatchMessage(&Message); // 위도우가 할 것은 끝났다 => 어플리케이션 WndProc를 불러다오 } |
GetMessage는 메시지 큐에서 메시지를 꺼내온 후 이 메시지를 TranslateMessage 함수로 넘겨 준다. TranslateMessage 함수는 전달된 메시지가 WM_KEYDOWN인지와 눌려진 키가 문자키인지 검사해 보고 조건이 맞을 경우 WM_CHAR 메시지를 만들어 메시지 큐에 덧붙이는 역할을 한다. 물론 문자 입력이 아닐 경우는 아무 일도 하지 않으며 이 메시지는 DispatchMessage 함수에 의해 WndProc으로 보내진다. 만약 메시지 루프에서 TranslateMessage 함수를 빼 버리면 WM_CHAR 메시지는 절대로 WndProc으로 전달되지 않을 것이다.
4-2-가. Mouse
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) // 어플리케이션 핵심 실제 메인 { HDC hdc; PAINTSTRUCT ps; static int x; static int y; static WCHAR wcBuffer[100];
switch (iMessage) { case WM_PAINT: hdc = BeginPaint(hWnd, &ps); SetTextAlign(hdc, TA_CENTER); TextOut(hdc, 100, 100, wcBuffer, lstrlen(wcBuffer)); EndPaint(hWnd, &ps); return 0; case WM_MOUSEMOVE: x = LOWORD(lParam); y = HIWORD(lParam); wsprintf(wcBuffer, L"x는 %d, y는 %d이다.", x, y); //s:메모리에 출력한다, ws:유니코드 지원함수이다. InvalidateRect(hWnd, NULL, TRUE); return 0; case WM_LBUTTONDBLCLK: wcBuffer[0] = 0; //wcBuffer을 비운다. InvalidateRect(hWnd, NULL, TRUE); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; }
return(DefWindowProc(hWnd, iMessage, wParam, lParam)); // DESTROY이외 처리는 윈도로 보냄 } |
![](https://t1.daumcdn.net/cfile/tistory/252973415649E15418)
4-2-나. 더블클릭
WndClass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; |
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) // 어플리케이션 핵심 실제 메인 { HDC hdc; PAINTSTRUCT ps; static int x = 100; static int y = 100; static WCHAR wcBuffer[100]; static BOOL bnowDraw = FALSE;
switch (iMessage) { case WM_LBUTTONDOWN: x = LOWORD(lParam); //클릭했을 때의 x좌표 y = HIWORD(lParam); //클릭했을 때의 y좌표 bnowDraw = TRUE; return 0; case WM_MOUSEMOVE: //마우스가 움직이면 무조건 발생한다. if (bnowDraw == TRUE) //왼쪽 버튼이 눌러져 있으면~ { hdc = GetDC(hWnd); MoveToEx(hdc, x, y, NULL); x = LOWORD(lParam); y = HIWORD(lParam); LineTo(hdc, x, y); ReleaseDC(hWnd, hdc); } return 0; case WM_LBUTTONUP: bnowDraw = FALSE; //if문을 사용하지 못하게 한다. return 0;
case WM_LBUTTONDBLCLK: InvalidateRect(hWnd, NULL, TRUE); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; }
return(DefWindowProc(hWnd, iMessage, wParam, lParam)); // DESTROY이외 처리는 윈도로 보냄 } |
![](https://t1.daumcdn.net/cfile/tistory/213955415649E15609)
=>더블클릭
![](https://t1.daumcdn.net/cfile/tistory/2518E7415649E15729)
4-3-가.타이머
case WM_CREATE : //딱 한 번 호출
SetTimer(hWnd,1,1000,NULL)
1 : TIMER 번호
1000 : 간격
NULL : 1초마다 호출될 함수 주소 => 없으면 WM_TIMER 메시지만 발생
case WM_DESTROY
KillTimer(hWnd,1);
1: 타이머 번호와 일치해야 함
=>테트리스의 경우 블록 떨어지는 속도, 미사일 속도..
4-3-나. SendMessage
SendMessage(hWnd, WM_TIMER, 1, 0);
발생시킬 메시지
wparam
lparam
=>창 열리면 바로 타임표시됨
static RECT rt={100,100,400,120};
InvalidateRect(hWnd,&rt,TRUE);
=> 해당 영역만 다시그림
![](https://t1.daumcdn.net/cfile/tistory/213D59415649E15905)
//4-3-가.타이머 LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) // 어플리케이션 핵심 실제 메인 { HDC hdc; PAINTSTRUCT ps; time_t mytime; static HANDLE hTimer; static char *str;
switch (iMessage) { case WM_CREATE: hTimer = (HANDLE) SetTimer(hWnd, 2, 1000, NULL); str = ""; case WM_TIMER: time(&mytime); str = ctime(&mytime); InvalidateRect(hWnd, NULL, TRUE); case WM_PAINT: hdc = BeginPaint(hWnd, &ps); TextOut(hdc, 100, 100, str, strlen(str)-1); EndPaint(hWnd, &ps); return 0; case WM_DESTROY: KillTimer(hWnd, 2); PostQuitMessage(0); return 0; }
return(DefWindowProc(hWnd, iMessage, wParam, lParam)); // DESTROY이외 처리는 윈도로 보냄 } |
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; SYSTEMTIME st; static TCHAR sTime[128]; static RECT rt = { 10, 100, 400, 300 };
switch (iMessage) { case WM_CREATE: SetTimer(hWnd,1,1000,NULL); SendMessage(hWnd, WM_TIMER, 1, 0); return 0; case WM_TIMER: // 타이머 구분시 wParam, lParam 에 인자 담아 SendMessage GetLocalTime(&st); wsprintf (sTime ,TEXT("지금 시간은 %d:%d:%d입니다") ,st.wHour ,st.wMinute ,st.wSecond); //InvalidateRect(hWnd,NULL,TRUE); InvalidateRect(hWnd, &rt, TRUE); return 0; case WM_PAINT: hdc=BeginPaint(hWnd,&ps); TextOut(hdc,10,100,sTime,lstrlen(sTime)); EndPaint(hWnd,&ps); return 0; case WM_DESTROY: KillTimer(hWnd,1); PostQuitMessage(0); return 0; } return(DefWindowProc(hWnd,iMessage,wParam,lParam)); } |
![](https://t1.daumcdn.net/cfile/tistory/223541415649E15B0E)
4-3-다. 두 개의 타이머
//4 - 3 - 다.두 개의 타이머 LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; SYSTEMTIME st; static TCHAR sTime[128]; static TCHAR sTime2[128]; static RECT rt = { 10, 100, 400, 400 };
switch (iMessage) { case WM_CREATE: SetTimer(hWnd,1,1000,NULL); SetTimer(hWnd, 2, 5000, NULL); SendMessage(hWnd, WM_TIMER, 1, 0); return 0; case WM_TIMER: // 타이머 구분시 wParam, lParam 에 인자 담아 SendMessage switch (wParam) { case 1: GetLocalTime(&st); wsprintf(sTime , TEXT("지금 시간은 %d:%d:%d입니다") , st.wHour , st.wMinute , st.wSecond); InvalidateRect(hWnd, &rt, TRUE); break; case 2: wsprintf(sTime2 , TEXT("타이머 2")); break; } return 0; case WM_PAINT: hdc=BeginPaint(hWnd,&ps); TextOut(hdc,10,100,sTime,lstrlen(sTime)); TextOut(hdc, 10, 200, sTime2, lstrlen(sTime2)); EndPaint(hWnd,&ps); return 0; case WM_DESTROY: KillTimer(hWnd,1); KillTimer(hWnd, 2); PostQuitMessage(0); return 0; } return(DefWindowProc(hWnd, iMessage, wParam, lParam)); } |
![](https://t1.daumcdn.net/cfile/tistory/253F69415649E15C03)
![](https://t1.daumcdn.net/cfile/tistory/241B5E415649E15E27)
4-3-라. 콜백 함수
WM_TIMER 메시지는 다른 메시지가 있을 경우 실행 순서에 밀려 늦게 호출되는 경우가 있지만 콜백 함수를 사용하면 정확한 시간에 호출된다는 점
![](https://t1.daumcdn.net/cfile/tistory/24233B3E5649E16035)
void CALLBACK TimerProc(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime) { HDC hdc; int i; hdc = GetDC(hWnd); for (i = 0; i<100; i++) SetPixel(hdc, rand() % 500, rand() % 400, RGB(rand() % 256, rand() % 256, rand() % 256, )); ReleaseDC(hWnd, hdc); }
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) { switch (iMessage) { case WM_CREATE: SetTimer(hWnd, 1, 100, (TIMERPROC)TimerProc); return 0; case WM_DESTROY: KillTimer(hWnd, 1); PostQuitMessage(0); return 0; } return(DefWindowProc(hWnd, iMessage, wParam, lParam)); } |
=>WM_PAINT 메시지 없으므로 다시 그려지지 않음
4-4-가. 생성및 파괴
WM_CREATE와 WM_DESTROY에 있던 코드를 그대로 WinMain으로 옮겼는데 실행시켜 보면 완전히 동일하게 동작할 것이다.
그런데 어쨋든 결과가 같기는 하지만 WinMain에서 하는 초기화와 종료 처리는 WM_CREATE, WM_DESTROY 메시지가 발생했을 때 하는 것과는 엄밀하게 따지면 다르다. 두 메시지는 특정한 윈도우에 관련된 초기/종료 처리를 하는데 사용하는 것이 좋고 WinMain에서는 프로그램 전역적인 초기/종료 처리를 하는 것이 좋다.
=4-4-나. 작업 영역
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; static RECT rt;
switch (iMessage) { case WM_CREATE: GetClientRect(hWnd, &rt); return 0; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); GetClientRect(hWnd, &rt); SetTextAlign(hdc, TA_CENTER); TextOut(hdc, rt.right / 2, rt.bottom / 2, "Center String", 13); EndPaint(hWnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return(DefWindowProc(hWnd, iMessage, wParam, lParam)); } |
=4-4-다. WM_SIZE
플레그 | 값 |
SIZE_MAXHIDE | 다른 윈도우가 최대화되어 이 윈도우가 가려졌다. |
SIZE_MAXIMIZED | 최대화되었다. |
SIZE_MAXSHOW | 다른 윈도우가 원래 크기로 복구되어 이 윈도우가 드러났다. |
SIZE_MINIMIZED | 최소화되었다. |
SIZE_RESTORED | 크기가 변경되었다. |
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; static RECT rt;
switch (iMessage) { case WM_PAINT: hdc = BeginPaint(hWnd, &ps); SetTextAlign(hdc, TA_CENTER); TextOut(hdc, rt.right / 2, rt.bottom / 2, "Center String", 13); EndPaint(hWnd, &ps); return 0; case WM_SIZE: //GetClientRect(hWnd, &rt); rt.right = LOWORD(lParam); rt.bottom = HIWORD(lParam); InvalidateRect(hWnd, NULL, TRUE); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return(DefWindowProc(hWnd, iMessage, wParam, lParam)); } |
![](https://t1.daumcdn.net/cfile/tistory/21235B3E5649E16235)
=>창 크기 변화 시에도 화면 중앙에 글자 표시
![](https://t1.daumcdn.net/cfile/tistory/2545BA3E5649E16410)
5-1-가. 리소스의 분리
5-2-가. 리소스 작성
![](https://t1.daumcdn.net/cfile/tistory/25231F3E5649E16635)
![](https://t1.daumcdn.net/cfile/tistory/214C403E5649E1680A)
=&File => File
![](https://t1.daumcdn.net/cfile/tistory/2338113E5649E16B1F)
=세부사상은 Properties에서 수정
![](https://t1.daumcdn.net/cfile/tistory/253EEB3E5649E16C18)
![](https://t1.daumcdn.net/cfile/tistory/2540A7435649E16E28)
=헤더파일 수정 가능해야 함
=
#include "resource.h"
WndClass.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; static RECT rt;
switch (iMessage) { case WM_COMMAND: switch (LOWORD(wParam)) { case ID_FILE_MENU1: MessageBox(hWnd, L"첫번째 메뉴를 선택했습니다.", L"Menu Demo", MB_OK); break; case ID_FILE_MENU2: MessageBox(hWnd, L"두번째 메뉴를 선택했습니다.", L"Menu Demo", MB_OK); break; case ID_FILE_EXIT: PostQuitMessage(0); break; } return 0; case WM_DESTROY: PostQuitMessage(0); return 0; default: return(DefWindowProc(hWnd, iMessage, wParam, lParam)); } } |
![](https://t1.daumcdn.net/cfile/tistory/264A02435649E1701E)
![](https://t1.daumcdn.net/cfile/tistory/244895435649E1711F)
=5-3 아이콘, 커서
![](https://t1.daumcdn.net/cfile/tistory/243CA7435649E1742C)