windows-nt/Source/XPSP1/NT/shell/browseui/autocomp.h
2020-09-26 16:20:57 +08:00

349 lines
15 KiB
C++

/* Copyright 1996 Microsoft */
#ifndef _AUTOCOMP_HPP_
#define _AUTOCOMP_HPP_
#include "accdel.h"
// TODO List:
// 1. Convert AutoComplete to be a Free Threaded object and move it and all it's
// lists into MultiApartment model.
// 2. Get thread out of ThreadPool API in shlwapi.dll instead of creating thead our
// selves.
// 3. See if SHWaitForSendMessageThread() will cause a lock if bg thread is in SendMessage().
// If so, make sure the bg loop's hard loop doesn't call SendMessage() in this case without
// first looking for QUIT message.
// WARNING On Usage:
// This object is marked Apartment model and this abuses COM. These are rules
// that need to be followed to prevent bugs. This object will be used within three scopes.
// The first scope is the caller doing: 1a) CoInitialize(), 1b) CoCreateInstance().
// 1c) p->Init(), 1d) p->Release(), 1e) CoUninitialize().
// The second scope is the object doing: 2a) Subclass();AddRef(), 2b) WM_DESTROY;Release();
// 1c) p->Init(), 1d) p->Release(), 1e) CoUninitialize().
// The third scope is the background thread doing: 3a) (in thread proc) CoInitialize(),
// 3b) CoUninitialize().
// This object requires that 1E come after 2B and that should be the only requirement
// for the use of this object.
//
// PRIVATE
//
#define AC_LIST_GROWTH_CONST 50
const WCHAR CH_WILDCARD = L'\1'; // indicates a wildcard search
//
// Debug Flags
//
#define AC_WARNING TF_WARNING + TF_AUTOCOMPLETE
#define AC_ERROR TF_ERROR + TF_AUTOCOMPLETE
#define AC_GENERAL TF_GENERAL + TF_AUTOCOMPLETE
#define AC_FUNC TF_FUNC + TF_AUTOCOMPLETE
// Enable test regkey
#define ALLOW_ALWAYS_DROP_UP
//
// WndProc messages to the dropdown window
//
enum
{
AM_BUTTONCLICK = WM_APP + 400,
AM_UPDATESCROLLPOS,
AM_DESTROY
};
//
// Flags passed from background thread when the search is completed
enum
{
SRCH_LIMITREACHED = 0x01, // out of memory or we reached our limit
SRCH_USESORTINDEX = 0x02, // use sort index to order results
};
#define ACO_UNINITIALIZED 0x80000000 // if autocomplete options have not been initialized
//
// PUBLIC
//
HRESULT SHUseDefaultAutoComplete(HWND hwndEdit,
IBrowserService * pbs, IN OPTIONAL
IAutoComplete2 ** ppac, OUT OPTIONAL
IShellService ** ppssACLISF, OUT OPTIONAL
BOOL fUseCMDMRU);
// Forward references
class CAutoComplete;
class CACString* CreateACString(LPCWSTR pszStr);
//+-------------------------------------------------------------------------
// CACString - Autocomplete string shared by foreground & background threads
//--------------------------------------------------------------------------
class CACString
{
public:
ULONG AddRef();
ULONG Release();
ULONG GetSortIndex() { return m_ulSortIndex; }
void SetSortIndex(ULONG ulIndex) { m_ulSortIndex = ulIndex; }
LPCWSTR GetStr() const { return m_sz; }
LPCWSTR GetStrToCompare() const { return m_sz + m_iIgnore; }
int GetLength() const { return m_cChars; }
int GetLengthToCompare() const { return m_cChars - m_iIgnore; }
const WCHAR& operator [] (int nIndex) const { return m_sz[nIndex]; }
operator LPCWSTR() { return m_sz; }
BOOL HasPrefix() { return m_iIgnore; }
BOOL PrefixLength() { return m_iIgnore; }
// Note, the following compare functions ignore the prefix of the CACString
int CompareSortingIndex(CACString& r);
int StrCmpI(LPCWSTR psz) { return ::StrCmpI(m_sz + m_iIgnore, psz); }
int StrCmpI(CACString& r) { return ::StrCmpI(m_sz + m_iIgnore, r.m_sz + r.m_iIgnore); }
int StrCmpNI(LPCWSTR psz, int cch) { return ::StrCmpNI(m_sz + m_iIgnore, psz, cch); }
protected:
friend CACString* CreateACString(LPCWSTR pszStr, int iIgnore, ULONG ulSortIndex);
// Prevent creation on stack
CACString();
LONG m_cRef; // reference count
int m_cChars; // length of string (excluding null)
int m_iIgnore; // # prefix characters to ignore when comparing strings
ULONG m_ulSortIndex; // can be used instead of default alphabetical sorting
WCHAR m_sz[1]; // first character of the string
};
//+-------------------------------------------------------------------------
// CACThread - Autocomplete thread that runs in the background
//--------------------------------------------------------------------------
class CACThread : public IUnknown
{
public:
// *** IUnknown ***
virtual STDMETHODIMP_(ULONG) AddRef();
virtual STDMETHODIMP_(ULONG) Release();
virtual STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
CACThread(CAutoComplete& rAutoComp);
virtual ~CACThread();
BOOL Init(IEnumString* pes, IACList* pacl);
void GotFocus();
void LostFocus();
BOOL HasFocus() { return m_fWorkItemQueued != 0; }
BOOL StartSearch(LPCWSTR pszSearch, DWORD dwOptions);
void StopSearch();
void SyncShutDownBGThread();
BOOL IsDisabled() { return m_fDisabled; }
// Helper functions
static BOOL MatchesSpecialPrefix(LPCWSTR pszSearch);
static int GetSpecialPrefixLen(LPCWSTR psz);
protected:
LONG m_cRef;
CAutoComplete* m_pAutoComp; // portion of autocomplete that runs on main thread
LONG m_fWorkItemQueued; // if request made to shlwapi thread pool
LONG m_idThread;
HANDLE m_hCreateEvent; // thread startup syncronizatrion
BOOL m_fDisabled:1; // is autocomplete disabled?
LPWSTR m_pszSearch; // String we are currently searching for
HDPA m_hdpa_list; // list of completions
DWORD m_dwSearchStatus;// see SRCH_* flags
IEnumString* m_pes; // Used internally for real AutoComplete functionality.
IEnumACString* m_peac; // Used with IEnumString to get sort index
IACList* m_pacl; // Additional methods for autocomplete lists (optional).
void _SendAsyncShutDownMsg(BOOL fFinalShutDown);
void _FreeThreadData();
HRESULT _ThreadLoop();
HRESULT _Next(LPWSTR szUrl, ULONG cchUrl, ULONG* pulSortIndex);
HRESULT _ProcessMessage(MSG * pMsg, DWORD * pdwTimeout, BOOL * pfStayAlive);
void _Search(LPWSTR pszSearch, DWORD dwOptions);
BOOL _AddToList(LPTSTR pszUrl, int cchMatch, ULONG ulSortIndex);
void _DoExpand(LPCWSTR pszSearch);
static DWORD WINAPI _ThreadProc(LPVOID lpv);
static int CALLBACK _DpaCompare(LPVOID p1, LPVOID p2, LPARAM lParam);
};
//+-------------------------------------------------------------------------
// CAutoComplete - Main autocomplete class that runs on the main UI thread
//--------------------------------------------------------------------------
class CAutoComplete
: public IAutoComplete2
, public IAutoCompleteDropDown
, public IEnumString
, public CDelegateAccessibleImpl
{
public:
//////////////////////////////////////////////////////
// Public Interfaces
//////////////////////////////////////////////////////
// *** IUnknown ***
virtual STDMETHODIMP_(ULONG) AddRef();
virtual STDMETHODIMP_(ULONG) Release();
virtual STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
// *** IEnumString ***
virtual STDMETHODIMP Next(ULONG celt, LPOLESTR *rgelt, ULONG *pceltFetched);
virtual STDMETHODIMP Skip(ULONG celt) { return E_NOTIMPL; }
virtual STDMETHODIMP Reset();
virtual STDMETHODIMP Clone(IEnumString **ppenum) { return E_NOTIMPL; }
// *** IAutoComplete ***
virtual STDMETHODIMP Init(HWND hwnd, IUnknown *punkACL, LPCOLESTR pwszRegKeyPath, LPCOLESTR pwszQuickCompleteString);
virtual STDMETHODIMP Enable(BOOL fEnable);
// *** IAutoComplete2 ***
virtual STDMETHODIMP SetOptions(DWORD dwFlag);
virtual STDMETHODIMP GetOptions(DWORD* pdwFlag);
// *** IAutoCompleteDropDown ***
virtual STDMETHODIMP GetDropDownStatus(DWORD *pdwFlags, LPWSTR *ppwszString);
virtual STDMETHODIMP ResetEnumerator();
// *** IAccessible ***
STDMETHODIMP get_accName(VARIANT varChild, BSTR *pszName);
protected:
// Methods called by the background thread
friend CACThread;
void SearchComplete(HDPA hdpa, DWORD dwSearchStatus) { PostMessage(m_hwndEdit, m_uMsgSearchComplete, dwSearchStatus, (LPARAM)hdpa); }
BOOL IsEnabled();
// Constructor / Destructor (protected so we can't create on stack)
CAutoComplete();
virtual ~CAutoComplete();
// Instance creator
friend HRESULT CAutoComplete_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi);
BOOL _Init();
// Private variables
LONG m_cRef;
CACThread* m_pThread; // background autocomplete thread
TCHAR m_szQuickComplete[MAX_PATH];
TCHAR m_szRegKeyPath[MAX_PATH];
DWORD m_dwFlags;
HWND m_hwndEdit;
HWND m_hwndCombo; // if m_hwndEdit is part of a combobox
HFONT m_hfontListView;
LPTSTR m_pszCurrent;
int m_iCurrent;
DWORD m_dwLastSearchFlags;
WNDPROC m_pOldListViewWndProc;
IEnumString * m_pes; // Used internally for real AutoComplete functionality.
IACList * m_pacl; // Additional methods for autocomplete lists (optional).
HDPA m_hdpa; // sorted completions list
HDPA m_hdpaSortIndex; // matches from m_hdpa ordered by sort index
LPWSTR m_pszLastSearch; // string last sent for completion
int m_iFirstMatch; // first match in list (-1 if no matches)
int m_iLastMatch; // last match in list (-1 if no matches)
int m_iAppended; // item completed in the edit box
BITBOOL m_fEditControlUnicode:1; // if the edit control is unicode.
BITBOOL m_fNeedNewList:1; // last search was truncated
BITBOOL m_fDropDownResized:1; // user has resized drop down
BITBOOL m_fAppended:1; // if something currently appended
BITBOOL m_fSearchForAdded:1; // if last item in dpa is "Search for <>"
BITBOOL m_fSearchFor:1; // if "Search for <>" is to be displayed
BITBOOL m_fImeCandidateOpen:1; // if the IME's candidate window is visible
DWORD m_dwOptions; // autocomplete options (ACO_*)
EDITWORDBREAKPROC m_oldEditWordBreakProc; // original word break proc for m_hwndEdit
// Member variables for drop-down auto-suggest window
HWND m_hwndDropDown; // Shows completions in drop-down window
HWND m_hwndList; // Shows completions in drop-down window
HWND m_hwndScroll; // scrollbar
HWND m_hwndGrip; // gripper for resizing the dropdown
int m_nStatusHeight; // height of status in drop-down
int m_nDropWidth; // width of drop-down window
int m_nDropHeight; // height of drop-down window
int m_cxGripper; // width/height of gripper
BITBOOL m_fDroppedUp:1; // if dropdown is over top the edit box
#ifdef ALLOW_ALWAYS_DROP_UP
BITBOOL m_fAlwaysDropUp:1; // TEST regkey to always drop up
#endif
BITBOOL m_fSettingText:1; // if setting the edit text
BITBOOL m_fInHotTracking:1; // if new selection is due to hot-tracking
// Member Variables used for external IEnumString
IEnumString * m_pesExtern; // Used internally for real AutoComplete functionality.
LPTSTR m_szEnumString;
// Registered messages sent to edit window
UINT m_uMsgSearchComplete;
UINT m_uMsgItemActivate;
static HHOOK s_hhookMouse; // windows hook installed when drop-down visible
static HWND s_hwndDropDown; // dropdown currently visible
static BOOL s_fNoActivate; // keep topmost-window from losing activation
void _OnSearchComplete(HDPA hdpa, DWORD dwSearchStatus);
BOOL _GetItem(int iIndex, LPWSTR pswText, int cchMax, BOOL fDisplayName);
void _UpdateCompletion(LPCWSTR pszTyped, int iChanged, BOOL fAppend);
void _HideDropDown();
void _ShowDropDown();
void _PositionDropDown();
void _SeeWhatsEnabled();
BOOL _IsAutoSuggestEnabled() { return m_dwOptions & ACO_AUTOSUGGEST; }
BOOL _IsRTLReadingEnabled() { return m_dwOptions & ACO_RTLREADING; }
BOOL _IsAutoAppendEnabled() { return (m_dwOptions & ACO_AUTOAPPEND) || (m_dwOptions & ACO_UNINITIALIZED); }
BOOL _IsComboboxDropped() { return (m_hwndCombo && ComboBox_GetDroppedState(m_hwndCombo)); }
void _UpdateGrip();
void _UpdateScrollbar();
static BOOL _IsWhack(TCHAR ch);
static BOOL _IsBreakChar(WCHAR wch);
BOOL _WantToAppendResults();
int _JumpToNextBreak(int iLoc, DWORD dwFlags);
BOOL _CursorMovement(WPARAM wParam);
void _RemoveCompletion();
void _GetEditText();
void _SetEditText(LPCWSTR psz);
void _UpdateText(int iStartSel, int iEndSel, LPCTSTR pszCurrent, LPCTSTR pszNew);
BOOL _OnKeyDown(WPARAM wParam);
LRESULT _OnChar(WPARAM wParam, LPARAM lParam);
void _StartCompletion(BOOL fAppend, BOOL fEvenIfEmpty = FALSE);
BOOL _StartSearch(LPCWSTR pszSearch);
void _StopSearch();
BOOL _ResetSearch();
void _GotFocus();
LPTSTR _QuickEnter();
BOOL _AppendNext(BOOL fAppendToWhack);
BOOL _AppendPrevious(BOOL fAppendToWhack);
void _Append(CACString& rStr, BOOL fAppendToWhack);
BOOL _SetQuickCompleteStrings(LPCOLESTR pcszRegKeyPath, LPCOLESTR pcszQuickCompleteString);
void _SubClassParent(HWND hwnd);
void _UnSubClassParent(HWND hwnd);
LRESULT _DropDownWndProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT _EditWndProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT _ListViewWndProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
void _DropDownDrawItem(LPDRAWITEMSTRUCT pdis);
BOOL _DropDownNotify(LPNMHDR pnmhdr);
static int _DPADestroyCallback(LPVOID p, LPVOID d);
static void _FreeDPAPtrs(HDPA hdpa);
static int CALLBACK _DPACompareSortIndex(LPVOID p1, LPVOID p2, LPARAM lParam);
static int CALLBACK EditWordBreakProcW(LPWSTR lpch, int ichCurrent, int cch, int code);
static LRESULT CALLBACK s_EditWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
static LRESULT CALLBACK s_DropDownWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK s_ListViewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK s_ParentWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
static LRESULT CALLBACK s_GripperWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
static LRESULT CALLBACK s_MouseHook(int nCode, WPARAM wParam, LPARAM lParam);
};
#endif