a637988939f90a17de0cdd9b0afe729780184703
[reactos.git] / reactos / dll / win32 / shell32 / autocomplete.c
1 /*
2 * AutoComplete interfaces implementation.
3 *
4 * Copyright 2004 Maxime Bellengé <maxime.bellenge@laposte.net>
5 *
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.
10 *
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.
15 *
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
19 */
20
21 /*
22 Implemented:
23 - ACO_AUTOAPPEND style
24 - ACO_AUTOSUGGEST style
25 - ACO_UPDOWNKEYDROPSLIST style
26
27 - Handle pwzsRegKeyPath and pwszQuickComplete in Init
28
29 TODO:
30 - implement ACO_SEARCH style
31 - implement ACO_FILTERPREFIXES style
32 - implement ACO_USETAB style
33 - implement ACO_RTLREADING style
34
35 */
36
37 #include <precomp.h>
38
39
40 WINE_DEFAULT_DEBUG_CHANNEL(shell);
41
42 typedef struct
43 {
44 const IAutoCompleteVtbl *lpVtbl;
45 const IAutoComplete2Vtbl *lpvtblAutoComplete2;
46 LONG ref;
47 BOOL enabled;
48 HWND hwndEdit;
49 HWND hwndListBox;
50 WNDPROC wpOrigEditProc;
51 WNDPROC wpOrigLBoxProc;
52 WCHAR *txtbackup;
53 WCHAR *quickComplete;
54 IEnumString *enumstr;
55 AUTOCOMPLETEOPTIONS options;
56 } IAutoCompleteImpl;
57
58 static const IAutoCompleteVtbl acvt;
59 static const IAutoComplete2Vtbl ac2vt;
60
61 static IAutoCompleteImpl * impl_from_IAutoComplete2( IAutoComplete2 *iface )
62 {
63 return (IAutoCompleteImpl *)((char*)iface - FIELD_OFFSET(IAutoCompleteImpl, lpvtblAutoComplete2));
64 }
65
66
67 /*
68 converts This to an interface pointer
69 */
70 #define _IUnknown_(This) (IUnknown*)&(This->lpVtbl)
71 #define _IAutoComplete2_(This) (IAutoComplete2*)&(This->lpvtblAutoComplete2)
72
73 static LRESULT APIENTRY ACEditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
74 static LRESULT APIENTRY ACLBoxSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
75
76 /**************************************************************************
77 * IAutoComplete_Constructor
78 */
79 HRESULT WINAPI IAutoComplete_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv)
80 {
81 IAutoCompleteImpl *lpac;
82
83 if (pUnkOuter && !IsEqualIID (riid, &IID_IUnknown))
84 return CLASS_E_NOAGGREGATION;
85
86 lpac = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAutoCompleteImpl));
87 if (!lpac)
88 return E_OUTOFMEMORY;
89
90 lpac->ref = 1;
91 lpac->lpVtbl = &acvt;
92 lpac->lpvtblAutoComplete2 = &ac2vt;
93 lpac->enabled = TRUE;
94 lpac->enumstr = NULL;
95 lpac->options = ACO_AUTOAPPEND;
96 lpac->wpOrigEditProc = NULL;
97 lpac->hwndListBox = NULL;
98 lpac->txtbackup = NULL;
99 lpac->quickComplete = NULL;
100
101 if (!SUCCEEDED (IUnknown_QueryInterface (_IUnknown_ (lpac), riid, ppv))) {
102 IUnknown_Release (_IUnknown_ (lpac));
103 return E_NOINTERFACE;
104 }
105
106 TRACE("-- (%p)->\n",lpac);
107
108 return S_OK;
109 }
110
111 /**************************************************************************
112 * AutoComplete_QueryInterface
113 */
114 static HRESULT WINAPI IAutoComplete_fnQueryInterface(
115 IAutoComplete * iface,
116 REFIID riid,
117 LPVOID *ppvObj)
118 {
119 IAutoCompleteImpl *This = (IAutoCompleteImpl *)iface;
120
121 TRACE("(%p)->(\n\tIID:\t%s,%p)\n", This, shdebugstr_guid(riid), ppvObj);
122 *ppvObj = NULL;
123
124 if(IsEqualIID(riid, &IID_IUnknown))
125 {
126 *ppvObj = This;
127 }
128 else if(IsEqualIID(riid, &IID_IAutoComplete))
129 {
130 *ppvObj = (IAutoComplete*)This;
131 }
132 else if(IsEqualIID(riid, &IID_IAutoComplete2))
133 {
134 *ppvObj = _IAutoComplete2_ (This);
135 }
136
137 if (*ppvObj)
138 {
139 IAutoComplete_AddRef((IAutoComplete*)*ppvObj);
140 TRACE("-- Interface: (%p)->(%p)\n", ppvObj, *ppvObj);
141 return S_OK;
142 }
143 TRACE("-- Interface: E_NOINTERFACE\n");
144 return E_NOINTERFACE;
145 }
146
147 /******************************************************************************
148 * IAutoComplete_fnAddRef
149 */
150 static ULONG WINAPI IAutoComplete_fnAddRef(
151 IAutoComplete * iface)
152 {
153 IAutoCompleteImpl *This = (IAutoCompleteImpl *)iface;
154 ULONG refCount = InterlockedIncrement(&This->ref);
155
156 TRACE("(%p)->(%u)\n", This, refCount - 1);
157
158 return refCount;
159 }
160
161 /******************************************************************************
162 * IAutoComplete_fnRelease
163 */
164 static ULONG WINAPI IAutoComplete_fnRelease(
165 IAutoComplete * iface)
166 {
167 IAutoCompleteImpl *This = (IAutoCompleteImpl *)iface;
168 ULONG refCount = InterlockedDecrement(&This->ref);
169
170 TRACE("(%p)->(%u)\n", This, refCount + 1);
171
172 if (!refCount) {
173 TRACE(" destroying IAutoComplete(%p)\n",This);
174 HeapFree(GetProcessHeap(), 0, This->quickComplete);
175 HeapFree(GetProcessHeap(), 0, This->txtbackup);
176 if (This->hwndListBox)
177 DestroyWindow(This->hwndListBox);
178 if (This->enumstr)
179 IEnumString_Release(This->enumstr);
180 HeapFree(GetProcessHeap(), 0, This);
181 }
182 return refCount;
183 }
184
185 /******************************************************************************
186 * IAutoComplete_fnEnable
187 */
188 static HRESULT WINAPI IAutoComplete_fnEnable(
189 IAutoComplete * iface,
190 BOOL fEnable)
191 {
192 IAutoCompleteImpl *This = (IAutoCompleteImpl *)iface;
193
194 HRESULT hr = S_OK;
195
196 TRACE("(%p)->(%s)\n", This, (fEnable)?"true":"false");
197
198 This->enabled = fEnable;
199
200 return hr;
201 }
202
203 /******************************************************************************
204 * IAutoComplete_fnInit
205 */
206 static HRESULT WINAPI IAutoComplete_fnInit(
207 IAutoComplete * iface,
208 HWND hwndEdit,
209 IUnknown *punkACL,
210 LPCOLESTR pwzsRegKeyPath,
211 LPCOLESTR pwszQuickComplete)
212 {
213 IAutoCompleteImpl *This = (IAutoCompleteImpl *)iface;
214 static const WCHAR lbName[] = {'L','i','s','t','B','o','x',0};
215
216 TRACE("(%p)->(0x%08lx, %p, %s, %s)\n",
217 This, (long)hwndEdit, punkACL, debugstr_w(pwzsRegKeyPath), debugstr_w(pwszQuickComplete));
218
219 if (This->options & ACO_AUTOSUGGEST) TRACE(" ACO_AUTOSUGGEST\n");
220 if (This->options & ACO_AUTOAPPEND) TRACE(" ACO_AUTOAPPEND\n");
221 if (This->options & ACO_SEARCH) FIXME(" ACO_SEARCH not supported\n");
222 if (This->options & ACO_FILTERPREFIXES) FIXME(" ACO_FILTERPREFIXES not supported\n");
223 if (This->options & ACO_USETAB) FIXME(" ACO_USETAB not supported\n");
224 if (This->options & ACO_UPDOWNKEYDROPSLIST) TRACE(" ACO_UPDOWNKEYDROPSLIST\n");
225 if (This->options & ACO_RTLREADING) FIXME(" ACO_RTLREADING not supported\n");
226
227 This->hwndEdit = hwndEdit;
228
229 if (!SUCCEEDED (IUnknown_QueryInterface (punkACL, &IID_IEnumString, (LPVOID*)&This->enumstr))) {
230 TRACE("No IEnumString interface\n");
231 return E_NOINTERFACE;
232 }
233
234 This->wpOrigEditProc = (WNDPROC) SetWindowLongPtrW( hwndEdit, GWLP_WNDPROC, (LONG_PTR) ACEditSubclassProc);
235 SetWindowLongPtrW( hwndEdit, GWLP_USERDATA, (LONG_PTR)This);
236
237 if (This->options & ACO_AUTOSUGGEST) {
238 HWND hwndParent;
239
240 hwndParent = GetParent(This->hwndEdit);
241
242 /* FIXME : The listbox should be resizable with the mouse. WS_THICKFRAME looks ugly */
243 This->hwndListBox = CreateWindowExW(0, lbName, NULL,
244 WS_BORDER | WS_CHILD | WS_VSCROLL | LBS_HASSTRINGS | LBS_NOTIFY | LBS_NOINTEGRALHEIGHT,
245 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
246 hwndParent, NULL,
247 (HINSTANCE)GetWindowLongPtrW( hwndParent, GWLP_HINSTANCE ), NULL);
248
249 if (This->hwndListBox) {
250 This->wpOrigLBoxProc = (WNDPROC) SetWindowLongPtrW( This->hwndListBox, GWLP_WNDPROC, (LONG_PTR) ACLBoxSubclassProc);
251 SetWindowLongPtrW( This->hwndListBox, GWLP_USERDATA, (LONG_PTR)This);
252 }
253 }
254
255 if (pwzsRegKeyPath) {
256 WCHAR *key;
257 WCHAR result[MAX_PATH];
258 WCHAR *value;
259 HKEY hKey = 0;
260 LONG res;
261 LONG len;
262
263 /* pwszRegKeyPath contains the key as well as the value, so we split */
264 key = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (wcslen(pwzsRegKeyPath)+1)*sizeof(WCHAR));
265 wcscpy(key, pwzsRegKeyPath);
266 value = strrchrW(key, '\\');
267 *value = 0;
268 value++;
269 /* Now value contains the value and buffer the key */
270 res = RegOpenKeyExW(HKEY_CURRENT_USER, key, 0, KEY_READ, &hKey);
271 if (res != ERROR_SUCCESS) {
272 /* if the key is not found, MSDN states we must seek in HKEY_LOCAL_MACHINE */
273 res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hKey);
274 }
275 if (res == ERROR_SUCCESS) {
276 res = RegQueryValueW(hKey, value, result, &len);
277 if (res == ERROR_SUCCESS) {
278 This->quickComplete = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len*sizeof(WCHAR));
279 wcscpy(This->quickComplete, result);
280 }
281 RegCloseKey(hKey);
282 }
283 HeapFree(GetProcessHeap(), 0, key);
284 }
285
286 if ((pwszQuickComplete) && (!This->quickComplete)) {
287 This->quickComplete = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (wcslen(pwszQuickComplete)+1)*sizeof(WCHAR));
288 wcscpy(This->quickComplete, pwszQuickComplete);
289 }
290
291 return S_OK;
292 }
293
294 /**************************************************************************
295 * IAutoComplete_fnVTable
296 */
297 static const IAutoCompleteVtbl acvt =
298 {
299 IAutoComplete_fnQueryInterface,
300 IAutoComplete_fnAddRef,
301 IAutoComplete_fnRelease,
302 IAutoComplete_fnInit,
303 IAutoComplete_fnEnable,
304 };
305
306 /**************************************************************************
307 * AutoComplete2_QueryInterface
308 */
309 static HRESULT WINAPI IAutoComplete2_fnQueryInterface(
310 IAutoComplete2 * iface,
311 REFIID riid,
312 LPVOID *ppvObj)
313 {
314 IAutoCompleteImpl *This = impl_from_IAutoComplete2(iface);
315
316 TRACE ("(%p)->(%s,%p)\n", This, shdebugstr_guid (riid), ppvObj);
317
318 return IAutoComplete_QueryInterface((IAutoComplete*)This, riid, ppvObj);
319 }
320
321 /******************************************************************************
322 * IAutoComplete2_fnAddRef
323 */
324 static ULONG WINAPI IAutoComplete2_fnAddRef(
325 IAutoComplete2 * iface)
326 {
327 IAutoCompleteImpl *This = impl_from_IAutoComplete2(iface);
328
329 TRACE ("(%p)->(count=%u)\n", This, This->ref);
330
331 return IAutoComplete2_AddRef((IAutoComplete*)This);
332 }
333
334 /******************************************************************************
335 * IAutoComplete2_fnRelease
336 */
337 static ULONG WINAPI IAutoComplete2_fnRelease(
338 IAutoComplete2 * iface)
339 {
340 IAutoCompleteImpl *This = impl_from_IAutoComplete2(iface);
341
342 TRACE ("(%p)->(count=%u)\n", This, This->ref);
343
344 return IAutoComplete_Release((IAutoComplete*)This);
345 }
346
347 /******************************************************************************
348 * IAutoComplete2_fnEnable
349 */
350 static HRESULT WINAPI IAutoComplete2_fnEnable(
351 IAutoComplete2 * iface,
352 BOOL fEnable)
353 {
354 IAutoCompleteImpl *This = impl_from_IAutoComplete2(iface);
355
356 TRACE ("(%p)->(%s)\n", This, (fEnable)?"true":"false");
357
358 return IAutoComplete_Enable((IAutoComplete*)This, fEnable);
359 }
360
361 /******************************************************************************
362 * IAutoComplete2_fnInit
363 */
364 static HRESULT WINAPI IAutoComplete2_fnInit(
365 IAutoComplete2 * iface,
366 HWND hwndEdit,
367 IUnknown *punkACL,
368 LPCOLESTR pwzsRegKeyPath,
369 LPCOLESTR pwszQuickComplete)
370 {
371 IAutoCompleteImpl *This = impl_from_IAutoComplete2(iface);
372
373 TRACE("(%p)\n", This);
374
375 return IAutoComplete_Init((IAutoComplete*)This, hwndEdit, punkACL, pwzsRegKeyPath, pwszQuickComplete);
376 }
377
378 /**************************************************************************
379 * IAutoComplete_fnGetOptions
380 */
381 static HRESULT WINAPI IAutoComplete2_fnGetOptions(
382 IAutoComplete2 * iface,
383 DWORD *pdwFlag)
384 {
385 HRESULT hr = S_OK;
386
387 IAutoCompleteImpl *This = impl_from_IAutoComplete2(iface);
388
389 TRACE("(%p) -> (%p)\n", This, pdwFlag);
390
391 *pdwFlag = This->options;
392
393 return hr;
394 }
395
396 /**************************************************************************
397 * IAutoComplete_fnSetOptions
398 */
399 static HRESULT WINAPI IAutoComplete2_fnSetOptions(
400 IAutoComplete2 * iface,
401 DWORD dwFlag)
402 {
403 HRESULT hr = S_OK;
404
405 IAutoCompleteImpl *This = impl_from_IAutoComplete2(iface);
406
407 TRACE("(%p) -> (0x%x)\n", This, dwFlag);
408
409 This->options = dwFlag;
410
411 return hr;
412 }
413
414 /**************************************************************************
415 * IAutoComplete2_fnVTable
416 */
417 static const IAutoComplete2Vtbl ac2vt =
418 {
419 IAutoComplete2_fnQueryInterface,
420 IAutoComplete2_fnAddRef,
421 IAutoComplete2_fnRelease,
422 IAutoComplete2_fnInit,
423 IAutoComplete2_fnEnable,
424 /* IAutoComplete2 */
425 IAutoComplete2_fnSetOptions,
426 IAutoComplete2_fnGetOptions,
427 };
428
429 /*
430 Window procedure for autocompletion
431 */
432 static LRESULT APIENTRY ACEditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
433 {
434 IAutoCompleteImpl *This = (IAutoCompleteImpl *)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
435 LPOLESTR strs;
436 HRESULT hr;
437 WCHAR hwndText[255];
438 WCHAR *hwndQCText;
439 RECT r;
440 BOOL control, filled, displayall = FALSE;
441 int cpt, height, sel;
442
443 if (!This->enabled) return CallWindowProcW(This->wpOrigEditProc, hwnd, uMsg, wParam, lParam);
444
445 switch (uMsg)
446 {
447 case CB_SHOWDROPDOWN:
448 ShowWindow(This->hwndListBox, SW_HIDE);
449 break;
450 case WM_KILLFOCUS:
451 if ((This->options && ACO_AUTOSUGGEST) &&
452 ((HWND)wParam != This->hwndListBox))
453 {
454 ShowWindow(This->hwndListBox, SW_HIDE);
455 }
456 break;
457 case WM_KEYUP:
458
459 GetWindowTextW( hwnd, (LPWSTR)hwndText, 255);
460
461 switch(wParam) {
462 case VK_RETURN:
463 /* If quickComplete is set and control is pressed, replace the string */
464 control = GetKeyState(VK_CONTROL) & 0x8000;
465 if (control && This->quickComplete) {
466 hwndQCText = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
467 (wcslen(This->quickComplete)+wcslen(hwndText))*sizeof(WCHAR));
468 sel = swprintf(hwndQCText, This->quickComplete, hwndText);
469 SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)hwndQCText);
470 SendMessageW(hwnd, EM_SETSEL, 0, sel);
471 HeapFree(GetProcessHeap(), 0, hwndQCText);
472 }
473
474 ShowWindow(This->hwndListBox, SW_HIDE);
475 return 0;
476 case VK_LEFT:
477 case VK_RIGHT:
478 return 0;
479 case VK_UP:
480 case VK_DOWN:
481 /* Two cases here :
482 - if the listbox is not visible, displays it
483 with all the entries if the style ACO_UPDOWNKEYDROPSLIST
484 is present but does not select anything.
485 - if the listbox is visible, change the selection
486 */
487 if ( (This->options & (ACO_AUTOSUGGEST | ACO_UPDOWNKEYDROPSLIST))
488 && (!IsWindowVisible(This->hwndListBox) && (! *hwndText)) )
489 {
490 /* We must display all the entries */
491 displayall = TRUE;
492 } else {
493 if (IsWindowVisible(This->hwndListBox)) {
494 int count;
495
496 count = SendMessageW(This->hwndListBox, LB_GETCOUNT, 0, 0);
497 /* Change the selection */
498 sel = SendMessageW(This->hwndListBox, LB_GETCURSEL, 0, 0);
499 if (wParam == VK_UP)
500 sel = ((sel-1)<0)?count-1:sel-1;
501 else
502 sel = ((sel+1)>= count)?-1:sel+1;
503 SendMessageW(This->hwndListBox, LB_SETCURSEL, sel, 0);
504 if (sel != -1) {
505 WCHAR *msg;
506 int len;
507
508 len = SendMessageW(This->hwndListBox, LB_GETTEXTLEN, sel, (LPARAM)NULL);
509 msg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (len+1)*sizeof(WCHAR));
510 SendMessageW(This->hwndListBox, LB_GETTEXT, sel, (LPARAM)msg);
511 SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)msg);
512 SendMessageW(hwnd, EM_SETSEL, wcslen(msg), wcslen(msg));
513 HeapFree(GetProcessHeap(), 0, msg);
514 } else {
515 SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)This->txtbackup);
516 SendMessageW(hwnd, EM_SETSEL, wcslen(This->txtbackup), wcslen(This->txtbackup));
517 }
518 }
519 return 0;
520 }
521 break;
522 case VK_BACK:
523 case VK_DELETE:
524 if ((! *hwndText) && (This->options & ACO_AUTOSUGGEST)) {
525 ShowWindow(This->hwndListBox, SW_HIDE);
526 return CallWindowProcW(This->wpOrigEditProc, hwnd, uMsg, wParam, lParam);
527 }
528 if (This->options & ACO_AUTOAPPEND) {
529 DWORD b;
530 SendMessageW(hwnd, EM_GETSEL, (WPARAM)&b, (LPARAM)NULL);
531 if (b>1) {
532 hwndText[b-1] = '\0';
533 } else {
534 hwndText[0] = '\0';
535 SetWindowTextW(hwnd, hwndText);
536 }
537 }
538 break;
539 default:
540 ;
541 }
542
543 SendMessageW(This->hwndListBox, LB_RESETCONTENT, 0, 0);
544
545 HeapFree(GetProcessHeap(), 0, This->txtbackup);
546 This->txtbackup = HeapAlloc(GetProcessHeap(),
547 HEAP_ZERO_MEMORY, (wcslen(hwndText)+1)*sizeof(WCHAR));
548 wcscpy(This->txtbackup, hwndText);
549
550 /* Returns if there is no text to search and we doesn't want to display all the entries */
551 if ((!displayall) && (! *hwndText) )
552 break;
553
554 IEnumString_Reset(This->enumstr);
555 filled = FALSE;
556 for(cpt = 0;;) {
557 hr = IEnumString_Next(This->enumstr, 1, &strs, NULL);
558 if (hr != S_OK)
559 break;
560
561 if ((LPWSTR)strstrW(strs, hwndText) == strs) {
562
563 if (This->options & ACO_AUTOAPPEND) {
564 SetWindowTextW(hwnd, strs);
565 SendMessageW(hwnd, EM_SETSEL, wcslen(hwndText), wcslen(strs));
566 break;
567 }
568
569 if (This->options & ACO_AUTOSUGGEST) {
570 SendMessageW(This->hwndListBox, LB_ADDSTRING, 0, (LPARAM)strs);
571 filled = TRUE;
572 cpt++;
573 }
574 }
575 }
576
577 if (This->options & ACO_AUTOSUGGEST) {
578 if (filled) {
579 height = SendMessageW(This->hwndListBox, LB_GETITEMHEIGHT, 0, 0);
580 SendMessageW(This->hwndListBox, LB_CARETOFF, 0, 0);
581 GetWindowRect(hwnd, &r);
582 SetParent(This->hwndListBox, HWND_DESKTOP);
583 /* It seems that Windows XP displays 7 lines at most
584 and otherwise displays a vertical scroll bar */
585 SetWindowPos(This->hwndListBox, HWND_TOP,
586 r.left, r.bottom + 1, r.right - r.left, min(height * 7, height*(cpt+1)),
587 SWP_SHOWWINDOW );
588 } else {
589 ShowWindow(This->hwndListBox, SW_HIDE);
590 }
591 }
592
593 break;
594 default:
595 return CallWindowProcW(This->wpOrigEditProc, hwnd, uMsg, wParam, lParam);
596
597 }
598
599 return 0;
600 }
601
602 static LRESULT APIENTRY ACLBoxSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
603 {
604 IAutoCompleteImpl *This = (IAutoCompleteImpl *)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
605 WCHAR *msg;
606 int sel, len;
607
608 switch (uMsg) {
609 case WM_MOUSEMOVE:
610 sel = SendMessageW(hwnd, LB_ITEMFROMPOINT, 0, lParam);
611 SendMessageW(hwnd, LB_SETCURSEL, (WPARAM)sel, (LPARAM)0);
612 break;
613 case WM_LBUTTONDOWN:
614 sel = SendMessageW(hwnd, LB_GETCURSEL, 0, 0);
615 if (sel < 0)
616 break;
617 len = SendMessageW(This->hwndListBox, LB_GETTEXTLEN, sel, 0);
618 msg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (len+1)*sizeof(WCHAR));
619 SendMessageW(hwnd, LB_GETTEXT, sel, (LPARAM)msg);
620 SendMessageW(This->hwndEdit, WM_SETTEXT, 0, (LPARAM)msg);
621 SendMessageW(This->hwndEdit, EM_SETSEL, 0, wcslen(msg));
622 ShowWindow(hwnd, SW_HIDE);
623 HeapFree(GetProcessHeap(), 0, msg);
624 break;
625 default:
626 return CallWindowProcW(This->wpOrigLBoxProc, hwnd, uMsg, wParam, lParam);
627 }
628 return 0;
629 }