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