/*
- * 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 } };
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,
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;
if (pidl)
{
- HRESULT hr = CNtObjectPidlHelper::GetInfoFromPidl(pidl, &info);
+ HRESULT hr = GetInfoFromPidl(pidl, &info);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
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;
}
}
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;
}