windows是怎样实现模式对话框的,我一直感到比较迷惑。
   非模式对话框非常好理解,因为在windows的消息循环并不对窗口进行特殊的对待,只是简单的将消息发给每个窗口的处理函数。而模式对话框却很奇怪,他可以阻止其他窗口对部分消息的响应,却可以处理像WM_PRINT的消息,怎么实现?????????????
   还是他只是独占了用户输入,不允许其他用户取得输入,其他窗口对消息的处理依然是进行中,如果是这样,那又该怎么实现?

解决方案 »

  1.   

    Windows是一个巨大的消息驱动结构,由用户发出消息,系统响应处理。非模态对话框是响应一个消息,系统处理一个消息,处理完毕后返回控制权给Windows。文档/视图框架结构与其类似。模态对话框在对话框创建后,挂起外部的消息,只是响应对话框内部的消息,而外部消息则全部"过滤"掉了,直到系统接收到WM_DESTROY或WM_CLOSE后,系统返回控制权给模态对话框创建前的线程,继续模态对话框创建前的线程将执行下面的代码。
    http://desktop.chinaitlab.com/VC/35730.html
      

  2.   

    Debug一下DoModal就知道了,其实也比较简单.内部加入一个消息循环,把对父窗口的鼠标和键盘消息过滤掉,其它消息照样发给父窗口.
      

  3.   

    http://desktop.chinaitlab.com/VC/35730.html
    这个确实讲的不错.
      

  4.   

    1.
    CDialog::CDialog(UINT nIDTemplate, CWnd* pParentWnd /*=NULL*/)
    {
    AFX_ZERO_INIT_OBJECT(CWnd);m_pParentWnd = pParentWnd;
    m_lpszTemplateName = MAKEINTRESOURCE(nIDTemplate);
    m_nIDHelp = nIDTemplate;
    }注意 pParentWnd 参数默认是 NULL,不是 this
    2.
    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();
    **因此父窗口应该来自 PreModalHWND CDialog::PreModal()
    {
    // cannot call DoModal on a dialog already constructed as modeless
    ASSERT(m_hWnd == NULL);// allow OLE servers to disable themselves
    CWinApp* pApp = AfxGetApp();
    if (pApp != NULL)
    pApp->EnableModeless(FALSE);// find parent HWND
    HWND hWnd = CWnd::GetSafeOwner_(m_pParentWnd->GetSafeHwnd(), &m_hWndTop);// hook for creation of dialog
    AfxHookWindowCreate(this);// return window to use as parent for dialog
    return hWnd;
    }
    **父窗口来自 GetSafeOwner_3.
    HWND PASCAL CWnd::GetSafeOwner_(HWND hParent, HWND* pWndTop)
    {
    // get window to start with
    HWND hWnd = hParent;
    if (hWnd == NULL)
    {
    CFrameWnd* pFrame = CCmdTarget::GetRoutingFrame_();
    if (pFrame != NULL)
    hWnd = pFrame->GetSafeHwnd();
    else
    hWnd = AfxGetMainWnd()->GetSafeHwnd();
    }***OK,到这里应该明白了,因为 hWnd = NULL(父窗口)
    因此最终的 hParent = AfxGetMainWnd()->GetSafeHwnd(),即 CMainFrame::m_hWnd楼主需要注意一个问题,模态对话框是一个比较有意思的东西,它的消息循环是伪造出来的,是对一个非模态对话框AfxHookWindowCreate并且RunModalLoop来完成的,恐怕在MFC你再找不出来其它窗口是这样创建的
    而且取父窗口不是保存一个值就可以了事的,你可以发现CWnd::GetParent 的方法是通过调用 ::GetParent 完成的,你所保存的值对它来说毫无意义
    我的目的是指出模态对话框的创建过程受到 AfxHookWindowCreate 的影响,使得创建过程受到控制,这就是 hParentWnd 的作用
      

  5.   

    谢谢大家,我大概理解了。
      其实我本来以为MFC的模式对话框也是通过api的DialogBox实现的,所以我想问的是api中DialogBox是怎么样实现,如goodboyws(深夜不眠者(VCMVP))所说内嵌消息消息循环,应该是可以实现的。