{"id":105212,"date":"2021-05-13T07:00:00","date_gmt":"2021-05-13T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=105212"},"modified":"2021-05-13T06:16:38","modified_gmt":"2021-05-13T13:16:38","slug":"20210513-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210513-00\/?p=105212\/","title":{"rendered":"Drag\/drop effects: The little drop information box"},"content":{"rendered":"<p>Explorer&#8217;s drag\/drop effects include a little message information box as part of the drop effect. For example, it will start with the message <i>Move to \u2e22folder\u2e25<\/i>, but if you hold the <kbd>Ctrl<\/kbd> key, the message changes to <i>Copy to \u2e22folder\u2e25<\/i>. How can you get a piece of that action?<\/p>\n<p>As we saw last time, <a title=\"Using Explorer's fancy drag\/drop effects in your own programs\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210512-00\/?p=105208\"> the visual drag\/drop feedback effects used by Explorer are available for general use<\/a>, via an object know as the shell drop target helper.<\/p>\n<p>Let&#8217;s take our scratch program and teach it how to add the fancy information box.<\/p>\n<p>The information box is configured by the <code>DROP\u00adDESCRIPTION<\/code> structure which is associated with the <code>CFSTR_<wbr \/>DROP\u00adDESCRIPTION<\/code> clipboard format.<\/p>\n<pre>#include &lt;strsafe.h&gt;\r\n\r\nHRESULT SetDropDescription(\r\n    IDataObject* dataObject, DROPIMAGETYPE type,\r\n    PCWSTR message = nullptr, PCWSTR insert = nullptr)\r\n{\r\n    wil::unique_hglobal_ptr&lt;DROPDESCRIPTION&gt; data(\r\n        reinterpret_cast&lt;DROPDESCRIPTION*&gt;(\r\n            GlobalAlloc(GPTR, sizeof(DROPDESCRIPTION))));\r\n    RETURN_IF_NULL_ALLOC(data);\r\n    data-&gt;type = type;\r\n    RETURN_IF_FAILED(StringCchCopyEx(data-&gt;szMessage, ARRAYSIZE(data-&gt;szMessage),\r\n        message, nullptr, nullptr, STRSAFE_IGNORE_NULLS));\r\n    RETURN_IF_FAILED(StringCchCopyEx(data-&gt;szInsert, ARRAYSIZE(data-&gt;szInsert),\r\n        insert, nullptr, nullptr, STRSAFE_IGNORE_NULLS));\r\n    FORMATETC fmte = { (CLIPFORMAT)RegisterClipboardFormat(CFSTR_DROPDESCRIPTION),\r\n        nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };\r\n    STGMEDIUM med = { TYMED_HGLOBAL };\r\n    med.hGlobal = data.get();\r\n    RETURN_IF_FAILED(dataObject-&gt;SetData(&amp;fmte, &amp;med, true));\r\n    data.release();\r\n    return S_OK;\r\n}\r\n<\/pre>\n<p>We allocate a <code>DROP\u00adDESCRIPTION<\/code> structure as an <code>HGLOBAL<\/code> and copy the drop image type, optional message, and optional message insertion into the structure before setting the data into the data object.<\/p>\n<p>You can read the documentation for <code>DROP\u00adDESCRIPTION<\/code> for details on how the message and message insertion interact. For this example, we&#8217;ll just use a simple message with no insertions.<\/p>\n<pre>struct SimpleDropTarget\r\n{\r\n    ...\r\n\r\n    STDMETHOD DragLeave()\r\n    {\r\n        <span style=\"color: blue;\">if (dto) SetDropDescription(dto.get(), DROPIMAGE_INVALID);<\/span>\r\n        dto = nullptr;\r\n        return helper-&gt;DragLeave();\r\n    }\r\n\r\n\r\n    HRESULT CalculateFeedback(\r\n        DWORD grfKeyState,\r\n        DWORD* pdwEffect)\r\n    {\r\n        if (grfKeyState &amp; MK_CONTROL) {\r\n            *pdwEffect = DROPEFFECT_COPY;\r\n            <span style=\"color: blue;\">SetDropDescription(dto.get(), DROPIMAGE_COPY,\r\n                L\"Copy with awesomesauce.\");<\/span>\r\n        }\r\n        else {\r\n            *pdwEffect = DROPEFFECT_MOVE;\r\n            <span style=\"color: blue;\">SetDropDescription(dto.get(), DROPIMAGE_MOVE,\r\n                L\"Move with awesomesauce.\");<\/span>\r\n        }\r\n        return S_OK;\r\n    }\r\n\r\n};\r\n<\/pre>\n<p>When we calculate the feedback, we also set the drop description to tell the user what will happen when the drop happens. We also clear the drop description (by setting it to &#8220;invalid&#8221; with an empty message)\u00b9 when the user decided not to drop it onto our drop target after all. This ensures that our custom description doesn&#8217;t hang around and accidentally get shown for other drop targets that don&#8217;t set a description.<\/p>\n<p>So there you have it, drag feedback done the same way that Explorer does it.<\/p>\n<p>\u00b9 There is no way to remove data from a data object, so the best you can do is replace the data with new data that says &#8220;Nevermind.&#8221;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Updating the description.<\/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-105212","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Updating the description.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105212","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=105212"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105212\/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=105212"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=105212"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=105212"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}