{"id":93745,"date":"2016-06-24T07:00:00","date_gmt":"2016-06-24T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=93745"},"modified":"2019-03-13T11:51:23","modified_gmt":"2019-03-13T18:51:23","slug":"20160624-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20160624-00\/?p=93745","title":{"rendered":"Why is my message queue full of WM_TIMER messages?"},"content":{"rendered":"<p>Dmitry wondered <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2013\/05\/23\/10420741.aspx#10420954\">how it&#8217;s possible for a lot of auto-generated messages to pile up in the message queue<\/a>. I remarked, &#8220;That&#8217;s a good question, and I didn&#8217;t provide all the information necessary to answer it. Answering it will take more than two sentences, so I will toss it onto the topic queue.&#8221; <\/p>\n<p>One of my colleagues wrote to me and said, &#8220;Hey, could you bump up the priority of that topic? I happen to have a bug where COM calls are failing because the message queue is full. I wrote some diagnostic code to drain the message queue to see what was in it, and it was full of unprocessed <code>WM_TIMER<\/code> messages. There were 53 timers running at 16ms each, and the UI thread stopped processing messages for 9 seconds.&#8221; <\/p>\n<p>Back when <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2013\/06\/05\/10423678.aspx\">I explained how asynchronous input worked<\/a>, I didn&#8217;t talk about where auto-generated messages came from. <\/p>\n<p>If a request for a message is about to say, &#8220;Nope, no matching messages,&#8221; the window manager makes one last check: &#8220;Is there an auto-generated message that could satisfy this request?&#8221; If so, then it generates the message, and hey look, there&#8217;s a message! <\/p>\n<p>The catch is that auto-generated messages are grouped together. For example, if you ask for any kind of mouse message, and there is an auto-generated <code>WM_MOUSE&shy;MOVE<\/code> available, then the window manager will generate a <code>WM_MOUSE&shy;MOVE<\/code> and then check if that matches the filter you provided. The auto-generation is done this way so that message ordering is preserved within a group. You wouldn&#8217;t want a mouse-up to be generated before the corresponding mouse-down. <\/p>\n<p>The message groups can be see in functions like <code>Get&shy;Queue&shy;Status<\/code> and the <code>PM_QS_*<\/code> flags to <code>Peek&shy;Message<\/code>. <\/p>\n<p>Okay, now we&#8217;re getting closer to seeing how auto-generated messages can pile up: If you are filtering for a message, and there is an auto-generated message from the same group, but which doesn&#8217;t match your filter, then the window manager will auto-generate the message, and then go back and re-run the &#8220;Find a message&#8221; code, which sees the auto-generated message but says, &#8220;Nope, I&#8217;m not interested in that message.&#8221; <\/p>\n<p>Another piece of the puzzle is understanding the timer group. There are two messages in the timer group. One is your friend and mine, <code>WM_TIMER<\/code>. The other is an undocumented internal message known as <code>WM_SYS&shy;TIMER<\/code>. This is an alternate universe of timers used by the system to manage system things, like the animated concentric circles in the <a HREF=\"https:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/ms645601(v=vs.85).aspx#_win32_Mouse_Sonar\">Mouse Sonar<\/a> feature, deciding when to time out the system tooltips (like the one that appears when you hover over the &times; button), driving autorepeat when you click on the scroll bar, and blinking the caret in an edit control. <\/p>\n<p>The final piece of the puzzle is the COM modal message loop. This is the message loop used by COM when you call a method on an STA that needs to be marshaled. COM notifies the destination thread that it needs to run some code, and then it enters a modal message loop waiting for the destination thread to reply, &#8220;Okay, I&#8217;m done. Here&#8217;s the answer.&#8221; <\/p>\n<p>The COM message loop is a complicated beast, most likely the result of over twenty years of evolution rather than having been designed that way from the beginning. One of the things that it does is peek <code>WM_SYS&shy;TIMER<\/code> messages. Another thing that it does is dispatch timer messages, provided you passed the <code>COWAIT_DISPATCH_WINDOW_MESSAGES<\/code> flag. <\/p>\n<p>Okay, here comes the wild ride. <\/p>\n<p>COM wants to process <code>WM_SYS&shy;TIMER<\/code> messages, but not <code>WM_TIMER<\/code> messages. It therefore does a <code>Peek&shy;Message(&amp;msg, nullptr, WM_SYS&shy;TIMER, WM_SYS&shy;TIMER, PM_REMOVE)<\/code>. If there is a <code>WM_SYS&shy;TIMER<\/code> message due, then the window manager generates the <code>WM_SYS&shy;TIMER<\/code> message on the fly, puts it in the queue, and the <code>Peek&shy;Message<\/code> function returns it. That&#8217;s the good case. <\/p>\n<p>Another good case is that there is neither a <code>WM_SYS&shy;TIMER<\/code> message nor a <code>WM_TIMER<\/code> message due. In that case, the window manager generates nothing, and the <code>Peek&shy;Message<\/code> function returns &#8220;Sorry, I didn&#8217;t find anything.&#8221; <\/p>\n<p>The bad case is where there is no <code>WM_SYS&shy;TIMER<\/code> message due, <i>but there is a <code>WM_TIMER<\/code> message due<\/i>. In that case, the window manager generates the <code>WM_TIMER<\/code> message on the fly and puts it in the queue. But the <code>Peek&shy;Message<\/code> function ignores that message because it&#8217;s interested only in <code>WM_SYS&shy;TIMER<\/code> messages. <\/p>\n<p>Result: A <code>WM_TIMER<\/code> message got generated and dumped into the queue. <\/p>\n<p>Every time a <code>WM_TIMER<\/code> comes due, another <code>WM_TIMER<\/code> message gets generated and added to the queue. Eventually, your queue fills up with <code>WM_TIMER<\/code> messages. <\/p>\n<p>My colleague replied, &#8220;Thanks for the explanation. Of course, it&#8217;s COM, the Bermuda triangle of Win32!&#8221; <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Where do timer messages come from, anyway?<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-93745","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Where do timer messages come from, anyway?<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/93745","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=93745"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/93745\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=93745"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=93745"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=93745"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}