MFC의 메시지 처리
목 차 1 2 3 4 5 메시지 개요 Message Map 처리 기본개념 Message Map의 구성 Message 처리단계 목 차 메시지 개요 1 메시지 구조 메시지 종류 Message Map 처리 기본개념 2 Message Map의 구성 3 Message 처리단계 4 메시지 매크로의 확장 5 DECLARE_MESSAGE_MAP BEGIN_MESSAGE_MAP END_MESSAGE_MAP Univ of Incheon, 고급프로그래밍
목 차 6 7 8 사용자 정의 메시지 메시지 처리방식의 종류 메시지 처리 흐름 큐를 경유하는 방식 큐를 경유하지 않는 방식 목 차 사용자 정의 메시지 6 메시지 처리방식의 종류 7 큐를 경유하는 방식 큐를 경유하지 않는 방식 메시지 처리 흐름 8 Message Loop Window Procedure DefWindowProc Univ of Incheon, 고급프로그래밍
메시지 개요(1/7) 메시지 구조 메시지 : 프로그램에 변화가 생겼을 때 Windows가 프로그램에게 알리는 정보 메시지는 MSG로 정의되는 구조체 (윈도우 핸들, 메시지 식별 번호, 추가 정보, 시간, 커서 위치 등 포함) typedef struct tagMSG { HWND hwnd; // 메시지가 발생한 윈도우 핸들 UINT message; // message id WPARAM wParam; // 추가 정보 LPARAM lParam; // 추가 정보 DWORD time; // 메시지 발생 시간 POINT pt; // 커서 위치 } MSG; <WINUSER.H> <WINDEF.H> typedef struct tagPOINT { LONG x; // 화면 좌표 LONG y; // 화면 좌표 } POINT; Univ of Incheon, 고급프로그래밍
메시지 개요(2/7) 사용자 입력 입력용 Device Driver(키보드, 마우스, 조이스틱) 응용 프로그램 응용 프로그램 응용 프로그램 메시지 큐 Device Driver Device Driver Device Driver Windows OS 입력 장치 출력 장치 사용자 입력 입력용 Device Driver(키보드, 마우스, 조이스틱) 메시지 큐 Windows 운영체제 응용 프로그램 출력용 Device Driver(모니터, 프린터, 디스크) 출력 Univ of Incheon, 고급프로그래밍
메시지 개요(3/7) 메시지 종류 윈도우 메시지(Windows Message) “WM_”으로 시작하는 메시지(WM_COMMAND 제외) 매개 변수를 가지고 있어 어떻게 처리할 것인지 결정 윈도우 관리메시지, 초기화 메시지, 입력메시지 명령 경로 배정없이 해당 윈도우에 직접 전달 컨트롤 통지 메시지(Control Notification Message) Button, Combo Box와 같은 제어객체나 자식윈도우에서 부모 윈도우로 보내는 메시지 명령 메시지(Command Message) 메뉴, 툴바, 액셀레이터 키와 같은 사용자 인터페이스 객체로부터 발생되는 WM_COMMAND 메시지 도큐먼트, 도큐먼트 템플릿, 뷰, 다른 Application 객체에 의해 발생 가능 사용자 정의 메시지 SendMessage()와 PostMessage()를 사용하여 메지시 전달 Univ of Incheon, 고급프로그래밍
메시지 개요(4/7) Windows Message 메시지 유형 발생상황 메시지 핸들러 함수 WM_CREATE 윈도우가 생성될 때 OnCreate() WM_ACTIVE 윈도우가 활성화 될 때 OnActive() WM_PAINT 윈도우가 다시 그려질 때 OnPaint() WM_SIZE 윈도우 크기가 변경될 때 OnSize() WM_MOVE 윈도가 움직일 때 OnMove() WM_TIMER 설정된 타이머 시간이 됐을 때 OnTimer() WM_DESTROY 윈도우가 종료될 때 OnDestroy() WM_MOUSEMOVE 마우스를 이동 OnMouseMove() WM_LBUTTONDBlCLK 왼쪽 마우스 버튼을 더블 클릭 OnLButtonDblclk() WM_LBUTTONDOWN 왼쪽 마우스 버튼을 누름 OnLButtonDown() WM_LBUTTONUP 왼쪽 마우스 버튼을 놓음 OnLButtonUp() WM_RBUTTONDBlCLK 오른쪽 마우스 버튼을 더블 클릭 OnRButtonDblclk() WM_RBUTTONDOWN 오른쪽 마우스 버튼을 누름 OnRButtonDown() WM_RBUTTONUP 오른쪽 마우스 버튼을 놓음 OnRButtonUp() Univ of Incheon, 고급프로그래밍
메시지 개요(5/7) 명령 메시지(WM_COMMAND) 메뉴의 선택, 키보드 가속기 사용과 같은 사용자의 행동에 의해 발생된 메시지 어떤 메뉴가 눌렸는지 구별하기 위해 메뉴의 ID가 윈도우 메시지의 WPARAM을 통해 전달 ON_COMMAND 메시지 맵 항목들을 가진 여러 응용 프로그램 구성 요소에 의해 처리 <프로젝트명.cpp> BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) ON_COMMAND (ID_FILE_NEW, OnFileNew) ON_COMMAND (ID_FILE_OPEN, OnFileOpen) ON_COMMAND (ID_FILE_SAVE, OnFileSave) ON_COMMAND (ID_FILE_SAVE_AS, OnFileSaveAs) ON_COMMAND (ID_FILE_EXIT, OnFileExit) END_MESSAGE_MAP() void CMainWindow::OnFileExit () { PostMessage (WM_CLOSE, 0, 0); } Univ of Incheon, 고급프로그래밍
메시지 개요(6/7) 만일 OnCommand라는 메시지 핸들러에서 모든 메시지를 처리를 하면 할 일이 너무 많아짐 일반적인 윈도우 메시지 처리는 CWnd 클래스를 상속받은 클래스들에서 처리 ( CWnd 클래스 상위 클래스는 윈도우 메시지 처리부분이 없음 ) WM_COMMAND 메시지는 CCmdTarget 클래스에 구현 CCmdTarget 클래스 하위 클래스는 모두 WM_COMMAND메시지 구현 가능 사용자가 메뉴 항목을 선택하여 프로그램에 명령을 내리면 WM_COMMAND 메시지가 모든 AFX 클래스에 전달 Univ of Incheon, 고급프로그래밍
메시지 개요(7/7) 파생 클래스 설명 CDocument 프로그램의 데이터를 처리하는 기능 CView WM_COMMAND 메시지 전달순서 CView 파생 클래스 CDocument CFrameWnd CWinApp 파생 클래스 설명 CDocument 프로그램의 데이터를 처리하는 기능 CView 데이터를 화면에 표시하는 기능 CWinApp 프로그램의 시작과 종료에 관련 된 커맨드 CFrameWnd 프레임 윈도우의 제어에 관계된 커멘드 처리 Univ of Incheon, 고급프로그래밍
Message Map 처리 기본개념(1/5) 메시지 맵이란 윈도우 메시지를 받아야 할 클래스가 가지는 정적 구조체 배열 이 정적 구조체 배열은 처리할 메시지와 메시지에 대응하는 멤버함수에 대한 포인터를 가짐 MFC는 메시지 맵의 코드 자동화를 위해 매크로를 사용 DECLARE_MESSAGE_MAP BEGIN_MESSAGE_MAP, END_MESSAGE_MAP ON_WM_LBUTTONDOWN() Univ of Incheon, 고급프로그래밍
Message Map 처리 기본개념(2/5) SDK기반에서는 메시지가 있는 경우에만 윈도우 프로시저를 호출 처리할 메시지가 없다면 CPU는 블록 상태가 되어 다른 응용프로그램이 CPU를 할당받아 일을 처리 MFC의 메시지 루프는 GetMessage()대신 PeekMessage() 사용 PeekMessage()는 블록상태가 되지 않음 처리할 메시지가 없는 시간(Idle Time)에 가상함수 OnIdle()이 호출됨 While ( GetMessage ( &msg, NULL, 0, 0 ) ) { TranslateMessage( &msg ); DispatchMessage ( &msg ); } Univ of Incheon, 고급프로그래밍
Message Map 처리 기본개념(3/5) SDK로 표현 MFC로 표현 해당하는 모듈을 모두 switch문으로 설정 LESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; switch (iMsg) case WM_CREATE : //윈도가 만들어질 때 모듈 break; case WM_PAINT : //화면 출력 모듈 case WM_KEYDOWN : //키 입력시 처리 모듈 case WM_CHAR : //문자 입력시 처리 모듈 case WM_DESTROY : //윈도가 없어질 때 모듈 } MFC로 표현 해당하는 모듈을 모두 switch문으로 설정 BEGIN_MESSAGE_MAP(CMyWnd, CWnd) ON_WM_CREATE( ) ON_WM_PAINT( ) ON_WM_KEYDOWN( ) ON_WM_CHAR( ) ON_WM_DESTROY( ) END_MESSAGE_MAP( ) Univ of Incheon, 고급프로그래밍
Message Map 처리 기본개념(4/5) Message Map의 이해 API 프로그램은 윈도우의 메시지를 처리할 때 윈도우 프로시저내에 중첩된 if문과 switch 문을 사용, 각각의 메시지에 대한 처리를 하는 이벤트 핸들러 코드를 작성 MFC 에서는 MESSAGE_MAP 매커니즘을 사용 따라서 if문이나 switch 문이 없다. MESSAGE_MAP의 메커니즘은 메시지와 이벤트 핸들러를 일대일로 연결시켜주는 테이블의 역할 수행 파생 클래스의 메시지 핸들러 함수를 여기에 등록하면 기반 클래스의 함수를 무시하고, 파생 클래스의 함수를 호출하는 매크로 Univ of Incheon, 고급프로그래밍
Message Map 처리 기본개념(5/5) MFC 메시지 맵의 핵심 코드의 자동화를 위하여 메시지 맵에 메시지와 메시지 핸들러 함수를 묶는 메시지의 매크로를 추가하여 사용 Handler0() { //… } Message ID 0 Handler0 Message ID 1 Handler1 Handler1() { //… } ● ● Message ID n-1 Handler n-1 Handler n-1() { //… } NULL Message Map Univ of Incheon, 고급프로그래밍
Message Map 의 구성 선언부 정의부 DECLARE_MESSAGE_MAP() BEGIN_MESSAGE_MAP() END_MESSAGE_MAP() Class CChildView : Public CWnd { …. DECLARE_MESSAGE_MAP( ) } BEGIN_MESSAGE_MAP(CChildView, CWnd) // 메시지 맵 엔트리 추가 END_MESSAGE_MAP() Univ of Incheon, 고급프로그래밍
Message 처리단계(1/3) 메시지 핸들러 함수 선언 (DECLARE_MESSAGE_MAP) ChildView.h class CChildView :: public CWnd { //{{AFX_MSG(CChildView) afx_msg void OnLButtonDown(UINT nFlags, CPoint point); afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); afx_msg void OnRButtonDown(UINT nFlags, CPoint point); //}}AFX_MSG DECLARE_MESSAGE_MAP( ) } ChildView.h 핸들러 함수 선언 Univ of Incheon, 고급프로그래밍
Message 처리단계(2/3) 메시지 매크로 (BEGIN_MESSAGE_MAP, END_MESSAGE_MAP) ChildView.cpp BEGIN_MESSAGE_MAP(CChildView, CWnd) //{{AFX_MSG_MAP(CChildView) ON_WM_LBUTTONDOWN( ) ON_WM_KEYDOWN( ) ON_WM_RBUTTONDOWN ( ) //}}AFX_MSG END_MESSAGE_MAP( ) Univ of Incheon, 고급프로그래밍
Message 처리단계(3/3) 핸들러 구현(함수) : 메시지를 처리하는 함수 구현 ChildView.cpp void CChildView::OnLButtonDown(UINT nFlag, Cpoint point) { CWnd::OnLButtonDown(nFlags, point); } void CChildView::OnKeyDown(UINT nFlag, Cpoint point) CWnd::OnKeyDown(nFlags, point); void CChildView::OnRButtonDown(UINT nFlag, Cpoint point) CWnd::OnRButtonDown(nFlags, point); Univ of Incheon, 고급프로그래밍
메시지 매크로의 확장(1/8) DECLARE_MESSAGE_MAP() AFXWIN.H Univ of Incheon, 고급프로그래밍
메시지 매크로의 확장(2/8) AFX_MSGMAP_ENTRY 메시지 맵 항목은 AFX_MSGMAP_ENTRY로 정의 메시지 식별번호, 통지코드, 개체식별 번호 등이 포함된 구조체 // 윈도우 메시지 ID // 통지코드 // 개체 식별 번호 // 개체범위의 마지막 식별 번호 // 메시지 핸들러 유형 // 메시지 핸들러 Univ of Incheon, 고급프로그래밍
메시지 매크로의 확장(3/8) AFX_MSGMAP 메시지 처리를 위해 메시지 맵에 등록되어있는 메시지 핸들러 호출 매시지 맵은 메시지 맵 항목들로 이루어진 배열 함수포인터 하나 Or 베이스 메시지맵 포인터 AND 메시지맵 엔트리 포인터 Univ of Incheon, 고급프로그래밍
메시지 매크로의 확장(4/8) BEGIN_MESSAGE_MAP GetMessageMap을 구현, messageMap초기화하며 메시지 맵이 정의된 클래스 기초 클래스 배열 열기 GetMessageMap을 구현, messageMap초기화하며 messageEntries[]에 메시지 맵 항목을 넣을 수 있게 준비 Univ of Incheon, 고급프로그래밍
메시지 매크로의 확장(5/8) Message Map entries 메시지 맵 매크로 형식은 메시지에 따라 다르다 Ex) WM_LBUTTONDOWN을 처리할 때 다음과 같은 매크로 필요 ON_WM_LBUTTONDOWN( ) ` ON_WM_LBUTTONDOWN은 WM_LBUTTONDOWN메시지 발생시 OnLButtonDown이 호출되어야 함 유저가 임의로 바꿀 수 없음 Univ of Incheon, 고급프로그래밍
메시지 매크로의 확장(6/8) END_MESSAGE_MAP ` 배열 닫기 윈도우 Message ID 메시지 handler messageEntries의 마지막임을 표시하는 메시지 맵 항목 추가, 메시지 맵 배열 종료 Univ of Incheon, 고급프로그래밍
메시지 매크로의 확장(7/8) BEGIN_MESSAGE_MAP(CChildView, CWnd) ON_WM_LBUTTONDOWN( ) ON_WM_KEYDOWN( ) ON_WM_RBUTTONDOWN( ) END_MESSAGE_MAP( ) const AFX_MSGMAP CChildView::GetMessageMap( ) const { return & CChildView::messageMap;} const AFX_MSGMAP CChildView::_message Map = {&CWnd::messageMap, &CChildView::_messageEntries[]}; const AFX_MSGMAP_ENTRY CChildView::_messageEntries[]={ {WM_LBUTTONDOWN, 0, 0, 0, AfxSig_vwp, &OnLButtonDown}, {WM_KEYDOWN, 0, 0, 0, AfxSig_vwp, &OnKeyDown}, {WM_RBUTTONDOWN, 0, 0, 0, AfxSig_vwp, &OnRButtonDown}, {0, 0, 0, 0, afxSig_end, (AFX_PMSG)0 } }; Univ of Incheon, 고급프로그래밍
메시지 매크로의 확장(8/8) MESSAGE_MAP의 특징 _messageEntries[] 배열의 크기를 한정하지 않고 있음 몇 개의 메시지가 추가될지 모름 여러 개 구조체 변수들 관련 AFX_MSGMAP AFX_MSGMAP_ENTRY 매크로 정의이기 때문에 컴파일 1차 패스에서 변환 각 클래스별로 메시지맵 관리 Univ of Incheon, 고급프로그래밍
사용자 정의 메시지(1/8) MFC가 제공하지 않는 윈도우 메시지 사용자가 직접 발생시키는 메시지 WM_MYMESSAGE라는 새로운 메시지를 만들고자 한다면 #define문을 이용 WM_USER이후의 값을 선언 WM_USER이후의 값(WM_USER+1)의 의미 윈도우 메시지는 “WINUSER.H”에 메시지 Number, 즉 ID값이 정의되어있음 (MFC에서 미리 정의한 Message ID) < (사용자 정의 Message ID) 따라서 중복 방지를 위해 WM_USER + 1, 2와 같은 방법으로 메시지 생성 프로젝트명View.cpp Univ of Incheon, 고급프로그래밍
사용자 정의 메시지(2/8) 메시지가 발생했을때 수행되는 함수를 헤더부에 설정 해당 메시지에 대한 핸들러 함수의 원형을 헤더부에 선언 <프로젝트명View.h> afx_msg void 핸들러함수명(WPARAM wParam, LPARAM lParam); wParam과 lParam인수는 처리중인 메시지에 따라 달리짐 프로젝트명View.h Univ of Incheon, 고급프로그래밍
사용자 정의 메시지(3/8) ON_MESSAGE매크로를 이용하여 정의한 메시지명과 함수명을 결합하여 선언 <메시지 매크로> ON_MESSAGE(메시지명, 함수명) 프로젝트명View.cpp Univ of Incheon, 고급프로그래밍
사용자 정의 메시지(4/8) 선언한 함수를 소스부에 만들고 해당 메시지가 수행되었을때의 함수를 만듬 다음과 같이 소스부에 핸들러 함수 구현 <소스부> void 클래스명 :: 함수명(WPARAM wParam, LPARAM lParam) { // 소스코딩 } UsrMsgTestView.cpp Univ of Incheon, 고급프로그래밍
사용자 정의 메시지(5/8) SendMessage 사용자가 만든 메시지는 사용자가 직접 메시지를 발생시킴 CWnd의 멤버 함수 WM_MYMESSAGE를 생성 LRESULT SendMessage ( UINT message, WPARAM wParam = 0, LPARAM lParam = 0); Message : 보내고자 하는 Message ID wParam : 메시지 정보와 함께 보내주는 WPARAM 인자 lParam : 메시지 정보와 함께 보내주는 lParam 인자 SendMessage(WM_MYMESSAGE, 0, 0); Univ of Incheon, 고급프로그래밍
사용자 정의 메시지(6/8) 사용자 정의 메시지의 예 (프로젝트명 : UsrMsgTest) UsrMsgTestView.cpp Message ID를 등록후 사용자 정의 메시지에 대한 핸들러 함수의 원형을 헤더에 선언 UsrMsgTestView.h Univ of Incheon, 고급프로그래밍
사용자 정의 메시지(7/8) 메시지 매크로를 메시지 맵 블럭내에 추가 한후 핸들러 함수 구현 UsrMsgTestView.cpp Univ of Incheon, 고급프로그래밍
사용자 정의 메시지(8/8) 프로그램 실행 결과 마우스 왼쪽버튼클릭 UsrMsgTestView.cpp Univ of Incheon, 고급프로그래밍
메시지 처리 방식의 종류(1/2) 큐 경유 방식 큐를 경유 하지 않는 방식 입력 메시지들(WM_LBUTTONDOWN, WM_KEYDOWN, WM_SYSTEMDOWN, WM_TIMER 등) message message queue message loop window procedure 큐를 경유 하지 않는 방식 입력 메시지를 제외한 대부분의 메시지들(WM_CREATE, WM_SIZE, WM_CLOSE,WM_PAINT() WM_DESTROY, WM_MOVE, 등) message window procedure Univ of Incheon, 고급프로그래밍
메시지 처리 방식의 종류(2/2) 하드웨어 장치 Windows O/S 응용 프로그램 입력 메시지 시스템 큐 응용 큐 메시지 루프 Window procedure 시스템 큐 입력 메시지 입력 제외 메시지 응용 큐 Univ of Incheon, 고급프로그래밍
메시지 처리 흐름(1/11) Message Loop 메시지 루프는 CWinThread::Run에 의해 실행 CWinThread::Run은 WM_QUIT가 발생할 때까지 반복적으로 메시지를 가져와 분배 CWnd::SendMessage 메시지 큐를 거치지 않고 메시지 발생 CWnd::PostMessage 메시지 큐에 메시지를 넣음 Univ of Incheon, 고급프로그래밍
메시지 처리 흐름(2/11) int CWinThread::Run() // idle time 상태를 추적하기 위한 변수 { BOOL bIdle = TRUE; LONG lIdleCount = 0; //WM_QUIT를 받을 때까지 메시지를 가져와 분배한다. for (;;) while ( bIdle && !::PeekMessage( &m_msgCur, ... ) ) {// bIdle이 TRUE 이고 메시지 큐에 메시지가 없는지 체크 if ( !OnIdle ( lIdleCount++ ) ) bIdle = FALSE; } do if ( !PumpMessage() ) return ExitInstance(); // WM_QUIT를 받으면 여기 if ( IsIdleMessage ( &m_msgCur ) ) bIdle = TRUE; // idle 메시지면 여기 IdleCount = 0; } while ( ::PeekMessage ( &m_msgCur, ... ) ); Univ of Incheon, 고급프로그래밍
메시지 처리 흐름(3/11) BOOL CWinThread::PumpMessage() { if ( !::GetMessage(&m_msgCur, ...) ) // message queue로부터 메시지를 가져온다. { return FALSE; // WM_QUIT를 받으면 FALSE를 반환하게 된다. } if ( m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur) ) { ::TranslateMessate(&m_msgCur); ::DispatchMessage(&m_msgCur); // window procedure에게 메시지 분배 return TRUE; 메시지가 없을때 CWinThread::OnIdle()을 호출하여 백그라운드작업 수행 메시지가 있을 경우 CWinThread::PumpMessage()를 호출 메시지 큐로부터 메시지를 가져와 윈도우 프로시저에 분배 DispatchMessage() 를 통해 메시지를 분배하기 이전에 가상함수인 PreTranslateMessage()를 호출함으로써 유저에게 입력 메시지를 가로챌 수 있는 기회 제공 Univ of Incheon, 고급프로그래밍
메시지 처리 흐름(4/11) Window Procedure 모든 메시지는 윈도우 프로시저에 의해 처리 ` 모든 메시지는 윈도우 프로시저에 의해 처리 CWnd::WindowProc()은 CWnd::OnWndMsg()를 호출하여 메시지 맵에 등록된 메시지 핸들러 호출 처리되지 않는 메시지는 CWnd::DefWindowProc()을 호출, default 방식으로 메시지 처리 Univ of Incheon, 고급프로그래밍
PreTranslateMesssage() 메시지 처리 흐름(5/11) event CWnd::OnWndMsg GetMesageMap( )을 사용하여 메시지맵에서 아이디에 해당하는 핸들러 검색 해당 메시지 핸들러(사용자 정의 메시지 핸들러) 검색 후 해당 메시지 핸들러 실행 예외) WM_COMMAND OnCommand 함수 호출 WM_NOTIFY OnNotify 함수 호출 1 CWinTread::Run() 2 CWinTread:: PumpMessage() 3 CWnd:: PreTranslateMesssage() 4 CWnd:: DispatchMesssage() 5 AfxWndProc( ) CWnd::OnCommand() 6 AfxCallWndProc( ) CWnd::OnNotify() 7 CWnd::OnWndMsg() CWnd:: GetMessageMap() Tread Message Queue 8 CWnd:: DefWindowProc() 6 Message Handling Function Univ of Incheon, 고급프로그래밍
메시지 처리 흐름(6/11) CWnd::OnWndMsg Wincore.cpp // WM_COMMAND 계열 처리 // WM_NOTIFY 계열 처리 // WM_ACTIVATE 처리 // WM_SETCURSOR 처리 CWnd::OnWndMsg Univ of Incheon, 고급프로그래밍
메시지 처리 흐름(7/11) GetMessageMap() 함수 // 캐쉬내에서 찾았다면 (메시지 처리를 캐쉬를 이용해서 찾는다) // message map entry에 등록된 메시지 핸들러가 없으면 FALSE 반환 GetMessageMap() 함수 유저클래스에서 사용한 BEGIN_MESSAGE_MAP 매크로가 확장시 재정의된 가상함수 이 함수는 CChildView::messageMap을 리턴 CChildView::messageMap안에는 CChildView::_messageEntries의 주소가 포함 결국 가장 하위레벨 클래스의 메시지 맵부터 검사 Univ of Incheon, 고급프로그래밍
메시지 처리 흐름(8/11) // 정해진 메시지인지 사용자 정의 메시지 핸들러 인지 판단 메시지 핸들러 검색함수 Messge id를 가지고 CChildView::_messageEntries를 검색해서 메시지 맵 항목 리턴 만약 WM_LBUTTONDOWN메세지면 {WM_LBUTTONDOWN, 0, 0, 0, afxSig_vwp, &OnLButtonDown}을리턴 //캐쉬가 정해져 있지 않으면 선형검색 Univ of Incheon, 고급프로그래밍
메시지 처리 흐름(9/11) // CWnd::OnWndMsg에서는 메시지 맵 항목의 6번째 멤버 변수인 pfn을 호출 // 각각 핸들러의 시그니처에 맞는 함수의 형태를 호출 // case가 많이 있음 // 핸들러 함수 실행 Univ of Incheon, 고급프로그래밍
메시지 처리 흐름(10/11) DefWindowProc CWnd::OnWndMsg에서는 메시지 핸들러가 현재 클래스에 있으면 현재 클래스의 메시지 핸들러를 호출하고 현재 클래스에 없으면 FALSE를 리턴해서 CWnd::WindowProc가 CWnd::DefWindowProc를 호출하도록 되어 있다 LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { ..... if (!OnWndMsg(message, wParam, lParam, &lResult)) lResult = DefWindowProc(message, wParam, lParam); <--- OnWndMsg에서 FALSE가 리턴되면 여기 } Univ of Incheon, 고급프로그래밍
메시지 처리 흐름(11/11) LRESULT CWnd::DefWindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam) { if (m_pfnSuper != NULL) return ::CallWindowProc(m_pfnSuper, m_hWnd, nMsg, wParam, lParam); WNDPROC pfnWndProc; if ((pfnWndProc = *GetSuperWndProcAddr()) == NULL) return ::DefWindowProc(m_hWnd, nMsg, wParam, lParam); else return ::CallWindowProc(pfnWndProc, m_hWnd, nMsg, wParam, lParam); } m_pfnSuper은 창이 서브클래싱(subclassing)되어 있을 때 서브클래싱된 창의 윈도우 프로시저(WNDPROC)을 가리키는 함수 포인터이다. 즉, CWnd::DefWindowProc은 창이 서브클래싱 된 경우 서브클래싱된 창의 윈도우 프로시저를 호출하고 서브클래싱 되지 않은 경우에는 ::DefWindowProc를 호출하여 default 방식으로 메시지를 처리하도록 하고 있다. Univ of Incheon, 고급프로그래밍