{"id":17033,"date":"2009-08-21T10:00:00","date_gmt":"2009-08-21T10:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2009\/08\/21\/restating-the-obvious-about-the-wm_notify-message\/"},"modified":"2009-08-21T10:00:00","modified_gmt":"2009-08-21T10:00:00","slug":"restating-the-obvious-about-the-wm_notify-message","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20090821-00\/?p=17033","title":{"rendered":"Restating the obvious about the WM_NOTIFY message"},"content":{"rendered":"<p>\nIt appears that people seemed to appreciate\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2006\/03\/02\/542115.aspx\">\nrestating the obvious about the <code>WM_COMMAND<\/code> message<\/a>,\nso I&#8217;ll try it again with the <code>WM_NOTIFY<\/code> message.\n<\/p>\n<p>\nThe <code>WM_NOTIFY<\/code> message is typically used by a control\nto communicate with its parent,\neither to provide information, request it, or both.\nAlthough that is the typical use,\nthere are exceptions.\nFor example, property sheets send the <code>WM_NOTIFY<\/code>\nto their <i>children<\/i>.\nProperty sheets are this sort-of backwards model,\nwhere the common controls provide the parent window (the property sheet)\nand applications provide the child windows (the property sheet pages).\nThe window manager doesn&#8217;t care who sends the message to whom,\nas long as the sender and recipient are in the same process.\n<\/p>\n<p>\nThe message cannot cross a process boundary because <code>WM_NOTIFY<\/code>\nis basically a sender-defined version of <code>WM_USER<\/code>.\nAnybody can define a new notification code and associate it with\nany structure they want (as long as the structure begins with\na <code>NMHDR<\/code>).\nThe window manager can&#8217;t marshal the structure between processes\nbecause the structure is defined by the control,\nnot the window manager.\n<\/p>\n<p>\nA little elaboration of that &#8220;sender-defined version of\n<code>WM_USER<\/code>&#8220;:\nAs we saw,\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2003\/12\/02\/55914.aspx\">\nthe meaning of <code>WM_USER<\/code> messages is determined by the\nimplementor of the window class<\/a>.\nIn other words, the code <i>receiving<\/i> the message decides what\n<code>WM_USER<\/code> means.\nThat works great if you&#8217;re some external code that wants to send a message\nto a known window class.\nBut what if you&#8217;re external code that wants to send a message to an\nunknown window class?\nFor example, you&#8217;re a list view control and you want to tell your parent\nabout some event.\nYou want to send a message to the parent window,\nbut which message?\nYou can&#8217;t send anything in the <code>WM_USER<\/code> range\nbecause each parent window defines independently what those messages mean,\nand it&#8217;s highly unlikely that all the parent windows are going to agree\nthat <code>WM_USER+205<\/code> means the same thing.\nFor similar reasons, the <code>WM_APP<\/code> range is no good.\nA registered message would work, but if you have hundreds of potential\nevents, then a hundred registered messages is a bit heavy-handed.\nThe old-school answer to this was the <code>WM_COMMAND<\/code> message,\nwhose notification code is defined by the sending control.\nUnfortunately,\nthe notification code is all you get; the other parameters are busy\ndoing other things.\nEnter <code>WM_NOTIFY<\/code>, which is basically\n<code>WM_COMMAND<\/code> on steroids:\nThe <code>NMHDR<\/code> structure contains everything that was\nin the <code>WM_COMMAND<\/code> message, and since it&#8217;s a structure,\nyou can embed the <code>NMHDR<\/code> inside a larger structure\nto provide (and possibly receive) more information.\n<\/p>\n<p>\nOkay, end of strange digression.\n<\/p>\n<p>\nThe <code>NMHDR<\/code> structure itself is a convention,\nin the same way that the parameters to <code>WM_COMMAND<\/code>\nare a convention.\nThe <code>hwndFrom<\/code> member is supposed to be the\ncontrol that generated the notification, but there&#8217;s\nno enforcement.\n<\/p>\n<p>\nFirst, there&#8217;s no way to enforce it.\nA window doesn&#8217;t send a message; code sends a message.\nYou can check the thread that is executing the code that\nis sending a message, but you don&#8217;t know which window\nthat code is associated with.\n<\/p>\n<p>\n&#8220;Well, the window that is sending the message is the one\nthat most recently received a message.&#8221;\n<\/p>\n<p>\nThat doesn&#8217;t work because you can have code associated\nwith one window call code associated with another window\nwithout actually sending a message.\nIn fact, you probably do this all the time:\n<\/p>\n<pre>\nclass CFrame : public CWindow {\n...\n LRESULT OnCommand(...);\n...\n CGraphWindow *m_pwndGraph;\n};\nLRESULT CFrame::OnCommand(...)\n{\n switch (idFrom) {\n case IDC_CPU: \/\/ user clicked the \"CPU\" button\n  m_pwndGraph-&gt;ChangeMode(CPU); \/\/ change to a CPU graph\n  ...\n}\n<\/pre>\n<p>\nSuppose that <code>CGraphWindow::ChangeMode<\/code> function\ncalls <code>SendMessage<\/code> as part of its processing.\nWhich window &#8220;sent&#8221; this message?\nSince you have the power to read code, the message was\nconceptually sent by <code>CGraphWindow<\/code>,\nbut the most recently received message is a <code>WM_COMMAND<\/code>\nsent to the frame window.\n<\/p>\n<p>\nYour method call is just a transfer of control inside your program.\nThe window manager doesn&#8217;t know what&#8217;s going on.\nAll it knows is that it delivered a <code>WM_COMMAND<\/code> message\nto the frame window, and then some mystery code executed, and\nthe next thing you know, somebody is sending a message.\nIt doesn&#8217;t have the source code to your program to know that\n&#8220;Oh, that&#8217;s coming from <code>CGraphWindow::ChangeMode<\/code>,\nand to get the window handle for <code>CGraphWindow<\/code>,\nI should call <code>CGraphWindow::operator HWND()<\/code>.&#8221;\n(And even if it did, imagine your surprise when your breakpoint\non <code>CGraphWindow::operator HWND()<\/code>\ngets hit because <code>SendMessage<\/code> called it!)\n<\/p>\n<p>\nSecond, even if there were some psychic way for the window\nmanager to figure out which window is sending the message,\nyou still wouldn&#8217;t want that.\nIt is common for <code>WM_NOTIFY<\/code> handlers of complex\ncontrols to forward the message to another window.\nFor example, the list view control in report mode\nreceives <code>WM_NOTIFY<\/code>\nmessages from the header control and forwards them\nback out to its own parent,\nso that the list view parent can respond to header notifications.\n(The parent normally should just let the list view handle it,\nbut the operation is performed in case you&#8217;re one of those\nspecial cases that needs it.)\n<\/p>\n<p>\nOkay, back to what the fields of <code>NMHDR<\/code> mean.\nThere are only three fixed fields to <code>NMHDR<\/code> and\nthey pretty much match up with the parameters to\n<code>WM_COMMAND<\/code>:\n<\/p>\n<ul>\n<li><code>hwndFrom<\/code> is the handle to the window that\n    is the logical source of the notification.<\/p>\n<li><code>idFrom<\/code> is the control ID corresponding to the\n    window specified by <code>hwndFrom<\/code>.\n    In other words, <code>idFrom = GetDlgCtrlID(hwndFrom)<\/code>.<\/p>\n<li><code>code<\/code> is the notification code.\n    The meaning of this notification code depends on the window\n    class of <code>hwndFrom<\/code>.\n<\/ul>\n<p>\nIt is an unwritten convention that the notification codes for\nthe common controls are all negative numbers.\nThis leaves positive numbers for applications to use for their\nown purposes.\nNot that applications strictly speaking needed the help,\nbecause the meaning of the notification code depends on the\nwindow that generated the notification,\nso if you want a brand new 32-bit message number namespace,\njust register a new window class, and boom, a whole new range\nof codes becomes available just to you.\n(Even though the notification code values do not need to be unique\nacross window classes,\nthe common controls team tries to keep the system-defined notification\ncodes from overlapping, just to make debugging easier.)\n<\/p>\n<p>\nThe <code>idFrom<\/code> member is provided as a convenience\nto the window receiving the message so that it can use a simple\n<code>switch<\/code> statement to figure out who is sending\nthe notification.\n<\/p>\n<p>\nOnce you figure out which notification you&#8217;re receiving,\nyou can use the documentation for that notification to see\nwhich structure is associated with the notification.\nThis answers Norman Diamond&#8217;s complaint\nthat he\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2006\/03\/02\/542115.aspx#552686\">\ncouldn&#8217;t figure out what to cast it to<\/a>.\nFor example, if the notification is\n<code>LVN_ITEMCHANGING<\/code>,\nwell, let&#8217;s see,\n<a HREF=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bb774847.aspx\">\nthe documentation for\n<code>LVN_ITEMCHANGING<\/code><\/a> says,\n<\/p>\n<blockquote CLASS=\"q\">\n<p>\n<code>LVN_ITEMCHANGING<\/code><br \/>\n<code>pnmv = (LPNMLISTVIEW) lParam;<\/code>\n<\/p>\n<p>\n<i>pnmv<\/i>: Pointer to an\n<a HREF=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bb774773.aspx\">\nNMLISTVIEW<\/a> structure\nthat identifies the item and specifies which of its attributes are changing.\n<\/p>\n<\/blockquote>\n<p>\nIn other words, your code goes something like this:\n<\/p>\n<pre>\ncase LVN_ITEMCHANGING:\n pnmv = (LPNMLISTVIEW) lParam;\n ... do stuff with pnmv ...\n<\/pre>\n<p>\nI&#8217;m not sure how much more explicit the documentation could be made to be.\nAll it was missing was the word <code>case<\/code> in front.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>It appears that people seemed to appreciate restating the obvious about the WM_COMMAND message, so I&#8217;ll try it again with the WM_NOTIFY message. The WM_NOTIFY message is typically used by a control to communicate with its parent, either to provide information, request it, or both. Although that is the typical use, there are exceptions. For [&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-17033","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>It appears that people seemed to appreciate restating the obvious about the WM_COMMAND message, so I&#8217;ll try it again with the WM_NOTIFY message. The WM_NOTIFY message is typically used by a control to communicate with its parent, either to provide information, request it, or both. Although that is the typical use, there are exceptions. For [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/17033","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=17033"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/17033\/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=17033"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=17033"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=17033"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}