Programming/Etc.

[MFC] 2. 윈도우 프로그래밍 및 SDK 프로그램 기초

꾸준희 2016. 11. 12. 21:30
728x90
반응형

1. 윈도우 프로그래밍 개요


  윈도우 프로그래밍이란 윈도우 운영체제에서 구동되는 응용 프로그램을 만드는 것이다. 따라서 윈도우 운영체제의 특징을 알아야 한다. 기존에 운영되었던 DOS와 같은 텍스트 기반 운영체제에 비해 WINDOW와 같은 그래픽 기반 운영체제가 훨씬 보기 편한게 사실이다. 이러한 프로그램을 만들기 위해서 메세지 구동 구조에 대해 알아야한다. 


  윈도우 운영체제에서 실행되는 대부분의 응용 프로그램은 메세지 구동 구조(Message-Driven Architecture)로 동작한다. 메세지는 운영체제가 프로그램의 외부 또는 내부에 변화가 발생했음을 해당 프로그램에 알리기 위한 개념이다. 


  하지만 대부분의 윈도우 응용 프로그램은 순차적으로 실행되지 않고 어떤 메세지를 받는가에 따라 코드의 실행 순서가 달라지기 때문에 그에 대한 동작이 달라질 수 있다. 시스템에서 외부에서 메세지를 발생시키는 이벤트가 발생하면 운영체제가 관리하는 시스템 메세지 큐(System Message Queue)에 정보가 저장되어 운영체제는 시스템 메세지 큐에 저장된 메세지를 적절한 응용 프로그램 메세지 큐에 보내게 된다. 


  멀티 태스킹과 멀티스레딩 개념을 간략히 소개하자면 멀티태스킹은 서로다른 응용프로그램 사이에서 두 가지를 실행하는 것이고, 멀티스레딩은 동시에 두 가지를 한 응용 프로그램 내부에서 사용하는 것이다. 즉, 멀티태스킹은 운영체제에서, 멀티스레딩은 해당 응용 프로그램에서 관리하게 된다. 






2. SDK 프로그램 기본 구조 


Win32 Application 폼을 이용하여 간단한 SDK 프로그램을 짜보았다. 윈도우창에 Hello, SDK라는 메세지를 띄우고, 마우스 이벤트가 발생하면 간단한 팝업창을 띄우는 예제이다. 메세지를 처리해주기 위해 상황별로 case를 나누어 각 이벤트를 처리해주어야 한다. 


Win32 Application을 생성하여 소스코드를 추가하였다.


헤더파일은 #include <windows.h> 를 이용한다. 


LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); 이라는 함수의 원형을 선언한다.


그 다음 int WINAPI WinMain(...) {...} 함수를 선언해주고나서 


윈도우 클래스를 초기화

운영체제에 등록

윈도우를 생성

화면에 띄우기

메세지 큐 처리


위와 같은 일들을 하는 코드를 추가해준다.



그 다음 LRESULT CALLBACK WndProc(...) {...} 윈도우 프로시저 함수를 추가해준다.


윈도우 프로시저 안에는 발생한 메세지의 종류에 따라 적절히 처리해주는 case 문을 작성하게 된다. 

case문에서 다루지 않은 메세지는 운영체제가 처리하도록 한다. 


전체 코드는 아래와 같다. 모든 저작권은 한빛미디어에게 있다.





결과 화면은 다음과 같다.



/* 중요한 점 */


참고자료 1 : http://lab.gamecodi.com/board/zboard.php?id=GAMECODILAB_QnA_etc&no=1775



코드를 쓰고있는데 문자열 부분에서 그러니까 

intelliSense: a value of type "const char *" cannot be assigned to an entity of type "LPCWSTR" 

이러한 오류가 발생해서 찾아보니 프로젝트를 유니코드 문자집합으로 생성해서 생기는 오류라고 한다.

그래서 소스코드 내에서 사용하게 될 문자열은 아래와 같은 형식으로 써야한다고 한다. 아니면 프로젝스 속성 - 일반 - 문자집합 항목에서 멀티바이트문자집합 사용을 누르면 된다고 한다.


원형 : "HelloClass";


유니코드 문자열로 바꾸기 : 


L"HelloClass"; 이렇게 사용하거나 아래와 같이 헤더 선언 후 사용하도록 한다. 아래 방법을 많이 쓴다.


