175

Click here to load reader

MFC Internals

  • Upload
    mikasi

  • View
    348

  • Download
    27

Embed Size (px)

DESCRIPTION

MFC Internals. C ontents. Chapter 01 MFC 개관 Chapter 02 MFC 와 C/SDK Chapter 03 MFC 에서의 Message 처리 Chapter 04 MFC Utility Class Chapter 05 모든 길은 Cobject 로 통한다 Chapter 06 MFC Dialog 와 Control Dialog Chapter 07 MFC 의 Document/View Architecture. Chapter 01 MFC 개관. Contents. - PowerPoint PPT Presentation

Citation preview

Page 1: MFC Internals

MFC Internals

Page 2: MFC Internals

비트교육센터[2]

비트교육센터

ContentsChapter 01MFC 개관

Chapter 02MFC 와 C/SDK

Chapter 03MFC 에서의 Message 처리

Chapter 04MFC Utility Class

Chapter 05모든 길은 Cobject 로 통한다

Chapter 06MFC Dialog 와 Control Dialog

Chapter 07MFC 의 Document/View Architecture

Page 3: MFC Internals

Chapter 01MFC 개관

Page 4: MFC Internals

비트교육센터[4]

비트교육센터

ContentsApplication Frameworks 정의MFC 의 역사MFC 의 설계 목적MFC 의 구성MFC code basics

Page 5: MFC Internals

비트교육센터[5]

비트교육센터

Application Frameworks

Framework– 특정 영역의 작업을 도와 주는 class 집합

Application Framework– 특정 OS 의 application 개발 작업을 도와 주는 class 집합

MFC (Microsoft Foundation Classes)– Windows 용 application 개발 작업을 도와 주는 framework

Page 6: MFC Internals

비트교육센터[6]

비트교육센터

MFC 의 역사1989 년

– AFX group 탄생Application framework technology development group 의 약자

– 목적Windows application 개발자를 위한 C++ 과 object-oriented 개념을

적용시킨 tool 의 개발

– First prototype 실패Too complex and too different from Windows itself

Page 7: MFC Internals

비트교육센터[7]

비트교육센터

MFC 의 역사 (cont’d)1992 년

– MFC version 1.0C/C++ version 7.0 과 함께 나옴60 개가 넘는 Windows application 개발을 위한 class 포함일반 목적의 여러 class 포함완벽하지 못했음

– 개발자로부터 많은 불평을 받음

Page 8: MFC Internals

비트교육센터[8]

비트교육센터

MFC 의 역사 (cont’d)1993 년

– MFC version 2.0Visual C++ version 1.0 과 Windows NT 와 함께 나옴100 개가 넘는 class 포함새로 포함된 내용

– 새로운 application architecture– 새로운 high-level abstractions

Page 9: MFC Internals

비트교육센터[9]

비트교육센터

MFC 의 역사 (cont’d)1993 년 말

– MFC version 2.5Visual C++ version 1.5 와 함께 나옴OLE2.0 과 ODBC 지원이 추가됨

1994 년

– MFC version 3.0Thread 에 대한 기능이 보강됨

Page 10: MFC Internals

비트교육센터[10]

비트교육센터

MFC 의 역사 (cont’d)1995 년

– MFC version 3.1추가된 기능

– Simple Messaging Application Programming Interface(MAPI)– WinSock

– MFC version 4.0Visual C++ version 4.0 과 함께 나옴개발환경의 발전 , 재사용성의 향상

Page 11: MFC Internals

비트교육센터[11]

비트교육센터

MFC 의 역사 (cont’d)1997 년

– MFC version 4.2Visual C++ version 5.0 과 함께 나옴Internet 등을 위한 기능 추가

1998 년– MFC version 6.0

Visual C++ version 6.0 과 함께 나옴User interface 향상 등의 기능이 포함

2002 년– MFC version 7.0

Visual C++ .net(7.0) 과 함께 나옴기존의 각 요소별 추가 및 확장

– DHTML(editing, dialog box, …), Ole control, …Static casting and MFC message maps

Page 12: MFC Internals

비트교육센터[12]

비트교육센터

MFC 의 역사 (cont’d)

MFC version 과 Visual C++ version

Microsoft Visual C++ version 6.06.0

Microsoft C/C++ version 7.01.0

Microsoft Visual C++ version 1.02.0

Microsoft Visual C++ version 1.02.1

Microsoft Visual C++ version 1.52.5

Microsoft Visual C++ version 2.03.0

Microsoft Visual C++ version 2.13.1

Microsoft Visual C++ version 2.23.2

Microsoft Visual C++ versions 4.0 and 4.14.0

Microsoft Visual C++ versions 4.2 and 5.04.2

Visual C++ versionMFC version

Page 13: MFC Internals

비트교육센터[13]

비트교육센터

MFC 설계 목적AFX 그룹의 설계 목적

– Real-World Application– Simplifying the Windows API– Using the existing knowledge of Windows– Foundation for large-scale applications– Small and fast framework

Page 14: MFC Internals

비트교육센터[14]

비트교육센터

MFC 의 구성MFC class 의 분류

– General-purpose classes– Windows API classes– Application framework classes– High-level abstractions– Operating System Extension

Page 15: MFC Internals

비트교육센터[15]

비트교육센터

MFC 의 구성 (cont’d)General-purpose Class

– 프로그램의 일반적 용도를 위한 class

(1) CObject classMFC 의 최상위 class

run-time type information, serialization, diagnostic function, support for dynamic creation 4 가지 중요한 기능 제공

CArchive, CDumpContext, CRuntimeClass 등과 연계되어 작용

Page 16: MFC Internals

비트교육센터[16]

비트교육센터

MFC 의 구성 (cont’d)(2) Exception-handling class

memory, I/O error 발생 시 처리CException : base classCArchiveException, CFileExceptionCMemoryException, CResourceExceptionCNotSupportedException, CUserExceptionCOleException, CDBException

Page 17: MFC Internals

비트교육센터[17]

비트교육센터

MFC 의 구성 (cont’d)(3) Collection class

Array : CByteArray, CWordArray, CDWordArray, CPtrArray, CObArray, CStringArray, CUnitArray

Linked list : CObList, CPtrList, CStringList

Map : CMapPtrToWord, CMapPtrToPtr, CMapStringToOb, CMapStringToPtr, CMapStringToString, CMapWordToOb, CMapWordToPtr

Page 18: MFC Internals

비트교육센터[18]

비트교육센터

MFC 의 구성 (cont’d)(4) Dynamic string class

CStringconcatenation, comparison, assignment 등의 기본 연산 제공

(5) File classCFile, CStdioFile, CMemFile추상적으로 disk 상의 파일 제어 , 실제로는 memory 상의 파일 제어

Page 19: MFC Internals

비트교육센터[19]

비트교육센터

MFC 의 구성 (cont’d)(6) Time class

CTime, CTimeSpan(7) 기타

CPoint, CSize, CRect : Windows structure

Page 20: MFC Internals

비트교육센터[20]

비트교육센터

MFC 의 구성 (cont’d)Windows API class

(1) Application 관련 class CCmdTarget : message 처리

CCmdUI : user interface 의 update

CWinThread : MFC program 의 실행 thread 를 의미 , 즉 program 의 main 을 포함

CWinApp : CWinThread 의 파생 class 으로서 standard windows application 을 표현

Page 21: MFC Internals

비트교육센터[21]

비트교육센터

MFC 의 구성 (cont’d)– Window 관련 class

CWnd : CCmdTarget 의 파생 class 이므로 message 를 handle. 윈도우를 다루는 API 포함 .

CFramWnd, CMDIFrameWnd : main frame window 로서 message 를 받는 첫 윈도우

CDialog, 공통다이어로그박스 (CFileDialog, CColorDialog, CFontDialog, CPrintDialog, CFindReplaceDialog)

CDataExchange : DDX/DDV

Page 22: MFC Internals

비트교육센터[22]

비트교육센터

MFC 의 구성 (cont’d)CPropertySheet, CPropertyPageControls : CButton, CEdit, …Cmenu

– GDI 관련 classCDC, CPaintDC, CWindowDC, CClientDC, CMetaFileDCCPen, CBrush, CFont, ...

Page 23: MFC Internals

비트교육센터[23]

비트교육센터

MFC 의 구성 (cont’d)Application framework class

– Document/View ArchitectureCDocTemplate, CSingleDocTemplate, CMultiDocTemplate : document

와 view 를 연결CDocument : data 를 관리CView : data 를 redering 하여 보여 줌

– Context-Sensitive Help

Page 24: MFC Internals

비트교육센터[24]

비트교육센터

MFC 의 구성 (cont’d)High-level abstraction

– Enhanced ViewsCScrollView, CFormViewCEditView, CListView, CRichEditView, CTreeView

– Splitter WindowCSplitterWnd : dynamic, static

– Control ViewsCToolBar, CStatusBar, CDialogBar

Page 25: MFC Internals

비트교육센터[25]

비트교육센터

MFC Code BasicsClass Declaration Subsections

– MFC library 개발 팀의 코딩 규칙Not based public/protected/privatePrivate 변수는 거의 사용하지 않는다 .

– Header / source file// Constructors// Attributes// Operations// Overridables// Implementation

Page 26: MFC Internals

비트교육센터[26]

비트교육센터

Example of Commentsclass CStdioFile : public CFile{ DECLARE_DYNAMIC(CStdioFile)public:// Constructors CStdioFile();...// Attributes FILE* m_pStream; // stdio FILE...// Operations virtual void WriteString(LPCTSTR lpsz);... virtual LPTSTR ReadString(LPTSTR lpsz, UINT nMax);...// Implementationpublic:...};

Page 27: MFC Internals

비트교육센터[27]

비트교육센터

MFC CommentsClass Declaration Subsections

– MFC library 개발 팀의 코딩 규칙– Class header file 의 각 항목의 의미

// Constructors( 생성자 함수들 , 초기화 함수들 )

– C++ constructors, any other initialization– 예 ) CWnd::Create– 대개는 public

