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

Car*_*l G 6 c# windows-shell

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

这是我目前的做法:

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

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);
}
Run Code Online (Sandbox Code Playgroud)

使用Desktop IShellFolder启动heirarchy:

int hResult = ShellApi.SHGetDesktopFolder(ref _shellFolder);
hResult = ShellApi.SHGetSpecialFolderLocation(IntPtr.Zero, CSIDL.CSIDL_DESKTOP, ref _fullPIdl);
Run Code Online (Sandbox Code Playgroud)

像这样检索孩子:

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

// Then repeatedly call:
pEnum.Next(1, out childRelativePIdl, out numberGotten);
Run Code Online (Sandbox Code Playgroud)

为孩子们构建新的完全合格的pIDL,如下所示:

_fullPIdl = ShellApi.ILCombine(parentFullPIdl, childRelativePIdl);
Run Code Online (Sandbox Code Playgroud)

(最后,使用:)检索孩子的IShellFolder

hResultUint = parentShellItem.ShellFolder.BindToObject(childRelativePIdl, IntPtr.Zero, ShellApi.IID_IShellFolder, out _shellFolder);
Run Code Online (Sandbox Code Playgroud)

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

TIA.

在Vista机器上的FYI 对应于KNOWNFOLDERIDGUID可能是一个解决方案(但不适合我,因为我必须与WinXP兼容.)

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


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

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;
}
Run Code Online (Sandbox Code Playgroud)

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

我的第二种方法是将两个指针引用的项标识符列表与项标识符列表进行比较,看它们是否相等.我执行编码的技术在这里在C.这是我到目前为止有:

Car*_*l G 3

Per Raymond Chen:ITEMIDLIST 可以是等效的,但无需逐字节相同。使用IShellFolder::CompareIDs测试等效性。