<Win32API>✔
================================================================
✔ 4-1-라. TranslateMessage
- GetMessage는 메시지 큐에서 메시지를 꺼내온후 이 메시지를 함수 TransleateMessage()로 넘겨준다.
- WM_KEYDOWN이 전달되려면 TransleateMessage()함수와DispatchMessage()함수까지 통과되어야 한다.
- DispatchMessage()함수에 의해 wndProc에 전달 되므로
* TranslateMessage 함수를 빼 버리면 WM_CHAR 메시지는 절대로 WndProc으로 전달되지 않을 것이다.
---------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd , UINT iMessage , WPARAM wParam , LPARAM lParam )
{
HDC hdc;
static int x;
static int y;
static BOOL bnowDraw = FALSE;
switch ( iMessage)
{
case WM_LBUTTONDOWN:
x = LOWORD( lParam);
y = HIWORD( lParam);
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;
return 0;
case WM_LBUTTONDBLCLK:
InvalidateRect( hWnd, NULL, TRUE);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return(DefWindowProcA( hWnd, iMessage, wParam, lParam));
}
![](https://t1.daumcdn.net/cfile/tistory/211AAF4E5649AF5E2B)
---------------------------------------------------
✔ 4-2-가. Mouse
- WParam(word) lParam(long)
옛날엔 2, 4
지금은 4, 4
버튼 | 누름 | 놓음 | 더블클릭 |
좌측 | WM_LBUTTONDOWN | WM_LBUTTONUP | WM_LBUTTONDBLCLK |
우측 | WM_RBUTTONDOWN | WM_RBUTTONUP | WM_RBUTTONDBLCLK |
중앙 | WM_MBUTTONDOWN | WM_MBUTTONUP | WM_MBUTTONDBLCLK |
- 버튼 세개에 각각 누름, 놓음, 더블 클릭 의 9가지 메시지가 있다.
* lParam의 상위 워드에 마우스 버튼이 눌러진 y좌표 ,하위 x좌표 를 가진다.
- 반으로 잘르면 x,y좌표를 얻는다.
- 절대 좌표가 아니고 (바탕화면 기준아니고) 창 안에서의 기준이다.
* 좌표값 검출을 위해 HIWORD, LOWORD 의 매크로 함수사용.
![](https://t1.daumcdn.net/cfile/tistory/2453694D5649AF9615)
* 조합키 상태는 다음표의 값들과 비트연산
값 | 설명 |
MK_CONTROL | Ctrl 키가 눌러져 있다. |
MK_LBUTTON | 마우스 왼쪽 버튼이 눌러져 있다. |
MK_RBUTTON | 마우스 오른쪽 버튼이 눌러져 있다. |
MK_MBUTTON | 마우스 중간 버튼이 눌러져 있다. |
MK_SHIFT | Shift 키가 눌러져 있다. |
- 왼쪽 마우스 버튼이 눌려지면 "WM_LBUTTONDOWN 메시지 발생"
-> 눌려진 위치좌표를 x,y 에 대입
-> 마우스가 움직이면 시작 지점~ 움직이는 지점까지 선을 긋는다.
- 그리는 것처럼 보이지만 실제 선을 긋고 있다. 버튼 때면 UP호출/누리면 DOWN
* WParam에는 마우스 버튼의 상태(누른상태/안누른상태 체크)와 키보드 조합키의 상태(Shift, Ctrl)가 전달된다.
- lParam 에 마우스 커서의 위치가 전달되고, wParam에 조합키 상태가 전달된다.
- 마우스 버튼이 놓아지면 bnowDraw를 FALSE로 변경하여 마우스가 움직여도 선이 안그려진다.
- 화면 그림을 그리기만 하고 복구 능력이없다.
* 이 문제의 해결은
- 화면 전체를 비트맵으로 저장
- 연결리스트를 사용하여 마우스의 움직임을 일일이 보관.
* 우리가 만든창은 가로가 65000정도가 한계다. 가로가 3000개 넘어가기 힘들다.
윈도우의 한계다.
- 하지만 이후에 long를 8로 올리면 가로 40억개 되니까 해결방법이 된다.
* C++아니라서 BOOL형이 존재 하지 않음. 용량이 실제 그렇게 작지 않다(typedef로 만들었기 때문에) 모르는 형이 나오면 존재하는것이 아니고 define해서 사용한것.
*lsprintf : 메모리에 출력하는 것(메모리 주소)
- 윈도우에서는 2바이트를 프린터 할수있는애 유니코드지원.
---------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd , UINT iMessage , WPARAM wParam , LPARAM lParam )
{
HDC hdc;
PAINTSTRUCT ps;
static int x;
static int y;
static WCHAR wcbuf[100];
static WCHAR str[256]; //WCHAR 2바이트 / TCHAR은 4바이트
int len;
switch ( iMessage)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_MOUSEMOVE:
x = LOWORD( lParam);
y = HIWORD( lParam);
wsprintf(wcbuf, L "x = %d, y = %d", x, y);
InvalidateRect( hWnd, NULL, TRUE);
return 0;
case WM_PAINT:
hdc = BeginPaint( hWnd, &ps);
TextOut(hdc, 50, 50, wcbuf, lstrlen(wcbuf)); //아스키1바이트만 지원 그래서 L
EndPaint( hWnd, &ps);
return 0;
}
return( DefWindowProc(hWnd , iMessage , wParam , lParam ));
}
![](https://t1.daumcdn.net/cfile/tistory/2518C14C5649AFD103)
---------------------------------------------------
✔ 4-2-나. 더블클릭
- InvalidateRect 함수 호출로 작업영역 전체 무효화
* 더블클릭 메시지를 발생하기 위해 메인을 드물게 수정한다.
- CS_DBLCLKS 플레그 추가
WndClass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS ;
* WM_Paint가 출력문자가 있으면 계속 다시 그려 안지워짐.
* buf의 0번째 자리를 초기화 해서 아무것도 출력되지 않도록 처리.
---------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd , UINT iMessage , WPARAM wParam , LPARAM lParam )
{
HDC hdc;
PAINTSTRUCT ps;
static int x;
static int y;
static WCHAR wcbuf[100];
static WCHAR str[256]; //WCHAR 2바이트 / TCHAR은 4바이트
int len;
switch ( iMessage)
{
case WM_MOUSEMOVE:
x = LOWORD( lParam);
y = HIWORD( lParam);
wsprintf(wcbuf, L "x = %d, y = %d", x, y);
InvalidateRect( hWnd, NULL, TRUE);
return 0;
case WM_PAINT:
hdc = BeginPaint( hWnd, &ps);
TextOut(hdc, 50, 50, wcbuf, lstrlen(wcbuf)); //아스키1바이트만 지원 그래서 L
EndPaint( hWnd, &ps);
return 0;
case WM_LBUTTONDBLCLK:
wcbuf[0] = 0;
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/2112404C5649B00B0A)
---------------------------------------------------
✔ 4-3-가. 타이머
- CREATE : 창이 생성될때 딱한번 호출 된다.
- setTimer: 타이머를 만드는 함수(hWnd(윈도우), 1(타이머 번호), 시간간격, 함수주소)
* 타이머 번호 우리가 알고 있어야 한다.
- 함수 주소 안넣으면 :WTimer이라는 메시지만 만들어진다. (주소를 적으면 시간간격으로 호출한다.)
- 현재 시간을 알아내는 mytime 현재시간을 초로 가져온다.
- 글자 형태의 시간. 을 계속 뿌린다. InvalidateRect
- killTimer (, 1): 타이머 번호와 일치해야 한다.
- 내부적으로 동적할당 받는 것 같아 닫아줘야 한다. 만들때 번호 받을때 번호 일치!
***게임에서
블럭이 떨어지는 속도
미사일의 속도***
---------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd , UINT iMessage , WPARAM wParam , LPARAM lParam )
{
HDC hdc;
PAINTSTRUCT ps;
//time_t mytime;
//static HANDLE hTimer;
SYSTEMTIME st;
static TCHAR sTime[128];
switch ( iMessage)
{
case WM_CREATE:
SetTimer( hWnd, 1, 1000, NULL);
//SendMessage(hWnd, WM_TIMER, 1, 0);
return 0;
case WM_TIMER:
GetLocalTime(&st);
wsprintf
(
sTime
, TEXT( "지금 시간 : %d: %d: %d 입니다." )
, st.wHour
, st.wMinute
, st.wSecond
);
InvalidateRect( hWnd, NULL, TRUE);
return 0;
case WM_PAINT:
hdc = BeginPaint( hWnd, &ps);
TextOut(hdc, 100, 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/2209C84C5649B03F12)
---------------------------------------------------
✔ 4-3-나. SendMessage
* 시계 프로그램의 문제1 : 1초 정도 경과후 시간 출력
- WM_TIMER 메시지는 최초로 호출 되는 시점이 프로그램 시작 1초후다.
- WM_CREATE 에서 타이머 설치 할때 주기를 1초로 주었다.
- WM_TIMER메시지를 강제로 발생시켜주기 위해 SendMessage 함수를 사용한다(hWnd 윈도우로 Msg메시지를 보냄)
- 타이머가 여러개면 switch 안에 switch
- 오락의 총알이 다르게 날라온다. 즉 타이머가 다르게 동작한다.
* 메시지 기반 운영체제인 윈도우즈의 SendMessage 함수는 빈번히 사용된다.
* 시계 프로그램의 문제2 : 몽땅지워지고 다시 출력되어 깜빡거린다. 그래서 무효화 영역을 최소화 한다.
---------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd , UINT iMessage , WPARAM wParam , LPARAM lParam )
{
HDC hdc;
PAINTSTRUCT ps;
SYSTEMTIME st;
static RECT rt = { 100, 100, 400, 120 };
static TCHAR sTime[128];
switch ( iMessage)
{
case WM_CREATE:
SetTimer( hWnd, 1, 1000, NULL);
SendMessage(hWnd , WM_TIMER , 1, 0);
return 0;
case WM_TIMER:
GetLocalTime(&st);
wsprintf
(
sTime
, TEXT( "지금 시간 : %d: %d: %d 입니다." )
, st.wHour
, st.wMinute
, st.wSecond
);
InvalidateRect(hWnd, &rt, TRUE);
return 0;
case WM_PAINT:
hdc = BeginPaint( hWnd, &ps);
TextOut(hdc, 100, 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 ));
}
✔ 4-3-다 . 두개의 타이머
* 타이머는 한꺼번에 여러개 설치 가능 .
- 16비트 윈도우즈에서 타이머는 최대 16개까지 설치할수 있다.
* 필요한 만큼 SetTimer를 호출
- 1초간격 타이머
- 5초간격 타이머
![](https://t1.daumcdn.net/cfile/tistory/275C5F485649B11C35)
4-3-라. 콜백 함수
프로그램이 실행되는 동안 지속적으로 수행해야 할 작업이 있다고 해 보자.
예를 들어 로고 애니메이션이나 백그라운드 음악 연주 등을 들 수 있는데 도스에서라면 다음과 같이 코드를 작성할 것이다.
for(;;) {
지속적인 작업
기타 작업
}
무한 루프가 전체 프로그램 코드를 감싸고 있고 이 루프 안에서 지속적으로 해야할 작업과 그외 작업을 수행하고 있다.
도스에서는 이런식으로 프로그램을 작성하는 것이 가능하며 실제로 이렇게 한다.
그러나 윈도우즈와 같은 멀티 태스킹 환경에서는 이런 방식을 사용해서는 안된다.
왜냐하면 한 프로그램이 제어권을 독점하고 있어서는 안되며 다른 프로그램도 실행시간을 가져야 하기 때문이다.
사용자는 수시로 작업 전환을 할 수 있어야 하는데 한 프로그램이 CPU를 독차지하고 있으면 안된다.
그래서 CPU를 독점하는 이런 무한루프를 작성해서는 안되며 반드시 메시지가 전달되었을 때에 한해 필요한 작업을 하도록 해야 한다.
이럴 때 사용하는 메시지가 바로 타이머 메시지이다.
✔ SetTimer
- 4번째 인수 : 타이머 프로시저 함수의 포인터를 가리킨다.
- NULL일 경우 첫번째 인수 hWnd로 WM_TIMER메시지가 전달된다.
- 함수를 만들어 네번째 인수에 함수명을 적어줌. 함수가 지정되면 시간마다 메시지 대신 함수를 호출
VOID CALLBACK TimerProc( HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime );
(hwnd : 타이머를 소유한 윈도우 핸들, , , dwTime : 윈도우즈가 실행된 후의 경과시간)
* 콜백함수와 WM_TIMER메시지 의 차이점
- WM_TIMER메시지는 다른 메시지가 있을 경우 실행 순서에 밀려 늦게 호출 되는 경우가 있음.
- 콜백함수를 사용하면 정확한 시간에 호출된다.
* 정확도를 필요로 하면 타이머 메시지보다 콜백 함수를 사용하는 것이 더 좋다.
* 지속적인 작업(for문에서 폴링방식)
✔ 콜백(CALLBACK Func)
일반적으로 API 함수들은 운영체제가 제공하며 프로그램에서는 이 함수들을 호출해서 운영체제의 서비스를 받는다.
예를 들어 도스의 시스템 콜 함수를 호출하여 디스크 입출력을 받는다든가
윈도우즈의 TextOut 함수를 호출하여 문자열을 출력하도록 하는 경우가 이에 해당한다.
반면 콜백 함수는 응용 프로그램이 제공하며 운영체제가 필요할 때 호출하는 함수로 호출되는 방향이 거꾸로 되어 콜백이라고 부르는 것이다.
"운영체제에 의해 호출되는 프로그램 내부의 함수"라고 할 수 있다
* 타이머의 콜백함수가 대표적이다. - 열거 함수 , 그래픽 함수등의 콜백함수도 사용한다.
* 콜백 함수의 예로 메시지 처리함수 WndProc이 있다.
메시지가 발생할때마다 윈도우즈가 호출해주며 응용프로그램 내부에 있지만 응용프로그램에서 직접 함수를 호출하지 않는다. 오직 운영체제만이 함수를 호출한다.
<0.1초마다 점을찍는다. 100개씩>
---------------------------------------------------
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 ));
}
![](https://t1.daumcdn.net/cfile/tistory/2137274E5649B1BC1A)
---------------------------------------------------
✔ 4-4- 가. 생성및 파괴
- 윈도우가 생성될때 보내지는 WM_CREATE : 각종 초기화하기에 적합한 장소
- 윈도우가 파괴될때 보내지는 WM_DESTROY : 종료처리하기에 적합
✔ 4-4- 나. 작업영역
- 우리가 생성한 getclientrect 우리가 만든 클라이언트 정보를 rt에 넣어준다.
---------------------------------------------------
<생성할때 크기를 알아내고, 정중앙을 계산하고 글자를 출력.>
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);
SetTextAlign(hdc, TA_CENTER);
TextOut(hdc, rt.right / 2, rt.bottom / 2, L "Center String", 13);
EndPaint( hWnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return ( DefWindowProc(hWnd , iMessage , wParam , lParam ));
}
- 메뉴(바)는 원점(0,0)이 아니다.
![](https://t1.daumcdn.net/cfile/tistory/2679B5415649B29717)
---------------------------------------------------
✔ 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_CREATE:
GetClientRect(hWnd, &rt);
return 0;*/
case WM_PAINT:
hdc = BeginPaint( hWnd, &ps);
SetTextAlign(hdc, TA_CENTER);
TextOut(hdc, rt.right / 2, rt.bottom / 2, L "Center String", 13);
EndPaint( hWnd, &ps);
return 0;
case WM_SIZE:
GetClientRect(hWnd, &rt); // 창크기를 알아냄
InvalidateRect(hWnd, NULL, TRUE);
또는
/*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/245CEB465649B2CB14)
---------------------------------------------------
✔ 4-4- 라. WM_MOVE
- 창을 이동 시키면 호출한다.
✔ 5-1- 가
- 리소스의 분리
- 리소스 편집기>> 메뉴
✔ 5-2-가. 리소스 작성
- 프로젝트 만들고, 소스를 붙인다.
- 디테일 한것은 프로퍼티즈에서 설정한다.(버전이 바뀌면서 그래픽 요소가 텍스트화 됨.)
* 메뉴를 만들어서 properties를 보면 캡션에 - 아이디를 자동으로 부여한다.
![](https://t1.daumcdn.net/cfile/tistory/24723A3F5649B2FB34)
예> VS이 자동으로 추가함.(숫자 알아서 넣는다.) 메뉴를 번호로 관리 하므로 고유번호를 알아서 메김 알아서 디파인 이름 정하고, 우리가 적은 메뉴이름과비슷하게 만들어 40001, 40002 .. 식으로 번호 매김. 편함..(반면 바보가 되는 개발자)
* 메뉴리소스는 고유 번호는 101번이다.
- 하부 메뉴는 40001 이고, 이 번호는 줄어들지 않는다. 시작 번호를 기준으로 무조건 증가한다. 완전한 고유 번호를 인지 하기 위해 삭제했던 번호는 다시 사용안한다.
* 메뉴 선택 = 해당 메뉴의 함수호출 의미이므로 반드시 고유해야 한다.
* 어떤 메뉴를 선택해도 WM_COMMAND가 호출
- wParam에 메뉴번호가 들어온다 메뉴를 건드리는게 w커멘드다. 그래서 고유한 번호를 부여한다.
<메뉴 만들기>
1. #include "resource.h" 추가
2. 메뉴를 만든다.
3. 윈메인을 추가한다(등록한다)
4. 자동으로 발급된 아이디에 따라서 배치하면 끝난다.
![](https://t1.daumcdn.net/cfile/tistory/250DFC435649B34431)
✔ 5-2-나. WM_COMMAND
값 | 설명 |
lParam | 통지 메시지를 발생시킨 컨트롤의 윈도우 핸들 |
LOWORD(wParam) | 메뉴나 액셀러레이터, 컨트롤의 ID |
HIWORD(wParam) | 컨트롤이 보내주는 통지 메시지, 메뉴가 선택된 경우는 0이 되며 액셀러레이터가 선택된 경우는 1이 된다. |
✔ 5-2-다.메뉴 편집기의 사용법 읽어보기
✔ 5-3 아이콘, 커서
![](https://t1.daumcdn.net/cfile/tistory/22226F3E5649B37509)