0bd98e01dedd844c940d319ab69c3abf7bff8481
[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 #include <exdispid.h>
10
11 WINE_DEFAULT_DEBUG_CHANNEL(shellfind);
12
13 // FIXME: Remove this declaration after the function has been fully implemented
14 EXTERN_C HRESULT
15 WINAPI
16 SHOpenFolderAndSelectItems(LPITEMIDLIST pidlFolder,
17 UINT cidl,
18 PCUITEMID_CHILD_ARRAY apidl,
19 DWORD dwFlags);
20
21 struct FolderViewColumns
22 {
23 LPCWSTR wzColumnName;
24 DWORD dwDefaultState;
25 int fmt;
26 int cxChar;
27 };
28
29 static FolderViewColumns g_ColumnDefs[] =
30 {
31 {L"Name", SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 30},
32 {L"In Folder", SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 30},
33 {L"Relevance", SHCOLSTATE_TYPE_STR, LVCFMT_LEFT, 0}
34 };
35
36 CFindFolder::CFindFolder() :
37 m_hStopEvent(NULL)
38 {
39 }
40
41 static LPITEMIDLIST _ILCreate(LPCWSTR lpszPath)
42 {
43 CComHeapPtr<ITEMIDLIST> lpFSPidl(ILCreateFromPathW(lpszPath));
44 if (!(LPITEMIDLIST)lpFSPidl)
45 {
46 ERR("Failed to create pidl from path\n");
47 return 0;
48 }
49 LPITEMIDLIST lpLastFSPidl = ILFindLastID(lpFSPidl);
50
51 int pathLen = (wcslen(lpszPath) + 1) * sizeof(WCHAR);
52 int cbData = sizeof(WORD) + pathLen + lpLastFSPidl->mkid.cb;
53 LPITEMIDLIST pidl = (LPITEMIDLIST) SHAlloc(cbData + sizeof(WORD));
54 if (!pidl)
55 return NULL;
56
57 LPBYTE p = (LPBYTE) pidl;
58 *((WORD *) p) = cbData;
59 p += sizeof(WORD);
60
61 memcpy(p, lpszPath, pathLen);
62 p += pathLen;
63
64 memcpy(p, lpLastFSPidl, lpLastFSPidl->mkid.cb);
65 p += lpLastFSPidl->mkid.cb;
66
67 *((WORD *) p) = 0;
68
69 return pidl;
70 }
71
72 static LPCWSTR _ILGetPath(LPCITEMIDLIST pidl)
73 {
74 if (!pidl || !pidl->mkid.cb)
75 return NULL;
76 return (LPCWSTR) pidl->mkid.abID;
77 }
78
79 static LPCITEMIDLIST _ILGetFSPidl(LPCITEMIDLIST pidl)
80 {
81 if (!pidl || !pidl->mkid.cb)
82 return pidl;
83 return (LPCITEMIDLIST) ((LPBYTE) pidl->mkid.abID
84 + ((wcslen((LPCWSTR) pidl->mkid.abID) + 1) * sizeof(WCHAR)));
85 }
86
87 struct _SearchData
88 {
89 HWND hwnd;
90 HANDLE hStopEvent;
91 CStringW szPath;
92 CStringW szFileName;
93 CStringA szQueryA;
94 CStringW szQueryW;
95 CComPtr<CFindFolder> pFindFolder;
96 };
97
98 template<typename TChar, typename TString, int (&StrNCmp)(const TChar *, const TChar *, size_t)>
99 static const TChar* StrStrN(const TChar *lpFirst, const TString &lpSrch, UINT cchMax)
100 {
101 if (!lpFirst || lpSrch.IsEmpty() || !cchMax)
102 return NULL;
103
104 for (UINT i = cchMax; i > 0 && *lpFirst; i--, lpFirst++)
105 {
106 if (!StrNCmp(lpFirst, lpSrch, lpSrch.GetLength()))
107 return (const TChar*)lpFirst;
108 }
109
110 return NULL;
111 }
112
113 template<typename TChar, typename TString, int (&StrNCmp)(const TChar *, const TChar *, size_t)>
114 static UINT StrStrNCount(const TChar *lpFirst, const TString &lpSrch, UINT cchMax)
115 {
116 const TChar *lpSearchEnd = lpFirst + cchMax;
117 UINT uCount = 0;
118 while (lpFirst < lpSearchEnd && (lpFirst = StrStrN<TChar, TString, StrNCmp>(lpFirst, lpSrch, cchMax)))
119 {
120 uCount++;
121 lpFirst += lpSrch.GetLength();
122 cchMax = lpSearchEnd - lpFirst;
123 }
124 return uCount;
125 }
126
127 static UINT StrStrCountNIA(const CHAR *lpFirst, const CStringA &lpSrch, UINT cchMax)
128 {
129 return StrStrNCount<CHAR, CStringA, _strnicmp>(lpFirst, lpSrch, cchMax);
130 }
131
132 static UINT StrStrCountNIW(const WCHAR *lpFirst, const CStringW &lpSrch, UINT cchMax)
133 {
134 return StrStrNCount<WCHAR, CStringW, _wcsnicmp>(lpFirst, lpSrch, cchMax);
135 }
136
137 static UINT SearchFile(LPCWSTR lpFilePath, _SearchData *pSearchData)
138 {
139 HANDLE hFile = CreateFileW(lpFilePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
140 if (hFile == INVALID_HANDLE_VALUE)
141 return 0;
142
143 DWORD size = GetFileSize(hFile, NULL);
144 HANDLE hFileMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
145 CloseHandle(hFile);
146 if (hFileMap == INVALID_HANDLE_VALUE)
147 return 0;
148
149 LPBYTE lpFileContent = (LPBYTE) MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
150 CloseHandle(hFileMap);
151 if (!lpFileContent)
152 return 0;
153
154 UINT uMatches = 0;
155 // Check for UTF-16 BOM
156 if (size >= 2 && lpFileContent[0] == 0xFF && lpFileContent[1] == 0xFE)
157 {
158 uMatches = StrStrCountNIW((LPCWSTR) lpFileContent, pSearchData->szQueryW, size / sizeof(WCHAR));
159 }
160 else
161 {
162 uMatches = StrStrCountNIA((LPCSTR) lpFileContent, pSearchData->szQueryA, size / sizeof(CHAR));
163 }
164
165 UnmapViewOfFile(lpFileContent);
166
167 return uMatches;
168 }
169
170 static UINT RecursiveFind(LPCWSTR lpPath, _SearchData *pSearchData)
171 {
172 if (WaitForSingleObject(pSearchData->hStopEvent, 0) != WAIT_TIMEOUT)
173 return 0;
174
175 WCHAR szPath[MAX_PATH];
176 WIN32_FIND_DATAW FindData;
177 HANDLE hFindFile;
178 BOOL bMoreFiles = TRUE;
179 UINT uTotalFound = 0;
180
181 PathCombineW(szPath, lpPath, L"*.*");
182
183 for (hFindFile = FindFirstFileW(szPath, &FindData);
184 bMoreFiles && hFindFile != INVALID_HANDLE_VALUE;
185 bMoreFiles = FindNextFileW(hFindFile, &FindData))
186 {
187 if (!wcscmp(FindData.cFileName, L".") || !wcscmp(FindData.cFileName, L".."))
188 continue;
189
190 PathCombineW(szPath, lpPath, FindData.cFileName);
191
192 if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
193 {
194 CStringW status;
195 status.Format(IDS_SEARCH_FOLDER, FindData.cFileName);
196 PostMessageW(pSearchData->hwnd, WM_SEARCH_UPDATE_STATUS, 0, (LPARAM) StrDupW(status.GetBuffer()));
197
198 uTotalFound += RecursiveFind(szPath, pSearchData);
199 }
200 else if ((pSearchData->szFileName.IsEmpty() || PathMatchSpecW(FindData.cFileName, pSearchData->szFileName))
201 && (pSearchData->szQueryA.IsEmpty() || SearchFile(szPath, pSearchData)))
202 {
203 uTotalFound++;
204 PostMessageW(pSearchData->hwnd, WM_SEARCH_ADD_RESULT, 0, (LPARAM) StrDupW(szPath));
205 }
206 }
207
208 if (hFindFile != INVALID_HANDLE_VALUE)
209 FindClose(hFindFile);
210
211 return uTotalFound;
212 }
213
214 DWORD WINAPI CFindFolder::SearchThreadProc(LPVOID lpParameter)
215 {
216 _SearchData *data = static_cast<_SearchData*>(lpParameter);
217
218 data->pFindFolder->NotifyConnections(DISPID_SEARCHSTART);
219
220 UINT uTotalFound = RecursiveFind(data->szPath, data);
221
222 data->pFindFolder->NotifyConnections(DISPID_SEARCHCOMPLETE);
223
224 CStringW status;
225 status.Format(IDS_SEARCH_FILES_FOUND, uTotalFound);
226 ::PostMessageW(data->hwnd, WM_SEARCH_UPDATE_STATUS, 0, (LPARAM) StrDupW(status.GetBuffer()));
227
228 delete data;
229
230 return 0;
231 }
232
233 void CFindFolder::NotifyConnections(DISPID id)
234 {
235 DISPPARAMS dispatchParams = {0};
236 CComDynamicUnkArray &subscribers =
237 IConnectionPointImpl<CFindFolder, &DIID_DSearchCommandEvents>::m_vec;
238 for (IUnknown** pSubscriber = subscribers.begin(); pSubscriber < subscribers.end(); pSubscriber++)
239 {
240 if (!*pSubscriber)
241 continue;
242
243 CComPtr<IDispatch> pDispatch;
244 HRESULT hResult = (*pSubscriber)->QueryInterface(IID_PPV_ARG(IDispatch, &pDispatch));
245 if (!FAILED_UNEXPECTEDLY(hResult))
246 pDispatch->Invoke(id, GUID_NULL, 0, DISPATCH_METHOD, &dispatchParams, NULL, NULL, NULL);
247 }
248 }
249
250 LRESULT CFindFolder::StartSearch(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
251 {
252 if (!lParam)
253 return 0;
254
255 // Clear all previous search results
256 UINT uItemIndex;
257 m_shellFolderView->RemoveObject(NULL, &uItemIndex);
258
259 _SearchData* pSearchData = new _SearchData();
260 pSearchData->pFindFolder = this;
261 pSearchData->hwnd = m_hWnd;
262
263 SearchStart *pSearchParams = (SearchStart *) lParam;
264 pSearchData->szPath = pSearchParams->szPath;
265 pSearchData->szFileName = pSearchParams->szFileName;
266 pSearchData->szQueryA = pSearchParams->szQuery;
267 pSearchData->szQueryW = pSearchParams->szQuery;
268 SHFree(pSearchParams);
269
270 if (m_hStopEvent)
271 SetEvent(m_hStopEvent);
272 pSearchData->hStopEvent = m_hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
273
274 if (!SHCreateThread(SearchThreadProc, pSearchData, NULL, NULL))
275 {
276 SHFree(pSearchData);
277 return HRESULT_FROM_WIN32(GetLastError());
278 }
279
280 return S_OK;
281 }
282
283 LRESULT CFindFolder::StopSearch(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
284 {
285 if (m_hStopEvent)
286 {
287 SetEvent(m_hStopEvent);
288 m_hStopEvent = NULL;
289 }
290 return 0;
291 }
292
293 LRESULT CFindFolder::AddResult(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
294 {
295 if (!lParam)
296 return 0;
297
298 CComHeapPtr<WCHAR> lpPath((LPWSTR) lParam);
299
300 CComHeapPtr<ITEMIDLIST> lpSearchPidl(_ILCreate(lpPath));
301 if (lpSearchPidl)
302 {
303 UINT uItemIndex;
304 m_shellFolderView->AddObject(lpSearchPidl, &uItemIndex);
305 }
306
307 return 0;
308 }
309
310 LRESULT CFindFolder::UpdateStatus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
311 {
312 CComHeapPtr<WCHAR> status((LPWSTR) lParam);
313 if (m_shellBrowser)
314 {
315 m_shellBrowser->SetStatusTextSB(status);
316 }
317
318 return S_OK;
319 }
320
321 // *** IShellFolder2 methods ***
322 STDMETHODIMP CFindFolder::GetDefaultSearchGUID(GUID *pguid)
323 {
324 UNIMPLEMENTED;
325 return E_NOTIMPL;
326 }
327
328 STDMETHODIMP CFindFolder::EnumSearches(IEnumExtraSearch **ppenum)
329 {
330 UNIMPLEMENTED;
331 return E_NOTIMPL;
332 }
333
334 STDMETHODIMP CFindFolder::GetDefaultColumn(DWORD, ULONG *pSort, ULONG *pDisplay)
335 {
336 if (pSort)
337 *pSort = 0;
338 if (pDisplay)
339 *pDisplay = 0;
340 return S_OK;
341 }
342
343 STDMETHODIMP CFindFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
344 {
345 if (!pcsFlags)
346 return E_INVALIDARG;
347 if (iColumn >= _countof(g_ColumnDefs))
348 return m_pisfInner->GetDefaultColumnState(iColumn - _countof(g_ColumnDefs) + 1, pcsFlags);
349 *pcsFlags = g_ColumnDefs[iColumn].dwDefaultState;
350 return S_OK;
351 }
352
353 STDMETHODIMP CFindFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv)
354 {
355 return m_pisfInner->GetDetailsEx(pidl, pscid, pv);
356 }
357
358 STDMETHODIMP CFindFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *pDetails)
359 {
360 if (iColumn >= _countof(g_ColumnDefs))
361 return m_pisfInner->GetDetailsOf(_ILGetFSPidl(pidl), iColumn - _countof(g_ColumnDefs) + 1, pDetails);
362
363 pDetails->cxChar = g_ColumnDefs[iColumn].cxChar;
364 pDetails->fmt = g_ColumnDefs[iColumn].fmt;
365
366 if (!pidl)
367 return SHSetStrRet(&pDetails->str, g_ColumnDefs[iColumn].wzColumnName);
368
369 if (iColumn == 1)
370 {
371 WCHAR path[MAX_PATH];
372 wcscpy(path, _ILGetPath(pidl));
373 PathRemoveFileSpecW(path);
374 return SHSetStrRet(&pDetails->str, path);
375 }
376
377 return GetDisplayNameOf(pidl, SHGDN_NORMAL, &pDetails->str);
378 }
379
380 STDMETHODIMP CFindFolder::MapColumnToSCID(UINT iColumn, SHCOLUMNID *pscid)
381 {
382 UNIMPLEMENTED;
383 return E_NOTIMPL;
384 }
385
386 // *** IShellFolder methods ***
387 STDMETHODIMP CFindFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, ULONG *pchEaten,
388 PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes)
389 {
390 UNIMPLEMENTED;
391 return E_NOTIMPL;
392 }
393
394 STDMETHODIMP CFindFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
395 {
396 *ppEnumIDList = NULL;
397 return S_FALSE;
398 }
399
400 STDMETHODIMP CFindFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
401 {
402 UNIMPLEMENTED;
403 return E_NOTIMPL;
404 }
405
406 STDMETHODIMP CFindFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
407 {
408 UNIMPLEMENTED;
409 return E_NOTIMPL;
410 }
411
412 STDMETHODIMP CFindFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
413 {
414 return m_pisfInner->CompareIDs(lParam, _ILGetFSPidl(pidl1), _ILGetFSPidl(pidl2));
415 }
416
417 STDMETHODIMP CFindFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut)
418 {
419 if (riid == IID_IShellView)
420 {
421 SFV_CREATE sfvparams = {};
422 sfvparams.cbSize = sizeof(SFV_CREATE);
423 sfvparams.pshf = this;
424 sfvparams.psfvcb = this;
425 HRESULT hr = SHCreateShellFolderView(&sfvparams, (IShellView **) ppvOut);
426 if (FAILED_UNEXPECTEDLY(hr))
427 {
428 return hr;
429 }
430
431 return ((IShellView * ) * ppvOut)->QueryInterface(IID_PPV_ARG(IShellFolderView, &m_shellFolderView));
432 }
433 return E_NOINTERFACE;
434 }
435
436 STDMETHODIMP CFindFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut)
437 {
438 CComHeapPtr<PCITEMID_CHILD> aFSPidl;
439 aFSPidl.Allocate(cidl);
440 for (UINT i = 0; i < cidl; i++)
441 {
442 aFSPidl[i] = _ILGetFSPidl(apidl[i]);
443 }
444
445 return m_pisfInner->GetAttributesOf(cidl, aFSPidl, rgfInOut);
446 }
447
448 STDMETHODIMP CFindFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid,
449 UINT *prgfInOut, LPVOID *ppvOut)
450 {
451 if (riid == IID_IDataObject && cidl == 1)
452 {
453 WCHAR path[MAX_PATH];
454 wcscpy(path, (LPCWSTR) apidl[0]->mkid.abID);
455 PathRemoveFileSpecW(path);
456 CComHeapPtr<ITEMIDLIST> rootPidl(ILCreateFromPathW(path));
457 if (!rootPidl)
458 return E_OUTOFMEMORY;
459 PCITEMID_CHILD aFSPidl[1];
460 aFSPidl[0] = _ILGetFSPidl(apidl[0]);
461 return IDataObject_Constructor(hwndOwner, rootPidl, aFSPidl, cidl, (IDataObject **) ppvOut);
462 }
463
464 if (cidl <= 0)
465 {
466 return m_pisfInner->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, ppvOut);
467 }
468
469 PCITEMID_CHILD *aFSPidl = new PCITEMID_CHILD[cidl];
470 for (UINT i = 0; i < cidl; i++)
471 {
472 aFSPidl[i] = _ILGetFSPidl(apidl[i]);
473 }
474
475 if (riid == IID_IContextMenu)
476 {
477 HKEY hKeys[16];
478 UINT cKeys = 0;
479 AddFSClassKeysToArray(aFSPidl[0], hKeys, &cKeys);
480
481 DEFCONTEXTMENU dcm;
482 dcm.hwnd = hwndOwner;
483 dcm.pcmcb = this;
484 dcm.pidlFolder = m_pidl;
485 dcm.psf = this;
486 dcm.cidl = cidl;
487 dcm.apidl = apidl;
488 dcm.cKeys = cKeys;
489 dcm.aKeys = hKeys;
490 dcm.punkAssociationInfo = NULL;
491 HRESULT hr = SHCreateDefaultContextMenu(&dcm, riid, ppvOut);
492 delete[] aFSPidl;
493
494 return hr;
495 }
496
497 HRESULT hr = m_pisfInner->GetUIObjectOf(hwndOwner, cidl, aFSPidl, riid, prgfInOut, ppvOut);
498 delete[] aFSPidl;
499
500 return hr;
501 }
502
503 STDMETHODIMP CFindFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET pName)
504 {
505 return m_pisfInner->GetDisplayNameOf(_ILGetFSPidl(pidl), dwFlags, pName);
506 }
507
508 STDMETHODIMP CFindFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, LPCOLESTR lpName, DWORD dwFlags,
509 PITEMID_CHILD *pPidlOut)
510 {
511 UNIMPLEMENTED;
512 return E_NOTIMPL;
513 }
514
515 //// *** IShellFolderViewCB method ***
516 STDMETHODIMP CFindFolder::MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
517 {
518 switch (uMsg)
519 {
520 case SFVM_DEFVIEWMODE:
521 {
522 FOLDERVIEWMODE *pViewMode = (FOLDERVIEWMODE *) lParam;
523 *pViewMode = FVM_DETAILS;
524 return S_OK;
525 }
526 case SFVM_WINDOWCREATED:
527 {
528 SubclassWindow((HWND) wParam);
529
530 CComPtr<IServiceProvider> pServiceProvider;
531 HRESULT hr = m_shellFolderView->QueryInterface(IID_PPV_ARG(IServiceProvider, &pServiceProvider));
532 if (FAILED_UNEXPECTEDLY(hr))
533 {
534 return hr;
535 }
536 return pServiceProvider->QueryService(SID_SShellBrowser, IID_PPV_ARG(IShellBrowser, &m_shellBrowser));
537 }
538 }
539 return E_NOTIMPL;
540 }
541
542 //// *** IContextMenuCB method ***
543 STDMETHODIMP CFindFolder::CallBack(IShellFolder *psf, HWND hwndOwner, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
544 {
545 switch (uMsg)
546 {
547 case DFM_MERGECONTEXTMENU:
548 {
549 QCMINFO *pqcminfo = (QCMINFO *) lParam;
550 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, pqcminfo->idCmdFirst++, MFT_SEPARATOR, NULL, 0);
551 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, pqcminfo->idCmdFirst++, MFT_STRING, L"Open Containing Folder", MFS_ENABLED);
552 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, pqcminfo->idCmdFirst++, MFT_SEPARATOR, NULL, 0);
553 return S_OK;
554 }
555 case DFM_INVOKECOMMAND:
556 case DFM_INVOKECOMMANDEX:
557 {
558 if (wParam != 1)
559 break;
560
561 PCUITEMID_CHILD *apidl;
562 UINT cidl;
563 HRESULT hr = m_shellFolderView->GetSelectedObjects(&apidl, &cidl);
564 if (FAILED_UNEXPECTEDLY(hr))
565 return hr;
566
567 for (UINT i = 0; i < cidl; i++)
568 {
569 CComHeapPtr<ITEMIDLIST> pidl;
570 DWORD attrs = 0;
571 hr = SHILCreateFromPathW((LPCWSTR) apidl[i]->mkid.abID, &pidl, &attrs);
572 if (SUCCEEDED(hr))
573 {
574 SHOpenFolderAndSelectItems(NULL, 1, &pidl, 0);
575 }
576 }
577
578 return S_OK;
579 }
580 case DFM_GETDEFSTATICID:
581 return S_FALSE;
582 }
583 return Shell_DefaultContextMenuCallBack(m_pisfInner, pdtobj);
584 }
585
586 //// *** IPersistFolder2 methods ***
587 STDMETHODIMP CFindFolder::GetCurFolder(LPITEMIDLIST *pidl)
588 {
589 *pidl = ILClone(m_pidl);
590 return S_OK;
591 }
592
593 // *** IPersistFolder methods ***
594 STDMETHODIMP CFindFolder::Initialize(LPCITEMIDLIST pidl)
595 {
596 m_pidl = ILClone(pidl);
597 if (!m_pidl)
598 return E_OUTOFMEMORY;
599
600 return SHELL32_CoCreateInitSF(m_pidl,
601 NULL,
602 NULL,
603 &CLSID_ShellFSFolder,
604 IID_PPV_ARG(IShellFolder2, &m_pisfInner));
605 }
606
607 // *** IPersist methods ***
608 STDMETHODIMP CFindFolder::GetClassID(CLSID *pClassId)
609 {
610 if (pClassId == NULL)
611 return E_INVALIDARG;
612 *pClassId = CLSID_FindFolder;
613 return S_OK;
614 }