I've hooked into the Windows shell, and am receiving notification events nicely to my hidden CWnd
.
When I receive the SHCNE_RENAMEITEM
event, the SHGetPathFromIDList()
function returns me the old file name, but not the new file name of the rename.
I've successfully hacked a pointer and discovered the new name, but this does not feel very safe to me. I tried using ILNext
/ILGetNext
/ILIsEmpty
to iterate the list, but these do not give me the new name. Is there a safer way?
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;
}
I should mention my registration code is using the New Delivery method.
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);
CodePudding user response:
You are on the right track, but your syntax is just over-complicated. SHChangeNotification_Lock()
will give you a pointer to an array of PIDLs, you don't need fancy type-casts to access the elements of that array.
Also, you need to call SHChangeNotification_Unlock()
before exiting your callback function.
Try something more like this instead:
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;
}