#include "shellprv.h" #include "findband.h" #include "finddlg.h" #include "findfilter.h" // DFW_xxx warning flags. #include "enumidlist.h" void DivWindow_RegisterClass(); // Namespace picker combo methods. STDAPI PopulateNamespaceCombo(HWND hwndComboEx, ADDCBXITEMCALLBACK pfn, LPARAM lParam); #define MAX_EDIT 256 #define SUBDLG_BORDERWIDTH 0 #define MIN_NAMESPACELIST_WIDTH 140 #define MIN_FILEASSOCLIST_WIDTH 175 #define LSUIS_WARNING 1 // LoadSaveUIState warning flags int CSearchWarningDlg_DoModal(HWND hwndParent, USHORT uDlgTemplate, BOOL* pbNoWarn); int CCISettingsDlg_DoModal(HWND hwndParent); BOOL IsConstraintName(LPCWSTR pwszConstraint, LPCWSTR pwszName) { return pwszName && (0 == StrCmpIW(pwszName, pwszConstraint)); } BOOL _GetWindowSize(HWND hwndDlg, SIZE *pSize) { RECT rc; if (::GetClientRect(hwndDlg, &rc)) { pSize->cx = RECTWIDTH(rc); pSize->cy = RECTHEIGHT(rc); return TRUE; } return FALSE; } BOOL _ModifyWindowStyle(HWND hwnd, DWORD dwAdd, DWORD dwRemove) { ASSERT(dwAdd || dwRemove); if (IsWindow(hwnd)) { DWORD dwStyle = GetWindowLong(hwnd, GWL_STYLE); if (dwAdd) dwStyle |= dwAdd; if (dwRemove) dwStyle &= ~dwRemove; SetWindowLong(hwnd, GWL_STYLE, dwStyle); return TRUE; } return FALSE; } BOOL _EnforceNumericEditRange( IN HWND hwndDlg, IN UINT nIDEdit, IN UINT nIDSpin, IN LONG nLow, IN LONG nHigh, IN BOOL bSigned = FALSE) { BOOL bRet = FALSE; BOOL bReset = FALSE; LONG lRet = -1; if (nIDSpin) { lRet = (LONG)SendDlgItemMessage(hwndDlg, nIDSpin, UDM_GETPOS, 0, 0); bRet = 0 == HIWORD(lRet); } if (!bRet) lRet = (LONG)GetDlgItemInt(hwndDlg, nIDEdit, &bRet, bSigned); if (lRet < nLow) { lRet = nLow; bReset = TRUE; } else if (lRet > nHigh) { lRet = nHigh; bReset = TRUE; } if (bReset) SetDlgItemInt(hwndDlg, nIDEdit, lRet, bSigned); return bRet; } BOOL _IsDirectoryServiceAvailable() { BOOL bRet = FALSE; IShellDispatch2* psd; if (SUCCEEDED(CoCreateInstance(CLSID_Shell, 0, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellDispatch2, &psd)))) { BSTR bstrName = SysAllocString(L"DirectoryServiceAvailable"); if (bstrName) { VARIANT varRet = {0}; if (SUCCEEDED(psd->GetSystemInformation(bstrName, &varRet))) { ASSERT(VT_BOOL == varRet.vt); bRet = varRet.boolVal; } SysFreeString(bstrName); } psd->Release(); } return bRet; } // Calculates number of pixels for dialog template units LONG _PixelsForDbu(HWND hwndDlg, LONG cDbu, BOOL bHorz) { RECT rc = {0,0,0,0}; if (bHorz) rc.right = cDbu; else rc.bottom = cDbu; if (MapDialogRect(hwndDlg, &rc)) return bHorz ? RECTWIDTH(rc) : RECTHEIGHT(rc); return 0; } // Retrieves a localizable horizontal or vertical metric value from // the resource module. LONG _GetResourceMetric(HWND hwndDlg, UINT nIDResource, BOOL bHorz /*orientation of metric*/) { TCHAR szMetric[48]; if (!EVAL(LoadString(HINST_THISDLL, nIDResource, szMetric, ARRAYSIZE(szMetric)))) return 0; LONG n = StrToInt(szMetric); return _PixelsForDbu(hwndDlg, n, bHorz); } // Calculates the date nDays + nMonths from pstSrc. nDays and/or nMonths // can be negative values. BOOL _CalcDateOffset(const SYSTEMTIME* pstSrc, int nDays, int nMonths, OUT SYSTEMTIME* pstDest) { ASSERT(pstSrc); ASSERT(pstDest); // Subtract 90 days from current date and stuff in date low range FILETIME ft; SystemTimeToFileTime(pstSrc, &ft); LARGE_INTEGER t; t.LowPart = ft.dwLowDateTime; t.HighPart = ft.dwHighDateTime; nDays += MulDiv(nMonths, 1461 /*days per 4 yrs*/, 48 /*months per 4 yrs*/); t.QuadPart += Int32x32To64(nDays * 24 /*hrs per day*/ * 3600 /*seconds per hr*/, 10000000 /*100 ns intervals per sec*/); ft.dwLowDateTime = t.LowPart; ft.dwHighDateTime = t.HighPart; FileTimeToSystemTime(&ft, pstDest); return TRUE; } // Loads a string into a combo box and assigns the string resource ID value // to the combo item's data. BOOL _LoadStringToCombo(HWND hwndCombo, int iPos, UINT idString, LPARAM lpData) { TCHAR szText[MAX_EDIT]; if (LoadString(HINST_THISDLL, idString, szText, ARRAYSIZE(szText))) { INT_PTR idx = ::SendMessage(hwndCombo, CB_INSERTSTRING, iPos, (LPARAM)szText); if (idx != CB_ERR) { ::SendMessage(hwndCombo, CB_SETITEMDATA, idx, lpData); return TRUE; } } return FALSE; } // Retrieves combo item's data. If idx == CB_ERR, the currently selected // item's data will be retrieved. LPARAM _GetComboData(HWND hwndCombo, INT_PTR idx = CB_ERR) { if (CB_ERR == idx) idx = SendMessage(hwndCombo, CB_GETCURSEL, 0, 0); if (CB_ERR == idx) return idx; return (LPARAM)::SendMessage(hwndCombo, CB_GETITEMDATA, idx, 0); } // Selects combo item with matching data, and returns the index // of the selected item. INT_PTR _SelectComboData(HWND hwndCombo, LPARAM lpData) { for (INT_PTR i = 0, cnt = SendMessage(hwndCombo, CB_GETCOUNT, 0, 0); i < cnt; i++) { LPARAM lParam = SendMessage(hwndCombo, CB_GETITEMDATA, i, 0); if (lParam != CB_ERR && lParam == lpData) { SendMessage(hwndCombo, CB_SETCURSEL, i, 0); return i; } } return CB_ERR; } BOOL _IsPathList(LPCTSTR pszPath) { return pszPath ? StrChr(pszPath, TEXT(';')) != NULL : FALSE; } HRESULT _IsPathValidUNC(HWND hWndParent, BOOL fNetValidate, LPCTSTR pszPath) { HRESULT hr = S_OK; if (PathIsUNC(pszPath)) { if (fNetValidate) { NETRESOURCE nr = {0}; TCHAR szPathBuffer[MAX_PATH]; hr = StringCchCopy(szPathBuffer, ARRAYSIZE(szPathBuffer), pszPath); if (SUCCEEDED(hr)) { nr.dwType = RESOURCETYPE_DISK; nr.lpRemoteName = szPathBuffer; if (NO_ERROR != WNetAddConnection3(hWndParent, &nr, NULL, NULL, CONNECT_TEMPORARY | CONNECT_INTERACTIVE)) { hr = E_FILE_NOT_FOUND; } } else { hr = E_FILE_NOT_FOUND; // Handle it like it's a bad file name } } } else { hr = S_FALSE; } return hr; } BOOL _IsFullPathMinusDriveLetter(LPCTSTR pszPath) { if (NULL == pszPath || PathIsUNC(pszPath)) return FALSE; ASSERT(!PathIsRelative(pszPath)); // Eat whitespace for (; (0 != *pszPath) && (TEXT(' ') == *pszPath) ; pszPath = CharNext(pszPath)); return TEXT('\\') == *pszPath && -1 == PathGetDriveNumber(pszPath); } BOOL _PathLooksLikeFilePattern(LPCTSTR pszPath) { return StrPBrk(pszPath, TEXT("?*")) != NULL; } BOOL _PathIsDblSlash(LPCTSTR pszPath) { return pszPath && (pszPath[0] == TEXT('\\')) && (pszPath[1] == TEXT('\\')); } BOOL _PathIsUNCServerShareOrSub(LPCTSTR pszPath) { int cSlash = 0; if (_PathIsDblSlash(pszPath)) { for (LPTSTR psz = (LPTSTR)pszPath; psz && *psz; psz = CharNext(psz)) { if (*psz == TEXT('\\')) cSlash++; } } return cSlash >= 3; } BOOL _IsPathLocalHarddrive(LPCTSTR pszPath) { int iDrive = PathGetDriveNumber(pszPath); if (iDrive != -1) { TCHAR szRoot[16]; return DRIVE_FIXED == GetDriveType(PathBuildRoot(szRoot, iDrive)); } return FALSE; } // from an object in the browser and it's site find the current pidl of what // we are looking at HRESULT _GetCurrentFolderIDList(IUnknown* punkSite, LPITEMIDLIST *ppidl) { *ppidl = NULL; IShellBrowser* psb; HRESULT hr = IUnknown_QueryService(punkSite, SID_STopLevelBrowser, IID_PPV_ARG(IShellBrowser, &psb)); if (SUCCEEDED(hr)) { IShellView* psv; hr = psb->QueryActiveShellView(&psv); if (SUCCEEDED(hr)) { IFolderView *pfv; hr = psv->QueryInterface(IID_PPV_ARG(IFolderView, &pfv)); if (SUCCEEDED(hr)) { IShellFolder* psf; hr = pfv->GetFolder(IID_PPV_ARG(IShellFolder, &psf)); if (SUCCEEDED(hr)) { hr = SHGetIDListFromUnk(psf, ppidl); psf->Release(); } pfv->Release(); } psv->Release(); } psb->Release(); } return hr; } HRESULT _PathValidate(LPCTSTR pszPath, HWND hWndParent, BOOL fNetValidate) { HRESULT hr = _IsPathValidUNC(hWndParent, fNetValidate, pszPath); if (S_OK == hr) { // We are done. } else if (E_FILE_NOT_FOUND != hr) { if (_IsPathList(pszPath) || PathIsSlow(pszPath, -1)) { hr = S_OK; // Skip check for slow files. } else { DWORD dwAttr; if (PathIsRelative(pszPath) || _IsFullPathMinusDriveLetter(pszPath)) { hr = E_FILE_NOT_FOUND; // don't accept anything but a fully qualified path at this point. dwAttr = -1; } else { dwAttr = GetFileAttributes(pszPath); // Does it exist? if (-1 == dwAttr) { HRESULT hrFromPrepareForWrite = S_OK; // Maybe the disk isn't inserted, so allow the user // the chance to insert it. if (hWndParent) { hrFromPrepareForWrite = SHPathPrepareForWrite(hWndParent, NULL, pszPath, SHPPFW_IGNOREFILENAME); if (SUCCEEDED(hrFromPrepareForWrite)) dwAttr = GetFileAttributes(pszPath); // Does it exist now? } // If SHPathPrepareForWrite() displays UI, then they will return HRESULT_FROM_WIN32(ERROR_CANCELLED) // so that the callers (us) will skip displaying our UI. If this is the case, when propagate that error. if (HRESULT_FROM_WIN32(ERROR_CANCELLED) == hrFromPrepareForWrite) { hr = hrFromPrepareForWrite; } else { if (-1 == dwAttr) hr = E_FILE_NOT_FOUND; // It doesn't exist. else hr = S_OK; // It exists now. } } } } } return hr; } BOOL _FmtError(UINT nIDFmt, LPCTSTR pszSub, LPTSTR szBuf, int cchBuf) { TCHAR szFmt[MAX_PATH]; if (EVAL(LoadString(HINST_THISDLL, nIDFmt, szFmt, ARRAYSIZE(szFmt)))) { StringCchPrintf(szBuf, cchBuf, szFmt, pszSub); // ok to truncate return TRUE; } return FALSE; } // Retrieves the window text as a variant value of the specified type. HRESULT _GetWindowValue(HWND hwndDlg, UINT nID, VARIANT* pvar) { TCHAR szText[MAX_EDIT]; LPTSTR pszText; if (::GetDlgItemText(hwndDlg, nID, szText, ARRAYSIZE(szText))) pszText = szText; else pszText = NULL; return InitVariantFromStr(pvar, pszText); } // Loads the window text from a string resource. BOOL _LoadWindowText(HWND hwnd, UINT nIDString) { TCHAR szText[MAX_PATH]; if (LoadString(HINST_THISDLL, nIDString, szText, ARRAYSIZE(szText))) return SetWindowText(hwnd, szText); return FALSE; } // Retrieves the window text as a variant value of the specified type. HRESULT _SetWindowValue(HWND hwndDlg, UINT nID, const VARIANT* pvar) { switch (pvar->vt) { case VT_BSTR: SetDlgItemTextW(hwndDlg, nID, pvar->bstrVal); break; case VT_UI4: SetDlgItemInt(hwndDlg, nID, pvar->uiVal, FALSE); break; case VT_I4: SetDlgItemInt(hwndDlg, nID, pvar->lVal, TRUE); break; default: return E_NOTIMPL; } return S_OK; } // Adds a named constraint to the specified search command extension object HRESULT _AddConstraint(ISearchCommandExt* pSrchCmd, LPCWSTR pwszConstraint, VARIANT* pvarValue) { HRESULT hr; BSTR bstrConstraint = SysAllocString(pwszConstraint); if (bstrConstraint) { hr = pSrchCmd->AddConstraint(bstrConstraint, *pvarValue); SysFreeString(bstrConstraint); } else hr = E_OUTOFMEMORY; return hr; } void _PaintDlg(HWND hwndDlg, const CMetrics& metrics, HDC hdcPaint = NULL, LPCRECT prc = NULL) { RECT rcPaint /* rcLine */; HDC hdc = hdcPaint; if (NULL == hdcPaint) hdc = GetDC(hwndDlg); if (prc == NULL) { GetClientRect(hwndDlg, &rcPaint); prc = &rcPaint; } FillRect(hdc, prc, metrics.BkgndBrush()); if (NULL == hdcPaint) ReleaseDC(hwndDlg, hdc); } void _EnsureVisible(HWND hwndDlg, HWND hwndVis, CFileSearchBand* pfsb) { ASSERT(pfsb); ASSERT(::IsWindow(hwndDlg)); ASSERT(::IsWindow(hwndVis)); RECT rcDlg, rcVis, rcX; GetWindowRect(hwndDlg, &rcDlg); GetWindowRect(hwndVis, &rcVis); if (IntersectRect(&rcX, &rcDlg, &rcVis)) pfsb->EnsureVisible(&rcX); } inline BOOL _IsKeyPressed(int virtkey) { return (GetKeyState(virtkey) & 8000) != 0; } HWND _CreateDivider(HWND hwndParent, UINT nIDC, const POINT& pt, int nThickness = 1, HWND hwndAfter = NULL) { HWND hwndDiv = CreateWindowEx(0, DIVWINDOW_CLASS, NULL, WS_CHILD|WS_CLIPSIBLINGS|WS_VISIBLE, pt.x, pt.y, 400, 1, hwndParent, IntToPtr_(HMENU, nIDC), HINST_THISDLL, NULL); if (IsWindow(hwndDiv)) { if (IsWindow(hwndAfter)) SetWindowPos(hwndDiv, hwndAfter, 0,0,0,0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE); SendMessage(hwndDiv, DWM_SETHEIGHT, nThickness, 0); return hwndDiv; } return NULL; } HWND _CreateLinkWindow(HWND hwndParent, UINT nIDC, const POINT& pt, UINT nIDCaption, BOOL bShow = TRUE) { DWORD dwStyle = WS_CHILD|WS_TABSTOP|WS_CLIPSIBLINGS; if (bShow) dwStyle |= WS_VISIBLE; HWND hwndCtl = CreateWindowEx(0, WC_LINK, NULL, dwStyle, pt.x, pt.y, 400, 18, hwndParent, IntToPtr_(HMENU, nIDC), HINST_THISDLL, NULL); if (IsWindow(hwndCtl)) { _LoadWindowText(hwndCtl, nIDCaption); return hwndCtl; } return NULL; } BOOL _EnableLink(HWND hwndLink, BOOL bEnable) { LWITEM item; item.mask = LWIF_ITEMINDEX|LWIF_STATE; item.stateMask = LWIS_ENABLED; item.state = bEnable ? LWIS_ENABLED : 0; item.iLink = 0; return (BOOL)SendMessage(hwndLink, LWM_SETITEM, 0, (LPARAM)&item); } int _CreateSearchLinks(HWND hwndDlg, const POINT& pt, UINT nCtlIDdlg /* ctl ID of link to hwndDlg */) { const UINT rgCtlID[] = { IDC_SEARCHLINK_FILES, IDC_SEARCHLINK_COMPUTERS, IDC_SEARCHLINK_PRINTERS, IDC_SEARCHLINK_PEOPLE, IDC_SEARCHLINK_INTERNET, }; const UINT rgCaptionID[] = { IDS_FSEARCH_SEARCHLINK_FILES, IDS_FSEARCH_SEARCHLINK_COMPUTERS, IDS_FSEARCH_SEARCHLINK_PRINTERS, IDS_FSEARCH_SEARCHLINK_PEOPLE, IDS_FSEARCH_SEARCHLINK_INTERNET, }; int cLinks = 0; BOOL bDSEnabled = _IsDirectoryServiceAvailable(); for (int i = 0; i < ARRAYSIZE(rgCtlID); i++) { // block creation of csearch, psearch search links // if Directory Service is not available. if (((IDC_SEARCHLINK_PRINTERS == rgCtlID[i]) && rgCtlID[i] != nCtlIDdlg && !bDSEnabled) || (IDC_SEARCHLINK_FILES == rgCtlID[i] && SHRestricted(REST_NOFIND))) { continue; } if (_CreateLinkWindow(hwndDlg, rgCtlID[i], pt, rgCaptionID[i])) cLinks++; } // Disable link to current dialog: _EnableLink(GetDlgItem(hwndDlg, nCtlIDdlg), FALSE); return cLinks; } void _LayoutLinkWindow( IN HWND hwnd, // parent window IN LONG left, // left position of link IN LONG right, // right position of link IN LONG yMargin, // vertical padding between links IN OUT LONG& y, // IN: where to start (RECT::top). OUT: where the last link was positioned (RECT::bottom). IN const int nCtlID) // ctl ID { HWND hwndLink; if (nCtlID > 0) { hwndLink = GetDlgItem(hwnd, nCtlID); RECT rcLink; if (!IsWindow(hwndLink)) return; ::GetWindowRect(hwndLink, &rcLink); ::MapWindowRect(NULL, hwnd, &rcLink); rcLink.left = left; rcLink.right = right; int cyIdeal = (int)::SendMessage(hwndLink, LWM_GETIDEALHEIGHT, RECTWIDTH(rcLink), 0); if (cyIdeal >= 0) rcLink.bottom = rcLink.top + cyIdeal; OffsetRect(&rcLink, 0, y - rcLink.top); y = rcLink.bottom; ::SetWindowPos(hwndLink, NULL, rcLink.left, rcLink.top, RECTWIDTH(rcLink), RECTHEIGHT(rcLink), SWP_NOZORDER|SWP_NOACTIVATE); } else if (nCtlID < 0) { // this is a divider window hwndLink = GetDlgItem(hwnd, -nCtlID); ::SetWindowPos(hwndLink, NULL, left, y + yMargin/2, right - left, 1, SWP_NOZORDER|SWP_NOACTIVATE); } y += yMargin; } void _LayoutLinkWindows( IN HWND hwnd, // parent window IN LONG left, // left position of links IN LONG right, // right position of links IN LONG yMargin, // vertical padding between links IN OUT LONG& y, // IN: where to start (RECT::top). OUT: where the last link was positioned (RECT::bottom). IN const int rgCtlID[],// array of link ctl IDs. use IDC_SEPARATOR for separators IN LONG cCtlID) // number of array elements to layout in rgCtlID. { for (int i = 0; i < cCtlID; i++) _LayoutLinkWindow(hwnd, left, right, yMargin, y, rgCtlID[i]); } // Retrieves AutoComplete flags // #define SZ_REGKEY_AUTOCOMPLETE_TAB TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoComplete") #define BOOL_NOT_SET 0x00000005 DWORD _GetAutoCompleteSettings() { DWORD dwACOptions = 0; if (SHRegGetBoolUSValue(REGSTR_PATH_AUTOCOMPLETE, REGSTR_VAL_USEAUTOAPPEND, FALSE, /*default:*/FALSE)) { dwACOptions |= ACO_AUTOAPPEND; } if (SHRegGetBoolUSValue(REGSTR_PATH_AUTOCOMPLETE, REGSTR_VAL_USEAUTOSUGGEST, FALSE, /*default:*/TRUE)) { dwACOptions |= ACO_AUTOSUGGEST; } // Windows uses the TAB key to move between controls in a dialog. UNIX and other // operating systems that use AutoComplete have traditionally used the TAB key to // iterate thru the AutoComplete possibilities. We need to default to disable the // TAB key (ACO_USETAB) unless the caller specifically wants it. We will also // turn it on static BOOL s_fAlwaysUseTab = BOOL_NOT_SET; if (BOOL_NOT_SET == s_fAlwaysUseTab) s_fAlwaysUseTab = SHRegGetBoolUSValue(SZ_REGKEY_AUTOCOMPLETE_TAB, TEXT("Always Use Tab"), FALSE, FALSE); if (s_fAlwaysUseTab) dwACOptions |= ACO_USETAB; return dwACOptions; } // Initializes and enables an MRU autocomplete list on the specified // edit control HRESULT _InitializeMru(HWND hwndEdit, IAutoComplete2** ppAutoComplete, LPCTSTR pszSubKey, IStringMru** ppStringMru) { *ppAutoComplete = NULL; *ppStringMru = NULL; HRESULT hr = CoCreateInstance(CLSID_AutoComplete, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IAutoComplete2, ppAutoComplete)); if (SUCCEEDED(hr)) { TCHAR szKey[MAX_PATH]; if (CFileSearchBand::MakeBandSubKey(pszSubKey, szKey, ARRAYSIZE(szKey)) > 0) { hr = CStringMru::CreateInstance(HKEY_CURRENT_USER, szKey, 25, FALSE, IID_PPV_ARG(IStringMru, ppStringMru)); if (SUCCEEDED(hr)) { hr = (*ppAutoComplete)->Init(hwndEdit, *ppStringMru, NULL, NULL); } } else hr = E_FAIL; } if (SUCCEEDED(hr)) { (*ppAutoComplete)->SetOptions(_GetAutoCompleteSettings()); (*ppAutoComplete)->Enable(TRUE); } else { ATOMICRELEASE((*ppAutoComplete)); ATOMICRELEASE((*ppStringMru)); } return hr; } HRESULT _AddMruStringFromWindow(IStringMru* pmru, HWND hwnd) { ASSERT(::IsWindow(hwnd)); HRESULT hr = E_FAIL; if (pmru) { TCHAR szText[MAX_PATH * 3]; if (GetWindowTextW(hwnd, szText, ARRAYSIZE(szText)) > 0) hr = pmru->Add(szText); else hr = S_FALSE; } return hr; } HRESULT _TestAutoCompleteDropDownState(IAutoComplete2* pac2, DWORD dwTest) { IAutoCompleteDropDown* pacdd; HRESULT hr = pac2->QueryInterface(IID_PPV_ARG(IAutoCompleteDropDown, &pacdd)); if (SUCCEEDED(hr)) { DWORD dwFlags; if (SUCCEEDED((hr = pacdd->GetDropDownStatus(&dwFlags, NULL)))) hr = (dwFlags & dwTest) ? S_OK : S_FALSE; pacdd->Release(); } return hr; } inline HWND _IndexServiceHelp(HWND hwnd) { return ::HtmlHelp(hwnd, TEXT("isconcepts.chm"), HH_DISPLAY_TOPIC, 0); } LRESULT CSubDlg::OnNcCalcsize(UINT, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { InflateRect((LPRECT)lParam, -SUBDLG_BORDERWIDTH, -SUBDLG_BORDERWIDTH); return 0; } LRESULT CSubDlg::OnNcPaint(UINT, WPARAM wParam, LPARAM lParam, BOOL&) { RECT rc; HDC hdc; HBRUSH hbr = _pfsb->GetMetrics().BorderBrush(); GetWindowRect(Hwnd(), &rc); OffsetRect(&rc, -rc.left, -rc.top); if (hbr && (hdc = GetWindowDC(Hwnd())) != NULL) { for (int i=0; i < SUBDLG_BORDERWIDTH; i++) { FrameRect(hdc, &rc, hbr); InflateRect(&rc, -1, -1); } ReleaseDC(Hwnd(), hdc); } return 0; } LRESULT CSubDlg::OnCtlColor(UINT, WPARAM wParam, LPARAM, BOOL&) { SetTextColor((HDC)wParam, _pfsb->GetMetrics().TextColor()); SetBkColor((HDC)wParam, _pfsb->GetMetrics().BkgndColor()); return (LRESULT)_pfsb->GetMetrics().BkgndBrush(); } LRESULT CSubDlg::OnPaint(UINT, WPARAM, LPARAM, BOOL&) { // Just going to call BeginPaint and EndPaint. All // painting done in WM_ERASEBKGND handler to avoid flicker. PAINTSTRUCT ps; HDC hdc = BeginPaint(_hwnd, &ps); if (hdc) { EndPaint(_hwnd, &ps); } return 0; } LRESULT CSubDlg::OnSize(UINT, WPARAM, LPARAM, BOOL&) { ASSERT(::IsWindow(Hwnd())); // was _Attach() called, e.g. from WM_INITDIALOG? _PaintDlg(Hwnd(), _pfsb->GetMetrics()); ValidateRect(Hwnd(), NULL); return 0; } LRESULT CSubDlg::OnEraseBkgnd(UINT, WPARAM wParam, LPARAM, BOOL&) { _PaintDlg(Hwnd(), _pfsb->GetMetrics(), (HDC)wParam); ValidateRect(Hwnd(), NULL); return TRUE; } STDMETHODIMP CSubDlg::TranslateAccelerator(MSG *pmsg) { if (_pfsb->IsKeyboardScroll(pmsg)) return S_OK; return _pfsb->IsDlgMessage(Hwnd(), pmsg); } LRESULT CSubDlg::OnChildSetFocusCmd(WORD wNotifyCode, WORD wID, HWND hwndCtl, BOOL& bHandled) { _EnsureVisible(_hwnd, hwndCtl, _pfsb); bHandled = FALSE; return 0; } LRESULT CSubDlg::OnChildSetFocusNotify(int, NMHDR *pnmh, BOOL& bHandled) { _EnsureVisible(_hwnd, pnmh->hwndFrom, _pfsb); bHandled = FALSE; return 0; } LRESULT CSubDlg::OnChildKillFocusCmd(WORD, WORD, HWND hwndCtl, BOOL&) { if (_pBandDlg) _pBandDlg->RememberFocus(hwndCtl); return 0; } LRESULT CSubDlg::OnChildKillFocusNotify(int, NMHDR *pnmh, BOOL&) { if (_pBandDlg) _pBandDlg->RememberFocus(pnmh->hwndFrom); return 0; } LRESULT CSubDlg::OnComboExEndEdit(int, NMHDR *pnmh, BOOL&) { if (CBENF_KILLFOCUS == ((NMCBEENDEDIT*)pnmh)->iWhy) { if (_pBandDlg) _pBandDlg->RememberFocus(pnmh->hwndFrom); } return 0; } // CDateDlg impl #define RECENTMONTHSRANGE_HIGH 999 #define RECENTDAYSRANGE_HIGH RECENTMONTHSRANGE_HIGH #define RECENTMONTHSRANGE_HIGH_LEN 3 // count of digits in RECENTMONTHSRANGE_HIGH #define RECENTDAYSRANGE_HIGH_LEN RECENTMONTHSRANGE_HIGH_LEN #define RECENTMONTHSRANGE_LOW 1 #define RECENTDAYSRANGE_LOW RECENTMONTHSRANGE_LOW LRESULT CDateDlg::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { ASSERT(_pfsb); _Attach(m_hWnd); HWND hwndCombo = GetDlgItem(IDC_WHICH_DATE); SendDlgItemMessage(IDC_RECENT_MONTHS_SPIN, UDM_SETRANGE32, RECENTMONTHSRANGE_HIGH, RECENTMONTHSRANGE_LOW); SendDlgItemMessage(IDC_RECENT_DAYS_SPIN, UDM_SETRANGE32, RECENTDAYSRANGE_HIGH, RECENTDAYSRANGE_LOW); SendDlgItemMessage(IDC_RECENT_MONTHS, EM_LIMITTEXT, RECENTMONTHSRANGE_HIGH_LEN, 0); SendDlgItemMessage(IDC_RECENT_DAYS, EM_LIMITTEXT, RECENTDAYSRANGE_HIGH_LEN, 0); SYSTEMTIME st[2] = {0}; // lower limit -- dos date does not support anything before 1/1/1980 st[0].wYear = 1980; st[0].wMonth = 1; st[0].wDay = 1; // upper limit st[1].wYear = 2099; st[1].wMonth = 12; st[1].wDay = 31; SendDlgItemMessage(IDC_DATERANGE_BEGIN, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st); SendDlgItemMessage(IDC_DATERANGE_END, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st); _LoadStringToCombo(hwndCombo, -1, IDS_FSEARCH_MODIFIED_DATE, IDS_FSEARCH_MODIFIED_DATE); _LoadStringToCombo(hwndCombo, -1, IDS_FSEARCH_CREATION_DATE, IDS_FSEARCH_CREATION_DATE); _LoadStringToCombo(hwndCombo, -1, IDS_FSEARCH_ACCESSED_DATE, IDS_FSEARCH_ACCESSED_DATE); Clear(); return TRUE; // Let the system set the focus } BOOL CDateDlg::Validate() { return TRUE; } STDMETHODIMP CDateDlg::AddConstraints(ISearchCommandExt* pSrchCmd) { VARIANT var; BOOL bErr; UINT_PTR nIDString = _GetComboData(GetDlgItem(IDC_WHICH_DATE)); HRESULT hr; #if 1 hr = InitVariantFromStr(&var, (IDS_FSEARCH_MODIFIED_DATE == nIDString) ? L"Write" : (IDS_FSEARCH_CREATION_DATE == nIDString) ? L"Create" : L"Access"); #else var.vt = VT_UI4; var.ulVal = (IDS_FSEARCH_MODIFIED_DATE == nIDString) ? 1 : (IDS_FSEARCH_CREATION_DATE == nIDString) ? 2 : (IDS_FSEARCH_ACCESSED_DATE == nIDString) ? 3 : 0; hr = S_OK; ASSERT(var.ulVal); #endif if (SUCCEEDED(hr)) { hr = _AddConstraint(pSrchCmd, L"WhichDate", &var); VariantClear(&var); } if (IsDlgButtonChecked(IDC_USE_RECENT_MONTHS)) { var.vt = VT_I4; var.ulVal = (ULONG)SendDlgItemMessage(IDC_RECENT_MONTHS_SPIN, UDM_GETPOS32, 0, (LPARAM)&bErr); if (!bErr) hr = _AddConstraint(pSrchCmd, L"DateNMonths", &var); } else if (IsDlgButtonChecked(IDC_USE_RECENT_DAYS)) { var.vt = VT_I4; var.ulVal = (ULONG)SendDlgItemMessage(IDC_RECENT_DAYS_SPIN, UDM_GETPOS32, 0, (LPARAM)&bErr); if (!bErr) hr = _AddConstraint(pSrchCmd, L"DateNDays", &var); } else if (IsDlgButtonChecked(IDC_USE_DATE_RANGE)) { SYSTEMTIME stBegin, stEnd; var.vt = VT_DATE; LRESULT lRetBegin = SendDlgItemMessage(IDC_DATERANGE_BEGIN, DTM_GETSYSTEMTIME, 0, (LPARAM)&stBegin); LRESULT lRetEnd = SendDlgItemMessage(IDC_DATERANGE_END, DTM_GETSYSTEMTIME, 0, (LPARAM)&stEnd); if (GDT_VALID == lRetBegin && GDT_VALID == lRetEnd) { #ifdef DEBUG FILETIME ft; //validate that we were passed a correct date //SystemTimeToFileTime calls internal API IsValidSystemTime. //This will save us from OLE Automation bug# 322789 // the only way we can get a date is through date/time picker // control which should validate the dates so just assert... ASSERT(SystemTimeToFileTime(&stBegin, &ft)); #endif SystemTimeToVariantTime(&stBegin, &var.date); hr = _AddConstraint(pSrchCmd, L"DateGE", &var); #ifdef DEBUG ASSERT(SystemTimeToFileTime(&stEnd, &ft)); #endif SystemTimeToVariantTime(&stEnd, &var.date); hr = _AddConstraint(pSrchCmd, L"DateLE", &var); } } return hr; } // S_FALSE: constraint restored to UI. S_OK: subdialog should be opened. // E_FAIL: constraint must be for some other subdlg. STDMETHODIMP CDateDlg::RestoreConstraint(const BSTR bstrName, const VARIANT* pValue) { HRESULT hr = E_FAIL; BOOL bUseMonths = FALSE, bUseDays = FALSE, bUseRange = FALSE; if (IsConstraintName(L"WhichDate", bstrName)) { ASSERT(VT_I4 == pValue->vt) UINT nIDS = pValue->lVal == 1 ? IDS_FSEARCH_MODIFIED_DATE : pValue->lVal == 2 ? IDS_FSEARCH_CREATION_DATE : pValue->lVal == 3 ? IDS_FSEARCH_ACCESSED_DATE : 0; if (nIDS != 0) _SelectComboData(GetDlgItem(IDC_WHICH_DATE), nIDS); return nIDS == IDS_FSEARCH_MODIFIED_DATE /*default*/ ? S_FALSE /* don't open */: S_OK /* open */; } if (IsConstraintName(L"DateNMonths", bstrName)) { ASSERT(VT_I4 == pValue->vt); bUseMonths = TRUE; _SetWindowValue(m_hWnd, IDC_RECENT_MONTHS, pValue); hr = S_OK; } else if (IsConstraintName(L"DateNDays", bstrName)) { ASSERT(VT_I4 == pValue->vt); bUseDays = TRUE; _SetWindowValue(m_hWnd, IDC_RECENT_DAYS, pValue); hr = S_OK; } else if (IsConstraintName(L"DateGE", bstrName)) { ASSERT(VT_DATE == pValue->vt); bUseRange = TRUE; SYSTEMTIME st; VariantTimeToSystemTime(pValue->date, &st); SendDlgItemMessage(IDC_DATERANGE_BEGIN, DTM_SETSYSTEMTIME, 0, (LPARAM)&st); hr = S_OK; } else if (IsConstraintName(L"DateLE", bstrName)) { ASSERT(VT_DATE == pValue->vt); bUseRange = TRUE; SYSTEMTIME st; VariantTimeToSystemTime(pValue->date, &st); SendDlgItemMessage(IDC_DATERANGE_END, DTM_SETSYSTEMTIME, 0, (LPARAM)&st); hr = S_OK; } if (S_OK == hr) { CheckDlgButton(IDC_USE_RECENT_MONTHS, bUseMonths); CheckDlgButton(IDC_USE_RECENT_DAYS, bUseDays); CheckDlgButton(IDC_USE_DATE_RANGE, bUseRange); EnableControls(); } return hr; } void CDateDlg::Clear() { SendDlgItemMessage(IDC_WHICH_DATE, CB_SETCURSEL, 0, 0); CheckDlgButton(IDC_USE_RECENT_MONTHS, 0); SetDlgItemInt(IDC_RECENT_MONTHS, 1, FALSE); CheckDlgButton(IDC_USE_RECENT_DAYS, 0); SetDlgItemInt(IDC_RECENT_DAYS, 1, FALSE); CheckDlgButton(IDC_USE_DATE_RANGE, 1); SYSTEMTIME stNow, stPrev; GetLocalTime(&stNow); SendDlgItemMessage(IDC_DATERANGE_END, DTM_SETSYSTEMTIME, 0, (LPARAM)&stNow); // Subtract 90 days from current date and stuff in date low range _CalcDateOffset(&stNow, 0, -1 /* 1 month ago */, &stPrev); SendDlgItemMessage(IDC_DATERANGE_BEGIN, DTM_SETSYSTEMTIME, 0, (LPARAM)&stPrev); EnableControls(); } LRESULT CDateDlg::OnSize(UINT, WPARAM wParam, LPARAM lParam, BOOL&) { POINTS pts = MAKEPOINTS(lParam); _PaintDlg(m_hWnd, _pfsb->GetMetrics()); ValidateRect(NULL); RECT rc; HWND hwndCtl = GetDlgItem(IDC_WHICH_DATE); ASSERT(hwndCtl); ::GetWindowRect(hwndCtl, &rc); ::MapWindowRect(NULL, m_hWnd, &rc); rc.right = pts.x - _pfsb->GetMetrics().CtlMarginX(); ::SetWindowPos(GetDlgItem(IDC_WHICH_DATE), NULL, 0, 0, RECTWIDTH(rc), RECTHEIGHT(rc), SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE); return 0; } LRESULT CDateDlg::OnMonthDaySpin(int nIDSpin, NMHDR *pnmh, BOOL& bHandled) { LPNMUPDOWN pud = (LPNMUPDOWN)pnmh; pud->iDelta *= -1; // increments of 1 month/day return 0; } LRESULT CDateDlg::OnBtnClick(WORD nCode, WORD nID, HWND hwndCtl, BOOL&) { EnableControls(); return 0; } LRESULT CDateDlg::OnMonthsKillFocus(WORD nCode, WORD nID, HWND hwndCtl, BOOL&) { _EnforceNumericEditRange(m_hWnd, IDC_RECENT_MONTHS, IDC_RECENT_MONTHS_SPIN, RECENTMONTHSRANGE_LOW, RECENTMONTHSRANGE_HIGH); return 0; } LRESULT CDateDlg::OnDaysKillFocus(WORD nCode, WORD nID, HWND hwndCtl, BOOL&) { _EnforceNumericEditRange(m_hWnd, IDC_RECENT_DAYS, IDC_RECENT_DAYS_SPIN, RECENTDAYSRANGE_LOW, RECENTDAYSRANGE_HIGH); return 0; } void CDateDlg::EnableControls() { UINT nSel = IsDlgButtonChecked(IDC_USE_RECENT_MONTHS) ? IDC_USE_RECENT_MONTHS : IsDlgButtonChecked(IDC_USE_RECENT_DAYS) ? IDC_USE_RECENT_DAYS : IsDlgButtonChecked(IDC_USE_DATE_RANGE) ? IDC_USE_DATE_RANGE : 0; ::EnableWindow(GetDlgItem(IDC_RECENT_MONTHS), IDC_USE_RECENT_MONTHS == nSel); ::EnableWindow(GetDlgItem(IDC_RECENT_MONTHS_SPIN), IDC_USE_RECENT_MONTHS == nSel); ::EnableWindow(GetDlgItem(IDC_RECENT_DAYS), IDC_USE_RECENT_DAYS == nSel); ::EnableWindow(GetDlgItem(IDC_RECENT_DAYS_SPIN), IDC_USE_RECENT_DAYS == nSel); ::EnableWindow(GetDlgItem(IDC_DATERANGE_BEGIN), IDC_USE_DATE_RANGE == nSel); ::EnableWindow(GetDlgItem(IDC_DATERANGE_END), IDC_USE_DATE_RANGE == nSel); } // CSizeDlg impl #define FILESIZERANGE_LOW 0 #define FILESIZERANGE_HIGH 99999999 #define FILESIZERANGE_HIGH_LEN 8 // count of digits in FILESIZERANGE_HIGH LRESULT CSizeDlg::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { _Attach(m_hWnd); HWND hwndCombo = GetDlgItem(IDC_WHICH_SIZE); SendDlgItemMessage(IDC_FILESIZE_SPIN, UDM_SETRANGE32, FILESIZERANGE_HIGH, FILESIZERANGE_LOW /*Kb*/); SendDlgItemMessage(IDC_FILESIZE, EM_LIMITTEXT, FILESIZERANGE_HIGH_LEN, 0); _LoadStringToCombo(hwndCombo, -1, IDS_FSEARCH_SIZE_GREATEREQUAL, IDS_FSEARCH_SIZE_GREATEREQUAL); _LoadStringToCombo(hwndCombo, -1, IDS_FSEARCH_SIZE_LESSEREQUAL, IDS_FSEARCH_SIZE_LESSEREQUAL); Clear(); return TRUE; // Let the system set the focus } STDMETHODIMP CSizeDlg::AddConstraints(ISearchCommandExt* pSrchCmd) { VARIANT var; BOOL bErr = FALSE; HRESULT hr = S_FALSE; UINT_PTR nIDString = _GetComboData(GetDlgItem(IDC_WHICH_SIZE)); var.vt = VT_UI8; // this will be limited to ~4000GB due to the size of the data in the control var.ullVal = (ULONG)SendDlgItemMessage(IDC_FILESIZE_SPIN, UDM_GETPOS32, 0, (LPARAM)&bErr); if (!bErr) { var.ullVal *= 1024; // KB to bytes. LPCWSTR pwszConstraint = (IDS_FSEARCH_SIZE_GREATEREQUAL == nIDString) ? L"SizeGE" : (IDS_FSEARCH_SIZE_LESSEREQUAL == nIDString) ? L"SizeLE" : NULL; if (pwszConstraint) hr = _AddConstraint(pSrchCmd, pwszConstraint, &var); } return hr; } // S_FALSE: constraint restored to UI. S_OK: subdialog should be opened. // E_FAIL: constraint must be for some other subdlg. STDMETHODIMP CSizeDlg::RestoreConstraint(const BSTR bstrName, const VARIANT* pValue) { HRESULT hr = E_FAIL; UINT nID = 0; if (IsConstraintName(L"SizeGE", bstrName)) { nID = IDS_FSEARCH_SIZE_GREATEREQUAL; hr = S_OK; } else if (IsConstraintName(L"SizeLE", bstrName)) { nID = IDS_FSEARCH_SIZE_LESSEREQUAL; hr = S_OK; } if (S_OK == hr) { ASSERT(VT_UI8 == pValue->vt); ULONG ulSize = pValue->ullVal/1024; // convert bytes to KB SetDlgItemInt(IDC_FILESIZE, ulSize, FALSE); ASSERT(nID != 0); _SelectComboData(GetDlgItem(IDC_WHICH_SIZE), nID); } return hr; } void CSizeDlg::Clear() { SendDlgItemMessage(IDC_WHICH_SIZE, CB_SETCURSEL, 0, 0); SetDlgItemInt(IDC_FILESIZE, 0, FALSE); } LRESULT CSizeDlg::OnSizeSpin(int nIDSpin, NMHDR *pnmh, BOOL& bHandled) { LPNMUPDOWN pud = (LPNMUPDOWN)pnmh; pud->iDelta *= -10; // increments of 10KB return 0; } LRESULT CSizeDlg::OnSizeKillFocus(WORD nCode, WORD nID, HWND hwndCtl, BOOL&) { _EnforceNumericEditRange(m_hWnd, IDC_FILESIZE, IDC_FILESIZE_SPIN, FILESIZERANGE_LOW, FILESIZERANGE_HIGH); return 0; } CTypeDlg::CTypeDlg(CFileSearchBand* pfsb) : CSubDlg(pfsb) { *_szRestoredExt = 0; } CTypeDlg::~CTypeDlg() { } LRESULT CTypeDlg::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { HWND hwndCombo = GetDlgItem(IDC_FILE_TYPE); HIMAGELIST hil = GetSystemImageListSmallIcons(); _Attach(m_hWnd); ::SendMessage(hwndCombo, CBEM_SETEXTENDEDSTYLE, CBES_EX_NOSIZELIMIT | CBES_EX_CASESENSITIVE, CBES_EX_NOSIZELIMIT | CBES_EX_CASESENSITIVE); ::SendMessage(hwndCombo, CBEM_SETIMAGELIST, 0, (LPARAM)hil); ::SendMessage(hwndCombo, CBEM_SETEXSTYLE, 0, 0); return TRUE; // Let the system set the focus } STDMETHODIMP CTypeDlg::AddConstraints(ISearchCommandExt* pSrchCmd) { LPTSTR pszText; HRESULT hr = S_FALSE; if (GetFileAssocComboSelItemText(GetDlgItem(IDC_FILE_TYPE), &pszText) >= 0 && pszText) { VARIANT var = {0}; if (*pszText && SUCCEEDED(InitVariantFromStr(&var, pszText)) && SUCCEEDED(_AddConstraint(pSrchCmd, L"FileType", &var))) { hr = S_OK; } VariantClear(&var); LocalFree((HLOCAL)pszText); } return hr; } // S_FALSE: constraint restored to UI. S_OK: subdialog should be opened. // E_FAIL: constraint must be for some other subdlg. STDMETHODIMP CTypeDlg::RestoreConstraint(const BSTR bstrName, const VARIANT* pValue) { if (IsConstraintName(L"FileType", bstrName)) { ASSERT(VT_BSTR == pValue->vt); HRESULT hr = StringCchCopy(_szRestoredExt, ARRAYSIZE(_szRestoredExt), pValue->bstrVal); if (SUCCEEDED(hr)) { INT_PTR i = _FindExtension(GetDlgItem(IDC_FILE_TYPE), _szRestoredExt); if (i != CB_ERR) { SendDlgItemMessage(IDC_FILE_TYPE, CB_SETCURSEL, i, 0); *_szRestoredExt = 0; } return S_OK; } *_szRestoredExt = 0; // throw away invalid data } return E_FAIL; } INT_PTR CTypeDlg::_FindExtension(HWND hwndCombo, TCHAR* pszExt) { INT_PTR i, cnt = ::SendMessage(hwndCombo, CB_GETCOUNT, 0, 0); LPTSTR pszData; BOOL bAllFileTypes = pszExt && (lstrcmp(TEXT("*.*"), pszExt) == 0); TCHAR szExt[MAX_PATH]; if (!bAllFileTypes) { // Remove wildcard characters. LPTSTR pszSrc = pszExt, pszDest = szExt; for (;; pszSrc = CharNext(pszSrc)) { if (TEXT('*') == *pszSrc) pszSrc = CharNext(pszSrc); if ((*(pszDest++) = *pszSrc) == 0) break; } pszExt = szExt; } if (pszExt && (bAllFileTypes || *pszExt)) { for (i = 0; i < cnt; i++) { pszData = (LPTSTR)::SendMessage(hwndCombo, CB_GETITEMDATA, i, 0); if (bAllFileTypes && (FILEASSOCIATIONSID_ALLFILETYPES == (UINT_PTR)pszData)) return i; if (pszData != (LPTSTR)FILEASSOCIATIONSID_ALLFILETYPES && pszData != (LPTSTR)CB_ERR && pszData != NULL) { if (0 == StrCmpI(pszExt, pszData)) return i; } } } return CB_ERR; } void CTypeDlg::Clear() { // Assign combo selection to 'all file types': HWND hwndCombo = GetDlgItem(IDC_FILE_TYPE); for (INT_PTR i = 0, cnt = ::SendMessage(hwndCombo, CB_GETCOUNT, 0, 0); i < cnt; i++) { if (FILEASSOCIATIONSID_ALLFILETYPES == _GetComboData(hwndCombo, i)) { ::SendMessage(hwndCombo, CB_SETCURSEL, i, 0); break; } } _szRestoredExt[0] = 0; } LRESULT CTypeDlg::OnFileTypeDeleteItem(int idCtrl, NMHDR *pnmh, BOOL& bHandled) { return DeleteFileAssocComboItem(pnmh); } LRESULT CTypeDlg::OnSize(UINT, WPARAM wParam, LPARAM lParam, BOOL&) { POINTS pts = MAKEPOINTS(lParam); _PaintDlg(m_hWnd, _pfsb->GetMetrics()); ValidateRect(NULL); RECT rc; HWND hwndCtl = GetDlgItem(IDC_FILE_TYPE); ASSERT(hwndCtl); ::GetWindowRect(hwndCtl, &rc); ::MapWindowRect(NULL, m_hWnd, &rc); rc.right = pts.x - _pfsb->GetMetrics().CtlMarginX(); ::SetWindowPos(hwndCtl, NULL, 0, 0, RECTWIDTH(rc), RECTHEIGHT(rc), SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE); return 0; } DWORD CTypeDlg::FileAssocThreadProc(void* pv) { FSEARCHTHREADSTATE *pState = (FSEARCHTHREADSTATE *)pv; CTypeDlg* pThis = (CTypeDlg*)pState->pvParam; if (PopulateFileAssocCombo(pState->hwndCtl, AddItemNotify, (LPARAM)pv) != E_ABORT) { ::PostMessage(::GetParent(pState->hwndCtl), WMU_COMBOPOPULATIONCOMPLETE, (WPARAM)pState->hwndCtl, 0); } pState->fComplete = TRUE; ATOMICRELEASE(pState->punkBand); return 0; } HRESULT CTypeDlg::AddItemNotify(ULONG fAction, PCBXITEM pItem, LPARAM lParam) { FSEARCHTHREADSTATE *pState = (FSEARCHTHREADSTATE *)lParam; ASSERT(pState); ASSERT(pState->hwndCtl); // Do we want to abort combo population thread? if (fAction & CBXCB_ADDING && pState->fCancel) return E_ABORT; // Set the current selection to 'all file types' if (fAction & CBXCB_ADDED) { BOOL bAllTypesItem = (FILEASSOCIATIONSID_ALLFILETYPES == pItem->lParam); CTypeDlg* pThis = (CTypeDlg*)pState->pvParam; ASSERT(pThis); // If this item is the one restored from a saved query // override any current selection and select it. if (*pThis->_szRestoredExt && !bAllTypesItem && pItem->lParam && 0 == lstrcmpi((LPCTSTR)pItem->lParam, pThis->_szRestoredExt)) { ::SendMessage(pState->hwndCtl, CB_SETCURSEL, pItem->iItem, 0); *pThis->_szRestoredExt = 0; } // If this item is the default ('all file types') and // nothing else is selected, select it. else if (bAllTypesItem) { if (CB_ERR == ::SendMessage(pState->hwndCtl, CB_GETCURSEL, 0, 0)) ::SendMessage(pState->hwndCtl, CB_SETCURSEL, pItem->iItem, 0); } } return S_OK; } LRESULT CTypeDlg::OnComboPopulationComplete(UINT, WPARAM, LPARAM, BOOL&) { // remove briefcase from type combo because briefcases no longer use this // extension (now they store clsid in desktop.ini INT_PTR iBfc = _FindExtension(GetDlgItem(IDC_FILE_TYPE), TEXT(".bfc")); if (iBfc != CB_ERR) { SendDlgItemMessage(IDC_FILE_TYPE, CB_DELETESTRING, (WPARAM)iBfc, 0); } if (*_szRestoredExt) { INT_PTR iSel = _FindExtension(GetDlgItem(IDC_FILE_TYPE), _szRestoredExt); if (iSel != CB_ERR) { SendDlgItemMessage(IDC_FILE_TYPE, CB_SETCURSEL, (WPARAM)iSel, 0); *_szRestoredExt = 0; } } return 0; } // Called when we are finished doing all the work to display the search band. // We then launch the thread to populate the file type drop down. By delaying this // until now, we can speed up the band loading. // No return becuase it's called async. void CTypeDlg::DoDelayedInit() { // Launch thread to populate the file types combo. _threadState.hwndCtl = GetDlgItem(IDC_FILE_TYPE); _threadState.pvParam = this; _threadState.fComplete = FALSE; _threadState.fCancel = FALSE; if (SUCCEEDED(SAFECAST(_pfsb, IFileSearchBand*)->QueryInterface(IID_PPV_ARG(IUnknown, &_threadState.punkBand)))) { if (!SHCreateThread(FileAssocThreadProc, &_threadState, CTF_COINIT, NULL)) { ATOMICRELEASE(_threadState.punkBand); } } } LRESULT CTypeDlg::OnDestroy(UINT, WPARAM, LPARAM, BOOL& bHandled) { _threadState.fCancel = TRUE; bHandled = FALSE; return 0; } void CTypeDlg::OnWinIniChange() { SendDlgItemMessage(IDC_FILE_TYPE, CB_SETDROPPEDWIDTH, _PixelsForDbu(m_hWnd, MIN_FILEASSOCLIST_WIDTH, TRUE), 0); } LRESULT CAdvancedDlg::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { _Attach(m_hWnd); Clear(); return TRUE; // Let the system set the focus } HRESULT AddButtonConstraintPersist(ISearchCommandExt* pSrchCmd, LPCWSTR pszConstraint, HWND hwndButton) { BOOL bValue = SendMessage(hwndButton, BM_GETCHECK, 0, 0) == BST_CHECKED; SHRegSetUSValue(TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"), pszConstraint, REG_DWORD, &bValue, sizeof(bValue), SHREGSET_HKCU | SHREGSET_FORCE_HKCU); VARIANT var = {0}; var.vt = VT_BOOL; var.boolVal = bValue ? VARIANT_TRUE : 0; return _AddConstraint(pSrchCmd, pszConstraint, &var); } STDMETHODIMP CAdvancedDlg::AddConstraints(ISearchCommandExt* pSrchCmd) { AddButtonConstraintPersist(pSrchCmd, L"SearchSystemDirs", GetDlgItem(IDC_USE_SYSTEMDIRS)); AddButtonConstraintPersist(pSrchCmd, L"SearchHidden", GetDlgItem(IDC_SEARCH_HIDDEN)); AddButtonConstraintPersist(pSrchCmd, L"IncludeSubFolders", GetDlgItem(IDC_USE_SUBFOLDERS)); AddButtonConstraintPersist(pSrchCmd, L"CaseSensitive", GetDlgItem(IDC_USE_CASE)); AddButtonConstraintPersist(pSrchCmd, L"SearchSlowFiles", GetDlgItem(IDC_USE_SLOW_FILES)); return S_OK; } // S_FALSE: constraint restored to UI. S_OK: subdialog should be opened. // E_FAIL: constraint must be for some other subdlg. STDMETHODIMP CAdvancedDlg::RestoreConstraint(const BSTR bstrName, const VARIANT* pValue) { if (IsConstraintName(L"IncludeSubFolders", bstrName)) { ASSERT(VT_BOOL == pValue->vt || VT_I4 == pValue->vt); CheckDlgButton(IDC_USE_SUBFOLDERS, pValue->lVal); return S_FALSE; // this is a default. don't force open the subdialog. } if (IsConstraintName(L"CaseSensitive", bstrName)) { ASSERT(VT_BOOL == pValue->vt || VT_I4 == pValue->vt); CheckDlgButton(IDC_USE_CASE, pValue->lVal); return pValue->lVal ? S_OK : S_FALSE; } if (IsConstraintName(L"SearchSlowFiles", bstrName)) { ASSERT(VT_BOOL == pValue->vt || VT_I4 == pValue->vt); CheckDlgButton(IDC_USE_SLOW_FILES, pValue->lVal); return pValue->lVal ? S_OK : S_FALSE; } if (IsConstraintName(L"SearchSystemDirs", bstrName)) { ASSERT(VT_BOOL == pValue->vt || VT_I4 == pValue->vt || VT_UI4 == pValue->vt); CheckDlgButton(IDC_USE_SYSTEMDIRS, pValue->lVal); return pValue->lVal ? S_OK : S_FALSE; } if (IsConstraintName(L"SearchHidden", bstrName)) { ASSERT(VT_BOOL == pValue->vt || VT_I4 == pValue->vt || VT_UI4 == pValue->vt); CheckDlgButton(IDC_SEARCH_HIDDEN, pValue->lVal); return pValue->lVal ? S_OK : S_FALSE; } return E_FAIL; } void CheckDlgButtonPersist(HWND hdlg, UINT id, LPCTSTR pszOption, BOOL bDefault) { BOOL bValue = SHRegGetBoolUSValue(TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"), pszOption, FALSE, bDefault); CheckDlgButton(hdlg, id, bValue); } void CAdvancedDlg::Clear() { CheckDlgButtonPersist(m_hWnd, IDC_USE_SYSTEMDIRS, L"SearchSystemDirs", IsOS(OS_ANYSERVER)); CheckDlgButtonPersist(m_hWnd, IDC_SEARCH_HIDDEN, L"SearchHidden", FALSE); CheckDlgButtonPersist(m_hWnd, IDC_USE_SUBFOLDERS, L"IncludeSubFolders", TRUE); CheckDlgButtonPersist(m_hWnd, IDC_USE_CASE, L"CaseSensitive", FALSE); CheckDlgButtonPersist(m_hWnd, IDC_USE_SLOW_FILES, L"SearchSlowFiles", FALSE); } COptionsDlg::COptionsDlg(CFileSearchBand* pfsb) : CSubDlg(pfsb), _dlgDate(pfsb), _dlgSize(pfsb), _dlgType(pfsb), _dlgAdvanced(pfsb) { // Verify that it initialized to 0's ASSERT(0 == _nCIStatusText); ZeroMemory(_subdlgs, sizeof(_subdlgs)); #define SUBDLG_ENTRY(idx, idCheck, dlg) \ { _subdlgs[idx].nIDCheck = idCheck; _subdlgs[idx].pDlg = &dlg; } SUBDLG_ENTRY(SUBDLG_DATE, IDC_USE_DATE, _dlgDate); SUBDLG_ENTRY(SUBDLG_TYPE, IDC_USE_TYPE, _dlgType); SUBDLG_ENTRY(SUBDLG_SIZE, IDC_USE_SIZE, _dlgSize); SUBDLG_ENTRY(SUBDLG_ADVANCED, IDC_USE_ADVANCED, _dlgAdvanced); } LRESULT COptionsDlg::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&) { _Attach(m_hWnd); _dlgDate.SetBandDlg(_pBandDlg); _dlgSize.SetBandDlg(_pBandDlg); _dlgType.SetBandDlg(_pBandDlg); _dlgAdvanced.SetBandDlg(_pBandDlg); // Gather some metrics from the fresh dialog template... CMetrics& metrics = _pfsb->GetMetrics(); RECT rc[3] = {0}; ASSERT(::IsWindow(GetDlgItem(IDC_USE_DATE))); ASSERT(::IsWindow(GetDlgItem(IDC_USE_TYPE))); ASSERT(::IsWindow(GetDlgItem(IDC_USE_ADVANCED))); ::GetWindowRect(GetDlgItem(IDC_USE_DATE), rc + 0); ::GetWindowRect(GetDlgItem(IDC_USE_TYPE), rc + 1); ::GetWindowRect(GetDlgItem(IDC_USE_ADVANCED), rc + 2); for (int i = 0; i < ARRAYSIZE(rc); i++) { // MapWindowPoints is mirroring aware only if you pass two points ::MapWindowRect(NULL, m_hWnd, &rc[i]); } metrics.ExpandOrigin().y = rc[0].top; metrics.CheckBoxRect() = rc[2]; OffsetRect(&metrics.CheckBoxRect(), -rc[0].left, -rc[0].top); // Create subdialogs and collect native sizes. if (_dlgDate.Create(m_hWnd)) _GetWindowSize(_dlgDate, &_subdlgs[SUBDLG_DATE].sizeDlg); if (_dlgSize.Create(m_hWnd)) _GetWindowSize(_dlgSize, &_subdlgs[SUBDLG_SIZE].sizeDlg); if (_dlgType.Create(m_hWnd)) _GetWindowSize(_dlgType, &_subdlgs[SUBDLG_TYPE].sizeDlg); if (_dlgAdvanced.Create(m_hWnd)) _GetWindowSize(_dlgAdvanced, &_subdlgs[SUBDLG_ADVANCED].sizeDlg); // Create index server link window POINT pt = {0}; HWND hwndCI = _CreateLinkWindow(m_hWnd, IDC_INDEX_SERVER, pt, IDS_FSEARCH_CI_DISABLED_LINK); UpdateSearchCmdStateUI(); // Layout controls LayoutControls(); return TRUE; } void COptionsDlg::OnWinIniChange() { CSubDlg::OnWinIniChange(); for (int i = 0; i < ARRAYSIZE(_subdlgs); i++) _subdlgs[i].pDlg->OnWinIniChange(); } void COptionsDlg::LoadSaveUIState(UINT nIDCtl, BOOL bSave) { } LRESULT COptionsDlg::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&) { POINTS pts = MAKEPOINTS(lParam); _PaintDlg(m_hWnd, _pfsb->GetMetrics()); LayoutControls(pts.x, pts.y); return 0; } void COptionsDlg::LayoutControls(int cx, int cy) { if (cx < 0 || cy < 0) { RECT rc; GetClientRect(&rc); cx = RECTWIDTH(rc); cy = RECTHEIGHT(rc); } HDWP hdwp = BeginDeferWindowPos(1 + (ARRAYSIZE(_subdlgs) * 2)); if (hdwp) { CMetrics& metrics = _pfsb->GetMetrics(); POINT ptOrigin = metrics.ExpandOrigin(); // For each checkbox and associated subdialog... for (int i = 0; i < ARRAYSIZE(_subdlgs); i++) { // Calculate checkbox position HWND hwndCheck = GetDlgItem(_subdlgs[i].nIDCheck); ASSERT(hwndCheck); SetRect(&_subdlgs[i].rcCheck, ptOrigin.x, ptOrigin.y, ptOrigin.x + RECTWIDTH(metrics.CheckBoxRect()), ptOrigin.y + RECTHEIGHT(metrics.CheckBoxRect())); // Calculate subdialog position ULONG dwDlgFlags = SWP_NOACTIVATE; if (IsDlgButtonChecked(_subdlgs[i].nIDCheck)) { // position the checkbox's dialog immediately below. SetRect(&_subdlgs[i].rcDlg, _subdlgs[i].rcCheck.left, _subdlgs[i].rcCheck.bottom, cx - 1, _subdlgs[i].rcCheck.bottom + _subdlgs[i].sizeDlg.cy); dwDlgFlags |= SWP_SHOWWINDOW; ptOrigin.y = _subdlgs[i].rcDlg.bottom + metrics.TightMarginY(); } else { ptOrigin.y = _subdlgs[i].rcCheck.bottom + metrics.TightMarginY(); dwDlgFlags |= SWP_HIDEWINDOW; } // Reposition the pair ::DeferWindowPos(hdwp, _subdlgs[i].pDlg->Hwnd(), hwndCheck, _subdlgs[i].rcDlg.left, _subdlgs[i].rcDlg.top, RECTWIDTH(_subdlgs[i].rcDlg), RECTHEIGHT(_subdlgs[i].rcDlg), dwDlgFlags); ::DeferWindowPos(hdwp, hwndCheck, NULL, _subdlgs[i].rcCheck.left, _subdlgs[i].rcCheck.top, RECTWIDTH(_subdlgs[i].rcCheck), RECTHEIGHT(_subdlgs[i].rcCheck), SWP_NOZORDER|SWP_NOACTIVATE); } _LayoutLinkWindow(m_hWnd, metrics.CtlMarginX(), cx - metrics.CtlMarginX(), metrics.TightMarginY(), ptOrigin.y, IDC_INDEX_SERVER); EndDeferWindowPos(hdwp); } } // Assigns focus to the options dialog. This cannot be done by // simply setting focus to the options dialog, which is a child // of another dialog; USER will simply assign focus to the parent dialog. // So we need to explicitly set focus to our first child. void COptionsDlg::TakeFocus() { for (HWND hwndCtl = GetWindow(GW_CHILD); ::IsWindow(hwndCtl); hwndCtl = ::GetWindow(hwndCtl, GW_HWNDNEXT)) { ULONG dwStyle = ::GetWindowLong(hwndCtl, GWL_STYLE); if (dwStyle & WS_TABSTOP) { ::SetFocus(hwndCtl); break; } } } // Note that we do not care about returning results from this, as it will // be started asynchronously. void COptionsDlg::DoDelayedInit() { // have subdialogs do delayed initialization for (int i = 0; i < ARRAYSIZE(_subdlgs); i++) { _subdlgs[i].pDlg->DoDelayedInit(); } } LONG COptionsDlg::QueryHeight(LONG cx /* proposed width */, LONG cy /* proposed height */) { HWND hwndBottommost = GetBottomItem(); RECT rcThis, rcBottommost; // Retrieve the current height of the bottommost link window. GetWindowRect(&rcThis); ::GetWindowRect(hwndBottommost, &rcBottommost); ::MapWindowRect(NULL, GetParent(), &rcThis); ::MapWindowRect(NULL, GetParent(), &rcBottommost); // If, at the specified width, we compute a height for the bottommost // linkwindow that is different from its current height (e.g, due to word wrap), // we'll compute a new window rect that will LONG cyBottommost = (LONG)::SendMessage(hwndBottommost, LWM_GETIDEALHEIGHT, cx - (_pfsb->GetMetrics().CtlMarginX() * 2), 0); if (cyBottommost > 0 && cyBottommost != RECTHEIGHT(rcBottommost)) rcThis.bottom = rcBottommost.top + cyBottommost + _pfsb->GetMetrics().TightMarginY(); return RECTHEIGHT(rcThis); } BOOL COptionsDlg::GetMinSize(SIZE *pSize) { pSize->cx = pSize->cy = 0; HWND hwndBottom = GetBottomItem(); if (!::IsWindow(hwndBottom)) return FALSE; RECT rcBottom; ::GetWindowRect(hwndBottom, &rcBottom); ::MapWindowRect(NULL, m_hWnd, &rcBottom); pSize->cx = 0; pSize->cy = rcBottom.bottom; return TRUE; } HWND COptionsDlg::GetBottomItem() { HWND hwndBottom = GetDlgItem(IDC_INDEX_SERVER); ASSERT(::IsWindow(hwndBottom)) return hwndBottom; } void COptionsDlg::UpdateSearchCmdStateUI(DISPID dispid) { UINT nStatusText; BOOL fCiRunning, fCiIndexed, fCiPermission; GetCIStatus(&fCiRunning, &fCiIndexed, &fCiPermission); if (fCiRunning) { if (fCiPermission) // we have permission to distinguish between ready and busy nStatusText = fCiIndexed ? IDS_FSEARCH_CI_READY_LINK : IDS_FSEARCH_CI_BUSY_LINK; else // no permission to distinguish between ready and busy; we'll // just say it's enabled. nStatusText = IDS_FSEARCH_CI_ENABLED_LINK; } else { nStatusText = IDS_FSEARCH_CI_DISABLED_LINK; } TCHAR szCaption[MAX_PATH]; if (nStatusText != _nCIStatusText && EVAL(LoadString(HINST_THISDLL, nStatusText, szCaption, ARRAYSIZE(szCaption)))) { SetDlgItemText(IDC_INDEX_SERVER, szCaption); _nCIStatusText = nStatusText; LayoutControls(); SizeToFit(FALSE); } } STDMETHODIMP COptionsDlg::AddConstraints(ISearchCommandExt* pSrchCmd) { HRESULT hrRet = S_OK; // have subdialogs add their constraints for (int i = 0; i < ARRAYSIZE(_subdlgs); i++) { if (::IsWindowVisible(_subdlgs[i].pDlg->Hwnd())) { HRESULT hr = _subdlgs[i].pDlg->AddConstraints(pSrchCmd); if (FAILED(hr)) hrRet = hr; } } return hrRet; } STDMETHODIMP COptionsDlg::RestoreConstraint(const BSTR bstrName, const VARIANT* pValue) { // Try subordinate dialogs. for (int i = 0; i < ARRAYSIZE(_subdlgs); i++) { HRESULT hr = _subdlgs[i].pDlg->RestoreConstraint(bstrName, pValue); if (S_OK == hr) // open the dialog { CheckDlgButton(_subdlgs[i].nIDCheck, TRUE); LayoutControls(); SizeToFit(); } // if success, we're done. if (SUCCEEDED(hr)) return hr; // otherwise, try next subdialog. } return E_FAIL; } STDMETHODIMP COptionsDlg::TranslateAccelerator(MSG *pmsg) { if (S_OK == CSubDlg::TranslateAccelerator(pmsg)) return S_OK; // Query subdialogs if (_dlgDate.IsChild(pmsg->hwnd) && S_OK == _dlgDate.TranslateAccelerator(pmsg)) return S_OK; if (_dlgType.IsChild(pmsg->hwnd) && S_OK == _dlgType.TranslateAccelerator(pmsg)) return S_OK; if (_dlgSize.IsChild(pmsg->hwnd) && S_OK == _dlgSize.TranslateAccelerator(pmsg)) return S_OK; if (_dlgAdvanced.IsChild(pmsg->hwnd) && S_OK == _dlgAdvanced.TranslateAccelerator(pmsg)) return S_OK; return _pfsb->IsDlgMessage(Hwnd(), pmsg); } BOOL COptionsDlg::Validate() { // have subdialogs do validatation for (int i = 0; i < ARRAYSIZE(_subdlgs); i++) { if (::IsWindowVisible(_subdlgs[i].pDlg->Hwnd())) if (!_subdlgs[i].pDlg->Validate()) return FALSE; } return TRUE; } void COptionsDlg::Clear() { // have subdialogs clear themselves. for (int i = 0; i < ARRAYSIZE(_subdlgs); i++) { _subdlgs[i].pDlg->Clear(); CheckDlgButton(_subdlgs[i].nIDCheck, FALSE); } LayoutControls(); SizeToFit(); } LRESULT COptionsDlg::OnBtnClick(WORD nCode, WORD nID, HWND hwndCtl, BOOL&) { #ifdef DEBUG // Is this a sub-dialog expansion/contraction? BOOL bIsSubDlgBtn = FALSE; for (int i = 0; i < ARRAYSIZE(_subdlgs) && !bIsSubDlgBtn; i++) { if (nID == _subdlgs[i].nIDCheck) bIsSubDlgBtn = TRUE; } ASSERT(bIsSubDlgBtn); #endif DEBUG LoadSaveUIState(nID, TRUE); // persist it. LayoutControls(); SizeToFit(!IsDlgButtonChecked(nID)); // don't need to scroll the band if we've expanded a subdialog, // but we do if we've contracted one. return 0; } void COptionsDlg::SizeToFit(BOOL bScrollBand) { SIZE size; GetMinSize(&size); size.cy += _pfsb->GetMetrics().TightMarginY(); SetWindowPos(NULL, 0, 0, size.cx, size.cy, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE); ULONG dwLayoutFlags = BLF_ALL; if (!bScrollBand) dwLayoutFlags &= ~BLF_SCROLLWINDOW; ::SendMessage(GetParent(), WMU_UPDATELAYOUT, dwLayoutFlags, 0); } LRESULT COptionsDlg::OnIndexServerClick(int idCtl, NMHDR *pnmh, BOOL&) { BOOL fCiRunning, fCiIndexed, fCiPermission = FALSE; HRESULT hr = GetCIStatus(&fCiRunning, &fCiIndexed, &fCiPermission); if (SUCCEEDED(hr) && fCiPermission) { // CI is idle or not runnning. Show status dialog. if (IDOK == CCISettingsDlg_DoModal(GetDlgItem(IDC_INDEX_SERVER))) { // reflect any state change in UI. ::PostMessage(GetParent(), WMU_STATECHANGE, 0, 0); } } else { // No permission? display CI help. _IndexServiceHelp(NULL); } return 0; } // CBandDlg impl CBandDlg::CBandDlg(CFileSearchBand* pfsb) : _pfsb(pfsb) { // Verify that it initialized to FALSE/NULL ASSERT(NULL == _hwnd); ASSERT(NULL == _hwndLastFocus); VariantInit(&_varScope0); VariantInit(&_varQueryFile0); } CBandDlg::~CBandDlg() { VariantClear(&_varScope0); VariantClear(&_varQueryFile0); } STDMETHODIMP CBandDlg::TranslateAccelerator(MSG *pmsg) { if (WM_KEYDOWN == pmsg->message || WM_KEYUP == pmsg->message) { IAutoComplete2* pac2; if (GetAutoCompleteObjectForWindow(pmsg->hwnd, &pac2)) { if (S_OK == _TestAutoCompleteDropDownState(pac2, ACDD_VISIBLE)) { TranslateMessage(pmsg); DispatchMessage(pmsg); pac2->Release(); return S_OK; } pac2->Release(); } } // Check for Ctrl+Nav Key: if (_pfsb->IsKeyboardScroll(pmsg)) return S_OK; return S_FALSE; } void CBandDlg::SetDefaultFocus() { HWND hwndFirst = GetFirstTabItem(); if (IsWindow(hwndFirst)) SetFocus(hwndFirst); } void CBandDlg::RememberFocus(HWND hwndFocus) { if (!IsWindow(hwndFocus)) { _hwndLastFocus = NULL; hwndFocus = GetFocus(); } if (IsChild(_hwnd, hwndFocus)) _hwndLastFocus = hwndFocus; } BOOL CBandDlg::RestoreFocus() { if (IsWindow(_hwndLastFocus)) { if (IsWindowVisible(_hwndLastFocus) && IsWindowEnabled(_hwndLastFocus)) { SetFocus(_hwndLastFocus); return TRUE; } } else _hwndLastFocus = NULL; return FALSE; } LRESULT CBandDlg::OnChildSetFocusCmd(WORD, WORD, HWND hwndCtl, BOOL& bHandled) { _EnsureVisible(_hwnd, hwndCtl, _pfsb); return 0; } LRESULT CBandDlg::OnChildSetFocusNotify(int, NMHDR *pnmh, BOOL&) { _EnsureVisible(_hwnd, pnmh->hwndFrom, _pfsb); return 0; } LRESULT CBandDlg::OnChildKillFocusCmd(WORD, WORD, HWND hwndCtl, BOOL&) { _hwndLastFocus = hwndCtl; return 0; } LRESULT CBandDlg::OnChildKillFocusNotify(int, NMHDR *pnmh, BOOL&) { _hwndLastFocus = pnmh->hwndFrom; return 0; } LRESULT CBandDlg::OnComboExEndEdit(int, NMHDR *pnmh, BOOL&) { if (CBEN_ENDEDIT == pnmh->code) { if (CBENF_KILLFOCUS == ((NMCBEENDEDIT*)pnmh)->iWhy) _hwndLastFocus = pnmh->hwndFrom; } return 0; } void CBandDlg::WndPosChanging(HWND hwndOC, LPWINDOWPOS pwp) { SIZE sizeMin; if (0 == (pwp->flags & SWP_NOSIZE) && GetMinSize(hwndOC, &sizeMin)) { if (pwp->cx < sizeMin.cx) pwp->cx = sizeMin.cx; if (pwp->cy < sizeMin.cy) pwp->cy = sizeMin.cy; } } LRESULT CBandDlg::OnSize(UINT, WPARAM wParam, LPARAM lParam, BOOL&) { POINTS pts = MAKEPOINTS(lParam); LayoutControls(pts.x, pts.y); return 0; } void CBandDlg::LayoutControls(int cx, int cy) { if (cx < 0 || cy < 0) { RECT rc; GetClientRect(_hwnd, &rc); cx = RECTWIDTH(rc); cy = RECTHEIGHT(rc); } _LayoutCaption(GetIconID(), GetCaptionID(), GetCaptionDivID(), cx); } BOOL CBandDlg::GetIdealSize(HWND hwndOC, SIZE *psize) const { ASSERT(psize); psize->cx = psize->cy = 0; if (!IsWindow(Hwnd())) return FALSE; SIZE sizeMin; if (GetMinSize(hwndOC, &sizeMin)) { RECT rcClient; ::GetClientRect(hwndOC, &rcClient); psize->cx = (RECTWIDTH(rcClient) < sizeMin.cx) ? sizeMin.cx : RECTWIDTH(rcClient); psize->cy = sizeMin.cy; return TRUE; } return FALSE; } LRESULT CBandDlg::OnPaint(UINT, WPARAM, LPARAM, BOOL&) { // Just going to call BeginPaint and EndPaint. All // painting done in WM_ERASEBKGND handler to avoid flicker. PAINTSTRUCT ps; HDC hdc = BeginPaint(_hwnd, &ps); if (hdc) EndPaint(_hwnd, &ps); return 0; } LRESULT CBandDlg::OnEraseBkgnd(UINT, WPARAM wParam, LPARAM, BOOL&) { ASSERT(::IsWindow(_hwnd)); // was _Attach() called, e.g. from WM_INITDIALOG? _PaintDlg(_hwnd, _pfsb->GetMetrics(), (HDC)wParam); ValidateRect(_hwnd, NULL); return TRUE; } LRESULT CBandDlg::OnCtlColorStatic(UINT, WPARAM wParam, LPARAM lParam, BOOL&) { SetTextColor((HDC)wParam, _pfsb->GetMetrics().TextColor()); SetBkColor((HDC)wParam, _pfsb->GetMetrics().BkgndColor()); return (LRESULT)_pfsb->GetMetrics().BkgndBrush(); } // Hack method to remove turds left after showing band toolbar. // Methinks this is a USER issue. [scotthan] void CBandDlg::RemoveToolbarTurds(int cyOffset) { RECT rcUpdate; GetClientRect(_hwnd, &rcUpdate); HWND hwndCtl = GetDlgItem(_hwnd, GetCaptionDivID()); if (hwndCtl) { RECT rc; GetWindowRect(hwndCtl, &rc); ::MapWindowRect(NULL, _hwnd, &rc); rcUpdate.bottom = rc.bottom; OffsetRect(&rcUpdate, 0, cyOffset); InvalidateRect(_hwnd, &rcUpdate, TRUE); InvalidateRect(hwndCtl, NULL, TRUE); UpdateWindow(hwndCtl); } hwndCtl = GetDlgItem(_hwnd, GetIconID()); if (hwndCtl) { InvalidateRect(hwndCtl, NULL, TRUE); UpdateWindow(hwndCtl); } hwndCtl = GetDlgItem(_hwnd, GetCaptionID()); if (hwndCtl) { InvalidateRect(hwndCtl, NULL, TRUE); UpdateWindow(hwndCtl); } UpdateWindow(_hwnd); } void CBandDlg::_BeautifyCaption(UINT nIDCaption, UINT nIDIcon, UINT nIDIconResource) { // Do some cosmetic and initialization stuff HFONT hf = _pfsb->GetMetrics().BoldFont(_hwnd); if (hf) SendDlgItemMessage(_hwnd, nIDCaption, WM_SETFONT, (WPARAM)hf, 0); if (nIDIcon && nIDIconResource) { HICON hiconCaption = _pfsb->GetMetrics().CaptionIcon(nIDIconResource); if (hiconCaption) SendDlgItemMessage(_hwnd, nIDIcon, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hiconCaption); } } void CBandDlg::_LayoutCaption(UINT nIDCaption, UINT nIDIcon, UINT nIDDiv, LONG cxDlg) { RECT rcIcon, rcCaption; LONG cxMargin = _pfsb->GetMetrics().CtlMarginX(); GetWindowRect(GetDlgItem(_hwnd, nIDIcon), &rcIcon); GetWindowRect(GetDlgItem(_hwnd, nIDCaption), &rcCaption); ::MapWindowRect(NULL, _hwnd, &rcIcon); ::MapWindowRect(NULL, _hwnd, &rcCaption); int nTop = max(rcIcon.bottom, rcCaption.bottom) + _PixelsForDbu(_hwnd, 1, FALSE); SetWindowPos(GetDlgItem(_hwnd, nIDDiv), GetDlgItem(_hwnd, nIDCaption), cxMargin, nTop, cxDlg - (cxMargin * 2), 2, SWP_NOACTIVATE); } void CBandDlg::_LayoutSearchLinks(UINT nIDCaption, UINT nIDDiv, BOOL bShowDiv, LONG left, LONG right, LONG yMargin, LONG& yStart, const int rgLinkIDs[], LONG cLinkIDs) { // Position divider if (bShowDiv != 0) { RECT rcDiv; SetRect(&rcDiv, left, yStart, right, yStart + 1); SetWindowPos(GetDlgItem(_hwnd, nIDDiv), GetDlgItem(_hwnd, nIDCaption), rcDiv.left, rcDiv.top, RECTWIDTH(rcDiv), RECTHEIGHT(rcDiv), SWP_NOACTIVATE|SWP_SHOWWINDOW); yStart += yMargin; } else ShowWindow(GetDlgItem(_hwnd, nIDDiv), SW_HIDE); // Position caption RECT rcCaption; GetWindowRect(GetDlgItem(_hwnd, nIDCaption), &rcCaption); ::MapWindowRect(NULL, _hwnd, &rcCaption); OffsetRect(&rcCaption, left - rcCaption.left, yStart - rcCaption.top); SetWindowPos(GetDlgItem(_hwnd, nIDCaption), NULL, left, yStart, 0,0, SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE); yStart += RECTHEIGHT(rcCaption) + yMargin; // Position links _LayoutLinkWindows(_hwnd, left, right, yMargin, yStart, rgLinkIDs, cLinkIDs); } LRESULT CBandDlg::OnEditChange(WORD, WORD, HWND, BOOL&) { _pfsb->SetDirty(); return 0; } LRESULT CBandDlg::OnSearchLink(int nID, LPNMHDR, BOOL&) { ASSERT(_pfsb); _pfsb->StopSearch(); switch (nID) { case IDC_SEARCHLINK_FILES: _pfsb->FindFilesOrFolders(FALSE, TRUE); break; case IDC_SEARCHLINK_COMPUTERS: _pfsb->FindComputer(FALSE, TRUE); break; case IDC_SEARCHLINK_PRINTERS: _pfsb->FindPrinter(FALSE, TRUE); break; case IDC_SEARCHLINK_PEOPLE: _pfsb->FindPeople(FALSE, TRUE); break; case IDC_SEARCHLINK_INTERNET: _pfsb->FindOnWeb(FALSE, TRUE); break; } return 0; } // Invoked when a client calls IFileSearchBand::SetSearchParameters() HRESULT CBandDlg::SetScope(IN VARIANT* pvarScope, BOOL bTrack) { HRESULT hr = S_OK; VariantClear(&_varScope0); // cache the scope if (pvarScope) hr = VariantCopy(&_varScope0, pvarScope); return hr; } HRESULT CBandDlg::GetScope(OUT VARIANT* pvarScope) { // retrieve the scope if (!pvarScope) return E_INVALIDARG; HRESULT hr = VariantCopy(pvarScope, &_varScope0); return SUCCEEDED(hr) ? (VT_EMPTY == _varScope0.vt ? S_FALSE : S_OK) : hr; } HRESULT CBandDlg::SetQueryFile(IN VARIANT* pvarFile) { return VariantCopy(&_varQueryFile0, pvarFile); } HRESULT CBandDlg::GetQueryFile(OUT VARIANT* pvarFile) { // retrieve the filename of the query to restore. if (!pvarFile) return E_INVALIDARG; VariantInit(pvarFile); HRESULT hr = VariantCopy(pvarFile, &_varQueryFile0); return SUCCEEDED(hr) ? (VT_EMPTY == _varQueryFile0.vt ? S_FALSE : S_OK) : hr; } // CFindFilesDlg impl #define FSEARCHMAIN_TABFIRST IDC_FILESPEC #define FSEARCHMAIN_TABLAST IDC_SEARCHLINK_INTERNET #define FSEARCHMAIN_BOTTOMMOST IDC_SEARCHLINK_INTERNET // bottom-most control #define FSEARCHMAIN_RIGHTMOST IDC_SEARCH_STOP // right-most control #define UISTATETIMER 1 #define UISTATETIMER_DELAY 4000 CFindFilesDlg::CFindFilesDlg(CFileSearchBand* pfsb) : CSearchCmdDlg(pfsb), _dlgOptions(pfsb), _iCurNamespace(CB_ERR), _fTrackScope(TRACKSCOPE_SPECIFIC), _dwWarningFlags(DFW_DEFAULT), _dwRunOnceWarningFlags(DFW_DEFAULT) { // Since we use the zero initializer for COM objects, all variables should // be initialized to NULL/FALSE/0 ASSERT(FALSE == _bScoped); ASSERT(FALSE == _fDisplayOptions); ASSERT(FALSE == _fNamespace); ASSERT(FALSE == _fDebuted); ASSERT(FALSE == _fBandFinishedDisplaying); ASSERT(NULL == _pacGrepText); ASSERT(NULL == _pmruGrepText); ASSERT(NULL == _pacFileSpec); ASSERT(NULL == _pmruFileSpec); ASSERT(0 == *_szInitialPath); ASSERT(0 == *_szInitialNames); ASSERT(0 == *_szCurrentPath); ASSERT(0 == *_szLocalDrives); ASSERT(NULL == _pidlInitial); } CFindFilesDlg::~CFindFilesDlg() { ATOMICRELEASE(_pacGrepText); ATOMICRELEASE(_pmruGrepText); ATOMICRELEASE(_pacFileSpec); ATOMICRELEASE(_pmruFileSpec); ILFree(_pidlInitial); } // Scope to a default namespace. BOOL CFindFilesDlg::SetDefaultScope() { // If we've already assigned a scope, bail early if (_bScoped) return TRUE; // Try establiblishing the preassigned (_szInitialXXX) scope: BOOL bScoped = _SetPreassignedScope(); if (!bScoped) { // Try setting scope to the current shell folder of the active view... bScoped = _SetFolderScope(); if (!bScoped) { // set it to the hard-coded shell default folder bScoped = _SetLocalDefaultScope(); } } return bScoped; } // Assignes the namespace control to the preassigned scope saved in // _szInitialNames/_szInitialPath/_pidlInitial BOOL CFindFilesDlg::_SetPreassignedScope() { BOOL bScoped = FALSE; if (*_szInitialNames || *_szInitialPath || _pidlInitial) bScoped = AssignNamespace(_szInitialPath, _pidlInitial, _szInitialNames, FALSE); return bScoped; } STDAPI_(BOOL) IsFTPFolder(IShellFolder * psf); // Scope to the namespace of the current shell folder view BOOL CFindFilesDlg::_SetFolderScope() { BOOL bScoped = FALSE; ASSERT(_pfsb->BandSite()); LPITEMIDLIST pidl; if (SUCCEEDED(_GetCurrentFolderIDList(_pfsb->BandSite(), &pidl))) { // Get the display name/path. IF it is an FTP site, then we need to get the name // as though it is for the address bar becasue when we call SHGetPathFromIDList, // it returns "" for FTP sites. IShellFolder *psf = NULL; if (SUCCEEDED(SHBindToObject(NULL, IID_X_PPV_ARG(IShellFolder, pidl, &psf))) && IsFTPFolder(psf)) { SHGetNameAndFlags(pidl, SHGDN_FORADDRESSBAR, _szInitialNames, ARRAYSIZE(_szInitialNames), NULL); SHGetNameAndFlags(pidl, SHGDN_FORPARSING, _szInitialPath, ARRAYSIZE(_szInitialNames), NULL); } else { SHGetNameAndFlags(pidl, SHGDN_NORMAL, _szInitialNames, ARRAYSIZE(_szInitialNames), NULL); SHGetPathFromIDList(pidl, _szInitialPath); // file system path only here! } if (psf) { psf->Release(); } // Store the pidl for use later if we are starting it async _pidlInitial = ILClone(pidl); // if we're tracking the scope loosely... if ((TRACKSCOPE_GENERAL == _fTrackScope) && _IsPathLocalHarddrive(_szInitialPath)) { // scope to local default scope *_szInitialNames = *_szInitialPath = 0; bScoped = _SetLocalDefaultScope(); } else if (_threadState.fComplete /* finished populating namespace combo */ && _szInitialPath[0]) { bScoped = AssignNamespace(_szInitialPath, pidl, _szInitialNames, FALSE); } ILFree(pidl); } return bScoped; } // Scope to the hard-coded shell default namespace. BOOL CFindFilesDlg::_SetLocalDefaultScope() { BOOL bScoped = FALSE; // Initialize fallback initial namespace // default to Local Hard Drives if possible if (_szLocalDrives[0] && AssignNamespace(NULL, NULL, _szLocalDrives, FALSE)) { bScoped = TRUE; } else { TCHAR szDesktopPath[MAX_PATH]; if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, NULL, SHGFP_TYPE_CURRENT, szDesktopPath)) && AssignNamespace(NULL, NULL, szDesktopPath, FALSE)) { bScoped = TRUE; } } // If we failed, this means that the namespace combo hasn't // been populated yet. // We just sit tight, cuz the populating thread will fall back on // the LocalDefaultScope. return bScoped; } // search **band** show/hide handler void CFindFilesDlg::OnBandShow(BOOL fShow) { CSearchCmdDlg::OnBandShow(fShow); if (fShow) { // Establish the first showing's band width if (!_fDebuted && _pfsb->IsBandDebut()) { _pfsb->SetDeskbandWidth(GetIdealDeskbandWidth()); _fDebuted = TRUE; } // If we're tracking the scope to the current folder shell view, // update it now, as it may have changed. if (_fTrackScope != TRACKSCOPE_NONE) { _bScoped = FALSE; _SetFolderScope(); } // restart our UI state timer SetTimer(UISTATETIMER, UISTATETIMER_DELAY); } else { // we're being hidden so stop updating our state indicators. KillTimer(UISTATETIMER); } } // search band **dialog** show/hide handler void CFindFilesDlg::OnBandDialogShow(BOOL fShow) { CSearchCmdDlg::OnBandDialogShow(fShow); if (fShow) { // If we're tracking the scope to the current folder shell view, // update it now, as it may have changed. if (_fTrackScope != TRACKSCOPE_NONE) { _bScoped = FALSE; _SetFolderScope(); } } } // Explicit scoping method. This will be called if a client // called IFileSearchBand::SetSearchParameters with a non-NULL scope. HRESULT CFindFilesDlg::SetScope(IN VARIANT* pvarScope, BOOL bTrack) { HRESULT hr = CBandDlg::SetScope(pvarScope, bTrack); if (S_OK != hr) return hr; LPITEMIDLIST pidlSearch = VariantToIDList(&_varScope0); if (pidlSearch) { SHGetNameAndFlags(pidlSearch, SHGDN_FORPARSING, _szInitialPath, ARRAYSIZE(_szInitialPath), NULL); SHGetNameAndFlags(pidlSearch, SHGDN_NORMAL, _szInitialNames, ARRAYSIZE(_szInitialNames), NULL); ILFree(pidlSearch); // Did we get one? if (*_szInitialNames || *_szInitialPath) { if (_bScoped) { // If we've already scoped, update the namespace combo. // Track if succeed and requested. if (AssignNamespace(_szInitialPath, NULL, _szInitialNames, FALSE) && bTrack) _fTrackScope = TRACKSCOPE_SPECIFIC; } else { // Not already scoped. We've assigned our initial namespace, // let the namespace thread completion handler update // the combo if (bTrack) _fTrackScope = TRACKSCOPE_SPECIFIC; } } } return S_OK; } LRESULT CFindFilesDlg::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { _Attach(m_hWnd); _dlgOptions.SetBandDlg(this); // Register specialty window classes. DivWindow_RegisterClass(); GroupButton_RegisterClass(); // Initialize some metrics CMetrics& metrics = _pfsb->GetMetrics(); RECT rc; _pfsb->GetMetrics().Init(m_hWnd); // SHAutoComplete(::GetWindow(GetDlgItem(IDC_NAMESPACE), GW_CHILD), SHACF_FILESYS_DIRS); ::GetWindowRect(GetDlgItem(IDC_FILESPEC), &rc); ::MapWindowRect(NULL, m_hWnd, &rc); metrics.ExpandOrigin().x = rc.left; // Position start, stop buttons. ::GetWindowRect(GetDlgItem(IDC_SEARCH_START), &rc); ::MapWindowRect(NULL, m_hWnd, &rc); int cxBtn = _GetResourceMetric(m_hWnd, IDS_FSEARCH_STARTSTOPWIDTH, TRUE); if (cxBtn > 0) { rc.right = rc.left + cxBtn; ::SetWindowPos(GetDlgItem(IDC_SEARCH_START), NULL, rc.left, rc.top, RECTWIDTH(rc), RECTHEIGHT(rc), SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE); OffsetRect(&rc, cxBtn + _PixelsForDbu(m_hWnd, 12, TRUE), 0); ::SetWindowPos(GetDlgItem(IDC_SEARCH_STOP), NULL, rc.left, rc.top, RECTWIDTH(rc), RECTHEIGHT(rc), SWP_NOZORDER|SWP_NOACTIVATE); } // Create subdialogs and collect native sizes. _dlgOptions.Create(m_hWnd); ASSERT(::IsWindow(_dlgOptions)); // Load settings LoadSaveUIState(0, FALSE); // Show/Hide the "Search" Options subdialog _dlgOptions.ShowWindow(_fDisplayOptions ? SW_SHOW : SW_HIDE); // Create 'link' child controls POINT pt; pt.x = metrics.CtlMarginX(); pt.y = 0; // Create 'Search Options' link and group button _CreateLinkWindow(m_hWnd, IDC_SEARCHLINK_OPTIONS, pt, IDS_FSEARCH_SEARCHLINK_OPTIONS, !_fDisplayOptions); TCHAR szGroupBtn[128]; EVAL(LoadString(HINST_THISDLL, IDS_FSEARCH_GROUPBTN_OPTIONS, szGroupBtn, ARRAYSIZE(szGroupBtn))); HWND hwndGrpBtn = CreateWindowEx(0, GROUPBUTTON_CLASS, szGroupBtn, WS_CHILD|WS_BORDER|WS_TABSTOP, pt.x, pt.y, 400, 18, m_hWnd, (HMENU)IDC_GROUPBTN_OPTIONS, HINST_THISDLL, NULL); if (::IsWindow(hwndGrpBtn)) { ::SendMessage(hwndGrpBtn, GBM_SETBUDDY, (WPARAM)_dlgOptions.m_hWnd, (LPARAM)GBBF_HRESIZE|GBBF_VSLAVE); ::ShowWindow(GetDlgItem(IDC_GROUPBTN_OPTIONS), _fDisplayOptions ? SW_SHOW : SW_HIDE); } // Create cross-navigation links _CreateSearchLinks(m_hWnd, pt, IDC_SEARCHLINK_FILES); _CreateDivider(m_hWnd, IDC_FSEARCH_DIV1, pt, 2, GetDlgItem(IDC_FSEARCH_CAPTION)); _CreateDivider(m_hWnd, IDC_FSEARCH_DIV2, pt, 1, GetDlgItem(IDC_SEARCHLINK_CAPTION)); _CreateDivider(m_hWnd, IDC_FSEARCH_DIV3, pt, 1, GetDlgItem(IDC_SEARCHLINK_PEOPLE)); // Do some cosmetic and initialization stuff OnWinIniChange(); _InitializeMru(GetDlgItem(IDC_FILESPEC), &_pacFileSpec, TEXT("FilesNamedMRU"), &_pmruFileSpec); _InitializeMru(GetDlgItem(IDC_GREPTEXT), &_pacGrepText, TEXT("ContainingTextMRU"), &_pmruGrepText); SendDlgItemMessage(IDC_FILESPEC, EM_LIMITTEXT, MAX_EDIT, 0); SendDlgItemMessage(IDC_GREPTEXT, EM_LIMITTEXT, MAX_EDIT, 0); SendDlgItemMessage(IDC_NAMESPACE, CBEM_SETEXTENDEDSTYLE, CBES_EX_NOSIZELIMIT | CBES_EX_CASESENSITIVE, CBES_EX_NOSIZELIMIT | CBES_EX_CASESENSITIVE); SendDlgItemMessage(IDC_NAMESPACE, CBEM_SETIMAGELIST, 0, (LPARAM)GetSystemImageListSmallIcons()); SendDlgItemMessage(IDC_NAMESPACE, CBEM_SETEXSTYLE, 0, 0); // Enable the cue banners for the edit boxes: TCHAR szCaption[128]; LoadString(HINST_THISDLL, IDS_FIND_CUEBANNER_FILE, szCaption, ARRAYSIZE(szCaption)); SendDlgItemMessage(IDC_FILESPEC, EM_SETCUEBANNER, 0, (LPARAM) szCaption); LoadString(HINST_THISDLL, IDS_FIND_CUEBANNER_GREP, szCaption, ARRAYSIZE(szCaption)); SendDlgItemMessage(IDC_GREPTEXT, EM_SETCUEBANNER, 0, (LPARAM) szCaption); // Bias the input reader towards file names SetModeBias(MODEBIASMODE_FILENAME); // Launch thread to populate the namespaces combo. _threadState.hwndCtl = GetDlgItem(IDC_NAMESPACE); _threadState.pvParam = this; _threadState.fComplete = FALSE; _threadState.fCancel = FALSE; if (SUCCEEDED(SAFECAST(_pfsb, IFileSearchBand*)->QueryInterface(IID_PPV_ARG(IUnknown, &_threadState.punkBand)))) { if (!SHCreateThread(NamespaceThreadProc, &_threadState, CTF_COINIT, NULL)) { ATOMICRELEASE(_threadState.punkBand); } } // Layout our subdialogs and update state representation... LayoutControls(); UpdateSearchCmdStateUI(); SetTimer(UISTATETIMER, UISTATETIMER_DELAY); return TRUE; // Let the system set the focus } LRESULT CFindFilesDlg::OnEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&) { // paint the background _PaintDlg(m_hWnd, _pfsb->GetMetrics(), (HDC)wParam); if (_fDisplayOptions) // ensure that the group button is updated. SendDlgItemMessage(IDC_GROUPBTN_OPTIONS, WM_NCPAINT, (WPARAM)1, 0); // validate our work. ValidateRect(NULL); return TRUE; } void CFindFilesDlg::OnWinIniChange() { CBandDlg::OnWinIniChange(); // redisplay animated icon HWND hwndIcon = GetDlgItem(IDC_FSEARCH_ICON); Animate_Close(hwndIcon); Animate_OpenEx(hwndIcon, HINST_THISDLL, MAKEINTRESOURCE(IDA_FINDFILE)); SendDlgItemMessage(IDC_NAMESPACE, CB_SETDROPPEDWIDTH, _PixelsForDbu(m_hWnd, MIN_NAMESPACELIST_WIDTH, TRUE), 0); _BeautifyCaption(IDC_FSEARCH_CAPTION); _dlgOptions.OnWinIniChange(); } LRESULT CFindFilesDlg::OnDestroy(UINT, WPARAM, LPARAM, BOOL& bHandled) { KillTimer(UISTATETIMER); StopSearch(); if (_pSrchCmd) { DisconnectEvents(); IUnknown_SetSite(_pSrchCmd, NULL); } _threadState.fCancel = TRUE; _fOnDestroy = TRUE; bHandled = FALSE; return 0; } BOOL CFindFilesDlg::Validate() { return _dlgOptions.Validate(); } STDMETHODIMP CFindFilesDlg::AddConstraints(ISearchCommandExt *pSrchCmd) { HRESULT hr; VARIANT var = {0}; TCHAR szPath[MAX_URL_STRING]; // If the user enters a path as a filename, it will recognize it as a path and replace // the filename with just the file portion and the namespace with the path. if (::GetDlgItemText(m_hWnd, IDC_FILESPEC, szPath, ARRAYSIZE(szPath)) > 0) { if (StrChr(szPath, TEXT('\\')) != NULL) { if (!_PathLooksLikeFilePattern(szPath) && (PathIsUNCServer(szPath) /* string test: \\server */|| _PathIsUNCServerShareOrSub(szPath) /* string test: \\server\share */ || PathIsDirectory(szPath)) /* this actually tests existence */) { ::SetDlgItemText(m_hWnd, IDC_FILESPEC, TEXT("*.*")); AssignNamespace(szPath, NULL, NULL, FALSE); } else { // just use the prefix for the file spec & the root for the location TCHAR szRoot[MAX_URL_STRING]; hr = StringCchCopy(szRoot, ARRAYSIZE(szRoot), szPath); // should always fit - both same size if (SUCCEEDED(hr)) { if (PathRemoveFileSpec(szRoot) && szRoot[0] != 0) { PathStripPath(szPath); ::SetDlgItemText(m_hWnd, IDC_FILESPEC, szPath); AssignNamespace(szRoot, NULL, NULL, FALSE); } } } } } // If _ReconcileNamespace could not add an item to the combo box for // the path entered, then it means that the path is likely invalid. // Get the path and check it here. IEnumIDList *penum; hr = _GetTargetNamespace(&penum); if (SUCCEEDED(hr)) { var.vt = VT_UNKNOWN; penum->QueryInterface(IID_PPV_ARG(IUnknown, &var.punkVal)); hr = _AddConstraint(pSrchCmd, L"LookIn", &var); VariantClear(&var); } else { GetDlgItemText(IDC_NAMESPACE, szPath, ARRAYSIZE(szPath)); hr = _PathValidate(szPath, GetParent(), TRUE); if (SUCCEEDED(hr)) { if (SUCCEEDED(InitVariantFromStr(&var, szPath))) { hr = _AddConstraint(pSrchCmd, L"LookIn", &var); VariantClear(&var); } } else { // _PathValidate's SHPathPrepareForWrite may have already displayed error if (HRESULT_FROM_WIN32(ERROR_CANCELLED) != hr) { TCHAR szMsg[MAX_URL_STRING]; if (_FmtError(IDS_FSEARCH_INVALIDFOLDER_FMT, szPath, szMsg, ARRAYSIZE(szMsg))) ShellMessageBox(HINST_THISDLL, GetParent(), szMsg, NULL, MB_OK | MB_ICONASTERISK); } ::SetFocus(GetDlgItem(IDC_NAMESPACE)); } } if (SUCCEEDED(hr)) { // Add 'Files Named' constraint if (S_OK == _GetWindowValue(m_hWnd, IDC_FILESPEC, &var)) { hr = _AddConstraint(pSrchCmd, L"Named", &var); if (SUCCEEDED(hr)) _AddMruStringFromWindow(_pmruFileSpec, GetDlgItem(IDC_FILESPEC)); VariantClear(&var); } // Add 'Containing Text' constraint if (S_OK == _GetWindowValue(m_hWnd, IDC_GREPTEXT, &var)) { VARIANT varQuery; ULONG ulDialect; BOOL fCiQuery = IsCiQuery(&var, &varQuery, &ulDialect); if (fCiQuery) { hr = _AddConstraint(pSrchCmd, L"IndexedSearch", &varQuery); if (SUCCEEDED(hr)) { _AddMruStringFromWindow(_pmruGrepText, GetDlgItem(IDC_GREPTEXT)); VariantClear(&var); var.vt = VT_UI4; var.ulVal = ulDialect; hr = _AddConstraint(pSrchCmd, L"QueryDialect", &var); } } else { // add to 'containing text' constraint hr = _AddConstraint(pSrchCmd, L"ContainingText", &var); if (SUCCEEDED(hr)) _AddMruStringFromWindow(_pmruGrepText, GetDlgItem(IDC_GREPTEXT)); } VariantClear(&varQuery); VariantClear(&var); } // Warning flags if (_dwRunOnceWarningFlags != DFW_DEFAULT) { // re-run the query w/ temporary warning bits. var.ulVal = _dwRunOnceWarningFlags; var.vt = VT_UI4; //_dwRunOnceWarningFlags = DFW_DEFAULT; cannot reset it here in case of error, must preserve them hr = _AddConstraint(pSrchCmd, L"WarningFlags", &var); } else if (_dwWarningFlags != DFW_DEFAULT) { var.ulVal = _dwWarningFlags; var.vt = VT_UI4; hr = _AddConstraint(pSrchCmd, L"WarningFlags", &var); } VariantClear(&var); hr = _dlgOptions.AddConstraints(pSrchCmd); } return hr; } STDMETHODIMP CFindFilesDlg::RestoreConstraint(const BSTR bstrName, const VARIANT* pValue) { if (IsConstraintName(L"Named", bstrName)) { _SetWindowValue(m_hWnd, IDC_FILESPEC, pValue); return S_FALSE; } if (IsConstraintName(L"IndexedSearch", bstrName)) { ASSERT(VT_BSTR == pValue->vt); if (pValue->bstrVal) { int cch = lstrlenW(pValue->bstrVal) + 2; LPWSTR pwszVal = new WCHAR[cch]; if (pwszVal) { *pwszVal = L'!'; StringCchCat(pwszVal, cch, pValue->bstrVal); // truncation ok } ::SetDlgItemTextW(m_hWnd, IDC_GREPTEXT, pwszVal); if (pwszVal) delete [] pwszVal; } return S_FALSE; } if (IsConstraintName(L"ContainingText", bstrName)) { _SetWindowValue(m_hWnd, IDC_GREPTEXT, pValue); return S_FALSE; } HRESULT hr = _dlgOptions.RestoreConstraint(bstrName, pValue); if (S_OK == hr) // opened a dialog _ShowOptions(TRUE); if (SUCCEEDED(hr)) return hr; return E_FAIL; } void CFindFilesDlg::RestoreSearch() { DFConstraint* pdfc = NULL; HRESULT hr; BOOL bMore = TRUE; ISearchCommandExt* pSrchCmd = GetSearchCmd(); if (NULL == pSrchCmd) return; CSearchCmdDlg::Clear(); // we'll anchor to any restored scope, or the default _fTrackScope = TRACKSCOPE_GENERAL; for (hr = pSrchCmd->GetNextConstraint(TRUE, &pdfc); S_OK == hr && bMore; hr = pSrchCmd->GetNextConstraint(FALSE, &pdfc)) { BSTR bstrName = NULL; if (S_OK == (hr = pdfc->get_Name(&bstrName)) && bstrName) { if (*bstrName == 0) bMore = FALSE; // no more constraints. else { VARIANT varValue = {0}; hr = pdfc->get_Value(&varValue); if (S_OK == hr) { // If this is the 'lookin' value, cache the path. if (IsConstraintName(L"LookIn", bstrName)) { if (VT_BSTR == varValue.vt && varValue.bstrVal) { // Assign path and clear display name (which we don't know or care about). if (_bScoped) AssignNamespace(varValue.bstrVal, NULL, NULL, FALSE); else { StringCchCopy(_szInitialPath, ARRAYSIZE(_szInitialPath), varValue.bstrVal); // truncation ok *_szInitialNames = 0; } } } else RestoreConstraint(bstrName, &varValue); VariantClear(&varValue); } } SysFreeString(bstrName); } pdfc->Release(); } LayoutControls(); _pfsb->UpdateLayout(); } HRESULT FirstIDList(IEnumIDList *penum, LPITEMIDLIST *ppidl) { penum->Reset(); return penum->Next(1, ppidl, NULL); } HRESULT CFindFilesDlg::_GetTargetNamespace(IEnumIDList **ppenum) { *ppenum = NULL; // We don't trust the comboex to handle the edit text properly so try to compensate... TCHAR szText[MAX_PATH]; GetDlgItemText(IDC_NAMESPACE, szText, ARRAYSIZE(szText)); INT_PTR iCurSel = SendDlgItemMessage(IDC_NAMESPACE, CB_GETCURSEL, 0, 0); if (CB_ERR != iCurSel) { UINT cchItem = SendDlgItemMessage(IDC_NAMESPACE, CB_GETLBTEXTLEN, (WPARAM)iCurSel, (LPARAM)0); if (cchItem != CB_ERR) { TCHAR *pszItemName = (TCHAR *)LocalAlloc(LPTR, (cchItem+1)*sizeof(TCHAR)); if (pszItemName != NULL) { if (CB_ERR == SendDlgItemMessage(IDC_NAMESPACE, CB_GETLBTEXT, (WPARAM)iCurSel, (LPARAM)pszItemName)) { pszItemName[0] = 0; } *ppenum = _GetItems(iCurSel); if (*ppenum) { if (lstrcmp(szText, pszItemName)) *ppenum = NULL; // combo edit/combo dropdown mismatch! } LocalFree(pszItemName); } } } return *ppenum ? S_OK : E_FAIL; } void CFindFilesDlg::Clear() { CSearchCmdDlg::Clear(); // Clear edit fields SetDlgItemText(IDC_FILESPEC, NULL); SetDlgItemText(IDC_GREPTEXT, NULL); _dlgOptions.Clear(); _pfsb->UpdateLayout(BLF_ALL); } void CFindFilesDlg::LoadSaveUIState(UINT nIDCtl, BOOL bSave) { if (0 == nIDCtl) // load/save all. { LoadSaveUIState(IDC_SEARCHLINK_OPTIONS, bSave); LoadSaveUIState(LSUIS_WARNING, bSave); } HKEY hkey = _pfsb->GetBandRegKey(bSave); if (hkey) { DWORD dwData; DWORD cbData; DWORD dwType = REG_DWORD; LPCTSTR pszVal = NULL; switch (nIDCtl) { case IDC_SEARCHLINK_OPTIONS: pszVal = TEXT("UseSearchOptions"); dwData = _fDisplayOptions; cbData = sizeof(dwData); break; case LSUIS_WARNING: pszVal = TEXT("Warnings"); dwData = _dwWarningFlags; cbData = sizeof(_dwWarningFlags); break; } if (bSave) { RegSetValueEx(hkey, pszVal, 0, dwType, (LPBYTE)&dwData, cbData); } else if (pszVal != NULL) { DWORD dwTypeActual; if (ERROR_SUCCESS == RegQueryValueEx(hkey, pszVal, 0, &dwTypeActual, (LPBYTE)&dwData, &cbData) && dwType == dwTypeActual) { switch (nIDCtl) { case IDC_SEARCHLINK_OPTIONS: _fDisplayOptions = BOOLIFY(dwData); break; case LSUIS_WARNING: _dwWarningFlags = dwData; break; } } } RegCloseKey(hkey); } } HWND CFindFilesDlg::GetFirstTabItem() const { return GetDlgItem(FSEARCHMAIN_TABFIRST); } HWND CFindFilesDlg::GetLastTabItem() const { return GetDlgItem(FSEARCHMAIN_TABLAST); } BOOL CFindFilesDlg::GetAutoCompleteObjectForWindow(HWND hwnd, IAutoComplete2** ppac2) { *ppac2 = NULL; if (hwnd == GetDlgItem(IDC_FILESPEC)) *ppac2 = _pacFileSpec; else if (hwnd == GetDlgItem(IDC_GREPTEXT)) *ppac2 = _pacGrepText; if (*ppac2) { (*ppac2)->AddRef(); return TRUE; } return CBandDlg::GetAutoCompleteObjectForWindow(hwnd, ppac2); } void CFindFilesDlg::_ShowNamespaceEditImage(BOOL bShow) { SendDlgItemMessage(IDC_NAMESPACE, CBEM_SETEXTENDEDSTYLE, CBES_EX_NOEDITIMAGE, bShow ? 0 : CBES_EX_NOEDITIMAGE); } STDMETHODIMP CFindFilesDlg::TranslateAccelerator(MSG *pmsg) { // Check for Ctrl+Nav Key: if (S_OK == CSearchCmdDlg::TranslateAccelerator(pmsg)) return S_OK; // Check for VK_RETURN key. if (WM_KEYDOWN == pmsg->message) { HWND hwndFocus = ::GetFocus(); if (hwndFocus == GetDlgItem(IDC_NAMESPACE) || ::IsChild(GetDlgItem(IDC_NAMESPACE), hwndFocus)) { if (VK_RETURN == pmsg->wParam || VK_TAB == pmsg->wParam || VK_F6 == pmsg->wParam) { _UIReconcileNamespace(); } else { // Hide edit image if this virtkey maps to a character, if (MapVirtualKey((UINT)pmsg->wParam, 2) != 0 /* it's a char */) _fNamespace = TRUE; _ShowNamespaceEditImage(!_fNamespace); } } } if (_dlgOptions.IsChild(pmsg->hwnd) && S_OK == _dlgOptions.TranslateAccelerator(pmsg)) return S_OK; // Handle it ourselves... return _pfsb->IsDlgMessage(m_hWnd, pmsg); } BOOL CFindFilesDlg::GetMinSize(HWND hwndOC, SIZE *psize) const { CMetrics& metrics = _pfsb->GetMetrics(); RECT rc; // Calculate minimum tracking width. ASSERT(psize); psize->cx = psize->cy = 0; if (!::IsWindow(m_hWnd)) return FALSE; // determine mininum width HWND hwndLimit = GetDlgItem(FSEARCHMAIN_RIGHTMOST); if (!::GetWindowRect(hwndLimit, &rc)) { ASSERT(hwndLimit != NULL); return FALSE; } ::MapWindowRect(NULL, m_hWnd, &rc); psize->cx = rc.right + metrics.CtlMarginX(); // determine mininum height hwndLimit = GetDlgItem(FSEARCHMAIN_BOTTOMMOST); if (!(::IsWindow(hwndLimit) && ::GetWindowRect(hwndLimit, &rc))) return FALSE; ::MapWindowRect(NULL, m_hWnd, &rc); psize->cy = rc.bottom + metrics.TightMarginY(); return TRUE; } int CFindFilesDlg::GetIdealDeskbandWidth() const { LONG cx0 = _GetResourceMetric(m_hWnd, IDS_FSEARCH_BANDWIDTH, TRUE); ASSERT(cx0 >= 0); return cx0 + (_pfsb->GetMetrics().CtlMarginX() * 2); } void CFindFilesDlg::LayoutControls(int cx, int cy) { if (cx < 0 || cy < 0) { RECT rcClient; GetClientRect(&rcClient); cx = RECTWIDTH(rcClient); cy = RECTHEIGHT(rcClient); } CBandDlg::LayoutControls(cx, cy); CMetrics& metrics = _pfsb->GetMetrics(); POINT ptOrigin = metrics.ExpandOrigin(); HDWP hdwp = BeginDeferWindowPos(6); if (hdwp) { // Resize edit, combo immediate children int i; enum { ircFILESPEC, ircGREPTEXT, ircNAMESPACE, ircSEARCHSTART, ircOPTIONGRP, ircOPTIONSDLG, ircLINKCAPTION, ircDIV2, irc_count }; RECT rcCtls[irc_count]; ::GetWindowRect(GetDlgItem(IDC_FILESPEC), &rcCtls[ircFILESPEC]); ::GetWindowRect(GetDlgItem(IDC_GREPTEXT), &rcCtls[ircGREPTEXT]); ::GetWindowRect(GetDlgItem(IDC_NAMESPACE), &rcCtls[ircNAMESPACE]); ::GetWindowRect(GetDlgItem(IDC_SEARCH_START), &rcCtls[ircSEARCHSTART]); ::GetWindowRect(GetDlgItem(IDC_GROUPBTN_OPTIONS), &rcCtls[ircOPTIONGRP]); ::GetWindowRect(GetDlgItem(IDC_SEARCHLINK_CAPTION), &rcCtls[ircLINKCAPTION]); ::GetWindowRect(GetDlgItem(IDC_FSEARCH_DIV2), &rcCtls[ircDIV2]); SIZE sizeOptions; _dlgOptions.GetWindowRect(&rcCtls[ircOPTIONSDLG]); _dlgOptions.GetMinSize(&sizeOptions); rcCtls[ircOPTIONSDLG].bottom = rcCtls[ircOPTIONSDLG].top + sizeOptions.cy; for (i = 0; i < ARRAYSIZE(rcCtls); i++) { // MapWindowPoints is mirroring aware only if you pass two points ::MapWindowRect(NULL, m_hWnd, &rcCtls[i]); } // Position caption elements _LayoutCaption(IDC_FSEARCH_CAPTION, IDC_FSEARCH_ICON, IDC_FSEARCH_DIV1, cx); // Resize ctl widths for (i = 0; i < irc_count; i++) rcCtls[i].right = cx - metrics.CtlMarginX(); // Stretch the 'Named' combo: ::DeferWindowPos(hdwp, GetDlgItem(IDC_FILESPEC), NULL, 0, 0, RECTWIDTH(*(rcCtls + ircFILESPEC)), RECTHEIGHT(*(rcCtls + ircFILESPEC)), SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE); // Stretch the 'Containing Text' combo: ::DeferWindowPos(hdwp, GetDlgItem(IDC_GREPTEXT), NULL, 0, 0, RECTWIDTH(*(rcCtls + ircGREPTEXT)), RECTHEIGHT(*(rcCtls + ircGREPTEXT)), SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE); // Stretch the 'Look In' combo ::DeferWindowPos(hdwp, GetDlgItem(IDC_NAMESPACE), NULL, 0, 0, RECTWIDTH(*(rcCtls + ircNAMESPACE)), RECTHEIGHT(*(rcCtls + ircNAMESPACE)), SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE); // Arrange dynamically positioned controls. ptOrigin.y = rcCtls[ircSEARCHSTART].bottom + metrics.LooseMarginY(); if (_fDisplayOptions) { OffsetRect(&rcCtls[ircOPTIONGRP], metrics.CtlMarginX() - rcCtls[ircOPTIONGRP].left, ptOrigin.y - rcCtls[ircOPTIONGRP].top); rcCtls[ircOPTIONSDLG].right = cx - metrics.CtlMarginX(); ::SetWindowPos(GetDlgItem(IDC_GROUPBTN_OPTIONS), NULL, rcCtls[ircOPTIONGRP].left, rcCtls[ircOPTIONGRP].top, RECTWIDTH(rcCtls[ircOPTIONGRP]), RECTHEIGHT(rcCtls[ircOPTIONGRP]), SWP_NOZORDER|SWP_NOACTIVATE); ::GetWindowRect(GetDlgItem(IDC_GROUPBTN_OPTIONS), &rcCtls[ircOPTIONGRP]); ::MapWindowRect(NULL, m_hWnd, &rcCtls[ircOPTIONGRP]); ptOrigin.y = rcCtls[ircOPTIONGRP].bottom + metrics.TightMarginY(); } else { // Position the 'Options' link _LayoutLinkWindow(m_hWnd, metrics.CtlMarginX(), cx - metrics.CtlMarginX(), metrics.TightMarginY(), ptOrigin.y, IDC_SEARCHLINK_OPTIONS); } ptOrigin.y += metrics.TightMarginY(); // Position the 'Search for Other Items' caption, divider and link windows const int rgLinkIDs[] = { IDC_SEARCHLINK_FILES, IDC_SEARCHLINK_COMPUTERS, IDC_SEARCHLINK_PRINTERS, IDC_SEARCHLINK_PEOPLE, -IDC_FSEARCH_DIV3, IDC_SEARCHLINK_INTERNET, }; _LayoutSearchLinks(IDC_SEARCHLINK_CAPTION, IDC_FSEARCH_DIV2, !_fDisplayOptions, metrics.CtlMarginX(), cx - metrics.CtlMarginX(), metrics.TightMarginY(), ptOrigin.y, rgLinkIDs, ARRAYSIZE(rgLinkIDs)); EndDeferWindowPos(hdwp); } } LRESULT CFindFilesDlg::OnUpdateLayout(UINT, WPARAM wParam, LPARAM, BOOL&) { LayoutControls(); _pfsb->UpdateLayout((ULONG)wParam); return 0; } LRESULT CFindFilesDlg::OnTimer(UINT, WPARAM wParam, LPARAM, BOOL&) { if (UISTATETIMER == wParam && IsWindowVisible()) UpdateSearchCmdStateUI(); return 0; } LRESULT CFindFilesDlg::OnOptions(int idCtl, NMHDR *pnmh, BOOL&) { _ShowOptions(!_fDisplayOptions); LoadSaveUIState(IDC_SEARCHLINK_OPTIONS, TRUE); if (_fDisplayOptions) _dlgOptions.TakeFocus(); else ::SetFocus(GetDlgItem(IDC_SEARCHLINK_OPTIONS)); return 0; } void CFindFilesDlg::_ShowOptions(BOOL bShow) { _fDisplayOptions = bShow; // don't need to scroll if we've expanded a subdialog, // but we do if we've contracted one. ULONG dwLayoutFlags = BLF_ALL; if (_fDisplayOptions) dwLayoutFlags &= ~BLF_SCROLLWINDOW; LayoutControls(); _pfsb->UpdateLayout(dwLayoutFlags); ::ShowWindow(GetDlgItem(IDC_GROUPBTN_OPTIONS), _fDisplayOptions ? SW_SHOW : SW_HIDE); ::ShowWindow(GetDlgItem(IDC_SEARCHLINK_OPTIONS), !_fDisplayOptions ? SW_SHOW : SW_HIDE); } LRESULT CFindFilesDlg::OnQueryOptionsHeight(int idCtl, NMHDR *pnmh, BOOL&) { GBNQUERYBUDDYSIZE* pqbs = (GBNQUERYBUDDYSIZE*)pnmh; pqbs->cy = _dlgOptions.QueryHeight(pqbs->cx, pqbs->cy); return TRUE; } void CFindFilesDlg::UpdateSearchCmdStateUI(DISPID eventID) { if (_fOnDestroy) return; if (DISPID_SEARCHCOMMAND_COMPLETE == eventID || DISPID_SEARCHCOMMAND_ABORT == eventID) _dwRunOnceWarningFlags = DFW_DEFAULT; CSearchCmdDlg::UpdateSearchCmdStateUI(eventID); _dlgOptions.UpdateSearchCmdStateUI(eventID); } BOOL CFindFilesDlg::OnSearchCmdError(HRESULT hr, LPCTSTR pszError) { if (SCEE_SCOPEMISMATCH == HRESULT_CODE(hr) || SCEE_INDEXNOTCOMPLETE == HRESULT_CODE(hr)) { // Set up checkbox BOOL fFlag = SCEE_SCOPEMISMATCH == HRESULT_CODE(hr)? DFW_IGNORE_CISCOPEMISMATCH : DFW_IGNORE_INDEXNOTCOMPLETE , fNoWarn = (_dwWarningFlags & fFlag) != 0, fNoWarnPrev = fNoWarn; USHORT uDlgT = SCEE_SCOPEMISMATCH == HRESULT_CODE(hr)? DLG_FSEARCH_SCOPEMISMATCH : DLG_FSEARCH_INDEXNOTCOMPLETE ; int nRet = CSearchWarningDlg_DoModal(m_hWnd, uDlgT, &fNoWarn); if (fNoWarn) _dwWarningFlags |= fFlag; else _dwWarningFlags &= ~fFlag; if (fNoWarnPrev != fNoWarn) LoadSaveUIState(LSUIS_WARNING, TRUE); if (IDOK == nRet) { _dwRunOnceWarningFlags |= _dwWarningFlags | fFlag ; // preserve the old run once flags... // hack one, hack two... let's be USER!!! [scotthan] PostMessage(WM_COMMAND, MAKEWPARAM(IDC_SEARCH_START, BN_CLICKED), (LPARAM)GetDlgItem(IDC_SEARCH_START)); } else ::SetFocus(GetDlgItem(IDC_NAMESPACE)); return TRUE; } return CSearchCmdDlg::OnSearchCmdError(hr, pszError); } LRESULT CFindFilesDlg::OnBtnClick(WORD nCode, WORD nID, HWND hwndCtl, BOOL&) { switch (nID) { case IDC_SEARCH_START: if (_ShouldReconcileNamespace()) _UIReconcileNamespace(TRUE); if (SUCCEEDED(StartSearch())) { EnableStartStopButton(hwndCtl, FALSE); StartStopAnimation(TRUE); } break; case IDC_SEARCH_STOP: StopSearch(); break; } return 0; } void CFindFilesDlg::NavigateToResults(IWebBrowser2* pwb2) { BSTR bstrUrl = SysAllocString(L"::{e17d4fc0-5564-11d1-83f2-00a0c90dc849}");// CLSID_DocFindFolder if (bstrUrl) { VARIANT varNil = {0}; pwb2->Navigate(bstrUrl, &varNil, &varNil, &varNil, &varNil); SysFreeString(bstrUrl); } } LRESULT CFindFilesDlg::OnStateChange(UINT, WPARAM, LPARAM, BOOL&) { UpdateSearchCmdStateUI(); return 0; } LRESULT CFindFilesDlg::OnNamespaceSelEndOk(WORD nCode, WORD nID, HWND hwndCtl, BOOL&) { LRESULT iSel = SendDlgItemMessage(IDC_NAMESPACE, CB_GETCURSEL, 0, 0); if (iSel != CB_ERR) { IEnumIDList *penum = _GetItems(iSel); if (NULL == penum) _BrowseAndAssignNamespace(); // Was this the "Browse..." item else _iCurNamespace = iSel; } _pfsb->SetDirty(); return 0; } LRESULT CFindFilesDlg::OnNamespaceEditChange(WORD wID, WORD wCode, HWND hwndCtl, BOOL& bHandled) { return OnEditChange(wID, wCode, hwndCtl, bHandled); } // Handler for CBN_SELENDCANCEL, CBN_DROPDOWN, CBN_KILLFOCUS LRESULT CFindFilesDlg::OnNamespaceReconcileCmd(WORD wID, WORD wCode, HWND hwndCtl, BOOL&) { if (_ShouldReconcileNamespace()) _UIReconcileNamespace(wCode != CBN_DROPDOWN); return 0; } // Handler for WM_NOTIFY::CBEN_ENDEDIT LRESULT CFindFilesDlg::OnNamespaceReconcileNotify(int idCtl, NMHDR *pnmh, BOOL& bHandled) { if (_ShouldReconcileNamespace()) { // Post ourselves a message to reconcile the ad hoc namespace. // Note: We need to do this because ComboBoxEx won't update his window text if he // is waiting for his CBEN_ENDEDIT notification message to return. PostMessage(WMU_NAMESPACERECONCILE, 0, 0); } bHandled = FALSE; // let base class have a crack as well. return 0; } // WMU_NAMESPACERECONCILE handler LRESULT CFindFilesDlg::OnNamespaceReconcileMsg(UINT, WPARAM, LPARAM, BOOL&) { if (_ShouldReconcileNamespace()) _UIReconcileNamespace(FALSE); return 0; } // WMU_BANDFINISHEDDISPLAYING handler // Note that we do not care about returning results from this, as it will // be started asynchronously. LRESULT CFindFilesDlg::OnBandFinishedDisplaying(UINT, WPARAM, LPARAM, BOOL&) { // Now that the search band has finished displaying, we will do the // delayed initialization. Make sure we don't do it twice. if (!_fBandFinishedDisplaying) { _fBandFinishedDisplaying = TRUE; _dlgOptions.DoDelayedInit(); } return 0; } BOOL CFindFilesDlg::_ShouldReconcileNamespace() { return _fNamespace || SendDlgItemMessage(IDC_NAMESPACE, CB_GETCURSEL, 0, 0) == CB_ERR; } // Invokes lower Namespace reconciliation helper, updates some UI and // instance state data. // this was added as a late RC 'safe' delta, and should have actually // become part of _ReconcileNamespace() impl. void CFindFilesDlg::_UIReconcileNamespace(BOOL bAsync) { LRESULT iSel = _ReconcileNamespace(bAsync); if (iSel != CB_ERR) _iCurNamespace = iSel; _ShowNamespaceEditImage(TRUE); _fNamespace = FALSE; // clear the ad hoc flag. } // Scans namespace combo for a matching namespace; if found, selects // the namespace item, otherwise adds an adhoc item and selects it. // // Important: don't call this directly, call _UIReconcileNamespace() // instead to ensure that instance state data is updated. INT_PTR CFindFilesDlg::_ReconcileNamespace(OPTIONAL BOOL bAsync) { INT_PTR iSel = SendDlgItemMessage(IDC_NAMESPACE, CB_GETCURSEL, 0, 0); if ((CB_ERR != iSel) && (NULL == _GetItems(iSel))) { // The user has selected the special Browse... item. // Irreconcilable. Return CB_ERR return CB_ERR; } // Don't know the namespace? Use current window text. TCHAR szNamespace[MAX_URL_STRING]; if (0 == GetDlgItemText(IDC_NAMESPACE, szNamespace, ARRAYSIZE(szNamespace))) return CB_ERR; INT_PTR iFind = _FindNamespace(szNamespace, NULL); // search display names if (CB_ERR == iFind) { // search paths TCHAR szTemp[MAX_URL_STRING]; StringCchCopy(szTemp, ARRAYSIZE(szTemp), szNamespace); // ok to truncate _PathFixup(szNamespace, ARRAYSIZE(szNamespace), szTemp); // don't care if this fails, the path might be a path list iFind = _FindNamespace(szNamespace, NULL); } // Not found in CB list? Add it if it's a valid path if (CB_ERR == iFind) { iSel = _AddNamespace(szNamespace, NULL, szNamespace, TRUE); } else { // found in CB list? Select it. if (bAsync) { // this was needed in cases of reconcile following kill focus ::PostMessage(GetDlgItem(IDC_NAMESPACE), CB_SETCURSEL, iFind, 0); } else { iSel = SendDlgItemMessage(IDC_NAMESPACE, CB_SETCURSEL, iFind, 0); } } return iSel; } BOOL CFindFilesDlg::_PathFixup(LPTSTR pszDst, UINT cchDst, LPCTSTR pszSrc) { ASSERT(pszDst); ASSERT(pszSrc); TCHAR szSrc[MAX_PATH]; TCHAR szFull[MAX_PATH]; if (SHExpandEnvironmentStrings(pszSrc, szSrc, ARRAYSIZE(szSrc)) && *szSrc) pszSrc = szSrc; if (_IsPathList(pszSrc)) { StringCchCopy(pszDst, cchDst, pszSrc); // ok to truncate return TRUE; } szFull[0] = 0; BOOL bRelative = PathIsRelative(pszSrc); BOOL bMissingDrive = bRelative ? FALSE : _IsFullPathMinusDriveLetter(pszSrc); // bMissingDrive =,e.g. "\foo", "\foo\bar", etc. PathIsRelative() reports FALSE in this case. if (bRelative || bMissingDrive) { ASSERT(_pfsb && _pfsb->BandSite()); LPITEMIDLIST pidl; HRESULT hr = _GetCurrentFolderIDList(_pfsb->BandSite(), &pidl); if (S_OK == hr) { TCHAR szCurDir[MAX_PATH]; // file system path only here! if (SHGetPathFromIDList(pidl, szCurDir) && StrCmpI(szCurDir, _szCurrentPath)) { StringCchCopy(_szCurrentPath, ARRAYSIZE(_szCurrentPath), szCurDir); // ok to truncate } if (*_szCurrentPath) { if (bRelative) { if (PathCombine(szFull, _szCurrentPath, pszSrc)) pszSrc = szFull; } else if (bMissingDrive) { int iDrive = PathGetDriveNumber(_szCurrentPath); if (-1 != iDrive) { TCHAR szRoot[MAX_PATH]; if (PathCombine(szFull, PathBuildRoot(szRoot, iDrive), pszSrc)) pszSrc = szFull; } } } ILFree(pidl); } } return PathCanonicalize(pszDst, pszSrc); } LRESULT CFindFilesDlg::OnNamespaceDeleteItem(int idCtrl, NMHDR *pnmh, BOOL& bHandled) { PNMCOMBOBOXEX pnmce = (PNMCOMBOBOXEX)pnmh; if (pnmce->ceItem.lParam) { IEnumIDList *penum = (IEnumIDList *)pnmce->ceItem.lParam; penum->Release(); } return 1; } DWORD CFindFilesDlg::NamespaceThreadProc(void* pv) { FSEARCHTHREADSTATE *pState = (FSEARCHTHREADSTATE *)pv; CFindFilesDlg* pThis = (CFindFilesDlg*)pState->pvParam; if (PopulateNamespaceCombo(pState->hwndCtl, AddNamespaceItemNotify, (LPARAM)pv) != E_ABORT) { ::PostMessage(::GetParent(pState->hwndCtl), WMU_COMBOPOPULATIONCOMPLETE, (WPARAM)pState->hwndCtl, 0); } pState->fComplete = TRUE; ATOMICRELEASE(pState->punkBand); return 0; } #define CBX_CSIDL_LOCALDRIVES 0x04FF // arbitrarily out of range of other CSIDL_xxx values. HRESULT CFindFilesDlg::AddNamespaceItemNotify(ULONG fAction, PCBXITEM pItem, LPARAM lParam) { FSEARCHTHREADSTATE *pState = (FSEARCHTHREADSTATE *)lParam; if (fAction & CBXCB_ADDING && pState->fCancel) return E_ABORT; // // Sets the string in the CFindFilesDlg as the display name. // This string is then used to set the default item in the // combo box. // if (fAction & CBXCB_ADDED && CBX_CSIDL_LOCALDRIVES == pItem->iID) { CFindFilesDlg* pffd = (CFindFilesDlg*)pState->pvParam; StringCchCopy(pffd->_szLocalDrives, ARRAYSIZE(pffd->_szLocalDrives), pItem->szText); // ok to truncate } return S_OK; } LRESULT CFindFilesDlg::OnComboPopulationComplete(UINT, WPARAM wParam, LPARAM, BOOL&) { _bScoped = SetDefaultScope(); return 0; } // bPassive TRUE -> assign only if no current selection BOOL CFindFilesDlg::AssignNamespace(LPCTSTR pszPath, LPCITEMIDLIST pidl, LPCTSTR pszName, BOOL bPassive) { INT_PTR iSel = CB_ERR; // If we don't yet have a current selection, establish it now. if (!bPassive || CB_ERR == (iSel = SendDlgItemMessage(IDC_NAMESPACE, CB_GETCURSEL, 0, 0))) { iSel = _FindNamespace(pszPath, pidl); // scan items by display name if we don't have pidl // otherwise choosing x:\my pictures (in browse) would end up selecting // my pictures folder and searching the wrong place if (CB_ERR == iSel && !pidl && !pszPath && pszName && *pszName) iSel = _FindNamespace(pszName, NULL); // Is this a folder we already know about? if (CB_ERR == iSel) { if (pidl || pszPath) iSel = _AddNamespace(pszPath, pidl, pszName, TRUE); if (iSel != CB_ERR) _iCurNamespace = iSel; } else { // yes: select it SendDlgItemMessage(IDC_NAMESPACE, CB_SETCURSEL, iSel, 0); _iCurNamespace = iSel; } } return CB_ERR != SendDlgItemMessage(IDC_NAMESPACE, CB_GETCURSEL, 0, 0); } HWND CFindFilesDlg::ShowHelp(HWND hwnd) { return ::HtmlHelp(hwnd, TEXT("find.chm"), HH_DISPLAY_TOPIC, 0); } // inserts something into the name space combo INT_PTR CFindFilesDlg::_AddNamespace(LPCTSTR pszPath, LPCITEMIDLIST pidl, LPCTSTR pszName, BOOL bSelectItem) { IEnumIDList *penum = NULL; if (pszPath) { CreateIEnumIDListPaths(pszPath, &penum); } else if (pidl) { CreateIEnumIDListOnIDLists(&pidl, 1, &penum); } CBXITEM item; item.iItem = CB_ERR; // failure result here if (penum) { LPITEMIDLIST pidlIcon; if (S_OK == FirstIDList(penum, &pidlIcon)) { if (NULL == pszName) pszName = pszPath; MakeCbxItem(&item, pszName, penum, pidlIcon, LISTINSERT_LAST, 1); INT_PTR iSel = item.iItem; if (SUCCEEDED(AddCbxItemToComboBox(GetDlgItem(IDC_NAMESPACE), &item, &iSel))) { penum = NULL; // don't release below item.iItem = iSel; if (bSelectItem) SendDlgItemMessage(IDC_NAMESPACE, CB_SETCURSEL, iSel, 0); } else { item.iItem = CB_ERR; } ILFree(pidlIcon); } if (penum) penum->Release(); // not inserted, free this } return item.iItem; } LPARAM CFindFilesDlg::_GetComboData(UINT id, INT_PTR idx) { if (CB_ERR == idx) idx = SendDlgItemMessage(id, CB_GETCURSEL, 0, 0); if (CB_ERR == idx) return idx; return (LPARAM)SendDlgItemMessage(id, CB_GETITEMDATA, idx, 0); } IEnumIDList *CFindFilesDlg::_GetItems(INT_PTR i) { IEnumIDList *penum = (IEnumIDList *)_GetComboData(IDC_NAMESPACE, i); return (INVALID_HANDLE_VALUE != penum) ? penum : NULL; } BOOL MatchItem(IEnumIDList *penum, LPCTSTR pszPath, LPCITEMIDLIST pidl) { BOOL bMatch = FALSE; // this is somewhat imprecise as we will match on the first IDList in the // enumerator. but generally that is the desired behavior for the special // items that include multiple implied items LPITEMIDLIST pidlFirst; if (S_OK == FirstIDList(penum, &pidlFirst)) { bMatch = pidl && ILIsEqual(pidl, pidlFirst); if (!bMatch && pszPath) { TCHAR szPath[MAX_PATH]; if (SUCCEEDED(SHGetNameAndFlags(pidlFirst, SHGDN_FORPARSING, szPath, ARRAYSIZE(szPath), NULL))) { bMatch = (0 == StrCmpI(pszPath, szPath)); } } ILFree(pidlFirst); } return bMatch; } // searches namespace comboboxex for the indicated item // returns: // index of item, CB_ERR (-1) if not found INT_PTR CFindFilesDlg::_FindNamespace(LPCTSTR pszPath, LPCITEMIDLIST pidl) { for (INT_PTR i = 0, cnt = SendDlgItemMessage(IDC_NAMESPACE, CB_GETCOUNT, 0, 0); i < cnt; i++) { IEnumIDList *penum = _GetItems(i); if (penum) { if (MatchItem(penum, pszPath, pidl)) return i; } } // fall back to finding by display name in the combo if (pszPath) return SendDlgItemMessage(IDC_NAMESPACE, CB_FINDSTRINGEXACT, -1, (LPARAM)pszPath); return CB_ERR; } // Invokes UI to select a namespace. // // Returns: // S_OK if the user has selected a valid item and the pszNamespace contains // a valid shell folder display name. // E_ABORT if the user canceled his search // E_FAIL if an error occurred HRESULT CFindFilesDlg::_BrowseForNamespace(LPTSTR pszName, UINT cchName, LPITEMIDLIST *ppidlRet) { *pszName = 0; TCHAR szTitle[128]; LoadString(HINST_THISDLL, IDS_SNS_BROWSERFORDIR_TITLE, szTitle, ARRAYSIZE(szTitle)); BROWSEINFO bi = {0}; bi.hwndOwner = m_hWnd; bi.lpszTitle = szTitle; bi.ulFlags = BIF_USENEWUI | BIF_EDITBOX; // | BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS; bi.lpfn = _BrowseCallback; bi.lParam = (LPARAM)this; HRESULT hr; *ppidlRet = SHBrowseForFolder(&bi); if (*ppidlRet) { SHGetNameAndFlags(*ppidlRet, SHGDN_NORMAL, pszName, cchName, NULL); hr = S_OK; } else { hr = E_ABORT; } return hr; } // Invokes SHBrowserForFolder UI and assigns results. void CFindFilesDlg::_BrowseAndAssignNamespace() { TCHAR szName[MAX_PATH]; LPITEMIDLIST pidl; if (SUCCEEDED(_BrowseForNamespace(szName, ARRAYSIZE(szName), &pidl))) { AssignNamespace(NULL, pidl, szName, FALSE); ILFree(pidl); } else { SendDlgItemMessage(IDC_NAMESPACE, CB_SETCURSEL, _iCurNamespace, 0); } } BOOL CFindFilesDlg::_IsSearchableFolder(LPCITEMIDLIST pidlFolder) { return TRUE; } int CFindFilesDlg::_BrowseCallback(HWND hwnd, UINT msg, LPARAM lParam, LPARAM lpData) { CFindFilesDlg *pThis = (CFindFilesDlg *)lpData; switch (msg) { case BFFM_INITIALIZED: // initializing: set default selection to drives if we can { LPITEMIDLIST pidlDefault = SHCloneSpecialIDList(NULL, CSIDL_DRIVES, TRUE); if (pidlDefault) { if (!::SendMessage(hwnd, BFFM_SETSELECTION, FALSE, (LPARAM)pidlDefault)) // if we fail to default to drives, default to desktop { ILFree(pidlDefault); pidlDefault = SHCloneSpecialIDList(NULL, CSIDL_DESKTOP, TRUE); ::SendMessage(hwnd, BFFM_SETSELECTION, FALSE, (LPARAM)pidlDefault); } ILFree(pidlDefault); } } break; case BFFM_SELCHANGED: // prevent non-searchable folder pidls from being selected. { BOOL bAllow = pThis->_IsSearchableFolder((LPCITEMIDLIST)lParam); ::SendMessage(hwnd, BFFM_ENABLEOK, 0, (LPARAM)bAllow); } break; } return 0; } class CSearchWarningDlg { private: CSearchWarningDlg() : _hwnd(NULL), _bNoWarn(FALSE) {} static BOOL_PTR WINAPI DlgProc(HWND, UINT, WPARAM, LPARAM); HWND _hwnd; BOOL _bNoWarn; friend int CSearchWarningDlg_DoModal(HWND hwndParent, USHORT uDlgT, BOOL* pbNoWarn); }; int CSearchWarningDlg_DoModal(HWND hwndParent, USHORT uDlgTemplate, BOOL* pbNoWarn) { ASSERT(pbNoWarn); CSearchWarningDlg dlg; dlg._bNoWarn = *pbNoWarn; int nRet = (int)DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(uDlgTemplate), hwndParent, CSearchWarningDlg::DlgProc, (LPARAM)&dlg); *pbNoWarn = dlg._bNoWarn; return nRet; } BOOL_PTR WINAPI CSearchWarningDlg::DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CSearchWarningDlg* pdlg = (CSearchWarningDlg*)GetWindowPtr(hwnd, GWLP_USERDATA); if (WM_INITDIALOG == uMsg) { pdlg = (CSearchWarningDlg*)lParam; pdlg->_hwnd = hwnd; SetWindowPtr(hwnd, GWLP_USERDATA, pdlg); CheckDlgButton(hwnd, IDC_NOSCOPEWARNING, pdlg->_bNoWarn); MessageBeep(MB_ICONASTERISK); return TRUE; } if (pdlg) { switch (uMsg) { case WM_COMMAND: switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDOK: case IDCANCEL: pdlg->_bNoWarn = IsDlgButtonChecked(hwnd, IDC_NOSCOPEWARNING); EndDialog(hwnd, GET_WM_COMMAND_ID(wParam, lParam)); break; } return TRUE; } } return FALSE; } class CCISettingsDlg { public: CCISettingsDlg() : _hwnd(NULL), _fCiIndexed(FALSE), _fCiRunning(FALSE), _fCiPermission(FALSE), _hProcessMMC(INVALID_HANDLE_VALUE) { } ~CCISettingsDlg() { if (_hProcessMMC != INVALID_HANDLE_VALUE) CloseHandle(_hProcessMMC); } static int DoModal(HWND hwndParent); static HWND CreateModeless(HWND hwndParent); protected: BOOL OnInitDialog(); BOOL OnOK(); private: static BOOL_PTR WINAPI DlgProc(HWND, UINT, WPARAM, LPARAM); void ShowAdvanced(); HWND _hwnd; BOOL _fCiIndexed, _fCiRunning, _fCiPermission; HANDLE _hProcessMMC; friend int CCISettingsDlg_DoModal(HWND hwndParent); }; int CCISettingsDlg_DoModal(HWND hwndParent) { CCISettingsDlg dlg; return (int)DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_INDEXSERVER), hwndParent, CCISettingsDlg::DlgProc, (LPARAM)&dlg); } BOOL_PTR WINAPI CCISettingsDlg::DlgProc(HWND hDlg, UINT nMsg, WPARAM wParam, LPARAM lParam) { CCISettingsDlg* pdlg = (CCISettingsDlg*)GetWindowPtr(hDlg, GWLP_USERDATA); if (WM_INITDIALOG == nMsg) { pdlg = (CCISettingsDlg*)lParam; pdlg->_hwnd = hDlg; SetWindowPtr(hDlg, GWLP_USERDATA, pdlg); return pdlg->OnInitDialog(); } if (pdlg) { switch (nMsg) { case WM_NCDESTROY: return TRUE; case WM_COMMAND: switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_CI_ADVANCED: pdlg->ShowAdvanced(); break; case IDOK: if (pdlg->OnOK()) EndDialog(hDlg, IDOK); break; case IDCANCEL: EndDialog(hDlg, GET_WM_COMMAND_ID(wParam, lParam)); break; case IDC_CI_HELP: _IndexServiceHelp(hDlg); break; } return TRUE; } } return FALSE; } void CCISettingsDlg::ShowAdvanced() { // have we already spawned MMC? if (_hProcessMMC != INVALID_HANDLE_VALUE) { if (WaitForSingleObject(_hProcessMMC, 0) != WAIT_OBJECT_0) { // MMC is still running, let user ATL+TAB or something but don't launch a second copy return; } _hProcessMMC = INVALID_HANDLE_VALUE; } TCHAR szProgram[MAX_PATH]; DWORD dwRet = GetSystemDirectory(szProgram, ARRAYSIZE(szProgram)); HRESULT hr = E_FAIL; if (dwRet == 0 || dwRet >= ARRAYSIZE(szProgram)) { hr = StringCchCopy(szProgram, ARRAYSIZE(szProgram), TEXT("ciadv.msc")); } else { if (PathAppend(szProgram, TEXT("ciadv.msc"))) { hr = S_OK; } } if (SUCCEEDED(hr)) { SHELLEXECUTEINFO sei = { sizeof(sei) }; sei.fMask = SEE_MASK_NOCLOSEPROCESS; sei.nShow = SW_SHOWNORMAL; sei.lpFile = szProgram; sei.lpParameters = TEXT("computername=localmachine"); if (ShellExecuteEx(&sei)) { _hProcessMMC = sei.hProcess; } } } BOOL CCISettingsDlg::OnInitDialog() { TCHAR szStatusFmt[128], szStatusText[MAX_PATH]; UINT nStatusText = IDS_FSEARCH_CI_DISABLED; GetCIStatus(&_fCiRunning, &_fCiIndexed, &_fCiPermission); if (_fCiRunning) { if (_fCiPermission) // permission to distinguish between ready, busy. nStatusText = _fCiIndexed ? IDS_FSEARCH_CI_READY : IDS_FSEARCH_CI_BUSY; else // no permission to distinguish between ready, busy; just say it's enabled. nStatusText = IDS_FSEARCH_CI_ENABLED; } if (LoadString(HINST_THISDLL, IDS_FSEARCH_CI_STATUSFMT, szStatusFmt, ARRAYSIZE(szStatusFmt))) { if (LoadString(HINST_THISDLL, nStatusText, szStatusText, ARRAYSIZE(szStatusText))) { TCHAR szStatus[MAX_PATH]; StringCchPrintf(szStatus, ARRAYSIZE(szStatus), szStatusFmt, szStatusText); // ok to truncate - for display only SetDlgItemText(_hwnd, IDC_CI_STATUS, szStatus); } } CheckDlgButton(_hwnd, IDC_ENABLE_CI, _fCiRunning); CheckDlgButton(_hwnd, IDC_BLOWOFF_CI, !_fCiRunning); EnableWindow(GetDlgItem(_hwnd, IDC_CI_PROMPT), _fCiPermission); EnableWindow(GetDlgItem(_hwnd, IDC_ENABLE_CI), _fCiPermission); EnableWindow(GetDlgItem(_hwnd, IDC_BLOWOFF_CI), _fCiPermission); return TRUE; } BOOL CCISettingsDlg::OnOK() { StartStopCI(IsDlgButtonChecked(_hwnd, IDC_ENABLE_CI) ? TRUE : FALSE); return TRUE; } #ifdef __PSEARCH_BANDDLG__ // CFindPrintersDlg impl #define PSEARCHDLG_TABFIRST IDC_PSEARCH_NAME #define PSEARCHDLG_TABLAST IDC_SEARCHLINK_INTERNET #define PSEARCHDLG_RIGHTMOST IDC_SEARCH_START #define PSEARCHDLG_BOTTOMMOST IDC_SEARCHLINK_INTERNET CFindPrintersDlg::CFindPrintersDlg(CFileSearchBand* pfsb) : CBandDlg(pfsb) { } CFindPrintersDlg::~CFindPrintersDlg() { } LRESULT CFindPrintersDlg::OnInitDialog(UINT, WPARAM, LPARAM, BOOL&) { _Attach(m_hWnd); ASSERT(Hwnd()); CMetrics& metrics = _pfsb->GetMetrics(); _pfsb->GetMetrics().Init(m_hWnd); POINT pt; pt.x = metrics.CtlMarginX(); pt.y = 0; _CreateSearchLinks(m_hWnd, pt, IDC_SEARCHLINK_PRINTERS); _CreateDivider(m_hWnd, IDC_FSEARCH_DIV1, pt, 2, GetDlgItem(IDC_PSEARCH_CAPTION)); _CreateDivider(m_hWnd, IDC_FSEARCH_DIV2, pt, 1, GetDlgItem(IDC_SEARCHLINK_CAPTION)); _CreateDivider(m_hWnd, IDC_FSEARCH_DIV3, pt, 1, GetDlgItem(IDC_SEARCHLINK_PEOPLE)); OnWinIniChange(); LayoutControls(-1, -1); return TRUE; } void CFindPrintersDlg::LayoutControls(int cx, int cy) { if (cx < 0 || cy < 0) { RECT rc; GetClientRect(&rc); cx = RECTWIDTH(rc); cy = RECTHEIGHT(rc); } CBandDlg::LayoutControls(cx, cy); CMetrics& metrics = _pfsb->GetMetrics(); const UINT nIDCtl[] = { IDC_PSEARCH_NAME, IDC_PSEARCH_LOCATION, IDC_PSEARCH_MODEL, }; RECT rcCtl[ARRAYSIZE(nIDCtl)]; // Stretch edit boxes to fit horz for (int i = 0; i< ARRAYSIZE(nIDCtl); i++) { HWND hwndCtl = GetDlgItem(nIDCtl[i]); if (hwndCtl && ::GetWindowRect(hwndCtl, &rcCtl[i])) { ::MapWindowRect(NULL, Hwnd(), &rcCtl[i]); rcCtl[i].right = cx - metrics.CtlMarginX(); ::SetWindowPos(hwndCtl, NULL, 0, 0, RECTWIDTH(*(rcCtl+i)), RECTHEIGHT(*(rcCtl+i)), SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE); } else SetRectEmpty(rcCtl + i); } // Position the 'Search for Other Items' caption, divider and link windows const int rgLinks[] = { IDC_SEARCHLINK_FILES, IDC_SEARCHLINK_COMPUTERS, IDC_SEARCHLINK_PRINTERS, IDC_SEARCHLINK_PEOPLE, -IDC_FSEARCH_DIV3, IDC_SEARCHLINK_INTERNET, }; RECT rc; ::GetWindowRect(GetDlgItem(IDC_SEARCH_START), &rc); ::MapWindowRect(NULL, m_hWnd, &rc); rc.bottom += metrics.LooseMarginY(); _LayoutSearchLinks(IDC_SEARCHLINK_CAPTION, IDC_FSEARCH_DIV2, TRUE, metrics.CtlMarginX(), cx - metrics.CtlMarginX(), metrics.TightMarginY(), rc.bottom, rgLinks, ARRAYSIZE(rgLinks)); } BOOL CFindPrintersDlg::Validate() { return TRUE; } void CFindPrintersDlg::Clear() { SetDlgItemText(IDC_PSEARCH_NAME, NULL); SetDlgItemText(IDC_PSEARCH_LOCATION, NULL); SetDlgItemText(IDC_PSEARCH_MODEL, NULL); } BOOL CFindPrintersDlg::GetMinSize(HWND hwndOC, SIZE *pSize) const { RECT rcRightmost, rcBottommost; HWND hwndRightmost = GetDlgItem(PSEARCHDLG_RIGHTMOST), hwndBottommost= GetDlgItem(PSEARCHDLG_BOTTOMMOST); ASSERT(::IsWindow(hwndRightmost)); ASSERT(::IsWindow(hwndBottommost)); ::GetWindowRect(hwndRightmost, &rcRightmost); ::MapWindowRect(NULL, m_hWnd, &rcRightmost); ::GetWindowRect(hwndBottommost, &rcBottommost); ::MapWindowRect(NULL, m_hWnd, &rcBottommost); pSize->cx = rcRightmost.right; pSize->cy = rcBottommost.bottom + _pfsb->GetMetrics().TightMarginY(); return TRUE; } HWND CFindPrintersDlg::GetFirstTabItem() const { return GetDlgItem(PSEARCHDLG_TABFIRST); } HWND CFindPrintersDlg::GetLastTabItem() const { return GetDlgItem(PSEARCHDLG_TABLAST); } STDMETHODIMP CFindPrintersDlg::TranslateAccelerator(MSG *pmsg) { if (S_OK == CBandDlg::TranslateAccelerator(pmsg)) return S_OK; // Handle it ourselves... return _pfsb->IsDlgMessage(m_hWnd, pmsg); } void CFindPrintersDlg::OnWinIniChange() { _BeautifyCaption(IDC_PSEARCH_CAPTION, IDC_PSEARCH_ICON, IDI_PSEARCH); } LRESULT CFindPrintersDlg::OnSearchStartBtn(WORD nCode, WORD nID, HWND hwndCtl, BOOL&) { WCHAR wszName[MAX_PATH], wszLocation[MAX_PATH], wszModel[MAX_PATH]; ::GetDlgItemTextW(m_hWnd, IDC_PSEARCH_NAME, wszName, ARRAYSIZE(wszName)); ::GetDlgItemTextW(m_hWnd, IDC_PSEARCH_LOCATION, wszLocation, ARRAYSIZE(wszLocation)); ::GetDlgItemTextW(m_hWnd, IDC_PSEARCH_MODEL, wszModel, ARRAYSIZE(wszModel)); ASSERT(_pfsb); ASSERT(_pfsb->BandSite()); IShellDispatch2* psd2; if (SUCCEEDED(CoCreateInstance(CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellDispatch2, &psd2)))) { BSTR bstrName = *wszName ? SysAllocString(wszName) : NULL, bstrLocation = *wszLocation ? SysAllocString(wszLocation) : NULL, bstrModel = *wszModel ? SysAllocString(wszModel) : NULL; if (FAILED(psd2->FindPrinter(bstrName, bstrLocation, bstrModel))) { SysFreeString(bstrName); SysFreeString(bstrLocation); SysFreeString(bstrModel); } psd2->Release(); } return 0; } #endif __PSEARCH_BANDDLG__ // CFindComputersDlg impl #define CSEARCHDLG_TABFIRST IDC_CSEARCH_NAME #define CSEARCHDLG_TABLAST IDC_SEARCHLINK_INTERNET #define CSEARCHDLG_RIGHTMOST IDC_SEARCH_STOP #define CSEARCHDLG_BOTTOMMOST IDC_SEARCHLINK_INTERNET CFindComputersDlg::CFindComputersDlg(CFileSearchBand* pfsb) : CSearchCmdDlg(pfsb), _pacComputerName(NULL), _pmruComputerName(NULL) { } CFindComputersDlg::~CFindComputersDlg() { ATOMICRELEASE(_pacComputerName); ATOMICRELEASE(_pmruComputerName); } LRESULT CFindComputersDlg::OnInitDialog(UINT, WPARAM, LPARAM, BOOL&) { _Attach(m_hWnd); ASSERT(Hwnd()); CMetrics& metrics = _pfsb->GetMetrics(); _pfsb->GetMetrics().Init(m_hWnd); // Register specialty window classes. DivWindow_RegisterClass(); POINT pt; pt.x = metrics.CtlMarginX(); pt.y = 0; _CreateSearchLinks(m_hWnd, pt, IDC_SEARCHLINK_COMPUTERS); _CreateDivider(m_hWnd, IDC_FSEARCH_DIV1, pt, 2, GetDlgItem(IDC_CSEARCH_CAPTION)); _CreateDivider(m_hWnd, IDC_FSEARCH_DIV2, pt, 1, GetDlgItem(IDC_SEARCHLINK_CAPTION)); _CreateDivider(m_hWnd, IDC_FSEARCH_DIV3, pt, 1, GetDlgItem(IDC_SEARCHLINK_PEOPLE)); _InitializeMru(GetDlgItem(IDC_CSEARCH_NAME), &_pacComputerName, TEXT("ComputerNameMRU"), &_pmruComputerName); SendDlgItemMessage(IDC_CSEARCH_NAME, EM_LIMITTEXT, MAX_PATH, 0); OnWinIniChange(); LayoutControls(-1, -1); return TRUE; } LRESULT CFindComputersDlg::OnDestroy(UINT, WPARAM, LPARAM, BOOL& bHandled) { StopSearch(); if (_pSrchCmd) { DisconnectEvents(); IUnknown_SetSite(_pSrchCmd, NULL); } bHandled = FALSE; _fOnDestroy = TRUE; return 0; } void CFindComputersDlg::LayoutControls(int cx, int cy) { if (cx < 0 || cy < 0) { RECT rc; GetClientRect(&rc); cx = RECTWIDTH(rc); cy = RECTHEIGHT(rc); } CBandDlg::LayoutControls(cx, cy); const UINT nIDCtl[] = { IDC_CSEARCH_NAME, }; RECT rcCtl[ARRAYSIZE(nIDCtl)]; CMetrics& metrics = _pfsb->GetMetrics(); for (int i = 0; i< ARRAYSIZE(nIDCtl); i++) { HWND hwndCtl = GetDlgItem(nIDCtl[i]); if (hwndCtl && ::GetWindowRect(hwndCtl, &rcCtl[i])) { ::MapWindowRect(NULL, m_hWnd, &rcCtl[i]); rcCtl[i].right = cx - metrics.CtlMarginX(); ::SetWindowPos(hwndCtl, NULL, 0, 0, RECTWIDTH(*(rcCtl+i)), RECTHEIGHT(*(rcCtl+i)), SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE); } else SetRectEmpty(rcCtl + i); } // Position the 'Search for Other Items' caption, divider and link windows const int rgLinks[] = { IDC_SEARCHLINK_FILES, IDC_SEARCHLINK_COMPUTERS, IDC_SEARCHLINK_PRINTERS, IDC_SEARCHLINK_PEOPLE, -IDC_FSEARCH_DIV3, IDC_SEARCHLINK_INTERNET, }; RECT rc; ::GetWindowRect(GetDlgItem(IDC_SEARCH_START), &rc); ::MapWindowRect(NULL, m_hWnd, &rc); rc.bottom += metrics.LooseMarginY(); _LayoutSearchLinks(IDC_SEARCHLINK_CAPTION, IDC_FSEARCH_DIV2, TRUE, metrics.CtlMarginX(), cx - metrics.CtlMarginX(), metrics.TightMarginY(), rc.bottom, rgLinks, ARRAYSIZE(rgLinks)); } BOOL CFindComputersDlg::Validate() { return TRUE; } STDMETHODIMP CFindComputersDlg::AddConstraints(ISearchCommandExt* pSrchCmd) { HRESULT hr = E_FAIL; TCHAR szName[MAX_PATH]; if (::GetDlgItemText(m_hWnd, IDC_CSEARCH_NAME, szName, ARRAYSIZE(szName)) <= 0) { StringCchCopy(szName, ARRAYSIZE(szName), TEXT("*")); // should always fit } VARIANT var; hr = InitVariantFromStr(&var, szName); if (SUCCEEDED(hr)) { hr = _AddConstraint(pSrchCmd, L"SearchFor", &var); if (SUCCEEDED(hr)) _AddMruStringFromWindow(_pmruComputerName, GetDlgItem(IDC_CSEARCH_NAME)); VariantClear(&var); } return hr; } void CFindComputersDlg::UpdateStatusText() { CSearchCmdDlg::UpdateStatusText(); } void CFindComputersDlg::RestoreSearch() { CSearchCmdDlg::RestoreSearch(); } void CFindComputersDlg::Clear() { CSearchCmdDlg::Clear(); SetDlgItemText(IDC_CSEARCH_NAME, NULL); } BOOL CFindComputersDlg::GetMinSize(HWND hwndOC, SIZE *pSize) const { RECT rcRightmost, rcBottommost; HWND hwndRightmost = GetDlgItem(CSEARCHDLG_RIGHTMOST), hwndBottommost= GetDlgItem(CSEARCHDLG_BOTTOMMOST); ASSERT(::IsWindow(hwndRightmost)); ASSERT(::IsWindow(hwndBottommost)); ::GetWindowRect(hwndRightmost, &rcRightmost); ::MapWindowRect(NULL, m_hWnd, &rcRightmost); ::GetWindowRect(hwndBottommost, &rcBottommost); ::MapWindowRect(NULL, m_hWnd, &rcBottommost); pSize->cx = rcRightmost.right; pSize->cy = rcBottommost.bottom + _pfsb->GetMetrics().TightMarginY(); return TRUE; } void CFindComputersDlg::NavigateToResults(IWebBrowser2* pwb2) { BSTR bstrUrl = SysAllocString(L"::{1f4de370-d627-11d1-ba4f-00a0c91eedba}");// CLSID_ComputerFindFolder if (bstrUrl) { VARIANT varNil = {0}; pwb2->Navigate(bstrUrl, &varNil, &varNil, &varNil, &varNil); SysFreeString(bstrUrl); } } HWND CFindComputersDlg::GetFirstTabItem() const { return GetDlgItem(CSEARCHDLG_TABFIRST); } HWND CFindComputersDlg::GetLastTabItem() const { return GetDlgItem(CSEARCHDLG_TABLAST); } BOOL CFindComputersDlg::GetAutoCompleteObjectForWindow(HWND hwnd, IAutoComplete2** ppac2) { if (hwnd == GetDlgItem(IDC_CSEARCH_NAME)) { *ppac2 = _pacComputerName; (*ppac2)->AddRef(); return TRUE; } return CBandDlg::GetAutoCompleteObjectForWindow(hwnd, ppac2); } STDMETHODIMP CFindComputersDlg::TranslateAccelerator(MSG *pmsg) { if (S_OK == CSearchCmdDlg::TranslateAccelerator(pmsg)) return S_OK; // Handle it ourselves... return _pfsb->IsDlgMessage(m_hWnd, pmsg); } void CFindComputersDlg::OnWinIniChange() { // redisplay animated icon HWND hwndIcon = GetDlgItem(IDC_CSEARCH_ICON); Animate_Close(hwndIcon); Animate_OpenEx(hwndIcon, HINST_THISDLL, MAKEINTRESOURCE(IDA_FINDCOMP)); _BeautifyCaption(IDC_CSEARCH_CAPTION); } LRESULT CFindComputersDlg::OnSearchStartBtn(WORD nCode, WORD nID, HWND hwndCtl, BOOL&) { if (SUCCEEDED(StartSearch())) { EnableStartStopButton(hwndCtl, FALSE); StartStopAnimation(TRUE); } return 0; } LRESULT CFindComputersDlg::OnSearchStopBtn(WORD nCode, WORD nID, HWND hwndCtl, BOOL&) { StopSearch(); return 0; } HWND CFindComputersDlg::ShowHelp(HWND hwnd) { return ::HtmlHelp(hwnd, TEXT("find.chm"), HH_DISPLAY_TOPIC, 0); } // CSearchCmdDlg object wrap and event sink CSearchCmdDlg::CSearchCmdDlg(CFileSearchBand* pfsb) : CBandDlg(pfsb), _pSrchCmd(NULL), _pcp(NULL), _dwConnection(0) { ASSERT(pfsb); } CSearchCmdDlg::~CSearchCmdDlg() { DisconnectEvents(); if (_pSrchCmd) { _pSrchCmd->Release(); _pSrchCmd = NULL; } } ISearchCommandExt* CSearchCmdDlg::GetSearchCmd() { if (_fOnDestroy) return NULL; ASSERT(_pfsb->BandSite() != NULL); // Instantiate docfind command object if (NULL == _pSrchCmd) { ASSERT(0 == _dwConnection); if (SUCCEEDED(CoCreateInstance(CLSID_DocFindCommand, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(ISearchCommandExt, &_pSrchCmd)))) { // Assign search type. _pSrchCmd->SearchFor(GetSearchType()); // cmd object needs site to get to browser IUnknown_SetSite(_pSrchCmd, _pfsb->BandSite()); // Connect events. ConnectToConnectionPoint(SAFECAST(this, DSearchCommandEvents*), DIID_DSearchCommandEvents, TRUE, _pSrchCmd, &_dwConnection, &_pcp); } } return _pSrchCmd; } HRESULT CSearchCmdDlg::DisconnectEvents() { HRESULT hr = S_FALSE; if (_pcp) { _pcp->Unadvise(_dwConnection); _pcp->Release(); _pcp = NULL; _dwConnection = 0; hr = S_OK; } return hr; } HRESULT CSearchCmdDlg::StartSearch() { HRESULT hr = E_INVALIDARG; if (Validate()) // Validate input { ISearchCommandExt* pSrchCmd = GetSearchCmd(); if (pSrchCmd) { pSrchCmd->ClearResults(); // Clear off current results hr = AddConstraints(pSrchCmd); if (SUCCEEDED(hr)) hr = Execute(TRUE); } } return hr; } void CSearchCmdDlg::StartStopAnimation(BOOL bStart) { HWND hwndAnimate = GetAnimation(); if (IsWindow(hwndAnimate)) { if (bStart) Animate_Play(hwndAnimate, 0, -1, -1); else Animate_Stop(hwndAnimate); } } // WMU_RESTORESEARCH handler LRESULT CSearchCmdDlg::OnRestoreSearch(UINT, WPARAM, LPARAM, BOOL&) { // We've posted ourselves this message in response to the event // dispatch because we want to do our restoration on the // band's primary thread rather than the OLE dispatch thread. // To do the work on the dispatch thread results in a premature // abort of the search restoration processing as the dispatch // thread terminates. RestoreSearch(); return 0; } void CSearchCmdDlg::Clear() { StopSearch(); ISearchCommandExt *pSrchCmd = GetSearchCmd(); if (pSrchCmd) pSrchCmd->ClearResults(); } HRESULT CSearchCmdDlg::Execute(BOOL bStart) { ASSERT(_pSrchCmd); VARIANT varRecordsAffected = {0}, varParams = {0}; return _pSrchCmd->Execute(&varRecordsAffected, &varParams, bStart ? 1 : 0); } void CSearchCmdDlg::StopSearch() { if (SearchInProgress()) Execute(FALSE); } HRESULT CSearchCmdDlg::SetQueryFile(IN VARIANT* pvarFile) { HRESULT hr = CBandDlg::SetQueryFile(pvarFile); if (S_OK == hr) { ISearchCommandExt* pSrchCmd = GetSearchCmd(); if (pSrchCmd) hr = pSrchCmd->RestoreSavedSearch(pvarFile); else hr = E_FAIL; } return hr; } void CSearchCmdDlg::UpdateSearchCmdStateUI(DISPID eventID) { if (_fOnDestroy) return; BOOL bStopEvent = (DISPID_SEARCHCOMMAND_COMPLETE == eventID || DISPID_SEARCHCOMMAND_ERROR == eventID || DISPID_SEARCHCOMMAND_ABORT == eventID), bStartEvent = DISPID_SEARCHCOMMAND_START == eventID; HWND hwndStart = GetDlgItem(Hwnd(), IDC_SEARCH_START), hwndStop = GetDlgItem(Hwnd(), IDC_SEARCH_STOP); if (IsWindow(hwndStart)) { EnableStartStopButton(hwndStart, !SearchInProgress()); if (bStopEvent && IsChild(Hwnd(), GetFocus())) { _pfsb->AutoActivate(); SetFocus(hwndStart); } } if (IsWindow(hwndStop)) { EnableStartStopButton(hwndStop, SearchInProgress()); if (bStartEvent) { _pfsb->AutoActivate(); SetFocus(hwndStop); } } if (bStopEvent || !SearchInProgress()) StartStopAnimation(FALSE); } void CSearchCmdDlg::EnableStartStopButton(HWND hwndBtn, BOOL bEnable) { if (IsWindow(hwndBtn)) { if (bEnable) _ModifyWindowStyle(hwndBtn, BS_DEFPUSHBUTTON, 0); else _ModifyWindowStyle(hwndBtn, 0, BS_DEFPUSHBUTTON); ::EnableWindow(hwndBtn, bEnable); } } // Extracts error information from ISearchCommandExt and // propagate BOOL CSearchCmdDlg::ProcessCmdError() { BOOL bRet = FALSE; ISearchCommandExt* pSrchCmd = GetSearchCmd(); if (pSrchCmd) { HRESULT hr = S_OK; BSTR bstrError = NULL; // request error information through ISearchCommandExt if (SUCCEEDED(pSrchCmd->GetErrorInfo(&bstrError, (int *)&hr))) // allow derivatives classes a crack at handling the error bRet = OnSearchCmdError(hr, bstrError ? bstrError : NULL); } return bRet; } BOOL CSearchCmdDlg::OnSearchCmdError(HRESULT hr, LPCTSTR pszError) { if (pszError) { ShellMessageBox(HINST_THISDLL, _pfsb->m_hWnd, pszError, NULL, MB_OK | MB_ICONASTERISK); return TRUE; } return FALSE; } void CSearchCmdDlg::UpdateStatusText() { if (_fOnDestroy) return; ASSERT(_pfsb && _pfsb->BandSite()); ISearchCommandExt* pSrchCmd = GetSearchCmd(); if (pSrchCmd) { BSTR bstrStatus; if (SUCCEEDED(pSrchCmd->get_ProgressText(&bstrStatus))) { IWebBrowserApp* pwba; if (SUCCEEDED(IUnknown_QueryServiceForWebBrowserApp(_pfsb->BandSite(), IID_PPV_ARG(IWebBrowserApp, &pwba)))) { pwba->put_StatusText(bstrStatus); pwba->Release(); } if (bstrStatus) SysFreeString(bstrStatus); } } } void CSearchCmdDlg::OnBandShow(BOOL bShow) { if (!bShow) StopSearch() ; } STDMETHODIMP CSearchCmdDlg::TranslateAccelerator(MSG *pmsg) { if (S_OK == CBandDlg::TranslateAccelerator(pmsg)) return S_OK; if (WM_KEYDOWN == pmsg->message && VK_ESCAPE == pmsg->wParam && SearchInProgress() && 0 == (GetKeyState(VK_CONTROL) & 0x8000)) { StopSearch(); } return S_FALSE; } STDMETHODIMP CSearchCmdDlg::QueryInterface(REFIID riid, void** ppv) { static const QITAB qit[] = { QITABENTMULTI(CSearchCmdDlg, IDispatch, DSearchCommandEvents), QITABENTMULTI2(CSearchCmdDlg, DIID_DSearchCommandEvents, DSearchCommandEvents), { 0 }, }; return QISearch(this, qit, riid, ppv); } STDMETHODIMP_(ULONG) CSearchCmdDlg::AddRef() { return ((IFileSearchBand*)_pfsb)->AddRef(); } STDMETHODIMP_(ULONG) CSearchCmdDlg::Release() { return ((IFileSearchBand*)_pfsb)->Release(); } // IDispatch STDMETHODIMP CSearchCmdDlg::Invoke(DISPID dispid, REFIID, LCID, WORD, DISPPARAMS*, VARIANT*, EXCEPINFO*, UINT*) { switch (dispid) { case DISPID_SEARCHCOMMAND_COMPLETE: case DISPID_SEARCHCOMMAND_ABORT: case DISPID_SEARCHCOMMAND_ERROR: case DISPID_SEARCHCOMMAND_START: _fSearchInProgress = (DISPID_SEARCHCOMMAND_START == dispid); _fSearchAborted = (DISPID_SEARCHCOMMAND_ABORT == dispid); UpdateSearchCmdStateUI(dispid); if (DISPID_SEARCHCOMMAND_ERROR == dispid) ProcessCmdError(); break; case DISPID_SEARCHCOMMAND_PROGRESSTEXT: UpdateStatusText(); break; case DISPID_SEARCHCOMMAND_RESTORE: PostMessage(Hwnd(), WMU_RESTORESEARCH, 0, 0); // See comments in the CSearchCmdDlg::OnRestoreSearch message handler. break; } return S_OK; } class CDivWindow { // All private members: CDivWindow(); ~CDivWindow(); static LRESULT WINAPI WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT EraseBkgnd(HDC hdc); LRESULT WindowPosChanging(WINDOWPOS* pwp); LRESULT SetHeight(LONG cy); LRESULT SetBkColor(COLORREF rgb); static ATOM _atom; // window class atom HWND _hwnd; LONG _cy; // enforced height. COLORREF _rgbBkgnd; // background color HBRUSH _hbrBkgnd; // background brush friend void WINAPI DivWindow_RegisterClass(); }; void DivWindow_RegisterClass() { WNDCLASSEX wc = {0}; wc.cbSize = sizeof(wc); wc.style = CS_GLOBALCLASS; wc.lpfnWndProc = CDivWindow::WndProc; wc.hInstance = HINST_THISDLL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); wc.lpszClassName = DIVWINDOW_CLASS; RegisterClassEx(&wc); } inline CDivWindow::CDivWindow() : _hwnd(NULL), _cy(1), _hbrBkgnd(NULL), _rgbBkgnd(COLOR_BTNFACE) { } inline CDivWindow::~CDivWindow() { if (_hbrBkgnd) DeleteObject(_hbrBkgnd); } LRESULT CDivWindow::EraseBkgnd(HDC hdc) { if (!_hbrBkgnd) return DefWindowProc(_hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0); RECT rc; GetClientRect(_hwnd, &rc); FillRect(hdc, &rc, _hbrBkgnd); return TRUE; } LRESULT CDivWindow::WindowPosChanging(WINDOWPOS* pwp) { // enforce height if (0 == (pwp->flags & SWP_NOSIZE)) pwp->cy = _cy; return 0; } LRESULT CDivWindow::SetHeight(LONG cy) { _cy = cy; return TRUE; } LRESULT CDivWindow::SetBkColor(COLORREF rgb) { if (rgb != _rgbBkgnd) { _rgbBkgnd = rgb; if (_hbrBkgnd) DeleteObject(_hbrBkgnd); _hbrBkgnd = CreateSolidBrush(_rgbBkgnd); InvalidateRect(_hwnd, NULL, TRUE); } return TRUE; } LRESULT WINAPI CDivWindow::WndProc(HWND hwnd, UINT nMsg, WPARAM wParam, LPARAM lParam) { CDivWindow* pThis = (CDivWindow*)GetWindowLongPtr(hwnd, GWLP_USERDATA); switch (nMsg) { case WM_ERASEBKGND: return pThis->EraseBkgnd((HDC)wParam); case WM_WINDOWPOSCHANGING: return pThis->WindowPosChanging((WINDOWPOS*)lParam); case WM_GETDLGCODE: return DLGC_STATIC; case DWM_SETHEIGHT: return pThis->SetHeight((LONG)wParam); case DWM_SETBKCOLOR: return pThis->SetBkColor((COLORREF)wParam); case WM_NCCREATE: if (NULL == (pThis = new CDivWindow)) return FALSE; pThis->_hwnd = hwnd; SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis); break; case WM_NCDESTROY: { LRESULT lRet = DefWindowProc(hwnd, nMsg, wParam, lParam); SetWindowPtr(hwnd, GWLP_USERDATA, 0); pThis->_hwnd = NULL; delete pThis; return lRet; } } return DefWindowProc(hwnd, nMsg, wParam, lParam); } // {C8F945CB-327A-4330-BB2F-C04122959488} static const IID IID_IStringMru = { 0xc8f945cb, 0x327a, 0x4330, { 0xbb, 0x2f, 0xc0, 0x41, 0x22, 0x95, 0x94, 0x88 } }; // Creates and initializes a CStringMru instance HRESULT CStringMru::CreateInstance(HKEY hKey, LPCTSTR szSubKey, LONG cMaxStrings, BOOL bCaseSensitive, REFIID riid, void ** ppv) { HRESULT hr; CStringMru* pmru = new CStringMru; if (NULL == pmru) return E_OUTOFMEMORY; pmru->_hKeyRoot = hKey; hr = StringCchCopy(pmru->_szSubKey, ARRAYSIZE(pmru->_szSubKey), szSubKey); if (SUCCEEDED(hr)) { if (cMaxStrings > 0) pmru->_cMax = cMaxStrings; pmru->_bCaseSensitive = bCaseSensitive; hr = pmru->QueryInterface(riid, ppv); } pmru->Release(); return hr; } CStringMru::CStringMru() : _cRef(1), _hKeyRoot(NULL), _hKey(NULL), _hdpaStrings(NULL), _cMax(25), _bCaseSensitive(TRUE), _iString(-1) { *_szSubKey = 0; } CStringMru::~CStringMru() { _Close(); _Clear(); } // Opens string MRU store HRESULT CStringMru::_Open() { if (_hKey) return S_OK; DWORD dwDisposition; DWORD dwErr = RegCreateKeyEx(_hKeyRoot, _szSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_QUERY_VALUE | KEY_SET_VALUE, NULL, &_hKey, &dwDisposition); return HRESULT_FROM_WIN32(dwErr); } // Deletes string MRU store void CStringMru::_Delete() { if (_hKey) _Close(); SHDeleteKey(_hKeyRoot, _szSubKey); } // Reads string MRU store into memory HRESULT CStringMru::_Read(OUT OPTIONAL LONG* pcRead) { HRESULT hr = E_FAIL; if (pcRead) *pcRead = 0; if (SUCCEEDED((hr = _Open()))) { _Clear(); // throw away existing cached strings _hdpaStrings = DPA_Create(4); // allocate dynarray if (NULL == _hdpaStrings) { hr = E_OUTOFMEMORY; } else { // step through string values in registry. for (int iString = 0; iString < _cMax; iString++) { TCHAR szVal[16]; TCHAR szString[MAX_URL_STRING]; StringCchPrintf(szVal, ARRAYSIZE(szVal), TEXT("%03d"), iString); // ok to truncate DWORD dwErr = SHRegGetString(_hKey, szVal, 0, szString, ARRAYSIZE(szString)); if (dwErr == ERROR_SUCCESS && *szString) { LPOLESTR pwszAdd; if (SUCCEEDED(SHStrDup(szString, &pwszAdd))) { if (DPA_AppendPtr(_hdpaStrings, pwszAdd) == -1) { CoTaskMemFree(pwszAdd); } } } } } _Close(); if (pcRead && _hdpaStrings) *pcRead = DPA_GetPtrCount(_hdpaStrings); } return hr; } // Writes string MRU store from memory HRESULT CStringMru::_Write(OUT OPTIONAL LONG* pcWritten) { HRESULT hr = E_FAIL; LONG cWritten = 0; if (pcWritten) *pcWritten = cWritten; // Delete store and re-create. _Delete(); if (NULL == _hdpaStrings) return S_FALSE; if (FAILED((hr = _Open()))) return hr; ASSERT(DPA_GetPtrCount(_hdpaStrings) <= _cMax); // step through string values in registry. for (int iString = 0, cnt = DPA_GetPtrCount(_hdpaStrings); iString < cnt; iString++) { TCHAR szVal[16]; TCHAR szString[MAX_URL_STRING]; StringCchPrintf(szVal, ARRAYSIZE(szVal), TEXT("%03d"), iString); // ok to truncate LPOLESTR pwszWrite = (LPOLESTR)DPA_FastGetPtr(_hdpaStrings, iString); SHUnicodeToTChar(pwszWrite, szString, ARRAYSIZE(szString)); DWORD dwErr = RegSetValueEx(_hKey, szVal, 0, REG_SZ, (LPBYTE)szString, sizeof(szString)); if (ERROR_SUCCESS == dwErr) cWritten++; } _Close(); if (pcWritten) *pcWritten = cWritten; return S_OK; } // Closes string MRU store void CStringMru::_Close() { if (_hKey) { RegCloseKey(_hKey); _hKey = NULL; } } // Adds a string to the store STDMETHODIMP CStringMru::Add(LPCOLESTR pwszAdd) { if (!(pwszAdd && *pwszAdd)) return E_INVALIDARG; if (NULL == _hdpaStrings) { _hdpaStrings = DPA_Create(4); if (NULL == _hdpaStrings) return E_OUTOFMEMORY; } HRESULT hr = E_FAIL; LONG iMatch = -1; for (LONG i = 0, cnt = DPA_GetPtrCount(_hdpaStrings); i < cnt; i++) { LPOLESTR pwsz = (LPOLESTR)DPA_FastGetPtr(_hdpaStrings, i); if (pwsz) { int nCompare = _bCaseSensitive ? StrCmpW(pwszAdd, pwsz) : StrCmpIW(pwszAdd, pwsz); if (0 == nCompare) { iMatch = i; break; } } } if (-1 == iMatch) { // Create a copy and add it to the list. LPOLESTR pwszCopy; hr = SHStrDup(pwszAdd, &pwszCopy); if (SUCCEEDED(hr)) { int iNew = DPA_InsertPtr(_hdpaStrings, 0, pwszCopy); if (iNew < 0) { CoTaskMemFree(pwszCopy); hr = E_OUTOFMEMORY; } } } else { hr = _Promote(iMatch); } if (S_OK == hr) { // If we've grown too large, delete LRU string int cStrings = DPA_GetPtrCount(_hdpaStrings); while (cStrings > _cMax) { LPOLESTR pwsz = (LPOLESTR)DPA_DeletePtr(_hdpaStrings, cStrings - 1); CoTaskMemFree(pwsz); cStrings--; } hr = _Write(); } return hr; } // Promotes a string to MRU HRESULT CStringMru::_Promote(LONG iString) { if (0 == iString) return S_OK; LONG cnt = _hdpaStrings ? DPA_GetPtrCount(_hdpaStrings) : 0 ; if (iString >= cnt) return E_INVALIDARG; LPOLESTR pwsz = (LPOLESTR)DPA_DeletePtr(_hdpaStrings, iString); if (pwsz) { int iMru = DPA_InsertPtr(_hdpaStrings, 0, pwsz); if (iMru < 0) { CoTaskMemFree(pwsz); return E_OUTOFMEMORY; } else { ASSERT(0 == iMru); return S_OK; } } return E_FAIL; } // Clears string MRU memory cache void CStringMru::_Clear() { if (_hdpaStrings) { for (int i = 0, cnt = DPA_GetPtrCount(_hdpaStrings); i < cnt; i++) { LPOLESTR pwsz = (LPOLESTR)DPA_FastGetPtr(_hdpaStrings, i); CoTaskMemFree(pwsz); } DPA_Destroy(_hdpaStrings); _hdpaStrings = NULL; } } STDMETHODIMP_(ULONG) CStringMru::AddRef(void) { return InterlockedIncrement(&_cRef); } STDMETHODIMP_(ULONG) CStringMru::Release(void) { ASSERT( 0 != _cRef ); ULONG cRef = InterlockedDecrement(&_cRef); if ( 0 == cRef ) { delete this; } return cRef; } STDMETHODIMP CStringMru::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(CStringMru, IEnumString), QITABENT(CStringMru, IStringMru), { 0 }, }; return QISearch(this, qit, riid, ppv); } // *** IEnumString *** STDMETHODIMP CStringMru::Next(ULONG celt, LPOLESTR *rgelt, ULONG *pceltFetched) { ULONG cFetched = 0; if (pceltFetched) *pceltFetched = cFetched; if (NULL == _hdpaStrings) { HRESULT hr = _Read(); if (FAILED(hr)) return hr; } for (int cnt = _hdpaStrings ? DPA_GetPtrCount(_hdpaStrings) : 0; cFetched < celt && (_iString + 1) < cnt;) { _iString++; LPOLESTR pwsz = (LPOLESTR)DPA_FastGetPtr(_hdpaStrings, _iString); if (pwsz) { if (SUCCEEDED(SHStrDup(pwsz, &rgelt[cFetched]))) { cFetched++; } } } if (pceltFetched) *pceltFetched = cFetched; return cFetched == celt ? S_OK : S_FALSE ; } STDMETHODIMP CStringMru::Skip(ULONG celt) { _iString += celt; if (_iString >= _cMax) _iString = _cMax - 1; return S_OK; } STDMETHODIMP CStringMru::Reset(void) { _iString = -1; return S_OK; } // Namespace selector combo methods HRESULT _MakeCSIDLCbxItem(UINT csidl, UINT csidl2, HWND hwndComboBoxEx, ADDCBXITEMCALLBACK pfn, LPARAM lParam) { LPCTSTR rgcsidl[2] = {MAKEINTRESOURCE(csidl), MAKEINTRESOURCE(csidl2)}; // note, CreateIEnumIDListOnCSIDLs checks SFGAO_NONENUMERATED so it filters // out things we should not display IEnumIDList *penum; HRESULT hr = CreateIEnumIDListOnCSIDLs(NULL, rgcsidl, (-1 == csidl2 ? 1 : 2), &penum); if (SUCCEEDED(hr)) { LPITEMIDLIST pidl; if (S_OK == FirstIDList(penum, &pidl)) { TCHAR szName[MAX_PATH]; SHGetNameAndFlags(pidl, SHGDN_NORMAL, szName, ARRAYSIZE(szName), NULL); CBXITEM item; item.iID = csidl; MakeCbxItem(&item, szName, penum, pidl, LISTINSERT_LAST, NO_ITEM_INDENT); hr = AddCbxItemToComboBoxCallback(hwndComboBoxEx, &item, pfn, lParam); if (SUCCEEDED(hr)) { penum = NULL; } ILFree(pidl); } if (penum) penum->Release(); } return hr; } BOOL AppendItemToItemsArray(LPITEMIDLIST pidl, LPITEMIDLIST rgItems[], UINT sizeItems, UINT *pcItems) { BOOL bAdded = FALSE; if (*pcItems < sizeItems) { DWORD dwFlags = SFGAO_NONENUMERATED; if (SUCCEEDED(SHGetNameAndFlags(pidl, SHGDN_NORMAL, NULL, 0, &dwFlags)) && !(dwFlags & SFGAO_NONENUMERATED)) { rgItems[(*pcItems)++] = pidl; bAdded = TRUE; pidl = NULL; // don't free below } } ILFree(pidl); // will be NULL if added to array, ownership transfered return bAdded; } BOOL AppendToItemsArray(LPCTSTR psz, LPITEMIDLIST rgItems[], UINT sizeItems, UINT *pcItems) { LPITEMIDLIST pidl; if (IS_INTRESOURCE(psz)) { SHGetFolderLocation(NULL, LOWORD((UINT_PTR)psz), NULL, 0, &pidl); } else { SHParseDisplayName(psz, NULL, &pidl, 0, NULL); } BOOL bAdded = FALSE; if (pidl) { bAdded = AppendItemToItemsArray(pidl, rgItems, sizeItems, pcItems); } return bAdded; } // Create an item to put into the "look in" combo box for // Local Hard Drives. Will search the following directories: // 1. My Documents // 2. The Desktop folder (not the root of all PIDLS) // 3. My Pictures // 4. My Music // 5. Documents and Settings // 6. The current directory // 7. The recycle bin // 8. All local drives. #define MIR(x) MAKEINTRESOURCE(x) HRESULT _MakeLocalHardDrivesCbxItem(HWND hwndComboBoxEx, ADDCBXITEMCALLBACK pfn, LPARAM lParam) { LPITEMIDLIST rgItems[32] = {0}; UINT cItems = 0; HRESULT hr = S_OK; AppendToItemsArray(MIR(CSIDL_PERSONAL), rgItems, ARRAYSIZE(rgItems), &cItems); AppendToItemsArray(MIR(CSIDL_COMMON_DOCUMENTS | CSIDL_FLAG_NO_ALIAS), rgItems, ARRAYSIZE(rgItems), &cItems); AppendToItemsArray(MIR(CSIDL_DESKTOPDIRECTORY | CSIDL_FLAG_NO_ALIAS), rgItems, ARRAYSIZE(rgItems), &cItems); AppendToItemsArray(MIR(CSIDL_COMMON_DESKTOPDIRECTORY), rgItems, ARRAYSIZE(rgItems), &cItems); AppendToItemsArray(MIR(CSIDL_MYPICTURES), rgItems, ARRAYSIZE(rgItems), &cItems); AppendToItemsArray(MIR(CSIDL_MYMUSIC), rgItems, ARRAYSIZE(rgItems), &cItems); AppendToItemsArray(MIR(CSIDL_MYVIDEO), rgItems, ARRAYSIZE(rgItems), &cItems); TCHAR szPath[MAX_PATH]; DWORD cchPath = ARRAYSIZE(szPath); if (GetProfilesDirectory(szPath, &cchPath)) { AppendToItemsArray(szPath, rgItems, ARRAYSIZE(rgItems), &cItems); } AppendToItemsArray(MIR(CSIDL_BITBUCKET), rgItems, ARRAYSIZE(rgItems), &cItems); TCHAR szDrives[128]; szDrives[0] = 0; LPITEMIDLIST pidlIcon = NULL; for (int i = 0; i < 26; i++) { TCHAR szDrive[4]; if (DRIVE_FIXED == GetDriveType(PathBuildRoot(szDrive, i))) { if (AppendToItemsArray(szDrive, rgItems, ARRAYSIZE(rgItems), &cItems)) { // grab the pidl of the first time to use for the icon if (pidlIcon == NULL) SHParseDisplayName(szDrive, NULL, &pidlIcon, 0, NULL); if (szDrives[0]) { hr = StringCchCat(szDrives, ARRAYSIZE(szDrives), TEXT(";")); if (FAILED(hr)) { break; } } szDrive[2] = 0; // remove the back slash hr = StringCchCat(szDrives, ARRAYSIZE(szDrives), szDrive); if (FAILED(hr)) { break; } } } } if (SUCCEEDED(hr)) { IEnumIDList *penum; hr = CreateIEnumIDListOnIDLists(rgItems, cItems, &penum); if (SUCCEEDED(hr)) { TCHAR szFmt[64]; LoadString(HINST_THISDLL, IDS_SNS_LOCALHARDDRIVES, szFmt, ARRAYSIZE(szFmt)); hr = StringCchPrintf(szPath, ARRAYSIZE(szPath), szFmt, szDrives); if (SUCCEEDED(hr)) { CBXITEM item; MakeCbxItem(&item, szPath, penum, pidlIcon, LISTINSERT_LAST, ITEM_INDENT); item.iID = CBX_CSIDL_LOCALDRIVES; hr = AddCbxItemToComboBoxCallback(hwndComboBoxEx, &item, pfn, lParam); } if (FAILED(hr)) penum->Release(); } } ILFree(pidlIcon); return hr; } typedef struct { HWND hwndComboBox; ADDCBXITEMCALLBACK pfn; LPARAM lParam; } ENUMITEMPARAM; HRESULT _PopulateDrivesCB(LPCITEMIDLIST pidl, void *pv) { ENUMITEMPARAM* peip = (ENUMITEMPARAM*)pv; ULONG ulAttrs = SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_NONENUMERATED; TCHAR szName[MAX_PATH]; HRESULT hr = SHGetNameAndFlags(pidl, SHGDN_NORMAL, szName, ARRAYSIZE(szName), &ulAttrs); if (SUCCEEDED(hr)) { if ((SFGAO_FOLDER | SFGAO_FILESYSTEM) == (ulAttrs & (SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_NONENUMERATED))) { IEnumIDList *penum; hr = CreateIEnumIDListOnIDLists(&pidl, 1, &penum); if (SUCCEEDED(hr)) { CBXITEM item; MakeCbxItem(&item, szName, penum, pidl, LISTINSERT_LAST, ITEM_INDENT); item.iID = CSIDL_DRIVES; hr = AddCbxItemToComboBoxCallback(peip->hwndComboBox, &item, peip->pfn, peip->lParam); if (SUCCEEDED(hr)) { penum = NULL; } else { penum->Release(); } } } else { hr = S_FALSE; } } return hr; } STDAPI PopulateNamespaceCombo(HWND hwndComboBoxEx, ADDCBXITEMCALLBACK pfn, LPARAM lParam) { ::SendMessage(hwndComboBoxEx, CB_RESETCONTENT, 0, 0); // CSIDL_DESKTOP - use just the file system locations, not the root of the whole // name space here to avoid searching everything HRESULT hr = _MakeCSIDLCbxItem(CSIDL_DESKTOPDIRECTORY | CSIDL_FLAG_NO_ALIAS, CSIDL_COMMON_DESKTOPDIRECTORY | CSIDL_FLAG_NO_ALIAS, hwndComboBoxEx, pfn, lParam); if (SUCCEEDED(hr)) hr = _MakeCSIDLCbxItem(CSIDL_PERSONAL, -1, hwndComboBoxEx, pfn, lParam); if (SUCCEEDED(hr)) hr = _MakeCSIDLCbxItem(CSIDL_MYPICTURES, -1, hwndComboBoxEx, pfn, lParam); if (SUCCEEDED(hr)) hr = _MakeCSIDLCbxItem(CSIDL_MYMUSIC, -1, hwndComboBoxEx, pfn, lParam); if (SUCCEEDED(hr)) { // My Computer and children // If My Docs has been redirected to a remote share, we'll want to prepend its path // to our My Computer path list; otherwise it'll be missed. UINT csidl2 = -1; TCHAR szPath[MAX_PATH]; if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, szPath)) && PathIsNetworkPath(szPath)) { csidl2 = CSIDL_PERSONAL; } hr = _MakeCSIDLCbxItem(CSIDL_DRIVES, csidl2, hwndComboBoxEx, pfn, lParam); if (SUCCEEDED(hr)) { // Local hard drives (Which has heuristics to search best places first...) hr = _MakeLocalHardDrivesCbxItem(hwndComboBoxEx, pfn, lParam); if (SUCCEEDED(hr)) { ENUMITEMPARAM eip = {0}; eip.hwndComboBox = hwndComboBoxEx; eip.pfn = pfn; eip.lParam = lParam; hr = EnumSpecialItemIDs(CSIDL_DRIVES, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, _PopulateDrivesCB, &eip); } } } if (SUCCEEDED(hr)) { // Browse... CBXITEM item; item.iID = -1; TCHAR szDisplayName[MAX_PATH]; LoadString(HINST_THISDLL, IDS_SNS_BROWSER_FOR_DIR, szDisplayName, ARRAYSIZE(szDisplayName)); MakeCbxItem(&item, szDisplayName, NULL, NULL, LISTINSERT_LAST, NO_ITEM_NOICON_INDENT); hr = AddCbxItemToComboBoxCallback(hwndComboBoxEx, &item, pfn, lParam); } return hr; }