48
1 MFC 의 의의의 의의

MFC 의 메시지 처리

  • Upload
    meena

  • View
    198

  • Download
    1

Embed Size (px)

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 Presentation

Citation preview

Page 1: MFC 의 메시지 처리

1

MFC 의 메시지 처리

Page 2: MFC 의 메시지 처리

Univ of Incheon, 고급프로그래밍2

목 차

메시지 개요1

Message Map 처리 기본개념2

Message Map 의 구성3

Message 처리단계4

메시지 매크로의 확장5

메시지 구조 메시지 종류

DECLARE_MESSAGE_MAP BEGIN_MESSAGE_MAP END_MESSAGE_MAP

Page 3: MFC 의 메시지 처리

Univ of Incheon, 고급프로그래밍3

목 차

사용자 정의 메시지6

메시지 처리 흐름8

메시지 처리방식의 종류7

큐를 경유하는 방식 큐를 경유하지 않는 방식

Message Loop Window Procedure DefWindowProc

Page 4: MFC 의 메시지 처리

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>

Page 5: MFC 의 메시지 처리

Univ of Incheon, 고급프로그래밍5

메시지 개요 (2/7)

evevDeviceDriverDeviceDriver

DeviceDriverDeviceDriver

DeviceDriverDeviceDriver

응용프로그램

응용프로그램

응용프로그램

응용프로그램

응용프로그램

응용프로그램

메시지 큐메시지 큐

입력 장치 출력 장치

Windows OS

사용자 입력 입력용 Device Driver( 키보드 , 마우스 , 조이스틱 )

메시지 큐 Windows 운영체제 응용 프로그램 출력용 Device Driver( 모니터 , 프린터 , 디스크 ) 출력

Page 6: MFC 의 메시지 처리

Univ of Incheon, 고급프로그래밍6

메시지 개요 (3/7)

메시지 종류 윈도우 메시지 (Windows Message)

“WM_” 으로 시작하는 메시지 (WM_COMMAND 제외 ) 매개 변수를 가지고 있어 어떻게 처리할 것인지 결정

윈도우 관리메시지 , 초기화 메시지 , 입력메시지 명령 경로 배정없이 해당 윈도우에 직접 전달

컨트롤 통지 메시지 (Control Notification Message) Button, Combo Box 와 같은 제어객체나 자식윈도우에서 부모 윈도우로

보내는 메시지

명령 메시지 (Command Message) 메뉴 , 툴바 , 액셀레이터 키와 같은 사용자 인터페이스 객체로부터 발생되는

WM_COMMAND 메시지 도큐먼트 , 도큐먼트 템플릿 , 뷰 , 다른 Application 객체에 의해 발생 가능

사용자 정의 메시지 SendMessage() 와 PostMessage() 를 사용하여 메지시 전달

Page 7: MFC 의 메시지 처리

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()

Page 8: MFC 의 메시지 처리

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)

Page 9: MFC 의 메시지 처리

Univ of Incheon, 고급프로그래밍9

메시지 개요 (6/7)

만일 OnCommand 라는 메시지 핸들러에서 모든 메시지를 처리를 하면 할 일이 너무 많아짐

일반적인 윈도우 메시지 처리는 CWnd 클래스를 상속받은 클래스들에서 처리

( CWnd 클래스 상위 클래스는 윈도우 메시지 처리부분이 없음 )

WM_COMMAND 메시지는 CCmdTarget 클래스에 구현 CCmdTarget 클래스 하위 클래스는 모두 WM_COMMAND

메시지 구현 가능

사용자가 메뉴 항목을 선택하여 프로그램에 명령을 내리면 WM_COMMAND 메시지가 모든 AFX 클래스에 전달

Page 10: MFC 의 메시지 처리

Univ of Incheon, 고급프로그래밍10

메시지 개요 (7/7)

WM_COMMAND 메시지 전달순서

CView파생 클래스

CDocument파생 클래스

CFrameWnd파생 클래스

CWinApp파생 클래스

파생 클래스 설명

CDocument 프로그램의 데이터를 처리하는 기능

CView 데이터를 화면에 표시하는 기능

CWinApp 프로그램의 시작과 종료에 관련 된 커맨드

CFrameWnd 프레임 윈도우의 제어에 관계된 커멘드 처리

Page 11: MFC 의 메시지 처리

Univ of Incheon, 고급프로그래밍11

메시지 맵이란 윈도우 메시지를 받아야 할 클래스가 가지는 정적 구조체 배열

이 정적 구조체 배열은 처리할 메시지와 메시지에 대응하는 멤버함수에 대한 포인터를 가짐

MFC 는 메시지 맵의 코드 자동화를 위해 매크로를 사용

DECLARE_MESSAGE_MAP

BEGIN_MESSAGE_MAP, END_MESSAGE_MAP

ON_WM_LBUTTONDOWN()

Message Map 처리 기본개념 (1/5)

Page 12: MFC 의 메시지 처리

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() 이 호출됨

