From: Gabriel Ivăncescu Subject: [PATCH 10/17] shell32/autocomplete: Send messages directly to the edit control and AutoComplete listbox Message-Id: <978226f77ee373ab3f19a0534411d292d0b08360.1536163731.git.gabrielopcode@gmail.com> Date: Wed, 5 Sep 2018 19:13:12 +0300 In-Reply-To: <695190c8471230e6a87e237a7c4a86e3281525b8.1536163731.git.gabrielopcode@gmail.com> References: <695190c8471230e6a87e237a7c4a86e3281525b8.1536163731.git.gabrielopcode@gmail.com> Send the messages directly to the edit control's window procedure (and likewise for the AutoComplete listbox) to reduce needless overhead and match Windows behavior. 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 --- dlls/shell32/autocomplete.c | 88 +++++++++++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 35 deletions(-) diff --git a/dlls/shell32/autocomplete.c b/dlls/shell32/autocomplete.c index 4305f65..b71cbc0 100644 --- a/dlls/shell32/autocomplete.c +++ b/dlls/shell32/autocomplete.c @@ -93,6 +93,21 @@ static inline IAutoCompleteImpl *impl_from_IAutoCompleteDropDown(IAutoCompleteDr return CONTAINING_RECORD(iface, IAutoCompleteImpl, IAutoCompleteDropDown_iface); } +static inline LRESULT send_to_LB(IAutoCompleteImpl *This, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + return CallWindowProcW(This->wpOrigLBoxProc, hwnd, msg, wParam, lParam); +} + +static void set_text_and_selection(IAutoCompleteImpl *This, HWND hwnd, WCHAR *text, WPARAM start, LPARAM end) +{ + /* Send it directly to the edit control to match Windows XP behavior */ + WNDPROC proc = This->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 void destroy_autocomplete_object(IAutoCompleteImpl *ac) { ac->hwndEdit = NULL; @@ -110,6 +125,7 @@ static LRESULT APIENTRY ACEditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, HRESULT hr; LRESULT ret; WCHAR *hwndText; + WNDPROC edit_proc; UINT len, old_len, cpt; BOOLEAN displayall = FALSE, noautoappend = !(This->options & ACO_AUTOAPPEND); INT sel; @@ -135,10 +151,14 @@ static LRESULT APIENTRY ACEditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, if (This->quickComplete && (GetKeyState(VK_CONTROL) & 0x8000)) { WCHAR *qc; size_t sz; - len = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0) + 1; /* include NUL */ + edit_proc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC); + edit_proc = edit_proc == ACEditSubclassProc ? This->wpOrigEditProc : edit_proc; + + len = CallWindowProcW(edit_proc, hwnd, WM_GETTEXTLENGTH, 0, 0); + len++; /* include NUL */ if (!(hwndText = heap_alloc(len * sizeof(WCHAR)))) return 0; - len = SendMessageW(hwnd, WM_GETTEXT, len, (LPARAM)hwndText); + len = CallWindowProcW(edit_proc, hwnd, WM_GETTEXT, len, (LPARAM)hwndText); sz = strlenW(This->quickComplete)+1 + max(len, 2); /* %s is 2 chars */ while ((qc = heap_alloc(sz * sizeof(WCHAR)))) { @@ -148,8 +168,7 @@ static LRESULT APIENTRY ACEditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, sel = snprintfW(qc, sz, This->quickComplete, hwndText, hwndText, hwndText); if (sel >= 0 && sel < sz) { - SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)qc); - SendMessageW(hwnd, EM_SETSEL, 0, sel); + set_text_and_selection(This, hwnd, qc, 0, sel); heap_free(qc); break; } @@ -183,30 +202,27 @@ static LRESULT APIENTRY ACEditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, goto autocomplete_text; } } else { - INT count = SendMessageW(This->hwndListBox, LB_GETCOUNT, 0, 0); + INT count = send_to_LB(This, This->hwndListBox, LB_GETCOUNT, 0, 0); /* Change the selection */ - sel = SendMessageW(This->hwndListBox, LB_GETCURSEL, 0, 0); + sel = send_to_LB(This, This->hwndListBox, LB_GETCURSEL, 0, 0); if (wParam == VK_UP) sel = ((sel-1) < -1) ? count-1 : sel-1; else sel = ((sel+1) >= count) ? -1 : sel+1; - SendMessageW(This->hwndListBox, LB_SETCURSEL, sel, 0); + send_to_LB(This, This->hwndListBox, LB_SETCURSEL, sel, 0); if (sel != -1) { WCHAR *msg; - UINT len = SendMessageW(This->hwndListBox, LB_GETTEXTLEN, sel, 0); + UINT len = send_to_LB(This, This->hwndListBox, LB_GETTEXTLEN, sel, 0); if ((msg = heap_alloc((len + 1)*sizeof(WCHAR)))) { - len = SendMessageW(This->hwndListBox, LB_GETTEXT, sel, (LPARAM)msg); - SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)msg); - SendMessageW(hwnd, EM_SETSEL, len, len); + len = send_to_LB(This, This->hwndListBox, LB_GETTEXT, sel, (LPARAM)msg); + set_text_and_selection(This, hwnd, msg, len, len); heap_free(msg); } } else { - UINT len; - SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)This->txtbackup); - len = strlenW(This->txtbackup); - SendMessageW(hwnd, EM_SETSEL, len, len); + UINT len = strlenW(This->txtbackup); + set_text_and_selection(This, hwnd, This->txtbackup, len, len); } return 0; } @@ -223,7 +239,9 @@ static LRESULT APIENTRY ACEditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, if (wParam < ' ') { handle_control_char: - len = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0); + edit_proc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC); + edit_proc = edit_proc == ACEditSubclassProc ? This->wpOrigEditProc : edit_proc; + len = CallWindowProcW(edit_proc, hwnd, WM_GETTEXTLENGTH, 0, 0); if ((This->options & ACO_AUTOSUGGEST) && len == 0) { ShowWindow(This->hwndListBox, SW_HIDE); return ret; @@ -233,17 +251,19 @@ static LRESULT APIENTRY ACEditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, } else { autocomplete_text: - len = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0); + edit_proc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC); + edit_proc = edit_proc == ACEditSubclassProc ? This->wpOrigEditProc : edit_proc; + len = CallWindowProcW(edit_proc, hwnd, WM_GETTEXTLENGTH, 0, 0); } old_len = len+1; /* include NUL */ if (!(hwndText = heap_alloc(old_len * sizeof(WCHAR)))) return ret; - len = SendMessageW(hwnd, WM_GETTEXT, old_len, (LPARAM)hwndText); + len = CallWindowProcW(edit_proc, hwnd, WM_GETTEXT, old_len, (LPARAM)hwndText); if (len+1 != old_len) hwndText = heap_realloc(hwndText, len+1); - SendMessageW(This->hwndListBox, LB_RESETCONTENT, 0, 0); + send_to_LB(This, This->hwndListBox, LB_RESETCONTENT, 0, 0); /* Set txtbackup to point to hwndText itself (which must not be released) */ heap_free(This->txtbackup); @@ -276,8 +296,7 @@ static LRESULT APIENTRY ACEditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, } else tmp = strs; - SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)tmp); - SendMessageW(hwnd, EM_SETSEL, len, strslen); + set_text_and_selection(This, hwnd, tmp, len, strslen); if (tmp != strs) heap_free(tmp); @@ -288,7 +307,7 @@ static LRESULT APIENTRY ACEditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, } if (This->options & ACO_AUTOSUGGEST) - SendMessageW(This->hwndListBox, LB_INSERTSTRING, -1, (LPARAM)strs); + send_to_LB(This, This->hwndListBox, LB_INSERTSTRING, -1, (LPARAM)strs); cpt++; } @@ -299,8 +318,8 @@ static LRESULT APIENTRY ACEditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, if (This->options & ACO_AUTOSUGGEST) { if (cpt) { RECT r; - UINT height = SendMessageW(This->hwndListBox, LB_GETITEMHEIGHT, 0, 0); - SendMessageW(This->hwndListBox, LB_CARETOFF, 0, 0); + UINT height = send_to_LB(This, This->hwndListBox, LB_GETITEMHEIGHT, 0, 0); + send_to_LB(This, This->hwndListBox, LB_CARETOFF, 0, 0); GetWindowRect(hwnd, &r); SetParent(This->hwndListBox, HWND_DESKTOP); /* It seems that Windows XP displays 7 lines at most @@ -338,24 +357,23 @@ static LRESULT APIENTRY ACLBoxSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, switch (uMsg) { case WM_MOUSEMOVE: - sel = SendMessageW(hwnd, LB_ITEMFROMPOINT, 0, lParam); - SendMessageW(hwnd, LB_SETCURSEL, sel, 0); + sel = send_to_LB(This, hwnd, LB_ITEMFROMPOINT, 0, lParam); + send_to_LB(This, hwnd, LB_SETCURSEL, sel, 0); break; case WM_LBUTTONDOWN: - sel = SendMessageW(hwnd, LB_GETCURSEL, 0, 0); + sel = send_to_LB(This, hwnd, LB_GETCURSEL, 0, 0); if (sel < 0) break; - len = SendMessageW(This->hwndListBox, LB_GETTEXTLEN, sel, 0); + len = send_to_LB(This, hwnd, LB_GETTEXTLEN, sel, 0); if ((msg = heap_alloc((len + 1)*sizeof(WCHAR)))) { - len = SendMessageW(hwnd, LB_GETTEXT, sel, (LPARAM)msg); - SendMessageW(This->hwndEdit, WM_SETTEXT, 0, (LPARAM)msg); - SendMessageW(This->hwndEdit, EM_SETSEL, 0, len); + len = send_to_LB(This, hwnd, LB_GETTEXT, sel, (LPARAM)msg); + set_text_and_selection(This, This->hwndEdit, msg, 0, len); ShowWindow(hwnd, SW_HIDE); heap_free(msg); } break; default: - return CallWindowProcW(This->wpOrigLBoxProc, hwnd, uMsg, wParam, lParam); + return send_to_LB(This, hwnd, uMsg, wParam, lParam); } return 0; } @@ -708,14 +726,14 @@ static HRESULT WINAPI IAutoCompleteDropDown_fnGetDropDownStatus( if (dropped) { int sel; - sel = SendMessageW(This->hwndListBox, LB_GETCURSEL, 0, 0); + sel = send_to_LB(This, This->hwndListBox, LB_GETCURSEL, 0, 0); if (sel >= 0) { DWORD len; - len = SendMessageW(This->hwndListBox, LB_GETTEXTLEN, sel, 0); + len = send_to_LB(This, This->hwndListBox, LB_GETTEXTLEN, sel, 0); *ppwszString = CoTaskMemAlloc((len+1)*sizeof(WCHAR)); - SendMessageW(This->hwndListBox, LB_GETTEXT, sel, (LPARAM)*ppwszString); + send_to_LB(This, This->hwndListBox, LB_GETTEXT, sel, (LPARAM)*ppwszString); } else *ppwszString = NULL; -- 1.9.1