mfc 의 메시지 처리
DESCRIPTION
MFC 의 메시지 처리. 1. 4. 메시지 개요. Message 처리단계. 2. 5. Message Map 처리 기본개념. 메시지 매크로의 확장. 3. Message Map 의 구성. 목 차. 메시지 구조 메시지 종류. DECLARE_MESSAGE_MAP BEGIN_MESSAGE_MAP END_MESSAGE_MAP. 6. 사용자 정의 메시지. 8. 메시지 처리 흐름. 7. 메시지 처리방식의 종류. 목 차. 큐를 경유하는 방식 - PowerPoint PPT PresentationTRANSCRIPT
1
MFC 의 메시지 처리
Univ of Incheon, 고급프로그래밍2
목 차
메시지 개요1
Message Map 처리 기본개념2
Message Map 의 구성3
Message 처리단계4
메시지 매크로의 확장5
메시지 구조 메시지 종류
DECLARE_MESSAGE_MAP BEGIN_MESSAGE_MAP END_MESSAGE_MAP
Univ of Incheon, 고급프로그래밍3
목 차
사용자 정의 메시지6
메시지 처리 흐름8
메시지 처리방식의 종류7
큐를 경유하는 방식 큐를 경유하지 않는 방식
Message Loop Window Procedure DefWindowProc
Univ of Incheon, 고급프로그래밍4
메시지 개요 (1/7)
메시지 구조 메시지 : 프로그램에 변화가 생겼을 때 Windows 가 프로그램에게 알리는 정보 메시지는 MSG 로 정의되는 구조체 ( 윈도우 핸들 , 메시지 식별 번호 , 추가 정보 , 시간 , 커서 위치 등 포함 )
typedef struct tagMSG { HWND hwnd; // 메시지가 발생한 윈도우 핸들 UINT message; // message id WPARAM wParam; // 추가 정보 LPARAM lParam; // 추가 정보
DWORD time; // 메시지 발생 시간 POINT pt; // 커서 위치 } MSG;
typedef struct tagPOINT { LONG x; // 화면 좌표 LONG y; // 화면 좌표 } POINT;
<WINUSER.H>
<WINDEF.H>
Univ of Incheon, 고급프로그래밍5
메시지 개요 (2/7)
evevDeviceDriverDeviceDriver
DeviceDriverDeviceDriver
DeviceDriverDeviceDriver
응용프로그램
응용프로그램
응용프로그램
응용프로그램
응용프로그램
응용프로그램
메시지 큐메시지 큐
입력 장치 출력 장치
Windows OS
사용자 입력 입력용 Device Driver( 키보드 , 마우스 , 조이스틱 )
메시지 큐 Windows 운영체제 응용 프로그램 출력용 Device Driver( 모니터 , 프린터 , 디스크 ) 출력
Univ of Incheon, 고급프로그래밍6
메시지 개요 (3/7)
메시지 종류 윈도우 메시지 (Windows Message)
“WM_” 으로 시작하는 메시지 (WM_COMMAND 제외 ) 매개 변수를 가지고 있어 어떻게 처리할 것인지 결정
윈도우 관리메시지 , 초기화 메시지 , 입력메시지 명령 경로 배정없이 해당 윈도우에 직접 전달
컨트롤 통지 메시지 (Control Notification Message) Button, Combo Box 와 같은 제어객체나 자식윈도우에서 부모 윈도우로
보내는 메시지
명령 메시지 (Command Message) 메뉴 , 툴바 , 액셀레이터 키와 같은 사용자 인터페이스 객체로부터 발생되는
WM_COMMAND 메시지 도큐먼트 , 도큐먼트 템플릿 , 뷰 , 다른 Application 객체에 의해 발생 가능
사용자 정의 메시지 SendMessage() 와 PostMessage() 를 사용하여 메지시 전달
Univ of Incheon, 고급프로그래밍7
메시지 개요 (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, 고급프로그래밍8
명령 메시지 (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); }
메시지 개요 (5/7)
Univ of Incheon, 고급프로그래밍9
메시지 개요 (6/7)
만일 OnCommand 라는 메시지 핸들러에서 모든 메시지를 처리를 하면 할 일이 너무 많아짐
일반적인 윈도우 메시지 처리는 CWnd 클래스를 상속받은 클래스들에서 처리
( CWnd 클래스 상위 클래스는 윈도우 메시지 처리부분이 없음 )
WM_COMMAND 메시지는 CCmdTarget 클래스에 구현 CCmdTarget 클래스 하위 클래스는 모두 WM_COMMAND
메시지 구현 가능
사용자가 메뉴 항목을 선택하여 프로그램에 명령을 내리면 WM_COMMAND 메시지가 모든 AFX 클래스에 전달
Univ of Incheon, 고급프로그래밍10
메시지 개요 (7/7)
WM_COMMAND 메시지 전달순서
CView파생 클래스
CDocument파생 클래스
CFrameWnd파생 클래스
CWinApp파생 클래스
파생 클래스 설명
CDocument 프로그램의 데이터를 처리하는 기능
CView 데이터를 화면에 표시하는 기능
CWinApp 프로그램의 시작과 종료에 관련 된 커맨드
CFrameWnd 프레임 윈도우의 제어에 관계된 커멘드 처리
Univ of Incheon, 고급프로그래밍11
메시지 맵이란 윈도우 메시지를 받아야 할 클래스가 가지는 정적 구조체 배열
이 정적 구조체 배열은 처리할 메시지와 메시지에 대응하는 멤버함수에 대한 포인터를 가짐
MFC 는 메시지 맵의 코드 자동화를 위해 매크로를 사용
DECLARE_MESSAGE_MAP
BEGIN_MESSAGE_MAP, END_MESSAGE_MAP
ON_WM_LBUTTONDOWN()
Message Map 처리 기본개념 (1/5)
Univ of Incheon, 고급프로그래밍12
Message Map 처리 기본개념 (2/5)
While ( GetMessage ( &msg, NULL, 0, 0 ) ){
TranslateMessage( &msg );DispatchMessage
( &msg );}
SDK 기반에서는 메시지가 있는 경우에만 윈도우 프로시저를 호출 처리할 메시지가 없다면 CPU 는 블록 상태가 되어 다른
응용프로그램이 CPU 를 할당받아 일을 처리
MFC 의 메시지 루프는 GetMessage() 대신 PeekMessage()
사용 PeekMessage() 는 블록상태가 되지 않음 처리할 메시지가 없는 시간 (Idle Time) 에 가상함수 OnIdle() 이 호출됨
Univ of Incheon, 고급프로그래밍13
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;
}}
해당하는 모듈을 모두 switch 문으로 설정
BEGIN_MESSAGE_MAP(CMyWnd, CWnd)
ON_WM_CREATE( )ON_WM_PAINT( )ON_WM_KEYDOWN( )ON_WM_CHAR( )ON_WM_DESTROY( )
END_MESSAGE_MAP( )
MFC 로 표현
Message Map 처리 기본개념 (3/5)
Univ of Incheon, 고급프로그래밍14
Message Map 처리 기본개념 (4/5)
Message Map 의 이해 API 프로그램은 윈도우의 메시지를 처리할 때 윈도우 프로시저내에 중첩된 if 문과 switch 문을 사용 , 각각의 메시지에 대한 처리를 하는 이벤트 핸들러 코드를 작성 MFC 에서는 MESSAGE_MAP 매커니즘을 사용 따라서 if 문이나 switch 문이 없다 . MESSAGE_MAP 의 메커니즘은 메시지와 이벤트 핸들러를 일대일로 연결시켜주는 테이블의 역할 수행 파생 클래스의 메시지 핸들러 함수를 여기에 등록하면 기반 클래스의 함수를 무시하고 , 파생 클래스의 함수를 호출하는 매크로
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
ON_WM_MOUSEMOVE()
ON_WM_CREATE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
CFrameWnd 에서 상속 받은CMainFrame 클래스의 메시지 맵 임을 나타냄
메시지 맵의 시작을 나타냄
메시지 맵의 끝을 나타냄
ClassWizard .가 파싱하는 부분 ClassWizard 이 부분은 에 의해
자동으로 관리됨
OnMouseMove 함수 오버라이딩OnCreate 함수 오버라이딩
Univ of Incheon, 고급프로그래밍15
MFC 메시지 맵의 핵심
구조체는 윈도우 MESSAGE MAP 에 대응하는 멤버 함수의 시작주소를 가짐
코드의 자동화를 위하여 메시지 맵에 메시지와 메시지 핸들러 함수를 묶는 메시지의 매크로를 추가하여 사용
Handler0(){ //…}
Handler1(){ //…}
Handler n-1(){ //…}
Message ID 1
Message ID 0 Handler0
Handler1
0
Message ID n-1 Handler n-1
NULL
●
●
●
Message Map
Message Map 처리 기본개념 (5/5)
●
●
●
Univ of Incheon, 고급프로그래밍16
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, 고급프로그래밍17
메시지 핸들러 함수 선언 (DECLARE_MESSAGE_MAP)
Message 처리단계 (1/3)
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, 고급프로그래밍18
메시지 매크로 (BEGIN_MESSAGE_MAP, END_MESSAGE_MAP)
Message 처리단계 (2/3)
BEGIN_MESSAGE_MAP(CChildView, CWnd)
//{{AFX_MSG_MAP(CChildView)
ON_WM_LBUTTONDOWN( )
ON_WM_KEYDOWN( )
ON_WM_RBUTTONDOWN ( )
//}}AFX_MSG
END_MESSAGE_MAP( )
ChildView.cpp
Univ of Incheon, 고급프로그래밍19
핸들러 구현 ( 함수 ) : 메시지를 처리하는 함수 구현
Message 처리단계 (3/3)
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);}
ChildView.cpp
Univ of Incheon, 고급프로그래밍20
메시지 매크로의 확장 (1/8)
DECLARE_MESSAGE_MAP()
AFXWIN.H
Univ of Incheon, 고급프로그래밍21
메시지 매크로의 확장 (2/8)
AFX_MSGMAP_ENTRY 메시지 맵 항목은 AFX_MSGMAP_ENTRY 로 정의 메시지 식별번호 , 통지코드 , 개체식별 번호 등이
포함된 구조체
// 윈도우 메시지 ID
// 통지코드
// 개체 식별 번호
// 개체범위의 마지막 식별 번호
// 메시지 핸들러 유형
// 메시지 핸들러
Univ of Incheon, 고급프로그래밍22
메시지 매크로의 확장 (3/8)
AFX_MSGMAP 메시지 처리를 위해 메시지 맵에 등록되어있는 메시지 핸들러 호출 매시지 맵은 메시지 맵 항목들로 이루어진 배열
함수포인터 하나 Or 베이스 메시지맵 포인터 AND 메시지맵 엔트리 포인터
Univ of Incheon, 고급프로그래밍23
메시지 매크로의 확장 (4/8)
BEGIN_MESSAGE_MAP
기초 클래스메시지 맵이
정의된 클래스
GetMessageMap 을 구현 , messageMap 초기화하며
messageEntries[] 에 메시지 맵 항목을 넣을 수 있게 준비
배열 열기
Univ of Incheon, 고급프로그래밍24
메시지 매크로의 확장 (5/8)Message Map entries
메시지 맵 매크로 형식은 메시지에 따라 다르다Ex) WM_LBUTTONDOWN을 처리할 때 다음과 같은 매크로 필요
ON_WM_LBUTTONDOWN( )
ON_WM_LBUTTONDOWN 은 WM_LBUTTONDOWN메시지 발생시 OnLButtonDown 이 호출되어야 함
유저가 임의로 바꿀 수 없음
`
Univ of Incheon, 고급프로그래밍25
메시지 매크로의 확장 (6/8)
END_MESSAGE_MAP
`
배열 닫기
윈도우 Message ID메시지 handler
messageEntries 의 마지막임을 표시하는 메시지 맵 항목 추가 ,
메시지 맵 배열 종료
Univ of Incheon, 고급프로그래밍26
메시지 매크로의 확장 (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, 고급프로그래밍27
MESSAGE_MAP 의 특징 _messageEntries[] 배열의 크기를 한정하지 않고 있음
몇 개의 메시지가 추가될지 모름
여러 개 구조체 변수들 관련 AFX_MSGMAP
AFX_MSGMAP_ENTRY
매크로 정의이기 때문에 컴파일 1 차 패스에서 변환 각 클래스별로 메시지맵 관리
메시지 매크로의 확장 (8/8)
Univ of Incheon, 고급프로그래밍28
사용자 정의 메시지 (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, 고급프로그래밍29
사용자 정의 메시지 (2/8)
메시지가 발생했을때 수행되는 함수를 헤더부에 설정
해당 메시지에 대한 핸들러 함수의 원형을 헤더부에 선언프로젝트명 View.h
< 프로젝트명 View.h>afx_msg void 핸들러함수명 (WPARAM wParam, LPARAM lParam);
wParam 과 lParam 인수는 처리중인 메시지에 따라 달리짐
Univ of Incheon, 고급프로그래밍30
사용자 정의 메시지 (3/8) ON_MESSAGE 매크로를 이용하여 정의한 메시지명과 함수명을
결합하여 선언
메시지 맵에 ON_MESSAGE() 라는 메시지 매크로를 추가
< 메시지 매크로 >ON_MESSAGE( 메시지명 , 함수명 )
프로젝트명 View.cpp
Univ of Incheon, 고급프로그래밍31
사용자 정의 메시지 (4/8)
선언한 함수를 소스부에 만들고 해당 메시지가 수행되었을때의 함수를 만듬
다음과 같이 소스부에 핸들러 함수 구현
< 소스부 >void 클래스명 :: 함수명 (WPARAM wParam, LPARAM lParam){
// 소스코딩}
UsrMsgTestView.cpp
Univ of Incheon, 고급프로그래밍32
사용자 정의 메시지 (5/8) SendMessage
사용자가 만든 메시지는 사용자가 직접 메시지를 발생시킴 이때 사용하는 함수가 SendMessage() CWnd 의 멤버 함수
WM_MYMESSAGE 를 생성
LRESULT SendMessage ( UINT message, WPARAM wParam = 0, LPARAM lParam = 0);
Message : 보내고자 하는 Message IDwParam : 메시지 정보와 함께 보내주는 WPARAM 인자lParam : 메시지 정보와 함께 보내주는 lParam 인자
SendMessage(WM_MYMESSAGE, 0, 0);
Univ of Incheon, 고급프로그래밍33
사용자 정의 메시지 (6/8) 사용자 정의 메시지의 예 ( 프로젝트명 :
UsrMsgTest) UsrMsgTestView.cpp
UsrMsgTestView.h
Message ID 를 등록후 사용자 정의 메시지에 대한 핸들러 함수의 원형을 헤더에 선언
Univ of Incheon, 고급프로그래밍34
사용자 정의 메시지 (7/8)
메시지 매크로를 메시지 맵 블럭내에 추가 한후 핸들러 함수 구현
UsrMsgTestView.cpp
UsrMsgTestView.cpp
Univ of Incheon, 고급프로그래밍35
사용자 정의 메시지 (8/8)
마우스 왼쪽버튼클릭
프로그램 실행 결과UsrMsgTestView.cpp
Univ of Incheon, 고급프로그래밍36
큐 경유 방식 입력 메시지들 (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
메시지 처리 방식의 종류 (1/2)
Univ of Incheon, 고급프로그래밍37
메시지 처리 방식의 종류 (2/2)
하드웨어 장치
Windows O/S 응용 프로그램
메시지 루프
Window procedure
시스템 큐입력 메시지
입력 제외메시지
응용 큐
Univ of Incheon, 고급프로그래밍38
메시지 처리 흐름 (1/11)
Message Loop 메시지 큐를 경유하는 메시지들은 Message Loop
를 통해 윈도우 프로시져에 전달 메시지 루프는 CWinThread::Run 에 의해 실행 CWinThread::Run 은 WM_QUIT 가 발생할
때까지 반복적으로 메시지를 가져와 분배 CWnd::SendMessage
메시지 큐를 거치지 않고 메시지 발생 CWnd::PostMessage
메시지 큐에 메시지를 넣음
Univ of Incheon, 고급프로그래밍39
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, ... ) );
} }
메시지 처리 흐름 (2/11)
Univ of Incheon, 고급프로그래밍40
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;
}
메시지 처리 흐름 (3/11)
메시지가 없을때 CWinThread::OnIdle() 을 호출하여 백그라운드작업 수행 메시지가 있을 경우 CWinThread::PumpMessage() 를 호출 메시지 큐로부터
메시지를 가져와 윈도우 프로시저에 분배 DispatchMessage() 를 통해 메시지를 분배하기 이전에 가상함수인
PreTranslateMessage() 를 호출함으로써 유저에게 입력 메시지를 가로챌 수 있는 기회 제공
Univ of Incheon, 고급프로그래밍41
Window Procedure
메시지 처리 흐름 (4/11)
모든 메시지는 윈도우 프로시저에 의해 처리 CWnd::WindowProc() 은 CWnd::OnWndMsg() 를
호출하여 메시지 맵에 등록된 메시지 핸들러 호출 처리되지 않는 메시지는 CWnd::DefWindowProc() 을 호
출 , default 방식으로 메시지 처리
`
Univ of Incheon, 고급프로그래밍42
메시지 처리 흐름 (5/11)
CWnd::OnWndMsg GetMesageMap( ) 을 사용하여 메시지맵에서
아이디에 해당하는 핸들러 검색 해당 메시지 핸들러 ( 사용자 정의 메시지 핸들러 )
검색 후 해당 메시지 핸들러 실행 예외 )
WM_COMMAND OnCommand 함수 호출
WM_NOTIFY OnNotify 함수 호출
event
CWnd::OnCommand()
CWnd::OnNotify()
CWnd::GetMessageMap()
6Message Handling
Function
1
2
3
4
5
6
7
8
CWinTread::Run()
CWinTread::PumpMessage()
CWnd::PreTranslateMesssage()
CWnd::DispatchMesssage()
AfxWndProc( )
AfxCallWndProc( )
CWnd::OnWndMsg()
CWnd::DefWindowProc()
Tread Message Queue
Univ of Incheon, 고급프로그래밍43
메시지 처리 흐름 (6/11)
Wincore.cpp
// WM_COMMAND 계열 처리
// WM_NOTIFY 계열 처리
// WM_ACTIVATE 처리
// WM_SETCURSOR 처리
CWnd::OnWndMsg
Univ of Incheon, 고급프로그래밍44
// 캐쉬내에서 찾았다면 ( 메시지 처리를 캐쉬를 이용해서 찾는다 )
// message map entry 에 등록된 메시지 핸들러가 없으면 FALSE 반환
메시지 처리 흐름 (7/11)
GetMessageMap() 함수 유저클래스에서 사용한 BEGIN_MESSAGE_MAP 매크로가 확장시 재정의된 가상함수 이 함수는 CChildView::messageMap 을 리턴 CChildView::messageMap안에는 CChildView::_messageEntries 의
주소가 포함 결국 가장 하위레벨 클래스의 메시지 맵부터 검사
Univ of Incheon, 고급프로그래밍45
// 정해진 메시지인지 사용자 정의 메시지 핸들러 인지 판단
//캐쉬가 정해져 있지 않으면 선형검색
메시지 핸들러 검색함수Messge id 를 가지고 CChildView::_messageEntries 를검색해서 메시지 맵 항목 리턴
만약 WM_LBUTTONDOWN 메세지면{WM_LBUTTONDOWN, 0, 0, 0, afxSig_vwp, &OnLButtonDown} 을리턴
메시지 처리 흐름 (8/11)
Univ of Incheon, 고급프로그래밍46
// CWnd::OnWndMsg 에서는 메시지 맵 항목의 6 번째 멤버 변수인 pfn 을 호출
// case 가 많이 있음
// 각각 핸들러의 시그니처에 맞는 함수의 형태를 호출
메시지 처리 흐름 (9/11)
// 핸들러 함수 실행
Univ of Incheon, 고급프로그래밍47
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 가 리턴되면 여기 .....
}
메시지 처리 흐름 (10/11)
DefWindowProc
Univ of Incheon, 고급프로그래밍48
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 방식으로 메시지를 처리하도록 하고 있다 .
메시지 처리 흐름 (11/11)