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结束程序.

你可能感兴趣的:(File,null,application,mfc,Parameters,initialization)