// Attributes( 위의 내용을 setting 하거나 얻어옴 )

– 대개는 documented public data members– Member functions( 위의 data 를 조작하는 ) : Get / Set 함수들

Page 28: MFC Internals

비트교육센터[28]

비트교육센터

MFC Code Basics (cont’d)// Operations( 값이 변한다 >??)

– Documented member functions– 대개는 public, non-const : side effects

// Overridables– 상속 받은 class 가 override 한 functions– Pure virtual functions

// Implementation( 현재 쓰고 있는 개념임 )– Implementation detail– Undocumented– 대개는 protected– 주의 : may change in future versions of MFC

Page 29: MFC Internals

비트교육센터[29]

비트교육센터

MFC Code Basics (cont’d)Variable Naming (common)

Pointer to a functionlpfnHookProc lpfncallback

hWnd hhandle

Z indicates NULL terminated.lpszFileName lpszLPSTR

lpWnd lpFAR *

pWnd p* (pointer)

dwPackedmessage dwDWORD

lAxisRatio lLONG

wListID wWORD

nMyUnsigned nUINT

nVariableCnt nint

blsSending bBOOL

cDirSeparator cchar

CommentExamplePrefixType

Page 30: MFC Internals

비트교육센터[30]

비트교육센터

MFC Code Basics (cont’d)

Variable Naming (MFC extensions)

pWndDialog pWndCWnd*

WndControl WndCWnd

strFind strCString

szRectangle szCSize

ptMouseClick ptCPoint

rectScroll rectCRect

ExamplePrefixClass

Page 31: MFC Internals

비트교육센터[31]

비트교육센터

MFC Code Basics (cont’d)

Symbol Naming

1-0x6FFFIDC_HANDIDC_Cursor resourceIcon resource

1-0x6FFFIDB_SMILEYIDB_Bitmap resource

0x2001-0x26FFHIDD_HELP_ABOUTHIDD_Dialog resource help context ID(for context-sensitive help)

1-0x6FFFIDD_ABOUTIDD_Dialog resource

1-0x6FFFIDR_MAINFRAMEIDR_Shared by multiple resources

RangeExamplePrefixType

Page 32: MFC Internals

비트교육센터[32]

비트교육센터

MFC Code Basics (cont’d)

Symbol Naming

8-0xDFFFIDC_COMBO1IDC_Control in dialog template

1-0x7FFFIDS_ERROR12IDS_String resource

0x3008-0x3DFFHIDP_FATALERRORHIDP_Message box help context

8-0xDFFFIDP_FATALERRORIDP_Message box prompt

0x1800-0x1DFFHID_CIRCLE_TOOLHID_Command help context

0x8000-0xDFFFID_CIRCLE_TOOLID_Menu or toolbar command

RangeExamplePrefixType

Page 33: MFC Internals

Chapter 02MFC 와 C/CDK

Page 34: MFC Internals

비트교육센터[34]

비트교육센터

ContentsIntroductionMFC versus C/SDKBasic Application Components

– CWinApp– CWnd– Window handles & Window objects

Find WinMain()Hidden Cool Stuff

– Registering Window Classes– MFC’s Windows Hooks– MFC’s Message Pump

MFC’s GDI Support

Page 35: MFC Internals

비트교육센터[35]

비트교육센터

IntroductionMFC

– 200 개 이상의 클래스들의 거대한 집합– But, MFC has also “Basic Windows Support”

A Windows program is still a Windows program– 어떤 언어 (C, C++, Delphi, …) 나 framework(MFC, OWL, …) 를 이용하든지

기본적인 요소들이 구현된다 .– Basic windows application support

WinMain, window class 등록 , 메시지 루프 , …

Page 36: MFC Internals

비트교육센터[36]

비트교육센터

IssueMFC 가 어떻게 Windows application 을 만드는가

– The application itself( 응용프로그램 그 자체 ) - main thread – Windows– Message handling( 위의 두가지를 연결해줌 )– The Graphics Device Interface (GDI)

Page 37: MFC Internals

비트교육센터[37]

비트교육센터

MFC vs. C/SDKMotivation

– 모든 Windows application 은 다음 2 개의 component 를 포함한다 .main application itselfmessage 를 핸들하는 하나 이상의 window

– C/SDK 개발 환경copy & pasteTime-consuming & inefficient

– C++/MFC 개발 환경OOP 활용 : inheritance & encaptulation필요한 부분만 변경

Page 38: MFC Internals

비트교육센터[38]

비트교육센터

Boilerplate Code왜 필요한가 ?

– Windows is event-driven OSImposes a grate deal of overhead

– Windows OSH/W 와 응용 프로그램을 연결하는 위치Application 에게 발생하는 이벤트를 알림이벤트를 다루기 위해 상당한 양의 코드가 항상 필요

Page 39: MFC Internals

비트교육센터[39]

비트교육센터

메시지 처리를 위한 작업들Set up a message handler and register it

– RegiserClass() : 윈도우 프로시져 등록

Windows 가 application 의 instance 들을 추적

application 은 Windows 에게 메시지를 요청 (ask) 하고 , 처리 (dispatch) 한다 .

application 이 종료될 때까지 위 작업을 반복한다 .

Page 40: MFC Internals

비트교육센터[40]

비트교육센터

Application 의 준비WinMain() 함수

– 프로그램의 시작점– Windows 로부터 프로그램을 실행하는데 필요한 정보를 얻어 오는 통로

현재 instance 의 handle, 직전에 실행된 instance 의 handle, command line argument, window 의 모습 ( 최대화 , 최소화 , …)

적어도 하나의 main window class 를 등록– User interface 를 제공

Message loop 를 설정Some initialization and setup( 초기화 작업 )

– Application specific, instance specific

Message handler 를 제공 최소한 WM_DESTROY 처리 -> WM_QUIT 생성

Page 41: MFC Internals

비트교육센터[41]

비트교육센터

Application 의 기본 요소

Main 함수Application specific

Initialization(Window class 등록 )

Instance specificInitialization

(Main window(UI) 생성 , 보여줌 )

Message loop

MessageHandler

Page 42: MFC Internals

비트교육센터[42]

비트교육센터

Source 1 : C/SDK#include <windows.h>HANDLE hInst; /* current instance */LRESULT CALLBACK MainWndProc(HANDLE hWnd, UINT message, WPARAM wParam, LPARAM

lParam){

switch(message) {case WM_LBUTTONDOWN:

MessageBox(hWnd,“Left mouse button clicked”, NULL, MB_OK);break;

case WM_DESTROY:PostQuitMessage(0);break;

default: /* Passes it on if unprocessed */return (DefWindowProc(hWnd, message, wParam, lParam));

}return 0;

}

Page 43: MFC Internals

비트교육센터[43]

비트교육센터

BOOL InitApplication(HANDLE hInstance){

WNDCLASS wc;

wc.style = 0; /* Class style(s) */wc.lpfnWndProc = MainWndProc; /* Message handler */wc.cbClsExtra = 0; /* No per-class extra data */wc.cbWndExtra = 0; /* No per-window extra data */wc.hInstance = hInstance; /* Application that owns the class*/wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);wc.hCursor = LoadCursor(NULL, IDC_ARROW);wc.hbrBackground = GetStockObject(WHITE_BRUSH);wc.lpszMenuName = NULL; /* Name of menu */wc.lpszClassName = “MinimalWClass”; /* Name of window class */

return (RegisterClass(&wc));}

Page 44: MFC Internals

비트교육센터[44]

비트교육센터

BOOL InitInstance(HANDLE hInstance, int nCmdShow) {

HWND hWnd; /* Main window handle */hInst = hInstance; // needed for loading resources //hWnd = CreateWindow(

“MinimalWClass”, /* Window class */“Minimal”, /* Caption */WS_OVERLAPPEDWINDOW, /* Window style */CW_USEDEFAULT, /* Default horizontal pos. */CW_USEDEFAULT, /* Default vertical pos. */CW_USEDEFAULT, /* Default width */CW_USEDEFAULT, /* Default height. */NULL, /* No parent */NULL, /* Use the window class menu */hInstance, /* This instance owns the window. */NULL);

Page 45: MFC Internals

비트교육센터[45]

비트교육센터

if (!hWnd)return (FALSE);

ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);return (TRUE);

}

Page 46: MFC Internals

비트교육센터[46]

비트교육센터

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {

MSG msg; /* message */if (!hPrevInstance) { /* First instance? */

if (!InitApplication(hInstance)) /* Shared stuff */return (FALSE); /* cannot initialize */

}

if (!InitInstance(hInstance, nCmdShow))return (FALSE);

while (GetMessage(&msg, NULL, 0, 0)) {TranslateMessage(&msg);DispatchMessage(&msg);

} return(msg.wParam);/*Returns the value from PostQuitMessage*/}

Page 47: MFC Internals

비트교육센터[47]

비트교육센터

Source 2 : MFC#include <afxwin.h> // MFC 주요 클래스 선언

class CGenericApp : public CWinApp {public:virtual BOOL InitInstance();

};

class CGenericWindow : public CFrameWnd {public:CGenericWindow() {

Create(NULL, “Generic”);}

afx_msg void OnLButtonDown(UINT nFlags, CPoint point);DECLARE_MESSAGE_MAP()

};

Page 48: MFC Internals

비트교육센터[48]

비트교육센터

BEGIN_MESSAGE_MAP(CGenericWindow, CFrameWnd)ON_WM_LBUTTONDOWN()

END_MESSAGE_MAP()

void CGenericWindow::OnLButtonDown(UINT nFlags, CPoint point) {MessageBox(“Left mouse button pressed…”, NULL, MB_OK);

}

BOOL CGenericApp::InitInstance() {m_pMainWnd = new CGenericWindow();m_pMainWnd->ShowWindow(m_nCmdShow);m_pMainWnd->UpdateWindow();return TRUE;

}

CGenericApp GenericApp;

Page 49: MFC Internals

