SHChangeNotify с поведением SHCNE_RMDIR, несовместимым между Windows 7 и Windows 10
обзор
я использую SHChangeNotify
с SHCNE_RMDIR
уведомить оболочку о папке, которая была удалена из моего расширения пространства имен оболочки. Я ожидаю, что это приведет к тому, что любые окна обозревателя (или другой оболочки), для которых их представление папок будет перемещено в удаленную папку (или любую из ее подпапок), будут перемещены в родительскую папку удаленной папки. Такое ожидаемое поведение наблюдается в Windows 10. Однако в Windows 7 эти окна перемещаются в удаленную папку.
Вопрос
Является ли это поведение в Windows 7 ошибкой, и / или есть ли что-то, что я могу сделать (не имея специального кода для Windows 7), чтобы получить одинаковое поведение для обеих ОС?
Подробные шаги для воспроизведения проблемы
Вот краткий обзор того, как создать и наблюдать проблему с нуля. Это включает использование "встроенного" расширения пространства имен 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 окна проводника и перейдите в следующие места:
- Мой компьютер \ Расширение пространства имен
- Мой компьютер \ Расширение пространства имен \FolderToRemove
- Мой компьютер \ Расширение пространства имен \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):
Дополнительные примечания
Я обнаружил, что могу получить желаемое поведение для Windows 7, указав родительскую папку удаленной папки в
SHChangeNotify
, Например:// 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);
Но когда я выполняю этот код в Windows 10, это, конечно, заставляет окна вернуться к
My Computer
что нежелательно. Если бы я пошел с этим обходным путем, мне понадобился бы другой код для разных ОС.
1 ответ
В рамках поддержки Microsoft мне была предоставлена следующая информация, которая описывает, как Explorer реагирует в этом рабочем процессе. Это, однако, не дает никаких объяснений, почему Windows 10 ведет себя по-разному:
Для любого окна браузера, перемещенного в папку, указанную в уведомлении SHCNE_RMDIR, или одного из его потомков, Explorer переместит окно браузера в допустимую (предковую) папку. Процесс определения новой папки, открываемой в окне обозревателя Explorer, начиная с абсолютного ITEMIDLIST папки, указанной в уведомлении SCHNE_RMDIR:
- Получите IShellFolder для родителя указанного абсолютного ITEMIDLIST.
- Проверьте дочернюю папку, вызвав IShellFolder::GetAttributesOf с флагом SFGAO_VALIDATE.
- Если GetAttributesOf сообщает, что элемент недействителен (возвращает ошибку), получите абсолютный ITEMIDLIST родительской папки и вернитесь к шагу 1.
- Если GetAttributesOf сообщает, что элемент действителен, вызовите IShellBrowser::BrowseObject окна браузера, чтобы перейти к допустимой папке.
На этапах воспроизведения, которые вы разместили в Stackru, у нас открываются окна браузера Explorer для следующих папок:
::{CLSID_MyComputer}::{CLSID_My расширение пространства имен}
::{CLSID_MyComputer}::{CLSID_My расширение пространства имен}\FolderToRemove
::{CLSID_MyComputer}::{CLSID_My расширение пространства имен}\FolderToRemove\subFolder
Вот как уведомление SHCNE_RMDIR для
::{CLSID_MyComputer}\::{CLSID_My Namespace Extension}\FolderToRemove
Папка обрабатывается окнами браузера:
Окно браузера переместилось на ::{CLSID_MyComputer}\::{CLSID_My Namespace Extension}
:
- Ничего не предпринимайте, поскольку эта папка не является удаляемой папкой или ее потомком.
Окно браузера переместилось на ::{CLSID_MyComputer}\::{CLSID_My Namespace Extension}\FolderToRemove
- Получите IShellFolder для папки::{CLSID_MyComputer}::{CLSID_My расширение пространства имен} и вызовите IShellFolder::GetAttributesOf(SFGAO_VALIDATE) в FolderToRemove.
- GetAttributesOf возвращает S_OK, поскольку FolderToRemove фактически не был удален.
- GetAttributesOf сообщает, что FolderToRemove является допустимым, это допустимая папка, вызовите IShellBrowser::BrowseObject для::{CLSID_MyComputer}::{CLSID_My расширение пространства имен}\FolderToRemove. По сути, это запрет, так как окно браузера уже перемещено в папку.
Окно браузера переместилось на ::{CLSID_MyComputer}\::{CLSID_My Namespace Extension}\FolderToRemove\subFolder
- Мы начнем с ITEMIDLIST папки::{CLSID_MyComputer}::{CLSID_My расширение пространства имен}\FolderToRemove, поскольку это папка, которая была указана в уведомлении SHCNE_RMDIR, а окно браузера перемещается в папку-потомок.
- Получите IShellFolder для папки::{CLSID_MyComputer}::{CLSID_My расширение пространства имен} и вызовите IShellFolder::GetAttributesOf(SFGAO_VALIDATE) в FolderToRemove.
- GetAttributesOf возвращает S_OK, поскольку FolderToRemove фактически не был удален.
- GetAttributesOf сообщает, что FolderToRemove является допустимым, это допустимая папка, вызовите IShellBrowser::BrowseObject для::{CLSID_MyComputer}::{CLSID_My расширение пространства имен}\FolderToRemove.
- Окно браузера переходит к FolderToRemoveFolder.