이 글에서는 win32 api 기본.cpp의 문법들을 정리한다.
1. 전방 선언 파트
// 전역 변수 부분
1.1. HINSTANCE
HINSTANCE를 ctrl + 더블 클릭하여 정의 하는 구문을 살펴보면 다음과 같다.
DECLARE_HANDLE(HINSTANCE);
한번 더 ctrl + 더블 클릭 하면
#define DECLARE_HANDLE(name) struct name##__{int unused;}; typedef struct name##__ *name
int unused라는 변수 하나를 가진 구조체가 나온다.
-> HINSTANCE 자료형은 정수 변수 하나를 저장하기 위한 구조체
-> 윈도우는 여기에 id를 저장하고 사용자 는 이 id 를 활용하여 핸들링이 가능하다.
즉 HINSTANCE hInst; 는 윈도우즈에서 실행되고 있는 프로그램을 구분하기 위한 ID
( 핸들링이란? )
1.2. WCHAR
Wide Character : 2byte 문자 자료형
szTitle : 타이틀 바에 적힐 문자열
szWindowClass : 윈도우의 키값으로 사용될 문자열
1.3. MyRegisterClass()
사용자가 사용할 윈도우의 정보를 등록하는 함수.
1.4. InitInstance()
윈도우의 ID를 생성하고, 이 값으로 위도우를 띄움
1.5. WndProc()
메시지 큐에 들어온 메세지의 종류에 따라 처리하는 함수.
1.6. About()
메뉴바의 도움말, 혹은 alt + / 를 누르면 나오는 정보창에 관한 함수
1.7. 코드 중간 중간의 보라색 글씨는 SAL(Source code Annotation Language)이다.
윈도우에서 자주쓰는 프로그램 방식으로 인자가 하는 역할에 대해서 설명한다.
주석 언어, 주석 문법 이라고 부른다.
1.8. 커널 객체(kernal Object)
메모리를 갖는 개체이지만 사용자가 접근할 수 없고 OS 가 관리하는 개체. ( ex. HWND hWnd)
unused 라는 int 형 변수가 하나 들어있는 구조체이다.
이를 자료형 이름을 문자로 하여 컴파일러가 자료형을 확인하고 실수를 체크할 수 있게 한다.
2. wWinMain ( 메인함수(시작함수))
2.0 역할
WndClass 정의 -> WndClass 등록 -> 윈도우 생성 -> 윈도우 출력 -> 메세지 루프
- WndClass 정의
WndClass : 윈도우 클래스(윈도우의 기반이 되는 클래스), 윈도우 클래스 정의란 - 만들고자 하는 윈도우의 속성을 정의하는 것을 의미.
- WndClass 등록
커널에 등록. 운영체제가 윈도우 클래스 를 인지할 수 있도록 등록하는 과정을 거치는 것.
- 윈도우 생성
윈도우 클래스가 커널에 등록되면 메모리에 윈도우 클래스를 올릴 수 있다. 메모리에 윈도우를 만드는 것을 " 윈도우 생성 " 이라 한다.
- 윈도우 출력
시각화 (화면에 출력)하는 것도 WinMain의 역할
- 메세지 루프
프로그램이 시작되면 여러가지 메시지(이벤트)가 발생된다. 메세지가 언제 들어올지 모르기 때문에 컴퓨터는 메세지 루프를돌면서 메세지가 발생하는 것을 기다린다. WinMain에서 메세지가 발생할 떄까지 메세지 루프를 돌다가 메세지가 발생하면 해당 메세지를 메세지 전용 함수(윈도우 프로시저, WndProc)로 메세지를 전달한다.
2.1 매개변수
- _IN_ HINSTANCE hInstance : 이 프로그램의 instance 핸들 값이 전달된다. hInstance : 현재 프로그램의 ID.
- _IN_opt_HINSTANCE hPrevInstance : 이전 프로그램의 Id를 나타내는 것으로 현재 사용되지 않고 있으며 따라서 항상 null이다.
- _IN_ LPWSTR lpCmdLine : 커맨드 라인 쉘에서 전달받은 인자. main 함수의 argc, argv 인자처럼 실행 인자가 전달된다. 하지만 main 함수처럼 인자들이 배열로 하나씩 나누어 져서 전달되는 것이 아니라 하나의 문자열로 전달된다. 또한 실행파일을 포함하지 않는다.
- _IN_ int nCmdShow : 응용프로그램의 초기 시작 형식이 전달.
2.2 함수 소스 구성
- UNREFERENCES_PARAMETER() : 참조 되지 않은 매개변수로 쓰일 일이 없다.
- LoadStringW() : wchar_t*를 인자로 받아서 해당 시작 주소에 문자열 복사. StringTable 문자열을 전역배열에서 불러온다.
-> hInstance : 문자열 리소스를 가진 인스턴스 핸들.
-> uId : 일어올 문자열의 ID.
-> IpBuffer : 문자열을 읽을 버퍼 (cchBufferMax 가 0이 아닌 경우)또는 문자열 리소스 자체에 대한 읽기 전용 포인터(cchBufferMax 가 0인 경우).
-> cchBufferMax : 버퍼의 크기(문자)이다. 지정된 문자 수보다 길면 문자여링 잘리고 null로 종료된다. 이 매개변수가 0이면 IpBuffer 는 문자열 리소스 자체에 대한 읽기 전용 포인터를 받는다.
-> IDS_APP_TITLE 은 리소스 헤더에 int 형으로 103으로 정의되어 string table에 선언되어 있다. 현재 어플리 케이션의 이름이다.
-> 반환값 : 종료 null 문자를 포함하지 않고 버퍼에 복사된 문자 수.
2.3 MyRegisterClass();
프로그램이 가질 윈도우의 기본 (세팅)를 등록하는 함수.
2.4 LoadAccelerators()
윈도우의 단축키 테이블을 작성하는 함수.
2.5 MSG msg;
메시지 큐에서 꺼낸 메세지를 담을 그릇 준비
다음은 MSG의 선언 부분
typedef struct tagMSG {
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
#ifdef _MAC
DWORD lPrivate;
#endif
} MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG;
2.6 while(GetMessage())
프로그램의 메세지 루프 시작 부분
- GetMessage() : 포커싱된 윈도우 쪽에서 발생한 메세지를 꺼내서 msg에 적어주는 함수. (프로세스에 발생한 메시지를 메세지 큐에서 꺼내온다.)
GetMessage의 return 조건 : 메시지 큐에 메시지가 존재하면 반환한다. 이때 발생한 메제시가 (msg.message == WM_QUIT)이면 return false 아니면 return true;
- 순서 : 메시지 큐에서 메시지를 꺼낸다 -> 꺼낸 메시지 msg 에 채운다.-> 꺼내본 메시지가 WM_QUIT이면 return false 로 while 문 종료 즉 프로그램 종료. WM_QUIT가 아니면 return true 로 GetMessage 종료.
- TranslateAccelerator() : 단축키 관련 메세지 인지 확인하고 처리
- TranslateMessage() : msg 를 분석해서 문자 메시지로 변환
- DispatchMessage() : 읽은 메시지를 윈도우 프로시져로 발송하는 역할
하나의 메시지는 위의 세가지 함수를 거치며 최종적으로 윈도우 프로시져에 의해 처리된다.
- PeekMessage() : getmessage 함수와 마찬가지로 메시지를 메시지 큐에서 꺼내오는 함수 첫번째 인자로 MSG 구조체를 받으며 메세지 큐로부터 얻은 메세지 값을 MSG 구조체에 저장한다.
PeekMessage는 GetMessage 와 리턴 조건이 다르다. peek(훔쳐보다)라는 단어 그대로 메세지 큐를 훑고 메세지 큐에 메시지가 존재하면 true, 존재하지 않으면 false 를 반환한다. 또한 PeekMessage 는 작업한(MSG 구조체에 저장한) 메시지를 메시지 큐에서 삭제하는 마지막 인자(PM_REMOVE)를 가진다. PeekMessage 는 메시지 큐에 메시지가 없으면 무작정기다리는 GetMessage 와 다르게 메시지가 없으면 false를 반환하기에 while()의 조건문에 넣을 수 없다. 메시지가 없다고 프로그램이 끝나버리기 때문.
따라서 while(true){ if(PeekMessage(){ } ) } 의 구조를 취해야 한다.
자세히 하면 다음과 같다.
while (true)
{
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
if (WM_QUIT == msd.message)
{
break;
}
else
{
// 메시지가 존재하고 WM_QUIT가 아닐때 메세지 번역 및 메세지 처리 함수로 전송
}
}
else
{
// 메시지 큐가 비었다면 실행할 코드
}
}
3. MyRegisterClass()
윈도우 생성 정보를 담고 있다.
- style : 작업 영역이 바뀔때마다 다시 그리게끔 설정. 윈도우의 형태를 지정한다 | (or) 을 사용해 여러개를 지정
- lpfnWndProc : 윈도우에 발생한 메시지를 처리할 함수 포인터.
- cbClsExtra & cbWndExtra : 특수한 목적으로 사용하는 윈도우 예약 영역. 사용하지 않을 때는 0으로 지정.
- hInstance : 해당 윈도우 클래스를 등록하는 대상 프로그램의 번호(ID).
- hIcon : 실행파일이 만들어질때 사용할 아이콘 이미지를 지정.
- hCursor : 윈도우가 사용한 커서 지정.
- hbrBackground : 윈도우 배경색상을 정한다. 배경 색상을 브러쉬로 칠하기 때문에 br 이란 접두사가 붙는다.
- lpszMenuName : 메뉴바 관련 ( lpszMenuName = nullptr; 이면 메뉴바가 사라짐 ). 만들어질 프로그램이 사용할 메뉴를 지정.
- lpszClassName : 윈도우 클래스의 이름을 정의.
- hIconSm : 16 * 16의 작은 아이콘 핸들
- RegisterClassExW(&wcex); : 윈도우즈 제공 함수. 위에서 채운 wcex를 전달함 .
4. InitInstance()
인스턴스 핸들을 전역변수에 저장하고 주 프로그램 창을 만든 다음 표시한다.
- hInst : 현재 프로그램의 ID를 전역변수에 저장. 다른 함수에서도 사용하기 때문이다.
- createWindowW() : 윈도우 ID(핸들)를 생성하는 함수. 실재로 창이 만들어 지는 시점이다.
-> 인자 :
lpClassName : 생성하는 윈도우 클래스를 지정하는 문자열.
lpWindowName : 생성되는 윈도우의 타이틀 바에 나타나는 문자열.
dwStyle : 윈도우의 형태를 지정. WS_OVERLAPPEDWINDOW 는 메모장과 유사한 형태의 가낭 무난한 윈도우 스타일. 접두사로 WS_가 붙으면 윈도우 스타일을 뜻한다.
x, y, nWidth, nHeight : 윈도우의 좌표와 너비 및 높이. CW_USEDEFAULT는 운영체제 판단하에 임의 출력.
hWndParent : 생성되는 윈도우의 부모 윈도우.
hMenu : 윈도우에서 사용할 메뉴의 핸들. nullptr 이면 윈도우 클래스의 속성을 정의할 때 정한 메뉴를 사용하는 것.
hInst : 윈도우를 만들어주는 주체인 프로그램의 핸들.
lpParam : CREATESTRUCT라는 구조체의 주소, 특별한 목적이 있을 때 사용. 보통은 nullptr.
-> szTitle : 창 타이틀, 이 자리에 문자열로 써 넣어도 그대로 창 이름으로 출력된다.
-> szWindowClass : 선언된 윈도우 클래스를 찾기 위한 클래스로 위 MyRegisterClass 구조체의 lpszClassName 과 같다.
- SetWindowPos() : 창의 처음의 크기를 정하는 함수.
- ShowWindow() : 윈도우를 화면에 보여줌.
- UpdateWindow() : 갱신할 무문이 있다면 갱신하라는 명령을 내린다.
5. WndProc()
메시지에 대한 처리 부분. WinMain은 윈도우 창을 만드는 역할이고 WndProc은 그 창안에서 발생하는 메시지를 처리한다.
-> WinMain 함수에서 메세지 루프를 통해서 발생한 메세지를 큐에 저장한다. 해당 메세지를 처리하기 위해서 메세지 처리 전용 함수( 윈도우 프로시저 )로 전달되어야 한다.
- 특징
WinMain에서 호출하는 것이 아닌, 윈도우에 의해서 호출된다.
WinMain 내에 존재하는 메세지 루프는 메세지 처리 전용 함수로 전달하는 역할만 한다.
윈도우 프로시저는 메세지가 들어오면 호출되며, 메세지에 맞게 내용을 처리한다.
콜백함수이다.
- 인수
HWND hWnd : 메세지를 받을 윈도우의 핸들
UNIT message : 받은 메세지
WPARAM wParam 과 LPARAM lParam : 메세지에 따른 부가 정보(마우스가 이동하는 이벤트가 발생하면 마우서의 x, y 좌표 정보와 같은 것들).
- WM_COMMAND : 프로그램의 메뉴바의 상호작용을 처리한다.
- WM_PAINT : 메인 윈도우의 작업 영역을 그린다.
작업영역의 좌상단은 (0,0)이다. 단위는 pixel 이다.
- WM_DESTROY : 종료 메시지를 게시하고 반환한다.
자료형 - LRESULT
접두사로 L이 붙었다는 것은 long 타입을 의미한다. 따라서 LRESULT 타입은 Win32 환경에서 메세지 처리를 마친 후 운영체제에 신호를 주기 위한 값(long type)이다. -> 윈도우 프리시저가 메세지 처리를 끝냈다고 운영체제에게 알려주는 값.
메세지 처리 결과에 따라 단순히 숫자가 반환될 수도 있고, 비트 플래그를 통해 운영체제가 확인할 수 있도록 결과를 반환, 이때 0을 반환한다는 것은 운영체제는 이 메세제에 관여 않고 프로그래머가 직접 처리하겠다는 의리를 갖는다. -1을 반환하면 운영체제가 진행하는 작업을 취소한다는 의미를 갖는다.
CALLBACK 함수
콜백함수는 사용자가 호출하는 함수가 아닌, 특정 트리거(이벤트)에 의해 운영체제가 자동으로 실행하는 함수.
* 메시지의 흐름
메시지큐 -> GetMessage가 메시지를 가져온다 -> TranslateMessage가 메세지를 번역한다 -> DispatchMessage가 메시지를 WndProc에 전달한다. -> WndProc에서 그 메시지에 대한 처리를 한다.
'assortrock > Win32 API' 카테고리의 다른 글
Win32 API - 키보드 입력 (0) | 2022.07.05 |
---|---|
Win32 API - 메세지 박스 출력 (0) | 2022.07.04 |
Win32 API - 도형 출력 (0) | 2022.07.04 |
Win32 API - DC (Device Context) (0) | 2022.07.04 |
Win32 API 배경 지식 - 핸들(Handle) (0) | 2022.06.30 |