[NTOBJSHEX]
[reactos.git] / reactos / dll / shellext / ntobjshex / regfolder.cpp
index 8001b51..fea0ff7 100644 (file)
 /*
  * PROJECT:     ReactOS shell extensions
  * LICENSE:     GPL - See COPYING in the top level directory
- * FILE:        dll\shellext\ntobjshex\ntobjns.cpp
+ * FILE:        dll/shellext/ntobjshex/regfolder.cpp
  * PURPOSE:     NT Object Namespace shell extension
  * PROGRAMMERS: David Quintana <gigaherz@gmail.com>
  */
 
 #include "precomp.h"
-#include "ntobjutil.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);
-
-// {1C6D6E08-2332-4A7B-A94D-6432DB2B5AE6}
-const GUID CLSID_RegistryFolder = { 0x1c6d6e08, 0x2332, 0x4a7b, { 0xa9, 0x4d, 0x64, 0x32, 0xdb, 0x2b, 0x5a, 0xe6 } };
-
-// {18A4B504-F6D8-4D8A-8661-6296514C2CF0}
-static const GUID GUID_RegistryColumns = { 0x18a4b504, 0xf6d8, 0x4d8a, { 0x86, 0x61, 0x62, 0x96, 0x51, 0x4c, 0x2c, 0xf0 } };
-
-enum RegistryColumns
-{
-    REGISTRY_COLUMN_NAME = 0,
-    REGISTRY_COLUMN_TYPE = 1,
-    REGISTRY_COLUMN_VALUE = 2,
-};
-
-class CRegistryFolderExtractIcon :
-    public CComObjectRootEx<CComMultiThreadModelNoCS>,
-    public IExtractIconW
-{
-    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 CRegistryPidlManager
-{
-private:
-    PWSTR m_ntPath;
-    HKEY m_hRoot;
-
-    HDPA m_hDpa;
-    UINT m_hDpaCount;
-
-    int  DpaDeleteCallback(RegPidlEntry * info)
-    {
-        CoTaskMemFree(info);
-        return 0;
-    }
-
-    static int CALLBACK s_DpaDeleteCallback(void *pItem, void *pData)
-    {
-        CRegistryPidlManager * mf = (CRegistryPidlManager*) pData;
-        RegPidlEntry  * item = (RegPidlEntry*) pItem;
-        return mf->DpaDeleteCallback(item);
-    }
-
-public:
-    CRegistryPidlManager() :
-        m_ntPath(NULL),
-        m_hRoot(NULL),
-        m_hDpa(NULL),
-        m_hDpaCount(0)
-    {
-    }
-
-    ~CRegistryPidlManager()
-    {
-        DPA_DestroyCallback(m_hDpa, s_DpaDeleteCallback, this);
-    }
-
-    HRESULT Initialize(PWSTR ntPath, HKEY hRoot)
-    {
-        m_ntPath = ntPath;
-        m_hRoot = hRoot;
-
-        m_hDpa = DPA_Create(10);
-
-        if (!m_hDpa)
-            return E_OUTOFMEMORY;
-
-        if (wcslen(m_ntPath) == 0 && m_hRoot == NULL)
-        {
-            HRESULT hr = EnumerateRootKeys(m_hDpa, &m_hDpaCount);
-            if (FAILED_UNEXPECTEDLY(hr))
-                return hr;
-        }
-        else
-        {
-            HRESULT hr = EnumerateRegistryKey(m_hDpa, m_ntPath, m_hRoot, &m_hDpaCount);
-            if (FAILED_UNEXPECTEDLY(hr))
-                return hr;
-        }
-
-        return S_OK;
-    }
-
-    HRESULT FindPidlInList(PCUITEMID_CHILD pcidl, RegPidlEntry ** pinfo)
-    {
-        HRESULT hr;
-
-        if (!m_hDpa)
-        {
-            return E_FAIL;
-        }
-
-        RegPidlEntry * info = (RegPidlEntry *) pcidl;
-        if ((info->cb < sizeof(RegPidlEntry)) || (info->magic != REGISTRY_PIDL_MAGIC))
-        {
-            ERR("FindPidlInList: Requested pidl is not of the correct type.\n");
-            return E_INVALIDARG;
-        }
-
-        TRACE("Searching for pidl { cb=%d } in a list of %d items\n", pcidl->mkid.cb, m_hDpaCount);
-
-        for (UINT i = 0; i < m_hDpaCount; i++)
-        {
-            RegPidlEntry * pInfo = (RegPidlEntry *) DPA_GetPtr(m_hDpa, i);
-            ASSERT(pInfo);
-
-            hr = CompareIDs(0, pInfo, pcidl);
-            if (FAILED_UNEXPECTEDLY(hr))
-                return hr;
-
-            if (hr == S_OK)
-            {
-                *pinfo = pInfo;
-                return S_OK;
-            }
-            else
-            {
-                TRACE("Comparison returned %d\n", (int) (short) (hr & 0xFFFF));
-            }
-        }
-
-        ERR("PIDL NOT FOUND: Requested filename: %S\n", info->entryName);
-        return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
-    }
-
-    HRESULT FindByName(LPCWSTR strParsingName, RegPidlEntry ** pinfo)
-    {
-        if (!m_hDpa)
-        {
-            return E_FAIL;
-        }
-
-        TRACE("Searching for '%S' in a list of %d items\n", strParsingName, m_hDpaCount);
-
-        for (int i = 0; i < (int) m_hDpaCount; i++)
-        {
-            RegPidlEntry * pInfo = (RegPidlEntry *) DPA_GetPtr(m_hDpa, i);
-            ASSERT(pInfo);
-
-            int order = CompareStringW(GetThreadLocale(), NORM_IGNORECASE,
-                pInfo->entryName, wcslen(pInfo->entryName),
-                strParsingName, wcslen(strParsingName));
-
-            if (order == CSTR_EQUAL)
-            {
-                *pinfo = pInfo;
-                return S_OK;
-            }
-        }
-
-        TRACE("Pidl not found\n");
-        return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
-    }
-
-    HRESULT GetPidl(UINT index, RegPidlEntry ** pEntry)
-    {
-        *pEntry = NULL;
-
-        RegPidlEntry * entry = (RegPidlEntry *) DPA_GetPtr(m_hDpa, index);
-        if (!entry)
-        {
-            return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
-        }
-
-        *pEntry = entry;
-        return S_OK;
-    }
-
-    HRESULT GetCount(UINT * count)
-    {
-        *count = m_hDpaCount;
-        return S_OK;
-    }
-
-
-    static LPITEMIDLIST CreatePidlFromItem(RegPidlEntry * entry)
-    {
-        LPITEMIDLIST idl = (LPITEMIDLIST) CoTaskMemAlloc(entry->cb + 2);
-        if (!idl)
-            return NULL;
-        memset(idl, 0, entry->cb + 2);
-        memcpy(idl, entry, entry->cb);
-        return idl;
-    }
-
-    HRESULT CompareIDs(LPARAM lParam, RegPidlEntry * first, RegPidlEntry * second)
-    {
-        if (LOWORD(lParam) != 0)
-        {
-            DbgPrint("Unsupported sorting mode.\n");
-            return E_INVALIDARG;
-        }
-
-        if (HIWORD(lParam) == SHCIDS_ALLFIELDS)
-        {
-            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 if (HIWORD(lParam) == SHCIDS_CANONICALONLY)
-        {
-            int minlength = min(first->entryNameLength, second->entryNameLength);
-            int ord = StrCmpNW(first->entryName, second->entryName, minlength);
-
-            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);
-        }
-        else
-        {
-            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);
-
-            int minlength = min(first->entryNameLength, second->entryNameLength);
-            int ord = StrCmpNW(first->entryName, second->entryName, minlength);
-
-            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;
-    }
-
-    HRESULT CompareIDs(LPARAM lParam, 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);
-    }
-
-    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);
-    }
-
-    ULONG ConvertAttributes(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 IsFolder(LPCITEMIDLIST pcidl)
-    {
-        RegPidlEntry * entry;
-        HRESULT hr = FindPidlInList(pcidl, &entry);
-        if (FAILED_UNEXPECTEDLY(hr))
-            return FALSE;
-
-        return (entry->entryType == REG_ENTRY_KEY) ||
-            (entry->entryType == REG_ENTRY_ROOT);
-    }
-
-    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_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 (%d)",
-                *(LARGE_INTEGER*) td, ((LARGE_INTEGER*) td)->QuadPart);
-            *strContents = strValue;
-            return S_OK;
-        }
-        default:
-        {
-            PCWSTR strTodo = L"<TODO: Convert value for display>";
-            DWORD bufferLength = (wcslen(strTodo) + 1) * sizeof(WCHAR);
-            PWSTR strValue = (PWSTR) CoTaskMemAlloc(bufferLength);
-            StringCbCopyW(strValue, bufferLength, strTodo);
-            *strContents = strValue;
-            return S_OK;
-        }
-        }
-    }
-
-    HRESULT FormatContentsForDisplay(RegPidlEntry * info, 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(NULL, m_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;
-        return S_OK;
-    }
-};
-
-class CRegistryFolderEnum :
-    public CComObjectRootEx<CComMultiThreadModelNoCS>,
-    public IEnumIDList
-{
-private:
-    CComPtr<CRegistryFolder> m_Folder;
-
-    HWND m_HwndOwner;
-    SHCONTF m_Flags;
-
-    UINT m_Index;
-    UINT m_Count;
-
-public:
-    CRegistryFolderEnum() :
-        m_HwndOwner(NULL),
-        m_Flags(0),
-        m_Index(0),
-        m_Count(0)
-    {
-    }
-
-    virtual ~CRegistryFolderEnum()
-    {
-    }
-
-    HRESULT Initialize(CRegistryFolder * folder, HWND hwndOwner, SHCONTF flags)
-    {
-        m_Folder = folder;
-
-        m_Folder->GetManager().GetCount(&m_Count);
-
-        m_HwndOwner = hwndOwner;
-        m_Flags = flags;
-
-        return Reset();
-    }
-
-    virtual HRESULT STDMETHODCALLTYPE Next(
-        ULONG celt,
-        LPITEMIDLIST *rgelt,
-        ULONG *pceltFetched)
-    {
-        if (pceltFetched)
-            *pceltFetched = 0;
-
-        if (m_Index >= m_Count)
-            return S_FALSE;
-
-        for (int i = 0; i < (int) celt;)
-        {
-            RegPidlEntry * tinfo;
-            BOOL flagsOk = FALSE;
-
-            do {
-                HRESULT hr = m_Folder->GetManager().GetPidl(m_Index++, &tinfo);
-                if (FAILED_UNEXPECTEDLY(hr))
-                    return hr;
-
-                switch (tinfo->entryType)
-                {
-                case REG_ENTRY_KEY:
-                case REG_ENTRY_ROOT:
-                    flagsOk = (m_Flags & SHCONTF_FOLDERS) != 0;
-                    break;
-                default:
-                    flagsOk = (m_Flags & SHCONTF_NONFOLDERS) != 0;
-                    break;
-                }
-            } while (m_Index < m_Count && !flagsOk);
-
-            if (flagsOk)
-            {
-                if (rgelt)
-                    rgelt[i] = m_Folder->GetManager().CreatePidlFromItem(tinfo);
-                i++;
-            }
-
-            if (m_Index == m_Count)
-            {
-                if (pceltFetched)
-                    *pceltFetched = i;
-                return (i == (int) celt) ? S_OK : S_FALSE;
-            }
-        }
-
-        if (pceltFetched) *pceltFetched = celt;
-        return S_OK;
-    }
-
-    virtual HRESULT STDMETHODCALLTYPE Skip(ULONG celt)
-    {
-        return Next(celt, NULL, NULL);
-    }
-
-    virtual HRESULT STDMETHODCALLTYPE Reset()
-    {
-        m_Index = 0;
-        return S_OK;
-    }
-
-    virtual HRESULT STDMETHODCALLTYPE Clone(IEnumIDList **ppenum)
-    {
-        return ShellObjectCreatorInit<CRegistryFolderEnum>(m_Folder, m_HwndOwner, m_Flags, IID_PPV_ARG(IEnumIDList, ppenum));
-    }
-
-    DECLARE_NOT_AGGREGATABLE(CRegistryFolderEnum)
-    DECLARE_PROTECT_FINAL_CONSTRUCT()
-
-    BEGIN_COM_MAP(CRegistryFolderEnum)
-        COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
-    END_COM_MAP()
-
-};
-
-//-----------------------------------------------------------------------------
-// CRegistryFolder
-
-CRegistryFolder::CRegistryFolder() :
-    m_PidlManager(NULL),
-    m_shellPidl(NULL)
-{
-}
-
-CRegistryFolder::~CRegistryFolder()
-{
-    TRACE("Destroying CRegistryFolder %p\n", this);
-}
-
-// IShellFolder
-HRESULT STDMETHODCALLTYPE CRegistryFolder::ParseDisplayName(
-    HWND hwndOwner,
-    LPBC pbcReserved,
-    LPOLESTR lpszDisplayName,
-    ULONG *pchEaten,
-    LPITEMIDLIST *ppidl,
-    ULONG *pdwAttributes)
-{
-    HRESULT hr;
-    RegPidlEntry * info;
-
-    if (!ppidl)
-        return E_POINTER;
-
-    if (pchEaten)
-        *pchEaten = 0;
-
-    if (pdwAttributes)
-        *pdwAttributes = 0;
-
-    TRACE("CRegistryFolder::ParseDisplayName name=%S (ntPath=%S)\n", lpszDisplayName, m_NtPath);
-
-    hr = m_PidlManager->FindByName(lpszDisplayName, &info);
-    if (FAILED(hr))
-    {
-        return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
-    }
-
-    *ppidl = m_PidlManager->CreatePidlFromItem(info);
-
-    if (pchEaten)
-        *pchEaten = wcslen(info->entryName);
-
-    if (pdwAttributes)
-        *pdwAttributes = m_PidlManager->ConvertAttributes(info, pdwAttributes);
-
-    return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE CRegistryFolder::EnumObjects(
-    HWND hwndOwner,
-    SHCONTF grfFlags,
-    IEnumIDList **ppenumIDList)
-{
-    return ShellObjectCreatorInit<CRegistryFolderEnum>(this, hwndOwner, grfFlags, IID_PPV_ARG(IEnumIDList, ppenumIDList));
-}
-
-HRESULT STDMETHODCALLTYPE CRegistryFolder::BindToObject(
-    LPCITEMIDLIST pidl,
-    LPBC pbcReserved,
-    REFIID riid,
-    void **ppvOut)
-{
-    RegPidlEntry * info;
-    HRESULT hr;
-
-    if (IsEqualIID(riid, IID_IShellFolder))
-    {
-        hr = m_PidlManager->FindPidlInList(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);
+WINE_DEFAULT_DEBUG_CHANNEL(ntobjshex);
 
-            hr = ShellObjectCreatorInit<CRegistryFolder>(fullPidl, path, m_hRoot, IID_PPV_ARG(IShellFolder, &psfChild));
-        }
+// {1C6D6E08-2332-4A7B-A94D-6432DB2B5AE6}
+const GUID CLSID_RegistryFolder = { 0x1c6d6e08, 0x2332, 0x4a7b, { 0xa9, 0x4d, 0x64, 0x32, 0xdb, 0x2b, 0x5a, 0xe6 } };
 
-        ILFree(fullPidl);
-        ILFree(first);
+// {18A4B504-F6D8-4D8A-8661-6296514C2CF0}
+static const GUID GUID_RegistryColumns = { 0x18a4b504, 0xf6d8, 0x4d8a, { 0x86, 0x61, 0x62, 0x96, 0x51, 0x4c, 0x2c, 0xf0 } };
 
-        if (rest->mkid.cb > 0)
-        {
-            return psfChild->BindToObject(rest, pbcReserved, riid, ppvOut);
-        }
+enum RegistryColumns
+{
+    REGISTRY_COLUMN_NAME = 0,
+    REGISTRY_COLUMN_TYPE,
+    REGISTRY_COLUMN_VALUE,
+    REGISTRY_COLUMN_END
+};
 
-        return psfChild->QueryInterface(riid, ppvOut);
-    }
+// -------------------------------
+// CRegistryFolderExtractIcon
+CRegistryFolderExtractIcon::CRegistryFolderExtractIcon() :
+    m_pcidlFolder(NULL),
+    m_pcidlChild(NULL)
+{
 
-    return E_NOTIMPL;
 }
 
-HRESULT STDMETHODCALLTYPE CRegistryFolder::BindToStorage(
-    LPCITEMIDLIST pidl,
-    LPBC pbcReserved,
-    REFIID riid,
-    void **ppvObj)
+CRegistryFolderExtractIcon::~CRegistryFolderExtractIcon()
 {
-    UNIMPLEMENTED;
-    return E_NOTIMPL;
+    if (m_pcidlFolder)
+        ILFree((LPITEMIDLIST)m_pcidlFolder);
+    if (m_pcidlChild)
+        ILFree((LPITEMIDLIST)m_pcidlChild);
 }
 
-HRESULT STDMETHODCALLTYPE CRegistryFolder::CompareIDs(
-    LPARAM lParam,
-    LPCITEMIDLIST pidl1,
-    LPCITEMIDLIST pidl2)
+HRESULT CRegistryFolderExtractIcon::Initialize(LPCWSTR ntPath, PCIDLIST_ABSOLUTE parent, UINT cidl, PCUITEMID_CHILD_ARRAY apidl)
 {
-    TRACE("CompareIDs\n");
-
-    HRESULT hr = m_PidlManager->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);
-    }
-
+    m_pcidlFolder = ILClone(parent);
+    if (cidl != 1)
+        return E_INVALIDARG;
+    m_pcidlChild = ILClone(apidl[0]);
     return S_OK;
 }
 
-HRESULT STDMETHODCALLTYPE CRegistryFolder::CreateViewObject(
-    HWND hwndOwner,
-    REFIID riid,
-    void **ppvOut)
+HRESULT STDMETHODCALLTYPE CRegistryFolderExtractIcon::GetIconLocation(
+    UINT uFlags,
+    LPWSTR szIconFile,
+    UINT cchMax,
+    INT *piIndex,
+    UINT *pwFlags)
 {
-    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);
-}
+    const RegPidlEntry * entry = (RegPidlEntry *)m_pcidlChild;
 
-HRESULT STDMETHODCALLTYPE CRegistryFolder::GetAttributesOf(
-    UINT cidl,
-    PCUITEMID_CHILD_ARRAY apidl,
-    SFGAOF *rgfInOut)
-{
-    RegPidlEntry * info;
-    HRESULT hr;
+    if ((entry->cb < sizeof(RegPidlEntry)) || (entry->magic != REGISTRY_PIDL_MAGIC))
+        return E_INVALIDARG;
 
-    TRACE("GetAttributesOf\n");
+    UINT flags = 0;
 
-    if (cidl == 0)
+    switch (entry->entryType)
     {
-        *rgfInOut &= SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_BROWSABLE;
+    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;
     }
-
-    for (int i = 0; i < (int) cidl; i++)
-    {
-        PCUITEMID_CHILD pidl = apidl[i];
-
-        hr = m_PidlManager->FindPidlInList(pidl, &info);
-        if (FAILED_UNEXPECTEDLY(hr))
-            return hr;
-
-        // Update attributes.
-        *rgfInOut = m_PidlManager->ConvertAttributes(info, rgfInOut);
-    }
-
-    return S_OK;
 }
 
-HRESULT STDMETHODCALLTYPE CRegistryFolder::GetUIObjectOf(
-    HWND hwndOwner,
-    UINT cidl,
-    PCUITEMID_CHILD_ARRAY apidl,
-    REFIID riid,
-    UINT *prgfInOut,
-    void **ppvOut)
+HRESULT STDMETHODCALLTYPE CRegistryFolderExtractIcon::Extract(
+    LPCWSTR pszFile,
+    UINT nIconIndex,
+    HICON *phiconLarge,
+    HICON *phiconSmall,
+    UINT nIconSize)
 {
-    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 && m_PidlManager->IsFolder(apidl[0]))
-        {
-            RegOpenKey(HKEY_CLASSES_ROOT, L"Folder", keys + 0);
-        }
-        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 (cidl == 1 && m_PidlManager->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 SHDefExtractIconW(pszFile, nIconIndex, 0, phiconLarge, phiconSmall, nIconSize);
+}
 
-            return pqa->QueryInterface(riid, ppvOut);
-        }
-    }
+// CRegistryFolder 
 
-    return E_NOTIMPL;
+CRegistryFolder::CRegistryFolder()
+{
 }
 
-HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDisplayNameOf(
-    LPCITEMIDLIST pidl,
-    SHGDNF uFlags,
-    STRRET *lpName)
+CRegistryFolder::~CRegistryFolder()
 {
-    RegPidlEntry * info;
-    HRESULT hr;
-
-    TRACE("GetDisplayNameOf %p\n", pidl);
-
-    hr = m_PidlManager->FindPidlInList(pidl, &info);
-    if (FAILED_UNEXPECTEDLY(hr))
-        return hr;
+}
 
-    if ((GET_SHGDN_RELATION(uFlags) == SHGDN_NORMAL) &&
-        (GET_SHGDN_FOR(uFlags) & SHGDN_FORPARSING))
+// IShellFolder
+HRESULT STDMETHODCALLTYPE CRegistryFolder::EnumObjects(
+    HWND hwndOwner,
+    SHCONTF grfFlags,
+    IEnumIDList **ppenumIDList)
+{
+    if (m_NtPath[0] == 0 && m_hRoot == NULL)
     {
-        WCHAR path[MAX_PATH] = { 0 };
-
-        hr = GetFullName(m_shellPidl, uFlags, path, _countof(path));
-        if (FAILED_UNEXPECTEDLY(hr))
-            return hr;
-
-        PathAppendW(path, info->entryName);
-
-        hr = MakeStrRetFromString(path, lpName);
-        if (FAILED_UNEXPECTEDLY(hr))
-            return hr;
-
-        LPCITEMIDLIST pidlFirst = ILCloneFirst(pidl);
-        LPCITEMIDLIST pidlNext = ILGetNext(pidl);
-
-        if (pidlNext && pidlNext->mkid.cb > 0)
-        {
-            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((LPITEMIDLIST) pidlFirst);
+        return GetEnumRegistryRoot(ppenumIDList);
     }
     else
     {
-        MakeStrRetFromString(info->entryName, info->entryNameLength, lpName);
+        return GetEnumRegistryKey(m_NtPath, m_hRoot, ppenumIDList);
     }
-
-    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)
+HRESULT STDMETHODCALLTYPE CRegistryFolder::InternalBindToObject(
+    PWSTR path,
+    const RegPidlEntry * info,
+    LPITEMIDLIST first,
+    LPCITEMIDLIST rest,
+    LPITEMIDLIST fullPidl,
+    LPBC pbcReserved,
+    IShellFolder** ppsfChild)
 {
-    if (!lpClassId)
-        return E_POINTER;
+    if (wcslen(m_NtPath) == 0 && m_hRoot == NULL)
+    {
+        return ShellObjectCreatorInit<CRegistryFolder>(fullPidl, L"", info->rootKey, IID_PPV_ARG(IShellFolder, ppsfChild));
+    }
 
-    *lpClassId = CLSID_RegistryFolder;
-    return S_OK;
+    return ShellObjectCreatorInit<CRegistryFolder>(fullPidl, path, m_hRoot, IID_PPV_ARG(IShellFolder, ppsfChild));
 }
 
-// IPersistFolder
 HRESULT STDMETHODCALLTYPE CRegistryFolder::Initialize(LPCITEMIDLIST pidl)
 {
     m_shellPidl = ILClone(pidl);
     m_hRoot = NULL;
 
-    PCWSTR ntPath = L"";
-
-    if (!m_PidlManager)
-    {
-        m_PidlManager = new CRegistryPidlManager();
-
-        StringCbCopy(m_NtPath, _countof(m_NtPath), ntPath);
-    }
-
-    return m_PidlManager->Initialize(m_NtPath, m_hRoot);
+    StringCbCopy(m_NtPath, _countof(m_NtPath), L"");
+    return S_OK;
 }
 
-// Internal
 HRESULT STDMETHODCALLTYPE CRegistryFolder::Initialize(LPCITEMIDLIST pidl, PCWSTR ntPath, HKEY hRoot)
 {
     m_shellPidl = ILClone(pidl);
     m_hRoot = hRoot;
 
-    if (!m_PidlManager)
-        m_PidlManager = new CRegistryPidlManager();
-
     StringCbCopy(m_NtPath, _countof(m_NtPath), ntPath);
-    return m_PidlManager->Initialize(m_NtPath, m_hRoot);
-}
-
-// 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;
 }
 
@@ -1059,14 +181,13 @@ HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDetailsEx(
     const SHCOLUMNID *pscid,
     VARIANT *pv)
 {
-    RegPidlEntry * info;
-    HRESULT hr;
+    const RegPidlEntry * info;
 
     TRACE("GetDetailsEx\n");
 
     if (pidl)
     {
-        hr = m_PidlManager->FindPidlInList(pidl, &info);
+        HRESULT hr = GetInfoFromPidl(pidl, &info);
         if (FAILED_UNEXPECTEDLY(hr))
             return hr;
 
@@ -1092,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);
                     }
@@ -1105,7 +226,7 @@ HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDetailsEx(
             {
                 PCWSTR strValueContents;
 
-                hr = m_PidlManager->FormatContentsForDisplay(info, &strValueContents);
+                hr = FormatContentsForDisplay(info, m_hRoot, m_NtPath, &strValueContents);
                 if (FAILED_UNEXPECTEDLY(hr))
                     return hr;
 
@@ -1117,7 +238,7 @@ HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDetailsEx(
 
                 hr = MakeVariantString(pv, strValueContents);
 
-                CoTaskMemFree((PVOID) strValueContents);
+                CoTaskMemFree((PVOID)strValueContents);
 
                 return hr;
 
@@ -1133,14 +254,13 @@ HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDetailsOf(
     UINT iColumn,
     SHELLDETAILS *psd)
 {
-    RegPidlEntry * info;
-    HRESULT hr;
+    const RegPidlEntry * info;
 
     TRACE("GetDetailsOf\n");
 
     if (pidl)
     {
-        hr = m_PidlManager->FindPidlInList(pidl, &info);
+        HRESULT hr = GetInfoFromPidl(pidl, &info);
         if (FAILED_UNEXPECTEDLY(hr))
             return hr;
 
@@ -1167,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));
                 }
@@ -1182,7 +302,7 @@ HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDetailsOf(
 
             PCWSTR strValueContents;
 
-            hr = m_PidlManager->FormatContentsForDisplay(info, &strValueContents);
+            hr = FormatContentsForDisplay(info, m_hRoot, m_NtPath, &strValueContents);
             if (FAILED_UNEXPECTEDLY(hr))
                 return hr;
 
@@ -1193,7 +313,7 @@ HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDetailsOf(
 
             hr = MakeStrRetFromString(strValueContents, &(psd->str));
 
-            CoTaskMemFree((PVOID) strValueContents);
+            CoTaskMemFree((PVOID)strValueContents);
 
             return hr;
         }
@@ -1252,30 +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)
+{
+    HRESULT hr;
+
+    LPARAM sortMode = lParam & 0xFFFF0000;
+    LPARAM column = lParam & 0x0000FFFF;
+
+    if (sortMode == SHCIDS_ALLFIELDS)
+    {
+        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)
+    {
+    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 (uMsg)
+    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:
     {
-    case SFVM_DEFVIEWMODE:
+        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:
     {
-        FOLDERVIEWMODE* pViewMode = (FOLDERVIEWMODE*) lParam;
-        *pViewMode = FVM_DETAILS;
+        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;
     }
     }
-    return E_NOTIMPL;
 }
 
-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;
 }