[PATCH 10/17] shell32/autocomplete: Send messages directly to the edit control and AutoComplete listbox

Gabriel Ivăncescu gabrielopcode at gmail.com
Wed Sep 5 11:13:12 CDT 2018


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 <gabrielopcode at gmail.com>
---
 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




More information about the wine-devel mailing list