비트교육센터[49]

비트교육센터

WinMain() Function– C/SDK : 존재– MFC : where? ( part of application framework )

Window class 등록– C/SDK : 존재– MFC : where?

Message loop– C/SDK : 존재– MFC : where?

Additional functions : idle processing, PreTranslateMessage()

C/SDK 와 MFC 의 비교

Page 50: MFC Internals

비트교육센터[50]

비트교육센터

C/SDK 와 MFC 의 비교 (cont’d)

Instance initialization– C/SDK : 존재– MFC : 존재 , 그러나 언제 실행 ?

Message handling– C/SDK : 존재– MFC : 존재 , 그러나 어떻게 command-routing, message-dispatch?

Member functions + Message mapAfxWndProc() : 공통 window procedure

항상 시작점이다 .

Page 51: MFC Internals

비트교육센터[51]

비트교육센터

Basic MFC Application ComponentsWindows application 의 두 가지 components

– Message pump– Window procedure

MFC 에서의 구현 방법– CWinApp

Application 을 나타내는 classapplication-specific : 초기화 , window 생성 , 메시지 루프

– CWndWindow 를 나타내는 class window-specific : 메시지 핸들링

Page 52: MFC Internals

비트교육센터[52]

비트교육센터

CWinApp (“AfxWin.h”)CWinApp : public CWinThread{public:// Constructor

CWinApp(LPCTSTR lpszAppName = NULL); // app name defaults to EXE name

// Attributes// Startup args (do not change)HINSTANCE m_hInstance;HINSTANCE m_hPrevInstance; // not usedLPTSTR m_lpCmdLine;int m_nCmdShow;

// Running args (can be changed in InitInstance)LPCTSTR m_pszAppName; // human readable name

// (from constructor or AFX_IDS_APP_TITLE)

Page 53: MFC Internals

비트교육센터[53]

비트교육센터

public: // set in constructor to override defaultLPCTSTR m_pszExeName; // executable name (no spaces)LPCTSTR m_pszHelpFilePath; // default based on module pathLPCTSTR m_pszProfileName; // default based on app name

// Overridables// hooks for your initialization codevirtual BOOL InitApplication();void SetCurrentHandles();// overrides for implementationvirtual BOOL InitInstance();virtual int ExitInstance(); // return app exit codevirtual int Run();virtual BOOL OnIdle(LONG lCount);

// return TRUE if more idle processingvirtual LRESULT ProcessWndProcException

(CException* e, const MSG* pMsg);

Page 54: MFC Internals

비트교육센터[54]

비트교육센터

public:virtual ~CWinApp();

protected://{{AFX_MSG(CWinApp)afx_msg void OnAppExit();afx_msg void OnUpdateRecentFileMenu(CCmdUI* pCmdUI);afx_msg BOOL OnOpenRecentFile(UINT nID);//}}AFX_MSGDECLARE_MESSAGE_MAP()

};

Page 55: MFC Internals

비트교육센터[55]

비트교육센터

CWinApp

AFXWIN.h멤버 변수와 멤버 함수

– WinMain() 에 전달된 command line parameter 를 관리할 변수m_hInstance : the current instance handlem_hPrevInstance : the previous instance handlem_lpCmdLine : the command line parametersm_nCmdShow : the show window flag

Page 56: MFC Internals

비트교육센터[56]

비트교육센터

CWinApp (cont’d)– m_pszAppName : application name– 관련 pointer

m_pszExeName : executable file namem_pszHelpFilePath : the path to help filem_pszProfileName : application profiles name

– 프로그램 실행 시 주어진 command line parameter 유지CCommandLineInfo class 이용 (AFXWIN.H)

Page 57: MFC Internals

비트교육센터[57]

비트교육센터

CWinApp (cont’d)

– InitInstance() : instance-specific 초기화– ExitInstance() : instance 종료 시 처리– Run() : message pump 수행– OnIdle() : Message queue 가 비었을 때 , Run 함수에 의해 호출

Page 58: MFC Internals

비트교육센터[58]

비트교육센터

CWnd

AFXWIN.H

2 가지 기능 수행– Wrapping the regular Windows API

예 : Create(), ShowWindow(), …– Higher-level MFC-related functionality

예 : default message handling

Page 59: MFC Internals

비트교육센터[59]

비트교육센터

CWnd ( 기능 1 )Wrapping the Windows API

– m_hWnd : regular API-level window handle 을 나타내기 위한 멤버변수– window handle 을 인자로 갖는 거의 모든 API 를 멤버 함수로 가진다 .

예 )

– AFXWIN2.INL : API 의 호출

APIHWND hWnd;ShowWindow(hWnd,SW_SHOWNORMAL);

MFCCWnd * pWnd;pWnd->ShowWindow(SW_SHOWNORMAL);

_AFXWIN_INLINE BOOL CWnd::ShowWindow(int nCmdShow){ ASSERT(::IsWindow(m_hWnd)); return ::ShowWindow(m_hWnd, nCmdShow); }

Page 60: MFC Internals

비트교육센터[60]

비트교육센터

CWnd ( 기능 2 )

Higher-level MFC-related functionality– CObject -> CCmdTarget -> CWnd– CObject derivation

Dynamic run-time informationSerialization

– CCmdTarget derivationMFC’s message-routing scheme

– Default message handling 제공

Page 61: MFC Internals

비트교육센터[61]

비트교육센터

_AFXWIN_INLINE void CWnd::OnActivate(UINT, CWnd*, BOOL){ Default(); }

LRESULT CWnd::Default(){ // call DefWindowProc with the last message _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData(); return DefWindowProc(pThreadState->m_lastSentMsg.message,

pThreadState->m_lastSentMsg.wParam, pThreadState->m_lastSentMsg.lParam);

}

예 : default message handling

Page 62: MFC Internals

비트교육센터[62]

비트교육센터

Turning Window Handles into Window Objects

Application

MFC object

Windows OS

Window handle

CHandleMap class

HighLevel

LowLevel

Page 63: MFC Internals

비트교육센터[63]

비트교육센터

계층적 관계High level : MFC object

– application 입장에서는 MFC object 를 이용

Low level : Window handle– Windows OS 는 handle 을 이용

MFC 는 어떤 handle 에 어떤 object 가 연결되어 있는지를 알아야 함

CHandleMap class 를 이용하여 구현

Page 64: MFC Internals

비트교육센터[64]

비트교육센터

CHandleMapAFXSTAT_.H

Mapping window handle to MFC object– Handle 이 주어지면 해당 object 를 찾음– Windows OS 가 callback 함수를 호출할 때 , window handle 을 parameter 로 호출– 그러나 , MFC 는 해당 CWnd- 파생 클래스 객체를 가지고 작업

Page 65: MFC Internals

비트교육센터[65]

비트교육센터

CHandleMap (cont’d)멤버변수

– CMapPtrToPtr m_permanantMapPermanent map명시적으로 객체가 생성될 때 정보가 추가됨 (CWnd’s::Create())객체가 종료될 때 정보가 제거됨 (CWnd’s::OnNcDestroy())cf) WM_NCCREAT -> WM_CREAT -> … -> WM_DESTROY -> WM_NCD

ESTROY

– CMapPtrToPtr m_temporaryMapTemporary map임시로 생성해야 할때 (ex: CWnd::GetActiveWindow())

-> 현재 활성화 되어 있는 오브젝트를 찾을때 사용실제로는 CWnd::HandleMap 에서 필요할 때 생성OnIdle() 에서 삭제 => DeleteTempMap() 호출

Page 66: MFC Internals

비트교육센터[66]

비트교육센터

CHandleMap (cont’d)

멤버함수– CWnd::FromHandle(HWND hWnd)

주어진 window handle 에 mapping 되는 object 의 pointer 를 얻을 때 사용

hWnd 를 wrap 하고 있는 CWnd pointer return만약 없으면 hWnd 를 wrap 하는 temporary CWnd return획득하면 역으로 object 를 통해 hWnd 의 접근이 용이 ( CWnd::m_hWnd 멤버 변수 )

Page 67: MFC Internals

비트교육센터[67]

비트교육센터

Temporary map 예

“AFXWIN2.INL”_AFXWIN_INLINE CWnd* PASCAL CWnd::GetActiveWindow()

{ return CWnd::FromHandle(::GetActiveWindow()); }

“Wincore.cpp”CWnd* PASCAL CWnd::FromHandle(HWND hWnd){

CHandleMap* pMap = afxMapHWND(TRUE); CWnd* pWnd = (CWnd*)pMap->FromHandle(hWnd);return pWnd;

}

Page 68: MFC Internals

비트교육센터[68]

비트교육센터

Temporary map 예 (cont’d)“Winhand.cpp”CObject* CHandleMap::FromHandle(HANDLE h){

if (h == NULL)return NULL;

CObject* pObject = LookupPermanent(h);if (pObject != NULL)

return pObject; // return permanent oneelse if ((pObject = LookupTemporary(h)) != NULL){

HANDLE* ph = (HANDLE*)((BYTE*)pObject + m_nOffset);ph[0] = h;if (m_nHandles == 2){

ph[1] = h;}return pObject; // return current temporary one

}

Page 69: MFC Internals

비트교육센터[69]

비트교육센터

Temporary map 예 (cont’d)CObject* pTemp = NULL;TRY {

pTemp = m_pClass->CreateObject();m_temporaryMap.SetAt((LPVOID)h, pTemp);

}CATCH_ALL(e) {

AfxSetNewHandler(pnhOldHandler);AfxEnableMemoryTracking(bEnable);THROW_LAST();

}END_CATCH_ALLAfxSetNewHandler(pnhOldHandler);AfxEnableMemoryTracking(bEnable);HANDLE* ph = (HANDLE*)((BYTE*)pTemp + m_nOffset);ph[0] = h;if (m_nHandles == 2) ph[1] = h;return pTemp;

}

Page 70: MFC Internals

비트교육센터[70]

비트교육센터

Other MappingAFX_MODULE_THREAD_STATE

