https://git.reactos.org/?p=reactos.git;a=commitdiff;h=7cbca9ad8a9ecb6f433b3556f41aaa46498598b9

commit 7cbca9ad8a9ecb6f433b3556f41aaa46498598b9
Author:     Katayama Hirofumi MZ <katayama.hirofumi...@gmail.com>
AuthorDate: Fri Sep 15 07:50:20 2023 +0900
Commit:     GitHub <nore...@github.com>
CommitDate: Fri Sep 15 07:50:20 2023 +0900

    [SHDOCVW] Implement MRU List for Shell Bag, Part 4 (#5686)
    
    Follow-up to #5646. Implement CMruNode class. CORE-9283
---
 dll/win32/shdocvw/mrulist.cpp | 267 +++++++++++++++++++++++++++++++++++++++---
 1 file changed, 248 insertions(+), 19 deletions(-)

diff --git a/dll/win32/shdocvw/mrulist.cpp b/dll/win32/shdocvw/mrulist.cpp
index 33e91aa0936..f17f4069ff2 100644
--- a/dll/win32/shdocvw/mrulist.cpp
+++ b/dll/win32/shdocvw/mrulist.cpp
@@ -24,6 +24,13 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(shdocvw);
 
+class CMruBase;
+    class CMruShortList;
+    class CMruLongList;
+        class CMruNode;
+            class CMruPidlList;
+class CMruClassFactory;
+
 extern "C" void __cxa_pure_virtual(void)
 {
     ::DebugBreak();
@@ -97,11 +104,11 @@ public:
 
     // Non-standard methods
     virtual BOOL _IsEqual(const SLOTITEMDATA *pItem, LPCVOID pvData, UINT 
cbData) const;
-    virtual HRESULT _DeleteValue(LPCWSTR pszValue);
+    virtual DWORD _DeleteValue(LPCWSTR pszValue);
     virtual HRESULT _InitSlots() = 0;
     virtual void _SaveSlots() = 0;
     virtual UINT _UpdateSlots(UINT iSlot) = 0;
-    virtual void _SlotString(DWORD dwSlot, LPWSTR psz, DWORD cch) = 0;
+    virtual void _SlotString(UINT iSlot, LPWSTR psz, DWORD cch) = 0;
     virtual HRESULT _GetSlot(UINT iSlot, UINT *puSlot) = 0;
     virtual HRESULT _RemoveSlot(UINT iSlot, UINT *puSlot) = 0;
 
@@ -399,7 +406,7 @@ BOOL CMruBase::_IsEqual(const SLOTITEMDATA *pItem, LPCVOID 
pvData, UINT cbData)
     }
 }
 
-HRESULT CMruBase::_DeleteValue(LPCWSTR pszValue)
+DWORD CMruBase::_DeleteValue(LPCWSTR pszValue)
 {
     return SHDeleteValueW(m_hKey, NULL, pszValue);
 }
@@ -435,7 +442,7 @@ protected:
     HRESULT _InitSlots() override;
     void _SaveSlots() override;
     UINT _UpdateSlots(UINT iSlot) override;
-    void _SlotString(DWORD dwSlot, LPWSTR psz, DWORD cch) override;
+    void _SlotString(UINT iSlot, LPWSTR psz, DWORD cch) override;
     HRESULT _GetSlot(UINT iSlot, UINT *puSlot) override;
     HRESULT _RemoveSlot(UINT iSlot, UINT *puSlot) override;
     friend class CMruLongList;
@@ -508,11 +515,11 @@ UINT CMruShortList::_UpdateSlots(UINT iSlot)
     return iData;
 }
 
-void CMruShortList::_SlotString(DWORD dwSlot, LPWSTR psz, DWORD cch)
+void CMruShortList::_SlotString(UINT iSlot, LPWSTR psz, DWORD cch)
 {
     if (cch >= 2)
     {
-        psz[0] = (WCHAR)(L'a' + dwSlot);
+        psz[0] = (WCHAR)(L'a' + iSlot);
         psz[1] = UNICODE_NULL;
     }
 }
