{"id":23063,"date":"2008-03-20T10:00:00","date_gmt":"2008-03-20T10:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2008\/03\/20\/what-a-drag-dragging-a-virtual-file-istorage-edition\/"},"modified":"2022-08-02T07:22:05","modified_gmt":"2022-08-02T14:22:05","slug":"20080320-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20080320-00\/?p=23063","title":{"rendered":"What a drag: Dragging a virtual file (IStorage edition)"},"content":{"rendered":"<p>There are three storage media that can be used for virtual file transfer. We&#8217;ve already seen <a title=\"What a drag: Dragging a virtual file (HGLOBAL edition)\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20080318-00\/?p=23083\"> <code>HGLOBAL<\/code><\/a> and <a title=\"What a drag: Dragging a virtual file (IStream edition)\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20080319-00\/?p=23073\"> <code>IStream<\/code><\/a>; the last one is <code>IStorage<\/code>. I doubt anybody will ever need to do virtual file transfer with structured storage, but here it is anyway. Remember that the theme of this series is &#8220;It&#8217;s the least you can do&#8221;, so I&#8217;m going to try to get away with as little as possible.<\/p>\n<p>Starting with our stream-based sample from last time, we need only make a few changes. First, of course, we have to declare that we provide an <code>IStorage<\/code> as our file contents.<\/p>\n<pre>CTinyDataObject::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_ISTORAGE<\/span>, \/* lindex *\/ 0);\r\n}\r\n<\/pre>\n<p>Next, we need to produce that storage 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: \/\/  Create an empty storage\r\n  <span style=\"color: blue;\">{\r\n    pmed-&gt;tymed = TYMED_ISTORAGE;\r\n    ILockBytes *plb;\r\n    HRESULT hr = CreateILockBytesOnHGlobal(NULL, TRUE, &amp;plb);\r\n    if (SUCCEEDED(hr)) {\r\n        hr = StgCreateDocfileOnILockBytes(plb,\r\n                STGM_READWRITE | STGM_SHARE_EXCLUSIVE |\r\n                STGM_CREATE | STGM_DIRECT,\r\n                0, &amp;pmed-&gt;pstg);\r\n        plb-&gt;Release();\r\n    }\r\n    return hr;\r\n  }<\/span>\r\n\r\n  return DV_E_FORMATETC;\r\n}\r\n<\/pre>\n<p>The hardest part was creating the empty storage object! The bookkeeping you&#8217;re by now well-familiar with. and, as noted when we made the <code>HGLOBAL<\/code>-based data object, there are additional attributes you can set in the <code>FILEGROUPDESCRIPTOR<\/code> to make the experience a bit smoother.<\/p>\n<p>That pretty much covers &#8220;The least you can do&#8221; for virtual file transfer in the shell. You can think of these little sample programs as &#8220;scratch data objects&#8221;\u2014you can use them as the basis for more complicated virtual file transfer scenarios. We&#8217;ll see more about this in future articles.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I doubt anybody will ever need this.<\/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-23063","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code","tag-what-a-drag"],"acf":[],"blog_post_summary":"<p>I doubt anybody will ever need this.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/23063","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=23063"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/23063\/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=23063"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=23063"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=23063"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}