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
, 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(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
, RegPidlEntry
* first
, 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
, 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(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 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(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(
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
,
872 TRACE("GetAttributesOf\n");
876 *rgfInOut
&= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
| SFGAO_BROWSABLE
;
880 for (int i
= 0; i
< (int) cidl
; i
++)
882 PCUITEMID_CHILD pidl
= apidl
[i
];
884 hr
= m_PidlManager
->FindPidlInList(pidl
, &info
);
885 if (FAILED_UNEXPECTEDLY(hr
))
888 // Update attributes.
889 *rgfInOut
= m_PidlManager
->ConvertAttributes(info
, rgfInOut
);
895 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetUIObjectOf(
898 PCUITEMID_CHILD_ARRAY apidl
,
903 TRACE("GetUIObjectOf\n");
905 if (IsEqualIID(riid
, IID_IContextMenu
) ||
906 IsEqualIID(riid
, IID_IContextMenu2
) ||
907 IsEqualIID(riid
, IID_IContextMenu3
))
909 CComPtr
<IContextMenu
> pcm
;
913 int nkeys
= _countof(keys
);
914 if (cidl
== 1 && m_PidlManager
->IsFolder(apidl
[0]))
916 RegOpenKey(HKEY_CLASSES_ROOT
, L
"Folder", keys
+ 0);
923 HRESULT hr
= CDefFolderMenu_Create2(m_shellPidl
, hwndOwner
, cidl
, apidl
, this, DefCtxMenuCallback
, nkeys
, keys
, &pcm
);
924 if (FAILED_UNEXPECTEDLY(hr
))
927 return pcm
->QueryInterface(riid
, ppvOut
);
930 if (IsEqualIID(riid
, IID_IExtractIconW
))
932 return ShellObjectCreatorInit
<CRegistryFolderExtractIcon
>(m_shellPidl
, cidl
, apidl
, riid
, ppvOut
);
935 if (IsEqualIID(riid
, IID_IDataObject
))
937 return CIDLData_CreateFromIDArray(m_shellPidl
, cidl
, apidl
, (IDataObject
**) ppvOut
);
940 if (IsEqualIID(riid
, IID_IQueryAssociations
))
942 if (cidl
== 1 && m_PidlManager
->IsFolder(apidl
[0]))
944 CComPtr
<IQueryAssociations
> pqa
;
945 HRESULT hr
= AssocCreate(CLSID_QueryAssociations
, IID_PPV_ARG(IQueryAssociations
, &pqa
));
946 if (FAILED_UNEXPECTEDLY(hr
))
949 hr
= pqa
->Init(ASSOCF_INIT_DEFAULTTOFOLDER
, L
"NTObjShEx.RegFolder", NULL
, hwndOwner
);
950 if (FAILED_UNEXPECTEDLY(hr
))
953 return pqa
->QueryInterface(riid
, ppvOut
);
960 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetDisplayNameOf(
968 TRACE("GetDisplayNameOf %p\n", pidl
);
970 hr
= m_PidlManager
->FindPidlInList(pidl
, &info
);
971 if (FAILED_UNEXPECTEDLY(hr
))
974 if ((GET_SHGDN_RELATION(uFlags
) == SHGDN_NORMAL
) &&
975 (GET_SHGDN_FOR(uFlags
) & SHGDN_FORPARSING
))
977 WCHAR path
[MAX_PATH
] = { 0 };
979 hr
= GetFullName(m_shellPidl
, uFlags
, path
, _countof(path
));
980 if (FAILED_UNEXPECTEDLY(hr
))
983 PathAppendW(path
, info
->entryName
);
985 hr
= MakeStrRetFromString(path
, lpName
);
986 if (FAILED_UNEXPECTEDLY(hr
))
989 LPCITEMIDLIST pidlFirst
= ILCloneFirst(pidl
);
990 LPCITEMIDLIST pidlNext
= ILGetNext(pidl
);
992 if (pidlNext
&& pidlNext
->mkid
.cb
> 0)
994 CComPtr
<IShellFolder
> psfChild
;
995 hr
= BindToObject(pidlFirst
, NULL
, IID_PPV_ARG(IShellFolder
, &psfChild
));
996 if (FAILED_UNEXPECTEDLY(hr
))
999 WCHAR temp
[MAX_PATH
];
1002 hr
= psfChild
->GetDisplayNameOf(pidlNext
, uFlags
| SHGDN_INFOLDER
, &childName
);
1003 if (FAILED_UNEXPECTEDLY(hr
))
1006 hr
= StrRetToBufW(&childName
, pidlNext
, temp
, _countof(temp
));
1007 if (FAILED_UNEXPECTEDLY(hr
))
1010 PathAppendW(path
, temp
);
1013 ILFree((LPITEMIDLIST
) pidlFirst
);
1017 MakeStrRetFromString(info
->entryName
, info
->entryNameLength
, lpName
);
1023 HRESULT STDMETHODCALLTYPE
CRegistryFolder::SetNameOf(
1028 LPITEMIDLIST
*ppidlOut
)
1035 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetClassID(CLSID
*lpClassId
)
1040 *lpClassId
= CLSID_RegistryFolder
;
1045 HRESULT STDMETHODCALLTYPE
CRegistryFolder::Initialize(LPCITEMIDLIST pidl
)
1047 m_shellPidl
= ILClone(pidl
);
1050 PCWSTR ntPath
= L
"";
1054 m_PidlManager
= new CRegistryPidlManager();
1056 StringCbCopy(m_NtPath
, _countof(m_NtPath
), ntPath
);
1059 return m_PidlManager
->Initialize(m_NtPath
, m_hRoot
);
1063 HRESULT STDMETHODCALLTYPE
CRegistryFolder::Initialize(LPCITEMIDLIST pidl
, PCWSTR ntPath
, HKEY hRoot
)
1065 m_shellPidl
= ILClone(pidl
);
1069 m_PidlManager
= new CRegistryPidlManager();
1071 StringCbCopy(m_NtPath
, _countof(m_NtPath
), ntPath
);
1072 return m_PidlManager
->Initialize(m_NtPath
, m_hRoot
);
1076 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetCurFolder(LPITEMIDLIST
* pidl
)
1079 *pidl
= ILClone(m_shellPidl
);
1086 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetDefaultSearchGUID(
1093 HRESULT STDMETHODCALLTYPE
CRegistryFolder::EnumSearches(
1094 IEnumExtraSearch
**ppenum
)
1100 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetDefaultColumn(
1112 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetDefaultColumnState(
1114 SHCOLSTATEF
*pcsFlags
)
1118 case REGISTRY_COLUMN_NAME
:
1119 *pcsFlags
= SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
;
1121 case REGISTRY_COLUMN_TYPE
:
1122 *pcsFlags
= SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
;
1124 case REGISTRY_COLUMN_VALUE
:
1125 *pcsFlags
= SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
| SHCOLSTATE_SLOW
;
1129 return E_INVALIDARG
;
1132 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetDetailsEx(
1134 const SHCOLUMNID
*pscid
,
1137 RegPidlEntry
* info
;
1140 TRACE("GetDetailsEx\n");
1144 hr
= m_PidlManager
->FindPidlInList(pidl
, &info
);
1145 if (FAILED_UNEXPECTEDLY(hr
))
1148 static const GUID storage
= PSGUID_STORAGE
;
1149 if (IsEqualGUID(pscid
->fmtid
, storage
))
1151 if (pscid
->pid
== PID_STG_NAME
)
1153 if (info
->entryNameLength
> 0)
1155 return MakeVariantString(pv
, info
->entryName
);
1157 return MakeVariantString(pv
, L
"(Default)");
1159 else if (pscid
->pid
== PID_STG_STORAGETYPE
)
1161 if (info
->entryType
== REG_ENTRY_ROOT
)
1163 return MakeVariantString(pv
, L
"Key");
1166 if (info
->entryType
== REG_ENTRY_KEY
)
1168 if (info
->contentsLength
> 0)
1170 PWSTR td
= (PWSTR
)(((PBYTE
) info
) + FIELD_OFFSET(RegPidlEntry
, entryName
) + info
->entryNameLength
+ sizeof(WCHAR
));
1172 return MakeVariantString(pv
, td
);
1174 return MakeVariantString(pv
, L
"Key");
1177 return MakeVariantString(pv
, RegistryTypeNames
[info
->contentType
]);
1179 else if (pscid
->pid
== PID_STG_CONTENTS
)
1181 PCWSTR strValueContents
;
1183 hr
= m_PidlManager
->FormatContentsForDisplay(info
, &strValueContents
);
1184 if (FAILED_UNEXPECTEDLY(hr
))
1189 V_VT(pv
) = VT_EMPTY
;
1193 hr
= MakeVariantString(pv
, strValueContents
);
1195 CoTaskMemFree((PVOID
) strValueContents
);
1203 return E_INVALIDARG
;
1206 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetDetailsOf(
1211 RegPidlEntry
* info
;
1214 TRACE("GetDetailsOf\n");
1218 hr
= m_PidlManager
->FindPidlInList(pidl
, &info
);
1219 if (FAILED_UNEXPECTEDLY(hr
))
1224 case REGISTRY_COLUMN_NAME
:
1225 psd
->fmt
= LVCFMT_LEFT
;
1227 if (info
->entryNameLength
> 0)
1229 return MakeStrRetFromString(info
->entryName
, info
->entryNameLength
, &(psd
->str
));
1231 return MakeStrRetFromString(L
"(Default)", &(psd
->str
));
1233 case REGISTRY_COLUMN_TYPE
:
1234 psd
->fmt
= LVCFMT_LEFT
;
1236 if (info
->entryType
== REG_ENTRY_ROOT
)
1238 return MakeStrRetFromString(L
"Key", &(psd
->str
));
1241 if (info
->entryType
== REG_ENTRY_KEY
)
1243 if (info
->contentsLength
> 0)
1245 PWSTR td
= (PWSTR
) (((PBYTE
) info
) + FIELD_OFFSET(RegPidlEntry
, entryName
) + info
->entryNameLength
+ sizeof(WCHAR
));
1247 return MakeStrRetFromString(td
, info
->contentsLength
, &(psd
->str
));
1250 return MakeStrRetFromString(L
"Key", &(psd
->str
));
1253 return MakeStrRetFromString(RegistryTypeNames
[info
->entryType
], &(psd
->str
));
1255 case REGISTRY_COLUMN_VALUE
:
1256 psd
->fmt
= LVCFMT_LEFT
;
1258 PCWSTR strValueContents
;
1260 hr
= m_PidlManager
->FormatContentsForDisplay(info
, &strValueContents
);
1261 if (FAILED_UNEXPECTEDLY(hr
))
1266 return MakeStrRetFromString(L
"(Empty)", &(psd
->str
));
1269 hr
= MakeStrRetFromString(strValueContents
, &(psd
->str
));
1271 CoTaskMemFree((PVOID
) strValueContents
);
1280 case REGISTRY_COLUMN_NAME
:
1281 psd
->fmt
= LVCFMT_LEFT
;
1284 // TODO: Make localizable
1285 MakeStrRetFromString(L
"Object Name", &(psd
->str
));
1287 case REGISTRY_COLUMN_TYPE
:
1288 psd
->fmt
= LVCFMT_LEFT
;
1291 // TODO: Make localizable
1292 MakeStrRetFromString(L
"Content Type", &(psd
->str
));
1294 case REGISTRY_COLUMN_VALUE
:
1295 psd
->fmt
= LVCFMT_LEFT
;
1298 // TODO: Make localizable
1299 MakeStrRetFromString(L
"Value", &(psd
->str
));
1304 return E_INVALIDARG
;
1307 HRESULT STDMETHODCALLTYPE
CRegistryFolder::MapColumnToSCID(
1311 static const GUID storage
= PSGUID_STORAGE
;
1314 case REGISTRY_COLUMN_NAME
:
1315 pscid
->fmtid
= storage
;
1316 pscid
->pid
= PID_STG_NAME
;
1318 case REGISTRY_COLUMN_TYPE
:
1319 pscid
->fmtid
= storage
;
1320 pscid
->pid
= PID_STG_STORAGETYPE
;
1322 case REGISTRY_COLUMN_VALUE
:
1323 pscid
->fmtid
= storage
;
1324 pscid
->pid
= PID_STG_CONTENTS
;
1327 return E_INVALIDARG
;
1330 HRESULT STDMETHODCALLTYPE
CRegistryFolder::MessageSFVCB(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1334 case SFVM_DEFVIEWMODE
:
1336 FOLDERVIEWMODE
* pViewMode
= (FOLDERVIEWMODE
*) lParam
;
1337 *pViewMode
= FVM_DETAILS
;
1340 case SFVM_COLUMNCLICK
:
1342 case SFVM_BACKGROUNDENUM
:
1344 case SFVM_DEFITEMCOUNT
:
1345 return m_PidlManager
->GetCount((UINT
*) lParam
);
1350 HRESULT
CRegistryFolder::DefCtxMenuCallback(IShellFolder
* /*psf*/, HWND
/*hwnd*/, IDataObject
* /*pdtobj*/, UINT uMsg
, WPARAM
/*wParam*/, LPARAM
/*lParam*/)
1354 case DFM_MERGECONTEXTMENU
:
1356 case DFM_INVOKECOMMAND
:
1357 case DFM_INVOKECOMMANDEX
:
1358 case DFM_GETDEFSTATICID
: // Required for Windows 7 to pick a default