– m_pmapHWNDwindow handles CWnd objects

– m_pmapHMENUmenu handles CMenu objects

– m_pmapHDCdevice context handles CDC objects

– m_pmapHGDIOBJGDI object handles CGDIObjects

– m_pmapHIMAGELISTimage list handles CImageList objects

Page 71: MFC Internals

비트교육센터[71]

비트교육센터

Attaching & DetachingWindow handles 과 CWnd-derived objects 를 연관시켜주는 함수

– CWnd::Attach()주어진 window handle 을 CWnd::m_hWnd 에 대입MFC’s permanent map 에 정보 추가

– CWnd::Detach()CWnd::m_hWnd 를 NULL 로 만듬MFC’s permanent map 에서 정보 제거

Page 72: MFC Internals

비트교육센터[72]

비트교육센터

CWnd::AttachBOOL CWnd::Attach(HWND hWndNew){

ASSERT(m_hWnd == NULL); // only attach once, detach on destroy

ASSERT(FromHandlePermanent(hWndNew) == NULL);// must not already be in permanent map

if (hWndNew == NULL) return FALSE;CHandleMap* pMap = afxMapHWND(TRUE);ASSERT(pMap != NULL);

pMap->SetPermanent(m_hWnd = hWndNew, this);AttachControlSite(pMap);return TRUE;

}

Page 73: MFC Internals

비트교육센터[73]

비트교육센터

CWnd::DetachHWND CWnd::Detach(){

HWND hWnd = m_hWnd;if (hWnd != NULL){

CHandleMap* pMap = afxMapHWND(); // don't create if not exist

if (pMap != NULL)pMap->RemoveHandle(m_hWnd);

m_hWnd = NULL;}m_pCtrlSite = NULL;return hWnd;

}

Page 74: MFC Internals

비트교육센터[74]

비트교육센터

주의

Multiple threads– Permanent( 영구 ) , temporary map( 임시 ) 모두 thread 단위로 저장– 전달할 경우 object 대신 HANDLE 을 보내는 것이 바람직

Window createWindow create

Thread 1Thread 1

Window createWindow create

Thread 2Thread 2

접근 불가접근 불가

Page 75: MFC Internals

비트교육센터[75]

비트교육센터

Find WinMain()APPCORE.CPP

– CWinApp 생성자 호출

APPMODULE.CPP ( 여기에 정의 )– _tWinMain()

extern "C" int WINAPI_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPTSTR lpCmdLine, int nCmdShow){

// call shared/exported WinMainreturn AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);

}

Page 76: MFC Internals

비트교육센터[76]

비트교육센터

Find WinMain() (cont’d)WINMAIN.CPP

– AfxWinMain()

int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)

{int nReturnCode = -1;CWinThread* pThread = AfxGetThread();CWinApp* pApp = AfxGetApp();// AFX internal initializationif (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))

goto InitFailure;

// App global initializations (rare)if (pApp != NULL && !pApp->InitApplication())

goto InitFailure;

Page 77: MFC Internals

비트교육센터[77]

비트교육센터

Find WinMain() (cont’d)

// Perform specific initializationsif (!pThread->InitInstance()){

if (pThread->m_pMainWnd != NULL){

pThread->m_pMainWnd->DestroyWindow();}nReturnCode = pThread->ExitInstance();goto InitFailure;

}nReturnCode = pThread->Run();AfxWinTerm();return nReturnCode;

}

Page 78: MFC Internals

비트교육센터[78]

비트교육센터

Find WinMain() (cont’d)APPINIT.CPP

– AfxWinInit()

BOOL AFXAPI AfxWinInit(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow){ // handle critical errors and avoid Windows message boxes SetErrorMode(SetErrorMode(0) | SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);

// set resource handles AFX_MODULE_STATE* pModuleState = AfxGetModuleState(); pModuleState->m_hCurrentInstanceHandle = hInstance; pModuleState->m_hCurrentResourceHandle = hInstance;

Page 79: MFC Internals

비트교육센터[79]

비트교육센터

Find WinMain() (cont’d)

// fill in the initial state for the application CWinApp* pApp = AfxGetApp(); if (pApp != NULL) {

// Windows specific initialization (not done if no CWinApp)pApp->m_hInstance = hInstance;pApp->m_hPrevInstance = hPrevInstance;pApp->m_lpCmdLine = lpCmdLine;pApp->m_nCmdShow = nCmdShow;pApp->SetCurrentHandles();

}

// initialize thread specific data (for main thread) if (!afxContextIsDLL) AfxInitThread(); return TRUE;}

Page 80: MFC Internals

비트교육센터[80]

비트교육센터

Find WinMain() (cont’d)InitApplication()

– application-specific, but do nothing

InitInstance()– instance-specific, virtual

Run()

Page 81: MFC Internals

비트교육센터[81]

비트교육센터

CWinApp 생성자

CWinApp::CWinApp(LPCTSTR lpszAppName){ if (lpszAppName != NULL) m_pszAppName = _tcsdup(lpszAppName); else m_pszAppName = NULL;

// initialize CWinThread state AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE(); AFX_MODULE_THREAD_STATE* pThreadState =

pModuleState->m_thread; pThreadState->m_pCurrentWinThread = this; m_hThread = ::GetCurrentThread(); m_nThreadID = ::GetCurrentThreadId();

// initialize CWinApp state ASSERT(afxCurrentWinApp == NULL); // only one CWinApp object please pModuleState->m_pCurrentWinApp = this; ASSERT(AfxGetApp() == this);

Page 82: MFC Internals

비트교육센터[82]

비트교육센터

CWinApp 생성자 (cont’d)// in non-running state until WinMainm_hInstance = NULL;m_pszHelpFilePath = NULL;m_pszProfileName = NULL;m_pszRegistryKey = NULL;m_pszExeName = NULL;m_pRecentFileList = NULL;m_pDocManager = NULL;m_atomApp = m_atomSystemTopic = NULL;m_lpCmdLine = NULL;m_pCmdInfo = NULL;// other initializationm_bHelpMode = FALSE;m_nSafetyPoolSize = 512; // default size

}

Page 83: MFC Internals

비트교육센터[83]

비트교육센터

InitApplication()BOOL CWinApp::InitApplication(){

if (CDocManager::pStaticDocManager != NULL){

if (m_pDocManager == NULL)m_pDocManager = CDocManager::pStaticDocManager;

CDocManager::pStaticDocManager = NULL;}

if (m_pDocManager != NULL)m_pDocManager->AddDocTemplate(NULL);

elseCDocManager::bStaticInit = FALSE;

return TRUE;}

Page 84: MFC Internals

비트교육센터[84]

비트교육센터

InitInstance()BOOL CWinApp::InitInstance(){

return TRUE;}

Page 85: MFC Internals

비트교육센터[85]

비트교육센터

Run()int CWinThread::Run(){

// for tracking the idle time stateBOOL bIdle = TRUE;LONG lIdleCount = 0;

// acquire and dispatch messages until a WM_QUIT message for (;;) {

// phase1: check to see if we can do idle workwhile (bIdle && !::PeekMessage(

&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE)){

// call OnIdle while in bIdle stateif (!OnIdle(lIdleCount++))

bIdle = FALSE; // assume "no idle" state}

Page 86: MFC Internals

비트교육센터[86]

비트교육센터

Run (cont’d)// phase2: pump messages while availabledo {

// pump message, but quit on WM_QUITif (!PumpMessage()) return ExitInstance();// reset "no idle" state after pumping "normal" messageif (IsIdleMessage(&m_msgCur)){

bIdle = TRUE;lIdleCount = 0;

}} while (::PeekMessage

(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));}ASSERT(FALSE); // not reachable

}

Page 87: MFC Internals

비트교육센터[87]

비트교육센터

MFC state information프로그램 종료까지 유지되는 정보AFX_MODULE_STATE class

– AFXSTAT_.H– 보유하는 정보

Main window handlesResource, module handlesMemory allocation trackingODBC support, OLE support, exception handling

Page 88: MFC Internals

비트교육센터[88]

비트교육센터

Hidden Cool Stuff2 issues

– window class 의 등록– Windows hook 와 MFC window 의 연결

Page 89: MFC Internals

비트교육센터[89]

비트교육센터

Registering Window Classes

Windows application– OS 에 적어도 하나 이상의 window class 를 등록해야만 한다 .

window class– window 의 기본적인 성질 정의

appearance ( via some flag )behavior ( via a callback function )

Page 90: MFC Internals

비트교육센터[90]

비트교육센터

Registering Window Classes (cont’d)

MFC 의 window class 등록– 4 개의 기본 window class 등록

regular child windowsa control bar windowan MDI frame windowa window for an SDI or MDI child window

– 기타common controls

Page 91: MFC Internals

비트교육센터[91]

비트교육센터

Registering Window Classes (cont’d)

WNDCLASSes and MFC

Style Style of window

LpfnWndProc window proc, must be AfxWndProcCbClsExtra not used ( 0 )CbWndExtra not used ( 0 )HInstance automatically filled with AfxGetInstanceHandleHIcon icon for frame windowHCursor cursor for when mouse is over windowHbrBackground background colorLpszMenuName not used ( NULL )LpszClassName class name

Page 92: MFC Internals

비트교육센터[92]

비트교육센터

Registering Window Classes (cont’d)

AfxWnd– Used for all child windows (CWnd::Create)– Class style : CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW– No icon– Arrow cursor– No background color

AfxFrameOrView– Used for frame windows and views – Class style : CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW– Icon AFX_IDI_STD_MDIFRAME– Arrow cursor– COLOR_WINDOW background color

Page 93: MFC Internals

비트교육센터[93]

비트교육센터

Registering Window Classes (cont’d)

AfxMDIFrame– Used for MDI frame window (CMDIFrameWnd::Create)– Class style : CS_DBLCLKS– Icon Icon AFX_IDI_STD_MDIFRAME– Arrow cursor– No background color

