Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1885 lines
50 KiB

  1. // findband.cpp : Implementation of CFileSearchBand
  2. #include "shellprv.h"
  3. #include "findband.h"
  4. #include "findfilter.h"
  5. #include <ciodm.h> // AdminIndexServer custom interface
  6. #define CGID_FileSearchBand CLSID_FileSearchBand
  7. extern int IsVK_TABCycler(MSG *pMsg);
  8. enum { // toolbar image list indices:
  9. iFSTBID_NEW,
  10. iFSTBID_HELP,
  11. };
  12. #define MAKE_FSTBID(ilIndex) (100 /*arbitrary*/ + (ilIndex))
  13. // toolbar button IDs
  14. #define FSTBID_NEW MAKE_FSTBID(iFSTBID_NEW)
  15. #define FSTBID_HELP MAKE_FSTBID(iFSTBID_HELP)
  16. static const TBBUTTON _rgtb[] =
  17. {
  18. { iFSTBID_NEW, FSTBID_NEW, TBSTATE_ENABLED, BTNS_AUTOSIZE | BTNS_SHOWTEXT,{0, 0}, 0, 0},
  19. { -1, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0},
  20. { iFSTBID_HELP, FSTBID_HELP, TBSTATE_ENABLED, BTNS_AUTOSIZE, {0, 0}, 0, 1},
  21. };
  22. inline BOOL _IsEditWindowClass(HWND hwndTest)
  23. {
  24. return IsWindowClass(hwndTest, TEXT("Edit"));
  25. }
  26. inline BOOL _IsComboWindowClass(HWND hwndTest)
  27. {
  28. #define COMBO_CLASS TEXT("ComboBox")
  29. return _IsEditWindowClass(hwndTest) ?
  30. IsWindowClass(GetParent(hwndTest), COMBO_CLASS) :
  31. IsWindowClass(hwndTest, COMBO_CLASS);
  32. }
  33. // CFileSearchBand impl
  34. CWndClassInfo& CFileSearchBand::GetWndClassInfo()
  35. {
  36. static CWndClassInfo wc = {
  37. { sizeof(WNDCLASSEX), CS_SAVEBITS, StartWindowProc,
  38. 0, 0, 0, 0, 0, 0, 0,
  39. FILESEARCHCTL_CLASS, 0 },
  40. NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
  41. };
  42. return wc;
  43. }
  44. CFileSearchBand::CFileSearchBand()
  45. : _dlgFSearch(this),
  46. _dlgCSearch(this),
  47. #ifdef __PSEARCH_BANDDLG__
  48. _dlgPSearch(this),
  49. #endif __PSEARCH_BANDDLG__
  50. _fValid(TRUE),
  51. _dwBandID(-1),
  52. _dwBandViewMode(DBIF_VIEWMODE_VERTICAL)
  53. {
  54. // Verify that it initialized correctly:
  55. ASSERT(_pBandDlg == NULL);
  56. ASSERT(_psb == NULL);
  57. ASSERT(_guidSearch == GUID_NULL);
  58. ASSERT(_fDirty == FALSE);
  59. ASSERT(_fDeskBand == FALSE);
  60. ASSERT(_punkSite == NULL);
  61. ASSERT(_bSendFinishedDisplaying == FALSE);
  62. m_bWindowOnly = TRUE;
  63. ZeroMemory(&_siHorz, sizeof(_siHorz));
  64. ZeroMemory(&_siVert, sizeof(_siVert));
  65. _siHorz.cbSize = _siVert.cbSize = sizeof(SCROLLINFO);
  66. _sizeMin.cx = _sizeMin.cy = 0;
  67. _sizeMax.cx = _sizeMax.cy = 32000; // arbitrarily large.
  68. }
  69. CFileSearchBand::~CFileSearchBand()
  70. {
  71. ImageList_Destroy(_hilDefault);
  72. ImageList_Destroy(_hilHot);
  73. }
  74. HWND CFileSearchBand::Create(
  75. HWND hWndParent,
  76. RECT& rcPos,
  77. LPCTSTR szWindowName,
  78. DWORD dwStyle,
  79. DWORD dwExStyle,
  80. UINT nID)
  81. {
  82. INITCOMMONCONTROLSEX icc;
  83. TCHAR szCaption[128];
  84. icc.dwSize = sizeof(icc);
  85. icc.dwICC = ICC_DATE_CLASSES|ICC_UPDOWN_CLASS|ICC_USEREX_CLASSES|ICC_ANIMATE_CLASS;
  86. EVAL(LoadString(HINST_THISDLL, IDS_FSEARCH_CAPTION, szCaption, ARRAYSIZE(szCaption)));
  87. InitCommonControlsEx(&icc);
  88. dwExStyle |= WS_EX_CONTROLPARENT;
  89. dwStyle |= WS_CLIPCHILDREN;
  90. return CWindowImpl<CFileSearchBand>::Create(hWndParent, rcPos, szCaption,
  91. dwStyle, dwExStyle, nID);
  92. }
  93. LRESULT CFileSearchBand::OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  94. {
  95. if (FAILED(ShowBandDialog(SRCID_SFileSearch)))
  96. return -1;
  97. return 0;
  98. }
  99. CBandDlg* CFileSearchBand::GetBandDialog(REFGUID guidSearch)
  100. {
  101. if (IsEqualGUID(guidSearch, SRCID_SFileSearch))
  102. {
  103. return &_dlgFSearch;
  104. }
  105. #ifdef __PSEARCH_BANDDLG__
  106. else if (IsEqualGUID(guidSearch, SRCID_SFindPrinter))
  107. {
  108. return &_dlgPSearch;
  109. }
  110. #endif __PSEARCH_BANDDLG__
  111. else if (IsEqualGUID(guidSearch, SRCID_SFindComputer))
  112. {
  113. return &_dlgCSearch;
  114. }
  115. return NULL;
  116. }
  117. // IFileSearchBand::SetSearchParameters()
  118. STDMETHODIMP CFileSearchBand::SetSearchParameters(
  119. IN BSTR* pbstrSearchID,
  120. IN VARIANT_BOOL bNavToResults,
  121. IN OPTIONAL VARIANT *pvarScope,
  122. IN OPTIONAL VARIANT *pvarQueryFile)
  123. {
  124. USES_CONVERSION;
  125. HRESULT hr;
  126. GUID guidSearch;
  127. if (SUCCEEDED(SHCLSIDFromString(W2T(*pbstrSearchID), &guidSearch)))
  128. {
  129. hr = ShowBandDialog(guidSearch, bNavToResults, TRUE);
  130. if (SUCCEEDED(hr))
  131. {
  132. CBandDlg* pBandDlg = GetBandDialog(guidSearch);
  133. ASSERT(pBandDlg);
  134. if (pvarScope && pvarScope->vt != VT_EMPTY)
  135. pBandDlg->SetScope(pvarScope, TRUE);
  136. if (pvarQueryFile && pvarQueryFile->vt != VT_EMPTY)
  137. pBandDlg->SetQueryFile(pvarQueryFile);
  138. }
  139. }
  140. else
  141. {
  142. hr = E_INVALIDARG;
  143. }
  144. return hr;
  145. }
  146. HRESULT CFileSearchBand::ShowBandDialog(
  147. REFGUID guidSearch,
  148. BOOL bNavigateToResults,
  149. BOOL bDefaultFocusCtl)
  150. {
  151. CBandDlg *pDlgNew = NULL,
  152. *pDlgOld = _pBandDlg;
  153. GUID guidOld = _guidSearch;
  154. BOOL bNewWindow = FALSE;
  155. if (NULL == (pDlgNew = GetBandDialog(guidSearch)))
  156. return E_INVALIDARG;
  157. _pBandDlg = pDlgNew;
  158. _guidSearch = guidSearch;
  159. // If the dialog window has not been created, do so now.
  160. if (!::IsWindow(pDlgNew->Hwnd()))
  161. {
  162. if (NULL == pDlgNew->Create(*this))
  163. {
  164. _pBandDlg = pDlgOld;
  165. _guidSearch = guidOld;
  166. return E_FAIL;
  167. }
  168. bNewWindow = TRUE;
  169. }
  170. if (pDlgNew != pDlgOld)
  171. {
  172. // If we have an active dialog, hide it
  173. if (pDlgOld && ::IsWindow(pDlgOld->Hwnd()))
  174. {
  175. ::ShowWindow(pDlgOld->Hwnd(), SW_HIDE);
  176. pDlgOld->OnBandDialogShow(FALSE);
  177. }
  178. bNewWindow = TRUE;
  179. }
  180. if (bNewWindow)
  181. {
  182. // Show the new dialog window
  183. UpdateLayout(BLF_ALL);
  184. _pBandDlg->OnBandDialogShow(TRUE);
  185. ::ShowWindow(_pBandDlg->Hwnd(), SW_SHOW);
  186. ::UpdateWindow(_pBandDlg->Hwnd());
  187. if (bDefaultFocusCtl)
  188. _pBandDlg->SetDefaultFocus();
  189. }
  190. if (bNavigateToResults)
  191. {
  192. // Navigate to results shell folder.
  193. IWebBrowser2* pwb2;
  194. HRESULT hr = IUnknown_QueryService(GetTopLevelBrowser(), SID_SWebBrowserApp, IID_PPV_ARG(IWebBrowser2, &pwb2));
  195. if (SUCCEEDED(hr))
  196. {
  197. _pBandDlg->NavigateToResults(pwb2);
  198. pwb2->Release();
  199. }
  200. }
  201. return S_OK;
  202. }
  203. void CFileSearchBand::AddButtons(BOOL fAdd)
  204. {
  205. if (_fDeskBand)
  206. {
  207. ASSERT(BandSite());
  208. IExplorerToolbar* piet;
  209. if (SUCCEEDED(BandSite()->QueryInterface(IID_PPV_ARG(IExplorerToolbar, &piet))))
  210. {
  211. if (fAdd)
  212. {
  213. HRESULT hr = piet->SetCommandTarget((IUnknown*)SAFECAST(this, IOleCommandTarget*), &CGID_FileSearchBand, 0);
  214. if (hr == S_OK)
  215. {
  216. if (!_fStrings)
  217. {
  218. piet->AddString(&CGID_SearchBand, HINST_THISDLL, IDS_FSEARCH_TBLABELS, &_cbOffset);
  219. _fStrings = TRUE;
  220. }
  221. if (LoadImageLists())
  222. piet->SetImageList(&CGID_FileSearchBand, _hilDefault, _hilHot, NULL);
  223. TBBUTTON rgtb[ARRAYSIZE(_rgtb)];
  224. memcpy(rgtb, _rgtb, sizeof(_rgtb));
  225. for (int i = 0; i < ARRAYSIZE(rgtb); i++)
  226. rgtb[i].iString += _cbOffset;
  227. piet->AddButtons(&CGID_FileSearchBand, ARRAYSIZE(rgtb), rgtb);
  228. }
  229. }
  230. else
  231. piet->SetCommandTarget(NULL, NULL, 0);
  232. piet->Release();
  233. }
  234. }
  235. }
  236. BOOL CFileSearchBand::LoadImageLists()
  237. {
  238. if (_hilDefault == NULL)
  239. {
  240. _hilDefault = ImageList_LoadImage(HINST_THISDLL,
  241. MAKEINTRESOURCE(IDB_FSEARCHTB_DEFAULT),
  242. 18, 0, CLR_DEFAULT, IMAGE_BITMAP,
  243. LR_CREATEDIBSECTION);
  244. }
  245. if (_hilHot == NULL)
  246. {
  247. _hilHot = ImageList_LoadImage(HINST_THISDLL,
  248. MAKEINTRESOURCE(IDB_FSEARCHTB_HOT),
  249. 18, 0, CLR_DEFAULT, IMAGE_BITMAP,
  250. LR_CREATEDIBSECTION);
  251. }
  252. return _hilDefault != NULL && _hilHot != NULL;
  253. }
  254. STDMETHODIMP CFileSearchBand::get_Scope(OUT VARIANT *pvarScope)
  255. {
  256. if (BandDlg())
  257. return _pBandDlg->GetScope(pvarScope);
  258. VariantInit(pvarScope);
  259. return E_FAIL;
  260. }
  261. STDMETHODIMP CFileSearchBand::get_QueryFile(OUT VARIANT *pvarFile)
  262. {
  263. if (BandDlg())
  264. return _pBandDlg->GetQueryFile(pvarFile);
  265. VariantInit(pvarFile);
  266. return E_FAIL;
  267. }
  268. STDMETHODIMP CFileSearchBand::get_SearchID(OUT BSTR* pbstrSearchID)
  269. {
  270. if (!pbstrSearchID)
  271. return E_POINTER;
  272. WCHAR wszGuid[GUIDSTR_MAX+1];
  273. SHStringFromGUIDW(_guidSearch, wszGuid, ARRAYSIZE(wszGuid));
  274. *pbstrSearchID = SysAllocString(wszGuid);
  275. return IsEqualGUID(GUID_NULL, _guidSearch) ? S_FALSE : S_OK;
  276. }
  277. CBandDlg* CFileSearchBand::BandDlg()
  278. {
  279. return _pBandDlg;
  280. }
  281. HRESULT CFileSearchBand::SetFocus()
  282. {
  283. HRESULT hr = AutoActivate();
  284. if (SUCCEEDED(hr))
  285. {
  286. if (!IsChild(GetFocus()))
  287. ::SetFocus(BandDlg()->Hwnd());
  288. }
  289. return hr;
  290. }
  291. LRESULT CFileSearchBand::OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&)
  292. {
  293. LRESULT lRet = CWindowImpl<CFileSearchBand>::DefWindowProc(uMsg, wParam, lParam);
  294. AutoActivate();
  295. return lRet;
  296. }
  297. LRESULT CFileSearchBand::OnWinIniChange(UINT, WPARAM, LPARAM, BOOL&)
  298. {
  299. _metrics.OnWinIniChange(BandDlg()->Hwnd());
  300. BandDlg()->OnWinIniChange();
  301. UpdateLayout();
  302. return 0;
  303. }
  304. HRESULT CFileSearchBand::AutoActivate()
  305. {
  306. HRESULT hr = S_OK;
  307. if (!::IsWindow(m_hWnd))
  308. return hr;
  309. if (_fDeskBand)
  310. {
  311. if (_punkSite)
  312. {
  313. IInputObjectSite* pios;
  314. hr = _punkSite->QueryInterface(IID_PPV_ARG(IInputObjectSite, &pios));
  315. if (SUCCEEDED(hr))
  316. {
  317. hr = pios->OnFocusChangeIS(SAFECAST(this, IInputObject*), TRUE);
  318. pios->Release();
  319. }
  320. }
  321. }
  322. else if (!m_bUIActive)
  323. {
  324. RECT rc;
  325. ::GetWindowRect(m_hWnd, &rc);
  326. ::MapWindowPoints(HWND_DESKTOP, GetParent(), (LPPOINT)&rc, 2);
  327. hr = DoVerb(OLEIVERB_UIACTIVATE, NULL, NULL, 0, GetParent(), &rc);
  328. }
  329. return hr;
  330. }
  331. void CFileSearchBand::SetDirty(BOOL bDirty)
  332. {
  333. _fDirty = bDirty;
  334. _dlgFSearch.UpdateSearchCmdStateUI();
  335. }
  336. LRESULT CFileSearchBand::OnSize(UINT, WPARAM wParam, LPARAM lParam, BOOL&)
  337. {
  338. POINTS pts = MAKEPOINTS(lParam);
  339. LayoutControls(pts.x, pts.y, BLF_ALL);
  340. return 0;
  341. }
  342. LRESULT CFileSearchBand::OnEraseBkgnd(UINT, WPARAM, LPARAM, BOOL&)
  343. {
  344. return TRUE;
  345. }
  346. HRESULT CFileSearchBand::SetObjectRects(LPCRECT prcPos, LPCRECT prcClip)
  347. {
  348. return IOleInPlaceObjectWindowlessImpl<class CFileSearchBand>::SetObjectRects(prcPos, prcClip);
  349. }
  350. STDMETHODIMP CFileSearchBand::PrivateQI(REFIID iid, void **ppvObject)
  351. {
  352. return _InternalQueryInterface(iid, ppvObject);
  353. }
  354. STDMETHODIMP CFileSearchBand::DoVerbUIActivate(LPCRECT prcPosRect, HWND hwndParent)
  355. {
  356. // Patch in shell32 logic.
  357. return CShell32AtlIDispatch<CFileSearchBand, &CLSID_FileSearchBand, &IID_IFileSearchBand, &LIBID_Shell32, 1, 0, CComTypeInfoHolder>::
  358. DoVerbUIActivate(prcPosRect, hwndParent, m_hWnd);
  359. }
  360. void CFileSearchBand::UpdateLayout(ULONG fLayoutFlags)
  361. {
  362. RECT rc;
  363. GetClientRect(&rc);
  364. LayoutControls(RECTWIDTH(rc), RECTHEIGHT(rc), fLayoutFlags);
  365. }
  366. void CFileSearchBand::LayoutControls(int cx, int cy, ULONG fLayoutFlags)
  367. {
  368. if (/*NULL == BandDlg() ||*/ !::IsWindow(BandDlg()->Hwnd()))
  369. return;
  370. SIZE sizeMin;
  371. BandDlg()->GetMinSize(m_hWnd, &sizeMin); // size of dialog
  372. if (fLayoutFlags & BLF_CALCSCROLL)
  373. {
  374. // Stash pos before recalculating
  375. POINT pos;
  376. pos.x = _siHorz.nPos;
  377. pos.y = _siVert.nPos;
  378. _siHorz.fMask = _siVert.fMask = (SIF_RANGE|SIF_PAGE);
  379. _siHorz.nPage = cx; // thumb width
  380. _siVert.nPage = cy; // thumb height
  381. SIZE sizeDelta; // difference between what we have to show and what is shown.
  382. sizeDelta.cx = sizeMin.cx - _siHorz.nPage;
  383. sizeDelta.cy = sizeMin.cy - _siVert.nPage;
  384. // establish maximum scroll positions
  385. _siHorz.nMax = sizeDelta.cx > 0 ? sizeMin.cx - 1 : 0;
  386. _siVert.nMax = sizeDelta.cy > 0 ? sizeMin.cy - 1 : 0;
  387. // establish horizontal scroll pos
  388. if (sizeDelta.cx <= 0)
  389. _siHorz.nPos = 0; // scroll to extreme left if we're removing scroll bar
  390. else if (sizeDelta.cx < _siHorz.nPos)
  391. _siHorz.nPos = sizeDelta.cx; // remove right-hand vacancy
  392. if (_siHorz.nPos != pos.x)
  393. _siHorz.fMask |= SIF_POS;
  394. // establish vertical scroll pos
  395. if (sizeDelta.cy <= 0)
  396. _siVert.nPos = 0; // scroll to top if we're removing scroll bar
  397. else if (sizeDelta.cy < _siVert.nPos)
  398. _siVert.nPos = sizeDelta.cy; // remove lower-portion vacancy
  399. if (_siVert.nPos != pos.y)
  400. _siVert.fMask |= SIF_POS;
  401. // Note: can't call SetScrollInfo here, as it may generate
  402. // a WM_SIZE and recurse back to this function before we had a
  403. // chance to SetWindowPos() our subdlg. So defer it until after
  404. // we've done this.
  405. }
  406. DWORD fSwp = SWP_NOZORDER | SWP_NOACTIVATE;
  407. if (0 == (fLayoutFlags & BLF_RESIZECHILDREN))
  408. fSwp |= SWP_NOSIZE;
  409. if (0 == (fLayoutFlags & BLF_SCROLLWINDOW))
  410. fSwp |= SWP_NOMOVE;
  411. // Move or size the main subdialog as requested...
  412. if (0 == (fSwp & SWP_NOMOVE) || 0 == (fSwp & SWP_NOSIZE))
  413. ::SetWindowPos(BandDlg()->Hwnd(), NULL, -_siHorz.nPos, -_siVert.nPos,
  414. max(cx, sizeMin.cx), max(cy, sizeMin.cy), fSwp);
  415. // Update scroll parameters
  416. if (fLayoutFlags & BLF_CALCSCROLL)
  417. {
  418. SetScrollInfo(SB_HORZ, &_siHorz, TRUE);
  419. SetScrollInfo(SB_VERT, &_siVert, TRUE);
  420. }
  421. }
  422. void CFileSearchBand::Scroll(int nBar, UINT uSBCode, int nNewPos /*optional*/)
  423. {
  424. int nDeltaMax;
  425. SCROLLINFO *psbi;
  426. const LONG nLine = 8;
  427. psbi = (SB_HORZ == nBar) ? &_siHorz : &_siVert;
  428. nDeltaMax = (psbi->nMax - psbi->nPage) + 1;
  429. switch (uSBCode)
  430. {
  431. case SB_LEFT:
  432. psbi->nPos--;
  433. break;
  434. case SB_RIGHT:
  435. psbi->nPos++;
  436. break;
  437. case SB_LINELEFT:
  438. psbi->nPos = max(psbi->nPos - nLine, 0);
  439. break;
  440. case SB_LINERIGHT:
  441. psbi->nPos = min(psbi->nPos + nLine, nDeltaMax);
  442. break;
  443. case SB_PAGELEFT:
  444. psbi->nPos = max(psbi->nPos - (int)psbi->nPage, 0);
  445. break;
  446. case SB_PAGERIGHT:
  447. psbi->nPos = min(psbi->nPos + (int)psbi->nPage, nDeltaMax);
  448. break;
  449. case SB_THUMBTRACK:
  450. psbi->nPos = nNewPos;
  451. break;
  452. case SB_THUMBPOSITION:
  453. psbi->nPos = nNewPos;
  454. break;
  455. case SB_ENDSCROLL:
  456. return;
  457. }
  458. psbi->fMask = SIF_POS;
  459. SetScrollInfo(nBar, psbi, TRUE);
  460. UpdateLayout(BLF_ALL &~ BLF_CALCSCROLL /*no need to recalc scroll state data*/);
  461. }
  462. // WM_HSCROLL/WM_VSCROLL handler
  463. LRESULT CFileSearchBand::OnScroll(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  464. {
  465. Scroll((WM_HSCROLL == nMsg) ? SB_HORZ : SB_VERT,
  466. LOWORD(wParam), HIWORD(wParam));
  467. return 0;
  468. }
  469. void CFileSearchBand::EnsureVisible(LPCRECT lprc /* in screen coords */)
  470. {
  471. ASSERT(lprc);
  472. RECT rc = *lprc;
  473. RECT rcClient;
  474. RECT vertexDeltas;
  475. SIZE scrollDelta;
  476. ::MapWindowPoints(HWND_DESKTOP, m_hWnd, (LPPOINT)&rc, POINTSPERRECT);
  477. GetClientRect(&rcClient);
  478. BOOL fTaller = RECTHEIGHT(rc) > RECTHEIGHT(rcClient);
  479. BOOL fFatter = RECTWIDTH(rc) > RECTWIDTH(rcClient);
  480. // Store deltas at each vertex
  481. SetRect(&vertexDeltas,
  482. rc.left - rcClient.left,
  483. rc.top - rcClient.top,
  484. rc.right - rcClient.right,
  485. rc.bottom - rcClient.bottom);
  486. // Compute scroll deltas
  487. scrollDelta.cx = (vertexDeltas.left < 0) ? vertexDeltas.left :
  488. (vertexDeltas.right > 0 && !fFatter) ? vertexDeltas.right :
  489. 0;
  490. scrollDelta.cy = (vertexDeltas.top < 0) ? vertexDeltas.top :
  491. (vertexDeltas.bottom > 0 && !fTaller) ? vertexDeltas.bottom :
  492. 0;
  493. // Scroll into view as necessary.
  494. if (scrollDelta.cx)
  495. {
  496. _siHorz.fMask = SIF_POS;
  497. _siHorz.nPos += scrollDelta.cx;
  498. SetScrollInfo(SB_HORZ, &_siHorz, TRUE);
  499. }
  500. if (scrollDelta.cy)
  501. {
  502. _siVert.fMask = SIF_POS;
  503. _siVert.nPos += scrollDelta.cy;
  504. SetScrollInfo(SB_VERT, &_siVert, TRUE);
  505. }
  506. UpdateLayout(BLF_ALL &~ BLF_CALCSCROLL);
  507. }
  508. HRESULT CFileSearchBand::TranslateAccelerator(MSG *pmsg)
  509. {
  510. return CShell32AtlIDispatch<CFileSearchBand, &CLSID_FileSearchBand, &IID_IFileSearchBand, &LIBID_Shell32, 1, 0, CComTypeInfoHolder>
  511. ::TranslateAcceleratorPriv(this, pmsg, m_spClientSite);
  512. }
  513. HRESULT CFileSearchBand::TranslateAcceleratorInternal(MSG *pmsg, IOleClientSite * pocs)
  514. {
  515. CBandDlg* pdlg = BandDlg();
  516. ASSERT(pdlg);
  517. if (::IsChild(pdlg->Hwnd(), pmsg->hwnd))
  518. {
  519. // Permit tabbing out of pane:
  520. int nDir;
  521. if ((nDir = IsVK_TABCycler(pmsg)) != 0)
  522. {
  523. if (nDir > 0 && (pmsg->hwnd == pdlg->GetLastTabItem()))
  524. return S_FALSE;
  525. if (nDir < 0 && (pmsg->hwnd == pdlg->GetFirstTabItem()))
  526. return S_FALSE;
  527. }
  528. // try base class handler
  529. if (S_OK == pdlg->TranslateAccelerator(pmsg))
  530. return S_OK;
  531. }
  532. else if (IsDialogMessage(pmsg))
  533. return S_OK;
  534. return IOleInPlaceActiveObjectImpl<CFileSearchBand>::TranslateAccelerator(pmsg);
  535. }
  536. // Determines whether the the specified message is keyboard input intended
  537. // to scroll the pane. If the pane is scrolled as a result of the
  538. // message, the function returns TRUE; otherwise it returns FALSE.
  539. BOOL CFileSearchBand::IsKeyboardScroll(MSG* pmsg)
  540. {
  541. if (pmsg->message == WM_KEYDOWN &&
  542. (GetKeyState(VK_CONTROL) & 0x8000) != 0 &&
  543. pmsg->wParam != VK_CONTROL)
  544. {
  545. int nBar = SB_VERT;
  546. UINT uSBCode;
  547. int nNewPos = 0;
  548. BOOL bEditCtl = _IsEditWindowClass(pmsg->hwnd);
  549. BOOL bScroll = TRUE;
  550. // Some of the following CTRL-key combinations are
  551. // not valid pane scroll keys if the target child window is an
  552. // edit control.
  553. switch (pmsg->wParam)
  554. {
  555. case VK_UP:
  556. uSBCode = SB_LINELEFT;
  557. break;
  558. case VK_DOWN:
  559. uSBCode = SB_LINERIGHT;
  560. break;
  561. case VK_PRIOR:
  562. uSBCode = SB_PAGELEFT;
  563. break;
  564. case VK_NEXT:
  565. uSBCode = SB_PAGERIGHT;
  566. break;
  567. case VK_END:
  568. uSBCode = SB_THUMBPOSITION;
  569. nNewPos = _siVert.nMax - _siVert.nPage;
  570. break;
  571. case VK_HOME:
  572. uSBCode = SB_THUMBPOSITION;
  573. nNewPos = 0;
  574. break;
  575. case VK_LEFT:
  576. bScroll = !bEditCtl;
  577. nBar = SB_HORZ;
  578. uSBCode = SB_LINELEFT;
  579. break;
  580. case VK_RIGHT:
  581. bScroll = !bEditCtl;
  582. nBar = SB_HORZ;
  583. uSBCode = SB_LINERIGHT;
  584. break;
  585. default:
  586. return FALSE;
  587. }
  588. // scroll only if we have to; reduce flicker.
  589. if (bScroll && ((SB_VERT == nBar && _siVert.nMax != 0) ||
  590. (SB_HORZ == nBar && _siHorz.nMax != 0)))
  591. {
  592. Scroll(nBar, uSBCode, nNewPos);
  593. return TRUE;
  594. }
  595. }
  596. return FALSE;
  597. }
  598. // Determines whether the indicated key should be passed to the top
  599. // level browser frame.
  600. BOOL CFileSearchBand::IsBrowserAccelerator(MSG *pmsg)
  601. {
  602. if ((WM_KEYDOWN == pmsg->message || WM_KEYUP == pmsg->message))
  603. {
  604. BOOL bCombobox = _IsComboWindowClass(pmsg->hwnd);
  605. BOOL bComboDropped = (BOOL)(bCombobox ? ::SendMessage(pmsg->hwnd, CB_GETDROPPEDSTATE, 0, 0) : FALSE);
  606. BOOL bEditCtl = _IsEditWindowClass(pmsg->hwnd);
  607. // Keys that we treat WITHOUT regard to state of CTRL key:
  608. if (VK_F4 == pmsg->wParam && bCombobox) // should toggle dropped/close-up of combo.
  609. return FALSE;
  610. // Keys that we treat WITH regard to state of CTRL key:
  611. if ((GetKeyState(VK_CONTROL) & 0x8000) != 0)
  612. {
  613. // Edit cut copy paste?
  614. if (bEditCtl)
  615. {
  616. switch (pmsg->wParam) {
  617. case 'C': case 'X': case 'V': case 'Z':
  618. return FALSE;
  619. }
  620. }
  621. return TRUE; // all other CTRL-key combinations are browser keys.
  622. }
  623. else
  624. {
  625. switch (pmsg->wParam)
  626. {
  627. // browser accelerators that may be shunted by edit controls.
  628. case VK_BACK:
  629. return !bEditCtl;
  630. if (VK_ESCAPE == pmsg->wParam) // should close up the combo.
  631. return bComboDropped;
  632. default:
  633. if (pmsg->wParam >= VK_F1 && pmsg->wParam <= VK_F24)
  634. return TRUE;
  635. }
  636. }
  637. }
  638. return FALSE;
  639. }
  640. HRESULT CFileSearchBand::IsDlgMessage(HWND hwnd, MSG *pmsg)
  641. {
  642. // handle tab cycling (Let browser handle F6)
  643. if (!IsVK_TABCycler(pmsg) || pmsg->wParam == VK_F6)
  644. {
  645. if (IsBrowserAccelerator(pmsg))
  646. {
  647. IShellBrowser* psb = GetTopLevelBrowser();
  648. return (psb && S_OK == psb->TranslateAcceleratorSB(pmsg, 0)) ?
  649. S_OK : S_FALSE;
  650. }
  651. }
  652. // send through dialog manager
  653. if (::IsDialogMessage((hwnd != NULL ? hwnd : m_hWnd), pmsg))
  654. return S_OK;
  655. // not handled.
  656. return S_FALSE ;
  657. }
  658. IShellBrowser* CFileSearchBand::GetTopLevelBrowser()
  659. {
  660. if (NULL == _psb)
  661. IUnknown_QueryService(BandSite(), SID_STopLevelBrowser, IID_PPV_ARG(IShellBrowser, &_psb));
  662. return _psb;
  663. }
  664. void CFileSearchBand::FinalRelease()
  665. {
  666. // ATL 2.1 has a bug in class unregistration. Here's
  667. // the work around:
  668. UnregisterClass(GetWndClassInfo().m_wc.lpszClassName,
  669. GetWndClassInfo().m_wc.hInstance);
  670. GetWndClassInfo().m_atom = 0;
  671. SetSite(NULL);
  672. }
  673. //-----------------------------//
  674. // IDeskBand : IDockingWindow
  675. STDMETHODIMP CFileSearchBand::GetBandInfo(DWORD dwBandID, DWORD dwViewMode, DESKBANDINFO* pdbi)
  676. {
  677. _dwBandID = dwBandID;
  678. _dwBandViewMode = dwViewMode;
  679. if (pdbi->dwMask & DBIM_MINSIZE)
  680. {
  681. pdbi->ptMinSize.x = _sizeMin.cx;
  682. pdbi->ptMinSize.y = _sizeMin.cy;
  683. }
  684. if (pdbi->dwMask & DBIM_MAXSIZE)
  685. {
  686. pdbi->ptMaxSize.x = _sizeMax.cx;
  687. pdbi->ptMaxSize.y = _sizeMax.cy;
  688. }
  689. if (pdbi->dwMask & DBIM_INTEGRAL)
  690. {
  691. pdbi->ptIntegral.x =
  692. pdbi->ptIntegral.y = 1;
  693. }
  694. if (pdbi->dwMask & DBIM_ACTUAL)
  695. {
  696. pdbi->ptActual.x =
  697. pdbi->ptActual.y = 0;
  698. }
  699. if (pdbi->dwMask & DBIM_TITLE)
  700. {
  701. TCHAR szTitle[256];
  702. EVAL(LoadString(HINST_THISDLL, IDS_FSEARCH_BANDCAPTION,
  703. szTitle, ARRAYSIZE(szTitle)));
  704. SHTCharToUnicode(szTitle, pdbi->wszTitle, ARRAYSIZE(szTitle));
  705. }
  706. if (pdbi->dwMask & DBIM_MODEFLAGS)
  707. {
  708. pdbi->dwModeFlags = DBIMF_NORMAL|DBIMF_VARIABLEHEIGHT|DBIMF_DEBOSSED|DBIMF_BKCOLOR;
  709. }
  710. if (pdbi->dwMask & DBIM_BKCOLOR)
  711. {
  712. pdbi->crBkgnd = GetSysColor(COLOR_3DFACE);
  713. }
  714. return S_OK;
  715. }
  716. BOOL CFileSearchBand::IsBandDebut()
  717. {
  718. HKEY hkey;
  719. BOOL bRet = TRUE;
  720. if (NULL == (hkey = GetBandRegKey(FALSE)))
  721. return bRet;
  722. BYTE rgData[128];
  723. DWORD cchData = sizeof(rgData);
  724. DWORD dwType;
  725. // Hack alert: we should maintain our own initialization reg value rather than using IE's
  726. // barsize entry.
  727. DWORD dwRet = RegQueryValueEx(hkey, TEXT("BarSize"), NULL, &dwType, rgData, &cchData);
  728. if ((ERROR_SUCCESS == dwRet || ERROR_MORE_DATA == dwRet) && cchData > 0)
  729. bRet = FALSE;
  730. RegCloseKey(hkey);
  731. return bRet;
  732. }
  733. // Hack alert: we should maintain our own reg key rather than using IE's
  734. #define FSB_REGKEYFMT TEXT("Software\\Microsoft\\Internet Explorer\\Explorer Bars\\%s")
  735. int CFileSearchBand::MakeBandKey(OUT LPTSTR pszKey, IN UINT cchKey)
  736. {
  737. TCHAR szClsid[GUIDSTR_MAX+1];
  738. SHStringFromGUID(CLSID_FileSearchBand, szClsid, ARRAYSIZE(szClsid));
  739. return wnsprintf(pszKey, cchKey, FSB_REGKEYFMT, szClsid);
  740. }
  741. int CFileSearchBand::MakeBandSubKey(IN LPCTSTR pszSubKey, OUT LPTSTR pszKey, IN UINT cchKey)
  742. {
  743. TCHAR szBandKey[MAX_PATH];
  744. int cchRet = MakeBandKey(szBandKey, ARRAYSIZE(szBandKey));
  745. if (cchRet > 0)
  746. {
  747. StrCpyN(pszKey, szBandKey, cchKey);
  748. if (pszSubKey && *pszSubKey && (cchKey - cchRet) > 1)
  749. {
  750. StrCat(pszKey, TEXT("\\"));
  751. cchRet++;
  752. cchKey -= cchRet;
  753. StrCpyN(pszKey + cchRet, pszSubKey, cchKey);
  754. return lstrlen(pszKey);
  755. }
  756. }
  757. return 0;
  758. }
  759. HKEY CFileSearchBand::GetBandRegKey(BOOL bCreateAlways)
  760. {
  761. HKEY hkey = NULL;
  762. TCHAR szKey[MAX_PATH];
  763. if (MakeBandKey(szKey, ARRAYSIZE(szKey)) > 0)
  764. {
  765. if (bCreateAlways)
  766. {
  767. DWORD dwDisp;
  768. if (ERROR_SUCCESS !=
  769. RegCreateKeyEx(HKEY_CURRENT_USER, szKey, 0, NULL, REG_OPTION_NON_VOLATILE,
  770. KEY_ALL_ACCESS, NULL, &hkey, &dwDisp))
  771. hkey = NULL;
  772. }
  773. else
  774. {
  775. if (ERROR_SUCCESS !=
  776. RegOpenKeyEx(HKEY_CURRENT_USER, szKey, 0, KEY_ALL_ACCESS, &hkey))
  777. hkey = NULL;
  778. }
  779. }
  780. return hkey;
  781. }
  782. void CFileSearchBand::SetDeskbandWidth(int cx)
  783. {
  784. SIZE sizeMin = _sizeMin,
  785. sizeMax = _sizeMax;
  786. RECT rc;
  787. // Bandsite hack: make sizemin == sizemax equal to
  788. // explicitly set band width:
  789. GetWindowRect(&rc);
  790. // note: you shouldn't be setting width if we're not a band.
  791. ASSERT(DBIF_VIEWMODE_VERTICAL == _dwBandViewMode);
  792. // note: height and width are reversed for vertical bands like us.
  793. _sizeMin.cx = _sizeMax.cx = -1; // ignore height
  794. _sizeMin.cy = _sizeMax.cy = cx; // assign new width.
  795. BandInfoChanged(); // force the site to enforce the desired size.
  796. _sizeMin = sizeMin;
  797. _sizeMax = sizeMax;
  798. // restore previous min/max. If we're to do it right now,
  799. // we'd be overrided by bandsite, who tries to establish the
  800. // infoband width after we're done.
  801. PostMessage(WMU_BANDINFOUPDATE, 0, 0);
  802. }
  803. // WMU_BANDINFOUPDATE handler
  804. LRESULT CFileSearchBand::OnBandInfoUpdate(UINT, WPARAM, LPARAM, BOOL&)
  805. {
  806. BandInfoChanged();
  807. return 0;
  808. }
  809. // Notifies the band site that DESKBANDINFO has changed
  810. HRESULT CFileSearchBand::BandInfoChanged()
  811. {
  812. ASSERT(_dwBandID != (DWORD)-1);
  813. VARIANTARG v = {0};
  814. v.vt = VT_I4;
  815. v.lVal = _dwBandID;
  816. return IUnknown_Exec(_punkSite, &CGID_DeskBand, DBID_BANDINFOCHANGED, 0, &v, NULL);
  817. }
  818. STDMETHODIMP CFileSearchBand::ShowDW(BOOL fShow)
  819. {
  820. if (::IsWindow(m_hWnd))
  821. {
  822. ShowWindow(fShow ? SW_SHOW : SW_HIDE);
  823. AddButtons(fShow);
  824. if (fShow && BandDlg() && ::IsWindow(BandDlg()->Hwnd()))
  825. BandDlg()->RemoveToolbarTurds(_siVert.nPos);
  826. BandDlg()->OnBandShow(fShow);
  827. }
  828. // Since we are now ready to display the band, we will send the
  829. // message that sub dialogs can begin their delayed initialization
  830. if (fShow && !_bSendFinishedDisplaying)
  831. {
  832. HWND hwndFindFiles = _dlgFSearch.Hwnd();
  833. if (hwndFindFiles)
  834. {
  835. if (::PostMessage(hwndFindFiles, WMU_BANDFINISHEDDISPLAYING, 0, 0))
  836. {
  837. _bSendFinishedDisplaying = TRUE;
  838. }
  839. }
  840. }
  841. return S_OK;
  842. }
  843. STDMETHODIMP CFileSearchBand::CloseDW(DWORD dwReserved)
  844. {
  845. if (::IsWindow(m_hWnd))
  846. DestroyWindow();
  847. return S_OK;
  848. }
  849. STDMETHODIMP CFileSearchBand::ResizeBorderDW(LPCRECT prcBorder, IUnknown* punkToolbarSite, BOOL fReserved)
  850. {
  851. return S_OK;
  852. }
  853. // IObjectWithSite
  854. STDMETHODIMP CFileSearchBand::SetSite(IUnknown* pSite)
  855. {
  856. ATOMICRELEASE(_psb); // free this guy just in case
  857. AdvertiseBand(pSite ? TRUE : FALSE);
  858. IUnknown_Set(&_punkSite, pSite);
  859. if (_punkSite)
  860. {
  861. HWND hwndSite;
  862. if (SUCCEEDED(IUnknown_GetWindow(_punkSite, &hwndSite)))
  863. {
  864. RECT rcPos;
  865. SetRect(&rcPos, 0, 0, 100, 400);
  866. m_hWnd = Create(hwndSite, rcPos, NULL,
  867. WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|WS_HSCROLL|WS_VSCROLL, 0, 0);
  868. }
  869. _fDeskBand = TRUE;
  870. }
  871. return S_OK;
  872. }
  873. STDMETHODIMP CFileSearchBand::FindFilesOrFolders(
  874. BOOL bNavigateToResults,
  875. BOOL bDefaultFocusCtl)
  876. {
  877. return ShowBandDialog(SRCID_SFileSearch,
  878. bNavigateToResults, bDefaultFocusCtl);
  879. }
  880. STDMETHODIMP CFileSearchBand::FindComputer(
  881. BOOL bNavigateToResults,
  882. BOOL bDefaultFocusCtl)
  883. {
  884. return ShowBandDialog(SRCID_SFindComputer,
  885. bNavigateToResults, bDefaultFocusCtl);
  886. }
  887. STDMETHODIMP CFileSearchBand::FindPrinter(
  888. BOOL bNavigateToResults,
  889. BOOL bDefaultFocusCtl)
  890. {
  891. #ifdef __PSEARCH_BANDDLG__
  892. return ShowBandDialog(SRCID_SFindPrinter,
  893. bNavigateToResults, bDefaultFocusCtl);
  894. #else __PSEARCH_BANDDLG__
  895. HRESULT hr = E_FAIL;
  896. ASSERT(BandSite());
  897. IShellDispatch2* psd2;
  898. hr = CoCreateInstance(CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
  899. IID_PPV_ARG(IShellDispatch2, &psd2));
  900. if (SUCCEEDED(hr))
  901. {
  902. hr = psd2->FindPrinter(NULL, NULL, NULL) ;
  903. psd2->Release();
  904. }
  905. return hr ;
  906. #endif __PSEARCH_BANDDLG__
  907. }
  908. STDMETHODIMP CFileSearchBand::FindPeople(BOOL bNavigateToResults, BOOL bDefaultFocusCtl)
  909. {
  910. IObjectWithSite* pows;
  911. HRESULT hr = CoCreateInstance(CLSID_SearchAssistantOC, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IObjectWithSite, &pows));
  912. if (SUCCEEDED(hr))
  913. {
  914. hr = pows->SetSite(BandSite());
  915. if (SUCCEEDED(hr))
  916. {
  917. ISearchAssistantOC* psaoc;
  918. hr = pows->QueryInterface(IID_PPV_ARG(ISearchAssistantOC, &psaoc));
  919. if (SUCCEEDED(hr))
  920. {
  921. hr = psaoc->FindPeople();
  922. psaoc->Release();
  923. }
  924. }
  925. pows->Release();
  926. }
  927. return hr;
  928. }
  929. STDMETHODIMP CFileSearchBand::FindOnWeb(BOOL bNavigateToResults, BOOL bDefaultFocusCtl)
  930. {
  931. IObjectWithSite* pows;
  932. HRESULT hr = CoCreateInstance(CLSID_SearchAssistantOC, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IObjectWithSite, &pows));
  933. if (SUCCEEDED(hr))
  934. {
  935. hr = pows->SetSite(BandSite());
  936. if (SUCCEEDED(hr))
  937. {
  938. ISearchAssistantOC* psaoc;
  939. hr = pows->QueryInterface(IID_PPV_ARG(ISearchAssistantOC, &psaoc));
  940. if (SUCCEEDED(hr))
  941. {
  942. hr = psaoc->FindOnWeb();
  943. psaoc->Release();
  944. }
  945. }
  946. pows->Release();
  947. }
  948. return hr;
  949. }
  950. // Make ourself available to clients of IWebBrowser2 by assigning
  951. // a VT_UNKNOWN property to the browser.
  952. HRESULT CFileSearchBand::AdvertiseBand(BOOL bAdvertise)
  953. {
  954. if (!BandSite())
  955. return E_UNEXPECTED;
  956. HRESULT hr = E_FAIL;
  957. IShellBrowser* psb = GetTopLevelBrowser();
  958. if (psb)
  959. {
  960. IWebBrowser2* pwb;
  961. hr = IUnknown_QueryService(psb, SID_SWebBrowserApp, IID_PPV_ARG(IWebBrowser2, &pwb));
  962. if (SUCCEEDED(hr))
  963. {
  964. BSTR bstrFileSearchBand;
  965. hr = BSTRFromCLSID(CLSID_FileSearchBand, &bstrFileSearchBand);
  966. if (SUCCEEDED(hr))
  967. {
  968. if (bAdvertise)
  969. {
  970. IUnknown *punk;
  971. hr = QueryInterface(IID_PPV_ARG(IUnknown, &punk));
  972. if (SUCCEEDED(hr))
  973. {
  974. VARIANT var;
  975. var.vt = VT_UNKNOWN;
  976. var.punkVal = punk;
  977. hr = pwb->PutProperty(bstrFileSearchBand, var);
  978. punk->Release();
  979. }
  980. }
  981. else
  982. {
  983. VARIANT var;
  984. hr = pwb->GetProperty(bstrFileSearchBand, &var);
  985. if (SUCCEEDED(hr))
  986. {
  987. if (VT_UNKNOWN == var.vt)
  988. {
  989. VARIANT varTmp = {0};
  990. hr = pwb->PutProperty(bstrFileSearchBand, varTmp);
  991. }
  992. VariantClear(&var);
  993. }
  994. }
  995. SysFreeString(bstrFileSearchBand);
  996. }
  997. pwb->Release();
  998. }
  999. }
  1000. return hr;
  1001. }
  1002. STDMETHODIMP CFileSearchBand::GetSite(REFIID riid, void **ppvSite)
  1003. {
  1004. *ppvSite = NULL;
  1005. return _punkSite ? _punkSite->QueryInterface(riid, ppvSite) : E_FAIL;
  1006. }
  1007. // IInputObject
  1008. STDMETHODIMP CFileSearchBand::HasFocusIO()
  1009. {
  1010. HWND hwndFocus = GetFocus();
  1011. return (::IsWindow(m_hWnd) && (m_hWnd == hwndFocus || IsChild(hwndFocus))) ?
  1012. S_OK : S_FALSE;
  1013. }
  1014. STDMETHODIMP CFileSearchBand::TranslateAcceleratorIO(MSG *pmsg)
  1015. {
  1016. return TranslateAccelerator(pmsg);
  1017. }
  1018. STDMETHODIMP CFileSearchBand::UIActivateIO(BOOL fActivate, MSG *pmsg)
  1019. {
  1020. if (fActivate)
  1021. AutoActivate();
  1022. CBandDlg* pdlg = BandDlg();
  1023. if (pdlg)
  1024. {
  1025. if (fActivate)
  1026. {
  1027. // Handle tabbing into pane
  1028. int nDir = IsVK_TABCycler(pmsg);
  1029. HWND hwndTarget = (nDir < 0) ? pdlg->GetLastTabItem() :
  1030. (nDir > 0) ? pdlg->GetFirstTabItem() :
  1031. NULL;
  1032. if (hwndTarget)
  1033. ::SetFocus(hwndTarget);
  1034. else if (!pdlg->RestoreFocus())
  1035. ::SetFocus(pdlg->Hwnd());
  1036. }
  1037. else
  1038. {
  1039. pdlg->RememberFocus(NULL);
  1040. }
  1041. }
  1042. return S_OK;
  1043. }
  1044. // IOleCommandTarget
  1045. STDMETHODIMP CFileSearchBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut)
  1046. {
  1047. if (pguidCmdGroup)
  1048. {
  1049. if (IsEqualGUID(*pguidCmdGroup, CGID_FileSearchBand))
  1050. {
  1051. switch (nCmdID)
  1052. {
  1053. case FSTBID_NEW:
  1054. if (_pBandDlg)
  1055. {
  1056. _pBandDlg->Clear();
  1057. _pBandDlg->LayoutControls();
  1058. UpdateLayout(BLF_ALL);
  1059. SetFocus();
  1060. _pBandDlg->SetDefaultFocus();
  1061. }
  1062. return S_OK;
  1063. case FSTBID_HELP:
  1064. if (_pBandDlg)
  1065. _pBandDlg->ShowHelp(NULL);
  1066. return S_OK;
  1067. }
  1068. }
  1069. }
  1070. return OLECMDERR_E_UNKNOWNGROUP;
  1071. }
  1072. STDMETHODIMP CFileSearchBand::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
  1073. {
  1074. if (pguidCmdGroup && IsEqualGUID(*pguidCmdGroup, CGID_FileSearchBand))
  1075. {
  1076. // Infotip text for toolbar buttons:
  1077. if (pCmdText)
  1078. {
  1079. ASSERT(1 == cCmds);
  1080. UINT nIDS = 0;
  1081. pCmdText->cwActual = 0;
  1082. switch (prgCmds[0].cmdID)
  1083. {
  1084. case iFSTBID_NEW:
  1085. case FSTBID_NEW:
  1086. nIDS = IDS_FSEARCH_NEWINFOTIP;
  1087. break;
  1088. case iFSTBID_HELP:
  1089. case FSTBID_HELP:
  1090. nIDS = IDS_FSEARCH_HELPINFOTIP;
  1091. break;
  1092. }
  1093. if (nIDS)
  1094. pCmdText->cwActual = LoadStringW(HINST_THISDLL, nIDS, pCmdText->rgwz, pCmdText->cwBuf);
  1095. return pCmdText->cwActual > 0 ? S_OK : E_FAIL;
  1096. }
  1097. }
  1098. return OLECMDERR_E_UNKNOWNGROUP;
  1099. }
  1100. // IServiceProvider
  1101. STDMETHODIMP CFileSearchBand::QueryService(REFGUID guidService, REFIID riid, void **ppv)
  1102. {
  1103. return E_NOTIMPL;
  1104. }
  1105. // IPersistStream
  1106. STDMETHODIMP CFileSearchBand::IsDirty(void)
  1107. {
  1108. return S_FALSE;
  1109. }
  1110. STDMETHODIMP CFileSearchBand::Load(IStream *pStm)
  1111. {
  1112. return E_NOTIMPL;
  1113. }
  1114. STDMETHODIMP CFileSearchBand::Save(IStream *pStm, BOOL fClearDirty)
  1115. {
  1116. return E_NOTIMPL;
  1117. }
  1118. STDMETHODIMP CFileSearchBand::GetSizeMax(ULARGE_INTEGER *pcbSize)
  1119. {
  1120. return E_NOTIMPL;
  1121. }
  1122. // IPersist
  1123. STDMETHODIMP CFileSearchBand::GetClassID(CLSID *pClassID)
  1124. {
  1125. *pClassID = CLSID_FileSearchBand;
  1126. return S_OK;
  1127. }
  1128. // CMetrics impl
  1129. CMetrics::CMetrics()
  1130. : _hbrBkgnd(NULL),
  1131. _hbrBorder(NULL),
  1132. _hfBold(NULL)
  1133. {
  1134. ZeroMemory(&_ptExpandOrigin, sizeof(_ptExpandOrigin));
  1135. ZeroMemory(&_rcCheckBox, sizeof(_rcCheckBox));
  1136. ZeroMemory(_rghiconCaption, sizeof(_rghiconCaption));
  1137. CreateResources();
  1138. }
  1139. void CMetrics::Init(HWND hwndDlg)
  1140. {
  1141. _cyTightMargin = _PixelsForDbu(hwndDlg, 3, FALSE);
  1142. _cyLooseMargin = 2 * _cyTightMargin;
  1143. _cxCtlMargin = _PixelsForDbu(hwndDlg, 7, TRUE);
  1144. }
  1145. BOOL CMetrics::CreateResources()
  1146. {
  1147. _hbrBkgnd = CreateSolidBrush(BkgndColor());
  1148. _hbrBorder= CreateSolidBrush(BorderColor());
  1149. return _hbrBkgnd != NULL && _hbrBorder != NULL;
  1150. }
  1151. BOOL CMetrics::GetWindowLogFont(HWND hwnd, OUT LOGFONT* plf)
  1152. {
  1153. HFONT hf = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0);
  1154. if (hf)
  1155. {
  1156. if (sizeof(*plf) == GetObject(hf, sizeof(*plf), plf))
  1157. return TRUE;
  1158. }
  1159. return FALSE;
  1160. }
  1161. HFONT CMetrics::BoldFont(HWND hwndDlg)
  1162. {
  1163. if (NULL == _hfBold)
  1164. {
  1165. LOGFONT lf;
  1166. if (GetWindowLogFont(hwndDlg, &lf))
  1167. {
  1168. lf.lfWeight = FW_BOLD;
  1169. SHAdjustLOGFONT(&lf); // locale-specific adjustments
  1170. _hfBold = CreateFontIndirect(&lf);
  1171. }
  1172. }
  1173. return _hfBold;
  1174. }
  1175. HICON CMetrics::CaptionIcon(UINT nIDIconResource)
  1176. {
  1177. for (int i = 0; i < ARRAYSIZE(_icons); i++)
  1178. {
  1179. if (_icons[i] == nIDIconResource)
  1180. {
  1181. if (NULL == _rghiconCaption[i])
  1182. {
  1183. _rghiconCaption[i] = (HICON)LoadImage(
  1184. HINST_THISDLL, MAKEINTRESOURCE(nIDIconResource),
  1185. IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
  1186. }
  1187. return _rghiconCaption[i];
  1188. }
  1189. }
  1190. return NULL;
  1191. }
  1192. void CMetrics::DestroyResources()
  1193. {
  1194. if (_hbrBkgnd)
  1195. {
  1196. DeleteObject(_hbrBkgnd);
  1197. _hbrBkgnd = NULL;
  1198. }
  1199. if (_hbrBorder)
  1200. {
  1201. DeleteObject(_hbrBorder);
  1202. _hbrBorder = NULL;
  1203. }
  1204. if (_hfBold)
  1205. {
  1206. DeleteObject(_hfBold);
  1207. _hfBold = NULL;
  1208. }
  1209. for (int i = 0; i < ARRAYSIZE(_icons); i++)
  1210. {
  1211. if (_rghiconCaption[i])
  1212. {
  1213. DestroyIcon(_rghiconCaption[i]);
  1214. _rghiconCaption[i] = NULL;
  1215. }
  1216. }
  1217. }
  1218. void CMetrics::OnWinIniChange(HWND hwndDlg)
  1219. {
  1220. DestroyResources();
  1221. // Force resource regen
  1222. CreateResources();
  1223. // Force font regen
  1224. BoldFont(hwndDlg);
  1225. Init(hwndDlg);
  1226. }
  1227. // returns:
  1228. // S_OK -> uptodate
  1229. // S_FALSE -> not up to date
  1230. // FAILED() -> volume not CIed
  1231. STDAPI CatalogUptodate(LPCWSTR pszCatalog, LPCWSTR pszMachine)
  1232. {
  1233. HRESULT hr = E_FAIL;
  1234. CI_STATE state = {0};
  1235. state.cbStruct = sizeof(state);
  1236. if (SUCCEEDED(CIState(pszCatalog, pszMachine, &state)))
  1237. {
  1238. BOOL fUpToDate = ((0 == state.cDocuments) &&
  1239. (0 == (state.eState & CI_STATE_SCANNING)) &&
  1240. (0 == (state.eState & CI_STATE_READING_USNS)) &&
  1241. (0 == (state.eState & CI_STATE_STARTING)) &&
  1242. (0 == (state.eState & CI_STATE_RECOVERING)));
  1243. if (fUpToDate)
  1244. {
  1245. hr = S_OK;
  1246. }
  1247. else
  1248. {
  1249. hr = S_FALSE;
  1250. }
  1251. }
  1252. return hr;
  1253. }
  1254. // returns:
  1255. // S_OK -> uptodate
  1256. // S_FALSE -> not up to date
  1257. // FAILED() -> volume not CIed
  1258. STDAPI PathUptodate(LPCWSTR pszPath)
  1259. {
  1260. HRESULT hr = E_FAIL;
  1261. WCHAR wszMachine[32], wszCatalog[MAX_PATH];
  1262. DWORD cchMachine = ARRAYSIZE(wszMachine), cchCatalog = ARRAYSIZE(wszCatalog);
  1263. if (S_OK == LocateCatalogsW(pszPath, 0, wszMachine, &cchMachine, wszCatalog, &cchCatalog))
  1264. {
  1265. hr = CatalogUptodate(wszCatalog, wszMachine);
  1266. }
  1267. return hr;
  1268. }
  1269. HRESULT LocalDrivesContentUpToDate()
  1270. {
  1271. HRESULT hr = S_OK; // assume yes
  1272. DWORD dwDriveMask = GetLogicalDrives();
  1273. for (int i = 0; i < 26; i++)
  1274. {
  1275. if (dwDriveMask & 1)
  1276. {
  1277. if (!IsRemovableDrive(i) && !IsRemoteDrive(i))
  1278. {
  1279. WCHAR wszPath[4];
  1280. PathBuildRoot(wszPath, i);
  1281. if (S_FALSE == PathUptodate(wszPath))
  1282. {
  1283. hr = S_FALSE;
  1284. break;
  1285. }
  1286. }
  1287. }
  1288. dwDriveMask >>= 1;
  1289. }
  1290. return hr;
  1291. }
  1292. HRESULT QueryCIStatus(DWORD *pdwStatus, BOOL *pbConfigAccess)
  1293. {
  1294. DWORD dwErr = ERROR_SUCCESS;
  1295. ASSERT(pdwStatus);
  1296. *pdwStatus = 0;
  1297. if (pbConfigAccess)
  1298. *pbConfigAccess = FALSE;
  1299. SC_HANDLE hScm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  1300. if (hScm)
  1301. {
  1302. SC_HANDLE hService = NULL;
  1303. // Test permission to muck around with service
  1304. if (pbConfigAccess)
  1305. {
  1306. hService = OpenService(hScm, L"cisvc",
  1307. SERVICE_START |SERVICE_STOP | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS);
  1308. if (hService)
  1309. {
  1310. *pbConfigAccess = TRUE;
  1311. }
  1312. }
  1313. // Query service status
  1314. if (NULL == hService)
  1315. hService = OpenService(hScm, L"cisvc", SERVICE_QUERY_STATUS);
  1316. if (hService)
  1317. {
  1318. SERVICE_STATUS status;
  1319. if (!QueryServiceStatus(hService, &status))
  1320. dwErr = GetLastError();
  1321. else
  1322. *pdwStatus = status.dwCurrentState;
  1323. CloseServiceHandle(hService);
  1324. }
  1325. else
  1326. dwErr = GetLastError();
  1327. CloseServiceHandle(hScm);
  1328. }
  1329. else
  1330. dwErr = GetLastError();
  1331. return HRESULT_FROM_WIN32(dwErr);
  1332. }
  1333. STDAPI GetCIStatus(BOOL *pbRunning, BOOL *pbIndexed, BOOL *pbPermission)
  1334. {
  1335. *pbRunning = *pbIndexed = *pbPermission = FALSE;
  1336. DWORD dwStatus = 0;
  1337. HRESULT hr = QueryCIStatus(&dwStatus, pbPermission);
  1338. if (SUCCEEDED(hr))
  1339. {
  1340. switch (dwStatus)
  1341. {
  1342. case SERVICE_START_PENDING:
  1343. case SERVICE_RUNNING:
  1344. case SERVICE_CONTINUE_PENDING:
  1345. *pbRunning = TRUE;
  1346. }
  1347. }
  1348. if (*pbRunning)
  1349. *pbIndexed = *pbPermission ? (S_OK == LocalDrivesContentUpToDate()) : TRUE;
  1350. return hr;
  1351. }
  1352. STDAPI StartStopCI(BOOL bStart)
  1353. {
  1354. DWORD dwErr = ERROR_SUCCESS;
  1355. SERVICE_STATUS status;
  1356. SC_HANDLE hScm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  1357. if (hScm)
  1358. {
  1359. DWORD dwAccess = SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | (bStart ? SERVICE_START : SERVICE_STOP);
  1360. SC_HANDLE hService = OpenService(hScm, L"cisvc", dwAccess);
  1361. if (hService)
  1362. {
  1363. if (QueryServiceStatus(hService, &status))
  1364. {
  1365. dwErr = ChangeServiceConfig(hService, SERVICE_NO_CHANGE,
  1366. bStart ? SERVICE_AUTO_START : SERVICE_DEMAND_START,
  1367. SERVICE_NO_CHANGE, NULL, NULL,
  1368. NULL, NULL, NULL, NULL, NULL);
  1369. // we'll ignore return value
  1370. if (bStart)
  1371. {
  1372. if (SERVICE_PAUSED == status.dwCurrentState ||
  1373. SERVICE_PAUSE_PENDING == status.dwCurrentState)
  1374. dwErr = ControlService(hService, SERVICE_CONTROL_CONTINUE, &status) ?
  1375. ERROR_SUCCESS : GetLastError();
  1376. else
  1377. {
  1378. dwErr = StartService(hService, 0, NULL) ? ERROR_SUCCESS : GetLastError();
  1379. if (ERROR_SERVICE_ALREADY_RUNNING == dwErr)
  1380. dwErr = ERROR_SUCCESS;
  1381. }
  1382. }
  1383. else
  1384. {
  1385. dwErr = ControlService(hService, SERVICE_CONTROL_STOP, &status) ?
  1386. ERROR_SUCCESS : GetLastError();
  1387. }
  1388. }
  1389. else
  1390. dwErr = GetLastError();
  1391. CloseServiceHandle(hService);
  1392. }
  1393. else
  1394. dwErr = GetLastError();
  1395. CloseServiceHandle(hScm);
  1396. }
  1397. else
  1398. dwErr = GetLastError();
  1399. return HRESULT_FROM_WIN32(dwErr);
  1400. }
  1401. inline BOOL IsWhite(WCHAR ch)
  1402. {
  1403. return L' ' == ch || L'\t' == ch || L'\n' == ch || L'\r' == ch;
  1404. }
  1405. inline BOOL IsParens(WCHAR ch)
  1406. {
  1407. return L'(' == ch || L')' == ch;
  1408. }
  1409. // Skips whitespace
  1410. static LPCWSTR SkipWhiteAndParens(IN LPCWSTR pwszTest)
  1411. {
  1412. while(pwszTest && *pwszTest &&
  1413. (IsWhite(*pwszTest) || IsParens(*pwszTest)))
  1414. pwszTest = CharNextW(pwszTest);
  1415. return (pwszTest && *pwszTest) ? pwszTest : NULL;
  1416. }
  1417. // Determines whether the indicated keyword is found in the specified
  1418. // prefix and/or suffix context. If successful, return value is address
  1419. // of first character beyond the keyword context; otherwise NULL.
  1420. static LPCWSTR IsKeywordContext(
  1421. IN LPCWSTR pwszTest,
  1422. IN OPTIONAL WCHAR chPrefix,
  1423. IN OPTIONAL LPCWSTR pwszKeyword,
  1424. IN OPTIONAL WCHAR chSuffix,
  1425. IN OPTIONAL WCHAR chSuffix2)
  1426. {
  1427. if ((pwszTest = SkipWhiteAndParens(pwszTest)) == NULL)
  1428. return NULL;
  1429. if (chPrefix)
  1430. {
  1431. if (chPrefix != *pwszTest)
  1432. return NULL;
  1433. pwszTest = CharNextW(pwszTest);
  1434. }
  1435. if (pwszKeyword)
  1436. {
  1437. if ((pwszTest = SkipWhiteAndParens(pwszTest)) == NULL)
  1438. return NULL;
  1439. if (StrStrIW(pwszTest, pwszKeyword) != pwszTest)
  1440. return NULL;
  1441. pwszTest += lstrlenW(pwszKeyword);
  1442. }
  1443. if (chSuffix)
  1444. {
  1445. if ((pwszTest = SkipWhiteAndParens(pwszTest)) == NULL)
  1446. return NULL;
  1447. if (*pwszTest != chSuffix)
  1448. return NULL;
  1449. pwszTest = CharNextW(pwszTest);
  1450. }
  1451. if (chSuffix2)
  1452. {
  1453. if ((pwszTest = SkipWhiteAndParens(pwszTest)) == NULL)
  1454. return NULL;
  1455. if (*pwszTest != chSuffix2)
  1456. return NULL;
  1457. pwszTest = CharNextW(pwszTest);
  1458. }
  1459. return pwszTest;
  1460. }
  1461. BOOL IsTripoliV1Token(LPCWSTR pwszQuery, LPCWSTR *ppwszOut /* trailing text */)
  1462. {
  1463. *ppwszOut = NULL;
  1464. LPCWSTR pwsz;
  1465. // Find the token
  1466. if ((pwsz = IsKeywordContext(pwszQuery, L'#', NULL, 0, 0)) != NULL ||
  1467. (pwsz = IsKeywordContext(pwszQuery, L'$', L"contents", 0, 0)) != NULL)
  1468. {
  1469. *ppwszOut = pwsz;
  1470. return TRUE;
  1471. }
  1472. return FALSE;
  1473. }
  1474. BOOL IsTripoliV2Token(LPCWSTR pwszQuery, LPCWSTR *ppwszOut /* trailing text */)
  1475. {
  1476. *ppwszOut = NULL;
  1477. LPCWSTR pwsz;
  1478. // Find the token
  1479. if ((pwsz = IsKeywordContext(pwszQuery, L'{', L"phrase", L'}', 0)) != NULL ||
  1480. (pwsz = IsKeywordContext(pwszQuery, L'{', L"freetext", L'}', 0)) != NULL ||
  1481. (pwsz = IsKeywordContext(pwszQuery, L'{', L"prop", 0, 0)) != NULL ||
  1482. (pwsz = IsKeywordContext(pwszQuery, L'{', L"regex", L'}', 0)) != NULL ||
  1483. (pwsz = IsKeywordContext(pwszQuery, L'{', L"coerce", L'}', 0)) != NULL ||
  1484. (pwsz = IsKeywordContext(pwszQuery, L'{', L"ve", L'}', 0)) != NULL ||
  1485. (pwsz = IsKeywordContext(pwszQuery, L'{', L"weight", 0, 0)) != NULL ||
  1486. (pwsz = IsKeywordContext(pwszQuery, L'{', L"vector", 0, 0)) != NULL ||
  1487. (pwsz = IsKeywordContext(pwszQuery, L'{', L"generate", 0, 0)) != NULL ||
  1488. (pwsz = IsKeywordContext(pwszQuery, L'@', NULL, 0, 0)) != NULL)
  1489. {
  1490. *ppwszOut = pwsz;
  1491. return TRUE;
  1492. }
  1493. return FALSE;
  1494. }
  1495. STDAPI_(BOOL) IsCiQuery(const VARIANT *pvarRaw, VARIANT *pvarQuery, ULONG *pulDialect)
  1496. {
  1497. BOOL bBang = FALSE;
  1498. VariantInit(pvarQuery);
  1499. *pulDialect = 0; // invalid value (valid values are > 0)
  1500. if (pvarRaw->vt != VT_BSTR || NULL == pvarRaw->bstrVal || 0 == *pvarRaw->bstrVal)
  1501. return FALSE;
  1502. LPCWSTR pwsz = pvarRaw->bstrVal;
  1503. // text beginning w/ '!' indicates that this text is a CI query.
  1504. // but it must be very first character (not even spaces are allowed)
  1505. if (pwsz && *pwsz)
  1506. {
  1507. if (L'!' == *pwsz)
  1508. {
  1509. // skip over '!'
  1510. bBang = TRUE;
  1511. if ((pwsz = CharNextW(pwsz)) == NULL || 0 == *pwsz)
  1512. return FALSE;
  1513. // fall through...
  1514. }
  1515. }
  1516. pwsz = SkipWhiteAndParens(pwsz);
  1517. if (pwsz && *pwsz)
  1518. {
  1519. // text looking like a query token
  1520. if (pwsz && *pwsz)
  1521. {
  1522. LPCWSTR pwszMore, pwszTemp;
  1523. // @ is valid in both tripoli v1 & v2 but it has extended usage in v2 so
  1524. // we put it as v2 token only
  1525. if (IsTripoliV2Token(pwsz, &pwszMore))
  1526. *pulDialect = ISQLANG_V2;
  1527. // no else here because if @ is used in combination w/ some v1 token
  1528. // we want the query to be v1.
  1529. if (IsTripoliV1Token(pwsz, &pwszTemp))
  1530. {
  1531. *pulDialect = ISQLANG_V1;
  1532. pwszMore = pwszTemp;
  1533. }
  1534. if (*pulDialect)
  1535. {
  1536. // See if there is anything substantial past the query tokens
  1537. pwszMore = SkipWhiteAndParens(pwszMore);
  1538. if (pwszMore && *pwszMore)
  1539. {
  1540. InitVariantFromStr(pvarQuery, pwsz);
  1541. return TRUE;
  1542. }
  1543. }
  1544. else
  1545. {
  1546. if (bBang)
  1547. {
  1548. InitVariantFromStr(pvarQuery, pwsz);
  1549. *pulDialect = ISQLANG_V1; // just pick one
  1550. return TRUE;
  1551. }
  1552. }
  1553. }
  1554. }
  1555. return FALSE;
  1556. }
  1557. // needed for ATL goo
  1558. LCID g_lcidLocale = MAKELCID(LANG_USER_DEFAULT, SORT_DEFAULT);
  1559. STDAPI CFileSearchBand_CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv)
  1560. {
  1561. HRESULT hr = CreateFromRegKey(REGSTR_PATH_EXPLORER, TEXT("FileFindBandHook"), riid, ppv);
  1562. if (FAILED(hr))
  1563. hr = CComCreator< CComObject< CFileSearchBand > >::CreateInstance((void *)pUnkOuter, IID_IUnknown, (void **)ppv);
  1564. return hr;
  1565. }