From: Gabriel Ivăncescu Subject: [PATCH v2 5/8] shell32/autocomplete: Send messages directly to the edit control's procedure Message-Id: <4416482679d9bcb58a14dcd706aa40bec582bbe3.1537444354.git.gabrielopcode@gmail.com> Date: Thu, 20 Sep 2018 14:55:38 +0300 In-Reply-To: References: Send the messages directly to the edit control's window procedure to match Windows behavior and reduce needless overhead. However, it appears that Windows allows hijacking WM_GETTEXT and WM_GETTEXTLENGTH for autocompletion, so handle that case separately. Signed-off-by: Gabriel Ivăncescu --- See the tests in the series for examples of that. dlls/shell32/autocomplete.c | 47 ++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/dlls/shell32/autocomplete.c b/dlls/shell32/autocomplete.c index 92afbe2..3326e31 100644 --- a/dlls/shell32/autocomplete.c +++ b/dlls/shell32/autocomplete.c @@ -90,6 +90,8 @@ static const WCHAR autocomplete_propertyW[] = {'W','i','n','e',' ','A','u','t',' 'c','o','m','p','l','e','t','e',' ', 'c','o','n','t','r','o','l',0}; +static LRESULT APIENTRY ACEditSubclassProc(HWND, UINT, WPARAM, LPARAM); + static inline IAutoCompleteImpl *impl_from_IAutoComplete2(IAutoComplete2 *iface) { return CONTAINING_RECORD(iface, IAutoCompleteImpl, IAutoComplete2_iface); @@ -100,6 +102,22 @@ static inline IAutoCompleteImpl *impl_from_IAutoCompleteDropDown(IAutoCompleteDr return CONTAINING_RECORD(iface, IAutoCompleteImpl, IAutoCompleteDropDown_iface); } +static inline WNDPROC get_edit_proc(IAutoCompleteImpl *ac, HWND hwnd) +{ + WNDPROC edit_proc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC); + return (edit_proc == ACEditSubclassProc) ? ac->wpOrigEditProc : edit_proc; +} + +static void set_text_and_selection(IAutoCompleteImpl *ac, HWND hwnd, WCHAR *text, WPARAM start, LPARAM end) +{ + /* Send it directly to the edit control to match Windows XP behavior */ + WNDPROC proc = ac->wpOrigEditProc; + + /* FIXME: send WM_SETREDRAW when the edit control supports it */ + if (CallWindowProcW(proc, hwnd, WM_SETTEXT, 0, (LPARAM)text)) + CallWindowProcW(proc, hwnd, EM_SETSEL, start, end); +} + static size_t format_quick_complete(WCHAR *dst, const WCHAR *qc, const WCHAR *str, size_t str_len) { /* Replace the first %s directly without using snprintf, to avoid @@ -142,8 +160,7 @@ static void autoappend_str(IAutoCompleteImpl *ac, WCHAR *text, UINT len, WCHAR * } else tmp = str; - SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)tmp); - SendMessageW(hwnd, EM_SETSEL, len, size - 1); + set_text_and_selection(ac, hwnd, tmp, len, size - 1); if (tmp != str) heap_free(tmp); } @@ -152,7 +169,8 @@ static void autocomplete_text(IAutoCompleteImpl *ac, HWND hwnd, enum autoappend_ { HRESULT hr; WCHAR *text; - UINT cpt, size, len = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0); + WNDPROC edit_proc = get_edit_proc(ac, hwnd); + UINT cpt, size, len = CallWindowProcW(edit_proc, hwnd, WM_GETTEXTLENGTH, 0, 0); if (flag != autoappend_flag_displayempty && len == 0) { @@ -164,7 +182,7 @@ static void autocomplete_text(IAutoCompleteImpl *ac, HWND hwnd, enum autoappend_ size = len + 1; if (!(text = heap_alloc(size * sizeof(WCHAR)))) return; - len = SendMessageW(hwnd, WM_GETTEXT, size, (LPARAM)text); + len = CallWindowProcW(edit_proc, hwnd, WM_GETTEXT, size, (LPARAM)text); if (len + 1 != size) text = heap_realloc(text, (len + 1) * sizeof(WCHAR)); @@ -247,17 +265,18 @@ static LRESULT ACEditSubclassProc_KeyDown(IAutoCompleteImpl *ac, HWND hwnd, UINT { WCHAR *text, *buf; size_t sz; - UINT len = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0); + WNDPROC edit_proc = get_edit_proc(ac, hwnd); + UINT len = CallWindowProcW(edit_proc, hwnd, WM_GETTEXTLENGTH, 0, 0); + if (!(text = heap_alloc((len + 1) * sizeof(WCHAR)))) return 0; - len = SendMessageW(hwnd, WM_GETTEXT, len + 1, (LPARAM)text); + len = CallWindowProcW(edit_proc, hwnd, WM_GETTEXT, len + 1, (LPARAM)text); sz = strlenW(ac->quickComplete) + 1 + len; if ((buf = heap_alloc(sz * sizeof(WCHAR)))) { len = format_quick_complete(buf, ac->quickComplete, text, len); - SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)buf); - SendMessageW(hwnd, EM_SETSEL, 0, len); + set_text_and_selection(ac, hwnd, buf, 0, len); heap_free(buf); } @@ -309,16 +328,13 @@ static LRESULT ACEditSubclassProc_KeyDown(IAutoCompleteImpl *ac, HWND hwnd, UINT if (!(msg = heap_alloc((len + 1) * sizeof(WCHAR)))) return 0; len = SendMessageW(ac->hwndListBox, LB_GETTEXT, sel, (LPARAM)msg); - SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)msg); - SendMessageW(hwnd, EM_SETSEL, len, len); + set_text_and_selection(ac, hwnd, msg, len, len); heap_free(msg); } else { - UINT len; - SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)ac->txtbackup); - len = strlenW(ac->txtbackup); - SendMessageW(hwnd, EM_SETSEL, len, len); + UINT len = strlenW(ac->txtbackup); + set_text_and_selection(ac, hwnd, ac->txtbackup, len, len); } return 0; } @@ -409,8 +425,7 @@ static LRESULT APIENTRY ACLBoxSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, if (!(msg = heap_alloc((len + 1) * sizeof(WCHAR)))) break; len = SendMessageW(hwnd, LB_GETTEXT, sel, (LPARAM)msg); - SendMessageW(This->hwndEdit, WM_SETTEXT, 0, (LPARAM)msg); - SendMessageW(This->hwndEdit, EM_SETSEL, 0, len); + set_text_and_selection(This, This->hwndEdit, msg, 0, len); ShowWindow(hwnd, SW_HIDE); heap_free(msg); break; -- 1.9.1