3ds Max C++ API Reference
WindowsMessageFilter Class Reference

Runs a message loop without blocking, allowing only acceptable Windows messages through to their destination UI controls. More...

#include <WindowsMessageFilter.h>

+ Inheritance diagram for WindowsMessageFilter:

Public Member Functions

CoreExport WindowsMessageFilter ()
 Constructor. More...
 
virtual CoreExport ~WindowsMessageFilter ()
 Destructor. More...
 
virtual CoreExport void RunNonBlockingMessageLoop ()
 Run a message loop without blocking, allowing only acceptable Windows messages through to their destination UI controls. More...
 
virtual CoreExport void AbortMessageLoop ()
 Abort the current message loop. More...
 
virtual CoreExport bool IsAcceptableMessage (const MSG &msg) const
 May the given message be delivered to its destination control? More...
 
virtual CoreExport bool IsAbortMessage (const MSG &msg) const
 Is the given message an "Abort" message? More...
 
virtual CoreExport bool ShouldRepostMessage (const MSG &msg) const
 Should the given message be reposted to the message queue? More...
 
virtual CoreExport bool Aborted () const
 Was the last message loop aborted? More...
 
CoreExport void AddUnfilteredWindow (HWND window)
 Add a window handle to the list of unfiltered windows. More...
 
CoreExport void RemoveUnfilteredWindow (HWND window)
 Remove a currently unfiltered window from the list. More...
 
CoreExport void ClearUnfilteredWindowList ()
 Remove all window handles from the list of unfiltered windows. More...
 
CoreExport bool IsUnfilteredWindow (HWND window) const
 Is the given window handle in the list of unfiltered windows? More...
 
CoreExport bool IsUnfilteredWindowChild (HWND child) const
 Is the given window a child of a registered unfiltered window? More...
 

Static Public Member Functions

static CoreExport bool IsQtSystemMessage (const MSG &msg)
 Returns if the given message is required for the underlying Qt event system and therefore needs to be accepted by the message filter. More...
 
- Static Public Member Functions inherited from MaxHeapOperators
static UtilExport voidoperator new (size_t size)
 Standard new operator used to allocate objects If there is insufficient memory, an exception will be thrown. More...
 
static UtilExport voidoperator new (size_t size, const std::nothrow_t &e)
 Standard new operator used to allocate objects if there is insufficient memory, NULL will be returned. More...
 
static UtilExport voidoperator new (size_t size, const char *filename, int line)
 New operator used to allocate objects that takes the filename and line number where the new was called If there is insufficient memory, an exception will be thrown. More...
 
static UtilExport voidoperator new (size_t size, int block_type, const char *filename, int line)
 New operator used to allocate objects that takes the type of memory, filename and line number where the new was called If there is insufficient memory, an exception will be thrown. More...
 
static UtilExport voidoperator new (size_t size, const std::nothrow_t &e, const char *filename, int line)
 New operator used to allocate objects that takes the filename and line number where the new was called If there is insufficient memory, NULL will be returned. More...
 
static UtilExport voidoperator new (size_t size, unsigned long flags)
 New operator used to allocate objects that takes extra flags to specify special operations If there is insufficient memory, an exception will be thrown. More...
 
static UtilExport voidoperator new (size_t size, const std::nothrow_t &e, unsigned long flags)
 New operator used to allocate objects that takes extra flags to specify special operations If there is insufficient memory, NULL will be returned. More...
 
static UtilExport voidoperator new[] (size_t size)
 New operator used to allocate arrays of objects If there is insufficient memory, an exception will be thrown. More...
 
static UtilExport voidoperator new[] (size_t size, const std::nothrow_t &e)
 New operator used to allocate arrays of objects If there is insufficient memory, NULL will be returned. More...
 
static UtilExport voidoperator new[] (size_t size, const char *filename, int line)
 New operator used to allocate arrays of objects If there is insufficient memory, an exception will be thrown. More...
 
static UtilExport voidoperator new[] (size_t size, int block_type, const char *filename, int line)
 New operator used to allocate arrays of objects. More...
 
