Comment obtenir en toute sécurité le nouveau nom de fichier à partir de l'événement SHNotify (SHCNE_RENAMEITEM)


GilesDMiddleton

Je me suis connecté au shell Windows et je reçois bien les événements de notification dans mon fichier CWnd.

Lorsque je reçois l' SHCNE_RENAMEITEMévénement, la SHGetPathFromIDList()fonction me renvoie l'ancien nom de fichier, mais pas le nouveau nom de fichier du renommage.

J'ai réussi à pirater un pointeur et à découvrir le nouveau nom, mais cela ne me semble pas très sûr. J'ai essayé d'utiliser ILNext/ ILGetNext/ ILIsEmptypour parcourir la liste, mais ceux-ci ne me donnent pas le nouveau nom. Existe-t-il un moyen plus sûr ?

afx_msg LRESULT OnChange(WPARAM wParam, LPARAM lParam)
{
   long lEvent = 0L;
   PIDLIST_ABSOLUTE* rgpidl=nullptr;
   TCHAR szFileOld[MAX_PATH] = L"\0";
   TCHAR szFileNew[MAX_PATH] = L"\0";
        
   HANDLE hNotifyLock = SHChangeNotification_Lock((HANDLE)wParam, (DWORD)lParam, &rgpidl, &lEvent);

   if (!SHGetPathFromIDListW((struct _ITEMIDLIST*)*rgpidl, szFileOld))
      return TRUE;

   if (lEvent & SHCNE_RENAMEITEM)
   {    
      struct _ITEMIDLIST* pNext = (struct _ITEMIDLIST*)*(&rgpidl[1]); // yes, I got lucky guessing the synatx.

      if (ILIsEmpty(pNext)) // probably not much safety on this, but trying to be kind.
         return TRUE;

      if (!SHGetPathFromIDListW(pNext, szFileNew)) 
        return TRUE;
   }
// other code.
   return FALSE;
}

Je dois mentionner que mon code d'enregistrement utilise la nouvelle méthode de livraison.

    BOOL fRecursive = FALSE;
    UINT uMsg = WM_FILE_CHANGED;
    long lEvents = SHCNE_UPDATEITEM | SHCNE_DELETE | SHCNE_CREATE | SHCNE_RENAMEITEM | SHCNE_UPDATEDIR;
    int const nSources = SHCNRF_ShellLevel | SHCNRF_InterruptLevel | SHCNRF_NewDelivery;
    SHChangeNotifyEntry const entries[] = { pidlWatch, fRecursive };

    m_lNotificationRegistry = SHChangeNotifyRegister(m_pWnd->m_hWnd, nSources, lEvents, uMsg, ARRAYSIZE(entries), entries);
Rémy Lebeau

Vous êtes sur la bonne voie, mais votre syntaxe est tout simplement trop compliquée. SHChangeNotification_Lock()vous donnera un pointeur vers un tableau de PIDL, vous n'avez pas besoin de conversions de type fantaisistes pour accéder aux éléments de ce tableau.

De plus, vous devez appeler SHChangeNotification_Unlock()avant de quitter votre fonction de rappel.

Essayez plutôt quelque chose comme ceci :

afx_msg LRESULT OnChange(WPARAM wParam, LPARAM lParam)
{
    long lEvent = 0L;
    PIDLIST_ABSOLUTE* rgpidl = nullptr;

    HANDLE hNotifyLock = SHChangeNotification_Lock((HANDLE)wParam, (DWORD)lParam, &rgpidl, &lEvent);

    if (lEvent & SHCNE_RENAMEITEM)
    {
        WCHAR szFileOld[MAX_PATH] = L"\0";
        WCHAR szFileNew[MAX_PATH] = L"\0"; 
        SHGetPathFromIDListW(rgpidl[0], szFileOld); 
        SHGetPathFromIDListW(rgpidl[1], szFileNew);

    }
    // other code.

    SHChangeNotification_Unlock(hNotifyLock);

    return FALSE;
} 

Articles connexes