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