// fsrchdlg.cpp : Implementation of CFindFilesDlg #include "shellprv.h" #include "fsearch.h" #include "fsrchdlg.h" #include "asuggest.h" // IAutoCompleteDropDown #include "docfind.h" // DFW_xxx warning flags. // shellprv.h brings in a bogus SubclassWindow macro def #ifdef SubclassWindow #undef SubclassWindow #endif SubclassWindow // HACK bust: this should be decl'd in a header file! extern "C" HIMAGELIST WINAPI _GetSystemImageListSmallIcons(); #define MAX_EDIT 256 #define SUBDLG_BORDERWIDTH 0 #define FOLDER_IMAGELIST_INDEX 3 #define MIN_NAMESPACELIST_WIDTH 140 #define MIN_FILEASSOCLIST_WIDTH 175 #define CSIDL_DEFAULT_PIDL CSIDL_DRIVES #define FILE_ATTRIBUTE_NOTFOUND 0xFFFFFFFF #define FINDHELPFILE TEXT("find.chm") #define FINDFILES_HELPTOPIC NULL //TEXT("win_tray_find_file.htm") #define FINDCOMPUTER_HELPTOPIC NULL //TEXT("find_computer.htm") #define INDEXSERVICE_HELPFILE TEXT("isconcepts.chm") #define INDEXSERVICE_HELPTOPIC NULL #define LSUIS_WARNING 1 // LoadSaveUIState warning flags #define AUTOSUGGEST_MRUCOUNT 25 // Activate load, save of subdialog state by undefing this: // #define _LOADSAVE_SUBDLG_UI__ // Forwards: int CSearchWarningDlg_DoModal(HWND hwndParent, USHORT uDlgTemplate, BOOL* pbNoWarn); int CCISettingsDlg_DoModal(HWND hwndParent); HWND CCISettingsDlg_CreateModeless(HWND hwndParent); // Helpers // constraint names (must be kept in sync w/ enumeration FSB_CONSTRAINT). const LPCWSTR constraint_names[] = { L"SearchFor", L"IndexedSearch", L"Named", L"LookIn", L"ContainingText", L"SizeLE", L"SizeGE", L"WhichDate", L"DateNMonths", L"DateNDays", L"DateLE", L"DateGE", L"FileType", L"IncludeSubFolders", L"CaseSensitive", L"RegularExpressions", L"SearchSlowFiles", L"QueryDialect", L"WarningFlags", }; LPCWSTR GetConstraintName(FSB_CONSTRAINT constraint) { if (constraint >= 0 && constraint < _fsbc_count) return constraint_names[constraint]; return NULL; } BOOL IsConstraintName(FSB_CONSTRAINT constraint, LPCWSTR pwszName) { LPCWSTR pwszConstraint = GetConstraintName(constraint); if (pwszConstraint && pwszName) return 0 == StrCmpIW(pwszName, pwszConstraint); return FALSE; } BOOL _GetWindowSize(HWND hwndDlg, LPSIZE 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, 0L); 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() { IShellDispatch2* psd; BOOL bRet = FALSE; if (SUCCEEDED(CoCreateInstance(CLSID_Shell, 0, CLSCTX_INPROC_SERVER, IID_IShellDispatch2, (void**)&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, 0L); if (CB_ERR == idx) return idx; return (LPARAM)::SendMessage(hwndCombo, CB_GETITEMDATA, idx, 0L); } // Selects combo item with matching data, and returns the index // of the selected item. INT_PTR _SelectComboData(HWND hwndCombo, LPARAM lpData) { INT_PTR i; INT_PTR cnt = SendMessage(hwndCombo, CB_GETCOUNT, 0, 0L); for (i = 0; i < cnt; i++) { LPARAM lParam = SendMessage(hwndCombo, CB_GETITEMDATA, i, 0L); if (lParam != CB_ERR && lParam == lpData) { SendMessage(hwndCombo, CB_SETCURSEL, i, 0L); return i; } } return CB_ERR; } // Draws a focus rect bounding the specified window. void _DrawCtlFocus(HWND hwnd) { HDC hdc; if ((hdc = GetDC(hwnd)) != NULL) { RECT rc; GetClientRect(hwnd, &rc); DrawFocusRect(hdc, &rc); ReleaseDC(hwnd, hdc); } } BOOL _IsPathList(LPCTSTR pszPath) { return pszPath ? StrChr(pszPath, TEXT(';')) != NULL : FALSE; } HRESULT _IsPathValidUNC(HWND hWndParent, BOOL fNetValidate, LPCTSTR pszPath) { HRESULT hr = S_OK; DWORD dwResult; NETRESOURCE nr; TCHAR pszPathBuffer[MAX_PATH]; // Safe IsPathUNC if ((TEXT('\\') != pszPath[0]) || (TEXT('\\') != pszPath[1]) || (TEXT('\0') == pszPath[3])) { return S_FALSE; } if (fNetValidate) { memset(&nr, 0, sizeof(NETRESOURCE)); StrCpyN(pszPathBuffer, pszPath, MAX_PATH); nr.dwType = RESOURCETYPE_DISK; nr.lpRemoteName = pszPathBuffer; dwResult = WNetAddConnection3(hWndParent, &nr, NULL, NULL, CONNECT_TEMPORARY | CONNECT_INTERACTIVE); if (NO_ERROR != dwResult) { return E_FAIL; } } return S_OK; } BOOL _IsFullPathMinusDriveLetter(LPCTSTR pszPath) { if (NULL == pszPath || PathIsUNC(pszPath)) return FALSE; ASSERT(!PathIsRelative(pszPath)); // Eat whitespace for (; (TEXT('\0') != *pszPath) && (TEXT(' ') == *pszPath); pszPath = CharNext(pszPath)); return TEXT('\\') == *pszPath && -1 == PathGetDriveNumber(pszPath); } inline BOOL _PathLooksLikeFilePattern(LPCTSTR pszPath) { return StrPBrk(pszPath, TEXT("?*")) != NULL; } inline BOOL _PathIsDblSlash(LPCTSTR pszPath) { if (pszPath) return (pszPath[0] == TEXT('\\') && pszPath[1] == TEXT('\\')); return FALSE; } BOOL _PathIsUNCServerShareOrSub(LPCTSTR pszPath) { if (pszPath) { if (_PathIsDblSlash(pszPath)) { int cSlash = 0; LPTSTR psz; for (psz = (LPTSTR)pszPath; psz && *psz; psz = CharNext(psz)) { if (*psz == TEXT('\\')) cSlash++; } return (cSlash >= 3); } } return FALSE; } BOOL _IsRegItemPath(LPCTSTR pszPath) { if (pszPath && *pszPath) { if (lstrlen(pszPath) > 3 && TEXT(':') == pszPath[0] && TEXT(':') == pszPath[1] && TEXT('{') == pszPath[2]) { return TRUE; } } return FALSE; } BOOL _IsPathLocalHarddrive(LPCTSTR pszPath) { if (!PathIsUNC(pszPath)) { int iDrive; if ((iDrive = PathGetDriveNumber(pszPath)) != -1) { TCHAR szRoot[16]; return DRIVE_FIXED == GetDriveType(PathBuildRoot(szRoot, iDrive)); } } return FALSE; } BOOL _IsPathLocalRoot(LPCTSTR pszPath) { if (!PathIsUNC(pszPath)) { int iDrive; if ((iDrive = PathGetDriveNumber(pszPath)) != -1) { TCHAR szRoot[16]; if (PathBuildRoot(szRoot, iDrive)) { if (0 == StrCmpI(szRoot, pszPath)) { switch (GetDriveType(szRoot)) { case DRIVE_REMOVABLE: case DRIVE_FIXED: case DRIVE_REMOTE: case DRIVE_CDROM: case DRIVE_RAMDISK: return TRUE; } } } } } return FALSE; } // Retrieves the name for the specified folder. HRESULT _GetNameFromFolder( IShellFolder* psf, BOOL bForParsing, LPTSTR pszName, UINT cchName) { HRESULT hr = E_FAIL; // Use IPersistFolder2: IPersistFolder2* ppf2; if (SUCCEEDED((hr = psf->QueryInterface(IID_IPersistFolder2, (void**)&ppf2)))) { LPITEMIDLIST pidl = NULL; if (SUCCEEDED((hr = ppf2->GetCurFolder(&pidl)))) { if (bForParsing) { ASSERT(cchName >= MAX_PATH); hr = SHGetPathFromIDList(pidl, pszName) ? S_OK : E_FAIL; } else { hr = SHGetNameAndFlags(pidl, SHGDN_NORMAL, pszName, cchName, NULL); } ILFree(pidl); } ppf2->Release(); } return hr; } // Retrieves the path, and optionally, the display name for the specified folder object. HRESULT _GetPathFromFolder(IShellFolder* psf, LPTSTR pszPath, UINT cchPath, LPTSTR pszName, UINT cchName) { IPersistFolder3* ppf3; PERSIST_FOLDER_TARGET_INFO pfti; HRESULT hr = E_FAIL; *pszPath = 0; if (pszName) *pszName = 0; // We'll try IPersistFolder3 first to ensure that // we get the target of a folder shortcuts if (SUCCEEDED((hr = psf->QueryInterface(IID_IPersistFolder3, (void**)&ppf3)))) { if (SUCCEEDED((hr = ppf3->GetFolderTargetInfo(&pfti)))) { // PERSIST_FOLDER_TARGET_INFO::pidlTargetFolder may sometimes // be NULL, so rely first on the PERSIST_FOLDER_TARGET_INFO::szTargetParsingName. // The only case this should be empty is if we have a special folder, // in which case we don't want to search it anyway. if (*pfti.szTargetParsingName) SHUnicodeToTChar(pfti.szTargetParsingName, pszPath, cchPath); else hr = E_FAIL; if (pfti.pidlTargetFolder) { if (0 == *pszPath) { ASSERT(cchPath >= MAX_PATH); hr = SHGetPathFromIDList(pfti.pidlTargetFolder, pszPath) ? S_OK : E_FAIL; } if (pszName) { SHGetNameAndFlags(pfti.pidlTargetFolder, SHGDN_NORMAL, pszName, cchName, NULL); } ILFree(pfti.pidlTargetFolder); } } ppf3->Release(); } // fall-back plan: if (0 == *pszPath) hr = _GetNameFromFolder(psf, TRUE, pszPath, cchPath); if (pszName && 0 == *pszName) _GetNameFromFolder(psf, FALSE, pszName, cchName); return hr; } BOOL _GetCurrentPathAndNamespace( IUnknown* punkSite, OUT LPTSTR pszPath, IN UINT cchPath, OUT LPTSTR pszNamespace, IN UINT cchNamespace) { USES_CONVERSION; BOOL bScoped = FALSE; ASSERT(punkSite); HRESULT hr = E_FAIL; // (1) Retrieve the file system path of the active defview's shellfolder IShellBrowser* psb; hr = IUnknown_QueryService(punkSite, SID_STopLevelBrowser, IID_IShellBrowser, (void**)&psb); if (SUCCEEDED(hr)) { IShellView* psv; hr = psb->QueryActiveShellView(&psv); if (SUCCEEDED(hr)) { IDefViewFrame* pdvf; hr = psv->QueryInterface(IID_IDefViewFrame, (void**)&pdvf); if (SUCCEEDED(hr)) { IShellFolder* psf; hr = pdvf->GetShellFolder(&psf); if (SUCCEEDED(hr)) { hr = _GetPathFromFolder(psf, pszPath, cchPath, pszNamespace, cchNamespace); // don't treat failure as error; if (FAILED(hr)) hr = S_FALSE; psf->Release(); } pdvf->Release(); } psv->Release(); } psb->Release(); } return hr; } HRESULT _PathValidate(LPCTSTR pszPath, OPTIONAL HWND hWndParent = NULL, OPTIONAL BOOL fNetValidate = FALSE, OUT OPTIONAL LPDWORD pdwAttr = NULL) { DWORD dwAttr; HRESULT hr = S_OK; if (pdwAttr) *pdwAttr = 0L; hr = _IsPathValidUNC(hWndParent, fNetValidate, pszPath); if (S_OK == hr) { // We are done. } else if (E_FAIL == hr) { hr = E_FILE_NOT_FOUND; } else { if (_IsPathList(pszPath) /*tokenized*/ || PathIsSlow(pszPath, FILE_ATTRIBUTE_NOTFOUND)) { hr = S_OK; // Skip check for slow files. } else { if (PathIsRelative(pszPath) || _IsFullPathMinusDriveLetter(pszPath)) { hr = E_FILE_NOT_FOUND; // don't accept anything but a fully qualified path at this point. dwAttr = FILE_ATTRIBUTE_NOTFOUND; } else { dwAttr = GetFileAttributes(pszPath); // Does it exist? if (FILE_ATTRIBUTE_NOTFOUND == dwAttr) { // Maybe the disk isn't inserted, so allow the user // the chance to insert it. if (hWndParent && SUCCEEDED(SHPathPrepareForWrite(hWndParent, NULL, pszPath, SHPPFW_IGNOREFILENAME))) { dwAttr = GetFileAttributes(pszPath); // Does it exist now? } if (FILE_ATTRIBUTE_NOTFOUND == dwAttr) hr = E_FILE_NOT_FOUND; // It doesn't exist. else hr = S_OK; // It exists now. } } if (pdwAttr) *pdwAttr = dwAttr; } } 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)))) { wnsprintf(szBuf, cchBuf, szFmt, pszSub); return TRUE; } return FALSE; } // Converts a TCHAR string to a variant of type VT_BSTR HRESULT _T2BstrVariant(LPCTSTR pszText, OUT VARIANT* pvar) { VariantInit(pvar); pvar->vt = VT_BSTR; pvar->bstrVal = SysAllocStringT(pszText); return S_OK; } // Concatenates a BSTR string token and delimiter to a variant of type VT_BSTR. HRESULT _BstrAppendToken(IN OUT BSTR* pbstr, IN LPCTSTR pszDelim, IN LPCTSTR pszToken) { USES_CONVERSION; ASSERT(pszToken); ASSERT(pbstr); int cch = lstrlen(pszToken) + (pszDelim ? lstrlen(pszDelim) : 0) + (*pbstr ? lstrlenW(*pbstr) : 0); LPWSTR pwszBuf; if (NULL == (pwszBuf = new WCHAR[cch + 1])) return E_OUTOFMEMORY; *pwszBuf = 0; if (*pbstr && **pbstr) { StrCatW(pwszBuf, *pbstr); if (*pwszBuf && pszDelim && *pszDelim) StrCatW(pwszBuf, T2W((LPTSTR)pszDelim)); } StrCatW(pwszBuf, T2W((LPTSTR)pszToken)); SysFreeString(*pbstr); *pbstr = SysAllocString(pwszBuf); delete[] pwszBuf; return *pbstr ? S_OK : E_OUTOFMEMORY; } // Retrieves the window text as a variant value of the specified type. HRESULT _GetWindowValue(HWND hwndDlg, UINT nID, VARTYPE vt, VARIANT* pvar) { TCHAR szText[MAX_EDIT]; HRESULT hr = S_FALSE; VariantInit(pvar); pvar->vt = vt; if (::GetDlgItemText(hwndDlg, nID, szText, ARRAYSIZE(szText))) { switch (vt) { case VT_BSTR: default: hr = _T2BstrVariant(szText, pvar); break; } } return hr; } // 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); return S_OK; case VT_UI4: SetDlgItemInt(hwndDlg, nID, pvar->uiVal, FALSE); return S_OK; case VT_I4: SetDlgItemInt(hwndDlg, nID, pvar->lVal, TRUE); return S_OK; } return E_NOTIMPL; } // Adds a named constraint to the specified search command extension object HRESULT _AddConstraint(ISearchCommandExt* pSrchCmd, LPCWSTR pwszConstraint, VARIANT* pvarValue) { HRESULT hres; BSTR bstrConstraint = NULL; if (NULL == (bstrConstraint = SysAllocString(pwszConstraint))) return E_OUTOFMEMORY; hres = pSrchCmd->AddConstraint(bstrConstraint, *pvarValue); SysFreeString(bstrConstraint); return hres; } 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; } inline DWORD WaitForThreadCompletion(HANDLE hThread) { if (INVALID_HANDLE_VALUE == hThread || NULL == hThread) return WAIT_OBJECT_0; return WaitForSingleObject(hThread, CBX_SNDMSG_TIMEOUT + 3000); } 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, (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, 0L); 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, LINKWINDOW_CLASS, NULL, dwStyle, pt.x, pt.y, 400, 18, hwndParent, (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); ::MapWindowPoints(HWND_DESKTOP, hwnd, (LPPOINT)&rcLink, POINTSPERRECT); rcLink.left = left; rcLink.right = right; int cyIdeal = (int)::SendMessage(hwndLink, LWM_GETIDEALHEIGHT, RECTWIDTH(&rcLink), 0L); 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 // BUGBUG: (this code was ripped off from shlwapi!util.cpp... #define SZ_REGKEY_AUTOCOMPLETE_TAB TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoComplete") #define SZ_REGVALUE_AUTOCOMPLETE_TAB TEXT("Always Use Tab") #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, SZ_REGVALUE_AUTOCOMPLETE_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( IN HWND hwndEdit, IAutoComplete2** ppAutoComplete, LPCTSTR pszSubKey, IStringMru** ppStringMru) { ASSERT(ppAutoComplete); ASSERT(ppStringMru); *ppAutoComplete = NULL; *ppStringMru = NULL; HRESULT hr = CoCreateInstance(CLSID_AutoComplete, NULL, CLSCTX_INPROC_SERVER, IID_IAutoComplete2, (void**)ppAutoComplete); if (SUCCEEDED(hr)) { TCHAR szKey[MAX_PATH]; if (CFileSearchBand::MakeBandSubKey(pszSubKey, szKey, ARRAYSIZE(szKey)) > 0) { hr = CStringMru::CreateInstance(HKEY_CURRENT_USER, szKey, AUTOSUGGEST_MRUCOUNT, FALSE, IID_IStringMru, (void**)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 != NULL) { UINT cch = GetWindowTextLength(hwnd); if (cch > 0) { LPOLESTR pwszText = new OLECHAR[cch + 1]; if (NULL == pwszText) return E_OUTOFMEMORY; if (GetWindowTextW(hwnd, pwszText, cch + 1) > 0) { hr = pmru->Add(pwszText); } delete[] pwszText; } else hr = S_FALSE; } return hr; } HRESULT _TestAutoCompleteDropDownState(IAutoComplete2* pac2, DWORD dwTest) { IAutoCompleteDropDown* pacdd; HRESULT hr = pac2->QueryInterface(IID_IAutoCompleteDropDown, (void**)&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 hwndOwner) { return ::HtmlHelp(hwndOwner, INDEXSERVICE_HELPFILE, HH_DISPLAY_TOPIC, (DWORD_PTR)INDEXSERVICE_HELPTOPIC); } // CSubDlg impl LRESULT CSubDlg::OnNcCalcsize(UINT, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { InflateRect((LPRECT)lParam, -SUBDLG_BORDERWIDTH, -SUBDLG_BORDERWIDTH); return 0L; } 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 0L; } 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&) { HDC hdc; PAINTSTRUCT ps; // Just going to call BeginPaint and EndPaint. All // painting done in WM_ERASEBKGND handler to avoid flicker. if ((hdc = BeginPaint(_hwnd, &ps)) != NULL) { EndPaint(_hwnd, &ps); } return 0L; } 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 0L; } LRESULT CSubDlg::OnEraseBkgnd(UINT, WPARAM wParam, LPARAM, BOOL&) { _PaintDlg(Hwnd(), _pfsb->GetMetrics(), (HDC)wParam); ValidateRect(Hwnd(), NULL); return TRUE; } STDMETHODIMP CSubDlg::TranslateAccelerator(LPMSG lpmsg) { if (_pfsb->IsKeyboardScroll(lpmsg)) return S_OK; return _pfsb->IsDlgMessage(Hwnd(), lpmsg); } LRESULT CSubDlg::OnChildSetFocusCmd( WORD wNotifyCode, WORD wID, HWND hwndCtl, BOOL& bHandled) { _EnsureVisible(_hwnd, hwndCtl, _pfsb); bHandled = FALSE; return 0L; } LRESULT CSubDlg::OnChildSetFocusNotify(int, LPNMHDR pnmh, BOOL& bHandled) { _EnsureVisible(_hwnd, pnmh->hwndFrom, _pfsb); bHandled = FALSE; return 0L; } LRESULT CSubDlg::OnChildKillFocusCmd(WORD, WORD, HWND hwndCtl, BOOL&) { if (_pBandDlg) _pBandDlg->RememberFocus(hwndCtl); return 0L; } LRESULT CSubDlg::OnChildKillFocusNotify(int, LPNMHDR pnmh, BOOL&) { if (_pBandDlg) _pBandDlg->RememberFocus(pnmh->hwndFrom); return 0L; } LRESULT CSubDlg::OnComboExEndEdit(int, LPNMHDR pnmh, BOOL&) { if (CBENF_KILLFOCUS == ((NMCBEENDEDIT*)pnmh)->iWhy) { if (_pBandDlg) _pBandDlg->RememberFocus(pnmh->hwndFrom); } return 0L; } // 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, 0L); SendDlgItemMessage(IDC_RECENT_DAYS, EM_LIMITTEXT, RECENTDAYSRANGE_HIGH_LEN, 0L); 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)); 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; ASSERT(var.ulVal); HRESULT hr = _AddConstraint(pSrchCmd, GetConstraintName(FSBC_WHICHDATE), &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, GetConstraintName(FSBC_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, GetConstraintName(FSBC_DATENDAYS), &var); } else if (IsDlgButtonChecked(IDC_USE_DATE_RANGE)) { SYSTEMTIME stBegin, stEnd; LRESULT lRetBegin, lRetEnd; var.vt = VT_DATE; lRetBegin = SendDlgItemMessage(IDC_DATERANGE_BEGIN, DTM_GETSYSTEMTIME, 0L, (LPARAM)&stBegin); lRetEnd = SendDlgItemMessage(IDC_DATERANGE_END, DTM_GETSYSTEMTIME, 0L, (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, GetConstraintName(FSBC_DATEGE), &var); #ifdef DEBUG ASSERT(SystemTimeToFileTime(&stEnd, &ft)); #endif SystemTimeToVariantTime(&stEnd, &var.date); hr = _AddConstraint(pSrchCmd, GetConstraintName(FSBC_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(FSBC_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(FSBC_DATENMONTHS, bstrName)) { ASSERT(VT_I4 == pValue->vt); bUseMonths = TRUE; _SetWindowValue(m_hWnd, IDC_RECENT_MONTHS, pValue); hr = S_OK; } else if (IsConstraintName(FSBC_DATENDAYS, bstrName)) { ASSERT(VT_I4 == pValue->vt); bUseDays = TRUE; _SetWindowValue(m_hWnd, IDC_RECENT_DAYS, pValue); hr = S_OK; } else if (IsConstraintName(FSBC_DATEGE, bstrName)) { ASSERT(VT_DATE == pValue->vt); bUseRange = TRUE; SYSTEMTIME st; VariantTimeToSystemTime(pValue->date, &st); SendDlgItemMessage(IDC_DATERANGE_BEGIN, DTM_SETSYSTEMTIME, 0L, (LPARAM)&st); hr = S_OK; } else if (IsConstraintName(FSBC_DATELE, bstrName)) { ASSERT(VT_DATE == pValue->vt); bUseRange = TRUE; SYSTEMTIME st; VariantTimeToSystemTime(pValue->date, &st); SendDlgItemMessage(IDC_DATERANGE_END, DTM_SETSYSTEMTIME, 0L, (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, 0L); 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); ::MapWindowPoints(HWND_DESKTOP, m_hWnd, (LPPOINT)&rc, POINTSPERRECT); 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 0L; } LRESULT CDateDlg::OnMonthDaySpin(int nIDSpin, LPNMHDR pnmh, BOOL& bHandled) { LPNMUPDOWN pud = (LPNMUPDOWN)pnmh; pud->iDelta *= -1; // increments of 1 month/day return 0L; } LRESULT CDateDlg::OnBtnClick(WORD nCode, WORD nID, HWND hwndCtl, BOOL&) { EnableControls(); return 0L; } 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 0L; } 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 0L; } 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 999999 #define FILESIZERANGE_HIGH_LEN 6 // 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, 0L); _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_UI4; var.ulVal = (ULONG)SendDlgItemMessage(IDC_FILESIZE_SPIN, UDM_GETPOS32, 0, (LPARAM)&bErr); if (!bErr) { var.ulVal *= 1024; // KB to bytes. LPCWSTR pwszConstraint = (IDS_FSEARCH_SIZE_GREATEREQUAL == nIDString) ? GetConstraintName(FSBC_SIZEGE) : (IDS_FSEARCH_SIZE_LESSEREQUAL == nIDString) ? GetConstraintName(FSBC_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(FSBC_SIZEGE, bstrName)) { nID = IDS_FSEARCH_SIZE_GREATEREQUAL; hr = S_OK; } else if (IsConstraintName(FSBC_SIZELE, bstrName)) { nID = IDS_FSEARCH_SIZE_LESSEREQUAL; hr = S_OK; } if (S_OK == hr) { ASSERT(VT_UI4 == pValue->vt); ULONG ulSize = pValue->ulVal / 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, 0L); SetDlgItemInt(IDC_FILESIZE, 0, FALSE); } LRESULT CSizeDlg::OnSizeSpin(int nIDSpin, LPNMHDR pnmh, BOOL& bHandled) { LPNMUPDOWN pud = (LPNMUPDOWN)pnmh; pud->iDelta *= -10; // increments of 10KB return 0L; } LRESULT CSizeDlg::OnSizeKillFocus(WORD nCode, WORD nID, HWND hwndCtl, BOOL&) { _EnforceNumericEditRange(m_hWnd, IDC_FILESIZE, IDC_FILESIZE_SPIN, FILESIZERANGE_LOW, FILESIZERANGE_HIGH); return 0L; } // CTypeDlg impl CTypeDlg::CTypeDlg(CFileSearchBand* pfsb) : CSubDlg(pfsb), _hFileAssocThread(INVALID_HANDLE_VALUE) { *_szRestoredExt = 0; } CTypeDlg::~CTypeDlg() { // Wait for thread completion DWORD dwWait = WaitForThreadCompletion(_hFileAssocThread); ASSERT(WAIT_TIMEOUT != dwWait); if (WAIT_TIMEOUT == dwWait) { ASSERT(FALSE); // file types combo population thread is hung. } CloseHandle(_hFileAssocThread); } 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); // Launch thread to populate the file types combo. _threadState.hwndCtl = GetDlgItem(IDC_FILE_TYPE); _threadState.pvParam = this; _threadState.fComplete = FALSE; _threadState.fCancel = FALSE; DWORD dwThreadID; _hFileAssocThread = CreateThread(NULL, 0L, FileAssocThreadProc, &_threadState, 0, &dwThreadID); return TRUE; // Let the system set the focus } STDMETHODIMP CTypeDlg::AddConstraints(ISearchCommandExt* pSrchCmd) { LPTSTR pszText; HWND hwndCombo = GetDlgItem(IDC_FILE_TYPE); ASSERT(hwndCombo); HRESULT hr = S_FALSE; if (_GetFileAssocComboSelItemText(hwndCombo, &pszText) >= 0 && pszText) { VARIANT var; if (*pszText && SUCCEEDED(_T2BstrVariant(pszText, &var)) && SUCCEEDED(_AddConstraint(pSrchCmd, GetConstraintName(FSBC_FILETYPE), &var))) hr = S_OK; 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(FSBC_FILETYPE, bstrName)) { ASSERT(VT_BSTR == pValue->vt); USES_CONVERSION; lstrcpyn(_szRestoredExt, W2T(pValue->bstrVal), ARRAYSIZE(_szRestoredExt)); INT_PTR i = _FindExtension(GetDlgItem(IDC_FILE_TYPE), _szRestoredExt); if (i != CB_ERR) { SendDlgItemMessage(IDC_FILE_TYPE, CB_SETCURSEL, i, 0L); *_szRestoredExt = 0; } return S_OK; } return E_FAIL; } INT_PTR CTypeDlg::_FindExtension(HWND hwndCombo, TCHAR* pszExt) { INT_PTR i, cnt = ::SendMessage(hwndCombo, CB_GETCOUNT, 0, 0L); 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, 0L); 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, 0L); i < cnt; i++) { if (FILEASSOCIATIONSID_ALLFILETYPES == _GetComboData(hwndCombo, i)) { ::SendMessage(hwndCombo, CB_SETCURSEL, i, 0L); break; } } *_szRestoredExt = 0; } LRESULT CTypeDlg::OnFileTypeDeleteItem(int idCtrl, LPNMHDR 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); ::MapWindowPoints(HWND_DESKTOP, m_hWnd, (LPPOINT)&rc, POINTSPERRECT); rc.right = pts.x - _pfsb->GetMetrics().CtlMarginX(); ::SetWindowPos(hwndCtl, NULL, 0, 0, RECTWIDTH(&rc), RECTHEIGHT(&rc), SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); return 0L; } DWORD CTypeDlg::FileAssocThreadProc(void* pvParam) { PFSEARCHTHREADSTATE pState = (PFSEARCHTHREADSTATE)pvParam; HRESULT hrOleInit = SHCoInitialize(); if (_PopulateFileAssocCombo(pState->hwndCtl, AddItemNotify, (LPARAM)pvParam) != E_ABORT) { ::PostMessage(::GetParent(pState->hwndCtl), WMU_COMBOPOPULATIONCOMPLETE, (WPARAM)pState->hwndCtl, 0L); } pState->fComplete = TRUE; SHCoUninitialize(hrOleInit); return 0; } STDMETHODIMP CTypeDlg::AddItemNotify(ULONG fAction, PCBXITEM pItem, LPARAM lParam) { PFSEARCHTHREADSTATE pState = (PFSEARCHTHREADSTATE)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, 0L); *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, 0L)) ::SendMessage(pState->hwndCtl, CB_SETCURSEL, pItem->iItem, 0L); } } 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, 0L); *_szRestoredExt = 0; } } return 0L; } LRESULT CTypeDlg::OnDestroy(UINT, WPARAM, LPARAM, BOOL& bHandled) { _threadState.fCancel = TRUE; bHandled = FALSE; return 0L; } void CTypeDlg::OnWinIniChange() { SendDlgItemMessage(IDC_FILE_TYPE, CB_SETDROPPEDWIDTH, _PixelsForDbu(m_hWnd, MIN_FILEASSOCLIST_WIDTH, TRUE), 0); } // CAdvancedDlg impl LRESULT CAdvancedDlg::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { _Attach(m_hWnd); Clear(); return TRUE; // Let the system set the focus } STDMETHODIMP CAdvancedDlg::AddConstraints(ISearchCommandExt* pSrchCmd) { VARIANT var; VariantInit(&var); var.vt = VT_BOOL; HRESULT hr; var.boolVal = IsDlgButtonChecked(IDC_USE_SUBFOLDERS) ? 1 : 0; hr = _AddConstraint(pSrchCmd, GetConstraintName(FSBC_SEARCHSUBFOLDERS), &var); var.boolVal = IsDlgButtonChecked(IDC_USE_CASE) ? 1 : 0; hr = _AddConstraint(pSrchCmd, GetConstraintName(FSBC_CASE), &var); #ifdef WINNT var.boolVal = IsDlgButtonChecked(IDC_USE_SLOW_FILES) ? 1 : 0; hr = _AddConstraint(pSrchCmd, GetConstraintName(FSBC_SLOWFILES), &var); #endif // WINNT 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(FSBC_SEARCHSUBFOLDERS, 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(FSBC_CASE, bstrName)) { ASSERT(VT_BOOL == pValue->vt || VT_I4 == pValue->vt); CheckDlgButton(IDC_USE_CASE, pValue->lVal); return pValue->lVal ? S_OK : S_FALSE; } #ifdef WINNT if (IsConstraintName(FSBC_SLOWFILES, bstrName)) { ASSERT(VT_BOOL == pValue->vt || VT_I4 == pValue->vt); CheckDlgButton(IDC_USE_SLOW_FILES, pValue->lVal); return pValue->lVal ? S_OK : S_FALSE; } #endif // WINNT return E_FAIL; } void CAdvancedDlg::Clear() { CheckDlgButton(IDC_USE_SUBFOLDERS, 1); CheckDlgButton(IDC_USE_CASE, 0); #ifdef WINNT CheckDlgButton(IDC_USE_SLOW_FILES, 0); #endif // WINNT } // COptionsDlg impl #ifdef WINNT #define OPTIONSDLG_BOTTOMMOST IDC_USE_SLOW_FILES #else #define OPTIONSDLG_BOTTOMMOST IDC_USE_CASE #endif COptionsDlg::COptionsDlg(CFileSearchBand* pfsb) : CSubDlg(pfsb), _dlgDate(pfsb), _dlgSize(pfsb), _dlgType(pfsb), _dlgAdvanced(pfsb), _nCIStatusText(0) { 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]; ZeroMemory(rc, sizeof(rc)); 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 ::MapWindowPoints(HWND_DESKTOP, m_hWnd, (LPPOINT)(&rc[i]), POINTSPERRECT); } 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); #ifdef WINNT // Create index server link window POINT pt; ZeroMemory(&pt, sizeof(pt)); HWND hwndCI = _CreateLinkWindow(m_hWnd, IDC_INDEX_SERVER, pt, IDS_FSEARCH_CI_DISABLED_LINK); UpdateSearchCmdStateUI(); #endif WINNT // Layout controls LayoutControls(); return TRUE; } void COptionsDlg::OnWinIniChange() { CSubDlg::OnWinIniChange(); for (int i = 0; i < SUBDLG_Count; i++) _subdlgs[i].pDlg->OnWinIniChange(); } BOOL _SaveCheck(HWND hwnd, UINT nIDCheck, HKEY hkey, LPCTSTR pszValue) { DWORD dwData = IsDlgButtonChecked(hwnd, nIDCheck); return ERROR_SUCCESS == RegSetValueEx(hkey, pszValue, 0, REG_DWORD, (LPBYTE)&dwData, sizeof(dwData)); } BOOL _LoadCheck(HWND hwnd, UINT nIDCheck, HKEY hkey, LPCTSTR pszValue) { DWORD dwData = IsDlgButtonChecked(hwnd, nIDCheck); DWORD cbData = sizeof(dwData); DWORD dwType; if (ERROR_SUCCESS == RegQueryValueEx(hkey, pszValue, 0, &dwType, (LPBYTE)&dwData, &cbData)) { CheckDlgButton(hwnd, nIDCheck, dwData); return TRUE; } return FALSE; } void COptionsDlg::LoadSaveUIState(UINT nIDCtl, BOOL bSave) { #ifdef _LOADSAVE_SUBDLG_UI__ if (0 == nIDCtl) // do all. { LoadSaveUIState(IDC_USE_DATE, bSave); LoadSaveUIState(IDC_USE_TYPE, bSave); LoadSaveUIState(IDC_USE_SIZE, bSave); LoadSaveUIState(IDC_USE_ADVANCED, bSave); LayoutControls(); SizeToFit(FALSE); return; } HKEY hkey; LPCTSTR pszVal = NULL; switch (nIDCtl) { case IDC_USE_DATE: pszVal = TEXT("UseDate"); break; case IDC_USE_TYPE: pszVal = TEXT("UseType"); break; case IDC_USE_SIZE: pszVal = TEXT("UseSize"); break; case IDC_USE_ADVANCED: pszVal = TEXT("UseAdvanced"); break; } ASSERT(pszVal != NULL); // invalid ctl ID! if (NULL == pszVal || NULL == (hkey = _pfsb->GetBandRegKey(bSave))) return; if (bSave) _SaveCheck(m_hWnd, nIDCtl, hkey, pszVal); else _LoadCheck(m_hWnd, nIDCtl, hkey, pszVal); RegCloseKey(hkey); #endif _LOADSAVE_SUBDLG_UI__ } 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 0L; } void COptionsDlg::LayoutControls(int cx, int cy) { if (cx < 0 || cy < 0) { RECT rc; GetClientRect(&rc); cx = RECTWIDTH(&rc); cy = RECTHEIGHT(&rc); } HDWP hdwp; if ((hdwp = BeginDeferWindowPos(1 + (SUBDLG_Count * 2))) != NULL) { CMetrics& metrics = _pfsb->GetMetrics(); POINT ptOrigin = metrics.ExpandOrigin(); // For each checkbox and associated subdialog... for (int i = 0; i < SUBDLG_Count; 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); } #ifdef WINNT _LayoutLinkWindow(m_hWnd, metrics.CtlMarginX(), cx - metrics.CtlMarginX(), metrics.TightMarginY(), ptOrigin.y, IDC_INDEX_SERVER); #endif WINNT 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; } } } LONG COptionsDlg::QueryHeight(LONG cx /* proposed width */, LONG cy /* proposed height */) { HWND hwndBottommost = GetDlgItem(IDC_INDEX_SERVER); RECT rcThis, rcBottommost; // Retrieve the current height of the bottommost link window. GetWindowRect(&rcThis); ::GetWindowRect(hwndBottommost, &rcBottommost); ::MapWindowPoints(HWND_DESKTOP, GetParent(), (LPPOINT)&rcThis, POINTSPERRECT); ::MapWindowPoints(HWND_DESKTOP, GetParent(), (LPPOINT)&rcBottommost, POINTSPERRECT); // 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)SendDlgItemMessage(IDC_INDEX_SERVER, LWM_GETIDEALHEIGHT, cx - (_pfsb->GetMetrics().CtlMarginX() * 2), 0L); if (cyBottommost > 0 && cyBottommost != RECTHEIGHT(&rcBottommost)) rcThis.bottom = rcBottommost.top + cyBottommost + _pfsb->GetMetrics().TightMarginY(); return RECTHEIGHT(&rcThis); } BOOL COptionsDlg::GetMinSize(LPSIZE pSize) const { pSize->cx = pSize->cy = 0; HWND hwndBottom = GetDlgItem(IDC_INDEX_SERVER); if (!IsWindow(hwndBottom)) { hwndBottom = IsDlgButtonChecked(IDC_USE_ADVANCED) ? _dlgAdvanced.GetDlgItem(OPTIONSDLG_BOTTOMMOST) : GetDlgItem(IDC_USE_ADVANCED); } if (!IsWindow(hwndBottom)) return FALSE; RECT rcBottom; ::GetWindowRect(hwndBottom, &rcBottom); ::MapWindowPoints(HWND_DESKTOP, m_hWnd, (LPPOINT)&rcBottom, POINTSPERRECT); pSize->cx = 0; pSize->cy = rcBottom.bottom; return TRUE; } void COptionsDlg::UpdateSearchCmdStateUI(DISPID dispid) { #ifdef WINNT BOOL fCiRunning = FALSE, fCiIndexed = FALSE, fCiPermission = FALSE; UINT nStatusText = IDS_FSEARCH_CI_DISABLED_LINK; HRESULT hr = 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; } 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); } #endif WINNT } STDMETHODIMP COptionsDlg::AddConstraints(ISearchCommandExt* pSrchCmd) { HRESULT hrRet = S_OK; // have subdialogs add their constraints for (int i = 0; i < SUBDLG_Count; 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 < SUBDLG_Count; 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(LPMSG lpmsg) { if (S_OK == CSubDlg::TranslateAccelerator(lpmsg)) return S_OK; // Query subdialogs if (_dlgDate.IsChild(lpmsg->hwnd) && S_OK == _dlgDate.TranslateAccelerator(lpmsg)) return S_OK; if (_dlgType.IsChild(lpmsg->hwnd) && S_OK == _dlgType.TranslateAccelerator(lpmsg)) return S_OK; if (_dlgSize.IsChild(lpmsg->hwnd) && S_OK == _dlgSize.TranslateAccelerator(lpmsg)) return S_OK; if (_dlgAdvanced.IsChild(lpmsg->hwnd) && S_OK == _dlgAdvanced.TranslateAccelerator(lpmsg)) return S_OK; return _pfsb->IsDlgMessage(Hwnd(), lpmsg); } BOOL COptionsDlg::Validate() { // have subdialogs do validatation for (int i = 0; i < SUBDLG_Count; 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 < SUBDLG_Count; 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 < SUBDLG_Count && !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 0L; } 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, 0L); } LRESULT COptionsDlg::OnIndexServerClick(int idCtl, LPNMHDR 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, 0L); } } else { // No permission? display CI help. _IndexServiceHelp(NULL); } return 0L; } // CBandDlg impl CBandDlg::CBandDlg(CFileSearchBand* pfsb) : _pfsb(pfsb), _hwnd(NULL), _hwndLastFocus(NULL) { VariantInit(&_varScope0); VariantInit(&_varQueryFile0); } CBandDlg::~CBandDlg() { VariantClear(&_varScope0); VariantClear(&_varQueryFile0); } STDMETHODIMP CBandDlg::TranslateAccelerator(LPMSG lpmsg) { if (WM_KEYDOWN == lpmsg->message || WM_KEYUP == lpmsg->message) { IAutoComplete2* pac2; if (GetAutoCompleteObjectForWindow(lpmsg->hwnd, &pac2)) { if (S_OK == _TestAutoCompleteDropDownState(pac2, ACDD_VISIBLE)) { TranslateMessage(lpmsg); DispatchMessage(lpmsg); pac2->Release(); return S_OK; } pac2->Release(); } } // Check for Ctrl+Nav Key: if (_pfsb->IsKeyboardScroll(lpmsg)) 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 0L; } LRESULT CBandDlg::OnChildSetFocusNotify(int, LPNMHDR pnmh, BOOL&) { _EnsureVisible(_hwnd, pnmh->hwndFrom, _pfsb); return 0L; } LRESULT CBandDlg::OnChildKillFocusCmd(WORD, WORD, HWND hwndCtl, BOOL&) { _hwndLastFocus = hwndCtl; return 0L; } LRESULT CBandDlg::OnChildKillFocusNotify(int, LPNMHDR pnmh, BOOL&) { _hwndLastFocus = pnmh->hwndFrom; return 0L; } LRESULT CBandDlg::OnComboExEndEdit(int, LPNMHDR pnmh, BOOL&) { if (CBEN_ENDEDIT == pnmh->code) { if (CBENF_KILLFOCUS == ((NMCBEENDEDIT*)pnmh)->iWhy) _hwndLastFocus = pnmh->hwndFrom; } return 0L; } 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 0L; } 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, LPSIZE 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&) { HDC hdc; PAINTSTRUCT ps; // Just going to call BeginPaint and EndPaint. All // painting done in WM_ERASEBKGND handler to avoid flicker. if ((hdc = BeginPaint(_hwnd, &ps)) != NULL) { EndPaint(_hwnd, &ps); } return 0L; } 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) { HWND hwndCtl; RECT rcUpdate; GetClientRect(_hwnd, &rcUpdate); if ((hwndCtl = GetDlgItem(_hwnd, GetCaptionDivID())) != NULL) { RECT rc; GetWindowRect(hwndCtl, &rc); MapWindowPoints(HWND_DESKTOP, _hwnd, (LPPOINT)&rc, POINTSPERRECT); rcUpdate.bottom = rc.bottom; OffsetRect(&rcUpdate, 0, cyOffset); InvalidateRect(_hwnd, &rcUpdate, TRUE); InvalidateRect(hwndCtl, NULL, TRUE); UpdateWindow(hwndCtl); } if ((hwndCtl = GetDlgItem(_hwnd, GetIconID())) != NULL) { InvalidateRect(hwndCtl, NULL, TRUE); UpdateWindow(hwndCtl); } if ((hwndCtl = GetDlgItem(_hwnd, GetCaptionID())) != NULL) { 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, 0L); 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); MapWindowPoints(HWND_DESKTOP, _hwnd, (LPPOINT)&rcIcon, POINTSPERRECT); MapWindowPoints(HWND_DESKTOP, _hwnd, (LPPOINT)&rcCaption, POINTSPERRECT); 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); MapWindowPoints(HWND_DESKTOP, _hwnd, (LPPOINT)&rcCaption, POINTSPERRECT); 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 0L; } 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 0L; } // Invoked when a client calls IFileSearchBand::SetSearchParameters() HRESULT CBandDlg::SetScope(IN VARIANT* pvarScope, BOOL bTrack) { VariantClear(&_varScope0); // cache the scope if (pvarScope) { VariantCopy(&_varScope0, pvarScope); VariantClear(pvarScope); } return S_OK; } HRESULT CBandDlg::GetScope(OUT VARIANT* pvarScope) { // retrieve the scope if (!pvarScope) return E_INVALIDARG; VariantCopy(pvarScope, &_varScope0); return VT_EMPTY == _varScope0.vt ? S_FALSE : S_OK; } HRESULT CBandDlg::SetQueryFile(IN VARIANT* pvarFile) { // cache the filename of the query to restore. VariantClear(&_varQueryFile0); if (pvarFile) VariantCopy(&_varQueryFile0, pvarFile); return S_OK; } HRESULT CBandDlg::GetQueryFile(OUT VARIANT* pvarFile) { // retrieve the filename of the query to restore. if (!pvarFile) return E_INVALIDARG; VariantCopy(pvarFile, &_varQueryFile0); return VT_EMPTY == _varQueryFile0.vt ? S_FALSE : S_OK; } // 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), _hNamespaceThread(INVALID_HANDLE_VALUE), _bScoped(FALSE), _fTrackScope(TRACKSCOPE_SPECIFIC), _fDisplayOptions(FALSE), _fDebuted(FALSE), _dwWarningFlags(DFW_DEFAULT), _dwRunOnceWarningFlags(DFW_DEFAULT), _fAdHocNamespace(FALSE), _pacGrepText(NULL), _pmruGrepText(NULL), _pacFileSpec(NULL), _pmruFileSpec(NULL) { // initialized scopes are blank *_szInitialPath = *_szInitialNamespace = *_szCurrentPath = *_szLocalDrives = 0; } CFindFilesDlg::~CFindFilesDlg() { ATOMICRELEASE(_pacGrepText); ATOMICRELEASE(_pmruGrepText); ATOMICRELEASE(_pacFileSpec); ATOMICRELEASE(_pmruFileSpec); // Wait for thread completion DWORD dwWait = WaitForThreadCompletion(_hNamespaceThread); ASSERT(WAIT_TIMEOUT != dwWait); if (WAIT_TIMEOUT == dwWait) { ASSERT(FALSE); // namespace combo population thread is hung. } CloseHandle(_hNamespaceThread); } // Scope to a default namespace. BOOL CFindFilesDlg::SetDefaultScope() { USES_CONVERSION; BOOL bScoped = FALSE; ASSERT(_pfsb->BandSite()); // If we've already assigned a scope, bail early if (_bScoped) return TRUE; // Try establiblishing the preassigned (_szInitialXXX) scope: if (!(bScoped = _SetPreassignedScope())) // Try setting scope to the current shell folder of the active view... if (!(bScoped = _SetFolderScope())) // set it to the hard-coded shell default folder bScoped = _SetLocalDefaultScope(); return bScoped; } // Assignes the namespace control to the preassigned scope saved in // _szInitialNamespace/_szInitialPath BOOL CFindFilesDlg::_SetPreassignedScope() { BOOL bScoped = FALSE; if (*_szInitialNamespace || *_szInitialPath) bScoped = AssignNamespace(_szInitialNamespace, _szInitialPath, FALSE); return bScoped; } // Scope to the namespace of the current shell folder view BOOL CFindFilesDlg::_SetFolderScope() { USES_CONVERSION; BOOL bScoped = FALSE; ASSERT(_pfsb->BandSite()); if (SUCCEEDED(_GetCurrentPathAndNamespace(_pfsb->BandSite(), _szInitialPath, ARRAYSIZE(_szInitialPath), _szInitialNamespace, ARRAYSIZE(_szInitialNamespace)))) { if (*_szInitialNamespace || *_szInitialPath) { // if we're tracking the scope loosely... if ((TRACKSCOPE_GENERAL == _fTrackScope) && _IsPathLocalHarddrive(_szInitialPath)) { // scope up to Local Hard Drives on a local folder *_szInitialNamespace = *_szInitialPath = 0; bScoped = _SetLocalDefaultScope(); } else if (_threadState.fComplete /* finished populating namespace combo */) { bScoped = AssignNamespace(_szInitialNamespace, _szInitialPath, FALSE); } } } return bScoped; } // Scope to the hard-coded shell default namespace. BOOL CFindFilesDlg::_SetLocalDefaultScope() { BOOL bScoped = FALSE; // Initialize fallback initial namespace // Try Local Hard Drives if (*_szLocalDrives != 0) bScoped = AssignNamespace(_szLocalDrives, NULL, FALSE); // 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, NULL); } 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, SIZECHARS(_szInitialPath), NULL); SHGetNameAndFlags(pidlSearch, SHGDN_NORMAL, _szInitialNamespace, SIZECHARS(_szInitialNamespace), NULL); ILFree(pidlSearch); // Did we get one? if (*_szInitialNamespace || *_szInitialPath) { if (_bScoped) { // If we've already scoped, update the namespace combo. // Track if succeed and requested. if (AssignNamespace(_szInitialNamespace, _szInitialPath, 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. EVAL(DivWindow_RegisterClass()); EVAL(LinkWindow_RegisterClass()); EVAL(GroupButton_RegisterClass()); // Initialize some metrics CMetrics& metrics = _pfsb->GetMetrics(); RECT rc; int cxBtn; _pfsb->GetMetrics().Init(m_hWnd); ::GetWindowRect(GetDlgItem(IDC_FILESPEC), &rc); ::MapWindowPoints(HWND_DESKTOP, m_hWnd, (LPPOINT)&rc, POINTSPERRECT); metrics.ExpandOrigin().x = rc.left; // Position start, stop buttons. // BUGBUG: this should go in LayoutControls(). ::GetWindowRect(GetDlgItem(IDC_SEARCH_START), &rc); ::MapWindowPoints(HWND_DESKTOP, m_hWnd, (LPPOINT)&rc, POINTSPERRECT); if ((cxBtn = _GetResourceMetric(m_hWnd, IDS_FSEARCH_STARTSTOPWIDTH, TRUE)) > 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, 0L); SendDlgItemMessage(IDC_GREPTEXT, EM_LIMITTEXT, MAX_EDIT, 0L); HWND hwndCombo = GetDlgItem(IDC_NAMESPACE); HIMAGELIST hil = _GetSystemImageListSmallIcons(); ::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); // Launch thread to populate the namespaces combo. _threadState.hwndCtl = GetDlgItem(IDC_NAMESPACE); _threadState.pvParam = this; _threadState.fComplete = FALSE; _threadState.fCancel = FALSE; DWORD dwThreadID; _hNamespaceThread = CreateThread(NULL, 0L, NamespaceThreadProc, &_threadState, 0, &dwThreadID); // Layout our subdialogs and update state representation... LayoutControls(); UpdateSearchCmdStateUI(); SetTimer(UISTATETIMER, UISTATETIMER_DELAY, NULL); 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, 0L); // 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), 0L); _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 0L; } BOOL CFindFilesDlg::Validate() { TCHAR szPath[MAX_URL_STRING], szTest[128]; UINT nErrStr; if (S_OK == _GetTargetNamespace(szPath, ARRAYSIZE(szPath), NULL, &nErrStr)) { EVAL(LoadString(HINST_THISDLL, IDS_FSEARCH_HTTP_SUBSTR, szTest, ARRAYSIZE(szTest))); if (StrStrI(szPath, szTest) != NULL) { ShellMessageBox(HINST_THISDLL, _pfsb->m_hWnd, MAKEINTRESOURCE(IDS_FSEARCH_HTTP_NOT_SUPPORTED), NULL, MB_OK | MB_ICONASTERISK); ::SetFocus(GetDlgItem(IDC_NAMESPACE)); return FALSE; } EVAL(LoadString(HINST_THISDLL, IDS_FSEARCH_FTP_SUBSTR, szTest, ARRAYSIZE(szTest))); if (StrStrI(szPath, szTest) != NULL) { ShellMessageBox(HINST_THISDLL, _pfsb->m_hWnd, MAKEINTRESOURCE(IDS_FSEARCH_FTP_NOT_SUPPORTED), NULL, MB_OK | MB_ICONASTERISK); ::SetFocus(GetDlgItem(IDC_NAMESPACE)); return FALSE; } // Handle selection of "Browse..." item EVAL(LoadString(HINST_THISDLL, IDS_SNS_BROWSER_FOR_DIR, szTest, ARRAYSIZE(szTest))); if (0 == StrCmp(szPath, szTest)) // "Browse..." { _BrowseAndAssignNamespace(); if (_GetTargetNamespace(szPath, ARRAYSIZE(szPath), NULL, &nErrStr) != S_OK) { if (nErrStr != 0) { ShellMessageBox(HINST_THISDLL, _pfsb->m_hWnd, MAKEINTRESOURCE(nErrStr), NULL, MB_OK | MB_ICONASTERISK); ::SetFocus(GetDlgItem(IDC_NAMESPACE)); } } return FALSE; } } else if (nErrStr != 0) { ShellMessageBox(HINST_THISDLL, _pfsb->m_hWnd, MAKEINTRESOURCE(nErrStr), NULL, MB_OK | MB_ICONASTERISK); ::SetFocus(GetDlgItem(IDC_NAMESPACE)); return FALSE; } if (!_dlgOptions.Validate()) return FALSE; return TRUE; } STDMETHODIMP CFindFilesDlg::AddConstraints(ISearchCommandExt* pSrchCmd) { HRESULT hr; VARIANT var; BOOL bNamespace = FALSE; // mandatory constraint // Add location (namespace) constraint(s) TCHAR szPath[MAX_URL_STRING]; COMBOBOXEXITEM item; item.mask = CBEIF_INDENT; VariantInit(&var); // 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, MAX_URL_STRING) > 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(NULL, szPath, FALSE); } else { // just use the prefix for the file spec & the root for the location TCHAR szRoot[MAX_URL_STRING]; lstrcpy(szRoot, szPath); if (PathRemoveFileSpec(szRoot) && szRoot[0] != TEXT('\0')) { PathStripPath(szPath); ::SetDlgItemText(m_hWnd, IDC_FILESPEC, szPath); AssignNamespace(NULL, szRoot, FALSE); } } } } if (SUCCEEDED(_GetTargetNamespace(szPath, ARRAYSIZE(szPath), &item))) { // If this namespace is a namespace combo singleton, // add it as single constraint if (_IsPathSingleton(szPath)) { if (_IsPathList(szPath)) { // todo: Validate each path token in the list } else { if (FAILED((hr = _PathValidate(szPath, GetParent(), TRUE)))) { 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)); return hr; } } if (SUCCEEDED(_T2BstrVariant(szPath, &var))) { if (FAILED((hr = _AddConstraint(pSrchCmd, GetConstraintName(FSBC_LOOKIN), &var)))) VariantClear(&var); else bNamespace = TRUE; } else VariantInit(&var); } // Not a singleton, enumerate child items and add their paths instead else { int iIndent = item.iIndent; while (S_OK == _GetNextNamespace(szPath, ARRAYSIZE(szPath), &item) && item.iIndent > iIndent) { _BstrAppendToken(&var.bstrVal, TEXT(";"), szPath); } if (NULL != var.bstrVal) { var.vt = VT_BSTR; if (FAILED((hr = _AddConstraint(pSrchCmd, GetConstraintName(FSBC_LOOKIN), &var)))) VariantClear(&var); else bNamespace = TRUE; } } } if (!bNamespace) { return E_FAIL; } // Add 'Files Named' constraint if (S_OK == _GetWindowValue(m_hWnd, IDC_FILESPEC, VT_BSTR, &var)) { if (SUCCEEDED((hr = _AddConstraint(pSrchCmd, GetConstraintName(FSBC_NAMED), &var)))) _AddMruStringFromWindow(_pmruFileSpec, GetDlgItem(IDC_FILESPEC)); VariantClear(&var); } // Add 'Containing Text' constraint if (S_OK == _GetWindowValue(m_hWnd, IDC_GREPTEXT, VT_BSTR, &var)) { VARIANT varQuery; ULONG ulDialect; BOOL fCiQuery = IsCiQuery(&var, &varQuery, &ulDialect, FALSE); BOOL bCaseSensitive = _dlgOptions.IsAdvancedOptionChecked(IDC_USE_CASE); // Is this a CI query? if (fCiQuery) { if (bCaseSensitive) { // todo: show dialog to warn that case-sensitivity will not be honored for // tripolish searches. } if (SUCCEEDED((hr = _AddConstraint(pSrchCmd, GetConstraintName(FSBC_INDEXEDSEARCH), &varQuery)))) { _AddMruStringFromWindow(_pmruGrepText, GetDlgItem(IDC_GREPTEXT)); VariantClear(&var); var.vt = VT_UI4; var.ulVal = ulDialect; hr = _AddConstraint(pSrchCmd, GetConstraintName(FSBC_QUERYDIALECT), &var); } } else { // add to 'containing text' constraint if (SUCCEEDED((hr = _AddConstraint(pSrchCmd, GetConstraintName(FSBC_CONTAININGTEXT), &var)))) _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, GetConstraintName(FSBC_WARNINGFLAGS), &var); } else if (_dwWarningFlags != DFW_DEFAULT) { var.ulVal = _dwWarningFlags; var.vt = VT_UI4; hr = _AddConstraint(pSrchCmd, GetConstraintName(FSBC_WARNINGFLAGS), &var); } VariantClear(&var); hr = _dlgOptions.AddConstraints(pSrchCmd); return hr; } STDMETHODIMP CFindFilesDlg::RestoreConstraint(const BSTR bstrName, const VARIANT* pValue) { if (IsConstraintName(FSBC_NAMED, bstrName)) { _SetWindowValue(m_hWnd, IDC_FILESPEC, pValue); return S_FALSE; } if (IsConstraintName(FSBC_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'!'; StrCatW(pwszVal, pValue->bstrVal); } ::SetDlgItemTextW(m_hWnd, IDC_GREPTEXT, pwszVal); if (pwszVal) delete[] pwszVal; } return S_FALSE; } if (IsConstraintName(FSBC_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; if (NULL == (pSrchCmd = GetSearchCmd())) { ASSERT(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; VariantInit(&varValue); if (S_OK == (hr = pdfc->get_Value(&varValue))) { // If this is the 'lookin' value, cache the path. if (IsConstraintName(FSBC_LOOKIN, bstrName)) { if (VT_BSTR == varValue.vt && varValue.bstrVal != 0) { USES_CONVERSION; // Assign path and clear display name (which we don't know or care about). if (_bScoped) AssignNamespace(NULL, W2T(varValue.bstrVal), FALSE); else { lstrcpyn(_szInitialPath, W2T(varValue.bstrVal), ARRAYSIZE(_szInitialPath)); *_szInitialNamespace = 0; } } } else RestoreConstraint(bstrName, &varValue); VariantClear(&varValue); } } SysFreeString(bstrName); } pdfc->Release(); } LayoutControls(); _pfsb->UpdateLayout(); } STDMETHODIMP CFindFilesDlg::_GetTargetNamespace( OUT LPTSTR pszPath, IN int cchPath, IN OUT OPTIONAL COMBOBOXEXITEM* pItem, OUT OPTIONAL UINT* puErrStr) { HWND hwndNamespace = GetDlgItem(IDC_NAMESPACE); TCHAR pszTempPathBuffer[MAX_PATH]; LPTSTR pszTempPath = pszTempPathBuffer; ASSERT(IsWindow(hwndNamespace)); ASSERT(pszPath); if (pItem) pItem = NULL; if (puErrStr) *puErrStr = 0; *pszPath = 0; INT_PTR iSel = _GetNamespaceComboSelItemText( hwndNamespace, TRUE /*want path*/, pszTempPath, MAX_PATH); // Note: if iSel == -1, the user browsed to or typed in a path. // Eat whitespace for (; (TEXT('\0') != *pszTempPath) && (TEXT(' ') == *pszTempPath); pszTempPath = CharNext(pszTempPath)); StrCpyN(pszPath, pszTempPath, cchPath); if (0 == *pszPath) { if (puErrStr) *puErrStr = IDS_FSEARCH_EMPTYFOLDER; return E_FAIL; } if (NULL == pItem) return S_OK; // done. pItem->iItem = iSel; if (iSel < 0) return S_FALSE; // retrieval of COMBOBOXEXITEM data impossible // Fetch the item. if (::SendMessage(hwndNamespace, CBEM_GETITEM, iSel, (LPARAM)pItem)) return S_OK; return S_FALSE; } STDMETHODIMP CFindFilesDlg::_GetNextNamespace(OUT LPTSTR pszPath, IN int cchPath, IN OUT COMBOBOXEXITEM* pItem) { HRESULT hr = E_FAIL; HWND hwndNamespace = GetDlgItem(IDC_NAMESPACE); ASSERT(IsWindow(hwndNamespace)); ASSERT(pItem); ASSERT(pszPath); *pszPath = 0; INT_PTR iItem = pItem->iItem; pItem->iItem++; // increment item index if (CB_ERR != _GetNamespaceComboItemText(hwndNamespace, pItem->iItem, TRUE, pszPath, cchPath)) { if (::SendMessage(hwndNamespace, CBEM_GETITEM, pItem->iItem, (LPARAM)pItem)) { hr = S_OK; } } if (FAILED(hr)) pItem->iItem = iItem; // failed; revert item index return hr; } 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; if ((hkey = _pfsb->GetBandRegKey(bSave)) != NULL) { DWORD dwData; DWORD cbData; DWORD dwType; LPCTSTR pszVal = NULL; switch (nIDCtl) { case IDC_SEARCHLINK_OPTIONS: pszVal = TEXT("UseSearchOptions"); dwData = _fDisplayOptions; cbData = sizeof(dwData); dwType = REG_DWORD; break; case LSUIS_WARNING: pszVal = TEXT("Warnings"); dwData = _dwWarningFlags; cbData = sizeof(_dwWarningFlags); dwType = REG_DWORD; break; } if (bSave) RegSetValueEx(hkey, pszVal, 0, dwType, (LPBYTE)&dwData, cbData); else { if (ERROR_SUCCESS == RegQueryValueEx(hkey, pszVal, 0, &dwType, (LPBYTE)&dwData, &cbData)) { switch (nIDCtl) { case IDC_SEARCHLINK_OPTIONS: _fDisplayOptions = BOOLIFY(dwData); break; case LSUIS_WARNING: _dwWarningFlags = dwData; break; } } } RegCloseKey(hkey); } #ifdef _LOADSAVE_SUBDLG_UI__ if (nIDCtl == 0) _dlgOptions.LoadSaveUIState(0, bSave); #endif _LOADSAVE_SUBDLG_UI__ } 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); } STDMETHODIMP CFindFilesDlg::TranslateAccelerator(LPMSG lpmsg) { // Check for Ctrl+Nav Key: if (S_OK == CSearchCmdDlg::TranslateAccelerator(lpmsg)) return S_OK; // Check for VK_RETURN key. if (WM_KEYDOWN == lpmsg->message) { HWND hwndFocus = ::GetFocus(); HWND hwndNamespace = GetDlgItem(IDC_NAMESPACE); if (hwndFocus == hwndNamespace || ::IsChild(hwndNamespace, hwndFocus)) { if (VK_RETURN == lpmsg->wParam || VK_TAB == lpmsg->wParam || VK_F6 == lpmsg->wParam) { _UIReconcileAdHocNamespace(hwndNamespace); } else { // Hide edit image if this virtkey maps to a character, if (MapVirtualKey((UINT)lpmsg->wParam, 2) != 0 /* it's a char */) _fAdHocNamespace = TRUE; _ShowNamespaceEditImage(!_fAdHocNamespace); } } } if (_dlgOptions.IsChild(lpmsg->hwnd) && S_OK == _dlgOptions.TranslateAccelerator(lpmsg)) return S_OK; // Handle it ourselves... return _pfsb->IsDlgMessage(m_hWnd, lpmsg); } BOOL CFindFilesDlg::GetMinSize(HWND hwndOC, LPSIZE 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; } ::MapWindowPoints(HWND_DESKTOP, m_hWnd, (LPPOINT)&rc, POINTSPERRECT); psize->cx = rc.right + metrics.CtlMarginX(); // determine mininum height hwndLimit = GetDlgItem(FSEARCHMAIN_BOTTOMMOST); if (!(IsWindow(hwndLimit) && ::GetWindowRect(hwndLimit, &rc))) return FALSE; ::MapWindowPoints(HWND_DESKTOP, m_hWnd, (LPPOINT)&rc, POINTSPERRECT); 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); } BOOL CFindFilesDlg::GetMinMaxInfo(HWND hwndOC, LPMINMAXINFO pmmi) { SIZE sizeMin; if (GetMinSize(hwndOC, &sizeMin)) { pmmi->ptMinTrackSize.x = sizeMin.cx; pmmi->ptMinTrackSize.y = sizeMin.cy; return TRUE; } return FALSE; } 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 ::MapWindowPoints(HWND_DESKTOP, m_hWnd, (LPPOINT)(&rcCtls[i]), POINTSPERRECT); } // 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]); ::MapWindowPoints(HWND_DESKTOP, m_hWnd, (LPPOINT)&rcCtls[ircOPTIONGRP], POINTSPERRECT); 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 0L; } LRESULT CFindFilesDlg::OnTimer(UINT, WPARAM wParam, LPARAM, BOOL&) { if (UISTATETIMER == wParam && IsWindowVisible()) UpdateSearchCmdStateUI(); return 0L; } LRESULT CFindFilesDlg::OnOptions(int idCtl, LPNMHDR pnmh, BOOL&) { _ShowOptions(!_fDisplayOptions); LoadSaveUIState(IDC_SEARCHLINK_OPTIONS, TRUE); if (_fDisplayOptions) _dlgOptions.TakeFocus(); else ::SetFocus(GetDlgItem(IDC_SEARCHLINK_OPTIONS)); return 0L; } 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, LPNMHDR 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 (_ShouldReconcileAdHocNamespace()) _UIReconcileAdHocNamespace(GetDlgItem(IDC_NAMESPACE), NULL, TRUE); EnableStartStopButton(hwndCtl, FALSE); StartStopAnimation(TRUE); if (FAILED(StartSearch())) { EnableStartStopButton(hwndCtl, TRUE); StartStopAnimation(FALSE); } break; } case IDC_SEARCH_STOP: StopSearch(); break; } return 0L; } void CFindFilesDlg::NavigateToResults(IWebBrowser2* pwb2) { BSTR bstrUrl = SysAllocString(L"::{e17d4fc0-5564-11d1-83f2-00a0c90dc849}"); VARIANT varNil; VariantInit(&varNil); pwb2->Navigate(bstrUrl, &varNil, &varNil, &varNil, &varNil); SysFreeString(bstrUrl); } LRESULT CFindFilesDlg::OnStateChange(UINT, WPARAM, LPARAM, BOOL&) { UpdateSearchCmdStateUI(); return 0L; } LRESULT CFindFilesDlg::OnNamespaceSelEndOk(WORD nCode, WORD nID, HWND hwndCtl, BOOL&) { LRESULT iSel; LPCVOID pvData = NULL; if ((iSel = SendDlgItemMessage(IDC_NAMESPACE, CB_GETCURSEL, 0, 0)) != CB_ERR) { // Was this the "Browse..." item (pvData == INVALID_HANDLE_VALUE)? if (INVALID_HANDLE_VALUE == (pvData = (LPCVOID)_GetComboData(GetDlgItem(IDC_NAMESPACE), iSel))) { _BrowseAndAssignNamespace(); } else _iCurNamespace = iSel; } _pfsb->SetDirty(); return 0L; } 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 (_ShouldReconcileAdHocNamespace()) _UIReconcileAdHocNamespace(hwndCtl, NULL, wCode != CBN_DROPDOWN); return 0L; } // Handler for WM_NOTIFY::CBEN_ENDEDIT LRESULT CFindFilesDlg::OnNamespaceReconcileNotify(int idCtl, LPNMHDR pnmh, BOOL& bHandled) { if (_ShouldReconcileAdHocNamespace()) { // 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, 0L); } bHandled = FALSE; // let base class have a crack as well. return 0L; } // WMU_NAMESPACERECONCILE handler LRESULT CFindFilesDlg::OnNamespaceReconcileMsg(UINT, WPARAM, LPARAM, BOOL&) { if (_ShouldReconcileAdHocNamespace()) _UIReconcileAdHocNamespace(GetDlgItem(IDC_NAMESPACE), NULL, FALSE); return 0L; } BOOL CFindFilesDlg::_ShouldReconcileAdHocNamespace() { return _fAdHocNamespace || SendDlgItemMessage(IDC_NAMESPACE, CB_GETCURSEL, 0, 0L) == CB_ERR; } // Invokes lower Namespace reconciliation helper, updates some UI and // instance state data. // [BUGBUG] this was added as a late RC 'safe' delta, and should have actually // become part of _ReconcileAdHocNamespace() impl. void CFindFilesDlg::_UIReconcileAdHocNamespace(HWND hwndNamespace, IN OPTIONAL LPCTSTR pszNamespace, BOOL bAsync) { ASSERT(IsWindow(hwndNamespace)); LRESULT iSel; if ((iSel = _ReconcileAdHocNamespace(hwndNamespace, pszNamespace, bAsync)) != CB_ERR) _iCurNamespace = iSel; _ShowNamespaceEditImage(TRUE); _fAdHocNamespace = 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 _UIReconcileAdHocNamespace() // instead to ensure that instance state data is updated. INT_PTR CFindFilesDlg::_ReconcileAdHocNamespace( IN HWND hwndCombo, IN OPTIONAL LPCTSTR pszNamespace, IN OPTIONAL BOOL bAsync) { TCHAR szNamespace[MAX_URL_STRING]; INT_PTR iSel = ::SendMessage(hwndCombo, CB_GETCURSEL, 0, 0L); if (iSel != CB_ERR) { void* pValue = (void*) ::SendMessage(hwndCombo, CB_GETITEMDATA, iSel, 0L); if (INVALID_HANDLE_VALUE == pValue) { // The user has selected the special Browse... item. // Irreconcilable. Return CB_ERR return CB_ERR; } } // Don't know the namespace? Use current window text. if (NULL == pszNamespace) { *szNamespace = NULL; ::GetWindowText(hwndCombo, szNamespace, ARRAYSIZE(szNamespace)); pszNamespace = szNamespace; } if (!(pszNamespace && *pszNamespace)) return CB_ERR; INT_PTR iFind; // search display names if (CB_ERR == (iFind = _FindNamespace(hwndCombo, pszNamespace, FALSE))) { // search paths TCHAR szTemp[MAX_URL_STRING]; StrCpy(szTemp, pszNamespace); _PathFixup(szNamespace, szTemp); // don't care if this fails, the path might be a path list pszNamespace = szNamespace; iFind = _FindNamespace(hwndCombo, pszNamespace, TRUE); } // Not found in CB list? Add it if it's a valid path if (CB_ERR == iFind) { if (SUCCEEDED(_PathValidate(pszNamespace))) { iSel = _AddAdHocNamespace(hwndCombo, pszNamespace, TRUE); } else { iSel = CB_ERR; } } else { // found in CB list? Select it. iSel = bAsync ? ::PostMessage(hwndCombo, CB_SETCURSEL, iFind, 0L) : // this was needed in cases of reconcile following kill focus; // comboex is trying not to recurse. ::SendMessage(hwndCombo, CB_SETCURSEL, iFind, 0L); } return iSel; } BOOL CFindFilesDlg::_PathFixup(LPTSTR pszDst, LPCTSTR pszSrc) { ASSERT(pszDst); ASSERT(pszSrc); TCHAR szFull[MAX_PATH]; if (_IsPathList(pszDst)) return TRUE; *szFull = 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); ASSERT(_pfsb->BandSite()); TCHAR szCurDir[MAX_PATH]; if (SUCCEEDED(_GetCurrentPathAndNamespace(_pfsb->BandSite(), szCurDir, ARRAYSIZE(szCurDir), NULL, 0))) { if (*szCurDir && StrCmpI(szCurDir, _szCurrentPath)) lstrcpy(_szCurrentPath, szCurDir); if (*_szCurrentPath) { if (bRelative) { if (PathCombine(szFull, _szCurrentPath, pszSrc)) pszSrc = szFull; } else if (bMissingDrive) { int iDrive; if ((iDrive = PathGetDriveNumber(_szCurrentPath)) != -1) { TCHAR szRoot[MAX_PATH]; if (PathCombine(szFull, PathBuildRoot(szRoot, iDrive), pszSrc)) pszSrc = szFull; } } } } } return PathCanonicalize(pszDst, pszSrc); } LRESULT CFindFilesDlg::OnNamespaceDeleteItem(int idCtrl, LPNMHDR pnmh, BOOL& bHandled) { return _DeleteNamespaceComboItem(pnmh); } DWORD CFindFilesDlg::NamespaceThreadProc(void* pvParam) { PFSEARCHTHREADSTATE pState = (PFSEARCHTHREADSTATE)pvParam; ASSERT(pState); HRESULT hrInit = SHCoInitialize(); if (_PopulateNamespaceCombo(pState->hwndCtl, AddNamespaceItemNotify, (LPARAM)pvParam) != E_ABORT) { ::PostMessage(::GetParent(pState->hwndCtl), WMU_COMBOPOPULATIONCOMPLETE, (WPARAM)pState->hwndCtl, 0L); } pState->fComplete = TRUE; SHCoUninitialize(hrInit); return 0L; } STDMETHODIMP CFindFilesDlg::AddNamespaceItemNotify(ULONG fAction, PCBXITEM pItem, LPARAM lParam) { PFSEARCHTHREADSTATE pState = (PFSEARCHTHREADSTATE)lParam; ASSERT(pState); if (fAction & CBXCB_ADDING && pState->fCancel) return E_ABORT; if (fAction & CBXCB_ADDED && CBX_CSIDL_LOCALDRIVES == pItem->iID) { CFindFilesDlg* pffd = (CFindFilesDlg*)pState->pvParam; ASSERT(pffd); lstrcpyn(pffd->_szLocalDrives, pItem->szText, ARRAYSIZE(pffd->_szLocalDrives)); } return S_OK; } LRESULT CFindFilesDlg::OnComboPopulationComplete(UINT, WPARAM wParam, LPARAM, BOOL&) { _bScoped = SetDefaultScope(); return 0L; } BOOL CFindFilesDlg::AssignNamespace( LPCTSTR pszNamespace, LPCTSTR pszPath, BOOL bPassive /*TRUE = assign only if no current selection*/) { INT_PTR iSel = CB_ERR; HWND hwndNamespace = GetDlgItem(IDC_NAMESPACE); // If we don't yet have a current selection, establish it now. if (!bPassive || CB_ERR == (iSel = ::SendMessage(hwndNamespace, CB_GETCURSEL, 0, 0L))) { if (pszPath && *pszPath) // scan items by file system path iSel = _FindNamespace(hwndNamespace, pszPath, TRUE); if (CB_ERR == iSel && pszNamespace && *pszNamespace) // scan items by display name iSel = _FindNamespace(hwndNamespace, pszNamespace, FALSE); // Is this a folder we already know about? if (CB_ERR == iSel) { // no: add and select it if (*pszPath) { if (_IsRegItemPath(pszPath)) return FALSE; // unsupported regitem if ((iSel = _AddAdHocNamespace(hwndNamespace, pszPath, TRUE)) != CB_ERR) _iCurNamespace = iSel; } else { return FALSE; // no path, nothing we can do. } } else { // yes: select it ::SendMessage(hwndNamespace, CB_SETCURSEL, iSel, 0L); _iCurNamespace = iSel; } } BOOL bRet = ::SendMessage(hwndNamespace, CB_GETCURSEL, 0, 0L) != CB_ERR; return bRet; } HWND CFindFilesDlg::ShowHelp(HWND hwndOwner) { return ::HtmlHelp(hwndOwner, FINDHELPFILE, HH_DISPLAY_TOPIC, (DWORD_PTR)FINDFILES_HELPTOPIC); } // utility methods // Reports whether a path is a namespace combo root item with // child items that constitute the 'real' search paths. BOOL CFindFilesDlg::_IsPathSingleton(IN LPCTSTR pszPath) { return pszPath ? StrCmpI(pszPath, NAMESPACECOMBO_RECENT_PARAM) != 0 : TRUE; } // Appends a file system path item to the specified namespace combo box. INT_PTR CFindFilesDlg::_AddAdHocNamespace(HWND hwndComboBox, IN LPCTSTR pszPath, BOOL bSelectItem) { CBXITEM item; item.iItem = CB_ERR; if (pszPath && *pszPath) { void* pvData = NULL; Str_SetPtr((LPTSTR*)&pvData, pszPath); if (SUCCEEDED(_MakeCbxItemKnownImage(&item, pszPath, pvData, FOLDER_IMAGELIST_INDEX, FOLDER_IMAGELIST_INDEX, CB_ERR, 1))) { INT_PTR iSel = item.iItem; if (SUCCEEDED(_AddCbxItemToComboBox(hwndComboBox, &item, &iSel))) { item.iItem = iSel; if (bSelectItem) ::SendMessage(hwndComboBox, CB_SETCURSEL, iSel, 0L); } else item.iItem = CB_ERR; } if (CB_ERR == item.iItem) Str_SetPtr((LPTSTR*)&pvData, NULL); } return item.iItem; } #if _NECESSARY_BUT_PROBABLY_NOT_EVER_ INT_PTR _FindComboStringI(HWND hwndComboBox, LPCTSTR pszNamespace) { if (IsWindow(hwndComboBox) && (pszNamespace && *pszNamespace)) { TCHAR szItem[MAX_URL_STRING]; INT_PTR i, cnt = SendMessage(hwndComboBox, CB_GETCOUNT, 0, 0L); for (i = 0; i < cnt; i++) { if (SendMessage(hwndComboBox, CB_GETLBTEXT, i, (LPARAM)szItem) != CB_ERR) { if (0 == lstrcmpi(szItem, pszNamespace)) return i; } } } return CB_ERR; } #endif // Scans a namespace comboboxex for the item with the indicated display name INT_PTR CFindFilesDlg::_FindNamespace(HWND hwndComboBox, LPCTSTR pszNamespace, BOOL bForParsing) { if (IsWindow(hwndComboBox) && pszNamespace && *pszNamespace) { if (!bForParsing) return ::SendMessage(hwndComboBox, CB_FINDSTRINGEXACT, -1, (LPARAM)pszNamespace); INT_PTR i, cnt = ::SendMessage(hwndComboBox, CB_GETCOUNT, 0, 0L); for (i = 0; i < cnt; i++) { LPCVOID pvData = (LPCVOID)_GetComboData(hwndComboBox, i); if (pvData && pvData != INVALID_HANDLE_VALUE) if (lstrcmpi(pszNamespace, (LPCTSTR)pvData) == 0) return i; } } return CB_ERR; } INT_PTR CFindFilesDlg::_FindNamespace(IN HWND hwndComboBox, IN LPCITEMIDLIST pidl) { TCHAR szNamespace[MAX_URL_STRING]; HRESULT hr = SHGetNameAndFlags(pidl, SHGDN_NORMAL, szNamespace, ARRAYSIZE(szNamespace), NULL); if (SUCCEEDED(hr)) return _FindNamespace(hwndComboBox, szNamespace, FALSE); return CB_ERR; } // _BrowseForNamespace - Invokes SHBrowseForFolder UI to select a namespace. // pszNamespace: Buffer (must be >= MAX_PATH chars) to receive shell folder display name // 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 STDMETHODIMP CFindFilesDlg::_BrowseForNamespace( HWND hwndOwner, IN OUT LPTSTR pszNamespace, IN UINT cchNamespace, OUT OPTIONAL LPBOOL pbForParsing, OUT OPTIONAL LPITEMIDLIST* ppidlRet) { HRESULT hr = E_FAIL; *pszNamespace = 0; if (pbForParsing) *pbForParsing = FALSE; if (ppidlRet) *ppidlRet = NULL; TCHAR szTitle[MAX_PATH]; if (EVAL(LoadString(HINST_THISDLL, IDS_SNS_BROWSERFORDIR_TITLE, szTitle, ARRAYSIZE(szTitle)))) { BROWSEINFO bi = {0}; LPITEMIDLIST pidl; bi.hwndOwner = hwndOwner; // bi.pszDisplayName = pszNamespace; - // If we want to display a friendly name then assign this value bi.pidlRoot = NULL; bi.lpszTitle = szTitle; bi.ulFlags = (BIF_USENEWUI | BIF_EDITBOX | BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS); bi.lpfn = _BrowseCallback; bi.lParam = (LPARAM)hwndOwner; pidl = SHBrowseForFolder(&bi); if (pidl) { hr = SHGetTargetFolderPath(pidl, pszNamespace, cchNamespace); if (SUCCEEDED(hr) && *pszNamespace) { if (pbForParsing) *pbForParsing = TRUE; } else { IShellFolder* psfDesktop; if (SUCCEEDED(SHGetDesktopFolder(&psfDesktop))) { STRRET strret; hr = psfDesktop->GetDisplayNameOf(pidl, SHGDN_NORMAL, &strret); if (SUCCEEDED(hr)) { hr = StrRetToBuf(&strret, pidl, pszNamespace, MAX_PATH); } psfDesktop->Release(); } } if (ppidlRet) *ppidlRet = pidl; else ILFree(pidl); } else hr = E_ABORT; } return hr; } // Invokes SHBrowserForFolder UI and assigns results. void CFindFilesDlg::_BrowseAndAssignNamespace() { TCHAR szPath[MAX_PATH]; BOOL bForParsing; LPITEMIDLIST pidl = NULL; // Present folder browse UI.. if (SUCCEEDED(_BrowseForNamespace(m_hWnd, szPath, ARRAYSIZE(szPath), &bForParsing, &pidl))) { INT_PTR iSel = _FindNamespace(GetDlgItem(IDC_NAMESPACE), szPath, bForParsing); if (iSel != CB_ERR) { SendDlgItemMessage(IDC_NAMESPACE, CB_SETCURSEL, iSel, 0L); _iCurNamespace = iSel; } else { if ((iSel = _AddAdHocNamespace(GetDlgItem(IDC_NAMESPACE), szPath, TRUE)) != CB_ERR) _iCurNamespace = iSel; } } else SendDlgItemMessage(IDC_NAMESPACE, CB_SETCURSEL, _iCurNamespace, 0L); if (pidl) ILFree(pidl); } BOOL CFindFilesDlg::_IsSearchableFolder( IN LPCITEMIDLIST pidlFolder, IN OPTIONAL HWND hwndOwner) { BOOL bSearchable = FALSE; TCHAR szFolder[MAX_PATH]; // Read through any folder shortcut to the target path. HRESULT hr = SHGetTargetFolderPath(pidlFolder, szFolder, ARRAYSIZE(szFolder)); if (SUCCEEDED(hr)) { bSearchable = TRUE; // Ah, a file system folder. } else if (IsWindow(hwndOwner)) { SHGetNameAndFlags(pidlFolder, SHGDN_NORMAL, szFolder, SIZECHARS(szFolder), NULL); bSearchable = (CB_ERR != _FindNamespace(::GetDlgItem(hwndOwner, IDC_NAMESPACE), szFolder, FALSE)); } return bSearchable; } int CFindFilesDlg::_BrowseCallback(HWND hwnd, UINT msg, LPARAM lParam, LPARAM lpData) { HWND hwndOwner = (HWND)lpData; ASSERT(IsWindow(hwndOwner)); switch (msg) { case BFFM_INITIALIZED: // initializing: set default selection { LPITEMIDLIST pidlDefault = SHCloneSpecialIDList(NULL, CSIDL_DRIVES, TRUE); if (pidlDefault) { ::SendMessage(hwnd, BFFM_SETSELECTION, FALSE, (LPARAM)pidlDefault); ILFree(pidlDefault); } } break; case BFFM_SELCHANGED: // prevent non-searchable folder pidls from being selected. { BOOL bAllow = _IsSearchableFolder((LPCITEMIDLIST)lParam, hwndOwner); ::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 = NULL; 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; } else pdlg = (CSearchWarningDlg*)GetWindowPtr(hwnd, GWLP_USERDATA); if (NULL == pdlg) return FALSE; switch (uMsg) { case WM_COMMAND: { WORD wID = LOWORD(wParam); BOOL bHandled = TRUE; switch (wID) { case IDOK: case IDCANCEL: pdlg->_bNoWarn = IsDlgButtonChecked(hwnd, IDC_NOSCOPEWARNING); EndDialog(hwnd, wID); break; default: bHandled = FALSE; } return bHandled; } } return FALSE; } class CCISettingsDlg { public: CCISettingsDlg() : _hwnd(NULL), _fHeapInst(FALSE), _fCiIndexed(FALSE), _fCiRunning(FALSE), _fCiPermission(FALSE) { InitMMCHandles(); } ~CCISettingsDlg() { CloseMMCHandles(); } 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(); void InitMMCHandles(); void CloseMMCHandles(); HWND _hwnd; BOOL _fHeapInst, _fCiIndexed, _fCiRunning, _fCiPermission; PROCESS_INFORMATION _mmc_process; friend int CCISettingsDlg_DoModal(HWND hwndParent); friend HWND CCISettingsDlg_CreateModeless(HWND hwndParent); }; int CCISettingsDlg_DoModal(HWND hwndParent) { CCISettingsDlg dlg; return (int)DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_INDEXSERVER), hwndParent, CCISettingsDlg::DlgProc, (LPARAM)&dlg); } HWND CCISettingsDlg_CreateModeless(HWND hwndParent) { HWND hdlg = NULL; CCISettingsDlg* pdlg; if ((pdlg = new CCISettingsDlg) != NULL) { pdlg->_fHeapInst = TRUE; if (NULL == (hdlg = CreateDialogParam( HINST_THISDLL, MAKEINTRESOURCE(DLG_INDEXSERVER), hwndParent, CCISettingsDlg::DlgProc, (LPARAM)&pdlg))) delete pdlg; } return hdlg; } BOOL_PTR WINAPI CCISettingsDlg::DlgProc(HWND hDlg, UINT nMsg, WPARAM wParam, LPARAM lParam) { CCISettingsDlg* pdlg = NULL; if (WM_INITDIALOG == nMsg) { pdlg = (CCISettingsDlg*)lParam; pdlg->_hwnd = hDlg; SetWindowPtr(hDlg, GWLP_USERDATA, pdlg); return pdlg->OnInitDialog(); } else pdlg = (CCISettingsDlg*)GetWindowPtr(hDlg, GWLP_USERDATA); if (NULL == pdlg) return FALSE; switch (nMsg) { case WM_NCDESTROY: if (pdlg->_fHeapInst) delete pdlg; return TRUE; case WM_COMMAND: { WORD wNotifyCode = HIWORD(wParam); WORD wID = LOWORD(wParam); HWND hwndCtl = (HWND)lParam; BOOL bHandled = TRUE; switch (wID) { case IDC_CI_ADVANCED: { pdlg->ShowAdvanced(); break; } case IDOK: if (pdlg->OnOK()) EndDialog(hDlg, IDOK); break; case IDCANCEL: EndDialog(hDlg, wID); break; case IDC_CI_HELP: _IndexServiceHelp(hDlg); break; default: bHandled = FALSE; } return bHandled; } } return FALSE; } void CCISettingsDlg::ShowAdvanced() { // have we already spawned MMC? if (_mmc_process.hProcess != INVALID_HANDLE_VALUE) { HANDLE hProcess; if ((hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, _mmc_process.dwProcessId)) != NULL) { // it's alive. bail CloseHandle(hProcess); return; } InitMMCHandles(); } // Light up MMC w/ Index Service snap-in. static LPCTSTR szCmdLine0 = TEXT("mmc.exe %systemroot%\\system32\\ciadv.msc computername=localmachine"); TCHAR szCmdLine[MAX_PATH]; if (SHExpandEnvironmentStrings(szCmdLine0, szCmdLine, ARRAYSIZE(szCmdLine))) { STARTUPINFO si = {0}; si.cb = sizeof(si); if (!CreateProcess(NULL, szCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &_mmc_process)) InitMMCHandles(); } } void CCISettingsDlg::InitMMCHandles() { _mmc_process.dwProcessId = _mmc_process.dwThreadId = 0; _mmc_process.hProcess = _mmc_process.hThread = INVALID_HANDLE_VALUE; } void CCISettingsDlg::CloseMMCHandles() { if (_mmc_process.hProcess != INVALID_HANDLE_VALUE) CloseHandle(_mmc_process.hProcess); if (_mmc_process.hThread != INVALID_HANDLE_VALUE) CloseHandle(_mmc_process.hThread); _mmc_process.hProcess = _mmc_process.hThread = INVALID_HANDLE_VALUE; } 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]; wnsprintf(szStatus, ARRAYSIZE(szStatus), szStatusFmt, szStatusText); 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() { BOOL fStart = IsDlgButtonChecked(_hwnd, IDC_ENABLE_CI) ? TRUE : FALSE; //if( fStart != _fCiRunning ) StartStopCI(fStart, TRUE); 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); EVAL(LinkWindow_RegisterClass()); 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])) { ::MapWindowPoints(HWND_DESKTOP, Hwnd(), (LPPOINT)&rcCtl[i], POINTSPERRECT); 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); ::MapWindowPoints(HWND_DESKTOP, m_hWnd, (LPPOINT)&rc, POINTSPERRECT); 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, LPSIZE pSize) const { RECT rcRightmost, rcBottommost; HWND hwndRightmost = GetDlgItem(PSEARCHDLG_RIGHTMOST), hwndBottommost = GetDlgItem(PSEARCHDLG_BOTTOMMOST); ASSERT(IsWindow(hwndRightmost)); ASSERT(IsWindow(hwndBottommost)); ::GetWindowRect(hwndRightmost, &rcRightmost); ::MapWindowPoints(HWND_DESKTOP, m_hWnd, (LPPOINT)&rcRightmost, POINTSPERRECT); ::GetWindowRect(hwndBottommost, &rcBottommost); ::MapWindowPoints(HWND_DESKTOP, m_hWnd, (LPPOINT)&rcBottommost, POINTSPERRECT); 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(LPMSG lpmsg) { if (S_OK == CBandDlg::TranslateAccelerator(lpmsg)) return S_OK; // Handle it ourselves... return _pfsb->IsDlgMessage(m_hWnd, lpmsg); } 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_IShellDispatch2, (void**)&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 0L; } #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. EVAL(DivWindow_RegisterClass()); EVAL(LinkWindow_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, 0L); 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 0L; } 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])) { ::MapWindowPoints(HWND_DESKTOP, m_hWnd, (LPPOINT)&rcCtl[i], POINTSPERRECT); 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); ::MapWindowPoints(HWND_DESKTOP, m_hWnd, (LPPOINT)&rc, POINTSPERRECT); 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, MAX_PATH) <= 0) { lstrcpy(szName, TEXT("*")); } VARIANT var; VariantInit(&var); if (SUCCEEDED(hr = _T2BstrVariant(szName, &var))) { if (SUCCEEDED((hr = _AddConstraint(pSrchCmd, GetConstraintName(FSBC_SEARCHFOR), &var)))) { _AddMruStringFromWindow(_pmruComputerName, GetDlgItem(IDC_CSEARCH_NAME)); } else { 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, LPSIZE pSize) const { RECT rcRightmost, rcBottommost; HWND hwndRightmost = GetDlgItem(CSEARCHDLG_RIGHTMOST), hwndBottommost = GetDlgItem(CSEARCHDLG_BOTTOMMOST); ASSERT(IsWindow(hwndRightmost)); ASSERT(IsWindow(hwndBottommost)); ::GetWindowRect(hwndRightmost, &rcRightmost); ::MapWindowPoints(HWND_DESKTOP, m_hWnd, (LPPOINT)&rcRightmost, POINTSPERRECT); ::GetWindowRect(hwndBottommost, &rcBottommost); ::MapWindowPoints(HWND_DESKTOP, m_hWnd, (LPPOINT)&rcBottommost, POINTSPERRECT); 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}"); VARIANT varNil; VariantInit(&varNil); 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(LPMSG lpmsg) { if (S_OK == CSearchCmdDlg::TranslateAccelerator(lpmsg)) return S_OK; // Handle it ourselves... return _pfsb->IsDlgMessage(m_hWnd, lpmsg); } 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&) { EnableStartStopButton(hwndCtl, FALSE); StartStopAnimation(TRUE); if (FAILED(StartSearch())) { EnableStartStopButton(hwndCtl, TRUE); StartStopAnimation(FALSE); } return 0L; } LRESULT CFindComputersDlg::OnSearchStopBtn(WORD nCode, WORD nID, HWND hwndCtl, BOOL&) { StopSearch(); return 0L; } HWND CFindComputersDlg::ShowHelp(HWND hwndOwner) { return ::HtmlHelp(hwndOwner, FINDHELPFILE, HH_DISPLAY_TOPIC, (DWORD_PTR)FINDCOMPUTER_HELPTOPIC); } // 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) { ISearchCommandExt* pSrchCmd; DWORD dwConnection = 0; if (FAILED(CoCreateInstance(CLSID_DocFindCommand, NULL, CLSCTX_INPROC_SERVER, IID_ISearchCommandExt, (void**)&pSrchCmd))) { ASSERT(FALSE); // error message return NULL; } // Assign search type. if (FAILED(pSrchCmd->SearchFor(GetSearchType()))) { pSrchCmd->Release(); return NULL; } // DocFindCommand refuses to work unless he's got a site. if (FAILED(IUnknown_SetSite(pSrchCmd, _pfsb->BandSite()))) { pSrchCmd->Release(); return NULL; } // Connect events. if (FAILED(ConnectEvents(pSrchCmd))) { IUnknown_SetSite(pSrchCmd, NULL); pSrchCmd->Release(); return NULL; } _pSrchCmd = pSrchCmd; } return _pSrchCmd; } HRESULT CSearchCmdDlg::ConnectEvents(IUnknown* punk) { HRESULT hr = E_FAIL; IConnectionPointContainer* pcpc = NULL; if (SUCCEEDED((hr = punk->QueryInterface(IID_IConnectionPointContainer, (void**)&pcpc)))) { IConnectionPoint* pcp = NULL; DWORD dwConnection = 0L; if (SUCCEEDED((hr = pcpc->FindConnectionPoint(DIID_DSearchCommandEvents, &pcp)))) { if (SUCCEEDED((hr = pcp->Advise(this, &dwConnection)))) { _pcp = pcp; _pcp->AddRef(); _dwConnection = dwConnection; } pcp->Release(); } pcpc->Release(); } return hr; } HRESULT CSearchCmdDlg::DisconnectEvents() { HRESULT hr = S_FALSE; if (_pcp) { _pcp->Unadvise(_dwConnection); _pcp->Release(); _pcp = NULL; _dwConnection = 0L; hr = S_OK; } return hr; } HRESULT CSearchCmdDlg::StartSearch() { HRESULT hr = S_OK; // Validate input if (!Validate()) return E_INVALIDARG; ISearchCommandExt* pSrchCmd; if (NULL == (pSrchCmd = GetSearchCmd())) { ASSERT(pSrchCmd); return E_FAIL; } // Clear off current results pSrchCmd->ClearResults(); if (FAILED((hr = AddConstraints(pSrchCmd)))) return hr; return Execute(TRUE); } 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 0L; } void CSearchCmdDlg::Clear() { StopSearch(); ISearchCommandExt* pSrchCmd; if (NULL == (pSrchCmd = GetSearchCmd())) { ASSERT(pSrchCmd); return; } pSrchCmd->ClearResults(); } HRESULT CSearchCmdDlg::Execute(BOOL bStart) { ASSERT(_pSrchCmd); VARIANT varRecordsAffected, varParams; LONG lOptions = bStart ? 1L : 0L; VariantInit(&varRecordsAffected); VariantInit(&varParams); return _pSrchCmd->Execute(&varRecordsAffected, &varParams, lOptions); } void CSearchCmdDlg::StopSearch() { if (SearchInProgress()) Execute(FALSE); } HRESULT CSearchCmdDlg::SetQueryFile(IN VARIANT* pvarFile) { HRESULT hr = CBandDlg::SetQueryFile(pvarFile); if (hr != S_OK) return hr; ISearchCommandExt* pSrchCmd; if (NULL == (pSrchCmd = GetSearchCmd())) { ASSERT(pSrchCmd); return E_FAIL; } return pSrchCmd->RestoreSavedSearch(pvarFile); } 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; if ((pSrchCmd = GetSearchCmd()) != NULL) { HRESULT hr = S_OK; BSTR bstrError = NULL; USES_CONVERSION; // 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 ? W2T(bstrError) : NULL); } else { ASSERT(pSrchCmd != 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); ASSERT(_pfsb->BandSite()); // BUGBUG: we probably should cache IWebBrowserApp* BSTR bstrStatus = NULL; ISearchCommandExt* pSrchCmd; if (NULL == (pSrchCmd = GetSearchCmd())) { ASSERT(pSrchCmd); return; } if (SUCCEEDED(pSrchCmd->get_ProgressText(&bstrStatus))) { IShellBrowser* psb; if (SUCCEEDED(IUnknown_QueryService(_pfsb->BandSite(), SID_STopLevelBrowser, IID_IShellBrowser, (void**)&psb))) { IShellView* psv; if (SUCCEEDED(psb->QueryActiveShellView(&psv))) { IWebBrowserApp* pwba; if (SUCCEEDED(IUnknown_QueryService(psv, SID_SWebBrowserApp, IID_IWebBrowserApp, (void**)&pwba))) { pwba->put_StatusText(bstrStatus); pwba->Release(); bstrStatus = NULL; } psv->Release(); } psb->Release(); } if (bstrStatus) SysFreeString(bstrStatus); } } void CSearchCmdDlg::OnBandShow(BOOL bShow) { if (!bShow) StopSearch(); } STDMETHODIMP CSearchCmdDlg::TranslateAccelerator(LPMSG 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; } // ISearchCommandExt wrapping dlg // IUnknown STDMETHODIMP CSearchCmdDlg::QueryInterface(REFIID riid, void** ppvObj) { if (riid == IID_IUnknown || riid == IID_IDispatch || riid == DIID_DSearchCommandEvents) { *ppvObj = (void*)this; AddRef(); return S_OK; } return E_NOINTERFACE; } 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, 0L); // See comments in the CSearchCmdDlg::OnRestoreSearch message handler. break; #if 0 case DISPID_SEARCHCOMMAND_UPDATE: break; #endif } 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 BOOL WINAPI DivWindow_RegisterClass(); friend BOOL WINAPI DivWindow_UnregisterClass(HINSTANCE); }; ATOM CDivWindow::_atom = 0; BOOL DivWindow_RegisterClass() { if (CDivWindow::_atom != 0) return CDivWindow::_atom; WNDCLASSEX wc; ZeroMemory(&wc, sizeof(wc)); 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; //wc.lpszMenuName //wc.hIcon //wc.hIconSm return (CDivWindow::_atom = RegisterClassEx(&wc)); } BOOL DivWindow_UnregisterClass(HINSTANCE) { return UnregisterClass(DIVWINDOW_CLASS, HINST_THISDLL); } 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, 0L); 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, LPVOID* ppv) { CStringMru* pmru = new CStringMru; if (NULL == pmru) return E_OUTOFMEMORY; pmru->_hKeyRoot = hKey; StrCpyN(pmru->_szSubKey, szSubKey, ARRAYSIZE(pmru->_szSubKey)); if (cMaxStrings > 0) pmru->_cMax = cMaxStrings; pmru->_bCaseSensitive = bCaseSensitive; HRESULT hr = pmru->QueryInterface(riid, ppv); pmru->Release(); return hr; } CStringMru::CStringMru() : _hKeyRoot(NULL), _hKey(NULL), _cRef(1), _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_ALL_ACCESS, 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]; ULONG dwType, cbString = sizeof(szString); wsprintf(szVal, TEXT("%03d"), iString); DWORD dwErr = RegQueryValueEx(_hKey, szVal, 0, &dwType, (LPBYTE)szString, &cbString); if (dwErr == ERROR_SUCCESS && REG_SZ == dwType && *szString) { UINT cch = lstrlen(szString) + 1; LPOLESTR pwszAdd = new OLECHAR[cch]; if (pwszAdd) { SHTCharToUnicode(szString, pwszAdd, cch); DPA_AppendPtr(_hdpaStrings, 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]; wsprintf(szVal, TEXT("%03d"), iString); 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) { if (NULL == (_hdpaStrings = DPA_Create(4))) 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 = new OLECHAR[lstrlenW(pwszAdd) + 1]; if (NULL == pwszCopy) return E_OUTOFMEMORY; StrCpyW(pwszCopy, pwszAdd); int iNew = DPA_InsertPtr(_hdpaStrings, 0, pwszCopy); if (iNew < 0) { delete[] pwszCopy; hr = E_OUTOFMEMORY; } else { ASSERT(0 == iNew); hr = S_OK; } } 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); if (pwsz) delete[] 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) { delete[] 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; if ((pwsz = (LPOLESTR)DPA_FastGetPtr(_hdpaStrings, i)) != NULL) delete[] pwsz; } DPA_Destroy(_hdpaStrings); _hdpaStrings = NULL; } } // *** IUnknown *** STDMETHODIMP_(ULONG) CStringMru::AddRef(void) { _cRef++; return 0; } STDMETHODIMP_(ULONG) CStringMru::Release(void) { if (_cRef > 0) { if (0 == --_cRef) delete this; } return 0; } STDMETHODIMP CStringMru::QueryInterface(REFIID riid, LPVOID * ppvObj) { if (!ppvObj) return E_POINTER; *ppvObj = NULL; if (IsEqualIID(riid, IID_IUnknown)) { *ppvObj = (IUnknown*)(IStringMru*)this; } else if (IsEqualIID(riid, IID_IEnumString)) { *ppvObj = (IEnumString*)this; } else if (IsEqualIID(riid, IID_IStringMru)) { *ppvObj = (IStringMru*)this; } if (*ppvObj) { AddRef(); return S_OK; } return E_NOINTERFACE; } // *** 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 ((rgelt[cFetched] = (LPOLESTR)CoTaskMemAlloc((lstrlenW(pwsz) + 1) * sizeof(OLECHAR))) != NULL) { StrCpyW(rgelt[cFetched], pwsz); 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; }