{"id":23073,"date":"2008-03-19T07:00:00","date_gmt":"2008-03-19T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2008\/03\/19\/what-a-drag-dragging-a-virtual-file-istream-edition\/"},"modified":"2022-08-02T07:19:08","modified_gmt":"2022-08-02T14:19:08","slug":"20080319-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20080319-00\/?p=23073\/","title":{"rendered":"What a drag: Dragging a virtual file (IStream edition)"},"content":{"rendered":"<p>Last time, we saw <a title=\"What a drag: Dragging a virtual file (HGLOBAL edition)\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20080318-00\/?p=23083\"> how to drag a virtual file whose contents are expressed as a block of bytes in memory (<code>HGLOBAL<\/code>)<\/a>. Often, a block of bytes is not a convenient way to express the contents of a virtual file. You might prefer to express it as a stream. For example, the contents might be dynamically generated (say by the output of an algorithm), or it might come in from an external source (say, a web page that is being downloaded). Let&#8217;s take our program from last time and convert it to return the file contents in the form of a stream. The first change we need to make is to our constructor, telling it to report file contents as a stream rather than as an <code>HGLOBAL<\/code>:<\/p>\n<pre>#include &lt;shlwapi.h&gt; \/\/ for SHOpenRegStream\r\n\r\nCTinyDataObject::CTinyDataObject() : m_cRef(1)\r\n{\r\n  SetFORMATETC(&amp;m_rgfe[DATA_FILEGROUPDESCRIPTOR],\r\n               RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR));\r\n  SetFORMATETC(&amp;m_rgfe[DATA_FILECONTENTS],\r\n               RegisterClipboardFormat(CFSTR_FILECONTENTS),\r\n               <span style=\"color: blue;\">TYMED_ISTREAM<\/span>, \/* lindex *\/ 0);\r\n}\r\n<\/pre>\n<p>Next, we need to produce that stream and its corresponding descriptor in our <code>IDataObject::GetData<\/code> handler:<\/p>\n<pre>HRESULT CTinyDataObject::GetData(FORMATETC *pfe, STGMEDIUM *pmed)\r\n{\r\n  ZeroMemory(pmed, sizeof(*pmed));\r\n\r\n  switch (GetDataIndex(pfe)) {\r\n  case DATA_FILEGROUPDESCRIPTOR:\r\n  {\r\n    FILEGROUPDESCRIPTOR fgd;\r\n    ZeroMemory(&amp;fgd, sizeof(fgd));\r\n    fgd.cItems = 1;\r\n    StringCchCopy(fgd.fgd[0].cFileName,\r\n                  ARRAYSIZE(fgd.fgd[0].cFileName),\r\n                  TEXT(\"Dummy\"));\r\n    pmed-&gt;tymed = TYMED_HGLOBAL;\r\n    return CreateHGlobalFromBlob(&amp;fgd, sizeof(fgd),\r\n                              GMEM_MOVEABLE, &amp;pmed-&gt;hGlobal);\r\n  }\r\n\r\n  case DATA_FILECONTENTS:\r\n    <span style=\"color: blue;\">pmed-&gt;tymed = TYMED_ISTREAM;\r\n    pmed-&gt;pstm = SHOpenRegStream(HKEY_LOCAL_MACHINE,\r\n       TEXT(\"Hardware\\\\Description\\\\System\\\\CentralProcessor\\\\0\"),\r\n       TEXT(\"~MHz\"), STGM_READ);\r\n    <span style=\"color: blue;\">\/\/ <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20140918-00\/?p=44033\">set the stream position properly<\/a>\r\n    if (pmed-&gt;pstm) {\r\n      LARGE_INTEGER liZero = { 0, 0 };\r\n      pmed-&gt;pstm-&gt;Seek(liZero, STREAM_SEEK_END, NULL);\r\n    }<\/span>\r\n    return pmed-&gt;pstm ? S_OK : E_FAIL;<\/span>\r\n  }\r\n\r\n  return DV_E_FORMATETC;\r\n}\r\n<\/pre>\n<p>Of course, in real life, you would use a more interesting stream than your CPU speed. I just chose that one as an example.<\/p>\n<p>As with our <code>HGLOBAL<\/code>-based data object, you can drop this data object onto an Explorer folder to create a file, into an Outlook message to create an attachment, and anywhere else a program supports the shell virtual file transfer model. And as with the <code>HGLOBAL<\/code> example, you can set various optional information in the <code>FILEGROUPDESCRIPTOR<\/code> in order to make the transfer go more smoothly, particularly the expected stream size. But I won&#8217;t go into it because the theme of this series is &#8220;It&#8217;s the least you can do&#8221;.<\/p>\n<p>But already you know enough to solve this customer&#8217;s problem:<\/p>\n<blockquote class=\"m\"><p>We need to know what directory the user dropped a file onto. We need to transfer data from another computer, so what we do is have the user drag a single dummy file, and then once we find out where the user dropped the dummy file, we can go in, delete the dummy file, and start transferring the data from the remote computer and saving it into real files in the destination directory.<\/p><\/blockquote>\n<p>Next time, we&#8217;ll look at the final storage medium that can be used for file transfer, the <code>TYMED_ISTORAGE<\/code>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The contents can be generated incrementally.<\/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,139],"class_list":["post-23073","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code","tag-what-a-drag"],"acf":[],"blog_post_summary":"<p>The contents can be generated incrementally.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/23073","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=23073"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/23073\/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=23073"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=23073"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=23073"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}