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

时间:2015-03-12 07:44:48

标签: winapi refresh intptr shell-extensions change-notification

在我的shell扩展中,我有文件系统中实际不存在的文件夹,但只对用户显示。

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

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

PIDLSHCNF_IDLIST所需的shell文件夹ID列表。

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

我知道我正确构造了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;
        }

1 个答案:

答案 0 :(得分:0)

我找到了解决方法。它不漂亮也不是最佳,但效果很好。

我没有使用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);