Page 13: MFC 의 메시지 처리

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)

Page 14: MFC 의 메시지 처리

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 함수 오버라이딩

Page 15: MFC 의 메시지 처리

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)

Page 16: MFC 의 메시지 처리

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()

Page 17: MFC 의 메시지 처리

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

핸들러함수 선언

핸들러함수 선언

Page 18: MFC 의 메시지 처리

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

Page 19: MFC 의 메시지 처리

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

Page 20: MFC 의 메시지 처리

Univ of Incheon, 고급프로그래밍20

메시지 매크로의 확장 (1/8)

DECLARE_MESSAGE_MAP()

AFXWIN.H

Page 21: MFC 의 메시지 처리

Univ of Incheon, 고급프로그래밍21

메시지 매크로의 확장 (2/8)

AFX_MSGMAP_ENTRY 메시지 맵 항목은 AFX_MSGMAP_ENTRY 로 정의 메시지 식별번호 , 통지코드 , 개체식별 번호 등이

포함된 구조체

// 윈도우 메시지 ID

// 통지코드

// 개체 식별 번호

// 개체범위의 마지막 식별 번호

// 메시지 핸들러 유형

// 메시지 핸들러

Page 22: MFC 의 메시지 처리

Univ of Incheon, 고급프로그래밍22

메시지 매크로의 확장 (3/8)

AFX_MSGMAP 메시지 처리를 위해 메시지 맵에 등록되어있는 메시지 핸들러 호출 매시지 맵은 메시지 맵 항목들로 이루어진 배열

함수포인터 하나 Or 베이스 메시지맵 포인터 AND 메시지맵 엔트리 포인터

Page 23: MFC 의 메시지 처리

Univ of Incheon, 고급프로그래밍23

메시지 매크로의 확장 (4/8)

BEGIN_MESSAGE_MAP

기초 클래스메시지 맵이

정의된 클래스

GetMessageMap 을 구현 , messageMap 초기화하며

messageEntries[] 에 메시지 맵 항목을 넣을 수 있게 준비

배열 열기

Page 24: MFC 의 메시지 처리

Univ of Incheon, 고급프로그래밍24

메시지 매크로의 확장 (5/8)Message Map entries

메시지 맵 매크로 형식은 메시지에 따라 다르다Ex) WM_LBUTTONDOWN을 처리할 때 다음과 같은 매크로 필요

ON_WM_LBUTTONDOWN( )

ON_WM_LBUTTONDOWN 은 WM_LBUTTONDOWN메시지 발생시 OnLButtonDown 이 호출되어야 함

유저가 임의로 바꿀 수 없음

`

Page 25: MFC 의 메시지 처리

Univ of Incheon, 고급프로그래밍25

메시지 매크로의 확장 (6/8)

END_MESSAGE_MAP

`

배열 닫기

윈도우 Message ID메시지 handler

messageEntries 의 마지막임을 표시하는 메시지 맵 항목 추가 ,

메시지 맵 배열 종료

Page 26: MFC 의 메시지 처리

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 }};

Page 27: MFC 의 메시지 처리

Univ of Incheon, 고급프로그래밍27

MESSAGE_MAP 의 특징 _messageEntries[] 배열의 크기를 한정하지 않고 있음

몇 개의 메시지가 추가될지 모름

여러 개 구조체 변수들 관련 AFX_MSGMAP

AFX_MSGMAP_ENTRY

매크로 정의이기 때문에 컴파일 1 차 패스에서 변환 각 클래스별로 메시지맵 관리

메시지 매크로의 확장 (8/8)

Page 28: MFC 의 메시지 처리

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

Page 29: MFC 의 메시지 처리

Univ of Incheon, 고급프로그래밍29

사용자 정의 메시지 (2/8)

메시지가 발생했을때 수행되는 함수를 헤더부에 설정

해당 메시지에 대한 핸들러 함수의 원형을 헤더부에 선언프로젝트명 View.h

< 프로젝트명 View.h>afx_msg void 핸들러함수명 (WPARAM wParam, LPARAM lParam);

wParam 과 lParam 인수는 처리중인 메시지에 따라 달리짐

Page 30: MFC 의 메시지 처리

Univ of Incheon, 고급프로그래밍30

사용자 정의 메시지 (3/8) ON_MESSAGE 매크로를 이용하여 정의한 메시지명과 함수명을

결합하여 선언

메시지 맵에 ON_MESSAGE() 라는 메시지 매크로를 추가

< 메시지 매크로 >ON_MESSAGE( 메시지명 , 함수명 )

프로젝트명 View.cpp

Page 31: MFC 의 메시지 처리

Univ of Incheon, 고급프로그래밍31

사용자 정의 메시지 (4/8)

선언한 함수를 소스부에 만들고 해당 메시지가 수행되었을때의 함수를 만듬

다음과 같이 소스부에 핸들러 함수 구현

