7. 다행히 그런 부분은 Windows (운영체제)가 알아서 처리해준다
대신 이러 이러한 방식으로 코딩 하라는 규칙이 있다
그 규칙에 따라서 코딩 하는 것을
사건 기반 프로그래밍
Event-Driven Programming
7
위 말이 이해가 안되면 1장을 다시 보세요
8. 8
메시지 처리 코딩
윈도우 생성 코딩
프로그램 끝 날 때 까지
이벤트 처리 과정
프로그래머가 실제로 하는 일
반복
9. 9
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT,
WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPSTR lpszArg,
int nCmdShow);
메시지 처리 코딩
윈도우 생성 코딩 WinMain
WndProc
함수가 왜 이렇게 복잡해 보이냐
함수가 달랑 두 개 뿐
10. 10
이벤트 처리하려면 어떤 정보가 있어야 할까?
메시지
• 이벤트는 어디서 발생?
• 어떤 이벤트 인데?
• 이벤트가 발생했을 때 어떤 상황이지?
• 이벤트 발생 시각은?
• 이벤트 발생할 때 마우스 위치는?
11. 11
• 이벤트는 어디서 발생?
• 어떤 이벤트 인데?
• 이벤트가 발생했을 때 어떤 상황이지?
• 이벤트 발생 시각은?
• 이벤트 발생할 때 마우스 위치는?
• 윈도우 구분 아이디 필요
• 이벤트 구분 아이디 필요
• 상황정보
• 이벤트 발생 시점 기록
• 마우스 위치 기록
typedef struct
{
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG
메시지 구조체
유추할 수는 있겠는데, 타입은 생소하군
12. 12
typedef struct
{
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG
unsigned int
Handle to a Window
HINSTANCE
handle to an Instance (Program)
다 생소하겠지만 위 두 개는 지금 기억
나머지는 차츰 알게 된다
15. 15
LRESULT CALLBACK WndProc(HWND, UINT,
WPARAM, LPARAM);
이벤트 처리 함수의 프로토타입
LRESULT
CALLBACK
HWND
UINT
WPARAM
LPARAM
리턴 타입; 알려고 하지 말자
함수 호출 방식 지정
윈도우 핸들
이벤트 아이디
부가정보 1
부가정보 2
PASCAL 언어 방식
C 언어 방식
• word parameter = 4 bytes
• long word parameter = 4 bytes
원래 word 는 2 bytes 이고 long은 2배 였지만 지금은 둘 다 4 bytes
16. 16
LRESULT CALLBACK WndProc(HWND, UINT,
WPARAM, LPARAM);
이벤트 처리 함수의 프로토타입
LRESULT
CALLBACK
HWND
UINT
WPARAM
LPARAM
리턴 타입; 자세히 알려고 하지 말자
함수 호출 방식 지정
윈도우 핸들
이벤트 아이디
부가정보 1
부가정보 2
PASCAL 언어 방식
C 언어 방식
__stdcall
원래는 이 키워드 인데 이름 바꾸고 callback 함수라고 불러
파라미터가 MSG와 일치
17. 17
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArg,
int nCmdShow)
{
}
윈도우 프로그램 시작 함수
WINAPI
HINSTANCE
LPSTR
파스칼 호출방식 지정
방금 실행된 프로그램 ID
이전에 실행된 프로그램 ID
실행 시 넘겨지는 문자열
윈도우 화면 출력 여부 결정하는 상수 값 넘어옴
새로운 데이터 타입에 너무 신경 쓰지 마세요
__stdcall
18. 18
WinMain()
{
}
윈도우 클래스 정의
윈도우 클래스 등록
윈도우 생성
메시지 루프
여기서 말하는 클래스는 C++ 클래스 아님
그냥 속성 모음; 속성 값 설정
설정한 속성들을 운영체제에게 알림
등록된 설정 값을 이용해서 윈도우 생성
메시지 처리 반복
윈도우생성 하려면 윈도우 클래스 정의 및 등록을 먼저
프로그램 끝 내려면 메시지 처리 반복을 끝내야 해
클래스 정의 및 등록은 어떻게 하는 거야
19. 19
WinMain(HINSTANCE hInstance,…)
{
WNDCLASS WndClass;
WndClass.style = NULL;
WndClass.lpfnWndProc = WndProc;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hInstance = hInstance;
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
WndClass.lpszMenuName = NULL;
WndClass.lpszClassName = "Hello";
}
클래스 정의: 구조체에 값 넣는 작업
프로그래머가 맘대로 정해줄 수 있는 부분
그 나머지는 거의 이래로 사용; 암기 불필요
프로그램 ID도 기록해 두네
이벤트 처리 함수 이름이네
21. 21
WinMain(HINSTANCE hInstance,…)
{
HWND hWnd;
hWnd = CreateWindow(
"Hello",
"Hello",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
}
윈도우 생성: 실제 윈도우 생성
CreateWindow 11개의 인자에 대해 잘 알아야 함
당장은 아니고 앞으로 차근차근
22. 22
WinMain(HINSTANCE hInstance,…)
{
HWND hWnd;
hWnd = CreateWindow(
"Hello",
"Hello",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
}
WndClass.lpszClassName = "Hello"; 대소문자 구분 안 한다
앞서 등록한 윈도우 클래스를 여기서 활용
윈도우 클래스 정의 부분에서 WndProc 있었는데… 이게 의미하는 바는 ?
23. 23
WinMain(…, int nCmdShow)
{
hWnd = CreateWindow(…);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
}
생성한 윈도우를 화면에 실제로 출력하게 한다
이거 안 해주면 윈도우를 만들어도 화면에 안 보여진다
두 개를 다 써줘야 한다 왜 두 개나? 이상하긴 하지만 일단 넘어가자
대개 첫 번째 인자는 hWnd
이미 만들어진 윈도우에게 뭔가 조작을 가는 함수, 대개 첫 번째 인자는 윈도우 핸
들인 함수를 포함하여 윈도우 프로그래밍에 필요한 함수와 SW_SHOW같은 상수. 이
들은 windows.h 에 정의되어 있다.
SW_SHOW, WS_HIDE
윈도우 API
24. 24
WinMain(…, )
{
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
메시지 루프: 발생한 이벤트를 반복해서 처리한다
그럼 언제 끝나 ?
GetMessage( ) 가 false가 될 때 반복문 종료
가지고 온 메시지가 WM_QUIT 일 때
메시지는 어디서 가지고 오더라 ? Application Queue 에서
메시지 처리는 WndProc에서 한다고 했는데 호출부분이 안보여
25. 25
WinMain(…, )
{
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
이벤트 발생에 따른 처리는 운영체제 몫
어떻게 처리할 지만 프로그래머 몫
여기서 내부적으로 WndProc 호출
왜 두 개나? 이상하긴 하지만 여기도 일단 넘어가자
이상 WinMain 파트 끝
26. 26
LRESULT CALLBACK WndProc(HWND hWnd, UINT mesg, WPARAM wParam, LPARAM lParam)
{
switch(mesg)
{
case WM_DESTROY :
PostQuitMessage(0);
return FALSE;
}
return DefWindowProc(hWnd, mesg, wParam, lParam);
}
이벤트가 발생할 때 마다 윈도우즈가 자동으로 호출
복잡해 보여도 그냥 함수, 쫄지마~
여기서 처리하고 있는 메시지는 ? 어떤 처리를 하고 있나 ?
PostQuitMessage(0)의 역할이 무엇인가 ?
WM_DESTROY
27. 27
LRESULT CALLBACK WndProc(HWND hWnd, UINT mesg, WPARAM wParam, LPARAM lParam)
{
switch(mesg)
{
case WM_DESTROY :
PostQuitMessage(0);
return FALSE;
}
return DefWindowProc(hWnd, mesg, wParam, lParam);
}
이벤트가 발생할 때 마다 윈도우즈가 자동으로 호출
복잡해 보여도 그냥 함수
여기서 처리하고 있는 메시지는 ? 어떤 처리를 하고 있나 ?
PostQuitMessage(0)의 역할이 무엇인가 ?
WM_QUIT 메시지를 어플리케이션 큐에 넣는다
처리 메시지
처리 내용
28. 28
LRESULT CALLBACK WndProc(HWND hWnd, UINT mesg, WPARAM wParam, LPARAM lParam)
{
switch(mesg)
{
case WM_DESTROY :
PostQuitMessage(0);
return FALSE;
}
return DefWindowProc(hWnd, mesg, wParam, lParam);
}
얘는 뭐 하는 녀석인가 ?
WM_SIZE
WM_MOVE
기본적인 윈도우 메시지 처리
30. 30
typedef LONG LONG;
typedef LONG LRESULT;
#define CALLBACK __stdcall
#define WINAPI __stdcall
#define VOID void
typedef unsigned int UINT; // 4바이트
typedef UINT WPARAM; // 4바이트
typedef LONG LPARAM; // 4바이트
typedef unsigned short WORD; // 2바이트
typedef unsigned long DWORD; // 4바이트
typedef CHAR *LPSTR, *PSTR; // 4바이트
typedef unsigned char BYTE; // 1바이트
typedef char CHAR; // 1바이트
typedef float FLOAT; // 4바이트
typedef int INT; // 4바이트
typedef int BOOL; // 4바이트
typedef struct tagPOINT { LONG x, LONG y } POINT;
참고로 한번 훑어 보세요 기존 것 재정의 한 것에 불과
※ 메모리 크기는 바뀔 수 있음