[PATCH 17/17] shell32/autocomplete: Use the optional IACList interface and IACList::Expand, if available

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


Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---

This enables Total Commander to show full paths on many edit boxes, like
on Windows, instead of just the current directory's entries.

I couldn't get the / delimiter to work at all on Windows XP, so MSDN is
probably wrong here. Despite that, I've actually added support for it in
this patch, as a Wine extension, to help with unix-style paths autocompletion
since we also support those.

After this patch series, it now matches Windows behavior very closely,
and it finally makes AutoComplete useable for me. :)

 dlls/shell32/autocomplete.c | 75 +++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 73 insertions(+), 2 deletions(-)

diff --git a/dlls/shell32/autocomplete.c b/dlls/shell32/autocomplete.c
index c145dc0..5262a9f 100644
--- a/dlls/shell32/autocomplete.c
+++ b/dlls/shell32/autocomplete.c
@@ -2,6 +2,7 @@
  *	AutoComplete interfaces implementation.
  *
  *	Copyright 2004	Maxime Bellengé <maxime.bellenge at laposte.net>
+ *	Copyright 2018	Gabriel Ivăncescu <gabrielopcode at gmail.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -23,7 +24,7 @@
   - ACO_AUTOAPPEND style
   - ACO_AUTOSUGGEST style
   - ACO_UPDOWNKEYDROPSLIST style
-
+  - IACList::Expand
   - Handle pwzsRegKeyPath and pwszQuickComplete in Init
 
   TODO:
@@ -78,6 +79,7 @@ typedef struct
     WCHAR *txtbackup;
     WCHAR *quickComplete;
     IEnumString *enumstr;
+    IACList *aclist;
 } IAutoCompleteImpl;
 
 static const WCHAR autocomplete_propertyW[] = {'W','i','n','e',' ','A','u','t','o',
@@ -117,6 +119,61 @@ static void hide_listbox(IAutoCompleteImpl *ac, HWND hwnd)
     send_to_LB(ac, hwnd, LB_RESETCONTENT, 0, 0);
 }
 
+static void aclist_expand(IAutoCompleteImpl *ac, WCHAR *txt)
+{
+    /* call IACList::Expand only when needed
+       '/' is allowed as a delim for unix paths */
+    WCHAR c, *p, *last_delim, *old_txt = ac->txtbackup;
+    size_t i = 0;
+
+    /* skip the shared prefix */
+    while ((c = tolowerW(txt[i])) == tolowerW(old_txt[i])) {
+        if (c == '\0')
+            return;
+        i++;
+    }
+
+    /* they differ at this point, check for a delim further in txt */
+    p = &txt[i];
+    while (*p != '\0') {
+        if (*p == '\\' || *p == '/') {
+            last_delim = p;
+            do {
+                p++;
+                if (*p == '\\' || *p == '/')
+                    last_delim = p;
+            } while(*p != '\0');
+            goto expand;
+        }
+        p++;
+    }
+
+    /* txt has no delim after i, check for a delim further in old_txt */
+    p = &old_txt[i];
+    while (*p != '\0') {
+        if (*p == '\\' || *p == '/') {
+            /* find the delim before i (if any) */
+            while (i--) {
+                if (txt[i] == '\\' || txt[i] == '/') {
+                    last_delim = &txt[i];
+                    goto expand;
+                }
+            }
+            break;  /* Windows doesn't expand without a delim */
+        }
+        p++;
+    }
+
+    /* they differ, but without any different delims, so no need to expand */
+    return;
+
+expand:
+    c = last_delim[1];
+    last_delim[1] = '\0';
+    IACList_Expand(ac->aclist, txt);
+    last_delim[1] = c;
+}
+
 static void destroy_autocomplete_object(IAutoCompleteImpl *ac)
 {
     ac->hwndEdit = NULL;
@@ -295,6 +352,16 @@ static LRESULT APIENTRY ACEditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam,
             if (len+1 != old_len)
                 hwndText = heap_realloc(hwndText, len+1);
 
+            /* Reset it here to simplify the logic in aclist_expand for
+               empty strings, since it tracks changes using txtbackup,
+               and Reset needs to be called before IACList::Expand */
+            IEnumString_Reset(This->enumstr);
+            if (This->aclist) {
+                aclist_expand(This, hwndText);
+                if (hwndText[len-1] == '\\' || hwndText[len-1] == '/')
+                    noautoappend = TRUE;
+            }
+
             /* Set txtbackup to point to hwndText itself (which must not be released) */
             heap_free(This->txtbackup);
             This->txtbackup = hwndText;
@@ -306,7 +373,6 @@ static LRESULT APIENTRY ACEditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam,
                 send_to_LB(This, This->hwndListBox, WM_SETREDRAW, FALSE, 0);
                 send_to_LB(This, This->hwndListBox, LB_RESETCONTENT, 0, 0);
             }
-            IEnumString_Reset(This->enumstr);
             for(cpt = 0;;) {
                 LPOLESTR strs = NULL;
                 ULONG fetched;
@@ -504,6 +570,8 @@ static ULONG WINAPI IAutoComplete2_fnRelease(
         heap_free(This->txtbackup);
         if (This->enumstr)
             IEnumString_Release(This->enumstr);
+        if (This->aclist)
+            IACList_Release(This->aclist);
         heap_free(This);
     }
     return refCount;
@@ -567,6 +635,9 @@ static HRESULT WINAPI IAutoComplete2_fnInit(
         return E_NOINTERFACE;
     }
 
+    if (FAILED (IUnknown_QueryInterface (punkACL, &IID_IACList, (LPVOID*)&This->aclist)))
+        This->aclist = NULL;
+
     This->initialized = TRUE;
     This->hwndEdit = hwndEdit;
 
-- 
1.9.1




More information about the wine-devel mailing list