// Classic Shell (c) 2009-2017, Ivo Beltchev // Open-Shell (c) 2017-2018, The Open-Shell Team // Confidential information of Ivo Beltchev. Not for disclosure or distribution without prior written consent from the author #include "stdafx.h" #include "SearchManager.h" #include "MenuContainer.h" #include "MetroLinkManager.h" #include "Settings.h" #include "SettingsUIHelper.h" #include "SettingsUI.h" #include "FNVHash.h" #include "ResourceHelper.h" #include "LogManager.h" #include "Translations.h" #include #include #include #include // attempt to get more accurate PIDLs for the search results by laundering them through a search folder. // this produces better search items for the CSC search connector (better icons and behavior) but is slow. //#define LAUNDER_SEARCH_RESULTS CSearchManager g_SearchManager; const CLSID CLSID_CSearchManager2={0x7D096C5F,0xAC08,0x4f1f,{0xBE,0xB7,0x5C,0x22,0xC5,0x17,0xCE,0x39}}; const int RANK_LIST_VERSION=1; const int RANK_LIST_SIZE=256; CSearchManager::CSearchManager( void ) { m_bInitialized=false; m_bRanksLoaded=false; memset(m_CriticalSections,0,sizeof(m_CriticalSections)); memset(m_CriticalSectionOwners,0,sizeof(m_CriticalSectionOwners)); m_SearchEvent=NULL; m_ExitEvent=NULL; memset(m_SearchThreads,0,sizeof(m_SearchThreads)); m_MainThreadId=0; m_LastRequestId=0; m_LastCompletedId=0; m_LastProgramsRequestId=0; m_SearchThreadCount=0; m_bProgramsFound=m_bSettingsFound=false; m_ProgramsHash=m_ProgramsHashOld=m_SettingsHash=m_SettingsHashOld=FNV_HASH0; } CSearchManager::~CSearchManager( void ) { Close(); } void CSearchManager::Init( void ) { m_bInitialized=true; for (int i=0;i='A' && str[0]<='Z' && str[1]==':') { const wchar_t *end=wcsrchr(str+2,'\\'); if (end) return searchText.Left((int)(end-str)); return searchText; } if (str[0]=='\\' && str[1]=='\\') { const wchar_t *end=wcsrchr(str+2,'\\'); if (end) return searchText.Left((int)(end-str)); } if (str[0]=='%') { const wchar_t *end=wcsrchr(str+1,'\\'); if (end) return searchText.Left((int)(end-str)); } } return CString(); } void CSearchManager::BeginSearch( const CString &searchText ) { Assert(GetCurrentThreadId()==m_MainThreadId); { Lock lock(this,LOCK_DATA); m_SearchText=searchText; // initialize the request with unique ID m_SearchRequest.requestId=++m_LastRequestId; m_SearchRequest.bSearchPrograms=GetSettingBool(L"SearchPrograms"); m_SearchRequest.bSearchPath=GetSettingBool(L"SearchPath"); m_SearchRequest.bSearchMetroApps=GetSettingBool(L"SearchMetroApps"); m_SearchRequest.bSearchMetroSettings=GetSettingBool(L"SearchMetroSettings"); m_SearchRequest.bSearchSettings=m_SearchRequest.bSearchPrograms; //GetSettingBool(L"SearchSettings"); m_SearchRequest.bSearchKeywords=GetSettingBool(L"SearchKeywords"); m_SearchRequest.bSearchFiles=GetSettingBool(L"SearchFiles"); m_SearchRequest.bSearchMetadata=GetSettingBool(L"SearchContents"); m_SearchRequest.bSearchTypes=GetSettingBool(L"SearchCategories"); m_SearchRequest.bSearchSubWord=GetSettingBool(L"SearchSubWord"); m_SearchRequest.bUseRanks=GetSettingBool(L"SearchTrack"); m_SearchRequest.bNoCommonFolders=(SHRestricted(REST_NOCOMMONGROUPS)!=0); m_SearchRequest.bPinnedFolder=(GetSettingInt(L"PinnedPrograms")==PINNED_PROGRAMS_PINNED); m_SearchRequest.searchText=searchText; m_SearchRequest.autoCompletePath=ParseAutoCompletePath(searchText); } SetEvent(m_SearchEvent); } void CSearchManager::CloseMenu( void ) { Lock lock(this,LOCK_DATA); m_LastRequestId++; m_LastProgramsRequestId=m_LastRequestId; if (g_LogCategories & LOG_SEARCH) { for (const auto& item : m_ProgramItems) { if (item.category == CATEGORY_PROGRAM) LOG_MENU(LOG_SEARCH, L"Program: '%s', %d", item.name, item.rank); } std::sort(m_SettingsItems.begin(), m_SettingsItems.end()); for (const auto& item : m_SettingsItems) { if (item.category == CATEGORY_SETTING) LOG_MENU(LOG_SEARCH, L"Setting: '%s', %d", item.name, item.rank); } for (const auto& item : m_SettingsItems) { if (item.category == CATEGORY_METROSETTING) LOG_MENU(LOG_SEARCH, L"MetroSetting: '%s', %d", item.name, item.rank); } } if (m_bProgramsFound) { m_ProgramItemsOld.swap(m_ProgramItems); m_ProgramsHashOld=m_ProgramsHash; } m_ProgramItems.clear(); m_ProgramsHash=FNV_HASH0; m_bProgramsFound=false; if (m_bSettingsFound) { m_SettingsItemsOld.swap(m_SettingsItems); m_SettingsHashOld=m_SettingsHash; } m_SettingsItems.clear(); m_SettingsHash=FNV_HASH0; m_bSettingsFound=false; m_bMetroSettingsFound = false; m_IndexedItems.clear(); m_AutoCompleteItems.clear(); m_AutoCompletePath.Empty(); m_LastAutoCompletePath.Empty(); } bool CSearchManager::CmpRankTime( const CSearchManager::ItemRank &rank1, const CSearchManager::ItemRank &rank2 ) { return rank1.lastTime>rank2.lastTime; } unsigned int CSearchManager::CalcItemsHash( const std::vector &items ) { unsigned int hash=FNV_HASH0; for (std::vector::const_iterator it=items.begin();it!=items.end();++it) { hash=CalcFNVHash(&it->category,sizeof(TItemCategory),hash); hash=CalcFNVHash(it->name,hash); hash=CalcFNVHash(it->keywords,hash); hash=CalcFNVHash(&it->pInfo,sizeof(void*),hash); hash=CalcFNVHash(&it->rank,sizeof(int),hash); hash=CalcFNVHash(&it->bMetroLink,sizeof(bool),hash); } return hash; } void CSearchManager::LoadItemRanks( void ) { Assert(GetCurrentThreadId()==m_MainThreadId); Lock lock(this,LOCK_RANKS); m_ItemRanks.clear(); if (GetSettingBool(L"SearchTrack")) { CRegKey regKey; if (regKey.Open(HKEY_CURRENT_USER,GetSettingsRegPath(),KEY_READ)==ERROR_SUCCESS) { ULONG size=0; regKey.QueryBinaryValue(L"ItemRanks",NULL,&size); if (size>0 && (size%sizeof(ItemRank))==0) { m_ItemRanks.resize(size/sizeof(ItemRank)); regKey.QueryBinaryValue(L"ItemRanks",&m_ItemRanks[0],&size); if (m_ItemRanks[0].hash!='CLSH' || m_ItemRanks[0].rank!=RANK_LIST_VERSION) m_ItemRanks.clear(); else if (m_ItemRanks.size()>RANK_LIST_SIZE) { std::sort(m_ItemRanks.begin()+1,m_ItemRanks.end(),CmpRankTime); m_ItemRanks.resize(RANK_LIST_SIZE); } } } if (m_ItemRanks.empty()) { ItemRank rank('CLSH',RANK_LIST_VERSION); m_ItemRanks.push_back(rank); } std::sort(m_ItemRanks.begin()+1,m_ItemRanks.end()); } m_bRanksLoaded=true; } void CSearchManager::AddItemRank( unsigned int hash ) { Assert(GetCurrentThreadId()==m_MainThreadId); Assert(m_bRanksLoaded); Lock lock(this,LOCK_RANKS); if (GetSettingBool(L"SearchTrack")) { FILETIME curTime; GetSystemTimeAsFileTime(&curTime); ItemRank rank(hash,1,curTime.dwHighDateTime); std::vector::iterator it=std::lower_bound(m_ItemRanks.begin()+1,m_ItemRanks.end(),rank); if (it!=m_ItemRanks.end() && it->hash==rank.hash) { it->rank++; it->lastTime=curTime.dwHighDateTime; } else { m_ItemRanks.push_back(rank); std::sort(m_ItemRanks.begin()+1,m_ItemRanks.end()); } } else { m_ItemRanks.clear(); ItemRank rank('CLSH',RANK_LIST_VERSION); m_ItemRanks.push_back(rank); } CRegKey reg; if (reg.Open(HKEY_CURRENT_USER,GetSettingsRegPath())!=ERROR_SUCCESS) reg.Create(HKEY_CURRENT_USER,GetSettingsRegPath()); reg.SetBinaryValue(L"ItemRanks",&m_ItemRanks[0],sizeof(ItemRank)*(int)m_ItemRanks.size()); } // Extensions to look for in the PATH directories static const wchar_t *g_pProgramExtensions[]= { L".EXE", L".COM", L".BAT", L".CMD", L".MSC", L".CPL", L".SCR", }; bool CSearchManager::AddSearchItem( IShellItem *pItem, const wchar_t *name, int flags, TItemCategory category, SearchRequest &searchRequest ) { CAbsolutePidl pidl; if (FAILED(SHGetIDListFromObject(pItem,&pidl))) return false; SearchItem item; item.category=CATEGORY_INVALID; item.pInfo=g_ItemManager.GetItemInfo(pItem,pidl,CItemManager::INFO_LINK|((flags&COLLECT_METRO)?CItemManager::INFO_METRO:0)); { CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS); item.bMetroLink=item.pInfo->IsMetroLink(); if ((flags&COLLECT_ONLY_METRO) && !item.bMetroLink) return false; if (item.bMetroLink && (!searchRequest.bSearchMetroApps || _wcsicmp(item.pInfo->GetAppid(),DESKTOP_APP_ID)==0)) return false; item.category=category; if (item.bMetroLink) { item.name=item.pInfo->GetMetroName(); StringUpper(item.name); } else item.name=name; } if (flags&COLLECT_KEYWORDS) { CComQIPtr pItem2=pItem; PROPVARIANT val; PropVariantInit(&val); pItem2->GetProperty(PKEY_Keywords,&val); if (val.vt==VT_EMPTY) pItem2->GetProperty(PKEY_HighKeywords,&val); wchar_t keywords[2048]; int len=0; if (val.vt==VT_BSTR || val.vt==VT_LPWSTR) { len+=Strcpy(keywords+len,_countof(keywords)-len,L";"); len+=Strcpy(keywords+len,_countof(keywords)-len,val.pwszVal); } else if (val.vt==(VT_VECTOR|VT_BSTR) || val.vt==(VT_VECTOR|VT_LPWSTR)) { for (ULONG i=0;i0) { CharUpper(keywords); item.keywords+=keywords; } PropVariantClear(&val); } Lock lock(this,LOCK_DATA); if (category==CATEGORY_PROGRAM || category==CATEGORY_SETTING || category==CATEGORY_METROSETTING) { if (searchRequest.requestId &items=(category==CATEGORY_PROGRAM)?m_ProgramItems:m_SettingsItems; if (category==CATEGORY_SETTING || category==CATEGORY_METROSETTING) { // remove duplicate settings for (std::vector::const_iterator it=items.begin();it!=items.end();++it) { if (wcscmp(it->name,item.name)==0 && it->bMetroLink==item.bMetroLink) { item.category=CATEGORY_INVALID; break; } } } if (searchRequest.bUseRanks) { Lock lock(this,LOCK_RANKS); Assert(m_bRanksLoaded); unsigned int hash; CComString pName; if (SUCCEEDED(pItem->GetDisplayName(SIGDN_PARENTRELATIVEPARSING,&pName))) { pName.MakeUpper(); hash=CalcFNVHash(pName); } else hash=CalcFNVHash(item.name); ItemRank rank(hash); std::vector::const_iterator it=std::lower_bound(m_ItemRanks.begin()+1,m_ItemRanks.end(),rank); if (it!=m_ItemRanks.end() && it->hash==rank.hash) item.rank=it->rank*2; } items.push_back(item); if (item.category==CATEGORY_METROSETTING) m_bMetroSettingsFound=true; } else if (category==CATEGORY_AUTOCOMPLETE) { item.rank=(flags&COLLECT_IS_FOLDER)?1:0; m_AutoCompleteItems.push_back(item); } if (!(flags&COLLECT_NOREFRESH)) { DWORD time=GetTickCount(); int dt=(time-searchRequest.searchTime); if (dt>1000) { CMenuContainer::RefreshSearch(); searchRequest.searchTime=time; } } return res; } void CSearchManager::CollectSearchItems( IShellItem *pFolder, int flags, TItemCategory category, SearchRequest &searchRequest ) { CComPtr pEnum; pFolder->BindToHandler(NULL,BHID_EnumItems,IID_IEnumShellItems,(void**)&pEnum); if (!pEnum) return; CComPtr pChild; while (pChild=NULL,pEnum->Next(1,&pChild,NULL)==S_OK) { if (category==CATEGORY_PROGRAM || category==CATEGORY_SETTING || category==CATEGORY_METROSETTING) { if (searchRequest.requestIdGetAttributes(SFGAO_FOLDER|SFGAO_STREAM|SFGAO_LINK|SFGAO_HIDDEN,&itemFlags))) { if (itemFlags&SFGAO_HIDDEN) continue; if ((flags&COLLECT_RECURSIVE) && (itemFlags&(SFGAO_FOLDER|SFGAO_STREAM|SFGAO_LINK))==SFGAO_FOLDER) { // go into subfolders but not archives or links to folders CollectSearchItems(pChild,flags,category,searchRequest); if (category==CATEGORY_PROGRAM || category==CATEGORY_SETTING || category==CATEGORY_METROSETTING) { if (searchRequest.requestIdGetDisplayName((flags&COLLECT_PROGRAMS)?SIGDN_PARENTRELATIVEPARSING:SIGDN_PARENTRELATIVEEDITING,&pName))) { pName.MakeUpper(); bool bSkip=false; if (flags&COLLECT_PROGRAMS) { bSkip=true; const wchar_t *ext=PathFindExtension(pName); for (int i=0;i<_countof(g_pProgramExtensions);i++) if (wcscmp(ext,g_pProgramExtensions[i])==0) { bSkip=false; break; } } if (!bSkip) AddSearchItem(pChild,pName,flags|((itemFlags&SFGAO_FOLDER)?COLLECT_IS_FOLDER:0),category,searchRequest); } } } } } bool CSearchManager::SearchScope::ParseSearchConnector( const wchar_t *fname ) { CComPtr pDoc; if (FAILED(pDoc.CoCreateInstance(L"Msxml2.FreeThreadedDOMDocument"))) return false; pDoc->put_async(VARIANT_FALSE); VARIANT_BOOL loaded; if (pDoc->load(CComVariant(fname),&loaded)!=S_OK || loaded!=VARIANT_TRUE) return false; CComPtr pRoot; HRESULT res=pDoc->selectSingleNode(CComBSTR(L"searchConnectorDescription"),&pRoot); if (res!=S_OK) return false; CComPtr pScope; res=pRoot->selectSingleNode(CComBSTR(L"scope"),&pScope); if (res==S_OK) { CComPtr pScopeItem; pScope->get_firstChild(&pScopeItem); while (pScopeItem) { CComBSTR name; pScopeItem->get_nodeName(&name); if (_wcsicmp(name,L"scopeItem")==0) { CComPtr pUrl; CComBSTR url; if (pScopeItem->selectSingleNode(CComBSTR(L"url"),&pUrl)==S_OK && pUrl->get_text(&url)==S_OK) { if (_wcsnicmp(url,L"file:",5)==0) return false; // ignore files CComPtr pMode, pDepth; CComBSTR mode, depth; bool bExclude=(pScopeItem->selectSingleNode(CComBSTR(L"mode"),&pMode)==S_OK && pMode->get_text(&mode)==S_OK && _wcsicmp(mode,L"exclude")==0); bool bShallow=(pScopeItem->selectSingleNode(CComBSTR(L"depth"),&pDepth)==S_OK && pDepth->get_text(&depth)==S_OK && _wcsicmp(depth,L"shallow")==0); CString url2; if (bExclude) url2.Format(bShallow?L"-=%s":L"-%s",(const wchar_t*)url); else url2.Format(bShallow?L"=%s":L"%s",(const wchar_t*)url); StringUpper(url2); roots.push_back(url2); } } CComPtr pNext; if (pScopeItem->get_nextSibling(&pNext)!=S_OK) break; pScopeItem=std::move(pNext); } return true; } CComPtr pTemplate; res=pRoot->selectSingleNode(CComBSTR(L"templateInfo"),&pTemplate); if (res==S_OK) { CComPtr pType; res=pTemplate->selectSingleNode(CComBSTR(L"folderType"),&pType); if (res==S_OK) { CComBSTR type; bCommunications=(pType->get_text(&type)==S_OK && _wcsicmp(type,L"{91475FE5-586B-4EBA-8D75-D17434B8CDF6}")==0); } } res=pRoot->selectSingleNode(CComBSTR(L"simpleLocation"),&pScope); if (res==S_OK) { CComPtr pUrl; res=pScope->selectSingleNode(CComBSTR(L"url"),&pUrl); if (res!=S_OK) return false; CComBSTR url; if (pUrl->get_text(&url)!=S_OK) return false; if (_wcsnicmp(url,L"file:",5)==0) return false; // ignore files CString url2(url); StringUpper(url2); roots.push_back(url2); return true; } return false; } void CSearchManager::SearchThread( void ) { HANDLE events[2]={m_SearchEvent,m_ExitEvent}; SearchRequest searchRequest; searchRequest.requestId=-1; InterlockedIncrement(&m_SearchThreadCount); while (1) { if (searchRequest.requestId==m_LastRequestId) { Lock lock(this,LOCK_DATA); if (searchRequest.requestId==m_LastRequestId) { m_LastCompletedId=searchRequest.requestId; CMenuContainer::RefreshSearch(); } } long count=InterlockedDecrement(&m_SearchThreadCount); // Trace(L"Search thread count: %d",count); if (WaitForMultipleObjects(2,events,FALSE,INFINITE)!=WAIT_OBJECT_0) break; count=InterlockedIncrement(&m_SearchThreadCount); // Trace(L"Search thread count: %d",count); { Lock lock(this,LOCK_DATA); if (m_SearchRequest.requestId!=m_LastRequestId) continue; searchRequest=m_SearchRequest; m_SearchRequest.requestId=0; m_IndexedItems.clear(); if (!searchRequest.autoCompletePath.IsEmpty() && searchRequest.autoCompletePath==m_LastAutoCompletePath) continue; m_AutoCompleteItems.clear(); m_AutoCompletePath=searchRequest.autoCompletePath; m_LastAutoCompletePath.Empty(); } // Trace(L"Search request: %d",searchRequest.requestId); searchRequest.searchTime=GetTickCount(); // find programs if (searchRequest.autoCompletePath.IsEmpty()) { if (searchRequest.searchText.IsEmpty() || wcsncmp(searchRequest.searchText,L"\\\\",2)==0) continue; Lock lock(this,LOCK_PROGRAMS); if (searchRequest.requestId pFolder; if (SUCCEEDED(ShGetKnownFolderItem(FOLDERID_StartMenu,&pFolder))) CollectSearchItems(pFolder,COLLECT_RECURSIVE|COLLECT_METRO|COLLECT_NOREFRESH,CATEGORY_PROGRAM,searchRequest); if (searchRequest.requestId pFolder; if (SUCCEEDED(ShGetKnownFolderItem(FOLDERID_CommonStartMenu,&pFolder))) CollectSearchItems(pFolder,COLLECT_RECURSIVE|COLLECT_METRO|COLLECT_NOREFRESH,CATEGORY_PROGRAM,searchRequest); if (searchRequest.requestId pFolder; if (SUCCEEDED(SHCreateItemFromParsingName(path,NULL,IID_IShellItem,(void**)&pFolder))) CollectSearchItems(pFolder,COLLECT_METRO|COLLECT_NOREFRESH,CATEGORY_PROGRAM,searchRequest); if (searchRequest.requestId pFolder; if (SUCCEEDED(ShGetKnownFolderItem(FOLDERID_Games,&pFolder))) CollectSearchItems(pFolder,COLLECT_RECURSIVE|COLLECT_METRO|COLLECT_NOREFRESH,CATEGORY_PROGRAM,searchRequest); if (searchRequest.requestId pFolder; if (SUCCEEDED(SHCreateItemFromParsingName(token,NULL,IID_IShellItem,(void**)&pFolder))) CollectSearchItems(pFolder,COLLECT_PROGRAMS|COLLECT_NOREFRESH,CATEGORY_PROGRAM,searchRequest); if (searchRequest.requestId=WIN_VER_WIN8 && searchRequest.bSearchMetroApps) { std::vector links; GetMetroLinks(links,true); for (std::vector::const_iterator it=links.begin();it!=links.end();++it) { if (GetWinVersion()pItem,L"",COLLECT_PROGRAMS|COLLECT_METRO|COLLECT_ONLY_METRO,CATEGORY_PROGRAM,searchRequest); else { CComString pName; if (SUCCEEDED(it->pItem->GetDisplayName(SIGDN_NORMALDISPLAY,&pName))) AddSearchItem(it->pItem,pName,COLLECT_PROGRAMS|COLLECT_METRO,CATEGORY_PROGRAM,searchRequest); } if (searchRequest.requestId pFolder; if (SUCCEEDED(ShGetKnownFolderItem(FOLDERID_ControlPanelFolder,&pFolder))) CollectSearchItems(pFolder,COLLECT_FOLDERS|COLLECT_NOREFRESH,CATEGORY_SETTING,searchRequest); if (searchRequest.requestId pFolder; if (SUCCEEDED(ShGetKnownFolderItem(FOLDERID_AdminTools,&pFolder))) CollectSearchItems(pFolder,COLLECT_RECURSIVE|COLLECT_NOREFRESH,CATEGORY_SETTING,searchRequest); if (searchRequest.requestId pFolder; if (SUCCEEDED(ShGetKnownFolderItem(FOLDERID_CommonAdminTools,&pFolder))) CollectSearchItems(pFolder,COLLECT_RECURSIVE|COLLECT_NOREFRESH,CATEGORY_SETTING,searchRequest); if (searchRequest.requestId pFolder; if (SUCCEEDED(SHCreateItemFromParsingName(L"shell:::{ED7BA470-8E54-465E-825C-99712043E01C}",NULL,IID_IShellItem,(void**)&pFolder))) CollectSearchItems(pFolder,(searchRequest.bSearchKeywords?COLLECT_KEYWORDS:0)|COLLECT_NOREFRESH,CATEGORY_SETTING,searchRequest); if (searchRequest.requestId pFolder; if (SUCCEEDED(SHCreateItemFromParsingName(L"shell:::{82E749ED-B971-4550-BAF7-06AA2BF7E836}",NULL,IID_IShellItem,(void**)&pFolder))) CollectSearchItems(pFolder,(searchRequest.bSearchKeywords?COLLECT_KEYWORDS:0)|COLLECT_NOREFRESH,CATEGORY_METROSETTING,searchRequest); if (searchRequest.requestId pFolder; wchar_t path[_MAX_PATH]; Strcpy(path,_countof(path),searchRequest.autoCompletePath); DoEnvironmentSubst(path,_countof(path)); if (SUCCEEDED(SHCreateItemFromParsingName(path,NULL,IID_IShellItem,(void**)&pFolder))) { SFGAOF itemFlags; if (SUCCEEDED(pFolder->GetAttributes(SFGAO_FOLDER|SFGAO_STREAM|SFGAO_LINK,&itemFlags)) && (itemFlags&(SFGAO_FOLDER|SFGAO_STREAM|SFGAO_LINK))==SFGAO_FOLDER) CollectSearchItems(pFolder,COLLECT_FOLDERS,CATEGORY_AUTOCOMPLETE,searchRequest); } { Lock lock(this,LOCK_DATA); if (searchRequest.requestId==m_LastRequestId) m_LastAutoCompletePath=searchRequest.autoCompletePath; } continue; } if (searchRequest.requestId!=m_LastRequestId || (!searchRequest.bSearchFiles && !searchRequest.bSearchMetroSettings)) continue; CMenuContainer::RefreshSearch(); searchRequest.searchTime=GetTickCount(); CDataSource dataSource; CSession session; if (SUCCEEDED(dataSource.OpenFromInitializationString(L"provider=Search.CollatorDSO.1;EXTENDED PROPERTIES=\"Application=Windows\"")) && SUCCEEDED(session.Open(dataSource))) { std::vector scopeList; if (searchRequest.bSearchMetroSettings && !m_bMetroSettingsFound) { scopeList.push_back(SearchScope()); SearchScope &scope=*scopeList.rbegin(); scope.bFiles=true; scope.name=FindTranslation(L"Search.CategoryPCSettings",L"Settings"); scope.categoryHash=CATEGORY_METROSETTING; scope.roots.push_back(L"FILE:"); } if (searchRequest.bSearchFiles) { // prepare roots CComPtr pLibrary; pLibrary.CoCreateInstance(CLSID_ShellLibrary); if (searchRequest.bSearchTypes && pLibrary) { CComPtr pLibraries; std::vector> libraries; static KNOWNFOLDERID defaultLibraries[]= { FOLDERID_DocumentsLibrary, FOLDERID_MusicLibrary, FOLDERID_PicturesLibrary, FOLDERID_VideosLibrary, }; { for (int i=0;i<_countof(defaultLibraries);i++) { CComPtr pItem; if (SUCCEEDED(ShGetKnownFolderItem(defaultLibraries[i],&pItem))) libraries.push_back(pItem); } } if (SUCCEEDED(ShGetKnownFolderItem(FOLDERID_Libraries,&pLibraries))) { CComPtr pEnum; pLibraries->BindToHandler(NULL,BHID_EnumItems,IID_IEnumShellItems,(void**)&pEnum); if (pEnum) { CComPtr pItem; while (pItem=NULL,pEnum->Next(1,&pItem,NULL)==S_OK) { bool bFound=false; for (size_t i=0;iCompare(pItem,SICHINT_CANONICAL,&order)) && order) { bFound=true; break; } } if (!bFound) libraries.push_back(pItem); } } } for (std::vector>::const_iterator it=libraries.begin();it!=libraries.end();++it) { if (!*it) continue; CComString pName; if (SUCCEEDED(pLibrary->LoadLibraryFromItem(*it,STGM_READ)) && SUCCEEDED((*it)->GetDisplayName(SIGDN_NORMALDISPLAY,&pName))) { scopeList.push_back(SearchScope()); SearchScope &scope=*scopeList.rbegin(); scope.bFiles=true; scope.name=pName; LOG_MENU(LOG_SEARCH,L"Category: %s",scope.name); SHGetIDListFromObject(*it,&scope.search); scope.categoryHash=CATEGORY_FILE; CComString pName2; if (SUCCEEDED((*it)->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING,&pName2))) scope.categoryHash|=(CalcFNVHash(pName)&~CATEGORY_MASK); CComPtr pArray; if (SUCCEEDED(pLibrary->GetFolders(LFF_FORCEFILESYSTEM,IID_IShellItemArray,(void**)&pArray)) && pArray) { CComPtr pEnum2; if (SUCCEEDED(pArray->EnumItems(&pEnum2)) && pEnum2) { CComPtr pFolder; while (pFolder=NULL,pEnum2->Next(1,&pFolder,NULL)==S_OK) { CComString pPath; if (SUCCEEDED(pFolder->GetDisplayName(SIGDN_FILESYSPATH,&pPath)) && pPath) { pPath.MakeUpper(); for (wchar_t *str=(wchar_t*)(const wchar_t*)pPath;*str;str++) if (*str=='\\') *str='/'; CString path; path.Format(L"FILE:%s/",(const wchar_t*)pPath); path.Replace(L"'",L"''"); scope.roots.push_back(path); LOG_MENU(LOG_SEARCH,L" Scope: %s",path); } } } } if (scope.roots.empty()) scopeList.pop_back(); } } } else { // one for files scopeList.push_back(SearchScope()); SearchScope &scope=*scopeList.rbegin(); scope.bFiles=true; scope.name=FindTranslation(L"Search.CategoryFiles",L"Files"); scope.categoryHash=CATEGORY_FILE; scope.categoryHash|=(CalcFNVHash(L"Files")&~CATEGORY_MASK); scope.roots.push_back(L"FILE:"); } { // search connectors CComPtr pSearches; if (SUCCEEDED(ShGetKnownFolderItem(FOLDERID_SavedSearches,&pSearches))) { CComPtr pEnum; pSearches->BindToHandler(NULL,BHID_EnumItems,IID_IEnumShellItems,(void**)&pEnum); PROPERTYKEY keyStartMenu; PSGetPropertyKeyFromName(L"System.StartMenu.IncludeInScope",&keyStartMenu); if (pEnum) { CComPtr pItem; while (pItem=NULL,pEnum->Next(1,&pItem,NULL)==S_OK) { CComString pName; pItem->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING,&pName); LOG_MENU(LOG_SEARCH,L"Search Root: %s",(const wchar_t*)pName); if (_wcsicmp(PathFindExtension(pName),L".searchconnector-ms")!=0) { LOG_MENU(LOG_SEARCH,L"Ignoring: not a search connector"); continue; } CComPtr pStore; pItem->BindToHandler(NULL,BHID_PropertyStore,IID_IPropertyStore,(void**)&pStore); if (!pStore) { LOG_MENU(LOG_SEARCH,L"Ignoring: no store"); continue; } PROPVARIANT val; PropVariantInit(&val); if (FAILED(pStore->GetValue(keyStartMenu,&val))) { LOG_MENU(LOG_SEARCH,L"Ignoring: no start menu1"); continue; } bool bStartMenu=(val.vt==VT_BOOL && val.boolVal); PropVariantClear(&val); if (!bStartMenu) { LOG_MENU(LOG_SEARCH,L"Ignoring: no start menu2"); continue; } scopeList.push_back(SearchScope()); SearchScope &scope=*scopeList.rbegin(); if (!scope.ParseSearchConnector(pName)) { scopeList.pop_back(); LOG_MENU(LOG_SEARCH,L"Ignoring: failed to parse searchconnector-ms"); continue; } if (GetWinVersion()>=WIN_VER_WIN10) { // ignore search connector using the WINRT scope - looks like it just duplicates the last search bool bWinRT=false; for (std::vector::const_iterator it=scope.roots.begin();it!=scope.roots.end();++it) { if (wcsncmp(*it,L"WINRT://",8)==0) { bWinRT=true; break; } } if (bWinRT) { scopeList.pop_back(); LOG_MENU(LOG_SEARCH,L"Ignoring: uses WINRT scope"); continue; } } scope.bFiles=false; SHGetIDListFromObject(pItem,&scope.search); scope.categoryHash=CATEGORY_ITEM; scope.categoryHash|=(CalcFNVHash(pName)&~CATEGORY_MASK); pName.Clear(); pItem->GetDisplayName(SIGDN_NORMALDISPLAY,&pName); scope.name=pName; LOG_MENU(LOG_SEARCH,L"Category: %s",scope.name); if (g_LogCategories&LOG_SEARCH) { for (std::vector::const_iterator it=scope.roots.begin();it!=scope.roots.end();++it) LOG_MENU(LOG_SEARCH,L" Scope: %s",*it); } } } } } if (searchRequest.bSearchTypes && pLibrary) { // one for uncategorized files scopeList.push_back(SearchScope()); SearchScope &scope=*scopeList.rbegin(); scope.bFiles=true; scope.name=FindTranslation(L"Search.CategoryFiles",L"Files"); scope.categoryHash=CATEGORY_FILE; scope.roots.push_back(L"FILE:"); } } const wchar_t *columns=L"System.ItemUrl, System.ItemType, Path, System.ItemPathDisplay, System.ItemNameDisplay"; const wchar_t *order=L"System.Search.Rank DESC, System.DateModified DESC, System.ItemNameDisplay ASC"; const wchar_t *orderComm=L"System.Contact.FileAsName ASC, System.Message.DateReceived DESC, System.Search.Rank DESC"; CComPtr pStore; pStore.CoCreateInstance(CLSID_InMemoryPropertyStore); if (!pStore) continue; CComPtr pBindCtx0; CreateBindCtx(0,&pBindCtx0); if (!pBindCtx0) continue; pBindCtx0->RegisterObjectParam((LPOLESTR)STR_PARSE_WITH_PROPERTIES,pStore); #ifdef LAUNDER_SEARCH_RESULTS CComPtr pSearchFactory; pSearchFactory.CoCreateInstance(CLSID_SearchFolderItemFactory); if (!pSearchFactory) continue; CComPtr pConditionFactory; pConditionFactory.CoCreateInstance(CLSID_ConditionFactory); if (!pConditionFactory) continue; #endif CCommand,CRowset> command0; { CComPtr pSearchManager; pSearchManager.CoCreateInstance(CLSID_CSearchManager2); if (!pSearchManager) continue; CComPtr pCatalogManager; pSearchManager->GetCatalog(L"SystemIndex",&pCatalogManager); if (!pCatalogManager) continue; CComPtr pQueryHelper; pCatalogManager->GetQueryHelper(&pQueryHelper); if (!pQueryHelper) continue; pQueryHelper->put_QuerySelectColumns(columns); pQueryHelper->put_QuerySorting(order); pQueryHelper->put_QueryWhereRestrictions(L"AND NOT System.Shell.SFGAOFlagsStrings = SOME ARRAY['superhidden'] AND System.Shell.OmitFromView!='true'"); if (!searchRequest.bSearchMetadata) pQueryHelper->put_QueryContentProperties(L"System.ItemNameDisplay"); CComString pQuery; pQueryHelper->GenerateSQLFromUserQuery(searchRequest.searchText,&pQuery); if (g_LogCategories&LOG_SEARCH_SQL) { wchar_t *query=const_cast((const wchar_t*)pQuery); int len=Strlen(query); for (int i=0;i pInfo=command0.GetInterface(); if (pInfo) { DBPROPID propids[1]={MSIDXSPROP_WHEREID}; DBPROPIDSET propset={propids,1,DBPROPSET_MSIDXS_ROWSETEXT}; ULONG csets; DBPROPSET *props=NULL; if (SUCCEEDED(pInfo->GetProperties(1,&propset,&csets,&props)) && props) { if (props->rgProperties) { if (props->rgProperties[0].vValue.vt==VT_UI4) whereid=props->rgProperties[0].vValue.uintVal; VariantClear(&props->rgProperties[0].vValue); } if (props->rgProperties) CoTaskMemFree(props->rgProperties); CoTaskMemFree(props); } } if (whereid==0xFFFFFFFF) { command0.Close(); continue; } for (auto it=scopeList.begin();it!=scopeList.end();++it) { if (it->roots.empty()) continue; wchar_t query[8192]; int len=Sprintf(query,_countof(query),L"SELECT TOP %d %s FROM SystemIndex WHERE REUSEWHERE(%u)",MAX_SEARCH_RESULTS,columns,whereid); if (it->roots.size()==1 && it->roots[0]==L"FILE:") { if (it->categoryHash==CATEGORY_METROSETTING) { len+=Strcpy(query+len,_countof(query)-len,L" AND System.Search.Store='FILE' AND System.FileName NOT LIKE 'Classic_%' AND System.ItemType='.settingcontent-ms'"); wchar_t userPath[_MAX_PATH]=L"%LOCALAPPDATA%\\Packages\\windows.immersivecontrolpanel_cw5n1h2txyewy\\LocalState\\Indexed\\Settings"; DoEnvironmentSubst(userPath,_countof(userPath)); len+=Sprintf(query+len,_countof(query)-len,L" AND SCOPE='%s'",userPath); } else { len+=Strcpy(query+len,_countof(query)-len,L" AND System.Search.Store='FILE' AND System.ItemType!='.settingcontent-ms'"); for (auto it2=scopeList.begin();it2!=it;++it2) { if (it2->categoryHash==CATEGORY_METROSETTING) continue; for (std::vector::iterator it3=it2->roots.begin();it3!=it2->roots.end();++it3) { if (wcsncmp(*it3,L"FILE:",5)==0) len+=Sprintf(query+len,_countof(query)-len,L" AND NOT SCOPE='%s'",*it3); } } if (searchRequest.bSearchPrograms) { // remove start menu/programs { CComString pPath; if (SUCCEEDED(ShGetKnownFolderPath(FOLDERID_StartMenu,&pPath))) len+=Sprintf(query+len,_countof(query)-len,L" AND NOT SCOPE='%s'",(const wchar_t*)pPath); } { CComString pPath; if (SUCCEEDED(ShGetKnownFolderPath(FOLDERID_Programs,&pPath))) len+=Sprintf(query+len,_countof(query)-len,L" AND NOT SCOPE='%s'",(const wchar_t*)pPath); } } if (searchRequest.bSearchPrograms || searchRequest.bNoCommonFolders) { // remove common start menu/programs { CComString pPath; if (SUCCEEDED(ShGetKnownFolderPath(FOLDERID_CommonStartMenu,&pPath))) len+=Sprintf(query+len,_countof(query)-len,L" AND NOT SCOPE='%s'",(const wchar_t*)pPath); } { CComString pPath; if (SUCCEEDED(ShGetKnownFolderPath(FOLDERID_CommonPrograms,&pPath))) len+=Sprintf(query+len,_countof(query)-len,L" AND NOT SCOPE='%s'",(const wchar_t*)pPath); } } } } else { for (std::vector::iterator it2=it->roots.begin();it2!=it->roots.end();++it2) { const wchar_t *scope=*it2; if (scope[0]=='-') { bool bShallow=false; scope++; if (scope[0]=='=') { bShallow=true; scope++; } if (bShallow) len+=Sprintf(query+len,_countof(query)-len,L" AND NOT DIRECTORY='%s'",scope); else len+=Sprintf(query+len,_countof(query)-len,L" AND NOT SCOPE='%s'",scope); } } len+=Sprintf(query+len,_countof(query)-len,L" AND ("); bool bFirst=true; for (std::vector::iterator it2=it->roots.begin();it2!=it->roots.end();++it2) { const wchar_t *scope=*it2; bool bExclude=false, bShallow=false; if (scope[0]=='-') { bExclude=true; scope++; } if (scope[0]=='=') { bShallow=true; scope++; } if (!bExclude) { if (bShallow) len+=Sprintf(query+len,_countof(query)-len,bFirst?L"DIRECTORY='%s'":L" OR DIRECTORY='%s'",scope); else len+=Sprintf(query+len,_countof(query)-len,bFirst?L"SCOPE='%s'":L" OR SCOPE='%s'",scope); bFirst=false; } } len+=Strcpy(query+len,_countof(query)-len,L")"); } len+=Sprintf(query+len,_countof(query)-len,L" ORDER BY %s",it->bCommunications?orderComm:order); if (g_LogCategories&LOG_SEARCH_SQL) { for (int i=0;i,CRowset> command; HRESULT hr=command.Open(session,query); if (FAILED(hr)) { LOG_MENU(LOG_SEARCH_SQL,L"Query failed: 0x%08X",hr); continue; } CComQIPtr pInfo=command.GetInterface(); DBPROPID propids[1]={MSIDXSPROP_RESULTS_FOUND}; DBPROPIDSET propset={propids,1,DBPROPSET_MSIDXS_ROWSETEXT}; ULONG csets; DBPROPSET *props=NULL; if (SUCCEEDED(pInfo->GetProperties(1,&propset,&csets,&props)) && props) { if (props->rgProperties) { if (props->rgProperties[0].vValue.vt==VT_I4) it->resultCount=props->rgProperties[0].vValue.intVal; VariantClear(&props->rgProperties[0].vValue); } if (props->rgProperties) CoTaskMemFree(props->rgProperties); CoTaskMemFree(props); } LOG_MENU(LOG_SEARCH_SQL,L"Query results: %d",it->resultCount); if (it->resultCount>0) { SearchCategory *pCategory=NULL; { Lock lock(this,LOCK_DATA); m_IndexedItems.push_back(SearchCategory()); pCategory=&*m_IndexedItems.rbegin(); pCategory->name=it->name; pCategory->categoryHash=it->categoryHash; pCategory->search.Clone(it->search); } while (command.MoveNext()==S_OK) { LOG_MENU(LOG_SEARCH_SQL,L"Result: %s, %s, %s, %s, %s",command.itemUrl,command.itemType,command.parsingPath,command.displayPath,command.displayName); SearchCategory::Item item; if (it->bFiles) { const wchar_t *path=wcsrchr(command.itemUrl,'/'); if (!path || _wcsicmp(path+1,command.displayName)!=0) item.name=command.displayName; } if (command.itemUrl[0]) { if (!it->bFiles) { #ifdef LAUNDER_SEARCH_RESULTS CComPtr pCondition; hr=pConditionFactory->CreateStringLeaf(PKEY_ItemUrl,COP_EQUAL,command.itemUrl,NULL,CONDITION_CREATION_DEFAULT,IID_PPV_ARGS(&pCondition)); if (pCondition) { pSearchFactory->SetCondition(pCondition); CAbsolutePidl pidl0; hr=pSearchFactory->GetIDList(&pidl0); CComPtr pFolder; hr=SHBindToObject(NULL,pidl0,NULL,IID_IShellFolder,(void**)&pFolder); if (SUCCEEDED(hr)) { CComPtr pEnum; pFolder->EnumObjects(NULL,SHCONTF_FOLDERS|SHCONTF_NONFOLDERS,&pEnum); PITEMID_CHILD child; if (pEnum && pEnum->Next(1,&child,NULL)==S_OK) { item.pidl.Attach(ILCombine(pidl0,child)); ILFree(child); } } } #else PROPVARIANT val; val.vt=VT_LPWSTR; val.pwszVal=command.itemType; pStore->SetValue(PKEY_ItemType,val); val.pwszVal=command.parsingPath; pStore->SetValue(PKEY_ParsingPath,val); val.pwszVal=command.displayPath; pStore->SetValue(PKEY_ItemPathDisplay,val); val.pwszVal=command.displayName; pStore->SetValue(PKEY_ItemNameDisplay,val); item.name=command.displayName; hr=SHParseDisplayName(command.itemUrl,pBindCtx0,&item.pidl,0,NULL); #endif } else { hr=SHParseDisplayName(command.itemUrl,NULL,&item.pidl,0,NULL); if (FAILED(hr) && _wcsnicmp(command.itemUrl,L"file:",5)==0) { for (wchar_t *str=command.itemUrl;*str;++str) { if (*str=='/') *str='\\'; } hr=SHParseDisplayName(command.itemUrl+5,NULL,&item.pidl,0,NULL); } } if (SUCCEEDED(hr)) { Lock lock(this,LOCK_DATA); if (searchRequest.requestId!=m_LastRequestId) break; pCategory->items.push_back(item); DWORD time=GetTickCount(); int dt=(time-searchRequest.searchTime); if (dt>1000) { CMenuContainer::RefreshSearch(); searchRequest.searchTime=time; } } } } } command.Close(); if (searchRequest.requestId!=m_LastRequestId) break; } command0.Close(); } } } DWORD CALLBACK CSearchManager::StaticSearchThread( void *param ) { // SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_IDLE); OleInitialize(NULL); ((CSearchManager*)param)->SearchThread(); OleUninitialize(); return 0; } void CSearchManager::GetSearchResults( SearchResults &results ) { results.programs.clear(); results.settings.clear(); results.metrosettings.clear(); results.indexed.clear(); results.autocomplete.clear(); results.autoCompletePath.Empty(); Lock lock(this,LOCK_DATA); results.autoCompletePath=m_AutoCompletePath; bool bSearchSubWord=GetSettingBool(L"SearchSubWord"); if (m_AutoCompletePath.IsEmpty()) { { std::vector &programs=m_bProgramsFound?m_ProgramItems:m_ProgramItemsOld; std::sort(programs.begin(),programs.end()); std::vector foundItems; for (std::vector::const_iterator it=programs.begin();it!=programs.end();++it) { if (it->category==CATEGORY_PROGRAM && it->MatchText(m_SearchText,bSearchSubWord)) { bool bDuplicate=false; bool bAppResolved=false; for (std::vector::const_iterator it2=foundItems.begin();it2!=foundItems.end();++it2) { if (wcscmp(it->name,(*it2)->name)==0 && it->bMetroLink==(*it2)->bMetroLink) { if (!bAppResolved) { bAppResolved=true; g_ItemManager.UpdateItemInfo(it->pInfo,CItemManager::INFO_LINK_APPID); } g_ItemManager.UpdateItemInfo((*it2)->pInfo,CItemManager::INFO_LINK_APPID); CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS); if (it->pInfo->GetAppid()==(*it2)->pInfo->GetAppid()) { bDuplicate=true; break; } } } if (!bDuplicate) { results.programs.push_back(it->pInfo); foundItems.push_back(&*it); } } } } { std::vector &settings=m_bSettingsFound?m_SettingsItems:m_SettingsItemsOld; for (std::vector::iterator it=settings.begin();it!=settings.end();++it) { int match=(it->category==CATEGORY_SETTING || it->category==CATEGORY_METROSETTING)?it->MatchText(m_SearchText,bSearchSubWord):0; it->rank=(it->rank&0xFFFFFFFE)|(match>>1); } std::sort(settings.begin(),settings.end()); for (std::vector::const_iterator it=settings.begin();it!=settings.end();++it) { if (it->MatchText(m_SearchText, bSearchSubWord)) { if (it->category==CATEGORY_SETTING) results.settings.push_back(it->pInfo); if (it->category==CATEGORY_METROSETTING) results.metrosettings.push_back(it->pInfo); } } } results.indexed=m_IndexedItems; } else { std::sort(m_AutoCompleteItems.begin(),m_AutoCompleteItems.end()); Assert(_wcsnicmp(m_SearchText,m_AutoCompletePath,m_AutoCompletePath.GetLength())==0); CString filter=m_SearchText.Mid(m_AutoCompletePath.GetLength()+1); if (!filter.IsEmpty()) filter+='*'; for (std::vector::const_iterator it=m_AutoCompleteItems.begin();it!=m_AutoCompleteItems.end();++it) { if (filter.IsEmpty() || PathMatchSpec(it->name,filter)) results.autocomplete.push_back(it->pInfo); } } results.bResults=(!results.programs.empty() || !results.settings.empty() || !results.metrosettings.empty() || !results.indexed.empty() || !results.autocomplete.empty()); results.bSearching=(m_LastCompletedId!=m_LastRequestId); } bool CSearchManager::SearchItem::MatchTextInt( const wchar_t *search, const CString &text, bool bSearchSubWord ) { if (text.IsEmpty()) return false; if (bSearchSubWord) { // split search into tokens and see if all are found for (const wchar_t *pSearch=search;*pSearch;) { wchar_t token[100]; pSearch=GetToken(pSearch,token,_countof(token),L" "); if (FindNLSStringEx(LOCALE_NAME_USER_DEFAULT,FIND_FROMSTART|LINGUISTIC_IGNORECASE|LINGUISTIC_IGNOREDIACRITIC,text,-1,token,-1,NULL,NULL,NULL,0)<0) return false; } } else { // split search into tokens, then see if any of the words start with those tokens for (const wchar_t *pSearch=search;*pSearch;) { wchar_t token[100]; pSearch=GetToken(pSearch,token,_countof(token),L" "); bool bFound=false; int len=Strlen(token); for (const wchar_t *pName=text;*pName;) { while (*pName && wcschr(L" \t.,$&[]{}();|",*pName)) pName++; if (FindNLSStringEx(LOCALE_NAME_USER_DEFAULT,FIND_STARTSWITH|LINGUISTIC_IGNORECASE|LINGUISTIC_IGNOREDIACRITIC,pName,-1,token,len,NULL,NULL,NULL,0)>=0) { bFound=true; break; } while (*pName && !wcschr(L" \t.,$&[]{}();|",*pName)) pName++; } if (!bFound) return false; } } return true; } void CSearchManager::LaunchExternalSearch( PIDLIST_ABSOLUTE root, unsigned int categoryHash, const CString &searchText ) { Assert(GetCurrentThreadId()==m_MainThreadId); if (searchText.IsEmpty()) return; CComPtr pConditionFactory; pConditionFactory.CoCreateInstance(CLSID_ConditionFactory); if (!pConditionFactory) return; CComPtr pSearchFactory; pSearchFactory.CoCreateInstance(CLSID_SearchFolderItemFactory); if (!pSearchFactory) return; std::vector> conditions; CComPtr pCondition; if (!root) { if (categoryHash==CATEGORY_FILE) { // uncategorized files PROPERTYKEY keyGroup; if (FAILED(PSGetPropertyKeyFromName(L"System.StartMenu.Group",&keyGroup))) return; if (FAILED(pConditionFactory->CreateStringLeaf(keyGroup,COP_EQUAL,L"files",NULL,CONDITION_CREATION_DEFAULT,IID_PPV_ARGS(&pCondition)))) return; conditions.push_back(pCondition); } else if ((categoryHash&CATEGORY_MASK)==CATEGORY_FILE) { // all files if (FAILED(pConditionFactory->CreateStringLeaf(PKEY_Search_Store,COP_EQUAL,L"file",NULL,CONDITION_CREATION_DEFAULT,IID_PPV_ARGS(&pCondition)))) return; conditions.push_back(pCondition); } pCondition=NULL; } PROPERTYKEY keyString; if (!GetSettingBool(L"SearchContents")) keyString=PKEY_ItemNameDisplay; else if (FAILED(PSGetPropertyKeyFromName(L"System.Generic.String",&keyString))) return; // create condition for each word const wchar_t *str=searchText; const wchar_t *str0=str; while (*str) { while (*str==' ') str++; CONDITION_OPERATION oper=*str=='"'?COP_WORD_EQUAL:COP_WORD_STARTSWITH; wchar_t token[100]; str=GetToken(str,token,_countof(token),L" "); if (SUCCEEDED(pConditionFactory->CreateStringLeaf(keyString,oper,token,NULL,CONDITION_CREATION_DEFAULT,IID_PPV_ARGS(&pCondition)))) { conditions.push_back(pCondition); pCondition=NULL; } } if (root) { PCIDLIST_ABSOLUTE pidls[1]={root}; CComPtr pArray; if (SUCCEEDED(SHCreateShellItemArrayFromIDLists(1,pidls,&pArray))) pSearchFactory->SetScope(pArray); } else if (categoryHash==CATEGORY_FILE) { CAbsolutePidl root2; SHParseDisplayName(L"::{DAF95313-E44D-46AF-BE1B-CBACEA2C3065}",NULL,&root2,0,NULL); PCIDLIST_ABSOLUTE pidls[1]={root2}; CComPtr pArray; if (SUCCEEDED(SHCreateShellItemArrayFromIDLists(1,pidls,&pArray))) pSearchFactory->SetScope(pArray); } if (conditions.size()==1) pSearchFactory->SetCondition(conditions[0]); else { CComPtr pConditionAnd; if (SUCCEEDED(pConditionFactory->CreateCompoundFromArray(CT_AND_CONDITION,&conditions[0].p,(ULONG)conditions.size(),CONDITION_CREATION_DEFAULT,IID_PPV_ARGS(&pConditionAnd)))) pSearchFactory->SetCondition(pConditionAnd); } CComPtr pSearchItem; if (FAILED(pSearchFactory->GetShellItem(IID_IShellItem,(void**)&pSearchItem))) return; SHELLEXECUTEINFO execute={sizeof(execute)}; execute.lpVerb=L"open"; execute.nShow=SW_SHOWNORMAL; execute.fMask=SEE_MASK_IDLIST; CAbsolutePidl pidl; if (SUCCEEDED(SHGetIDListFromObject(pSearchItem,&pidl))) { /* // Unsucessful attempt to use some undocumented APIs to highlight the search term in Explorer. // The seach box is populated with the text but the items are still not higlighted const GUID IID_IFilterCondition={0xFCA2857D,0x1760,0x4AD3,{0x8C,0x63,0xC9,0xB6,0x02,0xFC,0xBA,0xEA}}; interface IFilterCondition: public IPersistStream { }; const GUID IID_IShellFolder3={0x711B2CFD,0x93D1,0x422B,{0xBD,0xF4,0x69,0xBE,0x92,0x3F,0x24,0x49}}; typedef DWORD FILTERIDLISTTYPE; interface IShellFolder3: public IShellFolder2 { STDMETHOD(CreateFilteredIDList)(IFilterCondition *, FILTERIDLISTTYPE, IPropertyStore *, PITEMID_CHILD *)=0; // STDMETHOD(GetFilteredIDListType)(PCITEMID_CHILD, FILTERIDLISTTYPE *); // STDMETHOD(ModifyFilteredIDList)(PCITEMID_CHILD, IFilterCondition *, PITEMID_CHILD *); // STDMETHOD(ReparentFilteredIDList)(PCIDLIST_RELATIVE, PIDLIST_RELATIVE *); // STDMETHOD(CreateStackedIDList)(PROPERTYKEY const &, PIDLIST_ABSOLUTE *); // STDMETHOD(GetStackedKey)(PROPERTYKEY *); // STDMETHOD(EnumObjectsEx)(HWND, IBindCtx *, ULONG, IItemFilter *, IEnumIDList **); // STDMETHOD(GetConditions)(PROPERTYKEY const &, IQueryUnit *, REFIID, PVOID *); // STDMETHOD(GetAutoListFlags)(ULONG *); }; typedef HRESULT (WINAPI*tSHCreateFilter)( PCWSTR Name, PCWSTR InFolder, PROPERTYKEY const &PropertyKey, INT Type, ICondition *Condition, REFIID riid, PVOID *ppv ); tSHCreateFilter SHCreateFilter=(tSHCreateFilter)GetProcAddress(GetModuleHandle(L"shell32.dll"),MAKEINTRESOURCEA(818)); if (SHCreateFilter) { PROPERTYKEY wordWheel=PKEY_Kind; wordWheel.pid=5; CComPtr pFilter; HRESULT hr=SHCreateFilter(searchText,NULL,wordWheel,7,pCondition,IID_IFilterCondition,(void**)&pFilter); if (pFilter) { CComPtr pShellFolder3; SHBindToObject(NULL,pidl,NULL,IID_IShellFolder3,(void**)&pShellFolder3); if (pShellFolder3) { PITEMID_CHILD pChild; hr=pShellFolder3->CreateFilteredIDList(pFilter,2,NULL,&pChild); if (SUCCEEDED(hr)) { pSearchItem=NULL; if (SUCCEEDED(SHCreateItemWithParent(NULL,pShellFolder3,pChild,IID_IShellItem,(void**)&pSearchItem))) { CAbsolutePidl pidl2; if (SUCCEEDED(SHGetIDListFromObject(pSearchItem,&pidl2))) pidl.Swap(pidl2); } ILFree(pChild); } } } }*/ execute.lpIDList=pidl; ShellExecuteEx(&execute); } } void CSearchManager::LaunchInternetSearch( const CString &searchText ) { Assert(GetCurrentThreadId()==m_MainThreadId); if (searchText.IsEmpty()) return; if (IsEdgeDefaultBrowser()) { wchar_t search[256]; Sprintf(search,_countof(search),L"? %s",searchText); ShellExecute(NULL,NULL,L"shell:appsfolder\\Microsoft.MicrosoftEdge_8wekyb3d8bbwe!MicrosoftEdge",search,NULL,SW_SHOWNORMAL); } else { wchar_t path[_MAX_PATH]; DWORD size=_countof(path); if (SUCCEEDED(AssocQueryString(0,ASSOCSTR_EXECUTABLE,L"http",L"open",path,&size))) { wchar_t search[256]; Sprintf(search,_countof(search),L"\"? %s\"",searchText); ShellExecute(NULL,NULL,path,search,NULL,SW_SHOWNORMAL); } } } bool HasSearchService( void ) { bool bWSearch=false; SC_HANDLE hManager=OpenSCManager(NULL,NULL,SC_MANAGER_CONNECT); if (hManager) { SC_HANDLE hService=OpenService(hManager,L"WSearch",SERVICE_QUERY_STATUS); if(hService) { // service is installed SERVICE_STATUS status; if(QueryServiceStatus(hService,&status)) { bWSearch=(status.dwCurrentState==SERVICE_RUNNING); } CloseServiceHandle(hService); } CloseServiceHandle(hManager); } return bWSearch; }