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(a)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.