VS2010/MFC编程入门二(SDK编程和MFC编程框架比较)

          程序运行都要有入口函数,在之前的C++教程中都是main函数,而Windows应用程序的入口函数是WinMain函数,MFC程序也是从WinMain函数开始的。下面就给出用Windows SDK写的“HelloWorld”程序,与应用程序框架进行对比,这样能更好的了解框架是怎样运行的。Windows SDK开发程序就是不使用MFC类库,直接用Windows API函数进行软件开发。鸡啄米不是要讲解SDK开发,只是为了对比而简单介绍,至于SDK开发可以在大家学完MFC以后选择是否要研究,一般来说有简单了解就可以了。


SDK应用程序
       首先,给出Windows SDK应用程序“HelloWorld”的源码:  
 

#include <windows.h>      
LRESULT CALLBACK myWndProc(HWND hWindow, UINT msg, WPARAM wParam, LPARAM lParam);   
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)      
{      
  	const static TCHAR appName[] = TEXT("Hello world");      
  	WNDCLASSEX myWin;      
  	myWin.cbSize = sizeof(myWin);      
  	myWin.style = CS_HREDRAW | CS_VREDRAW;      
  	myWin.lpfnWndProc = myWndProc;      
  	myWin.cbClsExtra = 0;      
  	myWin.cbWndExtra = 0;      
  	myWin.hInstance = hInstance;      
 	myWin.hIcon = 0;      
  	myWin.hIconSm  = 0;      
  	myWin.hCursor = 0;      
  	myWin.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);      
  	myWin.lpszMenuName = 0;      
  	myWin.lpszClassName = appName;      
  	//Register      
  	if (!RegisterClassEx(&myWin)) return 0;      
  	const HWND hWindow = CreateWindow(      
    			appName,      
    			appName,      
    			WS_OVERLAPPEDWINDOW,      
    			CW_USEDEFAULT,      
    			CW_USEDEFAULT,      
    			CW_USEDEFAULT,      
    			CW_USEDEFAULT,      
    			0,      
    			0,      
    			hInstance,      
    			0);      
  	ShowWindow(hWindow,iCmdShow);      
  	UpdateWindow(hWindow);      
       
    	MSG msg;      
    	while(GetMessage(&msg,0,0,0))      
    	{      
      		TranslateMessage(&msg);      
      		DispatchMessage(&msg);      
    	}      
    	return (int)msg.wParam;         
}      
     
LRESULT CALLBACK myWndProc(HWND hWindow, UINT msg, WPARAM wParam, LPARAM lParam)      
{      
  	if (msg==WM_PAINT)      
  	{      
    		PAINTSTRUCT ps;      
    		const HDC hDC = BeginPaint(hWindow,&ps);      
    		RECT rect;      
    		GetClientRect(hWindow,&rect);      
    		DrawText(hDC,TEXT("HELLO WORLD"),-1,&rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);      
    		EndPaint(hWindow,&ps);      
    		return 0;      
  	}      
  	else if (msg==WM_DESTROY)      
  	{      
    		PostQuitMessage(0);      
    		return 0;      
  	}      
  	return DefWindowProc(hWindow,msg,wParam,lParam);      
}  

上面的程序运行的流程是:进入WinMain函数->初始化WNDCLASSEX,调用RegisterClassEx函数注册窗口类->调用ShowWindow和UpdateWindow函数显示并更新窗口->进入消息循环。关于消息循环再简单说下,Windows应用程序是消息驱动的,系统或用户让应用程序进行某项操作或完成某个任务时会发送消息,进入程序的消息队列,然后消息循环会将消息队列中的消息取出,交予相应的窗口过程处理,此程序的窗口过程函数就是myWndProc函数,窗口过程函数处理完消息就完成了某项操作或任务。本例是要显示“HELLO WORLD”字符串,UpdateWindow函数会发送WM_PAINT消息,但是此消息不经过消息队列而是直接送到窗口过程处理,在窗口过程函数中最终绘制了“HELLO WORLD”字符串。
 

 


MFC应用程序
首先在HelloWorld.cpp中定义全局对象theApp:CHelloWorldApp theApp;。调用CWinApp和CHelloWorldApp的构造函数后,进入WinMain函数(位于appmodul.cpp中)。
 

extern "C" int WINAPI   
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,   
    _In_ LPTSTR lpCmdLine, int nCmdShow)   
