2 * PROJECT: ReactOS shell extensions
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/shellext/ntobjshex/ntobjfolder.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 // {845B0FB2-66E0-416B-8F91-314E23F7C12D}
28 const GUID CLSID_NtObjectFolder
= { 0x845b0fb2, 0x66e0, 0x416b, { 0x8f, 0x91, 0x31, 0x4e, 0x23, 0xf7, 0xc1, 0x2d } };
30 // {F4C430C3-3A8D-4B56-A018-E598DA60C2E0}
31 static const GUID GUID_NtObjectColumns
= { 0xf4c430c3, 0x3a8d, 0x4b56, { 0xa0, 0x18, 0xe5, 0x98, 0xda, 0x60, 0xc2, 0xe0 } };
35 NTOBJECT_COLUMN_NAME
= 0,
37 NTOBJECT_COLUMN_LINKTARGET
,
41 class CNtObjectFolderExtractIcon
:
42 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
45 PCITEMID_CHILD m_pcidlChild
;
49 CNtObjectFolderExtractIcon() :
50 m_pcidlChild(NULL
), m_NtPath(NULL
)
55 virtual ~CNtObjectFolderExtractIcon()
58 ILFree((LPITEMIDLIST
) m_pcidlChild
);
61 HRESULT
Initialize(LPCWSTR ntPath
, UINT cidl
, PCUITEMID_CHILD_ARRAY apidl
)
66 m_pcidlChild
= ILClone(apidl
[0]);
70 virtual HRESULT STDMETHODCALLTYPE
GetIconLocation(
77 const NtPidlEntry
* entry
= (NtPidlEntry
*) m_pcidlChild
;
79 if ((entry
->cb
< sizeof(NtPidlEntry
)) || (entry
->magic
!= NT_OBJECT_PIDL_MAGIC
))
84 switch (entry
->objectType
)
86 case DIRECTORY_OBJECT
:
87 case SYMBOLICLINK_OBJECT
:
88 GetModuleFileNameW(g_hInstance
, szIconFile
, cchMax
);
89 *piIndex
= -((uFlags
& GIL_OPENICON
) ? IDI_NTOBJECTDIROPEN
: IDI_NTOBJECTDIR
);
93 GetModuleFileNameW(g_hInstance
, szIconFile
, cchMax
);
94 *piIndex
= -IDI_NTOBJECTDEVICE
;
98 GetModuleFileNameW(g_hInstance
, szIconFile
, cchMax
);
99 *piIndex
= -IDI_NTOBJECTPORT
;
103 GetModuleFileNameW(g_hInstance
, szIconFile
, cchMax
);
104 *piIndex
= -IDI_REGISTRYKEY
;
108 GetModuleFileNameW(g_hInstance
, szIconFile
, cchMax
);
109 *piIndex
= -IDI_NTOBJECTITEM
;
115 virtual HRESULT STDMETHODCALLTYPE
Extract(
122 return SHDefExtractIconW(pszFile
, nIconIndex
, 0, phiconLarge
, phiconSmall
, nIconSize
);
125 DECLARE_NOT_AGGREGATABLE(CNtObjectFolderExtractIcon
)
126 DECLARE_PROTECT_FINAL_CONSTRUCT()
128 BEGIN_COM_MAP(CNtObjectFolderExtractIcon
)
129 COM_INTERFACE_ENTRY_IID(IID_IExtractIconW
, IExtractIconW
)
134 class CNtObjectPidlHelper
137 static HRESULT
CompareIDs(LPARAM lParam
, const NtPidlEntry
* first
, const NtPidlEntry
* second
)
139 if ((lParam
& 0xFFFF0000) == SHCIDS_ALLFIELDS
)
144 int minsize
= min(first
->cb
, second
->cb
);
145 int ord
= memcmp(second
, first
, minsize
);
148 return MAKE_HRESULT(0, 0, (USHORT
) ord
);
150 if (second
->cb
> first
->cb
)
151 return MAKE_HRESULT(0, 0, (USHORT
) 1);
152 if (second
->cb
< first
->cb
)
153 return MAKE_HRESULT(0, 0, (USHORT
) -1);
157 bool canonical
= ((lParam
& 0xFFFF0000) == SHCIDS_CANONICALONLY
);
159 switch (lParam
& 0xFFFF)
161 case NTOBJECT_COLUMN_NAME
:
163 bool f1
= (first
->objectType
== KEY_OBJECT
) || (first
->objectType
== DIRECTORY_OBJECT
);
164 bool f2
= (second
->objectType
== KEY_OBJECT
) || (second
->objectType
== DIRECTORY_OBJECT
);
167 return MAKE_HRESULT(0, 0, (USHORT
) -1);
169 return MAKE_HRESULT(0, 0, (USHORT
) 1);
173 // Shortcut: avoid comparing contents if not necessary when the results are not for display.
174 if (second
->entryNameLength
> first
->entryNameLength
)
175 return MAKE_HRESULT(0, 0, (USHORT
) 1);
176 if (second
->entryNameLength
< first
->entryNameLength
)
177 return MAKE_HRESULT(0, 0, (USHORT
) -1);
179 int minlength
= min(first
->entryNameLength
, second
->entryNameLength
);
182 int ord
= memcmp(first
->entryName
, second
->entryName
, minlength
);
184 return MAKE_HRESULT(0, 0, (USHORT
) ord
);
190 int minlength
= min(first
->entryNameLength
, second
->entryNameLength
);
193 int ord
= StrCmpNW(first
->entryName
, second
->entryName
, minlength
/ sizeof(WCHAR
));
195 return MAKE_HRESULT(0, 0, (USHORT
) ord
);
198 if (second
->entryNameLength
> first
->entryNameLength
)
199 return MAKE_HRESULT(0, 0, (USHORT
) 1);
200 if (second
->entryNameLength
< first
->entryNameLength
)
201 return MAKE_HRESULT(0, 0, (USHORT
) -1);
206 case NTOBJECT_COLUMN_TYPE
:
208 int ord
= second
->objectType
- first
->objectType
;
210 return MAKE_HRESULT(0, 0, (USHORT
) 1);
212 return MAKE_HRESULT(0, 0, (USHORT
) -1);
216 case NTOBJECT_COLUMN_LINKTARGET
:
218 // Can't sort by value
223 DbgPrint("Unsupported sorting mode.\n");
232 static HRESULT
CompareIDs(LPARAM lParam
, const NtPidlEntry
* first
, LPCITEMIDLIST pcidl
)
234 LPCITEMIDLIST p
= pcidl
;
235 NtPidlEntry
* second
= (NtPidlEntry
*) &(p
->mkid
);
236 if ((second
->cb
< sizeof(NtPidlEntry
)) || (second
->magic
!= NT_OBJECT_PIDL_MAGIC
))
239 return CompareIDs(lParam
, first
, second
);
242 static HRESULT
CompareIDs(LPARAM lParam
, LPCITEMIDLIST pcidl1
, LPCITEMIDLIST pcidl2
)
244 LPCITEMIDLIST p
= pcidl1
;
245 NtPidlEntry
* first
= (NtPidlEntry
*) &(p
->mkid
);
246 if ((first
->cb
< sizeof(NtPidlEntry
)) || (first
->magic
!= NT_OBJECT_PIDL_MAGIC
))
249 return CompareIDs(lParam
, first
, pcidl2
);
252 static ULONG
ConvertAttributes(const NtPidlEntry
* entry
, PULONG inMask
)
254 ULONG mask
= inMask
? *inMask
: 0xFFFFFFFF;
255 ULONG flags
= SFGAO_HASPROPSHEET
| SFGAO_CANLINK
;
257 if (entry
->objectType
== DIRECTORY_OBJECT
)
258 flags
|= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
| SFGAO_BROWSABLE
;
260 if (entry
->objectType
== SYMBOLICLINK_OBJECT
)
261 flags
|= SFGAO_LINK
| SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
| SFGAO_BROWSABLE
;
263 if (entry
->objectType
== KEY_OBJECT
)
264 flags
|= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
| SFGAO_BROWSABLE
;
269 static BOOL
IsFolder(LPCITEMIDLIST pcidl
)
271 NtPidlEntry
* entry
= (NtPidlEntry
*) &(pcidl
->mkid
);
272 if ((entry
->cb
< sizeof(NtPidlEntry
)) || (entry
->magic
!= NT_OBJECT_PIDL_MAGIC
))
275 return (entry
->objectType
== DIRECTORY_OBJECT
) ||
276 (entry
->objectType
== SYMBOLICLINK_OBJECT
) ||
277 (entry
->objectType
== KEY_OBJECT
);
280 static HRESULT
GetInfoFromPidl(LPCITEMIDLIST pcidl
, const NtPidlEntry
** pentry
)
282 NtPidlEntry
* entry
= (NtPidlEntry
*) &(pcidl
->mkid
);
284 if (entry
->cb
< sizeof(NtPidlEntry
))
286 DbgPrint("PCIDL too small %l (required %l)\n", entry
->cb
, sizeof(NtPidlEntry
));
290 if (entry
->magic
!= NT_OBJECT_PIDL_MAGIC
)
292 DbgPrint("PCIDL magic mismatch %04x (expected %04x)\n", entry
->magic
, NT_OBJECT_PIDL_MAGIC
);
301 //-----------------------------------------------------------------------------
304 CNtObjectFolder::CNtObjectFolder() :
309 CNtObjectFolder::~CNtObjectFolder()
316 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::ParseDisplayName(
319 LPOLESTR lpszDisplayName
,
322 ULONG
*pdwAttributes
)
333 TRACE("CNtObjectFolder::ParseDisplayName name=%S (ntPath=%S)\n", lpszDisplayName
, m_NtPath
);
335 const NtPidlEntry
* info
;
337 HRESULT hr
= GetEnumNTDirectory(m_NtPath
, &it
);
341 PWSTR end
= StrChrW(lpszDisplayName
, '\\');
342 int length
= end
? end
- lpszDisplayName
: wcslen(lpszDisplayName
);
346 hr
= it
->Next(1, ppidl
, NULL
);
352 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
354 hr
= CNtObjectPidlHelper::GetInfoFromPidl(*ppidl
, &info
);
355 if (FAILED_UNEXPECTEDLY(hr
))
358 if (StrCmpNW(info
->entryName
, lpszDisplayName
, length
) == 0)
362 // if has remaining path to parse (and the path didn't just terminate in a backslash)
363 if (end
&& wcslen(end
) > 1)
365 CComPtr
<IShellFolder
> psfChild
;
366 hr
= BindToObject(*ppidl
, pbcReserved
, IID_PPV_ARG(IShellFolder
, &psfChild
));
367 if (FAILED_UNEXPECTEDLY(hr
))
371 hr
= psfChild
->ParseDisplayName(hwndOwner
, pbcReserved
, end
+ 1, pchEaten
, &child
, pdwAttributes
);
375 LPITEMIDLIST old
= *ppidl
;
376 *ppidl
= ILCombine(old
, child
);
379 // Count the path separator
386 *pdwAttributes
= CNtObjectPidlHelper::ConvertAttributes(info
, pdwAttributes
);
390 *pchEaten
+= wcslen(info
->entryName
);
395 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::EnumObjects(
398 IEnumIDList
**ppenumIDList
)
400 return GetEnumNTDirectory(m_NtPath
, ppenumIDList
);
403 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::BindToObject(
409 const NtPidlEntry
* info
;
411 if (IsEqualIID(riid
, IID_IShellFolder
))
413 HRESULT hr
= CNtObjectPidlHelper::GetInfoFromPidl(pidl
, &info
);
414 if (FAILED_UNEXPECTEDLY(hr
))
417 WCHAR path
[MAX_PATH
];
419 StringCbCopyW(path
, _countof(path
), m_NtPath
);
420 PathAppendW(path
, info
->entryName
);
422 LPITEMIDLIST first
= ILCloneFirst(pidl
);
423 LPCITEMIDLIST rest
= ILGetNext(pidl
);
425 LPITEMIDLIST fullPidl
= ILCombine(m_shellPidl
, first
);
427 if (info
->objectType
== SYMBOLICLINK_OBJECT
)
429 WCHAR wbLink
[MAX_PATH
] = { 0 };
431 RtlInitEmptyUnicodeString(&link
, wbLink
, sizeof(wbLink
));
433 hr
= GetNTObjectSymbolicLinkTarget(m_NtPath
, info
->entryName
, &link
);
434 if (FAILED_UNEXPECTEDLY(hr
))
439 if (link
.Buffer
[1] == L
':' && isalphaW(link
.Buffer
[0]))
441 CComPtr
<IShellFolder
> psfDesktop
;
442 hr
= SHGetDesktopFolder(&psfDesktop
);
443 if (FAILED_UNEXPECTEDLY(hr
))
446 hr
= psfDesktop
->ParseDisplayName(NULL
, NULL
, path
, NULL
, &first
, NULL
);
447 if (FAILED_UNEXPECTEDLY(hr
))
450 return psfDesktop
->BindToObject(rest
, pbcReserved
, riid
, ppvOut
);
453 StringCbCopyW(path
, _countof(path
), L
"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{845B0FB2-66E0-416B-8F91-314E23F7C12D}");
454 PathAppend(path
, link
.Buffer
);
456 CComPtr
<IShellFolder
> psfDesktop
;
457 hr
= SHGetDesktopFolder(&psfDesktop
);
458 if (FAILED_UNEXPECTEDLY(hr
))
463 hr
= psfDesktop
->ParseDisplayName(NULL
, NULL
, path
, NULL
, &pidl
, NULL
);
464 if (FAILED_UNEXPECTEDLY(hr
))
467 CComPtr
<IShellFolder
> psfChild
;
468 hr
= psfDesktop
->BindToObject(pidl
, NULL
, riid
, ppvOut
);
479 CComPtr
<IShellFolder
> psfChild
;
481 if (info
->objectType
== KEY_OBJECT
)
483 hr
= ShellObjectCreatorInit
<CRegistryFolder
>(fullPidl
, path
, (HKEY
) NULL
, IID_PPV_ARG(IShellFolder
, &psfChild
));
487 hr
= ShellObjectCreatorInit
<CNtObjectFolder
>(fullPidl
, path
, IID_PPV_ARG(IShellFolder
, &psfChild
));
493 if (rest
->mkid
.cb
> 0)
495 return psfChild
->BindToObject(rest
, pbcReserved
, riid
, ppvOut
);
498 return psfChild
->QueryInterface(riid
, ppvOut
);
504 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::BindToStorage(
514 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::CompareIDs(
519 TRACE("CompareIDs\n");
521 HRESULT hr
= CNtObjectPidlHelper::CompareIDs(lParam
, pidl1
, pidl2
);
525 LPCITEMIDLIST rest1
= ILGetNext(pidl1
);
526 LPCITEMIDLIST rest2
= ILGetNext(pidl2
);
528 bool hasNext1
= (rest1
->mkid
.cb
> 0);
529 bool hasNext2
= (rest2
->mkid
.cb
> 0);
531 if (hasNext1
|| hasNext2
)
533 if (hasNext1
&& !hasNext2
)
534 return MAKE_HRESULT(0, 0, (USHORT
) -1);
536 if (hasNext2
&& !hasNext1
)
537 return MAKE_HRESULT(0, 0, (USHORT
) 1);
539 LPCITEMIDLIST first1
= ILCloneFirst(pidl1
);
541 CComPtr
<IShellFolder
> psfNext
;
542 hr
= BindToObject(first1
, NULL
, IID_PPV_ARG(IShellFolder
, &psfNext
));
543 if (FAILED_UNEXPECTEDLY(hr
))
546 return psfNext
->CompareIDs(lParam
, rest1
, rest2
);
552 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::CreateViewObject(
557 if (!IsEqualIID(riid
, IID_IShellView
))
558 return E_NOINTERFACE
;
561 sfv
.cbSize
= sizeof(sfv
);
562 sfv
.pshf
= static_cast<IShellFolder
*>(this);
564 sfv
.psfvcb
= static_cast<IShellFolderViewCB
*>(this);
566 return SHCreateShellFolderView(&sfv
, (IShellView
**) ppvOut
);
569 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::GetAttributesOf(
571 PCUITEMID_CHILD_ARRAY apidl
,
574 const NtPidlEntry
* info
;
576 TRACE("GetAttributesOf %d\n", cidl
);
580 *rgfInOut
&= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
| SFGAO_BROWSABLE
;
584 for (int i
= 0; i
< (int) cidl
; i
++)
586 PCUITEMID_CHILD pidl
= apidl
[i
];
588 HRESULT hr
= CNtObjectPidlHelper::GetInfoFromPidl(pidl
, &info
);
589 if (FAILED_UNEXPECTEDLY(hr
))
592 // Update attributes.
593 *rgfInOut
= CNtObjectPidlHelper::ConvertAttributes(info
, rgfInOut
);
599 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::GetUIObjectOf(
602 PCUITEMID_CHILD_ARRAY apidl
,
608 TRACE("GetUIObjectOf\n");
610 if (IsEqualIID(riid
, IID_IContextMenu
) ||
611 IsEqualIID(riid
, IID_IContextMenu2
) ||
612 IsEqualIID(riid
, IID_IContextMenu3
))
614 CComPtr
<IContextMenu
> pcm
;
618 int nkeys
= _countof(keys
);
619 if (cidl
== 1 && CNtObjectPidlHelper::IsFolder(apidl
[0]))
621 res
= RegOpenKey(HKEY_CLASSES_ROOT
, L
"Folder", keys
+ 0);
622 if (!NT_SUCCESS(res
))
623 return HRESULT_FROM_NT(res
);
630 HRESULT hr
= CDefFolderMenu_Create2(m_shellPidl
, hwndOwner
, cidl
, apidl
, this, DefCtxMenuCallback
, nkeys
, keys
, &pcm
);
631 if (FAILED_UNEXPECTEDLY(hr
))
634 return pcm
->QueryInterface(riid
, ppvOut
);
637 if (IsEqualIID(riid
, IID_IExtractIconW
))
639 return ShellObjectCreatorInit
<CNtObjectFolderExtractIcon
>(m_NtPath
, cidl
, apidl
, riid
, ppvOut
);
642 if (IsEqualIID(riid
, IID_IDataObject
))
644 return CIDLData_CreateFromIDArray(m_shellPidl
, cidl
, apidl
, (IDataObject
**) ppvOut
);
647 if (IsEqualIID(riid
, IID_IQueryAssociations
))
649 if (cidl
== 1 && CNtObjectPidlHelper::IsFolder(apidl
[0]))
651 CComPtr
<IQueryAssociations
> pqa
;
652 HRESULT hr
= AssocCreate(CLSID_QueryAssociations
, IID_PPV_ARG(IQueryAssociations
, &pqa
));
653 if (FAILED_UNEXPECTEDLY(hr
))
656 hr
= pqa
->Init(ASSOCF_INIT_DEFAULTTOFOLDER
, L
"NTObjShEx.NTDirectory", NULL
, hwndOwner
);
657 if (FAILED_UNEXPECTEDLY(hr
))
660 return pqa
->QueryInterface(riid
, ppvOut
);
667 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::GetDisplayNameOf(
672 const NtPidlEntry
* info
;
674 TRACE("GetDisplayNameOf %p\n", pidl
);
676 HRESULT hr
= CNtObjectPidlHelper::GetInfoFromPidl(pidl
, &info
);
677 if (FAILED_UNEXPECTEDLY(hr
))
680 if (GET_SHGDN_FOR(uFlags
) & SHGDN_FOREDITING
)
682 hr
= MakeStrRetFromString(info
->entryName
, info
->entryNameLength
, lpName
);
683 if (FAILED_UNEXPECTEDLY(hr
))
687 WCHAR path
[MAX_PATH
] = { 0 };
689 if (GET_SHGDN_FOR(uFlags
) & SHGDN_FORPARSING
)
691 if (GET_SHGDN_RELATION(uFlags
) != SHGDN_INFOLDER
)
693 hr
= GetFullName(m_shellPidl
, uFlags
, path
, _countof(path
));
694 if (FAILED_UNEXPECTEDLY(hr
))
699 PathAppendW(path
, info
->entryName
);
701 LPCITEMIDLIST pidlNext
= ILGetNext(pidl
);
702 if (pidlNext
&& pidlNext
->mkid
.cb
> 0)
704 LPITEMIDLIST pidlFirst
= ILCloneFirst(pidl
);
706 CComPtr
<IShellFolder
> psfChild
;
707 hr
= BindToObject(pidlFirst
, NULL
, IID_PPV_ARG(IShellFolder
, &psfChild
));
708 if (FAILED_UNEXPECTEDLY(hr
))
711 WCHAR temp
[MAX_PATH
];
714 hr
= psfChild
->GetDisplayNameOf(pidlNext
, uFlags
| SHGDN_INFOLDER
, &childName
);
715 if (FAILED_UNEXPECTEDLY(hr
))
718 hr
= StrRetToBufW(&childName
, pidlNext
, temp
, _countof(temp
));
719 if (FAILED_UNEXPECTEDLY(hr
))
722 PathAppendW(path
, temp
);
727 hr
= MakeStrRetFromString(path
, lpName
);
728 if (FAILED_UNEXPECTEDLY(hr
))
734 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::SetNameOf(
739 LPITEMIDLIST
*ppidlOut
)
746 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::GetClassID(CLSID
*lpClassId
)
751 *lpClassId
= CLSID_NtObjectFolder
;
756 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::Initialize(LPCITEMIDLIST pidl
)
758 m_shellPidl
= ILClone(pidl
);
760 StringCbCopy(m_NtPath
, _countof(m_NtPath
), L
"\\");
766 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::Initialize(LPCITEMIDLIST pidl
, PCWSTR ntPath
)
768 m_shellPidl
= ILClone(pidl
);
770 StringCbCopy(m_NtPath
, _countof(m_NtPath
), ntPath
);
776 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::GetCurFolder(LPITEMIDLIST
* pidl
)
779 *pidl
= ILClone(m_shellPidl
);
786 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::GetDefaultSearchGUID(
793 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::EnumSearches(
794 IEnumExtraSearch
**ppenum
)
800 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::GetDefaultColumn(
812 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::GetDefaultColumnState(
814 SHCOLSTATEF
*pcsFlags
)
818 case NTOBJECT_COLUMN_NAME
:
819 *pcsFlags
= SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
;
821 case NTOBJECT_COLUMN_TYPE
:
822 *pcsFlags
= SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
;
824 case NTOBJECT_COLUMN_LINKTARGET
:
825 *pcsFlags
= SHCOLSTATE_TYPE_STR
| SHCOLSTATE_SLOW
;
832 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::GetDetailsEx(
834 const SHCOLUMNID
*pscid
,
837 const NtPidlEntry
* info
;
839 TRACE("GetDetailsEx\n");
843 HRESULT hr
= CNtObjectPidlHelper::GetInfoFromPidl(pidl
, &info
);
844 if (FAILED_UNEXPECTEDLY(hr
))
847 static const GUID storage
= PSGUID_STORAGE
;
848 if (IsEqualGUID(pscid
->fmtid
, storage
))
850 if (pscid
->pid
== PID_STG_NAME
)
852 return MakeVariantString(pv
, info
->entryName
);
854 else if (pscid
->pid
== PID_STG_STORAGETYPE
)
856 if (info
->objectType
< 0)
858 NtPidlTypeData
* td
= (NtPidlTypeData
*) (((PBYTE
) info
) + FIELD_OFFSET(NtPidlEntry
, entryName
) + info
->entryNameLength
+ sizeof(WCHAR
));
860 if (td
->typeNameLength
> 0)
862 return MakeVariantString(pv
, td
->typeName
);
866 return MakeVariantString(pv
, L
"Unknown");
871 return MakeVariantString(pv
, ObjectTypeNames
[info
->objectType
]);
875 else if (IsEqualGUID(pscid
->fmtid
, GUID_NtObjectColumns
))
877 if (pscid
->pid
== NTOBJECT_COLUMN_LINKTARGET
&& info
->objectType
== SYMBOLICLINK_OBJECT
)
879 WCHAR wbLink
[MAX_PATH
] = { 0 };
881 RtlInitEmptyUnicodeString(&link
, wbLink
, sizeof(wbLink
));
883 HRESULT hr
= GetNTObjectSymbolicLinkTarget(m_NtPath
, info
->entryName
, &link
);
885 if (!FAILED_UNEXPECTEDLY(hr
) && link
.Length
> 0)
887 return MakeVariantString(pv
, link
.Buffer
);
899 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::GetDetailsOf(
904 const NtPidlEntry
* info
;
906 TRACE("GetDetailsOf\n");
910 HRESULT hr
= CNtObjectPidlHelper::GetInfoFromPidl(pidl
, &info
);
911 if (FAILED_UNEXPECTEDLY(hr
))
916 case NTOBJECT_COLUMN_NAME
:
917 psd
->fmt
= LVCFMT_LEFT
;
919 MakeStrRetFromString(info
->entryName
, info
->entryNameLength
, &(psd
->str
));
921 case NTOBJECT_COLUMN_TYPE
:
922 psd
->fmt
= LVCFMT_LEFT
;
924 if (info
->objectType
< 0)
926 NtPidlTypeData
* td
= (NtPidlTypeData
*) (((PBYTE
) info
) + FIELD_OFFSET(NtPidlEntry
, entryName
) + info
->entryNameLength
+ sizeof(WCHAR
));
928 if (td
->typeNameLength
> 0)
929 MakeStrRetFromString(td
->typeName
, td
->typeNameLength
, &(psd
->str
));
931 MakeStrRetFromString(L
"Unknown", &(psd
->str
));
934 MakeStrRetFromString(ObjectTypeNames
[info
->objectType
], &(psd
->str
));
936 case NTOBJECT_COLUMN_LINKTARGET
:
938 psd
->fmt
= LVCFMT_LEFT
;
940 if (info
->objectType
== SYMBOLICLINK_OBJECT
)
942 WCHAR wbLink
[MAX_PATH
] = { 0 };
944 RtlInitEmptyUnicodeString(&link
, wbLink
, sizeof(wbLink
));
946 HRESULT hr
= GetNTObjectSymbolicLinkTarget(m_NtPath
, info
->entryName
, &link
);
948 if (!FAILED_UNEXPECTEDLY(hr
) && link
.Length
> 0)
950 MakeStrRetFromString(link
.Buffer
, link
.Length
, &(psd
->str
));
955 MakeStrRetFromString(L
"", &(psd
->str
));
964 case NTOBJECT_COLUMN_NAME
:
965 psd
->fmt
= LVCFMT_LEFT
;
968 // TODO: Make localizable
969 MakeStrRetFromString(L
"Object Name", &(psd
->str
));
971 case NTOBJECT_COLUMN_TYPE
:
972 psd
->fmt
= LVCFMT_LEFT
;
975 // TODO: Make localizable
976 MakeStrRetFromString(L
"Object Type", &(psd
->str
));
978 case NTOBJECT_COLUMN_LINKTARGET
:
979 psd
->fmt
= LVCFMT_LEFT
;
982 // TODO: Make localizable
983 MakeStrRetFromString(L
"Symlink Target", &(psd
->str
));
991 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::MapColumnToSCID(
995 static const GUID storage
= PSGUID_STORAGE
;
998 case NTOBJECT_COLUMN_NAME
:
999 pscid
->fmtid
= storage
;
1000 pscid
->pid
= PID_STG_NAME
;
1002 case NTOBJECT_COLUMN_TYPE
:
1003 pscid
->fmtid
= storage
;
1004 pscid
->pid
= PID_STG_STORAGETYPE
;
1006 case NTOBJECT_COLUMN_LINKTARGET
:
1007 pscid
->fmtid
= GUID_NtObjectColumns
;
1008 pscid
->pid
= NTOBJECT_COLUMN_LINKTARGET
;
1011 return E_INVALIDARG
;
1014 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::MessageSFVCB(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1018 case SFVM_DEFVIEWMODE
:
1020 FOLDERVIEWMODE
* pViewMode
= (FOLDERVIEWMODE
*) lParam
;
1021 *pViewMode
= FVM_DETAILS
;
1024 case SFVM_COLUMNCLICK
:
1026 case SFVM_BACKGROUNDENUM
:
1032 HRESULT
CNtObjectFolder::DefCtxMenuCallback(IShellFolder
* /*psf*/, HWND
/*hwnd*/, IDataObject
* /*pdtobj*/, UINT uMsg
, WPARAM
/*wParam*/, LPARAM
/*lParam*/)
1036 case DFM_MERGECONTEXTMENU
:
1038 case DFM_INVOKECOMMAND
:
1039 case DFM_INVOKECOMMANDEX
:
1040 case DFM_GETDEFSTATICID
: // Required for Windows 7 to pick a default