В моем расширении оболочки есть папки, которые на самом деле не существуют в файловой системе, а видны только пользователю.
Когда содержимое этих папок изменяется, я хочу их обновить, и в настоящее время я делаю это тем же способом, что и для обычных папок:
Win32.SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_IDLIST | SHCNF_FLUSH, PIDL, IntPtr.Zero);
В то время как PIDL
- это список идентификаторов папок оболочки, как того требует 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;
}
PIDL
, перебирая папки и их родительские папки, пока не дойду до корневой папки. Для каждой папки я сериализую ее вIntPtr
и добавляю в массив. Порядок массива таков, что моя текущая папка является последней, а корневая папка - первой. В конце я создаю единыйPIDL
из корневых данных и из массива. - person Mugen   schedule 15.03.2015CreatePIDL
. Я не делюсь им, потому что предпочитаю делиться как можно реже, этот код чувствителен. - person Mugen   schedule 15.03.2015IFolderItem
на основе некоторого корпоративного кода. Как вы думаете, какая область может быть актуальной?rootPIDL
свойство? - person Mugen   schedule 16.03.2015rootPIDL
, используя значение, данное мнеIPersistFolder.Initialize()
. Как вы думаете, проблема может быть вCreatePIDL()
? - person Mugen   schedule 18.05.2015SerializeInt
- это функция, которую я реализую как частьIFolderItem
. Короче говоря, он просто сериализует представление папки в байтовый массив. Он используется оболочкой через многие вызовы API, не доставлял мне никаких проблем в других местах. Реализация довольно громоздкая. Как вы ожидаете, что это сработает? - person Mugen   schedule 18.05.2015