>TranslateMessage
오직 TransleateMessage()가 wm_char메시지를 생성한다.
DispatchMessage() wndProc을 호출한다.
keydown이 전달되려면 translate와 dispatch까지 통과되어야 한다.
만약 translate를 빼버리면 char는 절대로발생하지 않는다.
>Mouse
WndProc의 wparam, lparam
옛날엔 2, 4 바이트
지금은 4, 4 바이트
lparam에서 x, y좌표가 날라온다.
이걸 절반으로 자르면 x, y좌표를 얻을 수 있다.
wparam정보에는 마우스버튼 상태와 키보드와 조합 상태가 전달된다.
lparam이 32비트이므로
x좌표 16비트, y좌표 16비트로 이루어졌으니
약6만5천, 약6만5천개가 한계라고 할 수 있다.
나중에 고해상도가 나왔을 때 lparam의 long을 8바이트로 올리면
약40억, 약40억이 되니 해결된다.
마우스 입력에 관한 메시지
마우스 좌표 출력
![](https://t1.daumcdn.net/cfile/tistory/265F6C4A56492B6406)
창내 좌표를 실시간으로 출력
InvalidateRect 함수를 호출하여 작업 영역 전체를 무효화시켜 버리면 된다.
WndClass.style 에 CS_DBLCLKS 를 추가해준다.
마우스 왼쪽 버튼을 두번 누르면 WM_LBUTTONDOWN 메시지와 WM_LBUTTONUP 메시지가 교대로 두번 발생할 뿐이며 아무리 마우스 버튼을 잽싸게 눌러대도 더블클릭 메시지는 발생하지 않는다. 윈도우 스타일에 이 플레그를 추가하고 마우스 버튼을 두번 누르면 두번째 WM_LBUTTONDOWN 메시지가 WM_LBUTTONDBLCLK 메시지로 변경된다. 더블클릭을 검출하는데는 그만큼 실행시간의 감소가 요구되기 때문이며 어떤 프로그램은 더블클릭보다 WM_LBUTTONDOWN을 두번 받기를 원할 수도 있기 때문이다. 그래서 꼭 필요한 경우에 한해서 더블클릭을 지원하도록 되어 있다. 또한 더블클릭으로 인정할 시간간격이나 마우스 포인터의 위치 따위의 규칙을 프로그램에서 자체적으로 만들어 쓸 수 있도록 하기 위한 이유도 있다
<클릭 전>
<클릭 후>
![](https://t1.daumcdn.net/cfile/tistory/233FF535564938AE31)
더블 클릭을 하면서 입력된 것을 모두 무효화
>타이머
사용자의 동작과는 상관없이 발생하는 메시지. 이 메시지는 한번 지정해 놓기만 하면 일정한 시간간격을 두고 연속적으로 계속 발생한다. 주기적으로 같은 동
을 반복해야 한다거나 여러번 나누어 해야 할 일이 있을 때 이 메시지를 이용. 타이머 메시지를 이용해서 간단한 시계를 하나 만들어 보도록.
WndProc의 선두에는 시간값을 저장할 time_t형의 변수 mytime과 이 시간값을 문자열로 변경하여 저장할 str, 그리고 타이머 핸들인 hTimer 세 개의 변수가 선언
UNIT SetTimer(HWND hWnd, UINT nIDEvent, UINT uElapse, TIMERPROC lpTimerFunc)
첫번째 인수 hWnd 인수는 타이머 메시지를 받을 윈도우
두번째 인수 nIDEvent는 타이머의 번호를 지정 ( 하나의 타이머만 사용할 경우 1을, 여러개의 타이머를 사용할 경우 겹치지 않도록 번호를 부여하도록 한다.
세번째 인수 uElapase는 1/1000초 단위로 타이머의 주기를 설정 ( 이 값이 1000이면 타이머 메시지가 1초에 한번씩 hWnd로 보내지게 될것)
네번째 인수는 타이머 메시지가 발생할 때마다 호출될 함수를 지정하는데 사용하지 않을 경우 NULL로 설정
![](https://t1.daumcdn.net/cfile/tistory/243DD34C564965DB03)
>SendMessage
위의 타이머에선 처음 실행시킨 직후에는 시간이 보이지 않다가 1초정도 경과한 후부터 시간이 보인다는 점.
화면 출력을 담당하는 WM_PAINT에서는 무조건 str 문자열을 화면으로 출력하기만 하고 이 문자열은 WM_TIMER에서 시간값을 조사한 후 설정해 주므로 WM_PAINT는 죄가 없다.
문제는 시간을 조사하는 WM_TIMER 메시지가 최초로 호출되는 시점이 프로그램 시작 1초후라는 점.
왜 그런가 하면 WM_CREATE에서 타이머를 설치할 때 타이머 주기를 1초로 주었기 때문이다. 이 문제를 해결하려면 프로그램 시작 직후에 WM_TIMER 메시지를 강제로 발생시켜 주어야 한다. 이 때 사용되는 함수가 SendMessage이다.
SendMessage(hWnd, WM_TIMER, 1, 0);
이 함수를 호출해야 할 시점은 프로그램이 시작된 직후인 WM_CREATE 에서이다
타이머를 설치한 직후에 SendMessage로 WM_TIMER 메시지를 보내주어 곧바로 시간을 조사한 후 조사한 시간을 화면에 출력
SendMessage의 세번째, 네번째 인수는 메시지의 추가 정보인 wParam, lParam이며 물론 보내는 메시지에 따라 의미는 달라진다. WM_TIMER 메시지는 wParam으로 타이머 ID를 보내도록 되어 있으므로 SendMessage의 세번째 인수에 타이머 ID인 1을 넘겨주었다. SendMessage의 리턴값도 물론 메시지에 따라 다르다.
이 프로그램이 가지는 두번째 문제점은 시간이 바뀔 때마다 화면이 깜박거린다는 점이다. 컴퓨터가 굉장히 빠르거나 화면이 작다면 잘 느낄 수 없지만 윈도우를 최대화시켜 놓고 보면 시간이 바뀔때 글자들이 지워졌다가 다시 그려지는 것이 보일 것이다. 왜 그런가 하면 WM_TIMER 메시지에서 시간을 변경한 후 화면을 다시 그리기 위해 다음과 같이 함수를 호출하기 때문이다.
InvalidateRect(hWnd,NULL,TRUE);
hWnd 윈도우를 무효화시키되 두번째 인수가 NULL이므로 화면 전체가 무효화되며 세번째 인수가 TRUE이므로 일단 화면을 지운 후 다시 그리게 된다. 화면 전체가 몽땅 다 지워졌다가 다시 출력되도록 했기 때문에 깜박거리는 것이 눈에 보이는 것이다. 그렇다고 해서 세번째 인수를 FALSE로 변경하여 지우지 않도록 한다면 이전에 출력되었던 시간위에 갱신된 시간이 덮여서 출력되므로 그렇게 해서도 안된다.
무효화 영역을 최소화하여 꼭 필요한 부분만 무효화하도록 해 주어야 한다
static RECT rt={95 , 95 , 355 , 125};
InvalidateRect(hWnd , &rt , TRUE);
>두 개의 타이머
타이머는 한꺼번에 여러개를 설치하여 사용할 수도 있다. 필요한만큼 SetTimer를 호출하되 두번째 인수인 타이머 ID를 각각 다르게 설정해 주어야 하며 타이머 간격은 물론 타이머의 용도에 따라 적절하게 설정하면 된다. 여러개의 타이머를 설치했을 경우에도 하나의 타이머를 설치했을 때처럼 전달되는 메시지는 WM_TIMER 하나뿐이다. 어떤 타이머에 의해 WM_TIMER 메시지가 발생했는지는 wParam으로 전달되는 타이머의 ID로 구분한다. 이 타이머 ID는 곧 SetTimer 함수가 타이머를 설치할 때 두번째 인수로 지정한 값이다.![](https://t1.daumcdn.net/cfile/tistory/246DA93F5649724316)
![](https://t1.daumcdn.net/cfile/tistory/27720A43564992C401)
하나의 타이머를 더 설치하여 5초에 한번씩 비프음을 울리도록 만들어 보았다
WM_CREATE에서 2번 ID로 5초 간격의 타이머를 하나 더 만들었다. 그러면 1번 타이머는 1초에 한번씩 WM_TIMER를 발생시킬 것이며 2번 타이머는 5초에 한번씩 WM_TIMER를 발생시킬 것이다. WM_TIMER 메시지 처리부분에서는 wParam값에 따라 어떤 타이머로부터 타이머 메시지가 발생했는지 보고 타이머 ID에 따른 처리를 하면 된다. wParam이 1이면 시간을 갱신한 후 화면을 다시 그리도록 하고 wParam이 2면 MessageBeep 함수를 호출하여 비프음을 낸다. WM_DESTROY에서는 설치된 타이머를 모두 해제해 주어야 한다.
>콜백 함수
프로그램이 실행되는 동안 지속적으로 수행해야 할 작업이 있다고 해 보자. 예를 들어 로고 애니메이션이나 백그라운드 음악 연주 등을 들 수 있는데 도스에서라면 다음과 같이 코드를 작성할 것이다.
한 루프가 전체 프로그램 코드를 감싸고 있고 이 루프 안에서 지속적으로 해야할 작업과 그외 작업을 수행하고 있다. 도스에서는 이런식으로 프로그램을 작성하는 것이 가능하며 실제로 이렇게 한다. 그러나 윈도우즈와 같은 멀티 태스킹 환경에서는 이런 방식을 사용해서는 안된다. 왜냐하면 한 프로그램이 제어권을 독점하고 있어서는 안되며 다른 프로그램도 실행시간을 가져야 하기 때문이다. 사용자는 수시로 작업 전환을 할 수 있어야 하는데 한 프로그램이 CPU를 독차지하고 있으면 안된다. 그래서 CPU를 독점하는 이런 무한루프를 작성해서는 안되며 반드시 메시지가 전달되었을 때에 한해 필요한 작업을 하도록 해야 한다. 이럴 때 사용하는 메시지가 바로 타이머 메시지.
![](https://t1.daumcdn.net/cfile/tistory/237CC4465649930B30)
게임으로 말하자면 총알을 쏘고 나서도 캐릭터는 움직인다. 2가지 작업을 동시에 한다는 것이다.
그렇다면 콜백 함수(Callback Function)란 무엇인지 그 의미를 좀 더 정확하게 알아보자. 일반적으로 API 함수들은 운영체제가 제공하며 프로그램에서는 이 함수들을 호출해서 운영체제의 서비스를 받는다. 예를 들어 도스의 시스템 콜 함수를 호출하여 디스크 입출력을 받는다든가 윈도우즈의 TextOut 함수를 호출하여 문자열을 출력하도록 하는 경우가 이에 해당한다. 반면 콜백 함수는 응용 프로그램이 제공하며 운영체제가 필요할 때 호출하는 함수이다. 호출되는 방향이 거꾸로 되었기 때문에 콜백이라고 부르는 것이다. 위 예제에서 TimerProc 함수는 SetTimer에서 지정한 시간마다 운영체제에 의해 호출된다. 콜백 함수를 문장화하여 정의내린다면 "운영체제에 의해 호출되는 프로그램 내부의 함수"라고 할 수 있다.
![](https://t1.daumcdn.net/cfile/tistory/232141465649939F12)
윈도우즈에서는 이런 콜백 함수가 빈번하게 사용되고 있으므로 개념을 잘 알아두도록 하자. 타이머의 콜백 함수가 대표적이며 이 외에도 중요한 열거 함수들과 몇몇 그래픽 함수 등의 콜백 함수를 사용한다. 그보다도 가장 가까운 콜백 함수의 예는 메시지 처리 함수인 WndProc이다. 이 함수는 메시지가 발생할 때마다 윈도우즈가 호출해 주며 응용 프로그램 내부에 있지만 응용 프로그램에서 직접 이 함수를 호출하지는 않는다. 오직 운영체제만이 이 함수를 호출한다.
>생성및 파괴
윈도우와 관련된 메시지 중 가장 간단한 메시지는 윈도우가 생성될 때 보내지는 WM_CREATE와 윈도우가 파괴될 때 보내지는 WM_DESTROY 두가지가 있다.
WM_CREATE 메시지는 CreateWindow 함수에 의해 메인 윈도우가 생성된 직후에 보내지므로 CreateWindow 함수 호출문 다음에 초기화 코드를 작성해도 효과는 같다. WM_DESTROY 메시지는 메인 윈도우가 파괴되기 직전에 보내지는데 메인 윈도우 파괴후에는 메시지 루프가 끝나게 되므로 메시지 루프 다음에 종료 처리 코드를 작성할 수도 있다.
>작업 영역
윈도우는 작업 영역(Client Area)과 비작업 영역(Non Client Area) 두 부분으로 구성되어 있다. 작업 영역이란 쉽게 말해서 윈도우 중앙의 흰 부분을 말하며 비작업 영역이란 그 외의 영역을 말한다.
원하는 위치에 정확하게 출력하려면 윈도우가 차지하고 있는 영역의 좌표를 조사해야 하는 것이 아니라 작업 영역의 좌표를 조사해야 한다. 이때는 다음 함수를 사용한다.
BOOL GetClientRect( HWND hWnd, LPRECT lpRect);
첫번재 인수로 대상 윈도우 핸들을 주고 두번째 인수로 리턴값을 돌려받기 위한 RECT 구조체의 포인터를 넘겨주면 된다.
함수 호출 후에 RECT 구조체에는 작업 영역의 좌표가 들어가는데 left, top은 항상 0이며 right, bottom에 우하단의 좌표가 대입된다.
![](https://t1.daumcdn.net/cfile/tistory/264F6933564994682C)
WM_CREATE에서 GetClientRect 함수로 작업 영역의 좌표를 구해 rt에 대입해 주었다. 그리고 WM_PAINT에서는 작업 영역의 중앙 좌표를 구해 문자열을 출력하되 정확하게 중앙이 되도록 하기 위해 문자열을 중앙 정렬
소스 파일에서 만든다