1. Introduction
Download
Report
Transcript 1. Introduction
MFC Internals
Contents
Chapter 01
MFC 개관
Chapter 02
MFC와 C/SDK
Chapter 03
MFC에서의 Message 처리
Chapter 04
MFC Utility Class
Chapter 05
모든 길은 Cobject로 통한다
Chapter 06
MFC Dialog와 Control Dialog
Chapter 07
MFC의 Document/View Architecture
[1]
비트교육센터
Chapter
01
MFC 개관
Contents
Application Frameworks 정의
MFC의 역사
MFC의 설계 목적
MFC의 구성
MFC code basics
[3]
비트교육센터
Application Frameworks
Framework
– 특정 영역의 작업을 도와 주는 class 집합
Application Framework
– 특정 OS의 application 개발 작업을 도와 주는 class 집합
MFC (Microsoft Foundation Classes)
– Windows용 application 개발 작업을 도와 주는 framework
[4]
비트교육센터
MFC의 역사
1989년
– AFX group 탄생
Application framework technology development group의 약자
– 목적
Windows application개발자를 위한 C++과 object-oriented 개념을 적용시킨
tool의 개발
– First prototype 실패
Too complex and too different from Windows itself
[5]
비트교육센터
MFC의 역사 (cont’d)
1992년
– MFC version 1.0
C/C++ version 7.0과 함께 나옴
60개가 넘는 Windows application 개발을 위한class포함
일반 목적의 여러 class포함
완벽하지 못했음
– 개발자로부터 많은 불평을 받음
[6]
비트교육센터
MFC의 역사 (cont’d)
1993년
– MFC version 2.0
Visual C++ version 1.0과 Windows NT와 함께 나옴
100개가 넘는 class포함
새로 포함된 내용
– 새로운 application architecture
– 새로운 high-level abstractions
[7]
비트교육센터
MFC의 역사 (cont’d)
1993년 말
– MFC version 2.5
Visual C++ version 1.5와 함께 나옴
OLE2.0과 ODBC 지원이 추가됨
1994년
– MFC version 3.0
Thread에 대한 기능이 보강됨
[8]
비트교육센터
MFC의 역사 (cont’d)
1995년
– MFC version 3.1
추가된 기능
– Simple Messaging Application Programming Interface(MAPI)
– WinSock
– MFC version 4.0
Visual C++ version 4.0과 함께 나옴
개발환경의 발전, 재사용성의 향상
[9]
비트교육센터
MFC의 역사 (cont’d)
1997년
– MFC version 4.2
Visual C++ version 5.0과 함께 나옴
Internet 등을 위한 기능 추가
1998년
– MFC version 6.0
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
[10]
비트교육센터
MFC의 역사(cont’d)
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
1.0
Microsoft C/C++ version 7.0
[11]
비트교육센터
MFC 설계 목적
AFX 그룹의 설계 목적
–
–
–
–
–
Real-World Application
Simplifying the Windows API
Using the existing knowledge of Windows
Foundation for large-scale applications
Small and fast framework
[12]
비트교육센터
MFC의 구성
MFC class 의 분류
–
–
–
–
–
General-purpose classes
Windows API classes
Application framework classes
High-level abstractions
Operating System Extension
[13]
비트교육센터
MFC의 구성(cont’d)
General-purpose Class
– 프로그램의 일반적 용도를 위한 class
(1) CObject class
MFC의 최상위 class
run-time type information,
serialization,
diagnostic function,
support for dynamic creation
4가지 중요한 기능 제공
CArchive, CDumpContext, CRuntimeClass 등과 연계되어 작용
[14]
비트교육센터
MFC의 구성(cont’d)
(2) Exception-handling class
memory, I/O error 발생 시 처리
CException : base class
CArchiveException, CFileException
CMemoryException, CResourceException
CNotSupportedException, CUserException
COleException, CDBException
[15]
비트교육센터
MFC의 구성(cont’d)
(3) Collection class
Array : CByteArray, CWordArray, CDWordArray, CPtrArray,
CObArray, CStringArray, CUnitArray
Linked list : CObList, CPtrList, CStringList
Map : CMapPtrToWord, CMapPtrToPtr,
CMapStringToOb,
CMapStringToPtr, CMapStringToString, CMapWordToOb,
CMapWordToPtr
[16]
비트교육센터
MFC의 구성(cont’d)
(4) Dynamic string class
CString
concatenation, comparison, assignment 등의 기본 연산 제공
(5) File class
CFile, CStdioFile, CMemFile
추상적으로 disk상의 파일 제어, 실제로는 memory상의 파일 제어
[17]
비트교육센터
MFC의 구성(cont’d)
(6) Time class
CTime, CTimeSpan
(7) 기타
CPoint, CSize, CRect : Windows structure
[18]
비트교육센터
MFC의 구성(cont’d)
Windows API class
(1) Application 관련 class
CCmdTarget : message 처리
CCmdUI : user interface의 update
CWinThread : MFC program의 실행 thread를 의미, 즉 program의 main을 포
함
CWinApp : CWinThread의 파생 class으로서 standard
windows application을 표현
[19]
비트교육센터
MFC의 구성(cont’d)
– Window 관련 class
CWnd : CCmdTarget의 파생 class이므로
message를 handle. 윈도우를 다루는 API 포함.
CFramWnd, CMDIFrameWnd : main frame window로서
message를 받는 첫 윈도우
CDialog, 공통다이어로그박스(CFileDialog, CColorDialog, CFontDialog,
CPrintDialog, CFindReplaceDialog)
CDataExchange : DDX/DDV
[20]
비트교육센터
MFC의 구성(cont’d)
CPropertySheet, CPropertyPage
Controls : CButton, CEdit, …
Cmenu
– GDI 관련 class
CDC, CPaintDC, CWindowDC, CClientDC, CMetaFileDC
CPen, CBrush, CFont, ...
[21]
비트교육센터
MFC의 구성(cont’d)
Application framework class
– Document/View Architecture
CDocTemplate, CSingleDocTemplate, CMultiDocTemplate : document와
view를 연결
CDocument : data를 관리
CView : data를 redering하여 보여 줌
– Context-Sensitive Help
[22]
비트교육센터
MFC의 구성(cont’d)
High-level abstraction
– Enhanced Views
CScrollView, CFormView
CEditView, CListView, CRichEditView, CTreeView
– Splitter Window
CSplitterWnd : dynamic, static
– Control Views
CToolBar, CStatusBar, CDialogBar
[23]
비트교육센터
MFC Code Basics
Class Declaration Subsections
– MFC library 개발 팀의 코딩 규칙
Not based public/protected/private
Private 변수는 거의 사용하지 않는다.
– Header / source file
// Constructors
// Attributes
// Operations
// Overridables
// Implementation
[24]
비트교육센터
Example of Comments
class CStdioFile : public CFile
{
DECLARE_DYNAMIC(CStdioFile)
public:
// Constructors
CStdioFile();
...
// Attributes
FILE* m_pStream; // stdio FILE
...
// Operations
virtual void WriteString(LPCTSTR lpsz);
...
virtual LPTSTR ReadString(LPTSTR lpsz, UINT nMax);
...
// Implementation
public:
...
};
[25]
비트교육센터
MFC Comments
Class Declaration Subsections
– MFC library 개발 팀의 코딩 규칙
– Class header file의 각 항목의 의미
// Constructors(생성자 함수들, 초기화 함수들)
– C++ constructors, any other initialization
– 예) CWnd::Create
– 대개는 public
// Attributes(위의 내용을 setting하거나 얻어옴)
– 대개는 documented public data members
– Member functions(위의 data를 조작하는) : Get / Set 함수들
[26]
비트교육센터
MFC Code Basics (cont’d)
// Operations(값이 변한다>??)
– Documented member functions
– 대개는 public, non-const : side effects
// Overridables
– 상속 받은 class가 override한 functions
– Pure virtual functions
// Implementation(현재 쓰고 있는 개념임)
–
–
–
–
Implementation detail
Undocumented
대개는 protected
주의 : may change in future versions of MFC
[27]
비트교육센터
MFC Code Basics (cont’d)
Variable Naming (common)
Type
Prefix
Example
Comment
char
c
cDirSeparator
BOOL
b
blsSending
int
n
nVariableCnt
UINT
n
nMyUnsigned
WORD
w
wListID
LONG
l
lAxisRatio
DWORD
dw
dwPackedmessage
* (pointer)
p
pWnd
FAR *
lp
lpWnd
LPSTR
handle
lpsz
h
lpszFileName
hWnd
Z indicates NULL terminated.
callback
lpfn
lpfnHookProc
Pointer to a function
[28]
비트교육센터
MFC Code Basics (cont’d)
Variable Naming (MFC extensions)
Class
Prefix
Example
CRect
rect
rectScroll
CPoint
pt
ptMouseClick
CSize
sz
szRectangle
CString
str
strFind
CWnd
Wnd
WndControl
CWnd*
pWnd
pWndDialog
[29]
비트교육센터
MFC Code Basics (cont’d)
Symbol Naming
Type
Prefix
Example
Range
Shared by multiple resources
IDR_
IDR_MAINFRAME
1-0x6FFF
Dialog resource
IDD_
IDD_ABOUT
1-0x6FFF
Dialog resource help context ID
(for context-sensitive help)
HIDD_
HIDD_HELP_ABOUT
0x2001-0x26FF
Bitmap resource
IDB_
IDB_SMILEY
1-0x6FFF
Cursor resource
Icon resource
IDC_
IDC_HAND
1-0x6FFF
[30]
비트교육센터
MFC Code Basics (cont’d)
Symbol Naming
Type
Prefix
Example
Range
Menu or toolbar command
ID_
ID_CIRCLE_TOOL
0x8000-0xDFFF
Command help context
HID_
HID_CIRCLE_TOOL
0x1800-0x1DFF
Message box prompt
IDP_
IDP_FATALERROR
8-0xDFFF
Message box help context
HIDP_
HIDP_FATALERROR
0x3008-0x3DFF
Control in dialog template
IDC_
IDC_COMBO1
8-0xDFFF
String resource
IDS_
IDS_ERROR12
1-0x7FFF
[31]
비트교육센터
Chapter
02
MFC와 C/CDK
Contents
Introduction
MFC versus C/SDK
Basic Application Components
– CWinApp
– CWnd
– Window handles & Window objects
Find WinMain()
Hidden Cool Stuff
– Registering Window Classes
– MFC’s Windows Hooks
– MFC’s Message Pump
MFC’s GDI Support
[33]
비트교육센터
Introduction
MFC
– 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
WinMain, window class 등록, 메시지 루프, …
[34]
비트교육센터
Issue
MFC가 어떻게 Windows application을 만드는가
– The application itself(응용프로그램 그 자체)
- main thread
– Windows
– Message handling(위의 두가지를 연결해줌)
– The Graphics Device Interface (GDI)
[35]
비트교육센터
MFC vs. C/SDK
Motivation
– 모든 Windows application은 다음 2개의 component를 포함한다.
main application itself
message를 핸들하는 하나 이상의 window
– C/SDK 개발 환경
copy & paste
Time-consuming & inefficient
– C++/MFC 개발 환경
OOP 활용 : inheritance & encaptulation
필요한 부분만 변경
[36]
비트교육센터
Boilerplate Code
왜 필요한가?
– Windows is event-driven OS
Imposes a grate deal of overhead
– Windows OS
H/W 와 응용 프로그램을 연결하는 위치
Application에게 발생하는 이벤트를 알림
이벤트를 다루기 위해 상당한 양의 코드가 항상 필요
[37]
비트교육센터
메시지 처리를 위한 작업들
Set up a message handler and register it
–
RegiserClass() : 윈도우 프로시져 등록
Windows가 application의 instance들을 추적
application은 Windows에게 메시지를 요청(ask)하고, 처리(dispatch)한다.
application이 종료될 때까지 위 작업을 반복한다.
[38]
비트교육센터
Application의 준비
WinMain() 함수
–
–
프로그램의 시작점
Windows 로부터 프로그램을 실행하는데 필요한 정보를 얻어 오는 통로
현재 instance의 handle, 직전에 실행된 instance의 handle, command line
argument, window의 모습(최대화, 최소화, …)
적어도 하나의 main window class를 등록
–
User interface를 제공
Message loop를 설정
Some initialization and setup(초기화 작업)
–
Application specific, instance specific
Message handler를 제공
최소한 WM_DESTROY 처리 -> WM_QUIT 생성
[39]
비트교육센터
Application의 기본 요소
Message
Handler
Main 함수
Application specific
Initialization
(Window class 등록)
Instance specific
Initialization
(Main window(UI)생성, 보여줌)
Message loop
[40]
비트교육센터
Source 1 : C/SDK
#include <windows.h>
HANDLE hInst;
/* current instance */
LRESULT CALLBACK MainWndProc(HANDLE hWnd, UINT message, WPARAM wParam, LPARAM
lParam)
{
switch(message) {
case WM_LBUTTONDOWN:
MessageBox(hWnd,“Left mouse button clicked”, NULL, MB_OK);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
/* Passes it on if unprocessed */
return (DefWindowProc(hWnd, message, wParam, lParam));
}
return 0;
}
[41]
비트교육센터
BOOL InitApplication(HANDLE hInstance){
WNDCLASS wc;
wc.style = 0;
/* Class style(s) */
wc.lpfnWndProc = MainWndProc;
/* Message handler */
wc.cbClsExtra = 0;
/* No per-class extra data */
wc.cbWndExtra = 0;
/* No per-window extra data */
wc.hInstance = hInstance;
/* Application that owns the class*/
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
/* Name of menu */
wc.lpszClassName = “MinimalWClass”;
/* Name of window class */
return (RegisterClass(&wc));
}
[42]
비트교육센터
BOOL InitInstance(HANDLE hInstance, int nCmdShow) {
HWND hWnd;
hInst = hInstance;
hWnd = CreateWindow(
“MinimalWClass”,
“Minimal”,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
/* Main window handle */
// needed for loading resources //
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
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. */
[43]
비트교육센터
if (!hWnd)
return (FALSE);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return (TRUE);
}
[44]
비트교육센터
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow) {
MSG msg;
/* message */
if (!hPrevInstance) {
/* First instance? */
if (!InitApplication(hInstance)) /* Shared stuff */
return (FALSE);
/* cannot initialize */
}
if (!InitInstance(hInstance, nCmdShow))
return (FALSE);
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return(msg.wParam);/*Returns the value from PostQuitMessage*/
}
[45]
비트교육센터
Source 2 : MFC
#include <afxwin.h>
// MFC 주요 클래스 선언
class CGenericApp : public CWinApp {
public:
virtual BOOL InitInstance();
};
class CGenericWindow : public CFrameWnd {
public:
CGenericWindow() {
Create(NULL, “Generic”);
}
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
DECLARE_MESSAGE_MAP()
};
[46]
비트교육센터
BEGIN_MESSAGE_MAP(CGenericWindow, CFrameWnd)
ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()
void CGenericWindow::OnLButtonDown(UINT nFlags, CPoint point) {
MessageBox(“Left mouse button pressed…”, NULL, MB_OK);
}
BOOL CGenericApp::InitInstance() {
m_pMainWnd = new CGenericWindow();
m_pMainWnd->ShowWindow(m_nCmdShow);
m_pMainWnd->UpdateWindow();
return TRUE;
}
CGenericApp GenericApp;
[47]
비트교육센터
C/SDK와 MFC의 비교
WinMain() Function
– C/SDK : 존재
– MFC : where? ( part of application framework )
Window class 등록
– C/SDK : 존재
– MFC : where?
Message loop
– C/SDK : 존재
– MFC : where?
Additional functions : idle processing, PreTranslateMessage()
[48]
비트교육센터
C/SDK와 MFC의 비교 (cont’d)
Instance initialization
– C/SDK : 존재
– MFC : 존재, 그러나 언제 실행?
Message handling
– C/SDK : 존재
– MFC : 존재, 그러나 어떻게 command-routing, message-dispatch?
Member functions + Message map
AfxWndProc() : 공통 window procedure
항상 시작점이다.
[49]
비트교육센터
Basic MFC Application Components
Windows application의 두 가지 components
– Message pump
– Window procedure
MFC에서의 구현 방법
– CWinApp
Application을 나타내는 class
application-specific : 초기화, window 생성, 메시지 루프
– CWnd
Window를 나타내는 class
window-specific : 메시지 핸들링
[50]
비트교육센터
CWinApp (“AfxWin.h”)
CWinApp : public CWinThread
{
public:
// Constructor
CWinApp(LPCTSTR lpszAppName = NULL);
// app name defaults to EXE name
// Attributes
// Startup args (do not change)
HINSTANCE
m_hInstance;
HINSTANCE
m_hPrevInstance; // not used
LPTSTR
m_lpCmdLine;
int
m_nCmdShow;
// Running args (can be changed in InitInstance)
LPCTSTR m_pszAppName; // human readable name
// (from constructor or AFX_IDS_APP_TITLE)
[51]
비트교육센터
public: // set in constructor to override default
LPCTSTR m_pszExeName;
// executable name (no spaces)
LPCTSTR m_pszHelpFilePath; // default based on module path
LPCTSTR m_pszProfileName; // default based on app name
// Overridables
// hooks for your initialization code
virtual BOOL InitApplication();
void SetCurrentHandles();
// overrides for implementation
virtual BOOL InitInstance();
virtual int ExitInstance(); // return app exit code
virtual int Run();
virtual BOOL OnIdle(LONG lCount);
// return TRUE if more idle processing
virtual LRESULT ProcessWndProcException
(CException* e, const MSG* pMsg);
[52]
비트교육센터
public:
virtual ~CWinApp();
protected:
//{{AFX_MSG(CWinApp)
afx_msg void OnAppExit();
afx_msg void OnUpdateRecentFileMenu(CCmdUI* pCmdUI);
afx_msg BOOL OnOpenRecentFile(UINT nID);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
[53]
비트교육센터
CWinApp
AFXWIN.h
멤버 변수와 멤버 함수
– WinMain()에 전달된 command line parameter 를 관리할 변수
m_hInstance : the current instance handle
m_hPrevInstance : the previous instance handle
m_lpCmdLine : the command line parameters
m_nCmdShow : the show window flag
[54]
비트교육센터
CWinApp (cont’d)
– m_pszAppName : application name
– 관련 pointer
m_pszExeName : executable file name
m_pszHelpFilePath : the path to help file
m_pszProfileName : application profiles name
– 프로그램 실행 시 주어진 command line parameter 유지
CCommandLineInfo class 이용 (AFXWIN.H)
[55]
비트교육센터
CWinApp (cont’d)
–
–
–
–
InitInstance() : instance-specific 초기화
ExitInstance() : instance 종료 시 처리
Run() : message pump 수행
OnIdle() : Message queue가 비었을 때, Run 함수에 의해 호출
[56]
비트교육센터
CWnd
AFXWIN.H
2가지 기능 수행
– Wrapping the regular Windows API
예: Create(), ShowWindow(), …
– Higher-level MFC-related functionality
예: default message handling
[57]
비트교육센터
CWnd ( 기능 1 )
Wrapping the Windows API
– m_hWnd : regular API-level window handle 을 나타내기 위한 멤버변수
– window handle을 인자로 갖는 거의 모든 API를 멤버 함수로 가진다.
예)
API
HWND hWnd;
ShowWindow(hWnd,SW_SHOWNORMAL);
MFC
CWnd * pWnd;
pWnd->ShowWindow(SW_SHOWNORMAL);
– AFXWIN2.INL : API 의 호출
_AFXWIN_INLINE BOOL CWnd::ShowWindow(int nCmdShow)
{ ASSERT(::IsWindow(m_hWnd));
return ::ShowWindow(m_hWnd, nCmdShow); }
[58]
비트교육센터
CWnd ( 기능 2 )
Higher-level MFC-related functionality
– CObject -> CCmdTarget -> CWnd
– CObject derivation
Dynamic run-time information
Serialization
– CCmdTarget derivation
MFC’s message-routing scheme
– Default message handling 제공
[59]
비트교육센터
예 : default message handling
_AFXWIN_INLINE void CWnd::OnActivate(UINT, CWnd*, BOOL)
{ Default(); }
LRESULT CWnd::Default()
{
// call DefWindowProc with the last message
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
return DefWindowProc(pThreadState->m_lastSentMsg.message,
pThreadState->m_lastSentMsg.wParam,
pThreadState->m_lastSentMsg.lParam);
}
[60]
비트교육센터
Turning Window Handles into Window Objects
High
Level
Application
MFC object
CHandleMap class
Low
Level
Windows OS
Window handle
[61]
비트교육센터
계층적 관계
High level : MFC object
– application 입장에서는 MFC object를 이용
Low level : Window handle
– Windows OS는 handle을 이용
MFC는 어떤 handle에 어떤 object가 연결되어 있는지를 알아야 함
CHandleMap class를 이용하여 구현
[62]
비트교육센터
CHandleMap
AFXSTAT_.H
Mapping window handle to MFC object
– Handle이 주어지면 해당 object를 찾음
– Windows OS가 callback 함수를 호출할 때, window handle을 parameter로 호
출
– 그러나, MFC는 해당 CWnd- 파생 클래스 객체를 가지고 작업
[63]
비트교육센터
CHandleMap (cont’d)
멤버변수
– CMapPtrToPtr m_permanantMap
Permanent map
명시적으로 객체가 생성될 때 정보가 추가됨(CWnd’s::Create())
객체가 종료될 때 정보가 제거됨 (CWnd’s::OnNcDestroy())
cf) WM_NCCREAT -> WM_CREAT -> … -> WM_DESTROY ->
WM_NCDESTROY
– CMapPtrToPtr m_temporaryMap
Temporary map
임시로 생성해야 할때(ex: CWnd::GetActiveWindow())
-> 현재 활성화 되어 있는 오브젝트를 찾을때 사용
실제로는 CWnd::HandleMap 에서 필요할 때 생성
OnIdle()에서 삭제 => DeleteTempMap() 호출
[64]
비트교육센터
CHandleMap (cont’d)
멤버함수
– CWnd::FromHandle(HWND hWnd)
주어진 window handle에 mapping되는 object의 pointer를 얻을 때 사용
hWnd를 wrap하고 있는 CWnd pointer return
만약 없으면 hWnd를 wrap하는 temporary CWnd return
획득하면 역으로 object를 통해 hWnd의 접근이 용이
( CWnd::m_hWnd 멤버 변수 )
[65]
비트교육센터
Temporary map 예
“AFXWIN2.INL”
_AFXWIN_INLINE CWnd* PASCAL CWnd::GetActiveWindow()
{ return CWnd::FromHandle(::GetActiveWindow()); }
“Wincore.cpp”
CWnd* PASCAL CWnd::FromHandle(HWND hWnd)
{
CHandleMap* pMap = afxMapHWND(TRUE);
CWnd* pWnd = (CWnd*)pMap->FromHandle(hWnd);
return pWnd;
}
[66]
비트교육센터
Temporary map 예 (cont’d)
“Winhand.cpp”
CObject* CHandleMap::FromHandle(HANDLE h)
{
if (h == NULL)
return NULL;
CObject* pObject = LookupPermanent(h);
if (pObject != NULL)
return pObject; // return permanent one
else if ((pObject = LookupTemporary(h)) != NULL)
{
HANDLE* ph = (HANDLE*)((BYTE*)pObject + m_nOffset);
ph[0] = h;
if (m_nHandles == 2)
{
ph[1] = h;
}
return pObject; // return current temporary one
}
[67]
비트교육센터
Temporary map 예 (cont’d)
CObject* pTemp = NULL;
TRY {
pTemp = m_pClass->CreateObject();
m_temporaryMap.SetAt((LPVOID)h, pTemp);
}
CATCH_ALL(e) {
AfxSetNewHandler(pnhOldHandler);
AfxEnableMemoryTracking(bEnable);
THROW_LAST();
}
END_CATCH_ALL
AfxSetNewHandler(pnhOldHandler);
AfxEnableMemoryTracking(bEnable);
HANDLE* ph = (HANDLE*)((BYTE*)pTemp + m_nOffset);
ph[0] = h;
if (m_nHandles == 2) ph[1] = h;
return pTemp;
}
[68]
비트교육센터
Other Mapping
AFX_MODULE_THREAD_STATE
– m_pmapHWND
window handles CWnd objects
– m_pmapHMENU
menu handles CMenu objects
– m_pmapHDC
device context handles CDC objects
– m_pmapHGDIOBJ
GDI object handles CGDIObjects
– m_pmapHIMAGELIST
image list handles CImageList objects
[69]
비트교육센터
Attaching & Detaching
Window handles과 CWnd-derived objects를 연관시켜주는 함수
– CWnd::Attach()
주어진 window handle을 CWnd::m_hWnd에 대입
MFC’s permanent map에 정보 추가
– CWnd::Detach()
CWnd::m_hWnd를 NULL로 만듬
MFC’s permanent map에서 정보 제거
[70]
비트교육센터
CWnd::Attach
BOOL CWnd::Attach(HWND hWndNew)
{
ASSERT(m_hWnd == NULL);
// only attach once, detach on destroy
ASSERT(FromHandlePermanent(hWndNew) == NULL);
// must not already be in permanent map
if (hWndNew == NULL)
return FALSE;
CHandleMap* pMap = afxMapHWND(TRUE);
ASSERT(pMap != NULL);
pMap->SetPermanent(m_hWnd = hWndNew, this);
AttachControlSite(pMap);
return TRUE;
}
[71]
비트교육센터
CWnd::Detach
HWND CWnd::Detach()
{
HWND hWnd = m_hWnd;
if (hWnd != NULL)
{
CHandleMap* pMap = afxMapHWND();
// don't create if not exist
if (pMap != NULL)
pMap->RemoveHandle(m_hWnd);
m_hWnd = NULL;
}
m_pCtrlSite = NULL;
return hWnd;
}
[72]
비트교육센터
주의
Multiple threads
– Permanent(영구) , temporary map(임시) 모두 thread 단위로 저장
– 전달할 경우 object 대신 HANDLE 을 보내는 것이 바람직
Thread 2
Thread 1
Window create
Window create
접근 불가
[73]
비트교육센터
Find WinMain()
APPCORE.CPP
– CWinApp 생성자 호출
APPMODULE.CPP (여기에 정의)
– _tWinMain()
extern "C" int WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
// call shared/exported WinMain
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
[74]
비트교육센터
Find WinMain() (cont’d)
WINMAIN.CPP
– AfxWinMain()
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR
lpCmdLine, int nCmdShow)
{
int nReturnCode = -1;
CWinThread* pThread = AfxGetThread();
CWinApp* pApp = AfxGetApp();
// AFX internal initialization
if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
goto InitFailure;
// App global initializations (rare)
if (pApp != NULL && !pApp->InitApplication())
goto InitFailure;
[75]
비트교육센터
Find WinMain() (cont’d)
// Perform specific initializations
if (!pThread->InitInstance())
{
if (pThread->m_pMainWnd != NULL)
{
pThread->m_pMainWnd->DestroyWindow();
}
nReturnCode = pThread->ExitInstance();
goto InitFailure;
}
nReturnCode = pThread->Run();
AfxWinTerm();
return nReturnCode;
}
[76]
비트교육센터
Find WinMain() (cont’d)
APPINIT.CPP
– AfxWinInit()
BOOL AFXAPI AfxWinInit(HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
// handle critical errors and avoid Windows message boxes
SetErrorMode(SetErrorMode(0) |
SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
// set resource handles
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
pModuleState->m_hCurrentInstanceHandle = hInstance;
pModuleState->m_hCurrentResourceHandle = hInstance;
[77]
비트교육센터
Find WinMain() (cont’d)
// fill in the initial state for the application
CWinApp* pApp = AfxGetApp();
if (pApp != NULL)
{
// Windows specific initialization (not done if no CWinApp)
pApp->m_hInstance = hInstance;
pApp->m_hPrevInstance = hPrevInstance;
pApp->m_lpCmdLine = lpCmdLine;
pApp->m_nCmdShow = nCmdShow;
pApp->SetCurrentHandles();
}
// initialize thread specific data (for main thread)
if (!afxContextIsDLL) AfxInitThread();
return TRUE;
}
[78]
비트교육센터
Find WinMain() (cont’d)
InitApplication()
– application-specific, but do nothing
InitInstance()
– instance-specific, virtual
Run()
[79]
비트교육센터
CWinApp 생성자
CWinApp::CWinApp(LPCTSTR lpszAppName)
{
if (lpszAppName != NULL) m_pszAppName = _tcsdup(lpszAppName);
else m_pszAppName = NULL;
// initialize CWinThread state
AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();
AFX_MODULE_THREAD_STATE* pThreadState =
pModuleState->m_thread;
pThreadState->m_pCurrentWinThread = this;
m_hThread = ::GetCurrentThread();
m_nThreadID = ::GetCurrentThreadId();
// initialize CWinApp state
ASSERT(afxCurrentWinApp == NULL); // only one CWinApp object please
pModuleState->m_pCurrentWinApp = this;
ASSERT(AfxGetApp() == this);
[80]
비트교육센터
CWinApp 생성자 (cont’d)
// in non-running state until WinMain
m_hInstance = NULL;
m_pszHelpFilePath = NULL;
m_pszProfileName = NULL;
m_pszRegistryKey = NULL;
m_pszExeName = NULL;
m_pRecentFileList = NULL;
m_pDocManager = NULL;
m_atomApp = m_atomSystemTopic = NULL;
m_lpCmdLine = NULL;
m_pCmdInfo = NULL;
// other initialization
m_bHelpMode = FALSE;
m_nSafetyPoolSize = 512;
// default size
}
[81]
비트교육센터
InitApplication()
BOOL CWinApp::InitApplication()
{
if (CDocManager::pStaticDocManager != NULL)
{
if (m_pDocManager == NULL)
m_pDocManager = CDocManager::pStaticDocManager;
CDocManager::pStaticDocManager = NULL;
}
if (m_pDocManager != NULL)
m_pDocManager->AddDocTemplate(NULL);
else
CDocManager::bStaticInit = FALSE;
return TRUE;
}
[82]
비트교육센터
InitInstance()
BOOL CWinApp::InitInstance()
{
return TRUE;
}
[83]
비트교육센터
Run()
int CWinThread::Run()
{
// for tracking the idle time state
BOOL bIdle = TRUE;
LONG lIdleCount = 0;
// acquire and dispatch messages until a WM_QUIT message
for (;;) {
// phase1: check to see if we can do idle work
while (bIdle && !::PeekMessage(
&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE))
{
// call OnIdle while in bIdle state
if (!OnIdle(lIdleCount++))
bIdle = FALSE; // assume "no idle" state
}
[84]
비트교육센터
Run (cont’d)
// phase2: pump messages while available
do {
// pump message, but quit on WM_QUIT
if (!PumpMessage())
return ExitInstance();
// reset "no idle" state after pumping "normal" message
if (IsIdleMessage(&m_msgCur))
{
bIdle = TRUE;
lIdleCount = 0;
}
} while (::PeekMessage
(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));
}
ASSERT(FALSE); // not reachable
}
[85]
비트교육센터
MFC state information
프로그램 종료까지 유지되는 정보
AFX_MODULE_STATE class
– AFXSTAT_.H
– 보유하는 정보
Main window handles
Resource, module handles
Memory allocation tracking
ODBC support, OLE support, exception handling
[86]
비트교육센터
Hidden Cool Stuff
2 issues
– window class의 등록
– Windows hook와 MFC window의 연결
[87]
비트교육센터
Registering Window Classes
Windows application
– OS 에 적어도 하나 이상의 window class를 등록해야만 한다.
window class
– window의 기본적인 성질 정의
appearance ( via some flag )
behavior ( via a callback function )
[88]
비트교육센터
Registering Window Classes (cont’d)
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
[89]
비트교육센터
Registering Window Classes (cont’d)
WNDCLASSes and MFC
Style
Style of window
LpfnWndProc
CbClsExtra
CbWndExtra
HInstance
HIcon
HCursor
HbrBackground
LpszMenuName
LpszClassName
window proc, must be AfxWndProc
not used ( 0 )
not used ( 0 )
automatically filled with AfxGetInstanceHandle
icon for frame window
cursor for when mouse is over window
background color
not used ( NULL )
class name
[90]
비트교육센터
Registering Window Classes (cont’d)
AfxWnd
–
–
–
–
–
Used for all child windows (CWnd::Create)
Class style : CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW
No icon
Arrow cursor
No background color
AfxFrameOrView
–
–
–
–
–
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
[91]
비트교육센터
Registering Window Classes (cont’d)
AfxMDIFrame
–
–
–
–
–
Used for MDI frame window (CMDIFrameWnd::Create)
Class style : CS_DBLCLKS
Icon Icon AFX_IDI_STD_MDIFRAME
Arrow cursor
No background color
AfxControlBar
–
–
–
–
–
Used for standard control bar implementation
Class style : 0
No icon
Arrow cursor
Gray background color (COLOR_BTNFACE)
[92]
비트교육센터
Registering Window Classes (cont’d)
AfxDeferRegisterClass()
– AFXIMPL.H
AfxEndDeferRegisterClass()
– WINCORE.CPP
#define AfxDeferRegisterClass(fClass) AfxEndDeferRegisterClass(fClass)
BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister);
[93]
비트교육센터
Class 등록 예
“WINCORE.CPP”
BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
LPCTSTR lpszWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight,
HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)
{
// allow modification of several common create parameters
CREATESTRUCT cs;
cs.dwExStyle = dwExStyle;
cs.lpszClass = lpszClassName;
cs.lpszName = lpszWindowName;
cs.style = dwStyle;
cs.x = x;
cs.y = y;
cs.cx = nWidth;
cs.cy = nHeight;
cs.hwndParent = hWndParent;
cs.hMenu = nIDorHMenu;
cs.hInstance = AfxGetInstanceHandle();
cs.lpCreateParams = lpParam;
[94]
비트교육센터
Class 등록 예 (cont’d)
if (!PreCreateWindow(cs))
{
PostNcDestroy();
return FALSE;
}
AfxHookWindowCreate(this);
HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass,
cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,
cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);
if (hWnd == NULL)
GetLastError());
if (!AfxUnhookWindowCreate()) PostNcDestroy();
if (hWnd == NULL)
return FALSE;
ASSERT(hWnd == m_hWnd);
// should have been set in send msg hook
return TRUE;
}
[95]
비트교육센터
Class 등록 예 (cont’d)
BOOL CWnd::PreCreateWindow(CREATESTRUCT& cs)
{
if (cs.lpszClass == NULL)
{
// make sure the default window class is registered
VERIFY(AfxDeferRegisterClass(AFX_WND_REG));
// no WNDCLASS provided - use child window default
ASSERT(cs.style & WS_CHILD);
cs.lpszClass = _afxWnd;
}
return TRUE;
}
[96]
비트교육센터
MFC’s Message Pump
CWinApp::Run()
– 이 함수가 실행되면서 실제 메시지 펌프가 동작하게 됨
– 이는 CWinApp가 CWinThread로 부터 상속받기 때문에 가능한 것임
– Thread 종류
Worker thread : 일반적으로 말하는 thread
Interface thread : Message pump
[97]
비트교육센터
MFC’s GDI 지원
GDI (Graphical Device Interface)
– Windows OS상의 풍부한 그리기 작업
– 장치 독립적 지원 : GDI + Device driver
DC (Device Context)
–
–
–
–
GDI의 핵심적인 개념
GDI 함수의 parameter
스크린, 프린터 등을 표시
구조체 : 객체 + 속성 + 모드
[98]
비트교육센터
Device Contexts
CDC
– CPaintDC
painting 작업이 발생할 때
BeginPaint() ~ EndPaint()
– CWindowDC
전체 스크린을 표시 (client area+frame)
GetWindowDC() ~ ReleaseDC()
– CClientDC
Client area를 표시
GetClientDC() ~ ReleaseDC()
– CMetaFileDC
메타파일에 대한 그리기 작업
생성자 ~ Create() ~ DeleteMetaFile()
[99]
비트교육센터
Graphic Objects
CGdiObject : Base class
–
–
–
–
–
–
CPen
CBrush
CFont
CBitmap
CPalette
CRgn
Win32 API의 함수들을 wrapping
[100]
비트교육센터
예제
CMyWnd::OnPaint() {
CPaintDC
CPen*
CPen
paintDC(this);
pOldPen;
bluePen(PS_SOLID, 25, RGB(0, 0, 255));
pOldPen = paintDC.SelectObject(&bluePen);
paintDC.MoveTo(1, 1);
paintDC.LineTo(100, 100);
paintDC.SelectObject(pOldPen);
}
[101]
비트교육센터
Chapter
03
MFC에서의 Message 처리
Contents
Introduction
Window messages
Message mapping
MFC가 message map을 이용하는 방법
Message loop의 hooking
[103]
비트교육센터
Introduction
Message handling
– C/SDK
Switch/case 문을 통해 구현
– MFC
Switch/case 문은 없다
Callback function은 어떻게 정의되는가
[104]
비트교육센터
Basic Components
MFC의 message handling 구조
– CCmdTarget class
– Message maps
MFC message maps에 대한 의문
–
–
–
–
어떻게 switch/case문을 대체하는가
어떤 data structure로 정의되는가
어떻게 message map이 작동하는가
어떻게 message가 연결되는가
[105]
비트교육센터
Window Messages
3개 부분으로 구성됨
– Unsigned integer
실제 메시지를 나타냄
– WPARAM
Word(32bits)크기의 parameter
메시지에 따른 특정 데이타
– LPARAM
4byte parameter
메시지에 따른 특정 데이타
[106]
비트교육센터
Window Messages (cont’d)
핸들링 해야 할 메시지의 분류
– Windows message
WM_ 로 시작하는 메시지들 (WM_COMMAND 제외)
일반적으로 window, view 등에서 핸들링
– Control notification
WM_COMMAND 중 notify, WM_NOTIFY
Control, 자식 window 가 부모 윈도우에게 전달하는 메시지들
예) EN_CHANGED 를 포함한 WM_COMMAND 메시지
– Command message
메뉴, 툴바, 엑셀레이터 등으로 인한 메시지
[107]
비트교육센터
Window Messages (cont’d)
핸들링 클래스
– Windows message, control notification
CWnd 로부터 파생된 클래스들 : HWND 를 포함
– Command message
다양한 종류 : CCmdTarget 로부터 파생된 클래스들
예) open 명령 핸들링 : application
[108]
비트교육센터
UI Objects and Command IDs
[109]
비트교육센터
Message Handling in C/SDK
Windows program의 정수
While (GetMessage(&msg, NULL, NULL, NULL))
{
// Translates virtual key codes
TranslateMessage(&msg);
// Dispatches message to window
DispatchMessage(&msg);
}
// Returns the value from PostQuitMessage
Return (msg.wParam);
[110]
비트교육센터
Message Handling in C/SDK (cont’d)
WNDCLASS ws;
…
ws.lpfnWndProc = WndProc;
…
RegisterClass(ws);
LRESULT WndProc(HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_CREATE:
…
break;
case WM_COMMAND:
switch (wParam) {
case IDM_ABOUT:
…
}
}
[111]
비트교육센터
Message Handling in MFC
방법 1
– Polymorphism : 가상 멤버 함수 이용
– 심각한 메모리 낭비
방법 2
– Message maps
– MFC 의 특징
[112]
비트교육센터
Message Mapping Internals
두 부분으로 구성
– CCmdTarget
Window message나 command를 받기 위해 반드시 상속받아야 하는 class
– Message map
Window message와 이를 처리하는 class member function을 연관시켜주는
mechanism
[113]
비트교육센터
CCmdTarget Class
메시지의 처리
– CCmdTarget의 파생 클래스
– 예
CWnd class
CDocument
CWinApp
[114]
비트교육센터
Message Map
Data structures
– AFX_MSGMAP_ENTRY(AFXWIN.H)
Message map table의 한 element(entry)
Message에 대한 정보와 message handler에 대한 정보를 저장
struct AFX_MSGMAP_ENTRY
{
UINT nMessage; // windows message
UINT nCode;
// control code or WM_NOTIFY code
UINT nID;
// control ID (or 0 for windows messages)
UINT nLastID; // used for entries specifying a range of control id's
UINT nSig;
// signature type (action) or pointer to message #
AFX_PMSG pfn; // routine to call (or special value)
};
[115]
비트교육센터
Message Map(contd.)
– AFX_MSGMAP(AFXWIN.H)
실제 message map
struct AFX_MSGMAP
{
#ifdef _AFXDLL
const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();
#else
const AFX_MSGMAP* pBaseMap;
#endif
const AFX_MSGMAP_ENTRY* lpEntries;
};
[116]
비트교육센터
Message Map Macros
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 _messageEntries[]; \
protected: \
static AFX_DATA const AFX_MSGMAP messageMap; \
virtual const AFX_MSGMAP* GetMessageMap() const; \
[117]
비트교육센터
Message Map Macros (cont’d)
#define BEGIN_MESSAGE_MAP(theClass, baseClass) \
const AFX_MSGMAP* theClass::GetMessageMap() const \
{ return &theClass::messageMap; } \
AFX_COMDAT AFX_DATADEF const AFX_MSGMAP theClass::messageMap = \
{ &baseClass::messageMap, &theClass::_messageEntries[0] }; \
AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[] = \
{\
#define END_MESSAGE_MAP() \
{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } \
}; \
[118]
비트교육센터
Massage Map 예
class CTestView : public Cview
{
protected:
//{{AFX_MSG(CTestView)
afx_msg void OnLButtonDblClk(UINT nFlags, Cpoint point);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
class CTestView : public Cview
{
protected:
afx_msg void OnLButtonDblClk(UINT nFlags, Cpoint point);
private:
static const AFX_MSGMAP_ENTRY _messageEntries[];
protected:
static const AFX_MSGMAP messageMap;
virtual const AFX_MSGMAP* GetMessageMap() const;
};
비트교육센터
[119]
Massage Map 예 (cont’d)
BEGIN_MESSAGE_MAP(CTestVIew, Cview)
//{{AFX_MSG_MAP(CTestView)
ON_COMMAND(ID_STRING_CENTER, OnStringCenter)
ON_WM_LBUTTONDBLCLK()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
const AFX_MSGMAP* CTestView::GetMessageMap() const
{ return &CTestView::messageMap; }
AFX_COMDAT AFX_DATADEF const AFX_MSGMAP CTestView::messageMap =
{ &CView::messageMap, &CTestView::_messageEntries[0] };
const AFX_MSGMAP_ENTRY CTestVIew::_messageEntries[] =
{ (BEGIN_MESSAGE_MAP)
ON_COMMAND(ID_STRING_CENTER, OnStringCenter)
ON_WM_LBUTTONDBLCLK()
{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } (END_MESSAGE_MAP)
};
[120]
비트교육센터
Message Map Entry Macro
AFXMSG_.H
#define ON_COMMAND(id, memberFxn) \
{ WM_COMMAND, CN_COMMAND, (WORD)id, (WORD)id, \
AfxSig_vv, (AFX_PMSG)&memberFxn },
userdefine(사용자가 지정한 이름 사용)
#define ON_WM_LBUTTONDBLCLK() \
{ WM_LBUTTONDBLCLK, 0, 0, 0, AfxSig_vwp, \
(AFX_PMSG)(AFX_PMSGW) \
(void (AFX_MSG_CALL CWnd::*) \
(UINT, CPoint))&OnLButtonDblClk },
만들어져 있는 이름을 사용
[121]
비트교육센터
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
[122]
비트교육센터
User-define Message
// inside the class declaration
afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);
For example:
#define WM_MYMESSAGE (WM_USER + 100)
BEGIN_MESSAGE_MAP(CMyWnd, CMyParentWndClass)
ON_MESSAGE(WM_MYMESSAGE, OnMyMessage)
END_MESSAGE_MAP()
CWnd* pWnd = ...;
pWnd->SendMessage(WM_MYMESSAGE);
[123]
비트교육센터
Handlers for Message-Map Ranges
종류
– ON_COMMAND_RANGE
– ON_UPDATE_COMMAND
– ON_CONTROL_RANGE
Message-Map Entry
– ID 는 연속적이어야 한다.
BEGIN_MESSAGE_MAP(CMyApp, CWinApp)
ON_COMMAND_RANGE(ID_MYCMD_ONE, ID_MYCMD_TEN,
OnDoSomething)
ON_CONTROL_RANGE(BN_CLICKED, IDC_BUTTON1,
IDC_BUTTON10, OnButtonClicked)
END_MESSAGE_MAP( )
[124]
비트교육센터
Handlers for Message-Map Ranges
Handlers
...
void CMyDialog::OnButtonClicked( UINT nID )
{
int nButton = nID - IDC_BUTTON1;
ASSERT( nButton >= 0 && nButton < 10 );
// ...
}
[125]
비트교육센터
MFC의 Message Map이용
MFC-based program
– 두 종류의 메시지를 처리
regular window messages
– WM_MOUSEMOVE, …
commands
– WM_COMMAND
– Message-mapping architecture의 이해
두 종류 메시지를 각각 추적
[126]
비트교육센터
How to be wired
16-bit version
– AfxWndProc()
Message handling procedure로 등록된 함수
32-bit version
– DefWindowProc() 가 message handler로 등록
– Message hook방법을 써서 결국에는 AfxWndProc()가 message를 처리하게 함
– Hooking function
_AfxCbtFilterHook(), _AfxStandardSubclass()
– 3D Control을 지원하기 위함
[127]
비트교육센터
How to be wired (cont’d)
“WinCore.cpp”
BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister)
{
// mask off all classes that are already registered
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
fToRegister &= ~pModuleState->m_fRegisteredClasses;
if (fToRegister == 0) return TRUE;
LONG fRegisteredClasses = 0;
// common initialization
WNDCLASS wndcls;
memset(&wndcls, 0, sizeof(WNDCLASS)); // start with NULL defaults
wndcls.lpfnWndProc = DefWindowProc;
wndcls.hInstance = AfxGetInstanceHandle();
wndcls.hCursor = afxData.hcurArrow;
[128]
비트교육센터
How to be wired (cont’d)
BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
LPCTSTR lpszWindowName, DWORD dwStyle,
int x, int y, int nWidth, int nHeight,
HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)
{
…
AfxHookWindowCreate(this);
}
void AFXAPI AfxHookWindowCreate(CWnd* pWnd)
{
if (pThreadState->m_hHookOldCbtFilter == NULL) {
pThreadState->m_hHookOldCbtFilter = ::SetWindowsHookEx(WH_CBT,
_AfxCbtFilterHook, NULL, ::GetCurrentThreadId());
if (pThreadState->m_hHookOldCbtFilter == NULL)
AfxThrowMemoryException();
}
pThreadState->m_pWndInit = pWnd;
}
[129]
비트교육센터
How to be wired (cont’d)
LRESULT CALLBACK
_AfxCbtFilterHook(int code, WPARAM wParam, LPARAM lParam)
{
…
// subclass the window if not already wired to AfxWndProc
if (!bAfxWndProc)
{
// subclass the window with standard AfxWndProc
oldWndProc = (WNDPROC)SetWindowLong(hWnd,
GWL_WNDPROC, (DWORD)afxWndProc);
ASSERT(oldWndProc != NULL);
*pOldWndProc = oldWndProc;
}
…
}
[130]
비트교육센터
Message Handling
AfxWndProc()(WINCORE.CPP)
– WM_QUERYAFXWNDPROC
MFC’s message map을 사용하는 MFC window인지를 확인할 수 있는
message
– 다른 message에 대해서는 AfxCallWndProc() 함수를 호출
LRESULT CALLBACK
AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
if (nMsg == WM_QUERYAFXWNDPROC)
return 1;
CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam);
}
[131]
비트교육센터
Message Handling (cont’d)
AfxCallWndProc()(WINCORE.CPP)
– Thread state 구조체에 message의 정보를 저장
– WM_INITDIALOG처리
Auto-center dialog위한 처리를 수행
– Window object의 window procedure호출
CWnd::WindowProc()(WINCORE.CPP)
내부적으로 OnWndMsg()를 호출
OnWndMsg()가 처리하지 못하면 CWnd::DefWindowProc()를 호출
[132]
비트교육센터
Message Handling (cont’d)
LRESULT AFXAPI AfxCallWndProc(CWnd* pWnd, HWND hWnd, UINT nMsg,
WPARAM wParam = 0, LPARAM lParam = 0)
{
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
MSG oldState = pThreadState->m_lastSentMsg; // save for nesting
pThreadState->m_lastSentMsg.hwnd = hWnd;
pThreadState->m_lastSentMsg.message = nMsg;
pThreadState->m_lastSentMsg.wParam = wParam;
pThreadState->m_lastSentMsg.lParam = lParam;
CRect rectOld;
DWORD dwStyle = 0;
if (nMsg == WM_INITDIALOG) _AfxPreInitDialog(pWnd, &rectOld, &dwStyle);
// delegate to object's WindowProc
lResult = pWnd->WindowProc(nMsg, wParam, lParam);
// more special case for WM_INITDIALOG
if (nMsg == WM_INITDIALOG) _AfxPostInitDialog(pWnd, rectOld, dwStyle);
pThreadState->m_lastSentMsg = oldState;
return lResult;
}
[133]
비트교육센터
Message Handling (cont’d)
CWnd::WndowProc()(WINCORE.CPP)
– virtual 이므로 override 가능
– 성능 향상을 위해 message-mapping system을 거치지 않고 처리해야 하는 메
시지에 대한 핸들링 가능
“WinCore.Cpp”
LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
// OnWndMsg does most of the work, except for DefWindowProc call
LRESULT lResult = 0;
if (!OnWndMsg(message, wParam, lParam, &lResult))
lResult = DefWindowProc(message, wParam, lParam);
return lResult;
}
[134]
비트교육센터
Message Handling (cont’d)
CWnd::OnWndMsg()(WINCORE.CPP)
– 특별히 처리하는 message
WM_COMMAND, WM_NOTIFY
WM_ACTIVATE, WM_SETCURSOR
– 기타 다른 message들은 message map을 이용하여 해당 message handler를
호출
[135]
비트교육센터
Message Handling (cont’d)
BOOL CWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam,
LRESULT* pResult)
{
// special case for commands
if (message == WM_COMMAND) {
if (OnCommand(wParam, lParam)) {
lResult = 1;
goto LReturnTrue;
}
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 ) { }
[136]
비트교육센터
Message Handling (cont’d)
const AFX_MSGMAP* pMessageMap; pMessageMap = GetMessageMap();
UINT iHash; iHash = (LOWORD((DWORD)pMessageMap) ^ message) &
(iHashMax-1);
AfxLockGlobals(CRIT_WINMSGCACHE);
AFX_MSG_CACHE* pMsgCache; pMsgCache = &_afxMsgCache[iHash];
const AFX_MSGMAP_ENTRY* lpEntry;
if (message == pMsgCache->nMsg && pMessageMap == pMsgCache>pMessageMap)
{
…
} else {
// not in cache, look for it
pMsgCache->nMsg = message;
pMsgCache->pMessageMap = pMessageMap;
for (/* pMessageMap already init'ed */; pMessageMap != NULL;
pMessageMap = pMessageMap->pBaseMap)
{
AfxFindMessageEntry();
}
[137]
비트교육센터
Message Handling Trace
두가지 종류의 message
– Regular window message
WM_MOUSEMOVE
– Command message
메뉴나 control이 보내는 message
WM_COMMAND
서로 다른 방식으로 처리
– CWnd::OnWndMsg()참고
[138]
비트교육센터
Handling WM_COMMAND
가정
– Main frame의 메뉴 명령 수행
CWnd::OnWndMsg()함수에서
– CWnd::OnCommand()함수 호출
CWnd::OnCommand()
– Virtual function(Framework이 적절한 version의 함수를 호출함)
– CFrameWnd::OnCommand()
On-line help에 관한 것이면 해당 기능 수행
아니면 CWnd::OnCommand()함수 호출
[139]
비트교육센터
Handling WM_COMMAND (cont’d)
“WinFrm.cpp”
BOOL CFrameWnd::OnCommand(WPARAM wParam, LPARAM lParam)
{
HWND hWndCtrl = (HWND)lParam;
UINT nID = LOWORD(wParam);
CFrameWnd* pFrameWnd = GetTopLevelFrame();
ASSERT_VALID(pFrameWnd);
if (pFrameWnd->m_bHelpMode&&hWndCtrl==NULL&&nID!=ID_HELP&&
nID!= ID_DEFAULT_HELP && nID != ID_CONTEXT_HELP) {
// route as help
if (!SendMessage(WM_COMMANDHELP, 0, HID_BASE_COMMAND+nID))
SendMessage(WM_COMMAND, ID_DEFAULT_HELP);
return TRUE;
}
// route as normal command
return CWnd::OnCommand(wParam, lParam);
}
[140]
비트교육센터
Handling WM_COMMAND (cont’d)
“WinCore.Cpp”
BOOL CWnd::OnCommand(WPARAM wParam, LPARAM lParam)
{
if (hWndCtrl == NULL)
else {
if (_afxThreadState->m_hLockoutNotifyWindow == m_hWnd)
return TRUE;
// locked out - ignore control notification
// reflect notification to child window control
if (ReflectLastMsg(hWndCtrl))
return TRUE; // eaten by child
// zero IDs for normal commands are not allowed
if (nID == 0)
return FALSE;
}
return OnCmdMsg(nID, nCode, NULL, NULL);
}
[141]
비트교육센터
Handling WM_COMMAND (cont’d)
CWnd::OnCommand()(WINCORE.CPP)
– LPARAM을 조사
– 만약 control이 보낸 message이면 control에게 다시 message를 reflect한 후
return
– 아니면 CWnd::OnCmdMsg()(virtual function)함수 호출
[142]
비트교육센터
Handling WM_COMMAND (cont’d)
“WinFrm.cpp”
BOOL CFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
CPushRoutingFrame push(this);
// pump through current view FIRST
CView* pView = GetActiveView();
if (pView != NULL && pView->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// then pump through frame
if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// last but not least, pump through app
CWinApp* pApp = AfxGetApp();
if (pApp != NULL && pApp->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
return FALSE;
}
[143]
비트교육센터
Handling WM_COMMAND (cont’d)
“ViewCore.cpp”
BOOL CView::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
// first pump through pane
if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// then pump through document
if (m_pDocument != NULL)
{
// special state for saving view before routing to document
CPushRoutingView push(this);
return m_pDocument->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}
return FALSE;
}
[144]
비트교육센터
Handling WM_COMMAND (cont’d)
“DocCore.cpp”
BOOL CDocument::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
if (CCmdTarget::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// otherwise check template
if (m_pDocTemplate != NULL &&
m_pDocTemplate->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
return FALSE;
}
[145]
비트교육센터
Handling WM_COMMAND (cont’d)
CFrameWnd::OnCmdMsg()(WINFRM.CPP)
– 다음의 순서로 해당 OnCmdMsg()함수를 호출
Active view
Active view’s document
Main frame window
Application
[146]
비트교육센터
Handling WM_COMMAND (cont’d)
만약 active view에 해당 handler가 있다면
– CView::OnCmdMsg()가 호출됨
CView::OnCmdMsg()(VIEWCORE.CPP)
– View에서 처리를 시도한 후 안되면 document에서 처리를 시도
– View에서 처리 시도는 CWnd::OnCmdMsg()함수의 호출로 이루어짐
– 이 때 CWnd는 OnCmdMsg를 override하지 않기 때문에
CCmdTarget::OnCmdMsg를 호출하는 결과가 됨
[147]
비트교육센터
Handling WM_COMMAND (cont’d)
“CmdTarg.cpp”
BOOL CCmdTarget::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
for (pMessageMap = GetMessageMap(); pMessageMap != NULL;
pMessageMap = pMessageMap->pBaseMap) {
lpEntry = AfxFindMessageEntry
(pMessageMap->lpEntries, nMsg, nCode, nID);
if (lpEntry != NULL) {
return _AfxDispatchCmdMsg(this, nID, nCode,
lpEntry->pfn, pExtra, lpEntry->nSig, pHandlerInfo);
}
}
return FALSE; // not handled
}
[148]
비트교육센터
Handling WM_COMMAND (cont’d)
CCmdTarget::OnCmdMsg()(CMDTARG.CPP)
– Message map을 보고 message handler를 찾음
– 찾게 되면 _AfxDispatchCmdMsg()함수를 호출하여 해당 handler를 실행시킴
_AfxDispatchCmdMsg()(CMDTARG.CPP)
– Function signature에 따라 다른 동작을 수행
Regular command
Extended command
Visual Basic control
등등
[149]
비트교육센터
Handling WM_COMMAND (cont’d)
Frame window일 때의 처리과정 정리
–
–
–
–
–
–
–
–
–
–
1. AfxWndProc()
1.1 AfxCallWndProc()
1.2CWnd::WindowProc()
1.2. 1CWnd::OnWndMsg()
CFrameWnd::OnCommand()
CWnd::OnCommand()
CFrameWnd::OnCmdMsg()
CCmdTarget::OnCmdMsg()
_AfxDispatchCmdMsg()
CMainFram::On~()
[150]
비트교육센터
Handling WM_COMMAND (cont’d)
Document일 때의 처리과정 정리
–
–
–
–
–
–
–
–
–
–
–
–
AfxWndProc()
AfxCallWndProc()
CWnd::WindowProc()
CWnd::OnWndMsg()
CFrameWnd::OnCommand()
CWnd::OnCommand()
CFrameWnd::OnCmdMsg()
CView::OnCmdMsg()
Cdocument::OnCmdMsg()
CCmdTarget::OnCmdMsg()
_AfxDispatchCmdMsg()
CMyDoc::On~()
[151]
비트교육센터
Handling WM_COMMAND (cont’d)
View일 때의 처리과정 정리
–
–
–
–
–
–
–
–
–
–
–
AfxWndProc()
AfxCallWndProc()
CWnd::WindowProc()
CWnd::OnWndMsg()
CFrameWnd::OnCommand()
CWnd::OnCommand()
CFrameWnd::OnCmdMsg()
CView::OnCmdMsg()
CCmdTarget::OnCmdMsg()
_AfxDispatchCmdMsg()
CMyView::On~()
[152]
비트교육센터
Handling WM_COMMAND (cont’d)
App일 때의 처리과정 정리
–
–
–
–
–
–
–
–
AfxWndProc()
AfxCallWndProc()
CWnd::WindowProc()
CWnd::OnWndMsg()
CFrameWnd::OnCommand()
CCmdTarget::OnCmdMsg()
_AfxDispatchCmdMsg()
CMyApp::On~()
[153]
비트교육센터
Handling WM_COMMAND (cont’d)
Dialog Box일 때의 처리과정 정리
–
–
–
–
–
–
–
–
AfxWndProc()
AfxCallWndProc()
CWnd::WindowProc()
CWnd::OnWndMsg()
CDialog::OnCmdMsg()
CCmdTarget::OnCmdMsg()
_AfxDispatchCmdMsg()
CAboutDlg::On~()
[154]
비트교육센터
예 – Clear All
Handling 과정 (MDI application)
–
–
–
–
–
Main frame window가 message를 받는다
현재 활성화된 MDI child window가 처리 할 기회를 얻는다
Child window가 먼저 view에게 처리 기회를 준다.
실패하여 view가 연결된 document가 처리를 시도한다
Document가 메시지 핸들러를 찾는 데 성공한다.
[155]
비트교육센터
Handling Regular Window Message
Command message일 때와 처음의 과정은 비슷
–
–
–
–
AfxWndProc()
AfxCallWndProc()
WindowProc()
OnWndMsg()
이 함수 안에서 message handler를 찾기 위해AfxFindMessageEntry()를
호출
[156]
비트교육센터
Handling Regular Window Message (cont’d)
AfxFindMessageEntry()
– 두 버전이 있음.
Assembly language : intel-based machine
C language : otherwise
– Message map에서 해당 핸들러가 있는지 검색
– END_MESSAGE_MAP에 의해 생성된 table의 끝까지 검색
[157]
비트교육센터
Handling Regular Window Message (cont’d)
Command message와의 차이점
– Command message는 handler를 찾기 위해서 여러 장소를 옮겨다님
– Regular message는 OnWndMsg()에서 handler를 찾으면 바로 해당 handler를
호출하고, 아니면 DefWindowProc()를 이용
[158]
비트교육센터
Handling Regular Window Message (cont’d)
예) View에서 WM_SIZE message처리 과정
–
–
–
–
–
AfxWndProc()
AfxCallWndProc()
CWnd::WindowProc()
CWnd::OnWndMsg()
CSdiappView::OnSize()
[159]
비트교육센터
Other Kinds of Messages
지금까지 살펴 본 메시지 종류
– WM_COMMAND
– Window messages(WM_SIZE, WM_MOVE, …)
그 이외의 메시지 종류
– WM_NOTIFY
– WM_ACTIVATE
– WM_SETCURSOR
[160]
비트교육센터
Other Kinds of Messages (cont’d)
WM_NOTIFY
– Control이 보내는 message
– 항상 notify message
– 반면, WM_COMMAND
command이거나 notify message
[161]
비트교육센터
Other Kinds of Messages (cont’d)
CWnd::OnWndMsg()에서
// special case for notifies
if (message == WM_NOTIFY)
{
NMHDR* pNMHDR = (NMHDR*)lParam;
if (pNMHDR->hwndFrom != NULL
&& OnNotify(wParam, lParam, &lResult))
goto LReturnTrue;
return FALSE;
…
}
struct NMHDR {
HWND
hwndFrom;
UINT
idFrom;
UINT
code;
// control that sent notification
// ID of control
// notification code
[162]
비트교육센터
Other Kinds of Messages (cont’d)
“Wincore.cpp”
BOOL CWnd::OnNotify(WPARAM, LPARAM lParam, LRESULT* pResult)
{
NMHDR* pNMHDR = (NMHDR*)lParam;
HWND hWndCtrl = pNMHDR->hwndFrom;
// get the child ID from the window itself
UINT nID = _AfxGetDlgCtrlID(hWndCtrl);
int nCode = pNMHDR->code;
if (_afxThreadState->m_hLockoutNotifyWindow == m_hWnd)
return TRUE;
// locked out - ignore control notification
// reflect notification to child window control
if (ReflectLastMsg(hWndCtrl, pResult)) return TRUE;
// eaten by child
AFX_NOTIFY notify;
notify.pResult = pResult;
notify.pNMHDR = pNMHDR;
return OnCmdMsg(nID, MAKELONG(nCode, WM_NOTIFY), ¬ify, NULL);
}
[163]
비트교육센터
Other Kinds of Messages (cont’d)
BOOL PASCAL CWnd::ReflectLastMsg(HWND hWndChild, LRESULT* pResult)
{
CHandleMap* pMap = afxMapHWND();
CWnd* pWnd = (CWnd*)pMap->LookupPermanent(hWndChild);
if (pWnd == NULL) {
// check if the window is an OLE control
…
return FALSE;
}
return pWnd->SendChildNotifyLastMsg(pResult);
}
[164]
비트교육센터
Other Kinds of Messages (cont’d)
BOOL CWnd::SendChildNotifyLastMsg(LRESULT* pResult)
{
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
return OnChildNotify(pThreadState->m_lastSentMsg.message,
pThreadState->m_lastSentMsg.wParam,
pThreadState->m_lastSentMsg.lParam, pResult);
}
[165]
비트교육센터
Other Kinds of Messages (cont’d)
Message reflection
– OnWndMsg()에서 OnNotify()를 호출
– OnNofity()는 다시 OnChildNotify()를 호출하여 control로 message를 다시 보냄
– 결국에는 control이 parent에 의존하지 않고 자신의 일을 처리하게 함
[166]
비트교육센터
Other Kinds of Messages (cont’d)
– WM_ACTIVATE
OnWndMsg()함수에서 _AfxHandleActivate()를 호출
– WM_SETCURSOR
OnWndMsg()함수에서 _AfxHandleSetCursor()함수 호출
[167]
비트교육센터
Speed Message-map Matching
방법
– 최근에 처리 된 메시지를 캐쉬에 저장
– 같은 메시지를 다시 처리할 가능성이 높음
장점
– Unhandled message 빠르고 효과적으로 처리
[168]
비트교육센터
Message Loop Hooking
Message loop hooking
– Message가 해당 handler에 의해 처리되기 전에 어떠한 작업을 하고 싶을때
– PreTranslateMessage()
CWinApp::PreTranslateMessage()
– CWinApp::Run()함수는 message가 message pump에 의해 처리되기
전에 위 함수를 호출
– TRUE를 return하면 message pump는 해당 message에 관해서는 처리
를 하지 않음
CWnd::PreTranslateMessage()
[169]
비트교육센터
Message Loop Hooking (cont’d)
“THRDCORE.cpp”
int CWinThread::Run()
{
// for tracking the idle time state
BOOL bIdle = TRUE;
LONG lIdleCount = 0;
// acquire and dispatch messages until a WM_QUIT message is received.
for (;;)
{
// phase1: check to see if we can do idle work
while (bIdle &&
!::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE))
{
// call OnIdle while in bIdle state
if (!OnIdle(lIdleCount++))
bIdle = FALSE; // assume "no idle" state
}
[170]
비트교육센터
Message Loop Hooking (cont’d)
// phase2: pump messages while available
do {
// pump message, but quit on WM_QUIT
if (!PumpMessage())
return ExitInstance();
// reset "no idle" state after pumping "normal" message
if (IsIdleMessage(&m_msgCur))
{
bIdle = TRUE;
lIdleCount = 0;
}
} while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));
}
ASSERT(FALSE); // not reachable
}
[171]
비트교육센터
Message Loop Hooking (cont’d)
BOOL CWinThread::PumpMessage()
{
ASSERT_VALID(this);
if (!::GetMessage(&m_msgCur, NULL, NULL, NULL))
{
}
// process this message
if (m_msgCur.message != WM_KICKIDLE
&& !PreTranslateMessage(&m_msgCur))
{
::TranslateMessage(&m_msgCur);
::DispatchMessage(&m_msgCur);
}
return TRUE;
}
[172]
비트교육센터
Message Loop Hooking (cont’d)
BOOL CWinThread::PreTranslateMessage(MSG* pMsg)
{
// if this is a thread-message, short-circuit this function
if (pMsg->hwnd == NULL && DispatchThreadMessageEx(pMsg))
return TRUE;
// walk from target to main window
CWnd* pMainWnd = AfxGetMainWnd();
if (CWnd::WalkPreTranslateTree(pMainWnd->GetSafeHwnd(), pMsg))
return TRUE;
// in case of modeless dialogs, last chance route through main
// window's accelerator table
if (pMainWnd != NULL) {
CWnd* pWnd = CWnd::FromHandle(pMsg->hwnd);
if (pWnd->GetTopLevelParent() != pMainWnd)
return pMainWnd->PreTranslateMessage(pMsg);
}
return FALSE; // no special processing
}
[173]
비트교육센터
Message Loop Hooking (cont’d)
“WinCore.Cpp”
BOOL PASCAL CWnd::WalkPreTranslateTree(HWND hWndStop, MSG* pMsg){
// walk from the target window up to the hWndStop window checking
// if any window wants to translate this message
for (HWND hWnd=pMsg->hwnd; hWnd != NULL;hWnd=::GetParent(hWnd)){
CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
if (pWnd != NULL) {
// target window is a C++ window
if (pWnd->PreTranslateMessage(pMsg))
return TRUE;
}
// got to hWndStop window without interest
if (hWnd == hWndStop)
break;
}
return FALSE;
// no special processing
}
[174]
비트교육센터