如何安全地从 SHNotify 事件中获取新文件名 (SHCNE_RENAMEITEM)

How to safely get the new filename from SHNotify event (SHCNE_RENAMEITEM)

我已经连接到 Windows shell,并且正在很好地接收到我隐藏的 CWnd

的通知事件

当我收到 SHCNE_RENAMEITEM 事件时,SHGetPathFromIDList() 函数 returns 我得到旧文件名,而不是重命名的新文件名。

我已经成功破解了一个指针并发现了新名称,但这对我来说并不是很安全。我尝试使用 ILNext/ILGetNext/ILIsEmpty 来迭代列表,但这些并没有给我新名称。有没有更安全的方法?

afx_msg LRESULT OnChange(WPARAM wParam, LPARAM lParam)
{
   long lEvent = 0L;
   PIDLIST_ABSOLUTE* rgpidl=nullptr;
   TCHAR szFileOld[MAX_PATH] = L"[=11=]";
   TCHAR szFileNew[MAX_PATH] = L"[=11=]";
        
   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;
}

我应该提到我的注册码正在使用新的交付方式。

    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);

您的方向是正确的,但您的语法只是 over-complicated。 SHChangeNotification_Lock() 会给你一个指向 PIDL 数组的指针,你不需要花哨的 type-casts 来访问该数组的元素。

此外,您需要在退出回调函数之前调用 SHChangeNotification_Unlock()

尝试更像这样的东西:

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"[=10=]";
        WCHAR szFileNew[MAX_PATH] = L"[=10=]"; 
        SHGetPathFromIDListW(rgpidl[0], szFileOld); 
        SHGetPathFromIDListW(rgpidl[1], szFileNew);

    }
    // other code.

    SHChangeNotification_Unlock(hNotifyLock);

    return FALSE;
}