MFC消息传递(单文档与对话框)

先针对单文档程序进行分析:

//首先进入_tWinMain函数,函数中调用AfxWinMain();

extern "C" int WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
// call shared/exported WinMain
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}

//下面是AfxWinMain函数的说明:

int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
........

int nReturnCode = -1;
CWinThread* pThread = AfxGetThread();
CWinApp* pApp = AfxGetApp();

// AFX internal initialization

//AFX的内部初始化:
if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
   goto InitFailure;

// App global initializations (rare)

//App全局的初始化:
if (pApp != NULL && !pApp->InitApplication())
   goto InitFailure;

// Perform specific initializations

//进行指定的初始化:
if (!pThread->InitInstance())
{
   if (pThread->m_pMainWnd != NULL)
   {
    TRACE0("Warning: Destroying non-NULL m_pMainWnd/n");
    pThread->m_pMainWnd->DestroyWindow();
   }
   nReturnCode = pThread->ExitInstance();
   goto InitFailure;
}

//进程运行:
nReturnCode = pThread->Run();

InitFailure:
.......

AfxWinTerm();
return nReturnCode;
}

//CWinThread的子类CWinApp的Run函数重写

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();
}

首先调用InitialInstance()

BOOL CSingleDocumentApp::InitInstance()
{
..........

//初始化文档模板,即添加文档类,主框架类,视图类三个动态类

//添加文档模板,多文档程序中需要多个模板。

CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
   IDR_MAINFRAME,
   RUNTIME_CLASS(CSingleDocumentDoc),
   RUNTIME_CLASS(CMainFrame),       // main SDI frame window
   RUNTIME_CLASS(CSingleDocumentView));
AddDocTemplate(pDocTemplate);

//控制台消息处理

// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);

// Dispatch commands specified on the command line
if (!ProcessShellCommand(cmdInfo))
   return FALSE;

//窗口显示

// The one and only window has been initialized, so show and update it.
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();

return TRUE;
}

//这里就进入了比较重要的地方了:

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

//如果是idle状态且没有其他的消息,系统会进行相关的内存释放???
   while (bIdle &&
    !::PeekMessage(&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 (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));
}

ASSERT(FALSE); // not reachable
}

//下面就进入了关键的消息泵函数了,核心啊:

BOOL CWinThread::PumpMessage()
{
ASSERT_VALID(this);

//GetMessage函数会从消息队列中取走消息,与带指定参数PM_NOREMOVE的PeekMessage函数不一样

if (!::GetMessage(&m_msgCur, NULL, NULL, NULL))
{
........

// process this message

if (m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur))

//TranslateMessage用于对键盘的输入的转换

//DispatchMessage用于消息的指派给各个反应单元了
{
   ::TranslateMessage(&m_msgCur);
   ::DispatchMessage(&m_msgCur);
}
return TRUE;
}

对于对话框应该注意到在APP类中的InitInstance中

//不管如何处理,最后都会返回一个FALSE

BOOL CDialogApp::InitInstance()
{
AfxEnableControlContainer();

// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need.

#ifdef _AFXDLL
Enable3dControls();    // Call this when using MFC in a shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif

CDialogDlg dlg;
m_pMainWnd = &dlg;
int nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
   // TODO: Place code here to handle when the dialog is
   // dismissed with OK
}
else if (nResponse == IDCANCEL)
{
   // TODO: Place code here to handle when the dialog is
   // dismissed with Cancel
}

// Since the dialog has been closed, return FALSE so that we exit the
// application, rather than start the application's message pump.
return FALSE;
}

那么在WinMain中调用InitInstace函数之后就会跳过调用pThread->Run(),消息泵进不去了,怎么办?

