MFC程序的生死因果

本文详细解析了MFC程序的启动过程,包括全局对象Application Object的创建与配置,以及WinMain函数背后的实现机制。通过深入探讨CWinApp和CFrameWnd类的作用,帮助读者理解MFC框架如何替代传统的WinMain和WndProc。
 
MFC程序的来龙去脉(causal relations)
 MFC的程序如何运行,第一件事情就是找出MFC程序的进入点.MFC程序也是Windows程序.所以它应该也有一个WinMain.但在程序中好象看不到..
 在程序进入点之前,还有一个(而且仅有一个)全局对象,这就是所谓的application object,当操作系统将程序加载并激活时,这个全局对象获得配置,其构造函数会先执行,比WinMain更早.所以先看application object.
 
CWinAPP和CFrameWnd
 Windows程序中WinMain和WndProc这两个部分其实都有相当程度的不变性.MFC就把有着相当固定行为的WinMain内部操作封装在CWinApp中,把着相当固定行为的WinProc内部操作封装在CFrameWnd中.即
#CWinApp代表程序本体
#CFrameWnd代表一个主框窗口(Frame Window)
 WinMain内部操作和WinProc内部操作都有着相当程度的固定行为,但它们毕竟需要面对不同应用程序而有某中变化.所以,我们必须以这两个类为基础,派生自己的类,并改写其中一部分成员函数.
 Class CMyWinApp : public CWinApp
 {
   
};
Class CMyFrameWnd : public CFrameWnd
 {
   
};
 
CWinApp—取代WinMain的地位
 CWinApp的派生对象被称为application object, CWinApp本身就代表一个程序本体.一个程序的本体是与程序本身有关而不于窗口有关的数据或动作无关.比如系统传进来的四个WinMain参数,InitApplication和InitInstance,消息循环等等.
下面是CWinApp的声明(MFC 4.x):
Class CWinApp : public CWinThread
{
 //Attributes
   //Startup arg( do not change )
   HINSTANCE m_hInstance;
   HINSTANCE m_hPrevInstance;
   LPSTR m_lpCmdLine;
   Int m_nCmdShow;
   //Running args (can be changed in InitInstance)
LPCTSTR m_pszAppName; //human readable name
LPCTSTR m_pszRegisteryKey; //used for registry entries
Public: //set in constructor to override default
   LPCTSTR m_pszExecName; //executable name (no spaces)
   LPCTSTR m_pszHelpFilePath; //default based on module path
   LPCTSTR m_pszProfileName; // default based on app path
 Public:
   //hooks for youe initialization code
   Virtual BOOL InitApplication();
   //overrides for implementation
   Virtual BOOL InitInstance();
   Virtual int ExitInstance();
   Virtual int Run();
   Virtual BOOL OnIdle(LONG lCount);
  
};
 几乎可以说CWinAPP取代了WinMain在SDK中的地位.这并不是说MFC程序没有WinMain,而是说传统上SDK程序的WinMain所完成的工作现在由CWinApp的三个函数完成:
Virtual BOOL InitApplication();
Virtual BOOL InitInstance();
Virtual int Run();
 WinMain只是扮演驾驭它们的角色.
 CWinApp应该有个成员变量记录主窗口的handle.在MFC2.5中的确有m_pMainWnd这个变量:
Class CWinApp : public CWinThread
{
 //Attributes
   //Startup arg( 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)
LPCTSTR m_pszAppName; //human readable name
LPCTSTR m_pszRegisteryKey; //used for registry entries
Public: //set in constructor to override default
   LPCTSTR m_pszExecName; //executable name (no spaces)
   LPCTSTR m_pszHelpFilePath; //default based on module path
   LPCTSTR m_pszProfileName; // default based on app path
 Public:
   //hooks for youe initialization code
   Virtual BOOL InitApplication();
   //overrides for implementation
   Virtual BOOL InitInstance();
   Virtual int ExitInstance();
   Virtual int Run();
   Virtual BOOL OnIdle(LONG lCount);
  
};
 
 从MFC4.x开始,m_pMainWnd已经被移往CWinThread中了(它是CWnd的父类):
Class CFramwWnd : 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;
  
};
 
CFrameWnd—取代WndProc的地位
 CFrameWnd主要用来掌握一个窗口,几乎说它是用来取代SDK程序中的窗口函数的地位.传统SDK的窗口函数写法是:
