Wine-devel
Threads by month
- ----- 2026 -----
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
February 2018
- 74 participants
- 746 discussions
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/comctl32/Makefile.in | 1 +
dlls/comctl32/combo.c | 35 -
dlls/comctl32/comctl32.h | 44 +
dlls/comctl32/commctrl.c | 4 +
dlls/comctl32/listbox.c | 3024 ++++++++++++++++++++++++++++++++++++++++++++
dlls/comctl32/tests/misc.c | 4 +-
dlls/user32/class.c | 2 -
7 files changed, 3076 insertions(+), 38 deletions(-)
create mode 100644 dlls/comctl32/listbox.c
diff --git a/dlls/comctl32/Makefile.in b/dlls/comctl32/Makefile.in
index 4adca3c93e..25d5e6716c 100644
--- a/dlls/comctl32/Makefile.in
+++ b/dlls/comctl32/Makefile.in
@@ -21,6 +21,7 @@ C_SRCS = \
hotkey.c \
imagelist.c \
ipaddress.c \
+ listbox.c \
listview.c \
monthcal.c \
nativefont.c \
diff --git a/dlls/comctl32/combo.c b/dlls/comctl32/combo.c
index 7a39cfcbef..43b4cb40f1 100644
--- a/dlls/comctl32/combo.c
+++ b/dlls/comctl32/combo.c
@@ -79,44 +79,9 @@ static UINT CBitHeight, CBitWidth;
#define COMBO_EDITBUTTONSPACE() 0
#define EDIT_CONTROL_PADDING() 1
-#define CBF_DROPPED 0x0001
-#define CBF_BUTTONDOWN 0x0002
-#define CBF_NOROLLUP 0x0004
-#define CBF_MEASUREITEM 0x0008
-#define CBF_FOCUSED 0x0010
-#define CBF_CAPTURE 0x0020
-#define CBF_EDIT 0x0040
-#define CBF_NORESIZE 0x0080
-#define CBF_NOTIFY 0x0100
-#define CBF_NOREDRAW 0x0200
-#define CBF_SELCHANGE 0x0400
-#define CBF_HOT 0x0800
-#define CBF_NOEDITNOTIFY 0x1000
-#define CBF_NOLBSELECT 0x2000 /* do not change current selection */
-#define CBF_BEENFOCUSED 0x4000 /* has it ever had focus */
-#define CBF_EUI 0x8000
-
#define ID_CB_LISTBOX 1000
#define ID_CB_EDIT 1001
-typedef struct
-{
- HWND self;
- HWND owner;
- UINT dwStyle;
- HWND hWndEdit;
- HWND hWndLBox;
- UINT wState;
- HFONT hFont;
- RECT textRect;
- RECT buttonRect;
- RECT droppedRect;
- INT droppedIndex;
- INT fixedOwnerDrawHeight;
- INT droppedWidth; /* last two are not used unless set */
- INT editHeight; /* explicitly */
-} HEADCOMBO, *LPHEADCOMBO;
-
/***********************************************************************
* COMBO_Init
*
diff --git a/dlls/comctl32/comctl32.h b/dlls/comctl32/comctl32.h
index 1ce9752951..18eaf7e5d1 100644
--- a/dlls/comctl32/comctl32.h
+++ b/dlls/comctl32/comctl32.h
@@ -107,6 +107,48 @@ extern HBRUSH COMCTL32_hPattern55AABrush DECLSPEC_HIDDEN;
#define IDS_BUTTON_CANCEL 3004
#define IDS_BUTTON_CLOSE 3005
+#define WM_SYSTIMER 0x0118
+
+enum combobox_state_flags
+{
+ CBF_DROPPED = 0x0001,
+ CBF_BUTTONDOWN = 0x0002,
+ CBF_NOROLLUP = 0x0004,
+ CBF_MEASUREITEM = 0x0008,
+ CBF_FOCUSED = 0x0010,
+ CBF_CAPTURE = 0x0020,
+ CBF_EDIT = 0x0040,
+ CBF_NORESIZE = 0x0080,
+ CBF_NOTIFY = 0x0100,
+ CBF_NOREDRAW = 0x0200,
+ CBF_SELCHANGE = 0x0400,
+ CBF_HOT = 0x0800,
+ CBF_NOEDITNOTIFY = 0x1000,
+ CBF_NOLBSELECT = 0x2000, /* do not change current selection */
+ CBF_BEENFOCUSED = 0x4000, /* has it ever had focus */
+ CBF_EUI = 0x8000,
+};
+
+typedef struct
+{
+ HWND self;
+ HWND owner;
+ UINT dwStyle;
+ HWND hWndEdit;
+ HWND hWndLBox;
+ UINT wState;
+ HFONT hFont;
+ RECT textRect;
+ RECT buttonRect;
+ RECT droppedRect;
+ INT droppedIndex;
+ INT fixedOwnerDrawHeight;
+ INT droppedWidth; /* last two are not used unless set */
+ INT editHeight; /* explicitly */
+} HEADCOMBO, *LPHEADCOMBO;
+
+extern BOOL COMBO_FlipListbox(HEADCOMBO *lphc, BOOL ok, BOOL bRedrawButton) DECLSPEC_HIDDEN;
+
typedef struct
{
COLORREF clrBtnHighlight; /* COLOR_BTNHIGHLIGHT */
@@ -181,6 +223,7 @@ extern void BUTTON_Register(void) DECLSPEC_HIDDEN;
extern void COMBO_Register(void) DECLSPEC_HIDDEN;
extern void COMBOEX_Register(void) DECLSPEC_HIDDEN;
extern void COMBOEX_Unregister(void) DECLSPEC_HIDDEN;
+extern void COMBOLBOX_Register(void) DECLSPEC_HIDDEN;
extern void DATETIME_Register(void) DECLSPEC_HIDDEN;
extern void DATETIME_Unregister(void) DECLSPEC_HIDDEN;
extern void EDIT_Register(void) DECLSPEC_HIDDEN;
@@ -192,6 +235,7 @@ extern void HOTKEY_Register(void) DECLSPEC_HIDDEN;
extern void HOTKEY_Unregister(void) DECLSPEC_HIDDEN;
extern void IPADDRESS_Register(void) DECLSPEC_HIDDEN;
extern void IPADDRESS_Unregister(void) DECLSPEC_HIDDEN;
+extern void LISTBOX_Register(void) DECLSPEC_HIDDEN;
extern void LISTVIEW_Register(void) DECLSPEC_HIDDEN;
extern void LISTVIEW_Unregister(void) DECLSPEC_HIDDEN;
extern void MONTHCAL_Register(void) DECLSPEC_HIDDEN;
diff --git a/dlls/comctl32/commctrl.c b/dlls/comctl32/commctrl.c
index 42c05e69fa..c1af1c89d6 100644
--- a/dlls/comctl32/commctrl.c
+++ b/dlls/comctl32/commctrl.c
@@ -100,7 +100,9 @@ static void unregister_versioned_classes(void)
{
VERSION WC_BUTTONA,
VERSION WC_COMBOBOXA,
+ VERSION "ComboLBox",
VERSION WC_EDITA,
+ VERSION WC_LISTBOXA,
VERSION WC_STATICA,
};
int i;
@@ -172,7 +174,9 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
BUTTON_Register ();
COMBO_Register ();
+ COMBOLBOX_Register ();
EDIT_Register ();
+ LISTBOX_Register ();
STATIC_Register ();
/* subclass user32 controls */
diff --git a/dlls/comctl32/listbox.c b/dlls/comctl32/listbox.c
new file mode 100644
index 0000000000..ad970225f1
--- /dev/null
+++ b/dlls/comctl32/listbox.c
@@ -0,0 +1,3024 @@
+/*
+ * Listbox controls
+ *
+ * Copyright 1996 Alexandre Julliard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * TODO:
+ * - LBS_NODATA
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "commctrl.h"
+#include "wine/unicode.h"
+#include "wine/exception.h"
+#include "wine/debug.h"
+
+#include "comctl32.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(listbox2);
+
+/* Items array granularity */
+#define LB_ARRAY_GRANULARITY 16
+
+/* Scrolling timeout in ms */
+#define LB_SCROLL_TIMEOUT 50
+
+/* Listbox system timer id */
+#define LB_TIMER_ID 2
+
+/* flag listbox changed while setredraw false - internal style */
+#define LBS_DISPLAYCHANGED 0x80000000
+
+/* Item structure */
+typedef struct
+{
+ LPWSTR str; /* Item text */
+ BOOL selected; /* Is item selected? */
+ UINT height; /* Item height (only for OWNERDRAWVARIABLE) */
+ ULONG_PTR data; /* User data */
+} LB_ITEMDATA;
+
+/* Listbox structure */
+typedef struct
+{
+ HWND self; /* Our own window handle */
+ HWND owner; /* Owner window to send notifications to */
+ UINT style; /* Window style */
+ INT width; /* Window width */
+ INT height; /* Window height */
+ LB_ITEMDATA *items; /* Array of items */
+ INT nb_items; /* Number of items */
+ INT top_item; /* Top visible item */
+ INT selected_item; /* Selected item */
+ INT focus_item; /* Item that has the focus */
+ INT anchor_item; /* Anchor item for extended selection */
+ INT item_height; /* Default item height */
+ INT page_size; /* Items per listbox page */
+ INT column_width; /* Column width for multi-column listboxes */
+ INT horz_extent; /* Horizontal extent */
+ INT horz_pos; /* Horizontal position */
+ INT nb_tabs; /* Number of tabs in array */
+ INT *tabs; /* Array of tabs */
+ INT avg_char_width; /* Average width of characters */
+ INT wheel_remain; /* Left over scroll amount */
+ BOOL caret_on; /* Is caret on? */
+ BOOL captured; /* Is mouse captured? */
+ BOOL in_focus;
+ HFONT font; /* Current font */
+ LCID locale; /* Current locale for string comparisons */
+ HEADCOMBO *lphc; /* ComboLBox */
+} LB_DESCR;
+
+
+#define IS_OWNERDRAW(descr) \
+ ((descr)->style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE))
+
+#define HAS_STRINGS(descr) \
+ (!IS_OWNERDRAW(descr) || ((descr)->style & LBS_HASSTRINGS))
+
+
+#define IS_MULTISELECT(descr) \
+ ((descr)->style & (LBS_MULTIPLESEL|LBS_EXTENDEDSEL) && \
+ !((descr)->style & LBS_NOSEL))
+
+#define SEND_NOTIFICATION(descr,code) \
+ (SendMessageW( (descr)->owner, WM_COMMAND, \
+ MAKEWPARAM( GetWindowLongPtrW((descr->self),GWLP_ID), (code)), (LPARAM)(descr->self) ))
+
+#define ISWIN31 (LOWORD(GetVersion()) == 0x0a03)
+
+/* Current timer status */
+typedef enum
+{
+ LB_TIMER_NONE,
+ LB_TIMER_UP,
+ LB_TIMER_LEFT,
+ LB_TIMER_DOWN,
+ LB_TIMER_RIGHT
+} TIMER_DIRECTION;
+
+static TIMER_DIRECTION LISTBOX_Timer = LB_TIMER_NONE;
+
+static LRESULT LISTBOX_GetItemRect( const LB_DESCR *descr, INT index, RECT *rect );
+
+/***********************************************************************
+ * LISTBOX_GetCurrentPageSize
+ *
+ * Return the current page size
+ */
+static INT LISTBOX_GetCurrentPageSize( const LB_DESCR *descr )
+{
+ INT i, height;
+ if (!(descr->style & LBS_OWNERDRAWVARIABLE)) return descr->page_size;
+ for (i = descr->top_item, height = 0; i < descr->nb_items; i++)
+ {
+ if ((height += descr->items[i].height) > descr->height) break;
+ }
+ if (i == descr->top_item) return 1;
+ else return i - descr->top_item;
+}
+
+
+/***********************************************************************
+ * LISTBOX_GetMaxTopIndex
+ *
+ * Return the maximum possible index for the top of the listbox.
+ */
+static INT LISTBOX_GetMaxTopIndex( const LB_DESCR *descr )
+{
+ INT max, page;
+
+ if (descr->style & LBS_OWNERDRAWVARIABLE)
+ {
+ page = descr->height;
+ for (max = descr->nb_items - 1; max >= 0; max--)
+ if ((page -= descr->items[max].height) < 0) break;
+ if (max < descr->nb_items - 1) max++;
+ }
+ else if (descr->style & LBS_MULTICOLUMN)
+ {
+ if ((page = descr->width / descr->column_width) < 1) page = 1;
+ max = (descr->nb_items + descr->page_size - 1) / descr->page_size;
+ max = (max - page) * descr->page_size;
+ }
+ else
+ {
+ max = descr->nb_items - descr->page_size;
+ }
+ if (max < 0) max = 0;
+ return max;
+}
+
+
+/***********************************************************************
+ * LISTBOX_UpdateScroll
+ *
+ * Update the scrollbars. Should be called whenever the content
+ * of the listbox changes.
+ */
+static void LISTBOX_UpdateScroll( LB_DESCR *descr )
+{
+ SCROLLINFO info;
+
+ /* Check the listbox scroll bar flags individually before we call
+ SetScrollInfo otherwise when the listbox style is WS_HSCROLL and
+ no WS_VSCROLL, we end up with an uninitialized, visible horizontal
+ scroll bar when we do not need one.
+ if (!(descr->style & WS_VSCROLL)) return;
+ */
+
+ /* It is important that we check descr->style, and not wnd->dwStyle,
+ for WS_VSCROLL, as the former is exactly the one passed in
+ argument to CreateWindow.
+ In Windows (and from now on in Wine :) a listbox created
+ with such a style (no WS_SCROLL) does not update
+ the scrollbar with listbox-related data, thus letting
+ the programmer use it for his/her own purposes. */
+
+ if (descr->style & LBS_NOREDRAW) return;
+ info.cbSize = sizeof(info);
+
+ if (descr->style & LBS_MULTICOLUMN)
+ {
+ info.nMin = 0;
+ info.nMax = (descr->nb_items - 1) / descr->page_size;
+ info.nPos = descr->top_item / descr->page_size;
+ info.nPage = descr->width / descr->column_width;
+ if (info.nPage < 1) info.nPage = 1;
+ info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
+ if (descr->style & LBS_DISABLENOSCROLL)
+ info.fMask |= SIF_DISABLENOSCROLL;
+ if (descr->style & WS_HSCROLL)
+ SetScrollInfo( descr->self, SB_HORZ, &info, TRUE );
+ info.nMax = 0;
+ info.fMask = SIF_RANGE;
+ if (descr->style & WS_VSCROLL)
+ SetScrollInfo( descr->self, SB_VERT, &info, TRUE );
+ }
+ else
+ {
+ info.nMin = 0;
+ info.nMax = descr->nb_items - 1;
+ info.nPos = descr->top_item;
+ info.nPage = LISTBOX_GetCurrentPageSize( descr );
+ info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
+ if (descr->style & LBS_DISABLENOSCROLL)
+ info.fMask |= SIF_DISABLENOSCROLL;
+ if (descr->style & WS_VSCROLL)
+ SetScrollInfo( descr->self, SB_VERT, &info, TRUE );
+
+ if ((descr->style & WS_HSCROLL) && descr->horz_extent)
+ {
+ info.nPos = descr->horz_pos;
+ info.nPage = descr->width;
+ info.fMask = SIF_POS | SIF_PAGE;
+ if (descr->style & LBS_DISABLENOSCROLL)
+ info.fMask |= SIF_DISABLENOSCROLL;
+ SetScrollInfo( descr->self, SB_HORZ, &info, TRUE );
+ }
+ else
+ {
+ if (descr->style & LBS_DISABLENOSCROLL)
+ {
+ info.nMin = 0;
+ info.nMax = 0;
+ info.fMask = SIF_RANGE | SIF_DISABLENOSCROLL;
+ SetScrollInfo( descr->self, SB_HORZ, &info, TRUE );
+ }
+ else
+ {
+ ShowScrollBar( descr->self, SB_HORZ, FALSE );
+ }
+ }
+ }
+}
+
+
+/***********************************************************************
+ * LISTBOX_SetTopItem
+ *
+ * Set the top item of the listbox, scrolling up or down if necessary.
+ */
+static LRESULT LISTBOX_SetTopItem( LB_DESCR *descr, INT index, BOOL scroll )
+{
+ INT max = LISTBOX_GetMaxTopIndex( descr );
+
+ TRACE("setting top item %d, scroll %d\n", index, scroll);
+
+ if (index > max) index = max;
+ if (index < 0) index = 0;
+ if (descr->style & LBS_MULTICOLUMN) index -= index % descr->page_size;
+ if (descr->top_item == index) return LB_OKAY;
+ if (scroll)
+ {
+ INT diff;
+ if (descr->style & LBS_MULTICOLUMN)
+ diff = (descr->top_item - index) / descr->page_size * descr->column_width;
+ else if (descr->style & LBS_OWNERDRAWVARIABLE)
+ {
+ INT i;
+ diff = 0;
+ if (index > descr->top_item)
+ {
+ for (i = index - 1; i >= descr->top_item; i--)
+ diff -= descr->items[i].height;
+ }
+ else
+ {
+ for (i = index; i < descr->top_item; i++)
+ diff += descr->items[i].height;
+ }
+ }
+ else
+ diff = (descr->top_item - index) * descr->item_height;
+
+ ScrollWindowEx( descr->self, 0, diff, NULL, NULL, 0, NULL,
+ SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
+ }
+ else
+ InvalidateRect( descr->self, NULL, TRUE );
+ descr->top_item = index;
+ LISTBOX_UpdateScroll( descr );
+ return LB_OKAY;
+}
+
+
+/***********************************************************************
+ * LISTBOX_UpdatePage
+ *
+ * Update the page size. Should be called when the size of
+ * the client area or the item height changes.
+ */
+static void LISTBOX_UpdatePage( LB_DESCR *descr )
+{
+ INT page_size;
+
+ if ((descr->item_height == 0) || (page_size = descr->height / descr->item_height) < 1)
+ page_size = 1;
+ if (page_size == descr->page_size) return;
+ descr->page_size = page_size;
+ if (descr->style & LBS_MULTICOLUMN)
+ InvalidateRect( descr->self, NULL, TRUE );
+ LISTBOX_SetTopItem( descr, descr->top_item, FALSE );
+}
+
+
+/***********************************************************************
+ * LISTBOX_UpdateSize
+ *
+ * Update the size of the listbox. Should be called when the size of
+ * the client area changes.
+ */
+static void LISTBOX_UpdateSize( LB_DESCR *descr )
+{
+ RECT rect;
+
+ GetClientRect( descr->self, &rect );
+ descr->width = rect.right - rect.left;
+ descr->height = rect.bottom - rect.top;
+ if (!(descr->style & LBS_NOINTEGRALHEIGHT) && !(descr->style & LBS_OWNERDRAWVARIABLE))
+ {
+ INT remaining;
+ RECT rect;
+
+ GetWindowRect( descr->self, &rect );
+ if(descr->item_height != 0)
+ remaining = descr->height % descr->item_height;
+ else
+ remaining = 0;
+ if ((descr->height > descr->item_height) && remaining)
+ {
+ TRACE("[%p]: changing height %d -> %d\n",
+ descr->self, descr->height, descr->height - remaining );
+ SetWindowPos( descr->self, 0, 0, 0, rect.right - rect.left,
+ rect.bottom - rect.top - remaining,
+ SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE );
+ return;
+ }
+ }
+ TRACE("[%p]: new size = %d,%d\n", descr->self, descr->width, descr->height );
+ LISTBOX_UpdatePage( descr );
+ LISTBOX_UpdateScroll( descr );
+
+ /* Invalidate the focused item so it will be repainted correctly */
+ if (LISTBOX_GetItemRect( descr, descr->focus_item, &rect ) == 1)
+ {
+ InvalidateRect( descr->self, &rect, FALSE );
+ }
+}
+
+
+/***********************************************************************
+ * LISTBOX_GetItemRect
+ *
+ * Get the rectangle enclosing an item, in listbox client coordinates.
+ * Return 1 if the rectangle is (partially) visible, 0 if hidden, -1 on error.
+ */
+static LRESULT LISTBOX_GetItemRect( const LB_DESCR *descr, INT index, RECT *rect )
+{
+ /* Index <= 0 is legal even on empty listboxes */
+ if (index && (index >= descr->nb_items))
+ {
+ SetRectEmpty(rect);
+ SetLastError(ERROR_INVALID_INDEX);
+ return LB_ERR;
+ }
+ SetRect( rect, 0, 0, descr->width, descr->height );
+ if (descr->style & LBS_MULTICOLUMN)
+ {
+ INT col = (index / descr->page_size) -
+ (descr->top_item / descr->page_size);
+ rect->left += col * descr->column_width;
+ rect->right = rect->left + descr->column_width;
+ rect->top += (index % descr->page_size) * descr->item_height;
+ rect->bottom = rect->top + descr->item_height;
+ }
+ else if (descr->style & LBS_OWNERDRAWVARIABLE)
+ {
+ INT i;
+ rect->right += descr->horz_pos;
+ if ((index >= 0) && (index < descr->nb_items))
+ {
+ if (index < descr->top_item)
+ {
+ for (i = descr->top_item-1; i >= index; i--)
+ rect->top -= descr->items[i].height;
+ }
+ else
+ {
+ for (i = descr->top_item; i < index; i++)
+ rect->top += descr->items[i].height;
+ }
+ rect->bottom = rect->top + descr->items[index].height;
+
+ }
+ }
+ else
+ {
+ rect->top += (index - descr->top_item) * descr->item_height;
+ rect->bottom = rect->top + descr->item_height;
+ rect->right += descr->horz_pos;
+ }
+
+ TRACE("item %d, rect %s\n", index, wine_dbgstr_rect(rect));
+
+ return ((rect->left < descr->width) && (rect->right > 0) &&
+ (rect->top < descr->height) && (rect->bottom > 0));
+}
+
+
+/***********************************************************************
+ * LISTBOX_GetItemFromPoint
+ *
+ * Return the item nearest from point (x,y) (in client coordinates).
+ */
+static INT LISTBOX_GetItemFromPoint( const LB_DESCR *descr, INT x, INT y )
+{
+ INT index = descr->top_item;
+
+ if (!descr->nb_items) return -1; /* No items */
+ if (descr->style & LBS_OWNERDRAWVARIABLE)
+ {
+ INT pos = 0;
+ if (y >= 0)
+ {
+ while (index < descr->nb_items)
+ {
+ if ((pos += descr->items[index].height) > y) break;
+ index++;
+ }
+ }
+ else
+ {
+ while (index > 0)
+ {
+ index--;
+ if ((pos -= descr->items[index].height) <= y) break;
+ }
+ }
+ }
+ else if (descr->style & LBS_MULTICOLUMN)
+ {
+ if (y >= descr->item_height * descr->page_size) return -1;
+ if (y >= 0) index += y / descr->item_height;
+ if (x >= 0) index += (x / descr->column_width) * descr->page_size;
+ else index -= (((x + 1) / descr->column_width) - 1) * descr->page_size;
+ }
+ else
+ {
+ index += (y / descr->item_height);
+ }
+ if (index < 0) return 0;
+ if (index >= descr->nb_items) return -1;
+ return index;
+}
+
+
+/***********************************************************************
+ * LISTBOX_PaintItem
+ *
+ * Paint an item.
+ */
+static void LISTBOX_PaintItem( LB_DESCR *descr, HDC hdc, const RECT *rect,
+ INT index, UINT action, BOOL ignoreFocus )
+{
+ LB_ITEMDATA *item = NULL;
+ if (index < descr->nb_items) item = &descr->items[index];
+
+ if (IS_OWNERDRAW(descr))
+ {
+ DRAWITEMSTRUCT dis;
+ RECT r;
+ HRGN hrgn;
+
+ if (!item)
+ {
+ if (action == ODA_FOCUS)
+ DrawFocusRect( hdc, rect );
+ else
+ ERR("called with an out of bounds index %d(%d) in owner draw, Not good.\n",index,descr->nb_items);
+ return;
+ }
+
+ /* some programs mess with the clipping region when
+ drawing the item, *and* restore the previous region
+ after they are done, so a region has better to exist
+ else everything ends clipped */
+ GetClientRect(descr->self, &r);
+ hrgn = set_control_clipping( hdc, &r );
+
+ dis.CtlType = ODT_LISTBOX;
+ dis.CtlID = GetWindowLongPtrW( descr->self, GWLP_ID );
+ dis.hwndItem = descr->self;
+ dis.itemAction = action;
+ dis.hDC = hdc;
+ dis.itemID = index;
+ dis.itemState = 0;
+ if (item->selected) dis.itemState |= ODS_SELECTED;
+ if (!ignoreFocus && (descr->focus_item == index) &&
+ (descr->caret_on) &&
+ (descr->in_focus)) dis.itemState |= ODS_FOCUS;
+ if (!IsWindowEnabled(descr->self)) dis.itemState |= ODS_DISABLED;
+ dis.itemData = item->data;
+ dis.rcItem = *rect;
+ TRACE("[%p]: drawitem %d (%s) action=%02x state=%02x rect=%s\n",
+ descr->self, index, debugstr_w(item->str), action,
+ dis.itemState, wine_dbgstr_rect(rect) );
+ SendMessageW(descr->owner, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis);
+ SelectClipRgn( hdc, hrgn );
+ if (hrgn) DeleteObject( hrgn );
+ }
+ else
+ {
+ COLORREF oldText = 0, oldBk = 0;
+
+ if (action == ODA_FOCUS)
+ {
+ DrawFocusRect( hdc, rect );
+ return;
+ }
+ if (item && item->selected)
+ {
+ oldBk = SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
+ oldText = SetTextColor( hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
+ }
+
+ TRACE("[%p]: painting %d (%s) action=%02x rect=%s\n",
+ descr->self, index, item ? debugstr_w(item->str) : "", action,
+ wine_dbgstr_rect(rect) );
+ if (!item)
+ ExtTextOutW( hdc, rect->left + 1, rect->top,
+ ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL );
+ else if (!(descr->style & LBS_USETABSTOPS))
+ ExtTextOutW( hdc, rect->left + 1, rect->top,
+ ETO_OPAQUE | ETO_CLIPPED, rect, item->str,
+ strlenW(item->str), NULL );
+ else
+ {
+ /* Output empty string to paint background in the full width. */
+ ExtTextOutW( hdc, rect->left + 1, rect->top,
+ ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL );
+ TabbedTextOutW( hdc, rect->left + 1 , rect->top,
+ item->str, strlenW(item->str),
+ descr->nb_tabs, descr->tabs, 0);
+ }
+ if (item && item->selected)
+ {
+ SetBkColor( hdc, oldBk );
+ SetTextColor( hdc, oldText );
+ }
+ if (!ignoreFocus && (descr->focus_item == index) &&
+ (descr->caret_on) &&
+ (descr->in_focus)) DrawFocusRect( hdc, rect );
+ }
+}
+
+
+/***********************************************************************
+ * LISTBOX_SetRedraw
+ *
+ * Change the redraw flag.
+ */
+static void LISTBOX_SetRedraw( LB_DESCR *descr, BOOL on )
+{
+ if (on)
+ {
+ if (!(descr->style & LBS_NOREDRAW)) return;
+ descr->style &= ~LBS_NOREDRAW;
+ if (descr->style & LBS_DISPLAYCHANGED)
+ { /* page was changed while setredraw false, refresh automatically */
+ InvalidateRect(descr->self, NULL, TRUE);
+ if ((descr->top_item + descr->page_size) > descr->nb_items)
+ { /* reset top of page if less than number of items/page */
+ descr->top_item = descr->nb_items - descr->page_size;
+ if (descr->top_item < 0) descr->top_item = 0;
+ }
+ descr->style &= ~LBS_DISPLAYCHANGED;
+ }
+ LISTBOX_UpdateScroll( descr );
+ }
+ else descr->style |= LBS_NOREDRAW;
+}
+
+
+/***********************************************************************
+ * LISTBOX_RepaintItem
+ *
+ * Repaint a single item synchronously.
+ */
+static void LISTBOX_RepaintItem( LB_DESCR *descr, INT index, UINT action )
+{
+ HDC hdc;
+ RECT rect;
+ HFONT oldFont = 0;
+ HBRUSH hbrush, oldBrush = 0;
+
+ /* Do not repaint the item if the item is not visible */
+ if (!IsWindowVisible(descr->self)) return;
+ if (descr->style & LBS_NOREDRAW)
+ {
+ descr->style |= LBS_DISPLAYCHANGED;
+ return;
+ }
+ if (LISTBOX_GetItemRect( descr, index, &rect ) != 1) return;
+ if (!(hdc = GetDCEx( descr->self, 0, DCX_CACHE ))) return;
+ if (descr->font) oldFont = SelectObject( hdc, descr->font );
+ hbrush = (HBRUSH)SendMessageW( descr->owner, WM_CTLCOLORLISTBOX,
+ (WPARAM)hdc, (LPARAM)descr->self );
+ if (hbrush) oldBrush = SelectObject( hdc, hbrush );
+ if (!IsWindowEnabled(descr->self))
+ SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
+ SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
+ LISTBOX_PaintItem( descr, hdc, &rect, index, action, TRUE );
+ if (oldFont) SelectObject( hdc, oldFont );
+ if (oldBrush) SelectObject( hdc, oldBrush );
+ ReleaseDC( descr->self, hdc );
+}
+
+
+/***********************************************************************
+ * LISTBOX_DrawFocusRect
+ */
+static void LISTBOX_DrawFocusRect( LB_DESCR *descr, BOOL on )
+{
+ HDC hdc;
+ RECT rect;
+ HFONT oldFont = 0;
+
+ /* Do not repaint the item if the item is not visible */
+ if (!IsWindowVisible(descr->self)) return;
+
+ if (descr->focus_item == -1) return;
+ if (!descr->caret_on || !descr->in_focus) return;
+
+ if (LISTBOX_GetItemRect( descr, descr->focus_item, &rect ) != 1) return;
+ if (!(hdc = GetDCEx( descr->self, 0, DCX_CACHE ))) return;
+ if (descr->font) oldFont = SelectObject( hdc, descr->font );
+ if (!IsWindowEnabled(descr->self))
+ SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
+ SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
+ LISTBOX_PaintItem( descr, hdc, &rect, descr->focus_item, ODA_FOCUS, !on );
+ if (oldFont) SelectObject( hdc, oldFont );
+ ReleaseDC( descr->self, hdc );
+}
+
+
+/***********************************************************************
+ * LISTBOX_InitStorage
+ */
+static LRESULT LISTBOX_InitStorage( LB_DESCR *descr, INT nb_items )
+{
+ LB_ITEMDATA *item;
+
+ nb_items += LB_ARRAY_GRANULARITY - 1;
+ nb_items -= (nb_items % LB_ARRAY_GRANULARITY);
+ if (descr->items) {
+ nb_items += HeapSize( GetProcessHeap(), 0, descr->items ) / sizeof(*item);
+ item = HeapReAlloc( GetProcessHeap(), 0, descr->items,
+ nb_items * sizeof(LB_ITEMDATA));
+ }
+ else {
+ item = HeapAlloc( GetProcessHeap(), 0,
+ nb_items * sizeof(LB_ITEMDATA));
+ }
+
+ if (!item)
+ {
+ SEND_NOTIFICATION( descr, LBN_ERRSPACE );
+ return LB_ERRSPACE;
+ }
+ descr->items = item;
+ return LB_OKAY;
+}
+
+
+/***********************************************************************
+ * LISTBOX_SetTabStops
+ */
+static BOOL LISTBOX_SetTabStops( LB_DESCR *descr, INT count, LPINT tabs )
+{
+ INT i;
+
+ if (!(descr->style & LBS_USETABSTOPS))
+ {
+ SetLastError(ERROR_LB_WITHOUT_TABSTOPS);
+ return FALSE;
+ }
+
+ HeapFree( GetProcessHeap(), 0, descr->tabs );
+ if (!(descr->nb_tabs = count))
+ {
+ descr->tabs = NULL;
+ return TRUE;
+ }
+ if (!(descr->tabs = HeapAlloc( GetProcessHeap(), 0,
+ descr->nb_tabs * sizeof(INT) )))
+ return FALSE;
+ memcpy( descr->tabs, tabs, descr->nb_tabs * sizeof(INT) );
+
+ /* convert into "dialog units"*/
+ for (i = 0; i < descr->nb_tabs; i++)
+ descr->tabs[i] = MulDiv(descr->tabs[i], descr->avg_char_width, 4);
+
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * LISTBOX_GetText
+ */
+static LRESULT LISTBOX_GetText( LB_DESCR *descr, INT index, LPWSTR buffer, BOOL unicode )
+{
+ DWORD len;
+
+ if ((index < 0) || (index >= descr->nb_items))
+ {
+ SetLastError(ERROR_INVALID_INDEX);
+ return LB_ERR;
+ }
+
+ if (HAS_STRINGS(descr))
+ {
+ if (!buffer)
+ return strlenW(descr->items[index].str);
+
+ TRACE("index %d (0x%04x) %s\n", index, index, debugstr_w(descr->items[index].str));
+
+ __TRY /* hide a Delphi bug that passes a read-only buffer */
+ {
+ strcpyW( buffer, descr->items[index].str );
+ len = strlenW(buffer);
+ }
+ __EXCEPT_PAGE_FAULT
+ {
+ WARN( "got an invalid buffer (Delphi bug?)\n" );
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return LB_ERR;
+ }
+ __ENDTRY
+ } else
+ {
+ if (buffer)
+ *((DWORD *)buffer) = *(DWORD *)&descr->items[index].data;
+ len = sizeof(DWORD);
+ }
+ return len;
+}
+
+static inline INT LISTBOX_lstrcmpiW( LCID lcid, LPCWSTR str1, LPCWSTR str2 )
+{
+ INT ret = CompareStringW( lcid, NORM_IGNORECASE, str1, -1, str2, -1 );
+ if (ret == CSTR_LESS_THAN)
+ return -1;
+ if (ret == CSTR_EQUAL)
+ return 0;
+ if (ret == CSTR_GREATER_THAN)
+ return 1;
+ return -1;
+}
+
+/***********************************************************************
+ * LISTBOX_FindStringPos
+ *
+ * Find the nearest string located before a given string in sort order.
+ * If 'exact' is TRUE, return an error if we don't get an exact match.
+ */
+static INT LISTBOX_FindStringPos( LB_DESCR *descr, LPCWSTR str, BOOL exact )
+{
+ INT index, min, max, res;
+
+ if (!(descr->style & LBS_SORT)) return -1; /* Add it at the end */
+ min = 0;
+ max = descr->nb_items;
+ while (min != max)
+ {
+ index = (min + max) / 2;
+ if (HAS_STRINGS(descr))
+ res = LISTBOX_lstrcmpiW( descr->locale, str, descr->items[index].str);
+ else
+ {
+ COMPAREITEMSTRUCT cis;
+ UINT id = (UINT)GetWindowLongPtrW( descr->self, GWLP_ID );
+
+ cis.CtlType = ODT_LISTBOX;
+ cis.CtlID = id;
+ cis.hwndItem = descr->self;
+ /* note that some application (MetaStock) expects the second item
+ * to be in the listbox */
+ cis.itemID1 = -1;
+ cis.itemData1 = (ULONG_PTR)str;
+ cis.itemID2 = index;
+ cis.itemData2 = descr->items[index].data;
+ cis.dwLocaleId = descr->locale;
+ res = SendMessageW( descr->owner, WM_COMPAREITEM, id, (LPARAM)&cis );
+ }
+ if (!res) return index;
+ if (res < 0) max = index;
+ else min = index + 1;
+ }
+ return exact ? -1 : max;
+}
+
+
+/***********************************************************************
+ * LISTBOX_FindFileStrPos
+ *
+ * Find the nearest string located before a given string in directory
+ * sort order (i.e. first files, then directories, then drives).
+ */
+static INT LISTBOX_FindFileStrPos( LB_DESCR *descr, LPCWSTR str )
+{
+ INT min, max, res;
+
+ if (!HAS_STRINGS(descr))
+ return LISTBOX_FindStringPos( descr, str, FALSE );
+ min = 0;
+ max = descr->nb_items;
+ while (min != max)
+ {
+ INT index = (min + max) / 2;
+ LPCWSTR p = descr->items[index].str;
+ if (*p == '[') /* drive or directory */
+ {
+ if (*str != '[') res = -1;
+ else if (p[1] == '-') /* drive */
+ {
+ if (str[1] == '-') res = str[2] - p[2];
+ else res = -1;
+ }
+ else /* directory */
+ {
+ if (str[1] == '-') res = 1;
+ else res = LISTBOX_lstrcmpiW( descr->locale, str, p );
+ }
+ }
+ else /* filename */
+ {
+ if (*str == '[') res = 1;
+ else res = LISTBOX_lstrcmpiW( descr->locale, str, p );
+ }
+ if (!res) return index;
+ if (res < 0) max = index;
+ else min = index + 1;
+ }
+ return max;
+}
+
+
+/***********************************************************************
+ * LISTBOX_FindString
+ *
+ * Find the item beginning with a given string.
+ */
+static INT LISTBOX_FindString( LB_DESCR *descr, INT start, LPCWSTR str, BOOL exact )
+{
+ INT i;
+ LB_ITEMDATA *item;
+
+ if (start >= descr->nb_items) start = -1;
+ item = descr->items + start + 1;
+ if (HAS_STRINGS(descr))
+ {
+ if (!str || ! str[0] ) return LB_ERR;
+ if (exact)
+ {
+ for (i = start + 1; i < descr->nb_items; i++, item++)
+ if (!LISTBOX_lstrcmpiW( descr->locale, str, item->str )) return i;
+ for (i = 0, item = descr->items; i <= start; i++, item++)
+ if (!LISTBOX_lstrcmpiW( descr->locale, str, item->str )) return i;
+ }
+ else
+ {
+ /* Special case for drives and directories: ignore prefix */
+#define CHECK_DRIVE(item) \
+ if ((item)->str[0] == '[') \
+ { \
+ if (!strncmpiW( str, (item)->str+1, len )) return i; \
+ if (((item)->str[1] == '-') && !strncmpiW(str, (item)->str+2, len)) \
+ return i; \
+ }
+
+ INT len = strlenW(str);
+ for (i = start + 1; i < descr->nb_items; i++, item++)
+ {
+ if (!strncmpiW( str, item->str, len )) return i;
+ CHECK_DRIVE(item);
+ }
+ for (i = 0, item = descr->items; i <= start; i++, item++)
+ {
+ if (!strncmpiW( str, item->str, len )) return i;
+ CHECK_DRIVE(item);
+ }
+#undef CHECK_DRIVE
+ }
+ }
+ else
+ {
+ if (exact && (descr->style & LBS_SORT))
+ /* If sorted, use a WM_COMPAREITEM binary search */
+ return LISTBOX_FindStringPos( descr, str, TRUE );
+
+ /* Otherwise use a linear search */
+ for (i = start + 1; i < descr->nb_items; i++, item++)
+ if (item->data == (ULONG_PTR)str) return i;
+ for (i = 0, item = descr->items; i <= start; i++, item++)
+ if (item->data == (ULONG_PTR)str) return i;
+ }
+ return LB_ERR;
+}
+
+
+/***********************************************************************
+ * LISTBOX_GetSelCount
+ */
+static LRESULT LISTBOX_GetSelCount( const LB_DESCR *descr )
+{
+ INT i, count;
+ const LB_ITEMDATA *item = descr->items;
+
+ if (!(descr->style & LBS_MULTIPLESEL) ||
+ (descr->style & LBS_NOSEL))
+ return LB_ERR;
+ for (i = count = 0; i < descr->nb_items; i++, item++)
+ if (item->selected) count++;
+ return count;
+}
+
+
+/***********************************************************************
+ * LISTBOX_GetSelItems
+ */
+static LRESULT LISTBOX_GetSelItems( const LB_DESCR *descr, INT max, LPINT array )
+{
+ INT i, count;
+ const LB_ITEMDATA *item = descr->items;
+
+ if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
+ for (i = count = 0; (i < descr->nb_items) && (count < max); i++, item++)
+ if (item->selected) array[count++] = i;
+ return count;
+}
+
+
+/***********************************************************************
+ * LISTBOX_Paint
+ */
+static LRESULT LISTBOX_Paint( LB_DESCR *descr, HDC hdc )
+{
+ INT i, col_pos = descr->page_size - 1;
+ RECT rect;
+ RECT focusRect = {-1, -1, -1, -1};
+ HFONT oldFont = 0;
+ HBRUSH hbrush, oldBrush = 0;
+
+ if (descr->style & LBS_NOREDRAW) return 0;
+
+ SetRect( &rect, 0, 0, descr->width, descr->height );
+ if (descr->style & LBS_MULTICOLUMN)
+ rect.right = rect.left + descr->column_width;
+ else if (descr->horz_pos)
+ {
+ SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
+ rect.right += descr->horz_pos;
+ }
+
+ if (descr->font) oldFont = SelectObject( hdc, descr->font );
+ hbrush = (HBRUSH)SendMessageW( descr->owner, WM_CTLCOLORLISTBOX,
+ (WPARAM)hdc, (LPARAM)descr->self );
+ if (hbrush) oldBrush = SelectObject( hdc, hbrush );
+ if (!IsWindowEnabled(descr->self)) SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
+
+ if (!descr->nb_items && (descr->focus_item != -1) && descr->caret_on &&
+ (descr->in_focus))
+ {
+ /* Special case for empty listbox: paint focus rect */
+ rect.bottom = rect.top + descr->item_height;
+ ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
+ &rect, NULL, 0, NULL );
+ LISTBOX_PaintItem( descr, hdc, &rect, descr->focus_item, ODA_FOCUS, FALSE );
+ rect.top = rect.bottom;
+ }
+
+ /* Paint all the item, regarding the selection
+ Focus state will be painted after */
+
+ for (i = descr->top_item; i < descr->nb_items; i++)
+ {
+ if (!(descr->style & LBS_OWNERDRAWVARIABLE))
+ rect.bottom = rect.top + descr->item_height;
+ else
+ rect.bottom = rect.top + descr->items[i].height;
+
+ /* keep the focus rect, to paint the focus item after */
+ if (i == descr->focus_item)
+ focusRect = rect;
+
+ LISTBOX_PaintItem( descr, hdc, &rect, i, ODA_DRAWENTIRE, TRUE );
+ rect.top = rect.bottom;
+
+ if ((descr->style & LBS_MULTICOLUMN) && !col_pos)
+ {
+ if (!IS_OWNERDRAW(descr))
+ {
+ /* Clear the bottom of the column */
+ if (rect.top < descr->height)
+ {
+ rect.bottom = descr->height;
+ ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
+ &rect, NULL, 0, NULL );
+ }
+ }
+
+ /* Go to the next column */
+ rect.left += descr->column_width;
+ rect.right += descr->column_width;
+ rect.top = 0;
+ col_pos = descr->page_size - 1;
+ }
+ else
+ {
+ col_pos--;
+ if (rect.top >= descr->height) break;
+ }
+ }
+
+ /* Paint the focus item now */
+ if (focusRect.top != focusRect.bottom &&
+ descr->caret_on && descr->in_focus)
+ LISTBOX_PaintItem( descr, hdc, &focusRect, descr->focus_item, ODA_FOCUS, FALSE );
+
+ if (!IS_OWNERDRAW(descr))
+ {
+ /* Clear the remainder of the client area */
+ if (rect.top < descr->height)
+ {
+ rect.bottom = descr->height;
+ ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
+ &rect, NULL, 0, NULL );
+ }
+ if (rect.right < descr->width)
+ {
+ rect.left = rect.right;
+ rect.right = descr->width;
+ rect.top = 0;
+ rect.bottom = descr->height;
+ ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
+ &rect, NULL, 0, NULL );
+ }
+ }
+ if (oldFont) SelectObject( hdc, oldFont );
+ if (oldBrush) SelectObject( hdc, oldBrush );
+ return 0;
+}
+
+
+/***********************************************************************
+ * LISTBOX_InvalidateItems
+ *
+ * Invalidate all items from a given item. If the specified item is not
+ * visible, nothing happens.
+ */
+static void LISTBOX_InvalidateItems( LB_DESCR *descr, INT index )
+{
+ RECT rect;
+
+ if (LISTBOX_GetItemRect( descr, index, &rect ) == 1)
+ {
+ if (descr->style & LBS_NOREDRAW)
+ {
+ descr->style |= LBS_DISPLAYCHANGED;
+ return;
+ }
+ rect.bottom = descr->height;
+ InvalidateRect( descr->self, &rect, TRUE );
+ if (descr->style & LBS_MULTICOLUMN)
+ {
+ /* Repaint the other columns */
+ rect.left = rect.right;
+ rect.right = descr->width;
+ rect.top = 0;
+ InvalidateRect( descr->self, &rect, TRUE );
+ }
+ }
+}
+
+static void LISTBOX_InvalidateItemRect( LB_DESCR *descr, INT index )
+{
+ RECT rect;
+
+ if (LISTBOX_GetItemRect( descr, index, &rect ) == 1)
+ InvalidateRect( descr->self, &rect, TRUE );
+}
+
+/***********************************************************************
+ * LISTBOX_GetItemHeight
+ */
+static LRESULT LISTBOX_GetItemHeight( const LB_DESCR *descr, INT index )
+{
+ if (descr->style & LBS_OWNERDRAWVARIABLE && descr->nb_items > 0)
+ {
+ if ((index < 0) || (index >= descr->nb_items))
+ {
+ SetLastError(ERROR_INVALID_INDEX);
+ return LB_ERR;
+ }
+ return descr->items[index].height;
+ }
+ else return descr->item_height;
+}
+
+
+/***********************************************************************
+ * LISTBOX_SetItemHeight
+ */
+static LRESULT LISTBOX_SetItemHeight( LB_DESCR *descr, INT index, INT height, BOOL repaint )
+{
+ if (height > MAXBYTE)
+ return -1;
+
+ if (!height) height = 1;
+
+ if (descr->style & LBS_OWNERDRAWVARIABLE)
+ {
+ if ((index < 0) || (index >= descr->nb_items))
+ {
+ SetLastError(ERROR_INVALID_INDEX);
+ return LB_ERR;
+ }
+ TRACE("[%p]: item %d height = %d\n", descr->self, index, height );
+ descr->items[index].height = height;
+ LISTBOX_UpdateScroll( descr );
+ if (repaint)
+ LISTBOX_InvalidateItems( descr, index );
+ }
+ else if (height != descr->item_height)
+ {
+ TRACE("[%p]: new height = %d\n", descr->self, height );
+ descr->item_height = height;
+ LISTBOX_UpdatePage( descr );
+ LISTBOX_UpdateScroll( descr );
+ if (repaint)
+ InvalidateRect( descr->self, 0, TRUE );
+ }
+ return LB_OKAY;
+}
+
+
+/***********************************************************************
+ * LISTBOX_SetHorizontalPos
+ */
+static void LISTBOX_SetHorizontalPos( LB_DESCR *descr, INT pos )
+{
+ INT diff;
+
+ if (pos > descr->horz_extent - descr->width)
+ pos = descr->horz_extent - descr->width;
+ if (pos < 0) pos = 0;
+ if (!(diff = descr->horz_pos - pos)) return;
+ TRACE("[%p]: new horz pos = %d\n", descr->self, pos );
+ descr->horz_pos = pos;
+ LISTBOX_UpdateScroll( descr );
+ if (abs(diff) < descr->width)
+ {
+ RECT rect;
+ /* Invalidate the focused item so it will be repainted correctly */
+ if (LISTBOX_GetItemRect( descr, descr->focus_item, &rect ) == 1)
+ InvalidateRect( descr->self, &rect, TRUE );
+ ScrollWindowEx( descr->self, diff, 0, NULL, NULL, 0, NULL,
+ SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
+ }
+ else
+ InvalidateRect( descr->self, NULL, TRUE );
+}
+
+
+/***********************************************************************
+ * LISTBOX_SetHorizontalExtent
+ */
+static LRESULT LISTBOX_SetHorizontalExtent( LB_DESCR *descr, INT extent )
+{
+ if (descr->style & LBS_MULTICOLUMN)
+ return LB_OKAY;
+ if (extent == descr->horz_extent) return LB_OKAY;
+ TRACE("[%p]: new horz extent = %d\n", descr->self, extent );
+ descr->horz_extent = extent;
+ if (descr->style & WS_HSCROLL) {
+ SCROLLINFO info;
+ info.cbSize = sizeof(info);
+ info.nMin = 0;
+ info.nMax = descr->horz_extent ? descr->horz_extent - 1 : 0;
+ info.fMask = SIF_RANGE;
+ if (descr->style & LBS_DISABLENOSCROLL)
+ info.fMask |= SIF_DISABLENOSCROLL;
+ SetScrollInfo( descr->self, SB_HORZ, &info, TRUE );
+ }
+ if (descr->horz_pos > extent - descr->width)
+ LISTBOX_SetHorizontalPos( descr, extent - descr->width );
+ return LB_OKAY;
+}
+
+
+/***********************************************************************
+ * LISTBOX_SetColumnWidth
+ */
+static LRESULT LISTBOX_SetColumnWidth( LB_DESCR *descr, INT width)
+{
+ if (width == descr->column_width) return LB_OKAY;
+ TRACE("[%p]: new column width = %d\n", descr->self, width );
+ descr->column_width = width;
+ LISTBOX_UpdatePage( descr );
+ return LB_OKAY;
+}
+
+
+/***********************************************************************
+ * LISTBOX_SetFont
+ *
+ * Returns the item height.
+ */
+static INT LISTBOX_SetFont( LB_DESCR *descr, HFONT font )
+{
+ HDC hdc;
+ HFONT oldFont = 0;
+ const char *alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ SIZE sz;
+
+ descr->font = font;
+
+ if (!(hdc = GetDCEx( descr->self, 0, DCX_CACHE )))
+ {
+ ERR("unable to get DC.\n" );
+ return 16;
+ }
+ if (font) oldFont = SelectObject( hdc, font );
+ GetTextExtentPointA( hdc, alphabet, 52, &sz);
+ if (oldFont) SelectObject( hdc, oldFont );
+ ReleaseDC( descr->self, hdc );
+
+ descr->avg_char_width = (sz.cx / 26 + 1) / 2;
+ if (!IS_OWNERDRAW(descr))
+ LISTBOX_SetItemHeight( descr, 0, sz.cy, FALSE );
+ return sz.cy;
+}
+
+
+/***********************************************************************
+ * LISTBOX_MakeItemVisible
+ *
+ * Make sure that a given item is partially or fully visible.
+ */
+static void LISTBOX_MakeItemVisible( LB_DESCR *descr, INT index, BOOL fully )
+{
+ INT top;
+
+ TRACE("current top item %d, index %d, fully %d\n", descr->top_item, index, fully);
+
+ if (index <= descr->top_item) top = index;
+ else if (descr->style & LBS_MULTICOLUMN)
+ {
+ INT cols = descr->width;
+ if (!fully) cols += descr->column_width - 1;
+ if (cols >= descr->column_width) cols /= descr->column_width;
+ else cols = 1;
+ if (index < descr->top_item + (descr->page_size * cols)) return;
+ top = index - descr->page_size * (cols - 1);
+ }
+ else if (descr->style & LBS_OWNERDRAWVARIABLE)
+ {
+ INT height = fully ? descr->items[index].height : 1;
+ for (top = index; top > descr->top_item; top--)
+ if ((height += descr->items[top-1].height) > descr->height) break;
+ }
+ else
+ {
+ if (index < descr->top_item + descr->page_size) return;
+ if (!fully && (index == descr->top_item + descr->page_size) &&
+ (descr->height > (descr->page_size * descr->item_height))) return;
+ top = index - descr->page_size + 1;
+ }
+ LISTBOX_SetTopItem( descr, top, TRUE );
+}
+
+/***********************************************************************
+ * LISTBOX_SetCaretIndex
+ *
+ * NOTES
+ * index must be between 0 and descr->nb_items-1, or LB_ERR is returned.
+ *
+ */
+static LRESULT LISTBOX_SetCaretIndex( LB_DESCR *descr, INT index, BOOL fully_visible )
+{
+ INT oldfocus = descr->focus_item;
+
+ TRACE("old focus %d, index %d\n", oldfocus, index);
+
+ if (descr->style & LBS_NOSEL) return LB_ERR;
+ if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
+ if (index == oldfocus) return LB_OKAY;
+
+ LISTBOX_DrawFocusRect( descr, FALSE );
+ descr->focus_item = index;
+
+ LISTBOX_MakeItemVisible( descr, index, fully_visible );
+ LISTBOX_DrawFocusRect( descr, TRUE );
+
+ return LB_OKAY;
+}
+
+
+/***********************************************************************
+ * LISTBOX_SelectItemRange
+ *
+ * Select a range of items. Should only be used on a MULTIPLESEL listbox.
+ */
+static LRESULT LISTBOX_SelectItemRange( LB_DESCR *descr, INT first,
+ INT last, BOOL on )
+{
+ INT i;
+
+ /* A few sanity checks */
+
+ if (descr->style & LBS_NOSEL) return LB_ERR;
+ if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
+
+ if (!descr->nb_items) return LB_OKAY;
+
+ if (last == -1 || last >= descr->nb_items) last = descr->nb_items - 1;
+ if (first < 0) first = 0;
+ if (last < first) return LB_OKAY;
+
+ if (on) /* Turn selection on */
+ {
+ for (i = first; i <= last; i++)
+ {
+ if (descr->items[i].selected) continue;
+ descr->items[i].selected = TRUE;
+ LISTBOX_InvalidateItemRect(descr, i);
+ }
+ }
+ else /* Turn selection off */
+ {
+ for (i = first; i <= last; i++)
+ {
+ if (!descr->items[i].selected) continue;
+ descr->items[i].selected = FALSE;
+ LISTBOX_InvalidateItemRect(descr, i);
+ }
+ }
+ return LB_OKAY;
+}
+
+/***********************************************************************
+ * LISTBOX_SetSelection
+ */
+static LRESULT LISTBOX_SetSelection( LB_DESCR *descr, INT index,
+ BOOL on, BOOL send_notify )
+{
+ TRACE( "cur_sel=%d index=%d notify=%s\n",
+ descr->selected_item, index, send_notify ? "YES" : "NO" );
+
+ if (descr->style & LBS_NOSEL)
+ {
+ descr->selected_item = index;
+ return LB_ERR;
+ }
+ if ((index < -1) || (index >= descr->nb_items)) return LB_ERR;
+ if (descr->style & LBS_MULTIPLESEL)
+ {
+ if (index == -1) /* Select all items */
+ return LISTBOX_SelectItemRange( descr, 0, descr->nb_items, on );
+ else /* Only one item */
+ return LISTBOX_SelectItemRange( descr, index, index, on );
+ }
+ else
+ {
+ INT oldsel = descr->selected_item;
+ if (index == oldsel) return LB_OKAY;
+ if (oldsel != -1) descr->items[oldsel].selected = FALSE;
+ if (index != -1) descr->items[index].selected = TRUE;
+ if (oldsel != -1) LISTBOX_RepaintItem( descr, oldsel, ODA_SELECT );
+ descr->selected_item = index;
+ if (index != -1) LISTBOX_RepaintItem( descr, index, ODA_SELECT );
+ if (send_notify && descr->nb_items) SEND_NOTIFICATION( descr,
+ (index != -1) ? LBN_SELCHANGE : LBN_SELCANCEL );
+ else
+ if( descr->lphc ) /* set selection change flag for parent combo */
+ descr->lphc->wState |= CBF_SELCHANGE;
+ }
+ return LB_OKAY;
+}
+
+
+/***********************************************************************
+ * LISTBOX_MoveCaret
+ *
+ * Change the caret position and extend the selection to the new caret.
+ */
+static void LISTBOX_MoveCaret( LB_DESCR *descr, INT index, BOOL fully_visible )
+{
+ TRACE("old focus %d, index %d\n", descr->focus_item, index);
+
+ if ((index < 0) || (index >= descr->nb_items))
+ return;
+
+ /* Important, repaint needs to be done in this order if
+ you want to mimic Windows behavior:
+ 1. Remove the focus and paint the item
+ 2. Remove the selection and paint the item(s)
+ 3. Set the selection and repaint the item(s)
+ 4. Set the focus to 'index' and repaint the item */
+
+ /* 1. remove the focus and repaint the item */
+ LISTBOX_DrawFocusRect( descr, FALSE );
+
+ /* 2. then turn off the previous selection */
+ /* 3. repaint the new selected item */
+ if (descr->style & LBS_EXTENDEDSEL)
+ {
+ if (descr->anchor_item != -1)
+ {
+ INT first = min( index, descr->anchor_item );
+ INT last = max( index, descr->anchor_item );
+ if (first > 0)
+ LISTBOX_SelectItemRange( descr, 0, first - 1, FALSE );
+ LISTBOX_SelectItemRange( descr, last + 1, -1, FALSE );
+ LISTBOX_SelectItemRange( descr, first, last, TRUE );
+ }
+ }
+ else if (!(descr->style & LBS_MULTIPLESEL))
+ {
+ /* Set selection to new caret item */
+ LISTBOX_SetSelection( descr, index, TRUE, FALSE );
+ }
+
+ /* 4. repaint the new item with the focus */
+ descr->focus_item = index;
+ LISTBOX_MakeItemVisible( descr, index, fully_visible );
+ LISTBOX_DrawFocusRect( descr, TRUE );
+}
+
+
+/***********************************************************************
+ * LISTBOX_InsertItem
+ */
+static LRESULT LISTBOX_InsertItem( LB_DESCR *descr, INT index,
+ LPWSTR str, ULONG_PTR data )
+{
+ LB_ITEMDATA *item;
+ INT max_items;
+ INT oldfocus = descr->focus_item;
+
+ if (index == -1) index = descr->nb_items;
+ else if ((index < 0) || (index > descr->nb_items)) return LB_ERR;
+ if (!descr->items) max_items = 0;
+ else max_items = HeapSize( GetProcessHeap(), 0, descr->items ) / sizeof(*item);
+ if (descr->nb_items == max_items)
+ {
+ /* We need to grow the array */
+ max_items += LB_ARRAY_GRANULARITY;
+ if (descr->items)
+ item = HeapReAlloc( GetProcessHeap(), 0, descr->items,
+ max_items * sizeof(LB_ITEMDATA) );
+ else
+ item = HeapAlloc( GetProcessHeap(), 0,
+ max_items * sizeof(LB_ITEMDATA) );
+ if (!item)
+ {
+ SEND_NOTIFICATION( descr, LBN_ERRSPACE );
+ return LB_ERRSPACE;
+ }
+ descr->items = item;
+ }
+
+ /* Insert the item structure */
+
+ item = &descr->items[index];
+ if (index < descr->nb_items)
+ RtlMoveMemory( item + 1, item,
+ (descr->nb_items - index) * sizeof(LB_ITEMDATA) );
+ item->str = str;
+ item->data = data;
+ item->height = 0;
+ item->selected = FALSE;
+ descr->nb_items++;
+
+ /* Get item height */
+
+ if (descr->style & LBS_OWNERDRAWVARIABLE)
+ {
+ MEASUREITEMSTRUCT mis;
+ UINT id = (UINT)GetWindowLongPtrW( descr->self, GWLP_ID );
+
+ mis.CtlType = ODT_LISTBOX;
+ mis.CtlID = id;
+ mis.itemID = index;
+ mis.itemData = descr->items[index].data;
+ mis.itemHeight = descr->item_height;
+ SendMessageW( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis );
+ item->height = mis.itemHeight ? mis.itemHeight : 1;
+ TRACE("[%p]: measure item %d (%s) = %d\n",
+ descr->self, index, str ? debugstr_w(str) : "", item->height );
+ }
+
+ /* Repaint the items */
+
+ LISTBOX_UpdateScroll( descr );
+ LISTBOX_InvalidateItems( descr, index );
+
+ /* Move selection and focused item */
+ /* If listbox was empty, set focus to the first item */
+ if (descr->nb_items == 1)
+ LISTBOX_SetCaretIndex( descr, 0, FALSE );
+ /* single select don't change selection index in win31 */
+ else if ((ISWIN31) && !(IS_MULTISELECT(descr)))
+ {
+ descr->selected_item++;
+ LISTBOX_SetSelection( descr, descr->selected_item-1, TRUE, FALSE );
+ }
+ else
+ {
+ if (index <= descr->selected_item)
+ {
+ descr->selected_item++;
+ descr->focus_item = oldfocus; /* focus not changed */
+ }
+ }
+ return LB_OKAY;
+}
+
+
+/***********************************************************************
+ * LISTBOX_InsertString
+ */
+static LRESULT LISTBOX_InsertString( LB_DESCR *descr, INT index, LPCWSTR str )
+{
+ LPWSTR new_str = NULL;
+ ULONG_PTR data = 0;
+ LRESULT ret;
+
+ if (HAS_STRINGS(descr))
+ {
+ static const WCHAR empty_stringW[] = { 0 };
+ if (!str) str = empty_stringW;
+ if (!(new_str = HeapAlloc( GetProcessHeap(), 0, (strlenW(str) + 1) * sizeof(WCHAR) )))
+ {
+ SEND_NOTIFICATION( descr, LBN_ERRSPACE );
+ return LB_ERRSPACE;
+ }
+ strcpyW(new_str, str);
+ }
+ else data = (ULONG_PTR)str;
+
+ if (index == -1) index = descr->nb_items;
+ if ((ret = LISTBOX_InsertItem( descr, index, new_str, data )) != 0)
+ {
+ HeapFree( GetProcessHeap(), 0, new_str );
+ return ret;
+ }
+
+ TRACE("[%p]: added item %d %s\n",
+ descr->self, index, HAS_STRINGS(descr) ? debugstr_w(new_str) : "" );
+ return index;
+}
+
+
+/***********************************************************************
+ * LISTBOX_DeleteItem
+ *
+ * Delete the content of an item. 'index' must be a valid index.
+ */
+static void LISTBOX_DeleteItem( LB_DESCR *descr, INT index )
+{
+ /* save the item data before it gets freed by LB_RESETCONTENT */
+ ULONG_PTR item_data = descr->items[index].data;
+ LPWSTR item_str = descr->items[index].str;
+
+ if (!descr->nb_items)
+ SendMessageW( descr->self, LB_RESETCONTENT, 0, 0 );
+
+ /* Note: Win 3.1 only sends DELETEITEM on owner-draw items,
+ * while Win95 sends it for all items with user data.
+ * It's probably better to send it too often than not
+ * often enough, so this is what we do here.
+ */
+ if (IS_OWNERDRAW(descr) || item_data)
+ {
+ DELETEITEMSTRUCT dis;
+ UINT id = (UINT)GetWindowLongPtrW( descr->self, GWLP_ID );
+
+ dis.CtlType = ODT_LISTBOX;
+ dis.CtlID = id;
+ dis.itemID = index;
+ dis.hwndItem = descr->self;
+ dis.itemData = item_data;
+ SendMessageW( descr->owner, WM_DELETEITEM, id, (LPARAM)&dis );
+ }
+ if (HAS_STRINGS(descr))
+ HeapFree( GetProcessHeap(), 0, item_str );
+}
+
+
+/***********************************************************************
+ * LISTBOX_RemoveItem
+ *
+ * Remove an item from the listbox and delete its content.
+ */
+static LRESULT LISTBOX_RemoveItem( LB_DESCR *descr, INT index )
+{
+ LB_ITEMDATA *item;
+ INT max_items;
+
+ if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
+
+ /* We need to invalidate the original rect instead of the updated one. */
+ LISTBOX_InvalidateItems( descr, index );
+
+ descr->nb_items--;
+ LISTBOX_DeleteItem( descr, index );
+
+ if (!descr->nb_items) return LB_OKAY;
+
+ /* Remove the item */
+
+ item = &descr->items[index];
+ if (index < descr->nb_items)
+ RtlMoveMemory( item, item + 1,
+ (descr->nb_items - index) * sizeof(LB_ITEMDATA) );
+ if (descr->anchor_item == descr->nb_items) descr->anchor_item--;
+
+ /* Shrink the item array if possible */
+
+ max_items = HeapSize( GetProcessHeap(), 0, descr->items ) / sizeof(LB_ITEMDATA);
+ if (descr->nb_items < max_items - 2*LB_ARRAY_GRANULARITY)
+ {
+ max_items -= LB_ARRAY_GRANULARITY;
+ item = HeapReAlloc( GetProcessHeap(), 0, descr->items,
+ max_items * sizeof(LB_ITEMDATA) );
+ if (item) descr->items = item;
+ }
+ /* Repaint the items */
+
+ LISTBOX_UpdateScroll( descr );
+ /* if we removed the scrollbar, reset the top of the list
+ (correct for owner-drawn ???) */
+ if (descr->nb_items == descr->page_size)
+ LISTBOX_SetTopItem( descr, 0, TRUE );
+
+ /* Move selection and focused item */
+ if (!IS_MULTISELECT(descr))
+ {
+ if (index == descr->selected_item)
+ descr->selected_item = -1;
+ else if (index < descr->selected_item)
+ {
+ descr->selected_item--;
+ if (ISWIN31) /* win 31 do not change the selected item number */
+ LISTBOX_SetSelection( descr, descr->selected_item + 1, TRUE, FALSE);
+ }
+ }
+
+ if (descr->focus_item >= descr->nb_items)
+ {
+ descr->focus_item = descr->nb_items - 1;
+ if (descr->focus_item < 0) descr->focus_item = 0;
+ }
+ return LB_OKAY;
+}
+
+
+/***********************************************************************
+ * LISTBOX_ResetContent
+ */
+static void LISTBOX_ResetContent( LB_DESCR *descr )
+{
+ INT i;
+
+ for(i = descr->nb_items - 1; i>=0; i--) LISTBOX_DeleteItem( descr, i);
+ HeapFree( GetProcessHeap(), 0, descr->items );
+ descr->nb_items = 0;
+ descr->top_item = 0;
+ descr->selected_item = -1;
+ descr->focus_item = 0;
+ descr->anchor_item = -1;
+ descr->items = NULL;
+}
+
+
+/***********************************************************************
+ * LISTBOX_SetCount
+ */
+static LRESULT LISTBOX_SetCount( LB_DESCR *descr, INT count )
+{
+ LRESULT ret;
+
+ if (HAS_STRINGS(descr))
+ {
+ SetLastError(ERROR_SETCOUNT_ON_BAD_LB);
+ return LB_ERR;
+ }
+
+ /* FIXME: this is far from optimal... */
+ if (count > descr->nb_items)
+ {
+ while (count > descr->nb_items)
+ if ((ret = LISTBOX_InsertString( descr, -1, 0 )) < 0)
+ return ret;
+ }
+ else if (count < descr->nb_items)
+ {
+ while (count < descr->nb_items)
+ if ((ret = LISTBOX_RemoveItem( descr, (descr->nb_items - 1) )) < 0)
+ return ret;
+ }
+
+ InvalidateRect( descr->self, NULL, TRUE );
+ return LB_OKAY;
+}
+
+
+/***********************************************************************
+ * LISTBOX_Directory
+ */
+static LRESULT LISTBOX_Directory( LB_DESCR *descr, UINT attrib,
+ LPCWSTR filespec, BOOL long_names )
+{
+ HANDLE handle;
+ LRESULT ret = LB_OKAY;
+ WIN32_FIND_DATAW entry;
+ int pos;
+ LRESULT maxinsert = LB_ERR;
+
+ /* don't scan directory if we just want drives exclusively */
+ if (attrib != (DDL_DRIVES | DDL_EXCLUSIVE)) {
+ /* scan directory */
+ if ((handle = FindFirstFileW(filespec, &entry)) == INVALID_HANDLE_VALUE)
+ {
+ int le = GetLastError();
+ if ((le != ERROR_NO_MORE_FILES) && (le != ERROR_FILE_NOT_FOUND)) return LB_ERR;
+ }
+ else
+ {
+ do
+ {
+ WCHAR buffer[270];
+ if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ static const WCHAR bracketW[] = { ']',0 };
+ static const WCHAR dotW[] = { '.',0 };
+ if (!(attrib & DDL_DIRECTORY) ||
+ !strcmpW( entry.cFileName, dotW )) continue;
+ buffer[0] = '[';
+ if (!long_names && entry.cAlternateFileName[0])
+ strcpyW( buffer + 1, entry.cAlternateFileName );
+ else
+ strcpyW( buffer + 1, entry.cFileName );
+ strcatW(buffer, bracketW);
+ }
+ else /* not a directory */
+ {
+#define ATTRIBS (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \
+ FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE)
+
+ if ((attrib & DDL_EXCLUSIVE) &&
+ ((attrib & ATTRIBS) != (entry.dwFileAttributes & ATTRIBS)))
+ continue;
+#undef ATTRIBS
+ if (!long_names && entry.cAlternateFileName[0])
+ strcpyW( buffer, entry.cAlternateFileName );
+ else
+ strcpyW( buffer, entry.cFileName );
+ }
+ if (!long_names) CharLowerW( buffer );
+ pos = LISTBOX_FindFileStrPos( descr, buffer );
+ if ((ret = LISTBOX_InsertString( descr, pos, buffer )) < 0)
+ break;
+ if (ret <= maxinsert) maxinsert++; else maxinsert = ret;
+ } while (FindNextFileW( handle, &entry ));
+ FindClose( handle );
+ }
+ }
+ if (ret >= 0)
+ {
+ ret = maxinsert;
+
+ /* scan drives */
+ if (attrib & DDL_DRIVES)
+ {
+ WCHAR buffer[] = {'[','-','a','-',']',0};
+ WCHAR root[] = {'A',':','\\',0};
+ int drive;
+ for (drive = 0; drive < 26; drive++, buffer[2]++, root[0]++)
+ {
+ if (GetDriveTypeW(root) <= DRIVE_NO_ROOT_DIR) continue;
+ if ((ret = LISTBOX_InsertString( descr, -1, buffer )) < 0)
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
+
+/***********************************************************************
+ * LISTBOX_HandleVScroll
+ */
+static LRESULT LISTBOX_HandleVScroll( LB_DESCR *descr, WORD scrollReq, WORD pos )
+{
+ SCROLLINFO info;
+
+ if (descr->style & LBS_MULTICOLUMN) return 0;
+ switch(scrollReq)
+ {
+ case SB_LINEUP:
+ LISTBOX_SetTopItem( descr, descr->top_item - 1, TRUE );
+ break;
+ case SB_LINEDOWN:
+ LISTBOX_SetTopItem( descr, descr->top_item + 1, TRUE );
+ break;
+ case SB_PAGEUP:
+ LISTBOX_SetTopItem( descr, descr->top_item -
+ LISTBOX_GetCurrentPageSize( descr ), TRUE );
+ break;
+ case SB_PAGEDOWN:
+ LISTBOX_SetTopItem( descr, descr->top_item +
+ LISTBOX_GetCurrentPageSize( descr ), TRUE );
+ break;
+ case SB_THUMBPOSITION:
+ LISTBOX_SetTopItem( descr, pos, TRUE );
+ break;
+ case SB_THUMBTRACK:
+ info.cbSize = sizeof(info);
+ info.fMask = SIF_TRACKPOS;
+ GetScrollInfo( descr->self, SB_VERT, &info );
+ LISTBOX_SetTopItem( descr, info.nTrackPos, TRUE );
+ break;
+ case SB_TOP:
+ LISTBOX_SetTopItem( descr, 0, TRUE );
+ break;
+ case SB_BOTTOM:
+ LISTBOX_SetTopItem( descr, descr->nb_items, TRUE );
+ break;
+ }
+ return 0;
+}
+
+
+/***********************************************************************
+ * LISTBOX_HandleHScroll
+ */
+static LRESULT LISTBOX_HandleHScroll( LB_DESCR *descr, WORD scrollReq, WORD pos )
+{
+ SCROLLINFO info;
+ INT page;
+
+ if (descr->style & LBS_MULTICOLUMN)
+ {
+ switch(scrollReq)
+ {
+ case SB_LINELEFT:
+ LISTBOX_SetTopItem( descr, descr->top_item-descr->page_size,
+ TRUE );
+ break;
+ case SB_LINERIGHT:
+ LISTBOX_SetTopItem( descr, descr->top_item+descr->page_size,
+ TRUE );
+ break;
+ case SB_PAGELEFT:
+ page = descr->width / descr->column_width;
+ if (page < 1) page = 1;
+ LISTBOX_SetTopItem( descr,
+ descr->top_item - page * descr->page_size, TRUE );
+ break;
+ case SB_PAGERIGHT:
+ page = descr->width / descr->column_width;
+ if (page < 1) page = 1;
+ LISTBOX_SetTopItem( descr,
+ descr->top_item + page * descr->page_size, TRUE );
+ break;
+ case SB_THUMBPOSITION:
+ LISTBOX_SetTopItem( descr, pos*descr->page_size, TRUE );
+ break;
+ case SB_THUMBTRACK:
+ info.cbSize = sizeof(info);
+ info.fMask = SIF_TRACKPOS;
+ GetScrollInfo( descr->self, SB_VERT, &info );
+ LISTBOX_SetTopItem( descr, info.nTrackPos*descr->page_size,
+ TRUE );
+ break;
+ case SB_LEFT:
+ LISTBOX_SetTopItem( descr, 0, TRUE );
+ break;
+ case SB_RIGHT:
+ LISTBOX_SetTopItem( descr, descr->nb_items, TRUE );
+ break;
+ }
+ }
+ else if (descr->horz_extent)
+ {
+ switch(scrollReq)
+ {
+ case SB_LINELEFT:
+ LISTBOX_SetHorizontalPos( descr, descr->horz_pos - 1 );
+ break;
+ case SB_LINERIGHT:
+ LISTBOX_SetHorizontalPos( descr, descr->horz_pos + 1 );
+ break;
+ case SB_PAGELEFT:
+ LISTBOX_SetHorizontalPos( descr,
+ descr->horz_pos - descr->width );
+ break;
+ case SB_PAGERIGHT:
+ LISTBOX_SetHorizontalPos( descr,
+ descr->horz_pos + descr->width );
+ break;
+ case SB_THUMBPOSITION:
+ LISTBOX_SetHorizontalPos( descr, pos );
+ break;
+ case SB_THUMBTRACK:
+ info.cbSize = sizeof(info);
+ info.fMask = SIF_TRACKPOS;
+ GetScrollInfo( descr->self, SB_HORZ, &info );
+ LISTBOX_SetHorizontalPos( descr, info.nTrackPos );
+ break;
+ case SB_LEFT:
+ LISTBOX_SetHorizontalPos( descr, 0 );
+ break;
+ case SB_RIGHT:
+ LISTBOX_SetHorizontalPos( descr,
+ descr->horz_extent - descr->width );
+ break;
+ }
+ }
+ return 0;
+}
+
+static LRESULT LISTBOX_HandleMouseWheel(LB_DESCR *descr, SHORT delta )
+{
+ UINT pulScrollLines = 3;
+
+ SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
+
+ /* if scrolling changes direction, ignore left overs */
+ if ((delta < 0 && descr->wheel_remain < 0) ||
+ (delta > 0 && descr->wheel_remain > 0))
+ descr->wheel_remain += delta;
+ else
+ descr->wheel_remain = delta;
+
+ if (descr->wheel_remain && pulScrollLines)
+ {
+ int cLineScroll;
+ pulScrollLines = min((UINT) descr->page_size, pulScrollLines);
+ cLineScroll = pulScrollLines * (float)descr->wheel_remain / WHEEL_DELTA;
+ descr->wheel_remain -= WHEEL_DELTA * cLineScroll / (int)pulScrollLines;
+ LISTBOX_SetTopItem( descr, descr->top_item - cLineScroll, TRUE );
+ }
+ return 0;
+}
+
+/***********************************************************************
+ * LISTBOX_HandleLButtonDown
+ */
+static LRESULT LISTBOX_HandleLButtonDown( LB_DESCR *descr, DWORD keys, INT x, INT y )
+{
+ INT index = LISTBOX_GetItemFromPoint( descr, x, y );
+
+ TRACE("[%p]: lbuttondown %d,%d item %d, focus item %d\n",
+ descr->self, x, y, index, descr->focus_item);
+
+ if (!descr->caret_on && (descr->in_focus)) return 0;
+
+ if (!descr->in_focus)
+ {
+ if( !descr->lphc ) SetFocus( descr->self );
+ else SetFocus( (descr->lphc->hWndEdit) ? descr->lphc->hWndEdit : descr->lphc->self );
+ }
+
+ if (index == -1) return 0;
+
+ if (!descr->lphc)
+ {
+ if (descr->style & LBS_NOTIFY )
+ SendMessageW( descr->owner, WM_LBTRACKPOINT, index,
+ MAKELPARAM( x, y ) );
+ }
+
+ descr->captured = TRUE;
+ SetCapture( descr->self );
+
+ if (descr->style & (LBS_EXTENDEDSEL | LBS_MULTIPLESEL))
+ {
+ /* we should perhaps make sure that all items are deselected
+ FIXME: needed for !LBS_EXTENDEDSEL, too ?
+ if (!(keys & (MK_SHIFT|MK_CONTROL)))
+ LISTBOX_SetSelection( descr, -1, FALSE, FALSE);
+ */
+
+ if (!(keys & MK_SHIFT)) descr->anchor_item = index;
+ if (keys & MK_CONTROL)
+ {
+ LISTBOX_SetCaretIndex( descr, index, FALSE );
+ LISTBOX_SetSelection( descr, index,
+ !descr->items[index].selected,
+ (descr->style & LBS_NOTIFY) != 0);
+ }
+ else
+ {
+ LISTBOX_MoveCaret( descr, index, FALSE );
+
+ if (descr->style & LBS_EXTENDEDSEL)
+ {
+ LISTBOX_SetSelection( descr, index,
+ descr->items[index].selected,
+ (descr->style & LBS_NOTIFY) != 0 );
+ }
+ else
+ {
+ LISTBOX_SetSelection( descr, index,
+ !descr->items[index].selected,
+ (descr->style & LBS_NOTIFY) != 0 );
+ }
+ }
+ }
+ else
+ {
+ descr->anchor_item = index;
+ LISTBOX_MoveCaret( descr, index, FALSE );
+ LISTBOX_SetSelection( descr, index,
+ TRUE, (descr->style & LBS_NOTIFY) != 0 );
+ }
+
+ if (!descr->lphc)
+ {
+ if (GetWindowLongW( descr->self, GWL_EXSTYLE ) & WS_EX_DRAGDETECT)
+ {
+ POINT pt;
+
+ pt.x = x;
+ pt.y = y;
+
+ if (DragDetect( descr->self, pt ))
+ SendMessageW( descr->owner, WM_BEGINDRAG, 0, 0 );
+ }
+ }
+ return 0;
+}
+
+
+/*************************************************************************
+ * LISTBOX_HandleLButtonDownCombo [Internal]
+ *
+ * Process LButtonDown message for the ComboListBox
+ *
+ * PARAMS
+ * pWnd [I] The windows internal structure
+ * pDescr [I] The ListBox internal structure
+ * keys [I] Key Flag (WM_LBUTTONDOWN doc for more info)
+ * x [I] X Mouse Coordinate
+ * y [I] Y Mouse Coordinate
+ *
+ * RETURNS
+ * 0 since we are processing the WM_LBUTTONDOWN Message
+ *
+ * NOTES
+ * This function is only to be used when a ListBox is a ComboListBox
+ */
+
+static LRESULT LISTBOX_HandleLButtonDownCombo( LB_DESCR *descr, UINT msg, DWORD keys, INT x, INT y)
+{
+ RECT clientRect, screenRect;
+ POINT mousePos;
+
+ mousePos.x = x;
+ mousePos.y = y;
+
+ GetClientRect(descr->self, &clientRect);
+
+ if(PtInRect(&clientRect, mousePos))
+ {
+ /* MousePos is in client, resume normal processing */
+ if (msg == WM_LBUTTONDOWN)
+ {
+ descr->lphc->droppedIndex = descr->nb_items ? descr->selected_item : -1;
+ return LISTBOX_HandleLButtonDown( descr, keys, x, y);
+ }
+ else if (descr->style & LBS_NOTIFY)
+ SEND_NOTIFICATION( descr, LBN_DBLCLK );
+ }
+ else
+ {
+ POINT screenMousePos;
+ HWND hWndOldCapture;
+
+ /* Check the Non-Client Area */
+ screenMousePos = mousePos;
+ hWndOldCapture = GetCapture();
+ ReleaseCapture();
+ GetWindowRect(descr->self, &screenRect);
+ ClientToScreen(descr->self, &screenMousePos);
+
+ if(!PtInRect(&screenRect, screenMousePos))
+ {
+ LISTBOX_SetCaretIndex( descr, descr->lphc->droppedIndex, FALSE );
+ LISTBOX_SetSelection( descr, descr->lphc->droppedIndex, FALSE, FALSE );
+ COMBO_FlipListbox( descr->lphc, FALSE, FALSE );
+ }
+ else
+ {
+ /* Check to see the NC is a scrollbar */
+ INT nHitTestType=0;
+ LONG style = GetWindowLongW( descr->self, GWL_STYLE );
+ /* Check Vertical scroll bar */
+ if (style & WS_VSCROLL)
+ {
+ clientRect.right += GetSystemMetrics(SM_CXVSCROLL);
+ if (PtInRect( &clientRect, mousePos ))
+ nHitTestType = HTVSCROLL;
+ }
+ /* Check horizontal scroll bar */
+ if (style & WS_HSCROLL)
+ {
+ clientRect.bottom += GetSystemMetrics(SM_CYHSCROLL);
+ if (PtInRect( &clientRect, mousePos ))
+ nHitTestType = HTHSCROLL;
+ }
+ /* Windows sends this message when a scrollbar is clicked
+ */
+
+ if(nHitTestType != 0)
+ {
+ SendMessageW(descr->self, WM_NCLBUTTONDOWN, nHitTestType,
+ MAKELONG(screenMousePos.x, screenMousePos.y));
+ }
+ /* Resume the Capture after scrolling is complete
+ */
+ if(hWndOldCapture != 0)
+ SetCapture(hWndOldCapture);
+ }
+ }
+ return 0;
+}
+
+/***********************************************************************
+ * LISTBOX_HandleLButtonUp
+ */
+static LRESULT LISTBOX_HandleLButtonUp( LB_DESCR *descr )
+{
+ if (LISTBOX_Timer != LB_TIMER_NONE)
+ KillSystemTimer( descr->self, LB_TIMER_ID );
+ LISTBOX_Timer = LB_TIMER_NONE;
+ if (descr->captured)
+ {
+ descr->captured = FALSE;
+ if (GetCapture() == descr->self) ReleaseCapture();
+ if ((descr->style & LBS_NOTIFY) && descr->nb_items)
+ SEND_NOTIFICATION( descr, LBN_SELCHANGE );
+ }
+ return 0;
+}
+
+
+/***********************************************************************
+ * LISTBOX_HandleTimer
+ *
+ * Handle scrolling upon a timer event.
+ * Return TRUE if scrolling should continue.
+ */
+static LRESULT LISTBOX_HandleTimer( LB_DESCR *descr, INT index, TIMER_DIRECTION dir )
+{
+ switch(dir)
+ {
+ case LB_TIMER_UP:
+ if (descr->top_item) index = descr->top_item - 1;
+ else index = 0;
+ break;
+ case LB_TIMER_LEFT:
+ if (descr->top_item) index -= descr->page_size;
+ break;
+ case LB_TIMER_DOWN:
+ index = descr->top_item + LISTBOX_GetCurrentPageSize( descr );
+ if (index == descr->focus_item) index++;
+ if (index >= descr->nb_items) index = descr->nb_items - 1;
+ break;
+ case LB_TIMER_RIGHT:
+ if (index + descr->page_size < descr->nb_items)
+ index += descr->page_size;
+ break;
+ case LB_TIMER_NONE:
+ break;
+ }
+ if (index == descr->focus_item) return FALSE;
+ LISTBOX_MoveCaret( descr, index, FALSE );
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * LISTBOX_HandleSystemTimer
+ *
+ * WM_SYSTIMER handler.
+ */
+static LRESULT LISTBOX_HandleSystemTimer( LB_DESCR *descr )
+{
+ if (!LISTBOX_HandleTimer( descr, descr->focus_item, LISTBOX_Timer ))
+ {
+ KillSystemTimer( descr->self, LB_TIMER_ID );
+ LISTBOX_Timer = LB_TIMER_NONE;
+ }
+ return 0;
+}
+
+
+/***********************************************************************
+ * LISTBOX_HandleMouseMove
+ *
+ * WM_MOUSEMOVE handler.
+ */
+static void LISTBOX_HandleMouseMove( LB_DESCR *descr,
+ INT x, INT y )
+{
+ INT index;
+ TIMER_DIRECTION dir = LB_TIMER_NONE;
+
+ if (!descr->captured) return;
+
+ if (descr->style & LBS_MULTICOLUMN)
+ {
+ if (y < 0) y = 0;
+ else if (y >= descr->item_height * descr->page_size)
+ y = descr->item_height * descr->page_size - 1;
+
+ if (x < 0)
+ {
+ dir = LB_TIMER_LEFT;
+ x = 0;
+ }
+ else if (x >= descr->width)
+ {
+ dir = LB_TIMER_RIGHT;
+ x = descr->width - 1;
+ }
+ }
+ else
+ {
+ if (y < 0) dir = LB_TIMER_UP; /* above */
+ else if (y >= descr->height) dir = LB_TIMER_DOWN; /* below */
+ }
+
+ index = LISTBOX_GetItemFromPoint( descr, x, y );
+ if (index == -1) index = descr->focus_item;
+ if (!LISTBOX_HandleTimer( descr, index, dir )) dir = LB_TIMER_NONE;
+
+ /* Start/stop the system timer */
+
+ if (dir != LB_TIMER_NONE)
+ SetSystemTimer( descr->self, LB_TIMER_ID, LB_SCROLL_TIMEOUT, NULL);
+ else if (LISTBOX_Timer != LB_TIMER_NONE)
+ KillSystemTimer( descr->self, LB_TIMER_ID );
+ LISTBOX_Timer = dir;
+}
+
+
+/***********************************************************************
+ * LISTBOX_HandleKeyDown
+ */
+static LRESULT LISTBOX_HandleKeyDown( LB_DESCR *descr, DWORD key )
+{
+ INT caret = -1;
+ BOOL bForceSelection = TRUE; /* select item pointed to by focus_item */
+ if ((IS_MULTISELECT(descr)) || (descr->selected_item == descr->focus_item))
+ bForceSelection = FALSE; /* only for single select list */
+
+ if (descr->style & LBS_WANTKEYBOARDINPUT)
+ {
+ caret = SendMessageW( descr->owner, WM_VKEYTOITEM,
+ MAKEWPARAM(LOWORD(key), descr->focus_item),
+ (LPARAM)descr->self );
+ if (caret == -2) return 0;
+ }
+ if (caret == -1) switch(key)
+ {
+ case VK_LEFT:
+ if (descr->style & LBS_MULTICOLUMN)
+ {
+ bForceSelection = FALSE;
+ if (descr->focus_item >= descr->page_size)
+ caret = descr->focus_item - descr->page_size;
+ break;
+ }
+ /* fall through */
+ case VK_UP:
+ caret = descr->focus_item - 1;
+ if (caret < 0) caret = 0;
+ break;
+ case VK_RIGHT:
+ if (descr->style & LBS_MULTICOLUMN)
+ {
+ bForceSelection = FALSE;
+ if (descr->focus_item + descr->page_size < descr->nb_items)
+ caret = descr->focus_item + descr->page_size;
+ break;
+ }
+ /* fall through */
+ case VK_DOWN:
+ caret = descr->focus_item + 1;
+ if (caret >= descr->nb_items) caret = descr->nb_items - 1;
+ break;
+
+ case VK_PRIOR:
+ if (descr->style & LBS_MULTICOLUMN)
+ {
+ INT page = descr->width / descr->column_width;
+ if (page < 1) page = 1;
+ caret = descr->focus_item - (page * descr->page_size) + 1;
+ }
+ else caret = descr->focus_item-LISTBOX_GetCurrentPageSize(descr) + 1;
+ if (caret < 0) caret = 0;
+ break;
+ case VK_NEXT:
+ if (descr->style & LBS_MULTICOLUMN)
+ {
+ INT page = descr->width / descr->column_width;
+ if (page < 1) page = 1;
+ caret = descr->focus_item + (page * descr->page_size) - 1;
+ }
+ else caret = descr->focus_item + LISTBOX_GetCurrentPageSize(descr) - 1;
+ if (caret >= descr->nb_items) caret = descr->nb_items - 1;
+ break;
+ case VK_HOME:
+ caret = 0;
+ break;
+ case VK_END:
+ caret = descr->nb_items - 1;
+ break;
+ case VK_SPACE:
+ if (descr->style & LBS_EXTENDEDSEL) caret = descr->focus_item;
+ else if (descr->style & LBS_MULTIPLESEL)
+ {
+ LISTBOX_SetSelection( descr, descr->focus_item,
+ !descr->items[descr->focus_item].selected,
+ (descr->style & LBS_NOTIFY) != 0 );
+ }
+ break;
+ default:
+ bForceSelection = FALSE;
+ }
+ if (bForceSelection) /* focused item is used instead of key */
+ caret = descr->focus_item;
+ if (caret >= 0)
+ {
+ if (((descr->style & LBS_EXTENDEDSEL) &&
+ !(GetKeyState( VK_SHIFT ) & 0x8000)) ||
+ !IS_MULTISELECT(descr))
+ descr->anchor_item = caret;
+ LISTBOX_MoveCaret( descr, caret, TRUE );
+
+ if (descr->style & LBS_MULTIPLESEL)
+ descr->selected_item = caret;
+ else
+ LISTBOX_SetSelection( descr, caret, TRUE, FALSE);
+ if (descr->style & LBS_NOTIFY)
+ {
+ if (descr->lphc && IsWindowVisible( descr->self ))
+ {
+ /* make sure that combo parent doesn't hide us */
+ descr->lphc->wState |= CBF_NOROLLUP;
+ }
+ if (descr->nb_items) SEND_NOTIFICATION( descr, LBN_SELCHANGE );
+ }
+ }
+ return 0;
+}
+
+
+/***********************************************************************
+ * LISTBOX_HandleChar
+ */
+static LRESULT LISTBOX_HandleChar( LB_DESCR *descr, WCHAR charW )
+{
+ INT caret = -1;
+ WCHAR str[2];
+
+ str[0] = charW;
+ str[1] = '\0';
+
+ if (descr->style & LBS_WANTKEYBOARDINPUT)
+ {
+ caret = SendMessageW( descr->owner, WM_CHARTOITEM,
+ MAKEWPARAM(charW, descr->focus_item),
+ (LPARAM)descr->self );
+ if (caret == -2) return 0;
+ }
+ if (caret == -1)
+ caret = LISTBOX_FindString( descr, descr->focus_item, str, FALSE);
+ if (caret != -1)
+ {
+ if ((!IS_MULTISELECT(descr)) && descr->selected_item == -1)
+ LISTBOX_SetSelection( descr, caret, TRUE, FALSE);
+ LISTBOX_MoveCaret( descr, caret, TRUE );
+ if ((descr->style & LBS_NOTIFY) && descr->nb_items)
+ SEND_NOTIFICATION( descr, LBN_SELCHANGE );
+ }
+ return 0;
+}
+
+
+/***********************************************************************
+ * LISTBOX_Create
+ */
+static BOOL LISTBOX_Create( HWND hwnd, LPHEADCOMBO lphc )
+{
+ LB_DESCR *descr;
+ MEASUREITEMSTRUCT mis;
+ RECT rect;
+
+ if (!(descr = HeapAlloc( GetProcessHeap(), 0, sizeof(*descr) )))
+ return FALSE;
+
+ GetClientRect( hwnd, &rect );
+ descr->self = hwnd;
+ descr->owner = GetParent( descr->self );
+ descr->style = GetWindowLongW( descr->self, GWL_STYLE );
+ descr->width = rect.right - rect.left;
+ descr->height = rect.bottom - rect.top;
+ descr->items = NULL;
+ descr->nb_items = 0;
+ descr->top_item = 0;
+ descr->selected_item = -1;
+ descr->focus_item = 0;
+ descr->anchor_item = -1;
+ descr->item_height = 1;
+ descr->page_size = 1;
+ descr->column_width = 150;
+ descr->horz_extent = 0;
+ descr->horz_pos = 0;
+ descr->nb_tabs = 0;
+ descr->tabs = NULL;
+ descr->wheel_remain = 0;
+ descr->caret_on = !lphc;
+ if (descr->style & LBS_NOSEL) descr->caret_on = FALSE;
+ descr->in_focus = FALSE;
+ descr->captured = FALSE;
+ descr->font = 0;
+ descr->locale = GetUserDefaultLCID();
+ descr->lphc = lphc;
+
+ if( lphc )
+ {
+ TRACE("[%p]: resetting owner %p -> %p\n", descr->self, descr->owner, lphc->self );
+ descr->owner = lphc->self;
+ }
+
+ SetWindowLongPtrW( descr->self, 0, (LONG_PTR)descr );
+
+/* if (wnd->dwExStyle & WS_EX_NOPARENTNOTIFY) descr->style &= ~LBS_NOTIFY;
+ */
+ if (descr->style & LBS_EXTENDEDSEL) descr->style |= LBS_MULTIPLESEL;
+ if (descr->style & LBS_MULTICOLUMN) descr->style &= ~LBS_OWNERDRAWVARIABLE;
+ if (descr->style & LBS_OWNERDRAWVARIABLE) descr->style |= LBS_NOINTEGRALHEIGHT;
+ descr->item_height = LISTBOX_SetFont( descr, 0 );
+
+ if (descr->style & LBS_OWNERDRAWFIXED)
+ {
+ if( descr->lphc && (descr->lphc->dwStyle & CBS_DROPDOWN))
+ {
+ /* WinWord gets VERY unhappy if we send WM_MEASUREITEM from here */
+ descr->item_height = lphc->fixedOwnerDrawHeight;
+ }
+ else
+ {
+ UINT id = (UINT)GetWindowLongPtrW( descr->self, GWLP_ID );
+ mis.CtlType = ODT_LISTBOX;
+ mis.CtlID = id;
+ mis.itemID = -1;
+ mis.itemWidth = 0;
+ mis.itemData = 0;
+ mis.itemHeight = descr->item_height;
+ SendMessageW( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis );
+ descr->item_height = mis.itemHeight ? mis.itemHeight : 1;
+ }
+ }
+
+ TRACE("owner: %p, style: %08x, width: %d, height: %d\n", descr->owner, descr->style, descr->width, descr->height);
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * LISTBOX_Destroy
+ */
+static BOOL LISTBOX_Destroy( LB_DESCR *descr )
+{
+ LISTBOX_ResetContent( descr );
+ SetWindowLongPtrW( descr->self, 0, 0 );
+ HeapFree( GetProcessHeap(), 0, descr );
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * ListBoxWndProc_common
+ */
+static LRESULT CALLBACK LISTBOX_WindowProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ LB_DESCR *descr = (LB_DESCR *)GetWindowLongPtrW( hwnd, 0 );
+ LPHEADCOMBO lphc = 0;
+ LRESULT ret;
+
+ if (!descr)
+ {
+ if (!IsWindow(hwnd)) return 0;
+
+ if (msg == WM_CREATE)
+ {
+ CREATESTRUCTW *lpcs = (CREATESTRUCTW *)lParam;
+ if (lpcs->style & LBS_COMBOBOX) lphc = lpcs->lpCreateParams;
+ if (!LISTBOX_Create( hwnd, lphc )) return -1;
+ TRACE("creating hwnd %p descr %p\n", hwnd, (void *)GetWindowLongPtrW( hwnd, 0 ) );
+ return 0;
+ }
+ /* Ignore all other messages before we get a WM_CREATE */
+ return DefWindowProcW( hwnd, msg, wParam, lParam );
+ }
+ if (descr->style & LBS_COMBOBOX) lphc = descr->lphc;
+
+ TRACE("[%p]: msg %#x wp %08lx lp %08lx\n", descr->self, msg, wParam, lParam );
+
+ switch(msg)
+ {
+ case LB_RESETCONTENT:
+ LISTBOX_ResetContent( descr );
+ LISTBOX_UpdateScroll( descr );
+ InvalidateRect( descr->self, NULL, TRUE );
+ return 0;
+
+ case LB_ADDSTRING:
+ {
+ const WCHAR *textW = (const WCHAR *)lParam;
+ INT index = LISTBOX_FindStringPos( descr, textW, FALSE );
+ return LISTBOX_InsertString( descr, index, textW );
+ }
+
+ case LB_INSERTSTRING:
+ return LISTBOX_InsertString( descr, wParam, (const WCHAR *)lParam );
+
+ case LB_ADDFILE:
+ {
+ const WCHAR *textW = (const WCHAR *)lParam;
+ INT index = LISTBOX_FindFileStrPos( descr, textW );
+ return LISTBOX_InsertString( descr, index, textW );
+ }
+
+ case LB_DELETESTRING:
+ if (LISTBOX_RemoveItem( descr, wParam) != LB_ERR)
+ return descr->nb_items;
+ else
+ {
+ SetLastError(ERROR_INVALID_INDEX);
+ return LB_ERR;
+ }
+
+ case LB_GETITEMDATA:
+ if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
+ {
+ SetLastError(ERROR_INVALID_INDEX);
+ return LB_ERR;
+ }
+ return descr->items[wParam].data;
+
+ case LB_SETITEMDATA:
+ if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
+ {
+ SetLastError(ERROR_INVALID_INDEX);
+ return LB_ERR;
+ }
+ descr->items[wParam].data = lParam;
+ /* undocumented: returns TRUE, not LB_OKAY (0) */
+ return TRUE;
+
+ case LB_GETCOUNT:
+ return descr->nb_items;
+
+ case LB_GETTEXT:
+ return LISTBOX_GetText( descr, wParam, (LPWSTR)lParam, TRUE );
+
+ case LB_GETTEXTLEN:
+ if ((INT)wParam >= descr->nb_items || (INT)wParam < 0)
+ {
+ SetLastError(ERROR_INVALID_INDEX);
+ return LB_ERR;
+ }
+ if (!HAS_STRINGS(descr)) return sizeof(DWORD);
+ return strlenW( descr->items[wParam].str );
+
+ case LB_GETCURSEL:
+ if (descr->nb_items == 0)
+ return LB_ERR;
+ if (!IS_MULTISELECT(descr))
+ return descr->selected_item;
+ if (descr->selected_item != -1)
+ return descr->selected_item;
+ return descr->focus_item;
+ /* otherwise, if the user tries to move the selection with the */
+ /* arrow keys, we will give the application something to choke on */
+ case LB_GETTOPINDEX:
+ return descr->top_item;
+
+ case LB_GETITEMHEIGHT:
+ return LISTBOX_GetItemHeight( descr, wParam );
+
+ case LB_SETITEMHEIGHT:
+ return LISTBOX_SetItemHeight( descr, wParam, lParam, TRUE );
+
+ case LB_ITEMFROMPOINT:
+ {
+ POINT pt;
+ RECT rect;
+ int index;
+ BOOL hit = TRUE;
+
+ /* The hiword of the return value is not a client area
+ hittest as suggested by MSDN, but rather a hittest on
+ the returned listbox item. */
+
+ if(descr->nb_items == 0)
+ return 0x1ffff; /* win9x returns 0x10000, we copy winnt */
+
+ pt.x = (short)LOWORD(lParam);
+ pt.y = (short)HIWORD(lParam);
+
+ SetRect(&rect, 0, 0, descr->width, descr->height);
+
+ if(!PtInRect(&rect, pt))
+ {
+ pt.x = min(pt.x, rect.right - 1);
+ pt.x = max(pt.x, 0);
+ pt.y = min(pt.y, rect.bottom - 1);
+ pt.y = max(pt.y, 0);
+ hit = FALSE;
+ }
+
+ index = LISTBOX_GetItemFromPoint(descr, pt.x, pt.y);
+
+ if(index == -1)
+ {
+ index = descr->nb_items - 1;
+ hit = FALSE;
+ }
+ return MAKELONG(index, hit ? 0 : 1);
+ }
+
+ case LB_SETCARETINDEX:
+ if ((!IS_MULTISELECT(descr)) && (descr->selected_item != -1)) return LB_ERR;
+ if (LISTBOX_SetCaretIndex( descr, wParam, !lParam ) == LB_ERR)
+ return LB_ERR;
+ else if (ISWIN31)
+ return wParam;
+ else
+ return LB_OKAY;
+
+ case LB_GETCARETINDEX:
+ return descr->focus_item;
+
+ case LB_SETTOPINDEX:
+ return LISTBOX_SetTopItem( descr, wParam, TRUE );
+
+ case LB_SETCOLUMNWIDTH:
+ return LISTBOX_SetColumnWidth( descr, wParam );
+
+ case LB_GETITEMRECT:
+ return LISTBOX_GetItemRect( descr, wParam, (RECT *)lParam );
+
+ case LB_FINDSTRING:
+ return LISTBOX_FindString( descr, wParam, (const WCHAR *)lParam, FALSE );
+
+ case LB_FINDSTRINGEXACT:
+ return LISTBOX_FindString( descr, wParam, (const WCHAR *)lParam, TRUE );
+
+ case LB_SELECTSTRING:
+ {
+ const WCHAR *textW = (const WCHAR *)lParam;
+ INT index;
+
+ if (HAS_STRINGS(descr))
+ TRACE("LB_SELECTSTRING: %s\n", debugstr_w(textW));
+
+ index = LISTBOX_FindString( descr, wParam, textW, FALSE );
+ if (index != LB_ERR)
+ {
+ LISTBOX_MoveCaret( descr, index, TRUE );
+ LISTBOX_SetSelection( descr, index, TRUE, FALSE );
+ }
+ return index;
+ }
+
+ case LB_GETSEL:
+ if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
+ return LB_ERR;
+ return descr->items[wParam].selected;
+
+ case LB_SETSEL:
+ return LISTBOX_SetSelection( descr, lParam, wParam, FALSE );
+
+ case LB_SETCURSEL:
+ if (IS_MULTISELECT(descr)) return LB_ERR;
+ LISTBOX_SetCaretIndex( descr, wParam, TRUE );
+ ret = LISTBOX_SetSelection( descr, wParam, TRUE, FALSE );
+ if (ret != LB_ERR) ret = descr->selected_item;
+ return ret;
+
+ case LB_GETSELCOUNT:
+ return LISTBOX_GetSelCount( descr );
+
+ case LB_GETSELITEMS:
+ return LISTBOX_GetSelItems( descr, wParam, (LPINT)lParam );
+
+ case LB_SELITEMRANGE:
+ if (LOWORD(lParam) <= HIWORD(lParam))
+ return LISTBOX_SelectItemRange( descr, LOWORD(lParam),
+ HIWORD(lParam), wParam );
+ else
+ return LISTBOX_SelectItemRange( descr, HIWORD(lParam),
+ LOWORD(lParam), wParam );
+
+ case LB_SELITEMRANGEEX:
+ if ((INT)lParam >= (INT)wParam)
+ return LISTBOX_SelectItemRange( descr, wParam, lParam, TRUE );
+ else
+ return LISTBOX_SelectItemRange( descr, lParam, wParam, FALSE);
+
+ case LB_GETHORIZONTALEXTENT:
+ return descr->horz_extent;
+
+ case LB_SETHORIZONTALEXTENT:
+ return LISTBOX_SetHorizontalExtent( descr, wParam );
+
+ case LB_GETANCHORINDEX:
+ return descr->anchor_item;
+
+ case LB_SETANCHORINDEX:
+ if (((INT)wParam < -1) || ((INT)wParam >= descr->nb_items))
+ {
+ SetLastError(ERROR_INVALID_INDEX);
+ return LB_ERR;
+ }
+ descr->anchor_item = (INT)wParam;
+ return LB_OKAY;
+
+ case LB_DIR:
+ return LISTBOX_Directory( descr, wParam, (const WCHAR *)lParam, msg == LB_DIR );
+
+ case LB_GETLOCALE:
+ return descr->locale;
+
+ case LB_SETLOCALE:
+ {
+ LCID ret;
+ if (!IsValidLocale((LCID)wParam, LCID_INSTALLED))
+ return LB_ERR;
+ ret = descr->locale;
+ descr->locale = (LCID)wParam;
+ return ret;
+ }
+
+ case LB_INITSTORAGE:
+ return LISTBOX_InitStorage( descr, wParam );
+
+ case LB_SETCOUNT:
+ return LISTBOX_SetCount( descr, (INT)wParam );
+
+ case LB_SETTABSTOPS:
+ return LISTBOX_SetTabStops( descr, wParam, (LPINT)lParam );
+
+ case LB_CARETON:
+ if (descr->caret_on)
+ return LB_OKAY;
+ descr->caret_on = TRUE;
+ if ((descr->focus_item != -1) && (descr->in_focus))
+ LISTBOX_RepaintItem( descr, descr->focus_item, ODA_FOCUS );
+ return LB_OKAY;
+
+ case LB_CARETOFF:
+ if (!descr->caret_on)
+ return LB_OKAY;
+ descr->caret_on = FALSE;
+ if ((descr->focus_item != -1) && (descr->in_focus))
+ LISTBOX_RepaintItem( descr, descr->focus_item, ODA_FOCUS );
+ return LB_OKAY;
+
+ case LB_GETLISTBOXINFO:
+ return descr->page_size;
+
+ case WM_DESTROY:
+ return LISTBOX_Destroy( descr );
+
+ case WM_ENABLE:
+ InvalidateRect( descr->self, NULL, TRUE );
+ return 0;
+
+ case WM_SETREDRAW:
+ LISTBOX_SetRedraw( descr, wParam != 0 );
+ return 0;
+
+ case WM_GETDLGCODE:
+ return DLGC_WANTARROWS | DLGC_WANTCHARS;
+
+ case WM_PRINTCLIENT:
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ HDC hdc = ( wParam ) ? ((HDC)wParam) : BeginPaint( descr->self, &ps );
+ ret = LISTBOX_Paint( descr, hdc );
+ if( !wParam ) EndPaint( descr->self, &ps );
+ }
+ return ret;
+ case WM_SIZE:
+ LISTBOX_UpdateSize( descr );
+ return 0;
+ case WM_GETFONT:
+ return (LRESULT)descr->font;
+ case WM_SETFONT:
+ LISTBOX_SetFont( descr, (HFONT)wParam );
+ if (lParam) InvalidateRect( descr->self, 0, TRUE );
+ return 0;
+ case WM_SETFOCUS:
+ descr->in_focus = TRUE;
+ descr->caret_on = TRUE;
+ if (descr->focus_item != -1)
+ LISTBOX_DrawFocusRect( descr, TRUE );
+ SEND_NOTIFICATION( descr, LBN_SETFOCUS );
+ return 0;
+ case WM_KILLFOCUS:
+ LISTBOX_HandleLButtonUp( descr ); /* Release capture if we have it */
+ descr->in_focus = FALSE;
+ descr->wheel_remain = 0;
+ if ((descr->focus_item != -1) && descr->caret_on)
+ LISTBOX_RepaintItem( descr, descr->focus_item, ODA_FOCUS );
+ SEND_NOTIFICATION( descr, LBN_KILLFOCUS );
+ return 0;
+ case WM_HSCROLL:
+ return LISTBOX_HandleHScroll( descr, LOWORD(wParam), HIWORD(wParam) );
+ case WM_VSCROLL:
+ return LISTBOX_HandleVScroll( descr, LOWORD(wParam), HIWORD(wParam) );
+ case WM_MOUSEWHEEL:
+ if (wParam & (MK_SHIFT | MK_CONTROL))
+ return DefWindowProcW( descr->self, msg, wParam, lParam );
+ return LISTBOX_HandleMouseWheel( descr, (SHORT)HIWORD(wParam) );
+ case WM_LBUTTONDOWN:
+ if (lphc)
+ return LISTBOX_HandleLButtonDownCombo(descr, msg, wParam,
+ (INT16)LOWORD(lParam),
+ (INT16)HIWORD(lParam) );
+ return LISTBOX_HandleLButtonDown( descr, wParam,
+ (INT16)LOWORD(lParam),
+ (INT16)HIWORD(lParam) );
+ case WM_LBUTTONDBLCLK:
+ if (lphc)
+ return LISTBOX_HandleLButtonDownCombo(descr, msg, wParam,
+ (INT16)LOWORD(lParam),
+ (INT16)HIWORD(lParam) );
+ if (descr->style & LBS_NOTIFY)
+ SEND_NOTIFICATION( descr, LBN_DBLCLK );
+ return 0;
+ case WM_MOUSEMOVE:
+ if ( lphc && ((lphc->dwStyle & CBS_DROPDOWNLIST) != CBS_SIMPLE) )
+ {
+ BOOL captured = descr->captured;
+ POINT mousePos;
+ RECT clientRect;
+
+ mousePos.x = (INT16)LOWORD(lParam);
+ mousePos.y = (INT16)HIWORD(lParam);
+
+ /*
+ * If we are in a dropdown combobox, we simulate that
+ * the mouse is captured to show the tracking of the item.
+ */
+ if (GetClientRect(descr->self, &clientRect) && PtInRect( &clientRect, mousePos ))
+ descr->captured = TRUE;
+
+ LISTBOX_HandleMouseMove( descr, mousePos.x, mousePos.y);
+
+ descr->captured = captured;
+ }
+ else if (GetCapture() == descr->self)
+ {
+ LISTBOX_HandleMouseMove( descr, (INT16)LOWORD(lParam),
+ (INT16)HIWORD(lParam) );
+ }
+ return 0;
+ case WM_LBUTTONUP:
+ if (lphc)
+ {
+ POINT mousePos;
+ RECT clientRect;
+
+ /*
+ * If the mouse button "up" is not in the listbox,
+ * we make sure there is no selection by re-selecting the
+ * item that was selected when the listbox was made visible.
+ */
+ mousePos.x = (INT16)LOWORD(lParam);
+ mousePos.y = (INT16)HIWORD(lParam);
+
+ GetClientRect(descr->self, &clientRect);
+
+ /*
+ * When the user clicks outside the combobox and the focus
+ * is lost, the owning combobox will send a fake buttonup with
+ * 0xFFFFFFF as the mouse location, we must also revert the
+ * selection to the original selection.
+ */
+ if ( (lParam == (LPARAM)-1) || (!PtInRect( &clientRect, mousePos )) )
+ LISTBOX_MoveCaret( descr, lphc->droppedIndex, FALSE );
+ }
+ return LISTBOX_HandleLButtonUp( descr );
+ case WM_KEYDOWN:
+ if( lphc && (lphc->dwStyle & CBS_DROPDOWNLIST) != CBS_SIMPLE )
+ {
+ /* for some reason Windows makes it possible to
+ * show/hide ComboLBox by sending it WM_KEYDOWNs */
+
+ if( (!(lphc->wState & CBF_EUI) && wParam == VK_F4) ||
+ ( (lphc->wState & CBF_EUI) && !(lphc->wState & CBF_DROPPED)
+ && (wParam == VK_DOWN || wParam == VK_UP)) )
+ {
+ COMBO_FlipListbox( lphc, FALSE, FALSE );
+ return 0;
+ }
+ }
+ return LISTBOX_HandleKeyDown( descr, wParam );
+ case WM_CHAR:
+ return LISTBOX_HandleChar( descr, wParam );
+
+ case WM_SYSTIMER:
+ return LISTBOX_HandleSystemTimer( descr );
+ case WM_ERASEBKGND:
+ if ((IS_OWNERDRAW(descr)) && !(descr->style & LBS_DISPLAYCHANGED))
+ {
+ RECT rect;
+ HBRUSH hbrush = (HBRUSH)SendMessageW( descr->owner, WM_CTLCOLORLISTBOX,
+ wParam, (LPARAM)descr->self );
+ TRACE("hbrush = %p\n", hbrush);
+ if(!hbrush)
+ hbrush = GetSysColorBrush(COLOR_WINDOW);
+ if(hbrush)
+ {
+ GetClientRect(descr->self, &rect);
+ FillRect((HDC)wParam, &rect, hbrush);
+ }
+ }
+ return 1;
+ case WM_DROPFILES:
+ if( lphc ) return 0;
+ return SendMessageW( descr->owner, msg, wParam, lParam );
+
+ case WM_NCDESTROY:
+ if( lphc && (lphc->dwStyle & CBS_DROPDOWNLIST) != CBS_SIMPLE )
+ lphc->hWndLBox = 0;
+ break;
+
+ case WM_NCACTIVATE:
+ if (lphc) return 0;
+ break;
+
+ default:
+ if ((msg >= WM_USER) && (msg < 0xc000))
+ WARN("[%p]: unknown msg %04x wp %08lx lp %08lx\n",
+ hwnd, msg, wParam, lParam );
+ }
+
+ return DefWindowProcW( hwnd, msg, wParam, lParam );
+}
+
+void LISTBOX_Register(void)
+{
+ WNDCLASSW wndClass;
+
+ memset(&wndClass, 0, sizeof(wndClass));
+ wndClass.style = CS_PARENTDC | CS_DBLCLKS | CS_GLOBALCLASS;
+ wndClass.lpfnWndProc = LISTBOX_WindowProc;
+ wndClass.cbClsExtra = 0;
+ wndClass.cbWndExtra = sizeof(LB_DESCR *);
+ wndClass.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
+ wndClass.hbrBackground = NULL;
+ wndClass.lpszClassName = WC_LISTBOXW;
+ RegisterClassW(&wndClass);
+}
+
+void COMBOLBOX_Register(void)
+{
+ static const WCHAR combolboxW[] = {'C','o','m','b','o','L','B','o','x',0};
+ WNDCLASSW wndClass;
+
+ memset(&wndClass, 0, sizeof(wndClass));
+ wndClass.style = CS_SAVEBITS | CS_DBLCLKS | CS_DROPSHADOW | CS_GLOBALCLASS;
+ wndClass.lpfnWndProc = LISTBOX_WindowProc;
+ wndClass.cbClsExtra = 0;
+ wndClass.cbWndExtra = sizeof(LB_DESCR *);
+ wndClass.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
+ wndClass.hbrBackground = NULL;
+ wndClass.lpszClassName = combolboxW;
+ RegisterClassW(&wndClass);
+}
diff --git a/dlls/comctl32/tests/misc.c b/dlls/comctl32/tests/misc.c
index 7c9b4cd02e..eca85d490b 100644
--- a/dlls/comctl32/tests/misc.c
+++ b/dlls/comctl32/tests/misc.c
@@ -348,7 +348,9 @@ static void check_class( const char *name, int must_exist, UINT style, UINT igno
todo_wine_if(strcmp(name, "Button") &&
strcmp(name, "ComboBox") &&
strcmp(name, "Edit") &&
- strcmp(name, "Static"))
+ strcmp(name, "Static") &&
+ strcmp(name, "ListBox") &&
+ strcmp(name, "ComboLBox"))
ok( !(~wc.style & style & ~ignore), "System class %s is missing bits %x (%08x/%08x)\n",
name, ~wc.style & style, wc.style, style );
ok( !(wc.style & ~style), "System class %s has extra bits %x (%08x/%08x)\n",
diff --git a/dlls/user32/class.c b/dlls/user32/class.c
index 0e05c1f426..e733cc2ce2 100644
--- a/dlls/user32/class.c
+++ b/dlls/user32/class.c
@@ -166,9 +166,7 @@ static BOOL is_builtin_class( const WCHAR *name )
{
static const WCHAR classesW[][20] =
{
- {'C','o','m','b','o','L','B','o','x',0},
{'I','M','E',0},
- {'L','i','s','t','B','o','x',0},
{'M','D','I','C','l','i','e','n','t',0},
{'S','c','r','o','l','l','b','a','r',0},
};
--
2.15.1
1
1
[PATCH] comctl32/comboex: Remove child windows subclass on window destruction
by Nikolay Sivov 14 Feb '18
by Nikolay Sivov 14 Feb '18
14 Feb '18
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/comctl32/comboex.c | 38 +++++++++++++++++++++++---------------
1 file changed, 23 insertions(+), 15 deletions(-)
diff --git a/dlls/comctl32/comboex.c b/dlls/comctl32/comboex.c
index 076a5524d5..3c3714ac56 100644
--- a/dlls/comctl32/comboex.c
+++ b/dlls/comctl32/comboex.c
@@ -1502,10 +1502,10 @@ static void COMBOEX_ResetContent (COMBOEX_INFO *infoPtr)
static LRESULT COMBOEX_Destroy (COMBOEX_INFO *infoPtr)
{
if (infoPtr->hwndCombo)
- RemoveWindowSubclass(infoPtr->hwndCombo, COMBOEX_ComboWndProc, COMBO_SUBCLASSID);
+ SetWindowSubclass(infoPtr->hwndCombo, COMBOEX_ComboWndProc, COMBO_SUBCLASSID, 0);
if (infoPtr->hwndEdit)
- RemoveWindowSubclass(infoPtr->hwndEdit, COMBOEX_EditWndProc, EDIT_SUBCLASSID);
+ SetWindowSubclass(infoPtr->hwndEdit, COMBOEX_EditWndProc, EDIT_SUBCLASSID, 0);
COMBOEX_FreeText (&infoPtr->edit);
COMBOEX_ResetContent (infoPtr);
@@ -1668,7 +1668,11 @@ COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
TRACE("hwnd=%p msg=%x wparam=%lx lParam=%lx, info_ptr=%p\n",
hwnd, uMsg, wParam, lParam, infoPtr);
- if (!infoPtr) return 0;
+ if (uMsg == WM_NCDESTROY)
+ RemoveWindowSubclass(hwnd, COMBOEX_EditWndProc, EDIT_SUBCLASSID);
+
+ if (!infoPtr)
+ return DefSubclassProc(hwnd, uMsg, wParam, lParam);
switch (uMsg)
{
@@ -1823,11 +1827,14 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
TRACE("hwnd=%p msg=%x wparam=%lx lParam=%lx, info_ptr=%p\n",
hwnd, uMsg, wParam, lParam, infoPtr);
- if (!infoPtr) return 0;
+ if (uMsg == WM_NCDESTROY)
+ RemoveWindowSubclass(hwnd, COMBOEX_ComboWndProc, COMBO_SUBCLASSID);
+
+ if (!infoPtr)
+ return DefSubclassProc(hwnd, uMsg, wParam, lParam);
switch (uMsg)
{
-
case WM_DRAWITEM:
/*
* The only way this message should come is from the
@@ -1835,7 +1842,7 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
* that ComboEx knows this is listbox.
*/
((DRAWITEMSTRUCT *)lParam)->itemState |= ODS_COMBOEXLBOX;
- return DefSubclassProc(hwnd, uMsg, wParam, lParam);
+ break;
case WM_ERASEBKGND:
hDC = (HDC) wParam;
@@ -1844,7 +1851,7 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
TRACE("erasing (%s)\n", wine_dbgstr_rect(&rect));
ExtTextOutW (hDC, 0, 0, ETO_OPAQUE, &rect, 0, 0, 0);
SetBkColor (hDC, obkc);
- return DefSubclassProc(hwnd, uMsg, wParam, lParam);
+ break;
case WM_SETCURSOR:
/*
@@ -1858,7 +1865,7 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
nmmse.pt.y = 0;
nmmse.dwHitInfo = lParam;
COMBOEX_Notify (infoPtr, NM_SETCURSOR, (NMHDR *)&nmmse);
- return DefSubclassProc(hwnd, uMsg, wParam, lParam);
+ break;
case WM_LBUTTONDOWN:
GetClientRect (hwnd, &rect);
@@ -1868,15 +1875,15 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
pt.x = (short)LOWORD(lParam);
pt.y = (short)HIWORD(lParam);
if (PtInRect(&rect, pt))
- return DefSubclassProc(hwnd, uMsg, wParam, lParam);
+ break;
infoPtr->flags |= WCBE_MOUSECAPTURED;
SetCapture(hwnd);
- break;
+ return 0;
case WM_LBUTTONUP:
if (!(infoPtr->flags & WCBE_MOUSECAPTURED))
- return DefSubclassProc(hwnd, uMsg, wParam, lParam);
+ break;
ReleaseCapture();
infoPtr->flags &= ~WCBE_MOUSECAPTURED;
@@ -1885,7 +1892,7 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
} else {
SendMessageW(hwnd, CB_SHOWDROPDOWN, TRUE, 0);
}
- break;
+ return 0;
case WM_MOUSEMOVE:
if ( (infoPtr->flags & WCBE_MOUSECAPTURED) &&
@@ -1894,7 +1901,7 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
COMBOEX_NotifyDragBegin(infoPtr, edit_text);
infoPtr->flags |= WCBE_MOUSEDRAGGED;
}
- return DefSubclassProc(hwnd, uMsg, wParam, lParam);
+ break;
case WM_COMMAND:
switch (HIWORD(wParam)) {
@@ -1975,9 +1982,10 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
break;
}/* fall through */
default:
- return DefSubclassProc(hwnd, uMsg, wParam, lParam);
+ ;
}
- return 0;
+
+ return DefSubclassProc(hwnd, uMsg, wParam, lParam);
}
--
2.15.1
1
0
14 Feb '18
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/comctl32/tests/button.c | 2 +-
dlls/comctl32/tests/combo.c | 6 +++---
dlls/comctl32/tests/static.c | 3 ++-
dlls/comctl32/tests/status.c | 2 +-
4 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/dlls/comctl32/tests/button.c b/dlls/comctl32/tests/button.c
index 96b8bea531..47aee3f622 100644
--- a/dlls/comctl32/tests/button.c
+++ b/dlls/comctl32/tests/button.c
@@ -454,7 +454,7 @@ static HWND create_button(DWORD style, HWND parent)
style |= WS_CHILD|BS_NOTIFY;
menuid = (HMENU)ID_BUTTON;
}
- hwnd = CreateWindowExA(0, "Button", "test", style, 0, 0, 50, 14, parent, menuid, 0, NULL);
+ hwnd = CreateWindowExA(0, WC_BUTTONA, "test", style, 0, 0, 50, 14, parent, menuid, 0, NULL);
ok(hwnd != NULL, "failed to create a button, 0x%08x, %p\n", style, parent);
pSetWindowSubclass(hwnd, button_subclass_proc, 0, 0);
return hwnd;
diff --git a/dlls/comctl32/tests/combo.c b/dlls/comctl32/tests/combo.c
index da2ded2328..b0457396c4 100644
--- a/dlls/comctl32/tests/combo.c
+++ b/dlls/comctl32/tests/combo.c
@@ -507,7 +507,7 @@ static BOOL init(void)
wc.lpfnWndProc = ComboExTestWndProc;
RegisterClassA(&wc);
- hMainWnd = CreateWindowA("static", "Test", WS_OVERLAPPEDWINDOW, 10, 10, 300, 300, NULL, NULL, NULL, 0);
+ hMainWnd = CreateWindowA(WC_STATICA, "Test", WS_OVERLAPPEDWINDOW, 10, 10, 300, 300, NULL, NULL, NULL, 0);
ShowWindow(hMainWnd, SW_SHOW);
hComboExParentWnd = CreateWindowExA(0, ComboExTestClass, "ComboEx test", WS_OVERLAPPEDWINDOW|WS_VISIBLE,
@@ -606,7 +606,7 @@ static void test_comboex_get_set_item(void)
static HWND create_combobox(DWORD style)
{
- return CreateWindowA("ComboBox", "Combo", WS_VISIBLE|WS_CHILD|style, 5, 5, 100, 100, hMainWnd, (HMENU)COMBO_ID, NULL, 0);
+ return CreateWindowA(WC_COMBOBOXA, "Combo", WS_VISIBLE|WS_CHILD|style, 5, 5, 100, 100, hMainWnd, (HMENU)COMBO_ID, NULL, 0);
}
static int font_height(HFONT hFont)
@@ -1035,7 +1035,7 @@ static void test_combo_editselection_focus(DWORD style)
get_combobox_info(hCombo, &cbInfo);
hEdit = cbInfo.hwndItem;
- hButton = CreateWindowA("Button", "OK", WS_VISIBLE|WS_CHILD|BS_DEFPUSHBUTTON,
+ hButton = CreateWindowA(WC_BUTTONA, "OK", WS_VISIBLE|WS_CHILD|BS_DEFPUSHBUTTON,
5, 50, 100, 20, hMainWnd, NULL,
(HINSTANCE)GetWindowLongPtrA(hMainWnd, GWLP_HINSTANCE), NULL);
diff --git a/dlls/comctl32/tests/static.c b/dlls/comctl32/tests/static.c
index 890fcf5b96..a65e352728 100644
--- a/dlls/comctl32/tests/static.c
+++ b/dlls/comctl32/tests/static.c
@@ -23,6 +23,7 @@
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
+#include "commctrl.h"
#include "wine/test.h"
@@ -53,7 +54,7 @@ static void flush_events(void)
static HWND create_static(DWORD style)
{
- return CreateWindowA("static", "Test", WS_VISIBLE|WS_CHILD|style, 5, 5, 100, 100, hMainWnd, (HMENU)CTRL_ID, NULL, 0);
+ return CreateWindowA(WC_STATICA, "Test", WS_VISIBLE|WS_CHILD|style, 5, 5, 100, 100, hMainWnd, (HMENU)CTRL_ID, NULL, 0);
}
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
diff --git a/dlls/comctl32/tests/status.c b/dlls/comctl32/tests/status.c
index f2fe1abf98..2308974761 100644
--- a/dlls/comctl32/tests/status.c
+++ b/dlls/comctl32/tests/status.c
@@ -607,7 +607,7 @@ START_TEST(status)
iccex.dwICC = ICC_BAR_CLASSES;
pInitCommonControlsEx(&iccex);
- g_hMainWnd = CreateWindowExA(0, "static", "", WS_OVERLAPPEDWINDOW,
+ g_hMainWnd = CreateWindowExA(0, WC_STATICA, "", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 672+2*GetSystemMetrics(SM_CXSIZEFRAME),
226+GetSystemMetrics(SM_CYCAPTION)+2*GetSystemMetrics(SM_CYSIZEFRAME),
NULL, NULL, GetModuleHandleA(NULL), 0);
--
2.15.1
1
0
1
0
13 Feb '18
Signed-off-by: Michael Stefaniuc <mstefani(a)winehq.org>
---
There are about 40+ more strdupW() functions around. Most using that
name, some prefixed with something else. Of course that is fodder for
more patches.
dlls/appwiz.cpl/appwiz.h | 16 ----------------
dlls/dpnet/dpnet_private.h | 8 --------
dlls/dwrite/dwrite_private.h | 16 ----------------
dlls/ieframe/ieframe.h | 16 ----------------
dlls/inetcomm/protocol.c | 16 ----------------
dlls/jscript/jscript.h | 16 ----------------
dlls/mshtml/mshtml_private.h | 16 ----------------
dlls/msxml3/msxml_private.h | 16 ----------------
dlls/ole32/errorinfo.c | 16 ----------------
dlls/sapi/sapi_private.h | 15 ---------------
dlls/schedsvc/schedsvc_private.h | 10 ----------
dlls/taskschd/taskschd_private.h | 10 ----------
dlls/urlmon/urlmon_main.h | 16 ----------------
dlls/vbscript/vbscript.h | 16 ----------------
dlls/wbemprox/wbemprox_private.h | 8 --------
dlls/wininet/internet.h | 16 ----------------
include/wine/heap.h | 16 ++++++++++++++++
17 files changed, 16 insertions(+), 227 deletions(-)
diff --git a/dlls/appwiz.cpl/appwiz.h b/dlls/appwiz.cpl/appwiz.h
index 2165ce11b1..5571ac158a 100644
--- a/dlls/appwiz.cpl/appwiz.h
+++ b/dlls/appwiz.cpl/appwiz.h
@@ -28,22 +28,6 @@ BOOL install_addon(addon_t) DECLSPEC_HIDDEN;
extern HINSTANCE hInst DECLSPEC_HIDDEN;
-static inline WCHAR *heap_strdupW(const WCHAR *str)
-{
- WCHAR *ret;
-
- if(str) {
- size_t size = strlenW(str)+1;
- ret = heap_alloc(size*sizeof(WCHAR));
- if(ret)
- memcpy(ret, str, size*sizeof(WCHAR));
- }else {
- ret = NULL;
- }
-
- return ret;
-}
-
static inline WCHAR *heap_strdupAtoW(const char *str)
{
WCHAR *ret = NULL;
diff --git a/dlls/dpnet/dpnet_private.h b/dlls/dpnet/dpnet_private.h
index 2e72360c89..467ee87f6f 100644
--- a/dlls/dpnet/dpnet_private.h
+++ b/dlls/dpnet/dpnet_private.h
@@ -155,12 +155,4 @@ typedef struct {
#define FE(x) { x, #x }
#define GE(x) { &x, #x }
-static inline WCHAR *heap_strdupW( const WCHAR *src )
-{
- WCHAR *dst;
- if (!src) return NULL;
- if ((dst = heap_alloc( (strlenW( src ) + 1) * sizeof(WCHAR) ))) strcpyW( dst, src );
- return dst;
-}
-
#endif
diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h
index 31b977a159..867356fd73 100644
--- a/dlls/dwrite/dwrite_private.h
+++ b/dlls/dwrite/dwrite_private.h
@@ -31,22 +31,6 @@ static const DWRITE_MATRIX identity =
0.0f, 0.0f
};
-static inline LPWSTR heap_strdupW(const WCHAR *str)
-{
- LPWSTR ret = NULL;
-
- if(str) {
- DWORD size;
-
- size = (strlenW(str)+1)*sizeof(WCHAR);
- ret = heap_alloc(size);
- if(ret)
- memcpy(ret, str, size);
- }
-
- return ret;
-}
-
static inline LPWSTR heap_strdupnW(const WCHAR *str, UINT32 len)
{
WCHAR *ret = NULL;
diff --git a/dlls/ieframe/ieframe.h b/dlls/ieframe/ieframe.h
index 8adf47e053..d2ba262a34 100644
--- a/dlls/ieframe/ieframe.h
+++ b/dlls/ieframe/ieframe.h
@@ -335,22 +335,6 @@ static inline void unlock_module(void) {
InterlockedDecrement(&module_ref);
}
-static inline LPWSTR heap_strdupW(LPCWSTR str)
-{
- LPWSTR ret = NULL;
-
- if(str) {
- DWORD size;
-
- size = (strlenW(str)+1)*sizeof(WCHAR);
- ret = heap_alloc(size);
- if(ret)
- memcpy(ret, str, size);
- }
-
- return ret;
-}
-
static inline LPWSTR co_strdupW(LPCWSTR str)
{
WCHAR *ret = CoTaskMemAlloc((strlenW(str) + 1)*sizeof(WCHAR));
diff --git a/dlls/inetcomm/protocol.c b/dlls/inetcomm/protocol.c
index 028463a269..7741dc8fb5 100644
--- a/dlls/inetcomm/protocol.c
+++ b/dlls/inetcomm/protocol.c
@@ -63,22 +63,6 @@ typedef struct {
static const WCHAR mhtml_prefixW[] = {'m','h','t','m','l',':'};
static const WCHAR mhtml_separatorW[] = {'!','x','-','u','s','c',':'};
-static inline LPWSTR heap_strdupW(LPCWSTR str)
-{
- LPWSTR ret = NULL;
-
- if(str) {
- DWORD size;
-
- size = (strlenW(str)+1)*sizeof(WCHAR);
- ret = heap_alloc(size);
- if(ret)
- memcpy(ret, str, size);
- }
-
- return ret;
-}
-
static HRESULT parse_mhtml_url(const WCHAR *url, mhtml_url_t *r)
{
const WCHAR *p;
diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h
index 1a247511ac..f3ed3d3523 100644
--- a/dlls/jscript/jscript.h
+++ b/dlls/jscript/jscript.h
@@ -55,22 +55,6 @@ void heap_pool_clear(heap_pool_t*) DECLSPEC_HIDDEN;
void heap_pool_free(heap_pool_t*) DECLSPEC_HIDDEN;
heap_pool_t *heap_pool_mark(heap_pool_t*) DECLSPEC_HIDDEN;
-static inline LPWSTR heap_strdupW(LPCWSTR str)
-{
- LPWSTR ret = NULL;
-
- if(str) {
- DWORD size;
-
- size = (strlenW(str)+1)*sizeof(WCHAR);
- ret = heap_alloc(size);
- if(ret)
- memcpy(ret, str, size);
- }
-
- return ret;
-}
-
typedef struct jsdisp_t jsdisp_t;
extern HINSTANCE jscript_hinstance DECLSPEC_HIDDEN;
diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h
index 5ed626477f..2b7018f38a 100644
--- a/dlls/mshtml/mshtml_private.h
+++ b/dlls/mshtml/mshtml_private.h
@@ -1189,22 +1189,6 @@ static inline void * __WINE_ALLOC_SIZE(2) heap_realloc_zero(void *mem, size_t le
return HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, mem, len);
}
-static inline LPWSTR heap_strdupW(LPCWSTR str)
-{
- LPWSTR ret = NULL;
-
- if(str) {
- DWORD size;
-
- size = (strlenW(str)+1)*sizeof(WCHAR);
- ret = heap_alloc(size);
- if(ret)
- memcpy(ret, str, size);
- }
-
- return ret;
-}
-
static inline LPWSTR heap_strndupW(LPCWSTR str, unsigned len)
{
LPWSTR ret = NULL;
diff --git a/dlls/msxml3/msxml_private.h b/dlls/msxml3/msxml_private.h
index 94ef66b23d..6880294160 100644
--- a/dlls/msxml3/msxml_private.h
+++ b/dlls/msxml3/msxml_private.h
@@ -170,22 +170,6 @@ static inline void* __WINE_ALLOC_SIZE(2) heap_realloc_zero(void *mem, size_t siz
return HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, mem, size);
}
-static inline LPWSTR heap_strdupW(LPCWSTR str)
-{
- LPWSTR ret = NULL;
-
- if(str) {
- DWORD size;
-
- size = (strlenW(str)+1)*sizeof(WCHAR);
- ret = heap_alloc(size);
- if(ret)
- memcpy(ret, str, size);
- }
-
- return ret;
-}
-
/* XSLProcessor parameter list */
struct xslprocessor_par
{
diff --git a/dlls/ole32/errorinfo.c b/dlls/ole32/errorinfo.c
index d5ec17207a..19f1b04b21 100644
--- a/dlls/ole32/errorinfo.c
+++ b/dlls/ole32/errorinfo.c
@@ -41,22 +41,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(ole);
-static inline WCHAR *heap_strdupW(const WCHAR *str)
-{
- WCHAR *ret = NULL;
-
- if(str) {
- size_t size;
-
- size = (strlenW(str)+1)*sizeof(WCHAR);
- ret = heap_alloc(size);
- if(ret)
- memcpy(ret, str, size);
- }
-
- return ret;
-}
-
typedef struct ErrorInfoImpl
{
IErrorInfo IErrorInfo_iface;
diff --git a/dlls/sapi/sapi_private.h b/dlls/sapi/sapi_private.h
index b069222c7d..cfc5f3e1ad 100644
--- a/dlls/sapi/sapi_private.h
+++ b/dlls/sapi/sapi_private.h
@@ -24,18 +24,3 @@
HRESULT data_key_create( IUnknown *outer, REFIID iid, void **obj ) DECLSPEC_HIDDEN;
HRESULT token_category_create( IUnknown *outer, REFIID iid, void **obj ) DECLSPEC_HIDDEN;
HRESULT token_enum_create( IUnknown *outer, REFIID iid, void **obj ) DECLSPEC_HIDDEN;
-
-static inline LPWSTR heap_strdupW(LPCWSTR str)
-{
- LPWSTR ret = NULL;
- DWORD size;
-
- if (str)
- {
- size = (strlenW( str ) + 1) * sizeof(WCHAR);
- ret = heap_alloc( size );
- if (ret) memcpy( ret, str, size );
- }
-
- return ret;
-}
diff --git a/dlls/schedsvc/schedsvc_private.h b/dlls/schedsvc/schedsvc_private.h
index 4404486998..60901d8ad8 100644
--- a/dlls/schedsvc/schedsvc_private.h
+++ b/dlls/schedsvc/schedsvc_private.h
@@ -24,14 +24,4 @@
void schedsvc_auto_start(void) DECLSPEC_HIDDEN;
-static inline WCHAR *heap_strdupW(const WCHAR *src)
-{
- WCHAR *dst;
- unsigned len;
- if (!src) return NULL;
- len = (strlenW(src) + 1) * sizeof(WCHAR);
- if ((dst = heap_alloc(len))) memcpy(dst, src, len);
- return dst;
-}
-
#endif /* __WINE_SCHEDSVC_PRIVATE_H__ */
diff --git a/dlls/taskschd/taskschd_private.h b/dlls/taskschd/taskschd_private.h
index 6c7f916a0f..67383cbf59 100644
--- a/dlls/taskschd/taskschd_private.h
+++ b/dlls/taskschd/taskschd_private.h
@@ -32,14 +32,4 @@ HRESULT RegisteredTaskCollection_create(const WCHAR *path, IRegisteredTaskCollec
WCHAR *get_full_path(const WCHAR *parent, const WCHAR *path) DECLSPEC_HIDDEN;
-static inline WCHAR *heap_strdupW(const WCHAR *src)
-{
- WCHAR *dst;
- unsigned len;
- if (!src) return NULL;
- len = (strlenW(src) + 1) * sizeof(WCHAR);
- if ((dst = heap_alloc(len))) memcpy(dst, src, len);
- return dst;
-}
-
#endif /* __WINE_TASKSCHD_PRIVATE_H__ */
diff --git a/dlls/urlmon/urlmon_main.h b/dlls/urlmon/urlmon_main.h
index a4a1c78d52..89cdd389a6 100644
--- a/dlls/urlmon/urlmon_main.h
+++ b/dlls/urlmon/urlmon_main.h
@@ -240,22 +240,6 @@ static inline void* __WINE_ALLOC_SIZE(2) heap_realloc_zero(void *mem, size_t siz
return HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, mem, size);
}
-static inline LPWSTR heap_strdupW(LPCWSTR str)
-{
- LPWSTR ret = NULL;
-
- if(str) {
- DWORD size;
-
- size = (strlenW(str)+1)*sizeof(WCHAR);
- ret = heap_alloc(size);
- if(ret)
- memcpy(ret, str, size);
- }
-
- return ret;
-}
-
static inline LPWSTR heap_strndupW(LPCWSTR str, int len)
{
LPWSTR ret = NULL;
diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h
index 5e935ff76a..d8af4d6855 100644
--- a/dlls/vbscript/vbscript.h
+++ b/dlls/vbscript/vbscript.h
@@ -431,22 +431,6 @@ HRESULT create_safearray_iter(SAFEARRAY *sa, IEnumVARIANT **ev) DECLSPEC_HIDDEN;
HRESULT WINAPI VBScriptFactory_CreateInstance(IClassFactory*,IUnknown*,REFIID,void**) DECLSPEC_HIDDEN;
HRESULT WINAPI VBScriptRegExpFactory_CreateInstance(IClassFactory*,IUnknown*,REFIID,void**) DECLSPEC_HIDDEN;
-static inline LPWSTR heap_strdupW(LPCWSTR str)
-{
- LPWSTR ret = NULL;
-
- if(str) {
- DWORD size;
-
- size = (strlenW(str)+1)*sizeof(WCHAR);
- ret = heap_alloc(size);
- if(ret)
- memcpy(ret, str, size);
- }
-
- return ret;
-}
-
#define VBSCRIPT_BUILD_VERSION 16978
#define VBSCRIPT_MAJOR_VERSION 5
#define VBSCRIPT_MINOR_VERSION 8
diff --git a/dlls/wbemprox/wbemprox_private.h b/dlls/wbemprox/wbemprox_private.h
index 54b1ba3d8e..47dca73a26 100644
--- a/dlls/wbemprox/wbemprox_private.h
+++ b/dlls/wbemprox/wbemprox_private.h
@@ -228,14 +228,6 @@ HRESULT service_stop_service(IWbemClassObject *, IWbemClassObject *, IWbemClassO
HRESULT security_get_sd(IWbemClassObject *, IWbemClassObject *, IWbemClassObject **) DECLSPEC_HIDDEN;
HRESULT security_set_sd(IWbemClassObject *, IWbemClassObject *, IWbemClassObject **) DECLSPEC_HIDDEN;
-static inline WCHAR *heap_strdupW( const WCHAR *src )
-{
- WCHAR *dst;
- if (!src) return NULL;
- if ((dst = heap_alloc( (strlenW( src ) + 1) * sizeof(WCHAR) ))) strcpyW( dst, src );
- return dst;
-}
-
static const WCHAR class_processW[] = {'W','i','n','3','2','_','P','r','o','c','e','s','s',0};
static const WCHAR class_serviceW[] = {'W','i','n','3','2','_','S','e','r','v','i','c','e',0};
static const WCHAR class_stdregprovW[] = {'S','t','d','R','e','g','P','r','o','v',0};
diff --git a/dlls/wininet/internet.h b/dlls/wininet/internet.h
index 498a79b080..736506a9ce 100644
--- a/dlls/wininet/internet.h
+++ b/dlls/wininet/internet.h
@@ -95,22 +95,6 @@ static inline void * __WINE_ALLOC_SIZE(2) heap_realloc_zero(void *mem, size_t le
return HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, mem, len);
}
-static inline LPWSTR heap_strdupW(LPCWSTR str)
-{
- LPWSTR ret = NULL;
-
- if(str) {
- DWORD size;
-
- size = (strlenW(str)+1)*sizeof(WCHAR);
- ret = heap_alloc(size);
- if(ret)
- memcpy(ret, str, size);
- }
-
- return ret;
-}
-
static inline char *heap_strdupA(const char *str)
{
char *ret = NULL;
diff --git a/include/wine/heap.h b/include/wine/heap.h
index 97d3a5662b..d970e03731 100644
--- a/include/wine/heap.h
+++ b/include/wine/heap.h
@@ -55,4 +55,20 @@ static inline void *heap_calloc(SIZE_T count, SIZE_T size)
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
}
+static inline WCHAR *heap_strdupW(const WCHAR *str)
+{
+ WCHAR *dst;
+ SIZE_T len;
+
+ if(!str)
+ return NULL;
+
+ len = (lstrlenW(str) + 1) * sizeof(*str);
+ dst = heap_alloc(len);
+ if (dst)
+ memcpy(dst, str, len);
+
+ return dst;
+}
+
#endif /* __WINE_WINE_HEAP_H */
--
2.14.3
3
6
13 Feb '18
Signed-off-by: Austin English <austinenglish(a)gmail.com>
---
include/d3d11.idl | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/include/d3d11.idl b/include/d3d11.idl
index a7b98126a1..f15f1217f1 100644
--- a/include/d3d11.idl
+++ b/include/d3d11.idl
@@ -168,6 +168,16 @@ const UINT D3D11_VS_OUTPUT_REGISTER_COUNT = 32;
const UINT D3D11_OMAC_SIZE = 16;
+cpp_quote("#endif")
+cpp_quote("#ifndef _D3D11_1_CONSTANTS")
+cpp_quote("#define _D3D11_1_CONSTANTS")
+const UINT D3D11_1_UAV_SLOT_COUNT = 64;
+cpp_quote("#endif")
+cpp_quote("#ifndef _D3D11_2_CONSTANTS")
+cpp_quote("#define _D3D11_2_CONSTANTS")
+const UINT D3D11_2_TILED_RESOURCE_TILE_SIZE_IN_BYTES = 65536;
+cpp_quote("#endif")
+
const UINT D3D11_PS_CS_UAV_REGISTER_COMPONENTS = 1;
const UINT D3D11_PS_CS_UAV_REGISTER_COUNT = 8;
const UINT D3D11_PS_CS_UAV_REGISTER_READS_PER_INST = 1;
--
2.13.6
1
0
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
Fixes e.g. msacm.l3acm being enumerated as "msac".".l3a".
This behaviour matches that on Windows tested mainly by manually modifying
the registry. If this is appropriate for a test I will add one.
dlls/msvfw32/msvideo_main.c | 53 +++++++++++++++++++++++----------------------
1 file changed, 27 insertions(+), 26 deletions(-)
diff --git a/dlls/msvfw32/msvideo_main.c b/dlls/msvfw32/msvideo_main.c
index d49ea74..82351d6 100644
--- a/dlls/msvfw32/msvideo_main.c
+++ b/dlls/msvfw32/msvideo_main.c
@@ -223,48 +223,48 @@ static int compare_fourcc(DWORD fcc1, DWORD fcc2)
return strncasecmp(fcc_str1, fcc_str2, 4);
}
-typedef BOOL (*enum_handler_t)(const char*, unsigned int, void*);
+typedef BOOL (*enum_handler_t)(const char *name, const char *driver, unsigned int index, void *param);
static BOOL enum_drivers(DWORD fccType, enum_handler_t handler, void* param)
{
- CHAR buf[2048], fccTypeStr[5], *s;
+ char fccTypeStr[4];
+ char name_buf[10];
+ char buf[2048];
+
DWORD i, cnt = 0, lRet;
BOOL result = FALSE;
HKEY hKey;
fourcc_to_string(fccTypeStr, fccType);
- fccTypeStr[4] = '.';
/* first, go through the registry entries */
lRet = RegOpenKeyExA(HKEY_LOCAL_MACHINE, HKLM_DRIVERS32, 0, KEY_QUERY_VALUE, &hKey);
if (lRet == ERROR_SUCCESS)
{
- DWORD name, data, type;
i = 0;
for (;;)
- {
- name = 10;
- data = sizeof buf - name;
- lRet = RegEnumValueA(hKey, i++, buf, &name, 0, &type, (LPBYTE)(buf+name), &data);
- if (lRet == ERROR_NO_MORE_ITEMS) break;
- if (lRet != ERROR_SUCCESS) continue;
- if (fccType && (name != 9 || strncasecmp(buf, fccTypeStr, 5))) continue;
- buf[name] = '=';
- if ((result = handler(buf, cnt++, param))) break;
- }
- RegCloseKey( hKey );
+ {
+ DWORD name_len = 10, driver_len = 128;
+ lRet = RegEnumValueA(hKey, i++, name_buf, &name_len, 0, 0, (BYTE *)buf, &driver_len);
+ if (lRet == ERROR_NO_MORE_ITEMS) break;
+ if (name_len != 9 || name_buf[4] != '.') continue;
+ if (fccType && strncasecmp(name_buf, fccTypeStr, 4)) continue;
+ if ((result = handler(name_buf, buf, cnt++, param))) break;
+ }
+ RegCloseKey( hKey );
}
if (result) return result;
/* if that didn't work, go through the values in system.ini */
if (GetPrivateProfileSectionA("drivers32", buf, sizeof(buf), "system.ini"))
{
- for (s = buf; *s; s += strlen(s) + 1)
- {
- TRACE("got %s\n", s);
- if (fccType && (strncasecmp(s, fccTypeStr, 5) || s[9] != '=')) continue;
- if ((result = handler(s, cnt++, param))) break;
- }
+ char *s;
+ for (s = buf; *s; s += strlen(s) + 1)
+ {
+ if (s[5] != '.' || s[9] != '=') continue;
+ if (fccType && strncasecmp(s, fccTypeStr, 4)) continue;
+ if ((result = handler(s, s + 10, cnt++, param))) break;
+ }
}
return result;
@@ -294,10 +294,11 @@ DWORD WINAPI VideoForWindowsVersion(void)
return 0x040003B6; /* 4.950 */
}
-static BOOL ICInfo_enum_handler(const char *drv, unsigned int nr, void *param)
+static BOOL ICInfo_enum_handler(const char *name, const char *driver, unsigned int nr, void *param)
{
ICINFO *lpicinfo = param;
- DWORD fccHandler = mmioStringToFOURCCA(drv + 5, 0);
+ DWORD fccType = mmioStringToFOURCCA(name, 0);
+ DWORD fccHandler = mmioStringToFOURCCA(name + 5, 0);
if (lpicinfo->fccHandler != nr && compare_fourcc(lpicinfo->fccHandler, fccHandler))
return FALSE;
@@ -308,7 +309,7 @@ static BOOL ICInfo_enum_handler(const char *drv, unsigned int nr, void *param)
lpicinfo->dwVersionICM = ICVERSION;
lpicinfo->szName[0] = 0;
lpicinfo->szDescription[0] = 0;
- MultiByteToWideChar(CP_ACP, 0, drv + 10, -1, lpicinfo->szDriver,
+ MultiByteToWideChar(CP_ACP, 0, driver, -1, lpicinfo->szDriver,
sizeof(lpicinfo->szDriver)/sizeof(WCHAR));
return TRUE;
@@ -647,10 +648,10 @@ static HIC try_driver(driver_info_t *info)
return 0;
}
-static BOOL ICLocate_enum_handler(const char *drv, unsigned int nr, void *param)
+static BOOL ICLocate_enum_handler(const char *name, const char *driver, unsigned int nr, void *param)
{
driver_info_t *info = param;
- info->fccHandler = mmioStringToFOURCCA(drv + 5, 0);
+ info->fccHandler = mmioStringToFOURCCA(name + 5, 0);
info->hic = try_driver(info);
return info->hic != 0;
}
--
2.7.4
2
3
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
Fixes e.g. msacm.l3acm being enumerated as "msac".".l3a".
This behaviour matches that on Windows tested mainly by manually modifying
the registry. If this is appropriate for a test I will add one.
v2: fix bad index breaking enumeration from system.ini
dlls/msvfw32/msvideo_main.c | 53 +++++++++++++++++++++++----------------------
1 file changed, 27 insertions(+), 26 deletions(-)
diff --git a/dlls/msvfw32/msvideo_main.c b/dlls/msvfw32/msvideo_main.c
index d49ea74..e071d95 100644
--- a/dlls/msvfw32/msvideo_main.c
+++ b/dlls/msvfw32/msvideo_main.c
@@ -223,48 +223,48 @@ static int compare_fourcc(DWORD fcc1, DWORD fcc2)
return strncasecmp(fcc_str1, fcc_str2, 4);
}
-typedef BOOL (*enum_handler_t)(const char*, unsigned int, void*);
+typedef BOOL (*enum_handler_t)(const char *name, const char *driver, unsigned int index, void *param);
static BOOL enum_drivers(DWORD fccType, enum_handler_t handler, void* param)
{
- CHAR buf[2048], fccTypeStr[5], *s;
+ char fccTypeStr[4];
+ char name_buf[10];
+ char buf[2048];
+
DWORD i, cnt = 0, lRet;
BOOL result = FALSE;
HKEY hKey;
fourcc_to_string(fccTypeStr, fccType);
- fccTypeStr[4] = '.';
/* first, go through the registry entries */
lRet = RegOpenKeyExA(HKEY_LOCAL_MACHINE, HKLM_DRIVERS32, 0, KEY_QUERY_VALUE, &hKey);
if (lRet == ERROR_SUCCESS)
{
- DWORD name, data, type;
i = 0;
for (;;)
- {
- name = 10;
- data = sizeof buf - name;
- lRet = RegEnumValueA(hKey, i++, buf, &name, 0, &type, (LPBYTE)(buf+name), &data);
- if (lRet == ERROR_NO_MORE_ITEMS) break;
- if (lRet != ERROR_SUCCESS) continue;
- if (fccType && (name != 9 || strncasecmp(buf, fccTypeStr, 5))) continue;
- buf[name] = '=';
- if ((result = handler(buf, cnt++, param))) break;
- }
- RegCloseKey( hKey );
+ {
+ DWORD name_len = 10, driver_len = 128;
+ lRet = RegEnumValueA(hKey, i++, name_buf, &name_len, 0, 0, (BYTE *)buf, &driver_len);
+ if (lRet == ERROR_NO_MORE_ITEMS) break;
+ if (name_len != 9 || name_buf[4] != '.') continue;
+ if (fccType && strncasecmp(name_buf, fccTypeStr, 4)) continue;
+ if ((result = handler(name_buf, buf, cnt++, param))) break;
+ }
+ RegCloseKey( hKey );
}
if (result) return result;
/* if that didn't work, go through the values in system.ini */
if (GetPrivateProfileSectionA("drivers32", buf, sizeof(buf), "system.ini"))
{
- for (s = buf; *s; s += strlen(s) + 1)
- {
- TRACE("got %s\n", s);
- if (fccType && (strncasecmp(s, fccTypeStr, 5) || s[9] != '=')) continue;
- if ((result = handler(s, cnt++, param))) break;
- }
+ char *s;
+ for (s = buf; *s; s += strlen(s) + 1)
+ {
+ if (s[4] != '.' || s[9] != '=') continue;
+ if (fccType && strncasecmp(s, fccTypeStr, 4)) continue;
+ if ((result = handler(s, s + 10, cnt++, param))) break;
+ }
}
return result;
@@ -294,10 +294,11 @@ DWORD WINAPI VideoForWindowsVersion(void)
return 0x040003B6; /* 4.950 */
}
-static BOOL ICInfo_enum_handler(const char *drv, unsigned int nr, void *param)
+static BOOL ICInfo_enum_handler(const char *name, const char *driver, unsigned int nr, void *param)
{
ICINFO *lpicinfo = param;
- DWORD fccHandler = mmioStringToFOURCCA(drv + 5, 0);
+ DWORD fccType = mmioStringToFOURCCA(name, 0);
+ DWORD fccHandler = mmioStringToFOURCCA(name + 5, 0);
if (lpicinfo->fccHandler != nr && compare_fourcc(lpicinfo->fccHandler, fccHandler))
return FALSE;
@@ -308,7 +309,7 @@ static BOOL ICInfo_enum_handler(const char *drv, unsigned int nr, void *param)
lpicinfo->dwVersionICM = ICVERSION;
lpicinfo->szName[0] = 0;
lpicinfo->szDescription[0] = 0;
- MultiByteToWideChar(CP_ACP, 0, drv + 10, -1, lpicinfo->szDriver,
+ MultiByteToWideChar(CP_ACP, 0, driver, -1, lpicinfo->szDriver,
sizeof(lpicinfo->szDriver)/sizeof(WCHAR));
return TRUE;
@@ -647,10 +648,10 @@ static HIC try_driver(driver_info_t *info)
return 0;
}
-static BOOL ICLocate_enum_handler(const char *drv, unsigned int nr, void *param)
+static BOOL ICLocate_enum_handler(const char *name, const char *driver, unsigned int nr, void *param)
{
driver_info_t *info = param;
- info->fccHandler = mmioStringToFOURCCA(drv + 5, 0);
+ info->fccHandler = mmioStringToFOURCCA(name + 5, 0);
info->hic = try_driver(info);
return info->hic != 0;
}
--
2.7.4
1
1
[PATCH] user32/tests: Add more message conversion tests with different user window procedures
by Nikolay Sivov 13 Feb '18
by Nikolay Sivov 13 Feb '18
13 Feb '18
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/user32/tests/dialog.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 96 insertions(+)
diff --git a/dlls/user32/tests/dialog.c b/dlls/user32/tests/dialog.c
index 33e755b0b7..1632484509 100644
--- a/dlls/user32/tests/dialog.c
+++ b/dlls/user32/tests/dialog.c
@@ -1602,6 +1602,96 @@ static INT_PTR CALLBACK test_aw_conversion_dlgproc2(HWND hdlg, UINT msg, WPARAM
return FALSE;
}
+static LRESULT CALLBACK test_aw_conversion_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
+ int mode = HandleToULong(GetPropA(hwnd, "test_mode"));
+ WCHAR *text = (WCHAR *)lparam;
+ char *textA = (char *)lparam;
+
+ switch (msg)
+ {
+ case WM_SETTEXT:
+ case WM_WININICHANGE:
+ case WM_DEVMODECHANGE:
+ case CB_DIR:
+ case LB_DIR:
+ case LB_ADDFILE:
+ case EM_REPLACESEL:
+ switch (mode)
+ {
+ case DLGPROCTEXT_DLGPROCA:
+ todo_wine_if(IsWindowUnicode(hwnd))
+ ok(textA == testtext, "%s: %s, unexpected text %s.\n", IsWindowUnicode(hwnd) ? "U" : "A",
+ testmodes[mode], textA);
+ break;
+ case DLGPROCTEXT_DLGPROCW:
+ todo_wine_if(!IsWindowUnicode(hwnd))
+ ok(text == testtextW, "%s: %s, unexpected text %s.\n", IsWindowUnicode(hwnd) ? "U" : "A", testmodes[mode],
+ wine_dbgstr_w(text));
+ break;
+ case DLGPROCTEXT_SNDMSGA:
+ if (IsWindowUnicode(hwnd))
+ ok(text != testtextW && !lstrcmpW(text, testtextW),
+ "U: %s, unexpected text %s.\n", testmodes[mode], wine_dbgstr_w(text));
+ else
+ ok(textA == testtext, "A: %s, unexpected text %s.\n", testmodes[mode], textA);
+ break;
+ case DLGPROCTEXT_SNDMSGW:
+ if (IsWindowUnicode(hwnd))
+ ok(text == testtextW, "U: %s, unexpected text %s.\n", testmodes[mode], wine_dbgstr_w(text));
+ else
+ ok(textA != testtext && !strcmp(textA, testtext), "A: %s, unexpected text %s.\n",
+ testmodes[mode], textA);
+ break;
+ }
+ break;
+ }
+
+ return IsWindowUnicode(hwnd) ? CallWindowProcW(oldproc, hwnd, msg, wparam, lparam) :
+ CallWindowProcA(oldproc, hwnd, msg, wparam, lparam);
+}
+
+static INT_PTR CALLBACK test_aw_conversion_dlgproc3(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ BOOL is_unicode = !!lparam;
+ LONG_PTR oldproc;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ ok(is_unicode == IsWindowUnicode(hdlg), "Unexpected unicode window property.\n");
+
+ oldproc = SetWindowLongPtrA(hdlg, GWLP_WNDPROC, (LONG_PTR)test_aw_conversion_wndproc);
+ SetWindowLongPtrA(hdlg, GWLP_USERDATA, oldproc);
+ ok(!IsWindowUnicode(hdlg), "Unexpected unicode window.\n");
+
+ dlg_test_aw_message(hdlg, WM_WININICHANGE);
+ dlg_test_aw_message(hdlg, WM_DEVMODECHANGE);
+ dlg_test_aw_message(hdlg, CB_DIR);
+ dlg_test_aw_message(hdlg, LB_DIR);
+ dlg_test_aw_message(hdlg, LB_ADDFILE);
+ dlg_test_aw_message(hdlg, EM_REPLACESEL);
+ dlg_test_aw_message(hdlg, WM_SETTEXT);
+
+ SetWindowLongPtrW(hdlg, GWLP_WNDPROC, (LONG_PTR)test_aw_conversion_wndproc);
+ ok(IsWindowUnicode(hdlg), "Expected unicode window.\n");
+
+ dlg_test_aw_message(hdlg, WM_WININICHANGE);
+ dlg_test_aw_message(hdlg, WM_DEVMODECHANGE);
+ dlg_test_aw_message(hdlg, CB_DIR);
+ dlg_test_aw_message(hdlg, LB_DIR);
+ dlg_test_aw_message(hdlg, LB_ADDFILE);
+ dlg_test_aw_message(hdlg, EM_REPLACESEL);
+ dlg_test_aw_message(hdlg, WM_SETTEXT);
+
+ SetWindowLongPtrA(hdlg, GWLP_WNDPROC, oldproc);
+ EndDialog(hdlg, -123);
+ return TRUE;
+ }
+ return FALSE;
+}
+
static void test_DialogBoxParam(void)
{
static const WCHAR nameW[] = {'T','E','S','T','_','E','M','P','T','Y','_','D','I','A','L','O','G',0};
@@ -1665,6 +1755,12 @@ static void test_DialogBoxParam(void)
ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, test_aw_conversion_dlgproc2, 0);
ok(ret == -123, "Unexpected ret value %ld.\n", ret);
+
+ ret = DialogBoxParamW(GetModuleHandleA(NULL), nameW, 0, test_aw_conversion_dlgproc3, 1);
+ ok(ret == -123, "Unexpected ret value %ld.\n", ret);
+
+ ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, test_aw_conversion_dlgproc3, 0);
+ ok(ret == -123, "Unexpected ret value %ld.\n", ret);
}
static void test_DisabledDialogTest(void)
--
2.15.1
2
1
[PATCH vkd3d 1/6] libs/vkd3d: Fix single descriptor handles in d3d12_command_list_OMSetRenderTargets().
by Józef Kucia 13 Feb '18
by Józef Kucia 13 Feb '18
13 Feb '18
From: Józef Kucia <jkucia(a)codeweavers.com>
Signed-off-by: Józef Kucia <jkucia(a)codeweavers.com>
---
libs/vkd3d/command.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c
index 4273a665e800..847581c03b65 100644
--- a/libs/vkd3d/command.c
+++ b/libs/vkd3d/command.c
@@ -3372,6 +3372,8 @@ static void STDMETHODCALLTYPE d3d12_command_list_OMSetRenderTargets(ID3D12Graphi
BOOL single_descriptor_handle, const D3D12_CPU_DESCRIPTOR_HANDLE *depth_stencil_descriptor)
{
struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList(iface);
+ const struct d3d12_rtv_desc *rtv_desc;
+ const struct d3d12_dsv_desc *dsv_desc;
unsigned int i;
TRACE("iface %p, render_target_descriptor_count %u, render_target_descriptors %p, "
@@ -3390,7 +3392,10 @@ static void STDMETHODCALLTYPE d3d12_command_list_OMSetRenderTargets(ID3D12Graphi
list->fb_height = 0;
for (i = 0; i < render_target_descriptor_count; ++i)
{
- const struct d3d12_rtv_desc *rtv_desc = d3d12_rtv_desc_from_cpu_handle(render_target_descriptors[i]);
+ if (single_descriptor_handle)
+ rtv_desc = d3d12_rtv_desc_from_cpu_handle(*render_target_descriptors) + i;
+ else
+ rtv_desc = d3d12_rtv_desc_from_cpu_handle(render_target_descriptors[i]);
d3d12_command_list_track_resource_usage(list, rtv_desc->resource);
@@ -3403,7 +3408,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_OMSetRenderTargets(ID3D12Graphi
if (depth_stencil_descriptor)
{
- const struct d3d12_dsv_desc *dsv_desc = d3d12_dsv_desc_from_cpu_handle(*depth_stencil_descriptor);
+ dsv_desc = d3d12_dsv_desc_from_cpu_handle(*depth_stencil_descriptor);
d3d12_command_list_track_resource_usage(list, dsv_desc->resource);
--
2.13.6
2
11