Skip to content

Instantly share code, notes, and snippets.

@LusainKim
Last active April 17, 2020 22:21
Show Gist options
  • Save LusainKim/d353a6d7b6a552756499 to your computer and use it in GitHub Desktop.
Save LusainKim/d353a6d7b6a552756499 to your computer and use it in GitHub Desktop.
simple win32api startup code
// 유니코드 기반입니다.
#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