[SHELLFIND] Fix handle leak for stop event
[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 ::SendMessageW(data->hwnd, WM_SEARCH_STOP, 0, 0);
228
229 CloseHandle(data->hStopEvent);
230 delete data;
231
232 return 0;
233 }
234
235 void CFindFolder::NotifyConnections(DISPID id)
236 {
237 DISPPARAMS dispatchParams = {0};
238 CComDynamicUnkArray &subscribers =
239 IConnectionPointImpl<CFindFolder, &DIID_DSearchCommandEvents>::m_vec;
240 for (IUnknown** pSubscriber = subscribers.begin(); pSubscriber < subscribers.end(); pSubscriber++)
241 {
242 if (!*pSubscriber)
243 continue;
244
245 CComPtr<IDispatch> pDispatch;
246 HRESULT hResult = (*pSubscriber)->QueryInterface(IID_PPV_ARG(IDispatch, &pDispatch));
247 if (!FAILED_UNEXPECTEDLY(hResult))
248 pDispatch->Invoke(id, GUID_NULL, 0, DISPATCH_METHOD, &dispatchParams, NULL, NULL, NULL);
249 }
250 }
251
252 LRESULT CFindFolder::StartSearch(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
253 {
254 if (!lParam)
255 return 0;
256
257 // Clear all previous search results
258 UINT uItemIndex;
259 m_shellFolderView->RemoveObject(NULL, &uItemIndex);
260
261 _SearchData* pSearchData = new _SearchData();
262 pSearchData->pFindFolder = this;
263 pSearchData->hwnd = m_hWnd;
264
265 SearchStart *pSearchParams = (SearchStart *) lParam;
266 pSearchData->szPath = pSearchParams->szPath;
267 pSearchData->szFileName = pSearchParams->szFileName;
268 pSearchData->szQueryA = pSearchParams->szQuery;
269 pSearchData->szQueryW = pSearchParams->szQuery;
270 SHFree(pSearchParams);
271
272 if (m_hStopEvent)
273 SetEvent(m_hStopEvent);
274 pSearchData->hStopEvent = m_hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
275
276 if (!SHCreateThread(SearchThreadProc, pSearchData, NULL, NULL))
277 {
278 SHFree(pSearchData);
279 return HRESULT_FROM_WIN32(GetLastError());
280 }
281
282 return S_OK;
283 }
284
285 LRESULT CFindFolder::StopSearch(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
286 {
287 if (m_hStopEvent)
288 {
289 SetEvent(m_hStopEvent);
290 m_hStopEvent = NULL;
291 }
292 return 0;
293 }
294
295 LRESULT CFindFolder::AddResult(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
296 {
297 if (!lParam)
298 return 0;
299
300 CComHeapPtr<WCHAR> lpPath((LPWSTR) lParam);
301
302 CComHeapPtr<ITEMIDLIST> lpSearchPidl(_ILCreate(lpPath));
303 if (lpSearchPidl)
304 {
305 UINT uItemIndex;
306 m_shellFolderView->AddObject(lpSearchPidl, &uItemIndex);
307 }
308
309 return 0;
310 }
311
312 LRESULT CFindFolder::UpdateStatus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
313 {
314 CComHeapPtr<WCHAR> status((LPWSTR) lParam);
315 if (m_shellBrowser)
316 {
317 m_shellBrowser->SetStatusTextSB(status);
318 }
319
320 return S_OK;
321 }
322
323 // *** IShellFolder2 methods ***
324 STDMETHODIMP CFindFolder::GetDefaultSearchGUID(GUID *pguid)
325 {
326 UNIMPLEMENTED;
327 return E_NOTIMPL;
328 }
329
330 STDMETHODIMP CFindFolder::EnumSearches(IEnumExtraSearch **ppenum)
331 {
332 UNIMPLEMENTED;
333 return E_NOTIMPL;
334 }
335
336 STDMETHODIMP CFindFolder::GetDefaultColumn(DWORD, ULONG *pSort, ULONG *pDisplay)
337 {
338 if (pSort)
339 *pSort = 0;
340 if (pDisplay)
341 *pDisplay = 0;
342 return S_OK;
343 }
344
345 STDMETHODIMP CFindFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
346 {
347 if (!pcsFlags)
348 return E_INVALIDARG;
349 if (iColumn >= _countof(g_ColumnDefs))
350 return m_pisfInner->GetDefaultColumnState(iColumn - _countof(g_ColumnDefs) + 1, pcsFlags);
351 *pcsFlags = g_ColumnDefs[iColumn].dwDefaultState;
352 return S_OK;
353 }
354
355 STDMETHODIMP CFindFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv)
356 {
357 return m_pisfInner->GetDetailsEx(pidl, pscid, pv);
358 }
359
360 STDMETHODIMP CFindFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *pDetails)
361 {
362 if (iColumn >= _countof(g_ColumnDefs))
363 return m_pisfInner->GetDetailsOf(_ILGetFSPidl(pidl), iColumn - _countof(g_ColumnDefs) + 1, pDetails);
364
365 pDetails->cxChar = g_ColumnDefs[iColumn].cxChar;
366 pDetails->fmt = g_ColumnDefs[iColumn].fmt;
367
368 if (!pidl)
369 return SHSetStrRet(&pDetails->str, g_ColumnDefs[iColumn].wzColumnName);
370
371 if (iColumn == 1)
372 {
373 WCHAR path[MAX_PATH];
374 wcscpy(path, _ILGetPath(pidl));
375 PathRemoveFileSpecW(path);
376 return SHSetStrRet(&pDetails->str, path);
377 }
378
379 return GetDisplayNameOf(pidl, SHGDN_NORMAL, &pDetails->str);
380 }
381
382 STDMETHODIMP CFindFolder::MapColumnToSCID(UINT iColumn, SHCOLUMNID *pscid)
383 {
384 UNIMPLEMENTED;
385 return E_NOTIMPL;
386 }
387
388 // *** IShellFolder methods ***
389 STDMETHODIMP CFindFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, ULONG *pchEaten,
390 PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes)
391 {
392 UNIMPLEMENTED;
393 return E_NOTIMPL;
394 }
395
396 STDMETHODIMP CFindFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
397 {
398 *ppEnumIDList = NULL;
399 return S_FALSE;
400 }
401
402 STDMETHODIMP CFindFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
403 {
404 UNIMPLEMENTED;
405 return E_NOTIMPL;
406 }
407
408 STDMETHODIMP CFindFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
409 {
410 UNIMPLEMENTED;
411 return E_NOTIMPL;
412 }
413
414 STDMETHODIMP CFindFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
415 {
416 return m_pisfInner->CompareIDs(lParam, _ILGetFSPidl(pidl1), _ILGetFSPidl(pidl2));
417 }
418
419 STDMETHODIMP CFindFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut)
420 {
421 if (riid == IID_IShellView)
422 {
423 SFV_CREATE sfvparams = {};
424 sfvparams.cbSize = sizeof(SFV_CREATE);
425 sfvparams.pshf = this;
426 sfvparams.psfvcb = this;
427 HRESULT hr = SHCreateShellFolderView(&sfvparams, (IShellView **) ppvOut);
428 if (FAILED_UNEXPECTEDLY(hr))
429 {
430 return hr;
431 }
432
433 return ((IShellView * ) * ppvOut)->QueryInterface(IID_PPV_ARG(IShellFolderView, &m_shellFolderView));
434 }
435 return E_NOINTERFACE;
436 }
437
438 STDMETHODIMP CFindFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut)
439 {
440 CComHeapPtr<PCITEMID_CHILD> aFSPidl;
441 aFSPidl.Allocate(cidl);
442 for (UINT i = 0; i < cidl; i++)
443 {
444 aFSPidl[i] = _ILGetFSPidl(apidl[i]);
445 }
446
447 return m_pisfInner->GetAttributesOf(cidl, aFSPidl, rgfInOut);
448 }
449
450 STDMETHODIMP CFindFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid,
451 UINT *prgfInOut, LPVOID *ppvOut)
452 {
453 if (riid == IID_IDataObject && cidl == 1)
454 {
455 WCHAR path[MAX_PATH];
456 wcscpy(path, (LPCWSTR) apidl[0]->mkid.abID);
457 PathRemoveFileSpecW(path);
458 CComHeapPtr<ITEMIDLIST> rootPidl(ILCreateFromPathW(path));
459 if (!rootPidl)
460 return E_OUTOFMEMORY;
461 PCITEMID_CHILD aFSPidl[1];
462 aFSPidl[0] = _ILGetFSPidl(apidl[0]);
463 return IDataObject_Constructor(hwndOwner, rootPidl, aFSPidl, cidl, (IDataObject **) ppvOut);
464 }
465
466 if (cidl <= 0)
467 {
468 return m_pisfInner->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, ppvOut);
469 }
470
471 PCITEMID_CHILD *aFSPidl = new PCITEMID_CHILD[cidl];
472 for (UINT i = 0; i < cidl; i++)
473 {
474 aFSPidl[i] = _ILGetFSPidl(apidl[i]);
475 }
476
477 if (riid == IID_IContextMenu)
478 {
479 HKEY hKeys[16];
480 UINT cKeys = 0;
481 AddFSClassKeysToArray(aFSPidl[0], hKeys, &cKeys);
482
483 DEFCONTEXTMENU dcm;
484 dcm.hwnd = hwndOwner;
485 dcm.pcmcb = this;
486 dcm.pidlFolder = m_pidl;
487 dcm.psf = this;
488 dcm.cidl = cidl;
489 dcm.apidl = apidl;
490 dcm.cKeys = cKeys;
491 dcm.aKeys = hKeys;
492 dcm.punkAssociationInfo = NULL;
493 HRESULT hr = SHCreateDefaultContextMenu(&dcm, riid, ppvOut);
494 delete[] aFSPidl;
495
496 return hr;
497 }
498
499 HRESULT hr = m_pisfInner->GetUIObjectOf(hwndOwner, cidl, aFSPidl, riid, prgfInOut, ppvOut);
500 delete[] aFSPidl;
501
502 return hr;
503 }
504
505 STDMETHODIMP CFindFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET pName)
506 {
507 return m_pisfInner->GetDisplayNameOf(_ILGetFSPidl(pidl), dwFlags, pName);
508 }
509
510 STDMETHODIMP CFindFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, LPCOLESTR lpName, DWORD dwFlags,
511 PITEMID_CHILD *pPidlOut)
512 {
513 UNIMPLEMENTED;
514 return E_NOTIMPL;
515 }
516
517 //// *** IShellFolderViewCB method ***
518 STDMETHODIMP CFindFolder::MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
519 {
520 switch (uMsg)
521 {
522 case SFVM_DEFVIEWMODE:
523 {
524 FOLDERVIEWMODE *pViewMode = (FOLDERVIEWMODE *) lParam;
525 *pViewMode = FVM_DETAILS;
526 return S_OK;
527 }
528 case SFVM_WINDOWCREATED:
529 {
530 SubclassWindow((HWND) wParam);
531
532 CComPtr<IServiceProvider> pServiceProvider;
533 HRESULT hr = m_shellFolderView->QueryInterface(IID_PPV_ARG(IServiceProvider, &pServiceProvider));
534 if (FAILED_UNEXPECTEDLY(hr))
535 {
536 return hr;
537 }
538 return pServiceProvider->QueryService(SID_SShellBrowser, IID_PPV_ARG(IShellBrowser, &m_shellBrowser));
539 }
540 }
541 return E_NOTIMPL;
542 }
543
544 //// *** IContextMenuCB method ***
545 STDMETHODIMP CFindFolder::CallBack(IShellFolder *psf, HWND hwndOwner, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
546 {
547 switch (uMsg)
548 {
549 case DFM_MERGECONTEXTMENU:
550 {
551 QCMINFO *pqcminfo = (QCMINFO *) lParam;
552 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, pqcminfo->idCmdFirst++, MFT_SEPARATOR, NULL, 0);
553 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, pqcminfo->idCmdFirst++, MFT_STRING, L"Open Containing Folder", MFS_ENABLED);
554 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, pqcminfo->idCmdFirst++, MFT_SEPARATOR, NULL, 0);
555 return S_OK;
556 }
557 case DFM_INVOKECOMMAND:
558 case DFM_INVOKECOMMANDEX:
559 {
560 if (wParam != 1)
561 break;
562
563 PCUITEMID_CHILD *apidl;
564 UINT cidl;
565 HRESULT hr = m_shellFolderView->GetSelectedObjects(&apidl, &cidl);
566 if (FAILED_UNEXPECTEDLY(hr))
567 return hr;
568
569 for (UINT i = 0; i < cidl; i++)
570 {
571 CComHeapPtr<ITEMIDLIST> pidl;
572 DWORD attrs = 0;
573 hr = SHILCreateFromPathW((LPCWSTR) apidl[i]->mkid.abID, &pidl, &attrs);
574 if (SUCCEEDED(hr))
575 {
576 SHOpenFolderAndSelectItems(NULL, 1, &pidl, 0);
577 }
578 }
579
580 return S_OK;
581 }
582 case DFM_GETDEFSTATICID:
583 return S_FALSE;
584 }
585 return Shell_DefaultContextMenuCallBack(m_pisfInner, pdtobj);
586 }
587
588 //// *** IPersistFolder2 methods ***
589 STDMETHODIMP CFindFolder::GetCurFolder(LPITEMIDLIST *pidl)
590 {
591 *pidl = ILClone(m_pidl);
592 return S_OK;
593 }
594
595 // *** IPersistFolder methods ***
596 STDMETHODIMP CFindFolder::Initialize(LPCITEMIDLIST pidl)
597 {
598 m_pidl = ILClone(pidl);
599 if (!m_pidl)
600 return E_OUTOFMEMORY;
601
602 return SHELL32_CoCreateInitSF(m_pidl,
603 NULL,
604 NULL,
605 &CLSID_ShellFSFolder,
606 IID_PPV_ARG(IShellFolder2, &m_pisfInner));
607 }
608
609 // *** IPersist methods ***
610 STDMETHODIMP CFindFolder::GetClassID(CLSID *pClassId)
611 {
612 if (pClassId == NULL)
613 return E_INVALIDARG;
614 *pClassId = CLSID_FindFolder;
615 return S_OK;
616 }