{"id":112116,"date":"2026-03-06T07:00:00","date_gmt":"2026-03-06T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=112116"},"modified":"2026-03-06T09:43:38","modified_gmt":"2026-03-06T17:43:38","slug":"20260306-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20260306-00\/?p=112116","title":{"rendered":"When <CODE>Read&shy;Directory&shy;ChangesW<\/CODE> reports that a deletion occurred, how can I learn more about the deleted thing?"},"content":{"rendered":"<p>A customer was using <code>Read\u00adDirectory\u00adChangesW<\/code> to monitor changes to a directory. However, they ran into a problem when they received a <code>FILE_<wbr \/>ACTION_<wbr \/>REMOVED<\/code> notification: Since the notification is raised when the item is deleted, they can&#8217;t do a <code>Get\u00adFile\u00adAttributesEx<\/code> to find out whether the deleted item was a file or a subdirectory, and if it was a file, the size of the deleted file. Their program needs that information as part of its directory monitoring, so what mechanism is there to recover that information?<\/p>\n<p>The <code>Read\u00adDirectory\u00adChangesW<\/code> function provides no way to recover information about the item that was deleted. All you get is the name of the item.<\/p>\n<p>Recall that <code>Read\u00adDirectory\u00adChangesW<\/code> is for <a title=\"ReadDirectoryChangesW reads directory changes, but what if the directory doesn't change?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20110812-00\/?p=9913\"> detecting changes to information that would appear in a directory listing<\/a>. The idea is that your program performs a <code>Find\u00adFirst\u00adFile<\/code>\/<code>Find\u00adNext\u00adFile<\/code> to build an in-memory cache for a directory, and then you can use <code>Read\u00adDirectory\u00adChangesW<\/code> to perform incremental updates to your cache. For example, if you see a <code>FILE_<wbr \/>ACTION_<wbr \/>ADDED<\/code>, then you can call <code>Get\u00adFile\u00adAttributes<\/code> or <code>Get\u00adFile\u00adAttributes\u00adEx<\/code> to get information about the thing that was added and update your cache. That way, when you see the <code>FILE_<wbr \/>ACTION_<wbr \/>REMOVED<\/code>, you can read the entry from your cache to get the information about the item that was removed (as well as removing it from your cache).<\/p>\n<p>There is a race condition here, however. If the item is added and then immediately deleted, then when you get around to calling <code>Get\u00adFile\u00adAttributes<\/code>, it won&#8217;t be there, so you don&#8217;t actually know what it was.<\/p>\n<p>Fortunately, there&#8217;s <code>Read\u00adDirectory\u00adChanges\u00adExW<\/code>. If you ask for <code>Read\u00adDirectory\u00adNotify\u00adExtended\u00adInformation<\/code>, then you get back a series of <code>FILE_<wbr \/>NOTIFY_<wbr \/>EXTENDED_<wbr \/>INFORMATION<\/code> structures, and in addition to the action and the file name, those also contain directory information about the item, including its file attributes. This information is provided both on the add and on the remove, so you can just look at the <code>FileAttributes<\/code> on the <code>FILE_<wbr \/>ACTION_<wbr \/>REMOVED<\/code> to see whether it was a file or a folder, and if it was a file, you can use the <code>FileSize<\/code> to see the logical size of the file at the time it was deleted.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>It&#8217;s already gone. If you need more information, you should have been remembering it.<\/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-112116","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>It&#8217;s already gone. If you need more information, you should have been remembering it.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/112116","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=112116"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/112116\/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=112116"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=112116"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=112116"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}