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>
11 #include <wine/unicode.h>
13 // {845B0FB2-66E0-416B-8F91-314E23F7C12D}
14 const GUID CLSID_NtObjectFolder
= { 0x845b0fb2, 0x66e0, 0x416b, { 0x8f, 0x91, 0x31, 0x4e, 0x23, 0xf7, 0xc1, 0x2d } };
16 // {F4C430C3-3A8D-4B56-A018-E598DA60C2E0}
17 static const GUID GUID_NtObjectColumns
= { 0xf4c430c3, 0x3a8d, 0x4b56, { 0xa0, 0x18, 0xe5, 0x98, 0xda, 0x60, 0xc2, 0xe0 } };
21 NTOBJECT_COLUMN_NAME
= 0,
23 NTOBJECT_COLUMN_LINKTARGET
,
27 CNtObjectFolderExtractIcon::CNtObjectFolderExtractIcon() :
34 CNtObjectFolderExtractIcon::~CNtObjectFolderExtractIcon()
37 ILFree((LPITEMIDLIST
) m_pcidlChild
);
40 HRESULT
CNtObjectFolderExtractIcon::Initialize(LPCWSTR ntPath
, PCIDLIST_ABSOLUTE parent
, UINT cidl
, PCUITEMID_CHILD_ARRAY apidl
)
45 m_pcidlChild
= ILClone(apidl
[0]);
49 HRESULT STDMETHODCALLTYPE
CNtObjectFolderExtractIcon::GetIconLocation(
56 const NtPidlEntry
* entry
= (NtPidlEntry
*) m_pcidlChild
;
58 if ((entry
->cb
< sizeof(NtPidlEntry
)) || (entry
->magic
!= NT_OBJECT_PIDL_MAGIC
))
63 switch (entry
->objectType
)
65 case DIRECTORY_OBJECT
:
66 case SYMBOLICLINK_OBJECT
:
67 GetModuleFileNameW(g_hInstance
, szIconFile
, cchMax
);
68 *piIndex
= -((uFlags
& GIL_OPENICON
) ? IDI_NTOBJECTDIROPEN
: IDI_NTOBJECTDIR
);
72 GetModuleFileNameW(g_hInstance
, szIconFile
, cchMax
);
73 *piIndex
= -IDI_NTOBJECTDEVICE
;
77 GetModuleFileNameW(g_hInstance
, szIconFile
, cchMax
);
78 *piIndex
= -IDI_NTOBJECTPORT
;
82 GetModuleFileNameW(g_hInstance
, szIconFile
, cchMax
);
83 *piIndex
= -IDI_REGISTRYKEY
;
87 GetModuleFileNameW(g_hInstance
, szIconFile
, cchMax
);
88 *piIndex
= -IDI_NTOBJECTITEM
;
94 HRESULT STDMETHODCALLTYPE
CNtObjectFolderExtractIcon::Extract(
101 return SHDefExtractIconW(pszFile
, nIconIndex
, 0, phiconLarge
, phiconSmall
, nIconSize
);
104 //-----------------------------------------------------------------------------
107 CNtObjectFolder::CNtObjectFolder()
111 CNtObjectFolder::~CNtObjectFolder()
117 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::EnumObjects(
120 IEnumIDList
**ppenumIDList
)
122 return GetEnumNTDirectory(m_NtPath
, ppenumIDList
);
125 BOOL STDMETHODCALLTYPE
CNtObjectFolder::IsSymLink(const NtPidlEntry
* info
)
127 return info
->objectType
== SYMBOLICLINK_OBJECT
;
130 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::ResolveSymLink(
131 const NtPidlEntry
* info
,
132 LPITEMIDLIST
* fullPidl
)
134 WCHAR wbLink
[MAX_PATH
] = { 0 };
136 RtlInitEmptyUnicodeString(&link
, wbLink
, sizeof(wbLink
));
140 HRESULT hr
= GetNTObjectSymbolicLinkTarget(m_NtPath
, info
->entryName
, &link
);
141 if (FAILED_UNEXPECTEDLY(hr
))
144 WCHAR path
[MAX_PATH
];
146 if (link
.Length
== 0)
149 if (link
.Buffer
[1] == L
':' && isalphaW(link
.Buffer
[0]))
151 StringCbCopyNW(path
, _countof(path
), link
.Buffer
, link
.Length
);
153 CComPtr
<IShellFolder
> psfDesktop
;
154 hr
= SHGetDesktopFolder(&psfDesktop
);
155 if (FAILED_UNEXPECTEDLY(hr
))
158 return psfDesktop
->ParseDisplayName(NULL
, NULL
, path
, NULL
, fullPidl
, NULL
);
161 StringCbCopyW(path
, _countof(path
), L
"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{845B0FB2-66E0-416B-8F91-314E23F7C12D}");
162 PathAppend(path
, link
.Buffer
);
164 CComPtr
<IShellFolder
> psfDesktop
;
165 hr
= SHGetDesktopFolder(&psfDesktop
);
166 if (FAILED_UNEXPECTEDLY(hr
))
171 hr
= psfDesktop
->ParseDisplayName(NULL
, NULL
, path
, NULL
, &pidl
, NULL
);
182 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::InternalBindToObject(
184 const NtPidlEntry
* info
,
187 LPITEMIDLIST fullPidl
,
189 IShellFolder
** ppsfChild
)
192 if (info
->objectType
== KEY_OBJECT
)
194 return ShellObjectCreatorInit
<CRegistryFolder
>(fullPidl
, path
, (HKEY
) NULL
, IID_PPV_ARG(IShellFolder
, ppsfChild
));
197 return ShellObjectCreatorInit
<CNtObjectFolder
>(fullPidl
, path
, IID_PPV_ARG(IShellFolder
, ppsfChild
));
201 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::Initialize(LPCITEMIDLIST pidl
)
203 m_shellPidl
= ILClone(pidl
);
205 StringCbCopy(m_NtPath
, _countof(m_NtPath
), L
"\\");
211 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::Initialize(LPCITEMIDLIST pidl
, PCWSTR ntPath
)
213 m_shellPidl
= ILClone(pidl
);
215 StringCbCopy(m_NtPath
, _countof(m_NtPath
), ntPath
);
220 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::GetDefaultColumnState(
222 SHCOLSTATEF
*pcsFlags
)
226 case NTOBJECT_COLUMN_NAME
:
227 *pcsFlags
= SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
;
229 case NTOBJECT_COLUMN_TYPE
:
230 *pcsFlags
= SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
;
232 case NTOBJECT_COLUMN_LINKTARGET
:
233 *pcsFlags
= SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
| SHCOLSTATE_SLOW
;
240 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::GetDetailsEx(
242 const SHCOLUMNID
*pscid
,
245 const NtPidlEntry
* info
;
247 TRACE("GetDetailsEx\n");
251 HRESULT hr
= GetInfoFromPidl(pidl
, &info
);
252 if (FAILED_UNEXPECTEDLY(hr
))
255 static const GUID storage
= PSGUID_STORAGE
;
256 if (IsEqualGUID(pscid
->fmtid
, storage
))
258 if (pscid
->pid
== PID_STG_NAME
)
260 return MakeVariantString(pv
, info
->entryName
);
262 else if (pscid
->pid
== PID_STG_STORAGETYPE
)
264 if (info
->objectType
< 0)
266 NtPidlTypeData
* td
= (NtPidlTypeData
*) (((PBYTE
) info
) + FIELD_OFFSET(NtPidlEntry
, entryName
) + info
->entryNameLength
+ sizeof(WCHAR
));
268 if (td
->typeNameLength
> 0)
270 return MakeVariantString(pv
, td
->typeName
);
274 return MakeVariantString(pv
, L
"Unknown");
279 return MakeVariantString(pv
, ObjectTypeNames
[info
->objectType
]);
283 else if (IsEqualGUID(pscid
->fmtid
, GUID_NtObjectColumns
))
285 if (pscid
->pid
== NTOBJECT_COLUMN_LINKTARGET
&& info
->objectType
== SYMBOLICLINK_OBJECT
)
287 WCHAR wbLink
[MAX_PATH
] = { 0 };
289 RtlInitEmptyUnicodeString(&link
, wbLink
, sizeof(wbLink
));
291 HRESULT hr
= GetNTObjectSymbolicLinkTarget(m_NtPath
, info
->entryName
, &link
);
293 if (!FAILED_UNEXPECTEDLY(hr
) && link
.Length
> 0)
295 return MakeVariantString(pv
, link
.Buffer
);
307 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::GetDetailsOf(
312 const NtPidlEntry
* info
;
314 TRACE("GetDetailsOf\n");
318 HRESULT hr
= GetInfoFromPidl(pidl
, &info
);
319 if (FAILED_UNEXPECTEDLY(hr
))
324 case NTOBJECT_COLUMN_NAME
:
325 psd
->fmt
= LVCFMT_LEFT
;
327 MakeStrRetFromString(info
->entryName
, info
->entryNameLength
, &(psd
->str
));
329 case NTOBJECT_COLUMN_TYPE
:
330 psd
->fmt
= LVCFMT_LEFT
;
332 if (info
->objectType
< 0)
334 NtPidlTypeData
* td
= (NtPidlTypeData
*) (((PBYTE
) info
) + FIELD_OFFSET(NtPidlEntry
, entryName
) + info
->entryNameLength
+ sizeof(WCHAR
));
336 if (td
->typeNameLength
> 0)
337 MakeStrRetFromString(td
->typeName
, td
->typeNameLength
, &(psd
->str
));
339 MakeStrRetFromString(L
"Unknown", &(psd
->str
));
342 MakeStrRetFromString(ObjectTypeNames
[info
->objectType
], &(psd
->str
));
344 case NTOBJECT_COLUMN_LINKTARGET
:
346 psd
->fmt
= LVCFMT_LEFT
;
348 if (info
->objectType
== SYMBOLICLINK_OBJECT
)
350 WCHAR wbLink
[MAX_PATH
] = { 0 };
352 RtlInitEmptyUnicodeString(&link
, wbLink
, sizeof(wbLink
));
354 HRESULT hr
= GetNTObjectSymbolicLinkTarget(m_NtPath
, info
->entryName
, &link
);
356 if (!FAILED_UNEXPECTEDLY(hr
) && link
.Length
> 0)
358 MakeStrRetFromString(link
.Buffer
, link
.Length
, &(psd
->str
));
363 MakeStrRetFromString(L
"", &(psd
->str
));
372 case NTOBJECT_COLUMN_NAME
:
373 psd
->fmt
= LVCFMT_LEFT
;
376 // TODO: Make localizable
377 MakeStrRetFromString(L
"Object Name", &(psd
->str
));
379 case NTOBJECT_COLUMN_TYPE
:
380 psd
->fmt
= LVCFMT_LEFT
;
383 // TODO: Make localizable
384 MakeStrRetFromString(L
"Object Type", &(psd
->str
));
386 case NTOBJECT_COLUMN_LINKTARGET
:
387 psd
->fmt
= LVCFMT_LEFT
;
390 // TODO: Make localizable
391 MakeStrRetFromString(L
"Symlink Target", &(psd
->str
));
399 HRESULT STDMETHODCALLTYPE
CNtObjectFolder::MapColumnToSCID(
403 static const GUID storage
= PSGUID_STORAGE
;
406 case NTOBJECT_COLUMN_NAME
:
407 pscid
->fmtid
= storage
;
408 pscid
->pid
= PID_STG_NAME
;
410 case NTOBJECT_COLUMN_TYPE
:
411 pscid
->fmtid
= storage
;
412 pscid
->pid
= PID_STG_STORAGETYPE
;
414 case NTOBJECT_COLUMN_LINKTARGET
:
415 pscid
->fmtid
= GUID_NtObjectColumns
;
416 pscid
->pid
= NTOBJECT_COLUMN_LINKTARGET
;
422 HRESULT
CNtObjectFolder::CompareIDs(LPARAM lParam
, const NtPidlEntry
* first
, const NtPidlEntry
* second
)
426 DWORD sortMode
= lParam
& 0xFFFF0000;
427 DWORD column
= lParam
& 0x0000FFFF;
429 if (sortMode
== SHCIDS_ALLFIELDS
)
434 int minsize
= min(first
->cb
, second
->cb
);
435 hr
= MAKE_COMPARE_HRESULT(memcmp(second
, first
, minsize
));
439 return MAKE_COMPARE_HRESULT(second
->cb
- first
->cb
);
444 case NTOBJECT_COLUMN_NAME
:
445 return CompareName(lParam
, first
, second
);
447 case NTOBJECT_COLUMN_TYPE
:
448 return MAKE_COMPARE_HRESULT(second
->objectType
- first
->objectType
);
450 case NTOBJECT_COLUMN_LINKTARGET
:
451 // Can't sort by link target yet
455 DbgPrint("Unsupported sorting mode.\n");
459 ULONG
CNtObjectFolder::ConvertAttributes(const NtPidlEntry
* entry
, PULONG inMask
)
461 ULONG mask
= inMask
? *inMask
: 0xFFFFFFFF;
462 ULONG flags
= SFGAO_HASPROPSHEET
| SFGAO_CANLINK
;
464 if (entry
->objectType
== DIRECTORY_OBJECT
)
465 flags
|= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
| SFGAO_BROWSABLE
;
467 if (entry
->objectType
== SYMBOLICLINK_OBJECT
)
468 flags
|= SFGAO_LINK
| SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
| SFGAO_BROWSABLE
;
470 if (entry
->objectType
== KEY_OBJECT
)
471 flags
|= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
| SFGAO_BROWSABLE
;
476 BOOL
CNtObjectFolder::IsFolder(const NtPidlEntry
* info
)
478 return (info
->objectType
== DIRECTORY_OBJECT
) ||
479 (info
->objectType
== SYMBOLICLINK_OBJECT
) ||
480 (info
->objectType
== KEY_OBJECT
);
483 HRESULT
CNtObjectFolder::GetInfoFromPidl(LPCITEMIDLIST pcidl
, const NtPidlEntry
** pentry
)
485 NtPidlEntry
* entry
= (NtPidlEntry
*) &(pcidl
->mkid
);
487 if (entry
->cb
< sizeof(NtPidlEntry
))
489 DbgPrint("PCIDL too small %l (required %l)\n", entry
->cb
, sizeof(NtPidlEntry
));
493 if (entry
->magic
!= NT_OBJECT_PIDL_MAGIC
)
495 DbgPrint("PCIDL magic mismatch %04x (expected %04x)\n", entry
->magic
, NT_OBJECT_PIDL_MAGIC
);