@@ -556,7 +563,7 @@ protected:
     HRESULT _InitSlots() override;
     void _SaveSlots() override;
     UINT _UpdateSlots(UINT iSlot) override;
-    void _SlotString(DWORD dwSlot, LPWSTR psz, DWORD cch) override;
+    void _SlotString(UINT iSlot, LPWSTR psz, DWORD cch) override;
     HRESULT _GetSlot(UINT iSlot, UINT *puSlot) override;
     HRESULT _RemoveSlot(UINT iSlot, UINT *puSlot) override;
 
@@ -633,9 +640,9 @@ UINT CMruLongList::_UpdateSlots(UINT iSlot)
     return uSlotData;
 }
 
-void CMruLongList::_SlotString(DWORD dwSlot, LPWSTR psz, DWORD cch)
+void CMruLongList::_SlotString(UINT iSlot, LPWSTR psz, DWORD cch)
 {
-    StringCchPrintfW(psz, cch, L"%d", dwSlot);
+    StringCchPrintfW(psz, cch, L"%d", iSlot);
 }
 
 HRESULT CMruLongList::_GetSlot(UINT iSlot, UINT *puSlot)
@@ -677,20 +684,20 @@ void CMruLongList::_ImportShortList()
     {
         for (;;)
         {
-            UINT uSlot;
-            hr = pShortList->_GetSlot(m_cSlots, &uSlot);
+            UINT iSlot;
+            hr = pShortList->_GetSlot(m_cSlots, &iSlot);
             if (FAILED(hr))
                 break;
 
             SLOTITEMDATA *pItem;
-            hr = pShortList->_GetSlotItem(uSlot, &pItem);
+            hr = pShortList->_GetSlotItem(iSlot, &pItem);
             if (FAILED(hr))
                 break;
 
-            _AddItem(uSlot, (const BYTE*)pItem->pvData, pItem->cbData);
-            pShortList->_DeleteItem(uSlot);
+            _AddItem(iSlot, (const BYTE*)pItem->pvData, pItem->cbData);
+            pShortList->_DeleteItem(iSlot);
 
-            m_puSlotData[m_cSlots++] = uSlot;
+            m_puSlotData[m_cSlots++] = iSlot;
         }
 
         m_bNeedSave = TRUE;
@@ -722,21 +729,38 @@ class CMruNode
     : public CMruLongList
 {
 protected:
-    UINT m_uSlotData = 0;                   // The slot data
+    UINT m_iSlot = 0;                       // The slot index
     CMruNode *m_pParent = NULL;             // The parent
     IShellFolder *m_pShellFolder = NULL;    // The shell folder
 
+    BOOL _InitLate();
+    BOOL _IsEqual(SLOTITEMDATA *pItem, LPCVOID pvData, UINT cbData);
+    DWORD _DeleteValue(LPCWSTR pszValue) override;
+
+    HRESULT _CreateNode(UINT iSlot, CMruNode **ppNewNode);
+    HRESULT _AddPidl(UINT iSlot, LPCITEMIDLIST pidl);
+    HRESULT _FindPidl(LPCITEMIDLIST pidl, UINT *piSlot);
+    HRESULT _GetPidlSlot(LPCITEMIDLIST pidl, BOOL bAdd, UINT *piSlot);
+
 public:
     CMruNode() { }
-    CMruNode(CMruNode *pParent, UINT uSlotData);
+    CMruNode(CMruNode *pParent, UINT iSlot);
     ~CMruNode() override;
 
     CMruNode *GetParent();
+
+    HRESULT BindToSlot(UINT iSlot, IShellFolder **ppSF);
+    HRESULT GetNode(BOOL bAdd, LPCITEMIDLIST pidl, CMruNode **pNewNode);
+    HRESULT GetNodeSlot(UINT *piSlot);
+    HRESULT SetNodeSlot(UINT iSlot);
+
+    HRESULT RemoveLeast(UINT *piSlot);
+    HRESULT Clear(CMruPidlList *pList);
 };
 
-CMruNode::CMruNode(CMruNode *pParent, UINT uSlotData)
+CMruNode::CMruNode(CMruNode *pParent, UINT iSlot)
 {
-    m_uSlotData = uSlotData;
+    m_iSlot = iSlot;
     m_pParent = pParent;
     pParent->AddRef();
 }
@@ -763,6 +787,183 @@ CMruNode *CMruNode::GetParent()
     return m_pParent;
 }
 
