목표
Window API를 사용하기 위해서 기본 프로젝트를 생성하는 시간을 갖겠습니다.
목차 클릭하면 해당 목차로 이동합니다.
Windows API의 기본 구조 - 헤더와 전역 변수
개요
이전 게시글에서 WIN32 API의 기본 구조의 이론과 데이터 타입에 대해서 다루었습니다. 이제 본격적으로 시작해보려고 합니다. 대부분의 공부는 처음부터 차근차근 배우는 Bottom-up 방식이었다면, 이번 공부는 전체적인 틀을 먼저 확인하고 분석해나가는 Top-down 방식으로 진행할 예정입니다. 처음에 구조를 잡는 것이 살짝 부담스러웠지만, 첫 고비를 잘 넘긴다면 보다 편한 마음으로 새로운 것을 받아들일 수 있습니다.
따라서, 이번 포스팅에서는 WIN32 API의 기본 구조를 코드로 직접 확인해보도록 하겠습니다.
프로젝트 생성
제가 사용하고 있는 IDE는 Visual Studio 2019입니다. 해당 IDE는 다음 링크에서 다운로드할 수 있습니다.
https://visualstudio.microsoft.com/ko/
먼저, Visual Studio를 켜면 우측에 다음과 같은 메뉴가 있습니다.
맨 하단에 "새 프로젝트 만들기(N)" 버튼이 있습니다.
이것을 선택하면 다음과 같은 화면이 뜨게 됩니다.
그럼 위와 같은 화면이 보일 텐데, "Windows 데스크톱 마법사"를 선택합니다.
보통 C언어를 작성할 때 "빈 프로젝트"로 작성을 많이 하는데 이번에는 WIN32 API를 사용한 애플리케이션을 작성할 예정이므로 위와 같이 선택합니다.(Windows 데스크톱 애플리케이션이 아닙니다!)
"새 프로젝트 구성"이 나올 텐데, 프로젝트와 솔루션의 이름을 작성하고 경로를 확인한 후 만들기를 누르면 "Windows 데스크톱 프로젝트"가 나옵니다. 그럼 다음과 같이 설정하고 확인을 누릅니다.
애플리케이션 종류 : 데스크톱 애플리케이션(.exe)
추가 옵션: 빈 프로젝트
그럼 우리가 알던 것과 동일한 프로젝트가 생성됩니다. 소스파일을 하나 생성해줍니다.
소스파일은 C++ 파일에 .c 확장자로 생성하면 됩니다. 이제 본격적으로 프로그래밍을 시작할 차례입니다!
Windows API의 기본 구조
Windows API의 기본 구조를 코드로 알아보도록 하겠습니다. 큰 틀을 이해하고 이전 포스팅에서 다룬 내용과 연결할 것입니다. 기본적으로 WIN32 API를 활용해 작성된 프로그램은 크게 WinMain, WndProc 함수로 구성됩니다.
헤더(header)
먼저, 헤더 파일을 포함시켜야 합니다. 기본적으로 <windows.h>와 <TCHAR.h> 2개의 헤더를 포함합니다.
<windows.h>
windows.h는 Windows API를 사용하기 위해 포함해야 합니다. windows.h에는 이전 포스팅에서 확인한 다양한 자료형들과 구조체들이 포함되어 있습니다. 위에 얼핏 보이는 HWND, HINSTANCE와 같은 자료형들이 그 예시입니다.
<TCHAR.h>
이름에서 유추해보자면 CHAR니까 문자열과 관련 있는 헤더라고 생각할 수 있습니다. 우리는 앞으로 _T형 문자열을 사용합니다. 이유를 가볍게 짚고 넘어가면, 기존에 사용하던 것들은 아스키 코드(ASCII code)를 사용합니다. 아스키 코드는 문자를 1byte로 표현합니다. 하지만, 한글과 같이 영어권이 아닌 언어들은 2byte로 표현되기 때문에 호환성 문제가 발생할 수 있습니다. 이를 해결하기 위해서 유니코드(Unicode)를 사용하는데, 유니코드는 모든 문자 집합을 지원합니다. 따라서 이를 위해 TCHAR 헤더를 포함합니다. 이와 관련한 내용은 추후 포스팅에서 조금 더 자세히 다루도록 하겠습니다.
WndProc(윈도우 프로시저) 함수
Windows API로 작성된 프로그램에서 가장 중요한 역할을 하는 WndProc(윈도우 프로시저) 함수입니다.
LRESULT CALLBACK WndProc(HWND, UNIT, WPARAM, LPARAM);
WndProc함수 선언문입니다. WndProc은 윈도우 프로시저를 의미합니다. 윈도우 프로시저는 메세지(이벤트)가 발생하면 이 메세지를 전달받아 처리하는 역할을 합니다.
참고 - [Windows API] API, MFC란, 윈도우 프로그래밍 동작 방식
윈도우 프로시저가 메세지를 처리하고 반환할 때는(반환형) LRESULT 타입으로 반환하게 됩니다.
자료형 - LRESULT
RESULT, 결과라는 뜻입니다. 결과는 결과인데 여기에 L을 살짝 곁들인.. 접두사로 L이 붙었다는 것은 long 타입을 의미합니다. 따라서, LRESULT 타입은 Win32 환경에서 메세지 처리를 마친 후 운영체제에 신호를 주기 위한 값(long type)입니다. 윈도우 프로시저가 메세지 처리를 끝냈다고 운영체제에게 알려주는 값입니다. 사실, LRESULT는 long 타입의 새로운 이름일 뿐입니다. 메세지 처리 결과를 알려준다는 것을 조금 더 직관적으로 나타내기 위해서 이런 변수명을 만들었습니다. 여기에 어느 값이 들어갈지는 메세지 처리 결과에 따라 상이합니다. 단순히 -1, 0, 1 등의 숫자가 반환될 수도 있고, 비트 플래그를 통해 운영체제가 확인할 수 있도록 결과를 반환합니다. 여기서, 0을 반환한다는 것은 운영체제는 이 메세지에 관여하지 않고 프로그래머가 직접 처리한다는 의미를 갖습니다. -1을 반환하게 되면 운영체제가 진행하는 작업을 취소한다는 의미를 갖습니다.
출처:https://en.wikipedia.org/wiki/HRESULT
CALLBACK 함수
LRESULT란 반환형 다음에 CALLBACK이라고 적혀있습니다. 이는 Callback function(콜백 함수)를 의미합니다. 간단하게 말하면 콜백 함수는 사용자가 호출하는 함수가 아닌, 특정 트리거(이벤트)에 의해 운영체제가 자동으로 실행하는 함수입니다. 다른 함수의 인자로써 이용되는 함수일 수도 있습니다. 윈도우 프로시저는 메세지가 발생하면 자동으로 실행되어 메세지를 확인해서 그에 맞는 행동을 취합니다.
윈도우 프로시저 함수의 매개변수는 밑에서 함수의 정의 부분에서 알아보도록 하겠습니다.
전역 변수 선언
g_hInst, hWndMain, lpszClass를 전역 변수로 선언한 것을 볼 수 있습니다. 많은 변수 중에 이 3개만 전역 변수로 선언한 데에는 필히 이유가 있습니다. 먼저, 각각의 의미를 알아보도록 하겠습니다.
HINSTANCE g_hInst;
HINSTANCE 타입의 g_hInst입니다. 전 포스팅에서 접두사로 H가 붙으면 Handle(핸들)의 의미를 갖는다고 했습니다.
참고- [Windows API] Win32 API에서 제공하는 자료형(데이터 타입) 모음과 핸들(HANDLE)
g_hInst는 인스턴스의 핸들입니다. 인스턴스라 함은 프로그램에 대한 정보라고 생각할 수 있습니다. 윈도우 프로시저와 같은 다른 함수들에서 프로그램에 대한 정보가 필요할 수 있습니다. 매번 매개변수로 전달하는 것은 비효율적이기 때문에 전역 변수로 생성해서 관리 및 사용할 수 있습니다. 접두사로 붙은 g_는 당연히 global의 약자로, 전역변수로 선언된 인스턴스 핸들을 의미합니다. 이 핸들 인스턴스를 사용하는 것은 잠시 후 WinMain 함수에서 확인할 수 있습니다.
HWND hWndMain;
HWND 타입의 hWndMain입니다. WND는 Window의 약자입니다. 이제는 딱 보면 윈도우의 핸들인 것을 알 수 있습니다. hWndMain은 메인 윈도우의 핸들입니다. 마찬가지로 여러 함수에서 윈도우의 정보가 필요할 수 있기 때문에 전역 변수로 선언해서 관리하는 것입니다.
LPCTSTR lpszClass = _T("Knowlege Pool");
LPCTSTR 타입의 lpszClass에 _T형 문자열 "Knowlege Pool"로 정의했습니다. 우선 데이터 타입 LPCTSTR이 살짝 복잡해 보입니다. 하나하나 뜯어서 보면 간단합니다. LP/C/TSTR로 나눠서 볼 수 있습니다. LP는 Long Pointer를 의미합니다. C는 const를 의미하고, TSTR은 T형 STR, 즉 T형 문자열입니다. T문자열의 long형 포인터를 상수화(const)해서 갖고 있겠다는 것입니다. 이름의 접두사인 lpsz도 포인터로 문자열을 가리킨다는 의미입니다. 예~전 16bit 시절 24bit 메모리를 관리하기 위해서 long pointer를 사용한다고 합니다. 이상하게 이런 디테일이 재밌고 기억에 잘 남더라구요.
어쨌든, lpszClass는 윈도우를 생성하는 클래스를 관리하는 변수입니다. 타이틀바에 출력되는 문자열입니다.
포스팅이 너무 길어지는 관계로 WinMain함수와 WndProc함수는 다음 포스팅에서 이어가도록 하겠습니다.
정리
이번 포스팅에서는 WIN32 프로젝트 생성 방법과 Windows API 프로그램의 기본 구조(헤더와 전역 변수)에 대해서 알아보았습니다.
'개발 > Win32 API Programming' 카테고리의 다른 글
[Windows API] Device Context란?, Win32 API를 활용해 문자열 출력하기 (0) | 2021.12.31 |
---|---|
[Windows API] Win32 API의 기본구조, 윈도우 프로시저 (0) | 2021.12.26 |
[Windows API] Win32 API의 기본구조, WinMain-(2) (0) | 2021.11.05 |
[Windows API] Win32 API에서 제공하는 자료형(데이터 타입) 모음과 핸들(HANDLE) (0) | 2021.10.07 |
[Windows API] API, MFC란, 윈도우 프로그래밍 동작 방식 (1) | 2021.09.28 |