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