深入浅出MFC第2版(PDF格式)-第74部分
按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
。。。
};
class CMyFrameWnd : public CFrameWnd
{
。。。
};
本章对衍生类别的命名规则是:在基础类别名称的前面加上〃My〃。这种规则真正上战场
时不见得适用,大型程序可能会自同一个基础类别衍生出许多自己的类别。不过以教学
目的而言,这种命名方式使我们从字面就知道类别之间的从属关系,颇为理想(根据我
的经验,初学者会被类别的命名搞得头昏脑胀)。
358
…………………………………………………………Page 421……………………………………………………………
第6章 MFC 程式的生死因果
CWinApp -取代 WinMain 的地位
CWinApp 的衍生对象被称为application object ,可以想见,CWinApp 本身就代表一个程
式本体。一个程序的本体是什么?回想第1章的SDK 程序,与程序本身有关而不与视
窗有关的资料或动作有些什么? 系统传进来的四个WinMain 参数算不算?
InitApplication 和InitInstance 算不算?消息循环算不算?都算,是的,以下是MFC 4。x
的CWinApp 声明(节录自AFXWIN。H ):
class CWinApp : public CWinThread
{
// Attributes
// Startup args (do not change)
HINSTANCE m_hInstance;
HINSTANCE m_hPrevInstance;
LPTSTR m_lpCmdLine;
int m_nCmdShow;
// Running args (can be changed in InitInstance)
LPCTSTR m_pszAppName; // human readable name
LPCTSTR m_pszRegistryKey; // used for registry entries
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
public:
// hooks for your initialization code
virtual BOOL InitApplication();
// overrides for implementation
virtual BOOL InitInstance();
virtual int ExitInstance();
virtual int Run();
virtual BOOL OnIdle(LONG lCount);
。。。
};
359
…………………………………………………………Page 422……………………………………………………………
第篇 湷觥 FC 程式設計
几乎可以说CWinApp 用来取代WinMain 在SDK 程序中的地位。这并不是说MFC 程序
没有WinMain (稍后我会解释),而是说传统上SDK 程序的WinMain 所完成的工作现
在由CWinApp 的三个函数完成:
virtual BOOL InitApplication();
virtual BOOL InitInstance();
virtual int Run();
WinMain 只是扮演役使它们的角色。
会不会觉得CWinApp 的成员变量中少了点什么东西?是不是应该有个成员变量记录主
窗口的handle (或是主窗口对应之C++ 对象)?的确,在MFC 2。5 中的确有
m_pMainWnd 这么个成员变量(以下节录自MFC 2。5 的AFXWIN。H ):
class CWinApp : public CCmdTarget
{
// Attributes
// Startup args (do not change)
HINSTANCE m_hInstance;
HINSTANCE m_hPrevInstance;
LPSTR m_lpCmdLine;
int m_nCmdShow;
// Running args (can be changed in InitInstance)
CWnd* m_pMainWnd; // main window (optional)
CWnd* m_pActiveWnd; // active main window (may not be m_pMainWnd)
const char* m_pszAppName; // human readable name
public: // set in constructor to override default
const char* m_pszExeName; // executable name (no spaces)
const char* m_pszHelpFilePath; // default based on module path
const char* m_pszProfileName; // default based on app name
public:
// hooks for your initialization code
virtual BOOL InitApplication();
virtual BOOL InitInstance();
// running and idle processing
virtual int Run();
virtual BOOL OnIdle(LONG lCount);
360
…………………………………………………………Page 423……………………………………………………………
第6章 MFC 程式的生死因果
// exiting
virtual int ExitInstance();
。。。
};
但从MFC 4。x 开始,m_pMainWnd 已经被移往CWinThread 中了(它是CWinApp 的父
类别)。以下内容节录自MFC 4。x 的AFXWIN。H :
class CWinThread : public CCmdTarget
{
// Attributes
CWnd* m_pMainWnd; // main window (usually same AfxGetApp()…》m_pMainWnd)
CWnd* m_pActiveWnd; // active main window (may not be m_pMainWnd)
// only valid while running
HANDLE m_hThread; // this thread's HANDLE
DWORD m_nThreadID; // this thread's ID
int GetThreadPriority();
BOOL SetThreadPriority(int nPriority);
// Operations
DWORD SuspendThread();
DWORD ResumeThread();
// Overridables
// thread initialization
virtual BOOL InitInstance();
// running and idle processing
virtual int Run();
virtual BOOL PreTranslateMessage(MSG* pMsg);
virtual BOOL PumpMessage(); // low level message pump
virtual BOOL OnIdle(LONG lCount); // return TRUE if more idle processing
public:
// valid after construction
AFX_THREADPROC m_pfnThreadProc;
。。。
};
熟悉Win32 的朋友,看到CWinThread 类别之中的SuspendThread 和ResumeThread 成
员函数,可能会发出会心微笑。
361
…………………………………………………………Page 424……………………………………………………………
第篇 湷觥 FC 程式設計
CFrameWnd -取代 WndProc 的地位
CFrameWnd 主要用来掌握一个窗口,几乎你可以说它是用来取代SDK 程序中的窗口函
式的地位。传统的SDK 窗口函数写法是:
long FAR PASCAL WndProc(HWND hWnd; UNIT msg; WORD wParam; LONG lParam)
{
switch(msg) {
case WM_MAND :
switch(wParam) {
case IDM_ABOUT :
OnAbout(hWnd; wParam; lParam);
break;
}
break;
case WM_PAINT :
OnPaint(hWnd; wParam; lParam);
break;
default :
DefWindowProc(hWnd; msg; wParam; lParam);
}
}
MFC 程序有新的作法,我们在Hello 程序中也为CMyFrameWnd 准备了两个消息处理
例程,声明如下:
class CMyFrameWnd : public CFrameWnd
{
public:
CMyFrameWnd();
afx_msg void OnPaint();
afx_msg void OnAbout();
DECLARE_MESSAGE_MAP ()
};
OnPaint 处理什么消息?OnAbout 又是处理什么消息?我想你很容易猜到,前者处理
WM_PAINT ,后者处理WM_MAND 的IDM_ABOUT 。这看起来十分俐落,但让人搞
不懂来龙去脉。程序中是不是应该有「把消息和处理函数关联在一起」的设定动作?是
的,这些设定在HELLO。CPP 才看得到。但让我先着一鞭:DECLARE_MESSAGE_MAP
宏与此有关。
362
…………………………………………………………Page 425……………………………………………………………
第6章 MFC 程式的生死因果
这种写法非常奇特,原因是MFC 内建了一个所谓的Message Map 机制,会把消息自动
送到「与消息对映之特定函数」去;消息与处理函数之间的对映关系由程序员指定。
DECLARE_MESSAGE_MAP 另搭配其它宏,就可以很便利地将消息与其处理函数关联
在一起:
BEGIN_MESSAGE_MAP(CMyFrameWnd; CFrameWnd)
ON_WM_PAINT()
ON_MAND(IDM_ABOUT; OnAbout)
END_MESSAGE_MAP()
稍后我就来探讨这些神秘的宏。
363
…………………………………………………………Page 426……………………………………………………………
第篇 湷觥 FC 程式設計
引爆器-Application object
我们已经看过HELLO。H 声明的两个类别,现在把目光转到HELLO。CPP 身上。这个档
案将两个类别实作出来,并产生一个所谓的application object 。故事就从这里展开。
下面这张图包括右半部的Hello 源代码与左半部的MFC 源代码。从这一节以降,我将
以此图解释MFC 程序的激活、运行、与结束。不同小节的图将标示出当时的程序进行
状况。
HELLO。CPP
1 CMyWinApp theApp; // application object
BOOL CMyWinApp::InitInstance()
WINMAIN。CPP
{
int AFXAPI AfxWinMain (。。。) m_pMainWnd = new CMyFrameWnd();
int AFXAPI AfxWinMain (。。。)
{