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 UI
5  * COPYRIGHT:   Copyright 2019 Brock Mammen
6  */
7 
8 #include "CSearchBar.h"
9 #include <psdk/wingdi.h>
10 #include <commoncontrols.h>
11 #include <../browseui.h>
12 #include <shellapi.h>
13 #include <exdispid.h>
14 
15 WINE_DEFAULT_DEBUG_CHANNEL(shellfind);
16 
17 #if 1
18 #undef UNIMPLEMENTED
19 
20 #define UNIMPLEMENTED DbgPrint("%s is UNIMPLEMENTED!\n", __FUNCTION__)
21 #endif
22 
23 CSearchBar::CSearchBar() :
24     m_pSite(NULL),
25     m_bVisible(FALSE)
26 {
27 }
28 
29 CSearchBar::~CSearchBar()
30 {
31 }
32 
33 LRESULT CSearchBar::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
34 {
35     HKEY hkey;
36     DWORD dwType;
37     DWORD size = sizeof(DWORD);
38     DWORD result;
39     DWORD SearchHiddenValue = 0;
40 
41     result = RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer", 0, KEY_QUERY_VALUE, &hkey);
42     if (result == ERROR_SUCCESS)
43     {
44         if (RegQueryValueEx(hkey, L"SearchHidden", NULL, &dwType, (LPBYTE)&SearchHiddenValue, &size) == ERROR_SUCCESS)
45         {
46             if ((dwType != REG_DWORD) || (size != sizeof(DWORD)))
47             {
48                 ERR("RegQueryKey for \"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\SearchHidden\" returned error(s).\n");
49                 SearchHiddenValue = 1;
50             }
51             else
52             {
53                 TRACE("SearchHidden is '%d'.\n", SearchHiddenValue);
54             }
55         }
56         else
57         {
58             ERR("RegQueryKey for \"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\SearchHidden\" Failed.\n");
59         }
60         RegCloseKey(hkey);
61     }
62     else
63         ERR("RegOpenKey for \"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\" Failed.\n");
64 
65     if (SearchHiddenValue != 0)
66         CheckDlgButton(IDC_SEARCH_HIDDEN, BST_CHECKED);
67     else
68         CheckDlgButton(IDC_SEARCH_HIDDEN, BST_UNCHECKED);
69 
70     SetSearchInProgress(FALSE);
71 
72     HWND hCombobox = GetDlgItem(IDC_SEARCH_COMBOBOX);
73     CComPtr<IImageList> pImageList;
74     HRESULT hResult = SHGetImageList(SHIL_SMALL, IID_PPV_ARG(IImageList, &pImageList));
75     SendMessage(hCombobox, CBEM_SETIMAGELIST, 0, FAILED_UNEXPECTEDLY(hResult) ? 0 : reinterpret_cast<LPARAM>(pImageList.p));
76 
77     SendMessage(hCombobox, CBEM_SETEXTENDEDSTYLE,
78         CBES_EX_CASESENSITIVE | CBES_EX_NOSIZELIMIT, CBES_EX_CASESENSITIVE | CBES_EX_NOSIZELIMIT);
79     HWND hEditControl = reinterpret_cast<HWND>(SendMessage(hCombobox, CBEM_GETEDITCONTROL, 0, 0));
80     hResult = CAddressEditBox_CreateInstance(IID_PPV_ARG(IAddressEditBox, &m_AddressEditBox));
81     if (FAILED_UNEXPECTEDLY(hResult))
82         return FALSE;
83 
84     hResult = m_AddressEditBox->Init(hCombobox, hEditControl, 0, m_pSite);
85     if (FAILED_UNEXPECTEDLY(hResult))
86         return FALSE;
87 
88     // Subscribe to navigation events
89     CComPtr<IShellBrowser> pShellBrowser;
90     hResult = IUnknown_QueryService(m_pSite, SID_SShellBrowser, IID_PPV_ARG(IShellBrowser, &pShellBrowser));
91     DWORD dwAdviseCookie;
92     if (SUCCEEDED(hResult))
93         AtlAdvise(pShellBrowser, static_cast<IDispatch *>(this), DIID_DWebBrowserEvents, &dwAdviseCookie);
94 
95     // Invoke the navigate event in case a search results folder is already open
96     DISPPARAMS params = {0};
97     Invoke(DISPID_NAVIGATECOMPLETE2, GUID_NULL, 0, DISPATCH_METHOD, &params, NULL, NULL, NULL);
98 
99     return TRUE;
100 }
101 
102 
103 // *** ATL event handlers ***
104 LRESULT CSearchBar::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
105 {
106     IUnknown_OnFocusChangeIS(m_pSite, static_cast<IDeskBand *>(this), TRUE);
107     bHandled = FALSE;
108     return TRUE;
109 }
110 
111 HRESULT CSearchBar::GetSearchResultsFolder(IShellBrowser **ppShellBrowser, HWND *pHwnd, IShellFolder **ppShellFolder)
112 {
113     HRESULT hr;
114     CComPtr<IShellBrowser> pShellBrowser;
115     if (!ppShellBrowser)
116         ppShellBrowser = &pShellBrowser;
117     if (!*ppShellBrowser)
118     {
119         hr = IUnknown_QueryService(m_pSite, SID_SShellBrowser, IID_PPV_ARG(IShellBrowser, ppShellBrowser));
120         if (FAILED_UNEXPECTEDLY(hr))
121             return hr;
122     }
123 
124     CComPtr<IShellView> pShellView;
125     hr = (*ppShellBrowser)->QueryActiveShellView(&pShellView);
126     if (FAILED(hr) || !pShellView)
127         return hr;
128 
129     CComPtr<IFolderView> pFolderView;
130     hr = pShellView->QueryInterface(IID_PPV_ARG(IFolderView, &pFolderView));
131     if (FAILED(hr) || !pFolderView)
132         return hr;
133 
134     CComPtr<IShellFolder> pShellFolder;
135     if (!ppShellFolder)
136         ppShellFolder = &pShellFolder;
137     hr = pFolderView->GetFolder(IID_PPV_ARG(IShellFolder, ppShellFolder));
138     if (FAILED(hr) || !pShellFolder)
139         return hr;
140 
141     CLSID clsid;
142     hr = IUnknown_GetClassID(*ppShellFolder, &clsid);
143     if (FAILED(hr))
144         return hr;
145     if (clsid != CLSID_FindFolder)
146         return E_FAIL;
147 
148     if (pHwnd)
149     {
150         hr = pShellView->GetWindow(pHwnd);
151         if (FAILED_UNEXPECTEDLY(hr))
152             return hr;
153     }
154 
155     return S_OK;
156 }
157 
158 LRESULT CSearchBar::OnSearchButtonClicked(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
159 {
160     size_t len = 0;
161     WCHAR endchar;
162     WCHAR startchar;
163 
164     CComHeapPtr<SearchStart> pSearchStart(static_cast<SearchStart *>(CoTaskMemAlloc(sizeof(SearchStart))));
165     GetDlgItemText(IDC_SEARCH_FILENAME, pSearchStart->szFileName, _countof(pSearchStart->szFileName));
166     GetDlgItemText(IDC_SEARCH_QUERY, pSearchStart->szQuery, _countof(pSearchStart->szQuery));
167 
168     pSearchStart->SearchHidden = IsDlgButtonChecked(IDC_SEARCH_HIDDEN);
169 
170     if (!GetAddressEditBoxPath(pSearchStart->szPath))
171     {
172         ShellMessageBoxW(_AtlBaseModule.GetResourceInstance(), m_hWnd, MAKEINTRESOURCEW(IDS_SEARCHINVALID), MAKEINTRESOURCEW(IDS_SEARCHLABEL), MB_OK | MB_ICONERROR, pSearchStart->szPath);
173         return 0;
174     }
175 
176     // See if we have an szFileName by testing for its entry lenth > 0 and our searched FileName does not contain
177     // an asterisk or a question mark. If so, then prepend and append an asterisk to the searched FileName.
178     // (i.e. it's equivalent to searching for *<the_file_name>* )
179     if (FAILED (StringCchLengthW (pSearchStart->szFileName, MAX_PATH, &len))) return 0;
180     if ((len > 0) && !wcspbrk(pSearchStart->szFileName, L"*?"))
181     {
182         endchar = pSearchStart->szFileName[len - 1];
183         startchar = pSearchStart->szFileName[0];
184         if ((len < MAX_PATH - 1) && (startchar != L'*'))
185         {
186             memmove(&pSearchStart->szFileName[1], &pSearchStart->szFileName[0],
187                    len * sizeof(WCHAR) + sizeof(WCHAR));
188             len = len + 1;
189             pSearchStart->szFileName[0] = L'*';
190         }
191 
192         // See if our last character is an asterisk and if not and we have room then add one
193         if ((len < MAX_PATH - 1) && (endchar != L'*'))
194             StringCchCatW(pSearchStart->szFileName, MAX_PATH, L"*");
195     }
196 
197     // Print our final search string for szFileName
198     TRACE("Searched szFileName is '%S'.\n", pSearchStart->szFileName);
199 
200     CComPtr<IShellBrowser> pShellBrowser;
201     HRESULT hr = IUnknown_QueryService(m_pSite, SID_SShellBrowser, IID_PPV_ARG(IShellBrowser, &pShellBrowser));
202     if (FAILED_UNEXPECTEDLY(hr))
203         return 0;
204 
205     HWND hwnd;
206     if (FAILED(GetSearchResultsFolder(&pShellBrowser, &hwnd, NULL)))
207     {
208         // Open a new search results folder
209         WCHAR szShellGuid[MAX_PATH];
210         const WCHAR shellGuidPrefix[] = L"shell:::";
211         memcpy(szShellGuid, shellGuidPrefix, sizeof(shellGuidPrefix));
212         hr = StringFromGUID2(CLSID_FindFolder, szShellGuid + _countof(shellGuidPrefix) - 1,
213                              _countof(szShellGuid) - _countof(shellGuidPrefix));
214         if (FAILED_UNEXPECTEDLY(hr))
215             return 0;
216 
217         CComHeapPtr<ITEMIDLIST> findFolderPidl;
218         hr = SHParseDisplayName(szShellGuid, NULL, &findFolderPidl, 0, NULL);
219         if (FAILED_UNEXPECTEDLY(hr))
220             return 0;
221 
222         hr = pShellBrowser->BrowseObject(findFolderPidl, 0);
223         if (FAILED_UNEXPECTEDLY(hr))
224             return 0;
225 
226         hr = GetSearchResultsFolder(&pShellBrowser, &hwnd, NULL);
227         if (FAILED_UNEXPECTEDLY(hr))
228             return 0;
229     }
230 
231     ::PostMessageW(hwnd, WM_SEARCH_START, 0, (LPARAM) pSearchStart.Detach());
232 
233     SetSearchInProgress(TRUE);
234 
235     return 0;
236 }
237 
238 LRESULT CSearchBar::OnStopButtonClicked(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
239 {
240     HWND hwnd;
241     HRESULT hr = GetSearchResultsFolder(NULL, &hwnd, NULL);
242     if (SUCCEEDED(hr))
243         ::PostMessageW(hwnd, WM_SEARCH_STOP, 0, 0);
244 
245     return 0;
246 }
247 
248 BOOL CSearchBar::GetAddressEditBoxPath(WCHAR *szPath)
249 {
250     HWND hComboboxEx = GetDlgItem(IDC_SEARCH_COMBOBOX);
251     ::GetWindowTextW(hComboboxEx, szPath, MAX_PATH);
252     INT iSelectedIndex = SendMessageW(hComboboxEx, CB_GETCURSEL, 0, 0);
253     if (iSelectedIndex != CB_ERR)
254     {
255         WCHAR szItemText[MAX_PATH];
256         COMBOBOXEXITEMW item = {0};
257         item.mask = CBEIF_LPARAM | CBEIF_TEXT;
258         item.iItem = iSelectedIndex;
259         item.pszText = szItemText;
260         item.cchTextMax = _countof(szItemText);
261         SendMessageW(hComboboxEx, CBEM_GETITEMW, 0, (LPARAM)&item);
262 
263         if (!wcscmp(szItemText, szPath) && SHGetPathFromIDListW((LPCITEMIDLIST)item.lParam, szItemText))
264         {
265             StringCbCopyW(szPath, MAX_PATH * sizeof(WCHAR), szItemText);
266             return TRUE;
267         }
268     }
269 
270     DWORD dwAttributes = GetFileAttributesW(szPath);
271     return dwAttributes != INVALID_FILE_ATTRIBUTES
272         && (dwAttributes & FILE_ATTRIBUTE_DIRECTORY);
273 }
274 
275 LRESULT CSearchBar::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
276 {
277     INT iWidth = LOWORD(lParam);
278     INT iPadding = 10;
279 
280     ((CWindow)GetDlgItem(IDC_SEARCH_LABEL)).SetWindowPos(NULL, 0, 0, iWidth - iPadding, 40, SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER);
281 
282     int inputs[] = { IDC_SEARCH_FILENAME, IDC_SEARCH_QUERY, IDC_SEARCH_COMBOBOX, IDC_SEARCH_BUTTON, IDC_SEARCH_STOP_BUTTON, IDC_PROGRESS_BAR };
283     HDWP hdwp = BeginDeferWindowPos(_countof(inputs));
284     for (SIZE_T i = 0; i < _countof(inputs); i++)
285     {
286         CWindow wnd = (CWindow) GetDlgItem(inputs[i]);
287         RECT rect;
288         wnd.GetWindowRect(&rect);
289         POINT pt = { rect.left, rect.top };
290         ScreenToClient(&pt);
291         hdwp = wnd.DeferWindowPos(hdwp,
292                                   HWND_TOP,
293                                   iPadding,
294                                   pt.y,
295                                   iWidth - iPadding * 2,
296                                   rect.bottom - rect.top,
297                                   SWP_NOZORDER | SWP_NOACTIVATE);
298     }
299     EndDeferWindowPos(hdwp);
300 
301     return 0;
302 }
303 
304 
305 // *** IOleWindow methods ***
306 HRESULT STDMETHODCALLTYPE CSearchBar::GetWindow(HWND *lphwnd)
307 {
308     if (!lphwnd)
309         return E_INVALIDARG;
310     *lphwnd = m_hWnd;
311     return S_OK;
312 }
313 
314 HRESULT STDMETHODCALLTYPE CSearchBar::ContextSensitiveHelp(BOOL fEnterMode)
315 {
316     UNIMPLEMENTED;
317     return E_NOTIMPL;
318 }
319 
320 
321 // *** IDockingWindow methods ***
322 HRESULT STDMETHODCALLTYPE CSearchBar::CloseDW(DWORD dwReserved)
323 {
324     // We do nothing, we don't have anything to save yet
325     TRACE("CloseDW called\n");
326     return S_OK;
327 }
328 
329 HRESULT STDMETHODCALLTYPE CSearchBar::ResizeBorderDW(const RECT *prcBorder, IUnknown *punkToolbarSite, BOOL fReserved)
330 {
331     /* Must return E_NOTIMPL according to MSDN */
332     return E_NOTIMPL;
333 }
334 
335 HRESULT STDMETHODCALLTYPE CSearchBar::ShowDW(BOOL fShow)
336 {
337     m_bVisible = fShow;
338     ShowWindow(fShow);
339     return S_OK;
340 }
341 
342 
343 // *** IDeskBand methods ***
344 HRESULT STDMETHODCALLTYPE CSearchBar::GetBandInfo(DWORD dwBandID, DWORD dwViewMode, DESKBANDINFO *pdbi)
345 {
346     if (!pdbi)
347     {
348         return E_INVALIDARG;
349     }
350 
351     if (pdbi->dwMask & DBIM_MINSIZE)
352     {
353         pdbi->ptMinSize.x = 200;
354         pdbi->ptMinSize.y = 30;
355     }
356 
357     if (pdbi->dwMask & DBIM_MAXSIZE)
358     {
359         pdbi->ptMaxSize.y = -1;
360     }
361 
362     if (pdbi->dwMask & DBIM_INTEGRAL)
363     {
364         pdbi->ptIntegral.y = 1;
365     }
366 
367     if (pdbi->dwMask & DBIM_ACTUAL)
368     {
369         pdbi->ptActual.x = 200;
370         pdbi->ptActual.y = 30;
371     }
372 
373     if (pdbi->dwMask & DBIM_TITLE)
374     {
375         if (!LoadStringW(_AtlBaseModule.GetResourceInstance(), IDS_SEARCHLABEL, pdbi->wszTitle, _countof(pdbi->wszTitle)))
376             return HRESULT_FROM_WIN32(GetLastError());
377     }
378 
379     if (pdbi->dwMask & DBIM_MODEFLAGS)
380     {
381         pdbi->dwModeFlags = DBIMF_NORMAL | DBIMF_VARIABLEHEIGHT;
382     }
383 
384     if (pdbi->dwMask & DBIM_BKCOLOR)
385     {
386         pdbi->dwMask &= ~DBIM_BKCOLOR;
387     }
388     return S_OK;
389 }
390 
391 
392 // *** IObjectWithSite methods ***
393 HRESULT STDMETHODCALLTYPE CSearchBar::SetSite(IUnknown *pUnkSite)
394 {
395     HRESULT hr;
396     HWND parentWnd;
397 
398     if (pUnkSite == m_pSite)
399         return S_OK;
400 
401     TRACE("SetSite called \n");
402     if (!pUnkSite)
403     {
404         DestroyWindow();
405         m_hWnd = NULL;
406         return S_OK;
407     }
408 
409     hr = IUnknown_GetWindow(pUnkSite, &parentWnd);
410     if (!SUCCEEDED(hr))
411     {
412         ERR("Could not get parent's window ! Status: %08lx\n", hr);
413         return E_INVALIDARG;
414     }
415 
416     m_pSite = pUnkSite;
417 
418     if (m_hWnd)
419     {
420         // Change its parent
421         SetParent(parentWnd);
422     }
423     else
424     {
425         CDialogImpl::Create(parentWnd);
426 
427     }
428     return S_OK;
429 }
430 
431 HRESULT STDMETHODCALLTYPE CSearchBar::GetSite(REFIID riid, void **ppvSite)
432 {
433     if (!ppvSite)
434         return E_POINTER;
435     *ppvSite = m_pSite;
436     return S_OK;
437 }
438 
439 
440 // *** IInputObject methods ***
441 HRESULT STDMETHODCALLTYPE CSearchBar::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
442 {
443     if (fActivate)
444     {
445         //SetFocus();
446         SetActiveWindow();
447     }
448     // TODO: handle message
449     if(lpMsg)
450     {
451         TranslateMessage(lpMsg);
452         DispatchMessage(lpMsg);
453     }
454     return S_OK;
455 }
456 
457 HRESULT STDMETHODCALLTYPE CSearchBar::HasFocusIO()
458 {
459     return S_OK;
460 }
461 
462 HRESULT STDMETHODCALLTYPE CSearchBar::TranslateAcceleratorIO(LPMSG lpMsg)
463 {
464     if (IsDialogMessage(lpMsg))
465         return S_OK;
466 
467     if ((lpMsg->hwnd == m_hWnd || IsChild(lpMsg->hwnd)))
468     {
469         TranslateMessage(lpMsg);
470         DispatchMessage(lpMsg);
471         return S_OK;
472     }
473 
474     return S_FALSE;
475 }
476 
477 // *** IPersist methods ***
478 HRESULT STDMETHODCALLTYPE CSearchBar::GetClassID(CLSID *pClassID)
479 {
480     if (!pClassID)
481         return E_POINTER;
482     *pClassID = CLSID_FileSearchBand;
483     return S_OK;
484 }
485 
486 
487 // *** IPersistStream methods ***
488 HRESULT STDMETHODCALLTYPE CSearchBar::IsDirty()
489 {
490     UNIMPLEMENTED;
491     return E_NOTIMPL;
492 }
493 
494 HRESULT STDMETHODCALLTYPE CSearchBar::Load(IStream *pStm)
495 {
496     UNIMPLEMENTED;
497     return E_NOTIMPL;
498 }
499 
500 HRESULT STDMETHODCALLTYPE CSearchBar::Save(IStream *pStm, BOOL fClearDirty)
501 {
502     UNIMPLEMENTED;
503     return E_NOTIMPL;
504 }
505 
506 HRESULT STDMETHODCALLTYPE CSearchBar::GetSizeMax(ULARGE_INTEGER *pcbSize)
507 {
508     // TODO: calculate max size
509     UNIMPLEMENTED;
510     return E_NOTIMPL;
511 }
512 
513 
514 // *** IDispatch methods ***
515 HRESULT STDMETHODCALLTYPE CSearchBar::GetTypeInfoCount(UINT *pctinfo)
516 {
517     UNIMPLEMENTED;
518     return E_NOTIMPL;
519 }
520 
521 HRESULT STDMETHODCALLTYPE CSearchBar::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
522 {
523     UNIMPLEMENTED;
524     return E_NOTIMPL;
525 }
526 
527 HRESULT STDMETHODCALLTYPE CSearchBar::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
528 {
529     UNIMPLEMENTED;
530     return E_NOTIMPL;
531 }
532 
533 void CSearchBar::SetSearchInProgress(BOOL bInProgress)
534 {
535     ::ShowWindow(GetDlgItem(IDC_SEARCH_BUTTON), bInProgress ? SW_HIDE : SW_SHOW);
536     ::ShowWindow(GetDlgItem(IDC_SEARCH_STOP_BUTTON), bInProgress ? SW_SHOW : SW_HIDE);
537     HWND hProgressBar = GetDlgItem(IDC_PROGRESS_BAR);
538     ::ShowWindow(hProgressBar, bInProgress ? SW_SHOW : SW_HIDE);
539     ::PostMessage(hProgressBar, PBM_SETMARQUEE, bInProgress, 0);
540 }
541 
542 HRESULT CSearchBar::TrySubscribeToSearchEvents()
543 {
544     CComPtr<IShellFolder> pShellFolder;
545     HRESULT hr = GetSearchResultsFolder(NULL, NULL, &pShellFolder);
546     if (FAILED(hr))
547         return hr;
548 
549     DWORD fAdviseCookie;
550     hr = AtlAdvise(pShellFolder, static_cast<IDispatch *>(this), DIID_DSearchCommandEvents, &fAdviseCookie);
551     if (FAILED_UNEXPECTEDLY(hr))
552         return hr;
553 
554     return S_OK;
555 }
556 
557 HRESULT STDMETHODCALLTYPE CSearchBar::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
558 {
559     switch (dispIdMember)
560     {
561     case DISPID_NAVIGATECOMPLETE2:
562     case DISPID_DOCUMENTCOMPLETE:
563     {
564         TrySubscribeToSearchEvents();
565 
566         // Remove the search results folder from the address box
567         CComPtr<IDispatch> pDispatch;
568         HRESULT hResult = m_AddressEditBox->QueryInterface(IID_PPV_ARG(IDispatch, &pDispatch));
569         if (FAILED_UNEXPECTEDLY(hResult))
570             return hResult;
571         pDispatch->Invoke(dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
572         CComPtr<IShellService> pShellService;
573         hResult = m_AddressEditBox->QueryInterface(IID_PPV_ARG(IShellService, &pShellService));
574         if (FAILED_UNEXPECTEDLY(hResult))
575             return hResult;
576         hResult = pShellService->SetOwner(NULL);
577         if (FAILED_UNEXPECTEDLY(hResult))
578             return hResult;
579         HWND hComboboxEx = GetDlgItem(IDC_SEARCH_COMBOBOX);
580         int index = SendMessageW(hComboboxEx, CB_GETCOUNT, 0, 0);
581         if (index <= 0)
582             return S_OK;
583         COMBOBOXEXITEMW item = {0};
584         item.mask = CBEIF_LPARAM;
585         item.iItem = index - 1;
586         SendMessageW(hComboboxEx, CBEM_GETITEMW, 0, (LPARAM)&item);
587         if (!item.lParam)
588             return S_OK;
589         CComPtr<IShellFolder> pDesktopFolder;
590         hResult = SHGetDesktopFolder(&pDesktopFolder);
591         if (FAILED_UNEXPECTEDLY(hResult))
592             return hResult;
593         CComPtr<IShellFolder> pShellFolder;
594         hResult = pDesktopFolder->BindToObject((LPCITEMIDLIST)item.lParam, NULL, IID_PPV_ARG(IShellFolder, &pShellFolder));
595         if (FAILED(hResult))
596             return S_OK;
597         CLSID clsid;
598         hResult = IUnknown_GetClassID(pShellFolder, &clsid);
599         if (SUCCEEDED(hResult) && clsid == CLSID_FindFolder)
600         {
601             SendMessageW(hComboboxEx, CBEM_DELETEITEM, item.iItem, 0);
602             SendMessageW(hComboboxEx, CB_SETCURSEL, 0, 0);
603         }
604         return S_OK;
605     }
606     case DISPID_SEARCHCOMPLETE:
607     case DISPID_SEARCHABORT:
608         SetSearchInProgress(FALSE);
609         return S_OK;
610     default:
611         return E_INVALIDARG;
612     }
613 }
614