4 * Copyright 1997 Alex Korobka
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * FIXME: roll up in Netscape 3.01.
23 * COPYRIGHT: See COPYING in the top level directory
24 * PROJECT: ReactOS User32
25 * PURPOSE: combobox control
26 * FILE: lib/user32/controls/combo.c
27 * PROGRAMER: Steven Edwards
28 * REVISION HISTORY: 2003/06/25 SAE Created
29 * NOTES: Adapted from Wine
39 #include "user32/regcontrol.h"
42 /* bits in the dwKeyData */
43 #define KEYDATA_ALT 0x2000
44 #define KEYDATA_PREVSTATE 0x4000
47 * Additional combo box definitions
50 #define CB_NOTIFY( lphc, code ) \
51 (SendMessageW((lphc)->owner, WM_COMMAND, \
52 MAKEWPARAM(GetWindowLongA((lphc)->self,GWL_ID), (code)), (LPARAM)(lphc)->self))
54 #define CB_DISABLED( lphc ) (!IsWindowEnabled((lphc)->self))
55 #define CB_OWNERDRAWN( lphc ) ((lphc)->dwStyle & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE))
56 #define CB_HASSTRINGS( lphc ) ((lphc)->dwStyle & CBS_HASSTRINGS)
57 #define CB_HWND( lphc ) ((lphc)->self)
59 #define ISWIN31 (LOWORD(GetVersion()) == 0x0a03)
64 static HBITMAP hComboBmp
= 0;
65 static UINT CBitHeight
, CBitWidth
;
68 * Look and feel dependant "constants"
71 #define COMBO_YBORDERGAP 5
72 #define COMBO_XBORDERSIZE() ( 2 )
73 #define COMBO_YBORDERSIZE() ( 2 )
74 #define COMBO_EDITBUTTONSPACE() ( 0 )
75 #define EDIT_CONTROL_PADDING() ( 1 )
77 // static LRESULT WINAPI ComboWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
78 static LRESULT WINAPI
ComboWndProcW( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
);
80 /*********************************************************************
81 * combo class descriptor
83 const struct builtin_class_descr COMBO_builtin_class
=
85 L
"ComboBox", /* name */
86 CS_GLOBALCLASS
| CS_PARENTDC
| CS_DBLCLKS
, /* style */
87 (WNDPROC
) ComboWndProcW
, /* procW */
88 sizeof(HEADCOMBO
*), /* extra */
89 (LPCWSTR
) IDC_ARROW
, /* cursor */
94 /***********************************************************************
97 * Load combo button bitmap.
99 static BOOL
COMBO_Init()
103 if( hComboBmp
) return TRUE
;
104 if( (hDC
= CreateCompatibleDC(0)) )
107 if( (hComboBmp
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_COMBO
))) )
113 GetObjectW( hComboBmp
, sizeof(bm
), &bm
);
114 CBitHeight
= bm
.bmHeight
;
115 CBitWidth
= bm
.bmWidth
;
117 DbgPrint("combo bitmap [%i,%i]\n", CBitWidth
, CBitHeight
);
119 hPrevB
= SelectObject( hDC
, hComboBmp
);
120 SetRect( &r
, 0, 0, CBitWidth
, CBitHeight
);
121 InvertRect( hDC
, &r
);
122 SelectObject( hDC
, hPrevB
);
131 /***********************************************************************
134 static LRESULT
COMBO_NCCreate(HWND hwnd
, LONG style
)
138 if (COMBO_Init() && (lphc
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(HEADCOMBO
))) )
141 SetWindowLongA( hwnd
, 0, (LONG
)lphc
);
143 /* some braindead apps do try to use scrollbar/border flags */
145 lphc
->dwStyle
= style
& ~(WS_BORDER
| WS_HSCROLL
| WS_VSCROLL
);
146 SetWindowLongA( hwnd
, GWL_STYLE
, style
& ~(WS_BORDER
| WS_HSCROLL
| WS_VSCROLL
) );
149 * We also have to remove the client edge style to make sure
150 * we don't end-up with a non client area.
152 SetWindowLongA( hwnd
, GWL_EXSTYLE
,
153 GetWindowLongA( hwnd
, GWL_EXSTYLE
) & ~WS_EX_CLIENTEDGE
);
155 if( !(style
& (CBS_OWNERDRAWFIXED
| CBS_OWNERDRAWVARIABLE
)) )
156 lphc
->dwStyle
|= CBS_HASSTRINGS
;
157 if( !(GetWindowLongA( hwnd
, GWL_EXSTYLE
) & WS_EX_NOPARENTNOTIFY
) )
158 lphc
->wState
|= CBF_NOTIFY
;
160 DbgPrint("[%p], style = %08x\n", lphc
, lphc
->dwStyle
);
166 /***********************************************************************
169 static LRESULT
COMBO_NCDestroy( LPHEADCOMBO lphc
)
174 DbgPrint("[%p]: freeing storage\n", lphc
->self
);
176 if( (CB_GETTYPE(lphc
) != CBS_SIMPLE
) && lphc
->hWndLBox
)
177 DestroyWindow( lphc
->hWndLBox
);
179 SetWindowLongA( lphc
->self
, 0, 0 );
180 HeapFree( GetProcessHeap(), 0, lphc
);
185 /***********************************************************************
186 * CBGetTextAreaHeight
188 * This method will calculate the height of the text area of the
190 * The height of the text area is set in two ways.
191 * It can be set explicitly through a combobox message or through a
192 * WM_MEASUREITEM callback.
193 * If this is not the case, the height is set to 13 dialog units.
194 * This height was determined through experimentation.
196 static INT
CBGetTextAreaHeight(
202 if( lphc
->editHeight
) /* explicitly set height */
204 iTextItemHeight
= lphc
->editHeight
;
209 HDC hDC
= GetDC(hwnd
);
214 hPrevFont
= SelectObject( hDC
, lphc
->hFont
);
216 GetTextMetricsW(hDC
, &tm
);
218 baseUnitY
= tm
.tmHeight
;
221 SelectObject( hDC
, hPrevFont
);
223 ReleaseDC(hwnd
, hDC
);
226 iTextItemHeight
= ((13 * baseUnitY
) / 8);
229 * This "formula" calculates the height of the complete control.
230 * To calculate the height of the text area, we have to remove the
233 iTextItemHeight
-= 2*COMBO_YBORDERSIZE();
236 /* Joakim: This seems to work better, the old formula caused the combo box
237 to be waaay to big with big font sizes */
238 iTextItemHeight
= baseUnitY
+2*COMBO_YBORDERSIZE();
242 * Check the ownerdraw case if we haven't asked the parent the size
245 if ( CB_OWNERDRAWN(lphc
) &&
246 (lphc
->wState
& CBF_MEASUREITEM
) )
248 MEASUREITEMSTRUCT measureItem
;
250 INT originalItemHeight
= iTextItemHeight
;
251 UINT id
= GetWindowLongA( lphc
->self
, GWL_ID
);
254 * We use the client rect for the width of the item.
256 GetClientRect(hwnd
, &clientRect
);
258 lphc
->wState
&= ~CBF_MEASUREITEM
;
261 * Send a first one to measure the size of the text area
263 measureItem
.CtlType
= ODT_COMBOBOX
;
264 measureItem
.CtlID
= id
;
265 measureItem
.itemID
= -1;
266 measureItem
.itemWidth
= clientRect
.right
;
267 measureItem
.itemHeight
= iTextItemHeight
- 6; /* ownerdrawn cb is taller */
268 measureItem
.itemData
= 0;
269 SendMessageW(lphc
->owner
, WM_MEASUREITEM
, id
, (LPARAM
)&measureItem
);
270 iTextItemHeight
= 6 + measureItem
.itemHeight
;
273 * Send a second one in the case of a fixed ownerdraw list to calculate the
274 * size of the list items. (we basically do this on behalf of the listbox)
276 if (lphc
->dwStyle
& CBS_OWNERDRAWFIXED
)
278 measureItem
.CtlType
= ODT_COMBOBOX
;
279 measureItem
.CtlID
= id
;
280 measureItem
.itemID
= 0;
281 measureItem
.itemWidth
= clientRect
.right
;
282 measureItem
.itemHeight
= originalItemHeight
;
283 measureItem
.itemData
= 0;
284 SendMessageW(lphc
->owner
, WM_MEASUREITEM
, id
, (LPARAM
)&measureItem
);
285 lphc
->fixedOwnerDrawHeight
= measureItem
.itemHeight
;
289 * Keep the size for the next time
291 lphc
->editHeight
= iTextItemHeight
;
294 return iTextItemHeight
;
297 /***********************************************************************
300 * The dummy resize is used for listboxes that have a popup to trigger
301 * a re-arranging of the contents of the combobox and the recalculation
302 * of the size of the "real" control window.
304 static void CBForceDummyResize(
310 newComboHeight
= CBGetTextAreaHeight(lphc
->self
,lphc
) + 2*COMBO_YBORDERSIZE();
312 GetWindowRect(lphc
->self
, &windowRect
);
315 * We have to be careful, resizing a combobox also has the meaning that the
316 * dropped rect will be resized. In this case, we want to trigger a resize
317 * to recalculate layout but we don't want to change the dropped rectangle
318 * So, we pass the height of text area of control as the height.
319 * this will cancel-out in the processing of the WM_WINDOWPOSCHANGING
322 SetWindowPos( lphc
->self
,
325 windowRect
.right
- windowRect
.left
,
327 SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
330 /***********************************************************************
333 * Set up component coordinates given valid lphc->RectCombo.
335 static void CBCalcPlacement(
343 * Again, start with the client rectangle.
345 GetClientRect(hwnd
, lprEdit
);
350 InflateRect(lprEdit
, -COMBO_XBORDERSIZE(), -COMBO_YBORDERSIZE());
353 * Chop off the bottom part to fit with the height of the text area.
355 lprEdit
->bottom
= lprEdit
->top
+ CBGetTextAreaHeight(hwnd
, lphc
);
358 * The button starts the same vertical position as the text area.
360 CopyRect(lprButton
, lprEdit
);
363 * If the combobox is "simple" there is no button.
365 if( CB_GETTYPE(lphc
) == CBS_SIMPLE
)
366 lprButton
->left
= lprButton
->right
= lprButton
->bottom
= 0;
370 * Let's assume the combobox button is the same width as the
372 * size the button horizontally and cut-off the text area.
374 lprButton
->left
= lprButton
->right
- GetSystemMetrics(SM_CXVSCROLL
);
375 lprEdit
->right
= lprButton
->left
;
379 * In the case of a dropdown, there is an additional spacing between the
380 * text area and the button.
382 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
384 lprEdit
->right
-= COMBO_EDITBUTTONSPACE();
388 * If we have an edit control, we space it away from the borders slightly.
390 if (CB_GETTYPE(lphc
) != CBS_DROPDOWNLIST
)
392 InflateRect(lprEdit
, -EDIT_CONTROL_PADDING(), -EDIT_CONTROL_PADDING());
396 * Adjust the size of the listbox popup.
398 if( CB_GETTYPE(lphc
) == CBS_SIMPLE
)
401 * Use the client rectangle to initialize the listbox rectangle
403 GetClientRect(hwnd
, lprLB
);
406 * Then, chop-off the top part.
408 lprLB
->top
= lprEdit
->bottom
+ COMBO_YBORDERSIZE();
413 * Make sure the dropped width is as large as the combobox itself.
415 if (lphc
->droppedWidth
< (lprButton
->right
+ COMBO_XBORDERSIZE()))
417 lprLB
->right
= lprLB
->left
+ (lprButton
->right
+ COMBO_XBORDERSIZE());
420 * In the case of a dropdown, the popup listbox is offset to the right.
421 * so, we want to make sure it's flush with the right side of the
424 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
425 lprLB
->right
-= COMBO_EDITBUTTONSPACE();
428 lprLB
->right
= lprLB
->left
+ lphc
->droppedWidth
;
431 DbgPrint("\ttext\t= (%ld,%ld-%ld,%ld)\n",
432 lprEdit
->left
, lprEdit
->top
, lprEdit
->right
, lprEdit
->bottom
);
434 DbgPrint("\tbutton\t= (%ld,%ld-%ld,%ld)\n",
435 lprButton
->left
, lprButton
->top
, lprButton
->right
, lprButton
->bottom
);
437 DbgPrint("\tlbox\t= (%ld,%ld-%ld,%ld)\n",
438 lprLB
->left
, lprLB
->top
, lprLB
->right
, lprLB
->bottom
);
441 /***********************************************************************
442 * CBGetDroppedControlRect
444 static void CBGetDroppedControlRect( LPHEADCOMBO lphc
, LPRECT lpRect
)
446 /* In windows, CB_GETDROPPEDCONTROLRECT returns the upper left corner
447 of the combo box and the lower right corner of the listbox */
449 GetWindowRect(lphc
->self
, lpRect
);
451 lpRect
->right
= lpRect
->left
+ lphc
->droppedRect
.right
- lphc
->droppedRect
.left
;
452 lpRect
->bottom
= lpRect
->top
+ lphc
->droppedRect
.bottom
- lphc
->droppedRect
.top
;
456 /***********************************************************************
457 * COMBO_WindowPosChanging
459 static LRESULT
COMBO_WindowPosChanging(
462 WINDOWPOS
* posChanging
)
465 * We need to override the WM_WINDOWPOSCHANGING method to handle all
466 * the non-simple comboboxes. The problem is that those controls are
467 * always the same height. We have to make sure they are not resized
470 if ( ( CB_GETTYPE(lphc
) != CBS_SIMPLE
) &&
471 ((posChanging
->flags
& SWP_NOSIZE
) == 0) )
475 newComboHeight
= CBGetTextAreaHeight(hwnd
,lphc
) +
476 2*COMBO_YBORDERSIZE();
479 * Resizing a combobox has another side effect, it resizes the dropped
480 * rectangle as well. However, it does it only if the new height for the
481 * combobox is different from the height it should have. In other words,
482 * if the application resizing the combobox only had the intention to resize
483 * the actual control, for example, to do the layout of a dialog that is
484 * resized, the height of the dropdown is not changed.
486 if (posChanging
->cy
!= newComboHeight
)
488 DbgPrint("posChanging->cy=%d, newComboHeight=%d, oldbot=%ld, oldtop=%ld\n",
489 posChanging
->cy
, newComboHeight
, lphc
->droppedRect
.bottom
,
490 lphc
->droppedRect
.top
);
491 lphc
->droppedRect
.bottom
= lphc
->droppedRect
.top
+ posChanging
->cy
- newComboHeight
;
493 posChanging
->cy
= newComboHeight
;
500 /***********************************************************************
503 static LRESULT
COMBO_Create( HWND hwnd
, LPHEADCOMBO lphc
, HWND hwndParent
, LONG style
,
506 static const WCHAR clbName
[] = {'C','o','m','b','o','L','B','o','x',0};
507 static const WCHAR editName
[] = {'E','d','i','t',0};
509 if( !CB_GETTYPE(lphc
) ) lphc
->dwStyle
|= CBS_SIMPLE
;
510 if( CB_GETTYPE(lphc
) != CBS_DROPDOWNLIST
) lphc
->wState
|= CBF_EDIT
;
512 lphc
->owner
= hwndParent
;
515 * The item height and dropped width are not set when the control
518 lphc
->droppedWidth
= lphc
->editHeight
= 0;
521 * The first time we go through, we want to measure the ownerdraw item
523 lphc
->wState
|= CBF_MEASUREITEM
;
525 /* M$ IE 3.01 actually creates (and rapidly destroys) an ownerless combobox */
527 if( lphc
->owner
|| !(style
& WS_VISIBLE
) )
533 * Initialize the dropped rect to the size of the client area of the
534 * control and then, force all the areas of the combobox to be
537 GetClientRect( hwnd
, &lphc
->droppedRect
);
538 CBCalcPlacement(hwnd
, lphc
, &lphc
->textRect
, &lphc
->buttonRect
, &lphc
->droppedRect
);
541 * Adjust the position of the popup listbox if it's necessary
543 if ( CB_GETTYPE(lphc
) != CBS_SIMPLE
)
545 lphc
->droppedRect
.top
= lphc
->textRect
.bottom
+ COMBO_YBORDERSIZE();
548 * If it's a dropdown, the listbox is offset
550 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
551 lphc
->droppedRect
.left
+= COMBO_EDITBUTTONSPACE();
553 ClientToScreen(hwnd
, (LPPOINT
)&lphc
->droppedRect
);
554 ClientToScreen(hwnd
, (LPPOINT
)&lphc
->droppedRect
.right
);
557 /* create listbox popup */
559 lbeStyle
= (LBS_NOTIFY
| WS_BORDER
| WS_CLIPSIBLINGS
| WS_CHILD
) |
560 (style
& (WS_VSCROLL
| CBS_OWNERDRAWFIXED
| CBS_OWNERDRAWVARIABLE
));
562 if( lphc
->dwStyle
& CBS_SORT
)
563 lbeStyle
|= LBS_SORT
;
564 if( lphc
->dwStyle
& CBS_HASSTRINGS
)
565 lbeStyle
|= LBS_HASSTRINGS
;
566 if( lphc
->dwStyle
& CBS_NOINTEGRALHEIGHT
)
567 lbeStyle
|= LBS_NOINTEGRALHEIGHT
;
568 if( lphc
->dwStyle
& CBS_DISABLENOSCROLL
)
569 lbeStyle
|= LBS_DISABLENOSCROLL
;
571 if( CB_GETTYPE(lphc
) == CBS_SIMPLE
) /* child listbox */
573 lbeStyle
|= WS_VISIBLE
;
576 * In win 95 look n feel, the listbox in the simple combobox has
577 * the WS_EXCLIENTEDGE style instead of the WS_BORDER style.
579 //if (TWEAK_WineLook > WIN31_LOOK)
581 lbeStyle
&= ~WS_BORDER
;
582 lbeExStyle
|= WS_EX_CLIENTEDGE
;
587 lphc
->hWndLBox
= CreateWindowExW(lbeExStyle
, clbName
, NULL
, lbeStyle
,
588 lphc
->droppedRect
.left
,
589 lphc
->droppedRect
.top
,
590 lphc
->droppedRect
.right
- lphc
->droppedRect
.left
,
591 lphc
->droppedRect
.bottom
- lphc
->droppedRect
.top
,
592 hwnd
, (HMENU
)ID_CB_LISTBOX
,
593 (HINSTANCE
)GetWindowLongA( hwnd
, GWL_HINSTANCE
), lphc
);
595 lphc
->hWndLBox
= CreateWindowExA(lbeExStyle
, "ComboLBox", NULL
, lbeStyle
,
596 lphc
->droppedRect
.left
,
597 lphc
->droppedRect
.top
,
598 lphc
->droppedRect
.right
- lphc
->droppedRect
.left
,
599 lphc
->droppedRect
.bottom
- lphc
->droppedRect
.top
,
600 hwnd
, (HMENU
)ID_CB_LISTBOX
,
601 (HINSTANCE
)GetWindowLongA( hwnd
, GWL_HINSTANCE
), lphc
);
606 lbeStyle
= WS_CHILD
| WS_VISIBLE
| ES_NOHIDESEL
| ES_LEFT
| ES_COMBO
;
609 * In Win95 look, the border fo the edit control is
610 * provided by the combobox
612 //if (TWEAK_WineLook == WIN31_LOOK)
613 // lbeStyle |= WS_BORDER;
615 if( lphc
->wState
& CBF_EDIT
)
617 if( lphc
->dwStyle
& CBS_OEMCONVERT
)
618 lbeStyle
|= ES_OEMCONVERT
;
619 if( lphc
->dwStyle
& CBS_AUTOHSCROLL
)
620 lbeStyle
|= ES_AUTOHSCROLL
;
621 if( lphc
->dwStyle
& CBS_LOWERCASE
)
622 lbeStyle
|= ES_LOWERCASE
;
623 else if( lphc
->dwStyle
& CBS_UPPERCASE
)
624 lbeStyle
|= ES_UPPERCASE
;
626 if (!IsWindowEnabled(hwnd
)) lbeStyle
|= WS_DISABLED
;
629 lphc
->hWndEdit
= CreateWindowExW(0, editName
, NULL
, lbeStyle
,
630 lphc
->textRect
.left
, lphc
->textRect
.top
,
631 lphc
->textRect
.right
- lphc
->textRect
.left
,
632 lphc
->textRect
.bottom
- lphc
->textRect
.top
,
633 hwnd
, (HMENU
)ID_CB_EDIT
,
634 (HINSTANCE
)GetWindowLongA( hwnd
, GWL_HINSTANCE
), NULL
);
636 lphc
->hWndEdit
= CreateWindowExA(0, "Edit", NULL
, lbeStyle
,
637 lphc
->textRect
.left
, lphc
->textRect
.top
,
638 lphc
->textRect
.right
- lphc
->textRect
.left
,
639 lphc
->textRect
.bottom
- lphc
->textRect
.top
,
640 hwnd
, (HMENU
)ID_CB_EDIT
,
641 (HINSTANCE
)GetWindowLongA( hwnd
, GWL_HINSTANCE
), NULL
);
643 if( !lphc
->hWndEdit
)
649 if( CB_GETTYPE(lphc
) != CBS_SIMPLE
)
651 /* Now do the trick with parent */
652 SetParent(lphc
->hWndLBox
, HWND_DESKTOP
);
654 * If the combo is a dropdown, we must resize the control
655 * to fit only the text area and button. To do this,
656 * we send a dummy resize and the WM_WINDOWPOSCHANGING message
657 * will take care of setting the height for us.
659 CBForceDummyResize(lphc
);
662 OutputDebugStringA("init done\n");
665 OutputDebugStringA("edit control failure.\n");
666 } else OutputDebugStringA("listbox failure.\n");
667 } else OutputDebugStringA("no owner for visible combo.\n");
669 /* CreateWindow() will send WM_NCDESTROY to cleanup */
674 /***********************************************************************
677 * Paint combo button (normal, pressed, and disabled states).
679 static void CBPaintButton(
686 if( lphc
->wState
& CBF_NOREDRAW
)
689 buttonState
= DFCS_SCROLLCOMBOBOX
;
691 if (lphc
->wState
& CBF_BUTTONDOWN
)
693 buttonState
|= DFCS_PUSHED
;
696 if (CB_DISABLED(lphc
))
698 buttonState
|= DFCS_INACTIVE
;
701 DrawFrameControl(hdc
,
707 /***********************************************************************
710 * Paint CBS_DROPDOWNLIST text field / update edit control contents.
712 static void CBPaintText(
720 if( lphc
->wState
& CBF_NOREDRAW
) return;
722 OutputDebugStringA("\n");
724 /* follow Windows combobox that sends a bunch of text
725 * inquiries to its listbox while processing WM_PAINT. */
727 if( (id
= SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0) ) != LB_ERR
)
729 size
= SendMessageW(lphc
->hWndLBox
, LB_GETTEXTLEN
, id
, 0);
731 FIXME("LB_ERR probably not handled yet\n");
732 if( (pText
= HeapAlloc( GetProcessHeap(), 0, (size
+ 1) * sizeof(WCHAR
))) )
734 /* size from LB_GETTEXTLEN may be too large, from LB_GETTEXT is accurate */
735 size
=SendMessageW(lphc
->hWndLBox
, LB_GETTEXT
, (WPARAM
)id
, (LPARAM
)pText
);
736 pText
[size
] = '\0'; /* just in case */
740 if( !CB_OWNERDRAWN(lphc
) )
743 if( lphc
->wState
& CBF_EDIT
)
745 static const WCHAR empty_stringW
[] = { 0 };
746 if( CB_HASSTRINGS(lphc
) ) SetWindowTextW( lphc
->hWndEdit
, pText
? pText
: empty_stringW
);
747 if( lphc
->wState
& CBF_FOCUSED
)
748 SendMessageW(lphc
->hWndEdit
, EM_SETSEL
, 0, (LPARAM
)(-1));
750 else /* paint text field ourselves */
752 UINT itemState
= ODS_COMBOBOXEDIT
;
753 HFONT hPrevFont
= (lphc
->hFont
) ? SelectObject(hdc
, lphc
->hFont
) : 0;
756 * Give ourselves some space.
758 InflateRect( &rectEdit
, -1, -1 );
760 if( CB_OWNERDRAWN(lphc
) )
764 UINT ctlid
= GetWindowLongA( lphc
->self
, GWL_ID
);
766 /* setup state for DRAWITEM message. Owner will highlight */
767 if ( (lphc
->wState
& CBF_FOCUSED
) &&
768 !(lphc
->wState
& CBF_DROPPED
) )
769 itemState
|= ODS_SELECTED
| ODS_FOCUS
;
772 * Save the current clip region.
773 * To retrieve the clip region, we need to create one "dummy"
776 clipRegion
= CreateRectRgnIndirect(&rectEdit
);
778 if (GetClipRgn(hdc
, clipRegion
)!=1)
780 DeleteObject(clipRegion
);
784 if (!IsWindowEnabled(lphc
->self
) & WS_DISABLED
) itemState
|= ODS_DISABLED
;
786 dis
.CtlType
= ODT_COMBOBOX
;
788 dis
.hwndItem
= lphc
->self
;
789 dis
.itemAction
= ODA_DRAWENTIRE
;
791 dis
.itemState
= itemState
;
793 dis
.rcItem
= rectEdit
;
794 dis
.itemData
= SendMessageW(lphc
->hWndLBox
, LB_GETITEMDATA
,
798 * Clip the DC and have the parent draw the item.
800 IntersectClipRect(hdc
,
801 rectEdit
.left
, rectEdit
.top
,
802 rectEdit
.right
, rectEdit
.bottom
);
804 SendMessageW(lphc
->owner
, WM_DRAWITEM
, ctlid
, (LPARAM
)&dis
);
807 * Reset the clipping region.
809 SelectClipRgn(hdc
, clipRegion
);
813 static const WCHAR empty_stringW
[] = { 0 };
815 if ( (lphc
->wState
& CBF_FOCUSED
) &&
816 !(lphc
->wState
& CBF_DROPPED
) ) {
819 FillRect( hdc
, &rectEdit
, GetSysColorBrush(COLOR_HIGHLIGHT
) );
820 SetBkColor( hdc
, GetSysColor( COLOR_HIGHLIGHT
) );
821 SetTextColor( hdc
, GetSysColor( COLOR_HIGHLIGHTTEXT
) );
827 ETO_OPAQUE
| ETO_CLIPPED
,
829 pText
? pText
: empty_stringW
, size
, NULL
);
831 if(lphc
->wState
& CBF_FOCUSED
&& !(lphc
->wState
& CBF_DROPPED
))
832 DrawFocusRect( hdc
, &rectEdit
);
836 SelectObject(hdc
, hPrevFont
);
839 HeapFree( GetProcessHeap(), 0, pText
);
842 /***********************************************************************
845 static void CBPaintBorder(
852 if (CB_GETTYPE(lphc
) != CBS_SIMPLE
)
854 GetClientRect(hwnd
, &clientRect
);
858 CopyRect(&clientRect
, &lphc
->textRect
);
860 InflateRect(&clientRect
, EDIT_CONTROL_PADDING(), EDIT_CONTROL_PADDING());
861 InflateRect(&clientRect
, COMBO_XBORDERSIZE(), COMBO_YBORDERSIZE());
864 DrawEdge(hdc
, &clientRect
, EDGE_SUNKEN
, BF_RECT
);
867 /***********************************************************************
868 * COMBO_PrepareColors
870 * This method will sent the appropriate WM_CTLCOLOR message to
871 * prepare and setup the colors for the combo's DC.
873 * It also returns the brush to use for the background.
875 static HBRUSH
COMBO_PrepareColors(
882 * Get the background brush for this control.
884 if (CB_DISABLED(lphc
))
886 hBkgBrush
= (HBRUSH
)SendMessageW(lphc
->owner
, WM_CTLCOLORSTATIC
,
887 (WPARAM
)hDC
, (LPARAM
)lphc
->self
);
890 * We have to change the text color since WM_CTLCOLORSTATIC will
891 * set it to the "enabled" color. This is the same behavior as the
894 SetTextColor(hDC
, GetSysColor(COLOR_GRAYTEXT
));
898 if (lphc
->wState
& CBF_EDIT
)
900 hBkgBrush
= (HBRUSH
)SendMessageW(lphc
->owner
, WM_CTLCOLOREDIT
,
901 (WPARAM
)hDC
, (LPARAM
)lphc
->self
);
905 hBkgBrush
= (HBRUSH
)SendMessageW(lphc
->owner
, WM_CTLCOLORLISTBOX
,
906 (WPARAM
)hDC
, (LPARAM
)lphc
->self
);
914 hBkgBrush
= GetSysColorBrush(COLOR_WINDOW
);
919 /***********************************************************************
920 * COMBO_EraseBackground
922 static LRESULT
COMBO_EraseBackground(
930 if(lphc
->wState
& CBF_EDIT
)
933 hDC
= (hParamDC
) ? hParamDC
936 * Retrieve the background brush
938 hBkgBrush
= COMBO_PrepareColors(lphc
, hDC
);
940 FillRect(hDC
, &lphc
->textRect
, hBkgBrush
);
943 ReleaseDC(hwnd
, hDC
);
948 /***********************************************************************
951 static LRESULT
COMBO_Paint(LPHEADCOMBO lphc
, HDC hParamDC
)
956 hDC
= (hParamDC
) ? hParamDC
957 : BeginPaint( lphc
->self
, &ps
);
959 DbgPrint("hdc=%p\n", hDC
);
961 if( hDC
&& !(lphc
->wState
& CBF_NOREDRAW
) )
963 HBRUSH hPrevBrush
, hBkgBrush
;
966 * Retrieve the background brush and select it in the
969 hBkgBrush
= COMBO_PrepareColors(lphc
, hDC
);
971 hPrevBrush
= SelectObject( hDC
, hBkgBrush
);
974 * In non 3.1 look, there is a sunken border on the combobox
976 //if (TWEAK_WineLook != WIN31_LOOK)
978 CBPaintBorder(lphc
->self
, lphc
, hDC
);
981 if( !IsRectEmpty(&lphc
->buttonRect
) )
983 CBPaintButton(lphc
, hDC
, lphc
->buttonRect
);
986 /* paint the edit control padding area */
987 if (CB_GETTYPE(lphc
) != CBS_DROPDOWNLIST
)
989 RECT rPadEdit
= lphc
->textRect
;
991 InflateRect(&rPadEdit
, EDIT_CONTROL_PADDING(), EDIT_CONTROL_PADDING());
993 FrameRect( hDC
, &rPadEdit
, GetSysColorBrush(COLOR_WINDOW
) );
996 if( !(lphc
->wState
& CBF_EDIT
) )
998 CBPaintText( lphc
, hDC
, lphc
->textRect
);
1002 SelectObject( hDC
, hPrevBrush
);
1006 EndPaint(lphc
->self
, &ps
);
1011 /***********************************************************************
1014 * Select listbox entry according to the contents of the edit control.
1016 static INT
CBUpdateLBox( LPHEADCOMBO lphc
, BOOL bSelect
)
1019 LPWSTR pText
= NULL
;
1022 length
= SendMessageW( lphc
->hWndEdit
, WM_GETTEXTLENGTH
, 0, 0 );
1025 pText
= HeapAlloc( GetProcessHeap(), 0, (length
+ 1) * sizeof(WCHAR
));
1027 DbgPrint("\t edit text length %i\n", length
);
1031 if( length
) GetWindowTextW( lphc
->hWndEdit
, pText
, length
+ 1);
1032 else pText
[0] = '\0';
1033 idx
= SendMessageW(lphc
->hWndLBox
, LB_FINDSTRING
,
1034 (WPARAM
)(-1), (LPARAM
)pText
);
1035 HeapFree( GetProcessHeap(), 0, pText
);
1038 SendMessageW(lphc
->hWndLBox
, LB_SETCURSEL
, (WPARAM
)(bSelect
? idx
: -1), 0);
1040 /* probably superfluous but Windows sends this too */
1041 SendMessageW(lphc
->hWndLBox
, LB_SETCARETINDEX
, (WPARAM
)(idx
< 0 ? 0 : idx
), 0);
1042 SendMessageW(lphc
->hWndLBox
, LB_SETTOPINDEX
, (WPARAM
)(idx
< 0 ? 0 : idx
), 0);
1047 /***********************************************************************
1050 * Copy a listbox entry to the edit control.
1052 static void CBUpdateEdit( LPHEADCOMBO lphc
, INT index
)
1055 LPWSTR pText
= NULL
;
1056 static const WCHAR empty_stringW
[] = { 0 };
1058 DbgPrint("\t %i\n", index
);
1060 if( index
>= 0 ) /* got an entry */
1062 length
= SendMessageW(lphc
->hWndLBox
, LB_GETTEXTLEN
, (WPARAM
)index
, 0);
1063 if( length
!= LB_ERR
)
1065 if( (pText
= HeapAlloc( GetProcessHeap(), 0, (length
+ 1) * sizeof(WCHAR
))) )
1067 SendMessageW(lphc
->hWndLBox
, LB_GETTEXT
,
1068 (WPARAM
)index
, (LPARAM
)pText
);
1073 lphc
->wState
|= (CBF_NOEDITNOTIFY
| CBF_NOLBSELECT
);
1074 SendMessageW(lphc
->hWndEdit
, WM_SETTEXT
, 0, pText
? (LPARAM
)pText
: (LPARAM
)empty_stringW
);
1075 lphc
->wState
&= ~(CBF_NOEDITNOTIFY
| CBF_NOLBSELECT
);
1077 if( lphc
->wState
& CBF_FOCUSED
)
1078 SendMessageW(lphc
->hWndEdit
, EM_SETSEL
, 0, (LPARAM
)(-1));
1081 HeapFree( GetProcessHeap(), 0, pText
);
1084 /***********************************************************************
1087 * Show listbox popup.
1089 static void CBDropDown( LPHEADCOMBO lphc
)
1095 DbgPrint("[%p]: drop down\n", lphc
->self
);
1097 CB_NOTIFY( lphc
, CBN_DROPDOWN
);
1101 lphc
->wState
|= CBF_DROPPED
;
1102 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
1104 lphc
->droppedIndex
= CBUpdateLBox( lphc
, TRUE
);
1106 /* Update edit only if item is in the list */
1107 if( !(lphc
->wState
& CBF_CAPTURE
) && lphc
->droppedIndex
>= 0)
1108 CBUpdateEdit( lphc
, lphc
->droppedIndex
);
1112 lphc
->droppedIndex
= SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
1114 SendMessageW(lphc
->hWndLBox
, LB_SETTOPINDEX
,
1115 (WPARAM
)(lphc
->droppedIndex
== LB_ERR
? 0 : lphc
->droppedIndex
), 0 );
1116 SendMessageW(lphc
->hWndLBox
, LB_CARETON
, 0, 0);
1119 /* now set popup position */
1120 GetWindowRect( lphc
->self
, &rect
);
1123 * If it's a dropdown, the listbox is offset
1125 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
1126 rect
.left
+= COMBO_EDITBUTTONSPACE();
1128 /* if the dropped height is greater than the total height of the dropped
1129 items list, then force the drop down list height to be the total height
1130 of the items in the dropped list */
1132 /* And Remove any extra space (Best Fit) */
1133 nDroppedHeight
= lphc
->droppedRect
.bottom
- lphc
->droppedRect
.top
;
1134 /* if listbox length has been set directly by its handle */
1135 GetWindowRect(lphc
->hWndLBox
, &r
);
1136 if (nDroppedHeight
< r
.bottom
- r
.top
)
1137 nDroppedHeight
= r
.bottom
- r
.top
;
1138 nItems
= (int)SendMessageW(lphc
->hWndLBox
, LB_GETCOUNT
, 0, 0);
1145 nIHeight
= (int)SendMessageW(lphc
->hWndLBox
, LB_GETITEMHEIGHT
, 0, 0);
1147 nHeight
= nIHeight
*nItems
;
1149 if (nHeight
< nDroppedHeight
- COMBO_YBORDERSIZE())
1150 nDroppedHeight
= nHeight
+ COMBO_YBORDERSIZE();
1152 if (nDroppedHeight
< nIHeight
)
1155 nDroppedHeight
= (nItems
+1)*nIHeight
;
1157 nDroppedHeight
= 6*nIHeight
;
1161 /*If height of dropped rectangle gets beyond a screen size it should go up, otherwise down.*/
1162 if( (rect
.bottom
+ nDroppedHeight
) >= GetSystemMetrics( SM_CYSCREEN
) )
1163 rect
.bottom
= rect
.top
- nDroppedHeight
;
1165 SetWindowPos( lphc
->hWndLBox
, HWND_TOP
, rect
.left
, rect
.bottom
,
1166 lphc
->droppedRect
.right
- lphc
->droppedRect
.left
,
1168 SWP_NOACTIVATE
| SWP_SHOWWINDOW
);
1171 if( !(lphc
->wState
& CBF_NOREDRAW
) )
1172 RedrawWindow( lphc
->self
, NULL
, 0, RDW_INVALIDATE
|
1173 RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
1175 EnableWindow( lphc
->hWndLBox
, TRUE
);
1176 if (GetCapture() != lphc
->self
)
1177 SetCapture(lphc
->hWndLBox
);
1180 /***********************************************************************
1183 * Hide listbox popup.
1185 static void CBRollUp( LPHEADCOMBO lphc
, BOOL ok
, BOOL bButton
)
1187 HWND hWnd
= lphc
->self
;
1189 DbgPrint("[%p]: sel ok? [%i] dropped? [%i]\n",
1190 lphc
->self
, (INT
)ok
, (INT
)(lphc
->wState
& CBF_DROPPED
));
1192 CB_NOTIFY( lphc
, (ok
) ? CBN_SELENDOK
: CBN_SELENDCANCEL
);
1194 if( IsWindow( hWnd
) && CB_GETTYPE(lphc
) != CBS_SIMPLE
)
1197 if( lphc
->wState
& CBF_DROPPED
)
1201 lphc
->wState
&= ~CBF_DROPPED
;
1202 ShowWindow( lphc
->hWndLBox
, SW_HIDE
);
1204 if(GetCapture() == lphc
->hWndLBox
)
1209 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
1211 rect
= lphc
->buttonRect
;
1222 rect
= lphc
->textRect
;
1227 if( bButton
&& !(lphc
->wState
& CBF_NOREDRAW
) )
1228 RedrawWindow( hWnd
, &rect
, 0, RDW_INVALIDATE
|
1229 RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
1230 CB_NOTIFY( lphc
, CBN_CLOSEUP
);
1235 /***********************************************************************
1238 * Used by the ComboLBox to show/hide itself in response to VK_F4, etc...
1240 BOOL
COMBO_FlipListbox( LPHEADCOMBO lphc
, BOOL ok
, BOOL bRedrawButton
)
1242 if( lphc
->wState
& CBF_DROPPED
)
1244 CBRollUp( lphc
, ok
, bRedrawButton
);
1252 /***********************************************************************
1255 static void CBRepaintButton( LPHEADCOMBO lphc
)
1257 InvalidateRect(lphc
->self
, &lphc
->buttonRect
, TRUE
);
1258 UpdateWindow(lphc
->self
);
1261 /***********************************************************************
1264 static void COMBO_SetFocus( LPHEADCOMBO lphc
)
1266 if( !(lphc
->wState
& CBF_FOCUSED
) )
1268 if( CB_GETTYPE(lphc
) == CBS_DROPDOWNLIST
)
1269 SendMessageW(lphc
->hWndLBox
, LB_CARETON
, 0, 0);
1271 /* This is wrong. Message sequences seem to indicate that this
1272 is set *after* the notify. */
1273 /* lphc->wState |= CBF_FOCUSED; */
1275 if( !(lphc
->wState
& CBF_EDIT
) )
1276 InvalidateRect(lphc
->self
, &lphc
->textRect
, TRUE
);
1278 CB_NOTIFY( lphc
, CBN_SETFOCUS
);
1279 lphc
->wState
|= CBF_FOCUSED
;
1283 /***********************************************************************
1286 static void COMBO_KillFocus( LPHEADCOMBO lphc
)
1288 HWND hWnd
= lphc
->self
;
1290 if( lphc
->wState
& CBF_FOCUSED
)
1292 CBRollUp( lphc
, FALSE
, TRUE
);
1293 if( IsWindow( hWnd
) )
1295 if( CB_GETTYPE(lphc
) == CBS_DROPDOWNLIST
)
1296 SendMessageW(lphc
->hWndLBox
, LB_CARETOFF
, 0, 0);
1298 lphc
->wState
&= ~CBF_FOCUSED
;
1301 if( !(lphc
->wState
& CBF_EDIT
) )
1302 InvalidateRect(lphc
->self
, &lphc
->textRect
, TRUE
);
1304 CB_NOTIFY( lphc
, CBN_KILLFOCUS
);
1309 /***********************************************************************
1312 static LRESULT
COMBO_Command( LPHEADCOMBO lphc
, WPARAM wParam
, HWND hWnd
)
1314 if ( lphc
->wState
& CBF_EDIT
&& lphc
->hWndEdit
== hWnd
)
1316 /* ">> 8" makes gcc generate jump-table instead of cmp ladder */
1318 switch( HIWORD(wParam
) >> 8 )
1320 case (EN_SETFOCUS
>> 8):
1322 DbgPrint("[%p]: edit [%p] got focus\n", lphc
->self
, lphc
->hWndEdit
);
1324 COMBO_SetFocus( lphc
);
1327 case (EN_KILLFOCUS
>> 8):
1329 DbgPrint("[%p]: edit [%p] lost focus\n", lphc
->self
, lphc
->hWndEdit
);
1331 /* NOTE: it seems that Windows' edit control sends an
1332 * undocumented message WM_USER + 0x1B instead of this
1333 * notification (only when it happens to be a part of
1334 * the combo). ?? - AK.
1337 COMBO_KillFocus( lphc
);
1341 case (EN_CHANGE
>> 8):
1343 * In some circumstances (when the selection of the combobox
1344 * is changed for example) we don't wans the EN_CHANGE notification
1345 * to be forwarded to the parent of the combobox. This code
1346 * checks a flag that is set in these occasions and ignores the
1349 if (lphc
->wState
& CBF_NOLBSELECT
)
1351 lphc
->wState
&= ~CBF_NOLBSELECT
;
1355 CBUpdateLBox( lphc
, lphc
->wState
& CBF_DROPPED
);
1358 if (!(lphc
->wState
& CBF_NOEDITNOTIFY
))
1359 CB_NOTIFY( lphc
, CBN_EDITCHANGE
);
1362 case (EN_UPDATE
>> 8):
1363 if (!(lphc
->wState
& CBF_NOEDITNOTIFY
))
1364 CB_NOTIFY( lphc
, CBN_EDITUPDATE
);
1367 case (EN_ERRSPACE
>> 8):
1368 CB_NOTIFY( lphc
, CBN_ERRSPACE
);
1371 else if( lphc
->hWndLBox
== hWnd
)
1373 switch( HIWORD(wParam
) )
1376 CB_NOTIFY( lphc
, CBN_ERRSPACE
);
1380 CB_NOTIFY( lphc
, CBN_DBLCLK
);
1386 DbgPrint("[%p]: lbox selection change [%x]\n", lphc
->self
, lphc
->wState
);
1388 if( HIWORD(wParam
) == LBN_SELCHANGE
)
1390 if( lphc
->wState
& CBF_EDIT
)
1392 INT index
= SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
1393 lphc
->wState
|= CBF_NOLBSELECT
;
1394 CBUpdateEdit( lphc
, index
);
1395 /* select text in edit, as Windows does */
1396 SendMessageW(lphc
->hWndEdit
, EM_SETSEL
, 0, (LPARAM
)(-1));
1399 InvalidateRect(lphc
->self
, &lphc
->textRect
, TRUE
);
1402 /* do not roll up if selection is being tracked
1403 * by arrowkeys in the dropdown listbox */
1404 if( ((lphc
->wState
& CBF_DROPPED
) && !(lphc
->wState
& CBF_NOROLLUP
)) )
1406 CBRollUp( lphc
, (HIWORD(wParam
) == LBN_SELCHANGE
), TRUE
);
1408 else lphc
->wState
&= ~CBF_NOROLLUP
;
1410 CB_NOTIFY( lphc
, CBN_SELCHANGE
);
1416 /* nothing to do here since ComboLBox always resets the focus to its
1417 * combo/edit counterpart */
1424 /***********************************************************************
1427 * Fixup an ownerdrawn item operation and pass it up to the combobox owner.
1429 static LRESULT
COMBO_ItemOp( LPHEADCOMBO lphc
, UINT msg
, LPARAM lParam
)
1431 HWND hWnd
= lphc
->self
;
1432 UINT id
= GetWindowLongA( hWnd
, GWL_ID
);
1434 DbgPrint("[%p]: ownerdraw op %04x\n", lphc
->self
, msg
);
1440 DELETEITEMSTRUCT
*lpIS
= (DELETEITEMSTRUCT
*)lParam
;
1441 lpIS
->CtlType
= ODT_COMBOBOX
;
1443 lpIS
->hwndItem
= hWnd
;
1448 DRAWITEMSTRUCT
*lpIS
= (DRAWITEMSTRUCT
*)lParam
;
1449 lpIS
->CtlType
= ODT_COMBOBOX
;
1451 lpIS
->hwndItem
= hWnd
;
1454 case WM_COMPAREITEM
:
1456 COMPAREITEMSTRUCT
*lpIS
= (COMPAREITEMSTRUCT
*)lParam
;
1457 lpIS
->CtlType
= ODT_COMBOBOX
;
1459 lpIS
->hwndItem
= hWnd
;
1462 case WM_MEASUREITEM
:
1464 MEASUREITEMSTRUCT
*lpIS
= (MEASUREITEMSTRUCT
*)lParam
;
1465 lpIS
->CtlType
= ODT_COMBOBOX
;
1470 return SendMessageW(lphc
->owner
, msg
, id
, lParam
);
1474 /***********************************************************************
1477 static LRESULT
COMBO_GetTextW( LPHEADCOMBO lphc
, INT count
, LPWSTR buf
)
1481 if( lphc
->wState
& CBF_EDIT
)
1482 return SendMessageW( lphc
->hWndEdit
, WM_GETTEXT
, count
, (LPARAM
)buf
);
1484 /* get it from the listbox */
1486 if (!count
|| !buf
) return 0;
1487 if( lphc
->hWndLBox
)
1489 INT idx
= SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
1490 if (idx
== LB_ERR
) goto error
;
1491 length
= SendMessageW(lphc
->hWndLBox
, LB_GETTEXTLEN
, idx
, 0 );
1492 if (length
== LB_ERR
) goto error
;
1494 /* 'length' is without the terminating character */
1495 if (length
>= count
)
1497 LPWSTR lpBuffer
= HeapAlloc(GetProcessHeap(), 0, (length
+ 1) * sizeof(WCHAR
));
1498 if (!lpBuffer
) goto error
;
1499 length
= SendMessageW(lphc
->hWndLBox
, LB_GETTEXT
, idx
, (LPARAM
)lpBuffer
);
1501 /* truncate if buffer is too short */
1502 if (length
!= LB_ERR
)
1504 lstrcpynW( buf
, lpBuffer
, count
);
1507 HeapFree( GetProcessHeap(), 0, lpBuffer
);
1509 else length
= SendMessageW(lphc
->hWndLBox
, LB_GETTEXT
, idx
, (LPARAM
)buf
);
1511 if (length
== LB_ERR
) return 0;
1515 error
: /* error - truncate string, return zero */
1521 /***********************************************************************
1524 * NOTE! LB_GETTEXT does not count terminating \0, WM_GETTEXT does.
1525 * also LB_GETTEXT might return values < 0, WM_GETTEXT doesn't.
1527 static LRESULT
COMBO_GetTextA( LPHEADCOMBO lphc
, INT count
, LPSTR buf
)
1531 if( lphc
->wState
& CBF_EDIT
)
1532 return SendMessageA( lphc
->hWndEdit
, WM_GETTEXT
, count
, (LPARAM
)buf
);
1534 /* get it from the listbox */
1536 if (!count
|| !buf
) return 0;
1537 if( lphc
->hWndLBox
)
1539 INT idx
= SendMessageA(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
1540 if (idx
== LB_ERR
) goto error
;
1541 length
= SendMessageA(lphc
->hWndLBox
, LB_GETTEXTLEN
, idx
, 0 );
1542 if (length
== LB_ERR
) goto error
;
1544 /* 'length' is without the terminating character */
1545 if (length
>= count
)
1547 LPSTR lpBuffer
= HeapAlloc(GetProcessHeap(), 0, (length
+ 1) );
1548 if (!lpBuffer
) goto error
;
1549 length
= SendMessageA(lphc
->hWndLBox
, LB_GETTEXT
, idx
, (LPARAM
)lpBuffer
);
1551 /* truncate if buffer is too short */
1552 if (length
!= LB_ERR
)
1554 lstrcpynA( buf
, lpBuffer
, count
);
1557 HeapFree( GetProcessHeap(), 0, lpBuffer
);
1559 else length
= SendMessageA(lphc
->hWndLBox
, LB_GETTEXT
, idx
, (LPARAM
)buf
);
1561 if (length
== LB_ERR
) return 0;
1565 error
: /* error - truncate string, return zero */
1571 /***********************************************************************
1574 * This function sets window positions according to the updated
1575 * component placement struct.
1577 static void CBResetPos(
1583 BOOL bDrop
= (CB_GETTYPE(lphc
) != CBS_SIMPLE
);
1585 /* NOTE: logs sometimes have WM_LBUTTONUP before a cascade of
1586 * sizing messages */
1588 if( lphc
->wState
& CBF_EDIT
)
1589 SetWindowPos( lphc
->hWndEdit
, 0,
1590 rectEdit
->left
, rectEdit
->top
,
1591 rectEdit
->right
- rectEdit
->left
,
1592 rectEdit
->bottom
- rectEdit
->top
,
1593 SWP_NOZORDER
| SWP_NOACTIVATE
| ((bDrop
) ? SWP_NOREDRAW
: 0) );
1595 SetWindowPos( lphc
->hWndLBox
, 0,
1596 rectLB
->left
, rectLB
->top
,
1597 rectLB
->right
- rectLB
->left
,
1598 rectLB
->bottom
- rectLB
->top
,
1599 SWP_NOACTIVATE
| SWP_NOZORDER
| ((bDrop
) ? SWP_NOREDRAW
: 0) );
1603 if( lphc
->wState
& CBF_DROPPED
)
1605 lphc
->wState
&= ~CBF_DROPPED
;
1606 ShowWindow( lphc
->hWndLBox
, SW_HIDE
);
1609 if( bRedraw
&& !(lphc
->wState
& CBF_NOREDRAW
) )
1610 RedrawWindow( lphc
->self
, NULL
, 0,
1611 RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
);
1616 /***********************************************************************
1619 static void COMBO_Size( LPHEADCOMBO lphc
)
1621 CBCalcPlacement(lphc
->self
,
1625 &lphc
->droppedRect
);
1627 CBResetPos( lphc
, &lphc
->textRect
, &lphc
->droppedRect
, TRUE
);
1631 /***********************************************************************
1634 static void COMBO_Font( LPHEADCOMBO lphc
, HFONT hFont
, BOOL bRedraw
)
1639 lphc
->hFont
= hFont
;
1642 * Propagate to owned windows.
1644 if( lphc
->wState
& CBF_EDIT
)
1645 SendMessageW(lphc
->hWndEdit
, WM_SETFONT
, (WPARAM
)hFont
, bRedraw
);
1646 SendMessageW(lphc
->hWndLBox
, WM_SETFONT
, (WPARAM
)hFont
, bRedraw
);
1649 * Redo the layout of the control.
1651 if ( CB_GETTYPE(lphc
) == CBS_SIMPLE
)
1653 CBCalcPlacement(lphc
->self
,
1657 &lphc
->droppedRect
);
1659 CBResetPos( lphc
, &lphc
->textRect
, &lphc
->droppedRect
, TRUE
);
1663 CBForceDummyResize(lphc
);
1668 /***********************************************************************
1669 * COMBO_SetItemHeight
1671 static LRESULT
COMBO_SetItemHeight( LPHEADCOMBO lphc
, INT index
, INT height
)
1673 LRESULT lRet
= CB_ERR
;
1675 if( index
== -1 ) /* set text field height */
1677 if( height
< 32768 )
1679 lphc
->editHeight
= height
;
1682 * Redo the layout of the control.
1684 if ( CB_GETTYPE(lphc
) == CBS_SIMPLE
)
1686 CBCalcPlacement(lphc
->self
,
1690 &lphc
->droppedRect
);
1692 CBResetPos( lphc
, &lphc
->textRect
, &lphc
->droppedRect
, TRUE
);
1696 CBForceDummyResize(lphc
);
1702 else if ( CB_OWNERDRAWN(lphc
) ) /* set listbox item height */
1703 lRet
= SendMessageW(lphc
->hWndLBox
, LB_SETITEMHEIGHT
,
1704 (WPARAM
)index
, (LPARAM
)height
);
1708 /***********************************************************************
1709 * COMBO_SelectString
1711 static LRESULT
COMBO_SelectString( LPHEADCOMBO lphc
, INT start
, LPARAM pText
, BOOL unicode
)
1713 INT index
= unicode
? SendMessageW(lphc
->hWndLBox
, LB_SELECTSTRING
, (WPARAM
)start
, pText
) :
1714 SendMessageA(lphc
->hWndLBox
, LB_SELECTSTRING
, (WPARAM
)start
, pText
);
1717 if( lphc
->wState
& CBF_EDIT
)
1718 CBUpdateEdit( lphc
, index
);
1721 InvalidateRect(lphc
->self
, &lphc
->textRect
, TRUE
);
1724 return (LRESULT
)index
;
1727 /***********************************************************************
1730 static void COMBO_LButtonDown( LPHEADCOMBO lphc
, LPARAM lParam
)
1734 HWND hWnd
= lphc
->self
;
1736 pt
.x
= LOWORD(lParam
);
1737 pt
.y
= HIWORD(lParam
);
1738 bButton
= PtInRect(&lphc
->buttonRect
, pt
);
1740 if( (CB_GETTYPE(lphc
) == CBS_DROPDOWNLIST
) ||
1741 (bButton
&& (CB_GETTYPE(lphc
) == CBS_DROPDOWN
)) )
1743 lphc
->wState
|= CBF_BUTTONDOWN
;
1744 if( lphc
->wState
& CBF_DROPPED
)
1746 /* got a click to cancel selection */
1748 lphc
->wState
&= ~CBF_BUTTONDOWN
;
1749 CBRollUp( lphc
, TRUE
, FALSE
);
1750 if( !IsWindow( hWnd
) ) return;
1752 if( lphc
->wState
& CBF_CAPTURE
)
1754 lphc
->wState
&= ~CBF_CAPTURE
;
1760 /* drop down the listbox and start tracking */
1762 lphc
->wState
|= CBF_CAPTURE
;
1766 if( bButton
) CBRepaintButton( lphc
);
1770 /***********************************************************************
1773 * Release capture and stop tracking if needed.
1775 static void COMBO_LButtonUp( LPHEADCOMBO lphc
)
1777 if( lphc
->wState
& CBF_CAPTURE
)
1779 lphc
->wState
&= ~CBF_CAPTURE
;
1780 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
1782 INT index
= CBUpdateLBox( lphc
, TRUE
);
1783 /* Update edit only if item is in the list */
1786 lphc
->wState
|= CBF_NOLBSELECT
;
1787 CBUpdateEdit( lphc
, index
);
1788 lphc
->wState
&= ~CBF_NOLBSELECT
;
1792 SetCapture(lphc
->hWndLBox
);
1795 if( lphc
->wState
& CBF_BUTTONDOWN
)
1797 lphc
->wState
&= ~CBF_BUTTONDOWN
;
1798 CBRepaintButton( lphc
);
1802 /***********************************************************************
1805 * Two things to do - track combo button and release capture when
1806 * pointer goes into the listbox.
1808 static void COMBO_MouseMove( LPHEADCOMBO lphc
, WPARAM wParam
, LPARAM lParam
)
1813 pt
.x
= LOWORD(lParam
);
1814 pt
.y
= HIWORD(lParam
);
1816 if( lphc
->wState
& CBF_BUTTONDOWN
)
1820 bButton
= PtInRect(&lphc
->buttonRect
, pt
);
1824 lphc
->wState
&= ~CBF_BUTTONDOWN
;
1825 CBRepaintButton( lphc
);
1829 GetClientRect( lphc
->hWndLBox
, &lbRect
);
1830 MapWindowPoints( lphc
->self
, lphc
->hWndLBox
, &pt
, 1 );
1831 if( PtInRect(&lbRect
, pt
) )
1833 lphc
->wState
&= ~CBF_CAPTURE
;
1835 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
) CBUpdateLBox( lphc
, TRUE
);
1837 /* hand over pointer tracking */
1838 SendMessageW(lphc
->hWndLBox
, WM_LBUTTONDOWN
, wParam
, lParam
);
1843 /***********************************************************************
1844 * ComboWndProc_common
1846 * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/ctrl/src/combobox_15.htm
1848 static LRESULT
ComboWndProc_common( HWND hwnd
, UINT message
,
1849 WPARAM wParam
, LPARAM lParam
, BOOL unicode
)
1851 LPHEADCOMBO lphc
= (LPHEADCOMBO
)GetWindowLongA( hwnd
, 0 );
1853 //TRACE("[%p]: msg %s wp %08x lp %08lx\n",
1854 // hwnd, SPY_GetMsgName(message, hwnd), wParam, lParam );
1856 if( lphc
|| message
== WM_NCCREATE
)
1860 /* System messages */
1864 LONG style
= unicode
? ((LPCREATESTRUCTW
)lParam
)->style
:
1865 ((LPCREATESTRUCTA
)lParam
)->style
;
1866 return COMBO_NCCreate(hwnd
, style
);
1869 COMBO_NCDestroy(lphc
);
1870 break;/* -> DefWindowProc */
1878 hwndParent
= ((LPCREATESTRUCTW
)lParam
)->hwndParent
;
1879 style
= ((LPCREATESTRUCTW
)lParam
)->style
;
1883 hwndParent
= ((LPCREATESTRUCTA
)lParam
)->hwndParent
;
1884 style
= ((LPCREATESTRUCTA
)lParam
)->style
;
1886 return COMBO_Create(hwnd
, lphc
, hwndParent
, style
, unicode
);
1889 case WM_PRINTCLIENT
:
1890 if (lParam
& PRF_ERASEBKGND
)
1891 COMBO_EraseBackground(hwnd
, lphc
, (HDC
)wParam
);
1895 /* wParam may contain a valid HDC! */
1896 return COMBO_Paint(lphc
, (HDC
)wParam
);
1898 return COMBO_EraseBackground(hwnd
, lphc
, (HDC
)wParam
);
1901 LRESULT result
= DLGC_WANTARROWS
| DLGC_WANTCHARS
;
1902 if (lParam
&& (((LPMSG
)lParam
)->message
== WM_KEYDOWN
))
1904 int vk
= (int)((LPMSG
)lParam
)->wParam
;
1906 if ((vk
== VK_RETURN
|| vk
== VK_ESCAPE
) && (lphc
->wState
& CBF_DROPPED
))
1907 result
|= DLGC_WANTMESSAGE
;
1911 case WM_WINDOWPOSCHANGING
:
1912 return COMBO_WindowPosChanging(hwnd
, lphc
, (LPWINDOWPOS
)lParam
);
1913 case WM_WINDOWPOSCHANGED
:
1914 /* SetWindowPos can be called on a Combobox to resize its Listbox.
1915 * In that case, the Combobox itself will not be resized, so we won't
1916 * get a WM_SIZE. Since we still want to update the Listbox, we have to
1921 if( lphc
->hWndLBox
&&
1922 !(lphc
->wState
& CBF_NORESIZE
) ) COMBO_Size( lphc
);
1925 COMBO_Font( lphc
, (HFONT
)wParam
, (BOOL
)lParam
);
1928 return (LRESULT
)lphc
->hFont
;
1930 if( lphc
->wState
& CBF_EDIT
)
1931 SetFocus( lphc
->hWndEdit
);
1933 COMBO_SetFocus( lphc
);
1937 //HWND hwndFocus = WIN_GetFullHandle( (HWND)wParam );
1939 // (hwndFocus != lphc->hWndEdit && hwndFocus != lphc->hWndLBox ))
1940 // COMBO_KillFocus( lphc );
1944 //return COMBO_Command( lphc, wParam, WIN_GetFullHandle( (HWND)lParam ) );
1945 return COMBO_Command( lphc
, wParam
, (HWND
)lParam
);
1948 return unicode
? COMBO_GetTextW( lphc
, wParam
, (LPWSTR
)lParam
)
1949 : COMBO_GetTextA( lphc
, wParam
, (LPSTR
)lParam
);
1951 case WM_GETTEXTLENGTH
:
1953 if ((message
== WM_GETTEXTLENGTH
) && !ISWIN31
&& !(lphc
->wState
& CBF_EDIT
))
1955 int j
= SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
1956 if (j
== -1) return 0;
1957 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_GETTEXTLEN
, j
, 0) :
1958 SendMessageA(lphc
->hWndLBox
, LB_GETTEXTLEN
, j
, 0);
1960 else if( lphc
->wState
& CBF_EDIT
)
1963 lphc
->wState
|= CBF_NOEDITNOTIFY
;
1964 ret
= unicode
? SendMessageW(lphc
->hWndEdit
, message
, wParam
, lParam
) :
1965 SendMessageA(lphc
->hWndEdit
, message
, wParam
, lParam
);
1966 lphc
->wState
&= ~CBF_NOEDITNOTIFY
;
1973 if( lphc
->wState
& CBF_EDIT
)
1975 return unicode
? SendMessageW(lphc
->hWndEdit
, message
, wParam
, lParam
) :
1976 SendMessageA(lphc
->hWndEdit
, message
, wParam
, lParam
);
1982 case WM_COMPAREITEM
:
1983 case WM_MEASUREITEM
:
1984 return COMBO_ItemOp(lphc
, message
, lParam
);
1986 if( lphc
->wState
& CBF_EDIT
)
1987 EnableWindow( lphc
->hWndEdit
, (BOOL
)wParam
);
1988 EnableWindow( lphc
->hWndLBox
, (BOOL
)wParam
);
1990 /* Force the control to repaint when the enabled state changes. */
1991 InvalidateRect(lphc
->self
, NULL
, TRUE
);
1995 lphc
->wState
&= ~CBF_NOREDRAW
;
1997 lphc
->wState
|= CBF_NOREDRAW
;
1999 if( lphc
->wState
& CBF_EDIT
)
2000 SendMessageW(lphc
->hWndEdit
, message
, wParam
, lParam
);
2001 SendMessageW(lphc
->hWndLBox
, message
, wParam
, lParam
);
2004 if( KEYDATA_ALT
& HIWORD(lParam
) )
2005 if( wParam
== VK_UP
|| wParam
== VK_DOWN
)
2006 COMBO_FlipListbox( lphc
, FALSE
, FALSE
);
2015 if ((wParam
== VK_RETURN
|| wParam
== VK_ESCAPE
) &&
2016 (lphc
->wState
& CBF_DROPPED
))
2018 CBRollUp( lphc
, wParam
== VK_RETURN
, FALSE
);
2022 if( lphc
->wState
& CBF_EDIT
)
2023 hwndTarget
= lphc
->hWndEdit
;
2025 hwndTarget
= lphc
->hWndLBox
;
2027 return unicode
? SendMessageW(hwndTarget
, message
, wParam
, lParam
) :
2028 SendMessageA(hwndTarget
, message
, wParam
, lParam
);
2030 case WM_LBUTTONDOWN
:
2031 if( !(lphc
->wState
& CBF_FOCUSED
) ) SetFocus( lphc
->self
);
2032 if( lphc
->wState
& CBF_FOCUSED
) COMBO_LButtonDown( lphc
, lParam
);
2035 COMBO_LButtonUp( lphc
);
2038 if( lphc
->wState
& CBF_CAPTURE
)
2039 COMBO_MouseMove( lphc
, wParam
, lParam
);
2043 if (wParam
& (MK_SHIFT
| MK_CONTROL
))
2044 return unicode
? DefWindowProcW(hwnd
, message
, wParam
, lParam
) :
2045 DefWindowProcA(hwnd
, message
, wParam
, lParam
);
2046 if (SHIWORD(wParam
) > 0) return SendMessageW(hwnd
, WM_KEYDOWN
, VK_UP
, 0);
2047 if (SHIWORD(wParam
) < 0) return SendMessageW(hwnd
, WM_KEYDOWN
, VK_DOWN
, 0);
2050 /* Combo messages */
2053 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_ADDSTRING
, 0, lParam
) :
2054 SendMessageA(lphc
->hWndLBox
, LB_ADDSTRING
, 0, lParam
);
2055 case CB_INSERTSTRING
:
2056 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_INSERTSTRING
, wParam
, lParam
) :
2057 SendMessageA(lphc
->hWndLBox
, LB_INSERTSTRING
, wParam
, lParam
);
2058 case CB_DELETESTRING
:
2059 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_DELETESTRING
, wParam
, 0) :
2060 SendMessageA(lphc
->hWndLBox
, LB_DELETESTRING
, wParam
, 0);
2061 case CB_SELECTSTRING
:
2062 return COMBO_SelectString(lphc
, (INT
)wParam
, lParam
, unicode
);
2064 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_FINDSTRING
, wParam
, lParam
) :
2065 SendMessageA(lphc
->hWndLBox
, LB_FINDSTRING
, wParam
, lParam
);
2066 case CB_FINDSTRINGEXACT
:
2067 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_FINDSTRINGEXACT
, wParam
, lParam
) :
2068 SendMessageA(lphc
->hWndLBox
, LB_FINDSTRINGEXACT
, wParam
, lParam
);
2069 case CB_SETITEMHEIGHT
:
2070 return COMBO_SetItemHeight( lphc
, (INT
)wParam
, (INT
)lParam
);
2071 case CB_GETITEMHEIGHT
:
2072 if( (INT
)wParam
>= 0 ) /* listbox item */
2073 return SendMessageW(lphc
->hWndLBox
, LB_GETITEMHEIGHT
, wParam
, 0);
2074 return CBGetTextAreaHeight(hwnd
, lphc
);
2075 case CB_RESETCONTENT
:
2076 SendMessageW(lphc
->hWndLBox
, LB_RESETCONTENT
, 0, 0);
2077 if( (lphc
->wState
& CBF_EDIT
) && CB_HASSTRINGS(lphc
) )
2079 static const WCHAR empty_stringW
[] = { 0 };
2080 SendMessageW(lphc
->hWndEdit
, WM_SETTEXT
, 0, (LPARAM
)empty_stringW
);
2083 InvalidateRect(lphc
->self
, NULL
, TRUE
);
2085 case CB_INITSTORAGE
:
2086 return SendMessageW(lphc
->hWndLBox
, LB_INITSTORAGE
, wParam
, lParam
);
2087 case CB_GETHORIZONTALEXTENT
:
2088 return SendMessageW(lphc
->hWndLBox
, LB_GETHORIZONTALEXTENT
, 0, 0);
2089 case CB_SETHORIZONTALEXTENT
:
2090 return SendMessageW(lphc
->hWndLBox
, LB_SETHORIZONTALEXTENT
, wParam
, 0);
2091 case CB_GETTOPINDEX
:
2092 return SendMessageW(lphc
->hWndLBox
, LB_GETTOPINDEX
, 0, 0);
2094 return SendMessageW(lphc
->hWndLBox
, LB_GETLOCALE
, 0, 0);
2096 return SendMessageW(lphc
->hWndLBox
, LB_SETLOCALE
, wParam
, 0);
2097 case CB_GETDROPPEDWIDTH
:
2098 if( lphc
->droppedWidth
)
2099 return lphc
->droppedWidth
;
2100 return lphc
->droppedRect
.right
- lphc
->droppedRect
.left
;
2101 case CB_SETDROPPEDWIDTH
:
2102 if( (CB_GETTYPE(lphc
) != CBS_SIMPLE
) &&
2103 (INT
)wParam
< 32768 ) lphc
->droppedWidth
= (INT
)wParam
;
2105 case CB_GETDROPPEDCONTROLRECT
:
2106 if( lParam
) CBGetDroppedControlRect(lphc
, (LPRECT
)lParam
);
2108 case CB_GETDROPPEDSTATE
:
2109 return (lphc
->wState
& CBF_DROPPED
) ? TRUE
: FALSE
;
2111 if(message
== CB_DIR
) message
= LB_DIR
;
2112 return unicode
? SendMessageW(lphc
->hWndLBox
, message
, wParam
, lParam
) :
2113 SendMessageA(lphc
->hWndLBox
, message
, wParam
, lParam
);
2115 case CB_SHOWDROPDOWN
:
2116 if( CB_GETTYPE(lphc
) != CBS_SIMPLE
)
2120 if( !(lphc
->wState
& CBF_DROPPED
) )
2124 if( lphc
->wState
& CBF_DROPPED
)
2125 CBRollUp( lphc
, FALSE
, TRUE
);
2129 return SendMessageW(lphc
->hWndLBox
, LB_GETCOUNT
, 0, 0);
2131 return SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
2133 lParam
= SendMessageW(lphc
->hWndLBox
, LB_SETCURSEL
, wParam
, 0);
2135 SendMessageW(lphc
->hWndLBox
, LB_SETTOPINDEX
, wParam
, 0);
2137 /* no LBN_SELCHANGE in this case, update manually */
2138 if( lphc
->wState
& CBF_EDIT
)
2139 CBUpdateEdit( lphc
, (INT
)wParam
);
2141 InvalidateRect(lphc
->self
, &lphc
->textRect
, TRUE
);
2142 lphc
->wState
&= ~CBF_SELCHANGE
;
2145 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_GETTEXT
, wParam
, lParam
) :
2146 SendMessageA(lphc
->hWndLBox
, LB_GETTEXT
, wParam
, lParam
);
2147 case CB_GETLBTEXTLEN
:
2148 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_GETTEXTLEN
, wParam
, 0) :
2149 SendMessageA(lphc
->hWndLBox
, LB_GETTEXTLEN
, wParam
, 0);
2150 case CB_GETITEMDATA
:
2151 return SendMessageW(lphc
->hWndLBox
, LB_GETITEMDATA
, wParam
, 0);
2152 case CB_SETITEMDATA
:
2153 return SendMessageW(lphc
->hWndLBox
, LB_SETITEMDATA
, wParam
, lParam
);
2155 /* Edit checks passed parameters itself */
2156 if( lphc
->wState
& CBF_EDIT
)
2157 return SendMessageW(lphc
->hWndEdit
, EM_GETSEL
, wParam
, lParam
);
2160 if( lphc
->wState
& CBF_EDIT
)
2161 return SendMessageW(lphc
->hWndEdit
, EM_SETSEL
,
2162 (INT
)(INT16
)LOWORD(lParam
), (INT
)(INT16
)HIWORD(lParam
) );
2164 case CB_SETEXTENDEDUI
:
2165 if( CB_GETTYPE(lphc
) == CBS_SIMPLE
)
2168 lphc
->wState
|= CBF_EUI
;
2169 else lphc
->wState
&= ~CBF_EUI
;
2171 case CB_GETEXTENDEDUI
:
2172 return (lphc
->wState
& CBF_EUI
) ? TRUE
: FALSE
;
2175 if (message
>= WM_USER
)
2176 DbgPrint("unknown msg WM_USER+%04x wp=%04x lp=%08lx\n",
2177 message
- WM_USER
, wParam
, lParam
);
2180 return unicode
? DefWindowProcW(hwnd
, message
, wParam
, lParam
) :
2181 DefWindowProcA(hwnd
, message
, wParam
, lParam
);
2185 /***********************************************************************
2188 * This is just a wrapper for the real ComboWndProc which locks/unlocks
2191 static LRESULT WINAPI
ComboWndProcA( HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
2193 if (!IsWindow(hwnd
)) return 0;
2194 return ComboWndProc_common( hwnd
, message
, wParam
, lParam
, FALSE
);
2198 /***********************************************************************
2201 static LRESULT WINAPI
ComboWndProcW( HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
2203 if (!IsWindow(hwnd
)) return 0;
2204 return ComboWndProc_common( hwnd
, message
, wParam
, lParam
, TRUE
);
2207 /*************************************************************************
2208 * GetComboBoxInfo (USER32.@)
2210 BOOL WINAPI
GetComboBoxInfo(HWND hwndCombo
, /* [in] handle to combo box */
2211 PCOMBOBOXINFO pcbi
/* [in/out] combo box information */)