MFC 메시지 맵 2 : 클래스를 사용해 프로그램을 구조화 MFC 마을



지난시간에는 C만을 이용해서 윈도우 응용프로그램을 만들고, WM_PAINT 메시지와 DC 에 대해서 간단히 알아 보았다.

MFC 메시지 맵 1 : 순수 C 로 구현된 윈도우 프로그램




이번시간에는 클래스를 사용해서 이전에 만들어 보았던 프로그램을 객체지향적으로 바꿔보겠다.


응용프로그램을 나타내는 CApp 클래스를 만들어 보자.

이전에 순수한 C 로 만들었던 윈도우 응용프로그램을 분석해보면 다음과 같은 세 부분으로 나눌 수 있다.

1. 윈도우 클래스를 등록하고 윈도우를 만드는 부분
2. 메시지 루프
3. 메시지 루프 탈출 부분

따라서 CApp 객체에서는 이에 대응해서 다음과 같은 멤버 함수를 가지면 된다.

1. 인스턴스를 초기화 하는 함수 InitInstance()
2. 메시지 루프 Run()
3. 인스턴스를 탈출하는 ExitInstance()


이러한 CApp 클래스를 설계해 두고, 프로그램 코드 상에서 CApp 객체를 하나 선언 한 다음에

WinMain 함수에서  app.InitInstance, app.Run, app.ExitInstance 를 호출한다.

메인 함수를 한번 보자.



01: #include "CApp.h"
02:
03: CApp app;
04:
05: int WINAPI WinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in LPSTR lpCmdLine, __in int nShowCmd )
06: {
07: app.InitInstance(hInstance, lpCmdLine, nShowCmd);
08: app.Run();
09: return app.ExitInstance();
10: }
11:
12: LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
13: {
14: switch(iMsg)
15: {
16: case WM_CREATE:
17: app.OnCreate();
18: return 0;
19: case WM_PAINT:
20: app.OnDraw();
21: return 0;
22: case WM_DESTROY:
23: app.OnDestroy();
24: return 0;
25: case WM_LBUTTONDOWN:
26: app.OnLButtonDown();
27: return 0;
28: }
29:
30: return DefWindowProc(hwnd, iMsg, wParam, lParam);
31: }

그리고 CApp 클래스의 선언부와 구현부를 확인 해 보자.

먼저 CApp.h 를 확인 해 보자.

01: #include <windows.h>
02: #include <tchar.h>
03:
04: #ifndef CAPP_CAPP_H
05:
06: LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
07:
08: class CApp
09: {
10: private:
11: static TCHAR szAppName[];
12: HWND m_hwnd;
13: MSG m_msg;
14: WNDCLASSEX m_wndclass;
15:
16: public:
17: void InitInstance(HINSTANCE hInstance, LPSTR szCmdLine, int iCmdShow);
18: void Run(void);
19: WPARAM ExitInstance(void);
20:
21: public:
22: void OnCreate(void);
23: void OnDraw(void);
24: void OnDestroy(void);
25: void OnLButtonDown(void);
26: };
27:
28: #endif

아래 파일은 CApp.cpp 파일이다.

01: #include "CApp.h"
02:
03: TCHAR CApp::szAppName[] = _T("Sample Program");
04:
05: void CApp::InitInstance(HINSTANCE hInstance, LPSTR szCmdLine, int iCmdShow)
06: {
07: m_wndclass.cbSize = sizeof(m_wndclass);
08: m_wndclass.style = CS_HREDRAW | CS_VREDRAW;
09: m_wndclass.lpfnWndProc = WndProc;
10: m_wndclass.cbClsExtra = 0;
11: m_wndclass.cbWndExtra = 0;
12: m_wndclass.hInstance = hInstance;
13: m_wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
14: m_wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
15: m_wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
16: m_wndclass.lpszMenuName = NULL;
17: m_wndclass.lpszClassName = szAppName;
18: m_wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
19:
20: RegisterClassEx ( &m_wndclass );
21:
22: m_hwnd = CreateWindow ( szAppName, _T("Simple"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
23: CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL );
24:
25: ShowWindow(m_hwnd, iCmdShow);
26: UpdateWindow(m_hwnd);
27: }
28:
29: void CApp::Run(void)
30: {
31: while ( GetMessage(&m_msg, NULL, 0, 0))
32: {
33: TranslateMessage(&m_msg);
34: DispatchMessage(&m_msg);
35: }
36: }
37:
38: WPARAM CApp::ExitInstance(void)
39: {
40: return m_msg.wParam;
41: }
42:
43: void CApp::OnCreate()
44: {
45:
46: }
47:
48: void CApp::OnDraw()
49: {
50: PAINTSTRUCT ps;
51: RECT rect;
52: HDC hdc;
53:
54: hdc = BeginPaint(m_hwnd, &ps);
55: GetClientRect(m_hwnd, &rect);
56: DrawText(hdc, _T("Hello Windows!"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER );
57: EndPaint(m_hwnd, &ps);
58: }
59:
60: void CApp::OnDestroy()
61: {
62: PostQuitMessage(0);
63: }
64:
65: void CApp::OnLButtonDown(void)
66: {
67: MessageBox(m_hwnd, _T("Button Down!"), _T("Hello"), MB_OK);
68: }


프로그램을 클래스로 만들어 놓았기 때문에, 추가되는 메시지는 CApp.h 에 이벤트 핸들러를 선언하고,

CApp.cpp 에 이벤트 핸들러를 구현 한 후 WndProc 에서 메시지 타입에 따라 이벤트 핸들러를 호출해 주면 된다.

case WM_PAINT : app.OnCreate() 와 같이.


이러한 방식의 문제점은 메시지가  추가될때마다 WndProc 를 수정해야 한다는 것이다.

200개나 되는 메시지를 미리 다 구현 해 놓을수는 없다. 필요할때마다 오버로딩해서 사용할 수 있어야 한다.

우리는 우리가 추가한 핸들러의 코드만을 작성하길 원한다.  OnCreate 이외의 부분에는 관심도 없고, 관심을 가져야 할 이유도 없다.

다음시간에는 어떻게 이러한 문제점을 해결할 것인지, 메시지 맵을 통해서 해결해 보겠다.




참고 - MFC 구조와 원리 p.206 ~ P.210

핑백

덧글

댓글 입력 영역


시계

라운드 시계

위키피디아