// findband.cpp : Implementation of CFileSearchBand #include "shellprv.h" #include "findband.h" #include "findfilter.h" #include // AdminIndexServer custom interface #define CGID_FileSearchBand CLSID_FileSearchBand extern int IsVK_TABCycler(MSG *pMsg); enum { // toolbar image list indices: iFSTBID_NEW, iFSTBID_HELP, }; #define MAKE_FSTBID(ilIndex) (100 /*arbitrary*/ + (ilIndex)) // toolbar button IDs #define FSTBID_NEW MAKE_FSTBID(iFSTBID_NEW) #define FSTBID_HELP MAKE_FSTBID(iFSTBID_HELP) static const TBBUTTON _rgtb[] = { { iFSTBID_NEW, FSTBID_NEW, TBSTATE_ENABLED, BTNS_AUTOSIZE | BTNS_SHOWTEXT,{0, 0}, 0, 0}, { -1, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0}, { iFSTBID_HELP, FSTBID_HELP, TBSTATE_ENABLED, BTNS_AUTOSIZE, {0, 0}, 0, 1}, }; inline BOOL _IsEditWindowClass(HWND hwndTest) { return IsWindowClass(hwndTest, TEXT("Edit")); } inline BOOL _IsComboWindowClass(HWND hwndTest) { #define COMBO_CLASS TEXT("ComboBox") return _IsEditWindowClass(hwndTest) ? IsWindowClass(GetParent(hwndTest), COMBO_CLASS) : IsWindowClass(hwndTest, COMBO_CLASS); } // CFileSearchBand impl CWndClassInfo& CFileSearchBand::GetWndClassInfo() { static CWndClassInfo wc = { { sizeof(WNDCLASSEX), CS_SAVEBITS, StartWindowProc, 0, 0, 0, 0, 0, 0, 0, FILESEARCHCTL_CLASS, 0 }, NULL, NULL, IDC_ARROW, TRUE, 0, _T("") }; return wc; } CFileSearchBand::CFileSearchBand() : _dlgFSearch(this), _dlgCSearch(this), #ifdef __PSEARCH_BANDDLG__ _dlgPSearch(this), #endif __PSEARCH_BANDDLG__ _fValid(TRUE), _dwBandID(-1), _dwBandViewMode(DBIF_VIEWMODE_VERTICAL) { // Verify that it initialized correctly: ASSERT(_pBandDlg == NULL); ASSERT(_psb == NULL); ASSERT(_guidSearch == GUID_NULL); ASSERT(_fDirty == FALSE); ASSERT(_fDeskBand == FALSE); ASSERT(_punkSite == NULL); ASSERT(_bSendFinishedDisplaying == FALSE); m_bWindowOnly = TRUE; ZeroMemory(&_siHorz, sizeof(_siHorz)); ZeroMemory(&_siVert, sizeof(_siVert)); _siHorz.cbSize = _siVert.cbSize = sizeof(SCROLLINFO); _sizeMin.cx = _sizeMin.cy = 0; _sizeMax.cx = _sizeMax.cy = 32000; // arbitrarily large. } CFileSearchBand::~CFileSearchBand() { ImageList_Destroy(_hilDefault); ImageList_Destroy(_hilHot); } HWND CFileSearchBand::Create( HWND hWndParent, RECT& rcPos, LPCTSTR szWindowName, DWORD dwStyle, DWORD dwExStyle, UINT nID) { INITCOMMONCONTROLSEX icc; TCHAR szCaption[128]; icc.dwSize = sizeof(icc); icc.dwICC = ICC_DATE_CLASSES|ICC_UPDOWN_CLASS|ICC_USEREX_CLASSES|ICC_ANIMATE_CLASS; EVAL(LoadString(HINST_THISDLL, IDS_FSEARCH_CAPTION, szCaption, ARRAYSIZE(szCaption))); InitCommonControlsEx(&icc); dwExStyle |= WS_EX_CONTROLPARENT; dwStyle |= WS_CLIPCHILDREN; return CWindowImpl::Create(hWndParent, rcPos, szCaption, dwStyle, dwExStyle, nID); } LRESULT CFileSearchBand::OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { if (FAILED(ShowBandDialog(SRCID_SFileSearch))) return -1; return 0; } CBandDlg* CFileSearchBand::GetBandDialog(REFGUID guidSearch) { if (IsEqualGUID(guidSearch, SRCID_SFileSearch)) { return &_dlgFSearch; } #ifdef __PSEARCH_BANDDLG__ else if (IsEqualGUID(guidSearch, SRCID_SFindPrinter)) { return &_dlgPSearch; } #endif __PSEARCH_BANDDLG__ else if (IsEqualGUID(guidSearch, SRCID_SFindComputer)) { return &_dlgCSearch; } return NULL; } // IFileSearchBand::SetSearchParameters() STDMETHODIMP CFileSearchBand::SetSearchParameters( IN BSTR* pbstrSearchID, IN VARIANT_BOOL bNavToResults, IN OPTIONAL VARIANT *pvarScope, IN OPTIONAL VARIANT *pvarQueryFile) { HRESULT hr; GUID guidSearch; if (SUCCEEDED(SHCLSIDFromString(*pbstrSearchID, &guidSearch))) { hr = ShowBandDialog(guidSearch, bNavToResults, TRUE); if (SUCCEEDED(hr)) { CBandDlg* pBandDlg = GetBandDialog(guidSearch); ASSERT(pBandDlg); if (pvarScope && pvarScope->vt != VT_EMPTY) pBandDlg->SetScope(pvarScope, TRUE); if (pvarQueryFile && pvarQueryFile->vt != VT_EMPTY) pBandDlg->SetQueryFile(pvarQueryFile); } } else { hr = E_INVALIDARG; } return hr; } HRESULT CFileSearchBand::ShowBandDialog( REFGUID guidSearch, BOOL bNavigateToResults, BOOL bDefaultFocusCtl) { CBandDlg *pDlgNew = NULL, *pDlgOld = _pBandDlg; GUID guidOld = _guidSearch; BOOL bNewWindow = FALSE; if (NULL == (pDlgNew = GetBandDialog(guidSearch))) return E_INVALIDARG; _pBandDlg = pDlgNew; _guidSearch = guidSearch; // If the dialog window has not been created, do so now. if (!::IsWindow(pDlgNew->Hwnd())) { if (NULL == pDlgNew->Create(*this)) { _pBandDlg = pDlgOld; _guidSearch = guidOld; return E_FAIL; } bNewWindow = TRUE; } if (pDlgNew != pDlgOld) { // If we have an active dialog, hide it if (pDlgOld && ::IsWindow(pDlgOld->Hwnd())) { ::ShowWindow(pDlgOld->Hwnd(), SW_HIDE); pDlgOld->OnBandDialogShow(FALSE); } bNewWindow = TRUE; } if (bNewWindow) { // Show the new dialog window UpdateLayout(BLF_ALL); _pBandDlg->OnBandDialogShow(TRUE); ::ShowWindow(_pBandDlg->Hwnd(), SW_SHOW); ::UpdateWindow(_pBandDlg->Hwnd()); if (bDefaultFocusCtl) _pBandDlg->SetDefaultFocus(); } if (bNavigateToResults) { // Navigate to results shell folder. IWebBrowser2* pwb2; HRESULT hr = IUnknown_QueryService(GetTopLevelBrowser(), SID_SWebBrowserApp, IID_PPV_ARG(IWebBrowser2, &pwb2)); if (SUCCEEDED(hr)) { _pBandDlg->NavigateToResults(pwb2); pwb2->Release(); } } return S_OK; } void CFileSearchBand::AddButtons(BOOL fAdd) { if (_fDeskBand) { ASSERT(BandSite()); IExplorerToolbar* piet; if (SUCCEEDED(BandSite()->QueryInterface(IID_PPV_ARG(IExplorerToolbar, &piet)))) { if (fAdd) { HRESULT hr = piet->SetCommandTarget((IUnknown*)SAFECAST(this, IOleCommandTarget*), &CGID_FileSearchBand, 0); if (hr == S_OK) { if (!_fStrings) { piet->AddString(&CGID_SearchBand, HINST_THISDLL, IDS_FSEARCH_TBLABELS, &_cbOffset); _fStrings = TRUE; } if (LoadImageLists()) piet->SetImageList(&CGID_FileSearchBand, _hilDefault, _hilHot, NULL); TBBUTTON rgtb[ARRAYSIZE(_rgtb)]; memcpy(rgtb, _rgtb, sizeof(_rgtb)); for (int i = 0; i < ARRAYSIZE(rgtb); i++) rgtb[i].iString += _cbOffset; piet->AddButtons(&CGID_FileSearchBand, ARRAYSIZE(rgtb), rgtb); } } else piet->SetCommandTarget(NULL, NULL, 0); piet->Release(); } } } BOOL CFileSearchBand::LoadImageLists() { if (_hilDefault == NULL) { _hilDefault = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDB_FSEARCHTB_DEFAULT), 18, 0, CLR_DEFAULT, IMAGE_BITMAP, LR_CREATEDIBSECTION); } if (_hilHot == NULL) { _hilHot = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDB_FSEARCHTB_HOT), 18, 0, CLR_DEFAULT, IMAGE_BITMAP, LR_CREATEDIBSECTION); } return _hilDefault != NULL && _hilHot != NULL; } STDMETHODIMP CFileSearchBand::get_Scope(OUT VARIANT *pvarScope) { if (BandDlg()) return _pBandDlg->GetScope(pvarScope); VariantInit(pvarScope); return E_FAIL; } STDMETHODIMP CFileSearchBand::get_QueryFile(OUT VARIANT *pvarFile) { if (BandDlg()) return _pBandDlg->GetQueryFile(pvarFile); VariantInit(pvarFile); return E_FAIL; } STDMETHODIMP CFileSearchBand::get_SearchID(OUT BSTR* pbstrSearchID) { if (!pbstrSearchID) return E_POINTER; WCHAR wszGuid[GUIDSTR_MAX+1]; SHStringFromGUIDW(_guidSearch, wszGuid, ARRAYSIZE(wszGuid)); *pbstrSearchID = SysAllocString(wszGuid); return IsEqualGUID(GUID_NULL, _guidSearch) ? S_FALSE : S_OK; } CBandDlg* CFileSearchBand::BandDlg() { return _pBandDlg; } HRESULT CFileSearchBand::SetFocus() { HRESULT hr = AutoActivate(); if (SUCCEEDED(hr)) { if (!IsChild(GetFocus())) ::SetFocus(BandDlg()->Hwnd()); } return hr; } LRESULT CFileSearchBand::OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&) { LRESULT lRet = CWindowImpl::DefWindowProc(uMsg, wParam, lParam); AutoActivate(); return lRet; } LRESULT CFileSearchBand::OnWinIniChange(UINT, WPARAM, LPARAM, BOOL&) { _metrics.OnWinIniChange(BandDlg()->Hwnd()); BandDlg()->OnWinIniChange(); UpdateLayout(); return 0; } HRESULT CFileSearchBand::AutoActivate() { HRESULT hr = S_OK; if (!::IsWindow(m_hWnd)) return hr; if (_fDeskBand) { if (_punkSite) { IInputObjectSite* pios; hr = _punkSite->QueryInterface(IID_PPV_ARG(IInputObjectSite, &pios)); if (SUCCEEDED(hr)) { hr = pios->OnFocusChangeIS(SAFECAST(this, IInputObject*), TRUE); pios->Release(); } } } else if (!m_bUIActive) { RECT rc; ::GetWindowRect(m_hWnd, &rc); ::MapWindowPoints(HWND_DESKTOP, GetParent(), (LPPOINT)&rc, 2); hr = DoVerb(OLEIVERB_UIACTIVATE, NULL, NULL, 0, GetParent(), &rc); } return hr; } void CFileSearchBand::SetDirty(BOOL bDirty) { _fDirty = bDirty; _dlgFSearch.UpdateSearchCmdStateUI(); } LRESULT CFileSearchBand::OnSize(UINT, WPARAM wParam, LPARAM lParam, BOOL&) { POINTS pts = MAKEPOINTS(lParam); LayoutControls(pts.x, pts.y, BLF_ALL); return 0; } LRESULT CFileSearchBand::OnEraseBkgnd(UINT, WPARAM, LPARAM, BOOL&) { return TRUE; } HRESULT CFileSearchBand::SetObjectRects(LPCRECT prcPos, LPCRECT prcClip) { return IOleInPlaceObjectWindowlessImpl::SetObjectRects(prcPos, prcClip); } STDMETHODIMP CFileSearchBand::PrivateQI(REFIID iid, void **ppvObject) { return _InternalQueryInterface(iid, ppvObject); } STDMETHODIMP CFileSearchBand::DoVerbUIActivate(LPCRECT prcPosRect, HWND hwndParent) { // Patch in shell32 logic. return CShell32AtlIDispatch:: DoVerbUIActivate(prcPosRect, hwndParent, m_hWnd); } void CFileSearchBand::UpdateLayout(ULONG fLayoutFlags) { RECT rc; GetClientRect(&rc); LayoutControls(RECTWIDTH(rc), RECTHEIGHT(rc), fLayoutFlags); } void CFileSearchBand::LayoutControls(int cx, int cy, ULONG fLayoutFlags) { if (/*NULL == BandDlg() ||*/ !::IsWindow(BandDlg()->Hwnd())) return; SIZE sizeMin; BandDlg()->GetMinSize(m_hWnd, &sizeMin); // size of dialog if (fLayoutFlags & BLF_CALCSCROLL) { // Stash pos before recalculating POINT pos; pos.x = _siHorz.nPos; pos.y = _siVert.nPos; _siHorz.fMask = _siVert.fMask = (SIF_RANGE|SIF_PAGE); _siHorz.nPage = cx; // thumb width _siVert.nPage = cy; // thumb height SIZE sizeDelta; // difference between what we have to show and what is shown. sizeDelta.cx = sizeMin.cx - _siHorz.nPage; sizeDelta.cy = sizeMin.cy - _siVert.nPage; // establish maximum scroll positions _siHorz.nMax = sizeDelta.cx > 0 ? sizeMin.cx - 1 : 0; _siVert.nMax = sizeDelta.cy > 0 ? sizeMin.cy - 1 : 0; // establish horizontal scroll pos if (sizeDelta.cx <= 0) _siHorz.nPos = 0; // scroll to extreme left if we're removing scroll bar else if (sizeDelta.cx < _siHorz.nPos) _siHorz.nPos = sizeDelta.cx; // remove right-hand vacancy if (_siHorz.nPos != pos.x) _siHorz.fMask |= SIF_POS; // establish vertical scroll pos if (sizeDelta.cy <= 0) _siVert.nPos = 0; // scroll to top if we're removing scroll bar else if (sizeDelta.cy < _siVert.nPos) _siVert.nPos = sizeDelta.cy; // remove lower-portion vacancy if (_siVert.nPos != pos.y) _siVert.fMask |= SIF_POS; // Note: can't call SetScrollInfo here, as it may generate // a WM_SIZE and recurse back to this function before we had a // chance to SetWindowPos() our subdlg. So defer it until after // we've done this. } DWORD fSwp = SWP_NOZORDER | SWP_NOACTIVATE; if (0 == (fLayoutFlags & BLF_RESIZECHILDREN)) fSwp |= SWP_NOSIZE; if (0 == (fLayoutFlags & BLF_SCROLLWINDOW)) fSwp |= SWP_NOMOVE; // Move or size the main subdialog as requested... if (0 == (fSwp & SWP_NOMOVE) || 0 == (fSwp & SWP_NOSIZE)) ::SetWindowPos(BandDlg()->Hwnd(), NULL, -_siHorz.nPos, -_siVert.nPos, max(cx, sizeMin.cx), max(cy, sizeMin.cy), fSwp); // Update scroll parameters if (fLayoutFlags & BLF_CALCSCROLL) { SetScrollInfo(SB_HORZ, &_siHorz, TRUE); SetScrollInfo(SB_VERT, &_siVert, TRUE); } } void CFileSearchBand::Scroll(int nBar, UINT uSBCode, int nNewPos /*optional*/) { int nDeltaMax; SCROLLINFO *psbi; const LONG nLine = 8; psbi = (SB_HORZ == nBar) ? &_siHorz : &_siVert; nDeltaMax = (psbi->nMax - psbi->nPage) + 1; switch (uSBCode) { case SB_LEFT: psbi->nPos--; break; case SB_RIGHT: psbi->nPos++; break; case SB_LINELEFT: psbi->nPos = max(psbi->nPos - nLine, 0); break; case SB_LINERIGHT: psbi->nPos = min(psbi->nPos + nLine, nDeltaMax); break; case SB_PAGELEFT: psbi->nPos = max(psbi->nPos - (int)psbi->nPage, 0); break; case SB_PAGERIGHT: psbi->nPos = min(psbi->nPos + (int)psbi->nPage, nDeltaMax); break; case SB_THUMBTRACK: psbi->nPos = nNewPos; break; case SB_THUMBPOSITION: psbi->nPos = nNewPos; break; case SB_ENDSCROLL: return; } psbi->fMask = SIF_POS; SetScrollInfo(nBar, psbi, TRUE); UpdateLayout(BLF_ALL &~ BLF_CALCSCROLL /*no need to recalc scroll state data*/); } // WM_HSCROLL/WM_VSCROLL handler LRESULT CFileSearchBand::OnScroll(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { Scroll((WM_HSCROLL == nMsg) ? SB_HORZ : SB_VERT, LOWORD(wParam), HIWORD(wParam)); return 0; } void CFileSearchBand::EnsureVisible(LPCRECT lprc /* in screen coords */) { ASSERT(lprc); RECT rc = *lprc; RECT rcClient; RECT vertexDeltas; SIZE scrollDelta; ::MapWindowPoints(HWND_DESKTOP, m_hWnd, (LPPOINT)&rc, POINTSPERRECT); GetClientRect(&rcClient); BOOL fTaller = RECTHEIGHT(rc) > RECTHEIGHT(rcClient); BOOL fFatter = RECTWIDTH(rc) > RECTWIDTH(rcClient); // Store deltas at each vertex SetRect(&vertexDeltas, rc.left - rcClient.left, rc.top - rcClient.top, rc.right - rcClient.right, rc.bottom - rcClient.bottom); // Compute scroll deltas scrollDelta.cx = (vertexDeltas.left < 0) ? vertexDeltas.left : (vertexDeltas.right > 0 && !fFatter) ? vertexDeltas.right : 0; scrollDelta.cy = (vertexDeltas.top < 0) ? vertexDeltas.top : (vertexDeltas.bottom > 0 && !fTaller) ? vertexDeltas.bottom : 0; // Scroll into view as necessary. if (scrollDelta.cx) { _siHorz.fMask = SIF_POS; _siHorz.nPos += scrollDelta.cx; SetScrollInfo(SB_HORZ, &_siHorz, TRUE); } if (scrollDelta.cy) { _siVert.fMask = SIF_POS; _siVert.nPos += scrollDelta.cy; SetScrollInfo(SB_VERT, &_siVert, TRUE); } UpdateLayout(BLF_ALL &~ BLF_CALCSCROLL); } HRESULT CFileSearchBand::TranslateAccelerator(MSG *pmsg) { return CShell32AtlIDispatch ::TranslateAcceleratorPriv(this, pmsg, m_spClientSite); } HRESULT CFileSearchBand::TranslateAcceleratorInternal(MSG *pmsg, IOleClientSite * pocs) { CBandDlg* pdlg = BandDlg(); ASSERT(pdlg); if (::IsChild(pdlg->Hwnd(), pmsg->hwnd)) { // Permit tabbing out of pane: int nDir; if ((nDir = IsVK_TABCycler(pmsg)) != 0) { if (nDir > 0 && (pmsg->hwnd == pdlg->GetLastTabItem())) return S_FALSE; if (nDir < 0 && (pmsg->hwnd == pdlg->GetFirstTabItem())) return S_FALSE; } // try base class handler if (S_OK == pdlg->TranslateAccelerator(pmsg)) return S_OK; } else if (IsDialogMessage(pmsg)) return S_OK; return IOleInPlaceActiveObjectImpl::TranslateAccelerator(pmsg); } // Determines whether the the specified message is keyboard input intended // to scroll the pane. If the pane is scrolled as a result of the // message, the function returns TRUE; otherwise it returns FALSE. BOOL CFileSearchBand::IsKeyboardScroll(MSG* pmsg) { if (pmsg->message == WM_KEYDOWN && (GetKeyState(VK_CONTROL) & 0x8000) != 0 && pmsg->wParam != VK_CONTROL) { int nBar = SB_VERT; UINT uSBCode; int nNewPos = 0; BOOL bEditCtl = _IsEditWindowClass(pmsg->hwnd); BOOL bScroll = TRUE; // Some of the following CTRL-key combinations are // not valid pane scroll keys if the target child window is an // edit control. switch (pmsg->wParam) { case VK_UP: uSBCode = SB_LINELEFT; break; case VK_DOWN: uSBCode = SB_LINERIGHT; break; case VK_PRIOR: uSBCode = SB_PAGELEFT; break; case VK_NEXT: uSBCode = SB_PAGERIGHT; break; case VK_END: uSBCode = SB_THUMBPOSITION; nNewPos = _siVert.nMax - _siVert.nPage; break; case VK_HOME: uSBCode = SB_THUMBPOSITION; nNewPos = 0; break; case VK_LEFT: bScroll = !bEditCtl; nBar = SB_HORZ; uSBCode = SB_LINELEFT; break; case VK_RIGHT: bScroll = !bEditCtl; nBar = SB_HORZ; uSBCode = SB_LINERIGHT; break; default: return FALSE; } // scroll only if we have to; reduce flicker. if (bScroll && ((SB_VERT == nBar && _siVert.nMax != 0) || (SB_HORZ == nBar && _siHorz.nMax != 0))) { Scroll(nBar, uSBCode, nNewPos); return TRUE; } } return FALSE; } // Determines whether the indicated key should be passed to the top // level browser frame. BOOL CFileSearchBand::IsBrowserAccelerator(MSG *pmsg) { if ((WM_KEYDOWN == pmsg->message || WM_KEYUP == pmsg->message)) { BOOL bCombobox = _IsComboWindowClass(pmsg->hwnd); BOOL bComboDropped = (BOOL)(bCombobox ? ::SendMessage(pmsg->hwnd, CB_GETDROPPEDSTATE, 0, 0) : FALSE); BOOL bEditCtl = _IsEditWindowClass(pmsg->hwnd); // Keys that we treat WITHOUT regard to state of CTRL key: if (VK_F4 == pmsg->wParam && bCombobox) // should toggle dropped/close-up of combo. return FALSE; // Keys that we treat WITH regard to state of CTRL key: if ((GetKeyState(VK_CONTROL) & 0x8000) != 0) { // Edit cut copy paste? if (bEditCtl) { switch (pmsg->wParam) { case 'C': case 'X': case 'V': case 'Z': return FALSE; } } return TRUE; // all other CTRL-key combinations are browser keys. } else { switch (pmsg->wParam) { // browser accelerators that may be shunted by edit controls. case VK_BACK: return !bEditCtl; if (VK_ESCAPE == pmsg->wParam) // should close up the combo. return bComboDropped; default: if (pmsg->wParam >= VK_F1 && pmsg->wParam <= VK_F24) return TRUE; } } } return FALSE; } HRESULT CFileSearchBand::IsDlgMessage(HWND hwnd, MSG *pmsg) { // handle tab cycling (Let browser handle F6) if (!IsVK_TABCycler(pmsg) || pmsg->wParam == VK_F6) { if (IsBrowserAccelerator(pmsg)) { IShellBrowser* psb = GetTopLevelBrowser(); return (psb && S_OK == psb->TranslateAcceleratorSB(pmsg, 0)) ? S_OK : S_FALSE; } } // send through dialog manager if (::IsDialogMessage((hwnd != NULL ? hwnd : m_hWnd), pmsg)) return S_OK; // not handled. return S_FALSE ; } IShellBrowser* CFileSearchBand::GetTopLevelBrowser() { if (NULL == _psb) IUnknown_QueryService(BandSite(), SID_STopLevelBrowser, IID_PPV_ARG(IShellBrowser, &_psb)); return _psb; } void CFileSearchBand::FinalRelease() { // ATL 2.1 has a bug in class unregistration. Here's // the work around: UnregisterClass(GetWndClassInfo().m_wc.lpszClassName, GetWndClassInfo().m_wc.hInstance); GetWndClassInfo().m_atom = 0; SetSite(NULL); } //-----------------------------// // IDeskBand : IDockingWindow STDMETHODIMP CFileSearchBand::GetBandInfo(DWORD dwBandID, DWORD dwViewMode, DESKBANDINFO* pdbi) { _dwBandID = dwBandID; _dwBandViewMode = dwViewMode; if (pdbi->dwMask & DBIM_MINSIZE) { pdbi->ptMinSize.x = _sizeMin.cx; pdbi->ptMinSize.y = _sizeMin.cy; } if (pdbi->dwMask & DBIM_MAXSIZE) { pdbi->ptMaxSize.x = _sizeMax.cx; pdbi->ptMaxSize.y = _sizeMax.cy; } if (pdbi->dwMask & DBIM_INTEGRAL) { pdbi->ptIntegral.x = pdbi->ptIntegral.y = 1; } if (pdbi->dwMask & DBIM_ACTUAL) { pdbi->ptActual.x = pdbi->ptActual.y = 0; } if (pdbi->dwMask & DBIM_TITLE) { TCHAR szTitle[256]; EVAL(LoadString(HINST_THISDLL, IDS_FSEARCH_BANDCAPTION, szTitle, ARRAYSIZE(szTitle))); SHTCharToUnicode(szTitle, pdbi->wszTitle, ARRAYSIZE(pdbi->wszTitle)); } if (pdbi->dwMask & DBIM_MODEFLAGS) { pdbi->dwModeFlags = DBIMF_NORMAL|DBIMF_VARIABLEHEIGHT|DBIMF_DEBOSSED|DBIMF_BKCOLOR; } if (pdbi->dwMask & DBIM_BKCOLOR) { pdbi->crBkgnd = GetSysColor(COLOR_3DFACE); } return S_OK; } BOOL CFileSearchBand::IsBandDebut() { HKEY hkey; BOOL bRet = TRUE; if (NULL == (hkey = GetBandRegKey(FALSE))) return bRet; BYTE rgData[128]; DWORD cbData = sizeof(rgData); DWORD dwType; // Hack alert: we should maintain our own initialization reg value rather than using IE's // barsize entry. DWORD dwRet = RegQueryValueEx(hkey, TEXT("BarSize"), NULL, &dwType, rgData, &cbData); if ((ERROR_SUCCESS == dwRet || ERROR_MORE_DATA == dwRet) && cbData > 0) bRet = FALSE; RegCloseKey(hkey); return bRet; } // Hack alert: we should maintain our own reg key rather than using IE's #define FSB_REGKEYFMT TEXT("Software\\Microsoft\\Internet Explorer\\Explorer Bars\\%s") int CFileSearchBand::MakeBandKey(OUT LPTSTR pszKey, IN UINT cchKey) { TCHAR szClsid[GUIDSTR_MAX+1]; SHStringFromGUID(CLSID_FileSearchBand, szClsid, ARRAYSIZE(szClsid)); return wnsprintf(pszKey, cchKey, FSB_REGKEYFMT, szClsid); } int CFileSearchBand::MakeBandSubKey(IN LPCTSTR pszSubKey, OUT LPTSTR pszKey, IN UINT cchKey) { TCHAR szBandKey[MAX_PATH]; int cchRet = MakeBandKey(szBandKey, ARRAYSIZE(szBandKey)); if (cchRet > 0) { StrCpyN(pszKey, szBandKey, cchKey); if (pszSubKey && *pszSubKey && (cchKey - cchRet) > 1) { StrCatBuff(pszKey, TEXT("\\"), cchKey); cchRet++; StrCpyN(pszKey + cchRet, pszSubKey, cchKey - cchRet); return lstrlen(pszKey); } } return 0; } HKEY CFileSearchBand::GetBandRegKey(BOOL bCreateAlways) { HKEY hkey = NULL; TCHAR szKey[MAX_PATH]; if (MakeBandKey(szKey, ARRAYSIZE(szKey)) > 0) { if (bCreateAlways) { DWORD dwDisp; if (ERROR_SUCCESS != RegCreateKeyEx(HKEY_CURRENT_USER, szKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hkey, &dwDisp)) hkey = NULL; } else { if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_CURRENT_USER, szKey, 0, KEY_READ | KEY_WRITE, &hkey)) hkey = NULL; } } return hkey; } void CFileSearchBand::SetDeskbandWidth(int cx) { SIZE sizeMin = _sizeMin, sizeMax = _sizeMax; RECT rc; // Bandsite hack: make sizemin == sizemax equal to // explicitly set band width: GetWindowRect(&rc); // note: you shouldn't be setting width if we're not a band. ASSERT(DBIF_VIEWMODE_VERTICAL == _dwBandViewMode); // note: height and width are reversed for vertical bands like us. _sizeMin.cx = _sizeMax.cx = -1; // ignore height _sizeMin.cy = _sizeMax.cy = cx; // assign new width. BandInfoChanged(); // force the site to enforce the desired size. _sizeMin = sizeMin; _sizeMax = sizeMax; // restore previous min/max. If we're to do it right now, // we'd be overrided by bandsite, who tries to establish the // infoband width after we're done. PostMessage(WMU_BANDINFOUPDATE, 0, 0); } // WMU_BANDINFOUPDATE handler LRESULT CFileSearchBand::OnBandInfoUpdate(UINT, WPARAM, LPARAM, BOOL&) { BandInfoChanged(); return 0; } // Notifies the band site that DESKBANDINFO has changed HRESULT CFileSearchBand::BandInfoChanged() { ASSERT(_dwBandID != (DWORD)-1); VARIANTARG v = {0}; v.vt = VT_I4; v.lVal = _dwBandID; return IUnknown_Exec(_punkSite, &CGID_DeskBand, DBID_BANDINFOCHANGED, 0, &v, NULL); } STDMETHODIMP CFileSearchBand::ShowDW(BOOL fShow) { if (::IsWindow(m_hWnd)) { ShowWindow(fShow ? SW_SHOW : SW_HIDE); AddButtons(fShow); if (fShow && BandDlg() && ::IsWindow(BandDlg()->Hwnd())) BandDlg()->RemoveToolbarTurds(_siVert.nPos); BandDlg()->OnBandShow(fShow); } // Since we are now ready to display the band, we will send the // message that sub dialogs can begin their delayed initialization if (fShow && !_bSendFinishedDisplaying) { HWND hwndFindFiles = _dlgFSearch.Hwnd(); if (hwndFindFiles) { if (::PostMessage(hwndFindFiles, WMU_BANDFINISHEDDISPLAYING, 0, 0)) { _bSendFinishedDisplaying = TRUE; } } } return S_OK; } STDMETHODIMP CFileSearchBand::CloseDW(DWORD dwReserved) { if (::IsWindow(m_hWnd)) DestroyWindow(); return S_OK; } STDMETHODIMP CFileSearchBand::ResizeBorderDW(LPCRECT prcBorder, IUnknown* punkToolbarSite, BOOL fReserved) { return S_OK; } // IObjectWithSite STDMETHODIMP CFileSearchBand::SetSite(IUnknown* pSite) { ATOMICRELEASE(_psb); // free this guy just in case AdvertiseBand(pSite ? TRUE : FALSE); IUnknown_Set(&_punkSite, pSite); if (_punkSite) { HWND hwndSite; if (SUCCEEDED(IUnknown_GetWindow(_punkSite, &hwndSite))) { RECT rcPos; SetRect(&rcPos, 0, 0, 100, 400); m_hWnd = Create(hwndSite, rcPos, NULL, WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|WS_HSCROLL|WS_VSCROLL, 0, 0); } _fDeskBand = TRUE; } return S_OK; } STDMETHODIMP CFileSearchBand::FindFilesOrFolders( BOOL bNavigateToResults, BOOL bDefaultFocusCtl) { return ShowBandDialog(SRCID_SFileSearch, bNavigateToResults, bDefaultFocusCtl); } STDMETHODIMP CFileSearchBand::FindComputer( BOOL bNavigateToResults, BOOL bDefaultFocusCtl) { return ShowBandDialog(SRCID_SFindComputer, bNavigateToResults, bDefaultFocusCtl); } STDMETHODIMP CFileSearchBand::FindPrinter( BOOL bNavigateToResults, BOOL bDefaultFocusCtl) { #ifdef __PSEARCH_BANDDLG__ return ShowBandDialog(SRCID_SFindPrinter, bNavigateToResults, bDefaultFocusCtl); #else __PSEARCH_BANDDLG__ HRESULT hr = E_FAIL; ASSERT(BandSite()); IShellDispatch2* psd2; hr = CoCreateInstance(CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellDispatch2, &psd2)); if (SUCCEEDED(hr)) { hr = psd2->FindPrinter(NULL, NULL, NULL) ; psd2->Release(); } return hr ; #endif __PSEARCH_BANDDLG__ } STDMETHODIMP CFileSearchBand::FindPeople(BOOL bNavigateToResults, BOOL bDefaultFocusCtl) { IObjectWithSite* pows; HRESULT hr = CoCreateInstance(CLSID_SearchAssistantOC, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IObjectWithSite, &pows)); if (SUCCEEDED(hr)) { hr = pows->SetSite(BandSite()); if (SUCCEEDED(hr)) { ISearchAssistantOC* psaoc; hr = pows->QueryInterface(IID_PPV_ARG(ISearchAssistantOC, &psaoc)); if (SUCCEEDED(hr)) { hr = psaoc->FindPeople(); psaoc->Release(); } } pows->Release(); } return hr; } STDMETHODIMP CFileSearchBand::FindOnWeb(BOOL bNavigateToResults, BOOL bDefaultFocusCtl) { IObjectWithSite* pows; HRESULT hr = CoCreateInstance(CLSID_SearchAssistantOC, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IObjectWithSite, &pows)); if (SUCCEEDED(hr)) { hr = pows->SetSite(BandSite()); if (SUCCEEDED(hr)) { ISearchAssistantOC* psaoc; hr = pows->QueryInterface(IID_PPV_ARG(ISearchAssistantOC, &psaoc)); if (SUCCEEDED(hr)) { hr = psaoc->FindOnWeb(); psaoc->Release(); } } pows->Release(); } return hr; } // Make ourself available to clients of IWebBrowser2 by assigning // a VT_UNKNOWN property to the browser. HRESULT CFileSearchBand::AdvertiseBand(BOOL bAdvertise) { if (!BandSite()) return E_UNEXPECTED; HRESULT hr = E_FAIL; IShellBrowser* psb = GetTopLevelBrowser(); if (psb) { IWebBrowser2* pwb; hr = IUnknown_QueryService(psb, SID_SWebBrowserApp, IID_PPV_ARG(IWebBrowser2, &pwb)); if (SUCCEEDED(hr)) { BSTR bstrFileSearchBand; hr = BSTRFromCLSID(CLSID_FileSearchBand, &bstrFileSearchBand); if (SUCCEEDED(hr)) { if (bAdvertise) { IUnknown *punk; hr = QueryInterface(IID_PPV_ARG(IUnknown, &punk)); if (SUCCEEDED(hr)) { VARIANT var; var.vt = VT_UNKNOWN; var.punkVal = punk; hr = pwb->PutProperty(bstrFileSearchBand, var); punk->Release(); } } else { VARIANT var; hr = pwb->GetProperty(bstrFileSearchBand, &var); if (SUCCEEDED(hr)) { if (VT_UNKNOWN == var.vt) { VARIANT varTmp = {0}; hr = pwb->PutProperty(bstrFileSearchBand, varTmp); } VariantClear(&var); } } SysFreeString(bstrFileSearchBand); } pwb->Release(); } } return hr; } STDMETHODIMP CFileSearchBand::GetSite(REFIID riid, void **ppvSite) { *ppvSite = NULL; return _punkSite ? _punkSite->QueryInterface(riid, ppvSite) : E_FAIL; } // IInputObject STDMETHODIMP CFileSearchBand::HasFocusIO() { HWND hwndFocus = GetFocus(); return (::IsWindow(m_hWnd) && (m_hWnd == hwndFocus || IsChild(hwndFocus))) ? S_OK : S_FALSE; } STDMETHODIMP CFileSearchBand::TranslateAcceleratorIO(MSG *pmsg) { return TranslateAccelerator(pmsg); } STDMETHODIMP CFileSearchBand::UIActivateIO(BOOL fActivate, MSG *pmsg) { if (fActivate) AutoActivate(); CBandDlg* pdlg = BandDlg(); if (pdlg) { if (fActivate) { // Handle tabbing into pane int nDir = IsVK_TABCycler(pmsg); HWND hwndTarget = (nDir < 0) ? pdlg->GetLastTabItem() : (nDir > 0) ? pdlg->GetFirstTabItem() : NULL; if (hwndTarget) ::SetFocus(hwndTarget); else if (!pdlg->RestoreFocus()) ::SetFocus(pdlg->Hwnd()); } else { pdlg->RememberFocus(NULL); } } return S_OK; } // IOleCommandTarget STDMETHODIMP CFileSearchBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut) { if (pguidCmdGroup) { if (IsEqualGUID(*pguidCmdGroup, CGID_FileSearchBand)) { switch (nCmdID) { case FSTBID_NEW: if (_pBandDlg) { _pBandDlg->Clear(); _pBandDlg->LayoutControls(); UpdateLayout(BLF_ALL); SetFocus(); _pBandDlg->SetDefaultFocus(); } return S_OK; case FSTBID_HELP: if (_pBandDlg) _pBandDlg->ShowHelp(NULL); return S_OK; } } } return OLECMDERR_E_UNKNOWNGROUP; } STDMETHODIMP CFileSearchBand::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText) { if (pguidCmdGroup && IsEqualGUID(*pguidCmdGroup, CGID_FileSearchBand)) { // Infotip text for toolbar buttons: if (pCmdText) { ASSERT(1 == cCmds); UINT nIDS = 0; pCmdText->cwActual = 0; switch (prgCmds[0].cmdID) { case iFSTBID_NEW: case FSTBID_NEW: nIDS = IDS_FSEARCH_NEWINFOTIP; break; case iFSTBID_HELP: case FSTBID_HELP: nIDS = IDS_FSEARCH_HELPINFOTIP; break; } if (nIDS) pCmdText->cwActual = LoadStringW(HINST_THISDLL, nIDS, pCmdText->rgwz, pCmdText->cwBuf); return pCmdText->cwActual > 0 ? S_OK : E_FAIL; } } return OLECMDERR_E_UNKNOWNGROUP; } // IServiceProvider STDMETHODIMP CFileSearchBand::QueryService(REFGUID guidService, REFIID riid, void **ppv) { return E_NOTIMPL; } // IPersistStream STDMETHODIMP CFileSearchBand::IsDirty(void) { return S_FALSE; } STDMETHODIMP CFileSearchBand::Load(IStream *pStm) { return E_NOTIMPL; } STDMETHODIMP CFileSearchBand::Save(IStream *pStm, BOOL fClearDirty) { return E_NOTIMPL; } STDMETHODIMP CFileSearchBand::GetSizeMax(ULARGE_INTEGER *pcbSize) { return E_NOTIMPL; } // IPersist STDMETHODIMP CFileSearchBand::GetClassID(CLSID *pClassID) { *pClassID = CLSID_FileSearchBand; return S_OK; } // CMetrics impl CMetrics::CMetrics() : _hbrBkgnd(NULL), _hbrBorder(NULL), _hfBold(NULL) { ZeroMemory(&_ptExpandOrigin, sizeof(_ptExpandOrigin)); ZeroMemory(&_rcCheckBox, sizeof(_rcCheckBox)); ZeroMemory(_rghiconCaption, sizeof(_rghiconCaption)); CreateResources(); } void CMetrics::Init(HWND hwndDlg) { _cyTightMargin = _PixelsForDbu(hwndDlg, 3, FALSE); _cyLooseMargin = 2 * _cyTightMargin; _cxCtlMargin = _PixelsForDbu(hwndDlg, 7, TRUE); } BOOL CMetrics::CreateResources() { _hbrBkgnd = CreateSolidBrush(BkgndColor()); _hbrBorder= CreateSolidBrush(BorderColor()); return _hbrBkgnd != NULL && _hbrBorder != NULL; } BOOL CMetrics::GetWindowLogFont(HWND hwnd, OUT LOGFONT* plf) { HFONT hf = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0); if (hf) { if (sizeof(*plf) == GetObject(hf, sizeof(*plf), plf)) return TRUE; } return FALSE; } HFONT CMetrics::BoldFont(HWND hwndDlg) { if (NULL == _hfBold) { LOGFONT lf; if (GetWindowLogFont(hwndDlg, &lf)) { lf.lfWeight = FW_BOLD; SHAdjustLOGFONT(&lf); // locale-specific adjustments _hfBold = CreateFontIndirect(&lf); } } return _hfBold; } HICON CMetrics::CaptionIcon(UINT nIDIconResource) { for (int i = 0; i < ARRAYSIZE(_icons); i++) { if (_icons[i] == nIDIconResource) { if (NULL == _rghiconCaption[i]) { _rghiconCaption[i] = (HICON)LoadImage( HINST_THISDLL, MAKEINTRESOURCE(nIDIconResource), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); } return _rghiconCaption[i]; } } return NULL; } void CMetrics::DestroyResources() { if (_hbrBkgnd) { DeleteObject(_hbrBkgnd); _hbrBkgnd = NULL; } if (_hbrBorder) { DeleteObject(_hbrBorder); _hbrBorder = NULL; } if (_hfBold) { DeleteObject(_hfBold); _hfBold = NULL; } for (int i = 0; i < ARRAYSIZE(_icons); i++) { if (_rghiconCaption[i]) { DestroyIcon(_rghiconCaption[i]); _rghiconCaption[i] = NULL; } } } void CMetrics::OnWinIniChange(HWND hwndDlg) { DestroyResources(); // Force resource regen CreateResources(); // Force font regen BoldFont(hwndDlg); Init(hwndDlg); } // returns: // S_OK -> uptodate // S_FALSE -> not up to date // FAILED() -> volume not CIed STDAPI CatalogUptodate(LPCWSTR pszCatalog, LPCWSTR pszMachine) { HRESULT hr = E_FAIL; CI_STATE state = {0}; state.cbStruct = sizeof(state); if (SUCCEEDED(CIState(pszCatalog, pszMachine, &state))) { BOOL fUpToDate = ((0 == state.cDocuments) && (0 == (state.eState & CI_STATE_SCANNING)) && (0 == (state.eState & CI_STATE_READING_USNS)) && (0 == (state.eState & CI_STATE_STARTING)) && (0 == (state.eState & CI_STATE_RECOVERING))); if (fUpToDate) { hr = S_OK; } else { hr = S_FALSE; } } return hr; } // returns: // S_OK -> uptodate // S_FALSE -> not up to date // FAILED() -> volume not CIed STDAPI PathUptodate(LPCWSTR pszPath) { HRESULT hr = E_FAIL; WCHAR wszMachine[32], wszCatalog[MAX_PATH]; DWORD cchMachine = ARRAYSIZE(wszMachine), cchCatalog = ARRAYSIZE(wszCatalog); if (S_OK == LocateCatalogsW(pszPath, 0, wszMachine, &cchMachine, wszCatalog, &cchCatalog)) { hr = CatalogUptodate(wszCatalog, wszMachine); } return hr; } HRESULT LocalDrivesContentUpToDate() { HRESULT hr = S_OK; // assume yes DWORD dwDriveMask = GetLogicalDrives(); for (int i = 0; i < 26; i++) { if (dwDriveMask & 1) { if (!IsRemovableDrive(i) && !IsRemoteDrive(i)) { WCHAR wszPath[4]; PathBuildRoot(wszPath, i); if (S_FALSE == PathUptodate(wszPath)) { hr = S_FALSE; break; } } } dwDriveMask >>= 1; } return hr; } HRESULT QueryCIStatus(DWORD *pdwStatus, BOOL *pbConfigAccess) { DWORD dwErr = ERROR_SUCCESS; ASSERT(pdwStatus); *pdwStatus = 0; if (pbConfigAccess) *pbConfigAccess = FALSE; SC_HANDLE hScm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); if (hScm) { SC_HANDLE hService = NULL; // Test permission to muck around with service if (pbConfigAccess) { hService = OpenService(hScm, L"cisvc", SERVICE_START |SERVICE_STOP | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS); if (hService) { *pbConfigAccess = TRUE; } } // Query service status if (NULL == hService) hService = OpenService(hScm, L"cisvc", SERVICE_QUERY_STATUS); if (hService) { SERVICE_STATUS status; if (!QueryServiceStatus(hService, &status)) dwErr = GetLastError(); else *pdwStatus = status.dwCurrentState; CloseServiceHandle(hService); } else dwErr = GetLastError(); CloseServiceHandle(hScm); } else dwErr = GetLastError(); return HRESULT_FROM_WIN32(dwErr); } STDAPI GetCIStatus(BOOL *pbRunning, BOOL *pbIndexed, BOOL *pbPermission) { *pbRunning = *pbIndexed = *pbPermission = FALSE; DWORD dwStatus = 0; HRESULT hr = QueryCIStatus(&dwStatus, pbPermission); if (SUCCEEDED(hr)) { switch (dwStatus) { case SERVICE_START_PENDING: case SERVICE_RUNNING: case SERVICE_CONTINUE_PENDING: *pbRunning = TRUE; } } if (*pbRunning) *pbIndexed = *pbPermission ? (S_OK == LocalDrivesContentUpToDate()) : TRUE; return hr; } STDAPI StartStopCI(BOOL bStart) { DWORD dwErr = ERROR_SUCCESS; SERVICE_STATUS status; SC_HANDLE hScm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); if (hScm) { DWORD dwAccess = SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | (bStart ? SERVICE_START : SERVICE_STOP); SC_HANDLE hService = OpenService(hScm, L"cisvc", dwAccess); if (hService) { if (QueryServiceStatus(hService, &status)) { dwErr = ChangeServiceConfig(hService, SERVICE_NO_CHANGE, bStart ? SERVICE_AUTO_START : SERVICE_DEMAND_START, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); // we'll ignore return value if (bStart) { if (SERVICE_PAUSED == status.dwCurrentState || SERVICE_PAUSE_PENDING == status.dwCurrentState) dwErr = ControlService(hService, SERVICE_CONTROL_CONTINUE, &status) ? ERROR_SUCCESS : GetLastError(); else { dwErr = StartService(hService, 0, NULL) ? ERROR_SUCCESS : GetLastError(); if (ERROR_SERVICE_ALREADY_RUNNING == dwErr) dwErr = ERROR_SUCCESS; } } else { dwErr = ControlService(hService, SERVICE_CONTROL_STOP, &status) ? ERROR_SUCCESS : GetLastError(); } } else dwErr = GetLastError(); CloseServiceHandle(hService); } else dwErr = GetLastError(); CloseServiceHandle(hScm); } else dwErr = GetLastError(); return HRESULT_FROM_WIN32(dwErr); } inline BOOL IsWhite(WCHAR ch) { return L' ' == ch || L'\t' == ch || L'\n' == ch || L'\r' == ch; } inline BOOL IsParens(WCHAR ch) { return L'(' == ch || L')' == ch; } // Skips whitespace static LPCWSTR SkipWhiteAndParens(IN LPCWSTR pwszTest) { while(pwszTest && *pwszTest && (IsWhite(*pwszTest) || IsParens(*pwszTest))) pwszTest = CharNextW(pwszTest); return (pwszTest && *pwszTest) ? pwszTest : NULL; } // Determines whether the indicated keyword is found in the specified // prefix and/or suffix context. If successful, return value is address // of first character beyond the keyword context; otherwise NULL. static LPCWSTR IsKeywordContext( IN LPCWSTR pwszTest, IN OPTIONAL WCHAR chPrefix, IN OPTIONAL LPCWSTR pwszKeyword, IN OPTIONAL WCHAR chSuffix, IN OPTIONAL WCHAR chSuffix2) { if ((pwszTest = SkipWhiteAndParens(pwszTest)) == NULL) return NULL; if (chPrefix) { if (chPrefix != *pwszTest) return NULL; pwszTest = CharNextW(pwszTest); } if (pwszKeyword) { if ((pwszTest = SkipWhiteAndParens(pwszTest)) == NULL) return NULL; if (StrStrIW(pwszTest, pwszKeyword) != pwszTest) return NULL; pwszTest += lstrlenW(pwszKeyword); } if (chSuffix) { if ((pwszTest = SkipWhiteAndParens(pwszTest)) == NULL) return NULL; if (*pwszTest != chSuffix) return NULL; pwszTest = CharNextW(pwszTest); } if (chSuffix2) { if ((pwszTest = SkipWhiteAndParens(pwszTest)) == NULL) return NULL; if (*pwszTest != chSuffix2) return NULL; pwszTest = CharNextW(pwszTest); } return pwszTest; } BOOL IsTripoliV1Token(LPCWSTR pwszQuery, LPCWSTR *ppwszOut /* trailing text */) { *ppwszOut = NULL; LPCWSTR pwsz; // Find the token if ((pwsz = IsKeywordContext(pwszQuery, L'#', NULL, 0, 0)) != NULL || (pwsz = IsKeywordContext(pwszQuery, L'$', L"contents", 0, 0)) != NULL) { *ppwszOut = pwsz; return TRUE; } return FALSE; } BOOL IsTripoliV2Token(LPCWSTR pwszQuery, LPCWSTR *ppwszOut /* trailing text */) { *ppwszOut = NULL; LPCWSTR pwsz; // Find the token if ((pwsz = IsKeywordContext(pwszQuery, L'{', L"phrase", L'}', 0)) != NULL || (pwsz = IsKeywordContext(pwszQuery, L'{', L"freetext", L'}', 0)) != NULL || (pwsz = IsKeywordContext(pwszQuery, L'{', L"prop", 0, 0)) != NULL || (pwsz = IsKeywordContext(pwszQuery, L'{', L"regex", L'}', 0)) != NULL || (pwsz = IsKeywordContext(pwszQuery, L'{', L"coerce", L'}', 0)) != NULL || (pwsz = IsKeywordContext(pwszQuery, L'{', L"ve", L'}', 0)) != NULL || (pwsz = IsKeywordContext(pwszQuery, L'{', L"weight", 0, 0)) != NULL || (pwsz = IsKeywordContext(pwszQuery, L'{', L"vector", 0, 0)) != NULL || (pwsz = IsKeywordContext(pwszQuery, L'{', L"generate", 0, 0)) != NULL || (pwsz = IsKeywordContext(pwszQuery, L'@', NULL, 0, 0)) != NULL) { *ppwszOut = pwsz; return TRUE; } return FALSE; } STDAPI_(BOOL) IsCiQuery(const VARIANT *pvarRaw, VARIANT *pvarQuery, ULONG *pulDialect) { BOOL bBang = FALSE; VariantInit(pvarQuery); *pulDialect = 0; // invalid value (valid values are > 0) if (pvarRaw->vt != VT_BSTR || NULL == pvarRaw->bstrVal || 0 == *pvarRaw->bstrVal) return FALSE; LPCWSTR pwsz = pvarRaw->bstrVal; // text beginning w/ '!' indicates that this text is a CI query. // but it must be very first character (not even spaces are allowed) if (pwsz && *pwsz) { if (L'!' == *pwsz) { // skip over '!' bBang = TRUE; if ((pwsz = CharNextW(pwsz)) == NULL || 0 == *pwsz) return FALSE; // fall through... } } pwsz = SkipWhiteAndParens(pwsz); if (pwsz && *pwsz) { // text looking like a query token if (pwsz && *pwsz) { LPCWSTR pwszMore, pwszTemp; // @ is valid in both tripoli v1 & v2 but it has extended usage in v2 so // we put it as v2 token only if (IsTripoliV2Token(pwsz, &pwszMore)) *pulDialect = ISQLANG_V2; // no else here because if @ is used in combination w/ some v1 token // we want the query to be v1. if (IsTripoliV1Token(pwsz, &pwszTemp)) { *pulDialect = ISQLANG_V1; pwszMore = pwszTemp; } if (*pulDialect) { // See if there is anything substantial past the query tokens pwszMore = SkipWhiteAndParens(pwszMore); if (pwszMore && *pwszMore) { InitVariantFromStr(pvarQuery, pwsz); return TRUE; } } else { if (bBang) { InitVariantFromStr(pvarQuery, pwsz); *pulDialect = ISQLANG_V1; // just pick one return TRUE; } } } } return FALSE; } // needed for ATL goo LCID g_lcidLocale = MAKELCID(LANG_USER_DEFAULT, SORT_DEFAULT); STDAPI CFileSearchBand_CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv) { HRESULT hr = CreateFromRegKey(REGSTR_PATH_EXPLORER, TEXT("FileFindBandHook"), riid, ppv); if (FAILED(hr)) hr = CComCreator< CComObject< CFileSearchBand > >::CreateInstance((void *)pUnkOuter, IID_IUnknown, (void **)ppv); return hr; }