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, ¶ms, 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