< 소스부 >void 클래스명 :: 함수명 (WPARAM wParam, LPARAM lParam){

// 소스코딩}

UsrMsgTestView.cpp

Page 32: MFC 의 메시지 처리

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);

Page 33: MFC 의 메시지 처리

Univ of Incheon, 고급프로그래밍33

사용자 정의 메시지 (6/8) 사용자 정의 메시지의 예 ( 프로젝트명 :

UsrMsgTest) UsrMsgTestView.cpp

UsrMsgTestView.h

Message ID 를 등록후 사용자 정의 메시지에 대한 핸들러 함수의 원형을 헤더에 선언

Page 34: MFC 의 메시지 처리

Univ of Incheon, 고급프로그래밍34

사용자 정의 메시지 (7/8)

메시지 매크로를 메시지 맵 블럭내에 추가 한후 핸들러 함수 구현

UsrMsgTestView.cpp

UsrMsgTestView.cpp

Page 35: MFC 의 메시지 처리

Univ of Incheon, 고급프로그래밍35

사용자 정의 메시지 (8/8)

마우스 왼쪽버튼클릭

프로그램 실행 결과UsrMsgTestView.cpp

Page 36: MFC 의 메시지 처리

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)

Page 37: MFC 의 메시지 처리

Univ of Incheon, 고급프로그래밍37

메시지 처리 방식의 종류 (2/2)

하드웨어 장치

Windows O/S 응용 프로그램

메시지 루프

Window procedure

시스템 큐입력 메시지

입력 제외메시지

응용 큐

Page 38: MFC 의 메시지 처리

Univ of Incheon, 고급프로그래밍38

메시지 처리 흐름 (1/11)

Message Loop 메시지 큐를 경유하는 메시지들은 Message Loop

를 통해 윈도우 프로시져에 전달 메시지 루프는 CWinThread::Run 에 의해 실행 CWinThread::Run 은 WM_QUIT 가 발생할

때까지 반복적으로 메시지를 가져와 분배 CWnd::SendMessage

메시지 큐를 거치지 않고 메시지 발생 CWnd::PostMessage

메시지 큐에 메시지를 넣음

Page 39: MFC 의 메시지 처리

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)

Page 40: MFC 의 메시지 처리

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() 를 호출함으로써 유저에게 입력 메시지를 가로챌 수 있는 기회 제공

Page 41: MFC 의 메시지 처리

Univ of Incheon, 고급프로그래밍41

Window Procedure

메시지 처리 흐름 (4/11)

모든 메시지는 윈도우 프로시저에 의해 처리 CWnd::WindowProc() 은 CWnd::OnWndMsg() 를

호출하여 메시지 맵에 등록된 메시지 핸들러 호출 처리되지 않는 메시지는 CWnd::DefWindowProc() 을 호

출 , default 방식으로 메시지 처리

`

Page 42: MFC 의 메시지 처리

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

Page 43: MFC 의 메시지 처리

Univ of Incheon, 고급프로그래밍43

메시지 처리 흐름 (6/11)

Wincore.cpp

// WM_COMMAND 계열 처리

// WM_NOTIFY 계열 처리

// WM_ACTIVATE 처리

// WM_SETCURSOR 처리

CWnd::OnWndMsg

Page 44: MFC 의 메시지 처리

Univ of Incheon, 고급프로그래밍44

// 캐쉬내에서 찾았다면 ( 메시지 처리를 캐쉬를 이용해서 찾는다 )

// message map entry 에 등록된 메시지 핸들러가 없으면 FALSE 반환

메시지 처리 흐름 (7/11)

GetMessageMap() 함수 유저클래스에서 사용한 BEGIN_MESSAGE_MAP 매크로가 확장시 재정의된 가상함수 이 함수는 CChildView::messageMap 을 리턴 CChildView::messageMap안에는 CChildView::_messageEntries 의

주소가 포함 결국 가장 하위레벨 클래스의 메시지 맵부터 검사

Page 45: MFC 의 메시지 처리

Univ of Incheon, 고급프로그래밍45

// 정해진 메시지인지 사용자 정의 메시지 핸들러 인지 판단

//캐쉬가 정해져 있지 않으면 선형검색

메시지 핸들러 검색함수Messge id 를 가지고 CChildView::_messageEntries 를검색해서 메시지 맵 항목 리턴

만약 WM_LBUTTONDOWN 메세지면{WM_LBUTTONDOWN, 0, 0, 0, afxSig_vwp, &OnLButtonDown} 을리턴

메시지 처리 흐름 (8/11)

Page 46: MFC 의 메시지 처리

Univ of Incheon, 고급프로그래밍46

// CWnd::OnWndMsg 에서는 메시지 맵 항목의 6 번째 멤버 변수인 pfn 을 호출

// case 가 많이 있음

// 각각 핸들러의 시그니처에 맞는 함수의 형태를 호출

메시지 처리 흐름 (9/11)

// 핸들러 함수 실행

Page 47: MFC 의 메시지 처리

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

Page 48: MFC 의 메시지 처리

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)