Winapi SHChangeNotify与SHCNE_RMDIR行为在Windows 7和Windows 10之间不一致 概述

Winapi SHChangeNotify与SHCNE_RMDIR行为在Windows 7和Windows 10之间不一致 概述,winapi,shell-extensions,shell32,shell-namespace-extension,Winapi,Shell Extensions,Shell32,Shell Namespace Extension,我正在使用withSHCNE\u RMDIR通知shell已从我的文件夹中删除的文件夹。我的期望是,这将导致将文件夹视图导航到已删除文件夹(或其任何子文件夹)的任何资源管理器(或其他shell)窗口导航到已删除文件夹的父文件夹。此预期行为发生在Windows 10上。但是,在Windows 7上,这些窗口将被导航到已删除的文件夹 问题: Windows 7上的这种行为是一个bug吗?或者我可以做些什么(不必为Windows 7编写特殊代码)来获得两个操作系统的相同行为吗 复制问题的详细步骤 下面

我正在使用with
SHCNE\u RMDIR
通知shell已从我的文件夹中删除的文件夹。我的期望是,这将导致将文件夹视图导航到已删除文件夹(或其任何子文件夹)的任何资源管理器(或其他shell)窗口导航到已删除文件夹的父文件夹。此预期行为发生在Windows 10上。但是,在Windows 7上,这些窗口将被导航到已删除的文件夹

问题: Windows 7上的这种行为是一个bug吗?或者我可以做些什么(不必为Windows 7编写特殊代码)来获得两个操作系统的相同行为吗

