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
)
168 m_hDpa
= DPA_Create(10);
171 return E_OUTOFMEMORY
;
173 if (wcslen(m_ntPath
) == 0 && m_hRoot
== NULL
)
175 HRESULT hr
= EnumerateRootKeys(m_hDpa
, &m_hDpaCount
);
176 if (FAILED_UNEXPECTEDLY(hr
))
181 HRESULT hr
= EnumerateRegistryKey(m_hDpa
, m_ntPath
, m_hRoot
, &m_hDpaCount
);
182 if (FAILED_UNEXPECTEDLY(hr
))
189 HRESULT
FindPidlInList(PCUITEMID_CHILD pcidl
, RegPidlEntry
** pinfo
)
198 RegPidlEntry
* info
= (RegPidlEntry
*) pcidl
;
199 if ((info
->cb
< sizeof(RegPidlEntry
)) || (info
->magic
!= REGISTRY_PIDL_MAGIC
))
201 ERR("FindPidlInList: Requested pidl is not of the correct type.\n");
205 TRACE("Searching for pidl { cb=%d } in a list of %d items\n", pcidl
->mkid
.cb
, m_hDpaCount
);
207 for (UINT i
= 0; i
< m_hDpaCount
; i
++)
209 RegPidlEntry
* pInfo
= (RegPidlEntry
*) DPA_GetPtr(m_hDpa
, i
);
212 hr
= CompareIDs(0, pInfo
, pcidl
);
213 if (FAILED_UNEXPECTEDLY(hr
))
223 TRACE("Comparison returned %d\n", (int) (short) (hr
& 0xFFFF));
227 ERR("PIDL NOT FOUND: Requested filename: %S\n", info
->entryName
);
228 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
231 HRESULT
FindByName(LPCWSTR strParsingName
, RegPidlEntry
** pinfo
)
238 TRACE("Searching for '%S' in a list of %d items\n", strParsingName
, m_hDpaCount
);
240 for (int i
= 0; i
< (int) m_hDpaCount
; i
++)
242 RegPidlEntry
* pInfo
= (RegPidlEntry
*) DPA_GetPtr(m_hDpa
, i
);
245 int order
= CompareStringW(GetThreadLocale(), NORM_IGNORECASE
,
246 pInfo
->entryName
, wcslen(pInfo
->entryName
),
247 strParsingName
, wcslen(strParsingName
));
249 if (order
== CSTR_EQUAL
)
256 TRACE("Pidl not found\n");
257 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
260 HRESULT
GetPidl(UINT index
, RegPidlEntry
** pEntry
)
264 RegPidlEntry
* entry
= (RegPidlEntry
*) DPA_GetPtr(m_hDpa
, index
);
267 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
274 HRESULT
GetCount(UINT
* count
)
276 *count
= m_hDpaCount
;
281 static LPITEMIDLIST
CreatePidlFromItem(RegPidlEntry
* entry
)
283 LPITEMIDLIST idl
= (LPITEMIDLIST
) CoTaskMemAlloc(entry
->cb
+ 2);
286 memset(idl
, 0, entry
->cb
+ 2);
287 memcpy(idl
, entry
, entry
->cb
);
291 HRESULT
CompareIDs(LPARAM lParam
, RegPidlEntry
* first
, RegPidlEntry
* second
)
293 if ((lParam
& 0xFFFF0000) == SHCIDS_ALLFIELDS
)
298 int minsize
= min(first
->cb
, second
->cb
);
299 int ord
= memcmp(second
, first
, minsize
);
302 return MAKE_HRESULT(0, 0, (USHORT
) ord
);
304 if (second
->cb
> first
->cb
)
305 return MAKE_HRESULT(0, 0, (USHORT
) 1);
306 if (second
->cb
< first
->cb
)
307 return MAKE_HRESULT(0, 0, (USHORT
) -1);
311 bool canonical
= ((lParam
& 0xFFFF0000) == SHCIDS_CANONICALONLY
);
313 switch (lParam
& 0xFFFF)
315 case REGISTRY_COLUMN_NAME
:
317 bool f1
= (first
->entryType
== REG_ENTRY_KEY
) || (first
->entryType
== REG_ENTRY_ROOT
);
318 bool f2
= (second
->entryType
== REG_ENTRY_KEY
) || (second
->entryType
== REG_ENTRY_ROOT
);
321 return MAKE_HRESULT(0, 0, (USHORT
) -1);
323 return MAKE_HRESULT(0, 0, (USHORT
) 1);
327 // Shortcut: avoid comparing contents if not necessary when the results are not for display.
328 if (second
->entryNameLength
> first
->entryNameLength
)
329 return MAKE_HRESULT(0, 0, (USHORT
) 1);
330 if (second
->entryNameLength
< first
->entryNameLength
)
331 return MAKE_HRESULT(0, 0, (USHORT
) -1);
334 int minlength
= min(first
->entryNameLength
, second
->entryNameLength
);
335 int ord
= StrCmpNW(first
->entryName
, second
->entryName
, minlength
);
338 return MAKE_HRESULT(0, 0, (USHORT
) ord
);
342 if (second
->entryNameLength
> first
->entryNameLength
)
343 return MAKE_HRESULT(0, 0, (USHORT
) 1);
344 if (second
->entryNameLength
< first
->entryNameLength
)
345 return MAKE_HRESULT(0, 0, (USHORT
) -1);
350 case REGISTRY_COLUMN_TYPE
:
352 int ord
= second
->contentType
- first
->contentType
;
354 return MAKE_HRESULT(0, 0, (USHORT
) 1);
356 return MAKE_HRESULT(0, 0, (USHORT
) -1);
360 case REGISTRY_COLUMN_VALUE
:
362 // Can't sort by value
367 DbgPrint("Unsupported sorting mode.\n");
376 HRESULT
CompareIDs(LPARAM lParam
, RegPidlEntry
* first
, LPCITEMIDLIST pcidl
)
378 LPCITEMIDLIST p
= pcidl
;
379 RegPidlEntry
* second
= (RegPidlEntry
*) &(p
->mkid
);
380 if ((second
->cb
< sizeof(RegPidlEntry
)) || (second
->magic
!= REGISTRY_PIDL_MAGIC
))
383 return CompareIDs(lParam
, first
, second
);
386 HRESULT
CompareIDs(LPARAM lParam
, LPCITEMIDLIST pcidl1
, LPCITEMIDLIST pcidl2
)
388 LPCITEMIDLIST p
= pcidl1
;
389 RegPidlEntry
* first
= (RegPidlEntry
*) &(p
->mkid
);
390 if ((first
->cb
< sizeof(RegPidlEntry
)) || (first
->magic
!= REGISTRY_PIDL_MAGIC
))
393 return CompareIDs(lParam
, first
, pcidl2
);
396 ULONG
ConvertAttributes(RegPidlEntry
* entry
, PULONG inMask
)
398 ULONG mask
= inMask
? *inMask
: 0xFFFFFFFF;
401 if ((entry
->entryType
== REG_ENTRY_KEY
) ||
402 (entry
->entryType
== REG_ENTRY_ROOT
))
403 flags
|= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
| SFGAO_BROWSABLE
;
408 BOOL
IsFolder(LPCITEMIDLIST pcidl
)
410 RegPidlEntry
* entry
;
411 HRESULT hr
= FindPidlInList(pcidl
, &entry
);
412 if (FAILED_UNEXPECTEDLY(hr
))
415 return (entry
->entryType
== REG_ENTRY_KEY
) ||
416 (entry
->entryType
== REG_ENTRY_ROOT
);
419 HRESULT
FormatValueData(DWORD contentType
, PVOID td
, DWORD contentsLength
, PCWSTR
* strContents
)
425 PCWSTR strTodo
= L
"";
426 DWORD bufferLength
= (wcslen(strTodo
) + 1) * sizeof(WCHAR
);
427 PWSTR strValue
= (PWSTR
) CoTaskMemAlloc(bufferLength
);
428 StringCbCopyW(strValue
, bufferLength
, strTodo
);
429 *strContents
= strValue
;
435 PWSTR strValue
= (PWSTR
) CoTaskMemAlloc(contentsLength
+ sizeof(WCHAR
));
436 StringCbCopyNW(strValue
, contentsLength
+ sizeof(WCHAR
), (LPCWSTR
) td
, contentsLength
);
437 *strContents
= strValue
;
442 DWORD bufferLength
= 64 * sizeof(WCHAR
);
443 PWSTR strValue
= (PWSTR
) CoTaskMemAlloc(bufferLength
);
444 StringCbPrintfW(strValue
, bufferLength
, L
"0x%08x (%d)",
445 *(DWORD
*) td
, *(DWORD
*) td
);
446 *strContents
= strValue
;
451 DWORD bufferLength
= 64 * sizeof(WCHAR
);
452 PWSTR strValue
= (PWSTR
) CoTaskMemAlloc(bufferLength
);
453 StringCbPrintfW(strValue
, bufferLength
, L
"0x%016llx (%d)",
454 *(LARGE_INTEGER
*) td
, ((LARGE_INTEGER
*) td
)->QuadPart
);
455 *strContents
= strValue
;
460 PCWSTR strTodo
= L
"<TODO: Convert value for display>";
461 DWORD bufferLength
= (wcslen(strTodo
) + 1) * sizeof(WCHAR
);
462 PWSTR strValue
= (PWSTR
) CoTaskMemAlloc(bufferLength
);
463 StringCbCopyW(strValue
, bufferLength
, strTodo
);
464 *strContents
= strValue
;
470 HRESULT
FormatContentsForDisplay(RegPidlEntry
* info
, PCWSTR
* strContents
)
472 PVOID td
= (((PBYTE
) info
) + FIELD_OFFSET(RegPidlEntry
, entryName
) + info
->entryNameLength
+ sizeof(WCHAR
));
474 if (info
->entryType
== REG_ENTRY_VALUE_WITH_CONTENT
)
476 if (info
->contentsLength
> 0)
478 return FormatValueData(info
->contentType
, td
, info
->contentsLength
, strContents
);
481 else if (info
->entryType
== REG_ENTRY_VALUE
)
485 HRESULT hr
= ReadRegistryValue(NULL
, m_ntPath
, info
->entryName
, &valueData
, &valueLength
);
486 if (FAILED_UNEXPECTEDLY(hr
))
488 PCWSTR strEmpty
= L
"(Error reading value)";
489 DWORD bufferLength
= (wcslen(strEmpty
) + 1) * sizeof(WCHAR
);
490 PWSTR strValue
= (PWSTR
) CoTaskMemAlloc(bufferLength
);
491 StringCbCopyW(strValue
, bufferLength
, strEmpty
);
492 *strContents
= strValue
;
498 hr
= FormatValueData(info
->contentType
, valueData
, valueLength
, strContents
);
500 CoTaskMemFree(valueData
);
507 PCWSTR strEmpty
= L
"";
508 DWORD bufferLength
= (wcslen(strEmpty
) + 1) * sizeof(WCHAR
);
509 PWSTR strValue
= (PWSTR
) CoTaskMemAlloc(bufferLength
);
510 StringCbCopyW(strValue
, bufferLength
, strEmpty
);
511 *strContents
= strValue
;
515 PCWSTR strEmpty
= L
"(Empty)";
516 DWORD bufferLength
= (wcslen(strEmpty
) + 1) * sizeof(WCHAR
);
517 PWSTR strValue
= (PWSTR
) CoTaskMemAlloc(bufferLength
);
518 StringCbCopyW(strValue
, bufferLength
, strEmpty
);
519 *strContents
= strValue
;
524 class CRegistryFolderEnum
:
525 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
529 CComPtr
<CRegistryFolder
> m_Folder
;
538 CRegistryFolderEnum() :
546 virtual ~CRegistryFolderEnum()
550 HRESULT
Initialize(CRegistryFolder
* folder
, HWND hwndOwner
, SHCONTF flags
)
554 m_Folder
->GetManager().GetCount(&m_Count
);
556 m_HwndOwner
= hwndOwner
;
562 virtual HRESULT STDMETHODCALLTYPE
Next(
570 if (m_Index
>= m_Count
)
573 for (int i
= 0; i
< (int) celt
;)
575 RegPidlEntry
* tinfo
;
576 BOOL flagsOk
= FALSE
;
579 HRESULT hr
= m_Folder
->GetManager().GetPidl(m_Index
++, &tinfo
);
580 if (FAILED_UNEXPECTEDLY(hr
))
583 switch (tinfo
->entryType
)
587 flagsOk
= (m_Flags
& SHCONTF_FOLDERS
) != 0;
590 flagsOk
= (m_Flags
& SHCONTF_NONFOLDERS
) != 0;
593 } while (m_Index
< m_Count
&& !flagsOk
);
598 rgelt
[i
] = m_Folder
->GetManager().CreatePidlFromItem(tinfo
);
602 if (m_Index
== m_Count
)
606 return (i
== (int) celt
) ? S_OK
: S_FALSE
;
610 if (pceltFetched
) *pceltFetched
= celt
;
614 virtual HRESULT STDMETHODCALLTYPE
Skip(ULONG celt
)
616 return Next(celt
, NULL
, NULL
);
619 virtual HRESULT STDMETHODCALLTYPE
Reset()
625 virtual HRESULT STDMETHODCALLTYPE
Clone(IEnumIDList
**ppenum
)
627 return ShellObjectCreatorInit
<CRegistryFolderEnum
>(m_Folder
, m_HwndOwner
, m_Flags
, IID_PPV_ARG(IEnumIDList
, ppenum
));
630 DECLARE_NOT_AGGREGATABLE(CRegistryFolderEnum
)
631 DECLARE_PROTECT_FINAL_CONSTRUCT()
633 BEGIN_COM_MAP(CRegistryFolderEnum
)
634 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList
, IEnumIDList
)
639 //-----------------------------------------------------------------------------
642 CRegistryFolder::CRegistryFolder() :
648 CRegistryFolder::~CRegistryFolder()
650 TRACE("Destroying CRegistryFolder %p\n", this);
654 HRESULT STDMETHODCALLTYPE
CRegistryFolder::ParseDisplayName(
657 LPOLESTR lpszDisplayName
,
660 ULONG
*pdwAttributes
)
674 TRACE("CRegistryFolder::ParseDisplayName name=%S (ntPath=%S)\n", lpszDisplayName
, m_NtPath
);
676 hr
= m_PidlManager
->FindByName(lpszDisplayName
, &info
);
679 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
682 *ppidl
= m_PidlManager
->CreatePidlFromItem(info
);
685 *pchEaten
= wcslen(info
->entryName
);
688 *pdwAttributes
= m_PidlManager
->ConvertAttributes(info
, pdwAttributes
);
693 HRESULT STDMETHODCALLTYPE
CRegistryFolder::EnumObjects(
696 IEnumIDList
**ppenumIDList
)
698 return ShellObjectCreatorInit
<CRegistryFolderEnum
>(this, hwndOwner
, grfFlags
, IID_PPV_ARG(IEnumIDList
, ppenumIDList
));
701 HRESULT STDMETHODCALLTYPE
CRegistryFolder::BindToObject(
710 if (IsEqualIID(riid
, IID_IShellFolder
))
712 hr
= m_PidlManager
->FindPidlInList(pidl
, &info
);
713 if (FAILED_UNEXPECTEDLY(hr
))
716 LPITEMIDLIST first
= ILCloneFirst(pidl
);
717 LPCITEMIDLIST rest
= ILGetNext(pidl
);
719 LPITEMIDLIST fullPidl
= ILCombine(m_shellPidl
, first
);
721 CComPtr
<IShellFolder
> psfChild
;
722 if (wcslen(m_NtPath
) == 0 && m_hRoot
== NULL
)
724 hr
= ShellObjectCreatorInit
<CRegistryFolder
>(fullPidl
, L
"", info
->rootKey
, IID_PPV_ARG(IShellFolder
, &psfChild
));
728 WCHAR path
[MAX_PATH
];
730 StringCbCopyW(path
, _countof(path
), m_NtPath
);
732 PathAppendW(path
, info
->entryName
);
734 hr
= ShellObjectCreatorInit
<CRegistryFolder
>(fullPidl
, path
, m_hRoot
, IID_PPV_ARG(IShellFolder
, &psfChild
));
740 if (rest
->mkid
.cb
> 0)
742 return psfChild
->BindToObject(rest
, pbcReserved
, riid
, ppvOut
);
745 return psfChild
->QueryInterface(riid
, ppvOut
);
751 HRESULT STDMETHODCALLTYPE
CRegistryFolder::BindToStorage(
761 HRESULT STDMETHODCALLTYPE
CRegistryFolder::CompareIDs(
766 TRACE("CompareIDs\n");
768 HRESULT hr
= m_PidlManager
->CompareIDs(lParam
, pidl1
, pidl2
);
772 LPCITEMIDLIST rest1
= ILGetNext(pidl1
);
773 LPCITEMIDLIST rest2
= ILGetNext(pidl2
);
775 bool hasNext1
= (rest1
->mkid
.cb
> 0);
776 bool hasNext2
= (rest2
->mkid
.cb
> 0);
778 if (hasNext1
|| hasNext2
)
780 if (hasNext1
&& !hasNext2
)
781 return MAKE_HRESULT(0, 0, (USHORT
) -1);
783 if (hasNext2
&& !hasNext1
)
784 return MAKE_HRESULT(0, 0, (USHORT
) 1);
786 LPCITEMIDLIST first1
= ILCloneFirst(pidl1
);
788 CComPtr
<IShellFolder
> psfNext
;
789 hr
= BindToObject(first1
, NULL
, IID_PPV_ARG(IShellFolder
, &psfNext
));
790 if (FAILED_UNEXPECTEDLY(hr
))
793 return psfNext
->CompareIDs(lParam
, rest1
, rest2
);
799 HRESULT STDMETHODCALLTYPE
CRegistryFolder::CreateViewObject(
804 if (!IsEqualIID(riid
, IID_IShellView
))
805 return E_NOINTERFACE
;
808 sfv
.cbSize
= sizeof(sfv
);
813 return SHCreateShellFolderView(&sfv
, (IShellView
**) ppvOut
);
816 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetAttributesOf(
818 PCUITEMID_CHILD_ARRAY apidl
,
824 TRACE("GetAttributesOf\n");
828 *rgfInOut
&= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
| SFGAO_BROWSABLE
;
832 for (int i
= 0; i
< (int) cidl
; i
++)
834 PCUITEMID_CHILD pidl
= apidl
[i
];
836 hr
= m_PidlManager
->FindPidlInList(pidl
, &info
);
837 if (FAILED_UNEXPECTEDLY(hr
))
840 // Update attributes.
841 *rgfInOut
= m_PidlManager
->ConvertAttributes(info
, rgfInOut
);
847 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetUIObjectOf(
850 PCUITEMID_CHILD_ARRAY apidl
,
855 TRACE("GetUIObjectOf\n");
857 if (IsEqualIID(riid
, IID_IContextMenu
) ||
858 IsEqualIID(riid
, IID_IContextMenu2
) ||
859 IsEqualIID(riid
, IID_IContextMenu3
))
861 CComPtr
<IContextMenu
> pcm
;
865 int nkeys
= _countof(keys
);
866 if (cidl
== 1 && m_PidlManager
->IsFolder(apidl
[0]))
868 RegOpenKey(HKEY_CLASSES_ROOT
, L
"Folder", keys
+ 0);
875 HRESULT hr
= CDefFolderMenu_Create2(m_shellPidl
, hwndOwner
, cidl
, apidl
, this, DefCtxMenuCallback
, nkeys
, keys
, &pcm
);
876 if (FAILED_UNEXPECTEDLY(hr
))
879 return pcm
->QueryInterface(riid
, ppvOut
);
882 if (IsEqualIID(riid
, IID_IExtractIconW
))
884 return ShellObjectCreatorInit
<CRegistryFolderExtractIcon
>(m_shellPidl
, cidl
, apidl
, riid
, ppvOut
);
887 if (IsEqualIID(riid
, IID_IDataObject
))
889 return CIDLData_CreateFromIDArray(m_shellPidl
, cidl
, apidl
, (IDataObject
**) ppvOut
);
892 if (IsEqualIID(riid
, IID_IQueryAssociations
))
894 if (cidl
== 1 && m_PidlManager
->IsFolder(apidl
[0]))
896 CComPtr
<IQueryAssociations
> pqa
;
897 HRESULT hr
= AssocCreate(CLSID_QueryAssociations
, IID_PPV_ARG(IQueryAssociations
, &pqa
));
898 if (FAILED_UNEXPECTEDLY(hr
))
901 hr
= pqa
->Init(ASSOCF_INIT_DEFAULTTOFOLDER
, L
"NTObjShEx.RegFolder", NULL
, hwndOwner
);
902 if (FAILED_UNEXPECTEDLY(hr
))
905 return pqa
->QueryInterface(riid
, ppvOut
);
912 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetDisplayNameOf(
920 TRACE("GetDisplayNameOf %p\n", pidl
);
922 hr
= m_PidlManager
->FindPidlInList(pidl
, &info
);
923 if (FAILED_UNEXPECTEDLY(hr
))
926 if ((GET_SHGDN_RELATION(uFlags
) == SHGDN_NORMAL
) &&
927 (GET_SHGDN_FOR(uFlags
) & SHGDN_FORPARSING
))
929 WCHAR path
[MAX_PATH
] = { 0 };
931 hr
= GetFullName(m_shellPidl
, uFlags
, path
, _countof(path
));
932 if (FAILED_UNEXPECTEDLY(hr
))
935 PathAppendW(path
, info
->entryName
);
937 hr
= MakeStrRetFromString(path
, lpName
);
938 if (FAILED_UNEXPECTEDLY(hr
))
941 LPCITEMIDLIST pidlFirst
= ILCloneFirst(pidl
);
942 LPCITEMIDLIST pidlNext
= ILGetNext(pidl
);
944 if (pidlNext
&& pidlNext
->mkid
.cb
> 0)
946 CComPtr
<IShellFolder
> psfChild
;
947 hr
= BindToObject(pidlFirst
, NULL
, IID_PPV_ARG(IShellFolder
, &psfChild
));
948 if (FAILED_UNEXPECTEDLY(hr
))
951 WCHAR temp
[MAX_PATH
];
954 hr
= psfChild
->GetDisplayNameOf(pidlNext
, uFlags
| SHGDN_INFOLDER
, &childName
);
955 if (FAILED_UNEXPECTEDLY(hr
))
958 hr
= StrRetToBufW(&childName
, pidlNext
, temp
, _countof(temp
));
959 if (FAILED_UNEXPECTEDLY(hr
))
962 PathAppendW(path
, temp
);
965 ILFree((LPITEMIDLIST
) pidlFirst
);
969 MakeStrRetFromString(info
->entryName
, info
->entryNameLength
, lpName
);
975 HRESULT STDMETHODCALLTYPE
CRegistryFolder::SetNameOf(
980 LPITEMIDLIST
*ppidlOut
)
987 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetClassID(CLSID
*lpClassId
)
992 *lpClassId
= CLSID_RegistryFolder
;
997 HRESULT STDMETHODCALLTYPE
CRegistryFolder::Initialize(LPCITEMIDLIST pidl
)
999 m_shellPidl
= ILClone(pidl
);
1002 PCWSTR ntPath
= L
"";
1006 m_PidlManager
= new CRegistryPidlManager();
1008 StringCbCopy(m_NtPath
, _countof(m_NtPath
), ntPath
);
1011 return m_PidlManager
->Initialize(m_NtPath
, m_hRoot
);
1015 HRESULT STDMETHODCALLTYPE
CRegistryFolder::Initialize(LPCITEMIDLIST pidl
, PCWSTR ntPath
, HKEY hRoot
)
1017 m_shellPidl
= ILClone(pidl
);
1021 m_PidlManager
= new CRegistryPidlManager();
1023 StringCbCopy(m_NtPath
, _countof(m_NtPath
), ntPath
);
1024 return m_PidlManager
->Initialize(m_NtPath
, m_hRoot
);
1028 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetCurFolder(LPITEMIDLIST
* pidl
)
1031 *pidl
= ILClone(m_shellPidl
);
1038 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetDefaultSearchGUID(
1045 HRESULT STDMETHODCALLTYPE
CRegistryFolder::EnumSearches(
1046 IEnumExtraSearch
**ppenum
)
1052 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetDefaultColumn(
1064 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetDefaultColumnState(
1066 SHCOLSTATEF
*pcsFlags
)
1070 case REGISTRY_COLUMN_NAME
:
1071 *pcsFlags
= SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
;
1073 case REGISTRY_COLUMN_TYPE
:
1074 *pcsFlags
= SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
;
1076 case REGISTRY_COLUMN_VALUE
:
1077 *pcsFlags
= SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
| SHCOLSTATE_SLOW
;
1081 return E_INVALIDARG
;
1084 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetDetailsEx(
1086 const SHCOLUMNID
*pscid
,
1089 RegPidlEntry
* info
;
1092 TRACE("GetDetailsEx\n");
1096 hr
= m_PidlManager
->FindPidlInList(pidl
, &info
);
1097 if (FAILED_UNEXPECTEDLY(hr
))
1100 static const GUID storage
= PSGUID_STORAGE
;
1101 if (IsEqualGUID(pscid
->fmtid
, storage
))
1103 if (pscid
->pid
== PID_STG_NAME
)
1105 if (info
->entryNameLength
> 0)
1107 return MakeVariantString(pv
, info
->entryName
);
1109 return MakeVariantString(pv
, L
"(Default)");
1111 else if (pscid
->pid
== PID_STG_STORAGETYPE
)
1113 if (info
->entryType
== REG_ENTRY_ROOT
)
1115 return MakeVariantString(pv
, L
"Key");
1118 if (info
->entryType
== REG_ENTRY_KEY
)
1120 if (info
->contentsLength
> 0)
1122 PWSTR td
= (PWSTR
)(((PBYTE
) info
) + FIELD_OFFSET(RegPidlEntry
, entryName
) + info
->entryNameLength
+ sizeof(WCHAR
));
1124 return MakeVariantString(pv
, td
);
1126 return MakeVariantString(pv
, L
"Key");
1129 return MakeVariantString(pv
, RegistryTypeNames
[info
->contentType
]);
1131 else if (pscid
->pid
== PID_STG_CONTENTS
)
1133 PCWSTR strValueContents
;
1135 hr
= m_PidlManager
->FormatContentsForDisplay(info
, &strValueContents
);
1136 if (FAILED_UNEXPECTEDLY(hr
))
1141 V_VT(pv
) = VT_EMPTY
;
1145 hr
= MakeVariantString(pv
, strValueContents
);
1147 CoTaskMemFree((PVOID
) strValueContents
);
1155 return E_INVALIDARG
;
1158 HRESULT STDMETHODCALLTYPE
CRegistryFolder::GetDetailsOf(
1163 RegPidlEntry
* info
;
1166 TRACE("GetDetailsOf\n");
1170 hr
= m_PidlManager
->FindPidlInList(pidl
, &info
);
1171 if (FAILED_UNEXPECTEDLY(hr
))
1176 case REGISTRY_COLUMN_NAME
:
1177 psd
->fmt
= LVCFMT_LEFT
;
1179 if (info
->entryNameLength
> 0)
1181 return MakeStrRetFromString(info
->entryName
, info
->entryNameLength
, &(psd
->str
));
1183 return MakeStrRetFromString(L
"(Default)", &(psd
->str
));
1185 case REGISTRY_COLUMN_TYPE
:
1186 psd
->fmt
= LVCFMT_LEFT
;
1188 if (info
->entryType
== REG_ENTRY_ROOT
)
1190 return MakeStrRetFromString(L
"Key", &(psd
->str
));
1193 if (info
->entryType
== REG_ENTRY_KEY
)
1195 if (info
->contentsLength
> 0)
1197 PWSTR td
= (PWSTR
) (((PBYTE
) info
) + FIELD_OFFSET(RegPidlEntry
, entryName
) + info
->entryNameLength
+ sizeof(WCHAR
));
1199 return MakeStrRetFromString(td
, info
->contentsLength
, &(psd
->str
));
1202 return MakeStrRetFromString(L
"Key", &(psd
->str
));
1205 return MakeStrRetFromString(RegistryTypeNames
[info
->entryType
], &(psd
->str
));
1207 case REGISTRY_COLUMN_VALUE
:
1208 psd
->fmt
= LVCFMT_LEFT
;
1210 PCWSTR strValueContents
;
1212 hr
= m_PidlManager
->FormatContentsForDisplay(info
, &strValueContents
);
1213 if (FAILED_UNEXPECTEDLY(hr
))
1218 return MakeStrRetFromString(L
"(Empty)", &(psd
->str
));
1221 hr
= MakeStrRetFromString(strValueContents
, &(psd
->str
));
1223 CoTaskMemFree((PVOID
) strValueContents
);
1232 case REGISTRY_COLUMN_NAME
:
1233 psd
->fmt
= LVCFMT_LEFT
;
1236 // TODO: Make localizable
1237 MakeStrRetFromString(L
"Object Name", &(psd
->str
));
1239 case REGISTRY_COLUMN_TYPE
:
1240 psd
->fmt
= LVCFMT_LEFT
;
1243 // TODO: Make localizable
1244 MakeStrRetFromString(L
"Content Type", &(psd
->str
));
1246 case REGISTRY_COLUMN_VALUE
:
1247 psd
->fmt
= LVCFMT_LEFT
;
1250 // TODO: Make localizable
1251 MakeStrRetFromString(L
"Value", &(psd
->str
));
1256 return E_INVALIDARG
;
1259 HRESULT STDMETHODCALLTYPE
CRegistryFolder::MapColumnToSCID(
1263 static const GUID storage
= PSGUID_STORAGE
;
1266 case REGISTRY_COLUMN_NAME
:
1267 pscid
->fmtid
= storage
;
1268 pscid
->pid
= PID_STG_NAME
;
1270 case REGISTRY_COLUMN_TYPE
:
1271 pscid
->fmtid
= storage
;
1272 pscid
->pid
= PID_STG_STORAGETYPE
;
1274 case REGISTRY_COLUMN_VALUE
:
1275 pscid
->fmtid
= storage
;
1276 pscid
->pid
= PID_STG_CONTENTS
;
1279 return E_INVALIDARG
;
1282 HRESULT STDMETHODCALLTYPE
CRegistryFolder::MessageSFVCB(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1286 case SFVM_DEFVIEWMODE
:
1288 FOLDERVIEWMODE
* pViewMode
= (FOLDERVIEWMODE
*) lParam
;
1289 *pViewMode
= FVM_DETAILS
;
1292 case SFVM_COLUMNCLICK
:
1294 case SFVM_BACKGROUNDENUM
:
1296 case SFVM_DEFITEMCOUNT
:
1297 return m_PidlManager
->GetCount((UINT
*) lParam
);
1302 HRESULT
CRegistryFolder::DefCtxMenuCallback(IShellFolder
* /*psf*/, HWND
/*hwnd*/, IDataObject
* /*pdtobj*/, UINT uMsg
, WPARAM
/*wParam*/, LPARAM
/*lParam*/)
1306 case DFM_MERGECONTEXTMENU
:
1308 case DFM_INVOKECOMMAND
:
1309 case DFM_INVOKECOMMANDEX
:
1310 case DFM_GETDEFSTATICID
: // Required for Windows 7 to pick a default