Menu

#95 New CMessageLoop implementation

closed
None
5
2020-03-30
2016-01-28
Anonymous
No

I have a suggestion for how to make the CMessageLoop class more useful. So what is wrong with current implementation?

I have a program where I use the CMainFrame::OnIdle event to handle ribbon/ menu/toolbar states - basically extending the UIUpdateToolBar function generated by the Wizard. In my implementation I send a window user message (WM_QUERYINTERFACE) to underlying windows. To my surprise, the OnIdle event newer stops coming (if I don’t send messages, it does). The reason for this is that CMessageLoop::IsIdleMessage consider my WM_QUERYINTERFACE to be a GUI changing message and turns idle on (CMessageLoop::bDoIdle = TRUE).

Ok, that’s easy to fix – override CMessageLoop::IsIdleMessage and add my message to the no- idle-messages. But no, IsIdleMessage is static! It cannot be overridden!

In my suggestion I have removed the function CMessageLoop::Run. I have also removed virtual on PreTranslateMessage and OnIdle – turning this class into a concrete base class with no vtable. Finally I renamed the class to CMessageLoopBase (e.g.). This implies that the class CAppModule must be changes as well (it must refer to CMessageLoopBase and not CMessageLoop).

I have then created a new template class CMessageLoopT, containing a slight modification of CMessageLoop::Run.

And finally a concrete class CMessageLoop, the default message loop class.

Here is an example of use:
*class CMyMessageLoop
: public CMessageLoopT<cmymessageloop>
{
public:
BOOL IsIdleMessage(MSG</cmymessageloop>
pMsg)
{
if (!super::IsIdleMessage(pMsg))
return FALSE;
switch (pMsg->message)
{
case WM_QUERYINTERFACE:
case WM_KICKIDLE:
case WM_TIMER:
case 0x8002:
return FALSE;
}
return TRUE;
}
} theLoop;
_Module.AddMessageLoop(&theLoop);

So what are pros and cons?

Pros:

  • Easy to hook into the message loop.
  • No vtable calls – faster.
  • Follow the ATL/WTL policy of favoring template override over vtable override.
  • If CMessageLoop is not specialized, old code will work unchanged.
  • No need to change wizard code.

Cons:

  • It’s possible that existing code get broken, but CMessageLoop is not a typical class to specialize, if it was not for IsIdleMessage, which is impossible.
  • If PreTranslateMessage and/or OnIdle is specialized, old code will not work unmodified.
A class like:
**class CMyMessageLoop
public CMessageLoop
{
...
};
Must be modified in order to work as before:
**class CMyMessageLoop
public CMessageLoopT< CMyMessageLoop >
{
...
};
**
I attached proposal code.
1 Attachments

Discussion

  • Nenad Stefanovic

    • status: open --> closed
     
  • Nenad Stefanovic

    This proposal is excellent and in the spirit of WTL design. I would gladly use it, but... it would require code changes in code emitted by the AppWizard (use of CMessageLoopBase ptr instead of CMessageLoop ptr). It would require changes in all existing projects. It would also break all custom message loop implementations.

    Because of that I went the other way and made IsIdleMessage() virtual. Now it is easy to override it in a derived class. It will cost us one more vtable entry. Before we were always trying to avoid that, but I think that now we can be a bit more generous.

    Note: Be careful with idle processing, it can easily slow down the app.

    Commit: https://sourceforge.net/p/wtl/git/ci/6cf1e60ab290ec5660297b14942e432b6b18878f/

     

Anonymous
Anonymous

Add attachments
Cancel





MongoDB Logo MongoDB