正文

生死MFC程序:MFC 封装2006-09-24 21:34:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/embed/18780.html

分享到:

生死MFC程序 (白乔) 关键词  MFC 封装 摘要 正文 MFC将大部分函数都进行了封装,程序员只要改写部分重要的virtual函数即可,这往往使初学者摸不着头脑,连个WinMain函数都看不到,程序从哪开始从哪结束?基本的条理搞不清,永远也不会有提高。下面简单讲下基运行过程. 1,CMyWinApp theApp  程序从这里开始 2,_tWinMain()   在APPMODUL.CPP 它实际上只调用AfxWinMain函数 3,AfxWinMain()   WINAMIN.CPP,去掉一些次要信息,它作的事就是: int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { int nReturnCode = -1; CWinThread* pThread = AfxGetThread(); CWinApp* pApp = AfxGetApp();  ->实际上就是取得CMyWinApp对象指针 AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow) pApp->InitApplication() pThread->InitInstance() pThread->Run(); AfxWinTerm(); return nReturnCode; } 其中: AfxGetApp();   AFXWIN.CPP中 InitApplication()  AFXWIN.CPP中 InitInstance()   AFXWIN.CPP中 实际上AfxWinMainy就是调用: CWinApp::InitApplication 因为我们程序没有改写它 CMyWinApp::InitInstance  我们改写了它且必须改写它,为什么?看源码就能证明一切 BOOL CWinApp::InitInstance() APPCORE.CPP中 { return TRUE; } 看到了吧,它什么也没干,直接return TRUE; CWinApp::Run(); 4:AfxWinInit()   AFX内部初始化操作,APPINIT.CPP中,贴下源码,如下: BOOL AFXAPI AfxWinInit(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { ..,去掉部分 pModuleState->m_hCurrentInstanceHandle = hInstance; pModuleState->m_hCurrentResourceHandle = hInstance; 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(); } if (!afxContextIsDLL)   AfxInitThread(); return TRUE; } 可以看到。它主要进行一些初始化工作.其中: AfxInitThread()  在THRDCORE.CPP中 5:CWinApp::InitApplication() APPCORE.CPP中, 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; } 5:CMyWinApp::InitInstance() 继InitApplication后就是InitInstance调用了。在我们改写的InitStance函数中,将是我们的主窗口的生命,在这里我们会有这样的操作: m_pMainWnd=new CMyFrameWnd();开始我们的主窗口,创建主窗口,MDI程序采取的是LoadFrame,大家可以看CFrameWnd::LoadFrame()(WNDFRM.CPP中),实际还是做了一样的事,大家不防看下源码。 6:CFrameWnd::Create() BOOL CFrameWnd::Create(LPCTSTR lpszClassName, 类名 LPCTSTR lpszWindowName,   窗口名 DWORD dwStyle,    样式 const RECT& rect,   区域,默认:rectDefault CWnd* pParentWnd,   父窗口 LPCTSTR lpszMenuName,   菜单 DWORD dwExStyle,   扩展样式 CCreateContext* pContext) { HMENU hMenu = NULL; if (lpszMenuName != NULL) {   HINSTANCE hInst = AfxFindResourceHandle(lpszMenuName, RT_MENU);   if ((hMenu = ::LoadMenu(hInst, lpszMenuName)) == NULL)   {    TRACE0("Warning: failed to load menu for CFrameWnd.\n");    PostNcDestroy();            // perhaps delete the C++ object    return FALSE;   } } m_strTitle = lpszWindowName;    // save title for later if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,   rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,   pParentWnd->GetSafeHwnd(), hMenu, (LPVOID)pContext)) {   TRACE0("Warning: failed to create CFrameWnd.\n");   if (hMenu != NULL)    DestroyMenu(hMenu);   return FALSE; } return TRUE; } 7:CWnd::CreateEx()  可以看到CFrameWnd::Create,只是调用了CreateEx 函数,CFrameWnd没有改字CreateEx 函数,所以它调用的是CWnd 类的函数. 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;   用过SDK写程序的朋友一定知道这是想做什么 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; 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); ... } 此函数又调用了PreCreateWindow,CreateWindowEx, 8:CFrameWnd:reCreateWindow(), PreCreateWindow是个virtual,由于this 指针的原故,这里是调用CFrameWnd的PreCreateWindow.一般我们的程序都会改写些函数,在此设定窗口的一些样式。 BOOL CFrameWnd:reCreateWindow(CREATESTRUCT& cs)  --->WINFRM.CPP { if (cs.lpszClass == NULL) {   VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));   cs.lpszClass = _afxWndFrameOrView;  // COLOR_WINDOW background } ... } #define AfxDeferRegisterClass(fClass) AfxEndDeferRegisterClass(fClass) AfxEndDeferRegisterClass()  --->WINCORE.CPP,在这个函数中,调用RegisterWithIcon(实际上还是要调用AfxRegisterClass),和AfxRegisterClass,会我们注五个窗口类.在non-Unicode下使用MFC动态链接版和谳试版,五个类为: "AfxWnd42d" "AfxControlBar42d" "AfxMDIFrame42d" "AfxFrameOrView42d" "AfxOleControl42d" 在Uncode中使用静态和调试版,是: "AfxWnd42sud" "AfxControlBar42sud" "AfxMDIFrame42sud" "AfxFrameOrView42sud" "AfxOleControl42sud" 大家可以看到了。PreCreateWindow是在窗口产生前被调用,用来注册窗口类,如果我们指定的窗口类为NULL,则会用系统默认的。可以来看下不同功能的窗口使用的窗口类: BOOL CWnd:reCreateWindow(CREATESTRUCT& cs) -->WINCORE.CPP { if (cs.lpszClass == NULL) {   ...   cs.lpszClass = _afxWnd;  file://使用_afxWnd窗口类 } } BOOL CFrameWnd:reCreateWindow(CREATESTRUCT& cs) -->WINFRM.CPP { if (cs.lpszClass == NULL) {   ...   cs.lpszClass = _afxWndFrameOrView;  // COLOR_WINDOW background } } BOOL CMDIFrameWnd:reCreateWindow(CREATESTRUCT& cs) -->WINMDI.CPP { if (cs.lpszClass == NULL) {   ...   cs.lpszClass = _afxWndMDIFrame;  file://使用_afxWndMDIFrame 窗口类 } return TRUE; } ... 9:CWinApp::Run()  程序到这里,窗口类注册好了。并显示出来了。UpDateWindow函数将会调用,并产生一个WM_PAINTIITH,等待处理。便进入了RUN函数, file://APPCORE.CPP/ int CWinApp::Run() { if (m_pMainWnd == NULL && AfxOleGetUserCtrl()) {   // Not launched /Embedding or /Automation, but has no main window!   TRACE0("Warning: m_pMainWnd is NULL in CWinApp::Run - quitting application.\n");   AfxPostQuitMessage(0); } return CWinThread::Run();  // 调用CWinThread::Run() } file://THRDCORE.CPP/ int CWinThread::Run() { ASSERT_VALID(this); // 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 &&    !:eekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE))   {    // call OnIdle while in bIdle state    if (!OnIdle(lIdleCount++))     bIdle = FALSE; // assume "no idle" state   }   // 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 (:eekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE)); } ASSERT(FALSE);  // not reachable } 如果没有消息,则调用OnIdle(),空闲处理,否则PumpMessage(),看下它做了什么? BOOL CWinThread:umpMessage() { ASSERT_VALID(this); if (!::GetMessage(&m_msgCur, NULL, NULL, NULL)) { #ifdef _DEBUG   if (afxTraceFlags & traceAppMsg)    TRACE0("CWinThread:umpMessage - Received WM_QUIT.\n");   m_nDisablePumpCount++; // application must die    // Note: prevents calling message loop things in 'ExitInstance'    // will never be decremented #endif   return FALSE; } #ifdef _DEBUG if (m_nDisablePumpCount != 0) {   TRACE0("Error: CWinThread:umpMessage called when not permitted.\n");   ASSERT(FALSE); } #endif #ifdef _DEBUG if (afxTraceFlags & traceAppMsg)   _AfxTraceMsg(_T("PumpMessage"), &m_msgCur); #endif // process this message if (m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur)) {   ::TranslateMessage(&m_msgCur);   :ispatchMessage(&m_msgCur); } return TRUE; } 呵,和SDK程序做法一样,GetMessage,TranslateMessage(),DisptchMessage()好了。进入到Run ()这里,程序就活动起来了。它会对一系列的消息进行处理。并在收到WM_CLOSE 消息时退出.默认函数对WM_CLOSE的处理是是调用:estroyWindow(),关因而发出WM_DESTROY消息,默认的的WM_DESTROY处理方式是调用:ostQuitMessage(),因此发出WM_QUIT,Run收到WM_QUIT时,就结束消息循环,调用ExitInstance,最后在AfxWinMain中执行AfxWinTerm结束程序.  

阅读(286) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册