3

I'm working on an MFC app. I have a class inheriting from CWinApp which tries to open an AfxMessageBox inside its InitInstance function.

When the AfxMessageBox function is called, no message-box is visible, but I hear a Windows bell sound. If I press Alt, the message box appears. Why isn't the AfxMessageBox appearing immediately?

This question mentions a similar issue, but the answer only refers to the non-MFC function MessageBox, not AfxMessageBox which is what I'm using:

MFC MessageBox Not Showing at Top Of All Windows


Update 1

I'm working on a minimal reproducible example, but it's tricky because this is part of a large application with poor encapsulation.

In my app, it appears that a call to the function ProcessShellCommand() is causing AfxMessageBox to stop working. However, calls to AfxMessageBox work correctly both before and after ProcessShellCommand in a newly-created MFC application.

It looks like some consequence of calling ProcessShellCommand is causing AfxMessageBox to behave differently, but I'm not sure how to identify all the consequences of calling ProcessShellCommand. When I'm debugging, the particular call to ProcessShellCommand includes a filename, so the file-open command is causing the app's CView to be launched.

In the OnInitialUpdate code for my CView-inheriting class, AfxMessageBox functions correctly. The best transition point I can identify between AfxMessageBox working, and not working, is when the CView's OnInitialUpdate function returns from it being called by ProcessShellCommand.


Update 2

It seems that m_pMainWnd is NULL before the call to ProcessShellCommand (while AfxMessageBox is working as expected), and non-NULL after the call to ProcessShellCommand.

Based on this discussion: Why would a message box be not displaying? , I tried printing out the message-queue contents before and after the call to ProcessShellCommand. Before, the message-queue only contains a single message. Afterwards, the message-queue printout loop is full of WM_PAINT and it never terminates until I press Alt. This makes me think that I'm running into a message-pump-related issue rather than something related to e.g. visibility state.

---------- More observations ------------

It looks like the call to AfxMessageBox stops inside win32u.dll; I determined this by hitting the 'pause execution' button while waiting for the message-box to appear. Here's the call-stack and debug screenshot:

Call stack Program pointer

13
  • A minimal reproducible example is required. Commented Dec 9, 2020 at 23:07
  • 1
    What version of VS? See also AfxMessageBox going on background.
    – dxiv
    Commented Dec 10, 2020 at 0:31
  • @dxiv VS2019. Thanks, I checked that link - seems to be suggesting a workaround by programmatically creating a key-press via PostMessage(WM_SYSKEYDOWN). This might be an OK band-aid but I would prefer to solve this the 'right' way.
    – afarley
    Commented Dec 10, 2020 at 0:33
  • 1
    @afarley This was reported as a bug back then, but the Microsoft Connect site was retired since and the old links no longer work.
    – dxiv
    Commented Dec 10, 2020 at 0:41
  • 1
    AfxMessageBox is essentially a wrapper around MessageBox. The latter accepts an explicit owner window handle. The former doesn't, and the owner is deduced from application state. Such is MFC: It seemingly simplifies the interface at the expense of requiring the user to know virtually every aspect of its internal implementation. Start by single-stepping into AfxMessageBox and take it from there. Commented Dec 10, 2020 at 10:22

2 Answers 2

1

I had the same problem with VS2109. An image is displayed using the OnDraw(..) function of the Cview class. The user selects a menu command to enter some data and if the data are not correct the AfxMessageBox(...) is called. Nothing really out of the ordinary. (I also noticed that when the message window does occasionally appear, it is painted very slowly).

This is a fix I found and I hope it helps. In your application, add the function DoMessageBox(...) with the following statements:

int CYourApplicationApp::DoMessageBox(LPCTSTR lpszPrompt, UINT nType, UINT 
nIDPrompt)
{  
    // call the base class
    int res = CWinApp::DoMessageBox(lpszPrompt, nType, nIDPrompt);

    CWnd* pWnd = CWnd::GetActiveWindow();

    ASSERT(pWnd);

    pWnd->PostMessageW(WM_SYSKEYDOWN);

    return res;
}

It may also be of general interest to know that one may also get the same problem by simply calling a dialog with the DoModal() function. On occasions, the dialog will appear only after one presses the [alt] key! It seems to me that there is a general problem with the way the CView class interacts with the CWndFrame class in that (for some unknown reason) it is pumping the latter with WM_PAINT messages.

0

It turns out that my CWinApp had a CFrameWnd class that I had forgotten about; I was focusing too much on the CView class.

In the CFrameWnd class, in the BEGIN_MESSAGE_MAP block, there was an ON_WM_TIMER(). I removed this from the message-map to test, and the AfxMessageBox() worked as expected.

When I create a fresh SDI application, there is no ON_WM_PAINT() in the message-map block, so I think this may have been added incorrectly. The class itself does not implement OnPaint(), so I guess this caused some unhandled WM_PAINT messages to be floating around.

It's a bit surprising that this doesn't lead to a compiler error; as I understand it, having ON_WM_PAINT() only makes sense if there's a corresponding OnPaint() function.

1
  • 1
    It could be that the base class provides a default OnPaint function that doesn't do what you need. Commented Dec 15, 2020 at 4:06

Not the answer you're looking for? Browse other questions tagged or ask your own question.