From 3285f698fde3c22fc02b304602983b9d7c2b284e Mon Sep 17 00:00:00 2001 From: Katayama Hirofumi MZ Date: Fri, 17 May 2024 08:10:15 +0900 Subject: [PATCH] [SHELL32][SDK] SHChangeNotify: Re-work Part 1 (#6898) Making shell change notification implementation better. Now recycle bin icon change is working. JIRA issue: CORE-13950 JIRA issue: CORE-19591 JIRA issue: CORE-11453 - Delete SHSimpleIDListFromPathA/W hacks. - Translate simple PIDLs (coming from SHSimpleIDListFromPathA/W) in CDefView::OnChangeNotify method. - Add CDefView::LV_RefreshIcons method for SHCNE_UPDATEIMAGE change event. - Rename CDefView::LV_ProdItem method as CDefView::LV_UpdateItem. - Call SHUpdateRecycleBinIcon in SHFileOperationW function. - Half-implement SHUpdateRecycleBinIcon. - Call SHChangeNotify in DeleteExt function. --- dll/win32/shell32/CDefView.cpp | 104 +++++++++++++++++----- dll/win32/shell32/dialogs/filetypes.cpp | 7 +- dll/win32/shell32/folders/CFSFolder.cpp | 1 + dll/win32/shell32/folders/CRecycleBin.cpp | 5 ++ dll/win32/shell32/shlfileop.cpp | 2 + dll/win32/shell32/wine/pidl.c | 15 +--- sdk/include/psdk/shlobj.h | 1 + sdk/include/reactos/undocshell.h | 1 + 8 files changed, 99 insertions(+), 37 deletions(-) diff --git a/dll/win32/shell32/CDefView.cpp b/dll/win32/shell32/CDefView.cpp index 50af36089db..655722ee8df 100644 --- a/dll/win32/shell32/CDefView.cpp +++ b/dll/win32/shell32/CDefView.cpp @@ -199,7 +199,9 @@ public: int LV_AddItem(PCUITEMID_CHILD pidl); BOOLEAN LV_DeleteItem(PCUITEMID_CHILD pidl); BOOLEAN LV_RenameItem(PCUITEMID_CHILD pidlOld, PCUITEMID_CHILD pidlNew); - BOOLEAN LV_ProdItem(PCUITEMID_CHILD pidl); + BOOLEAN LV_UpdateItem(PCUITEMID_CHILD pidl); + void LV_RefreshIcon(INT iItem); + void LV_RefreshIcons(); static INT CALLBACK fill_list(LPVOID ptr, LPVOID arg); HRESULT FillList(); HRESULT FillFileMenu(); @@ -973,6 +975,8 @@ BOOLEAN CDefView::LV_DeleteItem(PCUITEMID_CHILD pidl) if (nIndex < 0) return FALSE; + _DoFolderViewCB(SFVM_REMOVINGOBJECT, 0, (LPARAM)pidl); + return m_ListView.DeleteItem(nIndex); } @@ -1015,7 +1019,7 @@ BOOLEAN CDefView::LV_RenameItem(PCUITEMID_CHILD pidlOld, PCUITEMID_CHILD pidlNew return FALSE; } -BOOLEAN CDefView::LV_ProdItem(PCUITEMID_CHILD pidl) +BOOLEAN CDefView::LV_UpdateItem(PCUITEMID_CHILD pidl) { int nItem; LVITEMW lvItem; @@ -1028,6 +1032,8 @@ BOOLEAN CDefView::LV_ProdItem(PCUITEMID_CHILD pidl) if (-1 != nItem) { + _DoFolderViewCB(SFVM_UPDATINGOBJECT, 0, (LPARAM)pidl); + lvItem.mask = LVIF_IMAGE; lvItem.iItem = nItem; lvItem.iSubItem = 0; @@ -1040,6 +1046,31 @@ BOOLEAN CDefView::LV_ProdItem(PCUITEMID_CHILD pidl) return FALSE; } +void CDefView::LV_RefreshIcon(INT iItem) +{ + ASSERT(m_ListView); + + LVITEMW lvItem = { LVIF_IMAGE }; + lvItem.iItem = iItem; + lvItem.iImage = I_IMAGECALLBACK; + m_ListView.SetItem(&lvItem); + m_ListView.Update(iItem); +} + +void CDefView::LV_RefreshIcons() +{ + ASSERT(m_ListView); + + for (INT iItem = -1;;) + { + iItem = ListView_GetNextItem(m_ListView, iItem, LVNI_ALL); + if (iItem == -1) + break; + + LV_RefreshIcon(iItem); + } +} + INT CALLBACK CDefView::fill_list(LPVOID ptr, LPVOID arg) { PITEMID_CHILD pidl = static_cast(ptr); @@ -2311,46 +2342,75 @@ LRESULT CDefView::OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & return FALSE; } - BOOL bParent0 = ILIsParentOrSpecialParent(m_pidlParent, Pidls[0]); - BOOL bParent1 = ILIsParentOrSpecialParent(m_pidlParent, Pidls[1]); - TRACE("(%p)(%p,%p,0x%08x)\n", this, Pidls[0], Pidls[1], lParam); + // Translate PIDLs. + // SHSimpleIDListFromPathW creates fake PIDLs (lacking some attributes) + // FIXME: Use SHGetRealIDL + CComHeapPtr pidl0(Pidls[0]), pidl1(Pidls[1]); + WCHAR path[MAX_PATH]; + if (pidl0 && SHGetPathFromIDListW(pidl0, path) && PathFileExistsW(path)) + { + pidl0.Free(); + pidl0.Attach(ILCreateFromPathW(path)); + } + if (pidl1 && SHGetPathFromIDListW(pidl1, path) && PathFileExistsW(path)) + { + pidl1.Free(); + pidl1.Attach(ILCreateFromPathW(path)); + } + + PITEMID_CHILD child0 = NULL, child1 = NULL; + if (ILIsParentOrSpecialParent(m_pidlParent, pidl0)) + child0 = ILFindLastID(pidl0); + if (ILIsParentOrSpecialParent(m_pidlParent, pidl1)) + child1 = ILFindLastID(pidl1); + lEvent &= ~SHCNE_INTERRUPT; switch (lEvent) { case SHCNE_MKDIR: case SHCNE_CREATE: case SHCNE_DRIVEADD: - if (bParent0) - { - if (LV_FindItemByPidl(ILFindLastID(Pidls[0])) == -1) - LV_AddItem(ILFindLastID(Pidls[0])); - else - LV_ProdItem(ILFindLastID(Pidls[0])); - } + if (!child0) + break; + if (LV_FindItemByPidl(child0) < 0) + LV_AddItem(child0); + else + LV_UpdateItem(child0); break; case SHCNE_RMDIR: case SHCNE_DELETE: case SHCNE_DRIVEREMOVED: - if (bParent0) - LV_DeleteItem(ILFindLastID(Pidls[0])); + if (child0) + LV_DeleteItem(child0); break; case SHCNE_RENAMEFOLDER: case SHCNE_RENAMEITEM: - if (bParent0 && bParent1) - LV_RenameItem(ILFindLastID(Pidls[0]), ILFindLastID(Pidls[1])); - else if (bParent0) - LV_DeleteItem(ILFindLastID(Pidls[0])); - else if (bParent1) - LV_AddItem(ILFindLastID(Pidls[1])); + if (child0 && child1) + LV_RenameItem(child0, child1); + else if (child0) + LV_DeleteItem(child0); + else if (child1) + LV_AddItem(child1); break; case SHCNE_UPDATEITEM: - if (bParent0) - LV_RenameItem(ILFindLastID(Pidls[0]), ILFindLastID(Pidls[0])); + if (child0) + LV_UpdateItem(child0); + break; + case SHCNE_UPDATEIMAGE: + case SHCNE_MEDIAINSERTED: + case SHCNE_MEDIAREMOVED: + case SHCNE_ASSOCCHANGED: + LV_RefreshIcons(); break; case SHCNE_UPDATEDIR: + case SHCNE_ATTRIBUTES: Refresh(); + UpdateStatusbar(); + break; + case SHCNE_FREESPACE: + UpdateStatusbar(); break; } diff --git a/dll/win32/shell32/dialogs/filetypes.cpp b/dll/win32/shell32/dialogs/filetypes.cpp index 2c245d717ba..1f8403971da 100644 --- a/dll/win32/shell32/dialogs/filetypes.cpp +++ b/dll/win32/shell32/dialogs/filetypes.cpp @@ -66,7 +66,12 @@ DeleteExt(HWND hwndDlg, LPCWSTR pszExt) SHDeleteKeyW(HKEY_CLASSES_ROOT, szValue); // delete ".ext" key - return SHDeleteKeyW(HKEY_CLASSES_ROOT, pszExt) == ERROR_SUCCESS; + BOOL ret = (SHDeleteKeyW(HKEY_CLASSES_ROOT, pszExt) == ERROR_SUCCESS); + + // notify + SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_FLUSHNOWAIT, NULL, NULL); + + return ret; } static inline HICON diff --git a/dll/win32/shell32/folders/CFSFolder.cpp b/dll/win32/shell32/folders/CFSFolder.cpp index b89ecc45579..95a5030a2d3 100644 --- a/dll/win32/shell32/folders/CFSFolder.cpp +++ b/dll/win32/shell32/folders/CFSFolder.cpp @@ -683,6 +683,7 @@ HRESULT SHELL32_GetFSItemAttributes(IShellFolder * psf, LPCITEMIDLIST pidl, LPDW return S_OK; } +// This method is typically invoked from SHSimpleIDListFromPathA/W. HRESULT CFSFolder::_ParseSimple( _In_ LPOLESTR lpszDisplayName, _Inout_ WIN32_FIND_DATAW *pFind, diff --git a/dll/win32/shell32/folders/CRecycleBin.cpp b/dll/win32/shell32/folders/CRecycleBin.cpp index c8bceb589f4..3ade1981118 100644 --- a/dll/win32/shell32/folders/CRecycleBin.cpp +++ b/dll/win32/shell32/folders/CRecycleBin.cpp @@ -1078,6 +1078,11 @@ EXTERN_C HRESULT WINAPI SHUpdateRecycleBinIcon(void) { FIXME("stub\n"); + // HACK! This dwItem2 should be the icon index in the system image list that has changed. + // FIXME: Call SHMapPIDLToSystemImageListIndex + DWORD dwItem2 = -1; + + SHChangeNotify(SHCNE_UPDATEIMAGE, SHCNF_DWORD, NULL, &dwItem2); return S_OK; } diff --git a/dll/win32/shell32/shlfileop.cpp b/dll/win32/shell32/shlfileop.cpp index f1ecc455428..5e1309aabdf 100644 --- a/dll/win32/shell32/shlfileop.cpp +++ b/dll/win32/shell32/shlfileop.cpp @@ -2061,6 +2061,8 @@ cleanup: if (lpFileOp->wFunc != FO_DELETE) destroy_file_list(&flTo); + else if (lpFileOp->fFlags & FOF_ALLOWUNDO) + SHUpdateRecycleBinIcon(); if (ret == ERROR_CANCELLED) lpFileOp->fAnyOperationsAborted = TRUE; diff --git a/dll/win32/shell32/wine/pidl.c b/dll/win32/shell32/wine/pidl.c index 824af18984a..33495aead3a 100644 --- a/dll/win32/shell32/wine/pidl.c +++ b/dll/win32/shell32/wine/pidl.c @@ -1113,15 +1113,6 @@ LPITEMIDLIST WINAPI SHSimpleIDListFromPathA(LPCSTR lpszPath) wPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); MultiByteToWideChar(CP_ACP, 0, lpszPath, -1, wPath, len); } -#ifdef __REACTOS__ - // FIXME: Needs folder attribute - if (PathFileExistsW(wPath)) - { - pidl = ILCreateFromPathW(wPath); - HeapFree(GetProcessHeap(), 0, wPath); - return pidl; - } -#endif _ILParsePathW(wPath, NULL, TRUE, &pidl, NULL); @@ -1135,13 +1126,9 @@ LPITEMIDLIST WINAPI SHSimpleIDListFromPathW(LPCWSTR lpszPath) LPITEMIDLIST pidl = NULL; TRACE("%s\n", debugstr_w(lpszPath)); -#ifdef __REACTOS__ - // FIXME: Needs folder attribute - if (PathFileExistsW(lpszPath)) - return ILCreateFromPathW(lpszPath); -#endif _ILParsePathW(lpszPath, NULL, TRUE, &pidl, NULL); + TRACE("%s %p\n", debugstr_w(lpszPath), pidl); return pidl; } diff --git a/sdk/include/psdk/shlobj.h b/sdk/include/psdk/shlobj.h index 3d27f328631..bd60c13064c 100644 --- a/sdk/include/psdk/shlobj.h +++ b/sdk/include/psdk/shlobj.h @@ -1323,6 +1323,7 @@ SHCreateShellFolderViewEx( #define SFVM_SETISFV 39 #define SFVM_GETEXTVIEWS 40 /* undocumented */ #define SFVM_THISIDLIST 41 +#define SFVM_UPDATINGOBJECT 43 /* undocumented */ #define SFVM_ADDPROPERTYPAGES 47 #define SFVM_BACKGROUNDENUMDONE 48 #define SFVM_GETNOTIFY 49 diff --git a/sdk/include/reactos/undocshell.h b/sdk/include/reactos/undocshell.h index 0460a261cb7..94f6bf71702 100644 --- a/sdk/include/reactos/undocshell.h +++ b/sdk/include/reactos/undocshell.h @@ -122,6 +122,7 @@ typedef struct _SHCNF_PRINTJOB_INFO #define SHCNF_PRINTJOBA 0x0004 #define SHCNF_PRINTJOBW 0x0007 +HRESULT WINAPI SHUpdateRecycleBinIcon(void); /**************************************************************************** * Shell Common Dialogs