AfxControlBar– Used for standard control bar implementation– Class style : 0– No icon– Arrow cursor– Gray background color (COLOR_BTNFACE)

Page 94: MFC Internals

비트교육센터[94]

비트교육센터

Registering Window Classes (cont’d)AfxDeferRegisterClass()

– AFXIMPL.H

AfxEndDeferRegisterClass()– WINCORE.CPP

#define AfxDeferRegisterClass(fClass) AfxEndDeferRegisterClass(fClass)BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister);

Page 95: MFC Internals

비트교육센터[95]

비트교육센터

Class 등록 예“WINCORE.CPP”BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,

LPCTSTR lpszWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)

{// allow modification of several common create parametersCREATESTRUCT cs;cs.dwExStyle = dwExStyle;cs.lpszClass = lpszClassName;cs.lpszName = lpszWindowName;cs.style = dwStyle;cs.x = x; cs.y = y;cs.cx = nWidth; cs.cy = nHeight;cs.hwndParent = hWndParent;cs.hMenu = nIDorHMenu;cs.hInstance = AfxGetInstanceHandle();cs.lpCreateParams = lpParam;

Page 96: MFC Internals

비트교육센터[96]

비트교육센터

Class 등록 예 (cont’d)if (!PreCreateWindow(cs)) {

PostNcDestroy();return FALSE;

}AfxHookWindowCreate(this);HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass,

cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);

if (hWnd == NULL)GetLastError());if (!AfxUnhookWindowCreate()) PostNcDestroy();if (hWnd == NULL)return FALSE;ASSERT(hWnd == m_hWnd);

// should have been set in send msg hookreturn TRUE;

}

Page 97: MFC Internals

비트교육센터[97]

비트교육센터

Class 등록 예 (cont’d)BOOL CWnd::PreCreateWindow(CREATESTRUCT& cs){

if (cs.lpszClass == NULL){

// make sure the default window class is registeredVERIFY(AfxDeferRegisterClass(AFX_WND_REG));

// no WNDCLASS provided - use child window defaultASSERT(cs.style & WS_CHILD);cs.lpszClass = _afxWnd;

}return TRUE;

}

Page 98: MFC Internals

비트교육센터[98]

비트교육센터

MFC’s Message Pump

CWinApp::Run()– 이 함수가 실행되면서 실제 메시지 펌프가 동작하게 됨– 이는 CWinApp 가 CWinThread 로 부터 상속받기 때문에 가능한 것임– Thread 종류

Worker thread : 일반적으로 말하는 threadInterface thread : Message pump

Page 99: MFC Internals

비트교육센터[99]

비트교육센터

MFC’s GDI 지원GDI (Graphical Device Interface)

– Windows OS 상의 풍부한 그리기 작업– 장치 독립적 지원 : GDI + Device driver

DC (Device Context)– GDI 의 핵심적인 개념– GDI 함수의 parameter– 스크린 , 프린터 등을 표시– 구조체 : 객체 + 속성 + 모드

Page 100: MFC Internals

비트교육센터[100]

비트교육센터

Device Contexts

CDC– CPaintDC

painting 작업이 발생할 때BeginPaint() ~ EndPaint()

– CWindowDC전체 스크린을 표시 (client area+frame)GetWindowDC() ~ ReleaseDC()

– CClientDCClient area 를 표시GetClientDC() ~ ReleaseDC()

– CMetaFileDC메타파일에 대한 그리기 작업생성자 ~ Create() ~ DeleteMetaFile()

Page 101: MFC Internals

비트교육센터[101]

비트교육센터

Graphic ObjectsCGdiObject : Base class

– CPen– CBrush– CFont– CBitmap– CPalette– CRgn

Win32 API 의 함수들을 wrapping

Page 102: MFC Internals

비트교육센터[102]

비트교육센터

예제

CMyWnd::OnPaint() {CPaintDC paintDC(this);CPen* pOldPen;CPen bluePen(PS_SOLID, 25, RGB(0, 0, 255));

pOldPen = paintDC.SelectObject(&bluePen);paintDC.MoveTo(1, 1);paintDC.LineTo(100, 100);paintDC.SelectObject(pOldPen);

}

Page 103: MFC Internals

Chapter 03MFC 에서의 Message 처리

Page 104: MFC Internals

비트교육센터[104]

비트교육센터

ContentsIntroductionWindow messagesMessage mappingMFC 가 message map 을 이용하는 방법Message loop 의 hooking

Page 105: MFC Internals

비트교육센터[105]

비트교육센터

Introduction

Message handling– C/SDK

Switch/case 문을 통해 구현– MFC

Switch/case 문은 없다Callback function 은 어떻게 정의되는가

Page 106: MFC Internals

비트교육센터[106]

비트교육센터

Basic Components

MFC 의 message handling 구조– CCmdTarget class– Message maps

MFC message maps 에 대한 의문– 어떻게 switch/case 문을 대체하는가– 어떤 data structure 로 정의되는가– 어떻게 message map 이 작동하는가– 어떻게 message 가 연결되는가

Page 107: MFC Internals

비트교육센터[107]

비트교육센터

Window Messages3 개 부분으로 구성됨

– Unsigned integer실제 메시지를 나타냄

– WPARAMWord(32bits) 크기의 parameter메시지에 따른 특정 데이타

– LPARAM4byte parameter메시지에 따른 특정 데이타

Page 108: MFC Internals

비트교육센터[108]

비트교육센터

Window Messages (cont’d)

핸들링 해야 할 메시지의 분류– Windows message

WM_ 로 시작하는 메시지들 (WM_COMMAND 제외 )일반적으로 window, view 등에서 핸들링

– Control notificationWM_COMMAND 중 notify, WM_NOTIFYControl, 자식 window 가 부모 윈도우에게 전달하는 메시지들예 ) EN_CHANGED 를 포함한 WM_COMMAND 메시지

– Command message메뉴 , 툴바 , 엑셀레이터 등으로 인한 메시지

Page 109: MFC Internals

비트교육센터[109]

비트교육센터

Window Messages (cont’d)

핸들링 클래스– Windows message, control notification

CWnd 로부터 파생된 클래스들 : HWND 를 포함

– Command message다양한 종류 : CCmdTarget 로부터 파생된 클래스들예 ) open 명령 핸들링 : application

Page 110: MFC Internals

비트교육센터[110]

비트교육센터

UI Objects and Command IDs

Page 111: MFC Internals

비트교육센터[111]

비트교육센터

Message Handling in C/SDK

Windows program 의 정수

While (GetMessage(&msg, NULL, NULL, NULL)){

// Translates virtual key codesTranslateMessage(&msg);// Dispatches message to windowDispatchMessage(&msg);

}// Returns the value from PostQuitMessageReturn (msg.wParam);

Page 112: MFC Internals

비트교육센터[112]

비트교육센터

Message Handling in C/SDK (cont’d)WNDCLASS ws;…ws.lpfnWndProc = WndProc;…RegisterClass(ws);

LRESULT WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)

{switch (message) {

case WM_CREATE:…break;

case WM_COMMAND:switch (wParam) {

case IDM_ABOUT:…

}}

Page 113: MFC Internals

비트교육센터[113]

비트교육센터

Message Handling in MFC

방법 1– Polymorphism : 가상 멤버 함수 이용– 심각한 메모리 낭비

방법 2– Message maps– MFC 의 특징

Page 114: MFC Internals

비트교육센터[114]

비트교육센터

Message Mapping Internals두 부분으로 구성

– CCmdTargetWindow message 나 command 를 받기 위해 반드시 상속받아야

하는 class– Message map

Window message 와 이를 처리하는 class member function 을 연관시켜주는 mechanism

Page 115: MFC Internals

비트교육센터[115]

비트교육센터

CCmdTarget Class

메시지의 처리– CCmdTarget 의 파생 클래스– 예

CWnd classCDocumentCWinApp

Page 116: MFC Internals

비트교육센터[116]

비트교육센터

Message MapData structures

– AFX_MSGMAP_ENTRY(AFXWIN.H)Message map table 의 한 element(entry)Message 에 대한 정보와 message handler 에 대한 정보를 저장

struct AFX_MSGMAP_ENTRY{

UINT nMessage; // windows messageUINT nCode; // control code or WM_NOTIFY codeUINT nID; // control ID (or 0 for windows messages)UINT nLastID; // used for entries specifying a range of control id'sUINT nSig; // signature type (action) or pointer to message #AFX_PMSG pfn; // routine to call (or special value)

};

Page 117: MFC Internals

비트교육센터[117]

비트교육센터

Message Map(contd.)

– AFX_MSGMAP(AFXWIN.H)실제 message map

struct AFX_MSGMAP{#ifdef _AFXDLL

const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();#else

const AFX_MSGMAP* pBaseMap;#endif

const AFX_MSGMAP_ENTRY* lpEntries;};

Page 118: MFC Internals

비트교육센터[118]

비트교육센터

Message Map Macros

Macros (AFXWIN.H)– DECLARE_MESSAGE_MAP

Header file 에서 정의– BEGIN_MESSAGE_MAP / END_MESSAGE_MAP

Implementation file 에서 정의

#define DECLARE_MESSAGE_MAP() \private: \

static const AFX_MSGMAP_ENTRY _messageEntries[]; \protected: \

static AFX_DATA const AFX_MSGMAP messageMap; \virtual const AFX_MSGMAP* GetMessageMap() const; \

Page 119: MFC Internals

비트교육센터[119]

비트교육센터

Message Map Macros (cont’d)

#define BEGIN_MESSAGE_MAP(theClass, baseClass) \const AFX_MSGMAP* theClass::GetMessageMap() const \

{ return &theClass::messageMap; } \AFX_COMDAT AFX_DATADEF const AFX_MSGMAP theClass::messageMap = \{ &baseClass::messageMap, &theClass::_messageEntries[0] }; \AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[] = \{ \

#define END_MESSAGE_MAP() \{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } \

}; \

Page 120: MFC Internals

비트교육센터[120]

비트교육센터

Massage Map 예class CTestView : public Cview{protected:

//{{AFX_MSG(CTestView)afx_msg void OnLButtonDblClk(UINT nFlags, Cpoint point);//}}AFX_MSGDECLARE_MESSAGE_MAP()

};

class CTestView : public Cview{protected:

afx_msg void OnLButtonDblClk(UINT nFlags, Cpoint point);private:

static const AFX_MSGMAP_ENTRY _messageEntries[];protected:

static const AFX_MSGMAP messageMap;virtual const AFX_MSGMAP* GetMessageMap() const;

};

Page 121: MFC Internals

비트교육센터[121]

비트교육센터

Massage Map 예 (cont’d)BEGIN_MESSAGE_MAP(CTestVIew, Cview)

//{{AFX_MSG_MAP(CTestView)ON_COMMAND(ID_STRING_CENTER, OnStringCenter)ON_WM_LBUTTONDBLCLK()//}}AFX_MSG_MAP

END_MESSAGE_MAP()

const AFX_MSGMAP* CTestView::GetMessageMap() const{ return &CTestView::messageMap; }

AFX_COMDAT AFX_DATADEF const AFX_MSGMAP CTestView::messageMap = { &CView::messageMap, &CTestView::_messageEntries[0] };

const AFX_MSGMAP_ENTRY CTestVIew::_messageEntries[] ={ (BEGIN_MESSAGE_MAP)

ON_COMMAND(ID_STRING_CENTER, OnStringCenter)ON_WM_LBUTTONDBLCLK(){0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } (END_MESSAGE_MAP)

};

Page 122: MFC Internals

비트교육센터[122]

비트교육센터

Message Map Entry Macro

#define ON_COMMAND(id, memberFxn) \{ WM_COMMAND, CN_COMMAND, (WORD)id, (WORD)id, \AfxSig_vv, (AFX_PMSG)&memberFxn },

userdefine( 사용자가 지정한 이름 사용 )

#define ON_WM_LBUTTONDBLCLK() \{ WM_LBUTTONDBLCLK, 0, 0, 0, AfxSig_vwp, \

(AFX_PMSG)(AFX_PMSGW) \(void (AFX_MSG_CALL CWnd::*) \(UINT, CPoint))&OnLButtonDblClk },

