If you suppress GDI+ background thread, then you are expected to pump messages yourself

Raymond

When you initialize GDI+ by calling GdiplusStartup, you can choose to let GDI+ create its own notification thread (also know as the background thread), or you can suppress the notification thread and promise to do the work yourself. If you choose to do the work yourself, by setting Suppress­Background­Thread to TRUE, then the documentation says,

Call the hook and unhook functions before and after the application’s main message loop; that is, a message loop that is active for the lifetime of GDI+.

In order to successfully put the Notification­Hook function before your message loop and the Notification­Unhook function after it, you need to have a message loop to begin with.

The reason for the message loop is that GDI+ needs a helper window in order to listen for things like WM_SETTINGS­CHANGE messages so it knows when to invalidate its caches or adjust its behavior depending on things like whether the session is on the console or is redirected via Remote Desktop. And that helper window needs a message loop so it can process messages.

Normally, this helper window goes on the notification thread, but you can assume responsibility for the helper window, and it will go onto your thread, which by virtue of now being a UI thread, must pump messages. The idea is that your application probably already has a UI thread, so you may as well add the notification window to that thread. That way, you save a thread.

Unfortunately, some people didn’t quite understand this point. They saw the Suppress­Background­Thread option and said, “Hey, if I set this value to TRUE, then I save a thread!” They didn’t read to the part where it says that you need to put a message loop on that thread.

The result is that the next time the system sends a message to the helper window, the helper window cannot receive the message because the thread isn’t pumping messages, resulting in the usual negative consequences.

Next time, we’ll look more closely at one of those negative consequences.

 

6 comments

Comments are closed. Login to edit/delete your existing comments

  • Joe Beans

    It’s a shame so many API and framework threads are wasted listening for a single event. .NET and the shell namespace are horrible at that, then you have Job object notifications which need their own IOCP. I wish that more if not all notifications and continuations were posted to the default thread pool. I know that several Win32 functions like GetAddrInfoEx are doing this.

  • Kalle Niemitalo

    If you suppress the background thread, then how does GDI+ decide which thread should create the notification window?

    Is it the thread that calls GdiplusStartup? However, the same thread is not required to call GdiplusShutdown, and the documentation does not say that the thread even needs to be kept alive.

    Is it the thread that calls NotificationHook? However, you described that GDI+ created the notification window even though the application failed to call NotificationHook.

    This reminds me about SCardAccessStartedEvent, which used to create a window owned by thread that first called it, and started failing with ERROR_INVALID_WINDOW_HANDLE if that thread terminated. IIRC, it was corrected in Vista so that the function no longer relies on window messages.