Win32 API 2강. 프로그래밍 구조
목차
1. Win32 API 프로그래밍 구조
2. 프로젝트 생성과 문자집합에 대해
3. 윈도우 프로그래밍 기본 함수
4. WinMain() 작성 순서
5. WndProc() 작성 순서
6. 자동생성 코드 생성과 분석
7. 정리
1. Win32 API 프로그래밍 구조
WinMain()
▩ 역할
- 윈도우 구조체 등록, 생성
- 메시지 루프 : 메시지 체크와 전달
▩ WinMain() 구조
WinMain()
{
윈도우 구조체 설정 및 등록
윈도우 생성과 출력
메시지 루프
}
WinProc() 윈도우 프로시져
▩ 역할
- 메시지 처리
- 메시지의 실체?
WM_xxx, CB_xxx, LM_xxx, PBM_xxx 등
-> 모두 양의 정수값 이다.
WinProc() 구조
▩ 구조
WinProc()
{
switch(message)
{
case 메시지1 :
break;
case 메시지2 :
break;
default :
DefWndProc(); 예외적인 메시지를 모두 처리
}
메시지 전달과 처리 과정
▩ 메시지 루프와 WndProc()
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg); WinProc()함수에 메시지 전달과 호출
}
2. 프로젝트 생성과 문자집합
- win32 빈 프로젝트를 생성하기.
- 프로젝트 속성 -> 구성 속성 -> 고급 -> '멀티바이트 문자 집합'으로 설정하기.
문자 집합
▩ 멀티바이트
- 1~2 Byte크기의 문자집합
- 영문 한글 지원
- 일반 c 함수는 MBCS문집합 사용
▩ 유니코드 문자 집합
- 2Byte 크기의 문자집합
- 속도가 멀티바이트에 비해 빠름
- 아스키코드 값의 일부는 유니코드
▩ 문자와 문자열 예
▩ ASCII 문자열을 유니코드로 변환 매크로 함수
- LPTSTR str = TEXT("문자열")
3. 윈도우 프로그래밍 기본 함수
WinMain()함수의 원형
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd
);
#define WINAPI __stdcall
-hInstance
-hPrevInstance : 항상 0
-lpCmdLine : 프로그램 외부에서 내부로 값 설정
- nCmdShow : 윈도우 출력 형태에 관한 값
★ hInstance 만 사용
WndProc() 함수의 원형
LRESULT Wndproc(
HWND unnamedParam1,
UINT unnamedParam2,
WPARAM unnamedParam3,
LPARAM unnamedParam4
)
{...}
참고
- WinDef.h
#define CALLBACK __stdcall
typedef LONG_PTR LRESULT;
typedef long LONG_PTR
typedef unsigned int UINT;
typedef UINT_PTR WPARAM;
typedef unsigned int UINT_PTR;
typedef LONG_PTR LPARAM;
4. WinMain() 작성 순서
WinMain() 1단계
▩ 윈도우 구조체 설정
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX); 구조체의 크기
wcex.style = CS_HREDRAW | CS_VREDRAW; 윈도우 이동 또는 크기가 가로세로 변할 때 윈도우 그리기
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance,
MAKEINTRESOURCE(IDI_APPLICATION)); 기본 큰 아이콘
wcex.hCursor = LoadCursor(NULL, IDI_APPLICATION); 기본 커서
wcex.hbrBackground =
(HBRUSH)(COLOR_WINDOW + 1); 흰색 바탕화면
wcex.lpszMenuName = NULL; 메뉴 이름
wcex.lpszClassName = "basic"; 생성할 윈도우의 이름
wcex.hIconSm = LoadIcon(wcex.hInstance,
MAKEINTRESOURCE(IDI_APPLICATION)); 기본 작은 아이콘
MAKEINTRESOURCE() -> BMSC
#define MAKEINTRESOURCEA(i) ((LPSTR)((ULONG_PTR)((WORD)(i))))
WinMain() 2단계
▩ 구조체 등록
ATOM WINAPI RegisterClassEx(const WNDCLASSEX *lpwcx)
WinMain() 3단계
▩ 윈도우 생성
void CreateWindowA(
LPCTSTR lpClassName, //구조체명
LPCTSTR lpWindowName, //타이틀바
DWORD dwStyle, //윈도우 형태
int x, //출력 좌표x
int y, //출력 좌표y
int nWidth, //윈도우 가로길이
int nHeight, //윈도우 세로길이
HWND hWndParent, //부모 윈도우
HMENU hMenu, //메뉴바 핸들
HINSTANCE hInstance, //인스턴스
LPVOID lpParam //여분,NULL로 채움
);
dwStyle(윈도우 형태)은 msdn문서를 참고 https://docs.microsoft.com/en-us/windows/win32/winmsg/window-styles\
Window Styles (Winuser.h) - Win32 apps
The following are the window styles. After the window has been created, these styles cannot be modified, except as noted.
docs.microsoft.com
WinMain() 4단계
▩ 윈도우 출력
ShowWindow(hWnd, nShowCmd);
UpdateWindow(hWnd); // WM_PAINT 메시지 발생
또는
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd); // WM_PAINT 메시지 발생
WinMain() 5단계
▩ 메시지 루프를 구성하는 함수
BOOL GetMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax);
BOOL TranslateMessage(const MSG * lpMsg);
LRESULT DispatchMessage(const MSG * lpMsg);
WinMain() 5단계 : 메시지 루프
▩ MSG 구조체
typedef struct {
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
}MSG, *PMSG;
▩ GetMesage()
- 메시지 큐에 메시지를 가져오는 역할
- WM_QUIT가 발생할 때만 FALSE 리턴 그 외에는 TRUE 리턴
=> WM_QUIT가 발생할 때까지 대기
▩ TranslateMessage()
- 문자 키 또는 키 입력에 대한 메시지 변환
- WM_KEYDOWN => WM_CHAR
▩ DispatchMessage()
- WndProc() 함수 호출
- WndProc()가 종료될 때까지 대기
- WndProc()로 메시지 전달
5. WndProc() 작성 순서
WndProc() 기본 메시지
▩ WM_PAINT
- 최초 UpdateWIndow() 함수에 의해 발생
- 윈도우의 일부 영역을 새로 출력할 때 발생(윈도우 운영체제에서 발생)
▩ WM_DESTORY
- 윈도우가 화면에서 사라진 후에 보내지는 메시지
- 에 발생 함.
- 메모리에서 제거되기(WM_QUIT) 직전에 보내짐
WndProc() 기본 구조
LRESULT CALLBACK WndProc(
HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
switch (message)
{
case WM_PAINT:
break;
case WM_DESTROY:
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
WndProc() 1단계
▩ WM_PAINT : 화면 출력
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps); 화면 그리기 준비
EndPaint(hWnd, &ps); 화면 그리기 종료
break;
▩ PAINTSTRUCT 원형
typedef struct tagPAINTSTRUCT {
HDC hdc; // 화면 DC
BOOL fErase; // 배경 지우기
RECT rcPaint; // 출력할 클라이언트 영역
BOOL fRestore; // 예약
BOOL fIncUpdate; // 예약
BYTE rgbReserved[32]; // 예약
} PAINTSTRUCT, *PPAINTSTRUCT, *NPPAINTSTRUCT, *LPPAINTSTRUCT;
▩ WM_DESTROY 메시지 처리
case WM_DESTROY:
PostQuitMessage(0); 메모리 해제 관련코드, WM_QUIT발생
break;
WinMain과 WinProc 종합코드
main.cpp
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd)
{
// 윈도우 구조체 생성
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance,
MAKEINTRESOURCE(IDI_APPLICATION));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground =
(HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = "basic";
wcex.hIconSm = LoadIcon(wcex.hInstance,
MAKEINTRESOURCE(IDI_APPLICATION));
// 구조체 등록
RegisterClassEx(&wcex);
// 윈도우 생성
HWND hWnd = CreateWindow("basic", "HelloWorld",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
800, 600, NULL, NULL,
hInstance, NULL);
// 윈도우 화면에 출력
ShowWindow(hWnd, nShowCmd);
UpdateWindow(hWnd);
// 메시지 루프
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessageA(&msg);
}
return 0;
}
LRESULT CALLBACK WndProc(
HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
실행화면.
6. 자동생성 코드
프로그램을 작성할 때 마다 위의 WinMain, WinProc에 관련된 함수들을 작성하는 것은 매우 번거로운 일이다.
그래서 Visual Studio에서 win32 프로그램을 프로젝트에서 생성할 때 위의 모든 코드들을 자동생성 할 수 있다.
참고로, Visual Studio 2022이다.
위 사진과 같은 코드가 자동으로 생성되며 실행하면 윈도우 창이 출력된다.
실행화면.
세부적으로 윈도우의 생성, 등록, 출력 등의 코드는 다르지만 전체적인 흐름은 비슷하다.