#include "windows.h" LRESULT CALLBACK WndProc(HWND hwnd, UINT, WPARAM wParam, LPARAM lParam); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, LPSTR lpCmdLine,int nShowCmd) { MSG msg; HWND hwnd; WNDCLASS wndclass; wndclass.cbClsExtra=0; wndclass.cbWndExtra=0; wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.hCursor= LoadCursor(0,IDC_ARROW); wndclass.hIcon = LoadIcon(0,IDI_APPLICATION); wndclass.hInstance = hInstance; wndclass.lpfnWndProc = WndProc; wndclass.lpszClassName = TEXT("szAppName"); wndclass.lpszMenuName = 0; wndclass.style = CS_VREDRAW | CS_HREDRAW; if(!RegisterClass(&wndclass)) return 0; hwnd=CreateWindow(wndclass.lpszClassName, "Window Caption",WS_OVERLAPPEDWINDOW, ,500,500,500,500,0,0,hInstance,0); ShowWindow(hwnd, nShowCmd); UpdateWindow(hwnd); while(GetMessage(&msg,0,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_DESTROY: { PostQuitMessage(0); return 0; } } return DefWindowProc(hwnd, message, wParam, lParam); }
API 기본소스에는 WinMain과 WndProc 두개의 함수가 있다.
WinMain함수에서는 윈도우 클래스를 정의, 등록, 생성, 표시작업을 하고 메시지루프를 통해 메시지를 받고, 번역하고 번역된 메시지처리 함수인 WndProc 함수에 전달한다.
처음 API를 시작하는 분들은 이해가 잘가지 않더라도 일단 소스를 다 외워버리자. ( __)
물론 싫으면 안외워도 되겠지만.. 결국 외우게 되어있다. 그냥 외우자 ㅋㅋ
큰 그림은 아래의 플로우차트와 같은 방식으로 진행된다. 이를 염두해두고 소스가 어느단계에 있는지 이해해가면서 읽어주시길..
#include <windows.h>
다른 윈도우 헤더파일을 포함하는 마스터 파일.
WINDEF.H | 기본 형식 정의 |
WINNT.H | 유니코드지원을 위한 형식 정의 |
WINBASE.H | Kernel 함수 |
WINUSER.H | 사용자 인터페이스(UI) 함수 |
WINGDI.H | 그래픽 장치 인터페이스(GDI) 함수 |
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
Window Procedures는 항상 RegisterClass를 호출하여 등록한 특정한 윈도우 클래스와 연결
SendMessage라는 함수를 통해서 자신의 윈도우 프로시저를 간접적으로 호출
#define CALLBACK __stdcall (windef.h에서 정의)
함수 이름앞에 CALLBACK으로 선언, 모든 윈도우는 해당 윈도우 프로시저를 갖고 있다.
메시지 루프에서 해석된 메시지를 구체적으로 처리하는 기능을 수행
CALL BACK 함수는 윈도우에서 자동으로 불려지는 함수이므로 Language independent(호출형식을 동일하게 해야함)
Message 는 WINUSER.H에서 정의
메시지를 처리할 때에 반드시 윈도우프로시저로부터 0이 반환되어야 함
윈도우 프로시저가 처리하지 않는 모든 메시지들은 반드시 DefWindowProc 라는 이름의 Window함수에 전달되어야 한다.
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow)
int WINAPI WinMain ( HINSTANCE hInstance, // 현재 프로그램의 인스턴스 핸들 HINSTANCE hPrevInstance, // 이전에 실행된 인스턴스 핸들 // 16비트 운영체제에서 사용되었으며 호환성을 위해서 존재(일반적으로 NULL) LPSTR lpCmdLine, // 프로그램을 실행할 때 사용된 명령줄(도스의 argv에 해당) int nCmdShow // 프로그램이 실행될 상태 (최소화, 최대화, 보통) );
__stdcall 함수 호출시 함수쪽에서 리턴하기 전에 스택에 저장된 인자들을 정리하는 방식
16bit의 PSCAL호출규약과 동일
인스턴스 - 실제 메모리상에 할당된 객체로 모듈 인스턴스는 코드 영역에 데이터 인스턴스는 데이터 영역에 저장된다.
HWND hwnd;
핸들 : 프로그램에서 현재 사용중인 객체들을 식별하기 위해 윈도우 OS가 부여하는 고유번호
※ 포인터가 아닌 핸들을 이용하는 이유 : 메모리 할당시에 내부적으로 윈도우는 메모리를 이동시켜 필요공간을 확보한다.
MSG msg;
typedef struct tagMSG { HWND hwnd; // 메시지를 받을 윈도우의 핸들 UINT message; // 전달되는 메시지 유형 WPARAM wParam; // 메시지에 대한 추가 정보(32bit) LPARAM lParam; // 메시지에 대한 추가 정보(32bit) DWORD time; // 메시지가 발생된 시간 POINT pt; // 메시지가 발생할 때의 마우스 위치 } MSG;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_ASTERISK);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
typedef struct { UINT style; // 윈도우 스타일을 정의 WNDPROC lpfnWndProc; // 윈도우와 연결되는 윈도우 함수를 연결 int cbClsExtra; // 윈도우 클래스에서 사용하고자 하는 여분의 메모리 양(Byte) // 윈도우 클래스를 등록시 메모리를 추가로 할당 // SetClassLong, GetClassLong 함수로 이 메모리를 사용 int cbWndExtra; // 개별 윈도우에서 사용하고자 하는 여분의 메모리 양(Byte) // 개별 윈도우가 생성시 메모리를 추가로 할당 // SetWindowLong, GetWindowLong 함수로 이 메모리를 사용 HINSTANCE hInstance; // 프로그램의 인스턴스 핸들 HICON hIcon; // 윈도우 클래스를 기반으로 생성된 모든 윈도우에 대한 아이콘을 설정 // 프로그램이 실행될 때 아이콘은 Windows 작업 표시줄에 나타남 HCURSOR hCursor; // 윈도우에서 사용하는 커서를 지정 HBRUSH hbrBackground; // 윈도우의 배경색을 지정 LPCTSTR lpszMenuName; // 윈도우의 메뉴를 지정 LPCTSTR lpszClassName; // 클래스는 반드시 이름을 부여받아야함. } WNDCLASS, *PWNDCLASS;
if (!RegisterClass(&wndclass))
return 0;
RegisterClass함수를 호출하여 윈도우 클래스를 등록, 실패시 종료
hwnd = CreateWindow(wndclass.lpszClassName, "Window Caption", WS_OVERLAPPEDWINDOW,
500, 500, 500, 500, NULL, NULL, hInstance, NULL);
윈도우 생성 후 윈도우 핸들리턴
> WM_CREATE
HWND CreateWindow ( LPCTSTR lpClassName, // 윈도우 클래스 이름 LPCTSTR lpWindowName, // 윈도우 캡션(제목 표시줄) DWORD dwStyle, // 윈도우 스타일 int x, // x 위치 int y, // y 위치 int nWidth, // 넓이 int nHeight, // 높이 HWND hWndParent, // 부모 윈도우 핸들 HMENU hMenu, // 윈도우 메뉴 핸들 HINSTANCE hInstance, // 프로그램 인스턴스 핸들 LPVOID lpParam // CREATESTRUCT 구조체의 번지 );
ShowWindow(hwnd,iCmdShow);
생성된 윈도우를 화면에 출력,
> WM_SIZE, WM_SHOWWINDOW
UpdateWindow(hwnd);
> WM_PAINT, WM_MOVE
while (GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
메시지 루프 - OS로부터 전달된 메시지를 보관하는 큐에 어떤 메시지가 들어왔는지 지속적으로 분석
GetMessage - WM_QUIT 시에 false, 그외의 경우는 true를 리턴
TranslateMessage - 키보드 입력 메시지를 가공하여 프로그램에서 쉽게 사용 할 수 있도록 번역
DispatchMessage - 메시지 큐에서 꺼낸 메시지를 윈도우 프로시저로 전달, 윈도우 프로시저가 윈도우에게 컨트롤을 넘기기 전까지 반환되지 않음
return msg.wParam;
종료(msg.wParam == 0)
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
위에서 했음 ( __)
switch (message)
{
case WM_DESTROY:
윈도우가 종료되고 있음을 나타냄
종료단추를 클릭하면 시스템 메뉴의 종료 메뉴를 선택하면 WM_DESTROY 발생
{
PostQuitMessage(0);
메시지큐에 WM_QUIT를 삽입 > GetMessage()는 메시지쿠가 WM_QUIT 이면 0을 리턴
return 0;
}
}
※ 종료순서
WM_SYSCOMMAND > WM_CLOSE > DestoryWindow() > WM_DESTROY > PostQuitMesssage() > WM_QUIT > Message Queue
return DefWindowProc(hwnd,message,wParam,lParam);
WndProc은 메시지를 처리했을 경우 반드시 0을 리턴해 주어야 한다.
DefWindowProc 함수가 메시지를 처리했을 경우 이 함수가 리턴한 값을 WndProc 함수가 다시 리턴해 주어야 함
'일' 카테고리의 다른 글
02. 커널 오브젝트 下 (0) | 2009.08.18 |
---|---|
01. 커널 오브젝트 上 (0) | 2009.08.18 |
한 줄에 여러개의 숫자를 입력받아 배열에 할당 (0) | 2009.07.13 |
문자열 거꾸로 출력하기 (0) | 2009.07.13 |
2. 메시지 (0) | 2009.07.12 |