Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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