만들어져 있는 이름을 사용

AFXMSG_.H

Page 123: MFC Internals

비트교육센터[123]

비트교육센터

Message Type Macro Form

Predefined Windows messages ON_WM_XXXX

Commands ON_COMMAND

Update commands ON_UPDATE_COMMAND_UI

Control notifications ON_XXXX

User-defined message ON_MESSAGE

Registered Windows message ON_REGISTERED_MESSAGE

Range of command IDs ON_COMMAND_RANGE

Range of command Ids for updating ON_UPDATE_COMMAND_UI_RANGE

Range of control IDs ON_CONTROL_RANGE

Message Map Entry Macro (cont’d)Message Map Entry Macro (cont’d)

Page 124: MFC Internals

비트교육센터[124]

비트교육센터

User-define Message // inside the class declaration afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);

For example: #define WM_MYMESSAGE (WM_USER + 100)

BEGIN_MESSAGE_MAP(CMyWnd, CMyParentWndClass) ON_MESSAGE(WM_MYMESSAGE, OnMyMessage)END_MESSAGE_MAP()

CWnd* pWnd = ...;pWnd->SendMessage(WM_MYMESSAGE);

Page 125: MFC Internals

비트교육센터[125]

비트교육센터

Handlers for Message-Map Ranges

종류– ON_COMMAND_RANGE– ON_UPDATE_COMMAND– ON_CONTROL_RANGE

Message-Map Entry– ID 는 연속적이어야 한다 .

BEGIN_MESSAGE_MAP(CMyApp, CWinApp)ON_COMMAND_RANGE(ID_MYCMD_ONE, ID_MYCMD_TEN, On

DoSomething)ON_CONTROL_RANGE(BN_CLICKED, IDC_BUTTON1, IDC

_BUTTON10, OnButtonClicked)END_MESSAGE_MAP( )

Page 126: MFC Internals

비트교육센터[126]

비트교육센터

Handlers for Message-Map Ranges

Handlers

...void CMyDialog::OnButtonClicked( UINT nID ){ int nButton = nID - IDC_BUTTON1; ASSERT( nButton >= 0 && nButton < 10 ); // ...}

Page 127: MFC Internals

비트교육센터[127]

비트교육센터

MFC 의 Message Map 이용

MFC-based program– 두 종류의 메시지를 처리

regular window messages– WM_MOUSEMOVE, …

commands– WM_COMMAND

– Message-mapping architecture 의 이해두 종류 메시지를 각각 추적

Page 128: MFC Internals

비트교육센터[128]

비트교육센터

How to be wired16-bit version

– AfxWndProc()Message handling procedure 로 등록된 함수

32-bit version– DefWindowProc() 가 message handler 로 등록– Message hook 방법을 써서 결국에는 AfxWndProc() 가 message 를 처리하게 함– Hooking function

_AfxCbtFilterHook(), _AfxStandardSubclass()– 3D Control 을 지원하기 위함

Page 129: MFC Internals

비트교육센터[129]

비트교육센터

How to be wired (cont’d)

“WinCore.cpp”

BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister){

// mask off all classes that are already registeredAFX_MODULE_STATE* pModuleState = AfxGetModuleState();fToRegister &= ~pModuleState->m_fRegisteredClasses;if (fToRegister == 0) return TRUE;LONG fRegisteredClasses = 0;

// common initializationWNDCLASS wndcls;memset(&wndcls, 0, sizeof(WNDCLASS)); // start with NULL defaultswndcls.lpfnWndProc = DefWindowProc;wndcls.hInstance = AfxGetInstanceHandle();wndcls.hCursor = afxData.hcurArrow;

Page 130: MFC Internals

비트교육센터[130]

비트교육센터

How to be wired (cont’d)BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,

LPCTSTR lpszWindowName, DWORD dwStyle,int x, int y, int nWidth, int nHeight,HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)

{ … AfxHookWindowCreate(this);}void AFXAPI AfxHookWindowCreate(CWnd* pWnd){ if (pThreadState->m_hHookOldCbtFilter == NULL) {

pThreadState->m_hHookOldCbtFilter = ::SetWindowsHookEx(WH_CBT,_AfxCbtFilterHook, NULL, ::GetCurrentThreadId());

if (pThreadState->m_hHookOldCbtFilter == NULL)AfxThrowMemoryException();

} pThreadState->m_pWndInit = pWnd;}

Page 131: MFC Internals

비트교육센터[131]

비트교육센터

How to be wired (cont’d)LRESULT CALLBACK_AfxCbtFilterHook(int code, WPARAM wParam, LPARAM lParam){…

// subclass the window if not already wired to AfxWndProcif (!bAfxWndProc){

// subclass the window with standard AfxWndProcoldWndProc = (WNDPROC)SetWindowLong(hWnd,

GWL_WNDPROC, (DWORD)afxWndProc);ASSERT(oldWndProc != NULL);*pOldWndProc = oldWndProc;

}…}

Page 132: MFC Internals

비트교육센터[132]

비트교육센터

Message HandlingAfxWndProc()(WINCORE.CPP)

– WM_QUERYAFXWNDPROCMFC’s message map 을 사용하는 MFC window 인지를 확인할

수 있는 message– 다른 message 에 대해서는 AfxCallWndProc() 함수를 호출

LRESULT CALLBACKAfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam){

if (nMsg == WM_QUERYAFXWNDPROC)return 1;

CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam);

}

Page 133: MFC Internals

비트교육센터[133]

비트교육센터

Message Handling (cont’d)AfxCallWndProc()(WINCORE.CPP)

– Thread state 구조체에 message 의 정보를 저장– WM_INITDIALOG 처리

Auto-center dialog 위한 처리를 수행– Window object 의 window procedure 호출

CWnd::WindowProc()(WINCORE.CPP)내부적으로 OnWndMsg() 를 호출OnWndMsg() 가 처리하지 못하면 CWnd::DefWindowProc() 를 호출

Page 134: MFC Internals

비트교육센터[134]

비트교육센터

LRESULT AFXAPI AfxCallWndProc(CWnd* pWnd, HWND hWnd, UINT nMsg,WPARAM wParam = 0, LPARAM lParam = 0)

{_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();MSG oldState = pThreadState->m_lastSentMsg; // save for nestingpThreadState->m_lastSentMsg.hwnd = hWnd;pThreadState->m_lastSentMsg.message = nMsg;pThreadState->m_lastSentMsg.wParam = wParam;pThreadState->m_lastSentMsg.lParam = lParam;CRect rectOld;DWORD dwStyle = 0;if (nMsg == WM_INITDIALOG) _AfxPreInitDialog(pWnd, &rectOld, &dwStyle);// delegate to object's WindowProclResult = pWnd->WindowProc(nMsg, wParam, lParam);// more special case for WM_INITDIALOGif (nMsg == WM_INITDIALOG) _AfxPostInitDialog(pWnd, rectOld, dwStyle);pThreadState->m_lastSentMsg = oldState;return lResult;

}

Message Handling (cont’d)Message Handling (cont’d)

Page 135: MFC Internals

비트교육센터[135]

비트교육센터

“WinCore.Cpp”

LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam){

// OnWndMsg does most of the work, except for DefWindowProc callLRESULT lResult = 0;if (!OnWndMsg(message, wParam, lParam, &lResult))

lResult = DefWindowProc(message, wParam, lParam);return lResult;

}

Message Handling (cont’d)Message Handling (cont’d)

CWnd::WndowProc()(WINCORE.CPP)– virtual 이므로 override 가능– 성능 향상을 위해 message-mapping system 을 거치지 않고 처리해야 하는

메시지에 대한 핸들링 가능

Page 136: MFC Internals

비트교육센터[136]

비트교육센터

Message Handling (cont’d)CWnd::OnWndMsg()(WINCORE.CPP)

