2 * PROJECT: ReactOS Search Shell Extension
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Search results folder
5 * COPYRIGHT: Copyright 2019 Brock Mammen
8 #include "CFindFolder.h"
10 WINE_DEFAULT_DEBUG_CHANNEL(shellfind
);
12 // FIXME: Remove this declaration after the function has been fully implemented
15 SHOpenFolderAndSelectItems(LPITEMIDLIST pidlFolder
,
17 PCUITEMID_CHILD_ARRAY apidl
,
20 struct FolderViewColumns
28 static FolderViewColumns g_ColumnDefs
[] =
30 {L
"Name", SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_LEFT
, 30},
31 {L
"In Folder", SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_LEFT
, 30},
32 {L
"Relevance", SHCOLSTATE_TYPE_STR
, LVCFMT_LEFT
, 0}
35 CFindFolder::CFindFolder() :
40 static LPITEMIDLIST
_ILCreate(LPCWSTR lpszPath
, LPCITEMIDLIST lpcFindDataPidl
)
42 int pathLen
= (wcslen(lpszPath
) + 1) * sizeof(WCHAR
);
43 int cbData
= sizeof(WORD
) + pathLen
+ lpcFindDataPidl
->mkid
.cb
;
44 LPITEMIDLIST pidl
= (LPITEMIDLIST
) SHAlloc(cbData
+ sizeof(WORD
));
48 LPBYTE p
= (LPBYTE
) pidl
;
49 *((WORD
*) p
) = cbData
;
52 memcpy(p
, lpszPath
, pathLen
);
55 memcpy(p
, lpcFindDataPidl
, lpcFindDataPidl
->mkid
.cb
);
56 p
+= lpcFindDataPidl
->mkid
.cb
;
63 static LPCWSTR
_ILGetPath(LPCITEMIDLIST pidl
)
65 if (!pidl
|| !pidl
->mkid
.cb
)
67 return (LPCWSTR
) pidl
->mkid
.abID
;
70 static LPCITEMIDLIST
_ILGetFSPidl(LPCITEMIDLIST pidl
)
72 if (!pidl
|| !pidl
->mkid
.cb
)
74 return (LPCITEMIDLIST
) ((LPBYTE
) pidl
->mkid
.abID
75 + ((wcslen((LPCWSTR
) pidl
->mkid
.abID
) + 1) * sizeof(WCHAR
)));
78 LRESULT
CFindFolder::AddItem(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
&bHandled
)
84 LPWSTR path
= (LPWSTR
) lParam
;
86 CComPtr
<IShellFolder
> pShellFolder
;
87 hr
= SHGetDesktopFolder(&pShellFolder
);
88 if (FAILED_UNEXPECTEDLY(hr
))
94 CComHeapPtr
<ITEMIDLIST
> lpFSPidl
;
96 hr
= pShellFolder
->ParseDisplayName(NULL
, NULL
, path
, &pchEaten
, &lpFSPidl
, NULL
);
97 if (FAILED_UNEXPECTEDLY(hr
))
103 LPITEMIDLIST lpLastFSPidl
= ILFindLastID(lpFSPidl
);
104 CComHeapPtr
<ITEMIDLIST
> lpSearchPidl(_ILCreate(path
, lpLastFSPidl
));
108 return E_OUTOFMEMORY
;
112 hr
= m_shellFolderView
->AddObject(lpSearchPidl
, &uItemIndex
);
117 LRESULT
CFindFolder::UpdateStatus(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
&bHandled
)
119 LPWSTR status
= (LPWSTR
) lParam
;
122 m_shellBrowser
->SetStatusTextSB(status
);
129 // *** IShellFolder2 methods ***
130 STDMETHODIMP
CFindFolder::GetDefaultSearchGUID(GUID
*pguid
)
136 STDMETHODIMP
CFindFolder::EnumSearches(IEnumExtraSearch
**ppenum
)
142 STDMETHODIMP
CFindFolder::GetDefaultColumn(DWORD
, ULONG
*pSort
, ULONG
*pDisplay
)
151 STDMETHODIMP
CFindFolder::GetDefaultColumnState(UINT iColumn
, DWORD
*pcsFlags
)
155 if (iColumn
>= _countof(g_ColumnDefs
))
156 return m_pisfInner
->GetDefaultColumnState(iColumn
- _countof(g_ColumnDefs
) + 1, pcsFlags
);
157 *pcsFlags
= g_ColumnDefs
[iColumn
].dwDefaultState
;
161 STDMETHODIMP
CFindFolder::GetDetailsEx(PCUITEMID_CHILD pidl
, const SHCOLUMNID
*pscid
, VARIANT
*pv
)
163 return m_pisfInner
->GetDetailsEx(pidl
, pscid
, pv
);
166 STDMETHODIMP
CFindFolder::GetDetailsOf(PCUITEMID_CHILD pidl
, UINT iColumn
, SHELLDETAILS
*pDetails
)
168 if (iColumn
>= _countof(g_ColumnDefs
))
169 return m_pisfInner
->GetDetailsOf(_ILGetFSPidl(pidl
), iColumn
- _countof(g_ColumnDefs
) + 1, pDetails
);
171 pDetails
->cxChar
= g_ColumnDefs
[iColumn
].cxChar
;
172 pDetails
->fmt
= g_ColumnDefs
[iColumn
].fmt
;
175 return SHSetStrRet(&pDetails
->str
, g_ColumnDefs
[iColumn
].wzColumnName
);
179 WCHAR path
[MAX_PATH
];
180 wcscpy(path
, _ILGetPath(pidl
));
181 PathRemoveFileSpecW(path
);
182 return SHSetStrRet(&pDetails
->str
, path
);
185 return GetDisplayNameOf(pidl
, SHGDN_NORMAL
, &pDetails
->str
);
188 STDMETHODIMP
CFindFolder::MapColumnToSCID(UINT iColumn
, SHCOLUMNID
*pscid
)
194 // *** IShellFolder methods ***
195 STDMETHODIMP
CFindFolder::ParseDisplayName(HWND hwndOwner
, LPBC pbc
, LPOLESTR lpszDisplayName
, ULONG
*pchEaten
,
196 PIDLIST_RELATIVE
*ppidl
, ULONG
*pdwAttributes
)
202 STDMETHODIMP
CFindFolder::EnumObjects(HWND hwndOwner
, DWORD dwFlags
, LPENUMIDLIST
*ppEnumIDList
)
204 *ppEnumIDList
= NULL
;
208 STDMETHODIMP
CFindFolder::BindToObject(PCUIDLIST_RELATIVE pidl
, LPBC pbcReserved
, REFIID riid
, LPVOID
*ppvOut
)
214 STDMETHODIMP
CFindFolder::BindToStorage(PCUIDLIST_RELATIVE pidl
, LPBC pbcReserved
, REFIID riid
, LPVOID
*ppvOut
)
220 STDMETHODIMP
CFindFolder::CompareIDs(LPARAM lParam
, PCUIDLIST_RELATIVE pidl1
, PCUIDLIST_RELATIVE pidl2
)
222 return m_pisfInner
->CompareIDs(lParam
, _ILGetFSPidl(pidl1
), _ILGetFSPidl(pidl2
));
225 STDMETHODIMP
CFindFolder::CreateViewObject(HWND hwndOwner
, REFIID riid
, LPVOID
*ppvOut
)
227 if (riid
== IID_IShellView
)
229 SFV_CREATE sfvparams
= {};
230 sfvparams
.cbSize
= sizeof(SFV_CREATE
);
231 sfvparams
.pshf
= this;
232 sfvparams
.psfvcb
= this;
233 HRESULT hr
= SHCreateShellFolderView(&sfvparams
, (IShellView
**) ppvOut
);
234 if (FAILED_UNEXPECTEDLY(hr
))
239 return ((IShellView
* ) * ppvOut
)->QueryInterface(IID_PPV_ARG(IShellFolderView
, &m_shellFolderView
));
241 return E_NOINTERFACE
;
244 STDMETHODIMP
CFindFolder::GetAttributesOf(UINT cidl
, PCUITEMID_CHILD_ARRAY apidl
, DWORD
*rgfInOut
)
246 CComHeapPtr
<PCITEMID_CHILD
> aFSPidl
;
247 aFSPidl
.Allocate(cidl
);
248 for (UINT i
= 0; i
< cidl
; i
++)
250 aFSPidl
[i
] = _ILGetFSPidl(apidl
[i
]);
253 return m_pisfInner
->GetAttributesOf(cidl
, aFSPidl
, rgfInOut
);
256 STDMETHODIMP
CFindFolder::GetUIObjectOf(HWND hwndOwner
, UINT cidl
, PCUITEMID_CHILD_ARRAY apidl
, REFIID riid
,
257 UINT
*prgfInOut
, LPVOID
*ppvOut
)
259 if (riid
== IID_IDataObject
&& cidl
== 1)
261 WCHAR path
[MAX_PATH
];
262 wcscpy(path
, (LPCWSTR
) apidl
[0]->mkid
.abID
);
263 PathRemoveFileSpecW(path
);
264 CComHeapPtr
<ITEMIDLIST
> rootPidl(ILCreateFromPathW(path
));
266 return E_OUTOFMEMORY
;
267 PCITEMID_CHILD aFSPidl
[1];
268 aFSPidl
[0] = _ILGetFSPidl(apidl
[0]);
269 return IDataObject_Constructor(hwndOwner
, rootPidl
, aFSPidl
, cidl
, (IDataObject
**) ppvOut
);
274 return m_pisfInner
->GetUIObjectOf(hwndOwner
, cidl
, apidl
, riid
, prgfInOut
, ppvOut
);
277 PCITEMID_CHILD
*aFSPidl
= new PCITEMID_CHILD
[cidl
];
278 for (UINT i
= 0; i
< cidl
; i
++)
280 aFSPidl
[i
] = _ILGetFSPidl(apidl
[i
]);
283 if (riid
== IID_IContextMenu
)
287 AddFSClassKeysToArray(aFSPidl
[0], hKeys
, &cKeys
);
290 dcm
.hwnd
= hwndOwner
;
292 dcm
.pidlFolder
= m_pidl
;
298 dcm
.punkAssociationInfo
= NULL
;
299 HRESULT hr
= SHCreateDefaultContextMenu(&dcm
, riid
, ppvOut
);
305 HRESULT hr
= m_pisfInner
->GetUIObjectOf(hwndOwner
, cidl
, aFSPidl
, riid
, prgfInOut
, ppvOut
);
311 STDMETHODIMP
CFindFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl
, DWORD dwFlags
, LPSTRRET pName
)
313 return m_pisfInner
->GetDisplayNameOf(_ILGetFSPidl(pidl
), dwFlags
, pName
);
316 STDMETHODIMP
CFindFolder::SetNameOf(HWND hwndOwner
, PCUITEMID_CHILD pidl
, LPCOLESTR lpName
, DWORD dwFlags
,
317 PITEMID_CHILD
*pPidlOut
)
323 //// *** IShellFolderViewCB method ***
324 STDMETHODIMP
CFindFolder::MessageSFVCB(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
328 case SFVM_DEFVIEWMODE
:
330 FOLDERVIEWMODE
*pViewMode
= (FOLDERVIEWMODE
*) lParam
;
331 *pViewMode
= FVM_DETAILS
;
334 case SFVM_WINDOWCREATED
:
336 SubclassWindow((HWND
) wParam
);
338 CComPtr
<IServiceProvider
> pServiceProvider
;
339 HRESULT hr
= m_shellFolderView
->QueryInterface(IID_PPV_ARG(IServiceProvider
, &pServiceProvider
));
340 if (FAILED_UNEXPECTEDLY(hr
))
344 return pServiceProvider
->QueryService(SID_SShellBrowser
, IID_PPV_ARG(IShellBrowser
, &m_shellBrowser
));
350 //// *** IContextMenuCB method ***
351 STDMETHODIMP
CFindFolder::CallBack(IShellFolder
*psf
, HWND hwndOwner
, IDataObject
*pdtobj
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
355 case DFM_MERGECONTEXTMENU
:
357 QCMINFO
*pqcminfo
= (QCMINFO
*) lParam
;
358 _InsertMenuItemW(pqcminfo
->hmenu
, pqcminfo
->indexMenu
++, TRUE
, pqcminfo
->idCmdFirst
++, MFT_SEPARATOR
, NULL
, 0);
359 _InsertMenuItemW(pqcminfo
->hmenu
, pqcminfo
->indexMenu
++, TRUE
, pqcminfo
->idCmdFirst
++, MFT_STRING
, L
"Open Containing Folder", MFS_ENABLED
);
360 _InsertMenuItemW(pqcminfo
->hmenu
, pqcminfo
->indexMenu
++, TRUE
, pqcminfo
->idCmdFirst
++, MFT_SEPARATOR
, NULL
, 0);
363 case DFM_INVOKECOMMAND
:
364 case DFM_INVOKECOMMANDEX
:
369 PCUITEMID_CHILD
*apidl
;
371 HRESULT hr
= m_shellFolderView
->GetSelectedObjects(&apidl
, &cidl
);
372 if (FAILED_UNEXPECTEDLY(hr
))
375 for (UINT i
= 0; i
< cidl
; i
++)
377 CComHeapPtr
<ITEMIDLIST
> pidl
;
379 hr
= SHILCreateFromPathW((LPCWSTR
) apidl
[i
]->mkid
.abID
, &pidl
, &attrs
);
382 SHOpenFolderAndSelectItems(NULL
, 1, &pidl
, 0);
388 case DFM_GETDEFSTATICID
:
391 return Shell_DefaultContextMenuCallBack(m_pisfInner
, pdtobj
);
394 //// *** IPersistFolder2 methods ***
395 STDMETHODIMP
CFindFolder::GetCurFolder(LPITEMIDLIST
*pidl
)
397 *pidl
= ILClone(m_pidl
);
401 // *** IPersistFolder methods ***
402 STDMETHODIMP
CFindFolder::Initialize(LPCITEMIDLIST pidl
)
404 m_pidl
= ILClone(pidl
);
406 return E_OUTOFMEMORY
;
408 return SHELL32_CoCreateInitSF(m_pidl
,
411 &CLSID_ShellFSFolder
,
412 IID_PPV_ARG(IShellFolder2
, &m_pisfInner
));
415 // *** IPersist methods ***
416 STDMETHODIMP
CFindFolder::GetClassID(CLSID
*pClassId
)
418 if (pClassId
== NULL
)
420 memcpy(pClassId
, &CLSID_FindFolder
, sizeof(CLSID
));