Long FAR PASCAL WndProc(HWND hWnd,UINT msg,WORD wParam,LONG lParam)
{
 Switch(msg)
 {
   Case WM_COMMAND:
      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程序有新的做法,声明如下:
Class CMyFrameWnd : public CFrameWnd
{
 Public:
  CMyFrameWnd();
   Afx_msg void OnPaint();
   Afx_msg voif OnAbout();
   DECLARE_MESSAGE_MAP()
};
 
引爆器Application Object
 Application Object,每个MFC应用程序都有一个,而且也只有一个.当执行应用程序时,这个全局对象产生,于是构造函数执行起来.父类CWinApp的构造函数内容如下:
CWinApp:: CWinApp(LPCTSTR lpszAppName)
{
   m_pszAppName = lpszAppName;
   //initialize CWinThread state
   AFX_MODULE_THREAD_STATE * pThreadState = AfxGetMoudleThreadState();
   pThreadState->m_pCurrentWinThread = this;
  m_hThread = ::GetCurrentThread();
   m_nThreadID = ::GetCurrentThreadId();

   //initialize CWinApp state
   AFX_MOUDLE_STATE * pModueState = AfxGetModuleState();
   pModuleState->m_pCurrentWinApp = this;
   //in non-running state until WinMain
   m_hInstance = NULL;
   m_pszHelpFilePath = NULL;
   m_pszProfileName = NULL;
  m_pszRegistryKey = NULL;
   m_pszExeName = NULL;
   m_lpCmdLine = NULL;
   m_pCmdInfo = NULL;
  
}
 CWinApp之中的成员变量将因为Application Object这个全局对象的诞生而获得配置和初值.
 
隐晦不明的WinMain
 Application Object配置完成后,再说WinMain.可是我们并没有写WinMain程序代码,这是因为MFC早已准备好并由链接器直接加到应用程序代码中.
注意:-t是为了支持Unicode而准备的一个宏.
//in APPMODUL.CPP
Extern C int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrrevInstance,
LPTSTR lpCmdLine , int nCmdShow)
{
    //call shared/Exported WinMain
    Return AfxWinMain(hInstance, hPrrevInstance, lpCmdLine, nCmdShow);
}
 
AfxWinMain稍加整理,它的主要功能如下:
Int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine,int nCmdShow )
{
    ASSERT( hPrevInstance == NULL );
    Int nReturnCode = -1;
    CwinApp *pApp = AfxGetApp();
    AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
    pApp->InitApplication();
    pApp->InitInstance();
    nReturnCode = pApp->Run();
    AfxWinTerm();
    Return nReturnCode;
}
其中,AfxGetApp是一个全局函数,定义与AFXWINLINL:
_AFXWIN_INLINE CwinApp * AFXAPI AfxGetApp()
{ return afxCurrentWinApp ;}
afxCurrentWinApp又定义与AFXWIN.H:
#define afxCurrentWinApp AfxGetModuleState()->m_pCurrentWinApp
 AfxGetApp其实就是取得CmyWinApp对象指针,所以AfxWinMain中这样的操作:
CwimApp *pApp = AfxGetApp();
pApp->InitApplication();
pApp->InitInstance();
nReturnCode = pApp->Run();
其实就相当与调用:
CMyWinAPP:: InitApplication();
CMyWinAPP:: InitInstance();
CMyWinAPP::Run();
因而导致调用:
CWinAPP:: InitApplication();//因为CMyWinAPP并没有改写InitApplication
CWinAPP:: InitInstance();
CWinAPP::Run();
 

AfxWinInit—AFX内部初始化操作

 AfxWinInit是继CwinApp构造函数之后的第一个操作,它的操作摘要如下:

BOOL AFXAPI AfxWinInit( HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPSTR lpCmdLine, int nCmdShow)

{

         ASSERT(hProvInstance==NULL);

         //set  resource handles

         AFX_HANDLE_STATE *pState = AfxGetModuleState();

         pState->m_hCurrentInstanceHandle = hInstance;

         pState-> m_hCurrentResourceHandle = hInstance;

         //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(!afxContextIsNull)

         AfxInitThread();

Reurn TURE;

}

 

 
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值