RunModalLoop

本文详细解析了Windows应用程序中模态循环的实现机制,包括如何处理消息队列、如何进行空闲工作检查以及如何在不同的消息阶段进行窗口显示和更新。通过深入理解intCWnd::RunModalLoop函数,读者可以更好地掌握Windows应用程序的模态对话框处理流程。

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 = AfxGetCurrentMessage();

    // 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 (!AfxPumpMessage())
            {
                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 (AfxIsIdleMessage(pMsg))
            {
                bIdle = TRUE;
                lIdleCount = 0;
            }

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

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

 

<think>我们正在处理用户关于MFC隐藏窗口的问题。用户希望了解在MFC程序中隐藏窗口的实现方法,特别是创建时隐藏。根据用户提供的引用,我们可以总结出几种方法:1.使用SetWindowPos函数,并指定SWP_HIDEWINDOW标志(引用[1])。2.在创建非模态对话框时,通过ShowWindow(SW_HIDE)来隐藏(引用[2]和引用[5])。3.另外,引用[5]还展示了一种在创建主窗口时隐藏的方法:在创建对话框后立即调用ShowWindow(SW_HIDE),然后进入模态循环。同时,用户特别强调“创建时隐藏”,因此我们需要关注如何在窗口创建的那一刻就将其隐藏。在MFC中,窗口的显示状态通常在创建或打开时由ShowWindow函数的参数决定。例如,在创建窗口(Create函数)后立即调用ShowWindow(SW_HIDE)可以隐藏窗口。此外,我们还可以通过修改窗口的样式(例如,不包含WS_VISIBLE)来实现创建时隐藏。但是,需要注意的是,在MFC中使用DoModal创建模态对话框时,默认会显示对话框。因此,如果要在创建模态对话框时隐藏,则需要在创建后调用ShowWindow(SW_HIDE)。然而,引用[5]提供了一种替代DoModal的方法:使用Create和RunModalLoop,并在Create后立即调用ShowWindow(SW_HIDE)来隐藏对话框,然后进入模态循环。这样可以在不显示窗口的情况下运行模态循环。步骤:1.创建窗口(使用Create函数,而不是DoModal)。2.立即调用ShowWindow(SW_HIDE)隐藏窗口。3.调用RunModalLoop进入模态循环。另外,我们还可以通过修改窗口的样式来实现创建时隐藏。在创建窗口(Create)时,我们可以通过设置dwStyle参数,去掉WS_VISIBLE样式。这样窗口创建后不会显示。总结几种方法:方法1:在创建后立即调用ShowWindow例如,非模态对话框:CMyDialog*pDlg=newCMyDialog();pDlg->Create(IDD_MYDIALOG);pDlg->ShowWindow(SW_HIDE);对于主窗口(如主框架窗口),可以在InitInstance中创建后调用ShowWindow(SW_HIDE)。方法2:修改窗口样式,创建时不含WS_VISIBLE例如,在创建窗口时,使用dwStyle参数,不包含WS_VISIBLE标志。然后在需要显示时再调用ShowWindow(SW_SHOW)。方法3:对于模态对话框,避免使用DoModal,改用Create和RunModalLoop,并在Create后调用ShowWindow(SW_HIDE)。引用[5]中的代码示例:CMFCApplication1Dlgdlg;m_pMainWnd=&dlg;dlg.Create(CMFCApplication1Dlg::IDD);dlg.ShowWindow(SW_HIDE);dlg.RunModalLoop();需要注意的是,这样创建的对话框是模态的,但是创建时隐藏。另外,用户还提到隐藏任务栏图标,这可以通过设置扩展样式(比如WS_EX_TOOLWINDOW)来实现,但这与隐藏窗口本身不同。隐藏窗口指的是不显示窗口界面,而隐藏任务栏图标则是在任务栏不显示图标。根据用户需求,他可能还需要隐藏窗口的同时隐藏任务栏图标。引用[2]提到,可以通过设置父窗口的方式将主窗口图标隐藏。不过用户当前的问题集中在隐藏窗口的实现上。因此,我们提供以下步骤实现创建时隐藏窗口:步骤:1.创建窗口(Create函数)。2.调用ShowWindow(SW_HIDE)隐藏窗口。对于不同的窗口类型(如主框架、视图、对话框等),方法类似。示例代码:示例1:隐藏主框架窗口(在InitInstance中)//创建主框架窗口CMainFrame*pMainFrame=newCMainFrame;if(!pMainFrame->LoadFrame(IDR_MAINFRAME))returnFALSE;//隐藏主框架窗口pMainFrame->ShowWindow(SW_HIDE);m_pMainWnd=pMainFrame;示例2:隐藏模态对话框通常,我们使用DoModal来创建模态对话框,但DoModal会显示对话框。所以我们需要替换方法:CMyDialogdlg;dlg.Create(IDD_DIALOG1);dlg.ShowWindow(SW_HIDE);dlg.RunModalLoop();//进入模态循环注意:这种方式下,对话框被隐藏,但仍然可以处理消息。示例3:隐藏非模态对话框CMyDialog*pDlg=newCMyDialog;pDlg->Create(IDD_DIALOG1);pDlg->ShowWindow(SW_HIDE);此外,关于如何在创建时不显示窗口,也可以通过在创建窗口前修改窗口样式(在PreCreateWindow中)来实现。例如,在重载的PreCreateWindow函数中,去掉cs.style中的WS_VISIBLE标志:示例4:在视图/框架窗口的PreCreateWindow中隐藏BOOLCMainFrame::PreCreateWindow(CREATESTRUCT&cs){if(!CFrameWnd::PreCreateWindow(cs))returnFALSE;//移除WS_VISIBLE样式,这样窗口创建时不会显示cs.style&=~WS_VISIBLE;returnTRUE;}这样,在调用CFrameWnd::Create时,窗口不会显示,直到调用ShowWindow(SW_SHOW)才会显示。但是,对于对话框,由于是资源中定义的,默认可能包含WS_VISIBLE样式。我们可以修改资源属性,在资源编辑器中去除对话框的Visible属性(即取消选中Visible),这样在创建对话框时就不会自动显示。然后我们可以选择在需要时显示。在资源编辑器中:右键对话框->属性->取消勾选Visible属性。然后在代码中,使用Create创建对话框(非模态),然后根据需要调用ShowWindow(SW_SHOW)来显示。总结:创建时隐藏窗口的方法有多种,包括:-在创建后立即调用ShowWindow(SW_HIDE)-创建窗口时在样式(style)中去除WS_VISIBLE(通过修改CREATESTRUCT或在资源编辑器中修改对话框属性)-对于模态对话框,使用Create和RunModalLoop替代DoModal,并在Create后调用ShowWindow(SW_HIDE)选择哪种方法取决于窗口类型和具体需求。注意:隐藏窗口后,如果需要显示,可以调用ShowWindow(SW_SHOW)来显示窗口。相关问题:1.如何同时隐藏窗口和任务栏图标?2.如何判断一个窗口当前是隐藏还是显示?3.窗口隐藏后,如何重新显示?4.隐藏窗口后,子窗口刷新问题(如引用[4])如何处理?5.隐藏窗口时,如何避免在任务栏显示?根据引用[2],可以通过设置父窗口来隐藏任务栏图标。例如,将一个窗口的父窗口设置为另一个隐藏窗口,则它不会在任务栏显示。或者设置扩展样式WS_EX_TOOLWINDOW也可以避免在任务栏显示图标。</think> 在 MFC 程序中实现窗口隐藏(创建时即隐藏)可通过以下几种方法实现,根据窗口类型和需求选择合适方案: --- ### 🔧 方法一:创建后立即隐藏(通用方法) ```cpp // 创建模态对话框并隐藏(主窗口适用) CMyDialog dlg; m_pMainWnd = &dlg; // 设置为主窗口 dlg.Create(IDD_MYDIALOG); // 创建窗口 dlg.ShowWindow(SW_HIDE); // ✨ 关键隐藏指令 dlg.RunModalLoop(); // 进入消息循环 ``` *适用场景*:主窗口、模态对话框 *引用依据*:通过 `ShowWindow(SW_HIDE)` 在创建后立即隐藏窗口 [^5] --- ### ⚙️ 方法二:修改窗口样式(非模态对话框/控件) ```cpp // 创建时去除 WS_VISIBLE 样式 BOOL bSuccess = pDialog->Create( IDD_DIALOG1, GetDesktopWindow(), WS_CHILD | WS_BORDER // 移除 WS_VISIBLE ); ``` *注意事项*:需后续手动调用 `ShowWindow(SW_SHOW)` 显示窗口 *适用场景*:子窗口、非模态对话框、自定义控件 --- ### 🎨 方法三:资源编辑器设置(对话框专用) 1. 在资源编辑器中右键对话框 → 属性 2. 取消勾选 **Visible** 属性 ![](https://via.placeholder.com/300x200?text=取消勾选Visible) 3. 代码中正常使用 `DoModal()` 或 `Create()`,窗口创建时自动隐藏 *优势*:无需额外代码,直接隐藏 [^4] --- ### 🔍 判断窗口当前状态 ```cpp // 检查窗口是否隐藏 if (pWnd->GetStyle() & WS_VISIBLE) { // 检测样式标志 TRACE("窗口当前可见"); } // 或使用 API if (pWnd->IsWindowVisible()) { // 受父窗口影响 AfxMessageBox(_T("窗口实际可见")); } ``` *引用依据*:`GetStyle()` 检查 `WS_VISIBLE` 最可靠 [^3] --- ### 🚫 隐藏任务栏图标(附加需求) ```cpp // 设置扩展样式避免任务栏显示 ModifyStyleEx(0, WS_EX_TOOLWINDOW); // 或绑定到隐藏的父窗口 SetParent(&hiddenParentWnd); ``` *引用依据*:通过父窗口或扩展样式控制任务栏图标 [^1][^2] --- ### 💡 相关问题 1. **隐藏窗口后如何恢复显示?** → 使用 `ShowWindow(SW_SHOW)` 或 `ShowWindow(SW_RESTORE)` *难点*:需同步刷新子窗口(需设置 `WS_CLIPCHILDREN`)[^4] 2. **如何彻底隐藏窗口连带任务栏图标?** → 组合方案:`ShowWindow(SW_HIDE)` + `ModifyStyleEx(0, WS_EX_TOOLWINDOW)` 3. **窗口隐藏后如何防止内存泄漏?** → 非模态对话框需重写 `PostNcDestroy()` 执行 `delete this` 4. **隐藏窗口仍接收消息的正确方案?** → 创建时指定 `WS_POPUP` 风格而非 `WS_CHILD` 5. **系统托盘隐藏窗口的完整实现?** → 需配合 `NOTIFYICONDATA` 结构体实现托盘图标 > 📌 *关键提示*:使用 `IsWindowVisible()` 检测可见性时需注意父窗口的隐藏状态会影响结果 [^3],建议用 `(GetStyle() & WS_VISIBLE)` 作为主判断依据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值