static UtilExport voidoperator new[] (size_t size, const std::nothrow_t &e, const char *filename, int line)
 New operator used to allocate arrays of objects If there is insufficient memory, NULL will be returned. More...
 
static UtilExport voidoperator new[] (size_t size, unsigned long flags)
 New operator used to allocate arrays of objects If there is insufficient memory, an exception will be thrown. More...
 
static UtilExport voidoperator new[] (size_t size, const std::nothrow_t &e, unsigned long flags)
 New operator used to allocate arrays of objects If there is insufficient memory, NULL will be returned. More...
 
static UtilExport void operator delete (void *ptr)
 Standard delete operator used to deallocate an object If the pointer is invalid, an exception will be thrown. More...
 
static UtilExport void operator delete (void *ptr, const std::nothrow_t &e)
 Standard delete operator used to deallocate an object If the pointer is invalid, nothing will happen. More...
 
static UtilExport void operator delete (void *ptr, const char *filename, int line)
 Delete operator used to deallocate an object that takes the filename and line number where the delete was called If the pointer is invalid, an exception will be thrown. More...
 
static UtilExport void operator delete (void *ptr, int block_type, const char *filename, int line)
 Delete operator used to deallocate an object that takes the type of memory, filename and line number where the delete was called If the pointer is invalid, an exception will be thrown. More...
 
static UtilExport void operator delete (void *ptr, const std::nothrow_t &e, const char *filename, int line)
 Delete operator used to deallocate an object that takes the filename and line number where the delete was called If the pointer is invalid, nothing will happen. More...
 
static UtilExport void operator delete (void *ptr, unsigned long flags)
 Delete operator used to deallocate an object that takes extra flags to specify special operations If the pointer is invalid, an exception will be thrown. More...
 
static UtilExport void operator delete (void *ptr, const std::nothrow_t &e, unsigned long flags)
 Delete operator used to deallocate an object that takes extra flags to specify special operations If the pointer is invalid, nothing will happen. More...
 
static UtilExport void operator delete[] (void *ptr)
 Standard delete operator used to deallocate an array of objects If the pointer is invalid, an exception will be thrown. More...
 
static UtilExport void operator delete[] (void *ptr, const std::nothrow_t &e)
 Standard delete operator used to deallocate an array of objects If the pointer is invalid, nothing will happen. More...
 
static UtilExport void operator delete[] (void *ptr, const char *filename, int line)
 Delete operator used to deallocate an array of objects that takes the filename and line number where the delete was called If the pointer is invalid, an exception will be thrown. More...
 
static UtilExport void operator delete[] (void *ptr, int block_type, const char *filename, int line)
 Delete operator used to deallocate an array of objects that takes the type of memory, filename and line number where the delete was called If the pointer is invalid, an exception will be thrown. More...
 
static UtilExport void operator delete[] (void *ptr, const std::nothrow_t &e, const char *filename, int line)
 Delete operator used to deallocate an array of objects that takes the filename and line number where the delete was called If the pointer is invalid, nothing will happen. More...
 
static UtilExport void operator delete[] (void *ptr, unsigned long flags)
 Delete operator used to deallocate an array of objects that takes extra flags to specify special operations If the pointer is invalid, an exception will be thrown. More...
 
static UtilExport void operator delete[] (void *ptr, const std::nothrow_t &e, unsigned long flags)
 Delete operator used to deallocate an array of objects that takes extra flags to specify special operations If the pointer is invalid, an exception will be thrown. More...
 
static UtilExport voidoperator new (size_t size, void *placement_ptr)
 Placement new operator. More...
 
static UtilExport void operator delete (void *ptr, void *placement_ptr)
 Placement delete operator. More...
 
static UtilExport voidaligned_malloc (size_t size, size_t alignment)
 Allocates memory on a specified alignment boundary. More...
 
static UtilExport voidaligned_realloc (void *ptr, size_t size, size_t alignment)
 Reallocates memory on a specified alignment boundary. More...
 
static UtilExport void aligned_free (void *ptr)
 Frees a block of memory that was allocated with aligned_malloc/aligned_realloc. More...
 

Additional Inherited Members