#include<tchar.h>

_T("HelloClass");





2-1 예제 분석


1) windows.h 

이 헤더파일은 윈도우 API 함수 원형, 데이터 타입, 구조체, 매크로 상수 등이 선언되어있다. HINSTANCE, LPSTR, HWND 같은 데이터 타입이 저장되어있는 헤더이고, 필수적이다. 


2) WinMain() 

이 메인함수는 C 프로그램의 main() 함수에 해당되며, 프로그램을 실행하는 시작점이다. HINSTNCE 형 변수인 hInstance, hPrevInstance는 인스턴스 핸들이라고 부른다. hInstance는 메모리에 로드된 실행 파일의 위치를 나타내는 주소값이다. 이 값은 실행 파일에 포함된 리소스에 접근할 때 종종 사용된다. hPrevInstance는 16비트 윈도우의 잔재로 항상 NULL값을 가지게 된다. 


3) 윈도우 클래스 초기화와 등록

윈도우 클래스는 윈도우를 생성하는 데 필요한 다양한 정보를 담고 있는 구조체다. CreateWindow()함수를 사용하여 윈도우를 생성하게 된다. 이 함수의 첫번째 인자로 윈도우 클래스 이름이 전달되므로, 윈도우 생성 전에 윈도우 클래스를 운영체제에 등록하는 과정이 필요하다. 


가장 중요한 것은 lptnWndProc이다. 이는 일종의 함수 포인터로 윈도우가 운영체제로부터 받은 메세지를 처리할 사용자 정의 함수의 주소를 담고 있다. 윈도우 클래스가 등록되면 응용 프로그램은 특성이 동일한 윈도우를 여러 개 생성할 수 있는데, 이렇게 생성된 윈도우에서 발생한 메세지는 하나의 윈도우 프로시저에서 처리하게 된다. 


4) 윈도우 생성

CreateWindow() 함수의 인자 목록은 다음과 같다.

클래스이름, 윈도우이름, 윈도우스타일, x좌표, y좌표, 윈도우의 폭, 

윈도우의 높이, 부모 윈도우 핸들, 메뉴핸들, 인스턴스핸들, 옵션데이터


함수의 리턴값은 윈도우 핸들이라고 부르는데 윈도우를 유지하는 데 필요한 데이터 구조체를 가리키는 일종의 포인터이다. 


5) 메세지 루프

메세지 큐에서 메세지를 하나씩 꺼내서 처리하는 반복문을 메세지 루프라고 부른다. GetMessage() 함수는 메세지 큐에서 메세지 하나를 꺼내 msg 변수에 저장한다. TranslateMessage() 함수는 msg 변수에 키보드 메세지가 들어 있을 경우 문자를 만들어내는 역할을 한다. DispatchMessage() 함수는 메세지를 윈도우 프로시저에 보내는 역할을 한다. 


6) 윈도우 프로시저

윈도우 프로시저는 윈도우 메세지를 처리하는 핵심 함수이다. 하나의 윈도우 클래스를 기반으로 윈도우를 여러 개 생성한 경우 모든 윈도우가 윈도우 프로시저를 공유하므로 어느 윈도우에서 메세지가 발생했는지 구분할 필요가 있다. 


메세지 이름           : 메세지 발생 시점

WM_CREATE          : CreateWindow() 함수를 호출할 때

WM_LBUTTONDOWN  : 클라이언트 영역에서 마우스 왼쪽 버튼을 클릭할 때

WM_PAINT            : 클라이언트 영역의 일부 또는 전체를 다시 그릴 필요가 있을 때

WM_DESTROY        : 종료 버튼을 눌렀을 때 


/* 주의할 점 */

별개의 얘기지만.. case 문 설정 시 return은 꼭 해주어야한다. 안하면 바로 꺼져버리니까... return 0 하나를 빼먹어서 실행하자마자 윈도우 창이 꺼져버려서, 하위 시스템을 콘솔로도 바꿔보고, 윈도우창 유지하기 라는 걸 검색해보기도 했다..../-\ ... 


또 앞에 h라는 접두사가 붙은 변수는 handle에 관련된 것이고, fn은 function, p는 pointer, lp는 long pointer를 의미한다.





다음에는 MFC 프로그램 기본 구조와 SDK를 비교하고, 비주얼 C++ 개발환경에 대해서 알아보겠다. 

728x90
반응형