본문 바로가기
Develop/Win32 API와 게임 엔진

[Win32 API] 초기 소스코드 해석

by Tarra 2023. 5. 4.

 

 

 


개인 공부 후 자료를 남겨놓기 위한 목적이므로,
생략되거나 오류가 있을 수 있음을 알립니다.

 

 


 

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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
// First.cpp : Defines the entry point for the application.
//
 
#include "framework.h"
#include "First.h"
 
#define MAX_LOADSTRING 100
 
// Global Variables:
HINSTANCE hInst;                                // current instance
WCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name
 
// Forward declarations of functions included in this code module:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);
 
// 윈도우즈 프로그램의 시작점.
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                        // 프로그램의 인스턴스 핸들
                        // 주로 제일 많이 사용함 (거의 이것만 씀)
                     _In_opt_ HINSTANCE hPrevInstance,
                        // 바로 앞에 실행된 현재 프로그램의 인스턴스 핸들
                        // 호환성을 위해서만 존재하는 인수이므로 신경쓰지 않아도 됨.
                     _In_ LPWSTR    lpCmdLine,
                        // 명령행으로 입력된 프로그램 인수
                     _In_ int       nCmdShow)
                        // 프로그램이 실행될 형태, 최소화, 보통모양등이 전달된다.
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);
 
    // TODO: Place code here.
 
    // Initialize global strings
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_FIRST, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);
 
    // Perform application initialization:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }
 
    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_FIRST));
 
    MSG msg;
 
    // Main message loop:
    // 윈도우즈 프로그램에서 메세지를 처리하는 부분
    // GetMessage - 시스템이 유지하는 메시지 큐에서 메시지를 읽어들인다.
    // 해당 메시지는 첫번째 인수이 msg 구조체에 저장된다. 프로그램이 종료될 때까지 전체 while 루프가 계속 실행
    while (GetMessage(&msg, nullptr, 00))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            // 키보드 입력 메시지를 가종하여 프로그램에서 쉽게 쓸 수 있도록 해준다.
            // 키보드의 입력이 발생할 때, 문자가 입력되었다는 메시지(WM_CHAR)를 만드는 역할. 
            TranslateMessage(&msg);
            // 시스템 메시지 큐에서 꺼낸 메시지를 프로그램의 메시지 처리 함수(WndProc)로 전달한다.
            // GetMessage를 통해 MSG형의 구조체에 대입하고 이것을 DispatchMessage가 WndProc로 전달한다.
            DispatchMessage(&msg);
        }
    }
 
    // 가장 많이 사용하는 메시지 종류
    // WM_QUIT          프로그램을 끝낼때 발생하는 메시지
    // WM_LBUTTONDOWN   마우스의 좌측 버튼을 누를 경우 발생
    // WM_CHAR          키보드로부터 문자가 입력될 때 발생
    // WM_PAINT         화면을 다시 그려야할 경우 발생
    // WM_DESTROY       윈도우가 메모리에서 파괴될 때 발생
    // WM_CREATE        윈도우가 처음 만들어질 때 발생
 
    // WM_QUIT 메시지로부터 전달된 탈출 코드 (프로그램 종료)
    return (int) msg.wParam;
}
 
 
 
//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
 
// 이런 이런 특성을 가진 윈도우를 앞으로 사용하겠다는 등록 과정이다.
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;
 
    wcex.cbSize = sizeof(WNDCLASSEX);
 
    // 윈도우의 스타일을 정의
    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    // 윈도우의 메세지 처리 함수를 지정 / 거의 WndProc로 정해져 있음.
    wcex.lpfnWndProc    = WndProc;
    // 일종의 예약 영역. 아주 특수한 목적에 사용되는 여분의 공간
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    // 이 윈도우 클래스를 사용하는 프로그램의 번호
    wcex.hInstance      = hInstance;
    // 이 윈도우가 사용할 마우스 커서와 최소화되었을 경우 출력될 아이콘을 지정
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_FIRST));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    // 윈도우의 배경 색상을 지정한다.
    //wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.hbrBackground  = (HBRUSH)(BLACK_BRUSH);
    // 이 프로그램이 사용할 메뉴를 지정한다. / 사용하지 않을 경우 NULL
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_FIRST);
    // 윈도우 클래스의 이름을 정의한다. 윈도우 클래스의 이름은 보통 실행 파일의 이름과 일치시켜 작성한다.
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
 
    return RegisterClassExW(&wcex);
}
 
//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // Store instance handle in our global variable
 
   // MyRegisterClass를 기반으로 createWindowW를 실행.
   HWND hWnd = CreateWindowW(
       // (lpszClassName) 생성하고자 하는 윈도우의 클래스를 지정하는 문자열
       szWindowClass,
       // (lpszWindowName) 윈도우의 타이틀 바에 나타날 문자열이다.
       //szTitle,
       L"My first Win32 API Program",
       // (dwStyle) 만들고자 하는 윈도우의 형태를 지정하는 인수이다.
       // WS_OVERLAPPEDWINDOW를 사용하면 가장 무난한 윈도우 설정 상태가 된다.
       WS_OVERLAPPEDWINDOW,
       // (X, Y, nWidth, nHeight) 윈도우의 크기와 위치를 지정하며 픽셀 단위를 사용한다.
       CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
       // (hWndParnet) 부모 윈도우가 있을 경우 부모윈도우의 핸들을 지정해준다.
       nullptr,
       // (hmenu) 윈도우에서 사용할 메뉴의 핸들을 지정한다.
       // 이 인수로 지정된 메뉴는 현재 CreateWindow 함수를 기반으로 만들어지는 윈도우에서만 사용된다.
       nullptr,
       // (hinst) 윈도우를 만드는 주체, 즉 프로그램의 핸들을 지정한다.
       hInstance,
       // (lpvParam) CREATESTRUCT라는 구조체의 번지이며, 특수한 목적에 사용된다.
       nullptr);
 
   if (!hWnd)
   {
      return FALSE;
   }
 
   // hWnd인수는 화면으로 출력하고자 하는 윈도우의 핸들이다.
   // nCmdShow는 윈도우를 화면에 출력하는 방법을 지정한다.
   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);
 
   return TRUE;
}
 
//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE: Processes messages for the main window.
//
//  WM_COMMAND  - process the application menu
//  WM_PAINT    - Paint the main window
//  WM_DESTROY  - post a quit message and return
//
//
 
// [메시지 처리 함수] / 윈드프록
// 대부분의 실질적인 처리는 여기서 이루어진다.
LRESULT CALLBACK WndProc(
    // 메시지를 받을 윈도우의 핸들
    HWND hWnd, 
    // 어떤 변화가 발생했는가에 대한 정보 / If WM_MOVE라면 윈도우의 위치가 변경되었음을 알림
    UINT message, 
    // message에 따른 부가적인 정보를 가진다.
    WPARAM wParam, LPARAM lParam)
{
 
    // 메시지의 종류에 따라 다중 분기하여 메시지 별로 처리를 진행한다.
    switch (message)
    {
    case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // Parse the menu selections:
            switch (wmId)
            {
            case IDM_ABOUT:
                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                break;
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: Add any drawing code that uses hdc here...
            EndPaint(hWnd, &ps);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        // WndProc에서 처리하지 않은 나머지 메시지에 관한 처리를 해 준다.
        // 예를 들면 시스템 메뉴를 더블 클릭하면 프로그램을 종료하는 등의 기본 기능.
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
 
    // WndProc은 메시지를 처리했을 경우 반드시 0을 리턴해주어야 한다.
    return 0;
}
 
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;
 
    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}
 
cs