Windows
Windows라는 제품명과 같이 Windows용 응용 프로그램을 프로그래밍할 때 주된 주제 하나는 '창(Window)'을 만들고 관리하는 것이다. windows 응용 프로그램의 여러 구성요소, [주 창, 도구 모음, 메뉴, 스크롤바, 버튼, 기타 대화상자 컨트롤]은 모두 창이다. 따라서 windows 응용 프로그램은 일반적으로 다수의 창으로 구성된다.
1. 자원
Windows에서는 여러 개의 응용 프로그램이 동시에 실행될 수 있다. 따라서 CPU나 메모리, 모니터 화면 같은 하드웨어 자원들을 여러 응용 프로그램이 공유해야 한다.
그렇게 되면 여러 응용 프로그램이 자원(Resource)에 무질서하게 접근하게 된다. 이를 막기 위해 windows는 응용 프로그램이 하드웨어에 직접 접근을 못하게 막는다.
windows는 현재 인스턴스화되어 있는 응용 프로그램들을 관리하고 자원을 그 응용 프로그램들에 적절히 분배하는 것이다. 응용 프로그램의 관점에서 이는, 응용 프로그램이 실행 중인 다른 응용 프로그램들에 영향을 미칠 수 있는 어떤 작업을 수행하려면 반드시 windows를 거쳐야한다.
응용 프로그램이 직접 비디오 메모리에 뭔가 기록할 수 없다.
2. 사건, 메시지 대기열, 메시지, 메시지 루프
Windows 응용 프로그램은 사건 주도적 프로그래밍 모형(event - driven programming model)을 따른다. 사건[키 클릭, 마우스 클릭, 마우스 휠 움직임 등등 .. ]이 발생하면 그에 반응해서 작업을 진행한다.
사건이 발생하면 window는 메시지(message)를 보낸다. 그 메시지는 메시지 대기열(message queue/ 우선순위 대기열(priority queue))에 추가된다. 이러한 메시지는 메시지 루프(message loop)를 돌리면서 새로운 메시지가 있는지 검사한다.
새로운 메시지가 있으면 그 메시지에 연관되는 창과 연관된 창 프로시저(window procedure)에 메시지를 넘겨준다.
창 프로시저는 특정 메시지에 반응해서 실행되는 코드를 담는 함수로 개발자가 구현해야 한다. 창이 직접 처리하지 않는 메시지들은 기본 창 프로시저(default window procedure)로 넘겨주어서 거기에서 처리하게 된다.
win32 api는 dewindowproc이라는 이름의 기본 창 프로시저를 제공한다.
3. 그래픽 사용자 인터페이스 (GUI/ Graphical User Interface)
Direct3D응용 프로그램은 3차원 장면을 주 창의 클라이언트 영역(client area)에 렌더링한다.
4. 유니코드(Unicode)
하나의 문자를 4바이트(16비트) 값으로 표현한다.
* ASCII 문자열: char 배열로 표현되며, 각 문자는 1바이트(8비트) 크기
이 덕분에 여러 나라의 문자와 기호를 포함한 커다란 문자 집합을 표현할 수 있다. C++에서 유니코드를 사용할 때는 비트수가 많은 wchar_t를 사용한다. 32비트와 64비트 windows에서 wchar_t는 16비트이다. 이를 사용하기 위해서는 문자열 리터럴 앞에 대문자 L을 붙여야 한다. 접두사 L은 컴파일러에게 이 문자열 리터널을 char가 아니라 wchar_t들의 문자열로 취급하라고 알려주는 역할을 한다.
이뿐만 아니라 넓은 문자열을 사용할 때는 문자열 함수도 넓은 문자열 버전을 사용해야한다.
ASCII | UNICODE | 설명 |
strlen | wcslen | 문자열의 길이를 반환한다. |
strcpy | wcspy | 문자열을 복사한다. |
strcmp | wcscmp | 두 문자열을 지정된 길이만큼 비교한다. |
char* | wchar_t* | |
strcat | wcscat | 문자열을 이어 붙인다. |
strncpy | wcsncpy | 지정된 길이만큼 문자열을 복사한다. |
strchr | wcschr | 문자열에서 특정 문자를 찾는다. |
strstr | wcsstr | 문자열에서 특정 부분 문자열을 찾는다 |
strcasecmp | wcscasecmp | 대소문자를 구분하지 않고 두 문자열을 비교한다. |
strtok | wcstok | 문자열을 구분자로 분리한다. |
std::string | std::wstring |
5. 유니코드 설정하기 - MSVC (Microsoft Visual Studio)
상단 메뉴 프로젝트 -> 속성 -> 고급 -> 문자집합 -> 유니코드 문자 집합 사용

