[SHELLFIND] Message handler for adding search results
[reactos.git] / dll / win32 / browseui / shellfind / CFindFolder.cpp
1 /*
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
6 */
7
8 #include "CFindFolder.h"
9
10 WINE_DEFAULT_DEBUG_CHANNEL(shellfind);
11
12 struct FolderViewColumns
13 {
14 LPCWSTR wzColumnName;
15 DWORD dwDefaultState;
16 int fmt;
17 int cxChar;
18 };
19
20 static FolderViewColumns g_ColumnDefs[] =
21 {
22 {L"Name", SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 30},
23 {L"In Folder", SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 30},
24 {L"Relevance", SHCOLSTATE_TYPE_STR, LVCFMT_LEFT, 0}
25 };
26
27 static LPITEMIDLIST _ILCreate(LPCWSTR lpszPath, LPCITEMIDLIST lpcFindDataPidl)
28 {
29 int pathLen = (wcslen(lpszPath) + 1) * sizeof(WCHAR);
30 int cbData = sizeof(WORD) + pathLen + lpcFindDataPidl->mkid.cb;
31 LPITEMIDLIST pidl = (LPITEMIDLIST) SHAlloc(cbData + sizeof(WORD));
32 if (!pidl)
33 return NULL;
34
35 LPBYTE p = (LPBYTE) pidl;
36 *((WORD *) p) = cbData;
37 p += sizeof(WORD);
38
39 memcpy(p, lpszPath, pathLen);
40 p += pathLen;
41
42 memcpy(p, lpcFindDataPidl, lpcFindDataPidl->mkid.cb);
43 p += lpcFindDataPidl->mkid.cb;
44
45 *((WORD *) p) = 0;
46
47 return pidl;
48 }
49
50 static LPCWSTR _ILGetPath(LPCITEMIDLIST pidl)
51 {
52 if (!pidl || !pidl->mkid.cb)
53 return NULL;
54 return (LPCWSTR) pidl->mkid.abID;
55 }
56
57 static LPCITEMIDLIST _ILGetFSPidl(LPCITEMIDLIST pidl)
58 {
59 if (!pidl || !pidl->mkid.cb)
60 return pidl;
61 return (LPCITEMIDLIST) ((LPBYTE) pidl->mkid.abID
62 + ((wcslen((LPCWSTR) pidl->mkid.abID) + 1) * sizeof(WCHAR)));
63 }
64
65 LRESULT CFindFolder::AddItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
66 {
67 if (!lParam)
68 return 0;
69
70 HRESULT hr;
71 LPWSTR path = (LPWSTR) lParam;
72
73 CComPtr<IShellFolder> pShellFolder;
74 hr = SHGetDesktopFolder(&pShellFolder);
75 if (FAILED_UNEXPECTEDLY(hr))
76 {
77 LocalFree(path);
78 return hr;
79 }
80
81 LPITEMIDLIST lpFSPidl;
82 DWORD pchEaten;
83 hr = pShellFolder->ParseDisplayName(NULL, NULL, path, &pchEaten, &lpFSPidl, NULL);
84 if (FAILED_UNEXPECTEDLY(hr))
85 {
86 LocalFree(path);
87 return hr;
88 }
89
90 LPITEMIDLIST lpLastFSPidl = ILFindLastID(lpFSPidl);
91 LPITEMIDLIST lpSearchPidl = _ILCreate(path, lpLastFSPidl);
92 ILFree(lpFSPidl);
93 LocalFree(path);
94 if (!lpSearchPidl)
95 {
96 return E_OUTOFMEMORY;
97 }
98
99 UINT uItemIndex;
100 hr = m_shellFolderView->AddObject(lpSearchPidl, &uItemIndex);
101 ILFree(lpSearchPidl);
102
103 return hr;
104 }
105
106 // *** IShellFolder2 methods ***
107 STDMETHODIMP CFindFolder::GetDefaultSearchGUID(GUID *pguid)
108 {
109 UNIMPLEMENTED;
110 return E_NOTIMPL;
111 }
112
113 STDMETHODIMP CFindFolder::EnumSearches(IEnumExtraSearch **ppenum)
114 {
115 UNIMPLEMENTED;
116 return E_NOTIMPL;
117 }
118
119 STDMETHODIMP CFindFolder::GetDefaultColumn(DWORD, ULONG *pSort, ULONG *pDisplay)
120 {
121 if (pSort)
122 *pSort = 0;
123 if (pDisplay)
124 *pDisplay = 0;
125 return S_OK;
126 }
127
128 STDMETHODIMP CFindFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
129 {
130 if (!pcsFlags)
131 return E_INVALIDARG;
132 if (iColumn >= _countof(g_ColumnDefs))
133 return m_pisfInner->GetDefaultColumnState(iColumn - _countof(g_ColumnDefs) + 1, pcsFlags);
134 *pcsFlags = g_ColumnDefs[iColumn].dwDefaultState;
135 return S_OK;
136 }
137
138 STDMETHODIMP CFindFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv)
139 {
140 return m_pisfInner->GetDetailsEx(pidl, pscid, pv);
141 }
142
143 STDMETHODIMP CFindFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *pDetails)
144 {
145 if (iColumn >= _countof(g_ColumnDefs))
146 return m_pisfInner->GetDetailsOf(_ILGetFSPidl(pidl), iColumn - _countof(g_ColumnDefs) + 1, pDetails);
147
148 pDetails->cxChar = g_ColumnDefs[iColumn].cxChar;
149 pDetails->fmt = g_ColumnDefs[iColumn].fmt;
150
151 if (!pidl)
152 return SHSetStrRet(&pDetails->str, g_ColumnDefs[iColumn].wzColumnName);
153
154 if (iColumn == 1)
155 {
156 WCHAR path[MAX_PATH];
157 wcscpy(path, _ILGetPath(pidl));
158 PathRemoveFileSpecW(path);
159 return SHSetStrRet(&pDetails->str, path);
160 }
161
162 return GetDisplayNameOf(pidl, SHGDN_NORMAL, &pDetails->str);
163 }
164
165 STDMETHODIMP CFindFolder::MapColumnToSCID(UINT iColumn, SHCOLUMNID *pscid)
166 {
167 UNIMPLEMENTED;
168 return E_NOTIMPL;
169 }
170
171 // *** IShellFolder methods ***
172 STDMETHODIMP CFindFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, ULONG *pchEaten,
173 PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes)
174 {
175 UNIMPLEMENTED;
176 return E_NOTIMPL;
177 }
178
179 STDMETHODIMP CFindFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
180 {
181 *ppEnumIDList = NULL;
182 return S_FALSE;
183 }
184
185 STDMETHODIMP CFindFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
186 {
187 UNIMPLEMENTED;
188 return E_NOTIMPL;
189 }
190
191 STDMETHODIMP CFindFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
192 {
193 UNIMPLEMENTED;
194 return E_NOTIMPL;
195 }
196
197 STDMETHODIMP CFindFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
198 {
199 return m_pisfInner->CompareIDs(lParam, _ILGetFSPidl(pidl1), _ILGetFSPidl(pidl2));
200 }
201
202 STDMETHODIMP CFindFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut)
203 {
204 if (riid == IID_IShellView)
205 {
206 SFV_CREATE sfvparams = {};
207 sfvparams.cbSize = sizeof(SFV_CREATE);
208 sfvparams.pshf = this;
209 sfvparams.psfvcb = this;
210 HRESULT hr = SHCreateShellFolderView(&sfvparams, (IShellView **) ppvOut);
211 if (FAILED_UNEXPECTEDLY(hr))
212 {
213 return hr;
214 }
215
216 return ((IShellView * ) * ppvOut)->QueryInterface(IID_PPV_ARG(IShellFolderView, &m_shellFolderView));
217 }
218 return E_NOINTERFACE;
219 }
220
221 STDMETHODIMP CFindFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut)
222 {
223 CComHeapPtr<PCITEMID_CHILD> aFSPidl;
224 aFSPidl.Allocate(cidl);
225 for (UINT i = 0; i < cidl; i++)
226 {
227 aFSPidl[i] = _ILGetFSPidl(apidl[i]);
228 }
229
230 return m_pisfInner->GetAttributesOf(cidl, aFSPidl, rgfInOut);
231 }
232
233 STDMETHODIMP CFindFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid,
234 UINT *prgfInOut, LPVOID *ppvOut)
235 {
236 if (cidl <= 0)
237 {
238 return m_pisfInner->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, ppvOut);
239 }
240
241 PCITEMID_CHILD *aFSPidl = new PCITEMID_CHILD[cidl];
242 for (UINT i = 0; i < cidl; i++)
243 {
244 aFSPidl[i] = _ILGetFSPidl(apidl[i]);
245 }
246
247 HRESULT hr = m_pisfInner->GetUIObjectOf(hwndOwner, cidl, aFSPidl, riid, prgfInOut, ppvOut);
248 delete[] aFSPidl;
249
250 return hr;
251 }
252
253 STDMETHODIMP CFindFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET pName)
254 {
255 return m_pisfInner->GetDisplayNameOf(_ILGetFSPidl(pidl), dwFlags, pName);
256 }
257
258 STDMETHODIMP CFindFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, LPCOLESTR lpName, DWORD dwFlags,
259 PITEMID_CHILD *pPidlOut)
260 {
261 UNIMPLEMENTED;
262 return E_NOTIMPL;
263 }
264
265 //// *** IShellFolderViewCB method ***
266 STDMETHODIMP CFindFolder::MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
267 {
268 switch (uMsg)
269 {
270 case SFVM_DEFVIEWMODE:
271 {
272 FOLDERVIEWMODE *pViewMode = (FOLDERVIEWMODE *) lParam;
273 *pViewMode = FVM_DETAILS;
274 return S_OK;
275 }
276 case SFVM_WINDOWCREATED:
277 {
278 SubclassWindow((HWND) wParam);
279 return S_OK;
280 }
281 }
282 return E_NOTIMPL;
283 }
284
285 //// *** IPersistFolder2 methods ***
286 STDMETHODIMP CFindFolder::GetCurFolder(LPITEMIDLIST *pidl)
287 {
288 *pidl = ILClone(m_pidl);
289 return S_OK;
290 }
291
292 // *** IPersistFolder methods ***
293 STDMETHODIMP CFindFolder::Initialize(LPCITEMIDLIST pidl)
294 {
295 m_pidl = ILClone(pidl);
296 if (!m_pidl)
297 return E_OUTOFMEMORY;
298
299 return SHELL32_CoCreateInitSF(m_pidl,
300 NULL,
301 NULL,
302 &CLSID_ShellFSFolder,
303 IID_PPV_ARG(IShellFolder2, &m_pisfInner));
304 }
305
306 // *** IPersist methods ***
307 STDMETHODIMP CFindFolder::GetClassID(CLSID *pClassId)
308 {
309 if (pClassId == NULL)
310 return E_INVALIDARG;
311 memcpy(pClassId, &CLSID_FindFolder, sizeof(CLSID));
312 return S_OK;
313 }