1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <windows.h>
 
/* This is where all the input to the window goes to */
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
    switch(Message) {
        
        /* Upon destruction, tell the main thread to stop */
        case WM_CREATE:
            break
        case WM_DESTROY: {
            PostQuitMessage(0);
            break;
        }
        
        /* All other messages (a lot of them) are processed using default procedures */
        default:
            return DefWindowProc(hwnd, Message, wParam, lParam);
    }
    return 0;
}
 
/* The 'main' function of Win32 GUI programs: this is where execution starts */
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    WNDCLASSEX wc; /* A properties struct of our window */
    HWND hwnd; /* A 'HANDLE', hence the H, or a pointer to our window */
    MSG msg; /* A temporary location for all messages */
 
    /* zero out the struct and set the stuff we want to modify */
    memset(&wc,0,sizeof(wc));
    wc.cbSize         = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc     = WndProc; /* This is where we will send messages to */
    wc.hInstance     = hInstance;
    wc.hCursor         = LoadCursor(NULL, IDC_IBEAM);
    
    /* White, COLOR_WINDOW is just a #define for a system color, try Ctrl+Clicking it */
    wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = "Window Class Name";
    
    wc.hIcon         = LoadIcon(NULL, IDI_QUESTION); /* Load a standard icon */
    wc.hIconSm         = LoadIcon(NULL, IDI_QUESTION); /* use the name "A" to use the project icon */
 
    if(!RegisterClassEx(&wc)) {
        MessageBox(NULL"Window Registration Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);
        return 0;
    }
 
    hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,"Window Class Name","홍길동의 첫번째 윈도우 ",WS_VISIBLE|WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT0, /* x */
        CW_USEDEFAULT, /* y */
        CW_USEDEFAULT, /* width */
        CW_USEDEFAULT, /* height */
        NULL,NULL,hInstance,NULL);
 
    if(hwnd == NULL) {
        MessageBox(NULL"Window Creation Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);
        return 0;
    }
 
    /*
        This is the heart of our program where all input is processed and 
        sent to WndProc. Note that GetMessage blocks code flow until it receives something, so
        this loop will not produce unreasonably high CPU usage
    */
    while(GetMessage(&msg, NULL00> 0) { /* If no error is received... */
        TranslateMessage(&msg); /* Translate key codes to chars if present */
        DispatchMessage(&msg); /* Send it to WndProc */
    }
    return msg.wParam;
}
cs

----------------------------------------------------------------- 기본 코드 --------------------------------------------------

 

 

메세지 처리 과정

 

1.  키보드 마우스 등의 이벤트 발생

 

2. 이벤트를 "윈도우" 시스템이 감지 -> 메세지 큐에 쌓음

 

3. WinMain()함수에서 쌓인 메세지큐에서 메세지를 꺼냄

 

4. 꺼낸 메세지를 해석하여 메세지 처리 함수에 보낸다 (여기서 메세지처리 함수 : WndProc)

 

5. 메세지 처리함수가 메세지를 받아서 반응

 

 

 

 

 

각 코드 해석

 

1. WinMain() 함수

 

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)

 

WINAPI : 윈도우 프로그래밍을 의미 (콘솔 응용프로그램이 아님)

 

hInstance : 운영체제의 커널이 응용 프로그램에 부여한 ID로 메모리에서의 위치

               (프로그램에 커널이 부여한 ID, 메모리에 적재된 많은 응용프로그램을 구분하기 위함)

 

 

lpCmdLine : 명령 라인에서 프로그램 구동시 전달할 문자열 (C에서 main함수에 argv 넣는거랑 같음)

 

iCmdShow : 정숫값으로 윈도우가 화면에 출력될때 형태 정의(아직 안써봐서 모름)

 

 

 

 

2. WNDCLASSEX 구조체

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
typedef struct _WNDCLASSEX{
    UINT    cbSize;                //구조체 크기 
    UINT    style;                //출력 형태 
    WNDPROC    lpfnWndProc;        //프로시저 함수 
    int    cbClsExtra;                //클래스 여분 메모리 
    int    cbWndExtra;                //윈도우 여분 메모리 
    HANDLE    hInstance;            //윈도우 인스턴스 
    HICON    hIcon;                //아이콘 
    HCURSOR    hCursor;            //커서 
    HBRUSH    hbrBackground;        //배경 색 
    LPCTSTR    lpszMenuName;        //메뉴 이름 
    LPCTSTR    lpszClassName;        //클래스 이름 
    HICON    hIconSm;            //작은 아이콘  
};    WNDCLASSEX;
cs

 

