为什么控制面板的 PIDL 会不同?
我认为应该这样做 this 比较 PIDL:IShellFolder::CompareIDs().
I see that one should do this to compare PIDLs: IShellFolder::CompareIDs().
特别是,我试图检测给定的绝对 PIDL(或相对)是否是控制面板的.
In particular, I'm trying to detect if a given absolute PIDL (or relative) is that of the Control Panel.
但是,在实践中,我最终得到了两个 IShellFolder::CompareIDs() 声称不相等的 PIDL,当它们应该相等时(查看每个的 GetDisplayName(),我可以看到我们确实在查看控制面板).
However, in practice I end up with two PIDLs which IShellFolder::CompareIDs() claims are not equal, when they should be (looking at the GetDisplayName() for each, I can see that we're indeed looking at the Control Panel).
基本上,我通过以下方式获取控制面板的绝对 PIDL:
Basically, I'm obtaining the absolute PIDL for the Control panel by:
PIDL iidControlPanel = nullptr;
SHGetSpecialFolderLocation(hwnd, CSIDL_CONTROLS, &iidControlPanel);
然后像这样比较传入的枚举 shell 对象(参见 here 用于上下文 - 简而言之,这是查看枚举 CMFCShellTreeCtrl 内的桌面 shell 命名空间的结果):
And then comparing the incoming enumerated shell object like so (see here for context - in a nutshell this is looking at the results of enumerating the desktop shell namespace inside of CMFCShellTreeCtrl):
bool bIsControlPanel = CompareAbsolutePIDLs(iidControlPanel, pItem->pidlFQ);
作为参考,这里是比较函数:
For reference, here's the comparison function:
bool CompareAbsolutePIDLs(PIDLIST_ABSOLUTE pidl1, PIDLIST_ABSOLUTE pidl2)
{
CComPtr<IShellFolder> ishDesk;
SHGetDesktopFolder(&ishDesk);
HRESULT hr = ishDesk->CompareIDs(SHCIDS_CANONICALONLY, pidl1, pidl2);
return SUCCEEDED(hr) && HRESULT_CODE(hr) == 0;
}
在调试器中,我可以看到每个返回的 GetDisplayName():
In the debugger, I can see that GetDisplayName() for each returns:
"::{26EE0668-A00A-44D7-9371-BEB064C98683}"
"::{26EE0668-A00A-44D7-9371-BEB064C98683}"
在这里您可以看到 PIDL 的十六进制转储:
Here you can see the hex dump of the PIDLs:
1f 70 68 06 ee 26 0a a0 d7 44 93 71 be b0 64 c9 86 83 *0c* 00
1f 70 68 06 ee 26 0a a0 d7 44 93 71 be b0 64 c9 86 83 *00* 00
除了倒数第二个值(00 与 0c)外,底层 PIDLS 也是二进制相同的.我目前不知道为什么它们不同,或者我能做些什么来解决这个问题?!
The underlying PIDLS are also binary identical excepting the penultimate value (00 vs. 0c). I'm currently at a loss as to why they're different, or what I can do to resolve this issue?!
- 是否有另一种方法可以不包含看似虚假的额外空字节的方式获取控件的 PIDL?
- 或者,是否有更好的方法来获取枚举项的 PIDL(CMFCShellTreeCtrol 获取绝对 PIDL 的方式是否存在不足,以至于它无法包含最终的空字节?)
- 有没有办法将控制面板获取为相对 PIDL,然后将其与相对枚举 PIDL(我也有)进行比较?
- ???
推荐答案
这些确实是不同的 shell 对象.您可以使用 SIGDN_NORMALDISPLAY 选项将获得的 PIDL 传递给 SHGetNameFromIDList() 以将它们转换为可读字符串.长的 PIDL(带 0x0c)转换为所有控制面板项",短的 PIDL 转换为控制面板".
These really are different shell objects. You can pass the PIDLs you got to SHGetNameFromIDList() with the SIGDN_NORMALDISPLAY option to convert them to readable strings. The long PIDL (with 0x0c) converts to "All Control Panel Items", the short one converts to "Control Panel".
这个问题是通过使用 SHGetSpecialFolderLocation() 来检索控制面板控件的虚拟文件夹开始的.与桌面根目录下的控制面板对象不同.我认为您需要通过获取控制面板的 PIDL 并忽略虚拟文件夹来解决此问题.一种方法是使用 ILCloneFirst 将虚拟文件夹转换为根对象:
This problem got started by using SHGetSpecialFolderLocation() to retrieve the virtual folder for the Control Panel controls. Distinct from the Control Panel object off the desktop root. I think you need to fix this by obtaining the PIDL for Control Panel and ignore the virtual folder. One way to do so is by using ILCloneFirst to convert the virtual folder to the root object:
PITEMID_CHILD controlPanel = ILCloneFirst(iidControlPanel);
或者您可以硬编码控制面板 CLSID::{26EE0668-A00A-44D7-9371-BEB064C98683}",然后使用 SHParseDisplayName() 将其转换为 PIDL.
Or you can hard-code the control panel CLSID, "::{26EE0668-A00A-44D7-9371-BEB064C98683}", and convert it to a PIDL with SHParseDisplayName().
相关文章