+HRESULT CMruNode::_CreateNode(UINT iSlot, CMruNode **ppNewNode)
+{
+    CMruNode *pNewNode = new CMruNode(this, iSlot);
+    if (!pNewNode)
+        return E_OUTOFMEMORY;
+
+    WCHAR szBuff[12];
+    _SlotString(iSlot, szBuff, _countof(szBuff));
+
+    HRESULT hr = pNewNode->InitData(m_cSlotRooms, 0, m_hKey, szBuff, NULL);
+    if (FAILED(hr))
+        pNewNode->Release();
+    else
+        *ppNewNode = pNewNode;
+
+    return hr;
+}
+
+HRESULT CMruNode::GetNode(BOOL bAdd, LPCITEMIDLIST pidl, CMruNode **ppNewNode)
+{
+    if (!pidl || !pidl->mkid.cb)
+    {
+        *ppNewNode = this;
+        AddRef();
+        return S_OK;
+    }
+
+    if (!_InitLate())
+        return E_FAIL;
+
+    UINT iSlot;
+    HRESULT hr = _GetPidlSlot(pidl, bAdd, &iSlot);
+    if (FAILED(hr))
+    {
+        if (!bAdd)
+        {
+            *ppNewNode = this;
+            AddRef();
+            return S_FALSE;
+        }
+        return hr;
+    }
+
+    CMruNode *pNewNode;
+    hr = _CreateNode(iSlot, &pNewNode);
+    if (SUCCEEDED(hr))
+    {
+        _SaveSlots();
+
+        LPCITEMIDLIST pidl2 = (LPCITEMIDLIST)((LPBYTE)pidl + pidl->mkid.cb);
+        pNewNode->GetNode(bAdd, pidl2, ppNewNode);
+        pNewNode->Release();
+    }
+
+    return hr;
+}
+
+HRESULT CMruNode::BindToSlot(UINT iSlot, IShellFolder **ppSF)
+{
+    SLOTITEMDATA *pItem;
+    HRESULT hr = _GetSlotItem(iSlot, &pItem);
+    if (FAILED(hr))
+        return hr;
+
+    return m_pShellFolder->BindToObject((LPITEMIDLIST)pItem->pvData,
+                                        NULL,
+                                        IID_IShellFolder,
+                                        (void **)ppSF);
+}
+
+BOOL CMruNode::_InitLate()
+{
+    if (!m_pShellFolder)
+    {
+        if (m_pParent)
+            m_pParent->BindToSlot(m_iSlot, &m_pShellFolder);
+        else
+            SHGetDesktopFolder(&m_pShellFolder);
+    }
+    return !!m_pShellFolder;
+}
+
+BOOL CMruNode::_IsEqual(SLOTITEMDATA *pItem, LPCVOID pvData, UINT cbData)
+{
+    return m_pShellFolder->CompareIDs(0x10000000,
+                                      (LPITEMIDLIST)pItem->pvData,
+                                      (LPCITEMIDLIST)pvData) == 0;
+}
+
+HRESULT CMruNode::GetNodeSlot(UINT *piSlot)
+{
+    DWORD dwData, cbData = sizeof(dwData);
+    DWORD error = SHGetValueW(m_hKey, NULL, L"NodeSlot", NULL, &dwData, 
(piSlot ? &cbData : NULL));
+    if (error != ERROR_SUCCESS)
+        return E_FAIL;
+    *piSlot = (UINT)dwData;
+    return S_OK;
+}
+
+HRESULT CMruNode::SetNodeSlot(UINT iSlot)
+{
+    DWORD dwData = iSlot;
+    if (SHSetValueW(m_hKey, NULL, L"NodeSlot", REG_DWORD, &dwData, 
sizeof(dwData)) != ERROR_SUCCESS)
+        return E_FAIL;
+    return S_OK;
+}
+
+HRESULT CMruNode::_AddPidl(UINT iSlot, LPCITEMIDLIST pidl)
+{
+    return CMruBase::_AddItem(iSlot, (const BYTE*)pidl, sizeof(WORD) + 
pidl->mkid.cb);
+}
+
+DWORD CMruNode::_DeleteValue(LPCWSTR pszValue)
+{
+    CMruBase::_DeleteValue(pszValue);
+    return SHDeleteKeyW(m_hKey, pszValue);
+}
+
+HRESULT CMruNode::_FindPidl(LPCITEMIDLIST pidl, UINT *piSlot)
+{
+    return FindData((const BYTE *)pidl, sizeof(WORD) + pidl->mkid.cb, piSlot);
+}
+
+HRESULT CMruNode::_GetPidlSlot(LPCITEMIDLIST pidl, BOOL bAdd, UINT *piSlot)
+{
+    LPITEMIDLIST pidlFirst = ILCloneFirst(pidl);
+    if (!pidlFirst)
+        return E_OUTOFMEMORY;
+
+    UINT iSlot;
+    HRESULT hr = _FindPidl(pidlFirst, &iSlot);
+    if (SUCCEEDED(hr))
+    {
+        *piSlot = _UpdateSlots(iSlot);
+        hr = S_OK;
+    }
+    else if (bAdd)
+    {
+        *piSlot = _UpdateSlots(m_cSlots);
+        hr = _AddPidl(*piSlot, pidlFirst);
+    }
+
+    ILFree(pidlFirst);
+    return hr;
+}
+
+HRESULT CMruNode::RemoveLeast(UINT *piSlot)
+{
+    if (!m_cSlots)
+    {
+        CMruNode::GetNodeSlot(piSlot);
+        return S_FALSE;
+    }
+
+    UINT uSlot;
+    HRESULT hr = _GetSlot(m_cSlots - 1, &uSlot);
+    if (FAILED(hr))
+        return hr;
+
+    CMruNode *pNode;
+    hr = CMruNode::_CreateNode(uSlot, &pNode);
+    if (SUCCEEDED(hr))
+    {
+        hr = pNode->RemoveLeast(piSlot);
+        pNode->Release();
+    }
+
+    if (hr == S_FALSE)
+    {
+        Delete(m_cSlots - 1);
+        if (m_cSlots || SUCCEEDED(GetNodeSlot(0)))
+            return S_OK;
+    }
+
+    return hr;
+}
+
 class CMruPidlList
     : public IMruPidlList
     , public CMruNode
