Windows2000/private/shell/shell32/fsrchdlg.cpp
2020-09-30 17:12:32 +02:00

6091 lines
169 KiB
C++

// 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;
}