2 * PROJECT: ReactOS shell extensions
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/shellext/ntobjshex/ntobjfolder.h
5 * PURPOSE: NT Object Namespace shell extension
6 * PROGRAMMERS: David Quintana <gigaherz@gmail.com>
10 extern const GUID CLSID_NtObjectFolder
;
13 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
14 public IShellFolderViewCB
20 CFolderViewCB() : m_View(NULL
) {}
21 virtual ~CFolderViewCB() {}
23 virtual HRESULT STDMETHODCALLTYPE
MessageSFVCB(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
27 case SFVM_DEFVIEWMODE
:
29 FOLDERVIEWMODE
* pViewMode
= (FOLDERVIEWMODE
*)lParam
;
30 *pViewMode
= FVM_DETAILS
;
33 case SFVM_COLUMNCLICK
:
35 case SFVM_BACKGROUNDENUM
:
39 DbgPrint("MessageSFVCB unimplemented %d %08x %08x\n", uMsg
, wParam
, lParam
);
43 virtual HRESULT STDMETHODCALLTYPE
Initialize(IShellView
* psv
)
49 DECLARE_NOT_AGGREGATABLE(CFolderViewCB
)
50 DECLARE_PROTECT_FINAL_CONSTRUCT()
52 BEGIN_COM_MAP(CFolderViewCB
)
53 COM_INTERFACE_ENTRY_IID(IID_IShellFolderViewCB
, IShellFolderViewCB
)
57 template<class TSelf
, typename TItemId
, class TExtractIcon
>
59 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
61 public IPersistFolder2
64 WCHAR m_NtPath
[MAX_PATH
];
66 LPITEMIDLIST m_shellPidl
;
75 virtual ~CCommonFolder()
82 virtual HRESULT STDMETHODCALLTYPE
ParseDisplayName(
85 LPOLESTR lpszDisplayName
,
99 TRACE("CCommonFolder::ParseDisplayName name=%S (ntPath=%S)\n", lpszDisplayName
, m_NtPath
);
101 const TItemId
* info
;
103 HRESULT hr
= EnumObjects(hwndOwner
, SHCONTF_FOLDERS
| SHCONTF_NONFOLDERS
, &it
);
107 PWSTR end
= StrChrW(lpszDisplayName
, '\\');
108 int length
= end
? end
- lpszDisplayName
: wcslen(lpszDisplayName
);
112 hr
= it
->Next(1, ppidl
, NULL
);
118 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
120 hr
= GetInfoFromPidl(*ppidl
, &info
);
121 if (FAILED_UNEXPECTEDLY(hr
))
124 if (StrCmpNW(info
->entryName
, lpszDisplayName
, length
) == 0)
128 // if has remaining path to parse (and the path didn't just terminate in a backslash)
129 if (end
&& wcslen(end
) > 1)
131 CComPtr
<IShellFolder
> psfChild
;
132 hr
= BindToObject(*ppidl
, pbcReserved
, IID_PPV_ARG(IShellFolder
, &psfChild
));
133 if (FAILED_UNEXPECTEDLY(hr
))
137 hr
= psfChild
->ParseDisplayName(hwndOwner
, pbcReserved
, end
+ 1, pchEaten
, &child
, pdwAttributes
);
141 LPITEMIDLIST old
= *ppidl
;
142 *ppidl
= ILCombine(old
, child
);
145 // Count the path separator
152 *pdwAttributes
= ConvertAttributes(info
, pdwAttributes
);
156 *pchEaten
+= wcslen(info
->entryName
);
161 virtual HRESULT STDMETHODCALLTYPE
EnumObjects(
164 IEnumIDList
**ppenumIDList
) PURE
;
166 virtual HRESULT STDMETHODCALLTYPE
BindToObject(
172 const TItemId
* info
;
174 if (IsEqualIID(riid
, IID_IShellFolder
))
176 HRESULT hr
= GetInfoFromPidl(pidl
, &info
);
177 if (FAILED_UNEXPECTEDLY(hr
))
180 WCHAR path
[MAX_PATH
];
182 StringCbCopyW(path
, sizeof(path
), m_NtPath
);
183 PathAppendW(path
, info
->entryName
);
185 LPITEMIDLIST first
= ILCloneFirst(pidl
);
186 LPCITEMIDLIST rest
= ILGetNext(pidl
);
188 LPITEMIDLIST fullPidl
= ILCombine(m_shellPidl
, first
);
190 CComPtr
<IShellFolder
> psfChild
;
191 hr
= InternalBindToObject(path
, info
, first
, rest
, fullPidl
, pbcReserved
, &psfChild
);
202 if (rest
->mkid
.cb
> 0)
204 return psfChild
->BindToObject(rest
, pbcReserved
, riid
, ppvOut
);
207 return psfChild
->QueryInterface(riid
, ppvOut
);
214 virtual HRESULT STDMETHODCALLTYPE
InternalBindToObject(
216 const TItemId
* info
,
219 LPITEMIDLIST fullPidl
,
221 IShellFolder
** ppsfChild
) PURE
;
223 virtual HRESULT STDMETHODCALLTYPE
ResolveSymLink(
224 const TItemId
* info
,
225 LPITEMIDLIST
* fullPidl
)
232 virtual HRESULT STDMETHODCALLTYPE
BindToStorage(
242 virtual HRESULT STDMETHODCALLTYPE
CompareIDs(
249 TRACE("CompareIDs %d\n", lParam
);
252 hr
= GetInfoFromPidl(pidl1
, &id1
);
257 hr
= GetInfoFromPidl(pidl2
, &id2
);
261 hr
= CompareIDs(lParam
, id1
, id2
);
265 // The wollowing snipped is basically SHELL32_CompareChildren
267 PUIDLIST_RELATIVE rest1
= ILGetNext(pidl1
);
268 PUIDLIST_RELATIVE rest2
= ILGetNext(pidl2
);
270 bool isEmpty1
= (rest1
->mkid
.cb
== 0);
271 bool isEmpty2
= (rest2
->mkid
.cb
== 0);
273 if (isEmpty1
|| isEmpty2
)
274 return MAKE_COMPARE_HRESULT(isEmpty2
- isEmpty1
);
276 LPCITEMIDLIST first1
= ILCloneFirst(pidl1
);
278 return E_OUTOFMEMORY
;
280 CComPtr
<IShellFolder
> psfNext
;
281 hr
= BindToObject(first1
, NULL
, IID_PPV_ARG(IShellFolder
, &psfNext
));
282 if (FAILED_UNEXPECTEDLY(hr
))
285 return psfNext
->CompareIDs(lParam
, rest1
, rest2
);
289 virtual HRESULT STDMETHODCALLTYPE
CompareName(
291 const TItemId
* first
,
292 const TItemId
* second
)
294 bool f1
= IsFolder(first
);
295 bool f2
= IsFolder(second
);
297 HRESULT hr
= MAKE_COMPARE_HRESULT(f2
- f1
);
301 bool canonical
= (lParam
& 0xFFFF0000) == SHCIDS_CANONICALONLY
;
304 // Shortcut: avoid comparing contents if not necessary when the results are not for display.
305 hr
= MAKE_COMPARE_HRESULT(second
->entryNameLength
- first
->entryNameLength
);
309 int minlength
= min(first
->entryNameLength
, second
->entryNameLength
);
312 hr
= MAKE_COMPARE_HRESULT(memcmp(first
->entryName
, second
->entryName
, minlength
));
320 int minlength
= min(first
->entryNameLength
, second
->entryNameLength
);
323 hr
= MAKE_COMPARE_HRESULT(StrCmpNW(first
->entryName
, second
->entryName
, minlength
/ sizeof(WCHAR
)));
328 return MAKE_COMPARE_HRESULT(second
->entryNameLength
- first
->entryNameLength
);
332 virtual HRESULT STDMETHODCALLTYPE
CreateViewObject(
337 if (!IsEqualIID(riid
, IID_IShellView
))
338 return E_NOINTERFACE
;
340 _CComObject
<CFolderViewCB
> *pcb
;
342 HRESULT hr
= _CComObject
<CFolderViewCB
>::CreateInstance(&pcb
);
349 sfv
.cbSize
= sizeof(sfv
);
356 hr
= SHCreateShellFolderView(&sfv
, &view
);
360 pcb
->Initialize(view
);
369 virtual HRESULT STDMETHODCALLTYPE
GetAttributesOf(
371 PCUITEMID_CHILD_ARRAY apidl
,
374 const TItemId
* info
;
376 TRACE("GetAttributesOf %d\n", cidl
);
380 *rgfInOut
&= SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
| SFGAO_BROWSABLE
;
384 for (int i
= 0; i
< (int)cidl
; i
++)
386 PCUITEMID_CHILD pidl
= apidl
[i
];
388 HRESULT hr
= GetInfoFromPidl(pidl
, &info
);
389 if (FAILED_UNEXPECTEDLY(hr
))
392 // Update attributes.
393 *rgfInOut
= ConvertAttributes(info
, rgfInOut
);
399 virtual HRESULT STDMETHODCALLTYPE
GetUIObjectOf(
402 PCUITEMID_CHILD_ARRAY apidl
,
408 TRACE("GetUIObjectOf\n");
410 if (IsEqualIID(riid
, IID_IContextMenu
) ||
411 IsEqualIID(riid
, IID_IContextMenu2
) ||
412 IsEqualIID(riid
, IID_IContextMenu3
))
414 CComPtr
<IContextMenu
> pcm
;
418 LPITEMIDLIST parent
= m_shellPidl
;
420 CComPtr
<IShellFolder
> psfParent
= this;
424 int nkeys
= _countof(keys
);
425 if (cidl
== 1 && IsSymLink(apidl
[0]))
427 const TItemId
* info
;
428 HRESULT hr
= GetInfoFromPidl(apidl
[0], &info
);
433 hr
= ResolveSymLink(info
, &target
);
437 CComPtr
<IShellFolder
> psfTarget
;
438 hr
= ::SHBindToParent(target
, IID_PPV_ARG(IShellFolder
, &psfTarget
), &child
);
445 parent
= ILClone(target
);
446 ILRemoveLastID(parent
);
447 psfParent
= psfTarget
;
452 if (cidl
== 1 && IsFolder(apidl
[0]))
454 res
= RegOpenKey(HKEY_CLASSES_ROOT
, L
"Folder", keys
+ 0);
455 if (!NT_SUCCESS(res
))
456 return HRESULT_FROM_NT(res
);
463 HRESULT hr
= CDefFolderMenu_Create2(parent
, hwndOwner
, cidl
, apidl
, psfParent
, DefCtxMenuCallback
, nkeys
, keys
, &pcm
);
464 if (FAILED_UNEXPECTEDLY(hr
))
467 return pcm
->QueryInterface(riid
, ppvOut
);
470 if (IsEqualIID(riid
, IID_IExtractIconW
))
472 return ShellObjectCreatorInit
<TExtractIcon
>(m_NtPath
, m_shellPidl
, cidl
, apidl
, riid
, ppvOut
);
475 if (IsEqualIID(riid
, IID_IDataObject
))
477 return CIDLData_CreateFromIDArray(m_shellPidl
, cidl
, apidl
, (IDataObject
**)ppvOut
);
480 if (IsEqualIID(riid
, IID_IQueryAssociations
))
482 if (cidl
== 1 && IsFolder(apidl
[0]))
484 CComPtr
<IQueryAssociations
> pqa
;
485 HRESULT hr
= AssocCreate(CLSID_QueryAssociations
, IID_PPV_ARG(IQueryAssociations
, &pqa
));
486 if (FAILED_UNEXPECTEDLY(hr
))
489 hr
= pqa
->Init(ASSOCF_INIT_DEFAULTTOFOLDER
, L
"NTObjShEx.NTDirectory", NULL
, hwndOwner
);
490 if (FAILED_UNEXPECTEDLY(hr
))
493 return pqa
->QueryInterface(riid
, ppvOut
);
500 virtual HRESULT STDMETHODCALLTYPE
GetDisplayNameOf(
505 const TItemId
* info
;
507 TRACE("GetDisplayNameOf %p\n", pidl
);
509 HRESULT hr
= GetInfoFromPidl(pidl
, &info
);
510 if (FAILED_UNEXPECTEDLY(hr
))
513 if (GET_SHGDN_FOR(uFlags
) & SHGDN_FOREDITING
)
515 hr
= MakeStrRetFromString(info
->entryName
, info
->entryNameLength
, lpName
);
516 if (FAILED_UNEXPECTEDLY(hr
))
520 WCHAR path
[MAX_PATH
] = { 0 };
522 if (GET_SHGDN_FOR(uFlags
) & SHGDN_FORPARSING
)
524 if (GET_SHGDN_RELATION(uFlags
) != SHGDN_INFOLDER
)
526 hr
= GetFullName(m_shellPidl
, uFlags
, path
, _countof(path
));
527 if (FAILED_UNEXPECTEDLY(hr
))
532 PathAppendW(path
, info
->entryName
);
534 LPCITEMIDLIST pidlNext
= ILGetNext(pidl
);
535 if (pidlNext
&& pidlNext
->mkid
.cb
> 0)
537 LPITEMIDLIST pidlFirst
= ILCloneFirst(pidl
);
539 CComPtr
<IShellFolder
> psfChild
;
540 hr
= BindToObject(pidlFirst
, NULL
, IID_PPV_ARG(IShellFolder
, &psfChild
));
541 if (FAILED_UNEXPECTEDLY(hr
))
544 WCHAR temp
[MAX_PATH
];
547 hr
= psfChild
->GetDisplayNameOf(pidlNext
, uFlags
| SHGDN_INFOLDER
, &childName
);
548 if (FAILED_UNEXPECTEDLY(hr
))
551 hr
= StrRetToBufW(&childName
, pidlNext
, temp
, _countof(temp
));
552 if (FAILED_UNEXPECTEDLY(hr
))
555 PathAppendW(path
, temp
);
560 hr
= MakeStrRetFromString(path
, lpName
);
561 if (FAILED_UNEXPECTEDLY(hr
))
567 virtual HRESULT STDMETHODCALLTYPE
SetNameOf(
572 LPITEMIDLIST
*ppidlOut
)
579 virtual HRESULT STDMETHODCALLTYPE
GetDefaultSearchGUID(
586 virtual HRESULT STDMETHODCALLTYPE
EnumSearches(
587 IEnumExtraSearch
**ppenum
)
593 virtual HRESULT STDMETHODCALLTYPE
GetDefaultColumn(
605 virtual HRESULT STDMETHODCALLTYPE
GetDefaultColumnState(
607 SHCOLSTATEF
*pcsFlags
) PURE
;
609 virtual HRESULT STDMETHODCALLTYPE
GetDetailsEx(
611 const SHCOLUMNID
*pscid
,
614 virtual HRESULT STDMETHODCALLTYPE
GetDetailsOf(
617 SHELLDETAILS
*psd
) PURE
;
619 virtual HRESULT STDMETHODCALLTYPE
MapColumnToSCID(
621 SHCOLUMNID
*pscid
) PURE
;
624 virtual HRESULT STDMETHODCALLTYPE
GetClassID(CLSID
*lpClassId
)
629 *lpClassId
= CLSID_NtObjectFolder
;
634 virtual HRESULT STDMETHODCALLTYPE
Initialize(PCIDLIST_ABSOLUTE pidl
)
636 m_shellPidl
= ILClone(pidl
);
638 StringCbCopyW(m_NtPath
, sizeof(m_NtPath
), L
"\\");
644 virtual HRESULT STDMETHODCALLTYPE
GetCurFolder(PIDLIST_ABSOLUTE
* pidl
)
647 *pidl
= ILClone(m_shellPidl
);
655 virtual HRESULT STDMETHODCALLTYPE
CompareIDs(
657 const TItemId
* first
,
658 const TItemId
* second
) PURE
;
660 virtual ULONG STDMETHODCALLTYPE
ConvertAttributes(
661 const TItemId
* entry
,
664 virtual BOOL STDMETHODCALLTYPE
IsFolder(LPCITEMIDLIST pcidl
)
666 const TItemId
* info
;
668 HRESULT hr
= GetInfoFromPidl(pcidl
, &info
);
672 return IsFolder(info
);
675 virtual BOOL STDMETHODCALLTYPE
IsFolder(const TItemId
* info
) PURE
;
677 virtual BOOL STDMETHODCALLTYPE
IsSymLink(LPCITEMIDLIST pcidl
)
679 const TItemId
* info
;
681 HRESULT hr
= GetInfoFromPidl(pcidl
, &info
);
685 return IsSymLink(info
);
688 virtual BOOL STDMETHODCALLTYPE
IsSymLink(const TItemId
* info
)
693 virtual HRESULT
GetInfoFromPidl(LPCITEMIDLIST pcidl
, const TItemId
** pentry
) PURE
;
696 static HRESULT CALLBACK
DefCtxMenuCallback(IShellFolder
* /*psf*/, HWND
/*hwnd*/, IDataObject
* /*pdtobj*/, UINT uMsg
, WPARAM
/*wParam*/, LPARAM
/*lParam*/)
700 case DFM_MERGECONTEXTMENU
:
702 case DFM_INVOKECOMMAND
:
703 case DFM_INVOKECOMMANDEX
:
704 case DFM_GETDEFSTATICID
: // Required for Windows 7 to pick a default
710 DECLARE_NOT_AGGREGATABLE(TSelf
)
711 DECLARE_PROTECT_FINAL_CONSTRUCT()
714 COM_INTERFACE_ENTRY_IID(IID_IShellFolder
, IShellFolder
)
715 COM_INTERFACE_ENTRY_IID(IID_IShellFolder2
, IShellFolder2
)
716 COM_INTERFACE_ENTRY_IID(IID_IPersist
, IPersist
)
717 COM_INTERFACE_ENTRY_IID(IID_IPersistFolder
, IPersistFolder
)
718 COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2
, IPersistFolder2
)