설정 안 함 | 15 이후 char타입만 사용하도록 설정, ASCII문자열 처리만 지원하며, 유니코드 멀티코드는 사용하지 않는다. |
유니코드 문자 집합 사용 | TCHAR -> wchar_t 문자열 함수는 wcslen, wcscpy 등 유니코드 함수로 매핑. |
멀티바이트 문자 집합 사용 | TCHAR -> char 문자열 함수는 strlen, strcpy 등 ANSI 함수로 매핑 |
6. 기본적인 Windows 응용 프로그램
1) HWND / 핸들
- handle to a window (window handle)
- windows는 프로그래밍에서 windows가 내부적으로 관리하는 객체들을 지칭할 때에는 핸들을 사용하는 경우가 많다.
- windows가 정해 준 핸들 값을 보관하는 용도로 쓰인다.
- Win32 API에는 작업의 대상이 되는 창을 식별하기 위해 창 핸들을 요구하는 함수들이 많다.
2) WDNCLASS


3) CreateWindow

- WNDCLASS 인스턴스 자체가 아니라 그 인스턴스의 lpszClassName 필드에 설정한 클래스 이름을 이용해서 지정한다.
- 자신이 새로 생성한 창의 핸들(HWND)을 돌려준다. (생성하지 못했다면 0, null )
LPCSTR lpClassName | 클래스 이름 | RegisterClass, RegisterClassEx 함수로 등록된 클래스 이름이어야 한다. |
LPCSTR lpWindowName | 제목 | 캡션 바에 표시 될 텍스트 |
DWORD dwStyle | 스타일 | |
int X | 윈도우의 초기 X 좌표 | |
int Y | 윈도우의 초기 Y 좌표 | |
int nWidth | 윈도우의 초기 너비 | |
int nHeight | 윈도우의 초기 높이 | |
HWND hWndParent | 부모 윈도우 핸들 | 최상위 윈도우의 경우 null로 설정 |
HMENU hMenu | 메뉴 핸들 | 필요 없으면 null |
HINSTANCE hInstance | 애플리케이션 인스턴스 핸들 | |
LPVOID lpParam | 추가 매개변수 |
* 주요 스타일 *
WS_MINIMIZEBOX | 최소화 버튼 추가 |
WS_MAXIMIZEBOX | 최대화 버튼 추가 |
WS_SYSMENU | 시스템 x 버튼 추가 |
WS_OVERLAPPED | 기본 창 스타일 (타이틀 바 포함) |
WS_THICKFRAME | 창 크기 조절 |
WS_OVERLAPPEDWINDOW | 최소화, 확장, 닫기 버튼을 포함한 기본 창 스타일 |
WS_VISIBLE | 창을 생성 즉시 표시 |
WS_POPUP | 기본 윈도우 스타일을 무시하고 팝업 창처럼 동작 |
WS_CAPTION | 제목 표시줄(타이틀 바) 활성화 |
WS_BORDER | 테두리 활성화 |
WS_CLIPSIBLINGS | 부모 창이 형제(다른 자식 창) 영역을 그리지 않도록 설정 |
* 스타일 사용 예제 *
ex) 최소화, 확장, 닫기 버튼을 포함하고 확장 버튼은 비활성화 하고 싶은 경우
DWORD dwStyle = WS_VISIBLE | WS_POPUP | WS_CAPTION | WS_BORDER | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX;
4) 메시지 루프

Windows 애플리케이션은 실행되면 운영체제로부터 메시지를 받는다. 이 메시지를 GetMessage, PeekMessage 등 함수로 가져오고, TranslateMessage와 DispatchMessage를 이용하여 메시지를 처리한다.
- TranslateMessage: 키 입력 메시지 변환
- DispatchMessage: 메시지를 윈도우 프로시저로 전달(wndProc)
* PeekMessage *
게임은 메시지가 올 때까지 아무 일도 하지 않고 기다리는 것이 아니라, 스스로 끊임없이 갱신한다.
문제는, 메시지 루프에서 호출하는 GetMessage 함수는 메시지 대기열에 메시지가 없으면 스레드를 수면(sleeping) 상태로 전환하며, 메시지가 도착해야 스레드가 다시 깨어난다는 점이다. 이는 게임에 적합한 방식이 아니다.
해결방법은 GetMessage 대신 PeekMessage 함수를 사용하는 것이다. PeekMessage함수는 메시지가 없으면 즉시 제어권을 반환한다. 이는 논블로킹 루프라고도 부른다.
단점은 메시지가 없을 때도 계속 실행됨으로 CPU 사용률이 높다.
5) 창 프로시저

- 창이 받은 특정 메시지에 반응해서 실행하는 코드를 담은 함수로, 개발자가 직접 작성해야 한다.
- 모든 창 프로시저는 동일한 함수 서명을 따라야 한다.
- 응용 프로그램 자체는 이 함수를 호출하지 않는다. 이 함수는 창이 메시지를 처리할 때가 되면 windows가 호출해 준다.

'👨🏻💻 programming > ◽ 컴퓨터 공학' 카테고리의 다른 글
[세팅] pch : pre compile header 세팅, 다른 프로젝트 참조하기, 실행파일 저장위치 변경하기 (0) | 2025.03.06 |
---|---|
[assembly 명령어] mov, lea (0) | 2024.06.26 |
안 하는 것 보다 낫겠지
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!