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.

6019 lines
168 KiB

  1. #include "shellprv.h"
  2. #include "findband.h"
  3. #include "finddlg.h"
  4. #include "findfilter.h" // DFW_xxx warning flags.
  5. #include "enumidlist.h"
  6. void DivWindow_RegisterClass();
  7. // Namespace picker combo methods.
  8. STDAPI PopulateNamespaceCombo(HWND hwndComboEx, ADDCBXITEMCALLBACK pfn, LPARAM lParam);
  9. #define MAX_EDIT 256
  10. #define SUBDLG_BORDERWIDTH 0
  11. #define MIN_NAMESPACELIST_WIDTH 140
  12. #define MIN_FILEASSOCLIST_WIDTH 175
  13. #define LSUIS_WARNING 1 // LoadSaveUIState warning flags
  14. int CSearchWarningDlg_DoModal(HWND hwndParent, USHORT uDlgTemplate, BOOL* pbNoWarn);
  15. int CCISettingsDlg_DoModal(HWND hwndParent);
  16. BOOL IsConstraintName(LPCWSTR pwszConstraint, LPCWSTR pwszName)
  17. {
  18. return pwszName && (0 == StrCmpIW(pwszName, pwszConstraint));
  19. }
  20. BOOL _GetWindowSize(HWND hwndDlg, SIZE *pSize)
  21. {
  22. RECT rc;
  23. if (::GetClientRect(hwndDlg, &rc))
  24. {
  25. pSize->cx = RECTWIDTH(rc);
  26. pSize->cy = RECTHEIGHT(rc);
  27. return TRUE;
  28. }
  29. return FALSE;
  30. }
  31. BOOL _ModifyWindowStyle(HWND hwnd, DWORD dwAdd, DWORD dwRemove)
  32. {
  33. ASSERT(dwAdd || dwRemove);
  34. if (IsWindow(hwnd))
  35. {
  36. DWORD dwStyle = GetWindowLong(hwnd, GWL_STYLE);
  37. if (dwAdd)
  38. dwStyle |= dwAdd;
  39. if (dwRemove)
  40. dwStyle &= ~dwRemove;
  41. SetWindowLong(hwnd, GWL_STYLE, dwStyle);
  42. return TRUE;
  43. }
  44. return FALSE;
  45. }
  46. BOOL _EnforceNumericEditRange(
  47. IN HWND hwndDlg,
  48. IN UINT nIDEdit,
  49. IN UINT nIDSpin,
  50. IN LONG nLow,
  51. IN LONG nHigh,
  52. IN BOOL bSigned = FALSE)
  53. {
  54. BOOL bRet = FALSE;
  55. BOOL bReset = FALSE;
  56. LONG lRet = -1;
  57. if (nIDSpin)
  58. {
  59. lRet = (LONG)SendDlgItemMessage(hwndDlg, nIDSpin, UDM_GETPOS, 0, 0);
  60. bRet = 0 == HIWORD(lRet);
  61. }
  62. if (!bRet)
  63. lRet = (LONG)GetDlgItemInt(hwndDlg, nIDEdit, &bRet, bSigned);
  64. if (lRet < nLow)
  65. {
  66. lRet = nLow;
  67. bReset = TRUE;
  68. }
  69. else if (lRet > nHigh)
  70. {
  71. lRet = nHigh;
  72. bReset = TRUE;
  73. }
  74. if (bReset)
  75. SetDlgItemInt(hwndDlg, nIDEdit, lRet, bSigned);
  76. return bRet;
  77. }
  78. BOOL _IsDirectoryServiceAvailable()
  79. {
  80. BOOL bRet = FALSE;
  81. IShellDispatch2* psd;
  82. if (SUCCEEDED(CoCreateInstance(CLSID_Shell, 0, CLSCTX_INPROC_SERVER,
  83. IID_PPV_ARG(IShellDispatch2, &psd))))
  84. {
  85. BSTR bstrName = SysAllocString(L"DirectoryServiceAvailable");
  86. if (bstrName)
  87. {
  88. VARIANT varRet = {0};
  89. if (SUCCEEDED(psd->GetSystemInformation(bstrName, &varRet)))
  90. {
  91. ASSERT(VT_BOOL == varRet.vt);
  92. bRet = varRet.boolVal;
  93. }
  94. SysFreeString(bstrName);
  95. }
  96. psd->Release();
  97. }
  98. return bRet;
  99. }
  100. // Calculates number of pixels for dialog template units
  101. LONG _PixelsForDbu(HWND hwndDlg, LONG cDbu, BOOL bHorz)
  102. {
  103. RECT rc = {0,0,0,0};
  104. if (bHorz)
  105. rc.right = cDbu;
  106. else
  107. rc.bottom = cDbu;
  108. if (MapDialogRect(hwndDlg, &rc))
  109. return bHorz ? RECTWIDTH(rc) : RECTHEIGHT(rc);
  110. return 0;
  111. }
  112. // Retrieves a localizable horizontal or vertical metric value from
  113. // the resource module.
  114. LONG _GetResourceMetric(HWND hwndDlg, UINT nIDResource, BOOL bHorz /*orientation of metric*/)
  115. {
  116. TCHAR szMetric[48];
  117. if (!EVAL(LoadString(HINST_THISDLL, nIDResource,
  118. szMetric, ARRAYSIZE(szMetric))))
  119. return 0;
  120. LONG n = StrToInt(szMetric);
  121. return _PixelsForDbu(hwndDlg, n, bHorz);
  122. }
  123. // Calculates the date nDays + nMonths from pstSrc. nDays and/or nMonths
  124. // can be negative values.
  125. BOOL _CalcDateOffset(const SYSTEMTIME* pstSrc, int nDays, int nMonths, OUT SYSTEMTIME* pstDest)
  126. {
  127. ASSERT(pstSrc);
  128. ASSERT(pstDest);
  129. // Subtract 90 days from current date and stuff in date low range
  130. FILETIME ft;
  131. SystemTimeToFileTime(pstSrc, &ft);
  132. LARGE_INTEGER t;
  133. t.LowPart = ft.dwLowDateTime;
  134. t.HighPart = ft.dwHighDateTime;
  135. nDays += MulDiv(nMonths, 1461 /*days per 4 yrs*/, 48 /*months per 4 yrs*/);
  136. t.QuadPart += Int32x32To64(nDays * 24 /*hrs per day*/ * 3600 /*seconds per hr*/,
  137. 10000000 /*100 ns intervals per sec*/);
  138. ft.dwLowDateTime = t.LowPart;
  139. ft.dwHighDateTime = t.HighPart;
  140. FileTimeToSystemTime(&ft, pstDest);
  141. return TRUE;
  142. }
  143. // Loads a string into a combo box and assigns the string resource ID value
  144. // to the combo item's data.
  145. BOOL _LoadStringToCombo(HWND hwndCombo, int iPos, UINT idString, LPARAM lpData)
  146. {
  147. TCHAR szText[MAX_EDIT];
  148. if (LoadString(HINST_THISDLL, idString, szText, ARRAYSIZE(szText)))
  149. {
  150. INT_PTR idx = ::SendMessage(hwndCombo, CB_INSERTSTRING, iPos, (LPARAM)szText);
  151. if (idx != CB_ERR)
  152. {
  153. ::SendMessage(hwndCombo, CB_SETITEMDATA, idx, lpData);
  154. return TRUE;
  155. }
  156. }
  157. return FALSE;
  158. }
  159. // Retrieves combo item's data. If idx == CB_ERR, the currently selected
  160. // item's data will be retrieved.
  161. LPARAM _GetComboData(HWND hwndCombo, INT_PTR idx = CB_ERR)
  162. {
  163. if (CB_ERR == idx)
  164. idx = SendMessage(hwndCombo, CB_GETCURSEL, 0, 0);
  165. if (CB_ERR == idx)
  166. return idx;
  167. return (LPARAM)::SendMessage(hwndCombo, CB_GETITEMDATA, idx, 0);
  168. }
  169. // Selects combo item with matching data, and returns the index
  170. // of the selected item.
  171. INT_PTR _SelectComboData(HWND hwndCombo, LPARAM lpData)
  172. {
  173. for (INT_PTR i = 0, cnt = SendMessage(hwndCombo, CB_GETCOUNT, 0, 0); i < cnt; i++)
  174. {
  175. LPARAM lParam = SendMessage(hwndCombo, CB_GETITEMDATA, i, 0);
  176. if (lParam != CB_ERR && lParam == lpData)
  177. {
  178. SendMessage(hwndCombo, CB_SETCURSEL, i, 0);
  179. return i;
  180. }
  181. }
  182. return CB_ERR;
  183. }
  184. // Draws a focus rect bounding the specified window.
  185. void _DrawCtlFocus(HWND hwnd)
  186. {
  187. HDC hdc;
  188. if ((hdc = GetDC(hwnd)) != NULL)
  189. {
  190. RECT rc;
  191. GetClientRect(hwnd, &rc);
  192. DrawFocusRect(hdc, &rc);
  193. ReleaseDC(hwnd, hdc);
  194. }
  195. }
  196. BOOL _IsPathList(LPCTSTR pszPath)
  197. {
  198. return pszPath ? StrChr(pszPath, TEXT(';')) != NULL : FALSE;
  199. }
  200. HRESULT _IsPathValidUNC(HWND hWndParent, BOOL fNetValidate, LPCTSTR pszPath)
  201. {
  202. HRESULT hr = S_OK;
  203. if (PathIsUNC(pszPath))
  204. {
  205. if (fNetValidate)
  206. {
  207. NETRESOURCE nr = {0};
  208. TCHAR szPathBuffer[MAX_PATH];
  209. StrCpyN(szPathBuffer, pszPath, ARRAYSIZE(szPathBuffer));
  210. nr.dwType = RESOURCETYPE_DISK;
  211. nr.lpRemoteName = szPathBuffer;
  212. if (NO_ERROR != WNetAddConnection3(hWndParent, &nr, NULL, NULL,
  213. CONNECT_TEMPORARY | CONNECT_INTERACTIVE))
  214. {
  215. hr = E_FILE_NOT_FOUND;
  216. }
  217. }
  218. }
  219. else
  220. {
  221. hr = S_FALSE;
  222. }
  223. return hr;
  224. }
  225. BOOL _IsFullPathMinusDriveLetter(LPCTSTR pszPath)
  226. {
  227. if (NULL == pszPath || PathIsUNC(pszPath))
  228. return FALSE;
  229. ASSERT(!PathIsRelative(pszPath));
  230. // Eat whitespace
  231. for (; (0 != *pszPath) && (TEXT(' ') == *pszPath) ; pszPath = CharNext(pszPath));
  232. return TEXT('\\') == *pszPath &&
  233. -1 == PathGetDriveNumber(pszPath);
  234. }
  235. BOOL _PathLooksLikeFilePattern(LPCTSTR pszPath)
  236. {
  237. return StrPBrk(pszPath, TEXT("?*")) != NULL;
  238. }
  239. BOOL _PathIsDblSlash(LPCTSTR pszPath)
  240. {
  241. return pszPath && (pszPath[0] == TEXT('\\')) && (pszPath[1] == TEXT('\\'));
  242. }
  243. BOOL _PathIsUNCServerShareOrSub(LPCTSTR pszPath)
  244. {
  245. int cSlash = 0;
  246. if (_PathIsDblSlash(pszPath))
  247. {
  248. for (LPTSTR psz = (LPTSTR)pszPath; psz && *psz; psz = CharNext(psz))
  249. {
  250. if (*psz == TEXT('\\'))
  251. cSlash++;
  252. }
  253. }
  254. return cSlash >= 3;
  255. }
  256. BOOL _IsPathLocalHarddrive(LPCTSTR pszPath)
  257. {
  258. int iDrive = PathGetDriveNumber(pszPath);
  259. if (iDrive != -1)
  260. {
  261. TCHAR szRoot[16];
  262. return DRIVE_FIXED == GetDriveType(PathBuildRoot(szRoot, iDrive));
  263. }
  264. return FALSE;
  265. }
  266. BOOL _IsPathLocalRoot(LPCTSTR pszPath)
  267. {
  268. int iDrive = PathGetDriveNumber(pszPath);
  269. if (-1 != iDrive)
  270. {
  271. TCHAR szRoot[16];
  272. if (PathBuildRoot(szRoot, iDrive))
  273. {
  274. if (0 == StrCmpI(szRoot, pszPath))
  275. {
  276. switch (GetDriveType(szRoot))
  277. {
  278. case DRIVE_REMOVABLE:
  279. case DRIVE_FIXED:
  280. case DRIVE_REMOTE:
  281. case DRIVE_CDROM:
  282. case DRIVE_RAMDISK:
  283. return TRUE;
  284. }
  285. }
  286. }
  287. }
  288. return FALSE;
  289. }
  290. // from an object in the browser and it's site find the current pidl of what
  291. // we are looking at
  292. HRESULT _GetCurrentFolderIDList(IUnknown* punkSite, LPITEMIDLIST *ppidl)
  293. {
  294. *ppidl = NULL;
  295. IShellBrowser* psb;
  296. HRESULT hr = IUnknown_QueryService(punkSite, SID_STopLevelBrowser, IID_PPV_ARG(IShellBrowser, &psb));
  297. if (SUCCEEDED(hr))
  298. {
  299. IShellView* psv;
  300. hr = psb->QueryActiveShellView(&psv);
  301. if (SUCCEEDED(hr))
  302. {
  303. IFolderView *pfv;
  304. hr = psv->QueryInterface(IID_PPV_ARG(IFolderView, &pfv));
  305. if (SUCCEEDED(hr))
  306. {
  307. IShellFolder* psf;
  308. hr = pfv->GetFolder(IID_PPV_ARG(IShellFolder, &psf));
  309. if (SUCCEEDED(hr))
  310. {
  311. hr = SHGetIDListFromUnk(psf, ppidl);
  312. psf->Release();
  313. }
  314. pfv->Release();
  315. }
  316. psv->Release();
  317. }
  318. psb->Release();
  319. }
  320. return hr;
  321. }
  322. HRESULT _PathValidate(LPCTSTR pszPath, HWND hWndParent, BOOL fNetValidate)
  323. {
  324. HRESULT hr = _IsPathValidUNC(hWndParent, fNetValidate, pszPath);
  325. if (S_OK == hr)
  326. {
  327. // We are done.
  328. }
  329. else if (E_FILE_NOT_FOUND != hr)
  330. {
  331. if (_IsPathList(pszPath) || PathIsSlow(pszPath, -1))
  332. {
  333. hr = S_OK; // Skip check for slow files.
  334. }
  335. else
  336. {
  337. DWORD dwAttr;
  338. if (PathIsRelative(pszPath) || _IsFullPathMinusDriveLetter(pszPath))
  339. {
  340. hr = E_FILE_NOT_FOUND; // don't accept anything but a fully qualified path at this point.
  341. dwAttr = -1;
  342. }
  343. else
  344. {
  345. dwAttr = GetFileAttributes(pszPath); // Does it exist?
  346. if (-1 == dwAttr)
  347. {
  348. HRESULT hrFromPrepareForWrite = S_OK;
  349. // Maybe the disk isn't inserted, so allow the user
  350. // the chance to insert it.
  351. if (hWndParent)
  352. {
  353. hrFromPrepareForWrite = SHPathPrepareForWrite(hWndParent, NULL, pszPath, SHPPFW_IGNOREFILENAME);
  354. if (SUCCEEDED(hrFromPrepareForWrite))
  355. dwAttr = GetFileAttributes(pszPath); // Does it exist now?
  356. }
  357. // If SHPathPrepareForWrite() displays UI, then they will return HRESULT_FROM_WIN32(ERROR_CANCELLED)
  358. // so that the callers (us) will skip displaying our UI. If this is the case, when propagate that error.
  359. if (HRESULT_FROM_WIN32(ERROR_CANCELLED) == hrFromPrepareForWrite)
  360. {
  361. hr = hrFromPrepareForWrite;
  362. }
  363. else
  364. {
  365. if (-1 == dwAttr)
  366. hr = E_FILE_NOT_FOUND; // It doesn't exist.
  367. else
  368. hr = S_OK; // It exists now.
  369. }
  370. }
  371. }
  372. }
  373. }
  374. return hr;
  375. }
  376. BOOL _FmtError(UINT nIDFmt, LPCTSTR pszSub, LPTSTR szBuf, int cchBuf)
  377. {
  378. TCHAR szFmt[MAX_PATH];
  379. if (EVAL(LoadString(HINST_THISDLL, nIDFmt, szFmt, ARRAYSIZE(szFmt))))
  380. {
  381. wnsprintf(szBuf, cchBuf, szFmt, pszSub);
  382. return TRUE;
  383. }
  384. return FALSE;
  385. }
  386. // Retrieves the window text as a variant value of the specified type.
  387. HRESULT _GetWindowValue(HWND hwndDlg, UINT nID, VARIANT* pvar)
  388. {
  389. TCHAR szText[MAX_EDIT];
  390. LPTSTR pszText;
  391. if (::GetDlgItemText(hwndDlg, nID, szText, ARRAYSIZE(szText)))
  392. pszText = szText;
  393. else
  394. pszText = NULL;
  395. return InitVariantFromStr(pvar, pszText);
  396. }
  397. // Loads the window text from a string resource.
  398. BOOL _LoadWindowText(HWND hwnd, UINT nIDString)
  399. {
  400. TCHAR szText[MAX_PATH];
  401. if (LoadString(HINST_THISDLL, nIDString, szText, ARRAYSIZE(szText)))
  402. return SetWindowText(hwnd, szText);
  403. return FALSE;
  404. }
  405. // Retrieves the window text as a variant value of the specified type.
  406. HRESULT _SetWindowValue(HWND hwndDlg, UINT nID, const VARIANT* pvar)
  407. {
  408. switch (pvar->vt)
  409. {
  410. case VT_BSTR:
  411. SetDlgItemTextW(hwndDlg, nID, pvar->bstrVal);
  412. break;
  413. case VT_UI4:
  414. SetDlgItemInt(hwndDlg, nID, pvar->uiVal, FALSE);
  415. break;
  416. case VT_I4:
  417. SetDlgItemInt(hwndDlg, nID, pvar->lVal, TRUE);
  418. break;
  419. default:
  420. return E_NOTIMPL;
  421. }
  422. return S_OK;
  423. }
  424. // Adds a named constraint to the specified search command extension object
  425. HRESULT _AddConstraint(ISearchCommandExt* pSrchCmd, LPCWSTR pwszConstraint, VARIANT* pvarValue)
  426. {
  427. HRESULT hr;
  428. BSTR bstrConstraint = SysAllocString(pwszConstraint);
  429. if (bstrConstraint)
  430. {
  431. hr = pSrchCmd->AddConstraint(bstrConstraint, *pvarValue);
  432. SysFreeString(bstrConstraint);
  433. }
  434. else
  435. hr = E_OUTOFMEMORY;
  436. return hr;
  437. }
  438. void _PaintDlg(HWND hwndDlg, const CMetrics& metrics, HDC hdcPaint = NULL, LPCRECT prc = NULL)
  439. {
  440. RECT rcPaint /* rcLine */;
  441. HDC hdc = hdcPaint;
  442. if (NULL == hdcPaint)
  443. hdc = GetDC(hwndDlg);
  444. if (prc == NULL)
  445. {
  446. GetClientRect(hwndDlg, &rcPaint);
  447. prc = &rcPaint;
  448. }
  449. FillRect(hdc, prc, metrics.BkgndBrush());
  450. if (NULL == hdcPaint)
  451. ReleaseDC(hwndDlg, hdc);
  452. }
  453. void _EnsureVisible(HWND hwndDlg, HWND hwndVis, CFileSearchBand* pfsb)
  454. {
  455. ASSERT(pfsb);
  456. ASSERT(::IsWindow(hwndDlg));
  457. ASSERT(::IsWindow(hwndVis));
  458. RECT rcDlg, rcVis, rcX;
  459. GetWindowRect(hwndDlg, &rcDlg);
  460. GetWindowRect(hwndVis, &rcVis);
  461. if (IntersectRect(&rcX, &rcDlg, &rcVis))
  462. pfsb->EnsureVisible(&rcX);
  463. }
  464. inline BOOL _IsKeyPressed(int virtkey)
  465. {
  466. return (GetKeyState(virtkey) & 8000) != 0;
  467. }
  468. HWND _CreateDivider(HWND hwndParent, UINT nIDC, const POINT& pt, int nThickness = 1, HWND hwndAfter = NULL)
  469. {
  470. HWND hwndDiv = CreateWindowEx(0, DIVWINDOW_CLASS, NULL,
  471. WS_CHILD|WS_CLIPSIBLINGS|WS_VISIBLE,
  472. pt.x, pt.y, 400, 1, hwndParent,
  473. IntToPtr_(HMENU, nIDC), HINST_THISDLL, NULL);
  474. if (IsWindow(hwndDiv))
  475. {
  476. if (IsWindow(hwndAfter))
  477. SetWindowPos(hwndDiv, hwndAfter, 0,0,0,0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
  478. SendMessage(hwndDiv, DWM_SETHEIGHT, nThickness, 0);
  479. return hwndDiv;
  480. }
  481. return NULL;
  482. }
  483. HWND _CreateLinkWindow(HWND hwndParent, UINT nIDC, const POINT& pt, UINT nIDCaption, BOOL bShow = TRUE)
  484. {
  485. DWORD dwStyle = WS_CHILD|WS_TABSTOP|WS_CLIPSIBLINGS;
  486. if (bShow)
  487. dwStyle |= WS_VISIBLE;
  488. HWND hwndCtl = CreateWindowEx(0, WC_LINK, NULL, dwStyle,
  489. pt.x, pt.y, 400, 18, hwndParent,
  490. IntToPtr_(HMENU, nIDC), HINST_THISDLL, NULL);
  491. if (IsWindow(hwndCtl))
  492. {
  493. _LoadWindowText(hwndCtl, nIDCaption);
  494. return hwndCtl;
  495. }
  496. return NULL;
  497. }
  498. BOOL _EnableLink(HWND hwndLink, BOOL bEnable)
  499. {
  500. LWITEM item;
  501. item.mask = LWIF_ITEMINDEX|LWIF_STATE;
  502. item.stateMask = LWIS_ENABLED;
  503. item.state = bEnable ? LWIS_ENABLED : 0;
  504. item.iLink = 0;
  505. return (BOOL)SendMessage(hwndLink, LWM_SETITEM, 0, (LPARAM)&item);
  506. }
  507. int _CreateSearchLinks(HWND hwndDlg, const POINT& pt, UINT nCtlIDdlg /* ctl ID of link to hwndDlg */)
  508. {
  509. const UINT rgCtlID[] = {
  510. IDC_SEARCHLINK_FILES,
  511. IDC_SEARCHLINK_COMPUTERS,
  512. IDC_SEARCHLINK_PRINTERS,
  513. IDC_SEARCHLINK_PEOPLE,
  514. IDC_SEARCHLINK_INTERNET,
  515. };
  516. const UINT rgCaptionID[] = {
  517. IDS_FSEARCH_SEARCHLINK_FILES,
  518. IDS_FSEARCH_SEARCHLINK_COMPUTERS,
  519. IDS_FSEARCH_SEARCHLINK_PRINTERS,
  520. IDS_FSEARCH_SEARCHLINK_PEOPLE,
  521. IDS_FSEARCH_SEARCHLINK_INTERNET,
  522. };
  523. int cLinks = 0;
  524. BOOL bDSEnabled = _IsDirectoryServiceAvailable();
  525. for (int i = 0; i < ARRAYSIZE(rgCtlID); i++)
  526. {
  527. // block creation of csearch, psearch search links
  528. // if Directory Service is not available.
  529. if (((IDC_SEARCHLINK_PRINTERS == rgCtlID[i]) && rgCtlID[i] != nCtlIDdlg && !bDSEnabled)
  530. || (IDC_SEARCHLINK_FILES == rgCtlID[i] && SHRestricted(REST_NOFIND)))
  531. {
  532. continue;
  533. }
  534. if (_CreateLinkWindow(hwndDlg, rgCtlID[i], pt, rgCaptionID[i]))
  535. cLinks++;
  536. }
  537. // Disable link to current dialog:
  538. _EnableLink(GetDlgItem(hwndDlg, nCtlIDdlg), FALSE);
  539. return cLinks;
  540. }
  541. void _LayoutLinkWindow(
  542. IN HWND hwnd, // parent window
  543. IN LONG left, // left position of link
  544. IN LONG right, // right position of link
  545. IN LONG yMargin, // vertical padding between links
  546. IN OUT LONG& y, // IN: where to start (RECT::top). OUT: where the last link was positioned (RECT::bottom).
  547. IN const int nCtlID) // ctl ID
  548. {
  549. HWND hwndLink;
  550. if (nCtlID > 0)
  551. {
  552. hwndLink = GetDlgItem(hwnd, nCtlID);
  553. RECT rcLink;
  554. if (!IsWindow(hwndLink))
  555. return;
  556. ::GetWindowRect(hwndLink, &rcLink);
  557. ::MapWindowRect(NULL, hwnd, &rcLink);
  558. rcLink.left = left;
  559. rcLink.right = right;
  560. int cyIdeal = (int)::SendMessage(hwndLink, LWM_GETIDEALHEIGHT, RECTWIDTH(rcLink), 0);
  561. if (cyIdeal >= 0)
  562. rcLink.bottom = rcLink.top + cyIdeal;
  563. OffsetRect(&rcLink, 0, y - rcLink.top);
  564. y = rcLink.bottom;
  565. ::SetWindowPos(hwndLink, NULL,
  566. rcLink.left, rcLink.top,
  567. RECTWIDTH(rcLink), RECTHEIGHT(rcLink),
  568. SWP_NOZORDER|SWP_NOACTIVATE);
  569. }
  570. else if (nCtlID < 0)
  571. {
  572. // this is a divider window
  573. hwndLink = GetDlgItem(hwnd, -nCtlID);
  574. ::SetWindowPos(hwndLink, NULL, left, y + yMargin/2, right - left, 1,
  575. SWP_NOZORDER|SWP_NOACTIVATE);
  576. }
  577. y += yMargin;
  578. }
  579. void _LayoutLinkWindows(
  580. IN HWND hwnd, // parent window
  581. IN LONG left, // left position of links
  582. IN LONG right, // right position of links
  583. IN LONG yMargin, // vertical padding between links
  584. IN OUT LONG& y, // IN: where to start (RECT::top). OUT: where the last link was positioned (RECT::bottom).
  585. IN const int rgCtlID[],// array of link ctl IDs. use IDC_SEPARATOR for separators
  586. IN LONG cCtlID) // number of array elements to layout in rgCtlID.
  587. {
  588. for (int i = 0; i < cCtlID; i++)
  589. _LayoutLinkWindow(hwnd, left, right, yMargin, y, rgCtlID[i]);
  590. }
  591. // Retrieves AutoComplete flags
  592. //
  593. #define SZ_REGKEY_AUTOCOMPLETE_TAB TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoComplete")
  594. #define BOOL_NOT_SET 0x00000005
  595. DWORD _GetAutoCompleteSettings()
  596. {
  597. DWORD dwACOptions = 0;
  598. if (SHRegGetBoolUSValue(REGSTR_PATH_AUTOCOMPLETE, REGSTR_VAL_USEAUTOAPPEND, FALSE, /*default:*/FALSE))
  599. {
  600. dwACOptions |= ACO_AUTOAPPEND;
  601. }
  602. if (SHRegGetBoolUSValue(REGSTR_PATH_AUTOCOMPLETE, REGSTR_VAL_USEAUTOSUGGEST, FALSE, /*default:*/TRUE))
  603. {
  604. dwACOptions |= ACO_AUTOSUGGEST;
  605. }
  606. // Windows uses the TAB key to move between controls in a dialog. UNIX and other
  607. // operating systems that use AutoComplete have traditionally used the TAB key to
  608. // iterate thru the AutoComplete possibilities. We need to default to disable the
  609. // TAB key (ACO_USETAB) unless the caller specifically wants it. We will also
  610. // turn it on
  611. static BOOL s_fAlwaysUseTab = BOOL_NOT_SET;
  612. if (BOOL_NOT_SET == s_fAlwaysUseTab)
  613. s_fAlwaysUseTab = SHRegGetBoolUSValue(SZ_REGKEY_AUTOCOMPLETE_TAB, TEXT("Always Use Tab"), FALSE, FALSE);
  614. if (s_fAlwaysUseTab)
  615. dwACOptions |= ACO_USETAB;
  616. return dwACOptions;
  617. }
  618. // Initializes and enables an MRU autocomplete list on the specified
  619. // edit control
  620. HRESULT _InitializeMru(HWND hwndEdit, IAutoComplete2** ppAutoComplete, LPCTSTR pszSubKey, IStringMru** ppStringMru)
  621. {
  622. *ppAutoComplete = NULL;
  623. *ppStringMru = NULL;
  624. HRESULT hr = CoCreateInstance(CLSID_AutoComplete, NULL, CLSCTX_INPROC_SERVER,
  625. IID_PPV_ARG(IAutoComplete2, ppAutoComplete));
  626. if (SUCCEEDED(hr))
  627. {
  628. TCHAR szKey[MAX_PATH];
  629. if (CFileSearchBand::MakeBandSubKey(pszSubKey, szKey, ARRAYSIZE(szKey)) > 0)
  630. {
  631. hr = CStringMru::CreateInstance(HKEY_CURRENT_USER, szKey, 25, FALSE,
  632. IID_PPV_ARG(IStringMru, ppStringMru));
  633. if (SUCCEEDED(hr))
  634. {
  635. hr = (*ppAutoComplete)->Init(hwndEdit, *ppStringMru, NULL, NULL);
  636. }
  637. }
  638. else
  639. hr = E_FAIL;
  640. }
  641. if (SUCCEEDED(hr))
  642. {
  643. (*ppAutoComplete)->SetOptions(_GetAutoCompleteSettings());
  644. (*ppAutoComplete)->Enable(TRUE);
  645. }
  646. else
  647. {
  648. ATOMICRELEASE((*ppAutoComplete));
  649. ATOMICRELEASE((*ppStringMru));
  650. }
  651. return hr;
  652. }
  653. HRESULT _AddMruStringFromWindow(IStringMru* pmru, HWND hwnd)
  654. {
  655. ASSERT(::IsWindow(hwnd));
  656. HRESULT hr = E_FAIL;
  657. if (pmru)
  658. {
  659. TCHAR szText[MAX_PATH * 3];
  660. if (GetWindowTextW(hwnd, szText, ARRAYSIZE(szText)) > 0)
  661. hr = pmru->Add(szText);
  662. else
  663. hr = S_FALSE;
  664. }
  665. return hr;
  666. }
  667. HRESULT _TestAutoCompleteDropDownState(IAutoComplete2* pac2, DWORD dwTest)
  668. {
  669. IAutoCompleteDropDown* pacdd;
  670. HRESULT hr = pac2->QueryInterface(IID_PPV_ARG(IAutoCompleteDropDown, &pacdd));
  671. if (SUCCEEDED(hr))
  672. {
  673. DWORD dwFlags;
  674. if (SUCCEEDED((hr = pacdd->GetDropDownStatus(&dwFlags, NULL))))
  675. hr = (dwFlags & dwTest) ? S_OK : S_FALSE;
  676. pacdd->Release();
  677. }
  678. return hr;
  679. }
  680. inline HWND _IndexServiceHelp(HWND hwnd)
  681. {
  682. return ::HtmlHelp(hwnd, TEXT("isconcepts.chm"), HH_DISPLAY_TOPIC, 0);
  683. }
  684. LRESULT CSubDlg::OnNcCalcsize(UINT, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  685. {
  686. InflateRect((LPRECT)lParam, -SUBDLG_BORDERWIDTH, -SUBDLG_BORDERWIDTH);
  687. return 0;
  688. }
  689. LRESULT CSubDlg::OnNcPaint(UINT, WPARAM wParam, LPARAM lParam, BOOL&)
  690. {
  691. RECT rc;
  692. HDC hdc;
  693. HBRUSH hbr = _pfsb->GetMetrics().BorderBrush();
  694. GetWindowRect(Hwnd(), &rc);
  695. OffsetRect(&rc, -rc.left, -rc.top);
  696. if (hbr && (hdc = GetWindowDC(Hwnd())) != NULL)
  697. {
  698. for (int i=0; i < SUBDLG_BORDERWIDTH; i++)
  699. {
  700. FrameRect(hdc, &rc, hbr);
  701. InflateRect(&rc, -1, -1);
  702. }
  703. ReleaseDC(Hwnd(), hdc);
  704. }
  705. return 0;
  706. }
  707. LRESULT CSubDlg::OnCtlColor(UINT, WPARAM wParam, LPARAM, BOOL&)
  708. {
  709. SetTextColor((HDC)wParam, _pfsb->GetMetrics().TextColor());
  710. SetBkColor((HDC)wParam, _pfsb->GetMetrics().BkgndColor());
  711. return (LRESULT)_pfsb->GetMetrics().BkgndBrush();
  712. }
  713. LRESULT CSubDlg::OnPaint(UINT, WPARAM, LPARAM, BOOL&)
  714. {
  715. // Just going to call BeginPaint and EndPaint. All
  716. // painting done in WM_ERASEBKGND handler to avoid flicker.
  717. PAINTSTRUCT ps;
  718. HDC hdc = BeginPaint(_hwnd, &ps);
  719. if (hdc)
  720. {
  721. EndPaint(_hwnd, &ps);
  722. }
  723. return 0;
  724. }
  725. LRESULT CSubDlg::OnSize(UINT, WPARAM, LPARAM, BOOL&)
  726. {
  727. ASSERT(::IsWindow(Hwnd())); // was _Attach() called, e.g. from WM_INITDIALOG?
  728. _PaintDlg(Hwnd(), _pfsb->GetMetrics());
  729. ValidateRect(Hwnd(), NULL);
  730. return 0;
  731. }
  732. LRESULT CSubDlg::OnEraseBkgnd(UINT, WPARAM wParam, LPARAM, BOOL&)
  733. {
  734. _PaintDlg(Hwnd(), _pfsb->GetMetrics(), (HDC)wParam);
  735. ValidateRect(Hwnd(), NULL);
  736. return TRUE;
  737. }
  738. STDMETHODIMP CSubDlg::TranslateAccelerator(MSG *pmsg)
  739. {
  740. if (_pfsb->IsKeyboardScroll(pmsg))
  741. return S_OK;
  742. return _pfsb->IsDlgMessage(Hwnd(), pmsg);
  743. }
  744. LRESULT CSubDlg::OnChildSetFocusCmd(WORD wNotifyCode, WORD wID, HWND hwndCtl, BOOL& bHandled)
  745. {
  746. _EnsureVisible(_hwnd, hwndCtl, _pfsb);
  747. bHandled = FALSE;
  748. return 0;
  749. }
  750. LRESULT CSubDlg::OnChildSetFocusNotify(int, NMHDR *pnmh, BOOL& bHandled)
  751. {
  752. _EnsureVisible(_hwnd, pnmh->hwndFrom, _pfsb);
  753. bHandled = FALSE;
  754. return 0;
  755. }
  756. LRESULT CSubDlg::OnChildKillFocusCmd(WORD, WORD, HWND hwndCtl, BOOL&)
  757. {
  758. if (_pBandDlg)
  759. _pBandDlg->RememberFocus(hwndCtl);
  760. return 0;
  761. }
  762. LRESULT CSubDlg::OnChildKillFocusNotify(int, NMHDR *pnmh, BOOL&)
  763. {
  764. if (_pBandDlg)
  765. _pBandDlg->RememberFocus(pnmh->hwndFrom);
  766. return 0;
  767. }
  768. LRESULT CSubDlg::OnComboExEndEdit(int, NMHDR *pnmh, BOOL&)
  769. {
  770. if (CBENF_KILLFOCUS == ((NMCBEENDEDIT*)pnmh)->iWhy)
  771. {
  772. if (_pBandDlg)
  773. _pBandDlg->RememberFocus(pnmh->hwndFrom);
  774. }
  775. return 0;
  776. }
  777. // CDateDlg impl
  778. #define RECENTMONTHSRANGE_HIGH 999
  779. #define RECENTDAYSRANGE_HIGH RECENTMONTHSRANGE_HIGH
  780. #define RECENTMONTHSRANGE_HIGH_LEN 3 // count of digits in RECENTMONTHSRANGE_HIGH
  781. #define RECENTDAYSRANGE_HIGH_LEN RECENTMONTHSRANGE_HIGH_LEN
  782. #define RECENTMONTHSRANGE_LOW 1
  783. #define RECENTDAYSRANGE_LOW RECENTMONTHSRANGE_LOW
  784. LRESULT CDateDlg::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  785. {
  786. ASSERT(_pfsb);
  787. _Attach(m_hWnd);
  788. HWND hwndCombo = GetDlgItem(IDC_WHICH_DATE);
  789. SendDlgItemMessage(IDC_RECENT_MONTHS_SPIN, UDM_SETRANGE32,
  790. RECENTMONTHSRANGE_HIGH, RECENTMONTHSRANGE_LOW);
  791. SendDlgItemMessage(IDC_RECENT_DAYS_SPIN, UDM_SETRANGE32,
  792. RECENTDAYSRANGE_HIGH, RECENTDAYSRANGE_LOW);
  793. SendDlgItemMessage(IDC_RECENT_MONTHS, EM_LIMITTEXT, RECENTMONTHSRANGE_HIGH_LEN, 0);
  794. SendDlgItemMessage(IDC_RECENT_DAYS, EM_LIMITTEXT, RECENTDAYSRANGE_HIGH_LEN, 0);
  795. SYSTEMTIME st[2] = {0};
  796. // lower limit -- dos date does not support anything before 1/1/1980
  797. st[0].wYear = 1980;
  798. st[0].wMonth = 1;
  799. st[0].wDay = 1;
  800. // upper limit
  801. st[1].wYear = 2099;
  802. st[1].wMonth = 12;
  803. st[1].wDay = 31;
  804. SendDlgItemMessage(IDC_DATERANGE_BEGIN, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
  805. SendDlgItemMessage(IDC_DATERANGE_END, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
  806. _LoadStringToCombo(hwndCombo, -1, IDS_FSEARCH_MODIFIED_DATE, IDS_FSEARCH_MODIFIED_DATE);
  807. _LoadStringToCombo(hwndCombo, -1, IDS_FSEARCH_CREATION_DATE, IDS_FSEARCH_CREATION_DATE);
  808. _LoadStringToCombo(hwndCombo, -1, IDS_FSEARCH_ACCESSED_DATE, IDS_FSEARCH_ACCESSED_DATE);
  809. Clear();
  810. return TRUE; // Let the system set the focus
  811. }
  812. BOOL CDateDlg::Validate()
  813. {
  814. return TRUE;
  815. }
  816. STDMETHODIMP CDateDlg::AddConstraints(ISearchCommandExt* pSrchCmd)
  817. {
  818. VARIANT var;
  819. BOOL bErr;
  820. UINT_PTR nIDString = _GetComboData(GetDlgItem(IDC_WHICH_DATE));
  821. HRESULT hr;
  822. #if 1
  823. hr = InitVariantFromStr(&var,
  824. (IDS_FSEARCH_MODIFIED_DATE == nIDString) ? L"Write" :
  825. (IDS_FSEARCH_CREATION_DATE == nIDString) ? L"Create" : L"Access");
  826. #else
  827. var.vt = VT_UI4;
  828. var.ulVal = (IDS_FSEARCH_MODIFIED_DATE == nIDString) ? 1 :
  829. (IDS_FSEARCH_CREATION_DATE == nIDString) ? 2 :
  830. (IDS_FSEARCH_ACCESSED_DATE == nIDString) ? 3 : 0;
  831. hr = S_OK;
  832. ASSERT(var.ulVal);
  833. #endif
  834. if (SUCCEEDED(hr))
  835. {
  836. hr = _AddConstraint(pSrchCmd, L"WhichDate", &var);
  837. VariantClear(&var);
  838. }
  839. if (IsDlgButtonChecked(IDC_USE_RECENT_MONTHS))
  840. {
  841. var.vt = VT_I4;
  842. var.ulVal = (ULONG)SendDlgItemMessage(IDC_RECENT_MONTHS_SPIN, UDM_GETPOS32, 0, (LPARAM)&bErr);
  843. if (!bErr)
  844. hr = _AddConstraint(pSrchCmd, L"DateNMonths", &var);
  845. }
  846. else if (IsDlgButtonChecked(IDC_USE_RECENT_DAYS))
  847. {
  848. var.vt = VT_I4;
  849. var.ulVal = (ULONG)SendDlgItemMessage(IDC_RECENT_DAYS_SPIN, UDM_GETPOS32, 0, (LPARAM)&bErr);
  850. if (!bErr)
  851. hr = _AddConstraint(pSrchCmd, L"DateNDays", &var);
  852. }
  853. else if (IsDlgButtonChecked(IDC_USE_DATE_RANGE))
  854. {
  855. SYSTEMTIME stBegin, stEnd;
  856. var.vt = VT_DATE;
  857. LRESULT lRetBegin = SendDlgItemMessage(IDC_DATERANGE_BEGIN, DTM_GETSYSTEMTIME, 0, (LPARAM)&stBegin);
  858. LRESULT lRetEnd = SendDlgItemMessage(IDC_DATERANGE_END, DTM_GETSYSTEMTIME, 0, (LPARAM)&stEnd);
  859. if (GDT_VALID == lRetBegin && GDT_VALID == lRetEnd)
  860. {
  861. #ifdef DEBUG
  862. FILETIME ft;
  863. //validate that we were passed a correct date
  864. //SystemTimeToFileTime calls internal API IsValidSystemTime.
  865. //This will save us from OLE Automation bug# 322789
  866. // the only way we can get a date is through date/time picker
  867. // control which should validate the dates so just assert...
  868. ASSERT(SystemTimeToFileTime(&stBegin, &ft));
  869. #endif
  870. SystemTimeToVariantTime(&stBegin, &var.date);
  871. hr = _AddConstraint(pSrchCmd, L"DateGE", &var);
  872. #ifdef DEBUG
  873. ASSERT(SystemTimeToFileTime(&stEnd, &ft));
  874. #endif
  875. SystemTimeToVariantTime(&stEnd, &var.date);
  876. hr = _AddConstraint(pSrchCmd, L"DateLE", &var);
  877. }
  878. }
  879. return hr;
  880. }
  881. // S_FALSE: constraint restored to UI. S_OK: subdialog should be opened.
  882. // E_FAIL: constraint must be for some other subdlg.
  883. STDMETHODIMP CDateDlg::RestoreConstraint(const BSTR bstrName, const VARIANT* pValue)
  884. {
  885. HRESULT hr = E_FAIL;
  886. BOOL bUseMonths = FALSE,
  887. bUseDays = FALSE,
  888. bUseRange = FALSE;
  889. if (IsConstraintName(L"WhichDate", bstrName))
  890. {
  891. ASSERT(VT_I4 == pValue->vt)
  892. UINT nIDS = pValue->lVal == 1 ? IDS_FSEARCH_MODIFIED_DATE :
  893. pValue->lVal == 2 ? IDS_FSEARCH_CREATION_DATE :
  894. pValue->lVal == 3 ? IDS_FSEARCH_ACCESSED_DATE : 0;
  895. if (nIDS != 0)
  896. _SelectComboData(GetDlgItem(IDC_WHICH_DATE), nIDS);
  897. return nIDS == IDS_FSEARCH_MODIFIED_DATE /*default*/ ?
  898. S_FALSE /* don't open */: S_OK /* open */;
  899. }
  900. if (IsConstraintName(L"DateNMonths", bstrName))
  901. {
  902. ASSERT(VT_I4 == pValue->vt);
  903. bUseMonths = TRUE;
  904. _SetWindowValue(m_hWnd, IDC_RECENT_MONTHS, pValue);
  905. hr = S_OK;
  906. }
  907. else if (IsConstraintName(L"DateNDays", bstrName))
  908. {
  909. ASSERT(VT_I4 == pValue->vt);
  910. bUseDays = TRUE;
  911. _SetWindowValue(m_hWnd, IDC_RECENT_DAYS, pValue);
  912. hr = S_OK;
  913. }
  914. else if (IsConstraintName(L"DateGE", bstrName))
  915. {
  916. ASSERT(VT_DATE == pValue->vt);
  917. bUseRange = TRUE;
  918. SYSTEMTIME st;
  919. VariantTimeToSystemTime(pValue->date, &st);
  920. SendDlgItemMessage(IDC_DATERANGE_BEGIN, DTM_SETSYSTEMTIME, 0, (LPARAM)&st);
  921. hr = S_OK;
  922. }
  923. else if (IsConstraintName(L"DateLE", bstrName))
  924. {
  925. ASSERT(VT_DATE == pValue->vt);
  926. bUseRange = TRUE;
  927. SYSTEMTIME st;
  928. VariantTimeToSystemTime(pValue->date, &st);
  929. SendDlgItemMessage(IDC_DATERANGE_END, DTM_SETSYSTEMTIME, 0, (LPARAM)&st);
  930. hr = S_OK;
  931. }
  932. if (S_OK == hr)
  933. {
  934. CheckDlgButton(IDC_USE_RECENT_MONTHS, bUseMonths);
  935. CheckDlgButton(IDC_USE_RECENT_DAYS, bUseDays);
  936. CheckDlgButton(IDC_USE_DATE_RANGE, bUseRange);
  937. EnableControls();
  938. }
  939. return hr;
  940. }
  941. void CDateDlg::Clear()
  942. {
  943. SendDlgItemMessage(IDC_WHICH_DATE, CB_SETCURSEL, 0, 0);
  944. CheckDlgButton(IDC_USE_RECENT_MONTHS, 0);
  945. SetDlgItemInt(IDC_RECENT_MONTHS, 1, FALSE);
  946. CheckDlgButton(IDC_USE_RECENT_DAYS, 0);
  947. SetDlgItemInt(IDC_RECENT_DAYS, 1, FALSE);
  948. CheckDlgButton(IDC_USE_DATE_RANGE, 1);
  949. SYSTEMTIME stNow, stPrev;
  950. GetLocalTime(&stNow);
  951. SendDlgItemMessage(IDC_DATERANGE_END, DTM_SETSYSTEMTIME, 0, (LPARAM)&stNow);
  952. // Subtract 90 days from current date and stuff in date low range
  953. _CalcDateOffset(&stNow, 0, -1 /* 1 month ago */, &stPrev);
  954. SendDlgItemMessage(IDC_DATERANGE_BEGIN, DTM_SETSYSTEMTIME, 0, (LPARAM)&stPrev);
  955. EnableControls();
  956. }
  957. LRESULT CDateDlg::OnSize(UINT, WPARAM wParam, LPARAM lParam, BOOL&)
  958. {
  959. POINTS pts = MAKEPOINTS(lParam);
  960. _PaintDlg(m_hWnd, _pfsb->GetMetrics());
  961. ValidateRect(NULL);
  962. RECT rc;
  963. HWND hwndCtl = GetDlgItem(IDC_WHICH_DATE);
  964. ASSERT(hwndCtl);
  965. ::GetWindowRect(hwndCtl, &rc);
  966. ::MapWindowRect(NULL, m_hWnd, &rc);
  967. rc.right = pts.x - _pfsb->GetMetrics().CtlMarginX();
  968. ::SetWindowPos(GetDlgItem(IDC_WHICH_DATE), NULL, 0, 0,
  969. RECTWIDTH(rc), RECTHEIGHT(rc),
  970. SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
  971. return 0;
  972. }
  973. LRESULT CDateDlg::OnMonthDaySpin(int nIDSpin, NMHDR *pnmh, BOOL& bHandled)
  974. {
  975. LPNMUPDOWN pud = (LPNMUPDOWN)pnmh;
  976. pud->iDelta *= -1; // increments of 1 month/day
  977. return 0;
  978. }
  979. LRESULT CDateDlg::OnBtnClick(WORD nCode, WORD nID, HWND hwndCtl, BOOL&)
  980. {
  981. EnableControls();
  982. return 0;
  983. }
  984. LRESULT CDateDlg::OnMonthsKillFocus(WORD nCode, WORD nID, HWND hwndCtl, BOOL&)
  985. {
  986. _EnforceNumericEditRange(m_hWnd, IDC_RECENT_MONTHS, IDC_RECENT_MONTHS_SPIN,
  987. RECENTMONTHSRANGE_LOW, RECENTMONTHSRANGE_HIGH);
  988. return 0;
  989. }
  990. LRESULT CDateDlg::OnDaysKillFocus(WORD nCode, WORD nID, HWND hwndCtl, BOOL&)
  991. {
  992. _EnforceNumericEditRange(m_hWnd, IDC_RECENT_DAYS, IDC_RECENT_DAYS_SPIN,
  993. RECENTDAYSRANGE_LOW, RECENTDAYSRANGE_HIGH);
  994. return 0;
  995. }
  996. void CDateDlg::EnableControls()
  997. {
  998. UINT nSel = IsDlgButtonChecked(IDC_USE_RECENT_MONTHS) ? IDC_USE_RECENT_MONTHS :
  999. IsDlgButtonChecked(IDC_USE_RECENT_DAYS) ? IDC_USE_RECENT_DAYS :
  1000. IsDlgButtonChecked(IDC_USE_DATE_RANGE) ? IDC_USE_DATE_RANGE : 0;
  1001. ::EnableWindow(GetDlgItem(IDC_RECENT_MONTHS), IDC_USE_RECENT_MONTHS == nSel);
  1002. ::EnableWindow(GetDlgItem(IDC_RECENT_MONTHS_SPIN), IDC_USE_RECENT_MONTHS == nSel);
  1003. ::EnableWindow(GetDlgItem(IDC_RECENT_DAYS), IDC_USE_RECENT_DAYS == nSel);
  1004. ::EnableWindow(GetDlgItem(IDC_RECENT_DAYS_SPIN), IDC_USE_RECENT_DAYS == nSel);
  1005. ::EnableWindow(GetDlgItem(IDC_DATERANGE_BEGIN), IDC_USE_DATE_RANGE == nSel);
  1006. ::EnableWindow(GetDlgItem(IDC_DATERANGE_END), IDC_USE_DATE_RANGE == nSel);
  1007. }
  1008. // CSizeDlg impl
  1009. #define FILESIZERANGE_LOW 0
  1010. #define FILESIZERANGE_HIGH 99999999
  1011. #define FILESIZERANGE_HIGH_LEN 8 // count of digits in FILESIZERANGE_HIGH
  1012. LRESULT CSizeDlg::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  1013. {
  1014. _Attach(m_hWnd);
  1015. HWND hwndCombo = GetDlgItem(IDC_WHICH_SIZE);
  1016. SendDlgItemMessage(IDC_FILESIZE_SPIN, UDM_SETRANGE32,
  1017. FILESIZERANGE_HIGH, FILESIZERANGE_LOW /*Kb*/);
  1018. SendDlgItemMessage(IDC_FILESIZE, EM_LIMITTEXT, FILESIZERANGE_HIGH_LEN, 0);
  1019. _LoadStringToCombo(hwndCombo, -1,
  1020. IDS_FSEARCH_SIZE_GREATEREQUAL,
  1021. IDS_FSEARCH_SIZE_GREATEREQUAL);
  1022. _LoadStringToCombo(hwndCombo, -1,
  1023. IDS_FSEARCH_SIZE_LESSEREQUAL,
  1024. IDS_FSEARCH_SIZE_LESSEREQUAL);
  1025. Clear();
  1026. return TRUE; // Let the system set the focus
  1027. }
  1028. STDMETHODIMP CSizeDlg::AddConstraints(ISearchCommandExt* pSrchCmd)
  1029. {
  1030. VARIANT var;
  1031. BOOL bErr = FALSE;
  1032. HRESULT hr = S_FALSE;
  1033. UINT_PTR nIDString = _GetComboData(GetDlgItem(IDC_WHICH_SIZE));
  1034. var.vt = VT_UI4;
  1035. var.ulVal = (ULONG)SendDlgItemMessage(IDC_FILESIZE_SPIN, UDM_GETPOS32, 0, (LPARAM)&bErr);
  1036. if (!bErr)
  1037. {
  1038. var.ulVal *= 1024; // KB to bytes.
  1039. LPCWSTR pwszConstraint = (IDS_FSEARCH_SIZE_GREATEREQUAL == nIDString) ?
  1040. L"SizeGE" :
  1041. (IDS_FSEARCH_SIZE_LESSEREQUAL == nIDString) ?
  1042. L"SizeLE" : NULL;
  1043. if (pwszConstraint)
  1044. hr = _AddConstraint(pSrchCmd, pwszConstraint, &var);
  1045. }
  1046. return hr;
  1047. }
  1048. // S_FALSE: constraint restored to UI. S_OK: subdialog should be opened.
  1049. // E_FAIL: constraint must be for some other subdlg.
  1050. STDMETHODIMP CSizeDlg::RestoreConstraint(const BSTR bstrName, const VARIANT* pValue)
  1051. {
  1052. HRESULT hr = E_FAIL;
  1053. UINT nID = 0;
  1054. if (IsConstraintName(L"SizeGE", bstrName))
  1055. {
  1056. nID = IDS_FSEARCH_SIZE_GREATEREQUAL;
  1057. hr = S_OK;
  1058. }
  1059. else if (IsConstraintName(L"SizeLE", bstrName))
  1060. {
  1061. nID = IDS_FSEARCH_SIZE_LESSEREQUAL;
  1062. hr = S_OK;
  1063. }
  1064. if (S_OK == hr)
  1065. {
  1066. ASSERT(VT_UI4 == pValue->vt);
  1067. ULONG ulSize = pValue->ulVal/1024; // convert bytes to KB
  1068. SetDlgItemInt(IDC_FILESIZE, ulSize, FALSE);
  1069. ASSERT(nID != 0);
  1070. _SelectComboData(GetDlgItem(IDC_WHICH_SIZE), nID);
  1071. }
  1072. return hr;
  1073. }
  1074. void CSizeDlg::Clear()
  1075. {
  1076. SendDlgItemMessage(IDC_WHICH_SIZE, CB_SETCURSEL, 0, 0);
  1077. SetDlgItemInt(IDC_FILESIZE, 0, FALSE);
  1078. }
  1079. LRESULT CSizeDlg::OnSizeSpin(int nIDSpin, NMHDR *pnmh, BOOL& bHandled)
  1080. {
  1081. LPNMUPDOWN pud = (LPNMUPDOWN)pnmh;
  1082. pud->iDelta *= -10; // increments of 10KB
  1083. return 0;
  1084. }
  1085. LRESULT CSizeDlg::OnSizeKillFocus(WORD nCode, WORD nID, HWND hwndCtl, BOOL&)
  1086. {
  1087. _EnforceNumericEditRange(m_hWnd, IDC_FILESIZE, IDC_FILESIZE_SPIN,
  1088. FILESIZERANGE_LOW, FILESIZERANGE_HIGH);
  1089. return 0;
  1090. }
  1091. CTypeDlg::CTypeDlg(CFileSearchBand* pfsb) : CSubDlg(pfsb)
  1092. {
  1093. *_szRestoredExt = 0;
  1094. }
  1095. CTypeDlg::~CTypeDlg()
  1096. {
  1097. }
  1098. LRESULT CTypeDlg::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  1099. {
  1100. HWND hwndCombo = GetDlgItem(IDC_FILE_TYPE);
  1101. HIMAGELIST hil = GetSystemImageListSmallIcons();
  1102. _Attach(m_hWnd);
  1103. ::SendMessage(hwndCombo, CBEM_SETEXTENDEDSTYLE,
  1104. CBES_EX_NOSIZELIMIT | CBES_EX_CASESENSITIVE,
  1105. CBES_EX_NOSIZELIMIT | CBES_EX_CASESENSITIVE);
  1106. ::SendMessage(hwndCombo, CBEM_SETIMAGELIST, 0, (LPARAM)hil);
  1107. ::SendMessage(hwndCombo, CBEM_SETEXSTYLE, 0, 0);
  1108. return TRUE; // Let the system set the focus
  1109. }
  1110. STDMETHODIMP CTypeDlg::AddConstraints(ISearchCommandExt* pSrchCmd)
  1111. {
  1112. LPTSTR pszText;
  1113. HRESULT hr = S_FALSE;
  1114. if (GetFileAssocComboSelItemText(GetDlgItem(IDC_FILE_TYPE), &pszText) >= 0 && pszText)
  1115. {
  1116. VARIANT var = {0};
  1117. if (*pszText &&
  1118. SUCCEEDED(InitVariantFromStr(&var, pszText)) &&
  1119. SUCCEEDED(_AddConstraint(pSrchCmd, L"FileType", &var)))
  1120. {
  1121. hr = S_OK;
  1122. }
  1123. VariantClear(&var);
  1124. LocalFree((HLOCAL)pszText);
  1125. }
  1126. return hr;
  1127. }
  1128. // S_FALSE: constraint restored to UI. S_OK: subdialog should be opened.
  1129. // E_FAIL: constraint must be for some other subdlg.
  1130. STDMETHODIMP CTypeDlg::RestoreConstraint(const BSTR bstrName, const VARIANT* pValue)
  1131. {
  1132. if (IsConstraintName(L"FileType", bstrName))
  1133. {
  1134. ASSERT(VT_BSTR == pValue->vt);
  1135. USES_CONVERSION;
  1136. lstrcpyn(_szRestoredExt, W2T(pValue->bstrVal), ARRAYSIZE(_szRestoredExt));
  1137. INT_PTR i = _FindExtension(GetDlgItem(IDC_FILE_TYPE), _szRestoredExt);
  1138. if (i != CB_ERR)
  1139. {
  1140. SendDlgItemMessage(IDC_FILE_TYPE, CB_SETCURSEL, i, 0);
  1141. *_szRestoredExt = 0;
  1142. }
  1143. return S_OK;
  1144. }
  1145. return E_FAIL;
  1146. }
  1147. INT_PTR CTypeDlg::_FindExtension(HWND hwndCombo, TCHAR* pszExt)
  1148. {
  1149. INT_PTR i, cnt = ::SendMessage(hwndCombo, CB_GETCOUNT, 0, 0);
  1150. LPTSTR pszData;
  1151. BOOL bAllFileTypes = pszExt && (lstrcmp(TEXT("*.*"), pszExt) == 0);
  1152. TCHAR szExt[MAX_PATH];
  1153. if (!bAllFileTypes)
  1154. {
  1155. // Remove wildcard characters.
  1156. LPTSTR pszSrc = pszExt, pszDest = szExt;
  1157. for (;; pszSrc = CharNext(pszSrc))
  1158. {
  1159. if (TEXT('*') == *pszSrc)
  1160. pszSrc = CharNext(pszSrc);
  1161. if ((*(pszDest++) = *pszSrc) == 0)
  1162. break;
  1163. }
  1164. pszExt = szExt;
  1165. }
  1166. if (pszExt && (bAllFileTypes || *pszExt))
  1167. {
  1168. for (i = 0; i < cnt; i++)
  1169. {
  1170. pszData = (LPTSTR)::SendMessage(hwndCombo, CB_GETITEMDATA, i, 0);
  1171. if (bAllFileTypes && (FILEASSOCIATIONSID_ALLFILETYPES == (UINT_PTR)pszData))
  1172. return i;
  1173. if (pszData != (LPTSTR)FILEASSOCIATIONSID_ALLFILETYPES &&
  1174. pszData != (LPTSTR)CB_ERR &&
  1175. pszData != NULL)
  1176. {
  1177. if (0 == StrCmpI(pszExt, pszData))
  1178. return i;
  1179. }
  1180. }
  1181. }
  1182. return CB_ERR;
  1183. }
  1184. void CTypeDlg::Clear()
  1185. {
  1186. // Assign combo selection to 'all file types':
  1187. HWND hwndCombo = GetDlgItem(IDC_FILE_TYPE);
  1188. for (INT_PTR i = 0, cnt = ::SendMessage(hwndCombo, CB_GETCOUNT, 0, 0); i < cnt; i++)
  1189. {
  1190. if (FILEASSOCIATIONSID_ALLFILETYPES == _GetComboData(hwndCombo, i))
  1191. {
  1192. ::SendMessage(hwndCombo, CB_SETCURSEL, i, 0);
  1193. break;
  1194. }
  1195. }
  1196. _szRestoredExt[0] = 0;
  1197. }
  1198. LRESULT CTypeDlg::OnFileTypeDeleteItem(int idCtrl, NMHDR *pnmh, BOOL& bHandled)
  1199. {
  1200. return DeleteFileAssocComboItem(pnmh);
  1201. }
  1202. LRESULT CTypeDlg::OnSize(UINT, WPARAM wParam, LPARAM lParam, BOOL&)
  1203. {
  1204. POINTS pts = MAKEPOINTS(lParam);
  1205. _PaintDlg(m_hWnd, _pfsb->GetMetrics());
  1206. ValidateRect(NULL);
  1207. RECT rc;
  1208. HWND hwndCtl = GetDlgItem(IDC_FILE_TYPE);
  1209. ASSERT(hwndCtl);
  1210. ::GetWindowRect(hwndCtl, &rc);
  1211. ::MapWindowRect(NULL, m_hWnd, &rc);
  1212. rc.right = pts.x - _pfsb->GetMetrics().CtlMarginX();
  1213. ::SetWindowPos(hwndCtl, NULL, 0, 0,
  1214. RECTWIDTH(rc), RECTHEIGHT(rc),
  1215. SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
  1216. return 0;
  1217. }
  1218. DWORD CTypeDlg::FileAssocThreadProc(void* pv)
  1219. {
  1220. FSEARCHTHREADSTATE *pState = (FSEARCHTHREADSTATE *)pv;
  1221. CTypeDlg* pThis = (CTypeDlg*)pState->pvParam;
  1222. if (PopulateFileAssocCombo(pState->hwndCtl, AddItemNotify, (LPARAM)pv) != E_ABORT)
  1223. {
  1224. ::PostMessage(::GetParent(pState->hwndCtl), WMU_COMBOPOPULATIONCOMPLETE, (WPARAM)pState->hwndCtl, 0);
  1225. }
  1226. pState->fComplete = TRUE;
  1227. ATOMICRELEASE(pState->punkBand);
  1228. return 0;
  1229. }
  1230. HRESULT CTypeDlg::AddItemNotify(ULONG fAction, PCBXITEM pItem, LPARAM lParam)
  1231. {
  1232. FSEARCHTHREADSTATE *pState = (FSEARCHTHREADSTATE *)lParam;
  1233. ASSERT(pState);
  1234. ASSERT(pState->hwndCtl);
  1235. // Do we want to abort combo population thread?
  1236. if (fAction & CBXCB_ADDING && pState->fCancel)
  1237. return E_ABORT;
  1238. // Set the current selection to 'all file types'
  1239. if (fAction & CBXCB_ADDED)
  1240. {
  1241. BOOL bAllTypesItem = (FILEASSOCIATIONSID_ALLFILETYPES == pItem->lParam);
  1242. CTypeDlg* pThis = (CTypeDlg*)pState->pvParam;
  1243. ASSERT(pThis);
  1244. // If this item is the one restored from a saved query
  1245. // override any current selection and select it.
  1246. if (*pThis->_szRestoredExt && !bAllTypesItem && pItem->lParam &&
  1247. 0 == lstrcmpi((LPCTSTR)pItem->lParam, pThis->_szRestoredExt))
  1248. {
  1249. ::SendMessage(pState->hwndCtl, CB_SETCURSEL, pItem->iItem, 0);
  1250. *pThis->_szRestoredExt = 0;
  1251. }
  1252. // If this item is the default ('all file types') and
  1253. // nothing else is selected, select it.
  1254. else if (bAllTypesItem)
  1255. {
  1256. if (CB_ERR == ::SendMessage(pState->hwndCtl, CB_GETCURSEL, 0, 0))
  1257. ::SendMessage(pState->hwndCtl, CB_SETCURSEL, pItem->iItem, 0);
  1258. }
  1259. }
  1260. return S_OK;
  1261. }
  1262. LRESULT CTypeDlg::OnComboPopulationComplete(UINT, WPARAM, LPARAM, BOOL&)
  1263. {
  1264. // remove briefcase from type combo because briefcases no longer use this
  1265. // extension (now they store clsid in desktop.ini
  1266. INT_PTR iBfc = _FindExtension(GetDlgItem(IDC_FILE_TYPE), TEXT(".bfc"));
  1267. if (iBfc != CB_ERR)
  1268. {
  1269. SendDlgItemMessage(IDC_FILE_TYPE, CB_DELETESTRING, (WPARAM)iBfc, 0);
  1270. }
  1271. if (*_szRestoredExt)
  1272. {
  1273. INT_PTR iSel = _FindExtension(GetDlgItem(IDC_FILE_TYPE), _szRestoredExt);
  1274. if (iSel != CB_ERR)
  1275. {
  1276. SendDlgItemMessage(IDC_FILE_TYPE, CB_SETCURSEL, (WPARAM)iSel, 0);
  1277. *_szRestoredExt = 0;
  1278. }
  1279. }
  1280. return 0;
  1281. }
  1282. // Called when we are finished doing all the work to display the search band.
  1283. // We then launch the thread to populate the file type drop down. By delaying this
  1284. // until now, we can speed up the band loading.
  1285. // No return becuase it's called async.
  1286. void CTypeDlg::DoDelayedInit()
  1287. {
  1288. // Launch thread to populate the file types combo.
  1289. _threadState.hwndCtl = GetDlgItem(IDC_FILE_TYPE);
  1290. _threadState.pvParam = this;
  1291. _threadState.fComplete = FALSE;
  1292. _threadState.fCancel = FALSE;
  1293. if (SUCCEEDED(SAFECAST(_pfsb, IFileSearchBand*)->QueryInterface(IID_PPV_ARG(IUnknown, &_threadState.punkBand))))
  1294. {
  1295. if (!SHCreateThread(FileAssocThreadProc, &_threadState, CTF_COINIT, NULL))
  1296. {
  1297. ATOMICRELEASE(_threadState.punkBand);
  1298. }
  1299. }
  1300. }
  1301. LRESULT CTypeDlg::OnDestroy(UINT, WPARAM, LPARAM, BOOL& bHandled)
  1302. {
  1303. _threadState.fCancel = TRUE;
  1304. bHandled = FALSE;
  1305. return 0;
  1306. }
  1307. void CTypeDlg::OnWinIniChange()
  1308. {
  1309. SendDlgItemMessage(IDC_FILE_TYPE, CB_SETDROPPEDWIDTH,
  1310. _PixelsForDbu(m_hWnd, MIN_FILEASSOCLIST_WIDTH, TRUE), 0);
  1311. }
  1312. LRESULT CAdvancedDlg::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  1313. {
  1314. _Attach(m_hWnd);
  1315. Clear();
  1316. return TRUE; // Let the system set the focus
  1317. }
  1318. HRESULT AddButtonConstraintPersist(ISearchCommandExt* pSrchCmd, LPCWSTR pszConstraint, HWND hwndButton)
  1319. {
  1320. BOOL bValue = SendMessage(hwndButton, BM_GETCHECK, 0, 0) == BST_CHECKED;
  1321. SHRegSetUSValue(TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"), pszConstraint,
  1322. REG_DWORD, &bValue, sizeof(bValue), SHREGSET_HKCU | SHREGSET_FORCE_HKCU);
  1323. VARIANT var = {0};
  1324. var.vt = VT_BOOL;
  1325. var.boolVal = bValue ? VARIANT_TRUE : 0;
  1326. return _AddConstraint(pSrchCmd, pszConstraint, &var);
  1327. }
  1328. STDMETHODIMP CAdvancedDlg::AddConstraints(ISearchCommandExt* pSrchCmd)
  1329. {
  1330. AddButtonConstraintPersist(pSrchCmd, L"SearchSystemDirs", GetDlgItem(IDC_USE_SYSTEMDIRS));
  1331. AddButtonConstraintPersist(pSrchCmd, L"SearchHidden", GetDlgItem(IDC_SEARCH_HIDDEN));
  1332. AddButtonConstraintPersist(pSrchCmd, L"IncludeSubFolders", GetDlgItem(IDC_USE_SUBFOLDERS));
  1333. AddButtonConstraintPersist(pSrchCmd, L"CaseSensitive", GetDlgItem(IDC_USE_CASE));
  1334. AddButtonConstraintPersist(pSrchCmd, L"SearchSlowFiles", GetDlgItem(IDC_USE_SLOW_FILES));
  1335. return S_OK;
  1336. }
  1337. // S_FALSE: constraint restored to UI. S_OK: subdialog should be opened.
  1338. // E_FAIL: constraint must be for some other subdlg.
  1339. STDMETHODIMP CAdvancedDlg::RestoreConstraint(const BSTR bstrName, const VARIANT* pValue)
  1340. {
  1341. if (IsConstraintName(L"IncludeSubFolders", bstrName))
  1342. {
  1343. ASSERT(VT_BOOL == pValue->vt || VT_I4 == pValue->vt);
  1344. CheckDlgButton(IDC_USE_SUBFOLDERS, pValue->lVal);
  1345. return S_FALSE; // this is a default. don't force open the subdialog.
  1346. }
  1347. if (IsConstraintName(L"CaseSensitive", bstrName))
  1348. {
  1349. ASSERT(VT_BOOL == pValue->vt || VT_I4 == pValue->vt);
  1350. CheckDlgButton(IDC_USE_CASE, pValue->lVal);
  1351. return pValue->lVal ? S_OK : S_FALSE;
  1352. }
  1353. if (IsConstraintName(L"SearchSlowFiles", bstrName))
  1354. {
  1355. ASSERT(VT_BOOL == pValue->vt || VT_I4 == pValue->vt);
  1356. CheckDlgButton(IDC_USE_SLOW_FILES, pValue->lVal);
  1357. return pValue->lVal ? S_OK : S_FALSE;
  1358. }
  1359. if (IsConstraintName(L"SearchSystemDirs", bstrName))
  1360. {
  1361. ASSERT(VT_BOOL == pValue->vt || VT_I4 == pValue->vt || VT_UI4 == pValue->vt);
  1362. CheckDlgButton(IDC_USE_SYSTEMDIRS, pValue->lVal);
  1363. return pValue->lVal ? S_OK : S_FALSE;
  1364. }
  1365. if (IsConstraintName(L"SearchHidden", bstrName))
  1366. {
  1367. ASSERT(VT_BOOL == pValue->vt || VT_I4 == pValue->vt || VT_UI4 == pValue->vt);
  1368. CheckDlgButton(IDC_SEARCH_HIDDEN, pValue->lVal);
  1369. return pValue->lVal ? S_OK : S_FALSE;
  1370. }
  1371. return E_FAIL;
  1372. }
  1373. void CheckDlgButtonPersist(HWND hdlg, UINT id, LPCTSTR pszOption, BOOL bDefault)
  1374. {
  1375. BOOL bValue = SHRegGetBoolUSValue(TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"), pszOption, FALSE, bDefault);
  1376. CheckDlgButton(hdlg, id, bValue);
  1377. }
  1378. void CAdvancedDlg::Clear()
  1379. {
  1380. CheckDlgButtonPersist(m_hWnd, IDC_USE_SYSTEMDIRS, L"SearchSystemDirs", IsOS(OS_ANYSERVER));
  1381. CheckDlgButtonPersist(m_hWnd, IDC_SEARCH_HIDDEN, L"SearchHidden", FALSE);
  1382. CheckDlgButtonPersist(m_hWnd, IDC_USE_SUBFOLDERS, L"IncludeSubFolders", TRUE);
  1383. CheckDlgButtonPersist(m_hWnd, IDC_USE_CASE, L"CaseSensitive", FALSE);
  1384. CheckDlgButtonPersist(m_hWnd, IDC_USE_SLOW_FILES, L"SearchSlowFiles", FALSE);
  1385. }
  1386. COptionsDlg::COptionsDlg(CFileSearchBand* pfsb)
  1387. : CSubDlg(pfsb),
  1388. _dlgDate(pfsb),
  1389. _dlgSize(pfsb),
  1390. _dlgType(pfsb),
  1391. _dlgAdvanced(pfsb)
  1392. {
  1393. // Verify that it initialized to 0's
  1394. ASSERT(0 == _nCIStatusText);
  1395. ZeroMemory(_subdlgs, sizeof(_subdlgs));
  1396. #define SUBDLG_ENTRY(idx, idCheck, dlg) \
  1397. { _subdlgs[idx].nIDCheck = idCheck; _subdlgs[idx].pDlg = &dlg; }
  1398. SUBDLG_ENTRY(SUBDLG_DATE, IDC_USE_DATE, _dlgDate);
  1399. SUBDLG_ENTRY(SUBDLG_TYPE, IDC_USE_TYPE, _dlgType);
  1400. SUBDLG_ENTRY(SUBDLG_SIZE, IDC_USE_SIZE, _dlgSize);
  1401. SUBDLG_ENTRY(SUBDLG_ADVANCED, IDC_USE_ADVANCED, _dlgAdvanced);
  1402. }
  1403. LRESULT COptionsDlg::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&)
  1404. {
  1405. _Attach(m_hWnd);
  1406. _dlgDate.SetBandDlg(_pBandDlg);
  1407. _dlgSize.SetBandDlg(_pBandDlg);
  1408. _dlgType.SetBandDlg(_pBandDlg);
  1409. _dlgAdvanced.SetBandDlg(_pBandDlg);
  1410. // Gather some metrics from the fresh dialog template...
  1411. CMetrics& metrics = _pfsb->GetMetrics();
  1412. RECT rc[3] = {0};
  1413. ASSERT(::IsWindow(GetDlgItem(IDC_USE_DATE)));
  1414. ASSERT(::IsWindow(GetDlgItem(IDC_USE_TYPE)));
  1415. ASSERT(::IsWindow(GetDlgItem(IDC_USE_ADVANCED)));
  1416. ::GetWindowRect(GetDlgItem(IDC_USE_DATE), rc + 0);
  1417. ::GetWindowRect(GetDlgItem(IDC_USE_TYPE), rc + 1);
  1418. ::GetWindowRect(GetDlgItem(IDC_USE_ADVANCED), rc + 2);
  1419. for (int i = 0; i < ARRAYSIZE(rc); i++)
  1420. {
  1421. // MapWindowPoints is mirroring aware only if you pass two points
  1422. ::MapWindowRect(NULL, m_hWnd, &rc[i]);
  1423. }
  1424. metrics.ExpandOrigin().y = rc[0].top;
  1425. metrics.CheckBoxRect() = rc[2];
  1426. OffsetRect(&metrics.CheckBoxRect(), -rc[0].left, -rc[0].top);
  1427. // Create subdialogs and collect native sizes.
  1428. if (_dlgDate.Create(m_hWnd))
  1429. _GetWindowSize(_dlgDate, &_subdlgs[SUBDLG_DATE].sizeDlg);
  1430. if (_dlgSize.Create(m_hWnd))
  1431. _GetWindowSize(_dlgSize, &_subdlgs[SUBDLG_SIZE].sizeDlg);
  1432. if (_dlgType.Create(m_hWnd))
  1433. _GetWindowSize(_dlgType, &_subdlgs[SUBDLG_TYPE].sizeDlg);
  1434. if (_dlgAdvanced.Create(m_hWnd))
  1435. _GetWindowSize(_dlgAdvanced, &_subdlgs[SUBDLG_ADVANCED].sizeDlg);
  1436. // Create index server link window
  1437. POINT pt = {0};
  1438. HWND hwndCI = _CreateLinkWindow(m_hWnd, IDC_INDEX_SERVER,
  1439. pt, IDS_FSEARCH_CI_DISABLED_LINK);
  1440. UpdateSearchCmdStateUI();
  1441. // Layout controls
  1442. LayoutControls();
  1443. return TRUE;
  1444. }
  1445. void COptionsDlg::OnWinIniChange()
  1446. {
  1447. CSubDlg::OnWinIniChange();
  1448. for (int i = 0; i < ARRAYSIZE(_subdlgs); i++)
  1449. _subdlgs[i].pDlg->OnWinIniChange();
  1450. }
  1451. BOOL _SaveCheck(HWND hwnd, UINT nIDCheck, HKEY hkey, LPCTSTR pszValue)
  1452. {
  1453. DWORD dwData = IsDlgButtonChecked(hwnd, nIDCheck);
  1454. return ERROR_SUCCESS == RegSetValueEx(hkey, pszValue, 0, REG_DWORD, (LPBYTE)&dwData, sizeof(dwData));
  1455. }
  1456. BOOL _LoadCheck(HWND hwnd, UINT nIDCheck, HKEY hkey, LPCTSTR pszValue)
  1457. {
  1458. DWORD dwData = IsDlgButtonChecked(hwnd, nIDCheck);
  1459. DWORD cbData = sizeof(dwData);
  1460. if (ERROR_SUCCESS == RegQueryValueEx(hkey, pszValue, 0, NULL, (LPBYTE)&dwData, &cbData))
  1461. {
  1462. CheckDlgButton(hwnd, nIDCheck, dwData);
  1463. return TRUE;
  1464. }
  1465. return FALSE;
  1466. }
  1467. void COptionsDlg::LoadSaveUIState(UINT nIDCtl, BOOL bSave)
  1468. {
  1469. }
  1470. LRESULT COptionsDlg::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&)
  1471. {
  1472. POINTS pts = MAKEPOINTS(lParam);
  1473. _PaintDlg(m_hWnd, _pfsb->GetMetrics());
  1474. LayoutControls(pts.x, pts.y);
  1475. return 0;
  1476. }
  1477. void COptionsDlg::LayoutControls(int cx, int cy)
  1478. {
  1479. if (cx < 0 || cy < 0)
  1480. {
  1481. RECT rc;
  1482. GetClientRect(&rc);
  1483. cx = RECTWIDTH(rc);
  1484. cy = RECTHEIGHT(rc);
  1485. }
  1486. HDWP hdwp = BeginDeferWindowPos(1 + (ARRAYSIZE(_subdlgs) * 2));
  1487. if (hdwp)
  1488. {
  1489. CMetrics& metrics = _pfsb->GetMetrics();
  1490. POINT ptOrigin = metrics.ExpandOrigin();
  1491. // For each checkbox and associated subdialog...
  1492. for (int i = 0; i < ARRAYSIZE(_subdlgs); i++)
  1493. {
  1494. // Calculate checkbox position
  1495. HWND hwndCheck = GetDlgItem(_subdlgs[i].nIDCheck);
  1496. ASSERT(hwndCheck);
  1497. SetRect(&_subdlgs[i].rcCheck,
  1498. ptOrigin.x, ptOrigin.y,
  1499. ptOrigin.x + RECTWIDTH(metrics.CheckBoxRect()),
  1500. ptOrigin.y + RECTHEIGHT(metrics.CheckBoxRect()));
  1501. // Calculate subdialog position
  1502. ULONG dwDlgFlags = SWP_NOACTIVATE;
  1503. if (IsDlgButtonChecked(_subdlgs[i].nIDCheck))
  1504. {
  1505. // position the checkbox's dialog immediately below.
  1506. SetRect(&_subdlgs[i].rcDlg,
  1507. _subdlgs[i].rcCheck.left, _subdlgs[i].rcCheck.bottom,
  1508. cx - 1, _subdlgs[i].rcCheck.bottom + _subdlgs[i].sizeDlg.cy);
  1509. dwDlgFlags |= SWP_SHOWWINDOW;
  1510. ptOrigin.y = _subdlgs[i].rcDlg.bottom + metrics.TightMarginY();
  1511. }
  1512. else
  1513. {
  1514. ptOrigin.y = _subdlgs[i].rcCheck.bottom + metrics.TightMarginY();
  1515. dwDlgFlags |= SWP_HIDEWINDOW;
  1516. }
  1517. // Reposition the pair
  1518. ::DeferWindowPos(hdwp, _subdlgs[i].pDlg->Hwnd(), hwndCheck,
  1519. _subdlgs[i].rcDlg.left,
  1520. _subdlgs[i].rcDlg.top,
  1521. RECTWIDTH(_subdlgs[i].rcDlg),
  1522. RECTHEIGHT(_subdlgs[i].rcDlg),
  1523. dwDlgFlags);
  1524. ::DeferWindowPos(hdwp, hwndCheck, NULL,
  1525. _subdlgs[i].rcCheck.left,
  1526. _subdlgs[i].rcCheck.top,
  1527. RECTWIDTH(_subdlgs[i].rcCheck),
  1528. RECTHEIGHT(_subdlgs[i].rcCheck),
  1529. SWP_NOZORDER|SWP_NOACTIVATE);
  1530. }
  1531. _LayoutLinkWindow(m_hWnd, metrics.CtlMarginX(), cx - metrics.CtlMarginX(), metrics.TightMarginY(),
  1532. ptOrigin.y, IDC_INDEX_SERVER);
  1533. EndDeferWindowPos(hdwp);
  1534. }
  1535. }
  1536. // Assigns focus to the options dialog. This cannot be done by
  1537. // simply setting focus to the options dialog, which is a child
  1538. // of another dialog; USER will simply assign focus to the parent dialog.
  1539. // So we need to explicitly set focus to our first child.
  1540. void COptionsDlg::TakeFocus()
  1541. {
  1542. for (HWND hwndCtl = GetWindow(GW_CHILD);
  1543. ::IsWindow(hwndCtl);
  1544. hwndCtl = ::GetWindow(hwndCtl, GW_HWNDNEXT))
  1545. {
  1546. ULONG dwStyle = ::GetWindowLong(hwndCtl, GWL_STYLE);
  1547. if (dwStyle & WS_TABSTOP)
  1548. {
  1549. ::SetFocus(hwndCtl);
  1550. break;
  1551. }
  1552. }
  1553. }
  1554. // Note that we do not care about returning results from this, as it will
  1555. // be started asynchronously.
  1556. void COptionsDlg::DoDelayedInit()
  1557. {
  1558. // have subdialogs do delayed initialization
  1559. for (int i = 0; i < ARRAYSIZE(_subdlgs); i++)
  1560. {
  1561. _subdlgs[i].pDlg->DoDelayedInit();
  1562. }
  1563. }
  1564. LONG COptionsDlg::QueryHeight(LONG cx /* proposed width */, LONG cy /* proposed height */)
  1565. {
  1566. HWND hwndBottommost = GetBottomItem();
  1567. RECT rcThis, rcBottommost;
  1568. // Retrieve the current height of the bottommost link window.
  1569. GetWindowRect(&rcThis);
  1570. ::GetWindowRect(hwndBottommost, &rcBottommost);
  1571. ::MapWindowRect(NULL, GetParent(), &rcThis);
  1572. ::MapWindowRect(NULL, GetParent(), &rcBottommost);
  1573. // If, at the specified width, we compute a height for the bottommost
  1574. // linkwindow that is different from its current height (e.g, due to word wrap),
  1575. // we'll compute a new window rect that will
  1576. LONG cyBottommost = (LONG)::SendMessage(hwndBottommost, LWM_GETIDEALHEIGHT,
  1577. cx - (_pfsb->GetMetrics().CtlMarginX() * 2), 0);
  1578. if (cyBottommost > 0 && cyBottommost != RECTHEIGHT(rcBottommost))
  1579. rcThis.bottom = rcBottommost.top + cyBottommost + _pfsb->GetMetrics().TightMarginY();
  1580. return RECTHEIGHT(rcThis);
  1581. }
  1582. BOOL COptionsDlg::GetMinSize(SIZE *pSize)
  1583. {
  1584. pSize->cx = pSize->cy = 0;
  1585. HWND hwndBottom = GetBottomItem();
  1586. if (!::IsWindow(hwndBottom))
  1587. return FALSE;
  1588. RECT rcBottom;
  1589. ::GetWindowRect(hwndBottom, &rcBottom);
  1590. ::MapWindowRect(NULL, m_hWnd, &rcBottom);
  1591. pSize->cx = 0;
  1592. pSize->cy = rcBottom.bottom;
  1593. return TRUE;
  1594. }
  1595. HWND COptionsDlg::GetBottomItem()
  1596. {
  1597. HWND hwndBottom = GetDlgItem(IDC_INDEX_SERVER);
  1598. ASSERT(::IsWindow(hwndBottom))
  1599. return hwndBottom;
  1600. }
  1601. void COptionsDlg::UpdateSearchCmdStateUI(DISPID dispid)
  1602. {
  1603. UINT nStatusText;
  1604. BOOL fCiRunning, fCiIndexed, fCiPermission;
  1605. GetCIStatus(&fCiRunning, &fCiIndexed, &fCiPermission);
  1606. if (fCiRunning)
  1607. {
  1608. if (fCiPermission)
  1609. // we have permission to distinguish between ready and busy
  1610. nStatusText = fCiIndexed ? IDS_FSEARCH_CI_READY_LINK : IDS_FSEARCH_CI_BUSY_LINK;
  1611. else
  1612. // no permission to distinguish between ready and busy; we'll
  1613. // just say it's enabled.
  1614. nStatusText = IDS_FSEARCH_CI_ENABLED_LINK;
  1615. }
  1616. else
  1617. {
  1618. nStatusText = IDS_FSEARCH_CI_DISABLED_LINK;
  1619. }
  1620. TCHAR szCaption[MAX_PATH];
  1621. if (nStatusText != _nCIStatusText &&
  1622. EVAL(LoadString(HINST_THISDLL, nStatusText, szCaption, ARRAYSIZE(szCaption))))
  1623. {
  1624. SetDlgItemText(IDC_INDEX_SERVER, szCaption);
  1625. _nCIStatusText = nStatusText;
  1626. LayoutControls();
  1627. SizeToFit(FALSE);
  1628. }
  1629. }
  1630. STDMETHODIMP COptionsDlg::AddConstraints(ISearchCommandExt* pSrchCmd)
  1631. {
  1632. HRESULT hrRet = S_OK;
  1633. // have subdialogs add their constraints
  1634. for (int i = 0; i < ARRAYSIZE(_subdlgs); i++)
  1635. {
  1636. if (::IsWindowVisible(_subdlgs[i].pDlg->Hwnd()))
  1637. {
  1638. HRESULT hr = _subdlgs[i].pDlg->AddConstraints(pSrchCmd);
  1639. if (FAILED(hr))
  1640. hrRet = hr;
  1641. }
  1642. }
  1643. return hrRet;
  1644. }
  1645. STDMETHODIMP COptionsDlg::RestoreConstraint(const BSTR bstrName, const VARIANT* pValue)
  1646. {
  1647. // Try subordinate dialogs.
  1648. for (int i = 0; i < ARRAYSIZE(_subdlgs); i++)
  1649. {
  1650. HRESULT hr = _subdlgs[i].pDlg->RestoreConstraint(bstrName, pValue);
  1651. if (S_OK == hr) // open the dialog
  1652. {
  1653. CheckDlgButton(_subdlgs[i].nIDCheck, TRUE);
  1654. LayoutControls();
  1655. SizeToFit();
  1656. }
  1657. // if success, we're done.
  1658. if (SUCCEEDED(hr))
  1659. return hr;
  1660. // otherwise, try next subdialog.
  1661. }
  1662. return E_FAIL;
  1663. }
  1664. STDMETHODIMP COptionsDlg::TranslateAccelerator(MSG *pmsg)
  1665. {
  1666. if (S_OK == CSubDlg::TranslateAccelerator(pmsg))
  1667. return S_OK;
  1668. // Query subdialogs
  1669. if (_dlgDate.IsChild(pmsg->hwnd) &&
  1670. S_OK == _dlgDate.TranslateAccelerator(pmsg))
  1671. return S_OK;
  1672. if (_dlgType.IsChild(pmsg->hwnd) &&
  1673. S_OK == _dlgType.TranslateAccelerator(pmsg))
  1674. return S_OK;
  1675. if (_dlgSize.IsChild(pmsg->hwnd) &&
  1676. S_OK == _dlgSize.TranslateAccelerator(pmsg))
  1677. return S_OK;
  1678. if (_dlgAdvanced.IsChild(pmsg->hwnd) &&
  1679. S_OK == _dlgAdvanced.TranslateAccelerator(pmsg))
  1680. return S_OK;
  1681. return _pfsb->IsDlgMessage(Hwnd(), pmsg);
  1682. }
  1683. BOOL COptionsDlg::Validate()
  1684. {
  1685. // have subdialogs do validatation
  1686. for (int i = 0; i < ARRAYSIZE(_subdlgs); i++)
  1687. {
  1688. if (::IsWindowVisible(_subdlgs[i].pDlg->Hwnd()))
  1689. if (!_subdlgs[i].pDlg->Validate())
  1690. return FALSE;
  1691. }
  1692. return TRUE;
  1693. }
  1694. void COptionsDlg::Clear()
  1695. {
  1696. // have subdialogs clear themselves.
  1697. for (int i = 0; i < ARRAYSIZE(_subdlgs); i++)
  1698. {
  1699. _subdlgs[i].pDlg->Clear();
  1700. CheckDlgButton(_subdlgs[i].nIDCheck, FALSE);
  1701. }
  1702. LayoutControls();
  1703. SizeToFit();
  1704. }
  1705. LRESULT COptionsDlg::OnBtnClick(WORD nCode, WORD nID, HWND hwndCtl, BOOL&)
  1706. {
  1707. #ifdef DEBUG
  1708. // Is this a sub-dialog expansion/contraction?
  1709. BOOL bIsSubDlgBtn = FALSE;
  1710. for (int i = 0; i < ARRAYSIZE(_subdlgs) && !bIsSubDlgBtn; i++)
  1711. {
  1712. if (nID == _subdlgs[i].nIDCheck)
  1713. bIsSubDlgBtn = TRUE;
  1714. }
  1715. ASSERT(bIsSubDlgBtn);
  1716. #endif DEBUG
  1717. LoadSaveUIState(nID, TRUE); // persist it.
  1718. LayoutControls();
  1719. SizeToFit(!IsDlgButtonChecked(nID));
  1720. // don't need to scroll the band if we've expanded a subdialog,
  1721. // but we do if we've contracted one.
  1722. return 0;
  1723. }
  1724. void COptionsDlg::SizeToFit(BOOL bScrollBand)
  1725. {
  1726. SIZE size;
  1727. GetMinSize(&size);
  1728. size.cy += _pfsb->GetMetrics().TightMarginY();
  1729. SetWindowPos(NULL, 0, 0, size.cx, size.cy, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE);
  1730. ULONG dwLayoutFlags = BLF_ALL;
  1731. if (!bScrollBand)
  1732. dwLayoutFlags &= ~BLF_SCROLLWINDOW;
  1733. ::SendMessage(GetParent(), WMU_UPDATELAYOUT, dwLayoutFlags, 0);
  1734. }
  1735. LRESULT COptionsDlg::OnIndexServerClick(int idCtl, NMHDR *pnmh, BOOL&)
  1736. {
  1737. BOOL fCiRunning, fCiIndexed, fCiPermission = FALSE;
  1738. HRESULT hr = GetCIStatus(&fCiRunning, &fCiIndexed, &fCiPermission);
  1739. if (SUCCEEDED(hr) && fCiPermission)
  1740. {
  1741. // CI is idle or not runnning. Show status dialog.
  1742. if (IDOK == CCISettingsDlg_DoModal(GetDlgItem(IDC_INDEX_SERVER)))
  1743. {
  1744. // reflect any state change in UI.
  1745. ::PostMessage(GetParent(), WMU_STATECHANGE, 0, 0);
  1746. }
  1747. }
  1748. else
  1749. {
  1750. // No permission? display CI help.
  1751. _IndexServiceHelp(NULL);
  1752. }
  1753. return 0;
  1754. }
  1755. // CBandDlg impl
  1756. CBandDlg::CBandDlg(CFileSearchBand* pfsb)
  1757. : _pfsb(pfsb)
  1758. {
  1759. // Verify that it initialized to FALSE/NULL
  1760. ASSERT(NULL == _hwnd);
  1761. ASSERT(NULL == _hwndLastFocus);
  1762. VariantInit(&_varScope0);
  1763. VariantInit(&_varQueryFile0);
  1764. }
  1765. CBandDlg::~CBandDlg()
  1766. {
  1767. VariantClear(&_varScope0);
  1768. VariantClear(&_varQueryFile0);
  1769. }
  1770. STDMETHODIMP CBandDlg::TranslateAccelerator(MSG *pmsg)
  1771. {
  1772. if (WM_KEYDOWN == pmsg->message || WM_KEYUP == pmsg->message)
  1773. {
  1774. IAutoComplete2* pac2;
  1775. if (GetAutoCompleteObjectForWindow(pmsg->hwnd, &pac2))
  1776. {
  1777. if (S_OK == _TestAutoCompleteDropDownState(pac2, ACDD_VISIBLE))
  1778. {
  1779. TranslateMessage(pmsg);
  1780. DispatchMessage(pmsg);
  1781. pac2->Release();
  1782. return S_OK;
  1783. }
  1784. pac2->Release();
  1785. }
  1786. }
  1787. // Check for Ctrl+Nav Key:
  1788. if (_pfsb->IsKeyboardScroll(pmsg))
  1789. return S_OK;
  1790. return S_FALSE;
  1791. }
  1792. void CBandDlg::SetDefaultFocus()
  1793. {
  1794. HWND hwndFirst = GetFirstTabItem();
  1795. if (IsWindow(hwndFirst))
  1796. SetFocus(hwndFirst);
  1797. }
  1798. void CBandDlg::RememberFocus(HWND hwndFocus)
  1799. {
  1800. if (!IsWindow(hwndFocus))
  1801. {
  1802. _hwndLastFocus = NULL;
  1803. hwndFocus = GetFocus();
  1804. }
  1805. if (IsChild(_hwnd, hwndFocus))
  1806. _hwndLastFocus = hwndFocus;
  1807. }
  1808. BOOL CBandDlg::RestoreFocus()
  1809. {
  1810. if (IsWindow(_hwndLastFocus))
  1811. {
  1812. if (IsWindowVisible(_hwndLastFocus) && IsWindowEnabled(_hwndLastFocus))
  1813. {
  1814. SetFocus(_hwndLastFocus);
  1815. return TRUE;
  1816. }
  1817. }
  1818. else
  1819. _hwndLastFocus = NULL;
  1820. return FALSE;
  1821. }
  1822. LRESULT CBandDlg::OnChildSetFocusCmd(WORD, WORD, HWND hwndCtl, BOOL& bHandled)
  1823. {
  1824. _EnsureVisible(_hwnd, hwndCtl, _pfsb);
  1825. return 0;
  1826. }
  1827. LRESULT CBandDlg::OnChildSetFocusNotify(int, NMHDR *pnmh, BOOL&)
  1828. {
  1829. _EnsureVisible(_hwnd, pnmh->hwndFrom, _pfsb);
  1830. return 0;
  1831. }
  1832. LRESULT CBandDlg::OnChildKillFocusCmd(WORD, WORD, HWND hwndCtl, BOOL&)
  1833. {
  1834. _hwndLastFocus = hwndCtl;
  1835. return 0;
  1836. }
  1837. LRESULT CBandDlg::OnChildKillFocusNotify(int, NMHDR *pnmh, BOOL&)
  1838. {
  1839. _hwndLastFocus = pnmh->hwndFrom;
  1840. return 0;
  1841. }
  1842. LRESULT CBandDlg::OnComboExEndEdit(int, NMHDR *pnmh, BOOL&)
  1843. {
  1844. if (CBEN_ENDEDIT == pnmh->code)
  1845. {
  1846. if (CBENF_KILLFOCUS == ((NMCBEENDEDIT*)pnmh)->iWhy)
  1847. _hwndLastFocus = pnmh->hwndFrom;
  1848. }
  1849. return 0;
  1850. }
  1851. void CBandDlg::WndPosChanging(HWND hwndOC, LPWINDOWPOS pwp)
  1852. {
  1853. SIZE sizeMin;
  1854. if (0 == (pwp->flags & SWP_NOSIZE) && GetMinSize(hwndOC, &sizeMin))
  1855. {
  1856. if (pwp->cx < sizeMin.cx)
  1857. pwp->cx = sizeMin.cx;
  1858. if (pwp->cy < sizeMin.cy)
  1859. pwp->cy = sizeMin.cy;
  1860. }
  1861. }
  1862. LRESULT CBandDlg::OnSize(UINT, WPARAM wParam, LPARAM lParam, BOOL&)
  1863. {
  1864. POINTS pts = MAKEPOINTS(lParam);
  1865. LayoutControls(pts.x, pts.y);
  1866. return 0;
  1867. }
  1868. void CBandDlg::LayoutControls(int cx, int cy)
  1869. {
  1870. if (cx < 0 || cy < 0)
  1871. {
  1872. RECT rc;
  1873. GetClientRect(_hwnd, &rc);
  1874. cx = RECTWIDTH(rc);
  1875. cy = RECTHEIGHT(rc);
  1876. }
  1877. _LayoutCaption(GetIconID(), GetCaptionID(), GetCaptionDivID(), cx);
  1878. }
  1879. BOOL CBandDlg::GetIdealSize(HWND hwndOC, SIZE *psize) const
  1880. {
  1881. ASSERT(psize);
  1882. psize->cx = psize->cy = 0;
  1883. if (!IsWindow(Hwnd()))
  1884. return FALSE;
  1885. SIZE sizeMin;
  1886. if (GetMinSize(hwndOC, &sizeMin))
  1887. {
  1888. RECT rcClient;
  1889. ::GetClientRect(hwndOC, &rcClient);
  1890. psize->cx = (RECTWIDTH(rcClient) < sizeMin.cx) ? sizeMin.cx : RECTWIDTH(rcClient);
  1891. psize->cy = sizeMin.cy;
  1892. return TRUE;
  1893. }
  1894. return FALSE;
  1895. }
  1896. LRESULT CBandDlg::OnPaint(UINT, WPARAM, LPARAM, BOOL&)
  1897. {
  1898. // Just going to call BeginPaint and EndPaint. All
  1899. // painting done in WM_ERASEBKGND handler to avoid flicker.
  1900. PAINTSTRUCT ps;
  1901. HDC hdc = BeginPaint(_hwnd, &ps);
  1902. if (hdc)
  1903. EndPaint(_hwnd, &ps);
  1904. return 0;
  1905. }
  1906. LRESULT CBandDlg::OnEraseBkgnd(UINT, WPARAM wParam, LPARAM, BOOL&)
  1907. {
  1908. ASSERT(::IsWindow(_hwnd)); // was _Attach() called, e.g. from WM_INITDIALOG?
  1909. _PaintDlg(_hwnd, _pfsb->GetMetrics(), (HDC)wParam);
  1910. ValidateRect(_hwnd, NULL);
  1911. return TRUE;
  1912. }
  1913. LRESULT CBandDlg::OnCtlColorStatic(UINT, WPARAM wParam, LPARAM lParam, BOOL&)
  1914. {
  1915. SetTextColor((HDC)wParam, _pfsb->GetMetrics().TextColor());
  1916. SetBkColor((HDC)wParam, _pfsb->GetMetrics().BkgndColor());
  1917. return (LRESULT)_pfsb->GetMetrics().BkgndBrush();
  1918. }
  1919. // Hack method to remove turds left after showing band toolbar.
  1920. // Methinks this is a USER issue. [scotthan]
  1921. void CBandDlg::RemoveToolbarTurds(int cyOffset)
  1922. {
  1923. RECT rcUpdate;
  1924. GetClientRect(_hwnd, &rcUpdate);
  1925. HWND hwndCtl = GetDlgItem(_hwnd, GetCaptionDivID());
  1926. if (hwndCtl)
  1927. {
  1928. RECT rc;
  1929. GetWindowRect(hwndCtl, &rc);
  1930. ::MapWindowRect(NULL, _hwnd, &rc);
  1931. rcUpdate.bottom = rc.bottom;
  1932. OffsetRect(&rcUpdate, 0, cyOffset);
  1933. InvalidateRect(_hwnd, &rcUpdate, TRUE);
  1934. InvalidateRect(hwndCtl, NULL, TRUE);
  1935. UpdateWindow(hwndCtl);
  1936. }
  1937. hwndCtl = GetDlgItem(_hwnd, GetIconID());
  1938. if (hwndCtl)
  1939. {
  1940. InvalidateRect(hwndCtl, NULL, TRUE);
  1941. UpdateWindow(hwndCtl);
  1942. }
  1943. hwndCtl = GetDlgItem(_hwnd, GetCaptionID());
  1944. if (hwndCtl)
  1945. {
  1946. InvalidateRect(hwndCtl, NULL, TRUE);
  1947. UpdateWindow(hwndCtl);
  1948. }
  1949. UpdateWindow(_hwnd);
  1950. }
  1951. void CBandDlg::_BeautifyCaption(UINT nIDCaption, UINT nIDIcon, UINT nIDIconResource)
  1952. {
  1953. // Do some cosmetic and initialization stuff
  1954. HFONT hf = _pfsb->GetMetrics().BoldFont(_hwnd);
  1955. if (hf)
  1956. SendDlgItemMessage(_hwnd, nIDCaption, WM_SETFONT, (WPARAM)hf, 0);
  1957. if (nIDIcon && nIDIconResource)
  1958. {
  1959. HICON hiconCaption = _pfsb->GetMetrics().CaptionIcon(nIDIconResource);
  1960. if (hiconCaption)
  1961. SendDlgItemMessage(_hwnd, nIDIcon, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hiconCaption);
  1962. }
  1963. }
  1964. void CBandDlg::_LayoutCaption(UINT nIDCaption, UINT nIDIcon, UINT nIDDiv, LONG cxDlg)
  1965. {
  1966. RECT rcIcon, rcCaption;
  1967. LONG cxMargin = _pfsb->GetMetrics().CtlMarginX();
  1968. GetWindowRect(GetDlgItem(_hwnd, nIDIcon), &rcIcon);
  1969. GetWindowRect(GetDlgItem(_hwnd, nIDCaption), &rcCaption);
  1970. ::MapWindowRect(NULL, _hwnd, &rcIcon);
  1971. ::MapWindowRect(NULL, _hwnd, &rcCaption);
  1972. int nTop = max(rcIcon.bottom, rcCaption.bottom) + _PixelsForDbu(_hwnd, 1, FALSE);
  1973. SetWindowPos(GetDlgItem(_hwnd, nIDDiv), GetDlgItem(_hwnd, nIDCaption),
  1974. cxMargin, nTop, cxDlg - (cxMargin * 2), 2, SWP_NOACTIVATE);
  1975. }
  1976. void CBandDlg::_LayoutSearchLinks(UINT nIDCaption, UINT nIDDiv, BOOL bShowDiv, LONG left, LONG right, LONG yMargin,
  1977. LONG& yStart, const int rgLinkIDs[], LONG cLinkIDs)
  1978. {
  1979. // Position divider
  1980. if (bShowDiv != 0)
  1981. {
  1982. RECT rcDiv;
  1983. SetRect(&rcDiv, left, yStart, right, yStart + 1);
  1984. SetWindowPos(GetDlgItem(_hwnd, nIDDiv), GetDlgItem(_hwnd, nIDCaption),
  1985. rcDiv.left, rcDiv.top, RECTWIDTH(rcDiv), RECTHEIGHT(rcDiv),
  1986. SWP_NOACTIVATE|SWP_SHOWWINDOW);
  1987. yStart += yMargin;
  1988. }
  1989. else
  1990. ShowWindow(GetDlgItem(_hwnd, nIDDiv), SW_HIDE);
  1991. // Position caption
  1992. RECT rcCaption;
  1993. GetWindowRect(GetDlgItem(_hwnd, nIDCaption), &rcCaption);
  1994. ::MapWindowRect(NULL, _hwnd, &rcCaption);
  1995. OffsetRect(&rcCaption, left - rcCaption.left, yStart - rcCaption.top);
  1996. SetWindowPos(GetDlgItem(_hwnd, nIDCaption), NULL,
  1997. left, yStart, 0,0,
  1998. SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
  1999. yStart += RECTHEIGHT(rcCaption) + yMargin;
  2000. // Position links
  2001. _LayoutLinkWindows(_hwnd, left, right, yMargin, yStart, rgLinkIDs, cLinkIDs);
  2002. }
  2003. LRESULT CBandDlg::OnEditChange(WORD, WORD, HWND, BOOL&)
  2004. {
  2005. _pfsb->SetDirty();
  2006. return 0;
  2007. }
  2008. LRESULT CBandDlg::OnSearchLink(int nID, LPNMHDR, BOOL&)
  2009. {
  2010. ASSERT(_pfsb);
  2011. _pfsb->StopSearch();
  2012. switch (nID)
  2013. {
  2014. case IDC_SEARCHLINK_FILES:
  2015. _pfsb->FindFilesOrFolders(FALSE, TRUE);
  2016. break;
  2017. case IDC_SEARCHLINK_COMPUTERS:
  2018. _pfsb->FindComputer(FALSE, TRUE);
  2019. break;
  2020. case IDC_SEARCHLINK_PRINTERS:
  2021. _pfsb->FindPrinter(FALSE, TRUE);
  2022. break;
  2023. case IDC_SEARCHLINK_PEOPLE:
  2024. _pfsb->FindPeople(FALSE, TRUE);
  2025. break;
  2026. case IDC_SEARCHLINK_INTERNET:
  2027. _pfsb->FindOnWeb(FALSE, TRUE);
  2028. break;
  2029. }
  2030. return 0;
  2031. }
  2032. // Invoked when a client calls IFileSearchBand::SetSearchParameters()
  2033. HRESULT CBandDlg::SetScope(IN VARIANT* pvarScope, BOOL bTrack)
  2034. {
  2035. HRESULT hr = S_OK;
  2036. VariantClear(&_varScope0);
  2037. // cache the scope
  2038. if (pvarScope)
  2039. hr = VariantCopy(&_varScope0, pvarScope);
  2040. return hr;
  2041. }
  2042. HRESULT CBandDlg::GetScope(OUT VARIANT* pvarScope)
  2043. {
  2044. // retrieve the scope
  2045. if (!pvarScope)
  2046. return E_INVALIDARG;
  2047. HRESULT hr = VariantCopy(pvarScope, &_varScope0);
  2048. return SUCCEEDED(hr) ? (VT_EMPTY == _varScope0.vt ? S_FALSE : S_OK) : hr;
  2049. }
  2050. HRESULT CBandDlg::SetQueryFile(IN VARIANT* pvarFile)
  2051. {
  2052. return VariantCopy(&_varQueryFile0, pvarFile);
  2053. }
  2054. HRESULT CBandDlg::GetQueryFile(OUT VARIANT* pvarFile)
  2055. {
  2056. // retrieve the filename of the query to restore.
  2057. if (!pvarFile)
  2058. return E_INVALIDARG;
  2059. VariantInit(pvarFile);
  2060. HRESULT hr = VariantCopy(pvarFile, &_varQueryFile0);
  2061. return SUCCEEDED(hr) ? (VT_EMPTY == _varQueryFile0.vt ? S_FALSE : S_OK) : hr;
  2062. }
  2063. // CFindFilesDlg impl
  2064. #define FSEARCHMAIN_TABFIRST IDC_FILESPEC
  2065. #define FSEARCHMAIN_TABLAST IDC_SEARCHLINK_INTERNET
  2066. #define FSEARCHMAIN_BOTTOMMOST IDC_SEARCHLINK_INTERNET // bottom-most control
  2067. #define FSEARCHMAIN_RIGHTMOST IDC_SEARCH_STOP // right-most control
  2068. #define UISTATETIMER 1
  2069. #define UISTATETIMER_DELAY 4000
  2070. CFindFilesDlg::CFindFilesDlg(CFileSearchBand* pfsb)
  2071. : CSearchCmdDlg(pfsb),
  2072. _dlgOptions(pfsb),
  2073. _iCurNamespace(CB_ERR),
  2074. _fTrackScope(TRACKSCOPE_SPECIFIC),
  2075. _dwWarningFlags(DFW_DEFAULT),
  2076. _dwRunOnceWarningFlags(DFW_DEFAULT)
  2077. {
  2078. // Since we use the zero initializer for COM objects, all variables should
  2079. // be initialized to NULL/FALSE/0
  2080. ASSERT(FALSE == _bScoped);
  2081. ASSERT(FALSE == _fDisplayOptions);
  2082. ASSERT(FALSE == _fNamespace);
  2083. ASSERT(FALSE == _fDebuted);
  2084. ASSERT(FALSE == _fBandFinishedDisplaying);
  2085. ASSERT(NULL == _pacGrepText);
  2086. ASSERT(NULL == _pmruGrepText);
  2087. ASSERT(NULL == _pacFileSpec);
  2088. ASSERT(NULL == _pmruFileSpec);
  2089. ASSERT(0 == *_szInitialPath);
  2090. ASSERT(0 == *_szInitialNames);
  2091. ASSERT(0 == *_szCurrentPath);
  2092. ASSERT(0 == *_szLocalDrives);
  2093. ASSERT(NULL == _pidlInitial);
  2094. }
  2095. CFindFilesDlg::~CFindFilesDlg()
  2096. {
  2097. ATOMICRELEASE(_pacGrepText);
  2098. ATOMICRELEASE(_pmruGrepText);
  2099. ATOMICRELEASE(_pacFileSpec);
  2100. ATOMICRELEASE(_pmruFileSpec);
  2101. ILFree(_pidlInitial);
  2102. }
  2103. // Scope to a default namespace.
  2104. BOOL CFindFilesDlg::SetDefaultScope()
  2105. {
  2106. // If we've already assigned a scope, bail early
  2107. if (_bScoped)
  2108. return TRUE;
  2109. // Try establiblishing the preassigned (_szInitialXXX) scope:
  2110. BOOL bScoped = _SetPreassignedScope();
  2111. if (!bScoped)
  2112. {
  2113. // Try setting scope to the current shell folder of the active view...
  2114. bScoped = _SetFolderScope();
  2115. if (!bScoped)
  2116. {
  2117. // set it to the hard-coded shell default folder
  2118. bScoped = _SetLocalDefaultScope();
  2119. }
  2120. }
  2121. return bScoped;
  2122. }
  2123. // Assignes the namespace control to the preassigned scope saved in
  2124. // _szInitialNames/_szInitialPath/_pidlInitial
  2125. BOOL CFindFilesDlg::_SetPreassignedScope()
  2126. {
  2127. BOOL bScoped = FALSE;
  2128. if (*_szInitialNames || *_szInitialPath || _pidlInitial)
  2129. bScoped = AssignNamespace(_szInitialPath, _pidlInitial, _szInitialNames, FALSE);
  2130. return bScoped;
  2131. }
  2132. STDAPI_(BOOL) IsFTPFolder(IShellFolder * psf);
  2133. // Scope to the namespace of the current shell folder view
  2134. BOOL CFindFilesDlg::_SetFolderScope()
  2135. {
  2136. BOOL bScoped = FALSE;
  2137. ASSERT(_pfsb->BandSite());
  2138. LPITEMIDLIST pidl;
  2139. if (SUCCEEDED(_GetCurrentFolderIDList(_pfsb->BandSite(), &pidl)))
  2140. {
  2141. // Get the display name/path. IF it is an FTP site, then we need to get the name
  2142. // as though it is for the address bar becasue when we call SHGetPathFromIDList,
  2143. // it returns "" for FTP sites.
  2144. IShellFolder *psf = NULL;
  2145. if (SUCCEEDED(SHBindToObject(NULL, IID_X_PPV_ARG(IShellFolder, pidl, &psf)))
  2146. && IsFTPFolder(psf))
  2147. {
  2148. SHGetNameAndFlags(pidl, SHGDN_FORADDRESSBAR, _szInitialNames, ARRAYSIZE(_szInitialNames), NULL);
  2149. SHGetNameAndFlags(pidl, SHGDN_FORPARSING, _szInitialPath, ARRAYSIZE(_szInitialNames), NULL);
  2150. }
  2151. else
  2152. {
  2153. SHGetNameAndFlags(pidl, SHGDN_NORMAL, _szInitialNames, ARRAYSIZE(_szInitialNames), NULL);
  2154. SHGetPathFromIDList(pidl, _szInitialPath); // file system path only here!
  2155. }
  2156. if (psf)
  2157. {
  2158. psf->Release();
  2159. }
  2160. // Store the pidl for use later if we are starting it async
  2161. _pidlInitial = ILClone(pidl);
  2162. // if we're tracking the scope loosely...
  2163. if ((TRACKSCOPE_GENERAL == _fTrackScope) && _IsPathLocalHarddrive(_szInitialPath))
  2164. {
  2165. // scope to local default scope
  2166. *_szInitialNames = *_szInitialPath = 0;
  2167. bScoped = _SetLocalDefaultScope();
  2168. }
  2169. else if (_threadState.fComplete /* finished populating namespace combo */ &&
  2170. _szInitialPath[0])
  2171. {
  2172. bScoped = AssignNamespace(_szInitialPath, pidl, _szInitialNames, FALSE);
  2173. }
  2174. ILFree(pidl);
  2175. }
  2176. return bScoped;
  2177. }
  2178. // Scope to the hard-coded shell default namespace.
  2179. BOOL CFindFilesDlg::_SetLocalDefaultScope()
  2180. {
  2181. BOOL bScoped = FALSE;
  2182. // Initialize fallback initial namespace
  2183. // default to Local Hard Drives if possible
  2184. if (_szLocalDrives[0] &&
  2185. AssignNamespace(NULL, NULL, _szLocalDrives, FALSE))
  2186. {
  2187. bScoped = TRUE;
  2188. }
  2189. else
  2190. {
  2191. TCHAR szDesktopPath[MAX_PATH];
  2192. if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, NULL, SHGFP_TYPE_CURRENT, szDesktopPath)) &&
  2193. AssignNamespace(NULL, NULL, szDesktopPath, FALSE))
  2194. {
  2195. bScoped = TRUE;
  2196. }
  2197. }
  2198. // If we failed, this means that the namespace combo hasn't
  2199. // been populated yet.
  2200. // We just sit tight, cuz the populating thread will fall back on
  2201. // the LocalDefaultScope.
  2202. return bScoped;
  2203. }
  2204. // search **band** show/hide handler
  2205. void CFindFilesDlg::OnBandShow(BOOL fShow)
  2206. {
  2207. CSearchCmdDlg::OnBandShow(fShow);
  2208. if (fShow)
  2209. {
  2210. // Establish the first showing's band width
  2211. if (!_fDebuted && _pfsb->IsBandDebut())
  2212. {
  2213. _pfsb->SetDeskbandWidth(GetIdealDeskbandWidth());
  2214. _fDebuted = TRUE;
  2215. }
  2216. // If we're tracking the scope to the current folder shell view,
  2217. // update it now, as it may have changed.
  2218. if (_fTrackScope != TRACKSCOPE_NONE)
  2219. {
  2220. _bScoped = FALSE;
  2221. _SetFolderScope();
  2222. }
  2223. // restart our UI state timer
  2224. SetTimer(UISTATETIMER, UISTATETIMER_DELAY);
  2225. }
  2226. else
  2227. {
  2228. // we're being hidden so stop updating our state indicators.
  2229. KillTimer(UISTATETIMER);
  2230. }
  2231. }
  2232. // search band **dialog** show/hide handler
  2233. void CFindFilesDlg::OnBandDialogShow(BOOL fShow)
  2234. {
  2235. CSearchCmdDlg::OnBandDialogShow(fShow);
  2236. if (fShow)
  2237. {
  2238. // If we're tracking the scope to the current folder shell view,
  2239. // update it now, as it may have changed.
  2240. if (_fTrackScope != TRACKSCOPE_NONE)
  2241. {
  2242. _bScoped = FALSE;
  2243. _SetFolderScope();
  2244. }
  2245. }
  2246. }
  2247. // Explicit scoping method. This will be called if a client
  2248. // called IFileSearchBand::SetSearchParameters with a non-NULL scope.
  2249. HRESULT CFindFilesDlg::SetScope(IN VARIANT* pvarScope, BOOL bTrack)
  2250. {
  2251. HRESULT hr = CBandDlg::SetScope(pvarScope, bTrack);
  2252. if (S_OK != hr)
  2253. return hr;
  2254. LPITEMIDLIST pidlSearch = VariantToIDList(&_varScope0);
  2255. if (pidlSearch)
  2256. {
  2257. SHGetNameAndFlags(pidlSearch, SHGDN_FORPARSING, _szInitialPath, ARRAYSIZE(_szInitialPath), NULL);
  2258. SHGetNameAndFlags(pidlSearch, SHGDN_NORMAL, _szInitialNames, ARRAYSIZE(_szInitialNames), NULL);
  2259. ILFree(pidlSearch);
  2260. // Did we get one?
  2261. if (*_szInitialNames || *_szInitialPath)
  2262. {
  2263. if (_bScoped)
  2264. {
  2265. // If we've already scoped, update the namespace combo.
  2266. // Track if succeed and requested.
  2267. if (AssignNamespace(_szInitialPath, NULL, _szInitialNames, FALSE) && bTrack)
  2268. _fTrackScope = TRACKSCOPE_SPECIFIC;
  2269. }
  2270. else
  2271. {
  2272. // Not already scoped. We've assigned our initial namespace,
  2273. // let the namespace thread completion handler update
  2274. // the combo
  2275. if (bTrack)
  2276. _fTrackScope = TRACKSCOPE_SPECIFIC;
  2277. }
  2278. }
  2279. }
  2280. return S_OK;
  2281. }
  2282. LRESULT CFindFilesDlg::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  2283. {
  2284. _Attach(m_hWnd);
  2285. _dlgOptions.SetBandDlg(this);
  2286. // Register specialty window classes.
  2287. DivWindow_RegisterClass();
  2288. GroupButton_RegisterClass();
  2289. // Initialize some metrics
  2290. CMetrics& metrics = _pfsb->GetMetrics();
  2291. RECT rc;
  2292. _pfsb->GetMetrics().Init(m_hWnd);
  2293. // SHAutoComplete(::GetWindow(GetDlgItem(IDC_NAMESPACE), GW_CHILD), SHACF_FILESYS_DIRS);
  2294. ::GetWindowRect(GetDlgItem(IDC_FILESPEC), &rc);
  2295. ::MapWindowRect(NULL, m_hWnd, &rc);
  2296. metrics.ExpandOrigin().x = rc.left;
  2297. // Position start, stop buttons.
  2298. ::GetWindowRect(GetDlgItem(IDC_SEARCH_START), &rc);
  2299. ::MapWindowRect(NULL, m_hWnd, &rc);
  2300. int cxBtn = _GetResourceMetric(m_hWnd, IDS_FSEARCH_STARTSTOPWIDTH, TRUE);
  2301. if (cxBtn > 0)
  2302. {
  2303. rc.right = rc.left + cxBtn;
  2304. ::SetWindowPos(GetDlgItem(IDC_SEARCH_START), NULL,
  2305. rc.left, rc.top, RECTWIDTH(rc), RECTHEIGHT(rc),
  2306. SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
  2307. OffsetRect(&rc, cxBtn + _PixelsForDbu(m_hWnd, 12, TRUE), 0);
  2308. ::SetWindowPos(GetDlgItem(IDC_SEARCH_STOP), NULL,
  2309. rc.left, rc.top, RECTWIDTH(rc), RECTHEIGHT(rc),
  2310. SWP_NOZORDER|SWP_NOACTIVATE);
  2311. }
  2312. // Create subdialogs and collect native sizes.
  2313. _dlgOptions.Create(m_hWnd);
  2314. ASSERT(::IsWindow(_dlgOptions));
  2315. // Load settings
  2316. LoadSaveUIState(0, FALSE);
  2317. // Show/Hide the "Search" Options subdialog
  2318. _dlgOptions.ShowWindow(_fDisplayOptions ? SW_SHOW : SW_HIDE);
  2319. // Create 'link' child controls
  2320. POINT pt;
  2321. pt.x = metrics.CtlMarginX();
  2322. pt.y = 0;
  2323. // Create 'Search Options' link and group button
  2324. _CreateLinkWindow(m_hWnd, IDC_SEARCHLINK_OPTIONS, pt,
  2325. IDS_FSEARCH_SEARCHLINK_OPTIONS, !_fDisplayOptions);
  2326. TCHAR szGroupBtn[128];
  2327. EVAL(LoadString(HINST_THISDLL, IDS_FSEARCH_GROUPBTN_OPTIONS,
  2328. szGroupBtn, ARRAYSIZE(szGroupBtn)));
  2329. HWND hwndGrpBtn = CreateWindowEx(0, GROUPBUTTON_CLASS, szGroupBtn,
  2330. WS_CHILD|WS_BORDER|WS_TABSTOP, pt.x, pt.y, 400, 18,
  2331. m_hWnd, (HMENU)IDC_GROUPBTN_OPTIONS, HINST_THISDLL, NULL);
  2332. if (::IsWindow(hwndGrpBtn))
  2333. {
  2334. ::SendMessage(hwndGrpBtn, GBM_SETBUDDY,
  2335. (WPARAM)_dlgOptions.m_hWnd, (LPARAM)GBBF_HRESIZE|GBBF_VSLAVE);
  2336. ::ShowWindow(GetDlgItem(IDC_GROUPBTN_OPTIONS), _fDisplayOptions ? SW_SHOW : SW_HIDE);
  2337. }
  2338. // Create cross-navigation links
  2339. _CreateSearchLinks(m_hWnd, pt, IDC_SEARCHLINK_FILES);
  2340. _CreateDivider(m_hWnd, IDC_FSEARCH_DIV1, pt, 2, GetDlgItem(IDC_FSEARCH_CAPTION));
  2341. _CreateDivider(m_hWnd, IDC_FSEARCH_DIV2, pt, 1, GetDlgItem(IDC_SEARCHLINK_CAPTION));
  2342. _CreateDivider(m_hWnd, IDC_FSEARCH_DIV3, pt, 1, GetDlgItem(IDC_SEARCHLINK_PEOPLE));
  2343. // Do some cosmetic and initialization stuff
  2344. OnWinIniChange();
  2345. _InitializeMru(GetDlgItem(IDC_FILESPEC), &_pacFileSpec,
  2346. TEXT("FilesNamedMRU"), &_pmruFileSpec);
  2347. _InitializeMru(GetDlgItem(IDC_GREPTEXT), &_pacGrepText,
  2348. TEXT("ContainingTextMRU"), &_pmruGrepText);
  2349. SendDlgItemMessage(IDC_FILESPEC, EM_LIMITTEXT, MAX_EDIT, 0);
  2350. SendDlgItemMessage(IDC_GREPTEXT, EM_LIMITTEXT, MAX_EDIT, 0);
  2351. SendDlgItemMessage(IDC_NAMESPACE, CBEM_SETEXTENDEDSTYLE,
  2352. CBES_EX_NOSIZELIMIT | CBES_EX_CASESENSITIVE,
  2353. CBES_EX_NOSIZELIMIT | CBES_EX_CASESENSITIVE);
  2354. SendDlgItemMessage(IDC_NAMESPACE, CBEM_SETIMAGELIST, 0, (LPARAM)GetSystemImageListSmallIcons());
  2355. SendDlgItemMessage(IDC_NAMESPACE, CBEM_SETEXSTYLE, 0, 0);
  2356. // Enable the cue banners for the edit boxes:
  2357. TCHAR szCaption[128];
  2358. LoadString(HINST_THISDLL, IDS_FIND_CUEBANNER_FILE, szCaption, ARRAYSIZE(szCaption));
  2359. SendDlgItemMessage(IDC_FILESPEC, EM_SETCUEBANNER, 0, (LPARAM) szCaption);
  2360. LoadString(HINST_THISDLL, IDS_FIND_CUEBANNER_GREP, szCaption, ARRAYSIZE(szCaption));
  2361. SendDlgItemMessage(IDC_GREPTEXT, EM_SETCUEBANNER, 0, (LPARAM) szCaption);
  2362. // Bias the input reader towards file names
  2363. SetModeBias(MODEBIASMODE_FILENAME);
  2364. // Launch thread to populate the namespaces combo.
  2365. _threadState.hwndCtl = GetDlgItem(IDC_NAMESPACE);
  2366. _threadState.pvParam = this;
  2367. _threadState.fComplete = FALSE;
  2368. _threadState.fCancel = FALSE;
  2369. if (SUCCEEDED(SAFECAST(_pfsb, IFileSearchBand*)->QueryInterface(IID_PPV_ARG(IUnknown, &_threadState.punkBand))))
  2370. {
  2371. if (!SHCreateThread(NamespaceThreadProc, &_threadState, CTF_COINIT, NULL))
  2372. {
  2373. ATOMICRELEASE(_threadState.punkBand);
  2374. }
  2375. }
  2376. // Layout our subdialogs and update state representation...
  2377. LayoutControls();
  2378. UpdateSearchCmdStateUI();
  2379. SetTimer(UISTATETIMER, UISTATETIMER_DELAY);
  2380. return TRUE; // Let the system set the focus
  2381. }
  2382. LRESULT CFindFilesDlg::OnEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&)
  2383. {
  2384. // paint the background
  2385. _PaintDlg(m_hWnd, _pfsb->GetMetrics(), (HDC)wParam);
  2386. if (_fDisplayOptions)
  2387. // ensure that the group button is updated.
  2388. SendDlgItemMessage(IDC_GROUPBTN_OPTIONS, WM_NCPAINT, (WPARAM)1, 0);
  2389. // validate our work.
  2390. ValidateRect(NULL);
  2391. return TRUE;
  2392. }
  2393. void CFindFilesDlg::OnWinIniChange()
  2394. {
  2395. CBandDlg::OnWinIniChange();
  2396. // redisplay animated icon
  2397. HWND hwndIcon = GetDlgItem(IDC_FSEARCH_ICON);
  2398. Animate_Close(hwndIcon);
  2399. Animate_OpenEx(hwndIcon, HINST_THISDLL, MAKEINTRESOURCE(IDA_FINDFILE));
  2400. SendDlgItemMessage(IDC_NAMESPACE, CB_SETDROPPEDWIDTH,
  2401. _PixelsForDbu(m_hWnd, MIN_NAMESPACELIST_WIDTH, TRUE), 0);
  2402. _BeautifyCaption(IDC_FSEARCH_CAPTION);
  2403. _dlgOptions.OnWinIniChange();
  2404. }
  2405. LRESULT CFindFilesDlg::OnDestroy(UINT, WPARAM, LPARAM, BOOL& bHandled)
  2406. {
  2407. KillTimer(UISTATETIMER);
  2408. StopSearch();
  2409. if (_pSrchCmd)
  2410. {
  2411. DisconnectEvents();
  2412. IUnknown_SetSite(_pSrchCmd, NULL);
  2413. }
  2414. _threadState.fCancel = TRUE;
  2415. _fOnDestroy = TRUE;
  2416. bHandled = FALSE;
  2417. return 0;
  2418. }
  2419. BOOL CFindFilesDlg::Validate()
  2420. {
  2421. return _dlgOptions.Validate();
  2422. }
  2423. STDMETHODIMP CFindFilesDlg::AddConstraints(ISearchCommandExt *pSrchCmd)
  2424. {
  2425. HRESULT hr;
  2426. VARIANT var = {0};
  2427. TCHAR szPath[MAX_URL_STRING];
  2428. // If the user enters a path as a filename, it will recognize it as a path and replace
  2429. // the filename with just the file portion and the namespace with the path.
  2430. if (::GetDlgItemText(m_hWnd, IDC_FILESPEC, szPath, ARRAYSIZE(szPath)) > 0)
  2431. {
  2432. if (StrChr(szPath, TEXT('\\')) != NULL)
  2433. {
  2434. if (!_PathLooksLikeFilePattern(szPath) &&
  2435. (PathIsUNCServer(szPath) /* string test: \\server */||
  2436. _PathIsUNCServerShareOrSub(szPath) /* string test: \\server\share */ ||
  2437. PathIsDirectory(szPath)) /* this actually tests existence */)
  2438. {
  2439. ::SetDlgItemText(m_hWnd, IDC_FILESPEC, TEXT("*.*"));
  2440. AssignNamespace(szPath, NULL, NULL, FALSE);
  2441. }
  2442. else
  2443. {
  2444. // just use the prefix for the file spec & the root for the location
  2445. TCHAR szRoot[MAX_URL_STRING];
  2446. lstrcpy(szRoot, szPath);
  2447. if (PathRemoveFileSpec(szRoot) && szRoot[0] != 0)
  2448. {
  2449. PathStripPath(szPath);
  2450. ::SetDlgItemText(m_hWnd, IDC_FILESPEC, szPath);
  2451. AssignNamespace(szRoot, NULL, NULL, FALSE);
  2452. }
  2453. }
  2454. }
  2455. }
  2456. // If _ReconcileNamespace could not add an item to the combo box for
  2457. // the path entered, then it means that the path is likely invalid.
  2458. // Get the path and check it here.
  2459. IEnumIDList *penum;
  2460. hr = _GetTargetNamespace(&penum);
  2461. if (SUCCEEDED(hr))
  2462. {
  2463. var.vt = VT_UNKNOWN;
  2464. penum->QueryInterface(IID_PPV_ARG(IUnknown, &var.punkVal));
  2465. hr = _AddConstraint(pSrchCmd, L"LookIn", &var);
  2466. VariantClear(&var);
  2467. }
  2468. else
  2469. {
  2470. GetDlgItemText(IDC_NAMESPACE, szPath, ARRAYSIZE(szPath));
  2471. hr = _PathValidate(szPath, GetParent(), TRUE);
  2472. if (SUCCEEDED(hr))
  2473. {
  2474. if (SUCCEEDED(InitVariantFromStr(&var, szPath)))
  2475. {
  2476. hr = _AddConstraint(pSrchCmd, L"LookIn", &var);
  2477. VariantClear(&var);
  2478. }
  2479. }
  2480. else
  2481. {
  2482. // _PathValidate's SHPathPrepareForWrite may have already displayed error
  2483. if (HRESULT_FROM_WIN32(ERROR_CANCELLED) != hr)
  2484. {
  2485. TCHAR szMsg[MAX_URL_STRING];
  2486. if (_FmtError(IDS_FSEARCH_INVALIDFOLDER_FMT, szPath, szMsg, ARRAYSIZE(szMsg)))
  2487. ShellMessageBox(HINST_THISDLL, GetParent(), szMsg, NULL, MB_OK | MB_ICONASTERISK);
  2488. }
  2489. ::SetFocus(GetDlgItem(IDC_NAMESPACE));
  2490. }
  2491. }
  2492. if (SUCCEEDED(hr))
  2493. {
  2494. // Add 'Files Named' constraint
  2495. if (S_OK == _GetWindowValue(m_hWnd, IDC_FILESPEC, &var))
  2496. {
  2497. hr = _AddConstraint(pSrchCmd, L"Named", &var);
  2498. if (SUCCEEDED(hr))
  2499. _AddMruStringFromWindow(_pmruFileSpec, GetDlgItem(IDC_FILESPEC));
  2500. VariantClear(&var);
  2501. }
  2502. // Add 'Containing Text' constraint
  2503. if (S_OK == _GetWindowValue(m_hWnd, IDC_GREPTEXT, &var))
  2504. {
  2505. VARIANT varQuery;
  2506. ULONG ulDialect;
  2507. BOOL fCiQuery = IsCiQuery(&var, &varQuery, &ulDialect);
  2508. if (fCiQuery)
  2509. {
  2510. hr = _AddConstraint(pSrchCmd, L"IndexedSearch", &varQuery);
  2511. if (SUCCEEDED(hr))
  2512. {
  2513. _AddMruStringFromWindow(_pmruGrepText, GetDlgItem(IDC_GREPTEXT));
  2514. VariantClear(&var);
  2515. var.vt = VT_UI4;
  2516. var.ulVal = ulDialect;
  2517. hr = _AddConstraint(pSrchCmd, L"QueryDialect", &var);
  2518. }
  2519. }
  2520. else
  2521. {
  2522. // add to 'containing text' constraint
  2523. hr = _AddConstraint(pSrchCmd, L"ContainingText", &var);
  2524. if (SUCCEEDED(hr))
  2525. _AddMruStringFromWindow(_pmruGrepText, GetDlgItem(IDC_GREPTEXT));
  2526. }
  2527. VariantClear(&varQuery);
  2528. VariantClear(&var);
  2529. }
  2530. // Warning flags
  2531. if (_dwRunOnceWarningFlags != DFW_DEFAULT)
  2532. {
  2533. // re-run the query w/ temporary warning bits.
  2534. var.ulVal = _dwRunOnceWarningFlags;
  2535. var.vt = VT_UI4;
  2536. //_dwRunOnceWarningFlags = DFW_DEFAULT; cannot reset it here in case of error, must preserve them
  2537. hr = _AddConstraint(pSrchCmd, L"WarningFlags", &var);
  2538. }
  2539. else if (_dwWarningFlags != DFW_DEFAULT)
  2540. {
  2541. var.ulVal = _dwWarningFlags;
  2542. var.vt = VT_UI4;
  2543. hr = _AddConstraint(pSrchCmd, L"WarningFlags", &var);
  2544. }
  2545. VariantClear(&var);
  2546. hr = _dlgOptions.AddConstraints(pSrchCmd);
  2547. }
  2548. return hr;
  2549. }
  2550. STDMETHODIMP CFindFilesDlg::RestoreConstraint(const BSTR bstrName, const VARIANT* pValue)
  2551. {
  2552. if (IsConstraintName(L"Named", bstrName))
  2553. {
  2554. _SetWindowValue(m_hWnd, IDC_FILESPEC, pValue);
  2555. return S_FALSE;
  2556. }
  2557. if (IsConstraintName(L"IndexedSearch", bstrName))
  2558. {
  2559. ASSERT(VT_BSTR == pValue->vt);
  2560. if (pValue->bstrVal)
  2561. {
  2562. int cch = lstrlenW(pValue->bstrVal) + 2;
  2563. LPWSTR pwszVal = new WCHAR[cch];
  2564. if (pwszVal)
  2565. {
  2566. *pwszVal = L'!';
  2567. StrCatW(pwszVal, pValue->bstrVal);
  2568. }
  2569. ::SetDlgItemTextW(m_hWnd, IDC_GREPTEXT, pwszVal);
  2570. if (pwszVal)
  2571. delete [] pwszVal;
  2572. }
  2573. return S_FALSE;
  2574. }
  2575. if (IsConstraintName(L"ContainingText", bstrName))
  2576. {
  2577. _SetWindowValue(m_hWnd, IDC_GREPTEXT, pValue);
  2578. return S_FALSE;
  2579. }
  2580. HRESULT hr = _dlgOptions.RestoreConstraint(bstrName, pValue);
  2581. if (S_OK == hr) // opened a dialog
  2582. _ShowOptions(TRUE);
  2583. if (SUCCEEDED(hr))
  2584. return hr;
  2585. return E_FAIL;
  2586. }
  2587. void CFindFilesDlg::RestoreSearch()
  2588. {
  2589. DFConstraint* pdfc = NULL;
  2590. HRESULT hr;
  2591. BOOL bMore = TRUE;
  2592. ISearchCommandExt* pSrchCmd = GetSearchCmd();
  2593. if (NULL == pSrchCmd)
  2594. return;
  2595. CSearchCmdDlg::Clear();
  2596. // we'll anchor to any restored scope, or the default
  2597. _fTrackScope = TRACKSCOPE_GENERAL;
  2598. for (hr = pSrchCmd->GetNextConstraint(TRUE, &pdfc);
  2599. S_OK == hr && bMore;
  2600. hr = pSrchCmd->GetNextConstraint(FALSE, &pdfc))
  2601. {
  2602. BSTR bstrName = NULL;
  2603. if (S_OK == (hr = pdfc->get_Name(&bstrName)) && bstrName)
  2604. {
  2605. if (*bstrName == 0)
  2606. bMore = FALSE; // no more constraints.
  2607. else
  2608. {
  2609. VARIANT varValue = {0};
  2610. hr = pdfc->get_Value(&varValue);
  2611. if (S_OK == hr)
  2612. {
  2613. // If this is the 'lookin' value, cache the path.
  2614. if (IsConstraintName(L"LookIn", bstrName))
  2615. {
  2616. if (VT_BSTR == varValue.vt && varValue.bstrVal)
  2617. {
  2618. USES_CONVERSION;
  2619. // Assign path and clear display name (which we don't know or care about).
  2620. if (_bScoped)
  2621. AssignNamespace(W2T(varValue.bstrVal), NULL, NULL, FALSE);
  2622. else
  2623. {
  2624. lstrcpyn(_szInitialPath, W2T(varValue.bstrVal), ARRAYSIZE(_szInitialPath));
  2625. *_szInitialNames = 0;
  2626. }
  2627. }
  2628. }
  2629. else
  2630. RestoreConstraint(bstrName, &varValue);
  2631. VariantClear(&varValue);
  2632. }
  2633. }
  2634. SysFreeString(bstrName);
  2635. }
  2636. pdfc->Release();
  2637. }
  2638. LayoutControls();
  2639. _pfsb->UpdateLayout();
  2640. }
  2641. HRESULT FirstIDList(IEnumIDList *penum, LPITEMIDLIST *ppidl)
  2642. {
  2643. penum->Reset();
  2644. return penum->Next(1, ppidl, NULL);
  2645. }
  2646. HRESULT CFindFilesDlg::_GetTargetNamespace(IEnumIDList **ppenum)
  2647. {
  2648. *ppenum = NULL;
  2649. // We don't trust the comboex to handle the edit text properly so try to compensate...
  2650. TCHAR szText[MAX_PATH];
  2651. GetDlgItemText(IDC_NAMESPACE, szText, ARRAYSIZE(szText));
  2652. INT_PTR iCurSel = SendDlgItemMessage(IDC_NAMESPACE, CB_GETCURSEL, 0, 0);
  2653. if (CB_ERR != iCurSel)
  2654. {
  2655. TCHAR szItemName[MAX_PATH];
  2656. if (CB_ERR == SendDlgItemMessage(IDC_NAMESPACE, CB_GETLBTEXT, (WPARAM)iCurSel, (LPARAM)szItemName))
  2657. szItemName[0] = 0;
  2658. *ppenum = _GetItems(iCurSel);
  2659. if (*ppenum)
  2660. {
  2661. if (lstrcmp(szText, szItemName))
  2662. *ppenum = NULL; // combo edit/combo dropdown mismatch!
  2663. }
  2664. }
  2665. return *ppenum ? S_OK : E_FAIL;
  2666. }
  2667. void CFindFilesDlg::Clear()
  2668. {
  2669. CSearchCmdDlg::Clear();
  2670. // Clear edit fields
  2671. SetDlgItemText(IDC_FILESPEC, NULL);
  2672. SetDlgItemText(IDC_GREPTEXT, NULL);
  2673. _dlgOptions.Clear();
  2674. _pfsb->UpdateLayout(BLF_ALL);
  2675. }
  2676. void CFindFilesDlg::LoadSaveUIState(UINT nIDCtl, BOOL bSave)
  2677. {
  2678. if (0 == nIDCtl) // load/save all.
  2679. {
  2680. LoadSaveUIState(IDC_SEARCHLINK_OPTIONS, bSave);
  2681. LoadSaveUIState(LSUIS_WARNING, bSave);
  2682. }
  2683. HKEY hkey = _pfsb->GetBandRegKey(bSave);
  2684. if (hkey)
  2685. {
  2686. DWORD dwData;
  2687. DWORD cbData;
  2688. DWORD dwType;
  2689. LPCTSTR pszVal = NULL;
  2690. switch (nIDCtl)
  2691. {
  2692. case IDC_SEARCHLINK_OPTIONS:
  2693. pszVal = TEXT("UseSearchOptions");
  2694. dwData = _fDisplayOptions;
  2695. cbData = sizeof(dwData);
  2696. dwType = REG_DWORD;
  2697. break;
  2698. case LSUIS_WARNING:
  2699. pszVal = TEXT("Warnings");
  2700. dwData = _dwWarningFlags;
  2701. cbData = sizeof(_dwWarningFlags);
  2702. dwType = REG_DWORD;
  2703. break;
  2704. }
  2705. if (bSave)
  2706. RegSetValueEx(hkey, pszVal, 0, dwType, (LPBYTE)&dwData, cbData);
  2707. else
  2708. {
  2709. if (ERROR_SUCCESS == RegQueryValueEx(hkey, pszVal, 0, &dwType,
  2710. (LPBYTE)&dwData, &cbData))
  2711. {
  2712. switch (nIDCtl)
  2713. {
  2714. case IDC_SEARCHLINK_OPTIONS:
  2715. _fDisplayOptions = BOOLIFY(dwData);
  2716. break;
  2717. case LSUIS_WARNING:
  2718. _dwWarningFlags = dwData;
  2719. break;
  2720. }
  2721. }
  2722. }
  2723. RegCloseKey(hkey);
  2724. }
  2725. }
  2726. HWND CFindFilesDlg::GetFirstTabItem() const
  2727. {
  2728. return GetDlgItem(FSEARCHMAIN_TABFIRST);
  2729. }
  2730. HWND CFindFilesDlg::GetLastTabItem() const
  2731. {
  2732. return GetDlgItem(FSEARCHMAIN_TABLAST);
  2733. }
  2734. BOOL CFindFilesDlg::GetAutoCompleteObjectForWindow(HWND hwnd, IAutoComplete2** ppac2)
  2735. {
  2736. *ppac2 = NULL;
  2737. if (hwnd == GetDlgItem(IDC_FILESPEC))
  2738. *ppac2 = _pacFileSpec;
  2739. else if (hwnd == GetDlgItem(IDC_GREPTEXT))
  2740. *ppac2 = _pacGrepText;
  2741. if (*ppac2)
  2742. {
  2743. (*ppac2)->AddRef();
  2744. return TRUE;
  2745. }
  2746. return CBandDlg::GetAutoCompleteObjectForWindow(hwnd, ppac2);
  2747. }
  2748. void CFindFilesDlg::_ShowNamespaceEditImage(BOOL bShow)
  2749. {
  2750. SendDlgItemMessage(IDC_NAMESPACE, CBEM_SETEXTENDEDSTYLE, CBES_EX_NOEDITIMAGE, bShow ? 0 : CBES_EX_NOEDITIMAGE);
  2751. }
  2752. STDMETHODIMP CFindFilesDlg::TranslateAccelerator(MSG *pmsg)
  2753. {
  2754. // Check for Ctrl+Nav Key:
  2755. if (S_OK == CSearchCmdDlg::TranslateAccelerator(pmsg))
  2756. return S_OK;
  2757. // Check for VK_RETURN key.
  2758. if (WM_KEYDOWN == pmsg->message)
  2759. {
  2760. HWND hwndFocus = ::GetFocus();
  2761. if (hwndFocus == GetDlgItem(IDC_NAMESPACE) || ::IsChild(GetDlgItem(IDC_NAMESPACE), hwndFocus))
  2762. {
  2763. if (VK_RETURN == pmsg->wParam || VK_TAB == pmsg->wParam || VK_F6 == pmsg->wParam)
  2764. {
  2765. _UIReconcileNamespace();
  2766. }
  2767. else
  2768. {
  2769. // Hide edit image if this virtkey maps to a character,
  2770. if (MapVirtualKey((UINT)pmsg->wParam, 2) != 0 /* it's a char */)
  2771. _fNamespace = TRUE;
  2772. _ShowNamespaceEditImage(!_fNamespace);
  2773. }
  2774. }
  2775. }
  2776. if (_dlgOptions.IsChild(pmsg->hwnd) &&
  2777. S_OK == _dlgOptions.TranslateAccelerator(pmsg))
  2778. return S_OK;
  2779. // Handle it ourselves...
  2780. return _pfsb->IsDlgMessage(m_hWnd, pmsg);
  2781. }
  2782. BOOL CFindFilesDlg::GetMinSize(HWND hwndOC, SIZE *psize) const
  2783. {
  2784. CMetrics& metrics = _pfsb->GetMetrics();
  2785. RECT rc;
  2786. // Calculate minimum tracking width.
  2787. ASSERT(psize);
  2788. psize->cx = psize->cy = 0;
  2789. if (!::IsWindow(m_hWnd))
  2790. return FALSE;
  2791. // determine mininum width
  2792. HWND hwndLimit = GetDlgItem(FSEARCHMAIN_RIGHTMOST);
  2793. if (!::GetWindowRect(hwndLimit, &rc))
  2794. {
  2795. ASSERT(hwndLimit != NULL);
  2796. return FALSE;
  2797. }
  2798. ::MapWindowRect(NULL, m_hWnd, &rc);
  2799. psize->cx = rc.right + metrics.CtlMarginX();
  2800. // determine mininum height
  2801. hwndLimit = GetDlgItem(FSEARCHMAIN_BOTTOMMOST);
  2802. if (!(::IsWindow(hwndLimit) && ::GetWindowRect(hwndLimit, &rc)))
  2803. return FALSE;
  2804. ::MapWindowRect(NULL, m_hWnd, &rc);
  2805. psize->cy = rc.bottom + metrics.TightMarginY();
  2806. return TRUE;
  2807. }
  2808. int CFindFilesDlg::GetIdealDeskbandWidth() const
  2809. {
  2810. LONG cx0 = _GetResourceMetric(m_hWnd, IDS_FSEARCH_BANDWIDTH, TRUE);
  2811. ASSERT(cx0 >= 0);
  2812. return cx0 + (_pfsb->GetMetrics().CtlMarginX() * 2);
  2813. }
  2814. BOOL CFindFilesDlg::GetMinMaxInfo(HWND hwndOC, LPMINMAXINFO pmmi)
  2815. {
  2816. SIZE sizeMin;
  2817. if (GetMinSize(hwndOC, &sizeMin))
  2818. {
  2819. pmmi->ptMinTrackSize.x = sizeMin.cx;
  2820. pmmi->ptMinTrackSize.y = sizeMin.cy;
  2821. return TRUE;
  2822. }
  2823. return FALSE;
  2824. }
  2825. void CFindFilesDlg::LayoutControls(int cx, int cy)
  2826. {
  2827. if (cx < 0 || cy < 0)
  2828. {
  2829. RECT rcClient;
  2830. GetClientRect(&rcClient);
  2831. cx = RECTWIDTH(rcClient);
  2832. cy = RECTHEIGHT(rcClient);
  2833. }
  2834. CBandDlg::LayoutControls(cx, cy);
  2835. CMetrics& metrics = _pfsb->GetMetrics();
  2836. POINT ptOrigin = metrics.ExpandOrigin();
  2837. HDWP hdwp = BeginDeferWindowPos(6);
  2838. if (hdwp)
  2839. {
  2840. // Resize edit, combo immediate children
  2841. int i;
  2842. enum { ircFILESPEC,
  2843. ircGREPTEXT,
  2844. ircNAMESPACE,
  2845. ircSEARCHSTART,
  2846. ircOPTIONGRP,
  2847. ircOPTIONSDLG,
  2848. ircLINKCAPTION,
  2849. ircDIV2,
  2850. irc_count };
  2851. RECT rcCtls[irc_count];
  2852. ::GetWindowRect(GetDlgItem(IDC_FILESPEC), &rcCtls[ircFILESPEC]);
  2853. ::GetWindowRect(GetDlgItem(IDC_GREPTEXT), &rcCtls[ircGREPTEXT]);
  2854. ::GetWindowRect(GetDlgItem(IDC_NAMESPACE), &rcCtls[ircNAMESPACE]);
  2855. ::GetWindowRect(GetDlgItem(IDC_SEARCH_START), &rcCtls[ircSEARCHSTART]);
  2856. ::GetWindowRect(GetDlgItem(IDC_GROUPBTN_OPTIONS), &rcCtls[ircOPTIONGRP]);
  2857. ::GetWindowRect(GetDlgItem(IDC_SEARCHLINK_CAPTION), &rcCtls[ircLINKCAPTION]);
  2858. ::GetWindowRect(GetDlgItem(IDC_FSEARCH_DIV2), &rcCtls[ircDIV2]);
  2859. SIZE sizeOptions;
  2860. _dlgOptions.GetWindowRect(&rcCtls[ircOPTIONSDLG]);
  2861. _dlgOptions.GetMinSize(&sizeOptions);
  2862. rcCtls[ircOPTIONSDLG].bottom = rcCtls[ircOPTIONSDLG].top + sizeOptions.cy;
  2863. for (i = 0; i < ARRAYSIZE(rcCtls); i++)
  2864. {
  2865. // MapWindowPoints is mirroring aware only if you pass two points
  2866. ::MapWindowRect(NULL, m_hWnd, &rcCtls[i]);
  2867. }
  2868. // Position caption elements
  2869. _LayoutCaption(IDC_FSEARCH_CAPTION, IDC_FSEARCH_ICON, IDC_FSEARCH_DIV1, cx);
  2870. // Resize ctl widths
  2871. for (i = 0; i < irc_count; i++)
  2872. rcCtls[i].right = cx - metrics.CtlMarginX();
  2873. // Stretch the 'Named' combo:
  2874. ::DeferWindowPos(hdwp, GetDlgItem(IDC_FILESPEC), NULL, 0, 0,
  2875. RECTWIDTH(*(rcCtls + ircFILESPEC)), RECTHEIGHT(*(rcCtls + ircFILESPEC)),
  2876. SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
  2877. // Stretch the 'Containing Text' combo:
  2878. ::DeferWindowPos(hdwp, GetDlgItem(IDC_GREPTEXT), NULL, 0, 0,
  2879. RECTWIDTH(*(rcCtls + ircGREPTEXT)), RECTHEIGHT(*(rcCtls + ircGREPTEXT)),
  2880. SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
  2881. // Stretch the 'Look In' combo
  2882. ::DeferWindowPos(hdwp, GetDlgItem(IDC_NAMESPACE), NULL, 0, 0,
  2883. RECTWIDTH(*(rcCtls + ircNAMESPACE)), RECTHEIGHT(*(rcCtls + ircNAMESPACE)),
  2884. SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
  2885. // Arrange dynamically positioned controls.
  2886. ptOrigin.y = rcCtls[ircSEARCHSTART].bottom + metrics.LooseMarginY();
  2887. if (_fDisplayOptions)
  2888. {
  2889. OffsetRect(&rcCtls[ircOPTIONGRP], metrics.CtlMarginX() - rcCtls[ircOPTIONGRP].left,
  2890. ptOrigin.y - rcCtls[ircOPTIONGRP].top);
  2891. rcCtls[ircOPTIONSDLG].right = cx - metrics.CtlMarginX();
  2892. ::SetWindowPos(GetDlgItem(IDC_GROUPBTN_OPTIONS), NULL,
  2893. rcCtls[ircOPTIONGRP].left, rcCtls[ircOPTIONGRP].top,
  2894. RECTWIDTH(rcCtls[ircOPTIONGRP]), RECTHEIGHT(rcCtls[ircOPTIONGRP]),
  2895. SWP_NOZORDER|SWP_NOACTIVATE);
  2896. ::GetWindowRect(GetDlgItem(IDC_GROUPBTN_OPTIONS), &rcCtls[ircOPTIONGRP]);
  2897. ::MapWindowRect(NULL, m_hWnd, &rcCtls[ircOPTIONGRP]);
  2898. ptOrigin.y = rcCtls[ircOPTIONGRP].bottom + metrics.TightMarginY();
  2899. }
  2900. else
  2901. {
  2902. // Position the 'Options' link
  2903. _LayoutLinkWindow(m_hWnd, metrics.CtlMarginX(), cx - metrics.CtlMarginX(), metrics.TightMarginY(),
  2904. ptOrigin.y, IDC_SEARCHLINK_OPTIONS);
  2905. }
  2906. ptOrigin.y += metrics.TightMarginY();
  2907. // Position the 'Search for Other Items' caption, divider and link windows
  2908. const int rgLinkIDs[] = {
  2909. IDC_SEARCHLINK_FILES,
  2910. IDC_SEARCHLINK_COMPUTERS,
  2911. IDC_SEARCHLINK_PRINTERS,
  2912. IDC_SEARCHLINK_PEOPLE,
  2913. -IDC_FSEARCH_DIV3,
  2914. IDC_SEARCHLINK_INTERNET,
  2915. };
  2916. _LayoutSearchLinks(IDC_SEARCHLINK_CAPTION, IDC_FSEARCH_DIV2, !_fDisplayOptions,
  2917. metrics.CtlMarginX(), cx - metrics.CtlMarginX(), metrics.TightMarginY(),
  2918. ptOrigin.y, rgLinkIDs, ARRAYSIZE(rgLinkIDs));
  2919. EndDeferWindowPos(hdwp);
  2920. }
  2921. }
  2922. LRESULT CFindFilesDlg::OnUpdateLayout(UINT, WPARAM wParam, LPARAM, BOOL&)
  2923. {
  2924. LayoutControls();
  2925. _pfsb->UpdateLayout((ULONG)wParam);
  2926. return 0;
  2927. }
  2928. LRESULT CFindFilesDlg::OnTimer(UINT, WPARAM wParam, LPARAM, BOOL&)
  2929. {
  2930. if (UISTATETIMER == wParam && IsWindowVisible())
  2931. UpdateSearchCmdStateUI();
  2932. return 0;
  2933. }
  2934. LRESULT CFindFilesDlg::OnOptions(int idCtl, NMHDR *pnmh, BOOL&)
  2935. {
  2936. _ShowOptions(!_fDisplayOptions);
  2937. LoadSaveUIState(IDC_SEARCHLINK_OPTIONS, TRUE);
  2938. if (_fDisplayOptions)
  2939. _dlgOptions.TakeFocus();
  2940. else
  2941. ::SetFocus(GetDlgItem(IDC_SEARCHLINK_OPTIONS));
  2942. return 0;
  2943. }
  2944. void CFindFilesDlg::_ShowOptions(BOOL bShow)
  2945. {
  2946. _fDisplayOptions = bShow;
  2947. // don't need to scroll if we've expanded a subdialog,
  2948. // but we do if we've contracted one.
  2949. ULONG dwLayoutFlags = BLF_ALL;
  2950. if (_fDisplayOptions)
  2951. dwLayoutFlags &= ~BLF_SCROLLWINDOW;
  2952. LayoutControls();
  2953. _pfsb->UpdateLayout(dwLayoutFlags);
  2954. ::ShowWindow(GetDlgItem(IDC_GROUPBTN_OPTIONS), _fDisplayOptions ? SW_SHOW : SW_HIDE);
  2955. ::ShowWindow(GetDlgItem(IDC_SEARCHLINK_OPTIONS), !_fDisplayOptions ? SW_SHOW : SW_HIDE);
  2956. }
  2957. LRESULT CFindFilesDlg::OnQueryOptionsHeight(int idCtl, NMHDR *pnmh, BOOL&)
  2958. {
  2959. GBNQUERYBUDDYSIZE* pqbs = (GBNQUERYBUDDYSIZE*)pnmh;
  2960. pqbs->cy = _dlgOptions.QueryHeight(pqbs->cx, pqbs->cy);
  2961. return TRUE;
  2962. }
  2963. void CFindFilesDlg::UpdateSearchCmdStateUI(DISPID eventID)
  2964. {
  2965. if (_fOnDestroy)
  2966. return;
  2967. if (DISPID_SEARCHCOMMAND_COMPLETE == eventID
  2968. || DISPID_SEARCHCOMMAND_ABORT == eventID)
  2969. _dwRunOnceWarningFlags = DFW_DEFAULT;
  2970. CSearchCmdDlg::UpdateSearchCmdStateUI(eventID);
  2971. _dlgOptions.UpdateSearchCmdStateUI(eventID);
  2972. }
  2973. BOOL CFindFilesDlg::OnSearchCmdError(HRESULT hr, LPCTSTR pszError)
  2974. {
  2975. if (SCEE_SCOPEMISMATCH == HRESULT_CODE(hr)
  2976. || SCEE_INDEXNOTCOMPLETE == HRESULT_CODE(hr))
  2977. {
  2978. // Set up checkbox
  2979. BOOL fFlag = SCEE_SCOPEMISMATCH == HRESULT_CODE(hr)? DFW_IGNORE_CISCOPEMISMATCH :
  2980. DFW_IGNORE_INDEXNOTCOMPLETE ,
  2981. fNoWarn = (_dwWarningFlags & fFlag) != 0,
  2982. fNoWarnPrev = fNoWarn;
  2983. USHORT uDlgT = SCEE_SCOPEMISMATCH == HRESULT_CODE(hr)? DLG_FSEARCH_SCOPEMISMATCH :
  2984. DLG_FSEARCH_INDEXNOTCOMPLETE ;
  2985. int nRet = CSearchWarningDlg_DoModal(m_hWnd, uDlgT, &fNoWarn);
  2986. if (fNoWarn)
  2987. _dwWarningFlags |= fFlag;
  2988. else
  2989. _dwWarningFlags &= ~fFlag;
  2990. if (fNoWarnPrev != fNoWarn)
  2991. LoadSaveUIState(LSUIS_WARNING, TRUE);
  2992. if (IDOK == nRet)
  2993. {
  2994. _dwRunOnceWarningFlags |= _dwWarningFlags | fFlag ; // preserve the old run once flags...
  2995. // hack one, hack two... let's be USER!!! [scotthan]
  2996. PostMessage(WM_COMMAND, MAKEWPARAM(IDC_SEARCH_START, BN_CLICKED),
  2997. (LPARAM)GetDlgItem(IDC_SEARCH_START));
  2998. }
  2999. else
  3000. ::SetFocus(GetDlgItem(IDC_NAMESPACE));
  3001. return TRUE;
  3002. }
  3003. return CSearchCmdDlg::OnSearchCmdError(hr, pszError);
  3004. }
  3005. LRESULT CFindFilesDlg::OnBtnClick(WORD nCode, WORD nID, HWND hwndCtl, BOOL&)
  3006. {
  3007. switch (nID)
  3008. {
  3009. case IDC_SEARCH_START:
  3010. if (_ShouldReconcileNamespace())
  3011. _UIReconcileNamespace(TRUE);
  3012. if (SUCCEEDED(StartSearch()))
  3013. {
  3014. EnableStartStopButton(hwndCtl, FALSE);
  3015. StartStopAnimation(TRUE);
  3016. }
  3017. break;
  3018. case IDC_SEARCH_STOP:
  3019. StopSearch();
  3020. break;
  3021. }
  3022. return 0;
  3023. }
  3024. void CFindFilesDlg::NavigateToResults(IWebBrowser2* pwb2)
  3025. {
  3026. BSTR bstrUrl = SysAllocString(L"::{e17d4fc0-5564-11d1-83f2-00a0c90dc849}");// CLSID_DocFindFolder
  3027. if (bstrUrl)
  3028. {
  3029. VARIANT varNil = {0};
  3030. pwb2->Navigate(bstrUrl, &varNil, &varNil, &varNil, &varNil);
  3031. SysFreeString(bstrUrl);
  3032. }
  3033. }
  3034. LRESULT CFindFilesDlg::OnStateChange(UINT, WPARAM, LPARAM, BOOL&)
  3035. {
  3036. UpdateSearchCmdStateUI();
  3037. return 0;
  3038. }
  3039. LRESULT CFindFilesDlg::OnNamespaceSelEndOk(WORD nCode, WORD nID, HWND hwndCtl, BOOL&)
  3040. {
  3041. LRESULT iSel = SendDlgItemMessage(IDC_NAMESPACE, CB_GETCURSEL, 0, 0);
  3042. if (iSel != CB_ERR)
  3043. {
  3044. IEnumIDList *penum = _GetItems(iSel);
  3045. if (NULL == penum)
  3046. _BrowseAndAssignNamespace(); // Was this the "Browse..." item
  3047. else
  3048. _iCurNamespace = iSel;
  3049. }
  3050. _pfsb->SetDirty();
  3051. return 0;
  3052. }
  3053. LRESULT CFindFilesDlg::OnNamespaceEditChange(WORD wID, WORD wCode, HWND hwndCtl, BOOL& bHandled)
  3054. {
  3055. return OnEditChange(wID, wCode, hwndCtl, bHandled);
  3056. }
  3057. // Handler for CBN_SELENDCANCEL, CBN_DROPDOWN, CBN_KILLFOCUS
  3058. LRESULT CFindFilesDlg::OnNamespaceReconcileCmd(WORD wID, WORD wCode, HWND hwndCtl, BOOL&)
  3059. {
  3060. if (_ShouldReconcileNamespace())
  3061. _UIReconcileNamespace(wCode != CBN_DROPDOWN);
  3062. return 0;
  3063. }
  3064. // Handler for WM_NOTIFY::CBEN_ENDEDIT
  3065. LRESULT CFindFilesDlg::OnNamespaceReconcileNotify(int idCtl, NMHDR *pnmh, BOOL& bHandled)
  3066. {
  3067. if (_ShouldReconcileNamespace())
  3068. {
  3069. // Post ourselves a message to reconcile the ad hoc namespace.
  3070. // Note: We need to do this because ComboBoxEx won't update his window text if he
  3071. // is waiting for his CBEN_ENDEDIT notification message to return.
  3072. PostMessage(WMU_NAMESPACERECONCILE, 0, 0);
  3073. }
  3074. bHandled = FALSE; // let base class have a crack as well.
  3075. return 0;
  3076. }
  3077. // WMU_NAMESPACERECONCILE handler
  3078. LRESULT CFindFilesDlg::OnNamespaceReconcileMsg(UINT, WPARAM, LPARAM, BOOL&)
  3079. {
  3080. if (_ShouldReconcileNamespace())
  3081. _UIReconcileNamespace(FALSE);
  3082. return 0;
  3083. }
  3084. // WMU_BANDFINISHEDDISPLAYING handler
  3085. // Note that we do not care about returning results from this, as it will
  3086. // be started asynchronously.
  3087. LRESULT CFindFilesDlg::OnBandFinishedDisplaying(UINT, WPARAM, LPARAM, BOOL&)
  3088. {
  3089. // Now that the search band has finished displaying, we will do the
  3090. // delayed initialization. Make sure we don't do it twice.
  3091. if (!_fBandFinishedDisplaying)
  3092. {
  3093. _fBandFinishedDisplaying = TRUE;
  3094. _dlgOptions.DoDelayedInit();
  3095. }
  3096. return 0;
  3097. }
  3098. BOOL CFindFilesDlg::_ShouldReconcileNamespace()
  3099. {
  3100. return _fNamespace || SendDlgItemMessage(IDC_NAMESPACE, CB_GETCURSEL, 0, 0) == CB_ERR;
  3101. }
  3102. // Invokes lower Namespace reconciliation helper, updates some UI and
  3103. // instance state data.
  3104. // this was added as a late RC 'safe' delta, and should have actually
  3105. // become part of _ReconcileNamespace() impl.
  3106. void CFindFilesDlg::_UIReconcileNamespace(BOOL bAsync)
  3107. {
  3108. LRESULT iSel = _ReconcileNamespace(bAsync);
  3109. if (iSel != CB_ERR)
  3110. _iCurNamespace = iSel;
  3111. _ShowNamespaceEditImage(TRUE);
  3112. _fNamespace = FALSE; // clear the ad hoc flag.
  3113. }
  3114. // Scans namespace combo for a matching namespace; if found, selects
  3115. // the namespace item, otherwise adds an adhoc item and selects it.
  3116. //
  3117. // Important: don't call this directly, call _UIReconcileNamespace()
  3118. // instead to ensure that instance state data is updated.
  3119. INT_PTR CFindFilesDlg::_ReconcileNamespace(OPTIONAL BOOL bAsync)
  3120. {
  3121. INT_PTR iSel = SendDlgItemMessage(IDC_NAMESPACE, CB_GETCURSEL, 0, 0);
  3122. if ((CB_ERR != iSel) && (NULL == _GetItems(iSel)))
  3123. {
  3124. // The user has selected the special Browse... item.
  3125. // Irreconcilable. Return CB_ERR
  3126. return CB_ERR;
  3127. }
  3128. // Don't know the namespace? Use current window text.
  3129. TCHAR szNamespace[MAX_URL_STRING];
  3130. if (0 == GetDlgItemText(IDC_NAMESPACE, szNamespace, ARRAYSIZE(szNamespace)))
  3131. return CB_ERR;
  3132. INT_PTR iFind = _FindNamespace(szNamespace, NULL);
  3133. // search display names
  3134. if (CB_ERR == iFind)
  3135. {
  3136. // search paths
  3137. TCHAR szTemp[MAX_URL_STRING];
  3138. StrCpy(szTemp, szNamespace);
  3139. _PathFixup(szNamespace, szTemp); // don't care if this fails, the path might be a path list
  3140. iFind = _FindNamespace(szNamespace, NULL);
  3141. }
  3142. // Not found in CB list? Add it if it's a valid path
  3143. if (CB_ERR == iFind)
  3144. {
  3145. iSel = _AddNamespace(szNamespace, NULL, szNamespace, TRUE);
  3146. }
  3147. else
  3148. {
  3149. // found in CB list? Select it.
  3150. if (bAsync)
  3151. {
  3152. // this was needed in cases of reconcile following kill focus
  3153. ::PostMessage(GetDlgItem(IDC_NAMESPACE), CB_SETCURSEL, iFind, 0);
  3154. }
  3155. else
  3156. {
  3157. iSel = SendDlgItemMessage(IDC_NAMESPACE, CB_SETCURSEL, iFind, 0);
  3158. }
  3159. }
  3160. return iSel;
  3161. }
  3162. BOOL CFindFilesDlg::_PathFixup(LPTSTR pszDst, LPCTSTR pszSrc)
  3163. {
  3164. ASSERT(pszDst);
  3165. ASSERT(pszSrc);
  3166. TCHAR szSrc[MAX_PATH];
  3167. TCHAR szFull[MAX_PATH];
  3168. if (SHExpandEnvironmentStrings(pszSrc, szSrc, ARRAYSIZE(szSrc)) && *szSrc)
  3169. pszSrc = szSrc;
  3170. if (_IsPathList(pszSrc))
  3171. {
  3172. lstrcpy(pszDst, pszSrc);
  3173. return TRUE;
  3174. }
  3175. szFull[0] = 0;
  3176. BOOL bRelative = PathIsRelative(pszSrc);
  3177. BOOL bMissingDrive = bRelative ? FALSE : _IsFullPathMinusDriveLetter(pszSrc);
  3178. // bMissingDrive =,e.g. "\foo", "\foo\bar", etc. PathIsRelative() reports FALSE in this case.
  3179. if (bRelative || bMissingDrive)
  3180. {
  3181. ASSERT(_pfsb && _pfsb->BandSite());
  3182. LPITEMIDLIST pidl;
  3183. HRESULT hr = _GetCurrentFolderIDList(_pfsb->BandSite(), &pidl);
  3184. if (S_OK == hr)
  3185. {
  3186. TCHAR szCurDir[MAX_PATH];
  3187. // file system path only here!
  3188. if (SHGetPathFromIDList(pidl, szCurDir) &&
  3189. StrCmpI(szCurDir, _szCurrentPath))
  3190. {
  3191. lstrcpy(_szCurrentPath, szCurDir);
  3192. }
  3193. if (*_szCurrentPath)
  3194. {
  3195. if (bRelative)
  3196. {
  3197. if (PathCombine(szFull, _szCurrentPath, pszSrc))
  3198. pszSrc = szFull;
  3199. }
  3200. else if (bMissingDrive)
  3201. {
  3202. int iDrive = PathGetDriveNumber(_szCurrentPath);
  3203. if (-1 != iDrive)
  3204. {
  3205. TCHAR szRoot[MAX_PATH];
  3206. if (PathCombine(szFull, PathBuildRoot(szRoot, iDrive), pszSrc))
  3207. pszSrc = szFull;
  3208. }
  3209. }
  3210. }
  3211. ILFree(pidl);
  3212. }
  3213. }
  3214. return PathCanonicalize(pszDst, pszSrc);
  3215. }
  3216. LRESULT CFindFilesDlg::OnNamespaceDeleteItem(int idCtrl, NMHDR *pnmh, BOOL& bHandled)
  3217. {
  3218. PNMCOMBOBOXEX pnmce = (PNMCOMBOBOXEX)pnmh;
  3219. if (pnmce->ceItem.lParam)
  3220. {
  3221. IEnumIDList *penum = (IEnumIDList *)pnmce->ceItem.lParam;
  3222. penum->Release();
  3223. }
  3224. return 1;
  3225. }
  3226. DWORD CFindFilesDlg::NamespaceThreadProc(void* pv)
  3227. {
  3228. FSEARCHTHREADSTATE *pState = (FSEARCHTHREADSTATE *)pv;
  3229. CFindFilesDlg* pThis = (CFindFilesDlg*)pState->pvParam;
  3230. if (PopulateNamespaceCombo(pState->hwndCtl, AddNamespaceItemNotify, (LPARAM)pv) != E_ABORT)
  3231. {
  3232. ::PostMessage(::GetParent(pState->hwndCtl), WMU_COMBOPOPULATIONCOMPLETE, (WPARAM)pState->hwndCtl, 0);
  3233. }
  3234. pState->fComplete = TRUE;
  3235. ATOMICRELEASE(pState->punkBand);
  3236. return 0;
  3237. }
  3238. #define CBX_CSIDL_LOCALDRIVES 0x04FF // arbitrarily out of range of other CSIDL_xxx values.
  3239. HRESULT CFindFilesDlg::AddNamespaceItemNotify(ULONG fAction, PCBXITEM pItem, LPARAM lParam)
  3240. {
  3241. FSEARCHTHREADSTATE *pState = (FSEARCHTHREADSTATE *)lParam;
  3242. if (fAction & CBXCB_ADDING && pState->fCancel)
  3243. return E_ABORT;
  3244. //
  3245. // Sets the string in the CFindFilesDlg as the display name.
  3246. // This string is then used to set the default item in the
  3247. // combo box.
  3248. //
  3249. if (fAction & CBXCB_ADDED && CBX_CSIDL_LOCALDRIVES == pItem->iID)
  3250. {
  3251. CFindFilesDlg* pffd = (CFindFilesDlg*)pState->pvParam;
  3252. lstrcpyn(pffd->_szLocalDrives, pItem->szText, ARRAYSIZE(pffd->_szLocalDrives));
  3253. }
  3254. return S_OK;
  3255. }
  3256. LRESULT CFindFilesDlg::OnComboPopulationComplete(UINT, WPARAM wParam, LPARAM, BOOL&)
  3257. {
  3258. _bScoped = SetDefaultScope();
  3259. return 0;
  3260. }
  3261. // bPassive TRUE -> assign only if no current selection
  3262. BOOL CFindFilesDlg::AssignNamespace(LPCTSTR pszPath, LPCITEMIDLIST pidl, LPCTSTR pszName, BOOL bPassive)
  3263. {
  3264. INT_PTR iSel = CB_ERR;
  3265. // If we don't yet have a current selection, establish it now.
  3266. if (!bPassive || CB_ERR == (iSel = SendDlgItemMessage(IDC_NAMESPACE, CB_GETCURSEL, 0, 0)))
  3267. {
  3268. iSel = _FindNamespace(pszPath, pidl);
  3269. // scan items by display name if we don't have pidl
  3270. // otherwise choosing x:\my pictures (in browse) would end up selecting
  3271. // my pictures folder and searching the wrong place
  3272. if (CB_ERR == iSel && !pidl && !pszPath && pszName && *pszName)
  3273. iSel = _FindNamespace(pszName, NULL);
  3274. // Is this a folder we already know about?
  3275. if (CB_ERR == iSel)
  3276. {
  3277. if (pidl || pszPath)
  3278. iSel = _AddNamespace(pszPath, pidl, pszName, TRUE);
  3279. if (iSel != CB_ERR)
  3280. _iCurNamespace = iSel;
  3281. }
  3282. else
  3283. {
  3284. // yes: select it
  3285. SendDlgItemMessage(IDC_NAMESPACE, CB_SETCURSEL, iSel, 0);
  3286. _iCurNamespace = iSel;
  3287. }
  3288. }
  3289. return CB_ERR != SendDlgItemMessage(IDC_NAMESPACE, CB_GETCURSEL, 0, 0);
  3290. }
  3291. HWND CFindFilesDlg::ShowHelp(HWND hwnd)
  3292. {
  3293. return ::HtmlHelp(hwnd, TEXT("find.chm"), HH_DISPLAY_TOPIC, 0);
  3294. }
  3295. // inserts something into the name space combo
  3296. INT_PTR CFindFilesDlg::_AddNamespace(LPCTSTR pszPath, LPCITEMIDLIST pidl, LPCTSTR pszName, BOOL bSelectItem)
  3297. {
  3298. IEnumIDList *penum = NULL;
  3299. if (pszPath)
  3300. {
  3301. CreateIEnumIDListPaths(pszPath, &penum);
  3302. }
  3303. else if (pidl)
  3304. {
  3305. CreateIEnumIDListOnIDLists(&pidl, 1, &penum);
  3306. }
  3307. CBXITEM item;
  3308. item.iItem = CB_ERR; // failure result here
  3309. if (penum)
  3310. {
  3311. LPITEMIDLIST pidlIcon;
  3312. if (S_OK == FirstIDList(penum, &pidlIcon))
  3313. {
  3314. if (NULL == pszName)
  3315. pszName = pszPath;
  3316. MakeCbxItem(&item, pszName, penum, pidlIcon, LISTINSERT_LAST, 1);
  3317. INT_PTR iSel = item.iItem;
  3318. if (SUCCEEDED(AddCbxItemToComboBox(GetDlgItem(IDC_NAMESPACE), &item, &iSel)))
  3319. {
  3320. penum = NULL; // don't release below
  3321. item.iItem = iSel;
  3322. if (bSelectItem)
  3323. SendDlgItemMessage(IDC_NAMESPACE, CB_SETCURSEL, iSel, 0);
  3324. }
  3325. else
  3326. {
  3327. item.iItem = CB_ERR;
  3328. }
  3329. ILFree(pidlIcon);
  3330. }
  3331. if (penum)
  3332. penum->Release(); // not inserted, free this
  3333. }
  3334. return item.iItem;
  3335. }
  3336. LPARAM CFindFilesDlg::_GetComboData(UINT id, INT_PTR idx)
  3337. {
  3338. if (CB_ERR == idx)
  3339. idx = SendDlgItemMessage(id, CB_GETCURSEL, 0, 0);
  3340. if (CB_ERR == idx)
  3341. return idx;
  3342. return (LPARAM)SendDlgItemMessage(id, CB_GETITEMDATA, idx, 0);
  3343. }
  3344. IEnumIDList *CFindFilesDlg::_GetItems(INT_PTR i)
  3345. {
  3346. IEnumIDList *penum = (IEnumIDList *)_GetComboData(IDC_NAMESPACE, i);
  3347. return (INVALID_HANDLE_VALUE != penum) ? penum : NULL;
  3348. }
  3349. BOOL MatchItem(IEnumIDList *penum, LPCTSTR pszPath, LPCITEMIDLIST pidl)
  3350. {
  3351. BOOL bMatch = FALSE;
  3352. // this is somewhat imprecise as we will match on the first IDList in the
  3353. // enumerator. but generally that is the desired behavior for the special
  3354. // items that include multiple implied items
  3355. LPITEMIDLIST pidlFirst;
  3356. if (S_OK == FirstIDList(penum, &pidlFirst))
  3357. {
  3358. bMatch = pidl && ILIsEqual(pidl, pidlFirst);
  3359. if (!bMatch && pszPath)
  3360. {
  3361. TCHAR szPath[MAX_PATH];
  3362. if (SUCCEEDED(SHGetNameAndFlags(pidlFirst, SHGDN_FORPARSING, szPath, ARRAYSIZE(szPath), NULL)))
  3363. {
  3364. bMatch = (0 == StrCmpI(pszPath, szPath));
  3365. }
  3366. }
  3367. ILFree(pidlFirst);
  3368. }
  3369. return bMatch;
  3370. }
  3371. // searches namespace comboboxex for the indicated item
  3372. // returns:
  3373. // index of item, CB_ERR (-1) if not found
  3374. INT_PTR CFindFilesDlg::_FindNamespace(LPCTSTR pszPath, LPCITEMIDLIST pidl)
  3375. {
  3376. for (INT_PTR i = 0, cnt = SendDlgItemMessage(IDC_NAMESPACE, CB_GETCOUNT, 0, 0); i < cnt; i++)
  3377. {
  3378. IEnumIDList *penum = _GetItems(i);
  3379. if (penum)
  3380. {
  3381. if (MatchItem(penum, pszPath, pidl))
  3382. return i;
  3383. }
  3384. }
  3385. // fall back to finding by display name in the combo
  3386. if (pszPath)
  3387. return SendDlgItemMessage(IDC_NAMESPACE, CB_FINDSTRINGEXACT, -1, (LPARAM)pszPath);
  3388. return CB_ERR;
  3389. }
  3390. // Invokes UI to select a namespace.
  3391. //
  3392. // Returns:
  3393. // S_OK if the user has selected a valid item and the pszNamespace contains
  3394. // a valid shell folder display name.
  3395. // E_ABORT if the user canceled his search
  3396. // E_FAIL if an error occurred
  3397. HRESULT CFindFilesDlg::_BrowseForNamespace(LPTSTR pszName, UINT cchName, LPITEMIDLIST *ppidlRet)
  3398. {
  3399. *pszName = 0;
  3400. TCHAR szTitle[128];
  3401. LoadString(HINST_THISDLL, IDS_SNS_BROWSERFORDIR_TITLE, szTitle, ARRAYSIZE(szTitle));
  3402. BROWSEINFO bi = {0};
  3403. bi.hwndOwner = m_hWnd;
  3404. bi.lpszTitle = szTitle;
  3405. bi.ulFlags = BIF_USENEWUI | BIF_EDITBOX; // | BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS;
  3406. bi.lpfn = _BrowseCallback;
  3407. bi.lParam = (LPARAM)this;
  3408. HRESULT hr;
  3409. *ppidlRet = SHBrowseForFolder(&bi);
  3410. if (*ppidlRet)
  3411. {
  3412. SHGetNameAndFlags(*ppidlRet, SHGDN_NORMAL, pszName, cchName, NULL);
  3413. hr = S_OK;
  3414. }
  3415. else
  3416. {
  3417. hr = E_ABORT;
  3418. }
  3419. return hr;
  3420. }
  3421. // Invokes SHBrowserForFolder UI and assigns results.
  3422. void CFindFilesDlg::_BrowseAndAssignNamespace()
  3423. {
  3424. TCHAR szName[MAX_PATH];
  3425. LPITEMIDLIST pidl;
  3426. if (SUCCEEDED(_BrowseForNamespace(szName, ARRAYSIZE(szName), &pidl)))
  3427. {
  3428. AssignNamespace(NULL, pidl, szName, FALSE);
  3429. ILFree(pidl);
  3430. }
  3431. else
  3432. {
  3433. SendDlgItemMessage(IDC_NAMESPACE, CB_SETCURSEL, _iCurNamespace, 0);
  3434. }
  3435. }
  3436. BOOL CFindFilesDlg::_IsSearchableFolder(LPCITEMIDLIST pidlFolder)
  3437. {
  3438. return TRUE;
  3439. }
  3440. int CFindFilesDlg::_BrowseCallback(HWND hwnd, UINT msg, LPARAM lParam, LPARAM lpData)
  3441. {
  3442. CFindFilesDlg *pThis = (CFindFilesDlg *)lpData;
  3443. switch (msg)
  3444. {
  3445. case BFFM_INITIALIZED: // initializing: set default selection to drives if we can
  3446. {
  3447. LPITEMIDLIST pidlDefault = SHCloneSpecialIDList(NULL, CSIDL_DRIVES, TRUE);
  3448. if (pidlDefault)
  3449. {
  3450. if (!::SendMessage(hwnd, BFFM_SETSELECTION, FALSE, (LPARAM)pidlDefault)) // if we fail to default to drives, default to desktop
  3451. {
  3452. ILFree(pidlDefault);
  3453. pidlDefault = SHCloneSpecialIDList(NULL, CSIDL_DESKTOP, TRUE);
  3454. ::SendMessage(hwnd, BFFM_SETSELECTION, FALSE, (LPARAM)pidlDefault);
  3455. }
  3456. ILFree(pidlDefault);
  3457. }
  3458. }
  3459. break;
  3460. case BFFM_SELCHANGED: // prevent non-searchable folder pidls from being selected.
  3461. {
  3462. BOOL bAllow = pThis->_IsSearchableFolder((LPCITEMIDLIST)lParam);
  3463. ::SendMessage(hwnd, BFFM_ENABLEOK, 0, (LPARAM)bAllow);
  3464. }
  3465. break;
  3466. }
  3467. return 0;
  3468. }
  3469. class CSearchWarningDlg
  3470. {
  3471. private:
  3472. CSearchWarningDlg() : _hwnd(NULL), _bNoWarn(FALSE) {}
  3473. static BOOL_PTR WINAPI DlgProc(HWND, UINT, WPARAM, LPARAM);
  3474. HWND _hwnd;
  3475. BOOL _bNoWarn;
  3476. friend int CSearchWarningDlg_DoModal(HWND hwndParent, USHORT uDlgT, BOOL* pbNoWarn);
  3477. };
  3478. int CSearchWarningDlg_DoModal(HWND hwndParent, USHORT uDlgTemplate, BOOL* pbNoWarn)
  3479. {
  3480. ASSERT(pbNoWarn);
  3481. CSearchWarningDlg dlg;
  3482. dlg._bNoWarn = *pbNoWarn;
  3483. int nRet = (int)DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(uDlgTemplate),
  3484. hwndParent, CSearchWarningDlg::DlgProc, (LPARAM)&dlg);
  3485. *pbNoWarn = dlg._bNoWarn;
  3486. return nRet;
  3487. }
  3488. BOOL_PTR WINAPI CSearchWarningDlg::DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  3489. {
  3490. CSearchWarningDlg* pdlg = (CSearchWarningDlg*)GetWindowPtr(hwnd, GWLP_USERDATA);
  3491. if (WM_INITDIALOG == uMsg)
  3492. {
  3493. pdlg = (CSearchWarningDlg*)lParam;
  3494. pdlg->_hwnd = hwnd;
  3495. SetWindowPtr(hwnd, GWLP_USERDATA, pdlg);
  3496. CheckDlgButton(hwnd, IDC_NOSCOPEWARNING, pdlg->_bNoWarn);
  3497. MessageBeep(MB_ICONASTERISK);
  3498. return TRUE;
  3499. }
  3500. if (pdlg)
  3501. {
  3502. switch (uMsg)
  3503. {
  3504. case WM_COMMAND:
  3505. switch (GET_WM_COMMAND_ID(wParam, lParam))
  3506. {
  3507. case IDOK:
  3508. case IDCANCEL:
  3509. pdlg->_bNoWarn = IsDlgButtonChecked(hwnd, IDC_NOSCOPEWARNING);
  3510. EndDialog(hwnd, GET_WM_COMMAND_ID(wParam, lParam));
  3511. break;
  3512. }
  3513. return TRUE;
  3514. }
  3515. }
  3516. return FALSE;
  3517. }
  3518. class CCISettingsDlg
  3519. {
  3520. public:
  3521. CCISettingsDlg() : _hwnd(NULL), _fCiIndexed(FALSE), _fCiRunning(FALSE), _fCiPermission(FALSE), _hProcessMMC(INVALID_HANDLE_VALUE)
  3522. {
  3523. }
  3524. ~CCISettingsDlg()
  3525. {
  3526. if (_hProcessMMC != INVALID_HANDLE_VALUE)
  3527. CloseHandle(_hProcessMMC);
  3528. }
  3529. static int DoModal(HWND hwndParent);
  3530. static HWND CreateModeless(HWND hwndParent);
  3531. protected:
  3532. BOOL OnInitDialog();
  3533. BOOL OnOK();
  3534. private:
  3535. static BOOL_PTR WINAPI DlgProc(HWND, UINT, WPARAM, LPARAM);
  3536. void ShowAdvanced();
  3537. HWND _hwnd;
  3538. BOOL _fCiIndexed,
  3539. _fCiRunning,
  3540. _fCiPermission;
  3541. HANDLE _hProcessMMC;
  3542. friend int CCISettingsDlg_DoModal(HWND hwndParent);
  3543. };
  3544. int CCISettingsDlg_DoModal(HWND hwndParent)
  3545. {
  3546. CCISettingsDlg dlg;
  3547. return (int)DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_INDEXSERVER),
  3548. hwndParent, CCISettingsDlg::DlgProc, (LPARAM)&dlg);
  3549. }
  3550. BOOL_PTR WINAPI CCISettingsDlg::DlgProc(HWND hDlg, UINT nMsg, WPARAM wParam, LPARAM lParam)
  3551. {
  3552. CCISettingsDlg* pdlg = (CCISettingsDlg*)GetWindowPtr(hDlg, GWLP_USERDATA);
  3553. if (WM_INITDIALOG == nMsg)
  3554. {
  3555. pdlg = (CCISettingsDlg*)lParam;
  3556. pdlg->_hwnd = hDlg;
  3557. SetWindowPtr(hDlg, GWLP_USERDATA, pdlg);
  3558. return pdlg->OnInitDialog();
  3559. }
  3560. if (pdlg)
  3561. {
  3562. switch (nMsg)
  3563. {
  3564. case WM_NCDESTROY:
  3565. return TRUE;
  3566. case WM_COMMAND:
  3567. switch (GET_WM_COMMAND_ID(wParam, lParam))
  3568. {
  3569. case IDC_CI_ADVANCED:
  3570. pdlg->ShowAdvanced();
  3571. break;
  3572. case IDOK:
  3573. if (pdlg->OnOK())
  3574. EndDialog(hDlg, IDOK);
  3575. break;
  3576. case IDCANCEL:
  3577. EndDialog(hDlg, GET_WM_COMMAND_ID(wParam, lParam));
  3578. break;
  3579. case IDC_CI_HELP:
  3580. _IndexServiceHelp(hDlg);
  3581. break;
  3582. }
  3583. return TRUE;
  3584. }
  3585. }
  3586. return FALSE;
  3587. }
  3588. void CCISettingsDlg::ShowAdvanced()
  3589. {
  3590. // have we already spawned MMC?
  3591. if (_hProcessMMC != INVALID_HANDLE_VALUE)
  3592. {
  3593. if (WaitForSingleObject(_hProcessMMC, 0) != WAIT_OBJECT_0)
  3594. {
  3595. // MMC is still running, let user ATL+TAB or something but don't launch a second copy
  3596. return;
  3597. }
  3598. _hProcessMMC = INVALID_HANDLE_VALUE;
  3599. }
  3600. SHELLEXECUTEINFO sei = { sizeof(sei) };
  3601. sei.fMask = SEE_MASK_NOCLOSEPROCESS;
  3602. sei.nShow = SW_SHOWNORMAL;
  3603. sei.lpFile = TEXT("ciadv.msc");
  3604. sei.lpParameters = TEXT("computername=localmachine");
  3605. if (ShellExecuteEx(&sei))
  3606. {
  3607. _hProcessMMC = sei.hProcess;
  3608. }
  3609. }
  3610. BOOL CCISettingsDlg::OnInitDialog()
  3611. {
  3612. TCHAR szStatusFmt[128], szStatusText[MAX_PATH];
  3613. UINT nStatusText = IDS_FSEARCH_CI_DISABLED;
  3614. GetCIStatus(&_fCiRunning, &_fCiIndexed, &_fCiPermission);
  3615. if (_fCiRunning)
  3616. {
  3617. if (_fCiPermission)
  3618. // permission to distinguish between ready, busy.
  3619. nStatusText = _fCiIndexed ? IDS_FSEARCH_CI_READY : IDS_FSEARCH_CI_BUSY;
  3620. else
  3621. // no permission to distinguish between ready, busy; just say it's enabled.
  3622. nStatusText = IDS_FSEARCH_CI_ENABLED;
  3623. }
  3624. if (LoadString(HINST_THISDLL, IDS_FSEARCH_CI_STATUSFMT, szStatusFmt, ARRAYSIZE(szStatusFmt)))
  3625. {
  3626. if (LoadString(HINST_THISDLL, nStatusText, szStatusText, ARRAYSIZE(szStatusText)))
  3627. {
  3628. TCHAR szStatus[MAX_PATH];
  3629. wnsprintf(szStatus, ARRAYSIZE(szStatus), szStatusFmt, szStatusText);
  3630. SetDlgItemText(_hwnd, IDC_CI_STATUS, szStatus);
  3631. }
  3632. }
  3633. CheckDlgButton(_hwnd, IDC_ENABLE_CI, _fCiRunning);
  3634. CheckDlgButton(_hwnd, IDC_BLOWOFF_CI, !_fCiRunning);
  3635. EnableWindow(GetDlgItem(_hwnd, IDC_CI_PROMPT), _fCiPermission);
  3636. EnableWindow(GetDlgItem(_hwnd, IDC_ENABLE_CI), _fCiPermission);
  3637. EnableWindow(GetDlgItem(_hwnd, IDC_BLOWOFF_CI), _fCiPermission);
  3638. return TRUE;
  3639. }
  3640. BOOL CCISettingsDlg::OnOK()
  3641. {
  3642. StartStopCI(IsDlgButtonChecked(_hwnd, IDC_ENABLE_CI) ? TRUE : FALSE);
  3643. return TRUE;
  3644. }
  3645. #ifdef __PSEARCH_BANDDLG__
  3646. // CFindPrintersDlg impl
  3647. #define PSEARCHDLG_TABFIRST IDC_PSEARCH_NAME
  3648. #define PSEARCHDLG_TABLAST IDC_SEARCHLINK_INTERNET
  3649. #define PSEARCHDLG_RIGHTMOST IDC_SEARCH_START
  3650. #define PSEARCHDLG_BOTTOMMOST IDC_SEARCHLINK_INTERNET
  3651. CFindPrintersDlg::CFindPrintersDlg(CFileSearchBand* pfsb)
  3652. : CBandDlg(pfsb)
  3653. {
  3654. }
  3655. CFindPrintersDlg::~CFindPrintersDlg()
  3656. {
  3657. }
  3658. LRESULT CFindPrintersDlg::OnInitDialog(UINT, WPARAM, LPARAM, BOOL&)
  3659. {
  3660. _Attach(m_hWnd);
  3661. ASSERT(Hwnd());
  3662. CMetrics& metrics = _pfsb->GetMetrics();
  3663. _pfsb->GetMetrics().Init(m_hWnd);
  3664. POINT pt;
  3665. pt.x = metrics.CtlMarginX();
  3666. pt.y = 0;
  3667. _CreateSearchLinks(m_hWnd, pt, IDC_SEARCHLINK_PRINTERS);
  3668. _CreateDivider(m_hWnd, IDC_FSEARCH_DIV1, pt, 2, GetDlgItem(IDC_PSEARCH_CAPTION));
  3669. _CreateDivider(m_hWnd, IDC_FSEARCH_DIV2, pt, 1, GetDlgItem(IDC_SEARCHLINK_CAPTION));
  3670. _CreateDivider(m_hWnd, IDC_FSEARCH_DIV3, pt, 1, GetDlgItem(IDC_SEARCHLINK_PEOPLE));
  3671. OnWinIniChange();
  3672. LayoutControls(-1, -1);
  3673. return TRUE;
  3674. }
  3675. void CFindPrintersDlg::LayoutControls(int cx, int cy)
  3676. {
  3677. if (cx < 0 || cy < 0)
  3678. {
  3679. RECT rc;
  3680. GetClientRect(&rc);
  3681. cx = RECTWIDTH(rc);
  3682. cy = RECTHEIGHT(rc);
  3683. }
  3684. CBandDlg::LayoutControls(cx, cy);
  3685. CMetrics& metrics = _pfsb->GetMetrics();
  3686. const UINT nIDCtl[] = {
  3687. IDC_PSEARCH_NAME,
  3688. IDC_PSEARCH_LOCATION,
  3689. IDC_PSEARCH_MODEL,
  3690. };
  3691. RECT rcCtl[ARRAYSIZE(nIDCtl)];
  3692. // Stretch edit boxes to fit horz
  3693. for (int i = 0; i< ARRAYSIZE(nIDCtl); i++)
  3694. {
  3695. HWND hwndCtl = GetDlgItem(nIDCtl[i]);
  3696. if (hwndCtl && ::GetWindowRect(hwndCtl, &rcCtl[i]))
  3697. {
  3698. ::MapWindowRect(NULL, Hwnd(), &rcCtl[i]);
  3699. rcCtl[i].right = cx - metrics.CtlMarginX();
  3700. ::SetWindowPos(hwndCtl, NULL, 0, 0,
  3701. RECTWIDTH(*(rcCtl+i)), RECTHEIGHT(*(rcCtl+i)),
  3702. SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
  3703. }
  3704. else
  3705. SetRectEmpty(rcCtl + i);
  3706. }
  3707. // Position the 'Search for Other Items' caption, divider and link windows
  3708. const int rgLinks[] = {
  3709. IDC_SEARCHLINK_FILES,
  3710. IDC_SEARCHLINK_COMPUTERS,
  3711. IDC_SEARCHLINK_PRINTERS,
  3712. IDC_SEARCHLINK_PEOPLE,
  3713. -IDC_FSEARCH_DIV3,
  3714. IDC_SEARCHLINK_INTERNET,
  3715. };
  3716. RECT rc;
  3717. ::GetWindowRect(GetDlgItem(IDC_SEARCH_START), &rc);
  3718. ::MapWindowRect(NULL, m_hWnd, &rc);
  3719. rc.bottom += metrics.LooseMarginY();
  3720. _LayoutSearchLinks(IDC_SEARCHLINK_CAPTION, IDC_FSEARCH_DIV2, TRUE,
  3721. metrics.CtlMarginX(), cx - metrics.CtlMarginX(), metrics.TightMarginY(),
  3722. rc.bottom, rgLinks, ARRAYSIZE(rgLinks));
  3723. }
  3724. BOOL CFindPrintersDlg::Validate()
  3725. {
  3726. return TRUE;
  3727. }
  3728. void CFindPrintersDlg::Clear()
  3729. {
  3730. SetDlgItemText(IDC_PSEARCH_NAME, NULL);
  3731. SetDlgItemText(IDC_PSEARCH_LOCATION, NULL);
  3732. SetDlgItemText(IDC_PSEARCH_MODEL, NULL);
  3733. }
  3734. BOOL CFindPrintersDlg::GetMinSize(HWND hwndOC, SIZE *pSize) const
  3735. {
  3736. RECT rcRightmost, rcBottommost;
  3737. HWND hwndRightmost = GetDlgItem(PSEARCHDLG_RIGHTMOST),
  3738. hwndBottommost= GetDlgItem(PSEARCHDLG_BOTTOMMOST);
  3739. ASSERT(::IsWindow(hwndRightmost));
  3740. ASSERT(::IsWindow(hwndBottommost));
  3741. ::GetWindowRect(hwndRightmost, &rcRightmost);
  3742. ::MapWindowRect(NULL, m_hWnd, &rcRightmost);
  3743. ::GetWindowRect(hwndBottommost, &rcBottommost);
  3744. ::MapWindowRect(NULL, m_hWnd, &rcBottommost);
  3745. pSize->cx = rcRightmost.right;
  3746. pSize->cy = rcBottommost.bottom + _pfsb->GetMetrics().TightMarginY();
  3747. return TRUE;
  3748. }
  3749. HWND CFindPrintersDlg::GetFirstTabItem() const
  3750. {
  3751. return GetDlgItem(PSEARCHDLG_TABFIRST);
  3752. }
  3753. HWND CFindPrintersDlg::GetLastTabItem() const
  3754. {
  3755. return GetDlgItem(PSEARCHDLG_TABLAST);
  3756. }
  3757. STDMETHODIMP CFindPrintersDlg::TranslateAccelerator(MSG *pmsg)
  3758. {
  3759. if (S_OK == CBandDlg::TranslateAccelerator(pmsg))
  3760. return S_OK;
  3761. // Handle it ourselves...
  3762. return _pfsb->IsDlgMessage(m_hWnd, pmsg);
  3763. }
  3764. void CFindPrintersDlg::OnWinIniChange()
  3765. {
  3766. _BeautifyCaption(IDC_PSEARCH_CAPTION, IDC_PSEARCH_ICON, IDI_PSEARCH);
  3767. }
  3768. LRESULT CFindPrintersDlg::OnSearchStartBtn(WORD nCode, WORD nID, HWND hwndCtl, BOOL&)
  3769. {
  3770. WCHAR wszName[MAX_PATH],
  3771. wszLocation[MAX_PATH],
  3772. wszModel[MAX_PATH];
  3773. ::GetDlgItemTextW(m_hWnd, IDC_PSEARCH_NAME, wszName, ARRAYSIZE(wszName));
  3774. ::GetDlgItemTextW(m_hWnd, IDC_PSEARCH_LOCATION, wszLocation, ARRAYSIZE(wszLocation));
  3775. ::GetDlgItemTextW(m_hWnd, IDC_PSEARCH_MODEL, wszModel, ARRAYSIZE(wszModel));
  3776. ASSERT(_pfsb);
  3777. ASSERT(_pfsb->BandSite());
  3778. IShellDispatch2* psd2;
  3779. if (SUCCEEDED(CoCreateInstance(CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
  3780. IID_PPV_ARG(IShellDispatch2, &psd2))))
  3781. {
  3782. BSTR bstrName = *wszName ? SysAllocString(wszName) : NULL,
  3783. bstrLocation = *wszLocation ? SysAllocString(wszLocation) : NULL,
  3784. bstrModel = *wszModel ? SysAllocString(wszModel) : NULL;
  3785. if (FAILED(psd2->FindPrinter(bstrName, bstrLocation, bstrModel)))
  3786. {
  3787. SysFreeString(bstrName);
  3788. SysFreeString(bstrLocation);
  3789. SysFreeString(bstrModel);
  3790. }
  3791. psd2->Release();
  3792. }
  3793. return 0;
  3794. }
  3795. #endif __PSEARCH_BANDDLG__
  3796. // CFindComputersDlg impl
  3797. #define CSEARCHDLG_TABFIRST IDC_CSEARCH_NAME
  3798. #define CSEARCHDLG_TABLAST IDC_SEARCHLINK_INTERNET
  3799. #define CSEARCHDLG_RIGHTMOST IDC_SEARCH_STOP
  3800. #define CSEARCHDLG_BOTTOMMOST IDC_SEARCHLINK_INTERNET
  3801. CFindComputersDlg::CFindComputersDlg(CFileSearchBand* pfsb)
  3802. : CSearchCmdDlg(pfsb),
  3803. _pacComputerName(NULL),
  3804. _pmruComputerName(NULL)
  3805. {
  3806. }
  3807. CFindComputersDlg::~CFindComputersDlg()
  3808. {
  3809. ATOMICRELEASE(_pacComputerName);
  3810. ATOMICRELEASE(_pmruComputerName);
  3811. }
  3812. LRESULT CFindComputersDlg::OnInitDialog(UINT, WPARAM, LPARAM, BOOL&)
  3813. {
  3814. _Attach(m_hWnd);
  3815. ASSERT(Hwnd());
  3816. CMetrics& metrics = _pfsb->GetMetrics();
  3817. _pfsb->GetMetrics().Init(m_hWnd);
  3818. // Register specialty window classes.
  3819. DivWindow_RegisterClass();
  3820. POINT pt;
  3821. pt.x = metrics.CtlMarginX();
  3822. pt.y = 0;
  3823. _CreateSearchLinks(m_hWnd, pt, IDC_SEARCHLINK_COMPUTERS);
  3824. _CreateDivider(m_hWnd, IDC_FSEARCH_DIV1, pt, 2, GetDlgItem(IDC_CSEARCH_CAPTION));
  3825. _CreateDivider(m_hWnd, IDC_FSEARCH_DIV2, pt, 1, GetDlgItem(IDC_SEARCHLINK_CAPTION));
  3826. _CreateDivider(m_hWnd, IDC_FSEARCH_DIV3, pt, 1, GetDlgItem(IDC_SEARCHLINK_PEOPLE));
  3827. _InitializeMru(GetDlgItem(IDC_CSEARCH_NAME), &_pacComputerName,
  3828. TEXT("ComputerNameMRU"), &_pmruComputerName);
  3829. SendDlgItemMessage(IDC_CSEARCH_NAME, EM_LIMITTEXT, MAX_PATH, 0);
  3830. OnWinIniChange();
  3831. LayoutControls(-1, -1);
  3832. return TRUE;
  3833. }
  3834. LRESULT CFindComputersDlg::OnDestroy(UINT, WPARAM, LPARAM, BOOL& bHandled)
  3835. {
  3836. StopSearch();
  3837. if (_pSrchCmd)
  3838. {
  3839. DisconnectEvents();
  3840. IUnknown_SetSite(_pSrchCmd, NULL);
  3841. }
  3842. bHandled = FALSE;
  3843. _fOnDestroy = TRUE;
  3844. return 0;
  3845. }
  3846. void CFindComputersDlg::LayoutControls(int cx, int cy)
  3847. {
  3848. if (cx < 0 || cy < 0)
  3849. {
  3850. RECT rc;
  3851. GetClientRect(&rc);
  3852. cx = RECTWIDTH(rc);
  3853. cy = RECTHEIGHT(rc);
  3854. }
  3855. CBandDlg::LayoutControls(cx, cy);
  3856. const UINT nIDCtl[] = {
  3857. IDC_CSEARCH_NAME,
  3858. };
  3859. RECT rcCtl[ARRAYSIZE(nIDCtl)];
  3860. CMetrics& metrics = _pfsb->GetMetrics();
  3861. for (int i = 0; i< ARRAYSIZE(nIDCtl); i++)
  3862. {
  3863. HWND hwndCtl = GetDlgItem(nIDCtl[i]);
  3864. if (hwndCtl && ::GetWindowRect(hwndCtl, &rcCtl[i]))
  3865. {
  3866. ::MapWindowRect(NULL, m_hWnd, &rcCtl[i]);
  3867. rcCtl[i].right = cx - metrics.CtlMarginX();
  3868. ::SetWindowPos(hwndCtl, NULL, 0, 0,
  3869. RECTWIDTH(*(rcCtl+i)), RECTHEIGHT(*(rcCtl+i)),
  3870. SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
  3871. }
  3872. else
  3873. SetRectEmpty(rcCtl + i);
  3874. }
  3875. // Position the 'Search for Other Items' caption, divider and link windows
  3876. const int rgLinks[] = {
  3877. IDC_SEARCHLINK_FILES,
  3878. IDC_SEARCHLINK_COMPUTERS,
  3879. IDC_SEARCHLINK_PRINTERS,
  3880. IDC_SEARCHLINK_PEOPLE,
  3881. -IDC_FSEARCH_DIV3,
  3882. IDC_SEARCHLINK_INTERNET,
  3883. };
  3884. RECT rc;
  3885. ::GetWindowRect(GetDlgItem(IDC_SEARCH_START), &rc);
  3886. ::MapWindowRect(NULL, m_hWnd, &rc);
  3887. rc.bottom += metrics.LooseMarginY();
  3888. _LayoutSearchLinks(IDC_SEARCHLINK_CAPTION, IDC_FSEARCH_DIV2, TRUE,
  3889. metrics.CtlMarginX(), cx - metrics.CtlMarginX(), metrics.TightMarginY(),
  3890. rc.bottom, rgLinks, ARRAYSIZE(rgLinks));
  3891. }
  3892. BOOL CFindComputersDlg::Validate()
  3893. {
  3894. return TRUE;
  3895. }
  3896. STDMETHODIMP CFindComputersDlg::AddConstraints(ISearchCommandExt* pSrchCmd)
  3897. {
  3898. HRESULT hr = E_FAIL;
  3899. TCHAR szName[MAX_PATH];
  3900. if (::GetDlgItemText(m_hWnd, IDC_CSEARCH_NAME, szName, MAX_PATH) <= 0)
  3901. {
  3902. lstrcpy(szName, TEXT("*"));
  3903. }
  3904. VARIANT var;
  3905. hr = InitVariantFromStr(&var, szName);
  3906. if (SUCCEEDED(hr))
  3907. {
  3908. hr = _AddConstraint(pSrchCmd, L"SearchFor", &var);
  3909. if (SUCCEEDED(hr))
  3910. _AddMruStringFromWindow(_pmruComputerName, GetDlgItem(IDC_CSEARCH_NAME));
  3911. VariantClear(&var);
  3912. }
  3913. return hr;
  3914. }
  3915. void CFindComputersDlg::UpdateStatusText()
  3916. {
  3917. CSearchCmdDlg::UpdateStatusText();
  3918. }
  3919. void CFindComputersDlg::RestoreSearch()
  3920. {
  3921. CSearchCmdDlg::RestoreSearch();
  3922. }
  3923. void CFindComputersDlg::Clear()
  3924. {
  3925. CSearchCmdDlg::Clear();
  3926. SetDlgItemText(IDC_CSEARCH_NAME, NULL);
  3927. }
  3928. BOOL CFindComputersDlg::GetMinSize(HWND hwndOC, SIZE *pSize) const
  3929. {
  3930. RECT rcRightmost, rcBottommost;
  3931. HWND hwndRightmost = GetDlgItem(CSEARCHDLG_RIGHTMOST),
  3932. hwndBottommost= GetDlgItem(CSEARCHDLG_BOTTOMMOST);
  3933. ASSERT(::IsWindow(hwndRightmost));
  3934. ASSERT(::IsWindow(hwndBottommost));
  3935. ::GetWindowRect(hwndRightmost, &rcRightmost);
  3936. ::MapWindowRect(NULL, m_hWnd, &rcRightmost);
  3937. ::GetWindowRect(hwndBottommost, &rcBottommost);
  3938. ::MapWindowRect(NULL, m_hWnd, &rcBottommost);
  3939. pSize->cx = rcRightmost.right;
  3940. pSize->cy = rcBottommost.bottom + _pfsb->GetMetrics().TightMarginY();
  3941. return TRUE;
  3942. }
  3943. void CFindComputersDlg::NavigateToResults(IWebBrowser2* pwb2)
  3944. {
  3945. BSTR bstrUrl = SysAllocString(L"::{1f4de370-d627-11d1-ba4f-00a0c91eedba}");// CLSID_ComputerFindFolder
  3946. if (bstrUrl)
  3947. {
  3948. VARIANT varNil = {0};
  3949. pwb2->Navigate(bstrUrl, &varNil, &varNil, &varNil, &varNil);
  3950. SysFreeString(bstrUrl);
  3951. }
  3952. }
  3953. HWND CFindComputersDlg::GetFirstTabItem() const
  3954. {
  3955. return GetDlgItem(CSEARCHDLG_TABFIRST);
  3956. }
  3957. HWND CFindComputersDlg::GetLastTabItem() const
  3958. {
  3959. return GetDlgItem(CSEARCHDLG_TABLAST);
  3960. }
  3961. BOOL CFindComputersDlg::GetAutoCompleteObjectForWindow(HWND hwnd, IAutoComplete2** ppac2)
  3962. {
  3963. if (hwnd == GetDlgItem(IDC_CSEARCH_NAME))
  3964. {
  3965. *ppac2 = _pacComputerName;
  3966. (*ppac2)->AddRef();
  3967. return TRUE;
  3968. }
  3969. return CBandDlg::GetAutoCompleteObjectForWindow(hwnd, ppac2);
  3970. }
  3971. STDMETHODIMP CFindComputersDlg::TranslateAccelerator(MSG *pmsg)
  3972. {
  3973. if (S_OK == CSearchCmdDlg::TranslateAccelerator(pmsg))
  3974. return S_OK;
  3975. // Handle it ourselves...
  3976. return _pfsb->IsDlgMessage(m_hWnd, pmsg);
  3977. }
  3978. void CFindComputersDlg::OnWinIniChange()
  3979. {
  3980. // redisplay animated icon
  3981. HWND hwndIcon = GetDlgItem(IDC_CSEARCH_ICON);
  3982. Animate_Close(hwndIcon);
  3983. Animate_OpenEx(hwndIcon, HINST_THISDLL, MAKEINTRESOURCE(IDA_FINDCOMP));
  3984. _BeautifyCaption(IDC_CSEARCH_CAPTION);
  3985. }
  3986. LRESULT CFindComputersDlg::OnSearchStartBtn(WORD nCode, WORD nID, HWND hwndCtl, BOOL&)
  3987. {
  3988. if (SUCCEEDED(StartSearch()))
  3989. {
  3990. EnableStartStopButton(hwndCtl, FALSE);
  3991. StartStopAnimation(TRUE);
  3992. }
  3993. return 0;
  3994. }
  3995. LRESULT CFindComputersDlg::OnSearchStopBtn(WORD nCode, WORD nID, HWND hwndCtl, BOOL&)
  3996. {
  3997. StopSearch();
  3998. return 0;
  3999. }
  4000. HWND CFindComputersDlg::ShowHelp(HWND hwnd)
  4001. {
  4002. return ::HtmlHelp(hwnd, TEXT("find.chm"), HH_DISPLAY_TOPIC, 0);
  4003. }
  4004. // CSearchCmdDlg object wrap and event sink
  4005. CSearchCmdDlg::CSearchCmdDlg(CFileSearchBand* pfsb)
  4006. : CBandDlg(pfsb),
  4007. _pSrchCmd(NULL),
  4008. _pcp(NULL),
  4009. _dwConnection(0)
  4010. {
  4011. ASSERT(pfsb);
  4012. }
  4013. CSearchCmdDlg::~CSearchCmdDlg()
  4014. {
  4015. DisconnectEvents();
  4016. if (_pSrchCmd)
  4017. {
  4018. _pSrchCmd->Release();
  4019. _pSrchCmd = NULL;
  4020. }
  4021. }
  4022. ISearchCommandExt* CSearchCmdDlg::GetSearchCmd()
  4023. {
  4024. if (_fOnDestroy)
  4025. return NULL;
  4026. ASSERT(_pfsb->BandSite() != NULL);
  4027. // Instantiate docfind command object
  4028. if (NULL == _pSrchCmd)
  4029. {
  4030. ASSERT(0 == _dwConnection);
  4031. if (SUCCEEDED(CoCreateInstance(CLSID_DocFindCommand, NULL, CLSCTX_INPROC_SERVER,
  4032. IID_PPV_ARG(ISearchCommandExt, &_pSrchCmd))))
  4033. {
  4034. // Assign search type.
  4035. _pSrchCmd->SearchFor(GetSearchType());
  4036. // cmd object needs site to get to browser
  4037. IUnknown_SetSite(_pSrchCmd, _pfsb->BandSite());
  4038. // Connect events.
  4039. ConnectToConnectionPoint(SAFECAST(this, DSearchCommandEvents*), DIID_DSearchCommandEvents,
  4040. TRUE, _pSrchCmd, &_dwConnection, &_pcp);
  4041. }
  4042. }
  4043. return _pSrchCmd;
  4044. }
  4045. HRESULT CSearchCmdDlg::DisconnectEvents()
  4046. {
  4047. HRESULT hr = S_FALSE;
  4048. if (_pcp)
  4049. {
  4050. _pcp->Unadvise(_dwConnection);
  4051. _pcp->Release();
  4052. _pcp = NULL;
  4053. _dwConnection = 0;
  4054. hr = S_OK;
  4055. }
  4056. return hr;
  4057. }
  4058. HRESULT CSearchCmdDlg::StartSearch()
  4059. {
  4060. HRESULT hr = E_INVALIDARG;
  4061. if (Validate()) // Validate input
  4062. {
  4063. ISearchCommandExt* pSrchCmd = GetSearchCmd();
  4064. if (pSrchCmd)
  4065. {
  4066. pSrchCmd->ClearResults(); // Clear off current results
  4067. hr = AddConstraints(pSrchCmd);
  4068. if (SUCCEEDED(hr))
  4069. hr = Execute(TRUE);
  4070. }
  4071. }
  4072. return hr;
  4073. }
  4074. void CSearchCmdDlg::StartStopAnimation(BOOL bStart)
  4075. {
  4076. HWND hwndAnimate = GetAnimation();
  4077. if (IsWindow(hwndAnimate))
  4078. {
  4079. if (bStart)
  4080. Animate_Play(hwndAnimate, 0, -1, -1);
  4081. else
  4082. Animate_Stop(hwndAnimate);
  4083. }
  4084. }
  4085. // WMU_RESTORESEARCH handler
  4086. LRESULT CSearchCmdDlg::OnRestoreSearch(UINT, WPARAM, LPARAM, BOOL&)
  4087. {
  4088. // We've posted ourselves this message in response to the event
  4089. // dispatch because we want to do our restoration on the
  4090. // band's primary thread rather than the OLE dispatch thread.
  4091. // To do the work on the dispatch thread results in a premature
  4092. // abort of the search restoration processing as the dispatch
  4093. // thread terminates.
  4094. RestoreSearch();
  4095. return 0;
  4096. }
  4097. void CSearchCmdDlg::Clear()
  4098. {
  4099. StopSearch();
  4100. ISearchCommandExt *pSrchCmd = GetSearchCmd();
  4101. if (pSrchCmd)
  4102. pSrchCmd->ClearResults();
  4103. }
  4104. HRESULT CSearchCmdDlg::Execute(BOOL bStart)
  4105. {
  4106. ASSERT(_pSrchCmd);
  4107. VARIANT varRecordsAffected = {0}, varParams = {0};
  4108. return _pSrchCmd->Execute(&varRecordsAffected, &varParams, bStart ? 1 : 0);
  4109. }
  4110. void CSearchCmdDlg::StopSearch()
  4111. {
  4112. if (SearchInProgress())
  4113. Execute(FALSE);
  4114. }
  4115. HRESULT CSearchCmdDlg::SetQueryFile(IN VARIANT* pvarFile)
  4116. {
  4117. HRESULT hr = CBandDlg::SetQueryFile(pvarFile);
  4118. if (S_OK == hr)
  4119. {
  4120. ISearchCommandExt* pSrchCmd = GetSearchCmd();
  4121. if (pSrchCmd)
  4122. hr = pSrchCmd->RestoreSavedSearch(pvarFile);
  4123. else
  4124. hr = E_FAIL;
  4125. }
  4126. return hr;
  4127. }
  4128. void CSearchCmdDlg::UpdateSearchCmdStateUI(DISPID eventID)
  4129. {
  4130. if (_fOnDestroy)
  4131. return;
  4132. BOOL bStopEvent = (DISPID_SEARCHCOMMAND_COMPLETE == eventID ||
  4133. DISPID_SEARCHCOMMAND_ERROR == eventID ||
  4134. DISPID_SEARCHCOMMAND_ABORT == eventID),
  4135. bStartEvent = DISPID_SEARCHCOMMAND_START == eventID;
  4136. HWND hwndStart = GetDlgItem(Hwnd(), IDC_SEARCH_START),
  4137. hwndStop = GetDlgItem(Hwnd(), IDC_SEARCH_STOP);
  4138. if (IsWindow(hwndStart))
  4139. {
  4140. EnableStartStopButton(hwndStart, !SearchInProgress());
  4141. if (bStopEvent && IsChild(Hwnd(), GetFocus()))
  4142. {
  4143. _pfsb->AutoActivate();
  4144. SetFocus(hwndStart);
  4145. }
  4146. }
  4147. if (IsWindow(hwndStop))
  4148. {
  4149. EnableStartStopButton(hwndStop, SearchInProgress());
  4150. if (bStartEvent)
  4151. {
  4152. _pfsb->AutoActivate();
  4153. SetFocus(hwndStop);
  4154. }
  4155. }
  4156. if (bStopEvent || !SearchInProgress())
  4157. StartStopAnimation(FALSE);
  4158. }
  4159. void CSearchCmdDlg::EnableStartStopButton(HWND hwndBtn, BOOL bEnable)
  4160. {
  4161. if (IsWindow(hwndBtn))
  4162. {
  4163. if (bEnable)
  4164. _ModifyWindowStyle(hwndBtn, BS_DEFPUSHBUTTON, 0);
  4165. else
  4166. _ModifyWindowStyle(hwndBtn, 0, BS_DEFPUSHBUTTON);
  4167. ::EnableWindow(hwndBtn, bEnable);
  4168. }
  4169. }
  4170. // Extracts error information from ISearchCommandExt and
  4171. // propagate
  4172. BOOL CSearchCmdDlg::ProcessCmdError()
  4173. {
  4174. BOOL bRet = FALSE;
  4175. ISearchCommandExt* pSrchCmd = GetSearchCmd();
  4176. if (pSrchCmd)
  4177. {
  4178. HRESULT hr = S_OK;
  4179. BSTR bstrError = NULL;
  4180. USES_CONVERSION;
  4181. // request error information through ISearchCommandExt
  4182. if (SUCCEEDED(pSrchCmd->GetErrorInfo(&bstrError, (int *)&hr)))
  4183. // allow derivatives classes a crack at handling the error
  4184. bRet = OnSearchCmdError(hr, bstrError ? W2T(bstrError) : NULL);
  4185. }
  4186. return bRet;
  4187. }
  4188. BOOL CSearchCmdDlg::OnSearchCmdError(HRESULT hr, LPCTSTR pszError)
  4189. {
  4190. if (pszError)
  4191. {
  4192. ShellMessageBox(HINST_THISDLL, _pfsb->m_hWnd, pszError, NULL,
  4193. MB_OK | MB_ICONASTERISK);
  4194. return TRUE;
  4195. }
  4196. return FALSE;
  4197. }
  4198. void CSearchCmdDlg::UpdateStatusText()
  4199. {
  4200. if (_fOnDestroy)
  4201. return;
  4202. ASSERT(_pfsb && _pfsb->BandSite());
  4203. ISearchCommandExt* pSrchCmd = GetSearchCmd();
  4204. if (pSrchCmd)
  4205. {
  4206. BSTR bstrStatus;
  4207. if (SUCCEEDED(pSrchCmd->get_ProgressText(&bstrStatus)))
  4208. {
  4209. IWebBrowserApp* pwba;
  4210. if (SUCCEEDED(IUnknown_QueryServiceForWebBrowserApp(_pfsb->BandSite(), IID_PPV_ARG(IWebBrowserApp, &pwba))))
  4211. {
  4212. pwba->put_StatusText(bstrStatus);
  4213. pwba->Release();
  4214. }
  4215. if (bstrStatus)
  4216. SysFreeString(bstrStatus);
  4217. }
  4218. }
  4219. }
  4220. void CSearchCmdDlg::OnBandShow(BOOL bShow)
  4221. {
  4222. if (!bShow)
  4223. StopSearch() ;
  4224. }
  4225. STDMETHODIMP CSearchCmdDlg::TranslateAccelerator(MSG *pmsg)
  4226. {
  4227. if (S_OK == CBandDlg::TranslateAccelerator(pmsg))
  4228. return S_OK;
  4229. if (WM_KEYDOWN == pmsg->message &&
  4230. VK_ESCAPE == pmsg->wParam &&
  4231. SearchInProgress() &&
  4232. 0 == (GetKeyState(VK_CONTROL) & 0x8000))
  4233. {
  4234. StopSearch();
  4235. }
  4236. return S_FALSE;
  4237. }
  4238. STDMETHODIMP CSearchCmdDlg::QueryInterface(REFIID riid, void** ppv)
  4239. {
  4240. static const QITAB qit[] = {
  4241. QITABENTMULTI(CSearchCmdDlg, IDispatch, DSearchCommandEvents),
  4242. QITABENTMULTI2(CSearchCmdDlg, DIID_DSearchCommandEvents, DSearchCommandEvents),
  4243. { 0 },
  4244. };
  4245. return QISearch(this, qit, riid, ppv);
  4246. }
  4247. STDMETHODIMP_(ULONG) CSearchCmdDlg::AddRef()
  4248. {
  4249. return ((IFileSearchBand*)_pfsb)->AddRef();
  4250. }
  4251. STDMETHODIMP_(ULONG) CSearchCmdDlg::Release()
  4252. {
  4253. return ((IFileSearchBand*)_pfsb)->Release();
  4254. }
  4255. // IDispatch
  4256. STDMETHODIMP CSearchCmdDlg::Invoke(DISPID dispid, REFIID, LCID, WORD, DISPPARAMS*, VARIANT*, EXCEPINFO*, UINT*)
  4257. {
  4258. switch (dispid)
  4259. {
  4260. case DISPID_SEARCHCOMMAND_COMPLETE:
  4261. case DISPID_SEARCHCOMMAND_ABORT:
  4262. case DISPID_SEARCHCOMMAND_ERROR:
  4263. case DISPID_SEARCHCOMMAND_START:
  4264. _fSearchInProgress = (DISPID_SEARCHCOMMAND_START == dispid);
  4265. _fSearchAborted = (DISPID_SEARCHCOMMAND_ABORT == dispid);
  4266. UpdateSearchCmdStateUI(dispid);
  4267. if (DISPID_SEARCHCOMMAND_ERROR == dispid)
  4268. ProcessCmdError();
  4269. break;
  4270. case DISPID_SEARCHCOMMAND_PROGRESSTEXT:
  4271. UpdateStatusText();
  4272. break;
  4273. case DISPID_SEARCHCOMMAND_RESTORE:
  4274. PostMessage(Hwnd(), WMU_RESTORESEARCH, 0, 0);
  4275. // See comments in the CSearchCmdDlg::OnRestoreSearch message handler.
  4276. break;
  4277. }
  4278. return S_OK;
  4279. }
  4280. class CDivWindow
  4281. {
  4282. // All private members:
  4283. CDivWindow();
  4284. ~CDivWindow();
  4285. static LRESULT WINAPI WndProc(HWND, UINT, WPARAM, LPARAM);
  4286. LRESULT EraseBkgnd(HDC hdc);
  4287. LRESULT WindowPosChanging(WINDOWPOS* pwp);
  4288. LRESULT SetHeight(LONG cy);
  4289. LRESULT SetBkColor(COLORREF rgb);
  4290. static ATOM _atom; // window class atom
  4291. HWND _hwnd;
  4292. LONG _cy; // enforced height.
  4293. COLORREF _rgbBkgnd; // background color
  4294. HBRUSH _hbrBkgnd; // background brush
  4295. friend void WINAPI DivWindow_RegisterClass();
  4296. };
  4297. void DivWindow_RegisterClass()
  4298. {
  4299. WNDCLASSEX wc = {0};
  4300. wc.cbSize = sizeof(wc);
  4301. wc.style = CS_GLOBALCLASS;
  4302. wc.lpfnWndProc = CDivWindow::WndProc;
  4303. wc.hInstance = HINST_THISDLL;
  4304. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  4305. wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
  4306. wc.lpszClassName = DIVWINDOW_CLASS;
  4307. RegisterClassEx(&wc);
  4308. }
  4309. inline CDivWindow::CDivWindow() : _hwnd(NULL), _cy(1), _hbrBkgnd(NULL), _rgbBkgnd(COLOR_BTNFACE)
  4310. {
  4311. }
  4312. inline CDivWindow::~CDivWindow()
  4313. {
  4314. if (_hbrBkgnd)
  4315. DeleteObject(_hbrBkgnd);
  4316. }
  4317. LRESULT CDivWindow::EraseBkgnd(HDC hdc)
  4318. {
  4319. if (!_hbrBkgnd)
  4320. return DefWindowProc(_hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
  4321. RECT rc;
  4322. GetClientRect(_hwnd, &rc);
  4323. FillRect(hdc, &rc, _hbrBkgnd);
  4324. return TRUE;
  4325. }
  4326. LRESULT CDivWindow::WindowPosChanging(WINDOWPOS* pwp)
  4327. {
  4328. // enforce height
  4329. if (0 == (pwp->flags & SWP_NOSIZE))
  4330. pwp->cy = _cy;
  4331. return 0;
  4332. }
  4333. LRESULT CDivWindow::SetHeight(LONG cy)
  4334. {
  4335. _cy = cy;
  4336. return TRUE;
  4337. }
  4338. LRESULT CDivWindow::SetBkColor(COLORREF rgb)
  4339. {
  4340. if (rgb != _rgbBkgnd)
  4341. {
  4342. _rgbBkgnd = rgb;
  4343. if (_hbrBkgnd)
  4344. DeleteObject(_hbrBkgnd);
  4345. _hbrBkgnd = CreateSolidBrush(_rgbBkgnd);
  4346. InvalidateRect(_hwnd, NULL, TRUE);
  4347. }
  4348. return TRUE;
  4349. }
  4350. LRESULT WINAPI CDivWindow::WndProc(HWND hwnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
  4351. {
  4352. CDivWindow* pThis = (CDivWindow*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  4353. switch (nMsg)
  4354. {
  4355. case WM_ERASEBKGND:
  4356. return pThis->EraseBkgnd((HDC)wParam);
  4357. case WM_WINDOWPOSCHANGING:
  4358. return pThis->WindowPosChanging((WINDOWPOS*)lParam);
  4359. case WM_GETDLGCODE:
  4360. return DLGC_STATIC;
  4361. case DWM_SETHEIGHT:
  4362. return pThis->SetHeight((LONG)wParam);
  4363. case DWM_SETBKCOLOR:
  4364. return pThis->SetBkColor((COLORREF)wParam);
  4365. case WM_NCCREATE:
  4366. if (NULL == (pThis = new CDivWindow))
  4367. return FALSE;
  4368. pThis->_hwnd = hwnd;
  4369. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis);
  4370. break;
  4371. case WM_NCDESTROY:
  4372. {
  4373. LRESULT lRet = DefWindowProc(hwnd, nMsg, wParam, lParam);
  4374. SetWindowPtr(hwnd, GWLP_USERDATA, 0);
  4375. pThis->_hwnd = NULL;
  4376. delete pThis;
  4377. return lRet;
  4378. }
  4379. }
  4380. return DefWindowProc(hwnd, nMsg, wParam, lParam);
  4381. }
  4382. // {C8F945CB-327A-4330-BB2F-C04122959488}
  4383. static const IID IID_IStringMru =
  4384. { 0xc8f945cb, 0x327a, 0x4330, { 0xbb, 0x2f, 0xc0, 0x41, 0x22, 0x95, 0x94, 0x88 } };
  4385. // Creates and initializes a CStringMru instance
  4386. HRESULT CStringMru::CreateInstance(HKEY hKey, LPCTSTR szSubKey, LONG cMaxStrings, BOOL bCaseSensitive, REFIID riid, void ** ppv)
  4387. {
  4388. CStringMru* pmru = new CStringMru;
  4389. if (NULL == pmru)
  4390. return E_OUTOFMEMORY;
  4391. pmru->_hKeyRoot = hKey;
  4392. StrCpyN(pmru->_szSubKey, szSubKey, ARRAYSIZE(pmru->_szSubKey));
  4393. if (cMaxStrings > 0)
  4394. pmru->_cMax = cMaxStrings;
  4395. pmru->_bCaseSensitive = bCaseSensitive;
  4396. HRESULT hr = pmru->QueryInterface(riid, ppv);
  4397. pmru->Release();
  4398. return hr;
  4399. }
  4400. CStringMru::CStringMru() : _cRef(1), _hKeyRoot(NULL), _hKey(NULL),
  4401. _hdpaStrings(NULL), _cMax(25), _bCaseSensitive(TRUE), _iString(-1)
  4402. {
  4403. *_szSubKey = 0;
  4404. }
  4405. CStringMru::~CStringMru()
  4406. {
  4407. _Close();
  4408. _Clear();
  4409. }
  4410. // Opens string MRU store
  4411. HRESULT CStringMru::_Open()
  4412. {
  4413. if (_hKey)
  4414. return S_OK;
  4415. DWORD dwDisposition;
  4416. DWORD dwErr = RegCreateKeyEx(_hKeyRoot, _szSubKey, 0, NULL,
  4417. REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
  4418. NULL, &_hKey, &dwDisposition);
  4419. return HRESULT_FROM_WIN32(dwErr);
  4420. }
  4421. // Deletes string MRU store
  4422. void CStringMru::_Delete()
  4423. {
  4424. if (_hKey)
  4425. _Close();
  4426. SHDeleteKey(_hKeyRoot, _szSubKey);
  4427. }
  4428. // Reads string MRU store into memory
  4429. HRESULT CStringMru::_Read(OUT OPTIONAL LONG* pcRead)
  4430. {
  4431. HRESULT hr = E_FAIL;
  4432. if (pcRead)
  4433. *pcRead = 0;
  4434. if (SUCCEEDED((hr = _Open())))
  4435. {
  4436. _Clear(); // throw away existing cached strings
  4437. _hdpaStrings = DPA_Create(4); // allocate dynarray
  4438. if (NULL == _hdpaStrings)
  4439. {
  4440. hr = E_OUTOFMEMORY;
  4441. }
  4442. else
  4443. {
  4444. // step through string values in registry.
  4445. for (int iString = 0; iString < _cMax; iString++)
  4446. {
  4447. TCHAR szVal[16];
  4448. TCHAR szString[MAX_URL_STRING];
  4449. ULONG dwType, cbString = sizeof(szString);
  4450. wsprintf(szVal, TEXT("%03d"), iString);
  4451. DWORD dwErr = RegQueryValueEx(_hKey, szVal, 0, &dwType,
  4452. (LPBYTE)szString, &cbString);
  4453. if (dwErr == ERROR_SUCCESS && REG_SZ == dwType && *szString)
  4454. {
  4455. LPOLESTR pwszAdd;
  4456. if (SUCCEEDED(SHStrDup(szString, &pwszAdd)))
  4457. {
  4458. if (DPA_AppendPtr(_hdpaStrings, pwszAdd) == -1)
  4459. {
  4460. CoTaskMemFree(pwszAdd);
  4461. }
  4462. }
  4463. }
  4464. }
  4465. }
  4466. _Close();
  4467. if (pcRead && _hdpaStrings)
  4468. *pcRead = DPA_GetPtrCount(_hdpaStrings);
  4469. }
  4470. return hr;
  4471. }
  4472. // Writes string MRU store from memory
  4473. HRESULT CStringMru::_Write(OUT OPTIONAL LONG* pcWritten)
  4474. {
  4475. HRESULT hr = E_FAIL;
  4476. LONG cWritten = 0;
  4477. if (pcWritten)
  4478. *pcWritten = cWritten;
  4479. // Delete store and re-create.
  4480. _Delete();
  4481. if (NULL == _hdpaStrings)
  4482. return S_FALSE;
  4483. if (FAILED((hr = _Open())))
  4484. return hr;
  4485. ASSERT(DPA_GetPtrCount(_hdpaStrings) <= _cMax);
  4486. // step through string values in registry.
  4487. for (int iString = 0, cnt = DPA_GetPtrCount(_hdpaStrings);
  4488. iString < cnt; iString++)
  4489. {
  4490. TCHAR szVal[16];
  4491. TCHAR szString[MAX_URL_STRING];
  4492. wsprintf(szVal, TEXT("%03d"), iString);
  4493. LPOLESTR pwszWrite = (LPOLESTR)DPA_FastGetPtr(_hdpaStrings, iString);
  4494. SHUnicodeToTChar(pwszWrite, szString, ARRAYSIZE(szString));
  4495. DWORD dwErr = RegSetValueEx(_hKey, szVal, 0, REG_SZ,
  4496. (LPBYTE)szString, sizeof(szString));
  4497. if (ERROR_SUCCESS == dwErr)
  4498. cWritten++;
  4499. }
  4500. _Close();
  4501. if (pcWritten)
  4502. *pcWritten = cWritten;
  4503. return S_OK;
  4504. }
  4505. // Closes string MRU store
  4506. void CStringMru::_Close()
  4507. {
  4508. if (_hKey)
  4509. {
  4510. RegCloseKey(_hKey);
  4511. _hKey = NULL;
  4512. }
  4513. }
  4514. // Adds a string to the store
  4515. STDMETHODIMP CStringMru::Add(LPCOLESTR pwszAdd)
  4516. {
  4517. if (!(pwszAdd && *pwszAdd))
  4518. return E_INVALIDARG;
  4519. if (NULL == _hdpaStrings)
  4520. {
  4521. _hdpaStrings = DPA_Create(4);
  4522. if (NULL == _hdpaStrings)
  4523. return E_OUTOFMEMORY;
  4524. }
  4525. HRESULT hr = E_FAIL;
  4526. LONG iMatch = -1;
  4527. for (LONG i = 0, cnt = DPA_GetPtrCount(_hdpaStrings); i < cnt; i++)
  4528. {
  4529. LPOLESTR pwsz = (LPOLESTR)DPA_FastGetPtr(_hdpaStrings, i);
  4530. if (pwsz)
  4531. {
  4532. int nCompare = _bCaseSensitive ?
  4533. StrCmpW(pwszAdd, pwsz) : StrCmpIW(pwszAdd, pwsz);
  4534. if (0 == nCompare)
  4535. {
  4536. iMatch = i;
  4537. break;
  4538. }
  4539. }
  4540. }
  4541. if (-1 == iMatch)
  4542. {
  4543. // Create a copy and add it to the list.
  4544. LPOLESTR pwszCopy;
  4545. hr = SHStrDup(pwszAdd, &pwszCopy);
  4546. if (SUCCEEDED(hr))
  4547. {
  4548. int iNew = DPA_InsertPtr(_hdpaStrings, 0, pwszCopy);
  4549. if (iNew < 0)
  4550. {
  4551. CoTaskMemFree(pwszCopy);
  4552. hr = E_OUTOFMEMORY;
  4553. }
  4554. }
  4555. }
  4556. else
  4557. {
  4558. hr = _Promote(iMatch);
  4559. }
  4560. if (S_OK == hr)
  4561. {
  4562. // If we've grown too large, delete LRU string
  4563. int cStrings = DPA_GetPtrCount(_hdpaStrings);
  4564. while (cStrings > _cMax)
  4565. {
  4566. LPOLESTR pwsz = (LPOLESTR)DPA_DeletePtr(_hdpaStrings, cStrings - 1);
  4567. CoTaskMemFree(pwsz);
  4568. cStrings--;
  4569. }
  4570. hr = _Write();
  4571. }
  4572. return hr;
  4573. }
  4574. // Promotes a string to MRU
  4575. HRESULT CStringMru::_Promote(LONG iString)
  4576. {
  4577. if (0 == iString)
  4578. return S_OK;
  4579. LONG cnt = _hdpaStrings ? DPA_GetPtrCount(_hdpaStrings) : 0 ;
  4580. if (iString >= cnt)
  4581. return E_INVALIDARG;
  4582. LPOLESTR pwsz = (LPOLESTR)DPA_DeletePtr(_hdpaStrings, iString);
  4583. if (pwsz)
  4584. {
  4585. int iMru = DPA_InsertPtr(_hdpaStrings, 0, pwsz);
  4586. if (iMru < 0)
  4587. {
  4588. CoTaskMemFree(pwsz);
  4589. return E_OUTOFMEMORY;
  4590. }
  4591. else
  4592. {
  4593. ASSERT(0 == iMru);
  4594. return S_OK;
  4595. }
  4596. }
  4597. return E_FAIL;
  4598. }
  4599. // Clears string MRU memory cache
  4600. void CStringMru::_Clear()
  4601. {
  4602. if (_hdpaStrings)
  4603. {
  4604. for (int i = 0, cnt = DPA_GetPtrCount(_hdpaStrings); i < cnt; i++)
  4605. {
  4606. LPOLESTR pwsz = (LPOLESTR)DPA_FastGetPtr(_hdpaStrings, i);
  4607. CoTaskMemFree(pwsz);
  4608. }
  4609. DPA_Destroy(_hdpaStrings);
  4610. _hdpaStrings = NULL;
  4611. }
  4612. }
  4613. STDMETHODIMP_(ULONG) CStringMru::AddRef(void)
  4614. {
  4615. return InterlockedIncrement(&_cRef);
  4616. }
  4617. STDMETHODIMP_(ULONG) CStringMru::Release(void)
  4618. {
  4619. if (InterlockedDecrement(&_cRef))
  4620. return _cRef;
  4621. delete this;
  4622. return 0;
  4623. }
  4624. STDMETHODIMP CStringMru::QueryInterface(REFIID riid, void **ppv)
  4625. {
  4626. static const QITAB qit[] = {
  4627. QITABENT(CStringMru, IEnumString),
  4628. QITABENT(CStringMru, IStringMru),
  4629. { 0 },
  4630. };
  4631. return QISearch(this, qit, riid, ppv);
  4632. }
  4633. // *** IEnumString ***
  4634. STDMETHODIMP CStringMru::Next(ULONG celt, LPOLESTR *rgelt, ULONG *pceltFetched)
  4635. {
  4636. ULONG cFetched = 0;
  4637. if (pceltFetched)
  4638. *pceltFetched = cFetched;
  4639. if (NULL == _hdpaStrings)
  4640. {
  4641. HRESULT hr = _Read();
  4642. if (FAILED(hr))
  4643. return hr;
  4644. }
  4645. for (int cnt = _hdpaStrings ? DPA_GetPtrCount(_hdpaStrings) : 0;
  4646. cFetched < celt && (_iString + 1) < cnt;)
  4647. {
  4648. _iString++;
  4649. LPOLESTR pwsz = (LPOLESTR)DPA_FastGetPtr(_hdpaStrings, _iString);
  4650. if (pwsz)
  4651. {
  4652. if (SUCCEEDED(SHStrDup(pwsz, &rgelt[cFetched])))
  4653. {
  4654. cFetched++;
  4655. }
  4656. }
  4657. }
  4658. if (pceltFetched)
  4659. *pceltFetched = cFetched;
  4660. return cFetched == celt ? S_OK : S_FALSE ;
  4661. }
  4662. STDMETHODIMP CStringMru::Skip(ULONG celt)
  4663. {
  4664. _iString += celt;
  4665. if (_iString >= _cMax)
  4666. _iString = _cMax - 1;
  4667. return S_OK;
  4668. }
  4669. STDMETHODIMP CStringMru::Reset(void)
  4670. {
  4671. _iString = -1;
  4672. return S_OK;
  4673. }
  4674. // Namespace selector combo methods
  4675. HRESULT _BuildDrivesList(UINT uiFilter, LPCTSTR pszEnd, LPTSTR pszString, DWORD cchSize)
  4676. {
  4677. TCHAR szDriveList[MAX_PATH]; // Needs to be 'Z'-'A' (26) * 3 + 1 = 79.
  4678. UINT nSlot = 0;
  4679. UINT cchSeparator = lstrlen(TEXT(";"));
  4680. UINT cchEnd = lstrlen(pszEnd);
  4681. for (int i = 0; i < 26; i++)
  4682. {
  4683. TCHAR szDrive[4];
  4684. UINT uiDriveType = GetDriveType(PathBuildRoot(szDrive, i));
  4685. UINT driveNum, dwRest;
  4686. if ((driveNum = PathGetDriveNumber(szDrive)) != -1) {
  4687. dwRest = SHRestricted(REST_NODRIVES);
  4688. if (dwRest & (1 << driveNum))
  4689. continue;
  4690. }
  4691. if ((1 != uiDriveType) && // Make sure it exists.
  4692. ((-1 == uiFilter) ||
  4693. (uiFilter == uiDriveType)))
  4694. {
  4695. if (nSlot) // Do we need to add a separator before we add the next item?
  4696. {
  4697. StrCpy(szDriveList + nSlot, TEXT(";")); // Size guaranteed to not be a problem.
  4698. nSlot += cchSeparator;
  4699. }
  4700. szDriveList[nSlot++] = szDrive[0]; // terminate list.
  4701. StrCpy(szDriveList + nSlot, pszEnd); // Size guaranteed to not be a problem.
  4702. nSlot += cchEnd;
  4703. }
  4704. }
  4705. StrCpyN(pszString, szDriveList, cchSize); // Put back into the final location.
  4706. return S_OK;
  4707. }
  4708. HRESULT _MakeCSIDLCbxItem(UINT csidl, UINT csidl2, HWND hwndComboBoxEx, ADDCBXITEMCALLBACK pfn, LPARAM lParam)
  4709. {
  4710. LPCTSTR rgcsidl[2] = {MAKEINTRESOURCE(csidl), MAKEINTRESOURCE(csidl2)};
  4711. // note, CreateIEnumIDListOnCSIDLs checks SFGAO_NONENUMERATED so it filters
  4712. // out things we should not display
  4713. IEnumIDList *penum;
  4714. HRESULT hr = CreateIEnumIDListOnCSIDLs(NULL, rgcsidl, (-1 == csidl2 ? 1 : 2), &penum);
  4715. if (SUCCEEDED(hr))
  4716. {
  4717. LPITEMIDLIST pidl;
  4718. if (S_OK == FirstIDList(penum, &pidl))
  4719. {
  4720. TCHAR szName[MAX_PATH];
  4721. SHGetNameAndFlags(pidl, SHGDN_NORMAL, szName, ARRAYSIZE(szName), NULL);
  4722. CBXITEM item;
  4723. item.iID = csidl;
  4724. MakeCbxItem(&item, szName, penum, pidl, LISTINSERT_LAST, NO_ITEM_INDENT);
  4725. hr = AddCbxItemToComboBoxCallback(hwndComboBoxEx, &item, pfn, lParam);
  4726. if (SUCCEEDED(hr))
  4727. {
  4728. penum = NULL;
  4729. }
  4730. ILFree(pidl);
  4731. }
  4732. if (penum)
  4733. penum->Release();
  4734. }
  4735. return hr;
  4736. }
  4737. BOOL AppendItemToItemsArray(LPITEMIDLIST pidl, LPITEMIDLIST rgItems[], UINT sizeItems, UINT *pcItems)
  4738. {
  4739. BOOL bAdded = FALSE;
  4740. if (*pcItems < sizeItems)
  4741. {
  4742. DWORD dwFlags = SFGAO_NONENUMERATED;
  4743. if (SUCCEEDED(SHGetNameAndFlags(pidl, SHGDN_NORMAL, NULL, 0, &dwFlags)) &&
  4744. !(dwFlags & SFGAO_NONENUMERATED))
  4745. {
  4746. rgItems[(*pcItems)++] = pidl;
  4747. bAdded = TRUE;
  4748. pidl = NULL; // don't free below
  4749. }
  4750. }
  4751. ILFree(pidl); // will be NULL if added to array, ownership transfered
  4752. return bAdded;
  4753. }
  4754. BOOL AppendToItemsArray(LPCTSTR psz, LPITEMIDLIST rgItems[], UINT sizeItems, UINT *pcItems)
  4755. {
  4756. LPITEMIDLIST pidl;
  4757. if (IS_INTRESOURCE(psz))
  4758. {
  4759. SHGetFolderLocation(NULL, LOWORD((UINT_PTR)psz), NULL, 0, &pidl);
  4760. }
  4761. else
  4762. {
  4763. SHParseDisplayName(psz, NULL, &pidl, 0, NULL);
  4764. }
  4765. BOOL bAdded = FALSE;
  4766. if (pidl)
  4767. {
  4768. bAdded = AppendItemToItemsArray(pidl, rgItems, sizeItems, pcItems);
  4769. }
  4770. return bAdded;
  4771. }
  4772. // Create an item to put into the "look in" combo box for
  4773. // Local Hard Drives. Will search the following directories:
  4774. // 1. My Documents
  4775. // 2. The Desktop folder (not the root of all PIDLS)
  4776. // 3. My Pictures
  4777. // 4. My Music
  4778. // 5. Documents and Settings
  4779. // 6. The current directory
  4780. // 7. The recycle bin
  4781. // 8. All local drives.
  4782. #define MIR(x) MAKEINTRESOURCE(x)
  4783. HRESULT _MakeLocalHardDrivesCbxItem(HWND hwndComboBoxEx, ADDCBXITEMCALLBACK pfn, LPARAM lParam)
  4784. {
  4785. LPITEMIDLIST rgItems[32] = {0};
  4786. UINT cItems = 0;
  4787. AppendToItemsArray(MIR(CSIDL_PERSONAL), rgItems, ARRAYSIZE(rgItems), &cItems);
  4788. AppendToItemsArray(MIR(CSIDL_COMMON_DOCUMENTS | CSIDL_FLAG_NO_ALIAS), rgItems, ARRAYSIZE(rgItems), &cItems);
  4789. AppendToItemsArray(MIR(CSIDL_DESKTOPDIRECTORY | CSIDL_FLAG_NO_ALIAS), rgItems, ARRAYSIZE(rgItems), &cItems);
  4790. AppendToItemsArray(MIR(CSIDL_COMMON_DESKTOPDIRECTORY), rgItems, ARRAYSIZE(rgItems), &cItems);
  4791. AppendToItemsArray(MIR(CSIDL_MYPICTURES), rgItems, ARRAYSIZE(rgItems), &cItems);
  4792. AppendToItemsArray(MIR(CSIDL_MYMUSIC), rgItems, ARRAYSIZE(rgItems), &cItems);
  4793. AppendToItemsArray(MIR(CSIDL_MYVIDEO), rgItems, ARRAYSIZE(rgItems), &cItems);
  4794. TCHAR szPath[MAX_PATH];
  4795. DWORD cchPath = ARRAYSIZE(szPath);
  4796. if (GetProfilesDirectory(szPath, &cchPath))
  4797. {
  4798. AppendToItemsArray(szPath, rgItems, ARRAYSIZE(rgItems), &cItems);
  4799. }
  4800. AppendToItemsArray(MIR(CSIDL_BITBUCKET), rgItems, ARRAYSIZE(rgItems), &cItems);
  4801. TCHAR szDrives[128];
  4802. szDrives[0] = 0;
  4803. LPITEMIDLIST pidlIcon = NULL;
  4804. for (int i = 0; i < 26; i++)
  4805. {
  4806. TCHAR szDrive[4];
  4807. if (DRIVE_FIXED == GetDriveType(PathBuildRoot(szDrive, i)))
  4808. {
  4809. if (AppendToItemsArray(szDrive, rgItems, ARRAYSIZE(rgItems), &cItems))
  4810. {
  4811. // grab the pidl of the first time to use for the icon
  4812. if (pidlIcon == NULL)
  4813. SHParseDisplayName(szDrive, NULL, &pidlIcon, 0, NULL);
  4814. if (szDrives[0])
  4815. StrCatBuff(szDrives, TEXT(";"), ARRAYSIZE(szDrives));
  4816. szDrive[2] = 0; // remove the back slash
  4817. StrCatBuff(szDrives, szDrive, ARRAYSIZE(szDrives));
  4818. }
  4819. }
  4820. }
  4821. IEnumIDList *penum;
  4822. HRESULT hr = CreateIEnumIDListOnIDLists(rgItems, cItems, &penum);
  4823. if (SUCCEEDED(hr))
  4824. {
  4825. TCHAR szFmt[64];
  4826. LoadString(HINST_THISDLL, IDS_SNS_LOCALHARDDRIVES, szFmt, ARRAYSIZE(szFmt));
  4827. wnsprintf(szPath, ARRAYSIZE(szPath), szFmt, szDrives);
  4828. CBXITEM item;
  4829. MakeCbxItem(&item, szPath, penum, pidlIcon, LISTINSERT_LAST, ITEM_INDENT);
  4830. item.iID = CBX_CSIDL_LOCALDRIVES;
  4831. hr = AddCbxItemToComboBoxCallback(hwndComboBoxEx, &item, pfn, lParam);
  4832. if (FAILED(hr))
  4833. penum->Release();
  4834. }
  4835. ILFree(pidlIcon);
  4836. return hr;
  4837. }
  4838. typedef struct
  4839. {
  4840. HWND hwndComboBox;
  4841. ADDCBXITEMCALLBACK pfn;
  4842. LPARAM lParam;
  4843. } ENUMITEMPARAM;
  4844. HRESULT _PopulateDrivesCB(LPCITEMIDLIST pidl, void *pv)
  4845. {
  4846. ENUMITEMPARAM* peip = (ENUMITEMPARAM*)pv;
  4847. ULONG ulAttrs = SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_NONENUMERATED;
  4848. TCHAR szName[MAX_PATH];
  4849. HRESULT hr = SHGetNameAndFlags(pidl, SHGDN_NORMAL, szName, ARRAYSIZE(szName), &ulAttrs);
  4850. if (SUCCEEDED(hr))
  4851. {
  4852. if ((SFGAO_FOLDER | SFGAO_FILESYSTEM) == (ulAttrs & (SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_NONENUMERATED)))
  4853. {
  4854. IEnumIDList *penum;
  4855. hr = CreateIEnumIDListOnIDLists(&pidl, 1, &penum);
  4856. if (SUCCEEDED(hr))
  4857. {
  4858. CBXITEM item;
  4859. MakeCbxItem(&item, szName, penum, pidl, LISTINSERT_LAST, ITEM_INDENT);
  4860. item.iID = CSIDL_DRIVES;
  4861. hr = AddCbxItemToComboBoxCallback(peip->hwndComboBox, &item, peip->pfn, peip->lParam);
  4862. if (SUCCEEDED(hr))
  4863. {
  4864. penum = NULL;
  4865. }
  4866. else
  4867. {
  4868. penum->Release();
  4869. }
  4870. }
  4871. }
  4872. else
  4873. {
  4874. hr = S_FALSE;
  4875. }
  4876. }
  4877. return hr;
  4878. }
  4879. STDAPI PopulateNamespaceCombo(HWND hwndComboBoxEx, ADDCBXITEMCALLBACK pfn, LPARAM lParam)
  4880. {
  4881. ::SendMessage(hwndComboBoxEx, CB_RESETCONTENT, 0, 0);
  4882. // CSIDL_DESKTOP - use just the file system locations, not the root of the whole
  4883. // name space here to avoid searching everything
  4884. HRESULT hr = _MakeCSIDLCbxItem(CSIDL_DESKTOPDIRECTORY | CSIDL_FLAG_NO_ALIAS,
  4885. CSIDL_COMMON_DESKTOPDIRECTORY | CSIDL_FLAG_NO_ALIAS, hwndComboBoxEx, pfn, lParam);
  4886. if (SUCCEEDED(hr))
  4887. hr = _MakeCSIDLCbxItem(CSIDL_PERSONAL, -1, hwndComboBoxEx, pfn, lParam);
  4888. if (SUCCEEDED(hr))
  4889. hr = _MakeCSIDLCbxItem(CSIDL_MYPICTURES, -1, hwndComboBoxEx, pfn, lParam);
  4890. if (SUCCEEDED(hr))
  4891. hr = _MakeCSIDLCbxItem(CSIDL_MYMUSIC, -1, hwndComboBoxEx, pfn, lParam);
  4892. if (SUCCEEDED(hr))
  4893. {
  4894. // My Computer and children
  4895. // If My Docs has been redirected to a remote share, we'll want to prepend its path
  4896. // to our My Computer path list; otherwise it'll be missed.
  4897. UINT csidl2 = -1;
  4898. TCHAR szPath[MAX_PATH];
  4899. if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, szPath)) &&
  4900. PathIsNetworkPath(szPath))
  4901. {
  4902. csidl2 = CSIDL_PERSONAL;
  4903. }
  4904. hr = _MakeCSIDLCbxItem(CSIDL_DRIVES, csidl2, hwndComboBoxEx, pfn, lParam);
  4905. if (SUCCEEDED(hr))
  4906. {
  4907. // Local hard drives (Which has heuristics to search best places first...)
  4908. hr = _MakeLocalHardDrivesCbxItem(hwndComboBoxEx, pfn, lParam);
  4909. if (SUCCEEDED(hr))
  4910. {
  4911. ENUMITEMPARAM eip = {0};
  4912. eip.hwndComboBox = hwndComboBoxEx;
  4913. eip.pfn = pfn;
  4914. eip.lParam = lParam;
  4915. hr = EnumSpecialItemIDs(CSIDL_DRIVES, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, _PopulateDrivesCB, &eip);
  4916. }
  4917. }
  4918. }
  4919. if (SUCCEEDED(hr))
  4920. {
  4921. // Browse...
  4922. CBXITEM item;
  4923. item.iID = -1;
  4924. TCHAR szDisplayName[MAX_PATH];
  4925. LoadString(HINST_THISDLL, IDS_SNS_BROWSER_FOR_DIR, szDisplayName, ARRAYSIZE(szDisplayName));
  4926. MakeCbxItem(&item, szDisplayName, NULL, NULL, LISTINSERT_LAST, NO_ITEM_NOICON_INDENT);
  4927. hr = AddCbxItemToComboBoxCallback(hwndComboBoxEx, &item, pfn, lParam);
  4928. }
  4929. return hr;
  4930. }