티스토리 뷰

프로그래밍/MFC

MFC기본

에어버스 2018. 10. 28. 16:24

MFC기본 - 윈도우즈 MFC 프로그래밍 , 정보문화사, 유동근

 

VisualStudio2017 에서 Windows데스크톱 프로젝트를 만들고, 코드는 wWinMain() 안에 있는 코드는 모두 삭제하고 21행처럼 MessageBox() 호출 함수만 입력하고 실행하면 메시지 창이 뜬다.

위 코드는 콘솔 응용프로그램 인데,
프로그램 시작이 main() 이 아닌, 전역변수 클래스의 생성자가 먼저 실행한다.

프로그램 실행은 main()부터 시작한다고 알고 있는데, 전역변수 생성자는 CRT main(C-Runtime)이 전역변수로 선언된 객체의 생성자를 호출하기에, CRT main 이 시작함수이고 main()는 CRT main 함수에서 호출하는 함수일 뿐이다.

CRT main 역활

1. 전역변수로 선언된 객체의 생성자를 호출한다.
2. C/C++ 전역변수(__로 시작)를 초기화한다. 따라서 main 이후에는 이 변수를 그대로 사용할 수 있다.
3. C/C++ 런타임 메모리 할당함수나 new 같은 연산자에 의해서 할당된 힙메모리를 초기화 한다.

CRT main 은 컴파일러마다 다른 이름을 가지고 있다. 그리고 이것을 구현하는 주체는 컴파일러 제작회사이다. VisualStudio 인 경우 아래와 같다.

app종류     문자집합        CRT main                App시작함수

콘솔          ANSI            mainCRTStartup         main
                UINCODE      wmainCRTStartup       wmain

GUI           ANSI            WinMainCRTStartup     WinMain
                UINCODE      wWinMainCRTStartup   wWinMain

콘솔 프로젝트의 속성 창에서 링커/시스템/하위시스템 값을보면 위 그림과 같이 '콘솔'로 지정되어 있고, Win32 프로젝트는 '창' 으로 지정되어 있다.
여기서는 콘솔로 되어 있어 컴파일러는 mainCRTStartup 이나 wmainCRTStartup 함수를 제공한다.

메시지루프

GetMessage() 가 App 메시지큐에서에서 메시지를 하나씩 읽어와서 MSG 구조체에 저장하고 메시지큐에서 읽은 메시지를 삭제하고, TRUE를 반환한다. 이때 읽은 메시지를 처리하기 위해 메시지 루프 안에으로 들어간다. 만약, GetMessage()는 메시지 큐에서 메시지를 읽으려고 할때 메시지 큐에 메시지가 존재하지 않는다면, 대기상태로 들어가고, 이때 제어권은 OS에 반환하여 대기하는 것이때문에 CPU를 소모하지 않고 대하는것이다. GetMessage() 가 대기상태로 들어갈 때 OS는 다른 App에 대해 멀티태스킹을 수행한다. 이것을 비선점형(Non-Preemptive Multitasking) 멀티태스킹이라고 한다. 이것은 OS가 멀티태스킹을 수행하는 것이고, 결국 GetMessage() 입장에서 볼 때 GetMessage() 는 대기하거나 메시지를 읽거나 둘 중 한가지 일을 수행한다고 볼 수 있다.

DispatchMessage()는 MSG 구조체를 부분석하여 메시지를 발생시킨 윈도우 핸들(MSG 구조체 멤버의 핸들)을 이용해서 해당 윈도우 객체를 찾고 등록된 윈도우프로시저를 찾아 메시지를 발송한다.

하지만, 메시지 중에 어떤 메시지는 메시지 큐를 통하지 않고 바로 윈도우 프로시저로 전달되는 메시지가 있다.

1. Win32API 함수 호출에 의한 경우

예로, CreateWindow() 를 예로 들면,
WinMain()에서 윈도우를 생성할때 CreateWindow()를 호출하면 OS는 윈도우 객체를 OS내부에 생성하기 전에 WM_CREATE 라는 메시지를 발생시키지만, WM_CREATE 메시지는 메시지 큐에 들어가지 안혹 바로 윈도루 프로시저로 보내진다. 즉, CreateWindow() 가 WM_CREATE 메시지를 윈도우 프로시저로 보내버린다.
이와같이 Win32 API함수 호출에 의해 당장 처리되어야 하는 몇몇 메시지는 메시지 큐를 통하지 않고 바로 윈도우 프로시서로 보내진다. 이 경우 윈도우 프로시저를 호출하는 주체는 바로 메시지를 발생시킨 Win32 API 하수가 된다. 즉, 메시지 큐를 통과하는 메시지 처럼 DispatchMessage() 가 윈도우 프로시저를 호출하는 것이 아니다.

2. OS가 어떤 일을 수행하기 위해 바로 윈도우 프로시저로 메시지를 보내는 경우

사용자가 윈도우를 이동시키기 위해 드래그를 시작하면, OS는 윈도우가 이동해도 되는지를 App에 묻기 위해 WM_MOVING 이라는 메시지를 App에 보낸다. 이때 App은 WM_MOVING 메시지에 대해 적당히 답변을 해줌으로서 윈도우의 이동을 제어할 수 있다.
이렇게 OS가 어떤 일을 수행하기 위해 App의 도움이 필요한 경우 OS는 바로 윈도우프로시저로 메지를 보낸다. 그렇다면 이 경우 윈도우 프로시저를 호출하는 주체는 구굴까? 물론 DispatchMessage()는 아니다. 왜냐하면, DispatchMessage() 는 항상 메시지 큐에서 읽은 메시지를 발송하는 함수이기 때문이다.
그렇다고 OS가 보낸다고 생각해서도 안된다, 왜냐하면, App이 만약 어떤 메시지를 처리하고 있는 도중에 OS가 메시지를 윈도우 프로시저로 바로 보내면 윈도우 프로시저 입장에서 볼때 동시에 윈도우 프로시저가 재진입되는 상황이 발생하기 때문이다. 어떤 함수가 실행되고 있는데, 똑같은 함수가 또 실행된다는것이 가능한가? 그래서 OS는 윈도우 프로시저를 완전히 빠져 나왔을때 메시지를 보내기 위해 GetMessage()를 이용한다. 즉, App이 어떤 메시지를 완전히 처리하고 다음 메시지를 읽기 위해 GetMessage()를 호출할때 OS는 필요하다면 메시지 큐를 통하지 않는 메시지를 GetMessage()를 통해  바로 보내버린다.

이렇게  GetMessage() 는 많은 일을 한다.
1. 메시지 큐에서 메시지를 읽기
2. 메시지가 없는 경우 대기
3. 메시지 큐를 통과하지 않는 메시지를 바로 윈도우 프로시저로 보내기

이렇듯, GetMessage() 가 많은 일을 하기 때문에 App 은 항상 GetMessage() 가 아주 짧은 시간안에 실행될 수 있도록 App 코드를 구현해야 한다. 예를들면, 어떤 메시지를 처리하기 위해 윈도우 프로시저가 오랜 시간 반환되지 않는다면, 단순히 메시지 큐에 메시지가 지연되는 문제를 떠나 메시지 큐를 통과하지 않는 메시지도 전달되지 않음으로 App 의 모든 진행상황이 중단된다. 그래서 항상 GetMessgae() 가 실행될 수 있도록 App 코드를 구현해야 한다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31