shell32/autocomplete: Remove the property after replacing the callback instead of...
[wine.git] / dlls / shell32 / autocomplete.c
blobe3fe1fd3941523abf673d8b35de0dc9ccccaf715
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 size_t format_quick_complete(WCHAR *dst, const WCHAR *qc, const WCHAR *str, size_t str_len)
105 /* Replace the first %s directly without using snprintf, to avoid
106 exploits since the format string can be retrieved from the registry */
107 WCHAR *base = dst;
108 UINT args = 0;
109 while (*qc != '\0')
111 if (qc[0] == '%')
113 if (args < 1 && qc[1] == 's')
115 memcpy(dst, str, str_len * sizeof(WCHAR));
116 dst += str_len;
117 qc += 2;
118 args++;
119 continue;
121 qc += (qc[1] == '%');
123 *dst++ = *qc++;
125 *dst = '\0';
126 return dst - base;
129 static void autoappend_str(IAutoCompleteImpl *ac, WCHAR *text, UINT len, WCHAR *str, HWND hwnd)
131 WCHAR *tmp;
132 size_t size;
134 /* The character capitalization can be different,
135 so merge text and str into a new string */
136 size = len + strlenW(&str[len]) + 1;
138 if ((tmp = heap_alloc(size * sizeof(*tmp))))
140 memcpy(tmp, text, len * sizeof(*tmp));
141 memcpy(&tmp[len], &str[len], (size - len) * sizeof(*tmp));
143 else tmp = str;
145 SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)tmp);
146 SendMessageW(hwnd, EM_SETSEL, len, size - 1);
147 if (tmp != str)
148 heap_free(tmp);
151 static void autocomplete_text(IAutoCompleteImpl *ac, HWND hwnd, enum autoappend_flag flag)
153 HRESULT hr;
154 WCHAR *text;
155 UINT cpt, size, len = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0);
157 if (flag != autoappend_flag_displayempty && len == 0)
159 if (ac->options & ACO_AUTOSUGGEST)
160 ShowWindow(ac->hwndListBox, SW_HIDE);
161 return;
164 size = len + 1;
165 if (!(text = heap_alloc(size * sizeof(WCHAR))))
166 return;
167 len = SendMessageW(hwnd, WM_GETTEXT, size, (LPARAM)text);
168 if (len + 1 != size)
169 text = heap_realloc(text, (len + 1) * sizeof(WCHAR));
171 SendMessageW(ac->hwndListBox, LB_RESETCONTENT, 0, 0);
173 /* Set txtbackup to point to text itself (which must not be released) */
174 heap_free(ac->txtbackup);
175 ac->txtbackup = text;
177 IEnumString_Reset(ac->enumstr);
178 for (cpt = 0;;)
180 LPOLESTR strs = NULL;
181 ULONG fetched;
183 hr = IEnumString_Next(ac->enumstr, 1, &strs, &fetched);
184 if (hr != S_OK)
185 break;
187 if (!strncmpiW(text, strs, len))
189 if (cpt == 0 && flag == autoappend_flag_yes)
191 autoappend_str(ac, text, len, strs, hwnd);
192 if (!(ac->options & ACO_AUTOSUGGEST))
194 CoTaskMemFree(strs);
195 break;
199 if (ac->options & ACO_AUTOSUGGEST)
200 SendMessageW(ac->hwndListBox, LB_ADDSTRING, 0, (LPARAM)strs);
202 cpt++;
205 CoTaskMemFree(strs);
208 if (ac->options & ACO_AUTOSUGGEST)
210 if (cpt)
212 RECT r;
213 UINT height = SendMessageW(ac->hwndListBox, LB_GETITEMHEIGHT, 0, 0);
214 SendMessageW(ac->hwndListBox, LB_CARETOFF, 0, 0);
215 GetWindowRect(hwnd, &r);
216 SetParent(ac->hwndListBox, HWND_DESKTOP);
217 /* It seems that Windows XP displays 7 lines at most
218 and otherwise displays a vertical scroll bar */
219 SetWindowPos(ac->hwndListBox, HWND_TOP,
220 r.left, r.bottom + 1, r.right - r.left, height * min(cpt + 1, 7),
221 SWP_SHOWWINDOW );
223 else
224 ShowWindow(ac->hwndListBox, SW_HIDE);
228 static void destroy_autocomplete_object(IAutoCompleteImpl *ac)
230 ac->hwndEdit = NULL;
231 if (ac->hwndListBox)
232 DestroyWindow(ac->hwndListBox);
233 IAutoComplete2_Release(&ac->IAutoComplete2_iface);
237 Helper for ACEditSubclassProc
239 static LRESULT ACEditSubclassProc_KeyDown(IAutoCompleteImpl *ac, HWND hwnd, UINT uMsg,
240 WPARAM wParam, LPARAM lParam)
242 switch (wParam)
244 case VK_RETURN:
245 /* If quickComplete is set and control is pressed, replace the string */
246 if (ac->quickComplete && (GetKeyState(VK_CONTROL) & 0x8000))
248 WCHAR *text, *buf;
249 size_t sz;
250 UINT len = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0);
251 if (!(text = heap_alloc((len + 1) * sizeof(WCHAR))))
252 return 0;
253 len = SendMessageW(hwnd, WM_GETTEXT, len + 1, (LPARAM)text);
254 sz = strlenW(ac->quickComplete) + 1 + len;
256 if ((buf = heap_alloc(sz * sizeof(WCHAR))))
258 len = format_quick_complete(buf, ac->quickComplete, text, len);
259 SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)buf);
260 SendMessageW(hwnd, EM_SETSEL, 0, len);
261 heap_free(buf);
264 if (ac->options & ACO_AUTOSUGGEST)
265 ShowWindow(ac->hwndListBox, SW_HIDE);
266 heap_free(text);
267 return 0;
270 if (ac->options & ACO_AUTOSUGGEST)
271 ShowWindow(ac->hwndListBox, SW_HIDE);
272 break;
273 case VK_UP:
274 case VK_DOWN:
275 /* Two cases here:
276 - if the listbox is not visible and ACO_UPDOWNKEYDROPSLIST is
277 set, display it with all the entries, without selecting any
278 - if the listbox is visible, change the selection
280 if (!(ac->options & ACO_AUTOSUGGEST))
281 break;
283 if (!IsWindowVisible(ac->hwndListBox))
285 if (ac->options & ACO_UPDOWNKEYDROPSLIST)
287 autocomplete_text(ac, hwnd, autoappend_flag_displayempty);
288 return 0;
291 else
293 INT count, sel;
294 count = SendMessageW(ac->hwndListBox, LB_GETCOUNT, 0, 0);
296 /* Change the selection */
297 sel = SendMessageW(ac->hwndListBox, LB_GETCURSEL, 0, 0);
298 if (wParam == VK_UP)
299 sel = ((sel - 1) < 0) ? count - 1 : sel - 1;
300 else
301 sel = ((sel + 1) >= count) ? -1 : sel + 1;
302 SendMessageW(ac->hwndListBox, LB_SETCURSEL, sel, 0);
303 if (sel >= 0)
305 WCHAR *msg;
306 UINT len;
308 len = SendMessageW(ac->hwndListBox, LB_GETTEXTLEN, sel, 0);
309 if (!(msg = heap_alloc((len + 1) * sizeof(WCHAR))))
310 return 0;
311 len = SendMessageW(ac->hwndListBox, LB_GETTEXT, sel, (LPARAM)msg);
312 SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)msg);
313 SendMessageW(hwnd, EM_SETSEL, len, len);
314 heap_free(msg);
316 else
318 UINT len;
319 SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)ac->txtbackup);
320 len = strlenW(ac->txtbackup);
321 SendMessageW(hwnd, EM_SETSEL, len, len);
323 return 0;
325 break;
326 case VK_DELETE:
328 LRESULT ret = CallWindowProcW(ac->wpOrigEditProc, hwnd, uMsg, wParam, lParam);
329 autocomplete_text(ac, hwnd, autoappend_flag_no);
330 return ret;
333 return CallWindowProcW(ac->wpOrigEditProc, hwnd, uMsg, wParam, lParam);
337 Window procedure for autocompletion
339 static LRESULT APIENTRY ACEditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
341 IAutoCompleteImpl *This = GetPropW(hwnd, autocomplete_propertyW);
342 LRESULT ret;
344 if (!This->enabled) return CallWindowProcW(This->wpOrigEditProc, hwnd, uMsg, wParam, lParam);
346 switch (uMsg)
348 case CB_SHOWDROPDOWN:
349 if (This->options & ACO_AUTOSUGGEST)
350 ShowWindow(This->hwndListBox, SW_HIDE);
351 break;
352 case WM_KILLFOCUS:
353 if ((This->options & ACO_AUTOSUGGEST) && ((HWND)wParam != This->hwndListBox))
355 ShowWindow(This->hwndListBox, SW_HIDE);
357 return CallWindowProcW(This->wpOrigEditProc, hwnd, uMsg, wParam, lParam);
358 case WM_KEYDOWN:
359 return ACEditSubclassProc_KeyDown(This, hwnd, uMsg, wParam, lParam);
360 case WM_CHAR:
361 case WM_UNICHAR:
362 ret = CallWindowProcW(This->wpOrigEditProc, hwnd, uMsg, wParam, lParam);
363 autocomplete_text(This, hwnd, (This->options & ACO_AUTOAPPEND) && wParam >= ' '
364 ? autoappend_flag_yes : autoappend_flag_no);
365 return ret;
366 case WM_DESTROY:
368 WNDPROC proc = This->wpOrigEditProc;
370 SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)proc);
371 RemovePropW(hwnd, autocomplete_propertyW);
372 destroy_autocomplete_object(This);
373 return CallWindowProcW(proc, hwnd, uMsg, wParam, lParam);
375 default:
376 return CallWindowProcW(This->wpOrigEditProc, hwnd, uMsg, wParam, lParam);
379 return 0;
382 static LRESULT APIENTRY ACLBoxSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
384 IAutoCompleteImpl *This = (IAutoCompleteImpl *)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
385 WCHAR *msg;
386 int sel, len;
388 switch (uMsg) {
389 case WM_MOUSEMOVE:
390 sel = SendMessageW(hwnd, LB_ITEMFROMPOINT, 0, lParam);
391 SendMessageW(hwnd, LB_SETCURSEL, sel, 0);
392 break;
393 case WM_LBUTTONDOWN:
394 sel = SendMessageW(hwnd, LB_GETCURSEL, 0, 0);
395 if (sel < 0)
396 break;
397 len = SendMessageW(This->hwndListBox, LB_GETTEXTLEN, sel, 0);
398 if (!(msg = heap_alloc((len + 1) * sizeof(WCHAR))))
399 break;
400 len = SendMessageW(hwnd, LB_GETTEXT, sel, (LPARAM)msg);
401 SendMessageW(This->hwndEdit, WM_SETTEXT, 0, (LPARAM)msg);
402 SendMessageW(This->hwndEdit, EM_SETSEL, 0, len);
403 ShowWindow(hwnd, SW_HIDE);
404 heap_free(msg);
405 break;
406 default:
407 return CallWindowProcW(This->wpOrigLBoxProc, hwnd, uMsg, wParam, lParam);
409 return 0;
412 static void create_listbox(IAutoCompleteImpl *This)
414 HWND hwndParent;
416 hwndParent = GetParent(This->hwndEdit);
418 /* FIXME : The listbox should be resizable with the mouse. WS_THICKFRAME looks ugly */
419 This->hwndListBox = CreateWindowExW(0, WC_LISTBOXW, NULL,
420 WS_BORDER | WS_CHILD | WS_VSCROLL | LBS_HASSTRINGS | LBS_NOTIFY | LBS_NOINTEGRALHEIGHT,
421 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
422 hwndParent, NULL, shell32_hInstance, NULL );
424 if (This->hwndListBox) {
425 This->wpOrigLBoxProc = (WNDPROC) SetWindowLongPtrW( This->hwndListBox, GWLP_WNDPROC, (LONG_PTR) ACLBoxSubclassProc);
426 SetWindowLongPtrW( This->hwndListBox, GWLP_USERDATA, (LONG_PTR)This);
428 else
429 This->options &= ~ACO_AUTOSUGGEST;
432 /**************************************************************************
433 * AutoComplete_QueryInterface
435 static HRESULT WINAPI IAutoComplete2_fnQueryInterface(
436 IAutoComplete2 * iface,
437 REFIID riid,
438 LPVOID *ppvObj)
440 IAutoCompleteImpl *This = impl_from_IAutoComplete2(iface);
442 TRACE("(%p)->(IID:%s,%p)\n", This, shdebugstr_guid(riid), ppvObj);
443 *ppvObj = NULL;
445 if (IsEqualIID(riid, &IID_IUnknown) ||
446 IsEqualIID(riid, &IID_IAutoComplete) ||
447 IsEqualIID(riid, &IID_IAutoComplete2))
449 *ppvObj = &This->IAutoComplete2_iface;
451 else if (IsEqualIID(riid, &IID_IAutoCompleteDropDown))
453 *ppvObj = &This->IAutoCompleteDropDown_iface;
456 if (*ppvObj)
458 IUnknown_AddRef((IUnknown*)*ppvObj);
459 TRACE("-- Interface: (%p)->(%p)\n", ppvObj, *ppvObj);
460 return S_OK;
462 WARN("unsupported interface: %s\n", debugstr_guid(riid));
463 return E_NOINTERFACE;
466 /******************************************************************************
467 * IAutoComplete2_fnAddRef
469 static ULONG WINAPI IAutoComplete2_fnAddRef(
470 IAutoComplete2 * iface)
472 IAutoCompleteImpl *This = impl_from_IAutoComplete2(iface);
473 ULONG refCount = InterlockedIncrement(&This->ref);
475 TRACE("(%p)->(%u)\n", This, refCount - 1);
477 return refCount;
480 /******************************************************************************
481 * IAutoComplete2_fnRelease
483 static ULONG WINAPI IAutoComplete2_fnRelease(
484 IAutoComplete2 * iface)
486 IAutoCompleteImpl *This = impl_from_IAutoComplete2(iface);
487 ULONG refCount = InterlockedDecrement(&This->ref);
489 TRACE("(%p)->(%u)\n", This, refCount + 1);
491 if (!refCount) {
492 TRACE("destroying IAutoComplete(%p)\n", This);
493 heap_free(This->quickComplete);
494 heap_free(This->txtbackup);
495 if (This->enumstr)
496 IEnumString_Release(This->enumstr);
497 heap_free(This);
499 return refCount;
502 /******************************************************************************
503 * IAutoComplete2_fnEnable
505 static HRESULT WINAPI IAutoComplete2_fnEnable(
506 IAutoComplete2 * iface,
507 BOOL fEnable)
509 IAutoCompleteImpl *This = impl_from_IAutoComplete2(iface);
510 HRESULT hr = S_OK;
512 TRACE("(%p)->(%s)\n", This, (fEnable)?"true":"false");
514 This->enabled = fEnable;
516 return hr;
519 /******************************************************************************
520 * IAutoComplete2_fnInit
522 static HRESULT WINAPI IAutoComplete2_fnInit(
523 IAutoComplete2 * iface,
524 HWND hwndEdit,
525 IUnknown *punkACL,
526 LPCOLESTR pwzsRegKeyPath,
527 LPCOLESTR pwszQuickComplete)
529 IAutoCompleteImpl *prev, *This = impl_from_IAutoComplete2(iface);
531 TRACE("(%p)->(%p, %p, %s, %s)\n",
532 This, hwndEdit, punkACL, debugstr_w(pwzsRegKeyPath), debugstr_w(pwszQuickComplete));
534 if (This->options & ACO_SEARCH) FIXME(" ACO_SEARCH not supported\n");
535 if (This->options & ACO_FILTERPREFIXES) FIXME(" ACO_FILTERPREFIXES not supported\n");
536 if (This->options & ACO_USETAB) FIXME(" ACO_USETAB not supported\n");
537 if (This->options & ACO_RTLREADING) FIXME(" ACO_RTLREADING not supported\n");
539 if (!hwndEdit || !punkACL)
540 return E_INVALIDARG;
542 if (This->initialized)
544 WARN("Autocompletion object is already initialized\n");
545 /* This->hwndEdit is set to NULL when the edit window is destroyed. */
546 return This->hwndEdit ? E_FAIL : E_UNEXPECTED;
549 if (FAILED (IUnknown_QueryInterface (punkACL, &IID_IEnumString, (LPVOID*)&This->enumstr))) {
550 WARN("No IEnumString interface\n");
551 return E_NOINTERFACE;
554 This->initialized = TRUE;
555 This->hwndEdit = hwndEdit;
557 /* If another AutoComplete object was previously assigned to this edit control,
558 release it but keep the same callback on the control, to avoid an infinite
559 recursive loop in ACEditSubclassProc while the property is set to this object */
560 prev = GetPropW(hwndEdit, autocomplete_propertyW);
561 SetPropW(hwndEdit, autocomplete_propertyW, This);
563 if (prev && prev->initialized) {
564 This->wpOrigEditProc = prev->wpOrigEditProc;
565 destroy_autocomplete_object(prev);
567 else
568 This->wpOrigEditProc = (WNDPROC) SetWindowLongPtrW(hwndEdit, GWLP_WNDPROC, (LONG_PTR) ACEditSubclassProc);
570 /* Keep at least one reference to the object until the edit window is destroyed */
571 IAutoComplete2_AddRef(&This->IAutoComplete2_iface);
573 if (This->options & ACO_AUTOSUGGEST)
574 create_listbox(This);
576 if (pwzsRegKeyPath)
578 static const HKEY roots[] = { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE };
579 WCHAR *key, *value;
580 DWORD type, sz;
581 BYTE *qc;
582 HKEY hKey;
583 LSTATUS res;
584 size_t len;
585 UINT i;
587 /* pwszRegKeyPath contains the key as well as the value, so split it */
588 value = strrchrW(pwzsRegKeyPath, '\\');
589 len = value - pwzsRegKeyPath;
591 if (value && (key = heap_alloc((len+1) * sizeof(*key))) != NULL)
593 memcpy(key, pwzsRegKeyPath, len * sizeof(*key));
594 key[len] = '\0';
595 value++;
597 for (i = 0; i < ARRAY_SIZE(roots); i++)
599 if (RegOpenKeyExW(roots[i], key, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
600 continue;
601 sz = MAX_PATH * sizeof(WCHAR);
603 while ((qc = heap_alloc(sz)) != NULL)
605 res = RegQueryValueExW(hKey, value, NULL, &type, qc, &sz);
606 if (res == ERROR_SUCCESS && type == REG_SZ)
608 This->quickComplete = heap_realloc(qc, sz);
609 i = ARRAY_SIZE(roots);
610 break;
612 heap_free(qc);
613 if (res != ERROR_MORE_DATA || type != REG_SZ)
614 break;
616 RegCloseKey(hKey);
618 heap_free(key);
622 if (!This->quickComplete && pwszQuickComplete)
624 size_t len = strlenW(pwszQuickComplete)+1;
625 if ((This->quickComplete = heap_alloc(len * sizeof(WCHAR))) != NULL)
626 memcpy(This->quickComplete, pwszQuickComplete, len * sizeof(WCHAR));
629 return S_OK;
632 /**************************************************************************
633 * IAutoComplete2_fnGetOptions
635 static HRESULT WINAPI IAutoComplete2_fnGetOptions(
636 IAutoComplete2 * iface,
637 DWORD *pdwFlag)
639 IAutoCompleteImpl *This = impl_from_IAutoComplete2(iface);
640 HRESULT hr = S_OK;
642 TRACE("(%p) -> (%p)\n", This, pdwFlag);
644 *pdwFlag = This->options;
646 return hr;
649 /**************************************************************************
650 * IAutoComplete2_fnSetOptions
652 static HRESULT WINAPI IAutoComplete2_fnSetOptions(
653 IAutoComplete2 * iface,
654 DWORD dwFlag)
656 IAutoCompleteImpl *This = impl_from_IAutoComplete2(iface);
657 HRESULT hr = S_OK;
659 TRACE("(%p) -> (0x%x)\n", This, dwFlag);
661 This->options = dwFlag;
663 if ((This->options & ACO_AUTOSUGGEST) && This->hwndEdit && !This->hwndListBox)
664 create_listbox(This);
666 return hr;
669 /**************************************************************************
670 * IAutoComplete2 VTable
672 static const IAutoComplete2Vtbl acvt =
674 IAutoComplete2_fnQueryInterface,
675 IAutoComplete2_fnAddRef,
676 IAutoComplete2_fnRelease,
677 IAutoComplete2_fnInit,
678 IAutoComplete2_fnEnable,
679 /* IAutoComplete2 */
680 IAutoComplete2_fnSetOptions,
681 IAutoComplete2_fnGetOptions,
685 static HRESULT WINAPI IAutoCompleteDropDown_fnQueryInterface(IAutoCompleteDropDown *iface,
686 REFIID riid, LPVOID *ppvObj)
688 IAutoCompleteImpl *This = impl_from_IAutoCompleteDropDown(iface);
689 return IAutoComplete2_QueryInterface(&This->IAutoComplete2_iface, riid, ppvObj);
692 static ULONG WINAPI IAutoCompleteDropDown_fnAddRef(IAutoCompleteDropDown *iface)
694 IAutoCompleteImpl *This = impl_from_IAutoCompleteDropDown(iface);
695 return IAutoComplete2_AddRef(&This->IAutoComplete2_iface);
698 static ULONG WINAPI IAutoCompleteDropDown_fnRelease(IAutoCompleteDropDown *iface)
700 IAutoCompleteImpl *This = impl_from_IAutoCompleteDropDown(iface);
701 return IAutoComplete2_Release(&This->IAutoComplete2_iface);
704 /**************************************************************************
705 * IAutoCompleteDropDown_fnGetDropDownStatus
707 static HRESULT WINAPI IAutoCompleteDropDown_fnGetDropDownStatus(
708 IAutoCompleteDropDown *iface,
709 DWORD *pdwFlags,
710 LPWSTR *ppwszString)
712 IAutoCompleteImpl *This = impl_from_IAutoCompleteDropDown(iface);
713 BOOL dropped;
715 TRACE("(%p) -> (%p, %p)\n", This, pdwFlags, ppwszString);
717 dropped = IsWindowVisible(This->hwndListBox);
719 if (pdwFlags)
720 *pdwFlags = (dropped ? ACDD_VISIBLE : 0);
722 if (ppwszString) {
723 if (dropped) {
724 int sel;
726 sel = SendMessageW(This->hwndListBox, LB_GETCURSEL, 0, 0);
727 if (sel >= 0)
729 DWORD len;
731 len = SendMessageW(This->hwndListBox, LB_GETTEXTLEN, sel, 0);
732 *ppwszString = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
733 SendMessageW(This->hwndListBox, LB_GETTEXT, sel, (LPARAM)*ppwszString);
735 else
736 *ppwszString = NULL;
738 else
739 *ppwszString = NULL;
742 return S_OK;
745 /**************************************************************************
746 * IAutoCompleteDropDown_fnResetEnumarator
748 static HRESULT WINAPI IAutoCompleteDropDown_fnResetEnumerator(
749 IAutoCompleteDropDown *iface)
751 IAutoCompleteImpl *This = impl_from_IAutoCompleteDropDown(iface);
753 FIXME("(%p): stub\n", This);
755 return E_NOTIMPL;
758 /**************************************************************************
759 * IAutoCompleteDropDown VTable
761 static const IAutoCompleteDropDownVtbl acdropdownvt =
763 IAutoCompleteDropDown_fnQueryInterface,
764 IAutoCompleteDropDown_fnAddRef,
765 IAutoCompleteDropDown_fnRelease,
766 IAutoCompleteDropDown_fnGetDropDownStatus,
767 IAutoCompleteDropDown_fnResetEnumerator,
770 /**************************************************************************
771 * IAutoComplete_Constructor
773 HRESULT WINAPI IAutoComplete_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv)
775 IAutoCompleteImpl *lpac;
776 HRESULT hr;
778 if (pUnkOuter && !IsEqualIID (riid, &IID_IUnknown))
779 return CLASS_E_NOAGGREGATION;
781 lpac = heap_alloc_zero(sizeof(*lpac));
782 if (!lpac)
783 return E_OUTOFMEMORY;
785 lpac->ref = 1;
786 lpac->IAutoComplete2_iface.lpVtbl = &acvt;
787 lpac->IAutoCompleteDropDown_iface.lpVtbl = &acdropdownvt;
788 lpac->enabled = TRUE;
789 lpac->options = ACO_AUTOAPPEND;
791 hr = IAutoComplete2_QueryInterface(&lpac->IAutoComplete2_iface, riid, ppv);
792 IAutoComplete2_Release(&lpac->IAutoComplete2_iface);
794 TRACE("-- (%p)->\n",lpac);
796 return hr;