Last active
April 17, 2020 22:21
-
-
Save LusainKim/d353a6d7b6a552756499 to your computer and use it in GitHub Desktop.
simple win32api startup code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 유니코드 기반입니다. | |
#include <Windows.h> | |
#include <tchar.h> | |
// LoadString : 타이틀 이름과 윈도우 클래스 이름 길이. | |
#define MAX_LOADSTRING 100 | |
#define CLIENT_WIDTH 1200 // 클라이언트 너비 | |
#define CLIENT_HEIGHT 720 // 클라이언트 높이 | |
#define WINTITLE TEXT("Win32Program") // 클라이언트 타이틀 문자열 | |
#define WINCLASSNAME TEXT("winMain") // 메인 윈도우 클래스명 | |
// 전역 변수: | |
HINSTANCE hInst; // 현재 인스턴스입니다. | |
TCHAR szTitle[MAX_LOADSTRING]; // 제목 표시줄 텍스트입니다. | |
TCHAR szWindowClass[MAX_LOADSTRING]; // 기본 창 클래스 이름입니다. | |
// 이 코드 모듈에 들어 있는 함수의 정방향 선언입니다. | |
ATOM MyRegisterClass(HINSTANCE hInstance); | |
BOOL InitInstance(HINSTANCE, int); | |
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); | |
int APIENTRY _tWinMain( _In_ HINSTANCE hInstance, | |
_In_opt_ HINSTANCE hPrevInstance, | |
_In_ LPTSTR lpCmdLine, | |
_In_ int nCmdShow) | |
{ | |
UNREFERENCED_PARAMETER(hPrevInstance); | |
UNREFERENCED_PARAMETER(lpCmdLine); | |
// TODO: 여기에 코드를 입력합니다. | |
MSG msg; | |
wsprintf(szTitle, WINTITLE); | |
wsprintf(szWindowClass, WINCLASSNAME); | |
// 전역 문자열을 초기화합니다. | |
MyRegisterClass(hInstance); | |
// 응용 프로그램 초기화를 수행합니다. | |
if (!InitInstance(hInstance, nCmdShow)) | |
{ | |
return FALSE; | |
} | |
while (true) | |
{ | |
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) | |
{ | |
if (msg.message == WM_QUIT) break; | |
TranslateMessage(&msg); | |
DispatchMessage(&msg); | |
} | |
} | |
return (int)msg.wParam; | |
} | |
ATOM MyRegisterClass(HINSTANCE hInstance) | |
{ | |
WNDCLASSEX wcex; | |
wcex.cbSize = sizeof(WNDCLASSEX); | |
wcex.style = | |
CS_HREDRAW // 클라이언트의 너비를 변경하면, 전체 윈도우를 다시 그리게 한다. | |
| CS_VREDRAW // 클라이언트의 높이를 변경하면, 전체 윈도우를 다시 그리게 한다. | |
// | CS_DBLCLKS // 해당 윈도우에서 더블클릭을 사용해야 한다면 추가해야 한다. | |
; | |
wcex.lpfnWndProc = WndProc; // 함수포인터로 CALLBACK 함수를 지정. 함수는 HWND, MSG, WPARAM, LPARAM을 매개변수로 가져야만 함. | |
wcex.cbClsExtra = 0; | |
wcex.cbWndExtra = 0; | |
wcex.hInstance = hInstance; // 해당 프로그램의 인스턴스 핸들. | |
// MAKEINTERSOURCE : Make Inter Source. 프로그램 내부에 있는 리소스의 인덱스를 반환하는 매크로. | |
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION)); | |
wcex.hCursor = LoadCursor(NULL, IDC_ARROW); | |
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); | |
wcex.lpszMenuName = NULL; | |
wcex.lpszClassName = szWindowClass; | |
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION)); | |
return RegisterClassEx(&wcex); | |
} | |
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) | |
{ | |
// 메인 윈도우 핸들 | |
HWND hWnd; | |
// 윈도우 스타일 | |
DWORD dwStyle = | |
WS_OVERLAPPED // 디폴트 윈도우. 타이틀 바와 크기 조절이 안되는 경계선을 가진다. 아무런 스타일도 주지 않으면 이 스타일이 적용된다. | |
| WS_CAPTION // 타이틀 바를 가진 윈도우를 만들며 WS_BORDER 스타일을 포함한다. | |
| WS_SYSMENU // 시스템 메뉴를 가진 윈도우를 만든다. | |
| WS_MINIMIZEBOX // 최소화 버튼을 만든다. | |
| WS_BORDER // 단선으로 된 경계선을 만들며 크기 조정은 할 수 없다. | |
// | WS_THICKFRAME // 크기 조정이 가능한 두꺼운 경계선을 가진다. WS_BORDER와 같이 사용할 수 없다. | |
; // 추가로 필요한 윈도우 스타일은 http://www.soen.kr/lecture/win32api/reference/Function/CreateWindow.htm 참고. | |
// 인스턴스 핸들을 전역 변수에 저장 | |
hInst = hInstance; // 인스턴스 핸들을 전역 변수에 저장합니다. | |
// 데스크톱 윈도우 사이즈 | |
RECT getWinSize; | |
GetWindowRect(GetDesktopWindow(), &getWinSize); | |
// 클라이언트 사이즈 | |
RECT rc; | |
rc.left = rc.top = 0; | |
rc.right = CLIENT_WIDTH; | |
rc.bottom = CLIENT_HEIGHT; | |
// 윈도우 사이즈에 실제로 추가되는(캡션, 외곽선 등) 크기를 보정. | |
AdjustWindowRect(&rc, dwStyle, FALSE); | |
// 클라이언트 절대좌표(left, top) | |
// 데스크톱의 중앙에 클라이언트가 위치하도록 설정 | |
POINT ptClientWorld; | |
ptClientWorld.x = (getWinSize.right - CLIENT_WIDTH) / 2; | |
ptClientWorld.y = (getWinSize.bottom - CLIENT_HEIGHT) / 2; | |
// 윈도우 생성 | |
hWnd = CreateWindow( | |
szWindowClass // 윈도우 클래스 명 | |
, szTitle // 캡션 표시 문자열 | |
, dwStyle // 윈도우 스타일 | |
, ptClientWorld.x // 부모 윈도우 기반 윈도우 시작좌표 : x | |
, ptClientWorld.y // 부모 윈도우 기반 윈도우 시작좌표 : y | |
, rc.right - rc.left // 윈도우 사이즈 : width | |
, rc.bottom - rc.top // 윈도우 사이즈 : height | |
, NULL // 부모 윈도우. | |
, NULL // 메뉴 핸들 | |
, hInstance // 인스턴스 핸들 | |
, NULL // 추가 파라메터 : NULL | |
); | |
// 생성 실패시 프로그램 종료 | |
// 확인 : WndProc의 default msg handler가 DefWindowProc 함수를 반환하는가? | |
if (!hWnd) return FALSE; | |
// 윈도우 표시 | |
ShowWindow(hWnd, nCmdShow); | |
UpdateWindow(hWnd); | |
// 성공 반환 | |
return TRUE; | |
} | |
// end base code --------------- | |
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) | |
{ | |
// CALLBACK 함수이기 때문에 한 번 호출된 뒤 다음 호출 시 선언된 변수들은 값이 저장되지 않음. | |
// 해결방법 1 : static 키워드를 사용한다. (권장하지 않음) | |
// 해결방법 2 : 해당 윈도우에서 사용되는 변수들을 관리하는 구조체를 전역으로 만들어 사용한다. | |
PAINTSTRUCT ps; | |
HDC hdc; | |
switch (message) | |
{ | |
#pragma region 초기화 | |
case WM_CREATE: break; | |
#pragma endregion | |
#pragma region 마우스 버튼 클릭 시 호출되는 메시지 | |
case WM_LBUTTONDOWN: break; | |
case WM_RBUTTONDOWN: break; | |
case WM_LBUTTONUP: break; | |
case WM_RBUTTONUP: break; | |
case WM_MOUSEMOVE: break; | |
// 더블클릭은 WNDCLASSEX의 style에 CS_DBLCLKS 을 OR 연산 해야 쓸 수 있다. | |
// case WM_LBUTTONDBLCLK: break; | |
// 클라이언트 밖으로 마우스가 빠져나왔을 때 | |
case WM_MOUSELEAVE: break; | |
// 마우스 휠 버튼 | |
case WM_MBUTTONDOWN: break; | |
// 마우스 휠을 올렸다 내렸다 할 경우. 참고 : https://msdn.microsoft.com/ko-kr/library/windows/desktop/ms645617(v=vs.85).aspx | |
case WM_MOUSEWHEEL: break; | |
#pragma endregion | |
#pragma region 키보드 입력 시 호출되는 메시지 | |
case WM_KEYDOWN: break; | |
case WM_KEYUP: break; | |
case WM_CHAR: break; | |
#pragma endregion | |
#pragma region 랜더링. 그리기 이외의 연산은 절대로 하지 말 것. | |
case WM_PAINT: | |
hdc = BeginPaint(hWnd, &ps); | |
{ | |
// 더블버퍼링을 사용하는 기초적인 코드. 제대로 구현하기 위해서는 최초 한 번만 생성하여 쓰는 게 바람직합니다. | |
HDC memDC = CreateCompatibleDC(hdc); | |
HBITMAP memBit = CreateCompatibleBitmap(hdc, CLIENT_WIDTH, CLIENT_HEIGHT); | |
SelectObject(memDC, memBit); | |
// TODO : memDC를 이용하여 그림을 그립니다. | |
// 초기화 | |
RECT rcClient; | |
rcClient.left = rcClient.top = 0; | |
rcClient.right = CLIENT_WIDTH; | |
rcClient.bottom = CLIENT_HEIGHT; | |
// 테두리 없이 RECT 영역을 해당 색으로 칠해주는 함수 | |
// GetStockObject : 메모리를 할당하지 않고 시스템에 내장된 기본 브러쉬, 펜, 폰트를 사용할 수 있는 함수. | |
FillRect(memDC, &rcClient, (HBRUSH)GetStockObject(WHITE_BRUSH)); | |
TextOut(memDC, CLIENT_WIDTH / 2, CLIENT_HEIGHT / 2, TEXT("Hello, World!"), lstrlen(TEXT("Hello, World!"))); | |
// hdc에 복사 | |
BitBlt(hdc, 0, 0, CLIENT_WIDTH, CLIENT_HEIGHT, memDC, 0, 0, SRCCOPY); | |
DeleteDC(memDC); | |
DeleteObject(memBit); | |
} | |
EndPaint(hWnd, &ps); | |
break; | |
#pragma endregion | |
#pragma region 소멸 시 호출. 윈도우 프로시저를 소멸하고 싶으면 DestroyWindow(hWnd)를 호출. | |
case WM_DESTROY: | |
// 모든 리소스를 해제하고 프로그램을 종료시키는 함수. 일반적으로 메인 윈도우 프로시저에만 호출 할 것. | |
PostQuitMessage(0); | |
break; | |
#pragma endregion | |
// 해당 윈도우 프로시저에서 정의되지 않은 다른 작업들을 처리합니다. | |
// 해당 윈도우 프로시저에서 임의의 작업을 한 뒤 Windows API가 제공하는 기본 동작을 처리하고 싶을 때 호출 할 수도 있습니다. | |
default: return DefWindowProc(hWnd, message, wParam, lParam); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment