[FREELDR] Merge boot-drive and partition functionalities together (#6760)
[reactos.git] / dll / shellext / ntobjshex / ntobjfolder.cpp
index 48f2435..32c0316 100644 (file)
@@ -1,28 +1,13 @@
 /*
- * 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>
+ * PROJECT:     NT Object Namespace shell extension
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     NT Object Namespace folder class implementation
+ * COPYRIGHT:   Copyright 2015-2017 David Quintana <gigaherz@gmail.com>
  */
 
 #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);
+#include <wine/unicode.h>
 
 // {845B0FB2-66E0-416B-8F91-314E23F7C12D}
 const GUID CLSID_NtObjectFolder = { 0x845b0fb2, 0x66e0, 0x416b, { 0x8f, 0x91, 0x31, 0x4e, 0x23, 0xf7, 0xc1, 0x2d } };
@@ -38,340 +23,99 @@ enum NtObjectColumns
     NTOBJECT_COLUMN_END
 };
 
-class CNtObjectFolderExtractIcon :
-    public CComObjectRootEx<CComMultiThreadModelNoCS>,
-    public IExtractIconW
+CNtObjectFolderExtractIcon::CNtObjectFolderExtractIcon() :
+    m_NtPath(NULL),
+    m_pcidlChild(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);
-    }
+CNtObjectFolderExtractIcon::~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;
-    }
+HRESULT CNtObjectFolderExtractIcon::Initialize(LPCWSTR ntPath, PCIDLIST_ABSOLUTE parent, 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;
+HRESULT STDMETHODCALLTYPE CNtObjectFolderExtractIcon::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;
+    if ((entry->cb < sizeof(NtPidlEntry)) || (entry->magic != NT_OBJECT_PIDL_MAGIC))
+        return E_INVALIDARG;
 
-        UINT flags = 0;
+    UINT flags = 0;
 
-        switch (entry->objectType)
-        {
+    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
+HRESULT STDMETHODCALLTYPE CNtObjectFolderExtractIcon::Extract(
+    LPCWSTR pszFile,
+    UINT nIconIndex,
+    HICON *phiconLarge,
+    HICON *phiconSmall,
+    UINT nIconSize)
 {
-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;
-            }
-            }
-        }
-
-        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;
-
-        return flags & mask;
-    }
-
-    static BOOL IsFolder(LPCITEMIDLIST pcidl)
-    {
-        NtPidlEntry * entry = (NtPidlEntry*) &(pcidl->mkid);
-        if ((entry->cb < sizeof(NtPidlEntry)) || (entry->magic != NT_OBJECT_PIDL_MAGIC))
-            return FALSE;
-
-        return (entry->objectType == DIRECTORY_OBJECT) ||
-            (entry->objectType == SYMBOLICLINK_OBJECT) ||
-            (entry->objectType == KEY_OBJECT);
-    }
-
-    static HRESULT GetInfoFromPidl(LPCITEMIDLIST pcidl, const NtPidlEntry ** pentry)
-    {
-        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;
-        return S_OK;
-    }
-};
+    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;
-
-    while (TRUE)
-    {
-        hr = it->Next(1, ppidl, NULL);
-
-        if (FAILED(hr))
-            return hr;
-
-        if (hr != S_OK)
-            break;
-
-        hr = CNtObjectPidlHelper::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 = CNtObjectPidlHelper::ConvertAttributes(info, pdwAttributes);
-    }
-
-    return S_OK;
-}
 
 HRESULT STDMETHODCALLTYPE CNtObjectFolder::EnumObjects(
     HWND hwndOwner,
@@ -381,418 +125,118 @@ 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;
-
-                hr = psfDesktop->ParseDisplayName(NULL, NULL, path, NULL, &first, NULL);
-                if (FAILED_UNEXPECTEDLY(hr))
-                    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,
-    LPBC pbcReserved,
-    REFIID riid,
-    void **ppvObj)
+HRESULT STDMETHODCALLTYPE CNtObjectFolder::ResolveSymLink(
+    const NtPidlEntry * info,
+    LPITEMIDLIST * fullPidl)
 {
-    UNIMPLEMENTED;
-    return E_NOTIMPL;
-}
+    WCHAR wbLink[MAX_PATH] = { 0 };
+    UNICODE_STRING link;
+    RtlInitEmptyUnicodeString(&link, wbLink, sizeof(wbLink));
 
-HRESULT STDMETHODCALLTYPE CNtObjectFolder::CompareIDs(
-    LPARAM lParam,
-    LPCITEMIDLIST pidl1,
-    LPCITEMIDLIST pidl2)
-{
-    TRACE("CompareIDs\n");
+    *fullPidl = NULL;
 
-    HRESULT hr = CNtObjectPidlHelper::CompareIDs(lParam, pidl1, pidl2);
-    if (hr != S_OK)
+    HRESULT 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);
-
-    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 CNtObjectFolder::CreateViewObject(
-    HWND hwndOwner,
-    REFIID riid,
-    void **ppvOut)
-{
-    if (!IsEqualIID(riid, IID_IShellView))
-        return E_NOINTERFACE;
+    WCHAR path[MAX_PATH];
 
-    SFV_CREATE sfv;
-    sfv.cbSize = sizeof(sfv);
-    sfv.pshf = this;
-    sfv.psvOuter = NULL;
-    sfv.psfvcb = this;
+    if (link.Length == 0)
+        return E_UNEXPECTED;
 
-    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++)
+    if (link.Buffer[1] == L':' && isalphaW(link.Buffer[0]))
     {
-        PCUITEMID_CHILD pidl = apidl[i];
+        StringCbCopyNW(path, sizeof(path), link.Buffer, link.Length);
 
-        HRESULT hr = CNtObjectPidlHelper::GetInfoFromPidl(pidl, &info);
+        CComPtr<IShellFolder> psfDesktop;
+        hr = SHGetDesktopFolder(&psfDesktop);
         if (FAILED_UNEXPECTEDLY(hr))
             return hr;
 
-        // Update attributes.
-        *rgfInOut = CNtObjectPidlHelper::ConvertAttributes(info, rgfInOut);
+        return psfDesktop->ParseDisplayName(NULL, NULL, path, NULL, fullPidl, NULL);
     }
 
-    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];
+    StringCbCopyW(path, sizeof(path), L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{845B0FB2-66E0-416B-8F91-314E23F7C12D}");
+    PathAppend(path, link.Buffer);
 
-        int nkeys = _countof(keys);
-        if (cidl == 1 && CNtObjectPidlHelper::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<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));
-            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;
-}
-
-HRESULT STDMETHODCALLTYPE CNtObjectFolder::GetDisplayNameOf(
-    LPCITEMIDLIST pidl,
-    SHGDNF uFlags,
-    STRRET *lpName)
-{
-    const NtPidlEntry * info;
-
-    TRACE("GetDisplayNameOf %p\n", pidl);
-
-    HRESULT hr = CNtObjectPidlHelper::GetInfoFromPidl(pidl, &info);
+    CComPtr<IShellFolder> psfDesktop;
+    hr = SHGetDesktopFolder(&psfDesktop);
     if (FAILED_UNEXPECTEDLY(hr))
         return hr;
 
-    if ((GET_SHGDN_RELATION(uFlags) == SHGDN_NORMAL) &&
-        (GET_SHGDN_FOR(uFlags) & SHGDN_FORPARSING))
-    {
-        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;
+    LPITEMIDLIST pidl;
 
-        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;
+    hr = psfDesktop->ParseDisplayName(NULL, NULL, path, NULL, &pidl, NULL);
+    if (FAILED(hr))
+        return hr;
 
-            PathAppendW(path, temp);
-        }
+    *fullPidl = pidl;
 
-        ILFree((LPITEMIDLIST) pidlFirst);
-    }
-    else
-    {
-        MakeStrRetFromString(info->entryName, info->entryNameLength, lpName);
-    }
+    DumpIdList(pidl);
 
     return S_OK;
 }
 
-HRESULT STDMETHODCALLTYPE CNtObjectFolder::SetNameOf(
-    HWND hwnd,
-    LPCITEMIDLIST pidl,
-    LPCOLESTR lpszName,
-    SHGDNF uFlags,
-    LPITEMIDLIST *ppidlOut)
+HRESULT STDMETHODCALLTYPE CNtObjectFolder::InternalBindToObject(
+    PWSTR path,
+    const NtPidlEntry * info,
+    LPITEMIDLIST first,
+    LPCITEMIDLIST rest,
+    LPITEMIDLIST fullPidl,
+    LPBC pbcReserved,
+    IShellFolder** ppsfChild)
 {
-    UNIMPLEMENTED;
-    return E_NOTIMPL;
-}
 
-// IPersist
-HRESULT STDMETHODCALLTYPE CNtObjectFolder::GetClassID(CLSID *lpClassId)
-{
-    if (!lpClassId)
-        return E_POINTER;
+    if (info->objectType == KEY_OBJECT)
+    {
+        return ShellObjectCreatorInit<CRegistryFolder>(fullPidl, path, (HKEY) NULL, IID_PPV_ARG(IShellFolder, ppsfChild));
+    }
 
-    *lpClassId = CLSID_NtObjectFolder;
-    return S_OK;
+    return ShellObjectCreatorInit<CNtObjectFolder>(fullPidl, path, IID_PPV_ARG(IShellFolder, ppsfChild));
 }
 
 // IPersistFolder
-HRESULT STDMETHODCALLTYPE CNtObjectFolder::Initialize(LPCITEMIDLIST pidl)
+HRESULT STDMETHODCALLTYPE CNtObjectFolder::Initialize(PCIDLIST_ABSOLUTE pidl)
 {
     m_shellPidl = ILClone(pidl);
 
-    StringCbCopy(m_NtPath, _countof(m_NtPath), L"\\");
+    StringCbCopyW(m_NtPath, sizeof(m_NtPath), L"\\");
 
     return S_OK;
 }
 
 // Internal
-HRESULT STDMETHODCALLTYPE CNtObjectFolder::Initialize(LPCITEMIDLIST pidl, PCWSTR ntPath)
+HRESULT STDMETHODCALLTYPE CNtObjectFolder::Initialize(PCIDLIST_ABSOLUTE pidl, PCWSTR ntPath)
 {
     m_shellPidl = ILClone(pidl);
 
-    StringCbCopy(m_NtPath, _countof(m_NtPath), ntPath);
+    StringCbCopyW(m_NtPath, sizeof(m_NtPath), ntPath);
 
     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)
 {
     switch (iColumn)
     {
-    case NTOBJECT_COLUMN_NAME:
-        *pcsFlags = SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT;
-        return S_OK;
-    case NTOBJECT_COLUMN_TYPE:
-        *pcsFlags = SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT;
-        return S_OK;
-    case NTOBJECT_COLUMN_LINKTARGET:
-        *pcsFlags = SHCOLSTATE_TYPE_STR | SHCOLSTATE_SLOW;
-        return S_OK;
+        case NTOBJECT_COLUMN_NAME:
+            *pcsFlags = SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT;
+            return S_OK;
+
+        case NTOBJECT_COLUMN_TYPE:
+            *pcsFlags = SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT;
+            return S_OK;
+
+        case NTOBJECT_COLUMN_LINKTARGET:
+            *pcsFlags = SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT | SHCOLSTATE_SLOW;
+            return S_OK;
     }
 
     return E_INVALIDARG;
@@ -809,7 +253,7 @@ HRESULT STDMETHODCALLTYPE CNtObjectFolder::GetDetailsEx(
 
     if (pidl)
     {
-        HRESULT hr = CNtObjectPidlHelper::GetInfoFromPidl(pidl, &info);
+        HRESULT hr = GetInfoFromPidl(pidl, &info);
         if (FAILED_UNEXPECTEDLY(hr))
             return hr;
 
@@ -876,81 +320,89 @@ HRESULT STDMETHODCALLTYPE CNtObjectFolder::GetDetailsOf(
 
     if (pidl)
     {
-        HRESULT hr = CNtObjectPidlHelper::GetInfoFromPidl(pidl, &info);
+        HRESULT hr = GetInfoFromPidl(pidl, &info);
         if (FAILED_UNEXPECTEDLY(hr))
             return hr;
 
         switch (iColumn)
         {
-        case NTOBJECT_COLUMN_NAME:
-            psd->fmt = LVCFMT_LEFT;
+            case NTOBJECT_COLUMN_NAME:
+            {
+                psd->fmt = LVCFMT_LEFT;
 
-            MakeStrRetFromString(info->entryName, info->entryNameLength, &(psd->str));
-            return S_OK;
-        case NTOBJECT_COLUMN_TYPE:
-            psd->fmt = LVCFMT_LEFT;
+                MakeStrRetFromString(info->entryName, info->entryNameLength, &(psd->str));
+                return S_OK;
+            }
 
-            if (info->objectType < 0)
+            case NTOBJECT_COLUMN_TYPE:
             {
-                NtPidlTypeData * td = (NtPidlTypeData*) (((PBYTE) info) + FIELD_OFFSET(NtPidlEntry, entryName) + info->entryNameLength + sizeof(WCHAR));
+                psd->fmt = LVCFMT_LEFT;
 
-                if (td->typeNameLength > 0)
-                    MakeStrRetFromString(td->typeName, td->typeNameLength, &(psd->str));
+                if (info->objectType < 0)
+                {
+                    NtPidlTypeData * td = (NtPidlTypeData*) (((PBYTE) info) + FIELD_OFFSET(NtPidlEntry, entryName) + info->entryNameLength + sizeof(WCHAR));
+
+                    if (td->typeNameLength > 0)
+                        MakeStrRetFromString(td->typeName, td->typeNameLength, &(psd->str));
+                    else
+                        MakeStrRetFromString(L"Unknown", &(psd->str));
+                }
                 else
-                    MakeStrRetFromString(L"Unknown", &(psd->str));
+                    MakeStrRetFromString(ObjectTypeNames[info->objectType], &(psd->str));
+                return S_OK;
             }
-            else
-                MakeStrRetFromString(ObjectTypeNames[info->objectType], &(psd->str));
-            return S_OK;
-        case NTOBJECT_COLUMN_LINKTARGET:
-        {
-            psd->fmt = LVCFMT_LEFT;
 
-            if (info->objectType == SYMBOLICLINK_OBJECT)
+            case NTOBJECT_COLUMN_LINKTARGET:
             {
-                WCHAR wbLink[MAX_PATH] = { 0 };
-                UNICODE_STRING link;
-                RtlInitEmptyUnicodeString(&link, wbLink, sizeof(wbLink));
-
-                HRESULT hr = GetNTObjectSymbolicLinkTarget(m_NtPath, info->entryName, &link);
+                psd->fmt = LVCFMT_LEFT;
 
-                if (!FAILED_UNEXPECTEDLY(hr) && link.Length > 0)
+                if (info->objectType == SYMBOLICLINK_OBJECT)
                 {
-                    MakeStrRetFromString(link.Buffer, link.Length, &(psd->str));
-                    return S_OK;
+                    WCHAR wbLink[MAX_PATH] = { 0 };
+                    UNICODE_STRING link;
+                    RtlInitEmptyUnicodeString(&link, wbLink, sizeof(wbLink));
+
+                    HRESULT hr = GetNTObjectSymbolicLinkTarget(m_NtPath, info->entryName, &link);
+
+                    if (!FAILED_UNEXPECTEDLY(hr) && link.Length > 0)
+                    {
+                        MakeStrRetFromString(link.Buffer, link.Length, &(psd->str));
+                        return S_OK;
+                    }
                 }
-            }
 
-            MakeStrRetFromString(L"", &(psd->str));
-            return S_OK;
-        }
+                MakeStrRetFromString(L"", &(psd->str));
+                return S_OK;
+            }
         }
     }
     else
     {
         switch (iColumn)
         {
-        case NTOBJECT_COLUMN_NAME:
-            psd->fmt = LVCFMT_LEFT;
-            psd->cxChar = 30;
+            case NTOBJECT_COLUMN_NAME:
+                psd->fmt = LVCFMT_LEFT;
+                psd->cxChar = 30;
 
-            // TODO: Make localizable
-            MakeStrRetFromString(L"Object Name", &(psd->str));
-            return S_OK;
-        case NTOBJECT_COLUMN_TYPE:
-            psd->fmt = LVCFMT_LEFT;
-            psd->cxChar = 20;
+                // TODO: Make localizable
+                MakeStrRetFromString(L"Object Name", &(psd->str));
+                return S_OK;
 
-            // TODO: Make localizable
-            MakeStrRetFromString(L"Object Type", &(psd->str));
-            return S_OK;
-        case NTOBJECT_COLUMN_LINKTARGET:
-            psd->fmt = LVCFMT_LEFT;
-            psd->cxChar = 30;
+            case NTOBJECT_COLUMN_TYPE:
+                psd->fmt = LVCFMT_LEFT;
+                psd->cxChar = 20;
 
-            // TODO: Make localizable
-            MakeStrRetFromString(L"Symlink Target", &(psd->str));
-            return S_OK;
+                // TODO: Make localizable
+                MakeStrRetFromString(L"Object Type", &(psd->str));
+                return S_OK;
+
+            case NTOBJECT_COLUMN_LINKTARGET:
+                psd->fmt = LVCFMT_LEFT;
+                psd->cxChar = 30;
+
+                // TODO: Make localizable
+                MakeStrRetFromString(L"Symlink Target", &(psd->str));
+                return S_OK;
         }
     }
 
@@ -964,50 +416,125 @@ HRESULT STDMETHODCALLTYPE CNtObjectFolder::MapColumnToSCID(
     static const GUID storage = PSGUID_STORAGE;
     switch (iColumn)
     {
-    case NTOBJECT_COLUMN_NAME:
-        pscid->fmtid = storage;
-        pscid->pid = PID_STG_NAME;
-        return S_OK;
-    case NTOBJECT_COLUMN_TYPE:
-        pscid->fmtid = storage;
-        pscid->pid = PID_STG_STORAGETYPE;
-        return S_OK;
-    case NTOBJECT_COLUMN_LINKTARGET:
-        pscid->fmtid = GUID_NtObjectColumns;
-        pscid->pid = NTOBJECT_COLUMN_LINKTARGET;
-        return S_OK;
+        case NTOBJECT_COLUMN_NAME:
+            pscid->fmtid = storage;
+            pscid->pid = PID_STG_NAME;
+            return S_OK;
+
+        case NTOBJECT_COLUMN_TYPE:
+            pscid->fmtid = storage;
+            pscid->pid = PID_STG_STORAGETYPE;
+            return S_OK;
+
+        case NTOBJECT_COLUMN_LINKTARGET:
+            pscid->fmtid = GUID_NtObjectColumns;
+            pscid->pid = NTOBJECT_COLUMN_LINKTARGET;
+            return S_OK;
     }
     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;
+
+    DWORD sortMode = lParam & 0xFFFF0000;
+    DWORD 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:
+        {
+            if (first->objectType != SYMBOLICLINK_OBJECT && second->objectType != SYMBOLICLINK_OBJECT)
+                return CompareName(lParam, first, second);
+
+            if (first->objectType != SYMBOLICLINK_OBJECT || second->objectType != SYMBOLICLINK_OBJECT)
+                return first->objectType != SYMBOLICLINK_OBJECT ? S_GREATERTHAN : S_LESSTHAN;
+
+            WCHAR wbLink1[MAX_PATH] = { 0 }, wbLink2[MAX_PATH] = { 0 };
+            UNICODE_STRING firstLink, secondLink;
+            RtlInitEmptyUnicodeString(&firstLink, wbLink1, sizeof(wbLink1));
+
+            if (FAILED_UNEXPECTEDLY(GetNTObjectSymbolicLinkTarget(m_NtPath, first->entryName, &firstLink)))
+                return E_INVALIDARG;
+
+            RtlInitEmptyUnicodeString(&secondLink, wbLink2, sizeof(wbLink2));
+
+            if (FAILED_UNEXPECTEDLY(GetNTObjectSymbolicLinkTarget(m_NtPath, second->entryName, &secondLink)))
+                return E_INVALIDARG;
+
+            return MAKE_COMPARE_HRESULT(RtlCompareUnicodeString(&firstLink, &secondLink, TRUE));
+        }
     }
-    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(const NtPidlEntry * info)
+{
+    return (info->objectType == DIRECTORY_OBJECT) ||
+        (info->objectType == SYMBOLICLINK_OBJECT) ||
+        (info->objectType == KEY_OBJECT);
+}
+
+HRESULT CNtObjectFolder::GetInfoFromPidl(LPCITEMIDLIST pcidl, const NtPidlEntry ** pentry)
+{
+    if (!pcidl)
+    {
+        DbgPrint("PCIDL is NULL\n");
+        return E_INVALIDARG;
+    }
+
+    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)
     {
-    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 magic mismatch %04x (expected %04x)\n", entry->magic, NT_OBJECT_PIDL_MAGIC);
+        return E_INVALIDARG;
     }
-    return E_NOTIMPL;
+
+    *pentry = entry;
+    return S_OK;
 }