通过其pIDL识别Windows Shell特殊文件夹(即获取其CSIDL)(现在确定pIDL是否与C#相等) [英] Recognize Windows Shell Special Folder (i.e. get its CSIDL) via its pIDL (Now determine if pIDLs are equal with C#)

查看:36
本文介绍了通过其pIDL识别Windows Shell特殊文件夹(即获取其CSIDL)(现在确定pIDL是否与C#相等)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a situation where I want to perform special processing on some Windows shell special folders (those corresponding to values in the CSIDL enum.) (My solution must be WinXP compatible.) The problem I'm having is that when I encounter IShellFolders as I work my way down the heirarchy, I cannot find a way to match up the IShellFolders to their CSIDL.

这是我目前的方法:

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

Initialize a static one-to-one data structure (csidlToFromFullPIdl) of all CSIDLs to their pIDLs returned by 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);
}

使用Desktop IShellFolder开始继承:

Start the heirarchy with the Desktop IShellFolder:

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

像这样检索孩子:

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

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

像这样为孩子构造新的完全合格的pIDL:

Construct new fully-qualified pIDLs for the children like so:

_fullPIdl = ShellApi.ILCombine(parentFullPIdl, childRelativePIdl);

(最后,使用以下命令为孩子检索IShellFolder)

(Finally, retrieve the IShellFolder for the child using:)

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

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

The problem I'm having is that neither the childRelativePIdl nor the _fullPIdl correspond to any pIDLs in csidlToFromFullPIdl.

TIA.

在Vista计算机上的FYI 对应于KNOWNFOLDERID的GUID可能是一个解决方案(但对我而言不是,因为我必须与WinXP兼容.)

FYI on Vista machines the GUID corresponding to KNOWNFOLDERIDs may be a solution (but not for me as I must be WinXP compatible.)

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

I should also say that I think using the paths of the special folders (via SHGetSpecialFolderPath) is insufficient because several of the special folders in which I'm interested do not have paths. (E.g., CSIDL_DRIVES and CSIDL_NETWORK.)

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

I'm trying two approaches to this. The first is to use SHGetDataFromIDList to retrieve the Clsid, which I can then compare to known 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;
}

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

The problem with this approach is that the call to SHGetDataFromIDList returns an hResult that corresponds to throwing a NotImplementedException. Does this mean that SHGetDataFromIDList is unavailable on my system? (WinXP SP3.)

我的第二种方法是比较由两个指向项目标识符列表的指针引用的项目标识符列表,并查看它们是否相等.我正在C中实现一种在此处编码的技术.到目前为止,我是这样的:

My second approach is to compare the item identifier lists referenced by two pointers to item identifier lists and see if they are equal. I'm implementing a technique coded here in C. This is what I have so far:

推荐答案

Raymond Chen :项目列表可以是等效,但不逐字节相同.使用 IShellFolder :: CompareIDs 测试等效性.

Per Raymond Chen: ITEMIDLISTs can be equivalent without being byte-for-byte identical. Use IShellFolder::CompareIDs to test equivalence.

这篇关于通过其pIDL识别Windows Shell特殊文件夹(即获取其CSIDL)(现在确定pIDL是否与C#相等)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