{"id":43463,"date":"2014-12-05T07:00:00","date_gmt":"2014-12-05T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2014\/12\/05\/killing-a-window-timer-prevents-the-wm_timer-message-from-being-generated-for-that-timer-but-it-doesnt-retroactively-remove-ones-that-were-already-generated\/"},"modified":"2014-12-05T07:00:00","modified_gmt":"2014-12-05T07:00:00","slug":"killing-a-window-timer-prevents-the-wm_timer-message-from-being-generated-for-that-timer-but-it-doesnt-retroactively-remove-ones-that-were-already-generated","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20141205-00\/?p=43463\/","title":{"rendered":"Killing a window timer prevents the WM_TIMER message from being generated for that timer, but it doesn&#039;t retroactively remove ones that were already generated"},"content":{"rendered":"<p>\nCalling\n<code>Kill&shy;Timer<\/code>\nto cancel a window timer\nprevents <code>WM_TIMER<\/code> messages from being\ngenerated for that timer,\neven if one is overdue.\nIn other words,\ngive this sequence of operations:\n<\/p>\n<pre>\nSetTimer(hwnd, IDT_MYTIMER, 1000, NULL);\nSleep(2000);\nKillTimer(hwnd, IDT_MYTIMER);\n<\/pre>\n<p>\nno <code>WM_TIMER<\/code> message is ever generated.\nEven though a timer became due during the <code>Sleep<\/code>,\nno timer message was generated during the sleep\nbecause timer messages are generated on demand,\nand nobody demanded one.\nKilling the timer then removes the ability to demand a timer\nmessage,\nand the result is that no message ever appears.\n<\/p>\n<p>\nIn general, this means that\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2014\/12\/04\/10577881.aspx\">\nonce you kill a timer,\nyou will not receive any <code>WM_TIMER<\/code> messages\nfor that timer<\/a>.\n<\/p>\n<p>\nUnless you\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2013\/05\/23\/10420741.aspx\">\ndemanded one while the timer was active and didn&#8217;t process it<\/a>.\n<\/p>\n<p>\nLet&#8217;s try a variation:\n<\/p>\n<pre>\nSetTimer(hwnd, IDT_MYTIMER, 1000, NULL);\nSleep(2000);\nif (PeekMessage(&amp;msg, NULL, WM_TIMER, WM_TIMER, 0)) {\n DispatchMessage(&amp;msg);\n}\nKillTimer(hwnd, IDT_MYTIMER);\n<\/pre>\n<p>\nIn this case, the <code>Peek&shy;Message<\/code> function\nlooks for a <code>WM_TIMER<\/code> message in the queue,\nand if none is found, it asks for one to be generated on the fly\nif a timer is due.\nIt so happens that one is due (<code>IDT_MY&shy;TIMER<\/code>),\nso the <code>Peek&shy;Message<\/code> causes a\n<code>WM_TIMER<\/code> to be generated and placed in the queue.\nBut it doesn&#8217;t remain in this state for long, because\nthe message is removed from the queue by the\n<code>Peek&shy;Message<\/code> function.\n<\/p>\n<p>\nOkay, now let&#8217;s make things weird:\n<\/p>\n<pre>\nSetTimer(hwnd, IDT_MYTIMER, 1000, NULL);\nSleep(2000);\nif (PeekMessage(&amp;msg, NULL, WM_TIMER, WM_TIMER, <font COLOR=\"blue\">PM_NOREMOVE<\/font>)) {\n \/\/ oh hey there is an overdue timer, how about that\n}\nKillTimer(hwnd, IDT_MYTIMER);\n<\/pre>\n<p>\nThis time, we passed the\n<code>PM_NO&shy;REMOVE<\/code> flag.\nThe window manager goes through the same process as before,\nfirst looking for a <code>WM_TIMER<\/code> message in the queue,\nand then failing to find one,\ngenerates one on the fly since the <code>IDT_MY&shy;TIMER<\/code>\ntimer is overdue.\nBut the\n<code>PM_NO&shy;REMOVE<\/code> flag makes things weird\nbecause it says,\n&#8220;Thanks for generating that message for me.\nBut don&#8217;t remove it from the queue.\nLeave it there.\nI&#8217;ll deal with it later.&#8221;\n<\/p>\n<p>\nYou might do this if you want to stop processing\nif a timer elapses,\nbut you don&#8217;t want to handle the timer immediately because you are in\nsome sensitive state at the point you realize that you need to stop processing.\nInstead, you want to return back out to the main message loop and let it\ndeal with the timer.\n<\/p>\n<pre>\nBOOL DoWorkUntilTheNextTimer()\n{\n BOOL fFinished = FALSE;\n MSG msg;\n PrepareToDoWork();\n while (!PeekMessage(&amp;msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE)) {\n  if (AnyWorkLeft()) DoSomeWork();\n  else { fFinished = TRUE; break; }\n }\n CleanUpAfterDoingWork();\n return fFinished;\n}\n<\/pre>\n<p>\nAnd then you might call it like this:\n<\/p>\n<pre>\nvoid DoWorkForUpToOneSecond()\n{\n SetTimer(hwnd, IDT_MYTIMER, 1000, NULL);\n DoWorkUntilTheNextTimer();\n KillTimer(hwnd, IDT_MYTIMER);\n}\n<\/pre>\n<p>\nThe\n<code>Kill&shy;Timer<\/code> will prevent any new\ntimer messages from being generated for\n<code>IDT_MY&shy;TIMER<\/code>,\nbut it does not go back in time and retroactively\nun-generate the timer message that was generated\nwhen\n<code>Do&shy;Work&shy;Until&shy;The&shy;Next&shy;Timer<\/code>\nasked to see if there were any timer messages.\n<\/p>\n<p>\nYou are now in the strange situation where\na subsequent\ncall to <code>Peek&shy;Message<\/code> or\n<code>Get&shy;Message<\/code>\nwill retrieve a timer message for a timer that is no longer active!\n<\/p>\n<p>\nThis is captured in the MSDN documentation with the simple\nsentence,\n&#8220;The <b>Kill&shy;Timer<\/b> function does not remove\n<code>WM_TIMER<\/code> messages already posted to the message queue.&#8221;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Calling Kill&shy;Timer to cancel a window timer prevents WM_TIMER messages from being generated for that timer, even if one is overdue. In other words, give this sequence of operations: SetTimer(hwnd, IDT_MYTIMER, 1000, NULL); Sleep(2000); KillTimer(hwnd, IDT_MYTIMER); no WM_TIMER message is ever generated. Even though a timer became due during the Sleep, no timer message was [&hellip;]<\/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-43463","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Calling Kill&shy;Timer to cancel a window timer prevents WM_TIMER messages from being generated for that timer, even if one is overdue. In other words, give this sequence of operations: SetTimer(hwnd, IDT_MYTIMER, 1000, NULL); Sleep(2000); KillTimer(hwnd, IDT_MYTIMER); no WM_TIMER message is ever generated. Even though a timer became due during the Sleep, no timer message was [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/43463","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=43463"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/43463\/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=43463"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=43463"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=43463"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}