c# - 通过其 pIDL 识别 Windows Shell 特殊文件夹(即获取其 CSIDL)(现在确定 pIDL 是否与 C# 相同)

标签 c# windows-shell

我有一种情况,我想对一些 Windows shell 特殊文件夹(那些对应于 CSIDL 枚举中的值的文件夹)执行特殊处理。(我的解决方案必须与 WinXP 兼容。)我遇到的问题是,当我当我在层次结构中工作时遇到 IShellFolders,我找不到将 IShellFolders 与其 CSIDL 匹配的方法。

这是我目前的做法:

将所有 CSIDL 的静态一对一数据结构 (csidlToFromFullPIdl) 初始化为其由 SHGetSpecialFolderLocation 返回的 pIDL。

foreach (CSIDL csidl in Enum.GetValues(typeof(CSIDL))
{
    IntPtr fullPIdl = IntPtr.Zero;
    int hResult = ShellApi.SHGetSpecialFolderLocation(IntPtr.Zero, csidl, ref fullPIdl);
    if (hResult != 0)
        Marshal.ThrowExceptionForHR(hResult);
    csidlToFromFullPIdl.Add(csidl, fullPIdl);
}

使用 Desktop IShellFolder 开始层次结构:

int hResult = ShellApi.SHGetDesktopFolder(ref _shellFolder);
hResult = ShellApi.SHGetSpecialFolderLocation(IntPtr.Zero, CSIDL.CSIDL_DESKTOP, ref _fullPIdl);

像这样检索 child :

hResult = _shellFolder.EnumObjects(IntPtr.Zero, SHCONTF.SHCONTF_FOLDERS, out pEnum);

// Then repeatedly call:
pEnum.Next(1, out childRelativePIdl, out numberGotten);

像这样为 child 构建新的完全合格的 pIDL:

_fullPIdl = ShellApi.ILCombine(parentFullPIdl, childRelativePIdl);

(最后,使用以下方法检索子项的 IShellFolder:)

hResultUint = parentShellItem.ShellFolder.BindToObject(childRelativePIdl, IntPtr.Zero, ShellApi.IID_IShellFolder, out _shellFolder);

我遇到的问题是 childRelativePIdl 和 _fullPIdl 都不对应于 csidlToFromFullPIdl 中的任何 pIDL。

TIA。

在 Vista 机器上仅供引用 GUID corresponding to KNOWNFOLDERIDs可能是一个解决方案(但对我来说不是,因为我必须与 WinXP 兼容。)

我还应该说,我认为使用特殊文件夹的路径(通过 SHGetSpecialFolderPath)是不够的,因为我感兴趣的几个特殊文件夹没有路径。 (例如,CSIDL_DRIVES 和 CSIDL_NETWORK。)


我正在尝试两种方法。第一种是使用 SHGetDataFromIDList 检索 Clsid,然后我可以将其与已知的 Clsid 进行比较:

public static Guid GetClsidFromFullPIdl(IntPtr fullPIdl)
{
    // Get both parent's IShellFolder and pIDL relative to parent from full pIDL
    IntPtr pParentShellFolder;
    IntPtr relativePIdl = IntPtr.Zero;
    int hResultInt = ShellApi.SHBindToParent(fullPIdl, ShellGuids.IID_IShellFolder, out pParentShellFolder, ref relativePIdl);
    if (hResultInt != (int)HRESULT.S_OK)
        Marshal.ThrowExceptionForHR(hResultInt);
    object parentShellFolderObj = System.Runtime.InteropServices.Marshal.GetTypedObjectForIUnknown(
        pParentShellFolder, typeof(IShellFolder));
    IShellFolder parentShellFolder = (IShellFolder)parentShellFolderObj;

    SHDESCRIPTIONID descriptionId = new SHDESCRIPTIONID();
    IntPtr pDescriptionId = MarshalToPointer(descriptionId);
    // Next line returns hResult corresponding to NotImplementedException
    hResultInt = ShellApi.SHGetDataFromIDList(parentShellFolder, ref relativePIdl, SHGDFIL.SHGDFIL_DESCRIPTIONID, pDescriptionId,
        Marshal.SizeOf(typeof(SHDESCRIPTIONID)));
    if (hResultInt != (int)HRESULT.S_OK)
        Marshal.ThrowExceptionForHR(hResultInt);

    if (parentShellFolder != null)
        Marshal.ReleaseComObject(parentShellFolder);

    return descriptionId.Clsid;
}

static IntPtr MarshalToPointer(object data)
{
    IntPtr pData = Marshal.AllocHGlobal(Marshal.SizeOf(data));
    Marshal.StructureToPtr(data, pData, false);
    return pData;
}

此方法的问题在于,对 SHGetDataFromIDList 的调用会返回一个 hResult,该 hResult 对应于抛出 NotImplementedException。这是否意味着 SHGetDataFromIDList 在我的系统上不可用? (WinXP SP3.)

我的第二种方法是比较两个指向项目标识符列表的指针引用的项目标识符列表,看看它们是否相等。我正在实现一种编码为 here 的技术在 C 中。这是我目前所拥有的:

最佳答案

根据 Raymond Chen : ITEMIDLISTs 可以是等效的,而不是逐字节相同。使用 IShellFolder::CompareIDs测试等价性。

关于c# - 通过其 pIDL 识别 Windows Shell 特殊文件夹(即获取其 CSIDL)(现在确定 pIDL 是否与 C# 相同),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3572220/

相关文章:

c# - 创建 ParseTree(不是 AST)

c - 确定 shell 扩展是作为上下文菜单处理程序还是拖放处理程序调用

windows - ShellIconOverlayIdentifiers - 为什么这么少?

c# - 在 .NET 世界中开始学习 C# 还是 C++ 更好?

c# - 为什么不强制对泛型类型进行类约束?

java - 用于 java kiosk 应用程序的 windows shell

c++ - 如何正确更新托盘通知图标?

registry - windows shell中右键上下文菜单的操作

c# - 哪个更快?正则表达式还是 EndsWith?

c# - 用最小起订量模拟收集行为