刷新文件系统中不存在的文件夹

Refreshing a folder that doesn't exist in the file system

在我的 shell 扩展中,我有一些文件夹实际上并不存在于文件系统中,但只对用户如此显示。

当这些文件夹的内容发生变化时,我想刷新它们,目前我使用与常规文件夹相同的方法进行刷新:

Win32.SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_IDLIST | SHCNF_FLUSH, PIDL, IntPtr.Zero);

PIDL 是 shell 个文件夹 ID 的列表,根据 SHCNF_IDLIST 的要求。

问题是资源管理器无法处理我不存在的文件夹。它没有刷新它们,而是将我送回根文件夹。

我知道我构建 PIDL 是正确的,因为如前所述,此机制适用于现有文件夹。

如何覆盖 SHChangeNotify 的处理程序?或者有更好的调用刷新的方法吗?

编辑:

我的 PIDL 是如何生成的:

    IntPtr GetPIDL(IFolderItem target)
    {
        Stack stack = new Stack(5);
        IntPtr data = IntPtr.Zero;

        byte[] rootPIDL = null;

        IFolderItem curr = target;
        while (curr != null)
        {
            if (curr.rootPIDL != null)
            {
                rootPIDL = curr.rootPIDL;
            }
            else
            {
                data = curr.SerializeInt();
                stack.Push(data);
            }

            curr = curr.ParentFolder;
        }

        if (rootPIDL == null && stack.Count == 0)
            return IntPtr.Zero;

        object[] x = stack.ToArray();

        IntPtr[] pidls = null;

        int count = stack.Count;
        if (count > 0)
        {
            pidls = new IntPtr[stack.Count];
            for (int i = 0; i < count; i++)
            {
                pidls[i] = (IntPtr)stack.Pop();
            }
        }

        return CreatePIDL(rootPIDL, pidls);
    }

我的 CreatePIDL 实现:

        internal unsafe static IntPtr CreatePIDL(byte[] rootPIDL,IntPtr[] pidls)
        {
            int headerSize = Marshal.SizeOf(typeof(ushort));
            int totalSize = headerSize;
            if (rootPIDL != null)
                totalSize += rootPIDL.Length - headerSize;

            if (pidls!=null && pidls.Length > 0)
            {
                foreach (IntPtr data in pidls)
                {
                    totalSize += PIDLSize(data);
                }
            }

            IntPtr ret = PIDLAlloc(totalSize);
            IntPtr currPos = ret;

            if(rootPIDL!=null)
            {
                Marshal.Copy(rootPIDL, 0, currPos, rootLPIFQ.Length - headerSize);
                currPos = Win32.AdvancePtr(currPos, rootLPIFQ.Length - headerSize);
            }

            if (pidls != null && pidls.Length>0)
            {
                foreach (IntPtr data in pidls)
                {
                    int dataLength = PIDLSize(data);
                    Win32.CopyMemory(currPos, data, dataLength);
                    currPos = Win32.AdvancePtr(currPos, dataLength);
                }
           }
           Marshal.WriteInt16(currPos, (short)0);

            return ret;
        }

        internal static unsafe int PIDLSize(IntPtr ptr)
        {
            return (int) (*((ushort*)ptr));
        }

        internal unsafe static IntPtr PIDLAlloc(int size)
        {
            IntPtr ret = Marshal.AllocCoTaskMem(size);
            if (ret == IntPtr.Zero)
                throw new OutOfMemoryException();

            return ret;
        }

我找到了解决方法。它既不漂亮也不理想,但效果很好。

我没有使用 SHCNE_UPDATEDIR 调用通知,而是依次执行以下所有三个通知程序:

Win32.SHChangeNotify(SHCNE_MKDIR, SHCNF_IDLIST | SHCNF_FLUSH, PIDL, IntPtr.Zero);
Win32.SHChangeNotify(SHCNE_CREATE, SHCNF_IDLIST | SHCNF_FLUSH, PIDL, IntPtr.Zero);
Win32.SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST | SHCNF_FLUSH, PIDL, IntPtr.Zero);