Leaked source code of windows server 2003
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.

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