Dans mon extension shell, j'ai des dossiers qui n'existent pas dans le système de fichiers, mais n'apparaissent que pour l'utilisateur.Actualisation d'un dossier qui n'existe pas dans le système de fichiers
Lorsque le contenu de ces dossiers est changé, je veux les rafraîchir, et actuellement je le fais dans la même méthode que je fais pour les dossiers réguliers:
Win32.SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_IDLIST | SHCNF_FLUSH, PIDL, IntPtr.Zero);
Alors PIDL
est une liste d'ID de dossiers shell , comme requis par SHCNF_IDLIST
.
Le problème est que l'explorateur ne gère pas mes dossiers non existants. Au lieu de les rafraîchir, cela me renvoie au dossier racine.
Je sais que je construis correctement le PIDL
puisque ce mécanisme fonctionne pour les dossiers existants, comme mentionné précédemment. Comment puis-je remplacer le gestionnaire par SHChangeNotify
? Ou y a-t-il un meilleur moyen d'appeler l'actualisation?
Edit:
Comment mon PIDL
est généré:
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);
}
Mon CreatePIDL
mise en œuvre:
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;
}
La documentation à https://msdn.microsoft.com/en-us/library/ windows/desktop/bb762118% 28v = vs.85% 29.aspx indique que lors de l'appel de SHCNE_UPDATEDIR, le répertoire doit exister. – Mugen
Quelque chose ne va pas avec votre code. J'utilise SHChangeNotify (SHCNE_UPDATEDIR, SHCNF_IDLIST) pour mettre à jour mes dossiers d'espaces de noms virtuels et cela fonctionne. Pourriez-vous expliquer le terme "PIDL est une liste d'ID de dossiers shell"? –
@DenisAnisimov Mon but est de rafraîchir un dossier donné. Est-ce que ma liste ne contient que le dossier que je veux actualiser? Actuellement, je renvoie une liste de PIDL du répertoire courant et de son parent jusqu'à la racine. Pour obtenir le PIDL d'un élément de dossier donné (qui implémente IShellFolder et IShellFolder2), j'utilise simplement la classe Marshal. – Mugen