[PATCH 1/3] shell32/autocomplete: Don't crash when there's another AutoComplete object on the same edit control

Gabriel Ivăncescu gabrielopcode at gmail.com
Mon Aug 27 12:10:46 CDT 2018


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=22333
Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---
 dlls/shell32/autocomplete.c | 33 +++++++++++++++++++++++++--------
 1 file changed, 25 insertions(+), 8 deletions(-)

diff --git a/dlls/shell32/autocomplete.c b/dlls/shell32/autocomplete.c
index 99ce23d..5fe48e9 100644
--- a/dlls/shell32/autocomplete.c
+++ b/dlls/shell32/autocomplete.c
@@ -93,6 +93,14 @@ static inline IAutoCompleteImpl *impl_from_IAutoCompleteDropDown(IAutoCompleteDr
     return CONTAINING_RECORD(iface, IAutoCompleteImpl, IAutoCompleteDropDown_iface);
 }
 
+static void destroy_autocomplete_object(IAutoCompleteImpl *ac)
+{
+    ac->hwndEdit = NULL;
+    if (ac->hwndListBox)
+        DestroyWindow(ac->hwndListBox);
+    IAutoComplete2_Release(&ac->IAutoComplete2_iface);
+}
+
 /*
   Window procedure for autocompletion
  */
@@ -276,10 +284,7 @@ static LRESULT APIENTRY ACEditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam,
 
             RemovePropW(hwnd, autocomplete_propertyW);
             SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)proc);
-            This->hwndEdit = NULL;
-            if (This->hwndListBox)
-                    DestroyWindow(This->hwndListBox);
-            IAutoComplete2_Release(&This->IAutoComplete2_iface);
+            destroy_autocomplete_object(This);
             return CallWindowProcW(proc, hwnd, uMsg, wParam, lParam);
         }
         default:
@@ -434,7 +439,7 @@ static HRESULT WINAPI IAutoComplete2_fnInit(
     LPCOLESTR pwzsRegKeyPath,
     LPCOLESTR pwszQuickComplete)
 {
-    IAutoCompleteImpl *This = impl_from_IAutoComplete2(iface);
+    IAutoCompleteImpl *Other, *This = impl_from_IAutoComplete2(iface);
 
     TRACE("(%p)->(%p, %p, %s, %s)\n",
 	  This, hwndEdit, punkACL, debugstr_w(pwzsRegKeyPath), debugstr_w(pwszQuickComplete));
@@ -461,10 +466,22 @@ static HRESULT WINAPI IAutoComplete2_fnInit(
 
     This->initialized = TRUE;
     This->hwndEdit = hwndEdit;
-    This->wpOrigEditProc = (WNDPROC) SetWindowLongPtrW( hwndEdit, GWLP_WNDPROC, (LONG_PTR) ACEditSubclassProc);
-    /* Keep at least one reference to the object until the edit window is destroyed. */
+
+    /* If another AutoComplete object was previously assigned to this edit control,
+       release it but keep the same callback on the control, to avoid an infinite
+       recursive loop in ACEditSubclassProc while the property is set to this object */
+    Other = GetPropW(hwndEdit, autocomplete_propertyW);
+    SetPropW(hwndEdit, autocomplete_propertyW, This);
+
+    if (Other && Other->initialized) {
+        This->wpOrigEditProc = Other->wpOrigEditProc;
+        destroy_autocomplete_object(Other);
+    }
+    else
+        This->wpOrigEditProc = (WNDPROC) SetWindowLongPtrW(hwndEdit, GWLP_WNDPROC, (LONG_PTR) ACEditSubclassProc);
+
+    /* Keep at least one reference to the object until the edit window is destroyed */
     IAutoComplete2_AddRef(&This->IAutoComplete2_iface);
-    SetPropW( hwndEdit, autocomplete_propertyW, This );
 
     if (This->options & ACO_AUTOSUGGEST)
         create_listbox(This);
-- 
1.9.1




More information about the wine-devel mailing list