2 * PROJECT: ReactOS shell extensions
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll\shellext\ntobjshex\ntobjns.cpp
5 * PURPOSE: NT Object Namespace shell extension
6 * PROGRAMMERS: David Quintana <gigaherz@gmail.com>
10 #include "ntobjutil.h"
14 #define DFM_MERGECONTEXTMENU 1 // uFlags LPQCMINFO
15 #define DFM_INVOKECOMMAND 2 // idCmd pszArgs
16 #define DFM_INVOKECOMMANDEX 12 // idCmd PDFMICS
17 #define DFM_GETDEFSTATICID 14 // idCmd * 0
19 #define SHCIDS_ALLFIELDS 0x80000000L
20 #define SHCIDS_CANONICALONLY 0x10000000L
22 #define GET_SHGDN_FOR(dwFlags) ((DWORD)dwFlags & (DWORD)0x0000FF00)
23 #define GET_SHGDN_RELATION(dwFlags) ((DWORD)dwFlags & (DWORD)0x000000FF)
25 WINE_DEFAULT_DEBUG_CHANNEL(ntobjshex
);
27 // {1C6D6E08-2332-4A7B-A94D-6432DB2B5AE6}
28 const GUID CLSID_RegistryFolder
= { 0x1c6d6e08, 0x2332, 0x4a7b, { 0xa9, 0x4d, 0x64, 0x32, 0xdb, 0x2b, 0x5a, 0xe6 } };
30 // {18A4B504-F6D8-4D8A-8661-6296514C2CF0}
31 static const GUID GUID_RegistryColumns
= { 0x18a4b504, 0xf6d8, 0x4d8a, { 0x86, 0x61, 0x62, 0x96, 0x51, 0x4c, 0x2c, 0xf0 } };
35 REGISTRY_COLUMN_NAME
= 0,
37 REGISTRY_COLUMN_VALUE
,
41 class CRegistryFolderExtractIcon
:
42 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
45 PCIDLIST_ABSOLUTE m_pcidlFolder
;
46 PCITEMID_CHILD m_pcidlChild
;
49 CRegistryFolderExtractIcon() :
56 virtual ~CRegistryFolderExtractIcon()
59 ILFree((LPITEMIDLIST
) m_pcidlFolder
);
61 ILFree((LPITEMIDLIST
) m_pcidlChild
);
64 HRESULT
Initialize(PCIDLIST_ABSOLUTE parent
, UINT cidl
, PCUITEMID_CHILD_ARRAY apidl
)
66 m_pcidlFolder
= ILClone(parent
);
69 m_pcidlChild
= ILClone(apidl
[0]);
73 virtual HRESULT STDMETHODCALLTYPE
GetIconLocation(
80 const RegPidlEntry
* entry
= (RegPidlEntry
*) m_pcidlChild
;
82 if ((entry
->cb
< sizeof(RegPidlEntry
)) || (entry
->magic
!= REGISTRY_PIDL_MAGIC
))
87 switch (entry
->entryType
)
91 GetModuleFileNameW(g_hInstance
, szIconFile
, cchMax
);
92 *piIndex
= -IDI_REGISTRYKEY
;
96 GetModuleFileNameW(g_hInstance
, szIconFile
, cchMax
);
97 *piIndex
= -IDI_REGISTRYVALUE
;
101 GetModuleFileNameW(g_hInstance
, szIconFile
, cchMax
);
102 *piIndex
= -IDI_NTOBJECTITEM
;
108 virtual HRESULT STDMETHODCALLTYPE
Extract(
115 return SHDefExtractIconW(pszFile
, nIconIndex
, 0, phiconLarge
, phiconSmall
, nIconSize
);
118 DECLARE_NOT_AGGREGATABLE(CRegistryFolderExtractIcon
)
119 DECLARE_PROTECT_FINAL_CONSTRUCT()
121 BEGIN_COM_MAP(CRegistryFolderExtractIcon
)
122 COM_INTERFACE_ENTRY_IID(IID_IExtractIconW
, IExtractIconW
)
127 class CRegistryPidlManager
136 int DpaDeleteCallback(RegPidlEntry
* info
)
142 static int CALLBACK
s_DpaDeleteCallback(void *pItem
, void *pData
)
144 CRegistryPidlManager
* mf
= (CRegistryPidlManager
*) pData
;
145 RegPidlEntry
* item
= (RegPidlEntry
*) pItem
;
146 return mf
->DpaDeleteCallback(item
);
150 CRegistryPidlManager() :
158 ~CRegistryPidlManager()
160 DPA_DestroyCallback(m_hDpa
, s_DpaDeleteCallback
, this);
163 HRESULT
Initialize(PWSTR ntPath
, HKEY hRoot
)
177 m_hDpa
= DPA_Create(10);
180 return E_OUTOFMEMORY
;
182 if (wcslen(m_ntPath
) == 0 && m_hRoot
== NULL
)
184 HRESULT hr
= EnumerateRootKeys(m_hDpa
, &m_hDpaCount
);
185 if (FAILED_UNEXPECTEDLY(hr
))
190 HRESULT hr
= EnumerateRegistryKey(m_hDpa
, m_ntPath
, m_hRoot
, &m_hDpaCount
);
191 if (FAILED_UNEXPECTEDLY(hr
))
197 HRESULT
FindPidlInList(PCUITEMID_CHILD pcidl
, const RegPidlEntry
** pinfo
)
204 if (FAILED_UNEXPECTEDLY(hr
))
211 RegPidlEntry
* info
= (RegPidlEntry
*) pcidl
;
212 if ((info
->cb
< sizeof(RegPidlEntry
)) || (info
->magic
!= REGISTRY_PIDL_MAGIC
))
214 ERR("FindPidlInList: Requested pidl is not of the correct type.\n");
218 TRACE("Searching for pidl { cb=%d } in a list of %d items\n", pcidl
->mkid
.cb
, m_hDpaCount
);
220 for (UINT i
= 0; i
< m_hDpaCount
; i
++)
222 RegPidlEntry
* pInfo
= (RegPidlEntry
*) DPA_GetPtr(m_hDpa
, i
);
225 hr
= CompareIDs(0, pInfo
, pcidl
);
226 if (FAILED_UNEXPECTEDLY(hr
))
236 TRACE("Comparison returned %d\n", (int) (short) (hr
& 0xFFFF));
240 ERR("PIDL NOT FOUND: Requested filename: %S\n", info
->entryName
);
241 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
244 HRESULT
FindByName(LPCWSTR strParsingName
, RegPidlEntry
** pinfo
)
251 if (FAILED_UNEXPECTEDLY(hr
))
259 TRACE("Searching for '%S' in a list of %d items\n", strParsingName
, m_hDpaCount
);
261 for (int i
= 0; i
< (int) m_hDpaCount
; i
++)
263 RegPidlEntry
* pInfo
= (RegPidlEntry
*) DPA_GetPtr(m_hDpa
, i
);
266 int order
= CompareStringW(GetThreadLocale(), NORM_IGNORECASE
,
267 pInfo
->entryName
, wcslen(pInfo
->entryName
),
268 strParsingName
, wcslen(strParsingName
));
270 if (order
== CSTR_EQUAL
)
277 TRACE("Pidl not found\n");
278 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
281 HRESULT
GetPidl(UINT index
, RegPidlEntry
** pEntry
)
288 if (FAILED_UNEXPECTEDLY(hr
))
297 RegPidlEntry
* entry
= (RegPidlEntry
*) DPA_GetPtr(m_hDpa
, index
);
300 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
307 HRESULT
GetCount(UINT
* count
)
314 if (FAILED_UNEXPECTEDLY(hr
))
321 *count
= m_hDpaCount
;
326 static LPITEMIDLIST
CreatePidlFromItem(const RegPidlEntry
* entry
)
328 LPITEMIDLIST idl
= (LPITEMIDLIST
) CoTaskMemAlloc(entry
->cb
+ 2);
331 memset(idl
, 0, entry
->cb
+ 2);
332 memcpy(idl
, entry
, entry
->cb
);
336 static HRESULT
CompareIDs(LPARAM lParam
, const RegPidlEntry
* first
, const RegPidlEntry
* second
)
338 if ((lParam
& 0xFFFF0000) == SHCIDS_ALLFIELDS
)
343 int minsize
= min(first
->cb
, second
->cb
);
344 int ord
= memcmp(second
, first
, minsize
);
347 return MAKE_HRESULT(0, 0, (USHORT
) ord
);
349 if (second
->cb
> first
->cb
)
350 return MAKE_HRESULT(0, 0, (USHORT
) 1);
351 if (second
->cb
< first
->cb
)
352 return MAKE_HRESULT(0, 0, (USHORT
) -1);
356 bool canonical
= ((lParam
& 0xFFFF0000) == SHCIDS_CANONICALONLY
);
358 switch (lParam
& 0xFFFF)
360 case REGISTRY_COLUMN_NAME
:
362 bool f1
= (first
->entryType
== REG_ENTRY_KEY
) || (first
->entryType
== REG_ENTRY_ROOT
);
363 bool f2
= (second
->entryType
== REG_ENTRY_KEY
) || (second
->entryType
== REG_ENTRY_ROOT
);
366 return MAKE_HRESULT(0, 0, (USHORT
) -1);
368 return MAKE_HRESULT(0, 0, (USHORT
) 1);
372 // Shortcut: avoid comparing contents if not necessary when the results are not for display.
373 if (second
->entryNameLength
> first
->entryNameLength
)
374 return MAKE_HRESULT(0, 0, (USHORT
) 1);
375 if (second
->entryNameLength
< first
->entryNameLength
)
376 return MAKE_HRESULT(0, 0, (USHORT
) -1);
379 int minlength
= min(first
->entryNameLength
, second
->entryNameLength
);
380 int ord
= StrCmpNW(first
->entryName
, second
->entryName
, minlength
);
383 return MAKE_HRESULT(0, 0, (USHORT
) ord
);
387 if (second
->entryNameLength
> first
->entryNameLength
)
388 return MAKE_HRESULT(0, 0, (USHORT
) 1);
389 if (second
->entryNameLength
< first
->entryNameLength
)
390 return MAKE_HRESULT(0, 0, (USHORT
) -1);
395 case REGISTRY_COLUMN_TYPE
:
397 int ord
= second
->contentType
- first
->contentType
;
399 return MAKE_HRESULT(0, 0, (USHORT
) 1);
401 return MAKE_HRESULT(0, 0, (USHORT
) -1);
405 case REGISTRY_COLUMN_VALUE
:
407 // Can't sort by value
412 DbgPrint("Unsupported sorting mode.\n");
421 static HRESULT
CompareIDs(LPARAM lParam
, const RegPidlEntry
* first
, LPCITEMIDLIST pcidl
)
423 LPCITEMIDLIST p
= pcidl
;
424 RegPidlEntry
* second
= (RegPidlEntry
*) &(p
->mkid
);
425 if ((second
->cb
< sizeof(RegPidlEntry
)) || (second
->magic
!= REGISTRY_PIDL_MAGIC
))
428 return CompareIDs(lParam
, first
, second
);
431 static HRESULT
CompareIDs(LPARAM lParam
, LPCITEMIDLIST pcidl1
, LPCITEMIDLIST pcidl2
)
433 LPCITEMIDLIST p
= pcidl1
;
434 RegPidlEntry
* first
= (RegPidlEntry
*) &(p
->mkid
);
435 if ((first
->cb
< sizeof(RegPidlEntry
)) || (first
->magic
!= REGISTRY_PIDL_MAGIC
))
438 return CompareIDs(lParam
, first
, pcidl2
);
441 static ULONG
ConvertAttributes(const RegPidlEntry
* entry
, PULONG inMask
)
443 ULONG mask
= inMask
? *inMask
: 0xFFFFFFFF;
446 if ((entry
->entryType
== REG_ENTRY_KEY
) ||
447 (entry
->entryType
== REG_ENTRY_ROOT
))
448 flags
|= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
| SFGAO_BROWSABLE
;
453 BOOL
IsFolder(LPCITEMIDLIST pcidl
)
455 const RegPidlEntry
* entry
;
456 HRESULT hr
= FindPidlInList(pcidl
, &entry
);
457 if (FAILED_UNEXPECTEDLY(hr
))
460 return (entry
->entryType
== REG_ENTRY_KEY
) ||
461 (entry
->entryType
== REG_ENTRY_ROOT
);
464 static HRESULT
FormatValueData(DWORD contentType
, PVOID td
, DWORD contentsLength
, PCWSTR
* strContents
)
470 PCWSTR strTodo
= L
"";
471 DWORD bufferLength
= (wcslen(strTodo
) + 1) * sizeof(WCHAR
);
472 PWSTR strValue
= (PWSTR
) CoTaskMemAlloc(bufferLength
);
473 StringCbCopyW(strValue
, bufferLength
, strTodo
);
474 *strContents
= strValue
;
480 PWSTR strValue
= (PWSTR
) CoTaskMemAlloc(contentsLength
+ sizeof(WCHAR
));
481 StringCbCopyNW(strValue
, contentsLength
+ sizeof(WCHAR
), (LPCWSTR
) td
, contentsLength
);
482 *strContents
= strValue
;
487 DWORD bufferLength
= 64 * sizeof(WCHAR
);
488 PWSTR strValue
= (PWSTR
) CoTaskMemAlloc(bufferLength
);
489 StringCbPrintfW(strValue
, bufferLength
, L
"0x%08x (%d)",
490 *(DWORD
*) td
, *(DWORD
*) td
);
491 *strContents
= strValue
;
496 DWORD bufferLength
= 64 * sizeof(WCHAR
);
497 PWSTR strValue
= (PWSTR
) CoTaskMemAlloc(bufferLength
);
498 StringCbPrintfW(strValue
, bufferLength
, L
"0x%016llx (%d)",
499 *(LARGE_INTEGER
*) td
, ((LARGE_INTEGER
*) td
)->QuadPart
);
500 *strContents
= strValue
;
505 PCWSTR strTodo
= L
"<TODO: Convert value for display>";
506 DWORD bufferLength
= (wcslen(strTodo
) + 1) * sizeof(WCHAR
);
507 PWSTR strValue
= (PWSTR
) CoTaskMemAlloc(bufferLength
);
508 StringCbCopyW(strValue
, bufferLength
, strTodo
);
509 *strContents
= strValue
;
515 HRESULT
FormatContentsForDisplay(const RegPidlEntry
* info
, PCWSTR
* strContents
)
517 PVOID td
= (((PBYTE
) info
) + FIELD_OFFSET(RegPidlEntry
, entryName
) + info
->entryNameLength
+ sizeof(WCHAR
));
519 if (info
->entryType
== REG_ENTRY_VALUE_WITH_CONTENT
)
521 if (info
->contentsLength
> 0)
523 return FormatValueData(info
->contentType
, td
, info
->contentsLength
, strContents
);
526 else if (info
->entryType
== REG_ENTRY_VALUE
)
530 HRESULT hr
= ReadRegistryValue(NULL
, m_ntPath
, info
->entryName
, &valueData
, &valueLength
);
531 if (FAILED_UNEXPECTEDLY(hr
))
533 PCWSTR strEmpty
= L
"(Error reading value)";
534 DWORD bufferLength
= (wcslen(strEmpty
) + 1) * sizeof(WCHAR
);
535 PWSTR strValue
= (PWSTR
) CoTaskMemAlloc(bufferLength
);
536 StringCbCopyW(strValue
, bufferLength
, strEmpty
);
537 *strContents
= strValue
;
543 hr
= FormatValueData(info
->contentType
, valueData
, valueLength
, strContents
);
545 CoTaskMemFree(valueData
);
552 PCWSTR strEmpty
= L
"";
553 DWORD bufferLength
= (wcslen(strEmpty
) + 1) * sizeof(WCHAR
);
554 PWSTR strValue
= (PWSTR
) CoTaskMemAlloc(bufferLength
);
555 StringCbCopyW(strValue
, bufferLength
, strEmpty
);
556 *strContents
= strValue
;
560 PCWSTR strEmpty
= L
"(Empty)";
561 DWORD bufferLength
= (wcslen(strEmpty
) + 1) * sizeof(WCHAR
);
562 PWSTR strValue
= (PWSTR
) CoTaskMemAlloc(bufferLength
);
563 StringCbCopyW(strValue
, bufferLength
, strEmpty
);
564 *strContents
= strValue
;
569 class CRegistryFolderEnum
:
570 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
574 CComPtr
<CRegistryFolder
> m_Folder
;
583 CRegistryFolderEnum() :
591 virtual ~CRegistryFolderEnum()
595 HRESULT
Initialize(CRegistryFolder
* folder
, HWND hwndOwner
, SHCONTF flags
)
599 m_Folder
->GetManager().GetCount(&m_Count
);
601 m_HwndOwner
= hwndOwner
;
607 virtual HRESULT STDMETHODCALLTYPE
Next(
615 if (m_Index
>= m_Count
)
618 for (int i
= 0; i
< (int) celt
;)
620 RegPidlEntry
* tinfo
;
621 BOOL flagsOk
= FALSE
;
624 HRESULT hr
= m_Folder
->GetManager().GetPidl(m_Index
++, &tinfo
);
625 if (FAILED_UNEXPECTEDLY(hr
))
628 switch (tinfo
->entryType
)
632 flagsOk
= (m_Flags
& SHCONTF_FOLDERS
) != 0;
635 flagsOk
= (m_Flags
& SHCONTF_NONFOLDERS
) != 0;
638 } while (m_Index
< m_Count
&& !flagsOk
);
643 rgelt
[i
] = m_Folder
->GetManager().CreatePidlFromItem(tinfo
);
647 if (m_Index
== m_Count
)
651 return (i
== (int) celt
) ? S_OK
: S_FALSE
;
655 if (pceltFetched
) *pceltFetched
= celt
;
659 virtual HRESULT STDMETHODCALLTYPE
Skip(ULONG celt
)
661 return Next(celt
, NULL
, NULL
);
664 virtual HRESULT STDMETHODCALLTYPE
Reset()
670 virtual HRESULT STDMETHODCALLTYPE
Clone(IEnumIDList
**ppenum
)
672 return ShellObjectCreatorInit
<CRegistryFolderEnum
>(m_Folder
, m_HwndOwner
, m_Flags
, IID_PPV_ARG(IEnumIDList
, ppenum
));
675 DECLARE_NOT_AGGREGATABLE(CRegistryFolderEnum
)
676 DECLARE_PROTECT_FINAL_CONSTRUCT()
678 BEGIN_COM_MAP(CRegistryFolderEnum
)
679 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList
, IEnumIDList
)
684 //-----------------------------------------------------------------------------
687 CRegistryFolder::CRegistryFolder() :
693 CRegistryFolder::~CRegistryFolder()
698 delete m_PidlManager
;
702 HRESULT STDMETHODCALLTYPE
CRegistryFolder::ParseDisplayName(
705 LPOLESTR lpszDisplayName
,
708 ULONG
*pdwAttributes
)
722 TRACE("CRegistryFolder::ParseDisplayName name=%S (ntPath=%S)\n", lpszDisplayName
, m_NtPath
);
724 hr
= m_PidlManager
->FindByName(lpszDisplayName
, &info
);
727 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
730 *ppidl
= m_PidlManager
->CreatePidlFromItem(info
);
733 *pchEaten
= wcslen(info
->entryName
);
736 *pdwAttributes
= m_PidlManager
->ConvertAttributes(info
, pdwAttributes
);
741 HRESULT STDMETHODCALLTYPE
CRegistryFolder::EnumObjects(
744 IEnumIDList
**ppenumIDList
)
746 return ShellObjectCreatorInit
<CRegistryFolderEnum
>(this, hwndOwner
, grfFlags
, IID_PPV_ARG(IEnumIDList
, ppenumIDList
));
749 HRESULT STDMETHODCALLTYPE
CRegistryFolder::BindToObject(
755 const RegPidlEntry
* info
;
758 if (IsEqualIID(riid
, IID_IShellFolder
))
760 hr
= m_PidlManager
->FindPidlInList(pidl
, &info
);
761 if (FAILED_UNEXPECTEDLY(hr
))
764 LPITEMIDLIST first
= ILCloneFirst(pidl
);
765 LPCITEMIDLIST rest
= ILGetNext(pidl
);
767 LPITEMIDLIST fullPidl
= ILCombine(m_shellPidl
, first
);
769 CComPtr
<IShellFolder
> psfChild
;
770 if (wcslen(m_NtPath
) == 0 && m_hRoot
== NULL
)
772 hr
= ShellObjectCreatorInit
<CRegistryFolder
>(fullPidl
, L
"", info
->rootKey
, IID_PPV_ARG(IShellFolder
, &psfChild
));
776 WCHAR path
[MAX_PATH
];
778 StringCbCopyW(path
, _countof(path
), m_NtPath
);
780 PathAppendW(path
, info
->entryName
);
782 hr
= ShellObjectCreatorInit
<CRegistryFolder
>(fullPidl
, path
, m_hRoot
, IID_PPV_ARG(IShellFolder
, &psfChild
));
788 if (rest
->mkid
.cb
> 0)
790 return psfChild
->BindToObject(rest
, pbcReserved
, riid
, ppvOut
);
793 return psfChild
->QueryInterface(riid
, ppvOut
);
799 HRESULT STDMETHODCALLTYPE
CRegistryFolder::BindToStorage(
809 HRESULT STDMETHODCALLTYPE
CRegistryFolder::CompareIDs(
814 TRACE("CompareIDs\n");
816 HRESULT hr
= m_PidlManager
->CompareIDs(lParam
, pidl1
, pidl2
);
820 LPCITEMIDLIST rest1
= ILGetNext(pidl1
);
821 LPCITEMIDLIST rest2
= ILGetNext(pidl2
);
823 bool hasNext1
= (rest1
->mkid
.cb
> 0);
824 bool hasNext2
= (rest2
->mkid
.cb
> 0);
826 if (hasNext1
|| hasNext2
)
828 if (hasNext1
&& !hasNext2
)
829 return MAKE_HRESULT(0, 0, (USHORT
) -1);
831 if (hasNext2
&& !hasNext1
)
832 return MAKE_HRESULT(0, 0, (USHORT
) 1);
834 LPCITEMIDLIST first1
= ILCloneFirst(pidl1
);
836 CComPtr
<IShellFolder
> psfNext
;
837 hr
= BindToObject(first1
, NULL
, IID_PPV_ARG(IShellFolder
, &psfNext
));
838 if (FAILED_UNEXPECTEDLY(hr
))
841 return psfNext
->CompareIDs(lParam
, rest1
, rest2
);
847 HRESULT STDMETHODCALLTYPE
CRegistryFolder::CreateViewObject(
852 if (!IsEqualIID(riid
, IID_IShellView
))
853 return E_NOINTERFACE
;
856 sfv
.cbSize
= sizeof(sfv
);
861 return SHCreateShellFolderView(&sfv
, (IShellView
**) ppvOut
);
864 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetAttributesOf(
866 PCUITEMID_CHILD_ARRAY apidl
,
869 const RegPidlEntry
* info
;
871 TRACE("GetAttributesOf\n");
875 *rgfInOut
&= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
| SFGAO_BROWSABLE
;
879 for (int i
= 0; i
< (int) cidl
; i
++)
881 PCUITEMID_CHILD pidl
= apidl
[i
];
883 #ifndef DISABLE_STRICT_PIDL_CHECK
884 HRESULT hr
= m_PidlManager
->FindPidlInList(pidl
, &info
);
885 if (FAILED_UNEXPECTEDLY(hr
))
888 info
= (const RegPidlEntry
*) pidl
;
889 if (info
->magic
!= REGISTRY_PIDL_MAGIC
)
893 // Update attributes.
894 *rgfInOut
= m_PidlManager
->ConvertAttributes(info
, rgfInOut
);
900 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetUIObjectOf(
903 PCUITEMID_CHILD_ARRAY apidl
,
908 TRACE("GetUIObjectOf\n");
910 if (IsEqualIID(riid
, IID_IContextMenu
) ||
911 IsEqualIID(riid
, IID_IContextMenu2
) ||
912 IsEqualIID(riid
, IID_IContextMenu3
))
914 CComPtr
<IContextMenu
> pcm
;
918 int nkeys
= _countof(keys
);
919 if (cidl
== 1 && m_PidlManager
->IsFolder(apidl
[0]))
921 RegOpenKey(HKEY_CLASSES_ROOT
, L
"Folder", keys
+ 0);
928 HRESULT hr
= CDefFolderMenu_Create2(m_shellPidl
, hwndOwner
, cidl
, apidl
, this, DefCtxMenuCallback
, nkeys
, keys
, &pcm
);
929 if (FAILED_UNEXPECTEDLY(hr
))
932 return pcm
->QueryInterface(riid
, ppvOut
);
935 if (IsEqualIID(riid
, IID_IExtractIconW
))
937 return ShellObjectCreatorInit
<CRegistryFolderExtractIcon
>(m_shellPidl
, cidl
, apidl
, riid
, ppvOut
);
940 if (IsEqualIID(riid
, IID_IDataObject
))
942 return CIDLData_CreateFromIDArray(m_shellPidl
, cidl
, apidl
, (IDataObject
**) ppvOut
);
945 if (IsEqualIID(riid
, IID_IQueryAssociations
))
947 if (cidl
== 1 && m_PidlManager
->IsFolder(apidl
[0]))
949 CComPtr
<IQueryAssociations
> pqa
;
950 HRESULT hr
= AssocCreate(CLSID_QueryAssociations
, IID_PPV_ARG(IQueryAssociations
, &pqa
));
951 if (FAILED_UNEXPECTEDLY(hr
))
954 hr
= pqa
->Init(ASSOCF_INIT_DEFAULTTOFOLDER
, L
"NTObjShEx.RegFolder", NULL
, hwndOwner
);
955 if (FAILED_UNEXPECTEDLY(hr
))
958 return pqa
->QueryInterface(riid
, ppvOut
);
965 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetDisplayNameOf(
970 const RegPidlEntry
* info
;
973 TRACE("GetDisplayNameOf %p\n", pidl
);
975 #ifndef DISABLE_STRICT_PIDL_CHECK
976 hr
= m_PidlManager
->FindPidlInList(pidl
, &info
);
977 if (FAILED_UNEXPECTEDLY(hr
))
980 info
= (const RegPidlEntry
*) pidl
;
981 if (info
->magic
!= REGISTRY_PIDL_MAGIC
)
985 if ((GET_SHGDN_RELATION(uFlags
) == SHGDN_NORMAL
) &&
986 (GET_SHGDN_FOR(uFlags
) & SHGDN_FORPARSING
))
988 WCHAR path
[MAX_PATH
] = { 0 };
990 hr
= GetFullName(m_shellPidl
, uFlags
, path
, _countof(path
));
991 if (FAILED_UNEXPECTEDLY(hr
))
994 PathAppendW(path
, info
->entryName
);
996 hr
= MakeStrRetFromString(path
, lpName
);
997 if (FAILED_UNEXPECTEDLY(hr
))
1000 LPCITEMIDLIST pidlFirst
= ILCloneFirst(pidl
);
1001 LPCITEMIDLIST pidlNext
= ILGetNext(pidl
);
1003 if (pidlNext
&& pidlNext
->mkid
.cb
> 0)
1005 CComPtr
<IShellFolder
> psfChild
;
1006 hr
= BindToObject(pidlFirst
, NULL
, IID_PPV_ARG(IShellFolder
, &psfChild
));
1007 if (FAILED_UNEXPECTEDLY(hr
))
1010 WCHAR temp
[MAX_PATH
];
1013 hr
= psfChild
->GetDisplayNameOf(pidlNext
, uFlags
| SHGDN_INFOLDER
, &childName
);
1014 if (FAILED_UNEXPECTEDLY(hr
))
1017 hr
= StrRetToBufW(&childName
, pidlNext
, temp
, _countof(temp
));
1018 if (FAILED_UNEXPECTEDLY(hr
))
1021 PathAppendW(path
, temp
);
1024 ILFree((LPITEMIDLIST
) pidlFirst
);
1028 MakeStrRetFromString(info
->entryName
, info
->entryNameLength
, lpName
);
1034 HRESULT STDMETHODCALLTYPE
CRegistryFolder::SetNameOf(
1039 LPITEMIDLIST
*ppidlOut
)
1046 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetClassID(CLSID
*lpClassId
)
1051 *lpClassId
= CLSID_RegistryFolder
;
1056 HRESULT STDMETHODCALLTYPE
CRegistryFolder::Initialize(LPCITEMIDLIST pidl
)
1058 m_shellPidl
= ILClone(pidl
);
1061 PCWSTR ntPath
= L
"";
1065 m_PidlManager
= new CRegistryPidlManager();
1067 StringCbCopy(m_NtPath
, _countof(m_NtPath
), ntPath
);
1070 return m_PidlManager
->Initialize(m_NtPath
, m_hRoot
);
1074 HRESULT STDMETHODCALLTYPE
CRegistryFolder::Initialize(LPCITEMIDLIST pidl
, PCWSTR ntPath
, HKEY hRoot
)
1076 m_shellPidl
= ILClone(pidl
);
1080 m_PidlManager
= new CRegistryPidlManager();
1082 StringCbCopy(m_NtPath
, _countof(m_NtPath
), ntPath
);
1083 return m_PidlManager
->Initialize(m_NtPath
, m_hRoot
);
1087 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetCurFolder(LPITEMIDLIST
* pidl
)
1090 *pidl
= ILClone(m_shellPidl
);
1097 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetDefaultSearchGUID(
1104 HRESULT STDMETHODCALLTYPE
CRegistryFolder::EnumSearches(
1105 IEnumExtraSearch
**ppenum
)
1111 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetDefaultColumn(
1123 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetDefaultColumnState(
1125 SHCOLSTATEF
*pcsFlags
)
1129 case REGISTRY_COLUMN_NAME
:
1130 *pcsFlags
= SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
;
1132 case REGISTRY_COLUMN_TYPE
:
1133 *pcsFlags
= SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
;
1135 case REGISTRY_COLUMN_VALUE
:
1136 *pcsFlags
= SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
| SHCOLSTATE_SLOW
;
1140 return E_INVALIDARG
;
1143 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetDetailsEx(
1145 const SHCOLUMNID
*pscid
,
1148 const RegPidlEntry
* info
;
1151 TRACE("GetDetailsEx\n");
1155 #ifndef DISABLE_STRICT_PIDL_CHECK
1156 hr
= m_PidlManager
->FindPidlInList(pidl
, &info
);
1157 if (FAILED_UNEXPECTEDLY(hr
))
1160 info
= (const RegPidlEntry
*) pidl
;
1161 if (info
->magic
!= REGISTRY_PIDL_MAGIC
)
1162 return E_INVALIDARG
;
1165 static const GUID storage
= PSGUID_STORAGE
;
1166 if (IsEqualGUID(pscid
->fmtid
, storage
))
1168 if (pscid
->pid
== PID_STG_NAME
)
1170 if (info
->entryNameLength
> 0)
1172 return MakeVariantString(pv
, info
->entryName
);
1174 return MakeVariantString(pv
, L
"(Default)");
1176 else if (pscid
->pid
== PID_STG_STORAGETYPE
)
1178 if (info
->entryType
== REG_ENTRY_ROOT
)
1180 return MakeVariantString(pv
, L
"Key");
1183 if (info
->entryType
== REG_ENTRY_KEY
)
1185 if (info
->contentsLength
> 0)
1187 PWSTR td
= (PWSTR
)(((PBYTE
) info
) + FIELD_OFFSET(RegPidlEntry
, entryName
) + info
->entryNameLength
+ sizeof(WCHAR
));
1189 return MakeVariantString(pv
, td
);
1191 return MakeVariantString(pv
, L
"Key");
1194 return MakeVariantString(pv
, RegistryTypeNames
[info
->contentType
]);
1196 else if (pscid
->pid
== PID_STG_CONTENTS
)
1198 PCWSTR strValueContents
;
1200 hr
= m_PidlManager
->FormatContentsForDisplay(info
, &strValueContents
);
1201 if (FAILED_UNEXPECTEDLY(hr
))
1206 V_VT(pv
) = VT_EMPTY
;
1210 hr
= MakeVariantString(pv
, strValueContents
);
1212 CoTaskMemFree((PVOID
) strValueContents
);
1220 return E_INVALIDARG
;
1223 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetDetailsOf(
1228 const RegPidlEntry
* info
;
1231 TRACE("GetDetailsOf\n");
1235 #ifndef DISABLE_STRICT_PIDL_CHECK
1236 hr
= m_PidlManager
->FindPidlInList(pidl
, &info
);
1237 if (FAILED_UNEXPECTEDLY(hr
))
1240 info
= (const RegPidlEntry
*) pidl
;
1241 if (info
->magic
!= REGISTRY_PIDL_MAGIC
)
1242 return E_INVALIDARG
;
1247 case REGISTRY_COLUMN_NAME
:
1248 psd
->fmt
= LVCFMT_LEFT
;
1250 if (info
->entryNameLength
> 0)
1252 return MakeStrRetFromString(info
->entryName
, info
->entryNameLength
, &(psd
->str
));
1254 return MakeStrRetFromString(L
"(Default)", &(psd
->str
));
1256 case REGISTRY_COLUMN_TYPE
:
1257 psd
->fmt
= LVCFMT_LEFT
;
1259 if (info
->entryType
== REG_ENTRY_ROOT
)
1261 return MakeStrRetFromString(L
"Key", &(psd
->str
));
1264 if (info
->entryType
== REG_ENTRY_KEY
)
1266 if (info
->contentsLength
> 0)
1268 PWSTR td
= (PWSTR
) (((PBYTE
) info
) + FIELD_OFFSET(RegPidlEntry
, entryName
) + info
->entryNameLength
+ sizeof(WCHAR
));
1270 return MakeStrRetFromString(td
, info
->contentsLength
, &(psd
->str
));
1273 return MakeStrRetFromString(L
"Key", &(psd
->str
));
1276 return MakeStrRetFromString(RegistryTypeNames
[info
->entryType
], &(psd
->str
));
1278 case REGISTRY_COLUMN_VALUE
:
1279 psd
->fmt
= LVCFMT_LEFT
;
1281 PCWSTR strValueContents
;
1283 hr
= m_PidlManager
->FormatContentsForDisplay(info
, &strValueContents
);
1284 if (FAILED_UNEXPECTEDLY(hr
))
1289 return MakeStrRetFromString(L
"(Empty)", &(psd
->str
));
1292 hr
= MakeStrRetFromString(strValueContents
, &(psd
->str
));
1294 CoTaskMemFree((PVOID
) strValueContents
);
1303 case REGISTRY_COLUMN_NAME
:
1304 psd
->fmt
= LVCFMT_LEFT
;
1307 // TODO: Make localizable
1308 MakeStrRetFromString(L
"Object Name", &(psd
->str
));
1310 case REGISTRY_COLUMN_TYPE
:
1311 psd
->fmt
= LVCFMT_LEFT
;
1314 // TODO: Make localizable
1315 MakeStrRetFromString(L
"Content Type", &(psd
->str
));
1317 case REGISTRY_COLUMN_VALUE
:
1318 psd
->fmt
= LVCFMT_LEFT
;
1321 // TODO: Make localizable
1322 MakeStrRetFromString(L
"Value", &(psd
->str
));
1327 return E_INVALIDARG
;
1330 HRESULT STDMETHODCALLTYPE
CRegistryFolder::MapColumnToSCID(
1334 static const GUID storage
= PSGUID_STORAGE
;
1337 case REGISTRY_COLUMN_NAME
:
1338 pscid
->fmtid
= storage
;
1339 pscid
->pid
= PID_STG_NAME
;
1341 case REGISTRY_COLUMN_TYPE
:
1342 pscid
->fmtid
= storage
;
1343 pscid
->pid
= PID_STG_STORAGETYPE
;
1345 case REGISTRY_COLUMN_VALUE
:
1346 pscid
->fmtid
= storage
;
1347 pscid
->pid
= PID_STG_CONTENTS
;
1350 return E_INVALIDARG
;
1353 HRESULT STDMETHODCALLTYPE
CRegistryFolder::MessageSFVCB(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1357 case SFVM_DEFVIEWMODE
:
1359 FOLDERVIEWMODE
* pViewMode
= (FOLDERVIEWMODE
*) lParam
;
1360 *pViewMode
= FVM_DETAILS
;
1363 case SFVM_COLUMNCLICK
:
1365 case SFVM_BACKGROUNDENUM
:
1367 case SFVM_DEFITEMCOUNT
:
1368 return m_PidlManager
->GetCount((UINT
*) lParam
);
1373 HRESULT
CRegistryFolder::DefCtxMenuCallback(IShellFolder
* /*psf*/, HWND
/*hwnd*/, IDataObject
* /*pdtobj*/, UINT uMsg
, WPARAM
/*wParam*/, LPARAM
/*lParam*/)
1377 case DFM_MERGECONTEXTMENU
:
1379 case DFM_INVOKECOMMAND
:
1380 case DFM_INVOKECOMMANDEX
:
1381 case DFM_GETDEFSTATICID
: // Required for Windows 7 to pick a default