shell32/autocomplete: Send some messages directly to the edit control's procedure.
[wine.git] / dlls / shell32 / autocomplete.c
blob2f63d88b0541efc8df30514cf70aa26646c4042f
1 /*
2 * AutoComplete interfaces implementation.
4 * Copyright 2004 Maxime Bellengé <maxime.bellenge@laposte.net>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 Implemented:
23 - ACO_AUTOAPPEND style
24 - ACO_AUTOSUGGEST style
25 - ACO_UPDOWNKEYDROPSLIST style
27 - Handle pwzsRegKeyPath and pwszQuickComplete in Init
29 TODO:
30 - implement ACO_SEARCH style
31 - implement ACO_FILTERPREFIXES style
32 - implement ACO_USETAB style
33 - implement ACO_RTLREADING style
34 - implement ResetEnumerator
35 - string compares should be case-insensitive, the content of the list should be sorted
38 #include "config.h"
40 #include <stdarg.h>
41 #include <stdlib.h>
42 #include <string.h>
44 #define COBJMACROS
46 #include "wine/debug.h"
47 #include "windef.h"
48 #include "winbase.h"
49 #include "winreg.h"
50 #include "undocshell.h"
51 #include "shlwapi.h"
52 #include "winerror.h"
53 #include "objbase.h"
55 #include "pidl.h"
56 #include "shlobj.h"
57 #include "shldisp.h"
58 #include "debughlp.h"
59 #include "shell32_main.h"
61 #include "wine/unicode.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(shell);
65 typedef struct
67 IAutoComplete2 IAutoComplete2_iface;
68 IAutoCompleteDropDown IAutoCompleteDropDown_iface;
69 LONG ref;
70 BOOL initialized;
71 BOOL enabled;
72 HWND hwndEdit;
73 HWND hwndListBox;
74 WNDPROC wpOrigEditProc;
75 WNDPROC wpOrigLBoxProc;
76 WCHAR *txtbackup;
77 WCHAR *quickComplete;
78 IEnumString *enumstr;
79 AUTOCOMPLETEOPTIONS options;
80 } IAutoCompleteImpl;
82 enum autoappend_flag
84 autoappend_flag_yes,
85 autoappend_flag_no,
86 autoappend_flag_displayempty
89 static const WCHAR autocomplete_propertyW[] = {'W','i','n','e',' ','A','u','t','o',
90 'c','o','m','p','l','e','t','e',' ',
91 'c','o','n','t','r','o','l',0};
93 static inline IAutoCompleteImpl *impl_from_IAutoComplete2(IAutoComplete2 *iface)
95 return CONTAINING_RECORD(iface, IAutoCompleteImpl, IAutoComplete2_iface);
98 static inline IAutoCompleteImpl *impl_from_IAutoCompleteDropDown(IAutoCompleteDropDown *iface)
100 return CONTAINING_RECORD(iface, IAutoCompleteImpl, IAutoCompleteDropDown_iface);
103 static void set_text_and_selection(IAutoCompleteImpl *ac, HWND hwnd, WCHAR *text, WPARAM start, LPARAM end)
105 /* Send it directly to the edit control to match Windows behavior */
106 WNDPROC proc = ac->wpOrigEditProc;
107 if (CallWindowProcW(proc, hwnd, WM_SETTEXT, 0, (LPARAM)text))
108 CallWindowProcW(proc, hwnd, EM_SETSEL, start, end);
111 static size_t format_quick_complete(WCHAR *dst, const WCHAR *qc, const WCHAR *str, size_t str_len)
113 /* Replace the first %s directly without using snprintf, to avoid
114 exploits since the format string can be retrieved from the registry */
115 WCHAR *base = dst;
116 UINT args = 0;
117 while (*qc != '\0')
119 if (qc[0] == '%')
121 if (args < 1 && qc[1] == 's')
123 memcpy(dst, str, str_len * sizeof(WCHAR));
124 dst += str_len;
125 qc += 2;
126 args++;
127 continue;
129 qc += (qc[1] == '%');
131 *dst++ = *qc++;
133 *dst = '\0';
134 return dst - base;
137 static void autoappend_str(IAutoCompleteImpl *ac, WCHAR *text, UINT len, WCHAR *str, HWND hwnd)
139 WCHAR *tmp;
140 size_t size;
142 /* The character capitalization can be different,
143 so merge text and str into a new string */
144 size = len + strlenW(&str[len]) + 1;
146 if ((tmp = heap_alloc(size * sizeof(*tmp))))
148 memcpy(tmp, text, len * sizeof(*tmp));
149 memcpy(&tmp[len], &str[len], (size - len) * sizeof(*tmp));
151 else tmp = str;
153 set_text_and_selection(ac, hwnd, tmp, len, size - 1);
154 if (tmp != str)
155 heap_free(tmp);
158 static void autocomplete_text(IAutoCompleteImpl *ac, HWND hwnd, enum autoappend_flag flag)
160 HRESULT hr;
161 WCHAR *text;
162 UINT cpt, size, len = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0);
164 if (flag != autoappend_flag_displayempty && len == 0)
166 if (ac->options & ACO_AUTOSUGGEST)
167 ShowWindow(ac->hwndListBox, SW_HIDE);
168 return;
171 size = len + 1;
172 if (!(text = heap_alloc(size * sizeof(WCHAR))))
173 return;
174 len = SendMessageW(hwnd, WM_GETTEXT, size, (LPARAM)text);
175 if (len + 1 != size)
176 text = heap_realloc(text, (len + 1) * sizeof(WCHAR));
178 SendMessageW(ac->hwndListBox, LB_RESETCONTENT, 0, 0);
180 /* Set txtbackup to point to text itself (which must not be released) */
181 heap_free(ac->txtbackup);
182 ac->txtbackup = text;
184 IEnumString_Reset(ac->enumstr);
185 for (cpt = 0;;)
187 LPOLESTR strs = NULL;
188 ULONG fetched;
190 hr = IEnumString_Next(ac->enumstr, 1, &strs, &fetched);
191 if (hr != S_OK)
192 break;
194 if (!strncmpiW(text, strs, len))
196 if (cpt == 0 && flag == autoappend_flag_yes)
198 autoappend_str(ac, text, len, strs, hwnd);
199 if (!(ac->options & ACO_AUTOSUGGEST))
201 CoTaskMemFree(strs);
202 break;
206 if (ac->options & ACO_AUTOSUGGEST)
207 SendMessageW(ac->hwndListBox, LB_ADDSTRING, 0, (LPARAM)strs);
209 cpt++;
212 CoTaskMemFree(strs);
215 if (ac->options & ACO_AUTOSUGGEST)
217 if (cpt)
219 RECT r;
220 UINT height = SendMessageW(ac->hwndListBox, LB_GETITEMHEIGHT, 0, 0);
221 SendMessageW(ac->hwndListBox, LB_CARETOFF, 0, 0);
222 GetWindowRect(hwnd, &r);
223 SetParent(ac->hwndListBox, HWND_DESKTOP);
224 /* It seems that Windows XP displays 7 lines at most
225 and otherwise displays a vertical scroll bar */
226 SetWindowPos(ac->hwndListBox, HWND_TOP,
227 r.left, r.bottom + 1, r.right - r.left, height * min(cpt + 1, 7),
228 SWP_SHOWWINDOW );
230 else
231 ShowWindow(ac->hwndListBox, SW_HIDE);
235 static void destroy_autocomplete_object(IAutoCompleteImpl *ac)
237 ac->hwndEdit = NULL;
238 if (ac->hwndListBox)
239 DestroyWindow(ac->hwndListBox);
240 IAutoComplete2_Release(&ac->IAutoComplete2_iface);
244 Helper for ACEditSubclassProc
246 static LRESULT ACEditSubclassProc_KeyDown(IAutoCompleteImpl *ac, HWND hwnd, UINT uMsg,
247 WPARAM wParam, LPARAM lParam)
249 switch (wParam)
251 case VK_RETURN:
252 /* If quickComplete is set and control is pressed, replace the string */
253 if (ac->quickComplete && (GetKeyState(VK_CONTROL) & 0x8000))
255 WCHAR *text, *buf;
256 size_t sz;
257 UINT len = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0);
258 if (!(text = heap_alloc((len + 1) * sizeof(WCHAR))))
259 return 0;
260 len = SendMessageW(hwnd, WM_GETTEXT, len + 1, (LPARAM)text);
261 sz = strlenW(ac->quickComplete) + 1 + len;
263 if ((buf = heap_alloc(sz * sizeof(WCHAR))))
265 len = format_quick_complete(buf, ac->quickComplete, text, len);
266 set_text_and_selection(ac, hwnd, buf, 0, len);
267 heap_free(buf);
270 if (ac->options & ACO_AUTOSUGGEST)
271 ShowWindow(ac->hwndListBox, SW_HIDE);
272 heap_free(text);
273 return 0;
276 if (ac->options & ACO_AUTOSUGGEST)
277 ShowWindow(ac->hwndListBox, SW_HIDE);
278 break;
279 case VK_UP:
280 case VK_DOWN:
281 /* Two cases here:
282 - if the listbox is not visible and ACO_UPDOWNKEYDROPSLIST is
283 set, display it with all the entries, without selecting any
284 - if the listbox is visible, change the selection
286 if (!(ac->options & ACO_AUTOSUGGEST))
287 break;
289 if (!IsWindowVisible(ac->hwndListBox))
291 if (ac->options & ACO_UPDOWNKEYDROPSLIST)
293 autocomplete_text(ac, hwnd, autoappend_flag_displayempty);
294 return 0;
297 else
299 INT count, sel;
300 count = SendMessageW(ac->hwndListBox, LB_GETCOUNT, 0, 0);
302 /* Change the selection */
303 sel = SendMessageW(ac->hwndListBox, LB_GETCURSEL, 0, 0);
304 if (wParam == VK_UP)
305 sel = ((sel - 1) < -1) ? count - 1 : sel - 1;
306 else
307 sel = ((sel + 1) >= count) ? -1 : sel + 1;
308 SendMessageW(ac->hwndListBox, LB_SETCURSEL, sel, 0);
309 if (sel >= 0)
311 WCHAR *msg;
312 UINT len;
314 len = SendMessageW(ac->hwndListBox, LB_GETTEXTLEN, sel, 0);
315 if (!(msg = heap_alloc((len + 1) * sizeof(WCHAR))))
316 return 0;
317 len = SendMessageW(ac->hwndListBox, LB_GETTEXT, sel, (LPARAM)msg);
318 set_text_and_selection(ac, hwnd, msg, len, len);
319 heap_free(msg);
321 else
323 UINT len = strlenW(ac->txtbackup);
324 set_text_and_selection(ac, hwnd, ac->txtbackup, len, len);
326 return 0;
328 break;
329 case VK_DELETE:
331 LRESULT ret = CallWindowProcW(ac->wpOrigEditProc, hwnd, uMsg, wParam, lParam);
332 autocomplete_text(ac, hwnd, autoappend_flag_no);
333 return ret;
336 return CallWindowProcW(ac->wpOrigEditProc, hwnd, uMsg, wParam, lParam);
340 Window procedure for autocompletion
342 static LRESULT APIENTRY ACEditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
344 IAutoCompleteImpl *This = GetPropW(hwnd, autocomplete_propertyW);
345 LRESULT ret;
347 if (!This->enabled) return CallWindowProcW(This->wpOrigEditProc, hwnd, uMsg, wParam, lParam);
349 switch (uMsg)
351 case CB_SHOWDROPDOWN:
352 if (This->options & ACO_AUTOSUGGEST)
353 ShowWindow(This->hwndListBox, SW_HIDE);
354 return 0;
355 case WM_KILLFOCUS:
356 if ((This->options & ACO_AUTOSUGGEST) && ((HWND)wParam != This->hwndListBox))
358 ShowWindow(This->hwndListBox, SW_HIDE);
360 break;
361 case WM_KEYDOWN:
362 return ACEditSubclassProc_KeyDown(This, hwnd, uMsg, wParam, lParam);
363 case WM_CHAR:
364 case WM_UNICHAR:
365 /* Don't autocomplete at all on most control characters */
366 if (iscntrlW(wParam) && !(wParam >= '\b' && wParam <= '\r'))
367 break;
369 ret = CallWindowProcW(This->wpOrigEditProc, hwnd, uMsg, wParam, lParam);
370 autocomplete_text(This, hwnd, (This->options & ACO_AUTOAPPEND) && wParam >= ' '
371 ? autoappend_flag_yes : autoappend_flag_no);
372 return ret;
373 case WM_CUT:
374 case WM_CLEAR:
375 case WM_UNDO:
376 ret = CallWindowProcW(This->wpOrigEditProc, hwnd, uMsg, wParam, lParam);
377 autocomplete_text(This, hwnd, autoappend_flag_no);
378 return ret;
379 case WM_PASTE:
380 ret = CallWindowProcW(This->wpOrigEditProc, hwnd, uMsg, wParam, lParam);
381 autocomplete_text(This, hwnd, autoappend_flag_yes);
382 return ret;
383 case WM_DESTROY:
385 WNDPROC proc = This->wpOrigEditProc;
387 SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)proc);
388 RemovePropW(hwnd, autocomplete_propertyW);
389 destroy_autocomplete_object(This);
390 return CallWindowProcW(proc, hwnd, uMsg, wParam, lParam);
393 return CallWindowProcW(This->wpOrigEditProc, hwnd, uMsg, wParam, lParam);
396 static LRESULT APIENTRY ACLBoxSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
398 IAutoCompleteImpl *This = (IAutoCompleteImpl *)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
399 WCHAR *msg;
400 int sel, len;
402 switch (uMsg) {
403 case WM_MOUSEMOVE:
404 sel = SendMessageW(hwnd, LB_ITEMFROMPOINT, 0, lParam);
405 SendMessageW(hwnd, LB_SETCURSEL, sel, 0);
406 break;
407 case WM_LBUTTONDOWN:
408 sel = SendMessageW(hwnd, LB_GETCURSEL, 0, 0);
409 if (sel < 0)
410 break;
411 len = SendMessageW(This->hwndListBox, LB_GETTEXTLEN, sel, 0);
412 if (!(msg = heap_alloc((len + 1) * sizeof(WCHAR))))
413 break;
414 len = SendMessageW(hwnd, LB_GETTEXT, sel, (LPARAM)msg);
415 set_text_and_selection(This, This->hwndEdit, msg, 0, len);
416 ShowWindow(hwnd, SW_HIDE);
417 heap_free(msg);
418 break;
419 default:
420 return CallWindowProcW(This->wpOrigLBoxProc, hwnd, uMsg, wParam, lParam);
422 return 0;
425 static void create_listbox(IAutoCompleteImpl *This)
427 HWND hwndParent;
429 hwndParent = GetParent(This->hwndEdit);
431 /* FIXME : The listbox should be resizable with the mouse. WS_THICKFRAME looks ugly */
432 This->hwndListBox = CreateWindowExW(0, WC_LISTBOXW, NULL,
433 WS_BORDER | WS_CHILD | WS_VSCROLL | LBS_HASSTRINGS | LBS_NOTIFY | LBS_NOINTEGRALHEIGHT,
434 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
435 hwndParent, NULL, shell32_hInstance, NULL );
437 if (This->hwndListBox) {
438 This->wpOrigLBoxProc = (WNDPROC) SetWindowLongPtrW( This->hwndListBox, GWLP_WNDPROC, (LONG_PTR) ACLBoxSubclassProc);
439 SetWindowLongPtrW( This->hwndListBox, GWLP_USERDATA, (LONG_PTR)This);
441 else
442 This->options &= ~ACO_AUTOSUGGEST;
445 /**************************************************************************
446 * AutoComplete_QueryInterface
448 static HRESULT WINAPI IAutoComplete2_fnQueryInterface(
449 IAutoComplete2 * iface,
450 REFIID riid,
451 LPVOID *ppvObj)
453 IAutoCompleteImpl *This = impl_from_IAutoComplete2(iface);
455 TRACE("(%p)->(IID:%s,%p)\n", This, shdebugstr_guid(riid), ppvObj);
456 *ppvObj = NULL;
458 if (IsEqualIID(riid, &IID_IUnknown) ||
459 IsEqualIID(riid, &IID_IAutoComplete) ||
460 IsEqualIID(riid, &IID_IAutoComplete2))
462 *ppvObj = &This->IAutoComplete2_iface;
464 else if (IsEqualIID(riid, &IID_IAutoCompleteDropDown))
466 *ppvObj = &This->IAutoCompleteDropDown_iface;
469 if (*ppvObj)
471 IUnknown_AddRef((IUnknown*)*ppvObj);
472 TRACE("-- Interface: (%p)->(%p)\n", ppvObj, *ppvObj);
473 return S_OK;
475 WARN("unsupported interface: %s\n", debugstr_guid(riid));
476 return E_NOINTERFACE;
479 /******************************************************************************
480 * IAutoComplete2_fnAddRef
482 static ULONG WINAPI IAutoComplete2_fnAddRef(
483 IAutoComplete2 * iface)
485 IAutoCompleteImpl *This = impl_from_IAutoComplete2(iface);
486 ULONG refCount = InterlockedIncrement(&This->ref);
488 TRACE("(%p)->(%u)\n", This, refCount - 1);
490 return refCount;
493 /******************************************************************************
494 * IAutoComplete2_fnRelease
496 static ULONG WINAPI IAutoComplete2_fnRelease(
497 IAutoComplete2 * iface)
499 IAutoCompleteImpl *This = impl_from_IAutoComplete2(iface);
500 ULONG refCount = InterlockedDecrement(&This->ref);
502 TRACE("(%p)->(%u)\n", This, refCount + 1);
504 if (!refCount) {
505 TRACE("destroying IAutoComplete(%p)\n", This);
506 heap_free(This->quickComplete);
507 heap_free(This->txtbackup);
508 if (This->enumstr)
509 IEnumString_Release(This->enumstr);
510 heap_free(This);
512 return refCount;
515 /******************************************************************************
516 * IAutoComplete2_fnEnable
518 static HRESULT WINAPI IAutoComplete2_fnEnable(
519 IAutoComplete2 * iface,
520 BOOL fEnable)
522 IAutoCompleteImpl *This = impl_from_IAutoComplete2(iface);
523 HRESULT hr = S_OK;
525 TRACE("(%p)->(%s)\n", This, (fEnable)?"true":"false");
527 This->enabled = fEnable;
529 return hr;
532 /******************************************************************************
533 * IAutoComplete2_fnInit
535 static HRESULT WINAPI IAutoComplete2_fnInit(
536 IAutoComplete2 * iface,
537 HWND hwndEdit,
538 IUnknown *punkACL,
539 LPCOLESTR pwzsRegKeyPath,
540 LPCOLESTR pwszQuickComplete)
542 IAutoCompleteImpl *prev, *This = impl_from_IAutoComplete2(iface);
544 TRACE("(%p)->(%p, %p, %s, %s)\n",
545 This, hwndEdit, punkACL, debugstr_w(pwzsRegKeyPath), debugstr_w(pwszQuickComplete));
547 if (This->options & ACO_SEARCH) FIXME(" ACO_SEARCH not supported\n");
548 if (This->options & ACO_FILTERPREFIXES) FIXME(" ACO_FILTERPREFIXES not supported\n");
549 if (This->options & ACO_USETAB) FIXME(" ACO_USETAB not supported\n");
550 if (This->options & ACO_RTLREADING) FIXME(" ACO_RTLREADING not supported\n");
552 if (!hwndEdit || !punkACL)
553 return E_INVALIDARG;
555 if (This->initialized)
557 WARN("Autocompletion object is already initialized\n");
558 /* This->hwndEdit is set to NULL when the edit window is destroyed. */
559 return This->hwndEdit ? E_FAIL : E_UNEXPECTED;
562 if (FAILED (IUnknown_QueryInterface (punkACL, &IID_IEnumString, (LPVOID*)&This->enumstr))) {
563 WARN("No IEnumString interface\n");
564 return E_NOINTERFACE;
567 This->initialized = TRUE;
568 This->hwndEdit = hwndEdit;
570 /* If another AutoComplete object was previously assigned to this edit control,
571 release it but keep the same callback on the control, to avoid an infinite
572 recursive loop in ACEditSubclassProc while the property is set to this object */
573 prev = GetPropW(hwndEdit, autocomplete_propertyW);
574 SetPropW(hwndEdit, autocomplete_propertyW, This);
576 if (prev && prev->initialized) {
577 This->wpOrigEditProc = prev->wpOrigEditProc;
578 destroy_autocomplete_object(prev);
580 else
581 This->wpOrigEditProc = (WNDPROC) SetWindowLongPtrW(hwndEdit, GWLP_WNDPROC, (LONG_PTR) ACEditSubclassProc);
583 /* Keep at least one reference to the object until the edit window is destroyed */
584 IAutoComplete2_AddRef(&This->IAutoComplete2_iface);
586 if (This->options & ACO_AUTOSUGGEST)
587 create_listbox(This);
589 if (pwzsRegKeyPath)
591 static const HKEY roots[] = { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE };
592 WCHAR *key, *value;
593 DWORD type, sz;
594 BYTE *qc;
595 HKEY hKey;
596 LSTATUS res;
597 size_t len;
598 UINT i;
600 /* pwszRegKeyPath contains the key as well as the value, so split it */
601 value = strrchrW(pwzsRegKeyPath, '\\');
602 len = value - pwzsRegKeyPath;
604 if (value && (key = heap_alloc((len+1) * sizeof(*key))) != NULL)
606 memcpy(key, pwzsRegKeyPath, len * sizeof(*key));
607 key[len] = '\0';
608 value++;
610 for (i = 0; i < ARRAY_SIZE(roots); i++)
612 if (RegOpenKeyExW(roots[i], key, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
613 continue;
614 sz = MAX_PATH * sizeof(WCHAR);
616 while ((qc = heap_alloc(sz)) != NULL)
618 res = RegQueryValueExW(hKey, value, NULL, &type, qc, &sz);
619 if (res == ERROR_SUCCESS && type == REG_SZ)
621 This->quickComplete = heap_realloc(qc, sz);
622 i = ARRAY_SIZE(roots);
623 break;
625 heap_free(qc);
626 if (res != ERROR_MORE_DATA || type != REG_SZ)
627 break;
629 RegCloseKey(hKey);
631 heap_free(key);
635 if (!This->quickComplete && pwszQuickComplete)
637 size_t len = strlenW(pwszQuickComplete)+1;
638 if ((This->quickComplete = heap_alloc(len * sizeof(WCHAR))) != NULL)
639 memcpy(This->quickComplete, pwszQuickComplete, len * sizeof(WCHAR));
642 return S_OK;
645 /**************************************************************************
646 * IAutoComplete2_fnGetOptions
648 static HRESULT WINAPI IAutoComplete2_fnGetOptions(
649 IAutoComplete2 * iface,
650 DWORD *pdwFlag)
652 IAutoCompleteImpl *This = impl_from_IAutoComplete2(iface);
653 HRESULT hr = S_OK;
655 TRACE("(%p) -> (%p)\n", This, pdwFlag);
657 *pdwFlag = This->options;
659 return hr;
662 /**************************************************************************
663 * IAutoComplete2_fnSetOptions
665 static HRESULT WINAPI IAutoComplete2_fnSetOptions(
666 IAutoComplete2 * iface,
667 DWORD dwFlag)
669 IAutoCompleteImpl *This = impl_from_IAutoComplete2(iface);
670 HRESULT hr = S_OK;
672 TRACE("(%p) -> (0x%x)\n", This, dwFlag);
674 This->options = dwFlag;
676 if ((This->options & ACO_AUTOSUGGEST) && This->hwndEdit && !This->hwndListBox)
677 create_listbox(This);
679 return hr;
682 /**************************************************************************
683 * IAutoComplete2 VTable
685 static const IAutoComplete2Vtbl acvt =
687 IAutoComplete2_fnQueryInterface,
688 IAutoComplete2_fnAddRef,
689 IAutoComplete2_fnRelease,
690 IAutoComplete2_fnInit,
691 IAutoComplete2_fnEnable,
692 /* IAutoComplete2 */
693 IAutoComplete2_fnSetOptions,
694 IAutoComplete2_fnGetOptions,
698 static HRESULT WINAPI IAutoCompleteDropDown_fnQueryInterface(IAutoCompleteDropDown *iface,
699 REFIID riid, LPVOID *ppvObj)
701 IAutoCompleteImpl *This = impl_from_IAutoCompleteDropDown(iface);
702 return IAutoComplete2_QueryInterface(&This->IAutoComplete2_iface, riid, ppvObj);
705 static ULONG WINAPI IAutoCompleteDropDown_fnAddRef(IAutoCompleteDropDown *iface)
707 IAutoCompleteImpl *This = impl_from_IAutoCompleteDropDown(iface);
708 return IAutoComplete2_AddRef(&This->IAutoComplete2_iface);
711 static ULONG WINAPI IAutoCompleteDropDown_fnRelease(IAutoCompleteDropDown *iface)
713 IAutoCompleteImpl *This = impl_from_IAutoCompleteDropDown(iface);
714 return IAutoComplete2_Release(&This->IAutoComplete2_iface);
717 /**************************************************************************
718 * IAutoCompleteDropDown_fnGetDropDownStatus
720 static HRESULT WINAPI IAutoCompleteDropDown_fnGetDropDownStatus(
721 IAutoCompleteDropDown *iface,
722 DWORD *pdwFlags,
723 LPWSTR *ppwszString)
725 IAutoCompleteImpl *This = impl_from_IAutoCompleteDropDown(iface);
726 BOOL dropped;
728 TRACE("(%p) -> (%p, %p)\n", This, pdwFlags, ppwszString);
730 dropped = IsWindowVisible(This->hwndListBox);
732 if (pdwFlags)
733 *pdwFlags = (dropped ? ACDD_VISIBLE : 0);
735 if (ppwszString) {
736 if (dropped) {
737 int sel;
739 sel = SendMessageW(This->hwndListBox, LB_GETCURSEL, 0, 0);
740 if (sel >= 0)
742 DWORD len;
744 len = SendMessageW(This->hwndListBox, LB_GETTEXTLEN, sel, 0);
745 *ppwszString = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
746 SendMessageW(This->hwndListBox, LB_GETTEXT, sel, (LPARAM)*ppwszString);
748 else
749 *ppwszString = NULL;
751 else
752 *ppwszString = NULL;
755 return S_OK;
758 /**************************************************************************
759 * IAutoCompleteDropDown_fnResetEnumarator
761 static HRESULT WINAPI IAutoCompleteDropDown_fnResetEnumerator(
762 IAutoCompleteDropDown *iface)
764 IAutoCompleteImpl *This = impl_from_IAutoCompleteDropDown(iface);
766 FIXME("(%p): stub\n", This);
768 return E_NOTIMPL;
771 /**************************************************************************
772 * IAutoCompleteDropDown VTable
774 static const IAutoCompleteDropDownVtbl acdropdownvt =
776 IAutoCompleteDropDown_fnQueryInterface,
777 IAutoCompleteDropDown_fnAddRef,
778 IAutoCompleteDropDown_fnRelease,
779 IAutoCompleteDropDown_fnGetDropDownStatus,
780 IAutoCompleteDropDown_fnResetEnumerator,
783 /**************************************************************************
784 * IAutoComplete_Constructor
786 HRESULT WINAPI IAutoComplete_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv)
788 IAutoCompleteImpl *lpac;
789 HRESULT hr;
791 if (pUnkOuter && !IsEqualIID (riid, &IID_IUnknown))
792 return CLASS_E_NOAGGREGATION;
794 lpac = heap_alloc_zero(sizeof(*lpac));
795 if (!lpac)
796 return E_OUTOFMEMORY;
798 lpac->ref = 1;
799 lpac->IAutoComplete2_iface.lpVtbl = &acvt;
800 lpac->IAutoCompleteDropDown_iface.lpVtbl = &acdropdownvt;
801 lpac->enabled = TRUE;
802 lpac->options = ACO_AUTOAPPEND;
804 hr = IAutoComplete2_QueryInterface(&lpac->IAutoComplete2_iface, riid, ppv);
805 IAutoComplete2_Release(&lpac->IAutoComplete2_iface);
807 TRACE("-- (%p)->\n",lpac);
809 return hr;