【问题标题】:m_msgCur in Visual Studio 2019Visual Studio 2019 中的 m_msgCur
【发布时间】:2021-04-05 05:24:54
【问题描述】:

我目前正在将旧源代码转移到 Visual Studio 2019。

原始代码来自VC++6或更早版本。

在Windows MFC中,有一个名为CWinThread的类,根据旧源码,m_msgCur存在于该类中。但是,在 VS2019 中,它说 m_msgCur 不存在。然后我发现m_msgCur早就存在了(https://github.com/dblock/msiext/blob/master/externals/WinDDK/7600.16385.1/inc/mfc42/afxwin.h,MFC 4.2),在VS2019中被删除了。 MSG m_msgCur 包含线程的当前消息,但是 VS2019 中是否有任何替代变量?

// message pump for Run
MSG m_msgCur;                   // current message

已编辑:

项目链接:https://github.com/ValveSoftware/halflife/tree/master/utils/serverctrl

CServerCtrlDlg(继承自CDialog)在ServerCtrlDlg.h 中声明。 ServerCtrlDlg.cpp 包含它的工作原理。 ServerCtrlClg.cpp 包含<afxpriv.h><afxpriv.h> 包含afxwin.h,其中包含CWinThread

使用 m_msgCur 的 ServerCtrlDlg 的一部分

int CServerCtrlDlg::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());

        int iRet = RMLPreIdle();

        if (iRet < 0)
            goto ExitModal;
        else if (iRet > 0)
            continue;

        // 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
        {
            BOOL ShouldPump = TRUE;

            ASSERT(ContinueModal());

            // See if we are requiring messages to be in queue?
            if ( m_bOnlyPumpIfMessageInQueue )
            {
                // If there isn't a message, don't turn over control to PumpMessage
                //  since it will block
                if ( !::PeekMessage( pMsg, NULL, NULL, NULL, PM_NOREMOVE ) )
                {
                    ShouldPump = FALSE;
                }
            }

            // pump message, but quit on WM_QUIT
            if ( ShouldPump )
            {
                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;
}

【问题讨论】:

  • MFC 允许您挂钩到它的消息处理代码(例如ProcessMessageFilter)。根据您需要访问当前正在处理的消息的时间和原因,有几种方法可以获取它。答案将取决于此信息,因此您需要将其包含在您的问题中。
  • @IInspectable 我更新了我的问题并添加了源链接和一些代码。
  • 显示的代码似乎并不依赖于在其他地方填充的m_msgCur - 它只是将其用作局部变量。将其设为MSG msg = {0}; MSG* pMsg = &amp;msg; 并查看代码是否仍然有效。
  • 这个你看到了吗? social.msdn.microsoft.com/Forums/vstudio/en-US/…AfxGetThreadState()-&gt;m_msgCur.wParam;
  • @IgorTandetnik 问题在于它会破坏某些 MFC 代码所依赖的 AfxGetCurrentMessage,例如从 PostQuitMessage 获取退出代码。免责声明:这并不意味着对 MFC 设计的认可,只是对事实的陈述;-)

标签: visual-studio visual-c++ mfc


【解决方案1】:

简短的回答是替换:

    MSG* pMsg = &AfxGetThread()->m_msgCur;  // vc++ 6

与:

    MSG *pMsg = AfxGetCurrentMessage();     // vc++ 2019

然而,一个更好的答案是,如果你必须破解 CWnd::RunModalLoop,那么你应该做对,并更新 CServerCtrlDlg::RunModalLoop 以使其基于 VC++ 2019 中的当前 CWnd::RunModalLoop 代码,而不是从 VC++ 6 借来的旧代码。

CServerCtrlDlg::RunModalLoopmfc\src\wincore.cpp 中VC++ 6 中的CWnd::RunModalLoop 实现进行比较,发现以下标有//++ 的行已被添加。

int CServerCtrlDlg::RunModalLoop(DWORD dwFlags)
{
//...
    // acquire and dispatch messages until the modal state is done
    for (;;)
    {
        ASSERT(ContinueModal());

        int iRet = RMLPreIdle();                                                    //++
                                                                                    //++
        if (iRet < 0)                                                               //++
            goto ExitModal;                                                         //++
        else if (iRet > 0)                                                          //++
            continue;                                                               //++

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

            BOOL ShouldPump = TRUE;                                                 //++
                                                                                    //++
            // See if we are requiring messages to be in queue?                     //++
            if ( m_bOnlyPumpIfMessageInQueue )                                      //++
            {                                                                       //++
                // If there isn't a message, don't turn over control to PumpMessage //++
                //  since it will block                                             //++
                if ( !::PeekMessage( pMsg, NULL, NULL, NULL, PM_NOREMOVE ) )        //++
                {                                                                   //++
                    ShouldPump = FALSE;                                             //++
                }                                                                   //++
            }                                                                       //++

            if ( ShouldPump )                                                       //++
            {
                /* mfc code executed conditionally */
            }
//...
}

CServerCtrlDlg::RunModalLoop 应该更新为使用 VC++ 2019 CWnd::RunModalLoop 代码,然后将那些 //++ 行合并到其中。 CWnd::RunModalLoop 中的 MFC 更改在两个版本之间足够小,可以直接合并。

【讨论】:

    猜你喜欢
    • 2020-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-09
    • 2021-10-04
    • 2023-01-15
    • 2020-05-17
    • 1970-01-01
    相关资源
    最近更新 更多