[PATCH v3 3/6] shell32/autocomplete: Implement a cache and sort the enumerated strings for proper behavior

Huw Davies huw at codeweavers.com
Tue Oct 30 05:14:44 CDT 2018


On Thu, Oct 25, 2018 at 09:04:52PM +0300, Gabriel Ivăncescu wrote:
> Windows doesn't reset and re-enumerate it everytime autocompletion happens,
> and it also sorts the strings. This matches it more closely and makes it
> more useable on large lists as well.
> 
> Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
> ---
>  dlls/shell32/autocomplete.c | 207 +++++++++++++++++++++++++++++++++-----------
>  1 file changed, 157 insertions(+), 50 deletions(-)
> 
> diff --git a/dlls/shell32/autocomplete.c b/dlls/shell32/autocomplete.c
> index b3f86f3..9cfce4b 100644
> --- a/dlls/shell32/autocomplete.c
> +++ b/dlls/shell32/autocomplete.c
> @@ -25,7 +25,6 @@
>    - implement ACO_FILTERPREFIXES style
>    - implement ACO_RTLREADING style
>    - implement ResetEnumerator
> -  - string compares should be case-insensitive, the content of the list should be sorted
>    
>   */
>  #include "config.h"
> @@ -62,6 +61,8 @@ typedef struct
>      LONG ref;
>      BOOL initialized;
>      BOOL enabled;
> +    UINT enum_strs_num;
> +    WCHAR **enum_strs;
>      HWND hwndEdit;
>      HWND hwndListBox;
>      WNDPROC wpOrigEditProc;
> @@ -103,10 +104,102 @@ static void set_text_and_selection(IAutoCompleteImpl *ac, HWND hwnd, WCHAR *text
>          CallWindowProcW(proc, hwnd, EM_SETSEL, start, end);
>  }
>  
> +static int enumerate_strings_cmpfn(const void *a, const void *b)
> +{
> +    return strcmpiW(*(WCHAR* const*)a, *(WCHAR* const*)b);
> +}
> +
> +static void enumerate_strings(IAutoCompleteImpl *ac)
> +{
> +    /*
> +       Enumerate all of the strings and sort them in the internal list.
> +
> +       We don't free the enumerated strings (except on error) to avoid needless
> +       copies, until the next reset (or the object itself is destroyed)
> +    */
> +    UINT i, cur, array_size = 1024, curblock_size = array_size, numstrs = 0;
> +    LPOLESTR *strs = NULL, *tmp;
> +
> +    for (;;)
> +    {
> +        LONG rem;
> +        BOOL break_enum = FALSE;
> +
> +        if ((tmp = heap_realloc(strs, array_size * sizeof(*strs))) == NULL)
> +            goto fail;
> +        strs = tmp;
> +        rem = curblock_size;
> +
> +        while (rem > 0)
> +        {
> +            ULONG n = 0;
> +            cur = array_size - rem;
> +            IEnumString_Next(ac->enumstr, rem, &strs[cur], &n);
> +            if (n == 0)
> +            {
> +                break_enum = TRUE;
> +                break;
> +            }
> +            rem -= n;
> +        }
> +        if (break_enum) break;
> +        curblock_size = array_size;
> +        array_size += curblock_size;
> +    }
> +
> +    /* Allocate even if there were zero strings enumerated, to mark it non-NULL */
> +    numstrs = cur;

There are too many variables tracking size in this block which makes the whole
thing confusing.  You should just need array_size, cur and n.   If you really
need a boolean to break out of the outer loop then name that variable 'done'
and change the for (;;) -> while (!done)

Huw.



More information about the wine-devel mailing list