개발하는 리프터 꽃게맨입니다.

[WinAPI] 01. Windows 데스크톱 어플리케이션 메인 분석 본문

Window API

[WinAPI] 01. Windows 데스크톱 어플리케이션 메인 분석

파워꽃게맨 2024. 1. 30. 23:35

 

Windows 데스크톱 어플리케이션을 실행하면 위와같은 파일이 자동 생성됩니다.

콘솔 앱과는 사뭇다른 모습이고 처음보는 함수들이 난무합니다.

심지어 main도 안보이구요.

 

어쨌든 이 구조가 기본 window 프로그램을 만들기위한 프레임워크입니다.

 

위에서부터 천천히 분석해보도록 하겠습니다.

 

 

 

전역변수들을 볼 수 있습니다.

WCHAR은 그냥 2바이트 char 자료형을 재정의한 것 입니다.

 

HINSTANCE 는 프로그램의 HANDLE을 의미합니다.

윈도우 운영체제에서 실행되는 프로그램을 구별하기위한 ID값인데,

HINSTANCE는 Win32 프로그램이 메모리 상에 올라가있는 시작 주소 값을 저장하는 자료형입니다.

즉, HINSTANCE (핸들 인스턴스) 는 내 프로그램의 시작 주소라고 볼 수 있죠

 

즉, hInst는 우리 프로그램이 메모리 상에 올라가서 자리를 차지할텐데

그 시작주소를 가지는 변수라고 할 수 있죠.

매우 중요한 녀석입니다.

 

 

 

얘네들은 함수의 전방선언입니다.

 

 

 

wWinMain은 익히 알고있는 main함수입니다.

인자로 hInstancec, hPrevInstance, ... 등 여러가지 받아주고 있는데요

hInstance 는 메모리에 로드될 실행 파일의 시작 주소를 뜻합니다.

hPrevInstance는 의미없습니다. (실제로 msdn에 의미없다고 나와있습니다.)

lpCmdLine 명령행으로 입력된 프로그램 인수를 뜻합니다.

nCmdShow 프로그램이 실행될 형태이며, 최소화, 보통모양 등이 전달됩니다.

 

인자 앞에 _In_, _In_opt_ 등 적혀있는 것은

아무런 의미를 가지지 않는 주석과 같은 겁니다.

이런 것들은 SAL이라고 부릅니다.

 

사실 다 알 필요는 없습니다.

개발할 때 그렇게 필요한 정보인지는 모르겠네요.

 

아래 UNREFERENCE_.... 이것들은 무시해도 되는 녀석들입니다. 

의미없는 값이에요.

 

F12 타고 들어가보면 진짜 아무의미가 없다는 것을 알 수 있습니다.

 

 

그 다음 LoadString 에 대해서 알아봅니다.

문자열 리소스를 buffer에 로드하는 함수입니다.

 

 

윈도우 리소스 스트링 테이블에 가면

이렇게 IDS_APP_TITLE, IDC_WINDOWAPISTUDY 등... 존재하는데

캡션에 있는 값을 긁어와서 szTitle, szWindowClass 등의 버퍼에

MAX_LOADSTRING 만큼 읽어와서 저장하는 역할을 합니다.

 

다음 MyRegisterCalss 함수를 호출합니다.

 

 

이 코드는 내 Instance 를 윈도우에 등록하는 역할을 합니다.

초기 프로그램의 색상, 사이즈, 아이콘 등등을 설정합니다.

매개변수로 처음에 전역변수로 선언한 핸들인스턴스를 전달해주어

핸들인스턴스를 초기화 및 등록합니다.

 

 

즉 이 프로그램을 윈도우에 올리는 역할을 한다고 이해하시면 되겠습니다.

 

 

이 함수는 어플리케이션에 대한 초기화를 수행한 다음

윈도우를 생성하는 역할을 합니다.

 

 

hWnd 를 정의하는 모습을 보여주는데

이는 핸들윈도우라고 부르는 것입니다.

 

핸들윈도우는 윈도우의 핸들 번호를 저장하는 역할을 합니다.

 

핸들윈도우랑 핸들인스턴스의 차이에 대해서 알아보자면,

 

우리가 메모장을 띄우면 2개 3개 띄울 수 있죠?

근데 메모장은 같은 프로그램이지만

각각의 메모장은 다른 윈도우로 관리되지 않습니까?

핸들윈도우는 같은 프로그램 내에서 1개 이상의 윈도우를 식별하는데 사용되는 식별자입니다.

핸들인스턴스는 한 프로그램이 메모리에 올려진 시작 주소를 뜻하며, 메모장이 2~3개 띄워져 있어도 이들은 모두 동일한

핸들 인스턴스를 가집니다.

물론 다른 핸들 윈도우 값을 가지면서 말이죠!

 

CreateWindowW 라는 함수가 핸들윈도우를 만들어서 반환하는 함수입니다.

 

 

핸들 인스턴스를 토대로 핸들 윈도우가 정의됩니다.

 

 

 

이 부분은 단축키 파트입니다.

 

 

IDC_WINDOWAPISTUDY에 있는 Accelerator 단축키 정보를 가져와서 핸들 인스턴스에 등록합니다.

단축키 정보를 등록한다라고 이해하시면 되겠습니다.

 

 

마지막으로 메시지 루프입니다.

 

우리 프로세스에는 메시지 큐라는 것이 있습니다.

프로세스에 요청이 발생했을 때 요청(메시지)들은 메시지 큐에 저장됩니다.

프로세스는 메시지 큐에서 메시지를 꺼내서 요청을 처리합니다.

 

그래서 GetMessage 는

메시지 큐에 있는 메시지들을 확인하면서

메시지의 종류에 따라 로직을 처리해주는 역할을 합니다.

 

메시지 정보는 msg 에 전달합니다.

 

그리고 msg를 translatemessage, dispatchmessage 등의 함수로 해석해서

적절한 핸들러를 연결합니다.

 

이런 메시지는

 

 

내부 프로시저 함수에서 처리하게 됩니다.

보면 메시지를 해석해서, case에 따라서 적절한 처리를 해주는 것을 볼 수 있습니다.

 

 

 

자 다시 돌아와서

 

GetMessage 함수에 대해서 보겠습니다.

 

 

메시지 큐에서 메시지를 검색하고, 메시지가 반환되기 전까지 반환을 하지 않고 가만히 기다립니다.

즉 true가 반환되거나 메시지 반환전까지 대기하는 시간 동안 프로그램이 끝나지 않는다는 의미이죠.

 

만약 message 가 WM_QUIT 이라면 false 를 반환하고 while 루프는 끝나게 됩니다.

WM_QUIT 메시지는 윈도우를 X키를 눌러서 먼저 해제되어야할 메시지가 전부 해제가 된 뒤 반환됩니다.

즉, 안전하게 종료시키는 느낌이죠.

 

윈도우는 설명했던 것과 같이 메시지에 반응하는 형식으로 돌아갑니다.

 

그런데 만약 게임루프를 만들다고 해봅시다.

게임루프의 경우 아무런 메시지가 없더라도 while루프를 계속돌면서 업데이트 및 렌더링을 해야합니다.

그런데 GetMessage 함수의 경우 메시지가 없을 경우 메시지가 발견될 때까지 기다리고,

메시지가 있을 경우에만 while 내부 루프가 돌아갑니다.

 

즉, 게임에 사용하기에는 부적절한 것이죠.

 

게임 루프를 돌리기 위해서는 PeekMessage 함수를 사용해야만 합니다.

이 부분에 대해서는 다음 포스팅에 다뤄보도록 하겠습니다.