[NTOBJSHEX]
authorDavid Quintana <gigaherz@gmail.com>
Fri, 23 Jun 2017 21:28:36 +0000 (21:28 +0000)
committerDavid Quintana <gigaherz@gmail.com>
Fri, 23 Jun 2017 21:28:36 +0000 (21:28 +0000)
* Added a common superclass for the ntobj and registry folders.
* Refactored the ntobj and registry folders to make use of this superclass.
* Removed the concept of a "pidl helper", since it works best to just have the methods be part of the folders.
* Cleaned up the ItemID comparison logic.

svn path=/trunk/; revision=75175

reactos/dll/shellext/ntobjshex/foldercommon.cpp [new file with mode: 0644]
reactos/dll/shellext/ntobjshex/foldercommon.h [new file with mode: 0644]
reactos/dll/shellext/ntobjshex/ntobjenum.cpp
reactos/dll/shellext/ntobjshex/ntobjfolder.cpp
reactos/dll/shellext/ntobjshex/ntobjfolder.h
reactos/dll/shellext/ntobjshex/precomp.h
reactos/dll/shellext/ntobjshex/regfolder.cpp
reactos/dll/shellext/ntobjshex/regfolder.h

diff --git a/reactos/dll/shellext/ntobjshex/foldercommon.cpp b/reactos/dll/shellext/ntobjshex/foldercommon.cpp
new file mode 100644 (file)
index 0000000..b67e01e
--- /dev/null
@@ -0,0 +1,10 @@
+/*
+ * PROJECT:     ReactOS shell extensions
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        dll/shellext/ntobjshex/ntobjfolder.cpp
+ * PURPOSE:     NT Object Namespace shell extension
+ * PROGRAMMERS: David Quintana <gigaherz@gmail.com>
+ */
+
+#include "precomp.h"
+#include <ntquery.h>
diff --git a/reactos/dll/shellext/ntobjshex/foldercommon.h b/reactos/dll/shellext/ntobjshex/foldercommon.h
new file mode 100644 (file)
index 0000000..f6ffc2c
--- /dev/null
@@ -0,0 +1,676 @@
+/*
+ * PROJECT:     ReactOS shell extensions
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        dll/shellext/ntobjshex/ntobjfolder.h
+ * PURPOSE:     NT Object Namespace shell extension
+ * PROGRAMMERS: David Quintana <gigaherz@gmail.com>
+ */
+#pragma once
+
+extern const GUID CLSID_NtObjectFolder;
+
+class CFolderViewCB :
+    public CComObjectRootEx<CComMultiThreadModelNoCS>,
+    public IShellFolderViewCB
+{
+    IShellView* m_View;
+
+public:
+
+    CFolderViewCB() : m_View(NULL) {}
+    virtual ~CFolderViewCB() {}
+
+    virtual HRESULT STDMETHODCALLTYPE MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
+    {
+        switch (uMsg)
+        {
+        case SFVM_DEFVIEWMODE:
+        {
+            FOLDERVIEWMODE* pViewMode = (FOLDERVIEWMODE*)lParam;
+            *pViewMode = FVM_DETAILS;
+            return S_OK;
+        }
+        case SFVM_COLUMNCLICK:
+            return S_FALSE;
+        case SFVM_BACKGROUNDENUM:
+            return S_OK;
+        }
+
+        DbgPrint("MessageSFVCB unimplemented %d %08x %08x\n", uMsg, wParam, lParam);
+        return E_NOTIMPL;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE Initialize(IShellView* psv)
+    {
+        m_View = psv;
+        return S_OK;
+    }
+
+    DECLARE_NOT_AGGREGATABLE(CFolderViewCB)
+    DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+    BEGIN_COM_MAP(CFolderViewCB)
+        COM_INTERFACE_ENTRY_IID(IID_IShellFolderViewCB, IShellFolderViewCB)
+    END_COM_MAP()
+};
+
+template<class TSelf, typename TItemId, class TExtractIcon>
+class CCommonFolder :
+    public CComObjectRootEx<CComMultiThreadModelNoCS>,
+    public IShellFolder2,
+    public IPersistFolder2
+{
+protected:
+    WCHAR m_NtPath[MAX_PATH];
+
+    LPITEMIDLIST m_shellPidl;
+
+public:
+
+    CCommonFolder() :
+        m_shellPidl(NULL)
+    {
+    }
+
+    virtual ~CCommonFolder()
+    {
+        if (m_shellPidl)
+            ILFree(m_shellPidl);
+    }
+    
+    // IShellFolder
+    virtual HRESULT STDMETHODCALLTYPE ParseDisplayName(
+        HWND hwndOwner,
+        LPBC pbcReserved,
+        LPOLESTR lpszDisplayName,
+        ULONG *pchEaten,
+        LPITEMIDLIST *ppidl,
+        ULONG *pdwAttributes)
+    {
+        if (!ppidl)
+            return E_POINTER;
+
+        if (pchEaten)
+            *pchEaten = 0;
+
+        if (pdwAttributes)
+            *pdwAttributes = 0;
+
+        TRACE("CCommonFolder::ParseDisplayName name=%S (ntPath=%S)\n", lpszDisplayName, m_NtPath);
+
+        const TItemId * info;
+        IEnumIDList * it;
+        HRESULT hr = EnumObjects(hwndOwner, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &it);
+        if (FAILED(hr))
+            return hr;
+
+        PWSTR end = StrChrW(lpszDisplayName, '\\');
+        int length = end ? end - lpszDisplayName : wcslen(lpszDisplayName);
+
+        while (TRUE)
+        {
+            hr = it->Next(1, ppidl, NULL);
+
+            if (FAILED(hr))
+                return hr;
+
+            if (hr != S_OK)
+                return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+
+            hr = GetInfoFromPidl(*ppidl, &info);
+            if (FAILED_UNEXPECTEDLY(hr))
+                return hr;
+
+            if (StrCmpNW(info->entryName, lpszDisplayName, length) == 0)
+                break;
+        }
+
+        // if has remaining path to parse (and the path didn't just terminate in a backslash)
+        if (end && wcslen(end) > 1)
+        {
+            CComPtr<IShellFolder> psfChild;
+            hr = BindToObject(*ppidl, pbcReserved, IID_PPV_ARG(IShellFolder, &psfChild));
+            if (FAILED_UNEXPECTEDLY(hr))
+                return hr;
+
+            LPITEMIDLIST child;
+            hr = psfChild->ParseDisplayName(hwndOwner, pbcReserved, end + 1, pchEaten, &child, pdwAttributes);
+            if (FAILED(hr))
+                return hr;
+
+            LPITEMIDLIST old = *ppidl;
+            *ppidl = ILCombine(old, child);
+            ILFree(old);
+
+            // Count the path separator
+            if (pchEaten)
+                (*pchEaten) += 1;
+        }
+        else
+        {
+            if (pdwAttributes)
+                *pdwAttributes = ConvertAttributes(info, pdwAttributes);
+        }
+
+        if (pchEaten)
+            *pchEaten += wcslen(info->entryName);
+
+        return S_OK;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE EnumObjects(
+        HWND hwndOwner,
+        SHCONTF grfFlags,
+        IEnumIDList **ppenumIDList) PURE;
+
+    virtual HRESULT STDMETHODCALLTYPE BindToObject(
+        LPCITEMIDLIST pidl,
+        LPBC pbcReserved,
+        REFIID riid,
+        void **ppvOut)
+    {
+        const TItemId * info;
+
+        if (IsEqualIID(riid, IID_IShellFolder))
+        {
+            HRESULT hr = GetInfoFromPidl(pidl, &info);
+            if (FAILED_UNEXPECTEDLY(hr))
+                return hr;
+
+            WCHAR path[MAX_PATH];
+
+            StringCbCopyW(path, _countof(path), m_NtPath);
+            PathAppendW(path, info->entryName);
+
+            LPITEMIDLIST first = ILCloneFirst(pidl);
+            LPCITEMIDLIST rest = ILGetNext(pidl);
+
+            LPITEMIDLIST fullPidl = ILCombine(m_shellPidl, first);
+
+            if (IsSymLink(info))
+            {
+                return RedirectToSymLink(info, first, rest, pbcReserved, (IShellFolder**)ppvOut);
+            }
+
+            CComPtr<IShellFolder> psfChild;
+            hr = InternalBindToObject(path, info, first, rest, fullPidl, pbcReserved, &psfChild);
+
+            ILFree(fullPidl);
+            ILFree(first);
+
+            if (FAILED(hr))
+                return hr;
+
+            if (hr == S_FALSE)
+                return S_OK;
+
+            if (rest->mkid.cb > 0)
+            {
+                return psfChild->BindToObject(rest, pbcReserved, riid, ppvOut);
+            }
+
+            return psfChild->QueryInterface(riid, ppvOut);
+        }
+
+        return E_NOTIMPL;
+    }
+
+protected:
+    virtual HRESULT STDMETHODCALLTYPE InternalBindToObject(
+        PWSTR path,
+        const TItemId * info,
+        LPITEMIDLIST first,
+        LPCITEMIDLIST rest, 
+        LPITEMIDLIST fullPidl, 
+        LPBC pbcReserved,
+        IShellFolder** ppsfChild) PURE;
+
+public:
+    virtual HRESULT STDMETHODCALLTYPE RedirectToSymLink(
+        const TItemId * info,
+        LPITEMIDLIST first,
+        LPCITEMIDLIST rest,
+        LPBC pbcReserved,
+        IShellFolder ** ppsfChild)
+    {
+        return E_NOTIMPL;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE BindToStorage(
+        LPCITEMIDLIST pidl,
+        LPBC pbcReserved,
+        REFIID riid,
+        void **ppvObj)
+    {
+        UNIMPLEMENTED;
+        return E_NOTIMPL;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE CompareIDs(
+        LPARAM lParam,
+        LPCITEMIDLIST pidl1,
+        LPCITEMIDLIST pidl2)
+    {
+        HRESULT hr;
+
+        TRACE("CompareIDs %d\n", lParam);
+
+        const TItemId * id1;
+        hr = GetInfoFromPidl(pidl1, &id1);
+        if (FAILED(hr))
+            return E_INVALIDARG;
+
+        const TItemId * id2;
+        hr = GetInfoFromPidl(pidl2, &id2);
+        if (FAILED(hr))
+            return E_INVALIDARG;
+
+        hr = CompareIDs(lParam, id1, id2);
+        if (hr != S_EQUAL)
+            return hr;
+
+        // The wollowing snipped is basically SHELL32_CompareChildren
+
+        PUIDLIST_RELATIVE rest1 = ILGetNext(pidl1);
+        PUIDLIST_RELATIVE rest2 = ILGetNext(pidl2);
+
+        bool isEmpty1 = (rest1->mkid.cb == 0);
+        bool isEmpty2 = (rest2->mkid.cb == 0);
+
+        if (isEmpty1 || isEmpty1)
+            return MAKE_COMPARE_HRESULT(isEmpty2 - isEmpty1);
+
+        LPCITEMIDLIST first1 = ILCloneFirst(pidl1);
+        if (!first1)
+            return E_OUTOFMEMORY;
+
+        CComPtr<IShellFolder> psfNext;
+        hr = BindToObject(first1, NULL, IID_PPV_ARG(IShellFolder, &psfNext));
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
+
+        return psfNext->CompareIDs(lParam, rest1, rest2);
+    }
+
+protected:
+    virtual HRESULT STDMETHODCALLTYPE CompareName(
+        LPARAM lParam,
+        const TItemId * first,
+        const TItemId * second)
+    {
+        bool f1 = IsFolder(first);
+        bool f2 = IsFolder(second);
+
+        HRESULT hr = MAKE_COMPARE_HRESULT(f2 - f1);
+        if (hr != S_EQUAL)
+            return hr;
+
+        bool canonical = (lParam & 0xFFFF0000) == SHCIDS_CANONICALONLY;
+        if (canonical)
+        {
+            // Shortcut: avoid comparing contents if not necessary when the results are not for display.
+            hr = MAKE_COMPARE_HRESULT(second->entryNameLength - first->entryNameLength);
+            if (hr != S_EQUAL)
+                return hr;
+
+            int minlength = min(first->entryNameLength, second->entryNameLength);
+            if (minlength > 0)
+            {
+                hr = MAKE_COMPARE_HRESULT(memcmp(first->entryName, second->entryName, minlength));
+                if (hr != S_EQUAL)
+                    return hr;
+            }
+
+            return S_EQUAL;
+        }
+
+        int minlength = min(first->entryNameLength, second->entryNameLength);
+        if (minlength > 0)
+        {
+            hr = MAKE_COMPARE_HRESULT(StrCmpNW(first->entryName, second->entryName, minlength / sizeof(WCHAR)));
+            if (hr != S_EQUAL)
+                return hr;
+        }
+
+        return MAKE_COMPARE_HRESULT(second->entryNameLength - first->entryNameLength);
+    }
+
+public:
+    virtual HRESULT STDMETHODCALLTYPE CreateViewObject(
+        HWND hwndOwner,
+        REFIID riid,
+        void **ppvOut)
+    {
+        if (!IsEqualIID(riid, IID_IShellView))
+            return E_NOINTERFACE;
+
+        _CComObject<CFolderViewCB> *pcb;
+
+        HRESULT hr = _CComObject<CFolderViewCB>::CreateInstance(&pcb);
+        if (FAILED(hr))
+            return hr;
+
+        pcb->AddRef();
+
+        SFV_CREATE sfv;
+        sfv.cbSize = sizeof(sfv);
+        sfv.pshf = this;
+        sfv.psvOuter = NULL;
+        sfv.psfvcb = pcb;
+
+        IShellView* view;
+
+        hr = SHCreateShellFolderView(&sfv, &view);
+        if (FAILED(hr))
+            return hr;
+
+        pcb->Initialize(view);
+
+        pcb->Release();
+
+        *ppvOut = view;
+
+        return S_OK;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE GetAttributesOf(
+        UINT cidl,
+        PCUITEMID_CHILD_ARRAY apidl,
+        SFGAOF *rgfInOut)
+    {
+        const TItemId * info;
+
+        TRACE("GetAttributesOf %d\n", cidl);
+
+        if (cidl == 0)
+        {
+            *rgfInOut &= SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_BROWSABLE;
+            return S_OK;
+        }
+
+        for (int i = 0; i < (int)cidl; i++)
+        {
+            PCUITEMID_CHILD pidl = apidl[i];
+
+            HRESULT hr = GetInfoFromPidl(pidl, &info);
+            if (FAILED_UNEXPECTEDLY(hr))
+                return hr;
+
+            // Update attributes.
+            *rgfInOut = ConvertAttributes(info, rgfInOut);
+        }
+
+        return S_OK;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE GetUIObjectOf(
+        HWND hwndOwner,
+        UINT cidl,
+        PCUITEMID_CHILD_ARRAY apidl,
+        REFIID riid,
+        UINT *prgfInOut,
+        void **ppvOut)
+    {
+        DWORD res;
+        TRACE("GetUIObjectOf\n");
+
+        if (IsEqualIID(riid, IID_IContextMenu) ||
+            IsEqualIID(riid, IID_IContextMenu2) ||
+            IsEqualIID(riid, IID_IContextMenu3))
+        {
+            CComPtr<IContextMenu> pcm;
+
+            HKEY keys[1];
+
+            int nkeys = _countof(keys);
+            if (cidl == 1 && IsFolder(apidl[0]))
+            {
+                res = RegOpenKey(HKEY_CLASSES_ROOT, L"Folder", keys + 0);
+                if (!NT_SUCCESS(res))
+                    return HRESULT_FROM_NT(res);
+            }
+            else
+            {
+                nkeys = 0;
+            }
+
+            HRESULT hr = CDefFolderMenu_Create2(m_shellPidl, hwndOwner, cidl, apidl, this, DefCtxMenuCallback, nkeys, keys, &pcm);
+            if (FAILED_UNEXPECTEDLY(hr))
+                return hr;
+
+            return pcm->QueryInterface(riid, ppvOut);
+        }
+
+        if (IsEqualIID(riid, IID_IExtractIconW))
+        {
+            return ShellObjectCreatorInit<TExtractIcon>(m_NtPath, m_shellPidl, cidl, apidl, riid, ppvOut);
+        }
+
+        if (IsEqualIID(riid, IID_IDataObject))
+        {
+            return CIDLData_CreateFromIDArray(m_shellPidl, cidl, apidl, (IDataObject**)ppvOut);
+        }
+
+        if (IsEqualIID(riid, IID_IQueryAssociations))
+        {
+            if (cidl == 1 && IsFolder(apidl[0]))
+            {
+                CComPtr<IQueryAssociations> pqa;
+                HRESULT hr = AssocCreate(CLSID_QueryAssociations, IID_PPV_ARG(IQueryAssociations, &pqa));
+                if (FAILED_UNEXPECTEDLY(hr))
+                    return hr;
+
+                hr = pqa->Init(ASSOCF_INIT_DEFAULTTOFOLDER, L"NTObjShEx.NTDirectory", NULL, hwndOwner);
+                if (FAILED_UNEXPECTEDLY(hr))
+                    return hr;
+
+                return pqa->QueryInterface(riid, ppvOut);
+            }
+        }
+
+        return E_NOTIMPL;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE GetDisplayNameOf(
+        LPCITEMIDLIST pidl,
+        SHGDNF uFlags,
+        STRRET *lpName)
+    {
+        const TItemId * info;
+
+        TRACE("GetDisplayNameOf %p\n", pidl);
+
+        HRESULT hr = GetInfoFromPidl(pidl, &info);
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
+
+        if (GET_SHGDN_FOR(uFlags) & SHGDN_FOREDITING)
+        {
+            hr = MakeStrRetFromString(info->entryName, info->entryNameLength, lpName);
+            if (FAILED_UNEXPECTEDLY(hr))
+                return hr;
+        }
+
+        WCHAR path[MAX_PATH] = { 0 };
+
+        if (GET_SHGDN_FOR(uFlags) & SHGDN_FORPARSING)
+        {
+            if (GET_SHGDN_RELATION(uFlags) != SHGDN_INFOLDER)
+            {
+                hr = GetFullName(m_shellPidl, uFlags, path, _countof(path));
+                if (FAILED_UNEXPECTEDLY(hr))
+                    return hr;
+            }
+        }
+
+        PathAppendW(path, info->entryName);
+
+        LPCITEMIDLIST pidlNext = ILGetNext(pidl);
+        if (pidlNext && pidlNext->mkid.cb > 0)
+        {
+            LPITEMIDLIST pidlFirst = ILCloneFirst(pidl);
+
+            CComPtr<IShellFolder> psfChild;
+            hr = BindToObject(pidlFirst, NULL, IID_PPV_ARG(IShellFolder, &psfChild));
+            if (FAILED_UNEXPECTEDLY(hr))
+                return hr;
+
+            WCHAR temp[MAX_PATH];
+            STRRET childName;
+
+            hr = psfChild->GetDisplayNameOf(pidlNext, uFlags | SHGDN_INFOLDER, &childName);
+            if (FAILED_UNEXPECTEDLY(hr))
+                return hr;
+
+            hr = StrRetToBufW(&childName, pidlNext, temp, _countof(temp));
+            if (FAILED_UNEXPECTEDLY(hr))
+                return hr;
+
+            PathAppendW(path, temp);
+
+            ILFree(pidlFirst);
+        }
+
+        hr = MakeStrRetFromString(path, lpName);
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
+
+        return S_OK;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE SetNameOf(
+        HWND hwnd,
+        LPCITEMIDLIST pidl,
+        LPCOLESTR lpszName,
+        SHGDNF uFlags,
+        LPITEMIDLIST *ppidlOut)
+    {
+        UNIMPLEMENTED;
+        return E_NOTIMPL;
+    }
+
+    // IShellFolder2
+    virtual HRESULT STDMETHODCALLTYPE GetDefaultSearchGUID(
+        GUID *lpguid)
+    {
+        UNIMPLEMENTED;
+        return E_NOTIMPL;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE EnumSearches(
+        IEnumExtraSearch **ppenum)
+    {
+        UNIMPLEMENTED;
+        return E_NOTIMPL;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE GetDefaultColumn(
+        DWORD dwReserved,
+        ULONG *pSort,
+        ULONG *pDisplay)
+    {
+        if (pSort)
+            *pSort = 0;
+        if (pDisplay)
+            *pDisplay = 0;
+        return S_OK;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE GetDefaultColumnState(
+        UINT iColumn,
+        SHCOLSTATEF *pcsFlags) PURE;
+
+    virtual HRESULT STDMETHODCALLTYPE GetDetailsEx(
+        LPCITEMIDLIST pidl,
+        const SHCOLUMNID *pscid,
+        VARIANT *pv) PURE;
+
+    virtual HRESULT STDMETHODCALLTYPE GetDetailsOf(
+        LPCITEMIDLIST pidl,
+        UINT iColumn,
+        SHELLDETAILS *psd) PURE;
+
+    virtual HRESULT STDMETHODCALLTYPE MapColumnToSCID(
+        UINT iColumn,
+        SHCOLUMNID *pscid) PURE;
+
+    // IPersist
+    virtual HRESULT STDMETHODCALLTYPE GetClassID(CLSID *lpClassId)
+    {
+        if (!lpClassId)
+            return E_POINTER;
+
+        *lpClassId = CLSID_NtObjectFolder;
+        return S_OK;
+    }
+
+    // IPersistFolder
+    virtual HRESULT STDMETHODCALLTYPE Initialize(LPCITEMIDLIST pidl)
+    {
+        m_shellPidl = ILClone(pidl);
+
+        StringCbCopy(m_NtPath, _countof(m_NtPath), L"\\");
+
+        return S_OK;
+    }
+
+    // IPersistFolder2
+    virtual HRESULT STDMETHODCALLTYPE GetCurFolder(LPITEMIDLIST * pidl)
+    {
+        if (pidl)
+            *pidl = ILClone(m_shellPidl);
+        if (!m_shellPidl)
+            return S_FALSE;
+        return S_OK;
+    }
+
+    // Internal
+protected:
+    virtual HRESULT STDMETHODCALLTYPE CompareIDs(
+        LPARAM lParam, 
+        const TItemId * first, 
+        const TItemId * second) PURE;
+
+    virtual ULONG STDMETHODCALLTYPE ConvertAttributes(
+        const TItemId * entry,
+        PULONG inMask) PURE;
+
+    virtual BOOL STDMETHODCALLTYPE IsFolder(LPCITEMIDLIST pcidl) PURE;
+
+    virtual BOOL STDMETHODCALLTYPE IsFolder(const TItemId * info) PURE;
+
+    virtual BOOL STDMETHODCALLTYPE IsSymLink(const TItemId * info)
+    {
+        return FALSE;
+    }
+
+    virtual HRESULT GetInfoFromPidl(LPCITEMIDLIST pcidl, const TItemId ** pentry) PURE;
+
+public:
+    static HRESULT CALLBACK DefCtxMenuCallback(IShellFolder * /*psf*/, HWND /*hwnd*/, IDataObject * /*pdtobj*/, UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/)
+    {
+        switch (uMsg)
+        {
+        case DFM_MERGECONTEXTMENU:
+            return S_OK;
+        case DFM_INVOKECOMMAND:
+        case DFM_INVOKECOMMANDEX:
+        case DFM_GETDEFSTATICID: // Required for Windows 7 to pick a default
+            return S_FALSE;
+        }
+        return E_NOTIMPL;
+    }
+    
+    DECLARE_REGISTRY_RESOURCEID(IDR_REGISTRYFOLDER)
+    DECLARE_NOT_AGGREGATABLE(TSelf)
+    DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+    BEGIN_COM_MAP(TSelf)
+        COM_INTERFACE_ENTRY_IID(IID_IShellFolder, IShellFolder)
+        COM_INTERFACE_ENTRY_IID(IID_IShellFolder2, IShellFolder2)
+        COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist)
+        COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder)
+        COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2)
+    END_COM_MAP()
+
+};
\ No newline at end of file
index a199381..8e3a763 100644 (file)
@@ -16,9 +16,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#include <precomp.h>
-
-#include "ntobjenum.h"
+#include "precomp.h"
 #include <strsafe.h>
 
 WINE_DEFAULT_DEBUG_CHANNEL(ntobjshex);
index aef53a7..f5e09c3 100644 (file)
@@ -7,20 +7,6 @@
  */
 
 #include "precomp.h"
-#include "ntobjenum.h"
-#include <ntquery.h>
-#include "util.h"
-
-#define DFM_MERGECONTEXTMENU 1 // uFlags LPQCMINFO
-#define DFM_INVOKECOMMAND 2 // idCmd pszArgs
-#define DFM_INVOKECOMMANDEX 12 // idCmd PDFMICS
-#define DFM_GETDEFSTATICID 14 // idCmd * 0
-
-#define SHCIDS_ALLFIELDS 0x80000000L
-#define SHCIDS_CANONICALONLY 0x10000000L
-
-#define GET_SHGDN_FOR(dwFlags)         ((DWORD)dwFlags & (DWORD)0x0000FF00)
-#define GET_SHGDN_RELATION(dwFlags)    ((DWORD)dwFlags & (DWORD)0x000000FF)
 
 WINE_DEFAULT_DEBUG_CHANNEL(ntobjshex);
 
@@ -38,359 +24,95 @@ enum NtObjectColumns
     NTOBJECT_COLUMN_END
 };
 
-class CNtObjectFolderExtractIcon :
-    public CComObjectRootEx<CComMultiThreadModelNoCS>,
-    public IExtractIconW
+CNtObjectFolderExtractIcon::CNtObjectFolderExtractIcon() :
+    m_pcidlChild(NULL),
+    m_NtPath(NULL)
 {
-    PCITEMID_CHILD m_pcidlChild;
-    LPCWSTR m_NtPath;
-
-public:
-    CNtObjectFolderExtractIcon() :
-        m_pcidlChild(NULL), m_NtPath(NULL)
-    {
-
-    }
-
-    virtual ~CNtObjectFolderExtractIcon()
-    {
-        if (m_pcidlChild)
-            ILFree((LPITEMIDLIST) m_pcidlChild);
-    }
-
-    HRESULT Initialize(LPCWSTR ntPath, UINT cidl, PCUITEMID_CHILD_ARRAY apidl)
-    {
-        m_NtPath = ntPath;
-        if (cidl != 1)
-            return E_INVALIDARG;
-        m_pcidlChild = ILClone(apidl[0]);
-        return S_OK;
-    }
-
-    virtual HRESULT STDMETHODCALLTYPE GetIconLocation(
-        UINT uFlags,
-        LPWSTR szIconFile,
-        UINT cchMax,
-        INT *piIndex,
-        UINT *pwFlags)
-    {
-        const NtPidlEntry * entry = (NtPidlEntry *) m_pcidlChild;
-
-        if ((entry->cb < sizeof(NtPidlEntry)) || (entry->magic != NT_OBJECT_PIDL_MAGIC))
-            return E_INVALIDARG;
-
-        UINT flags = 0;
-
-        switch (entry->objectType)
-        {
-        case DIRECTORY_OBJECT:
-        case SYMBOLICLINK_OBJECT:
-            GetModuleFileNameW(g_hInstance, szIconFile, cchMax);
-            *piIndex = -((uFlags & GIL_OPENICON) ? IDI_NTOBJECTDIROPEN : IDI_NTOBJECTDIR);
-            *pwFlags = flags;
-            return S_OK;
-        case DEVICE_OBJECT:
-            GetModuleFileNameW(g_hInstance, szIconFile, cchMax);
-            *piIndex = -IDI_NTOBJECTDEVICE;
-            *pwFlags = flags;
-            return S_OK;
-        case PORT_OBJECT:
-            GetModuleFileNameW(g_hInstance, szIconFile, cchMax);
-            *piIndex = -IDI_NTOBJECTPORT;
-            *pwFlags = flags;
-            return S_OK;
-        case KEY_OBJECT:
-            GetModuleFileNameW(g_hInstance, szIconFile, cchMax);
-            *piIndex = -IDI_REGISTRYKEY;
-            *pwFlags = flags;
-            return S_OK;
-        default:
-            GetModuleFileNameW(g_hInstance, szIconFile, cchMax);
-            *piIndex = -IDI_NTOBJECTITEM;
-            *pwFlags = flags;
-            return S_OK;
-        }
-    }
 
-    virtual HRESULT STDMETHODCALLTYPE Extract(
-        LPCWSTR pszFile,
-        UINT nIconIndex,
-        HICON *phiconLarge,
-        HICON *phiconSmall,
-        UINT nIconSize)
-    {
-        return SHDefExtractIconW(pszFile, nIconIndex, 0, phiconLarge, phiconSmall, nIconSize);
-    }
-
-    DECLARE_NOT_AGGREGATABLE(CNtObjectFolderExtractIcon)
-    DECLARE_PROTECT_FINAL_CONSTRUCT()
-
-    BEGIN_COM_MAP(CNtObjectFolderExtractIcon)
-        COM_INTERFACE_ENTRY_IID(IID_IExtractIconW, IExtractIconW)
-    END_COM_MAP()
-
-};
+}
 
-class CNtObjectPidlHelper
+CNtObjectFolderExtractIcon::~CNtObjectFolderExtractIcon()
 {
-public:
-    static HRESULT CompareIDs(LPARAM lParam, const NtPidlEntry * first, const NtPidlEntry * second)
-    {
-        if ((lParam & 0xFFFF0000) == SHCIDS_ALLFIELDS)
-        {
-            if (lParam != 0)
-                return E_INVALIDARG;
-
-            int minsize = min(first->cb, second->cb);
-            int ord = memcmp(second, first, minsize);
-
-            if (ord != 0)
-                return MAKE_HRESULT(0, 0, (USHORT) ord);
-
-            if (second->cb > first->cb)
-                return MAKE_HRESULT(0, 0, (USHORT) 1);
-            if (second->cb < first->cb)
-                return MAKE_HRESULT(0, 0, (USHORT) -1);
-        }
-        else
-        {
-            bool canonical = ((lParam & 0xFFFF0000) == SHCIDS_CANONICALONLY);
-
-            switch (lParam & 0xFFFF)
-            {
-            case NTOBJECT_COLUMN_NAME:
-            {
-                bool f1 = (first->objectType == KEY_OBJECT) || (first->objectType == DIRECTORY_OBJECT);
-                bool f2 = (second->objectType == KEY_OBJECT) || (second->objectType == DIRECTORY_OBJECT);
-
-                if (f1 && !f2)
-                    return MAKE_HRESULT(0, 0, (USHORT) -1);
-                if (f2 && !f1)
-                    return MAKE_HRESULT(0, 0, (USHORT) 1);
-
-                if (canonical)
-                {
-                    // Shortcut: avoid comparing contents if not necessary when the results are not for display.
-                    if (second->entryNameLength > first->entryNameLength)
-                        return MAKE_HRESULT(0, 0, (USHORT) 1);
-                    if (second->entryNameLength < first->entryNameLength)
-                        return MAKE_HRESULT(0, 0, (USHORT) -1);
-
-                    int minlength = min(first->entryNameLength, second->entryNameLength);
-                    if (minlength > 0)
-                    {
-                        int ord = memcmp(first->entryName, second->entryName, minlength);
-                        if (ord != 0)
-                            return MAKE_HRESULT(0, 0, (USHORT) ord);
-                    }
-                    return S_OK;
-                }
-                else
-                {
-                    int minlength = min(first->entryNameLength, second->entryNameLength);
-                    if (minlength > 0)
-                    {
-                        int ord = StrCmpNW(first->entryName, second->entryName, minlength / sizeof(WCHAR));
-                        if (ord != 0)
-                            return MAKE_HRESULT(0, 0, (USHORT) ord);
-                    }
-
-                    if (second->entryNameLength > first->entryNameLength)
-                        return MAKE_HRESULT(0, 0, (USHORT) 1);
-                    if (second->entryNameLength < first->entryNameLength)
-                        return MAKE_HRESULT(0, 0, (USHORT) -1);
-
-                    return S_OK;
-                }
-            }
-            case NTOBJECT_COLUMN_TYPE:
-            {
-                int ord = second->objectType - first->objectType;
-                if (ord > 0)
-                    return MAKE_HRESULT(0, 0, (USHORT) 1);
-                if (ord < 0)
-                    return MAKE_HRESULT(0, 0, (USHORT) -1);
-
-                return S_OK;
-            }
-            case NTOBJECT_COLUMN_LINKTARGET:
-            {
-                // Can't sort by value
-                return E_INVALIDARG;
-            }
-            default:
-            {
-                DbgPrint("Unsupported sorting mode.\n");
-                return E_INVALIDARG;
-            }
-            }
-        }
+    if (m_pcidlChild)
+        ILFree((LPITEMIDLIST) m_pcidlChild);
+}
 
+HRESULT CNtObjectFolderExtractIcon::Initialize(LPCWSTR ntPath, PCIDLIST_ABSOLUTE parent, UINT cidl, PCUITEMID_CHILD_ARRAY apidl)
+{
+    m_NtPath = ntPath;
+    if (cidl != 1)
         return E_INVALIDARG;
-    }
-
-    static HRESULT CompareIDs(LPARAM lParam, const NtPidlEntry * first, LPCITEMIDLIST pcidl)
-    {
-        LPCITEMIDLIST p = pcidl;
-        NtPidlEntry * second = (NtPidlEntry*) &(p->mkid);
-        if ((second->cb < sizeof(NtPidlEntry)) || (second->magic != NT_OBJECT_PIDL_MAGIC))
-            return E_INVALIDARG;
-
-        return CompareIDs(lParam, first, second);
-    }
-
-    static HRESULT CompareIDs(LPARAM lParam, LPCITEMIDLIST pcidl1, LPCITEMIDLIST pcidl2)
-    {
-        LPCITEMIDLIST p = pcidl1;
-        NtPidlEntry * first = (NtPidlEntry*) &(p->mkid);
-        if ((first->cb < sizeof(NtPidlEntry)) || (first->magic != NT_OBJECT_PIDL_MAGIC))
-            return E_INVALIDARG;
-
-        return CompareIDs(lParam, first, pcidl2);
-    }
-
-    static ULONG ConvertAttributes(const NtPidlEntry * entry, PULONG inMask)
-    {
-        ULONG mask = inMask ? *inMask : 0xFFFFFFFF;
-        ULONG flags = SFGAO_HASPROPSHEET | SFGAO_CANLINK;
-
-        if (entry->objectType == DIRECTORY_OBJECT)
-            flags |= SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_BROWSABLE;
-
-        if (entry->objectType == SYMBOLICLINK_OBJECT)
-            flags |= SFGAO_LINK | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_BROWSABLE;
-
-        if (entry->objectType == KEY_OBJECT)
-            flags |= SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_BROWSABLE;
+    m_pcidlChild = ILClone(apidl[0]);
+    return S_OK;
+}
 
-        return flags & mask;
-    }
+HRESULT STDMETHODCALLTYPE CNtObjectFolderExtractIcon::GetIconLocation(
+    UINT uFlags,
+    LPWSTR szIconFile,
+    UINT cchMax,
+    INT *piIndex,
+    UINT *pwFlags)
+{
+    const NtPidlEntry * entry = (NtPidlEntry *) m_pcidlChild;
 
-    static BOOL IsFolder(LPCITEMIDLIST pcidl)
-    {
-        NtPidlEntry * entry = (NtPidlEntry*) &(pcidl->mkid);
-        if ((entry->cb < sizeof(NtPidlEntry)) || (entry->magic != NT_OBJECT_PIDL_MAGIC))
-            return FALSE;
+    if ((entry->cb < sizeof(NtPidlEntry)) || (entry->magic != NT_OBJECT_PIDL_MAGIC))
+        return E_INVALIDARG;
 
-        return (entry->objectType == DIRECTORY_OBJECT) ||
-            (entry->objectType == SYMBOLICLINK_OBJECT) ||
-            (entry->objectType == KEY_OBJECT);
-    }
+    UINT flags = 0;
 
-    static HRESULT GetInfoFromPidl(LPCITEMIDLIST pcidl, const NtPidlEntry ** pentry)
+    switch (entry->objectType)
     {
-        NtPidlEntry * entry = (NtPidlEntry*) &(pcidl->mkid);
-
-        if (entry->cb < sizeof(NtPidlEntry))
-        {
-            DbgPrint("PCIDL too small %l (required %l)\n", entry->cb, sizeof(NtPidlEntry));
-            return E_INVALIDARG;
-        }
-
-        if (entry->magic != NT_OBJECT_PIDL_MAGIC)
-        {
-            DbgPrint("PCIDL magic mismatch %04x (expected %04x)\n", entry->magic, NT_OBJECT_PIDL_MAGIC);
-            return E_INVALIDARG;
-        }
-
-        *pentry = entry;
+    case DIRECTORY_OBJECT:
+    case SYMBOLICLINK_OBJECT:
+        GetModuleFileNameW(g_hInstance, szIconFile, cchMax);
+        *piIndex = -((uFlags & GIL_OPENICON) ? IDI_NTOBJECTDIROPEN : IDI_NTOBJECTDIR);
+        *pwFlags = flags;
+        return S_OK;
+    case DEVICE_OBJECT:
+        GetModuleFileNameW(g_hInstance, szIconFile, cchMax);
+        *piIndex = -IDI_NTOBJECTDEVICE;
+        *pwFlags = flags;
+        return S_OK;
+    case PORT_OBJECT:
+        GetModuleFileNameW(g_hInstance, szIconFile, cchMax);
+        *piIndex = -IDI_NTOBJECTPORT;
+        *pwFlags = flags;
+        return S_OK;
+    case KEY_OBJECT:
+        GetModuleFileNameW(g_hInstance, szIconFile, cchMax);
+        *piIndex = -IDI_REGISTRYKEY;
+        *pwFlags = flags;
+        return S_OK;
+    default:
+        GetModuleFileNameW(g_hInstance, szIconFile, cchMax);
+        *piIndex = -IDI_NTOBJECTITEM;
+        *pwFlags = flags;
         return S_OK;
     }
-};
+}
+
+HRESULT STDMETHODCALLTYPE CNtObjectFolderExtractIcon::Extract(
+    LPCWSTR pszFile,
+    UINT nIconIndex,
+    HICON *phiconLarge,
+    HICON *phiconSmall,
+    UINT nIconSize)
+{
+    return SHDefExtractIconW(pszFile, nIconIndex, 0, phiconLarge, phiconSmall, nIconSize);
+}
 
 //-----------------------------------------------------------------------------
 // CNtObjectFolder
 
-CNtObjectFolder::CNtObjectFolder() :
-    m_shellPidl(NULL)
+CNtObjectFolder::CNtObjectFolder()
 {
 }
 
 CNtObjectFolder::~CNtObjectFolder()
 {
-    if (m_shellPidl)
-        ILFree(m_shellPidl);
 }
 
 // IShellFolder
-HRESULT STDMETHODCALLTYPE CNtObjectFolder::ParseDisplayName(
-    HWND hwndOwner,
-    LPBC pbcReserved,
-    LPOLESTR lpszDisplayName,
-    ULONG *pchEaten,
-    LPITEMIDLIST *ppidl,
-    ULONG *pdwAttributes)
-{
-    if (!ppidl)
-        return E_POINTER;
-
-    if (pchEaten)
-        *pchEaten = 0;
-
-    if (pdwAttributes)
-        *pdwAttributes = 0;
-
-    TRACE("CNtObjectFolder::ParseDisplayName name=%S (ntPath=%S)\n", lpszDisplayName, m_NtPath);
-
-    const NtPidlEntry * info;
-    IEnumIDList * it;
-    HRESULT hr = GetEnumNTDirectory(m_NtPath, &it);
-    if (FAILED(hr))
-        return hr;
-
-    PWSTR end = StrChrW(lpszDisplayName, '\\');
-    int length = end ? end - lpszDisplayName : wcslen(lpszDisplayName);
-
-    while (TRUE)
-    {
-        hr = it->Next(1, ppidl, NULL);
-
-        if (FAILED(hr))
-            return hr;
-
-        if (hr != S_OK)
-            return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
-
-        hr = CNtObjectPidlHelper::GetInfoFromPidl(*ppidl, &info);
-        if (FAILED_UNEXPECTEDLY(hr))
-            return hr;
-
-        if (StrCmpNW(info->entryName, lpszDisplayName, length) == 0)
-            break;
-    }
-
-    // if has remaining path to parse (and the path didn't just terminate in a backslash)
-    if (end && wcslen(end) > 1)
-    {
-        CComPtr<IShellFolder> psfChild;
-        hr = BindToObject(*ppidl, pbcReserved, IID_PPV_ARG(IShellFolder, &psfChild));
-        if (FAILED_UNEXPECTEDLY(hr))
-            return hr;
-
-        LPITEMIDLIST child;
-        hr = psfChild->ParseDisplayName(hwndOwner, pbcReserved, end + 1, pchEaten, &child, pdwAttributes);
-        if (FAILED(hr))
-            return hr;
-
-        LPITEMIDLIST old = *ppidl;
-        *ppidl = ILCombine(old, child);
-        ILFree(old);
-
-        // Count the path separator
-        if (pchEaten)
-            (*pchEaten) += 1;
-    }
-    else
-    {
-        if (pdwAttributes)
-            *pdwAttributes = CNtObjectPidlHelper::ConvertAttributes(info, pdwAttributes);
-    }
-
-    if (pchEaten)
-        *pchEaten += wcslen(info->entryName);
-
-    return S_OK;
-}
 
 HRESULT STDMETHODCALLTYPE CNtObjectFolder::EnumObjects(
     HWND hwndOwner,
@@ -400,356 +122,95 @@ HRESULT STDMETHODCALLTYPE CNtObjectFolder::EnumObjects(
     return GetEnumNTDirectory(m_NtPath, ppenumIDList);
 }
 
-HRESULT STDMETHODCALLTYPE CNtObjectFolder::BindToObject(
-    LPCITEMIDLIST pidl,
-    LPBC pbcReserved,
-    REFIID riid,
-    void **ppvOut)
+BOOL STDMETHODCALLTYPE CNtObjectFolder::IsSymLink(const NtPidlEntry * info)
 {
-    const NtPidlEntry * info;
-
-    if (IsEqualIID(riid, IID_IShellFolder))
-    {
-        HRESULT hr = CNtObjectPidlHelper::GetInfoFromPidl(pidl, &info);
-        if (FAILED_UNEXPECTEDLY(hr))
-            return hr;
-
-        WCHAR path[MAX_PATH];
-
-        StringCbCopyW(path, _countof(path), m_NtPath);
-        PathAppendW(path, info->entryName);
-
-        LPITEMIDLIST first = ILCloneFirst(pidl);
-        LPCITEMIDLIST rest = ILGetNext(pidl);
-
-        LPITEMIDLIST fullPidl = ILCombine(m_shellPidl, first);
-
-        if (info->objectType == SYMBOLICLINK_OBJECT)
-        {
-            WCHAR wbLink[MAX_PATH] = { 0 };
-            UNICODE_STRING link;
-            RtlInitEmptyUnicodeString(&link, wbLink, sizeof(wbLink));
-
-            hr = GetNTObjectSymbolicLinkTarget(m_NtPath, info->entryName, &link);
-            if (FAILED_UNEXPECTEDLY(hr))
-                return hr;
-
-            if (link.Length > 0)
-            {
-                if (link.Buffer[1] == L':' && isalphaW(link.Buffer[0]))
-                {
-                    CComPtr<IShellFolder> psfDesktop;
-                    hr = SHGetDesktopFolder(&psfDesktop);
-                    if (FAILED_UNEXPECTEDLY(hr))
-                        return hr;
-
-                    hr = psfDesktop->ParseDisplayName(NULL, NULL, path, NULL, &first, NULL);
-                    if (FAILED_UNEXPECTEDLY(hr))
-                        return hr;
-
-                    return psfDesktop->BindToObject(rest, pbcReserved, riid, ppvOut);
-                }
-
-                StringCbCopyW(path, _countof(path), L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{845B0FB2-66E0-416B-8F91-314E23F7C12D}");
-                PathAppend(path, link.Buffer);
-
-                CComPtr<IShellFolder> psfDesktop;
-                hr = SHGetDesktopFolder(&psfDesktop);
-                if (FAILED_UNEXPECTEDLY(hr))
-                    return hr;
-
-                LPITEMIDLIST pidl;
-
-                hr = psfDesktop->ParseDisplayName(NULL, NULL, path, NULL, &pidl, NULL);
-                if (FAILED_UNEXPECTEDLY(hr))
-                    return hr;
-
-                CComPtr<IShellFolder> psfChild;
-                hr =  psfDesktop->BindToObject(pidl, NULL, riid, ppvOut);
-                ILFree(pidl);
-
-                return hr;
-            }
-            else
-            {
-                return E_UNEXPECTED;
-            }
-        }
-
-        CComPtr<IShellFolder> psfChild;
-
-        if (info->objectType == KEY_OBJECT)
-        {
-            hr = ShellObjectCreatorInit<CRegistryFolder>(fullPidl, path, (HKEY) NULL, IID_PPV_ARG(IShellFolder, &psfChild));
-        }
-        else
-        {
-            hr = ShellObjectCreatorInit<CNtObjectFolder>(fullPidl, path, IID_PPV_ARG(IShellFolder, &psfChild));
-        }
-
-        ILFree(fullPidl);
-        ILFree(first);
-
-        if (rest->mkid.cb > 0)
-        {
-            return psfChild->BindToObject(rest, pbcReserved, riid, ppvOut);
-        }
-
-        return psfChild->QueryInterface(riid, ppvOut);
-    }
-
-    return E_NOTIMPL;
+    return info->objectType == SYMBOLICLINK_OBJECT;
 }
 
-HRESULT STDMETHODCALLTYPE CNtObjectFolder::BindToStorage(
-    LPCITEMIDLIST pidl,
+HRESULT STDMETHODCALLTYPE CNtObjectFolder::RedirectToSymLink(
+    const NtPidlEntry * info,
+    LPITEMIDLIST first,
+    LPCITEMIDLIST rest,
     LPBC pbcReserved,
-    REFIID riid,
-    void **ppvObj)
+    IShellFolder ** ppsfChild)
 {
-    UNIMPLEMENTED;
-    return E_NOTIMPL;
-}
+    HRESULT hr;
 
-HRESULT STDMETHODCALLTYPE CNtObjectFolder::CompareIDs(
-    LPARAM lParam,
-    LPCITEMIDLIST pidl1,
-    LPCITEMIDLIST pidl2)
-{
-    TRACE("CompareIDs\n");
+    WCHAR wbLink[MAX_PATH] = { 0 };
+    UNICODE_STRING link;
+    RtlInitEmptyUnicodeString(&link, wbLink, sizeof(wbLink));
 
-    HRESULT hr = CNtObjectPidlHelper::CompareIDs(lParam, pidl1, pidl2);
-    if (hr != S_OK)
+    hr = GetNTObjectSymbolicLinkTarget(m_NtPath, info->entryName, &link);
+    if (FAILED_UNEXPECTEDLY(hr))
         return hr;
 
-    LPCITEMIDLIST rest1 = ILGetNext(pidl1);
-    LPCITEMIDLIST rest2 = ILGetNext(pidl2);
-
-    bool hasNext1 = (rest1->mkid.cb > 0);
-    bool hasNext2 = (rest2->mkid.cb > 0);
+    WCHAR path[MAX_PATH];
 
-    if (hasNext1 || hasNext2)
+    if (link.Length > 0)
     {
-        if (hasNext1 && !hasNext2)
-            return MAKE_HRESULT(0, 0, (USHORT) -1);
-
-        if (hasNext2 && !hasNext1)
-            return MAKE_HRESULT(0, 0, (USHORT) 1);
-
-        LPCITEMIDLIST first1 = ILCloneFirst(pidl1);
-
-        CComPtr<IShellFolder> psfNext;
-        hr = BindToObject(first1, NULL, IID_PPV_ARG(IShellFolder, &psfNext));
-        if (FAILED_UNEXPECTEDLY(hr))
-            return hr;
-
-        return psfNext->CompareIDs(lParam, rest1, rest2);
-    }
-
-    return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE CNtObjectFolder::CreateViewObject(
-    HWND hwndOwner,
-    REFIID riid,
-    void **ppvOut)
-{
-    if (!IsEqualIID(riid, IID_IShellView))
-        return E_NOINTERFACE;
-
-    SFV_CREATE sfv;
-    sfv.cbSize = sizeof(sfv);
-    sfv.pshf = static_cast<IShellFolder*>(this);
-    sfv.psvOuter = NULL;
-    sfv.psfvcb = static_cast<IShellFolderViewCB*>(this);
-
-    return SHCreateShellFolderView(&sfv, (IShellView**) ppvOut);
-}
-
-HRESULT STDMETHODCALLTYPE CNtObjectFolder::GetAttributesOf(
-    UINT cidl,
-    PCUITEMID_CHILD_ARRAY apidl,
-    SFGAOF *rgfInOut)
-{
-    const NtPidlEntry * info;
-
-    TRACE("GetAttributesOf %d\n", cidl);
-
-    if (cidl == 0)
-    {
-        *rgfInOut &= SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_BROWSABLE;
-        return S_OK;
-    }
-
-    for (int i = 0; i < (int) cidl; i++)
-    {
-        PCUITEMID_CHILD pidl = apidl[i];
-
-        HRESULT hr = CNtObjectPidlHelper::GetInfoFromPidl(pidl, &info);
-        if (FAILED_UNEXPECTEDLY(hr))
-            return hr;
-
-        // Update attributes.
-        *rgfInOut = CNtObjectPidlHelper::ConvertAttributes(info, rgfInOut);
-    }
-
-    return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE CNtObjectFolder::GetUIObjectOf(
-    HWND hwndOwner,
-    UINT cidl,
-    PCUITEMID_CHILD_ARRAY apidl,
-    REFIID riid,
-    UINT *prgfInOut,
-    void **ppvOut)
-{
-    DWORD res;
-    TRACE("GetUIObjectOf\n");
-
-    if (IsEqualIID(riid, IID_IContextMenu) ||
-        IsEqualIID(riid, IID_IContextMenu2) ||
-        IsEqualIID(riid, IID_IContextMenu3))
-    {
-        CComPtr<IContextMenu> pcm;
-
-        HKEY keys[1];
-
-        int nkeys = _countof(keys);
-        if (cidl == 1 && CNtObjectPidlHelper::IsFolder(apidl[0]))
+        if (link.Buffer[1] == L':' && isalphaW(link.Buffer[0]))
         {
-            res = RegOpenKey(HKEY_CLASSES_ROOT, L"Folder", keys + 0);
-            if (!NT_SUCCESS(res))
-                return HRESULT_FROM_NT(res);
-        }
-        else
-        {
-            nkeys = 0;
-        }
+            StringCbCopyNW(path, _countof(path), link.Buffer, link.Length);
 
-        HRESULT hr = CDefFolderMenu_Create2(m_shellPidl, hwndOwner, cidl, apidl, this, DefCtxMenuCallback, nkeys, keys, &pcm);
-        if (FAILED_UNEXPECTEDLY(hr))
-            return hr;
-
-        return pcm->QueryInterface(riid, ppvOut);
-    }
-
-    if (IsEqualIID(riid, IID_IExtractIconW))
-    {
-        return ShellObjectCreatorInit<CNtObjectFolderExtractIcon>(m_NtPath, cidl, apidl, riid, ppvOut);
-    }
-
-    if (IsEqualIID(riid, IID_IDataObject))
-    {
-        return CIDLData_CreateFromIDArray(m_shellPidl, cidl, apidl, (IDataObject**) ppvOut);
-    }
-
-    if (IsEqualIID(riid, IID_IQueryAssociations))
-    {
-        if (cidl == 1 && CNtObjectPidlHelper::IsFolder(apidl[0]))
-        {
-            CComPtr<IQueryAssociations> pqa;
-            HRESULT hr = AssocCreate(CLSID_QueryAssociations, IID_PPV_ARG(IQueryAssociations, &pqa));
+            CComPtr<IShellFolder> psfDesktop;
+            hr = SHGetDesktopFolder(&psfDesktop);
             if (FAILED_UNEXPECTEDLY(hr))
                 return hr;
 
-            hr = pqa->Init(ASSOCF_INIT_DEFAULTTOFOLDER, L"NTObjShEx.NTDirectory", NULL, hwndOwner);
+            hr = psfDesktop->ParseDisplayName(NULL, NULL, path, NULL, &first, NULL);
             if (FAILED_UNEXPECTEDLY(hr))
                 return hr;
 
-            return pqa->QueryInterface(riid, ppvOut);
-        }
-    }
-
-    return E_NOTIMPL;
-}
-
-HRESULT STDMETHODCALLTYPE CNtObjectFolder::GetDisplayNameOf(
-    LPCITEMIDLIST pidl,
-    SHGDNF uFlags,
-    STRRET *lpName)
-{
-    const NtPidlEntry * info;
-
-    TRACE("GetDisplayNameOf %p\n", pidl);
-
-    HRESULT hr = CNtObjectPidlHelper::GetInfoFromPidl(pidl, &info);
-    if (FAILED_UNEXPECTEDLY(hr))
-        return hr;
-
-    if (GET_SHGDN_FOR(uFlags) & SHGDN_FOREDITING)
-    {
-        hr = MakeStrRetFromString(info->entryName, info->entryNameLength, lpName);
-        if (FAILED_UNEXPECTEDLY(hr))
-            return hr;
-    }
-
-    WCHAR path[MAX_PATH] = { 0 };
-
-    if (GET_SHGDN_FOR(uFlags) & SHGDN_FORPARSING)
-    {
-        if (GET_SHGDN_RELATION(uFlags) != SHGDN_INFOLDER)
-        {
-            hr = GetFullName(m_shellPidl, uFlags, path, _countof(path));
-            if (FAILED_UNEXPECTEDLY(hr))
+            hr = psfDesktop->BindToObject(rest, pbcReserved, IID_PPV_ARG(IShellFolder, ppsfChild));
+            if (FAILED(hr))
                 return hr;
-        }
-    }
 
-    PathAppendW(path, info->entryName);
+            return S_FALSE;;
+        }
 
-    LPCITEMIDLIST pidlNext = ILGetNext(pidl);
-    if (pidlNext && pidlNext->mkid.cb > 0)
-    {
-        LPITEMIDLIST pidlFirst = ILCloneFirst(pidl);
+        StringCbCopyW(path, _countof(path), L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{845B0FB2-66E0-416B-8F91-314E23F7C12D}");
+        PathAppend(path, link.Buffer);
 
-        CComPtr<IShellFolder> psfChild;
-        hr = BindToObject(pidlFirst, NULL, IID_PPV_ARG(IShellFolder, &psfChild));
+        CComPtr<IShellFolder> psfDesktop;
+        hr = SHGetDesktopFolder(&psfDesktop);
         if (FAILED_UNEXPECTEDLY(hr))
             return hr;
 
-        WCHAR temp[MAX_PATH];
-        STRRET childName;
+        LPITEMIDLIST pidl;
 
-        hr = psfChild->GetDisplayNameOf(pidlNext, uFlags | SHGDN_INFOLDER, &childName);
+        hr = psfDesktop->ParseDisplayName(NULL, NULL, path, NULL, &pidl, NULL);
         if (FAILED_UNEXPECTEDLY(hr))
             return hr;
 
-        hr = StrRetToBufW(&childName, pidlNext, temp, _countof(temp));
-        if (FAILED_UNEXPECTEDLY(hr))
-            return hr;
+        CComPtr<IShellFolder> psfChild;
+        hr = psfDesktop->BindToObject(pidl, pbcReserved, IID_PPV_ARG(IShellFolder, ppsfChild));
+        ILFree(pidl);
 
-        PathAppendW(path, temp);
+        if (FAILED(hr))
+            return hr;
 
-        ILFree(pidlFirst);
+        return S_FALSE;;
     }
 
-    hr = MakeStrRetFromString(path, lpName);
-    if (FAILED_UNEXPECTEDLY(hr))
-        return hr;
-
-    return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE CNtObjectFolder::SetNameOf(
-    HWND hwnd,
-    LPCITEMIDLIST pidl,
-    LPCOLESTR lpszName,
-    SHGDNF uFlags,
-    LPITEMIDLIST *ppidlOut)
-{
-    UNIMPLEMENTED;
-    return E_NOTIMPL;
+    return E_UNEXPECTED;
 }
 
-// IPersist
-HRESULT STDMETHODCALLTYPE CNtObjectFolder::GetClassID(CLSID *lpClassId)
+HRESULT STDMETHODCALLTYPE CNtObjectFolder::InternalBindToObject(
+    PWSTR path,
+    const NtPidlEntry * info,
+    LPITEMIDLIST first,
+    LPCITEMIDLIST rest,
+    LPITEMIDLIST fullPidl,
+    LPBC pbcReserved,
+    IShellFolder** ppsfChild)
 {
-    if (!lpClassId)
-        return E_POINTER;
 
-    *lpClassId = CLSID_NtObjectFolder;
-    return S_OK;
+    if (info->objectType == KEY_OBJECT)
+    {
+        return ShellObjectCreatorInit<CRegistryFolder>(fullPidl, path, (HKEY) NULL, IID_PPV_ARG(IShellFolder, ppsfChild));
+    }
+    
+    return ShellObjectCreatorInit<CNtObjectFolder>(fullPidl, path, IID_PPV_ARG(IShellFolder, ppsfChild));
 }
 
 // IPersistFolder
@@ -772,43 +233,6 @@ HRESULT STDMETHODCALLTYPE CNtObjectFolder::Initialize(LPCITEMIDLIST pidl, PCWSTR
     return S_OK;
 }
 
-// IPersistFolder2
-HRESULT STDMETHODCALLTYPE CNtObjectFolder::GetCurFolder(LPITEMIDLIST * pidl)
-{
-    if (pidl)
-        *pidl = ILClone(m_shellPidl);
-    if (!m_shellPidl)
-        return S_FALSE;
-    return S_OK;
-}
-
-// IShellFolder2
-HRESULT STDMETHODCALLTYPE CNtObjectFolder::GetDefaultSearchGUID(
-    GUID *lpguid)
-{
-    UNIMPLEMENTED;
-    return E_NOTIMPL;
-}
-
-HRESULT STDMETHODCALLTYPE CNtObjectFolder::EnumSearches(
-    IEnumExtraSearch **ppenum)
-{
-    UNIMPLEMENTED;
-    return E_NOTIMPL;
-}
-
-HRESULT STDMETHODCALLTYPE CNtObjectFolder::GetDefaultColumn(
-    DWORD dwReserved,
-    ULONG *pSort,
-    ULONG *pDisplay)
-{
-    if (pSort)
-        *pSort = 0;
-    if (pDisplay)
-        *pDisplay = 0;
-    return S_OK;
-}
-
 HRESULT STDMETHODCALLTYPE CNtObjectFolder::GetDefaultColumnState(
     UINT iColumn,
     SHCOLSTATEF *pcsFlags)
@@ -822,7 +246,7 @@ HRESULT STDMETHODCALLTYPE CNtObjectFolder::GetDefaultColumnState(
         *pcsFlags = SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT;
         return S_OK;
     case NTOBJECT_COLUMN_LINKTARGET:
-        *pcsFlags = SHCOLSTATE_TYPE_STR | SHCOLSTATE_SLOW;
+        *pcsFlags = SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT | SHCOLSTATE_SLOW;
         return S_OK;
     }
 
@@ -840,7 +264,7 @@ HRESULT STDMETHODCALLTYPE CNtObjectFolder::GetDetailsEx(
 
     if (pidl)
     {
-        HRESULT hr = CNtObjectPidlHelper::GetInfoFromPidl(pidl, &info);
+        HRESULT hr = GetInfoFromPidl(pidl, &info);
         if (FAILED_UNEXPECTEDLY(hr))
             return hr;
 
@@ -907,7 +331,7 @@ HRESULT STDMETHODCALLTYPE CNtObjectFolder::GetDetailsOf(
 
     if (pidl)
     {
-        HRESULT hr = CNtObjectPidlHelper::GetInfoFromPidl(pidl, &info);
+        HRESULT hr = GetInfoFromPidl(pidl, &info);
         if (FAILED_UNEXPECTEDLY(hr))
             return hr;
 
@@ -1011,34 +435,92 @@ HRESULT STDMETHODCALLTYPE CNtObjectFolder::MapColumnToSCID(
     return E_INVALIDARG;
 }
 
-HRESULT STDMETHODCALLTYPE CNtObjectFolder::MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
+HRESULT CNtObjectFolder::CompareIDs(LPARAM lParam, const NtPidlEntry * first, const NtPidlEntry * second)
 {
-    switch (uMsg)
-    {
-    case SFVM_DEFVIEWMODE:
+    HRESULT hr;
+
+    LPARAM sortMode = lParam & 0xFFFF0000;
+    LPARAM column = lParam & 0x0000FFFF;
+
+    if (sortMode == SHCIDS_ALLFIELDS)
     {
-        FOLDERVIEWMODE* pViewMode = (FOLDERVIEWMODE*) lParam;
-        *pViewMode = FVM_DETAILS;
-        return S_OK;
+        if (column != 0)
+            return E_INVALIDARG;
+
+        int minsize = min(first->cb, second->cb);
+        hr = MAKE_COMPARE_HRESULT(memcmp(second, first, minsize));
+        if (hr != S_EQUAL)
+            return hr;
+
+        return MAKE_COMPARE_HRESULT(second->cb - first->cb);
     }
-    case SFVM_COLUMNCLICK:
-        return S_FALSE;
-    case SFVM_BACKGROUNDENUM:
-        return S_OK;
+
+    switch (column)
+    {
+    case NTOBJECT_COLUMN_NAME:
+        return CompareName(lParam, first, second);
+
+    case NTOBJECT_COLUMN_TYPE:
+        return MAKE_COMPARE_HRESULT(second->objectType - first->objectType);
+
+    case NTOBJECT_COLUMN_LINKTARGET:
+        // Can't sort by link target yet
+        return E_INVALIDARG;
     }
-    return E_NOTIMPL;
+
+    DbgPrint("Unsupported sorting mode.\n");
+    return E_INVALIDARG;
 }
 
-HRESULT CNtObjectFolder::DefCtxMenuCallback(IShellFolder * /*psf*/, HWND /*hwnd*/, IDataObject * /*pdtobj*/, UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/)
+ULONG CNtObjectFolder::ConvertAttributes(const NtPidlEntry * entry, PULONG inMask)
 {
-    switch (uMsg)
+    ULONG mask = inMask ? *inMask : 0xFFFFFFFF;
+    ULONG flags = SFGAO_HASPROPSHEET | SFGAO_CANLINK;
+
+    if (entry->objectType == DIRECTORY_OBJECT)
+        flags |= SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_BROWSABLE;
+
+    if (entry->objectType == SYMBOLICLINK_OBJECT)
+        flags |= SFGAO_LINK | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_BROWSABLE;
+
+    if (entry->objectType == KEY_OBJECT)
+        flags |= SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_BROWSABLE;
+
+    return flags & mask;
+}
+
+BOOL CNtObjectFolder::IsFolder(LPCITEMIDLIST pcidl)
+{
+    NtPidlEntry * info = (NtPidlEntry*) &(pcidl->mkid);
+    if ((info->cb < sizeof(NtPidlEntry)) || (info->magic != NT_OBJECT_PIDL_MAGIC))
+        return FALSE;
+
+    return IsFolder(info);
+}
+
+BOOL CNtObjectFolder::IsFolder(const NtPidlEntry * info)
+{
+    return (info->objectType == DIRECTORY_OBJECT) ||
+        (info->objectType == SYMBOLICLINK_OBJECT) ||
+        (info->objectType == KEY_OBJECT);
+}
+
+HRESULT CNtObjectFolder::GetInfoFromPidl(LPCITEMIDLIST pcidl, const NtPidlEntry ** pentry)
+{
+    NtPidlEntry * entry = (NtPidlEntry*) &(pcidl->mkid);
+
+    if (entry->cb < sizeof(NtPidlEntry))
     {
-    case DFM_MERGECONTEXTMENU:
-        return S_OK;
-    case DFM_INVOKECOMMAND:
-    case DFM_INVOKECOMMANDEX:
-    case DFM_GETDEFSTATICID: // Required for Windows 7 to pick a default
-        return S_FALSE;
+        DbgPrint("PCIDL too small %l (required %l)\n", entry->cb, sizeof(NtPidlEntry));
+        return E_INVALIDARG;
     }
-    return E_NOTIMPL;
-}
+
+    if (entry->magic != NT_OBJECT_PIDL_MAGIC)
+    {
+        DbgPrint("PCIDL magic mismatch %04x (expected %04x)\n", entry->magic, NT_OBJECT_PIDL_MAGIC);
+        return E_INVALIDARG;
+    }
+
+    *pentry = entry;
+    return S_OK;
+}
\ No newline at end of file
index c689387..2bee6af 100644 (file)
@@ -9,94 +9,74 @@
 
 extern const GUID CLSID_NtObjectFolder;
 
-class CNtObjectFolder :
-    public CComCoClass<CNtObjectFolder, &CLSID_NtObjectFolder>,
+class CNtObjectFolderExtractIcon :
     public CComObjectRootEx<CComMultiThreadModelNoCS>,
-    public IShellFolder2,
-    public IPersistFolder2,
-    public IShellFolderViewCB
+    public IExtractIconW
 {
-    WCHAR m_NtPath[MAX_PATH];
+    PCWSTR m_NtPath;
+    PCIDLIST_ABSOLUTE m_pcidlFolder;
+    PCITEMID_CHILD    m_pcidlChild;
+
+public:
+    CNtObjectFolderExtractIcon();
+
+    virtual ~CNtObjectFolderExtractIcon();
 
-    LPITEMIDLIST m_shellPidl;
+    HRESULT Initialize(LPCWSTR ntPath, PCIDLIST_ABSOLUTE parent, UINT cidl, PCUITEMID_CHILD_ARRAY apidl);
 
+    virtual HRESULT STDMETHODCALLTYPE GetIconLocation(
+        UINT uFlags,
+        LPWSTR szIconFile,
+        UINT cchMax,
+        INT *piIndex,
+        UINT *pwFlags);
+
+    virtual HRESULT STDMETHODCALLTYPE Extract(
+        LPCWSTR pszFile,
+        UINT nIconIndex,
+        HICON *phiconLarge,
+        HICON *phiconSmall,
+        UINT nIconSize);
+
+    DECLARE_NOT_AGGREGATABLE(CNtObjectFolderExtractIcon)
+    DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+    BEGIN_COM_MAP(CNtObjectFolderExtractIcon)
+        COM_INTERFACE_ENTRY_IID(IID_IExtractIconW, IExtractIconW)
+    END_COM_MAP()
+
+};
+
+class CNtObjectFolder :
+    public CComCoClass<CNtObjectFolder, &CLSID_NtObjectFolder>,
+    public CCommonFolder<CNtObjectFolder, NtPidlEntry, CNtObjectFolderExtractIcon>
+{
 public:
 
     CNtObjectFolder();
     virtual ~CNtObjectFolder();
 
     // IShellFolder
-    virtual HRESULT STDMETHODCALLTYPE ParseDisplayName(
-        HWND hwndOwner,
-        LPBC pbcReserved,
-        LPOLESTR lpszDisplayName,
-        ULONG *pchEaten,
-        LPITEMIDLIST *ppidl,
-        ULONG *pdwAttributes);
 
     virtual HRESULT STDMETHODCALLTYPE EnumObjects(
         HWND hwndOwner,
         SHCONTF grfFlags,
         IEnumIDList **ppenumIDList);
 
-    virtual HRESULT STDMETHODCALLTYPE BindToObject(
-        LPCITEMIDLIST pidl,
+    virtual HRESULT STDMETHODCALLTYPE InternalBindToObject(
+        PWSTR path,
+        const NtPidlEntry * info,
+        LPITEMIDLIST first,
+        LPCITEMIDLIST rest,
+        LPITEMIDLIST fullPidl,
         LPBC pbcReserved,
-        REFIID riid,
-        void **ppvOut);
-
-    virtual HRESULT STDMETHODCALLTYPE BindToStorage(
-        LPCITEMIDLIST pidl,
+        IShellFolder** ppsfChild);
+    virtual HRESULT STDMETHODCALLTYPE RedirectToSymLink(
+        const NtPidlEntry * info,
+        LPITEMIDLIST first,
+        LPCITEMIDLIST rest,
         LPBC pbcReserved,
-        REFIID riid,
-        void **ppvObj);
-
-    virtual HRESULT STDMETHODCALLTYPE CompareIDs(
-        LPARAM lParam,
-        LPCITEMIDLIST pidl1,
-        LPCITEMIDLIST pidl2);
-
-    virtual HRESULT STDMETHODCALLTYPE CreateViewObject(
-        HWND hwndOwner,
-        REFIID riid,
-        void **ppvOut);
-
-    virtual HRESULT STDMETHODCALLTYPE GetAttributesOf(
-        UINT cidl,
-        PCUITEMID_CHILD_ARRAY apidl,
-        SFGAOF *rgfInOut);
-
-    virtual HRESULT STDMETHODCALLTYPE GetUIObjectOf(
-        HWND hwndOwner,
-        UINT cidl,
-        PCUITEMID_CHILD_ARRAY apidl,
-        REFIID riid,
-        UINT *prgfInOut,
-        void **ppvOut);
-
-    virtual HRESULT STDMETHODCALLTYPE GetDisplayNameOf(
-        LPCITEMIDLIST pidl,
-        SHGDNF uFlags,
-        STRRET *lpName);
-
-    virtual HRESULT STDMETHODCALLTYPE SetNameOf(
-        HWND hwnd,
-        LPCITEMIDLIST pidl,
-        LPCOLESTR lpszName,
-        SHGDNF uFlags,
-        LPITEMIDLIST *ppidlOut);
-
-    // IShellFolder2
-    virtual HRESULT STDMETHODCALLTYPE GetDefaultSearchGUID(
-        GUID *lpguid);
-
-    virtual HRESULT STDMETHODCALLTYPE EnumSearches(
-        IEnumExtraSearch **ppenum);
-
-    virtual HRESULT STDMETHODCALLTYPE GetDefaultColumn(
-        DWORD dwReserved,
-        ULONG *pSort,
-        ULONG *pDisplay);
+        IShellFolder ** ppsfChild);
 
     virtual HRESULT STDMETHODCALLTYPE GetDefaultColumnState(
         UINT iColumn,
@@ -116,34 +96,22 @@ public:
         UINT iColumn,
         SHCOLUMNID *pscid);
 
-    // IPersist
-    virtual HRESULT STDMETHODCALLTYPE GetClassID(CLSID *lpClassId);
-
     // IPersistFolder
     virtual HRESULT STDMETHODCALLTYPE Initialize(LPCITEMIDLIST pidl);
 
-    // IPersistFolder2
-    virtual HRESULT STDMETHODCALLTYPE GetCurFolder(LPITEMIDLIST * pidl);
-
-    // IShellFolderViewCB
-    virtual HRESULT STDMETHODCALLTYPE MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam);
-
     // Internal
     HRESULT STDMETHODCALLTYPE Initialize(LPCITEMIDLIST pidl, PCWSTR ntPath);
 
-    static HRESULT CALLBACK DefCtxMenuCallback(IShellFolder *, HWND, IDataObject *, UINT, WPARAM, LPARAM);
+protected:
+    virtual HRESULT STDMETHODCALLTYPE CompareIDs(LPARAM lParam, const NtPidlEntry * first, const NtPidlEntry * second);
+    virtual ULONG STDMETHODCALLTYPE ConvertAttributes(const NtPidlEntry * entry, PULONG inMask);
+    virtual BOOL STDMETHODCALLTYPE IsFolder(LPCITEMIDLIST pcidl);
+    virtual BOOL STDMETHODCALLTYPE IsFolder(const NtPidlEntry * info);
+    virtual BOOL STDMETHODCALLTYPE IsSymLink(const NtPidlEntry * info);
 
-    DECLARE_REGISTRY_RESOURCEID(IDR_NTOBJECTFOLDER)
-    DECLARE_NOT_AGGREGATABLE(CNtObjectFolder)
-    DECLARE_PROTECT_FINAL_CONSTRUCT()
+    virtual HRESULT GetInfoFromPidl(LPCITEMIDLIST pcidl, const NtPidlEntry ** pentry);
 
-    BEGIN_COM_MAP(CNtObjectFolder)
-        COM_INTERFACE_ENTRY_IID(IID_IShellFolder, IShellFolder)
-        COM_INTERFACE_ENTRY_IID(IID_IShellFolder2, IShellFolder2)
-        COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist)
-        COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder)
-        COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2)
-        COM_INTERFACE_ENTRY_IID(IID_IShellFolderViewCB, IShellFolderViewCB)
-    END_COM_MAP()
+    HRESULT FormatValueData(DWORD contentType, PVOID td, DWORD contentsLength, PCWSTR * strContents);
 
+    HRESULT FormatContentsForDisplay(const NtPidlEntry * info, HKEY rootKey, LPCWSTR ntPath, PCWSTR * strContents);
 };
\ No newline at end of file
index 207e943..049fd12 100644 (file)
@@ -46,5 +46,23 @@ extern HINSTANCE g_hInstance;
 DEFINE_GUID(CLSID_NtObjectFolder,
     0x845b0fb2, 0x66e0, 0x416b, 0x8f, 0x91, 0x31, 0x4e, 0x23, 0xf7, 0xc1, 0x2d);
 
+#define DFM_MERGECONTEXTMENU 1 // uFlags LPQCMINFO
+#define DFM_INVOKECOMMAND 2 // idCmd pszArgs
+#define DFM_INVOKECOMMANDEX 12 // idCmd PDFMICS
+#define DFM_GETDEFSTATICID 14 // idCmd * 0
+
+#define SHCIDS_ALLFIELDS 0x80000000L
+#define SHCIDS_CANONICALONLY 0x10000000L
+
+#define GET_SHGDN_FOR(dwFlags)         ((DWORD)dwFlags & (DWORD)0x0000FF00)
+#define GET_SHGDN_RELATION(dwFlags)    ((DWORD)dwFlags & (DWORD)0x000000FF)
+
+#include <rtlfuncs.h>
+#include <ntquery.h>
+#include "util.h"
+
+#include "ntobjenum.h"
+
+#include "foldercommon.h"
 #include "ntobjfolder.h"
 #include "regfolder.h"
index 8781886..fea0ff7 100644 (file)
@@ -7,20 +7,6 @@
  */
 
 #include "precomp.h"
-#include "ntobjenum.h"
-#include <ntquery.h>
-#include "util.h"
-
-#define DFM_MERGECONTEXTMENU 1 // uFlags LPQCMINFO
-#define DFM_INVOKECOMMAND 2 // idCmd pszArgs
-#define DFM_INVOKECOMMANDEX 12 // idCmd PDFMICS
-#define DFM_GETDEFSTATICID 14 // idCmd * 0
-
-#define SHCIDS_ALLFIELDS 0x80000000L
-#define SHCIDS_CANONICALONLY 0x10000000L
-
-#define GET_SHGDN_FOR(dwFlags)         ((DWORD)dwFlags & (DWORD)0x0000FF00)
-#define GET_SHGDN_RELATION(dwFlags)    ((DWORD)dwFlags & (DWORD)0x000000FF)
 
 WINE_DEFAULT_DEBUG_CHANNEL(ntobjshex);
 
@@ -38,483 +24,88 @@ enum RegistryColumns
     REGISTRY_COLUMN_END
 };
 
-class CRegistryFolderExtractIcon :
-    public CComObjectRootEx<CComMultiThreadModelNoCS>,
-    public IExtractIconW
+// -------------------------------
+// CRegistryFolderExtractIcon
+CRegistryFolderExtractIcon::CRegistryFolderExtractIcon() :
+    m_pcidlFolder(NULL),
+    m_pcidlChild(NULL)
 {
-    PCIDLIST_ABSOLUTE m_pcidlFolder;
-    PCITEMID_CHILD    m_pcidlChild;
-
-public:
-    CRegistryFolderExtractIcon() :
-        m_pcidlFolder(NULL),
-        m_pcidlChild(NULL)
-    {
-
-    }
-
-    virtual ~CRegistryFolderExtractIcon()
-    {
-        if (m_pcidlFolder)
-            ILFree((LPITEMIDLIST) m_pcidlFolder);
-        if (m_pcidlChild)
-            ILFree((LPITEMIDLIST) m_pcidlChild);
-    }
-
-    HRESULT Initialize(PCIDLIST_ABSOLUTE parent, UINT cidl, PCUITEMID_CHILD_ARRAY apidl)
-    {
-        m_pcidlFolder = ILClone(parent);
-        if (cidl != 1)
-            return E_INVALIDARG;
-        m_pcidlChild = ILClone(apidl[0]);
-        return S_OK;
-    }
-
-    virtual HRESULT STDMETHODCALLTYPE GetIconLocation(
-        UINT uFlags,
-        LPWSTR szIconFile,
-        UINT cchMax,
-        INT *piIndex,
-        UINT *pwFlags)
-    {
-        const RegPidlEntry * entry = (RegPidlEntry *) m_pcidlChild;
-
-        if ((entry->cb < sizeof(RegPidlEntry)) || (entry->magic != REGISTRY_PIDL_MAGIC))
-            return E_INVALIDARG;
-
-        UINT flags = 0;
-
-        switch (entry->entryType)
-        {
-        case REG_ENTRY_KEY:
-        case REG_ENTRY_ROOT:
-            GetModuleFileNameW(g_hInstance, szIconFile, cchMax);
-            *piIndex = -IDI_REGISTRYKEY;
-            *pwFlags = flags;
-            return S_OK;
-        case REG_ENTRY_VALUE:
-            GetModuleFileNameW(g_hInstance, szIconFile, cchMax);
-            *piIndex = -IDI_REGISTRYVALUE;
-            *pwFlags = flags;
-            return S_OK;
-        default:
-            GetModuleFileNameW(g_hInstance, szIconFile, cchMax);
-            *piIndex = -IDI_NTOBJECTITEM;
-            *pwFlags = flags;
-            return S_OK;
-        }
-    }
-
-    virtual HRESULT STDMETHODCALLTYPE Extract(
-        LPCWSTR pszFile,
-        UINT nIconIndex,
-        HICON *phiconLarge,
-        HICON *phiconSmall,
-        UINT nIconSize)
-    {
-        return SHDefExtractIconW(pszFile, nIconIndex, 0, phiconLarge, phiconSmall, nIconSize);
-    }
-
-    DECLARE_NOT_AGGREGATABLE(CRegistryFolderExtractIcon)
-    DECLARE_PROTECT_FINAL_CONSTRUCT()
 
-    BEGIN_COM_MAP(CRegistryFolderExtractIcon)
-        COM_INTERFACE_ENTRY_IID(IID_IExtractIconW, IExtractIconW)
-    END_COM_MAP()
-
-};
+}
 
-class CRegistryPidlHelper
+CRegistryFolderExtractIcon::~CRegistryFolderExtractIcon()
 {
-public:
-    static HRESULT CompareIDs(LPARAM lParam, const RegPidlEntry * first, const RegPidlEntry * second)
-    {
-        if ((lParam & 0xFFFF0000) == SHCIDS_ALLFIELDS)
-        {
-            if (lParam != 0)
-                return E_INVALIDARG;
-
-            int minsize = min(first->cb, second->cb);
-            int ord = memcmp(second, first, minsize);
-
-            if (ord != 0)
-                return MAKE_HRESULT(0, 0, (USHORT) ord);
-
-            if (second->cb > first->cb)
-                return MAKE_HRESULT(0, 0, (USHORT) 1);
-            if (second->cb < first->cb)
-                return MAKE_HRESULT(0, 0, (USHORT) -1);
-        }
-        else
-        {
-            bool canonical = ((lParam & 0xFFFF0000) == SHCIDS_CANONICALONLY);
-
-            switch (lParam & 0xFFFF)
-            {
-            case REGISTRY_COLUMN_NAME:
-            {
-                bool f1 = (first->entryType == REG_ENTRY_KEY) || (first->entryType == REG_ENTRY_ROOT);
-                bool f2 = (second->entryType == REG_ENTRY_KEY) || (second->entryType == REG_ENTRY_ROOT);
-
-                if (f1 && !f2)
-                    return MAKE_HRESULT(0, 0, (USHORT) -1);
-                if (f2 && !f1)
-                    return MAKE_HRESULT(0, 0, (USHORT) 1);
-
-                if (canonical)
-                {
-                    // Shortcut: avoid comparing contents if not necessary when the results are not for display.
-                    if (second->entryNameLength > first->entryNameLength)
-                        return MAKE_HRESULT(0, 0, (USHORT) 1);
-                    if (second->entryNameLength < first->entryNameLength)
-                        return MAKE_HRESULT(0, 0, (USHORT) -1);
-
-                    int minlength = min(first->entryNameLength, second->entryNameLength);
-                    if (minlength > 0)
-                    {
-                        int ord = memcmp(first->entryName, second->entryName, minlength);
-                        if (ord != 0)
-                            return MAKE_HRESULT(0, 0, (USHORT) ord);
-                    }
-                    return S_OK;
-                }
-                else
-                {
-                    int minlength = min(first->entryNameLength, second->entryNameLength);
-                    if (minlength > 0)
-                    {
-                        int ord = StrCmpNW(first->entryName, second->entryName, minlength / sizeof(WCHAR));
-                        if (ord != 0)
-                            return MAKE_HRESULT(0, 0, (USHORT) ord);
-                    }
-
-                    if (second->entryNameLength > first->entryNameLength)
-                        return MAKE_HRESULT(0, 0, (USHORT) 1);
-                    if (second->entryNameLength < first->entryNameLength)
-                        return MAKE_HRESULT(0, 0, (USHORT) -1);
-
-                    return S_OK;
-                }
-            }
-            case REGISTRY_COLUMN_TYPE:
-            {
-                int ord = second->contentType - first->contentType;
-                if (ord > 0)
-                    return MAKE_HRESULT(0, 0, (USHORT) 1);
-                if (ord < 0)
-                    return MAKE_HRESULT(0, 0, (USHORT) -1);
-
-                return S_OK;
-            }
-            case REGISTRY_COLUMN_VALUE:
-            {
-                // Can't sort by value
-                return E_INVALIDARG;
-            }
-            default:
-            {
-                DbgPrint("Unsupported sorting mode.\n");
-                return E_INVALIDARG;
-            }
-            }
-        }
+    if (m_pcidlFolder)
+        ILFree((LPITEMIDLIST)m_pcidlFolder);
+    if (m_pcidlChild)
+        ILFree((LPITEMIDLIST)m_pcidlChild);
+}
 
+HRESULT CRegistryFolderExtractIcon::Initialize(LPCWSTR ntPath, PCIDLIST_ABSOLUTE parent, UINT cidl, PCUITEMID_CHILD_ARRAY apidl)
+{
+    m_pcidlFolder = ILClone(parent);
+    if (cidl != 1)
         return E_INVALIDARG;
-    }
-
-    static HRESULT CompareIDs(LPARAM lParam, const RegPidlEntry * first, LPCITEMIDLIST pcidl)
-    {
-        LPCITEMIDLIST p = pcidl;
-        RegPidlEntry * second = (RegPidlEntry*) &(p->mkid);
-        if ((second->cb < sizeof(RegPidlEntry)) || (second->magic != REGISTRY_PIDL_MAGIC))
-            return E_INVALIDARG;
-
-        return CompareIDs(lParam, first, second);
-    }
-
-    static HRESULT CompareIDs(LPARAM lParam, LPCITEMIDLIST pcidl1, LPCITEMIDLIST pcidl2)
-    {
-        LPCITEMIDLIST p = pcidl1;
-        RegPidlEntry * first = (RegPidlEntry*) &(p->mkid);
-        if ((first->cb < sizeof(RegPidlEntry)) || (first->magic != REGISTRY_PIDL_MAGIC))
-            return E_INVALIDARG;
-
-        return CompareIDs(lParam, first, pcidl2);
-    }
-
-    static ULONG ConvertAttributes(const RegPidlEntry * entry, PULONG inMask)
-    {
-        ULONG mask = inMask ? *inMask : 0xFFFFFFFF;
-        ULONG flags = 0;
-
-        if ((entry->entryType == REG_ENTRY_KEY) ||
-            (entry->entryType == REG_ENTRY_ROOT))
-            flags |= SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_BROWSABLE;
+    m_pcidlChild = ILClone(apidl[0]);
+    return S_OK;
+}
 
-        return flags & mask;
-    }
+HRESULT STDMETHODCALLTYPE CRegistryFolderExtractIcon::GetIconLocation(
+    UINT uFlags,
+    LPWSTR szIconFile,
+    UINT cchMax,
+    INT *piIndex,
+    UINT *pwFlags)
+{
+    const RegPidlEntry * entry = (RegPidlEntry *)m_pcidlChild;
 
-    static BOOL IsFolder(LPCITEMIDLIST pcidl)
-    {
-        RegPidlEntry * entry = (RegPidlEntry*) &(pcidl->mkid);
-        if ((entry->cb < sizeof(RegPidlEntry)) || (entry->magic != REGISTRY_PIDL_MAGIC))
-            return FALSE;
+    if ((entry->cb < sizeof(RegPidlEntry)) || (entry->magic != REGISTRY_PIDL_MAGIC))
+        return E_INVALIDARG;
 
-        return (entry->entryType == REG_ENTRY_KEY) ||
-            (entry->entryType == REG_ENTRY_ROOT);
-    }
+    UINT flags = 0;
 
-    static HRESULT GetInfoFromPidl(LPCITEMIDLIST pcidl, const RegPidlEntry ** pentry)
+    switch (entry->entryType)
     {
-        RegPidlEntry * entry = (RegPidlEntry*) &(pcidl->mkid);
-
-        if (entry->cb < sizeof(RegPidlEntry))
-        {
-            DbgPrint("PCIDL too small %l (required %l)\n", entry->cb, sizeof(RegPidlEntry));
-            return E_INVALIDARG;
-        }
-
-        if (entry->magic != REGISTRY_PIDL_MAGIC)
-        {
-            DbgPrint("PCIDL magic mismatch %04x (expected %04x)\n", entry->magic, REGISTRY_PIDL_MAGIC);
-            return E_INVALIDARG;
-        }
-
-        *pentry = entry;
+    case REG_ENTRY_KEY:
+    case REG_ENTRY_ROOT:
+        GetModuleFileNameW(g_hInstance, szIconFile, cchMax);
+        *piIndex = -IDI_REGISTRYKEY;
+        *pwFlags = flags;
         return S_OK;
-    }
-
-    static HRESULT FormatValueData(DWORD contentType, PVOID td, DWORD contentsLength, PCWSTR * strContents)
-    {
-        switch (contentType)
-        {
-        case 0:
-        {
-            PCWSTR strTodo = L"";
-            DWORD bufferLength = (wcslen(strTodo) + 1) * sizeof(WCHAR);
-            PWSTR strValue = (PWSTR) CoTaskMemAlloc(bufferLength);
-            StringCbCopyW(strValue, bufferLength, strTodo);
-            *strContents = strValue;
-            return S_OK;
-        }
-        case REG_SZ:
-        case REG_EXPAND_SZ:
-        {
-            PWSTR strValue = (PWSTR) CoTaskMemAlloc(contentsLength + sizeof(WCHAR));
-            StringCbCopyNW(strValue, contentsLength + sizeof(WCHAR), (LPCWSTR) td, contentsLength);
-            *strContents = strValue;
-            return S_OK;
-        }
-        case REG_MULTI_SZ:
-        {
-            PCWSTR separator = L" "; // To match regedit
-            size_t sepChars = wcslen(separator);
-            int strings = 0;
-            int stringChars = 0;
-
-            PCWSTR strData = (PCWSTR)td;
-            while (*strData)
-            {
-                size_t len = wcslen(strData);
-                stringChars += len;
-                strData += len + 1; // Skips null-terminator
-                strings++;
-            }
-
-            int cch = stringChars + (strings - 1) * sepChars + 1;
-
-            PWSTR strValue = (PWSTR)CoTaskMemAlloc(cch * sizeof(WCHAR));
-
-            strValue[0] = 0;
-
-            strData = (PCWSTR)td;
-            while (*strData)
-            {
-                StrCatW(strValue, strData);
-                strData += wcslen(strData) + 1;
-                if (*strData)
-                    StrCatW(strValue, separator);
-            }
-
-            *strContents = strValue;
-            return S_OK;
-        }
-        case REG_DWORD:
-        {
-            DWORD bufferLength = 64 * sizeof(WCHAR);
-            PWSTR strValue = (PWSTR) CoTaskMemAlloc(bufferLength);
-            StringCbPrintfW(strValue, bufferLength, L"0x%08x (%d)",
-                *(DWORD*) td, *(DWORD*) td);
-            *strContents = strValue;
-            return S_OK;
-        }
-        case REG_QWORD:
-        {
-            DWORD bufferLength = 64 * sizeof(WCHAR);
-            PWSTR strValue = (PWSTR) CoTaskMemAlloc(bufferLength);
-            StringCbPrintfW(strValue, bufferLength, L"0x%016llx (%lld)",
-                *(LARGE_INTEGER*) td, ((LARGE_INTEGER*) td)->QuadPart);
-            *strContents = strValue;
-            return S_OK;
-        }
-        case REG_BINARY:
-        {
-            DWORD bufferLength = (contentsLength * 3 + 1) * sizeof(WCHAR);
-            PWSTR strValue = (PWSTR)CoTaskMemAlloc(bufferLength);
-            PWSTR strTemp = strValue;
-            PBYTE data = (PBYTE)td;
-            for (DWORD i = 0; i < contentsLength; i++)
-            {
-                StringCbPrintfW(strTemp, bufferLength, L"%02x ", data[i]);
-                strTemp += 3;
-                bufferLength -= 3;
-            }
-            *strContents = strValue;
-            return S_OK;
-        }
-        default:
-        {
-            PCWSTR strFormat = L"<Unimplemented value type %d>";
-            DWORD bufferLength = (wcslen(strFormat) + 15) * sizeof(WCHAR);
-            PWSTR strValue = (PWSTR) CoTaskMemAlloc(bufferLength);
-            StringCbPrintfW(strValue, bufferLength, strFormat, contentType);
-            *strContents = strValue;
-            return S_OK;
-        }
-        }
-    }
-
-    static HRESULT FormatContentsForDisplay(const RegPidlEntry * info, HKEY rootKey, LPCWSTR ntPath, PCWSTR * strContents)
-    {
-        PVOID td = (((PBYTE) info) + FIELD_OFFSET(RegPidlEntry, entryName) + info->entryNameLength + sizeof(WCHAR));
-
-        if (info->entryType == REG_ENTRY_VALUE_WITH_CONTENT)
-        {
-            if (info->contentsLength > 0)
-            {
-                return FormatValueData(info->contentType, td, info->contentsLength, strContents);
-            }
-        }
-        else if (info->entryType == REG_ENTRY_VALUE)
-        {
-            PVOID valueData;
-            DWORD valueLength;
-            HRESULT hr = ReadRegistryValue(rootKey, ntPath, info->entryName, &valueData, &valueLength);
-            if (FAILED_UNEXPECTEDLY(hr))
-            {
-                PCWSTR strEmpty = L"(Error reading value)";
-                DWORD bufferLength = (wcslen(strEmpty) + 1) * sizeof(WCHAR);
-                PWSTR strValue = (PWSTR) CoTaskMemAlloc(bufferLength);
-                StringCbCopyW(strValue, bufferLength, strEmpty);
-                *strContents = strValue;
-                return S_OK;
-            }
-
-            if (valueLength > 0)
-            {
-                hr = FormatValueData(info->contentType, valueData, valueLength, strContents);
-
-                CoTaskMemFree(valueData);
-
-                return hr;
-            }
-        }
-        else
-        {
-            PCWSTR strEmpty = L"";
-            DWORD bufferLength = (wcslen(strEmpty) + 1) * sizeof(WCHAR);
-            PWSTR strValue = (PWSTR) CoTaskMemAlloc(bufferLength);
-            StringCbCopyW(strValue, bufferLength, strEmpty);
-            *strContents = strValue;
-            return S_OK;
-        }
-
-        PCWSTR strEmpty = L"(Empty)";
-        DWORD bufferLength = (wcslen(strEmpty) + 1) * sizeof(WCHAR);
-        PWSTR strValue = (PWSTR) CoTaskMemAlloc(bufferLength);
-        StringCbCopyW(strValue, bufferLength, strEmpty);
-        *strContents = strValue;
+    case REG_ENTRY_VALUE:
+        GetModuleFileNameW(g_hInstance, szIconFile, cchMax);
+        *piIndex = -IDI_REGISTRYVALUE;
+        *pwFlags = flags;
+        return S_OK;
+    default:
+        GetModuleFileNameW(g_hInstance, szIconFile, cchMax);
+        *piIndex = -IDI_NTOBJECTITEM;
+        *pwFlags = flags;
         return S_OK;
     }
-};
-
-//-----------------------------------------------------------------------------
-// CRegistryFolder
+}
 
-CRegistryFolder::CRegistryFolder() :
-    m_shellPidl(NULL)
+HRESULT STDMETHODCALLTYPE CRegistryFolderExtractIcon::Extract(
+    LPCWSTR pszFile,
+    UINT nIconIndex,
+    HICON *phiconLarge,
+    HICON *phiconSmall,
+    UINT nIconSize)
 {
+    return SHDefExtractIconW(pszFile, nIconIndex, 0, phiconLarge, phiconSmall, nIconSize);
 }
 
-CRegistryFolder::~CRegistryFolder()
+// CRegistryFolder 
+
+CRegistryFolder::CRegistryFolder()
 {
-    if (m_shellPidl)
-        ILFree(m_shellPidl);
 }
 
-// IShellFolder
-HRESULT STDMETHODCALLTYPE CRegistryFolder::ParseDisplayName(
-    HWND hwndOwner,
-    LPBC pbcReserved,
-    LPOLESTR lpszDisplayName,
-    ULONG *pchEaten,
-    LPITEMIDLIST *ppidl,
-    ULONG *pdwAttributes)
+CRegistryFolder::~CRegistryFolder()
 {
-    if (!ppidl)
-        return E_POINTER;
-
-    if (pchEaten)
-        *pchEaten = 0;
-
-    if (pdwAttributes)
-        *pdwAttributes = 0;
-
-    TRACE("CRegistryFolder::ParseDisplayName name=%S (ntPath=%S)\n", lpszDisplayName, m_NtPath);
-
-    const RegPidlEntry * info;
-    IEnumIDList * it;
-    HRESULT hr = GetEnumNTDirectory(m_NtPath, &it);
-    if (FAILED(hr))
-    {
-        return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
-    }
-
-    while (TRUE)
-    {
-        hr = it->Next(1, ppidl, NULL);
-
-        if (FAILED(hr))
-            return hr;
-
-        if (hr != S_OK)
-            break;
-
-        hr = CRegistryPidlHelper::GetInfoFromPidl(*ppidl, &info);
-        if (FAILED_UNEXPECTEDLY(hr))
-            return hr;
-
-        if (StrCmpW(info->entryName, lpszDisplayName) == 0)
-            break;
-    }
-
-    if (hr != S_OK)
-    {
-        return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
-    }
-
-    if (pchEaten || pdwAttributes)
-    {
-        if (pchEaten)
-            *pchEaten = wcslen(info->entryName);
-
-        if (pdwAttributes)
-            *pdwAttributes = CRegistryPidlHelper::ConvertAttributes(info, pdwAttributes);
-    }
-
-    return S_OK;
 }
 
+// IShellFolder
 HRESULT STDMETHODCALLTYPE CRegistryFolder::EnumObjects(
     HWND hwndOwner,
     SHCONTF grfFlags,
@@ -530,307 +121,23 @@ HRESULT STDMETHODCALLTYPE CRegistryFolder::EnumObjects(
     }
 }
 
-HRESULT STDMETHODCALLTYPE CRegistryFolder::BindToObject(
-    LPCITEMIDLIST pidl,
-    LPBC pbcReserved,
-    REFIID riid,
-    void **ppvOut)
-{
-    const RegPidlEntry * info;
-
-    if (IsEqualIID(riid, IID_IShellFolder))
-    {
-        HRESULT hr = CRegistryPidlHelper::GetInfoFromPidl(pidl, &info);
-        if (FAILED_UNEXPECTEDLY(hr))
-            return hr;
-
-        LPITEMIDLIST first = ILCloneFirst(pidl);
-        LPCITEMIDLIST rest = ILGetNext(pidl);
-
-        LPITEMIDLIST fullPidl = ILCombine(m_shellPidl, first);
-
-        CComPtr<IShellFolder> psfChild;
-        if (wcslen(m_NtPath) == 0 && m_hRoot == NULL)
-        {
-            hr = ShellObjectCreatorInit<CRegistryFolder>(fullPidl, L"", info->rootKey, IID_PPV_ARG(IShellFolder, &psfChild));
-        }
-        else
-        {
-            WCHAR path[MAX_PATH];
-
-            StringCbCopyW(path, _countof(path), m_NtPath);
-
-            PathAppendW(path, info->entryName);
-
-            hr = ShellObjectCreatorInit<CRegistryFolder>(fullPidl, path, m_hRoot, IID_PPV_ARG(IShellFolder, &psfChild));
-        }
-
-        ILFree(fullPidl);
-        ILFree(first);
-
-        if (rest->mkid.cb > 0)
-        {
-            return psfChild->BindToObject(rest, pbcReserved, riid, ppvOut);
-        }
-
-        return psfChild->QueryInterface(riid, ppvOut);
-    }
-
-    return E_NOTIMPL;
-}
-
-HRESULT STDMETHODCALLTYPE CRegistryFolder::BindToStorage(
-    LPCITEMIDLIST pidl,
+HRESULT STDMETHODCALLTYPE CRegistryFolder::InternalBindToObject(
+    PWSTR path,
+    const RegPidlEntry * info,
+    LPITEMIDLIST first,
+    LPCITEMIDLIST rest,
+    LPITEMIDLIST fullPidl,
     LPBC pbcReserved,
-    REFIID riid,
-    void **ppvObj)
-{
-    UNIMPLEMENTED;
-    return E_NOTIMPL;
-}
-
-HRESULT STDMETHODCALLTYPE CRegistryFolder::CompareIDs(
-    LPARAM lParam,
-    LPCITEMIDLIST pidl1,
-    LPCITEMIDLIST pidl2)
+    IShellFolder** ppsfChild)
 {
-    TRACE("CompareIDs\n");
-
-    HRESULT hr = CRegistryPidlHelper::CompareIDs(lParam, pidl1, pidl2);
-    if (hr != S_OK)
-        return hr;
-
-    LPCITEMIDLIST rest1 = ILGetNext(pidl1);
-    LPCITEMIDLIST rest2 = ILGetNext(pidl2);
-
-    bool hasNext1 = (rest1->mkid.cb > 0);
-    bool hasNext2 = (rest2->mkid.cb > 0);
-
-    if (hasNext1 || hasNext2)
-    {
-        if (hasNext1 && !hasNext2)
-            return MAKE_HRESULT(0, 0, (USHORT) -1);
-
-        if (hasNext2 && !hasNext1)
-            return MAKE_HRESULT(0, 0, (USHORT) 1);
-
-        LPCITEMIDLIST first1 = ILCloneFirst(pidl1);
-
-        CComPtr<IShellFolder> psfNext;
-        hr = BindToObject(first1, NULL, IID_PPV_ARG(IShellFolder, &psfNext));
-        if (FAILED_UNEXPECTEDLY(hr))
-            return hr;
-
-        return psfNext->CompareIDs(lParam, rest1, rest2);
-    }
-
-    return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE CRegistryFolder::CreateViewObject(
-    HWND hwndOwner,
-    REFIID riid,
-    void **ppvOut)
-{
-    if (!IsEqualIID(riid, IID_IShellView))
-        return E_NOINTERFACE;
-
-    SFV_CREATE sfv;
-    sfv.cbSize = sizeof(sfv);
-    sfv.pshf = this;
-    sfv.psvOuter = NULL;
-    sfv.psfvcb = this;
-
-    return SHCreateShellFolderView(&sfv, (IShellView**) ppvOut);
-}
-
-HRESULT STDMETHODCALLTYPE CRegistryFolder::GetAttributesOf(
-    UINT cidl,
-    PCUITEMID_CHILD_ARRAY apidl,
-    SFGAOF *rgfInOut)
-{
-    const RegPidlEntry * info;
-
-    TRACE("GetAttributesOf\n");
-
-    if (cidl == 0)
-    {
-        *rgfInOut &= SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_BROWSABLE;
-        return S_OK;
-    }
-
-    for (int i = 0; i < (int) cidl; i++)
-    {
-        PCUITEMID_CHILD pidl = apidl[i];
-
-        HRESULT hr = CRegistryPidlHelper::GetInfoFromPidl(pidl, &info);
-        if (FAILED_UNEXPECTEDLY(hr))
-            return hr;
-
-        // Update attributes.
-        *rgfInOut = CRegistryPidlHelper::ConvertAttributes(info, rgfInOut);
-    }
-
-    return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE CRegistryFolder::GetUIObjectOf(
-    HWND hwndOwner,
-    UINT cidl,
-    PCUITEMID_CHILD_ARRAY apidl,
-    REFIID riid,
-    UINT *prgfInOut,
-    void **ppvOut)
-{
-    TRACE("GetUIObjectOf\n");
-
-    if (IsEqualIID(riid, IID_IContextMenu) ||
-        IsEqualIID(riid, IID_IContextMenu2) ||
-        IsEqualIID(riid, IID_IContextMenu3))
-    {
-        CComPtr<IContextMenu> pcm;
-
-        DWORD res;
-        HKEY keys[1];
-
-        int nkeys = _countof(keys);
-        if (cidl == 1 && CRegistryPidlHelper::IsFolder(apidl[0]))
-        {
-            res = RegOpenKey(HKEY_CLASSES_ROOT, L"Folder", keys + 0);
-            if (!NT_SUCCESS(res))
-                return HRESULT_FROM_NT(res);
-        }
-        else
-        {
-            nkeys = 0;
-        }
-
-        HRESULT hr = CDefFolderMenu_Create2(m_shellPidl, hwndOwner, cidl, apidl, this, DefCtxMenuCallback, nkeys, keys, &pcm);
-        if (FAILED_UNEXPECTEDLY(hr))
-            return hr;
-
-        return pcm->QueryInterface(riid, ppvOut);
-    }
-
-    if (IsEqualIID(riid, IID_IExtractIconW))
-    {
-        return ShellObjectCreatorInit<CRegistryFolderExtractIcon>(m_shellPidl, cidl, apidl, riid, ppvOut);
-    }
-
-    if (IsEqualIID(riid, IID_IDataObject))
-    {
-        return CIDLData_CreateFromIDArray(m_shellPidl, cidl, apidl, (IDataObject**) ppvOut);
-    }
-
-    if (IsEqualIID(riid, IID_IQueryAssociations))
+    if (wcslen(m_NtPath) == 0 && m_hRoot == NULL)
     {
-        if (cidl == 1 && CRegistryPidlHelper::IsFolder(apidl[0]))
-        {
-            CComPtr<IQueryAssociations> pqa;
-            HRESULT hr = AssocCreate(CLSID_QueryAssociations, IID_PPV_ARG(IQueryAssociations, &pqa));
-            if (FAILED_UNEXPECTEDLY(hr))
-                return hr;
-
-            hr = pqa->Init(ASSOCF_INIT_DEFAULTTOFOLDER, L"NTObjShEx.RegFolder", NULL, hwndOwner);
-            if (FAILED_UNEXPECTEDLY(hr))
-                return hr;
-
-            return pqa->QueryInterface(riid, ppvOut);
-        }
+        return ShellObjectCreatorInit<CRegistryFolder>(fullPidl, L"", info->rootKey, IID_PPV_ARG(IShellFolder, ppsfChild));
     }
 
-    return E_NOTIMPL;
+    return ShellObjectCreatorInit<CRegistryFolder>(fullPidl, path, m_hRoot, IID_PPV_ARG(IShellFolder, ppsfChild));
 }
 
-HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDisplayNameOf(
-    LPCITEMIDLIST pidl,
-    SHGDNF uFlags,
-    STRRET *lpName)
-{
-    const RegPidlEntry * info;
-
-    TRACE("GetDisplayNameOf %p\n", pidl);
-
-    HRESULT hr = CRegistryPidlHelper::GetInfoFromPidl(pidl, &info);
-    if (FAILED_UNEXPECTEDLY(hr))
-        return hr;
-
-    if (GET_SHGDN_FOR(uFlags) & SHGDN_FOREDITING)
-    {
-        hr = MakeStrRetFromString(info->entryName, info->entryNameLength, lpName);
-        if (FAILED_UNEXPECTEDLY(hr))
-            return hr;
-    }
-
-    WCHAR path[MAX_PATH] = { 0 };
-
-    if (GET_SHGDN_FOR(uFlags) & SHGDN_FORPARSING)
-    {
-        if (GET_SHGDN_RELATION(uFlags) != SHGDN_INFOLDER)
-        {
-            hr = GetFullName(m_shellPidl, uFlags, path, _countof(path));
-            if (FAILED_UNEXPECTEDLY(hr))
-                return hr;
-        }
-    }
-
-    PathAppendW(path, info->entryName);
-
-    LPCITEMIDLIST pidlNext = ILGetNext(pidl);
-    if (pidlNext && pidlNext->mkid.cb > 0)
-    {
-        LPITEMIDLIST pidlFirst = ILCloneFirst(pidl);
-
-        CComPtr<IShellFolder> psfChild;
-        hr = BindToObject(pidlFirst, NULL, IID_PPV_ARG(IShellFolder, &psfChild));
-        if (FAILED_UNEXPECTEDLY(hr))
-            return hr;
-
-        WCHAR temp[MAX_PATH];
-        STRRET childName;
-
-        hr = psfChild->GetDisplayNameOf(pidlNext, uFlags | SHGDN_INFOLDER, &childName);
-        if (FAILED_UNEXPECTEDLY(hr))
-            return hr;
-
-        hr = StrRetToBufW(&childName, pidlNext, temp, _countof(temp));
-        if (FAILED_UNEXPECTEDLY(hr))
-            return hr;
-
-        PathAppendW(path, temp);
-
-        ILFree(pidlFirst);
-    }
-
-    hr = MakeStrRetFromString(path, lpName);
-    if (FAILED_UNEXPECTEDLY(hr))
-        return hr;
-
-    return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE CRegistryFolder::SetNameOf(
-    HWND hwnd,
-    LPCITEMIDLIST pidl,
-    LPCOLESTR lpszName,
-    SHGDNF uFlags,
-    LPITEMIDLIST *ppidlOut)
-{
-    UNIMPLEMENTED;
-    return E_NOTIMPL;
-}
-
-// IPersist
-HRESULT STDMETHODCALLTYPE CRegistryFolder::GetClassID(CLSID *lpClassId)
-{
-    if (!lpClassId)
-        return E_POINTER;
-
-    *lpClassId = CLSID_RegistryFolder;
-    return S_OK;
-}
-
-// IPersistFolder
 HRESULT STDMETHODCALLTYPE CRegistryFolder::Initialize(LPCITEMIDLIST pidl)
 {
     m_shellPidl = ILClone(pidl);
@@ -840,7 +147,6 @@ HRESULT STDMETHODCALLTYPE CRegistryFolder::Initialize(LPCITEMIDLIST pidl)
     return S_OK;
 }
 
-// Internal
 HRESULT STDMETHODCALLTYPE CRegistryFolder::Initialize(LPCITEMIDLIST pidl, PCWSTR ntPath, HKEY hRoot)
 {
     m_shellPidl = ILClone(pidl);
@@ -850,43 +156,6 @@ HRESULT STDMETHODCALLTYPE CRegistryFolder::Initialize(LPCITEMIDLIST pidl, PCWSTR
     return S_OK;
 }
 
-// IPersistFolder2
-HRESULT STDMETHODCALLTYPE CRegistryFolder::GetCurFolder(LPITEMIDLIST * pidl)
-{
-    if (pidl)
-        *pidl = ILClone(m_shellPidl);
-    if (!m_shellPidl)
-        return S_FALSE;
-    return S_OK;
-}
-
-// IShellFolder2
-HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDefaultSearchGUID(
-    GUID *lpguid)
-{
-    UNIMPLEMENTED;
-    return E_NOTIMPL;
-}
-
-HRESULT STDMETHODCALLTYPE CRegistryFolder::EnumSearches(
-    IEnumExtraSearch **ppenum)
-{
-    UNIMPLEMENTED;
-    return E_NOTIMPL;
-}
-
-HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDefaultColumn(
-    DWORD dwReserved,
-    ULONG *pSort,
-    ULONG *pDisplay)
-{
-    if (pSort)
-        *pSort = 0;
-    if (pDisplay)
-        *pDisplay = 0;
-    return S_OK;
-}
-
 HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDefaultColumnState(
     UINT iColumn,
     SHCOLSTATEF *pcsFlags)
@@ -918,7 +187,7 @@ HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDetailsEx(
 
     if (pidl)
     {
-        HRESULT hr = CRegistryPidlHelper::GetInfoFromPidl(pidl, &info);
+        HRESULT hr = GetInfoFromPidl(pidl, &info);
         if (FAILED_UNEXPECTEDLY(hr))
             return hr;
 
@@ -944,7 +213,7 @@ HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDetailsEx(
                 {
                     if (info->contentsLength > 0)
                     {
-                        PWSTR td = (PWSTR) (((PBYTE) info) + FIELD_OFFSET(RegPidlEntry, entryName) + info->entryNameLength + sizeof(WCHAR));
+                        PWSTR td = (PWSTR)(((PBYTE)info) + FIELD_OFFSET(RegPidlEntry, entryName) + info->entryNameLength + sizeof(WCHAR));
 
                         return MakeVariantString(pv, td);
                     }
@@ -957,7 +226,7 @@ HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDetailsEx(
             {
                 PCWSTR strValueContents;
 
-                hr = CRegistryPidlHelper::FormatContentsForDisplay(info, m_hRoot, m_NtPath, &strValueContents);
+                hr = FormatContentsForDisplay(info, m_hRoot, m_NtPath, &strValueContents);
                 if (FAILED_UNEXPECTEDLY(hr))
                     return hr;
 
@@ -969,7 +238,7 @@ HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDetailsEx(
 
                 hr = MakeVariantString(pv, strValueContents);
 
-                CoTaskMemFree((PVOID) strValueContents);
+                CoTaskMemFree((PVOID)strValueContents);
 
                 return hr;
 
@@ -991,7 +260,7 @@ HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDetailsOf(
 
     if (pidl)
     {
-        HRESULT hr = CRegistryPidlHelper::GetInfoFromPidl(pidl, &info);
+        HRESULT hr = GetInfoFromPidl(pidl, &info);
         if (FAILED_UNEXPECTEDLY(hr))
             return hr;
 
@@ -1018,7 +287,7 @@ HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDetailsOf(
             {
                 if (info->contentsLength > 0)
                 {
-                    PWSTR td = (PWSTR) (((PBYTE) info) + FIELD_OFFSET(RegPidlEntry, entryName) + info->entryNameLength + sizeof(WCHAR));
+                    PWSTR td = (PWSTR)(((PBYTE)info) + FIELD_OFFSET(RegPidlEntry, entryName) + info->entryNameLength + sizeof(WCHAR));
 
                     return MakeStrRetFromString(td, info->contentsLength, &(psd->str));
                 }
@@ -1033,7 +302,7 @@ HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDetailsOf(
 
             PCWSTR strValueContents;
 
-            hr = CRegistryPidlHelper::FormatContentsForDisplay(info, m_hRoot, m_NtPath, &strValueContents);
+            hr = FormatContentsForDisplay(info, m_hRoot, m_NtPath, &strValueContents);
             if (FAILED_UNEXPECTEDLY(hr))
                 return hr;
 
@@ -1044,7 +313,7 @@ HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDetailsOf(
 
             hr = MakeStrRetFromString(strValueContents, &(psd->str));
 
-            CoTaskMemFree((PVOID) strValueContents);
+            CoTaskMemFree((PVOID)strValueContents);
 
             return hr;
         }
@@ -1103,34 +372,238 @@ HRESULT STDMETHODCALLTYPE CRegistryFolder::MapColumnToSCID(
     return E_INVALIDARG;
 }
 
-HRESULT STDMETHODCALLTYPE CRegistryFolder::MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
+HRESULT CRegistryFolder::CompareIDs(LPARAM lParam, const RegPidlEntry * first, const RegPidlEntry * second)
 {
-    switch (uMsg)
+    HRESULT hr;
+
+    LPARAM sortMode = lParam & 0xFFFF0000;
+    LPARAM column = lParam & 0x0000FFFF;
+
+    if (sortMode == SHCIDS_ALLFIELDS)
     {
-    case SFVM_DEFVIEWMODE:
+        if (column != 0)
+            return E_INVALIDARG;
+
+        int minsize = min(first->cb, second->cb);
+        hr = MAKE_COMPARE_HRESULT(memcmp(second, first, minsize));
+        if (hr != S_EQUAL)
+            return hr;
+
+        return MAKE_COMPARE_HRESULT(second->cb - first->cb);
+    }
+
+    switch (column)
     {
-        FOLDERVIEWMODE* pViewMode = (FOLDERVIEWMODE*) lParam;
-        *pViewMode = FVM_DETAILS;
+    case REGISTRY_COLUMN_NAME:
+        return CompareName(lParam, first, second);
+
+    case REGISTRY_COLUMN_TYPE:
+        return MAKE_COMPARE_HRESULT(second->contentType - first->contentType);
+
+    case REGISTRY_COLUMN_VALUE:
+        // Can't sort by link target yet
+        return E_INVALIDARG;
+    }
+
+    DbgPrint("Unsupported sorting mode.\n");
+    return E_INVALIDARG;
+}
+
+ULONG CRegistryFolder::ConvertAttributes(const RegPidlEntry * entry, PULONG inMask)
+{
+    ULONG mask = inMask ? *inMask : 0xFFFFFFFF;
+    ULONG flags = 0;
+
+    if ((entry->entryType == REG_ENTRY_KEY) ||
+        (entry->entryType == REG_ENTRY_ROOT))
+        flags |= SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_BROWSABLE;
+
+    return flags & mask;
+}
+
+BOOL CRegistryFolder::IsFolder(LPCITEMIDLIST pcidl)
+{
+    RegPidlEntry * entry = (RegPidlEntry*) &(pcidl->mkid);
+    if ((entry->cb < sizeof(RegPidlEntry)) || (entry->magic != REGISTRY_PIDL_MAGIC))
+        return FALSE;
+
+    return IsFolder(entry);
+}
+
+BOOL CRegistryFolder::IsFolder(const RegPidlEntry * info)
+{
+    return (info->entryType == REG_ENTRY_KEY) ||(info->entryType == REG_ENTRY_ROOT);
+}
+
+HRESULT CRegistryFolder::GetInfoFromPidl(LPCITEMIDLIST pcidl, const RegPidlEntry ** pentry)
+{
+    RegPidlEntry * entry = (RegPidlEntry*) &(pcidl->mkid);
+
+    if (entry->cb < sizeof(RegPidlEntry))
+    {
+        DbgPrint("PCIDL too small %l (required %l)\n", entry->cb, sizeof(RegPidlEntry));
+        return E_INVALIDARG;
+    }
+
+    if (entry->magic != REGISTRY_PIDL_MAGIC)
+    {
+        DbgPrint("PCIDL magic mismatch %04x (expected %04x)\n", entry->magic, REGISTRY_PIDL_MAGIC);
+        return E_INVALIDARG;
+    }
+
+    *pentry = entry;
+    return S_OK;
+}
+
+HRESULT CRegistryFolder::FormatValueData(DWORD contentType, PVOID td, DWORD contentsLength, PCWSTR * strContents)
+{
+    switch (contentType)
+    {
+    case 0:
+    {
+        PCWSTR strTodo = L"";
+        DWORD bufferLength = (wcslen(strTodo) + 1) * sizeof(WCHAR);
+        PWSTR strValue = (PWSTR)CoTaskMemAlloc(bufferLength);
+        StringCbCopyW(strValue, bufferLength, strTodo);
+        *strContents = strValue;
         return S_OK;
     }
-    case SFVM_COLUMNCLICK:
-        return S_FALSE;
-    case SFVM_BACKGROUNDENUM:
+    case REG_SZ:
+    case REG_EXPAND_SZ:
+    {
+        PWSTR strValue = (PWSTR)CoTaskMemAlloc(contentsLength + sizeof(WCHAR));
+        StringCbCopyNW(strValue, contentsLength + sizeof(WCHAR), (LPCWSTR)td, contentsLength);
+        *strContents = strValue;
         return S_OK;
     }
-    return E_NOTIMPL;
+    case REG_MULTI_SZ:
+    {
+        PCWSTR separator = L" "; // To match regedit
+        size_t sepChars = wcslen(separator);
+        int strings = 0;
+        int stringChars = 0;
+
+        PCWSTR strData = (PCWSTR)td;
+        while (*strData)
+        {
+            size_t len = wcslen(strData);
+            stringChars += len;
+            strData += len + 1; // Skips null-terminator
+            strings++;
+        }
+
+        int cch = stringChars + (strings - 1) * sepChars + 1;
+
+        PWSTR strValue = (PWSTR)CoTaskMemAlloc(cch * sizeof(WCHAR));
+
+        strValue[0] = 0;
+
+        strData = (PCWSTR)td;
+        while (*strData)
+        {
+            StrCatW(strValue, strData);
+            strData += wcslen(strData) + 1;
+            if (*strData)
+                StrCatW(strValue, separator);
+        }
+
+        *strContents = strValue;
+        return S_OK;
+    }
+    case REG_DWORD:
+    {
+        DWORD bufferLength = 64 * sizeof(WCHAR);
+        PWSTR strValue = (PWSTR)CoTaskMemAlloc(bufferLength);
+        StringCbPrintfW(strValue, bufferLength, L"0x%08x (%d)",
+            *(DWORD*)td, *(DWORD*)td);
+        *strContents = strValue;
+        return S_OK;
+    }
+    case REG_QWORD:
+    {
+        DWORD bufferLength = 64 * sizeof(WCHAR);
+        PWSTR strValue = (PWSTR)CoTaskMemAlloc(bufferLength);
+        StringCbPrintfW(strValue, bufferLength, L"0x%016llx (%lld)",
+            *(LARGE_INTEGER*)td, ((LARGE_INTEGER*)td)->QuadPart);
+        *strContents = strValue;
+        return S_OK;
+    }
+    case REG_BINARY:
+    {
+        DWORD bufferLength = (contentsLength * 3 + 1) * sizeof(WCHAR);
+        PWSTR strValue = (PWSTR)CoTaskMemAlloc(bufferLength);
+        PWSTR strTemp = strValue;
+        PBYTE data = (PBYTE)td;
+        for (DWORD i = 0; i < contentsLength; i++)
+        {
+            StringCbPrintfW(strTemp, bufferLength, L"%02x ", data[i]);
+            strTemp += 3;
+            bufferLength -= 3;
+        }
+        *strContents = strValue;
+        return S_OK;
+    }
+    default:
+    {
+        PCWSTR strFormat = L"<Unimplemented value type %d>";
+        DWORD bufferLength = (wcslen(strFormat) + 15) * sizeof(WCHAR);
+        PWSTR strValue = (PWSTR)CoTaskMemAlloc(bufferLength);
+        StringCbPrintfW(strValue, bufferLength, strFormat, contentType);
+        *strContents = strValue;
+        return S_OK;
+    }
+    }
 }
 
-HRESULT CRegistryFolder::DefCtxMenuCallback(IShellFolder * /*psf*/, HWND /*hwnd*/, IDataObject * /*pdtobj*/, UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/)
+HRESULT CRegistryFolder::FormatContentsForDisplay(const RegPidlEntry * info, HKEY rootKey, LPCWSTR ntPath, PCWSTR * strContents)
 {
-    switch (uMsg)
+    PVOID td = (((PBYTE)info) + FIELD_OFFSET(RegPidlEntry, entryName) + info->entryNameLength + sizeof(WCHAR));
+
+    if (info->entryType == REG_ENTRY_VALUE_WITH_CONTENT)
+    {
+        if (info->contentsLength > 0)
+        {
+            return FormatValueData(info->contentType, td, info->contentsLength, strContents);
+        }
+    }
+    else if (info->entryType == REG_ENTRY_VALUE)
+    {
+        PVOID valueData;
+        DWORD valueLength;
+        HRESULT hr = ReadRegistryValue(rootKey, ntPath, info->entryName, &valueData, &valueLength);
+        if (FAILED_UNEXPECTEDLY(hr))
+        {
+            PCWSTR strEmpty = L"(Error reading value)";
+            DWORD bufferLength = (wcslen(strEmpty) + 1) * sizeof(WCHAR);
+            PWSTR strValue = (PWSTR)CoTaskMemAlloc(bufferLength);
+            StringCbCopyW(strValue, bufferLength, strEmpty);
+            *strContents = strValue;
+            return S_OK;
+        }
+
+        if (valueLength > 0)
+        {
+            hr = FormatValueData(info->contentType, valueData, valueLength, strContents);
+
+            CoTaskMemFree(valueData);
+
+            return hr;
+        }
+    }
+    else
     {
-    case DFM_MERGECONTEXTMENU:
+        PCWSTR strEmpty = L"";
+        DWORD bufferLength = (wcslen(strEmpty) + 1) * sizeof(WCHAR);
+        PWSTR strValue = (PWSTR)CoTaskMemAlloc(bufferLength);
+        StringCbCopyW(strValue, bufferLength, strEmpty);
+        *strContents = strValue;
         return S_OK;
-    case DFM_INVOKECOMMAND:
-    case DFM_INVOKECOMMANDEX:
-    case DFM_GETDEFSTATICID: // Required for Windows 7 to pick a default
-        return S_FALSE;
     }
-    return E_NOTIMPL;
+
+    PCWSTR strEmpty = L"(Empty)";
+    DWORD bufferLength = (wcslen(strEmpty) + 1) * sizeof(WCHAR);
+    PWSTR strValue = (PWSTR)CoTaskMemAlloc(bufferLength);
+    StringCbCopyW(strValue, bufferLength, strEmpty);
+    *strContents = strValue;
+    return S_OK;
 }
index 55e4327..6d25163 100644 (file)
@@ -9,17 +9,48 @@
 
 extern const GUID CLSID_RegistryFolder;
 
+class CRegistryFolderExtractIcon :
+    public CComObjectRootEx<CComMultiThreadModelNoCS>,
+    public IExtractIconW
+{
+    PCIDLIST_ABSOLUTE m_pcidlFolder;
+    PCITEMID_CHILD    m_pcidlChild;
+
+public:
+    CRegistryFolderExtractIcon();
+
+    virtual ~CRegistryFolderExtractIcon();
+
+    HRESULT Initialize(LPCWSTR ntPath, PCIDLIST_ABSOLUTE parent, UINT cidl, PCUITEMID_CHILD_ARRAY apidl);
+
+    virtual HRESULT STDMETHODCALLTYPE GetIconLocation(
+        UINT uFlags,
+        LPWSTR szIconFile,
+        UINT cchMax,
+        INT *piIndex,
+        UINT *pwFlags);
+
+    virtual HRESULT STDMETHODCALLTYPE Extract(
+        LPCWSTR pszFile,
+        UINT nIconIndex,
+        HICON *phiconLarge,
+        HICON *phiconSmall,
+        UINT nIconSize);
+
+    DECLARE_NOT_AGGREGATABLE(CRegistryFolderExtractIcon)
+    DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+    BEGIN_COM_MAP(CRegistryFolderExtractIcon)
+        COM_INTERFACE_ENTRY_IID(IID_IExtractIconW, IExtractIconW)
+    END_COM_MAP()
+
+};
+
 class CRegistryFolder :
     public CComCoClass<CRegistryFolder, &CLSID_RegistryFolder>,
-    public CComObjectRootEx<CComMultiThreadModelNoCS>,
-    public IShellFolder2,
-    public IPersistFolder2,
-    public IShellFolderViewCB
+    public CCommonFolder<CRegistryFolder, RegPidlEntry, CRegistryFolderExtractIcon>
 {
     HKEY m_hRoot;
-    WCHAR m_NtPath[MAX_PATH];
-
-    LPITEMIDLIST m_shellPidl;
 
 public:
 
@@ -27,77 +58,19 @@ public:
     virtual ~CRegistryFolder();
 
     // IShellFolder
-    virtual HRESULT STDMETHODCALLTYPE ParseDisplayName(
-        HWND hwndOwner,
-        LPBC pbcReserved,
-        LPOLESTR lpszDisplayName,
-        ULONG *pchEaten,
-        LPITEMIDLIST *ppidl,
-        ULONG *pdwAttributes);
-
     virtual HRESULT STDMETHODCALLTYPE EnumObjects(
         HWND hwndOwner,
         SHCONTF grfFlags,
         IEnumIDList **ppenumIDList);
 
-    virtual HRESULT STDMETHODCALLTYPE BindToObject(
-        LPCITEMIDLIST pidl,
+    virtual HRESULT STDMETHODCALLTYPE InternalBindToObject(
+        PWSTR path,
+        const RegPidlEntry * info,
+        LPITEMIDLIST first,
+        LPCITEMIDLIST rest,
+        LPITEMIDLIST fullPidl,
         LPBC pbcReserved,
-        REFIID riid,
-        void **ppvOut);
-
-    virtual HRESULT STDMETHODCALLTYPE BindToStorage(
-        LPCITEMIDLIST pidl,
-        LPBC pbcReserved,
-        REFIID riid,
-        void **ppvObj);
-
-    virtual HRESULT STDMETHODCALLTYPE CompareIDs(
-        LPARAM lParam,
-        LPCITEMIDLIST pidl1,
-        LPCITEMIDLIST pidl2);
-
-    virtual HRESULT STDMETHODCALLTYPE CreateViewObject(
-        HWND hwndOwner,
-        REFIID riid,
-        void **ppvOut);
-
-    virtual HRESULT STDMETHODCALLTYPE GetAttributesOf(
-        UINT cidl,
-        PCUITEMID_CHILD_ARRAY apidl,
-        SFGAOF *rgfInOut);
-
-    virtual HRESULT STDMETHODCALLTYPE GetUIObjectOf(
-        HWND hwndOwner,
-        UINT cidl,
-        PCUITEMID_CHILD_ARRAY apidl,
-        REFIID riid,
-        UINT *prgfInOut,
-        void **ppvOut);
-
-    virtual HRESULT STDMETHODCALLTYPE GetDisplayNameOf(
-        LPCITEMIDLIST pidl,
-        SHGDNF uFlags,
-        STRRET *lpName);
-
-    virtual HRESULT STDMETHODCALLTYPE SetNameOf(
-        HWND hwnd,
-        LPCITEMIDLIST pidl,
-        LPCOLESTR lpszName,
-        SHGDNF uFlags,
-        LPITEMIDLIST *ppidlOut);
-
-    // IShellFolder2
-    virtual HRESULT STDMETHODCALLTYPE GetDefaultSearchGUID(
-        GUID *lpguid);
-
-    virtual HRESULT STDMETHODCALLTYPE EnumSearches(
-        IEnumExtraSearch **ppenum);
-
-    virtual HRESULT STDMETHODCALLTYPE GetDefaultColumn(
-        DWORD dwReserved,
-        ULONG *pSort,
-        ULONG *pDisplay);
+        IShellFolder** ppsfChild);
 
     virtual HRESULT STDMETHODCALLTYPE GetDefaultColumnState(
         UINT iColumn,
@@ -117,34 +90,21 @@ public:
         UINT iColumn,
         SHCOLUMNID *pscid);
 
-    // IPersist
-    virtual HRESULT STDMETHODCALLTYPE GetClassID(CLSID *lpClassId);
-
     // IPersistFolder
     virtual HRESULT STDMETHODCALLTYPE Initialize(LPCITEMIDLIST pidl);
 
-    // IPersistFolder2
-    virtual HRESULT STDMETHODCALLTYPE GetCurFolder(LPITEMIDLIST * pidl);
-
-    // IShellFolderViewCB
-    virtual HRESULT STDMETHODCALLTYPE MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam);
-
     // Internal
-    HRESULT STDMETHODCALLTYPE Initialize(LPCITEMIDLIST pidl, PCWSTR ntPath, HKEY hRoot);
+    virtual HRESULT STDMETHODCALLTYPE Initialize(LPCITEMIDLIST pidl, PCWSTR ntPath, HKEY hRoot);
 
-    static HRESULT CALLBACK DefCtxMenuCallback(IShellFolder *, HWND, IDataObject *, UINT, WPARAM, LPARAM);
+protected:
+    virtual HRESULT STDMETHODCALLTYPE CompareIDs(LPARAM lParam, const RegPidlEntry * first, const RegPidlEntry * second);
+    virtual ULONG STDMETHODCALLTYPE ConvertAttributes(const RegPidlEntry * entry, PULONG inMask);
+    virtual BOOL STDMETHODCALLTYPE IsFolder(LPCITEMIDLIST pcidl);
+    virtual BOOL STDMETHODCALLTYPE IsFolder(const RegPidlEntry * info);
 
-    DECLARE_REGISTRY_RESOURCEID(IDR_REGISTRYFOLDER)
-    DECLARE_NOT_AGGREGATABLE(CRegistryFolder)
-    DECLARE_PROTECT_FINAL_CONSTRUCT()
+    virtual HRESULT GetInfoFromPidl(LPCITEMIDLIST pcidl, const RegPidlEntry ** pentry);
 
-    BEGIN_COM_MAP(CRegistryFolder)
-        COM_INTERFACE_ENTRY_IID(IID_IShellFolder, IShellFolder)
-        COM_INTERFACE_ENTRY_IID(IID_IShellFolder2, IShellFolder2)
-        COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist)
-        COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder)
-        COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2)
-        COM_INTERFACE_ENTRY_IID(IID_IShellFolderViewCB, IShellFolderViewCB)
-    END_COM_MAP()
+    HRESULT FormatValueData(DWORD contentType, PVOID td, DWORD contentsLength, PCWSTR * strContents);
 
-};
\ No newline at end of file
+    HRESULT FormatContentsForDisplay(const RegPidlEntry * info, HKEY rootKey, LPCWSTR ntPath, PCWSTR * strContents);
+};