2 * PROJECT: ReactOS shell extensions
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/shellext/ntobjshex/regfolder.cpp
5 * PURPOSE: NT Object Namespace shell extension
6 * PROGRAMMERS: David Quintana <gigaherz@gmail.com>
10 #include "ntobjenum.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 CRegistryPidlHelper
130 static HRESULT
CompareIDs(LPARAM lParam
, const RegPidlEntry
* first
, const RegPidlEntry
* second
)
132 if ((lParam
& 0xFFFF0000) == SHCIDS_ALLFIELDS
)
137 int minsize
= min(first
->cb
, second
->cb
);
138 int ord
= memcmp(second
, first
, minsize
);
141 return MAKE_HRESULT(0, 0, (USHORT
) ord
);
143 if (second
->cb
> first
->cb
)
144 return MAKE_HRESULT(0, 0, (USHORT
) 1);
145 if (second
->cb
< first
->cb
)
146 return MAKE_HRESULT(0, 0, (USHORT
) -1);
150 bool canonical
= ((lParam
& 0xFFFF0000) == SHCIDS_CANONICALONLY
);
152 switch (lParam
& 0xFFFF)
154 case REGISTRY_COLUMN_NAME
:
156 bool f1
= (first
->entryType
== REG_ENTRY_KEY
) || (first
->entryType
== REG_ENTRY_ROOT
);
157 bool f2
= (second
->entryType
== REG_ENTRY_KEY
) || (second
->entryType
== REG_ENTRY_ROOT
);
160 return MAKE_HRESULT(0, 0, (USHORT
) -1);
162 return MAKE_HRESULT(0, 0, (USHORT
) 1);
166 // Shortcut: avoid comparing contents if not necessary when the results are not for display.
167 if (second
->entryNameLength
> first
->entryNameLength
)
168 return MAKE_HRESULT(0, 0, (USHORT
) 1);
169 if (second
->entryNameLength
< first
->entryNameLength
)
170 return MAKE_HRESULT(0, 0, (USHORT
) -1);
172 int minlength
= min(first
->entryNameLength
, second
->entryNameLength
);
175 int ord
= memcmp(first
->entryName
, second
->entryName
, minlength
);
177 return MAKE_HRESULT(0, 0, (USHORT
) ord
);
183 int minlength
= min(first
->entryNameLength
, second
->entryNameLength
);
186 int ord
= StrCmpNW(first
->entryName
, second
->entryName
, minlength
/ sizeof(WCHAR
));
188 return MAKE_HRESULT(0, 0, (USHORT
) ord
);
191 if (second
->entryNameLength
> first
->entryNameLength
)
192 return MAKE_HRESULT(0, 0, (USHORT
) 1);
193 if (second
->entryNameLength
< first
->entryNameLength
)
194 return MAKE_HRESULT(0, 0, (USHORT
) -1);
199 case REGISTRY_COLUMN_TYPE
:
201 int ord
= second
->contentType
- first
->contentType
;
203 return MAKE_HRESULT(0, 0, (USHORT
) 1);
205 return MAKE_HRESULT(0, 0, (USHORT
) -1);
209 case REGISTRY_COLUMN_VALUE
:
211 // Can't sort by value
216 DbgPrint("Unsupported sorting mode.\n");
225 static HRESULT
CompareIDs(LPARAM lParam
, const RegPidlEntry
* first
, LPCITEMIDLIST pcidl
)
227 LPCITEMIDLIST p
= pcidl
;
228 RegPidlEntry
* second
= (RegPidlEntry
*) &(p
->mkid
);
229 if ((second
->cb
< sizeof(RegPidlEntry
)) || (second
->magic
!= REGISTRY_PIDL_MAGIC
))
232 return CompareIDs(lParam
, first
, second
);
235 static HRESULT
CompareIDs(LPARAM lParam
, LPCITEMIDLIST pcidl1
, LPCITEMIDLIST pcidl2
)
237 LPCITEMIDLIST p
= pcidl1
;
238 RegPidlEntry
* first
= (RegPidlEntry
*) &(p
->mkid
);
239 if ((first
->cb
< sizeof(RegPidlEntry
)) || (first
->magic
!= REGISTRY_PIDL_MAGIC
))
242 return CompareIDs(lParam
, first
, pcidl2
);
245 static ULONG
ConvertAttributes(const RegPidlEntry
* entry
, PULONG inMask
)
247 ULONG mask
= inMask
? *inMask
: 0xFFFFFFFF;
250 if ((entry
->entryType
== REG_ENTRY_KEY
) ||
251 (entry
->entryType
== REG_ENTRY_ROOT
))
252 flags
|= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
| SFGAO_BROWSABLE
;
257 static BOOL
IsFolder(LPCITEMIDLIST pcidl
)
259 RegPidlEntry
* entry
= (RegPidlEntry
*) &(pcidl
->mkid
);
260 if ((entry
->cb
< sizeof(RegPidlEntry
)) || (entry
->magic
!= REGISTRY_PIDL_MAGIC
))
263 return (entry
->entryType
== REG_ENTRY_KEY
) ||
264 (entry
->entryType
== REG_ENTRY_ROOT
);
267 static HRESULT
GetInfoFromPidl(LPCITEMIDLIST pcidl
, const RegPidlEntry
** pentry
)
269 RegPidlEntry
* entry
= (RegPidlEntry
*) &(pcidl
->mkid
);
271 if (entry
->cb
< sizeof(RegPidlEntry
))
273 DbgPrint("PCIDL too small %l (required %l)\n", entry
->cb
, sizeof(RegPidlEntry
));
277 if (entry
->magic
!= REGISTRY_PIDL_MAGIC
)
279 DbgPrint("PCIDL magic mismatch %04x (expected %04x)\n", entry
->magic
, REGISTRY_PIDL_MAGIC
);
287 static HRESULT
FormatValueData(DWORD contentType
, PVOID td
, DWORD contentsLength
, PCWSTR
* strContents
)
293 PCWSTR strTodo
= L
"";
294 DWORD bufferLength
= (wcslen(strTodo
) + 1) * sizeof(WCHAR
);
295 PWSTR strValue
= (PWSTR
) CoTaskMemAlloc(bufferLength
);
296 StringCbCopyW(strValue
, bufferLength
, strTodo
);
297 *strContents
= strValue
;
303 PWSTR strValue
= (PWSTR
) CoTaskMemAlloc(contentsLength
+ sizeof(WCHAR
));
304 StringCbCopyNW(strValue
, contentsLength
+ sizeof(WCHAR
), (LPCWSTR
) td
, contentsLength
);
305 *strContents
= strValue
;
310 PCWSTR separator
= L
" "; // To match regedit
311 int sepChars
= wcslen(separator
);
315 PCWSTR strData
= (PCWSTR
)td
;
318 int l
= wcslen(strData
);
320 strData
+= l
+ 1; // Skips null-terminator
324 int cch
= stringChars
+ (strings
- 1) * sepChars
+ 1;
326 PWSTR strValue
= (PWSTR
)CoTaskMemAlloc(cch
* sizeof(WCHAR
));
330 strData
= (PCWSTR
)td
;
333 StrCatW(strValue
, strData
);
334 strData
+= wcslen(strData
) + 1;
336 StrCatW(strValue
, separator
);
339 *strContents
= strValue
;
344 DWORD bufferLength
= 64 * sizeof(WCHAR
);
345 PWSTR strValue
= (PWSTR
) CoTaskMemAlloc(bufferLength
);
346 StringCbPrintfW(strValue
, bufferLength
, L
"0x%08x (%d)",
347 *(DWORD
*) td
, *(DWORD
*) td
);
348 *strContents
= strValue
;
353 DWORD bufferLength
= 64 * sizeof(WCHAR
);
354 PWSTR strValue
= (PWSTR
) CoTaskMemAlloc(bufferLength
);
355 StringCbPrintfW(strValue
, bufferLength
, L
"0x%016llx (%lld)",
356 *(LARGE_INTEGER
*) td
, ((LARGE_INTEGER
*) td
)->QuadPart
);
357 *strContents
= strValue
;
362 DWORD bufferLength
= (contentsLength
* 3 + 1) * sizeof(WCHAR
);
363 PWSTR strValue
= (PWSTR
)CoTaskMemAlloc(bufferLength
);
364 PWSTR strTemp
= strValue
;
365 PBYTE data
= (PBYTE
)td
;
366 for (int i
= 0; i
< contentsLength
; i
++)
368 StringCbPrintfW(strTemp
, bufferLength
, L
"%02x ", data
[i
]);
372 *strContents
= strValue
;
377 PCWSTR strFormat
= L
"<Unimplemented value type %d>";
378 DWORD bufferLength
= (wcslen(strFormat
) + 15) * sizeof(WCHAR
);
379 PWSTR strValue
= (PWSTR
) CoTaskMemAlloc(bufferLength
);
380 StringCbPrintfW(strValue
, bufferLength
, strFormat
, contentType
);
381 *strContents
= strValue
;
387 static HRESULT
FormatContentsForDisplay(const RegPidlEntry
* info
, HKEY rootKey
, LPCWSTR ntPath
, PCWSTR
* strContents
)
389 PVOID td
= (((PBYTE
) info
) + FIELD_OFFSET(RegPidlEntry
, entryName
) + info
->entryNameLength
+ sizeof(WCHAR
));
391 if (info
->entryType
== REG_ENTRY_VALUE_WITH_CONTENT
)
393 if (info
->contentsLength
> 0)
395 return FormatValueData(info
->contentType
, td
, info
->contentsLength
, strContents
);
398 else if (info
->entryType
== REG_ENTRY_VALUE
)
402 HRESULT hr
= ReadRegistryValue(rootKey
, ntPath
, info
->entryName
, &valueData
, &valueLength
);
403 if (FAILED_UNEXPECTEDLY(hr
))
405 PCWSTR strEmpty
= L
"(Error reading value)";
406 DWORD bufferLength
= (wcslen(strEmpty
) + 1) * sizeof(WCHAR
);
407 PWSTR strValue
= (PWSTR
) CoTaskMemAlloc(bufferLength
);
408 StringCbCopyW(strValue
, bufferLength
, strEmpty
);
409 *strContents
= strValue
;
415 hr
= FormatValueData(info
->contentType
, valueData
, valueLength
, strContents
);
417 CoTaskMemFree(valueData
);
424 PCWSTR strEmpty
= L
"";
425 DWORD bufferLength
= (wcslen(strEmpty
) + 1) * sizeof(WCHAR
);
426 PWSTR strValue
= (PWSTR
) CoTaskMemAlloc(bufferLength
);
427 StringCbCopyW(strValue
, bufferLength
, strEmpty
);
428 *strContents
= strValue
;
432 PCWSTR strEmpty
= L
"(Empty)";
433 DWORD bufferLength
= (wcslen(strEmpty
) + 1) * sizeof(WCHAR
);
434 PWSTR strValue
= (PWSTR
) CoTaskMemAlloc(bufferLength
);
435 StringCbCopyW(strValue
, bufferLength
, strEmpty
);
436 *strContents
= strValue
;
441 //-----------------------------------------------------------------------------
444 CRegistryFolder::CRegistryFolder() :
449 CRegistryFolder::~CRegistryFolder()
456 HRESULT STDMETHODCALLTYPE
CRegistryFolder::ParseDisplayName(
459 LPOLESTR lpszDisplayName
,
462 ULONG
*pdwAttributes
)
473 TRACE("CRegistryFolder::ParseDisplayName name=%S (ntPath=%S)\n", lpszDisplayName
, m_NtPath
);
475 const RegPidlEntry
* info
;
477 HRESULT hr
= GetEnumNTDirectory(m_NtPath
, &it
);
480 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
485 hr
= it
->Next(1, ppidl
, NULL
);
493 hr
= CRegistryPidlHelper::GetInfoFromPidl(*ppidl
, &info
);
494 if (FAILED_UNEXPECTEDLY(hr
))
497 if (StrCmpW(info
->entryName
, lpszDisplayName
) == 0)
503 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
506 if (pchEaten
|| pdwAttributes
)
509 *pchEaten
= wcslen(info
->entryName
);
512 *pdwAttributes
= CRegistryPidlHelper::ConvertAttributes(info
, pdwAttributes
);
518 HRESULT STDMETHODCALLTYPE
CRegistryFolder::EnumObjects(
521 IEnumIDList
**ppenumIDList
)
523 if (m_NtPath
[0] == 0 && m_hRoot
== NULL
)
525 return GetEnumRegistryRoot(ppenumIDList
);
529 return GetEnumRegistryKey(m_NtPath
, m_hRoot
, ppenumIDList
);
533 HRESULT STDMETHODCALLTYPE
CRegistryFolder::BindToObject(
539 const RegPidlEntry
* info
;
541 if (IsEqualIID(riid
, IID_IShellFolder
))
543 HRESULT hr
= CRegistryPidlHelper::GetInfoFromPidl(pidl
, &info
);
544 if (FAILED_UNEXPECTEDLY(hr
))
547 LPITEMIDLIST first
= ILCloneFirst(pidl
);
548 LPCITEMIDLIST rest
= ILGetNext(pidl
);
550 LPITEMIDLIST fullPidl
= ILCombine(m_shellPidl
, first
);
552 CComPtr
<IShellFolder
> psfChild
;
553 if (wcslen(m_NtPath
) == 0 && m_hRoot
== NULL
)
555 hr
= ShellObjectCreatorInit
<CRegistryFolder
>(fullPidl
, L
"", info
->rootKey
, IID_PPV_ARG(IShellFolder
, &psfChild
));
559 WCHAR path
[MAX_PATH
];
561 StringCbCopyW(path
, _countof(path
), m_NtPath
);
563 PathAppendW(path
, info
->entryName
);
565 hr
= ShellObjectCreatorInit
<CRegistryFolder
>(fullPidl
, path
, m_hRoot
, IID_PPV_ARG(IShellFolder
, &psfChild
));
571 if (rest
->mkid
.cb
> 0)
573 return psfChild
->BindToObject(rest
, pbcReserved
, riid
, ppvOut
);
576 return psfChild
->QueryInterface(riid
, ppvOut
);
582 HRESULT STDMETHODCALLTYPE
CRegistryFolder::BindToStorage(
592 HRESULT STDMETHODCALLTYPE
CRegistryFolder::CompareIDs(
597 TRACE("CompareIDs\n");
599 HRESULT hr
= CRegistryPidlHelper::CompareIDs(lParam
, pidl1
, pidl2
);
603 LPCITEMIDLIST rest1
= ILGetNext(pidl1
);
604 LPCITEMIDLIST rest2
= ILGetNext(pidl2
);
606 bool hasNext1
= (rest1
->mkid
.cb
> 0);
607 bool hasNext2
= (rest2
->mkid
.cb
> 0);
609 if (hasNext1
|| hasNext2
)
611 if (hasNext1
&& !hasNext2
)
612 return MAKE_HRESULT(0, 0, (USHORT
) -1);
614 if (hasNext2
&& !hasNext1
)
615 return MAKE_HRESULT(0, 0, (USHORT
) 1);
617 LPCITEMIDLIST first1
= ILCloneFirst(pidl1
);
619 CComPtr
<IShellFolder
> psfNext
;
620 hr
= BindToObject(first1
, NULL
, IID_PPV_ARG(IShellFolder
, &psfNext
));
621 if (FAILED_UNEXPECTEDLY(hr
))
624 return psfNext
->CompareIDs(lParam
, rest1
, rest2
);
630 HRESULT STDMETHODCALLTYPE
CRegistryFolder::CreateViewObject(
635 if (!IsEqualIID(riid
, IID_IShellView
))
636 return E_NOINTERFACE
;
639 sfv
.cbSize
= sizeof(sfv
);
644 return SHCreateShellFolderView(&sfv
, (IShellView
**) ppvOut
);
647 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetAttributesOf(
649 PCUITEMID_CHILD_ARRAY apidl
,
652 const RegPidlEntry
* info
;
654 TRACE("GetAttributesOf\n");
658 *rgfInOut
&= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
| SFGAO_BROWSABLE
;
662 for (int i
= 0; i
< (int) cidl
; i
++)
664 PCUITEMID_CHILD pidl
= apidl
[i
];
666 HRESULT hr
= CRegistryPidlHelper::GetInfoFromPidl(pidl
, &info
);
667 if (FAILED_UNEXPECTEDLY(hr
))
670 // Update attributes.
671 *rgfInOut
= CRegistryPidlHelper::ConvertAttributes(info
, rgfInOut
);
677 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetUIObjectOf(
680 PCUITEMID_CHILD_ARRAY apidl
,
685 TRACE("GetUIObjectOf\n");
687 if (IsEqualIID(riid
, IID_IContextMenu
) ||
688 IsEqualIID(riid
, IID_IContextMenu2
) ||
689 IsEqualIID(riid
, IID_IContextMenu3
))
691 CComPtr
<IContextMenu
> pcm
;
696 int nkeys
= _countof(keys
);
697 if (cidl
== 1 && CRegistryPidlHelper::IsFolder(apidl
[0]))
699 res
= RegOpenKey(HKEY_CLASSES_ROOT
, L
"Folder", keys
+ 0);
700 if (!NT_SUCCESS(res
))
701 return HRESULT_FROM_NT(res
);
708 HRESULT hr
= CDefFolderMenu_Create2(m_shellPidl
, hwndOwner
, cidl
, apidl
, this, DefCtxMenuCallback
, nkeys
, keys
, &pcm
);
709 if (FAILED_UNEXPECTEDLY(hr
))
712 return pcm
->QueryInterface(riid
, ppvOut
);
715 if (IsEqualIID(riid
, IID_IExtractIconW
))
717 return ShellObjectCreatorInit
<CRegistryFolderExtractIcon
>(m_shellPidl
, cidl
, apidl
, riid
, ppvOut
);
720 if (IsEqualIID(riid
, IID_IDataObject
))
722 return CIDLData_CreateFromIDArray(m_shellPidl
, cidl
, apidl
, (IDataObject
**) ppvOut
);
725 if (IsEqualIID(riid
, IID_IQueryAssociations
))
727 if (cidl
== 1 && CRegistryPidlHelper::IsFolder(apidl
[0]))
729 CComPtr
<IQueryAssociations
> pqa
;
730 HRESULT hr
= AssocCreate(CLSID_QueryAssociations
, IID_PPV_ARG(IQueryAssociations
, &pqa
));
731 if (FAILED_UNEXPECTEDLY(hr
))
734 hr
= pqa
->Init(ASSOCF_INIT_DEFAULTTOFOLDER
, L
"NTObjShEx.RegFolder", NULL
, hwndOwner
);
735 if (FAILED_UNEXPECTEDLY(hr
))
738 return pqa
->QueryInterface(riid
, ppvOut
);
745 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetDisplayNameOf(
750 const RegPidlEntry
* info
;
752 TRACE("GetDisplayNameOf %p\n", pidl
);
754 HRESULT hr
= CRegistryPidlHelper::GetInfoFromPidl(pidl
, &info
);
755 if (FAILED_UNEXPECTEDLY(hr
))
758 if (GET_SHGDN_FOR(uFlags
) & SHGDN_FOREDITING
)
760 hr
= MakeStrRetFromString(info
->entryName
, info
->entryNameLength
, lpName
);
761 if (FAILED_UNEXPECTEDLY(hr
))
765 WCHAR path
[MAX_PATH
] = { 0 };
767 if (GET_SHGDN_FOR(uFlags
) & SHGDN_FORPARSING
)
769 if (GET_SHGDN_RELATION(uFlags
) != SHGDN_INFOLDER
)
771 hr
= GetFullName(m_shellPidl
, uFlags
, path
, _countof(path
));
772 if (FAILED_UNEXPECTEDLY(hr
))
777 PathAppendW(path
, info
->entryName
);
779 LPCITEMIDLIST pidlNext
= ILGetNext(pidl
);
780 if (pidlNext
&& pidlNext
->mkid
.cb
> 0)
782 LPITEMIDLIST pidlFirst
= ILCloneFirst(pidl
);
784 CComPtr
<IShellFolder
> psfChild
;
785 hr
= BindToObject(pidlFirst
, NULL
, IID_PPV_ARG(IShellFolder
, &psfChild
));
786 if (FAILED_UNEXPECTEDLY(hr
))
789 WCHAR temp
[MAX_PATH
];
792 hr
= psfChild
->GetDisplayNameOf(pidlNext
, uFlags
| SHGDN_INFOLDER
, &childName
);
793 if (FAILED_UNEXPECTEDLY(hr
))
796 hr
= StrRetToBufW(&childName
, pidlNext
, temp
, _countof(temp
));
797 if (FAILED_UNEXPECTEDLY(hr
))
800 PathAppendW(path
, temp
);
805 hr
= MakeStrRetFromString(path
, lpName
);
806 if (FAILED_UNEXPECTEDLY(hr
))
812 HRESULT STDMETHODCALLTYPE
CRegistryFolder::SetNameOf(
817 LPITEMIDLIST
*ppidlOut
)
824 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetClassID(CLSID
*lpClassId
)
829 *lpClassId
= CLSID_RegistryFolder
;
834 HRESULT STDMETHODCALLTYPE
CRegistryFolder::Initialize(LPCITEMIDLIST pidl
)
836 m_shellPidl
= ILClone(pidl
);
839 StringCbCopy(m_NtPath
, _countof(m_NtPath
), L
"");
844 HRESULT STDMETHODCALLTYPE
CRegistryFolder::Initialize(LPCITEMIDLIST pidl
, PCWSTR ntPath
, HKEY hRoot
)
846 m_shellPidl
= ILClone(pidl
);
849 StringCbCopy(m_NtPath
, _countof(m_NtPath
), ntPath
);
854 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetCurFolder(LPITEMIDLIST
* pidl
)
857 *pidl
= ILClone(m_shellPidl
);
864 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetDefaultSearchGUID(
871 HRESULT STDMETHODCALLTYPE
CRegistryFolder::EnumSearches(
872 IEnumExtraSearch
**ppenum
)
878 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetDefaultColumn(
890 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetDefaultColumnState(
892 SHCOLSTATEF
*pcsFlags
)
896 case REGISTRY_COLUMN_NAME
:
897 *pcsFlags
= SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
;
899 case REGISTRY_COLUMN_TYPE
:
900 *pcsFlags
= SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
;
902 case REGISTRY_COLUMN_VALUE
:
903 *pcsFlags
= SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
| SHCOLSTATE_SLOW
;
910 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetDetailsEx(
912 const SHCOLUMNID
*pscid
,
915 const RegPidlEntry
* info
;
917 TRACE("GetDetailsEx\n");
921 HRESULT hr
= CRegistryPidlHelper::GetInfoFromPidl(pidl
, &info
);
922 if (FAILED_UNEXPECTEDLY(hr
))
925 static const GUID storage
= PSGUID_STORAGE
;
926 if (IsEqualGUID(pscid
->fmtid
, storage
))
928 if (pscid
->pid
== PID_STG_NAME
)
930 if (info
->entryNameLength
> 0)
932 return MakeVariantString(pv
, info
->entryName
);
934 return MakeVariantString(pv
, L
"(Default)");
936 else if (pscid
->pid
== PID_STG_STORAGETYPE
)
938 if (info
->entryType
== REG_ENTRY_ROOT
)
940 return MakeVariantString(pv
, L
"Key");
943 if (info
->entryType
== REG_ENTRY_KEY
)
945 if (info
->contentsLength
> 0)
947 PWSTR td
= (PWSTR
) (((PBYTE
) info
) + FIELD_OFFSET(RegPidlEntry
, entryName
) + info
->entryNameLength
+ sizeof(WCHAR
));
949 return MakeVariantString(pv
, td
);
951 return MakeVariantString(pv
, L
"Key");
954 return MakeVariantString(pv
, RegistryTypeNames
[info
->contentType
]);
956 else if (pscid
->pid
== PID_STG_CONTENTS
)
958 PCWSTR strValueContents
;
960 hr
= CRegistryPidlHelper::FormatContentsForDisplay(info
, m_hRoot
, m_NtPath
, &strValueContents
);
961 if (FAILED_UNEXPECTEDLY(hr
))
970 hr
= MakeVariantString(pv
, strValueContents
);
972 CoTaskMemFree((PVOID
) strValueContents
);
983 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetDetailsOf(
988 const RegPidlEntry
* info
;
990 TRACE("GetDetailsOf\n");
994 HRESULT hr
= CRegistryPidlHelper::GetInfoFromPidl(pidl
, &info
);
995 if (FAILED_UNEXPECTEDLY(hr
))
1000 case REGISTRY_COLUMN_NAME
:
1001 psd
->fmt
= LVCFMT_LEFT
;
1003 if (info
->entryNameLength
> 0)
1005 return MakeStrRetFromString(info
->entryName
, info
->entryNameLength
, &(psd
->str
));
1007 return MakeStrRetFromString(L
"(Default)", &(psd
->str
));
1009 case REGISTRY_COLUMN_TYPE
:
1010 psd
->fmt
= LVCFMT_LEFT
;
1012 if (info
->entryType
== REG_ENTRY_ROOT
)
1014 return MakeStrRetFromString(L
"Key", &(psd
->str
));
1017 if (info
->entryType
== REG_ENTRY_KEY
)
1019 if (info
->contentsLength
> 0)
1021 PWSTR td
= (PWSTR
) (((PBYTE
) info
) + FIELD_OFFSET(RegPidlEntry
, entryName
) + info
->entryNameLength
+ sizeof(WCHAR
));
1023 return MakeStrRetFromString(td
, info
->contentsLength
, &(psd
->str
));
1026 return MakeStrRetFromString(L
"Key", &(psd
->str
));
1029 return MakeStrRetFromString(RegistryTypeNames
[info
->entryType
], &(psd
->str
));
1031 case REGISTRY_COLUMN_VALUE
:
1032 psd
->fmt
= LVCFMT_LEFT
;
1034 PCWSTR strValueContents
;
1036 hr
= CRegistryPidlHelper::FormatContentsForDisplay(info
, m_hRoot
, m_NtPath
, &strValueContents
);
1037 if (FAILED_UNEXPECTEDLY(hr
))
1042 return MakeStrRetFromString(L
"(Empty)", &(psd
->str
));
1045 hr
= MakeStrRetFromString(strValueContents
, &(psd
->str
));
1047 CoTaskMemFree((PVOID
) strValueContents
);
1056 case REGISTRY_COLUMN_NAME
:
1057 psd
->fmt
= LVCFMT_LEFT
;
1060 // TODO: Make localizable
1061 MakeStrRetFromString(L
"Object Name", &(psd
->str
));
1063 case REGISTRY_COLUMN_TYPE
:
1064 psd
->fmt
= LVCFMT_LEFT
;
1067 // TODO: Make localizable
1068 MakeStrRetFromString(L
"Content Type", &(psd
->str
));
1070 case REGISTRY_COLUMN_VALUE
:
1071 psd
->fmt
= LVCFMT_LEFT
;
1074 // TODO: Make localizable
1075 MakeStrRetFromString(L
"Value", &(psd
->str
));
1080 return E_INVALIDARG
;
1083 HRESULT STDMETHODCALLTYPE
CRegistryFolder::MapColumnToSCID(
1087 static const GUID storage
= PSGUID_STORAGE
;
1090 case REGISTRY_COLUMN_NAME
:
1091 pscid
->fmtid
= storage
;
1092 pscid
->pid
= PID_STG_NAME
;
1094 case REGISTRY_COLUMN_TYPE
:
1095 pscid
->fmtid
= storage
;
1096 pscid
->pid
= PID_STG_STORAGETYPE
;
1098 case REGISTRY_COLUMN_VALUE
:
1099 pscid
->fmtid
= storage
;
1100 pscid
->pid
= PID_STG_CONTENTS
;
1103 return E_INVALIDARG
;
1106 HRESULT STDMETHODCALLTYPE
CRegistryFolder::MessageSFVCB(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1110 case SFVM_DEFVIEWMODE
:
1112 FOLDERVIEWMODE
* pViewMode
= (FOLDERVIEWMODE
*) lParam
;
1113 *pViewMode
= FVM_DETAILS
;
1116 case SFVM_COLUMNCLICK
:
1118 case SFVM_BACKGROUNDENUM
:
1124 HRESULT
CRegistryFolder::DefCtxMenuCallback(IShellFolder
* /*psf*/, HWND
/*hwnd*/, IDataObject
* /*pdtobj*/, UINT uMsg
, WPARAM
/*wParam*/, LPARAM
/*lParam*/)
1128 case DFM_MERGECONTEXTMENU
:
1130 case DFM_INVOKECOMMAND
:
1131 case DFM_INVOKECOMMANDEX
:
1132 case DFM_GETDEFSTATICID
: // Required for Windows 7 to pick a default