– 특별히 처리하는 messageWM_COMMAND, WM_NOTIFYWM_ACTIVATE, WM_SETCURSOR

– 기타 다른 message 들은 message map 을 이용하여 해당 message handler 를 호출

Page 137: MFC Internals

비트교육센터[137]

비트교육센터

Message Handling (cont’d)BOOL CWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pRes

ult){

// special case for commandsif (message == WM_COMMAND) {

if (OnCommand(wParam, lParam)) {lResult = 1;goto LReturnTrue;

}return FALSE;

}// special case for notifiesif (message == WM_NOTIFY) { }// special case for activationif (message == WM_ACTIVATE) { }// special case for set cursor HTERRORif (message == WM_SETCURSOR ) { }

Page 138: MFC Internals

비트교육센터[138]

비트교육센터

Message Handling (cont’d)const AFX_MSGMAP* pMessageMap; pMessageMap = GetMessageMap();UINT iHash; iHash = (LOWORD((DWORD)pMessageMap) ^ message) & (iHashMax-1);AfxLockGlobals(CRIT_WINMSGCACHE);AFX_MSG_CACHE* pMsgCache; pMsgCache = &_afxMsgCache[iHash];const AFX_MSGMAP_ENTRY* lpEntry;if (message == pMsgCache->nMsg && pMessageMap == pMsgCache->pMessageMap){

…} else {

// not in cache, look for itpMsgCache->nMsg = message;pMsgCache->pMessageMap = pMessageMap;for (/* pMessageMap already init'ed */; pMessageMap != NULL;

pMessageMap = pMessageMap->pBaseMap) {AfxFindMessageEntry();

}

Page 139: MFC Internals

비트교육센터[139]

비트교육센터

Message Handling Trace두가지 종류의 message

– Regular window messageWM_MOUSEMOVE

– Command message메뉴나 control 이 보내는 messageWM_COMMAND

서로 다른 방식으로 처리– CWnd::OnWndMsg() 참고

Page 140: MFC Internals

비트교육센터[140]

비트교육센터

Handling WM_COMMAND가정

– Main frame 의 메뉴 명령 수행

CWnd::OnWndMsg() 함수에서– CWnd::OnCommand() 함수 호출

CWnd::OnCommand()– Virtual function(Framework 이 적절한 version 의 함수를 호출함 )– CFrameWnd::OnCommand()

On-line help 에 관한 것이면 해당 기능 수행아니면 CWnd::OnCommand() 함수 호출

Page 141: MFC Internals

비트교육센터[141]

비트교육센터

Handling WM_COMMAND (cont’d)“WinFrm.cpp”

BOOL CFrameWnd::OnCommand(WPARAM wParam, LPARAM lParam){

HWND hWndCtrl = (HWND)lParam;UINT nID = LOWORD(wParam);CFrameWnd* pFrameWnd = GetTopLevelFrame();ASSERT_VALID(pFrameWnd);if (pFrameWnd->m_bHelpMode&&hWndCtrl==NULL&&nID!=ID_HELP&&

nID!= ID_DEFAULT_HELP && nID != ID_CONTEXT_HELP) { // route as help if (!SendMessage(WM_COMMANDHELP, 0, HID_BASE_COMMAND+nID))

SendMessage(WM_COMMAND, ID_DEFAULT_HELP); return TRUE;}// route as normal commandreturn CWnd::OnCommand(wParam, lParam);

}

Page 142: MFC Internals

비트교육센터[142]

비트교육센터

Handling WM_COMMAND (cont’d)“WinCore.Cpp”BOOL CWnd::OnCommand(WPARAM wParam, LPARAM lParam){

if (hWndCtrl == NULL)else {

if (_afxThreadState->m_hLockoutNotifyWindow == m_hWnd)return TRUE; // locked out - ignore control notification

// reflect notification to child window controlif (ReflectLastMsg(hWndCtrl))

return TRUE; // eaten by child

// zero IDs for normal commands are not allowedif (nID == 0)

return FALSE;}return OnCmdMsg(nID, nCode, NULL, NULL);

}

Page 143: MFC Internals

비트교육센터[143]

비트교육센터

CWnd::OnCommand()(WINCORE.CPP)– LPARAM 을 조사– 만약 control 이 보낸 message 이면 control 에게 다시 message 를 reflect 한 후

return– 아니면 CWnd::OnCmdMsg()(virtual function) 함수 호출

Handling WM_COMMAND (cont’d)

Page 144: MFC Internals

비트교육센터[144]

비트교육센터

Handling WM_COMMAND (cont’d)“WinFrm.cpp”BOOL CFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra,

AFX_CMDHANDLERINFO* pHandlerInfo){

CPushRoutingFrame push(this);// pump through current view FIRSTCView* pView = GetActiveView();if (pView != NULL && pView->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))

return TRUE;// then pump through frameif (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))

return TRUE;// last but not least, pump through appCWinApp* pApp = AfxGetApp();if (pApp != NULL && pApp->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))

return TRUE;return FALSE;

}

Page 145: MFC Internals

비트교육센터[145]

비트교육센터

Handling WM_COMMAND (cont’d)“ViewCore.cpp”BOOL CView::OnCmdMsg(UINT nID, int nCode, void* pExtra,

AFX_CMDHANDLERINFO* pHandlerInfo){

// first pump through paneif (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))

return TRUE;// then pump through documentif (m_pDocument != NULL){

// special state for saving view before routing to documentCPushRoutingView push(this);return m_pDocument->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);

}return FALSE;

}

Page 146: MFC Internals

비트교육센터[146]

비트교육센터

Handling WM_COMMAND (cont’d)“DocCore.cpp”BOOL CDocument::OnCmdMsg(UINT nID, int nCode, void* pExtra,

AFX_CMDHANDLERINFO* pHandlerInfo){

if (CCmdTarget::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))return TRUE;

// otherwise check templateif (m_pDocTemplate != NULL && m_pDocTemplate->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))

return TRUE;

return FALSE;}

Page 147: MFC Internals

비트교육센터[147]

비트교육센터

CFrameWnd::OnCmdMsg()(WINFRM.CPP)

– 다음의 순서로 해당 OnCmdMsg() 함수를 호출Active viewActive view’s documentMain frame windowApplication

Handling WM_COMMAND (cont’d)

Page 148: MFC Internals

비트교육센터[148]

비트교육센터

만약 active view 에 해당 handler 가 있다면– CView::OnCmdMsg() 가 호출됨

CView::OnCmdMsg()(VIEWCORE.CPP)– View 에서 처리를 시도한 후 안되면 document 에서 처리를 시도– View 에서 처리 시도는 CWnd::OnCmdMsg() 함수의 호출로 이루어짐– 이 때 CWnd 는 OnCmdMsg 를 override 하지 않기 때문에 CCmdTarget::OnCmdM

sg 를 호출하는 결과가 됨

Handling WM_COMMAND (cont’d)

Page 149: MFC Internals

비트교육센터[149]

비트교육센터

Handling WM_COMMAND (cont’d)“CmdTarg.cpp”

BOOL CCmdTarget::OnCmdMsg(UINT nID, int nCode, void* pExtra,AFX_CMDHANDLERINFO* pHandlerInfo)

{for (pMessageMap = GetMessageMap(); pMessageMap != NULL; pMessageMap = pMessageMap->pBaseMap) {

lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries, nMsg, nCode, nID);

if (lpEntry != NULL) {return _AfxDispatchCmdMsg(this, nID, nCode,

lpEntry->pfn, pExtra, lpEntry->nSig, pHandlerInfo);}

}return FALSE; // not handled

}

Page 150: MFC Internals

비트교육센터[150]

비트교육센터

CCmdTarget::OnCmdMsg()(CMDTARG.CPP)– Message map 을 보고 message handler 를 찾음– 찾게 되면 _AfxDispatchCmdMsg() 함수를 호출하여 해당 handler 를 실행시킴

_AfxDispatchCmdMsg()(CMDTARG.CPP)– Function signature 에 따라 다른 동작을 수행

Regular commandExtended commandVisual Basic control 등등

Handling WM_COMMAND (cont’d)

Page 151: MFC Internals

비트교육센터[151]

비트교육센터

Frame window 일 때의 처리과정 정리– 1. AfxWndProc()– 1.1 AfxCallWndProc()– 1.2CWnd::WindowProc()– 1.2. 1CWnd::OnWndMsg()– CFrameWnd::OnCommand()– CWnd::OnCommand()– CFrameWnd::OnCmdMsg()– CCmdTarget::OnCmdMsg()– _AfxDispatchCmdMsg()– CMainFram::On~()

Handling WM_COMMAND (cont’d)

Page 152: MFC Internals

비트교육센터[152]

비트교육센터

Document 일 때의 처리과정 정리– AfxWndProc()– AfxCallWndProc()– CWnd::WindowProc()– CWnd::OnWndMsg()– CFrameWnd::OnCommand()– CWnd::OnCommand()– CFrameWnd::OnCmdMsg()– CView::OnCmdMsg()– Cdocument::OnCmdMsg()– CCmdTarget::OnCmdMsg()– _AfxDispatchCmdMsg()– CMyDoc::On~()

Handling WM_COMMAND (cont’d)

Page 153: MFC Internals

비트교육센터[153]

비트교육센터

View 일 때의 처리과정 정리– AfxWndProc()– AfxCallWndProc()– CWnd::WindowProc()– CWnd::OnWndMsg()– CFrameWnd::OnCommand()– CWnd::OnCommand()– CFrameWnd::OnCmdMsg()– CView::OnCmdMsg()– CCmdTarget::OnCmdMsg()– _AfxDispatchCmdMsg()– CMyView::On~()

Handling WM_COMMAND (cont’d)

Page 154: MFC Internals

비트교육센터[154]

비트교육센터

App 일 때의 처리과정 정리– AfxWndProc()– AfxCallWndProc()– CWnd::WindowProc()– CWnd::OnWndMsg()– CFrameWnd::OnCommand()– CCmdTarget::OnCmdMsg()– _AfxDispatchCmdMsg()– CMyApp::On~()