int CDialog::DoModal()
{
// can be constructed with a resource template or InitModalIndirect
ASSERT(m_lpszTemplateName != NULL || m_hDialogTemplate != NULL ||
   m_lpDialogTemplate != NULL);

// load resource as necessary
LPCDLGTEMPLATE lpDialogTemplate = m_lpDialogTemplate;
HGLOBAL hDialogTemplate = m_hDialogTemplate;
HINSTANCE hInst = AfxGetResourceHandle();
if (m_lpszTemplateName != NULL)
{
   hInst = AfxFindResourceHandle(m_lpszTemplateName, RT_DIALOG);
   HRSRC hResource = ::FindResource(hInst, m_lpszTemplateName, RT_DIALOG);
   hDialogTemplate = LoadResource(hInst, hResource);
}
if (hDialogTemplate != NULL)
   lpDialogTemplate = (LPCDLGTEMPLATE)LockResource(hDialogTemplate);

// return -1 in case of failure to load the dialog template resource
if (lpDialogTemplate == NULL)
   return -1;

// disable parent (before creating dialog)
HWND hWndParent = PreModal();
AfxUnhookWindowCreate();
BOOL bEnableParent = FALSE;
if (hWndParent != NULL && ::IsWindowEnabled(hWndParent))
{
   ::EnableWindow(hWndParent, FALSE);
   bEnableParent = TRUE;
}

TRY
{
   // create modeless dialog
   AfxHookWindowCreate(this);
   if (CreateDlgIndirect(lpDialogTemplate,
       CWnd::FromHandle(hWndParent), hInst))
   {
    if (m_nFlags & WF_CONTINUEMODAL)
    {
     // enter modal loop
     DWORD dwFlags = MLF_SHOWONIDLE;
     if (GetStyle() & DS_NOIDLEMSG)
      dwFlags |= MLF_NOIDLEMSG;
     VERIFY(RunModalLoop(dwFlags) == m_nModalResult);
    }

    // hide the window before enabling the parent, etc.
    if (m_hWnd != NULL)
     SetWindowPos(NULL, 0, 0, 0, 0, SWP_HIDEWINDOW|
      SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
   }
}
CATCH_ALL(e)
{
   DELETE_EXCEPTION(e);
   m_nModalResult = -1;
}
END_CATCH_ALL

if (bEnableParent)
   ::EnableWindow(hWndParent, TRUE);
if (hWndParent != NULL && ::GetActiveWindow() == m_hWnd)
   ::SetActiveWindow(hWndParent);

// destroy modal window
DestroyWindow();
PostModal();

// unlock/free resources as necessary
if (m_lpszTemplateName != NULL || m_hDialogTemplate != NULL)
   UnlockResource(hDialogTemplate);
if (m_lpszTemplateName != NULL)
   FreeResource(hDialogTemplate);

return m_nModalResult;
}

//哇嘎嘎,在这里进行消息的传递的啊

int CWnd::RunModalLoop(DWORD dwFlags)
{
ASSERT(::IsWindow(m_hWnd)); // window must be created
ASSERT(!(m_nFlags & WF_MODALLOOP)); // window must not already be in modal state

// for tracking the idle time state
BOOL bIdle = TRUE;
LONG lIdleCount = 0;
BOOL bShowIdle = (dwFlags & MLF_SHOWONIDLE) && !(GetStyle() & WS_VISIBLE);
HWND hWndParent = ::GetParent(m_hWnd);
m_nFlags |= (WF_MODALLOOP|WF_CONTINUEMODAL);
MSG* pMsg = &AfxGetThread()->m_msgCur;

// acquire and dispatch messages until the modal state is done
for (;;)
{
   ASSERT(ContinueModal());

   // phase1: check to see if we can do idle work
   while (bIdle &&
    !::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE))
   {
    ASSERT(ContinueModal());

    // show the dialog when the message queue goes idle
    if (bShowIdle)
    {
     ShowWindow(SW_SHOWNORMAL);
     UpdateWindow();
     bShowIdle = FALSE;
    }

    // call OnIdle while in bIdle state
    if (!(dwFlags & MLF_NOIDLEMSG) && hWndParent != NULL && lIdleCount == 0)
    {
     // send WM_ENTERIDLE to the parent
     ::SendMessage(hWndParent, WM_ENTERIDLE, MSGF_DIALOGBOX, (LPARAM)m_hWnd);
    }
    if ((dwFlags & MLF_NOKICKIDLE) ||
     !SendMessage(WM_KICKIDLE, MSGF_DIALOGBOX, lIdleCount++))
    {
     // stop idle processing next time
     bIdle = FALSE;
    }
   }

   // phase2: pump messages while available
do
   {
    ASSERT(ContinueModal());

    // pump message, but quit on WM_QUIT
    if (!AfxGetThread()->PumpMessage())
    {
     AfxPostQuitMessage(0);
     return -1;
    }

    // show the window when certain special messages rec'd
    if (bShowIdle &&
     (pMsg->message == 0x118 || pMsg->message == WM_SYSKEYDOWN))
    {
     ShowWindow(SW_SHOWNORMAL);
     UpdateWindow();
     bShowIdle = FALSE;
    }

    if (!ContinueModal())
     goto ExitModal;

    // reset "no idle" state after pumping "normal" message
    if (AfxGetThread()->IsIdleMessage(pMsg))
    {
     bIdle = TRUE;
     lIdleCount = 0;
    }

   } while (::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE));
}

ExitModal:
m_nFlags &= ~(WF_MODALLOOP|WF_CONTINUEMODAL);
return m_nModalResult;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值