{"id":30903,"date":"2006-06-12T07:00:00","date_gmt":"2006-06-12T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2006\/06\/12\/remember-what-happens-when-you-broadcast-a-message\/"},"modified":"2006-06-12T07:00:00","modified_gmt":"2006-06-12T07:00:00","slug":"remember-what-happens-when-you-broadcast-a-message","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20060612-00\/?p=30903","title":{"rendered":"Remember what happens when you broadcast a message"},"content":{"rendered":"<p>\nOccasionally I catch people doing things like broadcasting\na <code>WM_COMMAND<\/code> message to all top-level windows.\nThis is one of those things that is so obviously wrong I don&#8217;t\nsee how people even thought to try it in the first place.\n<\/p>\n<p>\nSuppose you broadcast the message\n<\/p>\n<pre>\nSendMessage(HWND_BROADCAST, WM_COMMAND, 100, 0);\n<\/pre>\n<p>\nWhat happens?\n<\/p>\n<p>\nEvery top-level window receives the message with the same parameters,\nand every top-level window starts interpreting those parameters\nin their own idiosyncratic way.\nAs you know (since you&#8217;ve written them yourself),\neach window procedure defines its own menu items and\nchild windows and there is no guarantee that command 100\nwill mean the same thing to each window.\nA dialog box with the template\n<\/p>\n<pre>\n#define IDC_USEDEFAULT 100\n...\n    AUTORADIOBUTTON \"Use &amp;default color\",\n                    IDC_USEDEFAULT, 14, 38, 68, 10, WS_TABSTOP\n<\/pre>\n<p>\nwould interpret the message as\n<\/p>\n<table>\n<tr>\n<td>id&nbsp;<\/td>\n<td>=&nbsp;<\/td>\n<td>IDC_USEDEFAULT (100)<\/td>\n<\/tr>\n<tr>\n<td>command&nbsp;<\/td>\n<td>=&nbsp;<\/td>\n<td>BN_CLICKED (0)<\/td>\n<\/tr>\n<tr>\n<td>window&nbsp;<\/td>\n<td>=&nbsp;<\/td>\n<td>NULL (0) &mdash; illegal parameter<\/td>\n<\/tr>\n<\/table>\n<p>\nDepending on how the dialog procedure is written,\nit might try to send a message back to the button control\n(and fail since you passed <code>NULL<\/code> as the window handle),\nor it might update some dialog state like disabling the color\ncustomization controls (since it was told that the\nuser clicked the &#8220;User default color&#8221; radio button).\n<\/p>\n<p>\nAnother dialog box might have the template\n<\/p>\n<pre>\n#define IDC_CHANGE 100\n...\n    PUSHBUTTON      \"C&amp;hange\", IDC_CHANGE, 88, 95, 50, 14\n<\/pre>\n<p>\nThis dialog procedure would interpret the message as\n<\/p>\n<table>\n<tr>\n<td>id&nbsp;<\/td>\n<td>=&nbsp;<\/td>\n<td>IDC_CHANGE (100)<\/td>\n<\/tr>\n<tr>\n<td>command&nbsp;<\/td>\n<td>=&nbsp;<\/td>\n<td>BN_CLICKED (0)<\/td>\n<\/tr>\n<tr>\n<td>window&nbsp;<\/td>\n<td>=&nbsp;<\/td>\n<td>NULL (0) &mdash; illegal parameter<\/td>\n<\/tr>\n<\/table>\n<p>\nThe reaction would probably be to apply the changes\nthat were pending in the dialog.\n<\/p>\n<p>\nMeanwhile, another window might have a menu that goes like this:\n<\/p>\n<pre>\n#define IDC_REFRESH 100\n...\n        MENUITEM \"&amp;Refresh\", IDC_REFRESH\n<\/pre>\n<p>\nIt is going to interpret the message as the user having selected\n&#8220;Refresh&#8221; from the window menu.\n<\/p>\n<table>\n<tr>\n<td>id&nbsp;<\/td>\n<td>=&nbsp;<\/td>\n<td>IDC_REFRESH (100)<\/td>\n<\/tr>\n<tr>\n<td>command&nbsp;<\/td>\n<td>=&nbsp;<\/td>\n<td>0 &mdash; illegal parameter, must be 1 for menu items<\/td>\n<\/tr>\n<tr>\n<td>window&nbsp;<\/td>\n<td>=&nbsp;<\/td>\n<td>NULL (0)<\/td>\n<\/tr>\n<\/table>\n<p>\nNot only is the command code invalid for a menu item,\nthe window might be in a state where the program had disabled\nthe &#8220;Refresh&#8221; option.\nYet you sent the window a message as if to say that the user\nselected it anyway,\nwhich is impossible.\nCongratulations, you just presented the program with an impossible\nsituation and it very well may crash as a result.\nFor example, the program may have disabled the &#8220;Refresh&#8221; option\nsince there is no current object to refresh.\nWhen you send it the &#8220;Refresh&#8221; command, it will try to refresh\nthe current object and crash with a null pointer error.\n<\/p>\n<p>\nObviously, then, you cannot broadcast the <code>WM_COMMAND<\/code>\nmessage since there is no universal meaning for any of the command IDs.\nA command ID that means &#8220;Refresh&#8221; to one window might mean &#8220;Change&#8221;\nto another.\n<\/p>\n<p>\nThe same logic applies to nearly all of the standard Windows messages.\nThe ones that are actually designed to be broadcast are as follows:\n<\/p>\n<table>\n<tr>\n<td>WM_SYSCOLORCHANGE<\/td>\n<\/tr>\n<tr>\n<td>WM_SETTINGCHANGE (= WM_WININICHANGE)<\/td>\n<\/tr>\n<tr>\n<td>WM_DEVMODECHANGE<\/td>\n<\/tr>\n<tr>\n<td>WM_FONTCHANGE<\/td>\n<\/tr>\n<tr>\n<td>WM_TIMECHANGE<\/td>\n<\/tr>\n<tr>\n<td>WM_DDE_INITIATE<\/td>\n<\/tr>\n<\/table>\n<p>\nIf you try to broadcast a message in the\n<code>WM_USER<\/code> or <code>WM_APP<\/code> ranges,\nthen you&#8217;re even crazier than I thought.\nAs we&#8217;ve already seen,\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2003\/12\/02\/55914.aspx\">\nthe meaning of window messages in those ranges are defined\nby the window class or the application that created the window<\/a>.\nNot only are the parameters to the message context-sensitive,\nthe message itself is!\nThis means that sending a random window a <code>WM_USER+1<\/code> message\n(say) will result in extremely random behavior.\n(We saw this before\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2004\/05\/05\/126427.aspx\">\nin the context of broadcasts<\/a>, but it applies to directed delivery, too.)\nIf it&#8217;s a dialog box, it will think you sent a\n<code>DM_SETDEFID<\/code> message, and you just changed that dialog&#8217;s\ndefault ID.\nIf it&#8217;s a common dialog box, it will think you sent a\n<code>WM_CHOOSEFONT_GETLOGFONT<\/code> message,\nand if you&#8217;re lucky, it will crash trying to return the\n<code>LOGFONT<\/code> through an invalid pointer.\n(If you&#8217;re not lucky, the parameter you passed will happen to be\na valid pointer and the program will merely corrupt its own memory\nin some strange way, only to behave erratically later on.)\nIf it&#8217;s a tooltip control, then you just sent it the\n<code>TTM_ACTIVATE<\/code> message and you just manipulated\nthe tooltip&#8217;s activation state.\n<\/p>\n<p>\nThe same caution applies, using the same logic, to\nsending messages without universal meaning to windows\nwhose window class you do not have an interface contract with.\nFor example, I&#8217;ll see people sending the\n<code>PSM_PRESSBUTTON<\/code> message to a window on the\nblind-faith assumption that it is a property sheet.\n<\/p>\n<p>\nRemember, then, that when you send a message to a window,\nyou need to be sure that\nthe window will interpret it in the manner you intend.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Occasionally I catch people doing things like broadcasting a WM_COMMAND message to all top-level windows. This is one of those things that is so obviously wrong I don&#8217;t see how people even thought to try it in the first place. Suppose you broadcast the message SendMessage(HWND_BROADCAST, WM_COMMAND, 100, 0); What happens? Every top-level window receives [&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-30903","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Occasionally I catch people doing things like broadcasting a WM_COMMAND message to all top-level windows. This is one of those things that is so obviously wrong I don&#8217;t see how people even thought to try it in the first place. Suppose you broadcast the message SendMessage(HWND_BROADCAST, WM_COMMAND, 100, 0); What happens? Every top-level window receives [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/30903","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=30903"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/30903\/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=30903"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=30903"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=30903"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}