Recognize Windows Shell Special Folder (i.e. get its CSIDL) via its pIDL (Now determine if pIDLs are equal with C#)

偶尔善良 提交于 2019-11-29 10:49:01
Carl G

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

static bool pIdlsAreEquivalent(IntPtr pIdl1, IntPtr pIdl2)
{
    if (pIdl1 == pIdl2) return true;
    if (pIdl1 == IntPtr.Zero || pIdl2 == IntPtr.Zero) return false;
    int pIdl1Size = GetItemIDSize(pIdl1);
    if (pIdl1Size != GetItemIDSize(pIdl2)) return false;
    byte[] byteArray1 = new byte[pIdl1Size];
    byte[] byteArray2 = new byte[pIdl1Size];
    Marshal.Copy(pIdl1, byteArray1, 0, pIdl1Size);
    Marshal.Copy(pIdl2, byteArray2, 0, pIdl1Size);
    for (int i = 0; i < pIdl1Size; i++)
    {
        if (byteArray1[i] != byteArray2[i])
            return false;
    }
    return true;
}

static int GetItemIdSize(IntPtr pIdl)
{
    if (pIdl == IntPtr.Zero) return 0;
    int size = 0;
    // Next line throws AccessViolationException
    ITEMIDLIST idl = (ITEMIDLIST)Marshal.PtrToStructure(pIdl, typeof(ITEMIDLIST));
    while (idl.mkid.cb > 0)
    {
        size += idl.mkid.cb;
        pIdl = (IntPtr)((int)pIdl + idl.mkid.cb);
        idl = (ITEMIDLIST)Marshal.PtrToStructure(pIdl, typeof(ITEMIDLIST));
    }
    return size;
}

public struct ITEMIDLIST 
{
    public SHITEMID mkid;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct SHITEMID
{
    public ushort cb; // The size of identifier, in bytes, including cb itself.

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
    public byte[] abID; // A variable-length item identifier.
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!