前言
对于部分Windows用户来说,出于个性化或系统盘污染等其它方面考虑,可能会有重定向桌面地址的需求。
对于常规用户来说,Windows的资源管理器自带的桌面的UserAssist面板配置(即右键桌面
文件夹项的属性面板)已经能够满足此要求。利用面板的位置
栏,能够方便地完成对桌面的迁移,具体操作见下图:Process Monitor工具完成对进程行为的监控。
简单熟悉Process Monitor的操作方法后,考虑到非编程方法方便直接操作的只有注册表,故而将监控的目标设定为Explorer.exe
,Operation
筛选为包含 Reg 且包含 Key
。再根据经验判断,能够显式的与变化关联的应当只有写操作,对于注册表来说即RegSetKeyValue
与RegCreateKey
方法。
完成以上设定后,操作系统自带的桌面移动面板,监控确定按钮按下
到桌面完成迁移
时间段内的行为。
以下为监控期间发生的行为(仅供参考):
因为重定向是地址字符串的变动,所以优先考虑注册表键值类型为REG_SZ
或REG_EXPAND_SZ
的键。可以发现变动的恰好是User Shell Folders
、Shell Folders
两项的Desktop
值。其后浏览其他键值变更,可以简单判断并非是影响目标的关键因素。此时可以确定该两项注册表项即为影响桌面定位的关键。
手动在regedit
修改两项的关联键值,并尝试手动F5
刷新,发现并未桌面并未更新。重启资源管理器后完成刷新。
重复监控过程,观察Explorer.exe
在注册表之外的其它操作,可以发现在上述注册表项修改完之后Explorer.exe
直接进行了文件映射的创建。此时基本可以判断在注册表项更新后或是更新前,存在某项操作通知了资源管理器操作的发生,而该操作并未被Process Monitor捕获,故无法继续使用非编程方法完成桌面的重定向。
(二)猜测 + 黑箱方法
尝试定位影响桌面路径的因素时,几个关键词是必不可少的。
合理利用Explorer
、Desktop
、Folder
、${当前桌面路径}
、${重定向后桌面路径}
几个关键字搜索筛选出可能相关的表项,并考察桌面重定向前后表项键值的变更情况,同样不难筛选出Shell Folders
、User Shell Folders
两个关联项。
后续操作同上。
总结
上述几种方法都能够较快的筛选出关联注册表项,但是没有编程方法的介入,都难以像Windows自带面板提供的操作那样完成高效、无缝切换。
从WINAPI切入
在方法①中,可以注意到桌面
跟一个名为Shell Folder
的对象脱不开关系。通过对MS DOC的查阅可以知道,Shell Folder
是Shell对象范畴内对文件夹的一类拓展,其扩大了文件夹的范畴,允许通过自定义的具体实现将异形对象抽象为文件夹实例。其中链接向物理路径的Shell Folder
实现于系统内置的Shell File System Folder
接口。
Shell Folder在微软文档中并无专门的篇幅描述,相关的样例代码也给得不多。对于初次接触到WINAPI Shell编程的人,庞大的框架与零散的API可能导致思路梳理困难,流程运行逻辑不清。
如若实在需要实例代码,可以尝试访问HotExample进行搜索。
此外,本文不会对相关内容进行过多阐述。
在Windows中,每一个Shell实例(通常)都有GUID描述符,对于Shell Folder
,其GUID可以在WINSDK - knownfolders.h
中找到。
在其中可以看到Desktop
的GUID为{B4BFCC3A-DB2C-424C-B029-7FE99A87C641}
。转向对注册表的访问,可以在SOFTWARE\Classes\CLSID
下找到该项。
浏览子项与键值可以发现,Desktop
继承自{0E5AAE11-A475-4c5b-AB00-C66DE400274E}
也即Shell File System Folder
,而从Instance\InitPropertyBag\TargetKnownFolder
可以知道,该Shell Folder
(即Desktop
)是指向同名实例的。
需要提及的是,Instance\InitPropertyBag\TargetFolderPath
与TargetKnownFolder
一样都是用于指定文件夹路径的,不同的是,前者指定的是具体路径,而后者指定了预定义的Folder ID
。
不过,借助相关资料和注册表搜索可以发现,此处的{B4BFCC3A-DB2C-424C-B029-7FE99A87C641}
并非是一个自引用。在CLSID
下定义的Shell Folder
最终会引用在SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FolderDescriptions
中定义的Folder ID
,最终传递给Explorer.exe
。
以下是二者的注册表项层级结构:
+ CLSID\{B4BFCC3A-DB2C-424C-B029-7FE99A87C641} - DescriptionID - System.IsPinnedToNameSpaceTree + DefaultIcon - (Default): C:\Windows\system32\imageres.dll,-183 + InProcServer32 - (Default): C:\Windows\system32\shell32.dll - ThreadingModel: Both + Instance - CLSID: {0E5AAE11-A475-4c5b-AB00-C66DE400274E} + InitPropertyBag - Attributes - TargetKnownFolder: {B4BFCC3A-DB2C-424C-B029-7FE99A87C641} + ShellFolder - Attributes - FolderValueFlags - SortOrderIndex + FolderDescriptions\{B4BFCC3A-DB2C-424C-B029-7FE99A87C641} - Attributes - Category - Icon: C:\Windows\system32\imageres.dll,-183 - LocalizedName: @C:\Windows\system32\shell32.dll,-21769 - Name: Desktop - PreCreate - PublishExpandedPath - RelativePath: Desktop - Roamable + PropertyBag - NoCustomize
相较于TargetFolderPath
的直接,TargetKnownFolder
则是绕了点弯来实现目标的定位。
从黑箱方法大致可以推断Explorer.exe
对Shell Folder
处理流程如下(不保证为系统实际情形):
FolderDescription\<GUID>\Name
将定义Known Folder
的名称,而Explorer.exe
将通过该名称在Shell Folder
、User Shell Folder
中检索得到其链接的路径。
了解上述流程之后,其实就可以发现重定向文件夹只有两步操作:
变更
Known Folder
的目标路径通知资源管理器
Known Folder
已经发生变化
在Shell对象编程中,有专门的方法SHChangeNotify
用于通知Shell对象相关事件的发生。
仔细阅读文档后,对于方法第一参数的选择可以是SHCNE_UPDATEDIR
或者SHCNE_UPDATEITEM
。
/** path is the re-located path of target known folder */SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_FLUSH | SHCNF_PATH, path, nullptr);
手动修改注册表项并使用上述代码完成对更新事件的分发,发现桌面依旧没有变化。由上述操作的总结,那么在假定事件成功分发的情况下,则可以怀疑被分发的事件并不实际存在,即:“变更 Known Folder 的目标路径”并未真正完成。
查阅官方文档发现存在专门的方法SHSetKnownFolderPath
完成对Known Folder
目标路径的设置。
重写核心代码如下:
#include <shlobj.h>bool SwitchDesktopTo(const wchar_t *path) { auto hr = SHSetKnownFolderPath(FOLDERID_Desktop, 0, nullptr, path); if (!SUCCEEDED(hr)) return false; LPITEMIDLIST list = nullptr; SHGetKnownFolderIDList(FOLDERID_Desktop, 0, nullptr, &list); if (!list) return false; SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_FLUSH | SHCNF_IDLIST, list, nullptr); ILFree(list); return true;}
目标达成,重定向的效果与系统面板提供的方法并无肉眼上的差别。
后期使用Process Monitor对该过程进行监控发现,注册表项的变动依旧限定在Shell Folder
与User Shell Folder
之内,故大致可以推断之前失败的原因在于SHSetKnownFolderPath
除了修改表项键值之外还在方法内部做了额外的操作;也正是因为该部分操作未被纳入手动hack,又导致了SHChangeNotify
没有成功地分发有效事件。
写在最后
到此为止,通过桌面重定向的探索,包含桌面实例在内的一系列IShellFolder
接口实现的外部结构大致清朗的。但是不论是相关注册表项的各键值的含义还是内部handler实现都处于相对模糊的状态。
该部分再通过像本文这样浅显的方法探究就不适合了。归根到底,要搞清楚Shell Object
,就得深入Windows Shell开发,就得通读文档,多联系多思考。
本文描述的Desktop
等同类文件夹作为Shell File System Folder
接口实例的实现,近似于一个简单的路径“快捷方式”,相比于子系统文件系统、共享文件夹、网络邻居这类高级实例还差得远。
共勉!
推荐本站淘宝优惠价购买喜欢的宝贝:
本文链接:https://sg.hqyman.cn/post/4858.html 非本站原创文章欢迎转载,原创文章需保留本站地址!


休息一下~~