{"id":17843,"date":"2009-06-18T10:00:00","date_gmt":"2009-06-18T10:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2009\/06\/18\/the-dangers-of-mixing-synchronous-and-asynchronous-state\/"},"modified":"2009-06-18T10:00:00","modified_gmt":"2009-06-18T10:00:00","slug":"the-dangers-of-mixing-synchronous-and-asynchronous-state","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20090618-00\/?p=17843","title":{"rendered":"The dangers of mixing synchronous and asynchronous state"},"content":{"rendered":"<p><P>\nThe window manager distinguishes between synchronous state\n(the state of the world based on what messages your program\nhas received)\nand asynchronous state (the actual state of the world this very instant).\nWe saw this earlier when discussing\n<A HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2004\/11\/30\/272262.aspx\">\nthe difference between <CODE>GetKeyState<\/CODE> and\n<CODE>GetAsyncKeyState<\/CODE><\/A>.\nHere are some other functions and their relationship to the queue state:\n<\/P>\n<TABLE BORDER=\"1\" RULES=\"all\" STYLE=\"border-collapse: collapse\">\n<TR><TH>Use synchronous state<\/TH>\n    <TH>Use asynchronous state<\/TH><\/TR>\n<TR><TD><CODE>GetActiveWindow<\/CODE><\/TD>\n    <TD><CODE>GetForegroundWindow<\/CODE><\/TD><\/TR>\n<TR><TD><CODE>GetMessagePos<\/CODE><\/TD>\n    <TD><CODE>GetCursorPos<\/CODE><\/TD><\/TR>\n<TR><TD><CODE>GetMessageTime<\/CODE><\/TD>\n    <TD><CODE>GetTickCount<\/CODE><\/TD><\/TR>\n<\/TABLE>\n<P>\nIf you query the asynchronous state while processing a message,\nyou can find yourself caught in a race condition,\nbecause the synchronous state of the system when the message was generated\nmay not match the asynchronous state of the system when you receive it.\nFor example, if the users presses a key, and then moves the mouse,\ncalling <CODE>GetCursorPos<\/CODE> from your keypress handler\nwill tell you were the cursor is right now,\nwhich is not the same as where the cursor was when the key was pressed.\n<\/P>\n<P>\nGenerally speaking, you should use the synchronous state during message\nhandling so that you react to the state of the system at the time the\ninput event took place.\nReacting to the asynchronous state of the system introduces race\nconditions if there is a change to the system state between the time\nthe message was generated and the time the message is processed.\n<\/P>\n<P>\nOf the above functions, <CODE>GetTickCount<\/CODE> is the only one\nI can think of that has a legitimate usage pattern in common use,\nnamely, when creating timing loops.\nBut if you want to know what time it was when\na key was pressed, then\n<CODE>GetMessageTime<\/CODE> is the function to use.\n<\/P>\n<P>\nThis is all a rather length lead-in for my remarks regarding\na comment claiming that\n<A HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2008\/05\/23\/8535427.aspx#8550623\">\nthere is no practical reason why you can&#8217;t use\n<CODE>GetForegroundWindow<\/CODE> to determine which window\nwas the one that had focus when a keyboard message was generated<\/A>.\nWell, actually, there is, and it&#8217;s precisely the race condition\nI&#8217;ve spent most of this article describing.\nSuppose the user presses a key\nand then switches to another program.\nNow your program gets around to processing the keyboard input,\nand you call <CODE>GetForegroundWindow<\/CODE>,\nand instead of getting a window from your application,\nyou get some other window from another program.\nYou then pass that window handle to <CODE>TranslateAccelerator<\/CODE>,\nthe keyboard event matches an entry in the accelerator,\nand boom, you just sent a random <CODE>WM_COMMAND<\/CODE> message\nto a program that will interpret it to mean something completely\ndifferent.\n<\/P>\n<P>\nRemember, just because your program has the line\n<\/P>\n<PRE>\n#define IDC_REFRESH    814\n<\/PRE>\n<P>\ndoesn&#8217;t mean that another program can&#8217;t have the line\n<\/P>\n<PRE>\n#define IDC_DELETEALL  814\n<\/PRE>\n<P>\nNow the user presses <CODE>F5<\/CODE> and switches from your program\nto that other program.\nYour program processes the message, queries the <I>asynchronous<\/I>\nforeground state with <CODE>GetForegroundWindow<\/CODE>, and gets\nthat other program&#8217;s window back.\nYou then translate the accelerator, and <CODE>TranslateAccelerator<\/CODE>\nposts the <CODE>WM_COMMAND(814)<\/CODE> message to that other program,\nwhich interprets it as &#8220;delete all&#8221;.\n<\/P>\n<P>\nThe great thing about this is that the users will probably blame the\nother program.\n&#8220;Sometimes, when I use this program, it spontaneously deletes all my\nitems.\nStupid program.\nIt&#8217;s so buggy.&#8221;\n<\/P>\n<P>\nCommenter poenits correctly points out that\n<A HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2008\/05\/23\/8535427.aspx#8545605\">\nI failed to take into account the case where the message is posted\ndirectly to the dialog<\/A>.\n(The dialog manager tries not to put keyboard focus on the dialog itself,\nbut if you play weird games, you can find yourself backed into that\nsituation, such as if you delete all the controls on a dialog!)\nThe fix, however, is not to translate the message directly to the\nwindow with keyboard focus, because the window with keyboard focus\nmight belong to a <I>third<\/I> dialog that you don&#8217;t want to translate\naccelerators for.\n(That other window might have used the other header file which defines\nmessage 814 to be <CODE>IDC_DELETEALL<\/CODE>.)\nJust check for your specific window directly:\n<\/P>\n<PRE>\nif (hwnd1== msg.hwnd || IsChild(hwnd1, msg.hwnd))\n    TranslateAccelerator(hwnd1, hAccel, &amp;msg);\nelse if (hwnd2 == msg.hwnd || IsChild(hwnd2, msg.hwnd))\n    TranslateAccelerator(hwnd2, hAccel, &amp;msg);\n<\/PRE>\n<P>\nThink of <CODE>TranslateAccelerator<\/CODE> as\n<CODE>MaybePostWM_COMMAND<\/CODE>.\nThe first parameter to <CODE>TranslateAccelerator<\/CODE> must\nbe a window you are certain knows how to\ninterpret the <CODE>WM_COMMAND<\/CODE> message that you might\nend up posting.\nYou know which windows understand your custom <CODE>WM_COMMAND<\/CODE>\nmessages.\nPass one of those known windows, not some random unknown window that\nyou calculated from unknown sources.\n<\/P>\n<P>\nPassing an unknown window as the first parameter to\n<CODE>TranslateAccelerator<\/CODE>\nis like\nfalling for one of those phishing scams.\nIf you get a random piece of email telling you &#8220;Hey, call this\nnumber and give me your personal information,&#8221;\nyou&#8217;re not going to do it.\nIf you really want to contact your bank,\nyou ignore the phone number in the email\nand just call the number you know and trust to be your bank&#8217;s\nservice desk.\nSimilarly, you shouldn&#8217;t be posting your personal messages to \nsome random window you receive.\nPost it to the known trusted window.\nOtherwise you&#8217;re just sending your money\nto some unknown recipient in Nigeria.\n<\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The window manager distinguishes between synchronous state (the state of the world based on what messages your program has received) and asynchronous state (the actual state of the world this very instant). We saw this earlier when discussing the difference between GetKeyState and GetAsyncKeyState. Here are some other functions and their relationship to the queue [&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-17843","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The window manager distinguishes between synchronous state (the state of the world based on what messages your program has received) and asynchronous state (the actual state of the world this very instant). We saw this earlier when discussing the difference between GetKeyState and GetAsyncKeyState. Here are some other functions and their relationship to the queue [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/17843","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=17843"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/17843\/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=17843"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=17843"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=17843"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}