{"id":32093,"date":"2006-03-02T10:00:10","date_gmt":"2006-03-02T10:00:10","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2006\/03\/02\/restating-the-obvious-about-the-wm_command-message\/"},"modified":"2006-03-02T10:00:10","modified_gmt":"2006-03-02T10:00:10","slug":"restating-the-obvious-about-the-wm_command-message","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20060302-10\/?p=32093","title":{"rendered":"Restating the obvious about the WM_COMMAND message"},"content":{"rendered":"<p>\nI&#8217;m satisfied with the MSDN documentation for\n<a HREF=\"http:\/\/msdn.microsoft.com\/library\/en-us\/winui\/winui\/windowsuserinterface\/resources\/menus\/menureference\/menumessages\/wm_command.asp\">\nthe <code>WM_COMMAND<\/code> message<\/a>,\nbut for the sake of mind-numbing completeness,\nI&#8217;m going to state the obvious in the hope that you,\ndear readers, can use this technique to\nfill in the obvious in other parts of MSDN.\n<\/p>\n<p>\nThe one-line summary of the <code>WM_COMMAND<\/code> message\nsays,\n&#8220;The WM_COMMAND message is sent when the user selects\na command item from a menu,\nwhen a control sends a notification message to its parent window,\nor when an accelerator keystroke is translated.&#8221;\nIn a nutshell, there are three scenarios that generate a\n<code>WM_COMMAND<\/code> message, namely the three listed above.\nYou want to think of the menu and accelerator scenarios of the\n<code>WM_COMMAND<\/code> message as special cases of the control scenario.\n<\/p>\n<p>\nThe high-order word of the <code>wParam<\/code> parameter\n&#8220;specifies the notification code if the message is from a control&#8221;.\nWhat does &#8220;control&#8221; mean here?\nRemember that you have to take things in context.\nThe <code>WM_COMMAND<\/code> message is being presented in the\ncontext of Win32 in general, and in the context of the window manager\nin particular.\nWindows such as edit boxes, push buttons, and list boxes\nare commonly called &#8220;controls&#8221;, as are all the window classes\nin the &#8220;common controls library&#8221;.\nIn the world of the window manager, a &#8220;control&#8221; is a window\nwhose purpose is to provide some degree of interactivity\n(which, in the case of the static control, might be no interactivity at all)\nin the service of its parent window.\nThe fact that the <code>WM_COMMAND<\/code> is used primarily\nin the context of dialog boxes further emphasizes the point\nthat the term &#8220;control&#8221; here is just a synonym for &#8220;child window&#8221;.\n<\/p>\n<p>\nWhat does &#8220;notification code&#8221; mean here?\nControl notification codes are arbitrary 16-bit values defined\nby the control itself.\nBy convention, they are named <code>xxN_xxxx<\/code>, where the &#8220;N&#8221;\nstands for &#8220;notification&#8221;.\nBe careful, however, not to confuse this with notification codes\nassociated with the <code>WM_NOTIFY<\/code> message.\nFortunately, every notification code specifies in its documentation\nwhether it arrives as a <code>WM_COMMAND<\/code> notification or\na <code>WM_NOTIFY<\/code> notification.\nA modern control designer is more likely to use\n<code>WM_NOTIFY<\/code> notifications since they allow\nadditional information to be passed with the notification.\nThe <code>WM_COMMAND<\/code> message, by comparison, passes\nonly the notification itself; the other parameters to\nthe <code>WM_COMMAND<\/code> message are forced, as we&#8217;ll see below.\nIf <code>WM_NOTIFY<\/code> is superior to <code>WM_COMMAND<\/code>,\nwhy do some controls use <code>WM_COMMAND<\/code>?\nBecause <code>WM_NOTIFY<\/code> wasn&#8217;t available until\nWindows&nbsp;95.\nControls that were written prior to Windows&nbsp;95 had to\ncontent themselves with the <code>WM_COMMAND<\/code> message.\n<\/p>\n<p>\n&#8220;If the message is from an accelerator, this value [the high-order\nword of the <code>wParam<\/code> parameter] is 1.&#8221;\nRemember, we&#8217;re still in the context of the window manager,\nand particular in the context of the <code>WM_COMMAND<\/code>\nmessage.\nThe accelerator here refers to messages generated by the call to\n<code>TranslateAccelerator<\/code> in the message loop.\n<\/p>\n<p>\n&#8220;If the message is from a menu, this value is zero.&#8221;\nIf the <code>WM_COMMAND<\/code> mesage was triggered by\nthe user selecting an item from a menu, then the high-order\nword of the <code>wParam<\/code> is zero.\n<\/p>\n<p>\nThe low-order word of the <code>wParam<\/code> parameter\n&#8220;specifies the identifier of the menu item, control, or\naccelerator.&#8221;\nThe identifier of a menu item or accelerator\nis the command code you associated\nwith it in your menu or accelerator template or (in the case of a menu item)\nwhen you manually created the menu item with a function like\n<code>InsertMenuItem<\/code>.\n(You probably named your menu item identifiers and accelerator\nidentifiers <code>IDM_something<\/code>.)\nThe identifier of a control is determined by the creator of the\ncontrol; recall that the\n<code>hMenu<\/code> parameter to the <code>CreateWindow<\/code>\nand <code>CreateWindowEx<\/code> functions is treated as a child\nwindow identifier if you&#8217;re creating a child window.\nIt is that identifier that the control identifier.\n(You can retrieve the identifier for a control by calling the\n<code>GetDlgCtrlID<\/code> function.)\n<\/p>\n<p>\nFinally, the <code>lParam<\/code> parameter is the\n&#8220;handle to the control sending the message if the message is from a control.\nOtherwise, this parameter is NULL.&#8221;\nIf the notification is generated by a child window\n(with a notification code appropriate for that child window, obviously),\nthen that child window handle is passed as the <code>lParam<\/code>.\nIf the notification is generated by an accelerator or a menu,\nthen the <code>lParam<\/code> is zero.\n<\/p>\n<p>\nNotice that nearly all of the parameters to the\n<code>WM_COMMAND<\/code> message are forced, once you&#8217;ve decided\nwhat notification you&#8217;re generating.\n<\/p>\n<p>\nIf you are generating a notification from a control,\nyou must pass the notification code in the high word of the\n<code>wParam<\/code>, the control identifier in the low word\nof the <code>wParam<\/code>, and the control handle as the\n<code>lParam<\/code>.\nIn other words, once you&#8217;ve decided that the\n<code>hwndC<\/code> window wants to send a\n<code>CN_READY<\/code> notification, you have no choice but\nto type\n<\/p>\n<pre>\nSendMessage(GetParent(hwndC), WM_COMMAND,\n            MAKEWPARAM(GetDlgCtrlID(hwndC), CN_READY),\n            (LPARAM)hwndC);\n<\/pre>\n<p>\nIn other words, all control notifications take the form\n<\/p>\n<pre>\nSendMessage(GetParent(hwndC), WM_COMMAND,\n            MAKEWPARAM(GetDlgCtrlID(hwndC), notificationCode),\n            (LPARAM)hwndC);\n<\/pre>\n<p>\nwhere <code>hwndC<\/code> is the control generating the notification\nand <code>notificationCode<\/code> is the notification code.\nOf course, you can use <code>PostMessage<\/code> instead of\n<code>SendMessage<\/code> if you would rather post the notification\nrather than sending it.\n<\/p>\n<p>\nThe other two cases (accelerators and menus) are not cases you\nwould normally code up, since you typically let the\n<code>TranslateAccelerator<\/code> function deal with accelerators\nand let the menu system deal with menu identifiers.\nBut if for some reason, you wanted to pretend that the user\nhad typed an accelerator or selected a menu item, you can generate\nthe notification manually by following the rules set out in the\ndocumentation.\n<\/p>\n<pre>\n\/\/ simulate the accelerator IDM_WHATEVER\nSendMessage(hwnd, WM_COMMAND,\n            MAKEWPARAM(IDM_WHATEVER, 1),\n            0);\n<\/pre>\n<p>\nHere, <code>hwnd<\/code> is the window that you want to pretend was\nthe window passed to the <code>TranslateAccelerator<\/code> function,\nand <code>IDM_WHATEVER<\/code> is the accelerator identifier.\n<\/p>\n<p>\nSimulating a menu selection is exactly the same, except that\n(according to the rules above), you set the high-order word of\nthe <code>wParam<\/code> to zero.\n<\/p>\n<pre>\n\/\/ simulate the menu item IDM_WHATEVER\nSendMessage(hwnd, WM_COMMAND,\n            MAKEWPARAM(IDM_WHATEVER, 0),\n            0);\n<\/pre>\n<p>\nHere, <code>hwnd<\/code> is the window associated with the menu.\nA window can be associated with a menu either by being created\nwith the menu (having passed the menu handle to the\n<code>CreateWindow<\/code> or <code>CreateWindowEx<\/code> function\nexplicitly, or having it done implicitly by including it with the\nclass registration) or by having been passed explicitly as\nthe window parameter to a function like\n<code>TrackPopupWindow<\/code>.\n<\/p>\n<p>\nOne significant difference between the accelerator\/menu case\nand the control notification case is that accelerator and menu\nidentifiers are defined by the calling application,\nwhereas control notifications are defined by the control.\n<\/p>\n<p>\nYou may have noticed the opportunity to &#8220;pun&#8221;\nthe control notification codes.\nIf a control defines a notification code as zero, then it will\n&#8220;look like&#8221; a menu item selection, since the high-order word\nof the <code>wParam<\/code> in the case of a menu item selection\nis zero.\nThe button control takes advantage of this pun:\n<\/p>\n<pre>\n#define BN_CLICKED          0\n<\/pre>\n<p>\nThis means that when the user clicks a button control,\nthe <code>WM_COMMAND<\/code> message that is generated\n&#8220;smells like&#8221; a menu selection notification.\nYou probably take advantage of this in your dialog procedure\nwithout even realizing it.\n<\/p>\n<p>\n(The static control also takes advantage of this pun:\n<\/p>\n<pre>\n#define STN_CLICKED         0\n<\/pre>\n<p>\nbut in order for the static control to generate the\n<code>STN_CLICKED<\/code> notification,\nyou have to set the <code>SS_NOTIFY<\/code> style.)\n<\/p>\n<p>\nI stated at the start that the accelerator and menu scenarios\nare just special cases of the control scenario.\nIf you take the pieces of the <code>WM_COMMAND<\/code> message\napart, you&#8217;ll see that they fall into two categories:\n<\/p>\n<ul>\n<li>What happened? (Notification code.)\n<li>Whom did it happen to? (Control handle and ID.)\n<\/ul>\n<p>\nIn the case of a menu or an accelerator, the &#8220;What happened?&#8221;\nis &#8220;The user clicked on the menu (0)&#8221; or\n&#8220;The user typed the accelerator (1)&#8221;.\nThe &#8220;Whom did it happen to?&#8221; is &#8220;This menu ID&#8221; or &#8220;This accelerator ID&#8221;.\nSince the notification is not coming from a control, the control\nhandle is <code>NULL<\/code>.\n<\/p>\n<p>\nI apologize to all you Win32 programmers for whom\nthis is just stating the obvious.\n<\/p>\n<p>\nNow that you&#8217;re an expert on the <code>WM_COMMAND<\/code> message,\nperhaps you can solve\n<a HREF=\"http:\/\/groups.google.com\/group\/comp.os.ms-windows.programmer.win32\/msg\/9d4372f762ad5c68\">\nthis person&#8217;s problem<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;m satisfied with the MSDN documentation for the WM_COMMAND message, but for the sake of mind-numbing completeness, I&#8217;m going to state the obvious in the hope that you, dear readers, can use this technique to fill in the obvious in other parts of MSDN. The one-line summary of the WM_COMMAND message says, &#8220;The WM_COMMAND message [&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-32093","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>I&#8217;m satisfied with the MSDN documentation for the WM_COMMAND message, but for the sake of mind-numbing completeness, I&#8217;m going to state the obvious in the hope that you, dear readers, can use this technique to fill in the obvious in other parts of MSDN. The one-line summary of the WM_COMMAND message says, &#8220;The WM_COMMAND message [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/32093","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=32093"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/32093\/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=32093"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=32093"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=32093"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}