490 likes | 1.04k Views
MFC 의 메시지 처리. 1. 4. 메시지 개요. Message 처리단계. 2. 5. Message Map 처리 기본개념. 메시지 매크로의 확장. 3. Message Map 의 구성. 목 차. 메시지 구조 메시지 종류. DECLARE_MESSAGE_MAP BEGIN_MESSAGE_MAP END_MESSAGE_MAP. 6. 사용자 정의 메시지. 8. 메시지 처리 흐름. 7. 메시지 처리방식의 종류. 목 차. 큐를 경유하는 방식
E N D
1 4 메시지 개요 Message 처리단계 2 5 Message Map 처리 기본개념 메시지 매크로의 확장 3 Message Map의 구성 목 차 • 메시지 구조 • 메시지 종류 • DECLARE_MESSAGE_MAP • BEGIN_MESSAGE_MAP • END_MESSAGE_MAP Univ of Incheon, 고급프로그래밍
6 사용자 정의 메시지 8 메시지 처리 흐름 7 메시지 처리방식의 종류 목 차 • 큐를 경유하는 방식 • 큐를 경유하지 않는 방식 • 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) ev 메시지 큐 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, 고급프로그래밍
메시지 유형 발생상황 메시지 핸들러 함수 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() 메시지 개요(4/7) • Windows Message 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, 고급프로그래밍
CView 파생 클래스 CDocument 파생 클래스 CFrameWnd 파생 클래스 CWinApp 파생 클래스 메시지 개요(7/7) • WM_COMMAND 메시지 전달순서 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로 표현 LESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; switch (iMsg) { case WM_CREATE : //윈도가 만들어질 때 모듈 break; case WM_PAINT : //화면 출력 모듈 break; case WM_KEYDOWN : //키 입력시 처리 모듈 break; case WM_CHAR: //문자 입력시 처리 모듈 break; case WM_DESTROY: //윈도가 없어질 때 모듈 break; } } 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 메시지 맵의 핵심 • 구조체는 윈도우 MESSAGE MAP에 대응하는 멤버 함수의 시작주소를 가짐 • 코드의 자동화를 위하여 메시지 맵에 메시지와 메시지 핸들러 함수를 묶는 메시지의 매크로를 추가하여 사용 Handler0() { //… } Message ID 0 Handler0 Message ID 1 Handler1 Handler1() { //… } ● ● ● ● ● ● Message ID n-1 Handler n-1 Handler n-1() { //… } 0 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, 고급프로그래밍
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( ) } 핸들러 함수 선언 Message 처리단계(1/3) • 메시지 핸들러 함수 선언 (DECLARE_MESSAGE_MAP) 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, 고급프로그래밍
// 윈도우 메시지 ID // 통지코드 // 개체 식별 번호 // 개체범위의 마지막 식별 번호 // 메시지 핸들러 유형 // 메시지 핸들러 메시지 매크로의 확장(2/8) • AFX_MSGMAP_ENTRY • 메시지 맵 항목은 AFX_MSGMAP_ENTRY로 정의 • 메시지 식별번호, 통지코드, 개체식별 번호 등이 포함된 구조체 Univ of Incheon, 고급프로그래밍
메시지 매크로의 확장(3/8) • AFX_MSGMAP • 메시지 처리를 위해 메시지 맵에 등록되어있는 메시지 핸들러 호출 • 매시지 맵은 메시지 맵 항목들로 이루어진 배열 함수포인터 하나 Or 베이스 메시지맵 포인터 AND 메시지맵 엔트리 포인터 Univ of Incheon, 고급프로그래밍
메시지 매크로의 확장(4/8) • BEGIN_MESSAGE_MAP 메시지 맵이 정의된 클래스 기초 클래스 배열 열기 • 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, 고급프로그래밍
` 배열 닫기 메시지 handler 윈도우 Message ID 메시지 매크로의 확장(6/8) • END_MESSAGE_MAP • messageEntries의 마지막임을 표시하는 메시지 맵 항목 추가, 메시지 맵 배열 종료 Univ of Incheon, 고급프로그래밍
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 } }; 메시지 매크로의 확장(7/8) Univ of Incheon, 고급프로그래밍
메시지 매크로의 확장(8/8) • MESSAGE_MAP의 특징 • _messageEntries[] 배열의 크기를 한정하지 않고 있음 몇 개의 메시지가 추가될지 모름 • 여러 개 구조체 변수들 관련 • AFX_MSGMAP • AFX_MSGMAP_ENTRY • 매크로 정의이기 때문에 컴파일 1차 패스에서 변환 • 각 클래스별로 메시지맵 관리 Univ of Incheon, 고급프로그래밍
프로젝트명View.cpp 사용자 정의 메시지(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와 같은 방법으로 메시지 생성 Univ of Incheon, 고급프로그래밍
<프로젝트명View.h> afx_msg void 핸들러함수명(WPARAM wParam, LPARAM lParam); wParam과 lParam인수는 처리중인 메시지에 따라 달리짐 프로젝트명View.h 사용자 정의 메시지(2/8) • 메시지가 발생했을때 수행되는 함수를 헤더부에 설정 • 해당 메시지에 대한 핸들러 함수의 원형을 헤더부에 선언 Univ of Incheon, 고급프로그래밍
프로젝트명View.cpp 사용자 정의 메시지(3/8) • ON_MESSAGE매크로를 이용하여 정의한 메시지명과 함수명을 결합하여 선언 • 메시지 맵에 ON_MESSAGE()라는 메시지 매크로를 추가 <메시지 매크로> ON_MESSAGE(메시지명, 함수명) Univ of Incheon, 고급프로그래밍
UsrMsgTestView.cpp 사용자 정의 메시지(4/8) • 선언한 함수를 소스부에 만들고 해당 메시지가 수행되었을때의 함수를 만듬 • 다음과 같이 소스부에 핸들러 함수 구현 <소스부> void 클래스명 :: 함수명(WPARAM wParam, LPARAM lParam) { // 소스코딩 } Univ of Incheon, 고급프로그래밍
SendMessage 사용자가 만든 메시지는 사용자가 직접 메시지를 발생시킴 이때 사용하는 함수가 SendMessage() CWnd의 멤버 함수 WM_MYMESSAGE를 생성 사용자 정의 메시지(5/8) 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, 고급프로그래밍
UsrMsgTestView.cpp UsrMsgTestView.h 사용자 정의 메시지(6/8) • 사용자 정의 메시지의 예 (프로젝트명 : UsrMsgTest) Message ID를 등록후 사용자 정의 메시지에 대한 핸들러 함수의 원형을 헤더에 선언 Univ of Incheon, 고급프로그래밍
UsrMsgTestView.cpp 사용자 정의 메시지(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, 고급프로그래밍
Windows O/S 응용 프로그램 하드웨어 장치 입력 메시지 시스템 큐 메시지 루프 응용 큐 입력 제외 메시지 Window procedure 메시지 처리 방식의 종류(2/2) Univ of Incheon, 고급프로그래밍
메시지 처리 흐름(1/11) • Message Loop • 메시지 큐를 경유하는 메시지들은 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) • 메시지가 없을때 CWinThread::OnIdle()을 호출하여 백그라운드작업 수행 • 메시지가 있을 경우 CWinThread::PumpMessage()를 호출 메시지 큐로부터 메시지를 가져와 윈도우 프로시저에 분배 • DispatchMessage() 를 통해 메시지를 분배하기 이전에 가상함수인 PreTranslateMessage()를 호출함으로써 유저에게 입력 메시지를 가로챌 수 있는 기회 제공 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; } Univ of Incheon, 고급프로그래밍
` 메시지 처리 흐름(4/11) • Window Procedure • 모든 메시지는 윈도우 프로시저에 의해 처리 • CWnd::WindowProc()은 CWnd::OnWndMsg()를 호출하여 메시지 맵에 등록된 메시지 핸들러 호출 • 처리되지 않는 메시지는 CWnd::DefWindowProc()을 호출, default 방식으로 메시지 처리 Univ of Incheon, 고급프로그래밍
메시지 처리 흐름(5/11) • CWnd::OnWndMsg • GetMesageMap( )을사용하여메시지맵에서 아이디에 해당하는 핸들러 검색 • 해당메시지핸들러(사용자정의메시지핸들러) 검색 후 해당 메시지 핸들러 실행 • 예외) WM_COMMAND OnCommand 함수 호출 WM_NOTIFY OnNotify 함수 호출 event 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, 고급프로그래밍
CWnd::OnWndMsg Wincore.cpp // WM_COMMAND 계열 처리 // WM_NOTIFY 계열 처리 // WM_ACTIVATE 처리 // WM_SETCURSOR 처리 메시지 처리 흐름(6/11) Univ of Incheon, 고급프로그래밍
메시지 처리 흐름(7/11) // 캐쉬내에서 찾았다면 (메시지 처리를 캐쉬를 이용해서 찾는다) // 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, 고급프로그래밍