{"id":21353,"date":"2008-08-06T10:00:00","date_gmt":"2008-08-06T10:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2008\/08\/06\/whats-with-this-msh_mousewheel-message\/"},"modified":"2008-08-06T10:00:00","modified_gmt":"2008-08-06T10:00:00","slug":"whats-with-this-msh_mousewheel-message","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20080806-00\/?p=21353","title":{"rendered":"What&#8217;s with this MSH_MOUSEWHEEL message?"},"content":{"rendered":"<p><P>\nThe hardware folks had this mouse wheel thing they were making,\nand they needed a way to get applications to support the mouse.\nNow, one way of doing this was to say,\n&#8220;Well, we&#8217;ll start selling this wheel mouse,\nbut no applications can use it until the next version of Windows\nis released, one that supports the wheel.&#8221;\nOf course, that would have meant waiting until Windows&nbsp;NT&nbsp;4\ncame out, and who know when that would be.\nPlus it meant that people would have to upgrade Windows\nin order to take advantage of their fancy new mouse.\nAs you can imagine, they weren&#8217;t too pleased with the\n&#8220;wait a few years&#8221; plan.\n<\/P>\n<P>\nIn the interim, they proposed a stopgap mechanism for applications\nto respond to the mouse wheel.\nEnter the <CODE>zmouse.h<\/CODE> header file and its\n<CODE>MSH_MOUSEWHEEL<\/CODE> registered message.\nWhen you installed the wheel mouse driver,\nit listened for wheel events from the hardware and posted\nthis new message when the mouse wheel turned,\nand applications could just respond to either\nthe <CODE>WM_MOUSEWHEEL<\/CODE> message\n(if running on a version of Windows that supported the message)\nor the <CODE>MSH_MOUSEWHEEL<\/CODE> message\n(if running on an older version of Windows that didn&#8217;t).\nUnfortunately, the two messages behave differently,\nso it&#8217;s not a simple matter of writing\n<\/P>\n<PRE>\nif (uMsg == WM_MOUSEWHEEL || uMsg == g_msgWheel) {\n &#8230; do wheel stuff &#8230;\n}\n<\/PRE>\n<P>\n(These next few paragraphs summarize what is\n<A HREF=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/ms645617.aspx\">\nalready spelled out in MSDN<\/A>;\nyou can skip them if you already know how the messages work.)\n<\/P>\n<P>\nFirst, let&#8217;s look at <CODE>WM_MOUSEWHEEL<\/CODE>.\nThis message is delivered to the window that has focus\n(in the <CODE>SetFocus<\/CODE> sense).\nIf the window procedure doesn&#8217;t handle the message\nand just passes it through to the <CODE>DefWindowProc<\/CODE> function,\nthen the <CODE>DefWindowProc<\/CODE> function forward the message\nto the window&#8217;s parent.\nIn this way, the <CODE>WM_MOUSEWHEEL<\/CODE> message\nautomatically &#8220;bubbles outward&#8221; from the focus window\nup the parent chain until somebody finally handles the\nmessage (or it goes all the way to the top without being handled at all).\n<\/P>\n<P>\nOn the other hand, the <CODE>MSH_MOUSEWHEEL<\/CODE> message\nworks from the outside in.\nIt is delivered to the foreground window\n(in the <CODE>SetForegroundWindow<\/CODE> sense).\nIf the window procedure doesn&#8217;t want to handle the message,\nit can forward the message to child windows of its choice,\nuntil one of them returns <CODE>TRUE<\/CODE> to indicate that\nthe message was handled, or until no further candidates exist.\n<\/P>\n<P>\nI&#8217;ll summarize these differences in a table,\nsince people seem to like tables so much.\n<\/P>\n<TABLE BORDER=\"1\" CELLPADDING=\"3\" CELLSPACING=\"0\" STYLE=\"border: 0pt;border-collapse: collapse\">\n<TR><TH><\/TH>\n    <TH>WM_MOUSEWHEEL<\/TH>\n    <TH>MSH_MOUSEWHEEL<\/TH><\/TR>\n<TR><TD>Propagation direction<\/TD>\n    <TD>Inside-out<\/TD>\n    <TD>Outside-in<\/TD><\/TR>\n<TR><TD>Propagation mechanism<\/TD>\n    <TD>DefWindowProc<\/TD>\n    <TD>SendMessage<\/TD><\/TR>\n<TR><TD>Handling<\/TD>\n    <TD>Automatic<\/TD>\n    <TD>Manual: Application checks return value<BR>\n    from child to determine what to do next<\/TD><\/TR>\n<TR><TD>Return value if processed<\/TD>\n    <TD>Zero<\/TD>\n    <TD>TRUE<\/TD><\/TR>\n<TR><TD>Return value if not processed<\/TD>\n    <TD>DefWindowProc<\/TD>\n    <TD>FALSE<\/TD><\/TR>\n<\/TABLE>\n<P>\nNotice that <CODE>WM_MOUSEWHEEL<\/CODE> is much simpler,\nand the inside-out propagation mechanism retains the spirit of\nother messages such\nas <CODE>WM_CONTEXTMENU<\/CODE>\nand <CODE>WM_SETCURSOR<\/CODE>.\nWhy can&#8217;t <CODE>MSH_MOUSEWHEEL<\/CODE>\ndo it the same way?\n<\/P>\n<P>\nWell, first of all, <CODE>MSH_MOUSEWHEEL<\/CODE> doesn&#8217;t have\nthe luxury of being able to modify the <CODE>DefWindowProc<\/CODE>\nfunction.\nAfter all, that&#8217;s the whole point of introducing the message\nin the first place,\nbecause we&#8217;re trying to add wheel support to an older operating\nsystem that predated mouse wheels.\nPut in other words,\nif we could modify <CODE>DefWindowProc<\/CODE> to handle the\n<CODE>MSH_MOUSEWHEEL<\/CODE> message, then we wouldn&#8217;t have\nneeded the <CODE>MSH_MOUSEWHEEL<\/CODE> message to begin with;\nwe would&#8217;ve just modified <CODE>DefWindowProc<\/CODE> to handle\nthe <CODE>WM_MOUSEWHEEL<\/CODE> message.\n<\/P>\n<P>\nThe argument in the previous paragraph is a frustratingly common one.\nGiven a problem&nbsp;X and a workaround&nbsp;Y,\nsomebody will ask,\n&#8220;Why didn&#8217;t you use method&nbsp;Z?&#8221;\nIf you look at method&nbsp;Z, though,\nyou&#8217;ll see that it suffers from the exact same problem&nbsp;X.\n<\/P>\n<P>\nHere&#8217;s a real-world example of the &#8220;confused workaround&#8221;:\n<\/P>\n<P>\n&#8220;Since the I-90 bridge is closed, I can&#8217;t take the 550 bus to get\nfrom Bellevue to Safeco Field.\nInstead, I&#8217;m going to take the 230 to Redmond, and then change\nto the 545.&#8221;\n<\/P>\n<P>\n<I>&mdash; Well, that&#8217;s silly. Why not take the 245 to Eastgate,\nand then change to the 554?\nIt&#8217;s a lot faster.<\/I>\n<\/P>\n<P>\n&#8220;Um, the 554 uses the I-90 bridge, too.&#8221;\n<\/P>\n<P>\nOkay, so you can&#8217;t change <CODE>DefWindowProc<\/CODE>,\nbut why not at least propagate the <CODE>MSH_MOUSEWHEEL<\/CODE>\nfrom the inside out instead of from the outside in?\n<\/P>\n<P>\nStarting with the focus window assumes you can even find out\nwhat the focus window is,\nbut if you had paid attention to the\n<A HREF=\"https:\/\/channel9.msdn.com\/Showpost.aspx?postid=116704\">\n<I>Five Things Every Win32 Programmer Should Know<\/I><\/A>,\nyou would have known that each thread\nhas its own focus window.\n(Not nitpickily true, but true enough.)\nConsequently, when\nthe helper program that injects <CODE>MSH_MOUSEWHEEL<\/CODE> messages\ncalls <CODE>GetFocus<\/CODE>, it just gets its own focus window,\nnot the focus window of the thread that controls the foreground window.\n(Remember, we&#8217;re talking 1996, long before the\n<CODE>GetGUIThreadInfo<\/CODE> function was invented.\nHistory buffs can find out more from\n<A HREF=\"http:\/\/www.codinghorror.com\/blog\/archives\/000865.html\">\nMeet The Inventor of the Mouse Wheel<\/A>.)\nSince inside-out was off the table,\nthat pretty much forced outside-in.\n<\/P>\n<P>\nNow that you know how mouse wheel messages work, you can explain the\nbehavior this customer is seeing:\n<\/P>\n<BLOCKQUOTE CLASS=\"q\">\nI&#8217;m seeing the <CODE>WM_MOUSEWHEEL<\/CODE> message being delivered\nto the wrong child window.\nI have a parent window with two children.\nEven though I move the mouse pointer over child&nbsp;1,\nthe <CODE>WM_MOUSEWHEEL<\/CODE> goes to child&nbsp;2.\n<\/BLOCKQUOTE><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The hardware folks had this mouse wheel thing they were making, and they needed a way to get applications to support the mouse. Now, one way of doing this was to say, &#8220;Well, we&#8217;ll start selling this wheel mouse, but no applications can use it until the next version of Windows is released, one that [&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":[2],"class_list":["post-21353","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-history"],"acf":[],"blog_post_summary":"<p>The hardware folks had this mouse wheel thing they were making, and they needed a way to get applications to support the mouse. Now, one way of doing this was to say, &#8220;Well, we&#8217;ll start selling this wheel mouse, but no applications can use it until the next version of Windows is released, one that [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/21353","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=21353"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/21353\/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=21353"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=21353"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=21353"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}