Handling WM_COMMAND (cont’d)

Page 155: MFC Internals

비트교육센터[155]

비트교육센터

Dialog Box 일 때의 처리과정 정리– AfxWndProc()– AfxCallWndProc()– CWnd::WindowProc()– CWnd::OnWndMsg()– CDialog::OnCmdMsg()– CCmdTarget::OnCmdMsg()– _AfxDispatchCmdMsg()– CAboutDlg::On~()

Handling WM_COMMAND (cont’d)

Page 156: MFC Internals

비트교육센터[156]

비트교육센터

예 – Clear All

Handling 과정 (MDI application)– Main frame window 가 message 를 받는다– 현재 활성화된 MDI child window 가 처리 할 기회를 얻는다– Child window 가 먼저 view 에게 처리 기회를 준다 .– 실패하여 view 가 연결된 document 가 처리를 시도한다– Document 가 메시지 핸들러를 찾는 데 성공한다 .

Page 157: MFC Internals

비트교육센터[157]

비트교육센터

Handling Regular Window MessageCommand message 일 때와 처음의 과정은 비슷

– AfxWndProc()– AfxCallWndProc()– WindowProc()– OnWndMsg()

이 함수 안에서 message handler 를 찾기 위해 AfxFindMessageEntry()를

호출

Page 158: MFC Internals

비트교육센터[158]

비트교육센터

Handling Regular Window Message (cont’d)

AfxFindMessageEntry()– 두 버전이 있음 .

Assembly language : intel-based machineC language : otherwise

– Message map 에서 해당 핸들러가 있는지 검색– END_MESSAGE_MAP 에 의해 생성된 table 의 끝까지 검색

Page 159: MFC Internals

비트교육센터[159]

비트교육센터

Command message 와의 차이점– Command message 는 handler 를 찾기 위해서 여러 장소를 옮겨다님– Regular message 는 OnWndMsg() 에서 handler 를 찾으면 바로 해당 handler 를

호출하고 , 아니면 DefWindowProc() 를 이용

Handling Regular Window Message (cont’d)

Page 160: MFC Internals

비트교육센터[160]

비트교육센터

예 ) View 에서 WM_SIZE message 처리 과정– AfxWndProc()– AfxCallWndProc()– CWnd::WindowProc()– CWnd::OnWndMsg()– CSdiappView::OnSize()

Handling Regular Window Message (cont’d)

Page 161: MFC Internals

비트교육센터[161]

비트교육센터

Other Kinds of Messages

지금까지 살펴 본 메시지 종류– WM_COMMAND– Window messages(WM_SIZE, WM_MOVE, …)

그 이외의 메시지 종류– WM_NOTIFY– WM_ACTIVATE– WM_SETCURSOR

Page 162: MFC Internals

비트교육센터[162]

비트교육센터

Other Kinds of Messages (cont’d)

WM_NOTIFY– Control 이 보내는 message– 항상 notify message– 반면 , WM_COMMAND

command 이거나 notify message

Page 163: MFC Internals

비트교육센터[163]

비트교육센터

Other Kinds of Messages (cont’d)

struct NMHDR {HWND hwndFrom; // control that sent notificationUINT idFrom; // ID of controlUINT code; // notification code

CWnd::OnWndMsg() 에서

// special case for notifies if (message == WM_NOTIFY) { NMHDR* pNMHDR = (NMHDR*)lParam;

if (pNMHDR->hwndFrom != NULL && OnNotify(wParam, lParam, &lResult))goto LReturnTrue;

return FALSE; …}

Page 164: MFC Internals

비트교육센터[164]

비트교육센터

Other Kinds of Messages (cont’d)“Wincore.cpp”BOOL CWnd::OnNotify(WPARAM, LPARAM lParam, LRESULT* pResult){

NMHDR* pNMHDR = (NMHDR*)lParam;HWND hWndCtrl = pNMHDR->hwndFrom;// get the child ID from the window itselfUINT nID = _AfxGetDlgCtrlID(hWndCtrl);int nCode = pNMHDR->code;if (_afxThreadState->m_hLockoutNotifyWindow == m_hWnd)

return TRUE; // locked out - ignore control notification// reflect notification to child window controlif (ReflectLastMsg(hWndCtrl, pResult)) return TRUE; // eaten by childAFX_NOTIFY notify;notify.pResult = pResult;notify.pNMHDR = pNMHDR;return OnCmdMsg(nID, MAKELONG(nCode, WM_NOTIFY), &notify, NULL);

}

Page 165: MFC Internals

비트교육센터[165]

비트교육센터

Other Kinds of Messages (cont’d)BOOL PASCAL CWnd::ReflectLastMsg(HWND hWndChild, LRESULT* pResult){

CHandleMap* pMap = afxMapHWND();CWnd* pWnd = (CWnd*)pMap->LookupPermanent(hWndChild);if (pWnd == NULL) {

// check if the window is an OLE control…return FALSE;

}

return pWnd->SendChildNotifyLastMsg(pResult);}

Page 166: MFC Internals

비트교육센터[166]

비트교육센터

Other Kinds of Messages (cont’d)BOOL CWnd::SendChildNotifyLastMsg(LRESULT* pResult){

_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();return OnChildNotify(pThreadState->m_lastSentMsg.message,

pThreadState->m_lastSentMsg.wParam, pThreadState->m_lastSentMsg.lParam, pResult);

}

Page 167: MFC Internals

비트교육센터[167]

비트교육센터

Other Kinds of Messages (cont’d)

Message reflection– OnWndMsg() 에서 OnNotify() 를 호출– OnNofity() 는 다시 OnChildNotify() 를 호출하여 control 로 message 를 다시 보냄– 결국에는 control 이 parent 에 의존하지 않고 자신의 일을 처리하게 함

Page 168: MFC Internals

비트교육센터[168]

비트교육센터

Other Kinds of Messages (cont’d)

– WM_ACTIVATEOnWndMsg() 함수에서 _AfxHandleActivate() 를 호출

– WM_SETCURSOROnWndMsg() 함수에서 _AfxHandleSetCursor() 함수 호출

Page 169: MFC Internals

비트교육센터[169]

비트교육센터

Speed Message-map Matching

방법– 최근에 처리 된 메시지를 캐쉬에 저장– 같은 메시지를 다시 처리할 가능성이 높음

장점– Unhandled message 빠르고 효과적으로 처리

Page 170: MFC Internals

비트교육센터[170]

비트교육센터

Message Loop HookingMessage loop hooking

– Message 가 해당 handler 에 의해 처리되기 전에 어떠한 작업을 하고 싶을때

– PreTranslateMessage()

CWinApp::PreTranslateMessage()– CWinApp::Run() 함수는 message 가 message pump 에 의해 처리되기

전에 위 함수를 호출

– TRUE 를 return 하면 message pump 는 해당 message 에 관해서는 처리를 하지 않음

CWnd::PreTranslateMessage()

Page 171: MFC Internals

비트교육센터[171]

비트교육센터

Message Loop Hooking (cont’d)

“THRDCORE.cpp”int CWinThread::Run(){

// for tracking the idle time stateBOOL bIdle = TRUE;LONG lIdleCount = 0;// acquire and dispatch messages until a WM_QUIT message is received.for (;;){

// phase1: check to see if we can do idle workwhile (bIdle &&!::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE)){

// call OnIdle while in bIdle stateif (!OnIdle(lIdleCount++))

bIdle = FALSE; // assume "no idle" state}

Page 172: MFC Internals

비트교육센터[172]

비트교육센터

Message Loop Hooking (cont’d)

// phase2: pump messages while availabledo {

// pump message, but quit on WM_QUITif (!PumpMessage())

return ExitInstance();

// reset "no idle" state after pumping "normal" messageif (IsIdleMessage(&m_msgCur)){

bIdle = TRUE;lIdleCount = 0;

}

} while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));}ASSERT(FALSE); // not reachable

}

Page 173: MFC Internals

비트교육센터[173]

비트교육센터

Message Loop Hooking (cont’d)

BOOL CWinThread::PumpMessage(){

ASSERT_VALID(this);

if (!::GetMessage(&m_msgCur, NULL, NULL, NULL)){}

// process this messageif (m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur)){

::TranslateMessage(&m_msgCur);::DispatchMessage(&m_msgCur);

}return TRUE;

}

Page 174: MFC Internals

비트교육센터[174]

비트교육센터

Message Loop Hooking (cont’d)

BOOL CWinThread::PreTranslateMessage(MSG* pMsg){

// if this is a thread-message, short-circuit this functionif (pMsg->hwnd == NULL && DispatchThreadMessageEx(pMsg))

return TRUE;// walk from target to main windowCWnd* pMainWnd = AfxGetMainWnd();if (CWnd::WalkPreTranslateTree(pMainWnd->GetSafeHwnd(), pMsg))

return TRUE;// in case of modeless dialogs, last chance route through main// window's accelerator tableif (pMainWnd != NULL) {

CWnd* pWnd = CWnd::FromHandle(pMsg->hwnd); if (pWnd->GetTopLevelParent() != pMainWnd)

return pMainWnd->PreTranslateMessage(pMsg);}return FALSE; // no special processing

}

Page 175: MFC Internals

비트교육센터[175]

비트교육센터

Message Loop Hooking (cont’d)

“WinCore.Cpp”BOOL PASCAL CWnd::WalkPreTranslateTree(HWND hWndStop, MSG* pMsg){

// walk from the target window up to the hWndStop window checking// if any window wants to translate this message

for (HWND hWnd=pMsg->hwnd; hWnd != NULL;hWnd=::GetParent(hWnd)){CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);if (pWnd != NULL) {

// target window is a C++ windowif (pWnd->PreTranslateMessage(pMsg))

return TRUE; }// got to hWndStop window without interestif (hWnd == hWndStop)

break;}return FALSE; // no special processing

}