MFC airensoar snu ac kr Introduction v v

  • Slides: 177
Download presentation
고급 MFC 권영근 airen@soar. snu. ac. kr

고급 MFC 권영근 airen@soar. snu. ac. kr

Introduction v 교재 Ø Ø v “MFC Internals”, George Shepherd, Addison-Wesley, 1996 MSDN Library,

Introduction v 교재 Ø Ø v “MFC Internals”, George Shepherd, Addison-Wesley, 1996 MSDN Library, http: //msdn. microsoft. com/library/ 선수 강좌 Ø Ø C++ Win 32 API

강의 계획 1. A Conceptual Overview of MFC 2. Basic Windows Support 3. Message

강의 계획 1. A Conceptual Overview of MFC 2. Basic Windows Support 3. Message Handling in MFC 4. The MFC Utility Classes 5. All Roads Lead to CObject 6. MFC Dialog and Control Classes 7. MFC’s Document/View Architecture 8. Advanced Document/View Internals 9. MFC’s Enhanced User-Interface Classes 10. MFC Dlls and Threads

Chap 1. A Conceptual Overview of MFC

Chap 1. A Conceptual Overview of MFC

Contents v v v Application Frameworks 정의 MFC의 역사 MFC의 설계 목적 MFC의 구성

Contents v v v Application Frameworks 정의 MFC의 역사 MFC의 설계 목적 MFC의 구성 MFC code basics

Application Frameworks v Framework Ø v Application Framework Ø v 특정 영역의 작업을 도와

Application Frameworks v Framework Ø v Application Framework Ø v 특정 영역의 작업을 도와 주는 class 집합 특정 OS의 application 개발 작업을 도와 주는 class 집 합 MFC (Microsoft Foundation Classes) Ø Windows용 application 개발 작업을 도와 주는 framework

MFC의 역사 v 1989년 Ø AFX group 탄생 ü Ø 목적 ü Ø Application

MFC의 역사 v 1989년 Ø AFX group 탄생 ü Ø 목적 ü Ø Application framework technology development group의 약자 Windows application개발자를 위한 C++과 object-oriented 개 념을 적용시킨 tool의 개발 First prototype 실패 ü Too complex and too different from Windows itself

MFC의 역사 (cont’d) v 1993년 Ø MFC version 2. 0 ü ü ü Visual

MFC의 역사 (cont’d) v 1993년 Ø MFC version 2. 0 ü ü ü Visual C++ version 1. 0과 Windows NT와 함께 나옴 100개가 넘는 class포함 새로 포함된 내용 Ø Ø 새로운 application architecture 새로운 high-level abstractions

MFC의 역사 (cont’d) v 1993년 Ø MFC version 2. 5 ü ü v Visual

MFC의 역사 (cont’d) v 1993년 Ø MFC version 2. 5 ü ü v Visual C++ version 1. 5와 함께 나옴 OLE 2. 0과 ODBC 지원이 추가됨 1994년 Ø MFC version 3. 0 ü Thread에 대한 기능이 보강됨

MFC의 역사 (cont’d) v 1995년 Ø MFC version 3. 1 ü 추가된 기능 Ø

MFC의 역사 (cont’d) v 1995년 Ø MFC version 3. 1 ü 추가된 기능 Ø Ø Ø Simple Messaging Application Programming Interface(MAPI) Win. Sock MFC version 4. 0 ü ü Visual C++ version 4. 0과 함께 나옴 개발환경의 발전, 재사용성의 향상

MFC의 역사 (cont’d) v 1997년 Ø MFC version 4. 2 ü ü v 1998년

MFC의 역사 (cont’d) v 1997년 Ø MFC version 4. 2 ü ü v 1998년 Ø MFC version 6. 0 ü ü v Visual C++ version 5. 0과 함께 나옴 Internet 등을 위한 기능 추가 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

MFC의 역사(cont’d) v MFC version과 Visual C++ version MFC version Visual C++ version 6.

MFC의 역사(cont’d) v MFC version과 Visual C++ version MFC version Visual C++ version 6. 0 Microsoft Visual C++ version 6. 0 4. 2 Microsoft Visual C++ versions 4. 2 and 5. 0 4. 0 Microsoft Visual C++ versions 4. 0 and 4. 1 3. 2 Microsoft Visual C++ version 2. 2 3. 1 Microsoft Visual C++ version 2. 1 3. 0 Microsoft Visual C++ version 2. 0 2. 5 Microsoft Visual C++ version 1. 5 2. 1 Microsoft Visual C++ version 1. 0 2. 0 Microsoft Visual C++ version 1. 0 Microsoft C/C++ version 7. 0

MFC 설계 목적 v AFX 그룹의 설계 목적 Ø Ø Ø Real-World Application Simplifying

MFC 설계 목적 v AFX 그룹의 설계 목적 Ø Ø Ø Real-World Application Simplifying the Windows API Using the existing knowledge of Windows Foundation for large-scale applications Small and fast framework

MFC의 구성 v MFC class 의 분류 Ø Ø General-purpose classes Windows API classes

MFC의 구성 v MFC class 의 분류 Ø Ø General-purpose classes Windows API classes Application framework classes High-level abstractions

MFC의 구성(cont’d) v General-purpose Class Ø Ø 프로그램의 일반적 용도를 위한 class CObject class

MFC의 구성(cont’d) v General-purpose Class Ø Ø 프로그램의 일반적 용도를 위한 class CObject class ü ü ü MFC의 최상위 class run-time type information, serialization, diagnostic function, support for dynamic creation 기능 제공 CArchive, CDump. Context, CRuntime. Class 등과 연계되어 작용

MFC의 구성(cont’d) Ø Exception-handling class ü ü ü memory, I/O error 발생 시 처리

MFC의 구성(cont’d) Ø Exception-handling class ü ü ü memory, I/O error 발생 시 처리 CException : base class CArchive. Exception, CFile. Exception CMemory. Exception, CResource. Exception CNot. Supported. Exception, CUser. Exception COle. Exception, CDBException

MFC의 구성(cont’d) Ø Collection class ü ü ü Array : CByte. Array, CWord. Array,

MFC의 구성(cont’d) Ø Collection class ü ü ü Array : CByte. Array, CWord. Array, CDWord. Array, CPtr. Array, COb. Array, CString. Array, CUnit. Array Linked list : COb. List, CPtr. List, CString. List Map : CMap. Ptr. To. Word, CMap. Ptr. To. Ptr, CMap. String. To. Ob, CMap. String. To. Ptr, CMap. String. To. String, CMap. Word. To. Ob, CMap. Word. To. Ptr

MFC의 구성(cont’d) Ø Dynamic string class ü ü Ø CString concatenation, comparison, assignment 등의

MFC의 구성(cont’d) Ø Dynamic string class ü ü Ø CString concatenation, comparison, assignment 등의 기본 연산 제공 File class ü ü CFile, CStdio. File, CMem. File 추상적으로 disk상의 파일 제어, 실제로는 memory상의 파일 제어

MFC의 구성(cont’d) Ø Time class ü Ø CTime, CTime. San 기타 ü CPoint, CSize,

MFC의 구성(cont’d) Ø Time class ü Ø CTime, CTime. San 기타 ü CPoint, CSize, CRect : Windows structure

MFC의 구성(cont’d) v Windows API class Ø Application 관련 class ü ü CCmd. Target

MFC의 구성(cont’d) v Windows API class Ø Application 관련 class ü ü CCmd. Target : message 처리 CCmd. UI : user interface의 update CWin. Thread : MFC program의 실행 thread를 의미, 즉 program의 main을 포함 CWin. App : CWin. Thread의 파생 class으로서 standard windows application을 표현

MFC의 구성(cont’d) Ø Window 관련 class ü ü CWnd : CCmd. Target의 파생 class이므로

MFC의 구성(cont’d) Ø Window 관련 class ü ü CWnd : CCmd. Target의 파생 class이므로 message를 handle. 윈도우를 다루는 API 포함. CFram. Wnd, CMDIFrame. Wnd : main frame window로서 message를 받는 첫 윈도우 CDialog, 공통다이어로그박스(CFile. Dialog, CColor. Dialog, CFont. Dialog, CPrint. Dialog, CFind. Replace. Dialog) CData. Exchange : DDX/DDV

MFC의 구성(cont’d) ü ü ü Ø CProperty. Sheet, CProperty. Page Controls : CButton, CEdit,

MFC의 구성(cont’d) ü ü ü Ø CProperty. Sheet, CProperty. Page Controls : CButton, CEdit, … CMenu GDI 관련 class ü ü CDC, CPaint. DC, CWindow. DC, CClient. DC, CMeta. File. DC CPen, CBrush, CFont, . . .

MFC의 구성(cont’d) v Application framework class Ø Document/View Architecture ü ü ü Ø CDoc.

MFC의 구성(cont’d) v Application framework class Ø Document/View Architecture ü ü ü Ø CDoc. Template, CSingle. Doc. Template, CMulti. Doc. Template : document와 view를 연결 CDocument : data를 관리 CView : data를 redering하여 보여 줌 Context-Sensitive Help

MFC의 구성(cont’d) v High-level abstraction Ø Enhanced Views ü ü Ø Splitter Window ü

MFC의 구성(cont’d) v High-level abstraction Ø Enhanced Views ü ü Ø Splitter Window ü Ø CScroll. View, CForm. View CEdit. View, CList. View, CRich. Edit. View, CTree. View CSplitter. Wnd : dynamic, static Control Views ü CTool. Bar, CStatus. Bar, CDialog. Bar

MFC Code Basics v Class Declaration Subsections Ø MFC library 개발 팀의 코딩 규칙

MFC Code Basics v Class Declaration Subsections Ø MFC library 개발 팀의 코딩 규칙 ü ü Ø Not based public/protected/private Private 변수는 거의 사용하지 않는다. Header / source file ü ü ü // Constructors // Attributes // Operations // Overridables // Implementation

