{"id":6293,"date":"2012-10-19T07:00:00","date_gmt":"2012-10-19T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2012\/10\/19\/using-wm_copydata-to-marshal-message-parameters-since-the-window-manager-otherwise-doesnt-know-how\/"},"modified":"2020-09-22T13:01:10","modified_gmt":"2020-09-22T20:01:10","slug":"using-wm_copydata-to-marshal-message-parameters-since-the-window-manager-otherwise-doesnt-know-how","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20121019-00\/?p=6293","title":{"rendered":"Using WM_COPYDATA to marshal message parameters since the window manager otherwise doesn&#8217;t know how"},"content":{"rendered":"<p>Miral asks for <a href=\"http:\/\/web.archive.org\/web\/20090307013746\/http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2007\/09\/10\/4849069.aspx#4858169\"> the recommended way of passing messages across processes if they require custom marshaling<\/a>.<\/p>\n<p>There is no one recommended way of doing the custom marshaling, although some are hackier than others.<\/p>\n<p>Probably the most <i>architecturally beautiful<\/i> way of doing it is to use a mechanism that <i>does<\/i> perform automatic marshaling, like COM and MIDL. Okay, it&#8217;s not actually automatic, but it does allow you just give MIDL your structures and some information about <a title=\"What does &quot;size_is&quot; mean in an IDL file?\" href=\"https:\/\/docs.microsoft.com\/en-us\/archive\/blogs\/larryosterman\/what-does-size_is-mean-in-an-idl-file\"> how they should be interpreted<\/a>, and the MIDL compiler autogenerates the marshaler. You can then pass the data back and forth by simply invoking COM methods and letting COM do the work.<\/p>\n<p><i>Architecturally beautiful<\/i> often turns into <i>forcing me to learn more than I really wanted to learn<\/i>, so here&#8217;s a more self-contained approach: Take advantage of the <code>WM_<wbr \/>COPY\u00adDATA<\/code> message. This is sort of the poor-man&#8217;s marshaler. All it knows how to marshal is a blob of bytes. It&#8217;s your responsibility to take what you want to marshal and serialize it into a blob of bytes. <code>WM_<wbr \/>COPY\u00adDATA<\/code> will get the bytes to the other side, and then the recipient needs to deserialize the blob of bytes back into your data. But at least <code>WM_<wbr \/>COPY\u00adDATA<\/code> does the tricky bit of getting the bytes from one side to the other.<\/p>\n<p>Let&#8217;s start with our <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20030723-00\/?p=43073\"> scratch program<\/a> and have it transfer data to another copy of itself. Make the following changes:<\/p>\n<pre><span style=\"color: blue;\">#include &lt;strsafe.h&gt;\r\n\r\nHWND g_hwndOther;\r\n\r\n#define CDSCODE_WINDOWPOS 42 \/\/ lpData -&gt; WINDOWPOS\r\n\r\nvoid OnWindowPosChanged(HWND hwnd, LPWINDOWPOS pwp)\r\n{\r\n if (g_hwndOther) {\r\n  COPYDATASTRUCT cds;\r\n  cds.dwData = CDSCODE_WINDOWPOS;\r\n  cds.cbData = sizeof(WINDOWPOS);\r\n  cds.lpData = pwp;\r\n  SendMessage(g_hwndOther, WM_COPYDATA,\r\n           reinterpret_cast&lt;WPARAM&gt;(hwnd),\r\n           reinterpret_cast&lt;LPARAM&gt;(&amp;cds));\r\n }\r\n FORWARD_WM_WINDOWPOSCHANGED(hwnd, pwp, DefWindowProc);\r\n}\r\n\r\nvoid OnCopyData(HWND hwnd, HWND hwndFrom, PCOPYDATASTRUCT pcds)\r\n{\r\n switch (pcds-&gt;dwData) {\r\n case CDSCODE_WINDOWPOS:\r\n  if (pcds-&gt;cbData == sizeof(WINDOWPOS)) {\r\n   LPWINDOWPOS pwp = static_cast&lt;LPWINDOWPOS&gt;(pcds-&gt;lpData);\r\n   TCHAR szMessage[256];\r\n   StringCchPrintf(szMessage, 256,\r\n    TEXT(\"From window %p: x=%d, y=%d, cx=%d, cy=%d, flags=%s %s\"),\r\n    hwndFrom, pwp-&gt;x, pwp-&gt;y, pwp-&gt;cx, pwp-&gt;cy,\r\n    (pwp-&gt;flags &amp; SWP_NOMOVE) ? TEXT(\"nomove\") : TEXT(\"move\"),\r\n    (pwp-&gt;flags &amp; SWP_NOSIZE) ? TEXT(\"nosize\") : TEXT(\"size\"));\r\n   SetWindowText(hwnd, szMessage);\r\n  }\r\n  break;\r\n }\r\n}<\/span>\r\n\r\n\/\/ WndProc\r\n\r\n<span style=\"color: blue;\">    HANDLE_MSG(hwnd, WM_WINDOWPOSCHANGED, OnWindowPosChanged);\r\n    HANDLE_MSG(hwnd, WM_COPYDATA, OnCopyData);<\/span>\r\n\r\n\/\/ WinMain\r\n    <span style=\"color: blue;\">\/\/ If there is another window called \"Scratch\", then it becomes\r\n    \/\/ our recipient.\r\n    g_hwndOther = FindWindow(TEXT(\"Scratch\"), TEXT(\"Scratch\"));<\/span>\r\n\r\n    hwnd = CreateWindow(\r\n        \"Scratch\",                      \/* Class Name *\/\r\n        <span style=\"color: blue;\">g_hwndOther ? TEXT(\"Sender\") : TEXT(\"Scratch\"),<\/span>\r\n        WS_OVERLAPPEDWINDOW,            \/* Style *\/\r\n        CW_USEDEFAULT, CW_USEDEFAULT,   \/* Position *\/\r\n        CW_USEDEFAULT, CW_USEDEFAULT,   \/* Size *\/\r\n        NULL,                           \/* Parent *\/\r\n        NULL,                           \/* No menu *\/\r\n        hinst,                          \/* Instance *\/\r\n        0);                             \/* No special parameters *\/\r\n\r\n<\/pre>\n<p>Just to make it easier to tell the two windows apart, I call the one sending the message &#8220;Sender&#8221;. (Note that my method for finding the other window is pretty rudimentary, because that&#8217;s not the point of the example.)<\/p>\n<p>Whenever the sender window receives a <code>WM_<wbr \/>WINDOW\u00adPOS\u00adCHANGED<\/code> message, it sends a copy of the <code>WINDOW\u00adPOS<\/code> structure to the recipient, which then displays it in its own title bar. Things to observe:<\/p>\n<ul>\n<li>The value you put into <code>dwData<\/code> can be anything you like. It&#8217;s just another <code>DWORD<\/code> of data. Traditionally, it&#8217;s used like a &#8220;message number&#8221;, used to communicate what type of data is being sent. In our case, we choose 42 to mean &#8220;The <code>lpData<\/code> points to a <code>WINDOW\u00adPOS<\/code> structure.&#8221;<\/li>\n<li>The <code>cbData<\/code> is the number of bytes you want to send, and <code>lpData<\/code> points to the buffer. In our case, the number of bytes is always the same, but variable-sized data is also fine.<\/li>\n<li>The <code>lpData<\/code> can point anywhere, as long as the memory is valid for the lifetime of the <code>Send\u00adMessage<\/code> call. In this case, I just point it at the data given to me by the window manager. Of course, if you allocated memory to put into <code>lpData<\/code>, then the responsibility for freeing it also belongs to you.<\/li>\n<li>For safety&#8217;s sake, I validate that when I get a <code>CDS\u00adCODE_<wbr \/>WINDOW\u00adPOS<\/code> request, the associated data really is the size of a <code>WINDOW\u00adPOS<\/code> structure. This helps protect against a rogue caller who tries to crash the application by sending a <code>CDS\u00adCODE_<wbr \/>WINDOW\u00adPOS<\/code> with a size less than <code>sizeof(WINDOW\u00adPOS)<\/code>, thereby triggering a buffer overflow. (Exercise: Under what other conditions can the size be incorrect? How would you fix that?)<\/li>\n<li>The <code>WM_<wbr \/>COPY\u00adDATA<\/code> copies data in only one direction. It does not provide a way to pass information back to the sender. (Exercise: How would you pass information back?)<\/li>\n<li>The <code>hwndFrom<\/code> parameter is a courtesy parameter, like <code>dwData<\/code>. There is currently no attempt to verify that the window really is that of the sender. (In practice, all that could really be verified is that the window belongs to the thread that is doing the sending, but right now, not even that level of validation is performed.)<\/li>\n<\/ul>\n<p>The <code>WM_<wbr \/>COPY\u00adDATA<\/code> message is suitable for small-to-medium-sized amounts of memory. Though if the amount of memory is so small that it fits into a <code>WPARAM<\/code> and <code>LPARAM<\/code>, then even <code>WM_<wbr \/>COPY\u00adDATA<\/code> is overkill.<\/p>\n<p>If you&#8217;re going to be passing large chunks of memory, then you may want to consider <a title=\"How do I pass a lot of data to a process when it starts up?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20031211-00\/?p=41543\"> using a shared memory handle instead<\/a>. The shared memory handle also has the benefit of being shared, which means that the recipient can modify the shared memory block, and the sender can see the changes. (Yes, this is one answer to the second exercise, but see if you can find another answer that tays within the spirit of the exercise.)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Miral asks for the recommended way of passing messages across processes if they require custom marshaling. There is no one recommended way of doing the custom marshaling, although some are hackier than others. Probably the most architecturally beautiful way of doing it is to use a mechanism that does perform automatic marshaling, like COM and [&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-6293","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Miral asks for the recommended way of passing messages across processes if they require custom marshaling. There is no one recommended way of doing the custom marshaling, although some are hackier than others. Probably the most architecturally beautiful way of doing it is to use a mechanism that does perform automatic marshaling, like COM and [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/6293","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=6293"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/6293\/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=6293"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=6293"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=6293"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}