- Protected Member Functions inherited from Noncopyable
 Noncopyable ()
 
 ~Noncopyable ()
 

Detailed Description

Runs a message loop without blocking, allowing only acceptable Windows messages through to their destination UI controls.

WindowsMessageFilter's message loop is a common idiom for Win32 progress dialogs. A progress dialog may call WindowsMessageFilter::RunNonBlockingMessageLoop periodically to allows paint messages through. In this way, the UI can refresh and the application appears to respond instead of entering Windows' "Not Responding" state.

WindowsMessageFilter also solves a common bug with our hosted WPF (.NET 3.5) UI controls. It appears that the operating system periodically sends a sort of heartbeat message to WPF controls. This message is in the user message range, above WM_USER. If this message is filtered out, as was the case for previous message filtering loops, the controls stop responding for the rest of the session.

The WindowsMessageFilter ensures that any messages required by the internal Qt event system are passed through for the Qt UI. This is automatically done within the default implementation of IsAcceptableMessage, which calls the IsQtSystemMessage method. If you provide a custom override for IsAcceptableMessage make sure it contains a call IsQtSystemMessage - without that the Qt UI can freeze.

The default implementation calls PeekMessage, removing messages from the message queue. It inspects each message in turn. If IsAbortMessage returns true for a message, the loop is aborted. If IsAcceptableMessage returns true for the message, it is passed to the application's main Translate and Dispatch message function. If IsAcceptableMessage returns false, and ShouldRepostMessage returns true, the message is reposted to the message queue. See each function's documentation for a description of its behaviour.

The implementation may be customized by creating a derived class and overriding any of IsAcceptableMessage, IsAbortMessage, or ShouldRepostMessage. Alternatively, a derived class may override RunNonBlockingMessageLoop to specialize the message filtering loop itself.

Example:

Generally, a message filtering loop looks like the following. This could be replaced by WindowsMessageFilter. Using WindowsMessageFilter is recommended over a custom solution, since it allows us to solve bugs like the WPF problem described above in one place for the entire application.

// returns false if the current processing should be aborted.
// Messages are allowed through for the passed-in HWND and its child controls.
bool CheckWindowsMessages(HWND hWnd)
{
MSG msg = {0};
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
// Quit message aborts
if(WM_QUIT == msg.message)
{
PostMessage(msg.hwnd, msg.message, msg.wParam, msg.lParam);
return false;
}
// Escape key is consumed and aborts processing
if(WM_KEYDOWN == msg.message && VK_ESCAPE == msg.wParam)
{
return false;
}
// Allow paint messages through, as well as any messages for the
// unfiltered window.
if( WM_PAINT == msg.message ||
WM_PAINTICON == msg.message ||
msg.hwnd == hWnd ||
IsChild(hWnd, msg.hwnd )
{
GetCOREInterface()->TranslateAndDispatchMAXMessage(msg);
}
}
return true; // allow processing to continue
}
#define NULL
Definition: autoptr.h:18

This message filter loop can be replaced with the WindowsMessageFilter as shown below.

bool CheckWindowsMessages(HWND hWnd)
{
messageFilter.AddUnfilteredWindow(hWnd);
messageFilter.RunNonBlockingMessageLoop();
return !messageFilter.Aborted();
}
Runs a message loop without blocking, allowing only acceptable Windows messages through to their dest...
Definition: WindowsMessageFilter.h:118
virtual CoreExport void RunNonBlockingMessageLoop()
Run a message loop without blocking, allowing only acceptable Windows messages through to their desti...
virtual CoreExport bool Aborted() const
Was the last message loop aborted?
CoreExport void AddUnfilteredWindow(HWND window)
Add a window handle to the list of unfiltered windows.

Constructor & Destructor Documentation

◆ WindowsMessageFilter()

Constructor.

◆ ~WindowsMessageFilter()

virtual CoreExport ~WindowsMessageFilter ( )
virtual

Destructor.

Member Function Documentation

◆ RunNonBlockingMessageLoop()

virtual CoreExport void RunNonBlockingMessageLoop ( )
virtual

Run a message loop without blocking, allowing only acceptable Windows messages through to their destination UI controls.