Example of Comments class CStdio. File : public CFile { DECLARE_DYNAMIC(CStdio. File) public: //

Example of Comments class CStdio. File : public CFile { DECLARE_DYNAMIC(CStdio. File) public: // Constructors CStdio. File(); . . . // Attributes FILE* m_p. Stream; // stdio FILE. . . // Operations virtual void Write. String(LPCTSTR lpsz); . . . virtual LPTSTR Read. String(LPTSTR lpsz, UINT n. Max); . . . // Implementation public: . . . };

MFC Comments v Class Declaration Subsections Ø Ø MFC library 개발 팀의 코딩 규칙

MFC Comments v Class Declaration Subsections Ø Ø MFC library 개발 팀의 코딩 규칙 Class header file의 각 항목의 의미 ü // Constructors Ø Ø Ø ü C++ constructors, any other initialization 예) CWnd: : Create 대개는 public // Attributes Ø Ø 대개는 documented public data members Member functions(위의 data를 조작하는) : Get / Set 함수들

MFC Code Basics (cont’d) ü // Operations Ø Ø ü // Overridables Ø Ø

MFC Code Basics (cont’d) ü // Operations Ø Ø ü // Overridables Ø Ø ü Documented member functions 대개는 public, non-const : side effects 상속 받은 class가 override한 functions Pure virtual functions // Implementation Ø Ø Implementation detail Undocumented 대개는 protected 주의 : may change in future versions of MFC

MFC Code Basics (cont’d) v Variable Naming (common) Type Prefix Example Comment char c

MFC Code Basics (cont’d) v Variable Naming (common) Type Prefix Example Comment char c c. Dir. Separator BOOL b bls. Sending int n n. Variable. Cnt UINT n n. My. Unsigned WORD w w. List. ID LONG l l. Axis. Ratio DWORD dw dw. Packedmessage * (pointer) p p. Wnd FAR * lp lp. Wnd LPSTR handle lpsz h lpsz. File. Name h. Wnd Z indicates NULL terminated. callback lpfn. Hook. Proc Pointer to a function

MFC Code Basics (cont’d) v Variable Naming (MFC extensions) Class Prefix Example CRect rect.

MFC Code Basics (cont’d) v Variable Naming (MFC extensions) Class Prefix Example CRect rect. Scroll CPoint pt pt. Mouse. Click CSize sz sz. Rectangle CString str. Find CWnd Wnd. Control CWnd* p. Wnd. Dialog

MFC Code Basics (cont’d) v Symbol Naming Type Prefix Example Range Shared by multiple

MFC Code Basics (cont’d) v Symbol Naming Type Prefix Example Range Shared by multiple resources IDR_MAINFRAME 1 -0 x 6 FFF Dialog resource IDD_ABOUT 1 -0 x 6 FFF Dialog resource help context ID (for context-sensitive help) HIDD_HELP_ABOUT 0 x 2001 -0 x 26 FF Bitmap resource IDB_SMILEY 1 -0 x 6 FFF Cursor resource Icon resource IDC_HAND 1 -0 x 6 FFF

MFC Code Basics (cont’d) v Symbol Naming Type Prefix Example Range Menu or toolbar

MFC Code Basics (cont’d) v Symbol Naming Type Prefix Example Range Menu or toolbar command ID_CIRCLE_TOOL 0 x 8000 -0 x. DFFF Command help context HID_CIRCLE_TOOL 0 x 1800 -0 x 1 DFF Message box prompt IDP_FATALERROR 8 -0 x. DFFF Message box help context HIDP_FATALERROR 0 x 3008 -0 x 3 DFF Control in dialog template IDC_COMBO 1 8 -0 x. DFFF String resource IDS_ERROR 12 1 -0 x 7 FFF

Chap. 2 Basic Windows Support

Chap. 2 Basic Windows Support

Contents v v v Introduction MFC versus C/SDK Basic Application Components Ø Ø Ø

Contents v v v Introduction MFC versus C/SDK Basic Application Components Ø Ø Ø v v Find Win. Main() Hidden Cool Stuff Ø Ø Ø v CWin. App CWnd Window handles & Window objects Registering Window Classes MFC’s Windows Hooks MFC’s Message Pump MFC’s GDI Support

Introduction v MFC Ø Ø v 200개 이상의 클래스들의 거대한 집합 But, MFC has

Introduction v MFC Ø Ø v 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 ü Win. Main, window class 등록, 메시지 루프, …

Issue v MFC가 어떻게 Windows application을 만드는가 Ø Ø The application itself Windows Message

Issue v MFC가 어떻게 Windows application을 만드는가 Ø Ø The application itself Windows Message handling The Graphics Device Interface (GDI)

MFC vs. C/SDK v Motivation Ø 모든 Windows application은 다음 2개의 component를 포함한다. ü

MFC vs. C/SDK v Motivation Ø 모든 Windows application은 다음 2개의 component를 포함한다. ü ü Ø C/SDK 개발 환경 ü ü Ø main application itself message를 핸들하는 하나 이상의 window copy & paste Time-consuming & inefficient C++/MFC 개발 환경 ü ü OOP 활용 : inheritance & encaptulation 필요한 부분만 변경

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

메시지 처리를 위한 작업들 v Set up a message handler and register it Ø Regiser. Class() v Windows가 application의 instance들을 추적 v application은 Windows에게 메시지를 요청(ask) 하고, 처리(dispatch)한다. v application이 종료될 때까지 위 작업을 반복한다.

Application의 준비 1. Win. Main() 함수 Ø Ø 프로그램의 시작점 Windows 로부터 프로그램을 실행하는데

Application의 준비 1. Win. Main() 함수 Ø Ø 프로그램의 시작점 Windows 로부터 프로그램을 실행하는데 필요한 정보 를 얻어 오는 통로 ü 2. 적어도 하나의 main window class를 등록 Ø 3. 4. User interface를 제공 Message loop를 설정 Some initialization and setup Ø 5. 현재 instance의 handle, 직전에 실행된 instance의 handle, command line argument, window의 모습(최대화, 최소화, …) Application specific, instance specific Message handler를 제공 v 최소한 WM_DESTROY 처리 -> WM_QUIT 생성

Application의 기본 요소 Message Handler Main 함수 Application specific Initialization (Window class 등록) Instance

Application의 기본 요소 Message Handler Main 함수 Application specific Initialization (Window class 등록) Instance specific Initialization (Main window(UI)생성, 보여줌) Message loop

Source 1 : C/SDK #include <windows. h> HANDLE h. Inst; /* current instance */

Source 1 : C/SDK #include <windows. h> HANDLE h. Inst; /* current instance */ LRESULT CALLBACK Main. Wnd. Proc(HANDLE h. Wnd, UINT message, WPARAM w. Param, LPARAM l. Param) { switch(message) { case WM_LBUTTONDOWN: Message. Box(h. Wnd, “Left mouse button clicked”, NULL, MB_OK); break; case WM_DESTROY: Post. Quit. Message(0); break; default: /* Passes it on if unprocessed */ return (Def. Window. Proc(h. Wnd, message, w. Param, l. Param)); } return 0; }

BOOL Init. Application(HANDLE h. Instance){ WNDCLASS wc; wc. style = 0; /* Class style(s)

BOOL Init. Application(HANDLE h. Instance){ WNDCLASS wc; wc. style = 0; /* Class style(s) */ wc. lpfn. Wnd. Proc = Main. Wnd. Proc; /* Message handler */ wc. cb. Cls. Extra = 0; /* No per-class extra data */ wc. cb. Wnd. Extra = 0; /* No per-window extra data */ wc. h. Instance = h. Instance; /* Application that owns the class*/ wc. h. Icon = Load. Icon(NULL, IDI_APPLICATION); wc. h. Cursor = Load. Cursor(NULL, IDC_ARROW); wc. hbr. Background = Get. Stock. Object(WHITE_BRUSH); wc. lpsz. Menu. Name = NULL; /* Name of menu */ wc. lpsz. Class. Name = “Minimal. WClass”; /* Name of window class */ return (Register. Class(&wc)); }

BOOL Init. Instance(HANDLE h. Instance, int n. Cmd. Show) { HWND h. Wnd; /*

BOOL Init. Instance(HANDLE h. Instance, int n. Cmd. Show) { HWND h. Wnd; /* Main window handle */ h. Inst = h. Instance; // needed for loading resources // h. Wnd = Create. Window( “Minimal. WClass”, “Minimal”, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, NULL, h. Instance, NULL); /* /* /* Window class */ Caption */ Window style */ Default horizontal pos. */ Default vertical pos. */ Default width */ Default height. */ No parent */ Use the window class menu */ This instance owns the window. */

if (!h. Wnd) return (FALSE); Show. Window(h. Wnd, n. Cmd. Show); Update. Window(h. Wnd);

if (!h. Wnd) return (FALSE); Show. Window(h. Wnd, n. Cmd. Show); Update. Window(h. Wnd); return (TRUE); }

int WINAPI Win. Main(HINSTANCE h. Instance, HINSTANCE h. Prev. Instance, LPSTR lp. Cmd. Line,

int WINAPI Win. Main(HINSTANCE h. Instance, HINSTANCE h. Prev. Instance, LPSTR lp. Cmd. Line, int n. Cmd. Show) { MSG msg; /* message */ if (!h. Prev. Instance) { if (!Init. Application(h. Instance)) return (FALSE); } /* First instance? */ /* Shared stuff */ /* cannot initialize */ if (!Init. Instance(h. Instance, n. Cmd. Show)) return (FALSE); while (Get. Message(&msg, NULL, 0, 0)) { Translate. Message(&msg); Dispatch. Message(&msg); } return(msg. w. Param); /*Returns the value from Post. Quit. Message*/ }

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

Source 2 : MFC #include <afxwin. h> // MFC 주요 클래스 선언 class CGeneric. App : public CWin. App { public: virtual BOOL Init. Instance(); }; class CGeneric. Window : public CFrame. Wnd { public: CGeneric. Window() { Create(NULL, “Generic”); } afx_msg void On. LButton. Down(UINT n. Flags, CPoint point); DECLARE_MESSAGE_MAP() };

BEGIN_MESSAGE_MAP(CGeneric. Window, CFrame. Wnd) ON_WM_LBUTTONDOWN() END_MESSAGE_MAP() void CGeneric. Window: : On. LButton. Down(UINT n.

BEGIN_MESSAGE_MAP(CGeneric. Window, CFrame. Wnd) ON_WM_LBUTTONDOWN() END_MESSAGE_MAP() void CGeneric. Window: : On. LButton. Down(UINT n. Flags, CPoint point) { Message. Box(“Left mouse button pressed…”, NULL, MB_OK); } BOOL CGeneric. App: : Init. Instance() { m_p. Main. Wnd = new CGeneric. Window(); m_p. Main. Wnd->Show. Window(m_n. Cmd. Show); m_p. Main. Wnd->Update. Window(); return TRUE; } CGeneric. App;

C/SDK와 MFC의 비교 v Win. Main() Function Ø Ø v Window class 등록 Ø

C/SDK와 MFC의 비교 v Win. Main() Function Ø Ø v Window class 등록 Ø Ø v C/SDK : 존재 MFC : where? ( part of application framework ) C/SDK : 존재 MFC : where? Message loop Ø Ø C/SDK : 존재 MFC : where? ü Additional functions : idle processing, Pre. Translate. Message()

C/SDK와 MFC의 비교 (cont’d) v Instance initialization Ø Ø v C/SDK : 존재 MFC

C/SDK와 MFC의 비교 (cont’d) v Instance initialization Ø Ø v C/SDK : 존재 MFC : 존재, 그러나 언제 실행? Message handling Ø Ø C/SDK : 존재 MFC : 존재, 그러나 어떻게 command-routing, message-dispatch? ü ü Member functions + Message map Afx. Wnd. Proc() : 공통 window procedure

Basic MFC Application Components v Windows application의 두 가지 components Ø Ø v Message

Basic MFC Application Components v Windows application의 두 가지 components Ø Ø v Message pump Window procedure MFC에서의 구현 방법 Ø CWin. App ü ü Ø Application을 나타내는 class application-specific : 초기화, window 생성, 메시지 루프 CWnd ü ü Window를 나타내는 class window-specific : 메시지 핸들링

CWin. App (“Afx. Win. h”) CWin. App : public CWin. Thread { public: //

CWin. App (“Afx. Win. h”) CWin. App : public CWin. Thread { public: // Constructor CWin. App(LPCTSTR lpsz. App. Name = NULL); to EXE name // app name defaults // Attributes // Startup args (do not change) HINSTANCE m_h. Instance; HINSTANCE m_h. Prev. Instance; // not used LPTSTR m_lp. Cmd. Line; int m_n. Cmd. Show; // Running args (can be changed in Init. Instance) LPCTSTR m_psz. App. Name; // human readable name // (from constructor or AFX_IDS_APP_TITLE)

public: // set in constructor to override default LPCTSTR m_psz. Exe. Name; // executable

public: // set in constructor to override default LPCTSTR m_psz. Exe. Name; // executable name (no spaces) LPCTSTR m_psz. Help. File. Path; // default based on module path LPCTSTR m_psz. Profile. Name; // default based on app name // Overridables // hooks for your initialization code virtual BOOL Init. Application(); void Set. Current. Handles(); // overrides for implementation virtual BOOL Init. Instance(); virtual int Exit. Instance(); // return app exit code virtual int Run(); virtual BOOL On. Idle(LONG l. Count); // return TRUE if more idle processing virtual LRESULT Process. Wnd. Proc. Exception (CException* e, const MSG* p. Msg);

public: virtual ~CWin. App(); protected: //{{AFX_MSG(CWin. App) afx_msg void On. App. Exit(); afx_msg void

public: virtual ~CWin. App(); protected: //{{AFX_MSG(CWin. App) afx_msg void On. App. Exit(); afx_msg void On. Update. Recent. File. Menu(CCmd. UI* p. Cmd. UI); afx_msg BOOL On. Open. Recent. File(UINT n. ID); //}}AFX_MSG DECLARE_MESSAGE_MAP() };

CWin. App v v AFXWIN. h 멤버 변수와 멤버 함수 Ø Win. Main()에 전달된

CWin. App v v AFXWIN. h 멤버 변수와 멤버 함수 Ø Win. Main()에 전달된 command line parameter 를 관리 할 변수 ü ü m_h. Instance : the current instance handle m_h. Prev. Instance : the previous instance handle m_lp. Cmd. Line : the command line parameters m_n. Cmd. Show : the show window flag

CWin. App (cont’d) Ø Ø m_psz. App. Name : application name 관련 pointer ü

CWin. App (cont’d) Ø Ø m_psz. App. Name : application name 관련 pointer ü ü ü Ø m_psz. Exe. Name : executable file name m_psz. Help. File. Path : the path to help file m_psz. Profile. Name : application profiles name 프로그램 실행 시 주어진 command line parameter 유 지 ü CCommand. Line. Info class 이용 (AFXWIN. H)

CWin. App (cont’d) Ø Ø Init. Instance() : instance-specific 초기화 Exit. Instance() : instance

CWin. App (cont’d) Ø Ø Init. Instance() : instance-specific 초기화 Exit. Instance() : instance 종료 시 처리 Run() : message pump 수행 On. Idle() : Message queue가 비었을 때, Run 함수에 의해 호출

CWnd v AFXWIN. H v 2가지 기능 수행 Ø Wrapping the regular Windows API

CWnd v AFXWIN. H v 2가지 기능 수행 Ø Wrapping the regular Windows API ü Ø 예: Create(), Show. Window(), … Higher-level MFC-related functionality ü 예: default message handling

CWnd ( 기능 1 ) v Wrapping the Windows API Ø Ø m_h. Wnd

CWnd ( 기능 1 ) v Wrapping the Windows API Ø Ø m_h. Wnd : regular API-level window handle 을 나타내 기 위한 멤버변수 window handle을 인자로 갖는 거의 모든 API를 멤버 함수로 가진다. ü 예) API HWND h. Wnd; Show. Window(h. Wnd, SW_SHOWNORMAL); MFC CWnd * p. Wnd; p. Wnd->Show. Window(SW_SHOWNORMAL); Ø AFXWIN 2. INL : API 의 호출 _AFXWIN_INLINE BOOL CWnd: : Show. Window(int n. Cmd. Show) { ASSERT(: : Is. Window(m_h. Wnd)); return : : Show. Window(m_h. Wnd, n. Cmd. Show); }

CWnd ( 기능 2 ) v Higher-level MFC-related functionality Ø Ø CObject -> CCmd.

CWnd ( 기능 2 ) v Higher-level MFC-related functionality Ø Ø CObject -> CCmd. Target -> CWnd CObject derivation ü ü Ø CCmd. Target derivation ü Ø Dynamic run-time information Serialization MFC’s message-routing scheme Default message handling 제공

예 : default message handling _AFXWIN_INLINE void CWnd: : On. Activate(UINT, CWnd*, BOOL) {

예 : default message handling _AFXWIN_INLINE void CWnd: : On. Activate(UINT, CWnd*, BOOL) { Default(); } LRESULT CWnd: : Default() { // call Def. Window. Proc with the last message _AFX_THREAD_STATE* p. Thread. State = _afx. Thread. State. Get. Data(); return Def. Window. Proc(p. Thread. State->m_last. Sent. Msg. message, p. Thread. State->m_last. Sent. Msg. w. Param, p. Thread. State->m_last. Sent. Msg. l. Param); }

Turning Window Handles into Window Objects High Level Application MFC object CHandle. Map class

Turning Window Handles into Window Objects High Level Application MFC object CHandle. Map class Low Level Windows OS Window handle

계층적 관계 v High level : MFC object Ø v Low level : Window

계층적 관계 v High level : MFC object Ø v Low level : Window handle Ø v v application 입장에서는 MFC object를 이용 Windows OS는 handle을 이용 MFC는 어떤 handle에 어떤 object가 연결되어 있 는지를 알아야 함 CHandle. Map class를 이용하여 구현

CHandle. Map v v AFXSTAT_. H Mapping window handle to MFC object Ø Ø

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

CHandle. Map (cont’d) v 멤버변수 Ø CMap. Ptr. To. Ptr m_permanant. Map ü ü

CHandle. Map (cont’d) v 멤버변수 Ø CMap. Ptr. To. Ptr m_permanant. Map ü ü Ø Permanent map 명시적으로 객체가 생성될 때 정보가 추가됨(CWnd’s: : Create()) 객체가 종료될 때 정보가 제거됨 (CWnd’s: : On. Nc. Destroy()) cf) WM_NCCREAT -> WM_CREAT -> … -> WM_DESTROY -> WM_NCDESTROY CMap. Ptr. To. Ptr m_temporary. Map ü ü Temporary map 임시로 생성해야 할때(ex: CWnd: : Get. Active. Window()) 실제로는 CWnd: : Handle. Map 에서 필요할 때 생성 On. Idle()에서 삭제 => Delete. Temp. Map() 호출

CHandle. Map (cont’d) v 멤버함수 Ø CWnd: : From. Handle(HWND h. Wnd) ü ü

CHandle. Map (cont’d) v 멤버함수 Ø CWnd: : From. Handle(HWND h. Wnd) ü ü 주어진 window handle에 mapping되는 object의 pointer를 얻 을 때 사용 h. Wnd를 wrap하고 있는 CWnd pointer return 만약 없으면 h. Wnd를 wrap하는 temporary CWnd return 획득하면 역으로 object를 통해 h. Wnd의 접근이 용이 ( CWnd: : m_h. Wnd 멤버 변수 )

Temporary map 예 “AFXWIN 2. INL” _AFXWIN_INLINE CWnd* PASCAL CWnd: : Get. Active. Window()

Temporary map 예 “AFXWIN 2. INL” _AFXWIN_INLINE CWnd* PASCAL CWnd: : Get. Active. Window() { return CWnd: : From. Handle(: : Get. Active. Window()); } “Wincore. cpp” CWnd* PASCAL CWnd: : From. Handle(HWND h. Wnd) { CHandle. Map* p. Map = afx. Map. HWND(TRUE); CWnd* p. Wnd = (CWnd*)p. Map->From. Handle(h. Wnd); return p. Wnd; }

Temporary map 예 (cont’d) “Winhand. cpp” CObject* CHandle. Map: : From. Handle(HANDLE h) {

Temporary map 예 (cont’d) “Winhand. cpp” CObject* CHandle. Map: : From. Handle(HANDLE h) { if (h == NULL) return NULL; CObject* p. Object = Lookup. Permanent(h); if (p. Object != NULL) return p. Object; // return permanent one else if ((p. Object = Lookup. Temporary(h)) != NULL) { HANDLE* ph = (HANDLE*)((BYTE*)p. Object + m_n. Offset); ph[0] = h; if (m_n. Handles == 2) { ph[1] = h; } return p. Object; // return current temporary one }

Temporary map 예 (cont’d) CObject* p. Temp = NULL; TRY { p. Temp =

Temporary map 예 (cont’d) CObject* p. Temp = NULL; TRY { p. Temp = m_p. Class->Create. Object(); m_temporary. Map. Set. At((LPVOID)h, p. Temp); } CATCH_ALL(e) { Afx. Set. New. Handler(pnh. Old. Handler); Afx. Enable. Memory. Tracking(b. Enable); THROW_LAST(); } END_CATCH_ALL Afx. Set. New. Handler(pnh. Old. Handler); Afx. Enable. Memory. Tracking(b. Enable); HANDLE* ph = (HANDLE*)((BYTE*)p. Temp + m_n. Offset); ph[0] = h; if (m_n. Handles == 2) ph[1] = h; return p. Temp; }

Other Mapping v AFX_MODULE_THREAD_STATE Ø m_pmap. HWND ü Ø m_pmap. HMENU ü Ø device

Other Mapping v AFX_MODULE_THREAD_STATE Ø m_pmap. HWND ü Ø m_pmap. HMENU ü Ø device context handles CDC objects m_pmap. HGDIOBJ ü Ø menu handles CMenu objects m_pmap. HDC ü Ø window handles CWnd objects GDI object handles CGDIObjects m_pmap. HIMAGELIST ü image list handles CImage. List objects

Attaching & Detaching v Window handles과 CWnd-derived objects를 연관 시켜주는 함수 Ø CWnd: :

Attaching & Detaching v Window handles과 CWnd-derived objects를 연관 시켜주는 함수 Ø CWnd: : Attach() ü ü Ø 주어진 window handle을 CWnd: : m_h. Wnd에 대입 MFC’s permanent map에 정보 추가 CWnd: : Detach() ü ü CWnd: : m_h. Wnd를 NULL로 만듬 MFC’s permanent map에서 정보 제거

CWnd: : Attach BOOL CWnd: : Attach(HWND h. Wnd. New) { ASSERT(m_h. Wnd ==

CWnd: : Attach BOOL CWnd: : Attach(HWND h. Wnd. New) { ASSERT(m_h. Wnd == NULL); // only attach once, detach on destroy ASSERT(From. Handle. Permanent(h. Wnd. New) == NULL); // must not already be in permanent map if (h. Wnd. New == NULL) return FALSE; CHandle. Map* p. Map = afx. Map. HWND(TRUE); ASSERT(p. Map != NULL); p. Map->Set. Permanent(m_h. Wnd = h. Wnd. New, this); Attach. Control. Site(p. Map); return TRUE; }

CWnd: : Detach HWND CWnd: : Detach() { HWND h. Wnd = m_h. Wnd;

CWnd: : Detach HWND CWnd: : Detach() { HWND h. Wnd = m_h. Wnd; if (h. Wnd != NULL) { CHandle. Map* p. Map = afx. Map. HWND(); // don't create if not exist if (p. Map != NULL) p. Map->Remove. Handle(m_h. Wnd); m_h. Wnd = NULL; } m_p. Ctrl. Site = NULL; return h. Wnd; }

주의 v Multiple threads Ø Ø Permanent , temporary map 모두 thread 단위로 저장

주의 v Multiple threads Ø Ø Permanent , temporary map 모두 thread 단위로 저장 전달할 경우 object 대신 HANDLE 을 보내는 것이 바람 직 Thread 1 Thread 2 Window create 접근 불가

Find Win. Main() v APPCORE. CPP Ø v CWin. App 생성자 호출 APPMODULE. CPP

Find Win. Main() v APPCORE. CPP Ø v CWin. App 생성자 호출 APPMODULE. CPP Ø _t. Win. Main() extern "C" int WINAPI _t. Win. Main(HINSTANCE h. Instance, HINSTANCE h. Prev. Instance, LPTSTR lp. Cmd. Line, int n. Cmd. Show) { // call shared/exported Win. Main return Afx. Win. Main(h. Instance, h. Prev. Instance, lp. Cmd. Line, n. Cmd. Show); }

Find Win. Main() (cont’d) v WINMAIN. CPP Ø Afx. Win. Main() int AFXAPI Afx.

Find Win. Main() (cont’d) v WINMAIN. CPP Ø Afx. Win. Main() int AFXAPI Afx. Win. Main(HINSTANCE h. Instance, HINSTANCE h. Prev. Instance, LPTSTR lp. Cmd. Line, int n. Cmd. Show) { int n. Return. Code = -1; CWin. Thread* p. Thread = Afx. Get. Thread(); CWin. App* p. App = Afx. Get. App(); // AFX internal initialization if (!Afx. Win. Init(h. Instance, h. Prev. Instance, lp. Cmd. Line, n. Cmd. Show)) goto Init. Failure; // App global initializations (rare) if (p. App != NULL && !p. App->Init. Application()) goto Init. Failure;

Find Win. Main() (cont’d) // Perform specific initializations if (!p. Thread->Init. Instance()) { if

Find Win. Main() (cont’d) // Perform specific initializations if (!p. Thread->Init. Instance()) { if (p. Thread->m_p. Main. Wnd != NULL) { p. Thread->m_p. Main. Wnd->Destroy. Window(); } n. Return. Code = p. Thread->Exit. Instance(); goto Init. Failure; } n. Return. Code = p. Thread->Run(); Afx. Win. Term(); return n. Return. Code; }

Find Win. Main() (cont’d) v APPINIT. CPP Ø Afx. Win. Init() BOOL AFXAPI Afx.

Find Win. Main() (cont’d) v APPINIT. CPP Ø Afx. Win. Init() BOOL AFXAPI Afx. Win. Init(HINSTANCE h. Instance, HINSTANCE h. Prev. Instance, LPTSTR lp. Cmd. Line, int n. Cmd. Show) { // handle critical errors and avoid Windows message boxes Set. Error. Mode(0) | SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); // set resource handles AFX_MODULE_STATE* p. Module. State = Afx. Get. Module. State(); p. Module. State->m_h. Current. Instance. Handle = h. Instance; p. Module. State->m_h. Current. Resource. Handle = h. Instance;

Find Win. Main() (cont’d) // fill in the initial state for the application CWin.

Find Win. Main() (cont’d) // fill in the initial state for the application CWin. App* p. App = Afx. Get. App(); if (p. App != NULL) { // Windows specific initialization (not done if no CWin. App) p. App->m_h. Instance = h. Instance; p. App->m_h. Prev. Instance = h. Prev. Instance; p. App->m_lp. Cmd. Line = lp. Cmd. Line; p. App->m_n. Cmd. Show = n. Cmd. Show; p. App->Set. Current. Handles(); } // initialize thread specific data (for main thread) if (!afx. Context. Is. DLL) Afx. Init. Thread(); return TRUE; }

Find Win. Main() (cont’d) v Init. Application() Ø v Init. Instance() Ø v application-specific,

Find Win. Main() (cont’d) v Init. Application() Ø v Init. Instance() Ø v application-specific, but do nothing instance-specific, virtual Run()

CWin. App 생성자 CWin. App: : CWin. App(LPCTSTR lpsz. App. Name) { if (lpsz.

CWin. App 생성자 CWin. App: : CWin. App(LPCTSTR lpsz. App. Name) { if (lpsz. App. Name != NULL) m_psz. App. Name = _tcsdup(lpsz. App. Name); else m_psz. App. Name = NULL; // initialize CWin. Thread state AFX_MODULE_STATE* p. Module. State = _AFX_CMDTARGET_GETSTATE(); AFX_MODULE_THREAD_STATE* p. Thread. State = p. Module. State->m_thread; p. Thread. State->m_p. Current. Win. Thread = this; m_h. Thread = : : Get. Current. Thread(); m_n. Thread. ID = : : Get. Current. Thread. Id(); // initialize CWin. App state ASSERT(afx. Current. Win. App == NULL); // only one CWin. App object please p. Module. State->m_p. Current. Win. App = this; ASSERT(Afx. Get. App() == this);

CWin. App 생성자 (cont’d) // in non-running state until Win. Main m_h. Instance =

CWin. App 생성자 (cont’d) // in non-running state until Win. Main m_h. Instance = NULL; m_psz. Help. File. Path = NULL; m_psz. Profile. Name = NULL; m_psz. Registry. Key = NULL; m_psz. Exe. Name = NULL; m_p. Recent. File. List = NULL; m_p. Doc. Manager = NULL; m_atom. App = m_atom. System. Topic = NULL; m_lp. Cmd. Line = NULL; m_p. Cmd. Info = NULL; // other initialization m_b. Help. Mode = FALSE; m_n. Safety. Pool. Size = 512; // default size }

Init. Application() BOOL CWin. App: : Init. Application() { if (CDoc. Manager: : p.

Init. Application() BOOL CWin. App: : Init. Application() { if (CDoc. Manager: : p. Static. Doc. Manager != NULL) { if (m_p. Doc. Manager == NULL) m_p. Doc. Manager = CDoc. Manager: : p. Static. Doc. Manager; CDoc. Manager: : p. Static. Doc. Manager = NULL; } if (m_p. Doc. Manager != NULL) m_p. Doc. Manager->Add. Doc. Template(NULL); else CDoc. Manager: : b. Static. Init = FALSE; return TRUE; }

Init. Instance() BOOL CWin. App: : Init. Instance() { return TRUE; }

Init. Instance() BOOL CWin. App: : Init. Instance() { return TRUE; }

Run() int CWin. Thread: : Run() { // for tracking the idle time state

Run() int CWin. Thread: : Run() { // for tracking the idle time state BOOL b. Idle = TRUE; LONG l. Idle. Count = 0; // acquire and dispatch messages until a WM_QUIT message for (; ; ) { // phase 1: check to see if we can do idle work while (b. Idle && !: : Peek. Message( &m_msg. Cur, NULL, PM_NOREMOVE)) { // call On. Idle while in b. Idle state if (!On. Idle(l. Idle. Count++)) b. Idle = FALSE; // assume "no idle" state }

Run (cont’d) // phase 2: pump messages while available do { // pump message,

Run (cont’d) // phase 2: pump messages while available do { // pump message, but quit on WM_QUIT if (!Pump. Message()) return Exit. Instance(); // reset "no idle" state after pumping "normal" message if (Is. Idle. Message(&m_msg. Cur)) { b. Idle = TRUE; l. Idle. Count = 0; } } while (: : Peek. Message (&m_msg. Cur, NULL, PM_NOREMOVE)); } ASSERT(FALSE); // not reachable }

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

MFC state information v v 프로그램 종료까지 유지되는 정보 AFX_MODULE_STATE class Ø Ø AFXSTAT_. H 보유하는 정보 ü ü Main window handles Resource, module handles Memory allocation tracking ODBC support, OLE support, exception handling

Hidden Cool Stuff v 2 issues Ø Ø window class의 등록 Windows hook와 MFC

Hidden Cool Stuff v 2 issues Ø Ø window class의 등록 Windows hook와 MFC window의 연결

Registering Window Classes v Windows application Ø v OS 에 적어도 하나 이상의 window

Registering Window Classes v Windows application Ø v OS 에 적어도 하나 이상의 window class를 등록해야만 한다. window class Ø window의 기본적인 성질 정의 ü ü appearance ( via some flag ) behavior ( via a callback function )

Registering Window Classes (cont’d) v MFC의 window class 등록 Ø 4개의 기본 window class

Registering Window Classes (cont’d) v MFC의 window class 등록 Ø 4개의 기본 window class 등록 ü ü Ø regular child windows a control bar window an MDI frame window a window for an SDI or MDI child window 기타 ü common controls

Registering Window Classes (cont’d) v WNDCLASSes and MFC Style of window Lpfn. Wnd. Proc

Registering Window Classes (cont’d) v WNDCLASSes and MFC Style of window Lpfn. Wnd. Proc Cb. Cls. Extra Cb. Wnd. Extra HInstance HIcon HCursor Hbr. Background Lpsz. Menu. Name Lpsz. Class. Name window proc, must be Afx. Wnd. Proc not used ( 0 ) automatically filled with Afx. Get. Instance. Handle icon for frame window cursor for when mouse is over window background color not used ( NULL ) class name

Registering Window Classes (cont’d) v Afx. Wnd Ø Ø Ø v Used for all

Registering Window Classes (cont’d) v Afx. Wnd Ø Ø Ø v Used for all child windows (CWnd: : Create) Class style : CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW No icon Arrow cursor No background color Afx. Frame. Or. View Ø Ø Ø 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

Registering Window Classes (cont’d) v Afx. MDIFrame Ø Ø Ø v Used for MDI

Registering Window Classes (cont’d) v Afx. MDIFrame Ø Ø Ø v Used for MDI frame window (CMDIFrame. Wnd: : Create) Class style : CS_DBLCLKS Icon AFX_IDI_STD_MDIFRAME Arrow cursor No background color Afx. Control. Bar Ø Ø Ø Used for standard control bar implementation Class style : 0 No icon Arrow cursor Gray background color (COLOR_BTNFACE)

Registering Window Classes (cont’d) v Afx. Defer. Register. Class() Ø v AFXIMPL. H Afx.

Registering Window Classes (cont’d) v Afx. Defer. Register. Class() Ø v AFXIMPL. H Afx. End. Defer. Register. Class() Ø WINCORE. CPP #define Afx. Defer. Register. Class(f. Class) Afx. End. Defer. Register. Class(f. Class) BOOL AFXAPI Afx. End. Defer. Register. Class(LONG f. To. Register);

Class 등록 예 “WINCORE. CPP” BOOL CWnd: : Create. Ex(DWORD dw. Ex. Style, LPCTSTR

Class 등록 예 “WINCORE. CPP” BOOL CWnd: : Create. Ex(DWORD dw. Ex. Style, LPCTSTR lpsz. Class. Name, LPCTSTR lpsz. Window. Name, DWORD dw. Style, int x, int y, int n. Width, int n. Height, HWND h. Wnd. Parent, HMENU n. IDor. HMenu, LPVOID lp. Param) { // allow modification of several common create parameters CREATESTRUCT cs; cs. dw. Ex. Style = dw. Ex. Style; cs. lpsz. Class = lpsz. Class. Name; cs. lpsz. Name = lpsz. Window. Name; cs. style = dw. Style; cs. x = x; cs. y = y; cs. cx = n. Width; cs. cy = n. Height; cs. hwnd. Parent = h. Wnd. Parent; cs. h. Menu = n. IDor. HMenu; cs. h. Instance = Afx. Get. Instance. Handle(); cs. lp. Create. Params = lp. Param;

Class 등록 예 (cont’d) if (!Pre. Create. Window(cs)) { Post. Nc. Destroy(); return FALSE;

Class 등록 예 (cont’d) if (!Pre. Create. Window(cs)) { Post. Nc. Destroy(); return FALSE; } Afx. Hook. Window. Create(this); HWND h. Wnd = : : Create. Window. Ex(cs. dw. Ex. Style, cs. lpsz. Class, cs. lpsz. Name, cs. style, cs. x, cs. y, cs. cx, cs. cy, cs. hwnd. Parent, cs. h. Menu, cs. h. Instance, cs. lp. Create. Params); if (h. Wnd == NULL) Get. Last. Error()); if (!Afx. Unhook. Window. Create()) Post. Nc. Destroy(); if (h. Wnd == NULL) return FALSE; ASSERT(h. Wnd == m_h. Wnd); // should have been set in send msg hook return TRUE; }

Class 등록 예 (cont’d) BOOL CWnd: : Pre. Create. Window(CREATESTRUCT& cs) { if (cs.

Class 등록 예 (cont’d) BOOL CWnd: : Pre. Create. Window(CREATESTRUCT& cs) { if (cs. lpsz. Class == NULL) { // make sure the default window class is registered VERIFY(Afx. Defer. Register. Class(AFX_WND_REG)); // no WNDCLASS provided - use child window default ASSERT(cs. style & WS_CHILD); cs. lpsz. Class = _afx. Wnd; } return TRUE; }

Device Contexts v CDC Ø CPaint. DC ü ü Ø CWindow. DC ü ü

Device Contexts v CDC Ø CPaint. DC ü ü Ø CWindow. DC ü ü Ø 전체 스크린을 표시 (client area+frame) Get. Window. DC() ~ Release. DC() CClient. DC ü ü Ø painting 작업이 발생할 때 Begin. Paint() ~ End. Paint() Client area를 표시 Get. Client. DC() ~ Release. DC() CMeta. File. DC ü ü 메타파일에 대한 그리기 작업 생성자 ~ Create() ~ Delete. Meta. File()

Graphic Objects v CGdi. Object : Base class Ø Ø Ø v CPen CBrush

Graphic Objects v CGdi. Object : Base class Ø Ø Ø v CPen CBrush CFont CBitmap CPalette CRgn Win 32 API의 함수들을 wrapping

예제 CMy. Wnd: : On. Paint() { CPaint. DC CPen* CPen paint. DC(this); p.

예제 CMy. Wnd: : On. Paint() { CPaint. DC CPen* CPen paint. DC(this); p. Old. Pen; blue. Pen(PS_SOLID, 25, RGB(0, 0, 255)); p. Old. Pen = paint. DC. Select. Object(&blue. Pen); paint. DC. Move. To(1, 1); paint. DC. Line. To(100, 100); paint. DC. Select. Object(p. Old. Pen); }

Chap. 3 Message Handling

Chap. 3 Message Handling

Contents v v v Introduction Window messages Message mapping MFC가 message map을 이용하는 방법

Contents v v v Introduction Window messages Message mapping MFC가 message map을 이용하는 방법 Message loop의 hooking

Introduction v Message handling Ø C/SDK ü Ø Switch/case 문을 통해 구현 MFC ü

Introduction v Message handling Ø C/SDK ü Ø Switch/case 문을 통해 구현 MFC ü ü Switch/case 문은 없다 Callback function은 어떻게 정의되는가

Basic Components v MFC의 message handling 구조 Ø Ø v CCmd. Target class Message

Basic Components v MFC의 message handling 구조 Ø Ø v CCmd. Target class Message maps MFC message maps에 대한 의문 Ø Ø 어떻게 switch/case문을 대체하는가 어떤 data structure로 정의되는가 어떻게 message map이 작동하는가 어떻게 message가 연결되는가

Window Messages (cont’d) v 핸들링 클래스 Ø Windows message, control notification ü Ø CWnd

Window Messages (cont’d) v 핸들링 클래스 Ø Windows message, control notification ü Ø CWnd 로부터 파생된 클래스들 : HWND 를 포함 Command message ü ü 다양한 종류 : CCmd. Target 로부터 파생된 클래스들 예) open 명령 핸들링 : application

UI Objects and Command IDs

UI Objects and Command IDs

Message Handling in C/SDK v Windows program의 정수 While (Get. Message(&msg, NULL, NULL)) {

Message Handling in C/SDK v Windows program의 정수 While (Get. Message(&msg, NULL, NULL)) { // Translates virtual key codes Translate. Message(&msg); // Dispatches message to window Dispatch. Message(&msg); } // Returns the value from Post. Quit. Message Return (msg. w. Param);

Message Handling in C/SDK (cont’d) WNDCLASS ws; … ws. lpfn. Wnd. Proc = Wnd.

Message Handling in C/SDK (cont’d) WNDCLASS ws; … ws. lpfn. Wnd. Proc = Wnd. Proc; … Register. Class(ws); LRSULT Wnd. Proc(HWND hwnd, UINT message, WPARAM w. Param, LPARAM l. Param) { switch (message) { case WM_CREATE: … break; case WM_COMMAND: switch (w. Param) { case IDM_ABOUT: … } }

Message Handling in MFC v 방법 1 Ø Ø v Polymorphism : 가상 멤버

Message Handling in MFC v 방법 1 Ø Ø v Polymorphism : 가상 멤버 함수 이용 심각한 메모리 낭비 방법 2 Ø Ø Message maps MFC 의 특징

Message Mapping Internals v 두 부분으로 구성 Ø CCmd. Target ü Ø Window message나

Message Mapping Internals v 두 부분으로 구성 Ø CCmd. Target ü Ø Window message나 command를 받기 위해 반드시 상속받아 야 하는 class Message map ü Window message와 이를 처리하는 class member function을 연관시켜주는 mechanism

CCmd. Target Class v 메시지의 처리 Ø Ø CCmd. Target의 파생 클래스 예 ü

CCmd. Target Class v 메시지의 처리 Ø Ø CCmd. Target의 파생 클래스 예 ü ü ü CWnd class CDocument CWin. App

Message Map v Data structures Ø AFX_MSGMAP_ENTRY(AFXWIN. H) ü ü Message map table의 한

Message Map v Data structures Ø AFX_MSGMAP_ENTRY(AFXWIN. H) ü ü Message map table의 한 element(entry) Message에 대한 정보와 message handler에 대한 정보 를 저장 struct AFX_MSGMAP_ENTRY { UINT n. Message; // windows message UINT n. Code; // control code or WM_NOTIFY code UINT n. ID; // control ID (or 0 for windows messages) UINT n. Last. ID; // used for entries specifying a range of control id's UINT n. Sig; // signature type (action) or pointer to message # AFX_PMSG pfn; // routine to call (or special value) };

Message Map(contd. ) Ø AFX_MSGMAP(AFXWIN. H) ü 실제 message map struct AFX_MSGMAP { #ifdef

Message Map(contd. ) Ø AFX_MSGMAP(AFXWIN. H) ü 실제 message map struct AFX_MSGMAP { #ifdef _AFXDLL const AFX_MSGMAP* (PASCAL* pfn. Get. Base. Map)(); #else const AFX_MSGMAP* p. Base. Map; #endif const AFX_MSGMAP_ENTRY* lp. Entries; };

Message Map Macros v Macros (AFXWIN. H) Ø DECLARE_MESSAGE_MAP ü Ø Header file에서 정의

Message Map Macros v 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 _message. Entries[]; protected: static AFX_DATA const AFX_MSGMAP message. Map; virtual const AFX_MSGMAP* Get. Message. Map() const;

Message Map Macros (cont’d) #define BEGIN_MESSAGE_MAP(the. Class, base. Class)  const AFX_MSGMAP* the. Class:

Message Map Macros (cont’d) #define BEGIN_MESSAGE_MAP(the. Class, base. Class) const AFX_MSGMAP* the. Class: : Get. Message. Map() const { return &the. Class: : message. Map; } AFX_COMDAT AFX_DATADEF const AFX_MSGMAP the. Class: : message. Map = { &base. Class: : message. Map, &the. Class: : _message. Entries[0] }; AFX_COMDAT const AFX_MSGMAP_ENTRY the. Class: : _message. Entries[] = { #define END_MESSAGE_MAP() {0, 0, Afx. Sig_end, (AFX_PMSG)0 } };

Massage Map 예 class CTest. View : public Cview { protected: //{{AFX_MSG(CTest. View) afx_msg

Massage Map 예 class CTest. View : public Cview { protected: //{{AFX_MSG(CTest. View) afx_msg void On. LButton. Dbl. Clk(UINT n. Flags, Cpoint); //}}AFX_MSG DECLARE_MESSAGE_MAP() }; class CTest. View : public Cview { protected: afx_msg void On. LButton. Dbl. Clk(UINT n. Flags, Cpoint); private: static const AFX_MSGMAP_ENTRY _message. Entries[]; protected: static const AFX_MSGMAP message. Map; virtual const AFX_MSGMAP* Get. Message. Map() const; };

Massage Map 예 (cont’d) BEGIN_MESSAGE_MAP(CTest. VIew, Cview) //{{AFX_MSG_MAP(CTest. View) ON_COMMAND(ID_STRING_CENTER, On. String. Center) ON_WM_LBUTTONDBLCLK()

Massage Map 예 (cont’d) BEGIN_MESSAGE_MAP(CTest. VIew, Cview) //{{AFX_MSG_MAP(CTest. View) ON_COMMAND(ID_STRING_CENTER, On. String. Center) ON_WM_LBUTTONDBLCLK() //}}AFX_MSG_MAP END_MESSAGE_MAP() const AFX_MSGMAP* CTest. View: : Get. Message. Map() const { return &CTest. View: : message. Map; } AFX_COMDAT AFX_DATADEF const AFX_MSGMAP CTest. View: : message. Map = { &CView: : message. Map, &CTest. View: : _message. Entries[0] }; const AFX_MSGMAP_ENTRY CTest. VIew: : _message. Entries[] = { ON_COMMAND(ID_STRING_CENTER, On. String. Center) ON_WM_LBUTTONDBLCLK() {0, 0, Afx. Sig_end, (AFX_PMSG)0 } };

Message Map Entry Macro v AFXMSG_. H #define ON_COMMAND(id, member. Fxn)  { WM_COMMAND,

Message Map Entry Macro v AFXMSG_. H #define ON_COMMAND(id, member. Fxn) { WM_COMMAND, CN_COMMAND, (WORD)id, Afx. Sig_vv, (AFX_PMSG)&member. Fxn }, #define ON_WM_LBUTTONDBLCLK() { WM_LBUTTONDBLCLK, 0, 0, 0, Afx. Sig_vwp, (AFX_PMSG)(AFX_PMSGW) (void (AFX_MSG_CALL CWnd: : *) (UINT, CPoint))&On. LButton. Dbl. Clk },

Message Map Entry Macro (cont’d) Message Type Macro Form Predefined Windows messages ON_WM_XXXX Commands

Message Map Entry Macro (cont’d) 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

User-define Message // inside the class declaration afx_msg LRESULT On. My. Message(WPARAM w. Param,

User-define Message // inside the class declaration afx_msg LRESULT On. My. Message(WPARAM w. Param, LPARAM l. Param); For example: #define WM_MYMESSAGE (WM_USER + 100) BEGIN_MESSAGE_MAP(CMy. Wnd, CMy. Parent. Wnd. Class) ON_MESSAGE(WM_MYMESSAGE, On. My. Message) END_MESSAGE_MAP() CWnd* p. Wnd =. . . ; p. Wnd->Send. Message(WM_MYMESSAGE);

Handlers for Message-Map Ranges v 종류 Ø Ø Ø v ON_COMMAND_RANGE ON_UPDATE_COMMAND ON_CONTROL_RANGE Message-Map

Handlers for Message-Map Ranges v 종류 Ø Ø Ø v ON_COMMAND_RANGE ON_UPDATE_COMMAND ON_CONTROL_RANGE Message-Map Entry Ø ID 는 연속적이어야 한다. BEGIN_MESSAGE_MAP(CMy. App, CWin. App) ON_COMMAND_RANGE(ID_MYCMD_ONE, ID_MYCMD_TEN, On. Do. Something) ON_CONTROL_RANGE(BN_CLICKED, IDC_BUTTON 10, On. Button. Clicked) END_MESSAGE_MAP( )

Handlers for Message-Map Ranges v Handlers . . . void CMy. Dialog: : On.

Handlers for Message-Map Ranges v Handlers . . . void CMy. Dialog: : On. Button. Clicked( UINT n. ID ) { int n. Button = n. ID - IDC_BUTTON 1; ASSERT( n. Button >= 0 && n. Button < 10 ); //. . . }

MFC의 Message Map이용 v MFC-based program Ø 두 종류의 메시지를 처리 ü regular window

MFC의 Message Map이용 v MFC-based program Ø 두 종류의 메시지를 처리 ü regular window messages Ø ü commands Ø Ø WM_MOUSEMOVE, … WM_COMMAND Message-mapping architecture의 이해 ü 두 종류 메시지를 각각 추적

How to be wired v 16 -bit version Ø Afx. Wnd. Proc() ü v

How to be wired v 16 -bit version Ø Afx. Wnd. Proc() ü v Message handling procedure로 등록된 함수 32 -bit version Ø Ø Ø Def. Window. Proc() 가 message handler로 등록 Message hook방법을 써서 결국에는 Afx. Wnd. Proc()가 message를 처리하게 함 Hooking function ü Ø _Afx. Cbt. Filter. Hook(), _Afx. Standard. Subclass() 3 D Control을 지원하기 위함

How to be wired (cont’d) “Win. Core. cpp” BOOL AFXAPI Afx. End. Defer. Register.

How to be wired (cont’d) “Win. Core. cpp” BOOL AFXAPI Afx. End. Defer. Register. Class(LONG f. To. Register) { // mask off all classes that are already registered AFX_MODULE_STATE* p. Module. State = Afx. Get. Module. State(); f. To. Register &= ~p. Module. State->m_f. Registered. Classes; if (f. To. Register == 0) return TRUE; LONG f. Registered. Classes = 0; // common initialization WNDCLASS wndcls; memset(&wndcls, 0, sizeof(WNDCLASS)); // start with NULL defaults wndcls. lpfn. Wnd. Proc = Def. Window. Proc; wndcls. h. Instance = Afx. Get. Instance. Handle(); wndcls. h. Cursor = afx. Data. hcur. Arrow;

How to be wired (cont’d) BOOL CWnd: : Create. Ex(DWORD dw. Ex. Style, LPCTSTR

How to be wired (cont’d) BOOL CWnd: : Create. Ex(DWORD dw. Ex. Style, LPCTSTR lpsz. Class. Name, LPCTSTR lpsz. Window. Name, DWORD dw. Style, int x, int y, int n. Width, int n. Height, HWND h. Wnd. Parent, HMENU n. IDor. HMenu, LPVOID lp. Param) { … Afx. Hook. Window. Create(this); } void AFXAPI Afx. Hook. Window. Create(CWnd* p. Wnd) { if (p. Thread. State->m_h. Hook. Old. Cbt. Filter == NULL) { p. Thread. State->m_h. Hook. Old. Cbt. Filter = : : Set. Windows. Hook. Ex(WH_CBT, _Afx. Cbt. Filter. Hook, NULL, : : Get. Current. Thread. Id()); if (p. Thread. State->m_h. Hook. Old. Cbt. Filter == NULL) Afx. Throw. Memory. Exception(); } p. Thread. State->m_p. Wnd. Init = p. Wnd; }

How to be wired (cont’d) LRESULT CALLBACK _Afx. Cbt. Filter. Hook(int code, WPARAM w.

How to be wired (cont’d) LRESULT CALLBACK _Afx. Cbt. Filter. Hook(int code, WPARAM w. Param, LPARAM l. Param) { … // subclass the window if not already wired to Afx. Wnd. Proc if (!b. Afx. Wnd. Proc) { // subclass the window with standard Afx. Wnd. Proc old. Wnd. Proc = (WNDPROC)Set. Window. Long(h. Wnd, GWL_WNDPROC, (DWORD)afx. Wnd. Proc); ASSERT(old. Wnd. Proc != NULL); *p. Old. Wnd. Proc = old. Wnd. Proc; } … }

Message Handling v Afx. Wnd. Proc()(WINCORE. CPP) Ø WM_QUERYAFXWNDPROC ü Ø MFC’s message map을

Message Handling v Afx. Wnd. Proc()(WINCORE. CPP) Ø WM_QUERYAFXWNDPROC ü Ø MFC’s message map을 사용하는 MFC window인지를 확 인할 수 있는 message 다른 message에 대해서는 Afx. Call. Wnd. Proc() 함수 를 호출 LRESULT CALLBACK Afx. Wnd. Proc(HWND h. Wnd, UINT n. Msg, WPARAM w. Param, LPARAM l. Param) { if (n. Msg == WM_QUERYAFXWNDPROC) return 1; CWnd* p. Wnd = CWnd: : From. Handle. Permanent(h. Wnd); return Afx. Call. Wnd. Proc(p. Wnd, h. Wnd, n. Msg, w. Param, l. Param); }

Message Handling (cont’d) v Afx. Call. Wnd. Proc()(WINCORE. CPP) Ø Ø Thread state 구조체에

Message Handling (cont’d) v Afx. Call. Wnd. Proc()(WINCORE. CPP) Ø Ø Thread state 구조체에 message의 정보를 저장 WM_INITDIALOG처리 ü Ø Auto-center dialog위한 처리를 수행 Window object의 window procedure호출 ü ü ü CWnd: : Window. Proc()(WINCORE. CPP) 내부적으로 On. Wnd. Msg()를 호출 On. Wnd. Msg()가 처리하지 못하면 CWnd: : Def. Window. Proc()를 호출

Message Handling (cont’d) LRESULT AFXAPI Afx. Call. Wnd. Proc(CWnd* p. Wnd, HWND h. Wnd,

Message Handling (cont’d) LRESULT AFXAPI Afx. Call. Wnd. Proc(CWnd* p. Wnd, HWND h. Wnd, UINT n. Msg, WPARAM w. Param = 0, LPARAM l. Param = 0) { _AFX_THREAD_STATE* p. Thread. State = _afx. Thread. State. Get. Data(); MSG old. State = p. Thread. State->m_last. Sent. Msg; // save for nesting p. Thread. State->m_last. Sent. Msg. hwnd = h. Wnd; p. Thread. State->m_last. Sent. Msg. message = n. Msg; p. Thread. State->m_last. Sent. Msg. w. Param = w. Param; p. Thread. State->m_last. Sent. Msg. l. Param = l. Param; CRect rect. Old; DWORD dw. Style = 0; if (n. Msg == WM_INITDIALOG) _Afx. Pre. Init. Dialog(p. Wnd, &rect. Old, &dw. Style); // delegate to object's Window. Proc l. Result = p. Wnd->Window. Proc(n. Msg, w. Param, l. Param); // more special case for WM_INITDIALOG if (n. Msg == WM_INITDIALOG) _Afx. Post. Init. Dialog(p. Wnd, rect. Old, dw. Style); p. Thread. State->m_last. Sent. Msg = old. State; return l. Result; }

Message Handling (cont’d) v CWnd: : Wndow. Proc()(WINCORE. CPP) Ø Ø virtual 이므로 override

Message Handling (cont’d) v CWnd: : Wndow. Proc()(WINCORE. CPP) Ø Ø virtual 이므로 override 가능 성능 향상을 위해 message-mapping system을 거치지 않고 처리해야 하는 메시지에 대한 핸들링 가능 “Win. Core. Cpp” LRESULT CWnd: : Window. Proc(UINT message, WPARAM w. Param, LPARAM l. Param) { // On. Wnd. Msg does most of the work, except for Def. Window. Proc call LRESULT l. Result = 0; if (!On. Wnd. Msg(message, w. Param, l. Param, &l. Result)) l. Result = Def. Window. Proc(message, w. Param, l. Param); return l. Result; }

Message Handling (cont’d) v CWnd: : On. Wnd. Msg()(WINCORE. CPP) Ø 특별히 처리하는 message

Message Handling (cont’d) v CWnd: : On. Wnd. Msg()(WINCORE. CPP) Ø 특별히 처리하는 message ü ü Ø WM_COMMAND, WM_NOTIFY WM_ACTIVATE, WM_SETCURSOR 기타 다른 message들은 message map을 이용하여 해 당 message handler를 호출

Message Handling (cont’d) BOOL CWnd: : On. Wnd. Msg(UINT message, WPARAM w. Param, LPARAM

Message Handling (cont’d) BOOL CWnd: : On. Wnd. Msg(UINT message, WPARAM w. Param, LPARAM l. Param, LRESULT* p. Result) { // special case for commands if (message == WM_COMMAND) { if (On. Command(w. Param, l. Param)) { l. Result = 1; goto LReturn. True; } return FALSE; } // special case for notifies if (message == WM_NOTIFY) { } // special case for activation if (message == WM_ACTIVATE) { } // special case for set cursor HTERROR if (message == WM_SETCURSOR ) { }

Message Handling (cont’d) const AFX_MSGMAP* p. Message. Map; p. Message. Map = Get. Message.

Message Handling (cont’d) const AFX_MSGMAP* p. Message. Map; p. Message. Map = Get. Message. Map(); UINT i. Hash; i. Hash = (LOWORD((DWORD)p. Message. Map) ^ message) & (i. Hash. Max-1); Afx. Lock. Globals(CRIT_WINMSGCACHE); AFX_MSG_CACHE* p. Msg. Cache; p. Msg. Cache = &_afx. Msg. Cache[i. Hash]; const AFX_MSGMAP_ENTRY* lp. Entry; if (message == p. Msg. Cache->n. Msg && p. Message. Map == p. Msg. Cache>p. Message. Map) { … } else { // not in cache, look for it p. Msg. Cache->n. Msg = message; p. Msg. Cache->p. Message. Map = p. Message. Map; for (/* p. Message. Map already init'ed */; p. Message. Map != NULL; p. Message. Map = p. Message. Map->p. Base. Map) { Afx. Find. Message. Entry(); }

Message Handling Trace v 두가지 종류의 message Ø Regular window message ü Ø Command

Message Handling Trace v 두가지 종류의 message Ø Regular window message ü Ø Command message ü ü v WM_MOUSEMOVE 메뉴나 control이 보내는 message WM_COMMAND 서로 다른 방식으로 처리 Ø CWnd: : On. Wnd. Msg()참고

Handling WM_COMMAND v 가정 Ø v CWnd: : On. Wnd. Msg()함수에서 Ø v Main

Handling WM_COMMAND v 가정 Ø v CWnd: : On. Wnd. Msg()함수에서 Ø v Main frame의 메뉴 명령 수행 CWnd: : On. Command()함수 호출 CWnd: : On. Command() Ø Ø Virtual function(Framework이 적절한 version의 함수 를 호출함) CFrame. Wnd: : On. Command() ü ü On-line help에 관한 것이면 해당 기능 수행 아니면 CWnd: : On. Command()함수 호출

Handling WM_COMMAND (cont’d) “Win. Frm. cpp” BOOL CFrame. Wnd: : On. Command(WPARAM w. Param,

Handling WM_COMMAND (cont’d) “Win. Frm. cpp” BOOL CFrame. Wnd: : On. Command(WPARAM w. Param, LPARAM l. Param) { HWND h. Wnd. Ctrl = (HWND)l. Param; UINT n. ID = LOWORD(w. Param); CFrame. Wnd* p. Frame. Wnd = Get. Top. Level. Frame(); ASSERT_VALID(p. Frame. Wnd); if (p. Frame. Wnd->m_b. Help. Mode&&h. Wnd. Ctrl==NULL&&n. ID!=ID_HELP&& n. ID!= ID_DEFAULT_HELP && n. ID != ID_CONTEXT_HELP) { // route as help if (!Send. Message(WM_COMMANDHELP, 0, HID_BASE_COMMAND+n. ID)) Send. Message(WM_COMMAND, ID_DEFAULT_HELP); return TRUE; } // route as normal command return CWnd: : On. Command(w. Param, l. Param); }

Handling WM_COMMAND (cont’d) “Win. Core. Cpp” BOOL CWnd: : On. Command(WPARAM w. Param, LPARAM

Handling WM_COMMAND (cont’d) “Win. Core. Cpp” BOOL CWnd: : On. Command(WPARAM w. Param, LPARAM l. Param) { if (h. Wnd. Ctrl == NULL) else { if (_afx. Thread. State->m_h. Lockout. Notify. Window == m_h. Wnd) return TRUE; // locked out - ignore control notification // reflect notification to child window control if (Reflect. Last. Msg(h. Wnd. Ctrl)) return TRUE; // eaten by child // zero IDs for normal commands are not allowed if (n. ID == 0) return FALSE; } return On. Cmd. Msg(n. ID, n. Code, NULL); }

Handling WM_COMMAND (cont’d) v CWnd: : On. Command()(WINCORE. CPP) Ø Ø Ø LPARAM을 조사

Handling WM_COMMAND (cont’d) v CWnd: : On. Command()(WINCORE. CPP) Ø Ø Ø LPARAM을 조사 만약 control이 보낸 message이면 control에게 다시 message를 reflect한 후 return 아니면 CWnd: : On. Cmd. Msg()(virtual function)함수 호 출

Handling WM_COMMAND (cont’d) “Win. Frm. cpp” BOOL CFrame. Wnd: : On. Cmd. Msg(UINT n.

Handling WM_COMMAND (cont’d) “Win. Frm. cpp” BOOL CFrame. Wnd: : On. Cmd. Msg(UINT n. ID, int n. Code, void* p. Extra, AFX_CMDHANDLERINFO* p. Handler. Info) { CPush. Routing. Frame push(this); // pump through current view FIRST CView* p. View = Get. Active. View(); if (p. View != NULL && p. View->On. Cmd. Msg(n. ID, n. Code, p. Extra, p. Handler. Info)) return TRUE; // then pump through frame if (CWnd: : On. Cmd. Msg(n. ID, n. Code, p. Extra, p. Handler. Info)) return TRUE; // last but not least, pump through app CWin. App* p. App = Afx. Get. App(); if (p. App != NULL && p. App->On. Cmd. Msg(n. ID, n. Code, p. Extra, p. Handler. Info)) return TRUE; return FALSE; }

Handling WM_COMMAND (cont’d) “View. Core. cpp” BOOL CView: : On. Cmd. Msg(UINT n. ID,

Handling WM_COMMAND (cont’d) “View. Core. cpp” BOOL CView: : On. Cmd. Msg(UINT n. ID, int n. Code, void* p. Extra, AFX_CMDHANDLERINFO* p. Handler. Info) { // first pump through pane if (CWnd: : On. Cmd. Msg(n. ID, n. Code, p. Extra, p. Handler. Info)) return TRUE; // then pump through document if (m_p. Document != NULL) { // special state for saving view before routing to document CPush. Routing. View push(this); return m_p. Document->On. Cmd. Msg(n. ID, n. Code, p. Extra, p. Handler. Info); } return FALSE; }

Handling WM_COMMAND (cont’d) “Doc. Core. cpp” BOOL CDocument: : On. Cmd. Msg(UINT n. ID,

Handling WM_COMMAND (cont’d) “Doc. Core. cpp” BOOL CDocument: : On. Cmd. Msg(UINT n. ID, int n. Code, void* p. Extra, AFX_CMDHANDLERINFO* p. Handler. Info) { if (CCmd. Target: : On. Cmd. Msg(n. ID, n. Code, p. Extra, p. Handler. Info)) return TRUE; // otherwise check template if (m_p. Doc. Template != NULL && m_p. Doc. Template->On. Cmd. Msg(n. ID, n. Code, p. Extra, p. Handler. Info)) return TRUE; return FALSE; }

Handling WM_COMMAND (cont’d) v CFrame. Wnd: : On. Cmd. Msg()(WINFRM. CPP) Ø 다음의 순서로

Handling WM_COMMAND (cont’d) v CFrame. Wnd: : On. Cmd. Msg()(WINFRM. CPP) Ø 다음의 순서로 해당 On. Cmd. Msg()함수를 호출 ü ü Active view’s document Main frame window Application

Handling WM_COMMAND (cont’d) v 만약 active view에 해당 handler가 있다면 Ø v CView: :

Handling WM_COMMAND (cont’d) v 만약 active view에 해당 handler가 있다면 Ø v CView: : On. Cmd. Msg()가 호출됨 CView: : On. Cmd. Msg()(VIEWCORE. CPP) Ø Ø Ø View에서 처리를 시도한 후 안되면 document에서 처 리를 시도 View에서 처리 시도는 CWnd: : On. Cmd. Msg()함수의 호 출로 이루어짐 이 때 CWnd는 On. Cmd. Msg를 override하지 않기 때문 에 CCmd. Target: : On. Cmd. Msg를 호출하는 결과가 됨

Handling WM_COMMAND (cont’d) “Cmd. Targ. cpp” BOOL CCmd. Target: : On. Cmd. Msg(UINT n.

Handling WM_COMMAND (cont’d) “Cmd. Targ. cpp” BOOL CCmd. Target: : On. Cmd. Msg(UINT n. ID, int n. Code, void* p. Extra, AFX_CMDHANDLERINFO* p. Handler. Info) { for (p. Message. Map = Get. Message. Map(); p. Message. Map != NULL; p. Message. Map = p. Message. Map->p. Base. Map) { lp. Entry = Afx. Find. Message. Entry (p. Message. Map->lp. Entries, n. Msg, n. Code, n. ID); if (lp. Entry != NULL) { return _Afx. Dispatch. Cmd. Msg(this, n. ID, n. Code, lp. Entry->pfn, p. Extra, lp. Entry->n. Sig, p. Handler. Info); } } return FALSE; // not handled }

Handling WM_COMMAND (cont’d) v CCmd. Target: : On. Cmd. Msg()(CMDTARG. CPP) Ø Ø v

Handling WM_COMMAND (cont’d) v CCmd. Target: : On. Cmd. Msg()(CMDTARG. CPP) Ø Ø v Message map을 보고 message handler를 찾음 찾게 되면 _Afx. Dispatch. Cmd. Msg()함수를 호출하여 해 당 handler를 실행시킴 _Afx. Dispatch. Cmd. Msg()(CMDTARG. CPP) Ø Function signature에 따라 다른 동작을 수행 ü ü Regular command Extended command Visual Basic control 등등

Handling WM_COMMAND (cont’d) v Frame window일 때의 처리과정 정리 Ø Ø Ø Ø Ø

Handling WM_COMMAND (cont’d) v Frame window일 때의 처리과정 정리 Ø Ø Ø Ø Ø Afx. Wnd. Proc() Afx. Call. Wnd. Proc() CWnd: : Window. Proc() CWnd: : On. Wnd. Msg() CFrame. Wnd: : On. Command() CFrame. Wnd: : On. Cmd. Msg() CCmd. Target: : On. Cmd. Msg() _Afx. Dispatch. Cmd. Msg() CMain. Fram: : On~()

Handling WM_COMMAND (cont’d) v Document일 때의 처리과정 정리 Ø Ø Ø Afx. Wnd. Proc()

Handling WM_COMMAND (cont’d) v Document일 때의 처리과정 정리 Ø Ø Ø Afx. Wnd. Proc() Afx. Call. Wnd. Proc() CWnd: : Window. Proc() CWnd: : On. Wnd. Msg() CFrame. Wnd: : On. Command() CFrame. Wnd: : On. Cmd. Msg() CView: : On. Cmd. Msg() Cdocument: : On. Cmd. Msg() CCmd. Target: : On. Cmd. Msg() _Afx. Dispatch. Cmd. Msg() CMy. Doc: : On~()

Handling WM_COMMAND (cont’d) v View일 때의 처리과정 정리 Ø Ø Ø Afx. Wnd. Proc()

Handling WM_COMMAND (cont’d) v View일 때의 처리과정 정리 Ø Ø Ø Afx. Wnd. Proc() Afx. Call. Wnd. Proc() CWnd: : Window. Proc() CWnd: : On. Wnd. Msg() CFrame. Wnd: : On. Command() CFrame. Wnd: : On. Cmd. Msg() CView: : On. Cmd. Msg() CCmd. Target: : On. Cmd. Msg() _Afx. Dispatch. Cmd. Msg() CMy. View: : On~()

Handling WM_COMMAND (cont’d) v App일 때의 처리과정 정리 Ø Ø Ø Ø Afx. Wnd.

Handling WM_COMMAND (cont’d) v App일 때의 처리과정 정리 Ø Ø Ø Ø Afx. Wnd. Proc() Afx. Call. Wnd. Proc() CWnd: : Window. Proc() CWnd: : On. Wnd. Msg() CFrame. Wnd: : On. Command() CCmd. Target: : On. Cmd. Msg() _Afx. Dispatch. Cmd. Msg() CMy. App: : On~()

Handling WM_COMMAND (cont’d) v Dialog Box일 때의 처리과정 정리 Ø Ø Ø Ø Afx.

Handling WM_COMMAND (cont’d) v Dialog Box일 때의 처리과정 정리 Ø Ø Ø Ø Afx. Wnd. Proc() Afx. Call. Wnd. Proc() CWnd: : Window. Proc() CWnd: : On. Wnd. Msg() CDialog: : On. Cmd. Msg() CCmd. Target: : On. Cmd. Msg() _Afx. Dispatch. Cmd. Msg() CAbout. Dlg: : On~()

Handling Regular Window Message v Command message일 때와 처음의 과정은 비슷 Ø Ø Afx.

Handling Regular Window Message v Command message일 때와 처음의 과정은 비슷 Ø Ø Afx. Wnd. Proc() Afx. Call. Wnd. Proc() Window. Proc() On. Wnd. Msg() ü 이 함수 안에서 message handler를 찾기 위해 Afx. Find. Message. Entry()를 호출

Handling Regular Window Message (cont’d) v Afx. Find. Message. Entry() Ø 두 버전이 있음.

Handling Regular Window Message (cont’d) v Afx. Find. Message. Entry() Ø 두 버전이 있음. ü ü Ø Ø Assembly language : intel-based machine C language : otherwise Message map에서 해당 핸들러가 있는지 검색 END_MESSAGE_MAP에 의해 생성된 table의 끝까지 검 색

Handling Regular Window Message (cont’d) v Command message와의 차이점 Ø Ø Command message는 handler를

Handling Regular Window Message (cont’d) v Command message와의 차이점 Ø Ø Command message는 handler를 찾기 위해서 여러 장 소를 옮겨다님 Regular message는 On. Wnd. Msg()에서 handler를 찾으 면 바로 해당 handler를 호출하고, 아니면 Def. Window. Proc()를 이용

Handling Regular Window Message (cont’d) v 예) View에서 WM_SIZE message처리 과정 Ø Ø Ø

Handling Regular Window Message (cont’d) v 예) View에서 WM_SIZE message처리 과정 Ø Ø Ø Afx. Wnd. Proc() Afx. Call. Wnd. Proc() CWnd: : Window. Proc() CWnd: : On. Wnd. Msg() CSdiapp. View: : On. Size()

Other Kinds of Messages v 지금까지 살펴 본 메시지 종류 Ø Ø v WM_COMMAND

Other Kinds of Messages v 지금까지 살펴 본 메시지 종류 Ø Ø v WM_COMMAND Window messages(WM_SIZE, WM_MOVE, …) 그 이외의 메시지 종류 Ø Ø Ø WM_NOTIFY WM_ACTIVATE WM_SETCURSOR

Other Kinds of Messages (cont’d) v WM_NOTIFY Ø Ø Ø Control이 보내는 message 항상

Other Kinds of Messages (cont’d) v WM_NOTIFY Ø Ø Ø Control이 보내는 message 항상 notify message 반면, WM_COMMAND ü command이거나 notify message

Other Kinds of Messages (cont’d) CWnd: : On. Wnd. Msg()에서 // special case for

Other Kinds of Messages (cont’d) CWnd: : On. Wnd. Msg()에서 // special case for notifies if (message == WM_NOTIFY) { NMHDR* p. NMHDR = (NMHDR*)l. Param; if (p. NMHDR->hwnd. From != NULL && On. Notify(w. Param, l. Param, &l. Result)) goto LReturn. True; return FALSE; … } struct NMHDR { HWND hwnd. From; UINT id. From; UINT code; // control that sent notification // ID of control // notification code

Other Kinds of Messages (cont’d) “Wincore. cpp” BOOL CWnd: : On. Notify(WPARAM, LPARAM l.

Other Kinds of Messages (cont’d) “Wincore. cpp” BOOL CWnd: : On. Notify(WPARAM, LPARAM l. Param, LRESULT* p. Result) { NMHDR* p. NMHDR = (NMHDR*)l. Param; HWND h. Wnd. Ctrl = p. NMHDR->hwnd. From; // get the child ID from the window itself UINT n. ID = _Afx. Get. Dlg. Ctrl. ID(h. Wnd. Ctrl); int n. Code = p. NMHDR->code; if (_afx. Thread. State->m_h. Lockout. Notify. Window == m_h. Wnd) return TRUE; // locked out - ignore control notification // reflect notification to child window control if (Reflect. Last. Msg(h. Wnd. Ctrl, p. Result)) return TRUE; // eaten by child AFX_NOTIFY notify; notify. p. Result = p. Result; notify. p. NMHDR = p. NMHDR; return On. Cmd. Msg(n. ID, MAKELONG(n. Code, WM_NOTIFY), &notify, NULL); }

Other Kinds of Messages (cont’d) BOOL PASCAL CWnd: : Reflect. Last. Msg(HWND h. Wnd.

Other Kinds of Messages (cont’d) BOOL PASCAL CWnd: : Reflect. Last. Msg(HWND h. Wnd. Child, LRESULT* p. Result) { CHandle. Map* p. Map = afx. Map. HWND(); CWnd* p. Wnd = (CWnd*)p. Map->Lookup. Permanent(h. Wnd. Child); if (p. Wnd == NULL) { // check if the window is an OLE control … return FALSE; } return p. Wnd->Send. Child. Notify. Last. Msg(p. Result); }

Other Kinds of Messages (cont’d) BOOL CWnd: : Send. Child. Notify. Last. Msg(LRESULT* p.

Other Kinds of Messages (cont’d) BOOL CWnd: : Send. Child. Notify. Last. Msg(LRESULT* p. Result) { _AFX_THREAD_STATE* p. Thread. State = _afx. Thread. State. Get. Data(); return On. Child. Notify(p. Thread. State->m_last. Sent. Msg. message, p. Thread. State->m_last. Sent. Msg. w. Param, p. Thread. State->m_last. Sent. Msg. l. Param, p. Result); }

Other Kinds of Messages (cont’d) v Message reflection Ø Ø Ø On. Wnd. Msg()에서

Other Kinds of Messages (cont’d) v Message reflection Ø Ø Ø On. Wnd. Msg()에서 On. Notify()를 호출 On. Nofity()는 다시 On. Child. Notify()를 호출하여 control 로 message를 다시 보냄 결국에는 control이 parent에 의존하지 않고 자신의 일 을 처리하게 함

Other Kinds of Messages (cont’d) Ø WM_ACTIVATE ü Ø On. Wnd. Msg()함수에서 _Afx. Handle.

Other Kinds of Messages (cont’d) Ø WM_ACTIVATE ü Ø On. Wnd. Msg()함수에서 _Afx. Handle. Activate()를 호출 WM_SETCURSOR ü On. Wnd. Msg()함수에서 _Afx. Handle. Set. Cursor()함수 호출

Message Loop Hooking v Message loop hooking Ø Ø Message가 해당 handler에 의해 처리되기

Message Loop Hooking v Message loop hooking Ø Ø Message가 해당 handler에 의해 처리되기 전에 어떠한 작업을 하고 싶을때 Pre. Translate. Message() ü CWin. App: : Pre. Translate. Message() Ø Ø ü CWin. App: : Run()함수는 message가 message pump에 의해 처 리되기 전에 위 함수를 호출 TRUE를 return하면 message pump는 해당 message에 관해 서는 처리를 하지 않음 CWnd: : Pre. Translate. Message()

Message Loop Hooking (cont’d) “THRDCORE. cpp” int CWin. Thread: : Run() { // for

Message Loop Hooking (cont’d) “THRDCORE. cpp” int CWin. Thread: : Run() { // for tracking the idle time state BOOL b. Idle = TRUE; LONG l. Idle. Count = 0; // acquire and dispatch messages until a WM_QUIT message is received. for (; ; ) { // phase 1: check to see if we can do idle work while (b. Idle && !: : Peek. Message(&m_msg. Cur, NULL, PM_NOREMOVE)) { // call On. Idle while in b. Idle state if (!On. Idle(l. Idle. Count++)) b. Idle = FALSE; // assume "no idle" state }

Message Loop Hooking (cont’d) // phase 2: pump messages while available do { //

Message Loop Hooking (cont’d) // phase 2: pump messages while available do { // pump message, but quit on WM_QUIT if (!Pump. Message()) return Exit. Instance(); // reset "no idle" state after pumping "normal" message if (Is. Idle. Message(&m_msg. Cur)) { b. Idle = TRUE; l. Idle. Count = 0; } } while (: : Peek. Message(&m_msg. Cur, NULL, PM_NOREMOVE)); } ASSERT(FALSE); // not reachable }

Message Loop Hooking (cont’d) BOOL CWin. Thread: : Pump. Message() { ASSERT_VALID(this); if (!:

Message Loop Hooking (cont’d) BOOL CWin. Thread: : Pump. Message() { ASSERT_VALID(this); if (!: : Get. Message(&m_msg. Cur, NULL, NULL)) { } // process this message if (m_msg. Cur. message != WM_KICKIDLE && !Pre. Translate. Message(&m_msg. Cur)) { : : Translate. Message(&m_msg. Cur); : : Dispatch. Message(&m_msg. Cur); } return TRUE; }

Message Loop Hooking (cont’d) BOOL CWin. Thread: : Pre. Translate. Message(MSG* p. Msg) {

Message Loop Hooking (cont’d) BOOL CWin. Thread: : Pre. Translate. Message(MSG* p. Msg) { // if this is a thread-message, short-circuit this function if (p. Msg->hwnd == NULL && Dispatch. Thread. Message. Ex(p. Msg)) return TRUE; // walk from target to main window CWnd* p. Main. Wnd = Afx. Get. Main. Wnd(); if (CWnd: : Walk. Pre. Translate. Tree(p. Main. Wnd->Get. Safe. Hwnd(), p. Msg)) return TRUE; // in case of modeless dialogs, last chance route through main // window's accelerator table if (p. Main. Wnd != NULL) { CWnd* p. Wnd = CWnd: : From. Handle(p. Msg->hwnd); if (p. Wnd->Get. Top. Level. Parent() != p. Main. Wnd) return p. Main. Wnd->Pre. Translate. Message(p. Msg); } return FALSE; // no special processing }

Message Loop Hooking (cont’d) “Win. Core. Cpp” BOOL PASCAL CWnd: : Walk. Pre. Translate.

Message Loop Hooking (cont’d) “Win. Core. Cpp” BOOL PASCAL CWnd: : Walk. Pre. Translate. Tree(HWND h. Wnd. Stop, MSG* p. Msg) { // walk from the target window up to the h. Wnd. Stop window checking // if any window wants to translate this message for (HWND h. Wnd=p. Msg->hwnd; h. Wnd != NULL; h. Wnd=: : Get. Parent(h. Wnd)) { CWnd* p. Wnd = CWnd: : From. Handle. Permanent(h. Wnd); if (p. Wnd != NULL) { // target window is a C++ window if (p. Wnd->Pre. Translate. Message(p. Msg)) return TRUE; } // got to h. Wnd. Stop window without interest if (h. Wnd == h. Wnd. Stop) break; } return FALSE; // no special processing }