按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
#define CALLBACK __stdcall // 一种函数调用习惯
可以在AFXWIN 。H 中发现af x_msg 的意义:
#define afx_msg // intentional placeholder
// 故意安排的一个空位置。也许以后版本会用到。
MFC 程序的来龙去脉 (causal relations)
让我们从第1章的C/SDK 观念出发,看看MFC 程序如何运作。
357
…………………………………………………………Page 420……………………………………………………………
第篇 湷觥 FC 程式設計
第一件事情就是找出MFC 程序的进入点。MFC 程序也是Windows 程序,所以它应该
也有一个WinMain,但是我们在Hello 程序看不到它的踪影。是的,但先别急,在程序
进入点之前,更有一个(而且仅有一个)全域对象(本例名为theApp ),这是所谓的
application object ,当操作系统将程序加载并激活,这个全域对象获得配置,其构造式会
先执行,比WinMain 更早。所以以时间顺序来说,我们先看看这个application object 。
我只借用两个类别:CWinApp 和 CFrameWnd
你已经看过了图6…2,作为一个最最粗浅的MFC 程序,Hello 是如此单纯,只有一个视
窗。回想第一章Generic 程序的写法,其主体在于WinMain 和WndProc,而这两个部份
其实都有相当程度的不变性。好极了,MFC 就把有着相当固定行为之WinMain 内部动作
包装在CWinApp 中,把有着相当固定行为之WndProc 内部动作包装在CFrameWnd 中。
也就是说:
■ CWinApp 代表程序本体
■ CFrameWnd 代表一个主框窗口(Frame Window )
但虽然我说,WinMain 内部动作和WndProc 内部动作都有着相当程度的固定行为,它
们毕竟需要面对不同应用程序而有某种变化。所以,你必须以这两个类别为基础,衍生
自己的类别,并改写其中一部份成员函数。
class CMyWinApp : public CWinApp
{
。。。
};
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 成