#pragma warning(suppress: 4985)   
{   
    // call shared/exported WinMain   
    return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);   
}  



 在TCHAR.h中,有此定义:#define _tWinMain   WinMain,所以这里的_tWinMain就是WinMain函数。它调用了AfxWinMain函数(位于WinMain.cpp中)。

int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nCmdShow)   
{    
       .............略   
       // App global initializations (rare)   
       if (pApp != NULL && !pApp->InitApplication())   
              goto InitFailure;   
  
       if (!pThread->InitInstance())   
       {   
              .........略   
       }   
         // Run函数位于THRDCORE.cpp中,由此函数进入消息循环   
       nReturnCode = pThread->Run();   
  
       ..............略   
  
       return nReturnCode;   
}   

上面InitInstance函数的代码如下:
BOOL CTestApp::InitInstance()        
{       
       .............略       
       CSingleDocTemplate* pDocTemplate;       
       pDocTemplate = new CSingleDocTemplate(       
              IDR_MAINFRAME,       
              RUNTIME_CLASS(CTestDoc),       
              RUNTIME_CLASS(CMainFrame),      // main SDI frame window       
              RUNTIME_CLASS(CTestView));     
       if (!pDocTemplate)   
             return FALSE;     
       AddDocTemplate(pDocTemplate);       
       // Parse command line for standard shell commands, DDE, file open       
      
       CCommandLineInfo cmdInfo;       
       ParseCommandLine(cmdInfo);       
      
       //ProcessShellCommand位于AppUI2.cpp中,注册并创建窗口       
       if (!ProcessShellCommand(cmdInfo))       
             return FALSE;       
      
       m_pMainWnd->ShowWindow(SW_SHOW);       
       m_pMainWnd->UpdateWindow();       
      
       return TRUE;       
}      



         InitInstance中的ProcessShellCommand函数又调用了CMainFrame的LoadFrame函数注册并创建了窗口,执行完ProcessShellCommand函数以后,调用了m_pMainWnd的ShowWindow和UpdateWindow函数显示并更新框架窗口。这些是不是与上面的SDK程序十分类似?
接下来该是消息循环了,上面的AfxWinMain函数中调用了pThread的Run函数(位于THRDCORE.cpp中),在Run中包含了消息循环。Run函数的代码如下:

int CWinThread::Run()       
{       
        .............略       
        // 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));       
       ..............略       
}       
        
BOOL CWinThread::PumpMessage()       
{     
       return AfxInternalPumpMessage();    
}    
  
BOOL AFXAPI AfxInternalPumpMessage()   
{   
       _AFX_THREAD_STATE *pState = AfxGetThreadState();   
      
       if (!::GetMessage(&(pState->m_msgCur), NULL, NULL, NULL))          
       {       
             .............略       
       }       
       ...............略       
       if (pState->m_msgCur.message != WM_KICKIDLE && !AfxPreTranslateMessage(&(pState->m_msgCur)))   
       {   
             ::TranslateMessage(&(pState->m_msgCur));   
             ::DispatchMessage(&(pState->m_msgCur));   
       }     
      
       return TRUE;       
}       


 


 我们看到PumpMessage中通过调用GetMessage、TranslateMessage、DispatchMessage等建立了消息循环并投递消息。
       窗口过程函数AfxWinProc形式如下:

LRESULT CALLBACK AfxWndProc(HWND hWnd,UINT nMsg,WPARAM wParam, LPARAM lParam)   
{   
      ……   
      CWnd*pWnd=CWnd::FromHandlePermanent(hWnd);  
      ReturnAfxCallWndProc(pWnd,hWnd,nMsg,wParam,lParam);   
}  


 
  两者运行过程对比
       到此,通过对比可以发现,MFC应用程序的运行流程与SDK程序是类似的,都是先进行一些初始化过程,再注册并创建窗口,然后显示、更新窗口,最后进入消息循环,消息都由窗口过程函数处理。现在大家是不是觉得有些头绪了?在运行流程上有基本的掌握即可。
       二.MFC应用程序框架主要类之间的关系
       在第二讲中,给大家演示了如何利用应用程序向导生成单文档应用程序框架,可以看到程序的基本框架和必要的代码都自动生成了,上一讲又讲解了文件组成结构,实际上在前面自动生成的框架中比较重要的类包括以下几个:CHelloWorldApp、CMainFrame、CHelloWorldDoc和CHelloWorldView,至于其他的类比如CClassView、CFileView等都是在框架窗口(CMainFrame)上创建的面板等,不是必要的。
 


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值