复制问题的详细步骤 下面是如何从头开始创建和观察问题的演练。这涉及到使用一个名为a的“内置”Microsoft命名空间扩展(而不是我真正的命名空间扩展)。我使用它是为了简单,同时也表明它与我的特定名称空间扩展无关。此示例命名空间扩展所做的只是在“我的计算机”下创建一个图标,该图标将浏览到您的%TEMP%目录

  • 安装名称空间扩展并将其注册到“我的电脑”下。为此,请在注册表中输入以下内容:

    HKEY_CURRENT_USER\Software\Classes\CLSID
    
      {0672A6D1-A6E0-40FE-AB16-F25BADC6D9E4}=REG_SZ_EXPAND:"My Namespace Extension"
        DescriptionID=REG_DWORD:0x00000008
        System.IsPinnedToNameSpaceTree=REG_DWORD:0x00000001
        DefaultIcon=REG_EXPAND_SZ:"%SystemRoot%\system32\main.cpl,9"
        InProcServer32=REG_EXPAND_SZ:"%SystemRoot%\system32\shdocvw.dll"
          ThreadingModel=REG_SZ:"Apartment"
        ShellFolder
          Attributes=REG_DWORD:0x60000000
        Instance
          CLSID=REG_SZ:"{0AFACED1-E828-11D1-9187-B532F1E9575D}"
          InitPropertyBag
            Attributes=REG_DWORD:0x00000011
            Target=REG_SZ_EXPAND:"%TEMP%"
    
    下面是一个.reg文件,它将为您自动执行此操作:

    Windows Registry Editor Version 5.00
    
    [HKEY_CURRENT_USER\Software\Classes\CLSID\{0672A6D1-A6E0-40FE-AB16-F25BADC6D9E4}]
    @="My Namespace Extension"
    "System.IsPinnedToNameSpaceTree"=dword:00000001
    "DescriptionID"=dword:00000008
    
    [HKEY_CURRENT_USER\Software\Classes\CLSID\{0672A6D1-A6E0-40FE-AB16-F25BADC6D9E4}\DefaultIcon]
    @=hex(2):25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,00,74,00,25,\
      00,5c,00,73,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,6d,00,61,00,\
      69,00,6e,00,2e,00,63,00,70,00,6c,00,2c,00,39,00,00,00
    
    [HKEY_CURRENT_USER\Software\Classes\CLSID\{0672A6D1-A6E0-40FE-AB16-F25BADC6D9E4}\InProcServer32]
    @=hex(2):25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,00,74,00,25,\
      00,5c,00,73,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,73,00,68,00,\
      64,00,6f,00,63,00,76,00,77,00,2e,00,64,00,6c,00,6c,00,00,00
    "ThreadingModel"="Apartment"
    
    [HKEY_CURRENT_USER\Software\Classes\CLSID\{0672A6D1-A6E0-40FE-AB16-F25BADC6D9E4}\Instance]
    "CLSID"="{0AFACED1-E828-11D1-9187-B532F1E9575D}"
    
    [HKEY_CURRENT_USER\Software\Classes\CLSID\{0672A6D1-A6E0-40FE-AB16-F25BADC6D9E4}\Instance\InitPropertyBag]
    "Attributes"=dword:00000011
    "Target"=hex(2):25,00,54,00,45,00,4d,00,50,00,25,00,00,00
    
    [HKEY_CURRENT_USER\Software\Classes\CLSID\{0672A6D1-A6E0-40FE-AB16-F25BADC6D9E4}\ShellFolder]
    "Attributes"=dword:60000000
    
    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\MyComputer\Namespace\{0672A6D1-A6E0-40FE-AB16-F25BADC6D9E4}]
    @="My Namespace Extension"
    
    以下.reg文件将允许您轻松删除上述注册表项:

    Windows Registry Editor Version 5.00
    
    [-HKEY_CURRENT_USER\Software\Classes\CLSID\{0672A6D1-A6E0-40FE-AB16-F25BADC6D9E4}]
    
    [-HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\MyComputer\Namespace\{0672A6D1-A6E0-40FE-AB16-F25BADC6D9E4}]
    
  • 此时,当您打开资源管理器窗口并在“我的电脑”中导航时,您应该会看到“我的命名空间扩展”。浏览它会显示您的%TEMP%目录文件夹/文件

  • %TEMP%
    文件夹中创建一个名为
    FolderToRemove
    的目录。在
    FolderToRemove
    中创建名为
    subFolder
    的子文件夹

  • 打开3个资源管理器窗口并浏览到以下位置:

    • 我的计算机\我的命名空间扩展
    • 我的计算机\My Namespace Extension\FolderToRemove
    • 我的计算机\My Namespace Extension\FolderToRemove\subFolder

  • 在Windows 7上,执行以下C++代码:

    // This path represents My Computer\My Namespace Extension\FolderToRemove
    const wchar_t * pPath = L"::{20d04fe0-3aea-1069-a2d8-08002b30309d}\\::{0672A6D1-A6E0-40FE-AB16-F25BADC6D9E4}\\FolderToRemove";
    SHChangeNotify(SHCNE_RMDIR, SHCNF_PATH, pPath, NULL);
    
  • 执行上述代码后,您会注意到唯一更改的资源管理器窗口是最初导航到
    My Computer\My Namespace Extension\FolderToRemove\subFolder
    的窗口。请注意,它现在指向
    My Computer\My Namespace Extension\FolderToRemove

  • 预期其中两个资源管理器窗口已更改,因此它们都被导航到
    My Computer\My Namespace Extension
    (已删除文件夹的父文件夹)。以下是预期行为的图像(这是Windows 10上发生的情况):

  • 附加说明
    • 我发现,通过在
      shchangennotify
      中指定已删除文件夹的父文件夹,可以获得Windows 7所需的行为。例如:

      // This path represents My Computer\My Namespace Extension
      const wchar_t * pPath = L"::{20d04fe0-3aea-1069-a2d8-08002b30309d}\\::{0672A6D1-A6E0-40FE-AB16-F25BADC6D9E4}";
      SHChangeNotify(SHCNE_RMDIR, SHCNF_PATH, pPath, NULL);
      
      但是当我在Windows10上执行此代码时,它当然会导致窗口被导航回
      我的计算机
      ,这是不需要的。如果我采用这种解决方法,我需要为不同的操作系统编写不同的代码


    作为Microsoft支持案例的一部分,我得到了以下信息,这些信息描述了Explorer在此工作流中的反应。然而,对于Windows 10为何表现不同,它没有给出任何理由:


    对于导航到SHCNE_RMDIR通知中指定的文件夹或其子代之一的任何浏览器窗口,资源管理器将导航浏览器窗口到有效的(祖先)文件夹。从SCHNE_RMDIR通知中指定的文件夹的绝对ITEMIDLIST开始,确定要在Explorer浏览器窗口中打开的新文件夹的过程如下:

  • 获取指定绝对项IDList的父项的IShellFolder
  • 通过使用SFGAO_验证标志调用IShellFolder::GetAttributesOf来验证子文件夹
  • 如果GetAttributesOf报告该项无效(返回错误),请获取父文件夹的绝对ItemIdle列表并返回步骤1
  • 如果GetAttributesOf报告该项有效,请调用浏览器窗口的IShellBrowser::BrowseObject导航到有效文件夹
  • 在您发布到StackOverflow的复制步骤中,我们打开了以下文件夹的资源管理器浏览器窗口:

    ::{CLSID_MyComputer}::{CLSID_My Namespace Extension}

    ::{CLSID_MyComputer}::{CLSID_My Namespace Extension}\FolderToRemove

    ::{CLSID_MyComputer}::{CLSID_我的命名空间 扩展名}\FolderToRemove\子文件夹

    以下是SHCNE_RMDIR通知如何

    :{CLSID_MyComputer}\:{CLSID_mynamespace Extension}\FolderToRemove

    文件夹由浏览器窗口处理:

    浏览器窗口导航到
    ::{CLSID_MyComputer}\:{CLSID_mynamespace Extension}

  • 不执行任何操作,因为此文件夹不是要删除的文件夹或其子文件夹之一
  • 浏览器窗口导航到
    ::{CLSID_MyComputer}\:{CLSID_My Namespace Extension}\FolderToRemove

  • 获取以下文件夹的IShellFolder::{CLSID_MyComputer}::{CLSID_My Namespace Extension}文件夹,并在FolderToRemove上调用IShellFolder::GetAttributesOf(SFGAO_VALIDATE)
  • GetAttributesOf返回S_OK,因为FolderToRemove未实际删除
  • GetAttributesOf报告FolderToRemove有效这是一个有效的文件夹,请在以下位置调用IShellBrowser::BrowseObject:{CLSID_MyComputer}::{CLSID_My Namespace Extension}\FolderToRemove。这本质上是一个无操作,因为浏览器窗口已经导航到该文件夹
  • 浏览器窗口导航到
    ::{CLSID_MyComputer}\:{CLSID_My Namespace Extension}\FolderToRemove\subFolder

  • 我们从以下项的ITEMIDLIST开始::{CLSID_MyComputer}::{CLSID