1
votes

I'm currently transferring old source code to Visual Studio 2019.

The original code is from VC++6 or older.

In Windows MFC, there is a class called CWinThread, and according to the old source code, m_msgCur exists in the class. However, in VS2019, it says that m_msgCur does not exist. Then I found that m_msgCur existed long ago (https://github.com/dblock/msiext/blob/master/externals/WinDDK/7600.16385.1/inc/mfc42/afxwin.h, MFC 4.2) and it is deleted in VS2019. MSG m_msgCur contains current message of the thread, but is there any alternative variable in VS2019?

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

Edited:

Project link: https://github.com/ValveSoftware/halflife/tree/master/utils/serverctrl

Class CServerCtrlDlg (inherited from CDialog) is declared in ServerCtrlDlg.h. ServerCtrlDlg.cpp contains how it works. ServerCtrlClg.cpp includes <afxpriv.h>, and <afxpriv.h> contains afxwin.h, which has CWinThread.

Part of ServerCtrlDlg that uses m_msgCur

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;
}
1
MFC allows you to hook into its message processing code (e.g. ProcessMessageFilter). Depending on when and why you need to access the message that's currently being handled, there are several ways to get it. An answer will depend on this information, so you'll need to include it in your question.IInspectable
@IInspectable I updated my question and added the source link and the some of the codes.fel1x.mintchoco
The code shown doesn't seem to rely on m_msgCur being populated elsewhere - it just uses it as a local variable. Make it MSG msg = {0}; MSG* pMsg = &msg; and see if the code still works.Igor Tandetnik
This you see this? social.msdn.microsoft.com/Forums/vstudio/en-US/… AfxGetThreadState()->m_msgCur.wParam;Andrew Truckle
@IgorTandetnik Problem with that is it would break AfxGetCurrentMessage which some MFC code relies on, for example to fetch the exit code from PostQuitMessage. Disclaimer: this is not meant as an endorsement of MFC design, just a statement of fact ;-)dxiv

1 Answers

3
votes

Short answer is to replace:

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

with:

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

A better answer, however, is that if you must hack CWnd::RunModalLoop then you should do it right, and update CServerCtrlDlg::RunModalLoop to base it on the current CWnd::RunModalLoop code from VC++ 2019, instead of the old code borrowed from VC++ 6.

Comparing CServerCtrlDlg::RunModalLoop to the CWnd::RunModalLoop implementation in VC++ 6 from mfc\src\wincore.cpp shows the following lines marked with //++ as having been added.

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 should be updated to use the VC++ 2019 CWnd::RunModalLoop code, instead, then those //++ lines merged into it. The MFC changes in CWnd::RunModalLoop are small enough between the two versions that merging is straightforward.