Messages deemed acceptable by IsAcceptableMessage are Translated and Dispatched. An Abort message, as determined by IsAbortMessage is consumed, sets Aborted to true, and exits the loop. A message may be reposted to the end of the message queue if it is not acceptable and if ShouldRepostMessage returns true. The loop exits normally when the message queue is depleted.

Note that this call is ignored if not called from the main thread.

◆ AbortMessageLoop()

virtual CoreExport void AbortMessageLoop ( )
virtual

Abort the current message loop.

Sets Aborted to true immediately, then aborts the currently running message loop when control returns.

◆ IsAcceptableMessage()

virtual CoreExport bool IsAcceptableMessage ( const MSG &  msg) const
virtual

May the given message be delivered to its destination control?

The default implementation considers the following messages acceptable:

  • WM_PAINT
  • WM_PAINTICON
  • Any user message (>= WM_USER)
  • Any message required by the underlying Qt event system. This check uses IsQtSystemMessage for determining acceptable messages.
  • Any message whose hwnd value is a registered unfiltered window or a registered unfiltered window's child.
Parameters
msgMessage to evaluate.
Returns
true if the message is acceptable, false otherwise.
See also
IsQtSystemMessage()

◆ IsAbortMessage()

virtual CoreExport bool IsAbortMessage ( const MSG &  msg) const
virtual

Is the given message an "Abort" message?

The default implementation considers an ESC key down message as an "Abort" message.

Parameters
msgMessage to evaluate.
Returns
true if the message is an Abort message, false otherwise.

◆ ShouldRepostMessage()

virtual CoreExport bool ShouldRepostMessage ( const MSG &  msg) const
virtual

Should the given message be reposted to the message queue?

The default implementation only returns true for WM_QUIT.

Parameters
msgMessage to evaluate.
Returns
true if the message should be reposted, false otherwise.

◆ Aborted()

virtual CoreExport bool Aborted ( ) const
virtual

Was the last message loop aborted?

The Aborted value is reset to false at the start of any call to RunNonBlockingMessageLoop. If the loop terminates by depleting the message queue, Aborted will remain false. On the other hand, if the message loop finds an Abort or Quit message, it will abort, and mark Aborted as true. Similarly, if a client calls AbortMessageLoop, the message loop will abort and set Aborted to true.

Returns
true if the message loop aborted early, false otherwise.

◆ AddUnfilteredWindow()

CoreExport void AddUnfilteredWindow ( HWND  window)

Add a window handle to the list of unfiltered windows.

All messages intended for the given window will be allowed through the message filter.

Note that adding duplicate elements will place the same element multiple times in the list. If a set of window handles may be added multiple times, it is better to call clear first.

Parameters
windowWindow handle to leave unfiltered.

◆ RemoveUnfilteredWindow()

CoreExport void RemoveUnfilteredWindow ( HWND  window)

Remove a currently unfiltered window from the list.

This command is ignored if the window is not present in the list. If the window handle was added multiple times, all instances of it will be removed from the list.

Parameters
windowWindow handle to remove from the list of unfiltered windows.

◆ ClearUnfilteredWindowList()

CoreExport void ClearUnfilteredWindowList ( )

Remove all window handles from the list of unfiltered windows.

◆ IsUnfilteredWindow()

CoreExport bool IsUnfilteredWindow ( HWND  window) const

Is the given window handle in the list of unfiltered windows?

Parameters
windowWindow handle for which to look.
Returns
true if the given window handled is in the unfiltered list, false otherwise.

◆ IsUnfilteredWindowChild()

CoreExport bool IsUnfilteredWindowChild ( HWND  child) const

Is the given window a child of a registered unfiltered window?

Parameters
childWindow handle to examine.
Returns
true if this window handle is a child of a registered unfiltered window, false otherwise.

◆ IsQtSystemMessage()

static CoreExport bool IsQtSystemMessage ( const MSG &  msg)
static

Returns if the given message is required for the underlying Qt event system and therefore needs to be accepted by the message filter.

Parameters
msgMessage to evaluate.
Returns
true if the message is required Qt system message, false otherwise.
See also
IsAcceptableMessage()