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 static LPITEMIDLIST
_ILCreate(LPCWSTR lpszPath
, LPCITEMIDLIST lpcFindDataPidl
)
37 int pathLen
= (wcslen(lpszPath
) + 1) * sizeof(WCHAR
);
38 int cbData
= sizeof(WORD
) + pathLen
+ lpcFindDataPidl
->mkid
.cb
;
39 LPITEMIDLIST pidl
= (LPITEMIDLIST
) SHAlloc(cbData
+ sizeof(WORD
));
43 LPBYTE p
= (LPBYTE
) pidl
;
44 *((WORD
*) p
) = cbData
;
47 memcpy(p
, lpszPath
, pathLen
);
50 memcpy(p
, lpcFindDataPidl
, lpcFindDataPidl
->mkid
.cb
);
51 p
+= lpcFindDataPidl
->mkid
.cb
;
58 static LPCWSTR
_ILGetPath(LPCITEMIDLIST pidl
)
60 if (!pidl
|| !pidl
->mkid
.cb
)
62 return (LPCWSTR
) pidl
->mkid
.abID
;
65 static LPCITEMIDLIST
_ILGetFSPidl(LPCITEMIDLIST pidl
)
67 if (!pidl
|| !pidl
->mkid
.cb
)
69 return (LPCITEMIDLIST
) ((LPBYTE
) pidl
->mkid
.abID
70 + ((wcslen((LPCWSTR
) pidl
->mkid
.abID
) + 1) * sizeof(WCHAR
)));
73 LRESULT
CFindFolder::AddItem(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
&bHandled
)
79 LPWSTR path
= (LPWSTR
) lParam
;
81 CComPtr
<IShellFolder
> pShellFolder
;
82 hr
= SHGetDesktopFolder(&pShellFolder
);
83 if (FAILED_UNEXPECTEDLY(hr
))
89 LPITEMIDLIST lpFSPidl
;
91 hr
= pShellFolder
->ParseDisplayName(NULL
, NULL
, path
, &pchEaten
, &lpFSPidl
, NULL
);
92 if (FAILED_UNEXPECTEDLY(hr
))
98 LPITEMIDLIST lpLastFSPidl
= ILFindLastID(lpFSPidl
);
99 LPITEMIDLIST lpSearchPidl
= _ILCreate(path
, lpLastFSPidl
);
104 return E_OUTOFMEMORY
;
108 hr
= m_shellFolderView
->AddObject(lpSearchPidl
, &uItemIndex
);
109 ILFree(lpSearchPidl
);
114 LRESULT
CFindFolder::UpdateStatus(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
&bHandled
)
116 LPWSTR status
= (LPWSTR
) lParam
;
119 m_shellBrowser
->SetStatusTextSB(status
);
126 // *** IShellFolder2 methods ***
127 STDMETHODIMP
CFindFolder::GetDefaultSearchGUID(GUID
*pguid
)
133 STDMETHODIMP
CFindFolder::EnumSearches(IEnumExtraSearch
**ppenum
)
139 STDMETHODIMP
CFindFolder::GetDefaultColumn(DWORD
, ULONG
*pSort
, ULONG
*pDisplay
)
148 STDMETHODIMP
CFindFolder::GetDefaultColumnState(UINT iColumn
, DWORD
*pcsFlags
)
152 if (iColumn
>= _countof(g_ColumnDefs
))
153 return m_pisfInner
->GetDefaultColumnState(iColumn
- _countof(g_ColumnDefs
) + 1, pcsFlags
);
154 *pcsFlags
= g_ColumnDefs
[iColumn
].dwDefaultState
;
158 STDMETHODIMP
CFindFolder::GetDetailsEx(PCUITEMID_CHILD pidl
, const SHCOLUMNID
*pscid
, VARIANT
*pv
)
160 return m_pisfInner
->GetDetailsEx(pidl
, pscid
, pv
);
163 STDMETHODIMP
CFindFolder::GetDetailsOf(PCUITEMID_CHILD pidl
, UINT iColumn
, SHELLDETAILS
*pDetails
)
165 if (iColumn
>= _countof(g_ColumnDefs
))
166 return m_pisfInner
->GetDetailsOf(_ILGetFSPidl(pidl
), iColumn
- _countof(g_ColumnDefs
) + 1, pDetails
);
168 pDetails
->cxChar
= g_ColumnDefs
[iColumn
].cxChar
;
169 pDetails
->fmt
= g_ColumnDefs
[iColumn
].fmt
;
172 return SHSetStrRet(&pDetails
->str
, g_ColumnDefs
[iColumn
].wzColumnName
);
176 WCHAR path
[MAX_PATH
];
177 wcscpy(path
, _ILGetPath(pidl
));
178 PathRemoveFileSpecW(path
);
179 return SHSetStrRet(&pDetails
->str
, path
);
182 return GetDisplayNameOf(pidl
, SHGDN_NORMAL
, &pDetails
->str
);
185 STDMETHODIMP
CFindFolder::MapColumnToSCID(UINT iColumn
, SHCOLUMNID
*pscid
)
191 // *** IShellFolder methods ***
192 STDMETHODIMP
CFindFolder::ParseDisplayName(HWND hwndOwner
, LPBC pbc
, LPOLESTR lpszDisplayName
, ULONG
*pchEaten
,
193 PIDLIST_RELATIVE
*ppidl
, ULONG
*pdwAttributes
)
199 STDMETHODIMP
CFindFolder::EnumObjects(HWND hwndOwner
, DWORD dwFlags
, LPENUMIDLIST
*ppEnumIDList
)
201 *ppEnumIDList
= NULL
;
205 STDMETHODIMP
CFindFolder::BindToObject(PCUIDLIST_RELATIVE pidl
, LPBC pbcReserved
, REFIID riid
, LPVOID
*ppvOut
)
211 STDMETHODIMP
CFindFolder::BindToStorage(PCUIDLIST_RELATIVE pidl
, LPBC pbcReserved
, REFIID riid
, LPVOID
*ppvOut
)
217 STDMETHODIMP
CFindFolder::CompareIDs(LPARAM lParam
, PCUIDLIST_RELATIVE pidl1
, PCUIDLIST_RELATIVE pidl2
)
219 return m_pisfInner
->CompareIDs(lParam
, _ILGetFSPidl(pidl1
), _ILGetFSPidl(pidl2
));
222 STDMETHODIMP
CFindFolder::CreateViewObject(HWND hwndOwner
, REFIID riid
, LPVOID
*ppvOut
)
224 if (riid
== IID_IShellView
)
226 SFV_CREATE sfvparams
= {};
227 sfvparams
.cbSize
= sizeof(SFV_CREATE
);
228 sfvparams
.pshf
= this;
229 sfvparams
.psfvcb
= this;
230 HRESULT hr
= SHCreateShellFolderView(&sfvparams
, (IShellView
**) ppvOut
);
231 if (FAILED_UNEXPECTEDLY(hr
))
236 return ((IShellView
* ) * ppvOut
)->QueryInterface(IID_PPV_ARG(IShellFolderView
, &m_shellFolderView
));
238 return E_NOINTERFACE
;
241 STDMETHODIMP
CFindFolder::GetAttributesOf(UINT cidl
, PCUITEMID_CHILD_ARRAY apidl
, DWORD
*rgfInOut
)
243 CComHeapPtr
<PCITEMID_CHILD
> aFSPidl
;
244 aFSPidl
.Allocate(cidl
);
245 for (UINT i
= 0; i
< cidl
; i
++)
247 aFSPidl
[i
] = _ILGetFSPidl(apidl
[i
]);
250 return m_pisfInner
->GetAttributesOf(cidl
, aFSPidl
, rgfInOut
);
253 STDMETHODIMP
CFindFolder::GetUIObjectOf(HWND hwndOwner
, UINT cidl
, PCUITEMID_CHILD_ARRAY apidl
, REFIID riid
,
254 UINT
*prgfInOut
, LPVOID
*ppvOut
)
256 if (riid
== IID_IDataObject
&& cidl
== 1)
258 WCHAR path
[MAX_PATH
];
259 wcscpy(path
, (LPCWSTR
) apidl
[0]->mkid
.abID
);
260 PathRemoveFileSpecW(path
);
261 LPITEMIDLIST rootPidl
= ILCreateFromPathW(path
);
263 return E_OUTOFMEMORY
;
264 PCITEMID_CHILD aFSPidl
[1];
265 aFSPidl
[0] = _ILGetFSPidl(apidl
[0]);
266 return IDataObject_Constructor(hwndOwner
, rootPidl
, aFSPidl
, cidl
, (IDataObject
**) ppvOut
);
271 return m_pisfInner
->GetUIObjectOf(hwndOwner
, cidl
, apidl
, riid
, prgfInOut
, ppvOut
);
274 PCITEMID_CHILD
*aFSPidl
= new PCITEMID_CHILD
[cidl
];
275 for (UINT i
= 0; i
< cidl
; i
++)
277 aFSPidl
[i
] = _ILGetFSPidl(apidl
[i
]);
280 if (riid
== IID_IContextMenu
)
284 AddFSClassKeysToArray(aFSPidl
[0], hKeys
, &cKeys
);
287 dcm
.hwnd
= hwndOwner
;
289 dcm
.pidlFolder
= m_pidl
;
295 dcm
.punkAssociationInfo
= NULL
;
296 HRESULT hr
= SHCreateDefaultContextMenu(&dcm
, riid
, ppvOut
);
302 HRESULT hr
= m_pisfInner
->GetUIObjectOf(hwndOwner
, cidl
, aFSPidl
, riid
, prgfInOut
, ppvOut
);
308 STDMETHODIMP
CFindFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl
, DWORD dwFlags
, LPSTRRET pName
)
310 return m_pisfInner
->GetDisplayNameOf(_ILGetFSPidl(pidl
), dwFlags
, pName
);
313 STDMETHODIMP
CFindFolder::SetNameOf(HWND hwndOwner
, PCUITEMID_CHILD pidl
, LPCOLESTR lpName
, DWORD dwFlags
,
314 PITEMID_CHILD
*pPidlOut
)
320 //// *** IShellFolderViewCB method ***
321 STDMETHODIMP
CFindFolder::MessageSFVCB(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
325 case SFVM_DEFVIEWMODE
:
327 FOLDERVIEWMODE
*pViewMode
= (FOLDERVIEWMODE
*) lParam
;
328 *pViewMode
= FVM_DETAILS
;
331 case SFVM_WINDOWCREATED
:
333 SubclassWindow((HWND
) wParam
);
335 CComPtr
<IServiceProvider
> pServiceProvider
;
336 HRESULT hr
= m_shellFolderView
->QueryInterface(IID_PPV_ARG(IServiceProvider
, &pServiceProvider
));
337 if (FAILED_UNEXPECTEDLY(hr
))
341 return pServiceProvider
->QueryService(SID_SShellBrowser
, IID_PPV_ARG(IShellBrowser
, &m_shellBrowser
));
347 //// *** IContextMenuCB method ***
348 STDMETHODIMP
CFindFolder::CallBack(IShellFolder
*psf
, HWND hwndOwner
, IDataObject
*pdtobj
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
352 case DFM_MERGECONTEXTMENU
:
354 QCMINFO
*pqcminfo
= (QCMINFO
*) lParam
;
355 _InsertMenuItemW(pqcminfo
->hmenu
, pqcminfo
->indexMenu
++, TRUE
, pqcminfo
->idCmdFirst
++, MFT_SEPARATOR
, NULL
, 0);
356 _InsertMenuItemW(pqcminfo
->hmenu
, pqcminfo
->indexMenu
++, TRUE
, pqcminfo
->idCmdFirst
++, MFT_STRING
, L
"Open Containing Folder", MFS_ENABLED
);
357 _InsertMenuItemW(pqcminfo
->hmenu
, pqcminfo
->indexMenu
++, TRUE
, pqcminfo
->idCmdFirst
++, MFT_SEPARATOR
, NULL
, 0);
360 case DFM_INVOKECOMMAND
:
361 case DFM_INVOKECOMMANDEX
:
366 PCUITEMID_CHILD
*apidl
;
368 HRESULT hr
= m_shellFolderView
->GetSelectedObjects(&apidl
, &cidl
);
369 if (FAILED_UNEXPECTEDLY(hr
))
372 for (UINT i
= 0; i
< cidl
; i
++)
376 hr
= SHILCreateFromPathW((LPCWSTR
) apidl
[i
]->mkid
.abID
, &pidl
, &attrs
);
379 SHOpenFolderAndSelectItems(NULL
, 1, &pidl
, 0);
385 case DFM_GETDEFSTATICID
:
388 return Shell_DefaultContextMenuCallBack(m_pisfInner
, pdtobj
);
391 //// *** IPersistFolder2 methods ***
392 STDMETHODIMP
CFindFolder::GetCurFolder(LPITEMIDLIST
*pidl
)
394 *pidl
= ILClone(m_pidl
);
398 // *** IPersistFolder methods ***
399 STDMETHODIMP
CFindFolder::Initialize(LPCITEMIDLIST pidl
)
401 m_pidl
= ILClone(pidl
);
403 return E_OUTOFMEMORY
;
405 return SHELL32_CoCreateInitSF(m_pidl
,
408 &CLSID_ShellFSFolder
,
409 IID_PPV_ARG(IShellFolder2
, &m_pisfInner
));
412 // *** IPersist methods ***
413 STDMETHODIMP
CFindFolder::GetClassID(CLSID
*pClassId
)
415 if (pClassId
== NULL
)
417 memcpy(pClassId
, &CLSID_FindFolder
, sizeof(CLSID
));