lpfnWndProc : 메세지 처리에 사용될 함수 (여기선  wc.lpfnWndProc     = WndProc;)

hCursor : 마우스를 가져다 댔을때 모양 설정

 

(ex : wc.hCursor  = LoadCursor(NULL, IDC_IBEAM);)

 

 

 

 

3. 윈도우 생성

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
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                 //생성 윈도우 정보  
); 
cs

 

 

ex)

hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,"Window Class Name","윈도우 타이틀 이름 ",WS_VISIBLE|WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT0, /* x */
CW_USEDEFAULT, /* y */
CW_USEDEFAULT, /* width */
CW_USEDEFAULT, /* height */
NULL,NULL,hInstance,NULL);

 

 

먼저 내 dev c++에서는 CreateWindow가 아닌 CreateWindowEx를 자동으로 만들어 주는데

CreateWindow의 확장 버전으로 가장 맨앞에 매개변수를 하나 더 받는다 기능이 추가된듯 한데 중요한것 같지 않으니 그냥 넘어가자

 

알아야할 것

 

내 화면에 띄울 윈도우 이름이 lpWindowName이다 

 

윈도우스타일(dwStyle)중에 

WS_OVERLAPPEDWINDOW 옵션은 타이틀바에 최소화 , 최대화, 닫기 버튼이 나타나고 마우스 오른쪽클릭시 나타나는 시스템 메뉴도 지원해주는 형태의 윈도우이다. 유용할 것 같으니 알아두자

(WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXMIZEBOX 와 같다)

 

x,y,width,height값은 숫자로 입력해도 되지만 CW_USEDEFAULT  옵션을 이용해 커널에게 맡기는 방법이 있다.

 

 

 

4. 메세지 처리 함수 : WndProc()

1
2
3
4
5
6
7
LRESULT WndProc(
    HWND hWnd,
    UINT iMsg,
    WPARAM wParam,
    LPARAM lParam
 
);
cs

 

 

함수 반환타입인 LRESULT는 32비트의 값을 알려주는 반환타입이라고 한다.

 

hWND : 생성된 윈도우 핸들 CreateWindow() 함수를 이용해 생성

 

iMsg : UINT 타입은 unsigned int 줄인말이다.

메세지 번호를 의미한다 

 

wParam,lParam : 32비트 값으로 키보드에서 눌린 문자의 코드값이 들어있을수 있고 마우스의 위치가 들어 있을 수도 있다. (상황에 따라 다름)

 

 

ex)

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
    switch(Message) {
        
        /* Upon destruction, tell the main thread to stop */
        case WM_CREATE:
            break
        case WM_DESTROY: {
            PostQuitMessage(0);
            break;
        }
        
        /* All other messages (a lot of them) are processed using default procedures */
        default:
            return DefWindowProc(hwnd, Message, wParam, lParam);
    }
    return 0;
}
cs

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

cf)

책에서는 클래스 name을 지정할때

    wc.lpszClassName = "Window Class Name";가 아닌

    wc.lpszClassName = _T("Window Class Name")을 사용하였는데 프로젝트에서 사용하는 문자집합이 멀티바이트든 유니코드는 상관없이 처리하기 위함이라 한다. 나중에 안되는게 나오면 _T를 쓰자. 

 

( _T 함수는 #include <TCHAR.H> 헤더에 있다.)

 

 

 

 

 

 

 

 

 

출처 : 

 

핵심 API로 배우는 윈도우 프로그래밍,   강경우 지음    출판사 : 한빛아카데미

 

http://soen.kr/lecture/win32api/reference/Function/LoadCursor.htm

 

Win32 API Reference

설명 표준 커서 또는 응용 프로그램의 리소스에 정의되어 있는 커서를 읽어온다. 단, 이미 커서가 로드되어 있을 때는 다시 읽지 않고 읽어 놓은 커서의 핸들을 구해 준다. 만약 lpCursorName 인수가 가리키는 리소스가 커서가 아닌 다른 리소스이더라도 이 함수는 NULL을 리턴하지 않으므로 반드시 커서 리소스만 지정하도록 주의해야 한다. 하나의 커서 리소스에 여러 가지 색상의 커서가 있을 경우 현재 화면 설정에 가장 적합한 커서를 읽어준다.

soen.kr

 

 

+ Recent posts