@@ -821,6 +1022,8 @@ public:
         UINT *puSlots,
         UINT *pcSlots) override;
     STDMETHODIMP PruneKids(LPCITEMIDLIST pidl) override;
+
+    void EmptyNodeSlot(UINT iSlot);
 };
 
 STDMETHODIMP CMruPidlList::QueryInterface(REFIID riid, void **ppvObj)
@@ -888,6 +1091,32 @@ EXTERN_C HRESULT CMruPidlList_CreateInstance(DWORD_PTR 
dwUnused1, void **ppv, DW
     return S_OK;
 }
 
+void CMruPidlList::EmptyNodeSlot(UINT iSlot)
+{
+    m_pbSlots[iSlot - 1] = 0;
+    m_bNeedSave = TRUE;
+}
+
+HRESULT CMruNode::Clear(CMruPidlList *pList)
+{
+    UINT uSlot;
+    while (SUCCEEDED(_GetSlot(0, &uSlot)))
+    {
+        CMruNode *pNode;
+        if (SUCCEEDED(CMruNode::_CreateNode(uSlot, &pNode)))
+        {
+            UINT iSlot;
+            if (SUCCEEDED(pNode->GetNodeSlot(&iSlot)))
+                pList->EmptyNodeSlot(iSlot);
+
+            pNode->Clear(pList);
+            pNode->Release();
+        }
+        Delete(0);
+    }
+    return S_OK;
+}
+
 class CMruClassFactory : public IClassFactory
 {
 protected:

Reply via email to