{"id":97375,"date":"2017-11-09T07:00:00","date_gmt":"2017-11-09T22:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=97375"},"modified":"2019-03-13T01:20:08","modified_gmt":"2019-03-13T08:20:08","slug":"20171109-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20171109-00\/?p=97375\/","title":{"rendered":"How can I cancel the <CODE>INamespace&shy;Walk::<\/CODE><CODE>Walk<\/CODE> operation?"},"content":{"rendered":"<p>We saw that <a HREF=\"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20171108-00\/?p=97365\">you can stop a <code>INamespace&shy;Walk::<\/code><code>Walk<\/code> operation by returning a COM error code from the <code>Enter&shy;Folder<\/code> or <code>Found&shy;Item<\/code> callback<\/a>. <\/p>\n<p>So let&#8217;s do that in order to add a timeout to the namespace walk operation. At each callback, we&#8217;ll check how much time has elapsed since the operation started, and if it&#8217;s too long, then we return <code>HRESULT_<\/code><code>FROM_<\/code><code>WIN32(<\/code><code>ERROR_<\/code><code>CANCELLED)<\/code>. <\/p>\n<pre>\n#define STRICT\n#include &lt;windows.h&gt;\n#include &lt;shlobj.h&gt;\n#include &lt;wrl\/client.h&gt;\n#include &lt;wrl\/implements.h&gt;\n#include &lt;stdio.h&gt; \/\/ Horrors! Mixing stdio and C++!\n\nnamespace wrl = Microsoft::WRL;\n\nclass WalkCallback : public wrl::RuntimeClass&lt;\n  wrl::RuntimeClassFlags&lt;wrl::ClassicCom&gt;,\n  INamespaceWalkCB&gt;\n{\npublic:\n  \/\/ INamespaceWalkCB\n  IFACEMETHODIMP FoundItem(IShellFolder *,\n   PCUITEMID_CHILD) override\n   { m_itemCount++; return TimeoutStatus(); }\n\n  IFACEMETHODIMP EnterFolder(IShellFolder *,\n   PCUITEMID_CHILD) override\n   { m_folderCount++; return TimeoutStatus(); }\n\n  IFACEMETHODIMP LeaveFolder(IShellFolder *,\n   PCUITEMID_CHILD) override { return S_OK; }\n\n  IFACEMETHODIMP InitializeProgressDialog(PWSTR *ppszTitle,\n    PWSTR *ppszCancel) override\n    { *ppszTitle = nullptr; *ppszCancel = nullptr;\n      return E_NOTIMPL; }\n\n  int ItemCount() const { return m_itemCount; }\n  int FolderCount() const { return m_folderCount; }\n\nprivate:\n  bool IsTimedOut()\n    { return <a HREF=\"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20050531-22\/?p=35493\">GetTickCount() - m_startTime<\/a> &gt; 1000; }\n\n  HRESULT TimeoutStatus()\n    { return IsTimedOut() ?\n      HRESULT_FROM_WIN32(ERROR_CANCELLED) : S_OK; }\n\n  DWORD m_startTime = GetTickCount();\n  int m_itemCount = 0;\n  int m_folderCount = 0;\n};\n<\/pre>\n<p>Our callback object implements <code>INamespace&shy;Walk&shy;CB<\/code> by tallying the number of items and folders it encounters. When we find an item or folder, we increment the appropriate counter and check whether we have reached the timeout. If so, we return <code>HRESULT_<\/code><code>FROM_<\/code><code>WIN32(<\/code><code>ERROR_<\/code><code>CANCELLED)<\/code> to stop the operation. <\/p>\n<p>Let&#8217;s take it for a spin. <\/p>\n<pre>\nint __cdecl wmain(int argc, PWSTR argv[])\n{\n  <a HREF=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/\">CCoInitialize<\/a> coinit;\n\n  wrl::ComPtr&lt;INamespaceWalk&gt; walk;\n  CoCreateInstance(CLSID_NamespaceWalker, nullptr,\n    CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&amp;walk));\n\n  wrl::ComPtr&lt;IShellItem&gt; root;\n  SHCreateItemFromParsingName(argv[1], nullptr,\n    IID_PPV_ARGS(&amp;root));\n\n  auto callback = wrl::Make&lt;WalkCallback&gt;();\n\n  HRESULT hr = walk-&gt;Walk(root.Get(), NSWF_DEFAULT,\n    100, callback.Get());\n\n  printf(\"Walk completed with result 0x%08x\\n\", hr);\n  printf(\"Found %d items and %d folders\\n\",\n   callback-&gt;ItemCount(), callback-&gt;FolderCount());\n\n  return 0;\n}\n<\/pre>\n<p>When I ran this on a small directory tree, I got <\/p>\n<pre>\nWalk completed with result 0x00000000\nFound 43 items and 6 folders\n<\/pre>\n<p>The walk completed in less than one second, so the walk operation completed with <code>S_OK<\/code>. <\/p>\n<p>I repeated the exercise on <code>C:\\Users<\/code> and got <\/p>\n<pre>\nWalk completed with result 0x80070005\nFound 0 items and 2 folders\n<\/pre>\n<p>The walk operation encountered an <code>E_ACCESS<\/code><code>DENIED<\/code> error before one second elapsed. <\/p>\n<p>Next, I tried it with my own home directory. <\/p>\n<pre>\nWalk completed with result 0x800704c7\nFound 3940 items and 2990 folders\n<\/pre>\n<p>It found 3940 items and 2990 folders before it ran out of time. <\/p>\n<p>Next time, we&#8217;ll dig a little bit deeper into cancellation. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>You can cancel it during a <CODE>INamespace&shy;Walk&shy;CB<\/CODE> callback.<\/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-97375","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>You can cancel it during a <CODE>INamespace&shy;Walk&shy;CB<\/CODE> callback.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/97375","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=97375"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/97375\/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=97375"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=97375"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=97375"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}