[comctl32]
[reactos.git] / reactos / dll / win32 / comctl32 / listview.c
index 1c0f58b..3b5ffe4 100644 (file)
@@ -6,7 +6,8 @@
  * Copyright 2000 Jason Mawdsley
  * Copyright 2001 CodeWeavers Inc.
  * Copyright 2002 Dimitrie O. Paun
- * Copyright 2009 Nikolay Sivov
+ * Copyright 2009-2011 Nikolay Sivov
+ * Copyright 2009 Owen Rudge for CodeWeavers
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -73,7 +74,6 @@
  *
  * States
  *   -- LVIS_ACTIVATING (not currently supported by comctl32.dll version 6.0)
- *   -- LVIS_CUT
  *   -- LVIS_DROPHILITED
  *   -- LVIS_OVERLAYMASK
  *
@@ -98,9 +98,7 @@
  *   -- LVN_BEGINSCROLL, LVN_ENDSCROLL
  *   -- LVN_GETINFOTIP
  *   -- LVN_HOTTRACK
- *   -- LVN_MARQUEEBEGIN
  *   -- LVN_SETDISPINFO
- *   -- NM_HOVER
  *   -- LVN_BEGINRDRAG
  *
  * Messages:
 
 WINE_DEFAULT_DEBUG_CHANNEL(listview);
 
-/* make sure you set this to 0 for production use! */
-#define DEBUG_RANGES 1
-
 typedef struct tagCOLUMN_INFO
 {
   RECT rcHeader;       /* tracks the header's rectangle */
@@ -237,81 +232,121 @@ typedef struct tagDELAYED_ITEM_EDIT
 
 typedef struct tagLISTVIEW_INFO
 {
+  /* control window */
   HWND hwndSelf;
-  HBRUSH hBkBrush;
-  COLORREF clrBk;
-  COLORREF clrText;
-  COLORREF clrTextBk;
-  HIMAGELIST himlNormal;
-  HIMAGELIST himlSmall;
-  HIMAGELIST himlState;
-  BOOL bLButtonDown;
-  BOOL bRButtonDown;
-  BOOL bDragging;
-  POINT ptClickPos;         /* point where the user clicked */ 
-  BOOL bNoItemMetrics;         /* flags if item metrics are not yet computed */
-  INT nItemHeight;
-  INT nItemWidth;
-  RANGES selectionRanges;
-  INT nSelectionMark;
-  INT nHotItem;
-  SHORT notifyFormat;
-  HWND hwndNotify;
   RECT rcList;                 /* This rectangle is really the window
                                * client rectangle possibly reduced by the 
                                * horizontal scroll bar and/or header - see 
                                * LISTVIEW_UpdateSize. This rectangle offset
                                * by the LISTVIEW_GetOrigin value is in
                                * client coordinates   */
-  SIZE iconSize;
-  SIZE iconSpacing;
-  SIZE iconStateSize;
-  UINT uCallbackMask;
-  HWND hwndHeader;
-  HCURSOR hHotCursor;
-  HFONT hDefaultFont;
-  HFONT hFont;
-  INT ntmHeight;               /* Some cached metrics of the font used */
-  INT ntmMaxCharWidth;         /* by the listview to draw items */
-  INT nEllipsisWidth;
-  BOOL bRedraw;                /* Turns on/off repaints & invalidations */
-  BOOL bAutoarrange;           /* Autoarrange flag when NOT in LVS_AUTOARRANGE */
-  BOOL bFocus;
+
+  /* notification window */
+  SHORT notifyFormat;
+  HWND hwndNotify;
   BOOL bDoChangeNotify;         /* send change notification messages? */
-  INT nFocusedItem;
-  RECT rcFocus;
-  DWORD dwStyle;               /* the cached window GWL_STYLE */
-  DWORD dwLvExStyle;           /* extended listview style */
-  DWORD uView;                 /* current view available through LVM_[G,S]ETVIEW */
+  UINT uCallbackMask;
+
+  /* tooltips */
+  HWND hwndToolTip;
+
+  /* items */
   INT nItemCount;              /* the number of items in the list */
   HDPA hdpaItems;               /* array ITEM_INFO pointers */
   HDPA hdpaItemIds;             /* array of ITEM_ID pointers */
   HDPA hdpaPosX;               /* maintains the (X, Y) coordinates of the */
   HDPA hdpaPosY;               /* items in LVS_ICON, and LVS_SMALLICON modes */
+  RANGES selectionRanges;
+  INT nSelectionMark;           /* item to start next multiselection from */
+  INT nHotItem;
+  BOOL bAutoarrange;           /* Autoarrange flag when NOT in LVS_AUTOARRANGE */
+
+  /* columns */
   HDPA hdpaColumns;            /* array of COLUMN_INFO pointers */
   BOOL colRectsDirty;          /* trigger column rectangles requery from header */
-  POINT currIconPos;           /* this is the position next icon will be placed */
-  PFNLVCOMPARE pfnCompare;
+
+  /* item metrics */
+  BOOL bNoItemMetrics;         /* flags if item metrics are not yet computed */
+  INT nItemHeight;
+  INT nItemWidth;
+
+  /* sorting */
+  PFNLVCOMPARE pfnCompare;      /* sorting callback pointer */
   LPARAM lParamSort;
+
+  /* style */
+  DWORD dwStyle;               /* the cached window GWL_STYLE */
+  DWORD dwLvExStyle;           /* extended listview style */
+  DWORD uView;                 /* current view available through LVM_[G,S]ETVIEW */
+
+  /* edit item */
   HWND hwndEdit;
   WNDPROC EditWndProc;
   INT nEditLabelItem;
-  INT nLButtonDownItem;                /* tracks item to reset multiselection on WM_LBUTTONUP */
-  DWORD dwHoverTime;
-  HWND hwndToolTip;
+  DELAYED_ITEM_EDIT itemEdit;   /* Pointer to this structure will be the timer ID */
+
+  /* icons */
+  HIMAGELIST himlNormal;
+  HIMAGELIST himlSmall;
+  HIMAGELIST himlState;
+  SIZE iconSize;
+  SIZE iconSpacing;
+  SIZE iconStateSize;
+  POINT currIconPos;        /* this is the position next icon will be placed */
+
+  /* header */
+  HWND hwndHeader;
+  INT xTrackLine;           /* The x coefficient of the track line or -1 if none */
+
+  /* marquee selection */
+  BOOL bMarqueeSelect;      /* marquee selection/highlight underway */
+  BOOL bScrolling;
+  RECT marqueeRect;         /* absolute coordinates of marquee selection */
+  RECT marqueeDrawRect;     /* relative coordinates for drawing marquee */
+  POINT marqueeOrigin;      /* absolute coordinates of marquee click origin */
+
+  /* focus drawing */
+  BOOL bFocus;              /* control has focus */
+  INT nFocusedItem;
+  RECT rcFocus;             /* focus bounds */
+
+  /* colors */
+  HBRUSH hBkBrush;
+  COLORREF clrBk;
+  COLORREF clrText;
+  COLORREF clrTextBk;
+  BOOL bDefaultBkColor;
+
+  /* font */
+  HFONT hDefaultFont;
+  HFONT hFont;
+  INT ntmHeight;            /* Some cached metrics of the font used */
+  INT ntmMaxCharWidth;      /* by the listview to draw items */
+  INT nEllipsisWidth;
 
-  DWORD cditemmode;             /* Keep the custom draw flags for an item/row */
+  /* mouse operation */
+  BOOL bLButtonDown;
+  BOOL bRButtonDown;
+  BOOL bDragging;
+  POINT ptClickPos;         /* point where the user clicked */
+  INT nLButtonDownItem;     /* tracks item to reset multiselection on WM_LBUTTONUP */
+  DWORD dwHoverTime;
+  HCURSOR hHotCursor;
 
+  /* keyboard operation */
   DWORD lastKeyPressTimestamp;
   WPARAM charCode;
   INT nSearchParamLength;
   WCHAR szSearchParam[ MAX_PATH ];
-  BOOL bIsDrawing;
-  INT nMeasureItemHeight;
-  INT xTrackLine;               /* The x coefficient of the track line or -1 if none */
-  DELAYED_ITEM_EDIT itemEdit;   /* Pointer to this structure will be the timer ID */
 
-  DWORD iVersion; /* CCM_[G,S]ETVERSION */
+  /* painting */
+  DWORD cditemmode;        /* Keep the custom draw flags for an item/row */
+  BOOL bIsDrawing;         /* Drawing in progress */
+  INT nMeasureItemHeight;  /* WM_MEASUREITEM result */
+  BOOL bRedraw;            /* WM_SETREDRAW switch */
+
+  /* misc */
+  DWORD iVersion;          /* CCM_[G,S]ETVERSION */
 } LISTVIEW_INFO;
 
 /*
@@ -326,7 +361,7 @@ typedef struct tagLISTVIEW_INFO
 #define SB_INTERNAL      -1
 
 /* maximum size of a label */
-#define DISP_TEXT_SIZE 512
+#define DISP_TEXT_SIZE 260
 
 /* padding for items in list and small icon display modes */
 #define WIDTH_PADDING 12
@@ -414,7 +449,6 @@ static void LISTVIEW_GetItemBox(const LISTVIEW_INFO *, INT, LPRECT);
 static void LISTVIEW_GetItemOrigin(const LISTVIEW_INFO *, INT, LPPOINT);
 static BOOL LISTVIEW_GetItemPosition(const LISTVIEW_INFO *, INT, LPPOINT);
 static BOOL LISTVIEW_GetItemRect(const LISTVIEW_INFO *, INT, LPRECT);
-static INT LISTVIEW_GetLabelWidth(const LISTVIEW_INFO *, INT);
 static void LISTVIEW_GetOrigin(const LISTVIEW_INFO *, LPPOINT);
 static BOOL LISTVIEW_GetViewRect(const LISTVIEW_INFO *, LPRECT);
 static void LISTVIEW_UpdateSize(LISTVIEW_INFO *);
@@ -423,13 +457,13 @@ static INT LISTVIEW_GetStringWidthT(const LISTVIEW_INFO *, LPCWSTR, BOOL);
 static BOOL LISTVIEW_KeySelection(LISTVIEW_INFO *, INT, BOOL);
 static UINT LISTVIEW_GetItemState(const LISTVIEW_INFO *, INT, UINT);
 static BOOL LISTVIEW_SetItemState(LISTVIEW_INFO *, INT, const LVITEMW *);
-static LRESULT LISTVIEW_VScroll(LISTVIEW_INFO *, INT, INT, HWND);
-static LRESULT LISTVIEW_HScroll(LISTVIEW_INFO *, INT, INT, HWND);
+static LRESULT LISTVIEW_VScroll(LISTVIEW_INFO *, INT, INT);
+static LRESULT LISTVIEW_HScroll(LISTVIEW_INFO *, INT, INT);
 static BOOL LISTVIEW_EnsureVisible(LISTVIEW_INFO *, INT, BOOL);
-static HWND CreateEditLabelT(LISTVIEW_INFO *, LPCWSTR, DWORD, BOOL);
 static HIMAGELIST LISTVIEW_SetImageList(LISTVIEW_INFO *, INT, HIMAGELIST);
 static INT LISTVIEW_HitTest(const LISTVIEW_INFO *, LPLVHITTESTINFO, BOOL, BOOL);
 static BOOL LISTVIEW_EndEditLabelT(LISTVIEW_INFO *, BOOL, BOOL);
+static BOOL LISTVIEW_Scroll(LISTVIEW_INFO *, INT, INT);
 
 /******** Text handling functions *************************************/
 
@@ -441,20 +475,14 @@ static BOOL LISTVIEW_EndEditLabelT(LISTVIEW_INFO *, BOOL, BOOL);
  *   W: Unicode, T: ANSI/Unicode - function of isW
  */
 
-static inline BOOL is_textW(LPCWSTR text)
+static inline BOOL is_text(LPCWSTR text)
 {
     return text != NULL && text != LPSTR_TEXTCALLBACKW;
 }
 
-static inline BOOL is_textT(LPCWSTR text, BOOL isW)
-{
-    /* we can ignore isW since LPSTR_TEXTCALLBACKW == LPSTR_TEXTCALLBACKA */
-    return is_textW(text);
-}
-
 static inline int textlenT(LPCWSTR text, BOOL isW)
 {
-    return !is_textT(text, isW) ? 0 :
+    return !is_text(text) ? 0 :
           isW ? lstrlenW(text) : lstrlenA((LPCSTR)text);
 }
 
@@ -472,7 +500,7 @@ static inline LPWSTR textdupTtoW(LPCWSTR text, BOOL isW)
 {
     LPWSTR wstr = (LPWSTR)text;
 
-    if (!isW && is_textT(text, isW))
+    if (!isW && is_text(text))
     {
        INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)text, -1, NULL, 0);
        wstr = Alloc(len * sizeof(WCHAR));
@@ -484,7 +512,7 @@ static inline LPWSTR textdupTtoW(LPCWSTR text, BOOL isW)
 
 static inline void textfreeT(LPWSTR wstr, BOOL isW)
 {
-    if (!isW && is_textT(wstr, isW)) Free (wstr);
+    if (!isW && is_text(wstr)) Free (wstr);
 }
 
 /*
@@ -497,7 +525,7 @@ static BOOL textsetptrT(LPWSTR *dest, LPCWSTR src, BOOL isW)
     
     if (src == LPSTR_TEXTCALLBACKW)
     {
-       if (is_textW(*dest)) Free(*dest);
+       if (is_text(*dest)) Free(*dest);
        *dest = LPSTR_TEXTCALLBACKW;
     }
     else
@@ -516,7 +544,7 @@ static BOOL textsetptrT(LPWSTR *dest, LPCWSTR src, BOOL isW)
 static inline int textcmpWT(LPCWSTR aw, LPCWSTR bt, BOOL isW)
 {
     if (!aw) return bt ? -1 : 0;
-    if (!bt) return aw ? 1 : 0;
+    if (!bt) return 1;
     if (aw == LPSTR_TEXTCALLBACKW)
        return bt == LPSTR_TEXTCALLBACKW ? 1 : -1;
     if (bt != LPSTR_TEXTCALLBACKW)
@@ -590,7 +618,7 @@ static const char* debugscrollinfo(const SCROLLINFO *pScrollInfo)
     if (pScrollInfo->fMask & SIF_TRACKPOS)
        len = snprintf(buf, size, "nTrackPos=%d, ", pScrollInfo->nTrackPos);
     else len = 0;
-    if (len == -1) goto end; buf += len; size -= len;
+    if (len == -1) goto end; buf += len;
     goto undo;
 end:
     buf = text + strlen(text);
@@ -635,7 +663,7 @@ static const char* debuglvitem_t(const LVITEMW *lpLVItem, BOOL isW)
     if (lpLVItem->mask & LVIF_INDENT)
        len = snprintf(buf, size, "iIndent=%d, ", lpLVItem->iIndent);
     else len = 0;
-    if (len == -1) goto end; buf += len; size -= len;
+    if (len == -1) goto end; buf += len;
     goto undo;
 end:
     buf = text + strlen(text);
@@ -675,7 +703,7 @@ static const char* debuglvcolumn_t(const LVCOLUMNW *lpColumn, BOOL isW)
     if (lpColumn->mask & LVCF_ORDER)
        len = snprintf(buf, size, "iOrder=%d, ", lpColumn->iOrder);
     else len = 0;
-    if (len == -1) goto end; buf += len; size -= len;
+    if (len == -1) goto end; buf += len;
     goto undo;
 end:
     buf = text + strlen(text);
@@ -716,25 +744,37 @@ static int get_ansi_notification(UINT unicodeNotificationCode)
 {
     switch (unicodeNotificationCode)
     {
+    case LVN_BEGINLABELEDITA:
     case LVN_BEGINLABELEDITW: return LVN_BEGINLABELEDITA;
+    case LVN_ENDLABELEDITA:
     case LVN_ENDLABELEDITW: return LVN_ENDLABELEDITA;
+    case LVN_GETDISPINFOA:
     case LVN_GETDISPINFOW: return LVN_GETDISPINFOA;
+    case LVN_SETDISPINFOA:
     case LVN_SETDISPINFOW: return LVN_SETDISPINFOA;
+    case LVN_ODFINDITEMA:
     case LVN_ODFINDITEMW: return LVN_ODFINDITEMA;
+    case LVN_GETINFOTIPA:
     case LVN_GETINFOTIPW: return LVN_GETINFOTIPA;
     /* header forwards */
+    case HDN_TRACKA:
     case HDN_TRACKW: return HDN_TRACKA;
+    case HDN_ENDTRACKA:
     case HDN_ENDTRACKW: return HDN_ENDTRACKA;
     case HDN_BEGINDRAG: return HDN_BEGINDRAG;
     case HDN_ENDDRAG: return HDN_ENDDRAG;
+    case HDN_ITEMCHANGINGA:
     case HDN_ITEMCHANGINGW: return HDN_ITEMCHANGINGA;
+    case HDN_ITEMCHANGEDA:
     case HDN_ITEMCHANGEDW: return HDN_ITEMCHANGEDA;
+    case HDN_ITEMCLICKA:
     case HDN_ITEMCLICKW: return HDN_ITEMCLICKA;
+    case HDN_DIVIDERDBLCLICKA:
     case HDN_DIVIDERDBLCLICKW: return HDN_DIVIDERDBLCLICKA;
+    default: break;
     }
-    ERR("unknown notification %x\n", unicodeNotificationCode);
-    assert(FALSE);
-    return 0;
+    FIXME("unknown notification %x\n", unicodeNotificationCode);
+    return unicodeNotificationCode;
 }
 
 /* forwards header notifications to listview parent */
@@ -748,12 +788,12 @@ static LRESULT notify_forward_header(const LISTVIEW_INFO *infoPtr, const NMHEADE
 
     /* on unicode format exit earlier */
     if (infoPtr->notifyFormat == NFR_UNICODE)
-        return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY,
-                            (WPARAM)lpnmh->hdr.idFrom, (LPARAM)lpnmh);
+        return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, lpnmh->hdr.idFrom,
+                            (LPARAM)lpnmh);
 
     /* header always supplies unicode notifications,
        all we have to do is to convert strings to ANSI */
-    nmhA = *(NMHEADERA*)lpnmh;
+    nmhA = *(const NMHEADERA*)lpnmh;
     if (lpnmh->pitem)
     {
         hditema = *(HDITEMA*)lpnmh->pitem;
@@ -778,8 +818,8 @@ static LRESULT notify_forward_header(const LISTVIEW_INFO *infoPtr, const NMHEADE
     }
     nmhA.hdr.code = get_ansi_notification(lpnmh->hdr.code);
 
-    ret = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY,
-                       (WPARAM)nmhA.hdr.idFrom, (LPARAM)&nmhA);
+    ret = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmhA.hdr.idFrom,
+                       (LPARAM)&nmhA);
 
     /* cleanup */
     Free(text);
@@ -826,6 +866,7 @@ static inline void notify_itemactivate(const LISTVIEW_INFO *infoPtr, const LVHIT
       item.mask = LVIF_PARAM|LVIF_STATE;
       item.iItem = htInfo->iItem;
       item.iSubItem = 0;
+      item.stateMask = (UINT)-1;
       if (LISTVIEW_GetItemT(infoPtr, &item, TRUE)) {
          nmia.lParam = item.lParam;
          nmia.uOldState = item.state;
@@ -889,74 +930,104 @@ static BOOL notify_deleteitem(const LISTVIEW_INFO *infoPtr, INT nItem)
   Send notification. depends on dispinfoW having same
   structure as dispinfoA.
   infoPtr : listview struct
-  notificationCode : *Unicode* notification code
+  code : *Unicode* notification code
   pdi : dispinfo structure (can be unicode or ansi)
   isW : TRUE if dispinfo is Unicode
 */
-static BOOL notify_dispinfoT(const LISTVIEW_INFO *infoPtr, UINT notificationCode, LPNMLVDISPINFOW pdi, BOOL isW)
+static BOOL notify_dispinfoT(const LISTVIEW_INFO *infoPtr, UINT code, LPNMLVDISPINFOW pdi, BOOL isW)
 {
-    BOOL bResult = FALSE;
-    BOOL convertToAnsi = FALSE, convertToUnicode = FALSE;
-    INT cchTempBufMax = 0, savCchTextMax = 0;
-    UINT realNotifCode;
-    LPWSTR pszTempBuf = NULL, savPszText = NULL;
+    INT length = 0, ret_length;
+    LPWSTR buffer = NULL, ret_text;
+    BOOL return_ansi = FALSE;
+    BOOL return_unicode = FALSE;
+    BOOL ret;
 
-    if ((pdi->item.mask & LVIF_TEXT) && is_textT(pdi->item.pszText, isW))
+    if ((pdi->item.mask & LVIF_TEXT) && is_text(pdi->item.pszText))
     {
-       convertToAnsi = (isW && infoPtr->notifyFormat == NFR_ANSI);
-       convertToUnicode = (!isW && infoPtr->notifyFormat == NFR_UNICODE);
+       return_unicode = ( isW && infoPtr->notifyFormat == NFR_ANSI);
+       return_ansi    = (!isW && infoPtr->notifyFormat == NFR_UNICODE);
     }
 
-    if (convertToAnsi || convertToUnicode)
+    ret_length = pdi->item.cchTextMax;
+    ret_text = pdi->item.pszText;
+
+    if (return_unicode || return_ansi)
     {
-       if (notificationCode != LVN_GETDISPINFOW)
-       {
-           cchTempBufMax = convertToUnicode ?
+        if (code != LVN_GETDISPINFOW)
+        {
+            length = return_ansi ?
                        MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pdi->item.pszText, -1, NULL, 0):
                        WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, NULL, 0, NULL, NULL);
-       }
-       else
-       {
-           cchTempBufMax = pdi->item.cchTextMax;
-           *pdi->item.pszText = 0; /* make sure we don't process garbage */
-       }
-
-       pszTempBuf = Alloc( (convertToUnicode ? sizeof(WCHAR) : sizeof(CHAR)) * cchTempBufMax);
-        if (!pszTempBuf) return FALSE;
-
-       if (convertToUnicode)
-           MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pdi->item.pszText, -1,
-                               pszTempBuf, cchTempBufMax);
-       else
-           WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, (LPSTR) pszTempBuf,
-                               cchTempBufMax, NULL, NULL);
+        }
+        else
+        {
+            length = pdi->item.cchTextMax;
+            *pdi->item.pszText = 0; /* make sure we don't process garbage */
+        }
+
+        buffer = Alloc( (return_ansi ? sizeof(WCHAR) : sizeof(CHAR)) * length);
+        if (!buffer) return FALSE;
+
+        if (return_ansi)
+            MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pdi->item.pszText, -1,
+                               buffer, length);
+        else
+            WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, (LPSTR) buffer,
+                               length, NULL, NULL);
 
-        savCchTextMax = pdi->item.cchTextMax;
-        savPszText = pdi->item.pszText;
-        pdi->item.pszText = pszTempBuf;
-        pdi->item.cchTextMax = cchTempBufMax;
+        pdi->item.pszText = buffer;
+        pdi->item.cchTextMax = length;
     }
 
     if (infoPtr->notifyFormat == NFR_ANSI)
-       realNotifCode = get_ansi_notification(notificationCode);
-    else
-       realNotifCode = notificationCode;
+        code = get_ansi_notification(code);
+
     TRACE(" pdi->item=%s\n", debuglvitem_t(&pdi->item, infoPtr->notifyFormat != NFR_ANSI));
-    bResult = notify_hdr(infoPtr, realNotifCode, &pdi->hdr);
+    ret = notify_hdr(infoPtr, code, &pdi->hdr);
+    TRACE(" resulting code=%d\n", pdi->hdr.code);
 
-    if (convertToUnicode || convertToAnsi)
+    if (return_ansi || return_unicode)
     {
-       if (convertToUnicode) /* note : pointer can be changed by app ! */
-           WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, (LPSTR) savPszText,
-                                savCchTextMax, NULL, NULL);
-       else
-           MultiByteToWideChar(CP_ACP, 0, (LPSTR) pdi->item.pszText, -1,
-                               savPszText, savCchTextMax);
-        pdi->item.pszText = savPszText; /* restores our buffer */
-        pdi->item.cchTextMax = savCchTextMax;
-        Free (pszTempBuf);
+        if (return_ansi && (pdi->hdr.code == LVN_GETDISPINFOA))
+        {
+            strcpy((char*)ret_text, (char*)pdi->item.pszText);
+        }
+        else if (return_unicode && (pdi->hdr.code == LVN_GETDISPINFOW))
+        {
+            strcpyW(ret_text, pdi->item.pszText);
+        }
+        else if (return_ansi) /* note : pointer can be changed by app ! */
+        {
+           WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, (LPSTR) ret_text,
+                ret_length, NULL, NULL);
+        }
+        else
+            MultiByteToWideChar(CP_ACP, 0, (LPSTR) pdi->item.pszText, -1,
+                ret_text, ret_length);
+
+        pdi->item.pszText = ret_text; /* restores our buffer */
+        pdi->item.cchTextMax = ret_length;
+
+        Free(buffer);
+        return ret;
     }
-    return bResult;
+
+    /* if dipsinfo holder changed notification code then convert */
+    if (!isW && (pdi->hdr.code == LVN_GETDISPINFOW) && (pdi->item.mask & LVIF_TEXT))
+    {
+        length = WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, NULL, 0, NULL, NULL);
+
+        buffer = Alloc(length * sizeof(CHAR));
+        if (!buffer) return FALSE;
+
+        WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, (LPSTR) buffer,
+                ret_length, NULL, NULL);
+
+        strcpy((LPSTR)pdi->item.pszText, (LPSTR)buffer);
+        Free(buffer);
+    }
+
+    return ret;
 }
 
 static void customdraw_fill(NMLVCUSTOMDRAW *lpnmlvcd, const LISTVIEW_INFO *infoPtr, HDC hdc,
@@ -1266,20 +1337,17 @@ static inline BOOL iterator_rangesitems(ITERATOR* i, RANGES ranges)
 }
 
 /***
- * Creates an iterator over the items which intersect lprc.
+ * Creates an iterator over the items which intersect frame.
+ * Uses absolute coordinates rather than compensating for the current offset.
  */
-static BOOL iterator_frameditems(ITERATOR* i, const LISTVIEW_INFO* infoPtr, const RECT *lprc)
+static BOOL iterator_frameditems_absolute(ITERATOR* i, const LISTVIEW_INFO* infoPtr, const RECT *frame)
 {
-    RECT frame = *lprc, rcItem, rcTemp;
-    POINT Origin;
+    RECT rcItem, rcTemp;
     
     /* in case we fail, we want to return an empty iterator */
     if (!iterator_empty(i)) return FALSE;
 
-    LISTVIEW_GetOrigin(infoPtr, &Origin);
-
-    TRACE("(lprc=%s)\n", wine_dbgstr_rect(lprc));
-    OffsetRect(&frame, -Origin.x, -Origin.y);
+    TRACE("(frame=%s)\n", wine_dbgstr_rect(frame));
 
     if (infoPtr->uView == LV_VIEW_ICON || infoPtr->uView == LV_VIEW_SMALLICON)
     {
@@ -1288,7 +1356,7 @@ static BOOL iterator_frameditems(ITERATOR* i, const LISTVIEW_INFO* infoPtr, cons
        if (infoPtr->uView == LV_VIEW_ICON && infoPtr->nFocusedItem != -1)
        {
            LISTVIEW_GetItemBox(infoPtr, infoPtr->nFocusedItem, &rcItem);
-           if (IntersectRect(&rcTemp, &rcItem, lprc))
+           if (IntersectRect(&rcTemp, &rcItem, frame))
                i->nSpecial = infoPtr->nFocusedItem;
        }
        if (!(iterator_rangesitems(i, ranges_create(50)))) return FALSE;
@@ -1300,7 +1368,7 @@ static BOOL iterator_frameditems(ITERATOR* i, const LISTVIEW_INFO* infoPtr, cons
            rcItem.top = (LONG_PTR)DPA_GetPtr(infoPtr->hdpaPosY, nItem);
            rcItem.right = rcItem.left + infoPtr->nItemWidth;
            rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
-           if (IntersectRect(&rcTemp, &rcItem, &frame))
+           if (IntersectRect(&rcTemp, &rcItem, frame))
                ranges_additem(i->ranges, nItem);
        }
        return TRUE;
@@ -1309,11 +1377,11 @@ static BOOL iterator_frameditems(ITERATOR* i, const LISTVIEW_INFO* infoPtr, cons
     {
        RANGE range;
        
-       if (frame.left >= infoPtr->nItemWidth) return TRUE;
-       if (frame.top >= infoPtr->nItemHeight * infoPtr->nItemCount) return TRUE;
+       if (frame->left >= infoPtr->nItemWidth) return TRUE;
+       if (frame->top >= infoPtr->nItemHeight * infoPtr->nItemCount) return TRUE;
        
-       range.lower = max(frame.top / infoPtr->nItemHeight, 0);
-       range.upper = min((frame.bottom - 1) / infoPtr->nItemHeight, infoPtr->nItemCount - 1) + 1;
+       range.lower = max(frame->top / infoPtr->nItemHeight, 0);
+       range.upper = min((frame->bottom - 1) / infoPtr->nItemHeight, infoPtr->nItemCount - 1) + 1;
        if (range.upper <= range.lower) return TRUE;
        if (!iterator_rangeitems(i, range)) return FALSE;
        TRACE("    report=%s\n", debugrange(&i->range));
@@ -1321,8 +1389,8 @@ static BOOL iterator_frameditems(ITERATOR* i, const LISTVIEW_INFO* infoPtr, cons
     else
     {
        INT nPerCol = max((infoPtr->rcList.bottom - infoPtr->rcList.top) / infoPtr->nItemHeight, 1);
-       INT nFirstRow = max(frame.top / infoPtr->nItemHeight, 0);
-       INT nLastRow = min((frame.bottom - 1) / infoPtr->nItemHeight, nPerCol - 1);
+       INT nFirstRow = max(frame->top / infoPtr->nItemHeight, 0);
+       INT nLastRow = min((frame->bottom - 1) / infoPtr->nItemHeight, nPerCol - 1);
        INT nFirstCol;
        INT nLastCol;
        INT lower;
@@ -1331,13 +1399,13 @@ static BOOL iterator_frameditems(ITERATOR* i, const LISTVIEW_INFO* infoPtr, cons
 
        if (infoPtr->nItemWidth)
        {
-           nFirstCol = max(frame.left / infoPtr->nItemWidth, 0);
-            nLastCol  = min((frame.right - 1) / infoPtr->nItemWidth, (infoPtr->nItemCount + nPerCol - 1) / nPerCol);
+           nFirstCol = max(frame->left / infoPtr->nItemWidth, 0);
+            nLastCol  = min((frame->right - 1) / infoPtr->nItemWidth, (infoPtr->nItemCount + nPerCol - 1) / nPerCol);
        }
        else
        {
-           nFirstCol = max(frame.left, 0);
-            nLastCol  = min(frame.right - 1, (infoPtr->nItemCount + nPerCol - 1) / nPerCol);
+           nFirstCol = max(frame->left, 0);
+            nLastCol  = min(frame->right - 1, (infoPtr->nItemCount + nPerCol - 1) / nPerCol);
        }
 
        lower = nFirstCol * nPerCol + nFirstRow;
@@ -1362,6 +1430,22 @@ static BOOL iterator_frameditems(ITERATOR* i, const LISTVIEW_INFO* infoPtr, cons
     return TRUE;
 }
 
+/***
+ * Creates an iterator over the items which intersect lprc.
+ */
+static BOOL iterator_frameditems(ITERATOR* i, const LISTVIEW_INFO* infoPtr, const RECT *lprc)
+{
+    RECT frame = *lprc;
+    POINT Origin;
+
+    TRACE("(lprc=%s)\n", wine_dbgstr_rect(lprc));
+
+    LISTVIEW_GetOrigin(infoPtr, &Origin);
+    OffsetRect(&frame, -Origin.x, -Origin.y);
+
+    return iterator_frameditems_absolute(i, infoPtr, &frame);
+}
+
 /***
  * Creates an iterator over the items which intersect the visible region of hdc.
  */
@@ -1525,7 +1609,7 @@ static INT LISTVIEW_CreateHeader(LISTVIEW_INFO *infoPtr)
     SendMessageW(infoPtr->hwndHeader, HDM_SETUNICODEFORMAT, TRUE, 0);
 
     /* set header font */
-    SendMessageW(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont, (LPARAM)TRUE);
+    SendMessageW(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont, TRUE);
 
     LISTVIEW_UpdateSize(infoPtr);
 
@@ -1536,6 +1620,13 @@ static inline void LISTVIEW_GetHeaderRect(const LISTVIEW_INFO *infoPtr, INT nSub
 {
     *lprc = LISTVIEW_GetColumnInfo(infoPtr, nSubItem)->rcHeader;
 }
+
+static inline BOOL LISTVIEW_IsHeaderEnabled(const LISTVIEW_INFO *infoPtr)
+{
+    return (infoPtr->uView == LV_VIEW_DETAILS ||
+            infoPtr->dwLvExStyle & LVS_EX_HEADERINALLVIEWS) &&
+          !(infoPtr->dwStyle & LVS_NOCOLUMNHEADER);
+}
        
 static inline BOOL LISTVIEW_GetItemW(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem)
 {
@@ -1545,8 +1636,19 @@ static inline BOOL LISTVIEW_GetItemW(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpL
 /* used to handle collapse main item column case */
 static inline BOOL LISTVIEW_DrawFocusRect(const LISTVIEW_INFO *infoPtr, HDC hdc)
 {
-    return (infoPtr->rcFocus.left < infoPtr->rcFocus.right) ?
-            DrawFocusRect(hdc, &infoPtr->rcFocus) : FALSE;
+    BOOL Ret = FALSE;
+
+    if (infoPtr->rcFocus.left < infoPtr->rcFocus.right)
+    {
+        DWORD dwOldBkColor, dwOldTextColor;
+
+        dwOldBkColor = SetBkColor(hdc, RGB(255, 255, 255));
+        dwOldTextColor = SetBkColor(hdc, RGB(0, 0, 0));
+        Ret = DrawFocusRect(hdc, &infoPtr->rcFocus);
+        SetBkColor(hdc, dwOldBkColor);
+        SetBkColor(hdc, dwOldTextColor);
+    }
+    return Ret;
 }
 
 /* Listview invalidation functions: use _only_ these functions to invalidate */
@@ -1683,14 +1785,15 @@ static inline INT LISTVIEW_GetCountPerColumn(const LISTVIEW_INFO *infoPtr)
  */
 static INT LISTVIEW_ProcessLetterKeys(LISTVIEW_INFO *infoPtr, WPARAM charCode, LPARAM keyData)
 {
-    INT nItem;
-    INT endidx,idx;
-    LVITEMW item;
     WCHAR buffer[MAX_PATH];
-    DWORD lastKeyPressTimestamp = infoPtr->lastKeyPressTimestamp;
+    INT endidx, startidx;
+    DWORD prevTime;
+    LVITEMW item;
+    INT nItem;
+    INT diff;
 
     /* simple parameter checking */
-    if (!charCode || !keyData) return 0;
+    if (!charCode || !keyData || infoPtr->nItemCount == 0) return 0;
 
     /* only allow the valid WM_CHARs through */
     if (!isalnumW(charCode) &&
@@ -1705,86 +1808,94 @@ static INT LISTVIEW_ProcessLetterKeys(LISTVIEW_INFO *infoPtr, WPARAM charCode, L
         charCode != '<' && charCode != ',' && charCode != '~')
         return 0;
 
-    /* if there's one item or less, there is no where to go */
-    if (infoPtr->nItemCount <= 1) return 0;
-
     /* update the search parameters */
+    prevTime = infoPtr->lastKeyPressTimestamp;
     infoPtr->lastKeyPressTimestamp = GetTickCount();
-    if (infoPtr->lastKeyPressTimestamp - lastKeyPressTimestamp < KEY_DELAY) {
-        if (infoPtr->nSearchParamLength < MAX_PATH-1)
-            infoPtr->szSearchParam[infoPtr->nSearchParamLength++]=charCode;
+    diff = infoPtr->lastKeyPressTimestamp - prevTime;
+
+    if (diff >= 0 && diff < KEY_DELAY)
+    {
+        if (infoPtr->nSearchParamLength < MAX_PATH - 1)
+            infoPtr->szSearchParam[infoPtr->nSearchParamLength++] = charCode;
+
         if (infoPtr->charCode != charCode)
             infoPtr->charCode = charCode = 0;
-    } else {
-        infoPtr->charCode=charCode;
-        infoPtr->szSearchParam[0]=charCode;
-        infoPtr->nSearchParamLength=1;
-        /* Redundant with the 1 char string */
-        charCode=0;
+    }
+    else
+    {
+        infoPtr->charCode = charCode;
+        infoPtr->szSearchParam[0] = charCode;
+        infoPtr->nSearchParamLength = 1;
     }
 
     /* and search from the current position */
-    nItem=-1;
-    if (infoPtr->nFocusedItem >= 0) {
-        endidx=infoPtr->nFocusedItem;
-        idx=endidx;
-        /* if looking for single character match,
-         * then we must always move forward
-         */
-        if (infoPtr->nSearchParamLength == 1)
-            idx++;
-    } else {
-        endidx=infoPtr->nItemCount;
-        idx=0;
-    }
+    nItem = -1;
+    endidx = infoPtr->nItemCount;
+
+    /* should start from next after focused item, so next item that matches
+       will be selected, if there isn't any and focused matches it will be selected
+       on second search stage from beginning of the list */
+    if (infoPtr->nFocusedItem >= 0 && infoPtr->nItemCount > 1)
+        startidx = infoPtr->nFocusedItem + 1;
+    else
+        startidx = 0;
 
-    /* Let application handle this for virtual listview */
+    /* let application handle this for virtual listview */
     if (infoPtr->dwStyle & LVS_OWNERDATA)
     {
         NMLVFINDITEMW nmlv;
-        LVFINDINFOW lvfi;
 
-        ZeroMemory(&lvfi, sizeof(lvfi));
-        lvfi.flags = (LVFI_WRAP | LVFI_PARTIAL);
-        infoPtr->szSearchParam[infoPtr->nSearchParamLength] = '\0';
-        lvfi.psz = infoPtr->szSearchParam;
-        nmlv.iStart = idx;
-        nmlv.lvfi = lvfi;
+        memset(&nmlv.lvfi, 0, sizeof(nmlv.lvfi));
+        nmlv.lvfi.flags = (LVFI_WRAP | LVFI_PARTIAL);
+        nmlv.lvfi.psz = infoPtr->szSearchParam;
+        nmlv.iStart = startidx;
+
+        infoPtr->szSearchParam[infoPtr->nSearchParamLength] = 0;
 
         nItem = notify_hdr(infoPtr, LVN_ODFINDITEMW, (LPNMHDR)&nmlv.hdr);
+    }
+    else
+    {
+        INT i = startidx;
 
-        if (nItem != -1)
-            LISTVIEW_KeySelection(infoPtr, nItem, FALSE);
+        /* first search in [startidx, endidx), on failure continue in [0, startidx) */
+        while (1)
+        {
+            /* start from first item if not found with >= startidx */
+            if (i == infoPtr->nItemCount && startidx > 0)
+            {
+                endidx = startidx;
+                startidx = 0;
+            }
 
-        return 0;
-    }
+            for (i = startidx; i < endidx; i++)
+            {
+                /* retrieve text */
+                item.mask = LVIF_TEXT;
+                item.iItem = i;
+                item.iSubItem = 0;
+                item.pszText = buffer;
+                item.cchTextMax = MAX_PATH;
+                if (!LISTVIEW_GetItemW(infoPtr, &item)) return 0;
+
+                if (lstrncmpiW(item.pszText, infoPtr->szSearchParam, infoPtr->nSearchParamLength) == 0)
+                {
+                    nItem = i;
+                    break;
+                }
+                else if (nItem == -1 && lstrncmpiW(item.pszText, infoPtr->szSearchParam, 1) == 0)
+                {
+                    /* this would work but we must keep looking for a longer match */
+                    nItem = i;
+                }
+            }
 
-    do {
-        if (idx == infoPtr->nItemCount) {
-            if (endidx == infoPtr->nItemCount || endidx == 0)
+            if ( nItem != -1 || /* found something */
+                 endidx != infoPtr->nItemCount || /* second search done */
+                (startidx == 0 && endidx == infoPtr->nItemCount) /* full range for first search */ )
                 break;
-            idx=0;
-        }
-
-        /* get item */
-        item.mask = LVIF_TEXT;
-        item.iItem = idx;
-        item.iSubItem = 0;
-        item.pszText = buffer;
-        item.cchTextMax = MAX_PATH;
-        if (!LISTVIEW_GetItemW(infoPtr, &item)) return 0;
-
-        /* check for a match */
-        if (lstrncmpiW(item.pszText,infoPtr->szSearchParam,infoPtr->nSearchParamLength) == 0) {
-            nItem=idx;
-            break;
-        } else if ( (charCode != 0) && (nItem == -1) && (nItem != infoPtr->nFocusedItem) &&
-                    (lstrncmpiW(item.pszText,infoPtr->szSearchParam,1) == 0) ) {
-            /* This would work but we must keep looking for a longer match */
-            nItem=idx;
-        }
-        idx++;
-    } while (idx != endidx);
+        };
+    }
 
     if (nItem != -1)
         LISTVIEW_KeySelection(infoPtr, nItem, FALSE);
@@ -1874,7 +1985,23 @@ static void LISTVIEW_UpdateScroll(const LISTVIEW_INFO *infoPtr)
 
        if (LISTVIEW_GetViewRect(infoPtr, &rcView)) horzInfo.nMax = rcView.right - rcView.left;
     }
-  
+
+    if (LISTVIEW_IsHeaderEnabled(infoPtr))
+    {
+       if (DPA_GetPtrCount(infoPtr->hdpaColumns))
+       {
+           RECT rcHeader;
+           INT index;
+
+           index = SendMessageW(infoPtr->hwndHeader, HDM_ORDERTOINDEX,
+                                 DPA_GetPtrCount(infoPtr->hdpaColumns) - 1, 0);
+
+           LISTVIEW_GetHeaderRect(infoPtr, index, &rcHeader);
+           horzInfo.nMax = rcHeader.right;
+           TRACE("horzInfo.nMax=%d\n", horzInfo.nMax);
+       }
+    }
+
     horzInfo.fMask = SIF_RANGE | SIF_PAGE;
     horzInfo.nMax = max(horzInfo.nMax - 1, 0);
     dx = GetScrollPos(infoPtr->hwndSelf, SB_HORZ);
@@ -1924,7 +2051,7 @@ static void LISTVIEW_UpdateScroll(const LISTVIEW_INFO *infoPtr)
     }
 
     /* Update the Header Control */
-    if (infoPtr->uView == LV_VIEW_DETAILS)
+    if (infoPtr->hwndHeader)
     {
        horzInfo.fMask = SIF_POS;
        GetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &horzInfo);
@@ -2234,7 +2361,7 @@ static void LISTVIEW_GetItemMetrics(const LISTVIEW_INFO *infoPtr, const LVITEMW
        
        /* we need the text in non owner draw mode */
        assert(lpLVItem->mask & LVIF_TEXT);
-       if (is_textT(lpLVItem->pszText, TRUE))
+       if (is_text(lpLVItem->pszText))
         {
            HFONT hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
            HDC hdc = GetDC(infoPtr->hwndSelf);
@@ -2733,15 +2860,27 @@ static INT LISTVIEW_CalculateItemWidth(const LISTVIEW_INFO *infoPtr)
     }
     else /* LV_VIEW_SMALLICON, or LV_VIEW_LIST */
     {
+       WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
+       LVITEMW lvItem;
        INT i;
-       
+
+       lvItem.mask = LVIF_TEXT;
+       lvItem.iSubItem = 0;
+
        for (i = 0; i < infoPtr->nItemCount; i++)
-           nItemWidth = max(LISTVIEW_GetLabelWidth(infoPtr, i), nItemWidth);
+       {
+           lvItem.iItem = i;
+           lvItem.pszText = szDispText;
+           lvItem.cchTextMax = DISP_TEXT_SIZE;
+           if (LISTVIEW_GetItemW(infoPtr, &lvItem))
+               nItemWidth = max(LISTVIEW_GetStringWidthT(infoPtr, lvItem.pszText, TRUE),
+                                nItemWidth);
+       }
 
         if (infoPtr->himlSmall) nItemWidth += infoPtr->iconSize.cx; 
         if (infoPtr->himlState) nItemWidth += infoPtr->iconStateSize.cx;
 
-       nItemWidth = max(DEFAULT_COLUMN_WIDTH, nItemWidth + WIDTH_PADDING);
+        nItemWidth = max(DEFAULT_COLUMN_WIDTH, nItemWidth + WIDTH_PADDING);
     }
 
     return nItemWidth;
@@ -2862,11 +3001,7 @@ static INT CALLBACK ranges_cmp(LPVOID range1, LPVOID range2, LPARAM flags)
     return cmp;
 }
 
-#if DEBUG_RANGES
-#define ranges_check(ranges, desc) ranges_assert(ranges, desc, __FUNCTION__, __LINE__)
-#else
-#define ranges_check(ranges, desc) do { } while(0)
-#endif
+#define ranges_check(ranges, desc) if (TRACE_ON(listview)) ranges_assert(ranges, desc, __FUNCTION__, __LINE__)
 
 static void ranges_assert(RANGES ranges, LPCSTR desc, const char *func, int line)
 {
@@ -3091,28 +3226,30 @@ static BOOL ranges_del(RANGES ranges, RANGE range)
 
     TRACE("(%s)\n", debugrange(&range));
     ranges_check(ranges, "before del");
-    
+
     /* we don't use DPAS_SORTED here, since we need *
      * to find the first overlapping range          */
     index = DPA_Search(ranges->hdpa, &range, 0, ranges_cmp, 0, 0);
-    while(index != -1) 
+    while(index != -1)
     {
        chkrgn = DPA_GetPtr(ranges->hdpa, index);
-       
-        TRACE("Matches range %s @%d\n", debugrange(chkrgn), index); 
+
+       TRACE("Matches range %s @%d\n", debugrange(chkrgn), index);
 
        /* case 1: Same range */
        if ( (chkrgn->upper == range.upper) &&
             (chkrgn->lower == range.lower) )
        {
            DPA_DeletePtr(ranges->hdpa, index);
+           Free(chkrgn);
            break;
        }
        /* case 2: engulf */
        else if ( (chkrgn->upper <= range.upper) &&
-                 (chkrgn->lower >= range.lower) ) 
+                 (chkrgn->lower >= range.lower) )
        {
            DPA_DeletePtr(ranges->hdpa, index);
+           Free(chkrgn);
        }
        /* case 3: overlap upper */
        else if ( (chkrgn->upper <= range.upper) &&
@@ -3130,7 +3267,7 @@ static BOOL ranges_del(RANGES ranges, RANGE range)
        /* case 5: fully internal */
        else
        {
-           RANGE tmprgn = *chkrgn, *newrgn;
+           RANGE *newrgn;
 
            if (!(newrgn = Alloc(sizeof(RANGE)))) goto fail;
            newrgn->lower = chkrgn->lower;
@@ -3141,7 +3278,6 @@ static BOOL ranges_del(RANGES ranges, RANGE range)
                Free(newrgn);
                goto fail;
            }
-           chkrgn = &tmprgn;
            break;
        }
 
@@ -3536,7 +3672,7 @@ static BOOL LISTVIEW_GetItemAtPt(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVIte
     return LISTVIEW_GetItemT(infoPtr, lpLVItem, TRUE);
 }
 
-static inline BOOL LISTVIEW_isHotTracking(const LISTVIEW_INFO *infoPtr)
+static inline BOOL LISTVIEW_IsHotTracking(const LISTVIEW_INFO *infoPtr)
 {
     return ((infoPtr->dwLvExStyle & LVS_EX_TRACKSELECT) ||
             (infoPtr->dwLvExStyle & LVS_EX_ONECLICKACTIVATE) ||
@@ -3561,9 +3697,13 @@ static inline BOOL LISTVIEW_isHotTracking(const LISTVIEW_INFO *infoPtr)
  * over the item for a certain period of time.
  *
  */
-static LRESULT LISTVIEW_MouseHover(LISTVIEW_INFO *infoPtr, WORD fwKeys, INT x, INT y)
+static LRESULT LISTVIEW_MouseHover(LISTVIEW_INFO *infoPtr, INT x, INT y)
 {
-    if (LISTVIEW_isHotTracking(infoPtr))
+    NMHDR hdr;
+
+    if (notify_hdr(infoPtr, NM_HOVER, &hdr)) return 0;
+
+    if (LISTVIEW_IsHotTracking(infoPtr))
     {
         LVITEMW item;
         POINT pt;
@@ -3573,48 +3713,283 @@ static LRESULT LISTVIEW_MouseHover(LISTVIEW_INFO *infoPtr, WORD fwKeys, INT x, I
 
         if (LISTVIEW_GetItemAtPt(infoPtr, &item, pt))
             LISTVIEW_SetSelection(infoPtr, item.iItem);
+
+        SetFocus(infoPtr->hwndSelf);
     }
 
     return 0;
 }
 
+#define SCROLL_LEFT   0x1
+#define SCROLL_RIGHT  0x2
+#define SCROLL_UP     0x4
+#define SCROLL_DOWN   0x8
+
 /***
  * DESCRIPTION:
- * Called whenever WM_MOUSEMOVE is received.
+ * Utility routine to draw and highlight items within a marquee selection rectangle.
  *
  * PARAMETER(S):
- * [I] infoPtr : valid pointer to the listview structure
- * [I] fwKeys : key indicator
- * [I] x,y : mouse position
+ * [I] infoPtr     : valid pointer to the listview structure
+ * [I] coords_orig : original co-ordinates of the cursor
+ * [I] coords_offs : offsetted coordinates of the cursor
+ * [I] offset      : offset amount
+ * [I] scroll      : Bitmask of which directions we should scroll, if at all
  *
  * RETURN:
- *   0 if the message is processed, non-zero if there was an error
+ *   None.
  */
-static LRESULT LISTVIEW_MouseMove(LISTVIEW_INFO *infoPtr, WORD fwKeys, INT x, INT y)
+static void LISTVIEW_MarqueeHighlight(LISTVIEW_INFO *infoPtr, const POINT *coords_orig,
+                                      const POINT *coords_offs, const POINT *offset,
+                                      INT scroll)
 {
-    TRACKMOUSEEVENT trackinfo;
+    BOOL controlDown = FALSE;
+    LVITEMW item;
+    ITERATOR i;
+    RECT rect;
 
-    if (!(fwKeys & MK_LBUTTON))
-        infoPtr->bLButtonDown = FALSE;
+    if (coords_offs->x > infoPtr->marqueeOrigin.x)
+    {
+        rect.left = infoPtr->marqueeOrigin.x;
+        rect.right = coords_offs->x;
+    }
+    else
+    {
+        rect.left = coords_offs->x;
+        rect.right = infoPtr->marqueeOrigin.x;
+    }
 
-    if (infoPtr->bLButtonDown)
+    if (coords_offs->y > infoPtr->marqueeOrigin.y)
     {
-        POINT tmp;
-        RECT rect;
-        LVHITTESTINFO lvHitTestInfo;
-        WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
-        WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
+        rect.top = infoPtr->marqueeOrigin.y;
+        rect.bottom = coords_offs->y;
+    }
+    else
+    {
+        rect.top = coords_offs->y;
+        rect.bottom = infoPtr->marqueeOrigin.y;
+    }
 
-        rect.left = infoPtr->ptClickPos.x - wDragWidth;
-        rect.right = infoPtr->ptClickPos.x + wDragWidth;
-        rect.top = infoPtr->ptClickPos.y - wDragHeight;
-        rect.bottom = infoPtr->ptClickPos.y + wDragHeight;
+    /* Cancel out the old marquee rectangle and draw the new one */
+    LISTVIEW_InvalidateRect(infoPtr, &infoPtr->marqueeDrawRect);
 
-        tmp.x = x;
-        tmp.y = y;
+    /* Scroll by the appropriate distance if applicable - speed up scrolling as
+       the cursor is further away */
 
-        lvHitTestInfo.pt = tmp;
-        LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, TRUE);
+    if ((scroll & SCROLL_LEFT) && (coords_orig->x <= 0))
+        LISTVIEW_Scroll(infoPtr, coords_orig->x, 0);
+
+    if ((scroll & SCROLL_RIGHT) && (coords_orig->x >= infoPtr->rcList.right))
+        LISTVIEW_Scroll(infoPtr, (coords_orig->x - infoPtr->rcList.right), 0);
+
+    if ((scroll & SCROLL_UP) && (coords_orig->y <= 0))
+        LISTVIEW_Scroll(infoPtr, 0, coords_orig->y);
+
+    if ((scroll & SCROLL_DOWN) && (coords_orig->y >= infoPtr->rcList.bottom))
+        LISTVIEW_Scroll(infoPtr, 0, (coords_orig->y - infoPtr->rcList.bottom));
+
+    /* Invert the items in the old marquee rectangle */
+    iterator_frameditems_absolute(&i, infoPtr, &infoPtr->marqueeRect);
+
+    while (iterator_next(&i))
+    {
+        if (i.nItem > -1)
+        {
+            if (LISTVIEW_GetItemState(infoPtr, i.nItem, LVIS_SELECTED) == LVIS_SELECTED)
+                item.state = 0;
+            else
+                item.state = LVIS_SELECTED;
+
+            item.stateMask = LVIS_SELECTED;
+
+            LISTVIEW_SetItemState(infoPtr, i.nItem, &item);
+        }
+    }
+
+    iterator_destroy(&i);
+
+    CopyRect(&infoPtr->marqueeRect, &rect);
+
+    CopyRect(&infoPtr->marqueeDrawRect, &rect);
+    OffsetRect(&infoPtr->marqueeDrawRect, offset->x, offset->y);
+
+    /* Iterate over the items within our marquee rectangle */
+    iterator_frameditems_absolute(&i, infoPtr, &infoPtr->marqueeRect);
+
+    if (GetKeyState(VK_CONTROL) & 0x8000)
+        controlDown = TRUE;
+
+    while (iterator_next(&i))
+    {
+        if (i.nItem > -1)
+        {
+            /* If CTRL is pressed, invert. If not, always select the item. */
+            if ((controlDown) && (LISTVIEW_GetItemState(infoPtr, i.nItem, LVIS_SELECTED)))
+                item.state = 0;
+            else
+                item.state = LVIS_SELECTED;
+
+            item.stateMask = LVIS_SELECTED;
+
+            LISTVIEW_SetItemState(infoPtr, i.nItem, &item);
+        }
+    }
+
+    iterator_destroy(&i);
+    LISTVIEW_InvalidateRect(infoPtr, &rect);
+}
+
+/***
+ * DESCRIPTION:
+ * Called when we are in a marquee selection that involves scrolling the listview (ie,
+ * the cursor is outside the bounds of the client area). This is a TIMERPROC.
+ *
+ * PARAMETER(S):
+ * [I] hwnd : Handle to the listview
+ * [I] uMsg : WM_TIMER (ignored)
+ * [I] idEvent : The timer ID interpreted as a pointer to a LISTVIEW_INFO struct
+ * [I] dwTimer : The elapsed time (ignored)
+ *
+ * RETURN:
+ *   None.
+ */
+static VOID CALLBACK LISTVIEW_ScrollTimer(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
+{
+    LISTVIEW_INFO *infoPtr;
+    SCROLLINFO scrollInfo;
+    POINT coords_orig;
+    POINT coords_offs;
+    POINT offset;
+    INT scroll = 0;
+
+    infoPtr = (LISTVIEW_INFO *) idEvent;
+
+    if (!infoPtr)
+        return;
+
+    /* Get the current cursor position and convert to client coordinates */
+    GetCursorPos(&coords_orig);
+    ScreenToClient(hWnd, &coords_orig);
+
+    /* Ensure coordinates are within client bounds */
+    coords_offs.x = max(min(coords_orig.x, infoPtr->rcList.right), 0);
+    coords_offs.y = max(min(coords_orig.y, infoPtr->rcList.bottom), 0);
+
+    /* Get offset */
+    LISTVIEW_GetOrigin(infoPtr, &offset);
+
+    /* Offset coordinates by the appropriate amount */
+    coords_offs.x -= offset.x;
+    coords_offs.y -= offset.y;
+
+    scrollInfo.cbSize = sizeof(SCROLLINFO);
+    scrollInfo.fMask = SIF_ALL;
+
+    /* Work out in which directions we can scroll */
+    if (GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo))
+    {
+        if (scrollInfo.nPos != scrollInfo.nMin)
+            scroll |= SCROLL_UP;
+
+        if (((scrollInfo.nPage + scrollInfo.nPos) - 1) != scrollInfo.nMax)
+            scroll |= SCROLL_DOWN;
+    }
+
+    if (GetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &scrollInfo))
+    {
+        if (scrollInfo.nPos != scrollInfo.nMin)
+            scroll |= SCROLL_LEFT;
+
+        if (((scrollInfo.nPage + scrollInfo.nPos) - 1) != scrollInfo.nMax)
+            scroll |= SCROLL_RIGHT;
+    }
+
+    if (((coords_orig.x <= 0) && (scroll & SCROLL_LEFT)) ||
+        ((coords_orig.y <= 0) && (scroll & SCROLL_UP))   ||
+        ((coords_orig.x >= infoPtr->rcList.right) && (scroll & SCROLL_RIGHT)) ||
+        ((coords_orig.y >= infoPtr->rcList.bottom) && (scroll & SCROLL_DOWN)))
+    {
+        LISTVIEW_MarqueeHighlight(infoPtr, &coords_orig, &coords_offs, &offset, scroll);
+    }
+}
+
+/***
+ * DESCRIPTION:
+ * Called whenever WM_MOUSEMOVE is received.
+ *
+ * PARAMETER(S):
+ * [I] infoPtr : valid pointer to the listview structure
+ * [I] fwKeys : key indicator
+ * [I] x,y : mouse position
+ *
+ * RETURN:
+ *   0 if the message is processed, non-zero if there was an error
+ */
+static LRESULT LISTVIEW_MouseMove(LISTVIEW_INFO *infoPtr, WORD fwKeys, INT x, INT y)
+{
+    if (!(fwKeys & MK_LBUTTON))
+        infoPtr->bLButtonDown = FALSE;
+
+    if (infoPtr->bLButtonDown)
+    {
+        POINT tmp;
+        RECT rect;
+        LVHITTESTINFO lvHitTestInfo;
+        WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
+        WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
+
+        if (infoPtr->bMarqueeSelect)
+        {
+            POINT coords_orig;
+            POINT coords_offs;
+            POINT offset;
+
+            coords_orig.x = x;
+            coords_orig.y = y;
+
+            /* Get offset */
+            LISTVIEW_GetOrigin(infoPtr, &offset);
+
+            /* Ensure coordinates are within client bounds */
+            coords_offs.x = max(min(x, infoPtr->rcList.right), 0);
+            coords_offs.y = max(min(y, infoPtr->rcList.bottom), 0);
+
+            /* Offset coordinates by the appropriate amount */
+            coords_offs.x -= offset.x;
+            coords_offs.y -= offset.y;
+
+            /* Enable the timer if we're going outside our bounds, in case the user doesn't
+               move the mouse again */
+
+            if ((x <= 0) || (y <= 0) || (x >= infoPtr->rcList.right) ||
+                (y >= infoPtr->rcList.bottom))
+            {
+                if (!infoPtr->bScrolling)
+                {
+                    infoPtr->bScrolling = TRUE;
+                    SetTimer(infoPtr->hwndSelf, (UINT_PTR) infoPtr, 1, LISTVIEW_ScrollTimer);
+                }
+            }
+            else
+            {
+                infoPtr->bScrolling = FALSE;
+                KillTimer(infoPtr->hwndSelf, (UINT_PTR) infoPtr);
+            }
+
+            LISTVIEW_MarqueeHighlight(infoPtr, &coords_orig, &coords_offs, &offset, 0);
+            return 0;
+        }
+
+        rect.left = infoPtr->ptClickPos.x - wDragWidth;
+        rect.right = infoPtr->ptClickPos.x + wDragWidth;
+        rect.top = infoPtr->ptClickPos.y - wDragHeight;
+        rect.bottom = infoPtr->ptClickPos.y + wDragHeight;
+
+        tmp.x = x;
+        tmp.y = y;
+
+        lvHitTestInfo.pt = tmp;
+        LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, TRUE);
 
         /* reset item marker */
         if (infoPtr->nLButtonDownItem != lvHitTestInfo.iItem)
@@ -3640,17 +4015,42 @@ static LRESULT LISTVIEW_MouseMove(LISTVIEW_INFO *infoPtr, WORD fwKeys, INT x, IN
 
             if (!infoPtr->bDragging)
             {
-                NMLISTVIEW nmlv;
-
                 lvHitTestInfo.pt = infoPtr->ptClickPos;
                 LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, TRUE);
 
-                ZeroMemory(&nmlv, sizeof(nmlv));
-                nmlv.iItem = lvHitTestInfo.iItem;
-                nmlv.ptAction = infoPtr->ptClickPos;
+                /* If the click is outside the range of an item, begin a
+                   highlight. If not, begin an item drag. */
+                if (lvHitTestInfo.iItem == -1)
+                {
+                    NMHDR hdr;
+
+                    /* If we're allowing multiple selections, send notification.
+                       If return value is non-zero, cancel. */
+                    if (!(infoPtr->dwStyle & LVS_SINGLESEL) && (notify_hdr(infoPtr, LVN_MARQUEEBEGIN, &hdr) == 0))
+                    {
+                        /* Store the absolute coordinates of the click */
+                        POINT offset;
+                        LISTVIEW_GetOrigin(infoPtr, &offset);
+
+                        infoPtr->marqueeOrigin.x = infoPtr->ptClickPos.x - offset.x;
+                        infoPtr->marqueeOrigin.y = infoPtr->ptClickPos.y - offset.y;
+
+                        /* Begin selection and capture mouse */
+                        infoPtr->bMarqueeSelect = TRUE;
+                        SetCapture(infoPtr->hwndSelf);
+                    }
+                }
+                else
+                {
+                    NMLISTVIEW nmlv;
+
+                    ZeroMemory(&nmlv, sizeof(nmlv));
+                    nmlv.iItem = lvHitTestInfo.iItem;
+                    nmlv.ptAction = infoPtr->ptClickPos;
 
-                notify_listview(infoPtr, LVN_BEGINDRAG, &nmlv);
-                infoPtr->bDragging = TRUE;
+                    notify_listview(infoPtr, LVN_BEGINDRAG, &nmlv);
+                    infoPtr->bDragging = TRUE;
+                }
             }
 
             return 0;
@@ -3658,18 +4058,19 @@ static LRESULT LISTVIEW_MouseMove(LISTVIEW_INFO *infoPtr, WORD fwKeys, INT x, IN
     }
 
     /* see if we are supposed to be tracking mouse hovering */
-    if (LISTVIEW_isHotTracking(infoPtr)) {
-        /* fill in the trackinfo struct */
+    if (LISTVIEW_IsHotTracking(infoPtr)) {
+        TRACKMOUSEEVENT trackinfo;
+
         trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
         trackinfo.dwFlags = TME_QUERY;
-        trackinfo.hwndTrack = infoPtr->hwndSelf;
-        trackinfo.dwHoverTime = infoPtr->dwHoverTime;
 
         /* see if we are already tracking this hwnd */
         _TrackMouseEvent(&trackinfo);
 
-        if(!(trackinfo.dwFlags & TME_HOVER)) {
-            trackinfo.dwFlags = TME_HOVER;
+        if(!(trackinfo.dwFlags & TME_HOVER) || trackinfo.hwndTrack != infoPtr->hwndSelf) {
+            trackinfo.dwFlags     = TME_HOVER;
+            trackinfo.dwHoverTime = infoPtr->dwHoverTime;
+            trackinfo.hwndTrack   = infoPtr->hwndSelf;
 
             /* call TRACKMOUSEEVENT so we receive WM_MOUSEHOVER messages */
             _TrackMouseEvent(&trackinfo);
@@ -3914,12 +4315,11 @@ static BOOL set_sub_item(const LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem,
        *bChanged = TRUE;
     }
     
-    if (lpLVItem->mask & LVIF_IMAGE)
-       if (lpSubItem->hdr.iImage != lpLVItem->iImage)
-       {
-           lpSubItem->hdr.iImage = lpLVItem->iImage;
-           *bChanged = TRUE;
-       }
+    if ((lpLVItem->mask & LVIF_IMAGE) && (lpSubItem->hdr.iImage != lpLVItem->iImage))
+    {
+        lpSubItem->hdr.iImage = lpLVItem->iImage;
+        *bChanged = TRUE;
+    }
 
     if ((lpLVItem->mask & LVIF_TEXT) && textcmpWT(lpSubItem->hdr.pszText, lpLVItem->pszText, isW))
     {
@@ -3955,7 +4355,7 @@ static BOOL LISTVIEW_SetItemT(LISTVIEW_INFO *infoPtr, LVITEMW *lpLVItem, BOOL is
        return FALSE;
 
     /* For efficiency, we transform the lpLVItem->pszText to Unicode here */
-    if ((lpLVItem->mask & LVIF_TEXT) && is_textW(lpLVItem->pszText))
+    if ((lpLVItem->mask & LVIF_TEXT) && is_text(lpLVItem->pszText))
     {
        pszText = lpLVItem->pszText;
        lpLVItem->pszText = textdupTtoW(lpLVItem->pszText, isW);
@@ -4089,7 +4489,7 @@ static BOOL LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, INT nS
     lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
     if (nSubItem == 0) lvItem.mask |= LVIF_STATE;
     if (infoPtr->uView == LV_VIEW_DETAILS) lvItem.mask |= LVIF_INDENT;
-    lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED | LVIS_STATEIMAGEMASK;
+    lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED | LVIS_STATEIMAGEMASK | LVIS_CUT;
     lvItem.iItem = nItem;
     lvItem.iSubItem = nSubItem;
     lvItem.state = 0;
@@ -4192,14 +4592,23 @@ static BOOL LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, INT nS
        }
     }
 
-    /* small icons */
+    /* item icons */
     himl = (infoPtr->uView == LV_VIEW_ICON ? infoPtr->himlNormal : infoPtr->himlSmall);
     if (himl && lvItem.iImage >= 0 && !IsRectEmpty(&rcIcon))
     {
+        UINT style;
+
         TRACE("iImage=%d\n", lvItem.iImage);
+
+        if (lvItem.state & (LVIS_SELECTED | LVIS_CUT) && infoPtr->bFocus)
+            style = ILD_SELECTED;
+        else
+            style = ILD_NORMAL;
+
         ImageList_DrawEx(himl, lvItem.iImage, hdc, rcIcon.left, rcIcon.top,
-                         rcIcon.right - rcIcon.left, rcIcon.bottom - rcIcon.top, infoPtr->clrBk, CLR_DEFAULT,
-                         (lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus) ? ILD_SELECTED : ILD_NORMAL);
+                         rcIcon.right - rcIcon.left, rcIcon.bottom - rcIcon.top, infoPtr->clrBk,
+                         lvItem.state & LVIS_CUT ? RGB(255, 255, 255) : CLR_DEFAULT,
+                         style);
     }
 
     /* Don't bother painting item being edited */
@@ -4643,6 +5052,14 @@ enddraw:
     if ((infoPtr->uView == LV_VIEW_DETAILS) && infoPtr->dwLvExStyle & LVS_EX_GRIDLINES)
         LISTVIEW_RefreshReportGrid(infoPtr, hdc);
 
+    /* Draw marquee rectangle if appropriate */
+    if (infoPtr->bMarqueeSelect)
+    {
+        SetBkColor(hdc, RGB(255, 255, 255));
+        SetTextColor(hdc, RGB(0, 0, 0));
+        DrawFocusRect(hdc, &infoPtr->marqueeDrawRect);
+    }
+
     if (cdmode & CDRF_NOTIFYPOSTPAINT)
        notify_postpaint(infoPtr, &nmlvcd);
 
@@ -4684,8 +5101,6 @@ enddraw:
 static DWORD LISTVIEW_ApproximateViewRect(const LISTVIEW_INFO *infoPtr, INT nItemCount,
                                             WORD wWidth, WORD wHeight)
 {
-  INT nItemCountPerColumn = 1;
-  INT nColumnCount = 0;
   DWORD dwViewRect = 0;
 
   if (nItemCount == -1)
@@ -4693,6 +5108,9 @@ static DWORD LISTVIEW_ApproximateViewRect(const LISTVIEW_INFO *infoPtr, INT nIte
 
   if (infoPtr->uView == LV_VIEW_LIST)
   {
+    INT nItemCountPerColumn = 1;
+    INT nColumnCount = 0;
+
     if (wHeight == 0xFFFF)
     {
       /* use current height */
@@ -4744,10 +5162,43 @@ static DWORD LISTVIEW_ApproximateViewRect(const LISTVIEW_INFO *infoPtr, INT nIte
 
     dwViewRect = MAKELONG(wWidth, wHeight);
   }
+  else if (infoPtr->uView == LV_VIEW_ICON)
+  {
+    UINT rows,cols;
+    UINT nItemWidth;
+    UINT nItemHeight;
+
+    nItemWidth = infoPtr->iconSpacing.cx;
+    nItemHeight = infoPtr->iconSpacing.cy;
+
+    if (wWidth == 0xffff)
+      wWidth = infoPtr->rcList.right - infoPtr->rcList.left;
+
+    if (wWidth < nItemWidth)
+      wWidth = nItemWidth;
+
+    cols = wWidth / nItemWidth;
+    if (cols > nItemCount)
+      cols = nItemCount;
+    if (cols < 1)
+        cols = 1;
+
+    if (nItemCount)
+    {
+      rows = nItemCount / cols;
+      if (nItemCount % cols)
+        rows++;
+    }
+    else
+      rows = 0;
+
+    wHeight = (nItemHeight * rows)+2;
+    wWidth = (nItemWidth * cols)+2;
+
+    dwViewRect = MAKELONG(wWidth, wHeight);
+  }
   else if (infoPtr->uView == LV_VIEW_SMALLICON)
     FIXME("uView == LV_VIEW_SMALLICON: not implemented\n");
-  else if (infoPtr->uView == LV_VIEW_ICON)
-    FIXME("uView == LV_VIEW_ICON: not implemented\n");
 
   return dwViewRect;
 }
@@ -4764,11 +5215,14 @@ static DWORD LISTVIEW_ApproximateViewRect(const LISTVIEW_INFO *infoPtr, INT nIte
  */
 static LRESULT LISTVIEW_CancelEditLabel(LISTVIEW_INFO *infoPtr)
 {
-    /* handle value will be lost after LISTVIEW_EndEditLabelT */
-    HWND edit = infoPtr->hwndEdit;
+    if (infoPtr->hwndEdit)
+    {
+        /* handle value will be lost after LISTVIEW_EndEditLabelT */
+        HWND edit = infoPtr->hwndEdit;
 
-    LISTVIEW_EndEditLabelT(infoPtr, TRUE, IsWindowUnicode(infoPtr->hwndEdit));
-    SendMessageW(edit, WM_CLOSE, 0, 0);
+        LISTVIEW_EndEditLabelT(infoPtr, TRUE, IsWindowUnicode(infoPtr->hwndEdit));
+        SendMessageW(edit, WM_CLOSE, 0, 0);
+    }
 
     return TRUE;
 }
@@ -4795,7 +5249,7 @@ static HIMAGELIST LISTVIEW_CreateDragImage(LISTVIEW_INFO *infoPtr, INT iItem, LP
     HIMAGELIST dragList = 0;
     TRACE("iItem=%d Count=%d\n", iItem, infoPtr->nItemCount);
 
-    if (iItem < 0 || iItem >= infoPtr->nItemCount)
+    if (iItem < 0 || iItem >= infoPtr->nItemCount || !lppt)
         return 0;
 
     rcItem.left = LVIR_BOUNDS;
@@ -4855,6 +5309,8 @@ static BOOL LISTVIEW_DeleteAllItems(LISTVIEW_INFO *infoPtr, BOOL destroy)
     HDPA hdpaSubItems = NULL;
     BOOL bSuppress;
     ITEMHDR *hdrItem;
+    ITEM_INFO *lpItem;
+    ITEM_ID *lpID;
     INT i, j;
 
     TRACE("()\n");
@@ -4876,14 +5332,21 @@ static BOOL LISTVIEW_DeleteAllItems(LISTVIEW_INFO *infoPtr, BOOL destroy)
     {
        if (!(infoPtr->dwStyle & LVS_OWNERDATA))
        {
-            /* send LVN_DELETEITEM notification, if not suppressed
-               and if it is not a virtual listview */
-            if (!bSuppress) notify_deleteitem(infoPtr, i);
-            hdpaSubItems = DPA_GetPtr(infoPtr->hdpaItems, i);
+           /* send LVN_DELETEITEM notification, if not suppressed
+              and if it is not a virtual listview */
+           if (!bSuppress) notify_deleteitem(infoPtr, i);
+           hdpaSubItems = DPA_GetPtr(infoPtr->hdpaItems, i);
+           lpItem = DPA_GetPtr(hdpaSubItems, 0);
+           /* free id struct */
+           j = DPA_GetPtrIndex(infoPtr->hdpaItemIds, lpItem->id);
+           lpID = DPA_GetPtr(infoPtr->hdpaItemIds, j);
+           DPA_DeletePtr(infoPtr->hdpaItemIds, j);
+           Free(lpID);
+           /* both item and subitem start with ITEMHDR header */
            for (j = 0; j < DPA_GetPtrCount(hdpaSubItems); j++)
            {
-                hdrItem = DPA_GetPtr(hdpaSubItems, j);
-               if (is_textW(hdrItem->pszText)) Free(hdrItem->pszText);
+               hdrItem = DPA_GetPtr(hdpaSubItems, j);
+               if (is_text(hdrItem->pszText)) Free(hdrItem->pszText);
                Free(hdrItem);
            }
            DPA_Destroy(hdpaSubItems);
@@ -5025,7 +5488,7 @@ static BOOL LISTVIEW_DeleteColumn(LISTVIEW_INFO *infoPtr, INT nColumn)
            if (nSubItem > 0)
            {
                /* free string */
-               if (is_textW(lpDelItem->hdr.pszText))
+               if (is_text(lpDelItem->hdr.pszText))
                    Free(lpDelItem->hdr.pszText);
 
                /* free item */
@@ -5174,7 +5637,7 @@ static BOOL LISTVIEW_DeleteItem(LISTVIEW_INFO *infoPtr, INT nItem)
        for (i = 0; i < DPA_GetPtrCount(hdpaSubItems); i++)
        {
             hdrItem = DPA_GetPtr(hdpaSubItems, i);
-           if (is_textW(hdrItem->pszText)) Free(hdrItem->pszText);
+           if (is_text(hdrItem->pszText)) Free(hdrItem->pszText);
             Free(hdrItem);
         }
         DPA_Destroy(hdpaSubItems);
@@ -5212,6 +5675,7 @@ static BOOL LISTVIEW_DeleteItem(LISTVIEW_INFO *infoPtr, INT nItem)
 static BOOL LISTVIEW_EndEditLabelT(LISTVIEW_INFO *infoPtr, BOOL storeText, BOOL isW)
 {
     HWND hwndSelf = infoPtr->hwndSelf;
+    WCHAR szDispText[DISP_TEXT_SIZE] = { 0 };
     NMLVDISPINFOW dispInfo;
     INT editedItem = infoPtr->nEditLabelItem;
     BOOL bSame;
@@ -5242,7 +5706,9 @@ static BOOL LISTVIEW_EndEditLabelT(LISTVIEW_INFO *infoPtr, BOOL storeText, BOOL
     dispInfo.item.iItem = editedItem;
     dispInfo.item.iSubItem = 0;
     dispInfo.item.stateMask = ~0;
-    if (!LISTVIEW_GetItemW(infoPtr, &dispInfo.item))
+    dispInfo.item.pszText = szDispText;
+    dispInfo.item.cchTextMax = DISP_TEXT_SIZE;
+    if (!LISTVIEW_GetItemT(infoPtr, &dispInfo.item, isW))
     {
        res = FALSE;
        goto cleanup;
@@ -5256,16 +5722,11 @@ static BOOL LISTVIEW_EndEditLabelT(LISTVIEW_INFO *infoPtr, BOOL storeText, BOOL
         bSame = (lstrcmpW(dispInfo.item.pszText, tmp) == 0);
         textfreeT(tmp, FALSE);
     }
-    if (bSame)
-    {
-        res = TRUE;
-        goto cleanup;
-    }
 
     /* add the text from the edit in */
     dispInfo.item.mask |= LVIF_TEXT;
-    dispInfo.item.pszText = pszText;
-    dispInfo.item.cchTextMax = textlenT(pszText, isW);
+    dispInfo.item.pszText = bSame ? NULL : pszText;
+    dispInfo.item.cchTextMax = bSame ? 0 : textlenT(pszText, isW);
 
     /* Do we need to update the Item Text */
     if (!notify_dispinfoT(infoPtr, LVN_ENDLABELEDITW, &dispInfo, isW))
@@ -5279,6 +5740,11 @@ static BOOL LISTVIEW_EndEditLabelT(LISTVIEW_INFO *infoPtr, BOOL storeText, BOOL
        goto cleanup;
     }
     if (!pszText) return TRUE;
+    if (bSame)
+    {
+        res = TRUE;
+        goto cleanup;
+    }
 
     if (!(infoPtr->dwStyle & LVS_OWNERDATA))
     {
@@ -5306,6 +5772,134 @@ cleanup:
     return res;
 }
 
+/***
+ * DESCRIPTION:
+ * Subclassed edit control windproc function
+ *
+ * PARAMETER(S):
+ * [I] hwnd : the edit window handle
+ * [I] uMsg : the message that is to be processed
+ * [I] wParam : first message parameter
+ * [I] lParam : second message parameter
+ * [I] isW : TRUE if input is Unicode
+ *
+ * RETURN:
+ *   Zero.
+ */
+static LRESULT EditLblWndProcT(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL isW)
+{
+    LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongPtrW(GetParent(hwnd), 0);
+    BOOL save = TRUE;
+
+    TRACE("(hwnd=%p, uMsg=%x, wParam=%lx, lParam=%lx, isW=%d)\n",
+         hwnd, uMsg, wParam, lParam, isW);
+
+    switch (uMsg)
+    {
+       case WM_GETDLGCODE:
+         return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
+
+       case WM_DESTROY:
+       {
+           WNDPROC editProc = infoPtr->EditWndProc;
+           infoPtr->EditWndProc = 0;
+           SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (DWORD_PTR)editProc);
+           return CallWindowProcT(editProc, hwnd, uMsg, wParam, lParam, isW);
+       }
+
+       case WM_KEYDOWN:
+           if (VK_ESCAPE == (INT)wParam)
+           {
+               save = FALSE;
+                break;
+           }
+           else if (VK_RETURN == (INT)wParam)
+               break;
+
+       default:
+           return CallWindowProcT(infoPtr->EditWndProc, hwnd, uMsg, wParam, lParam, isW);
+    }
+
+    /* kill the edit */
+    if (infoPtr->hwndEdit)
+       LISTVIEW_EndEditLabelT(infoPtr, save, isW);
+
+    SendMessageW(hwnd, WM_CLOSE, 0, 0);
+    return 0;
+}
+
+/***
+ * DESCRIPTION:
+ * Subclassed edit control Unicode windproc function
+ *
+ * PARAMETER(S):
+ * [I] hwnd : the edit window handle
+ * [I] uMsg : the message that is to be processed
+ * [I] wParam : first message parameter
+ * [I] lParam : second message parameter
+ *
+ * RETURN:
+ */
+static LRESULT CALLBACK EditLblWndProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+    return EditLblWndProcT(hwnd, uMsg, wParam, lParam, TRUE);
+}
+
+/***
+ * DESCRIPTION:
+ * Subclassed edit control ANSI windproc function
+ *
+ * PARAMETER(S):
+ * [I] hwnd : the edit window handle
+ * [I] uMsg : the message that is to be processed
+ * [I] wParam : first message parameter
+ * [I] lParam : second message parameter
+ *
+ * RETURN:
+ */
+static LRESULT CALLBACK EditLblWndProcA(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+    return EditLblWndProcT(hwnd, uMsg, wParam, lParam, FALSE);
+}
+
+/***
+ * DESCRIPTION:
+ * Creates a subclassed edit control
+ *
+ * PARAMETER(S):
+ * [I] infoPtr : valid pointer to the listview structure
+ * [I] text : initial text for the edit
+ * [I] style : the window style
+ * [I] isW : TRUE if input is Unicode
+ *
+ * RETURN:
+ */
+static HWND CreateEditLabelT(LISTVIEW_INFO *infoPtr, LPCWSTR text, BOOL isW)
+{
+    static const DWORD style = WS_CHILDWINDOW|WS_CLIPSIBLINGS|ES_LEFT|ES_AUTOHSCROLL|WS_BORDER|WS_VISIBLE;
+    HINSTANCE hinst = (HINSTANCE)GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_HINSTANCE);
+    HWND hedit;
+
+    TRACE("(%p, text=%s, isW=%d)\n", infoPtr, debugtext_t(text, isW), isW);
+
+    /* window will be resized and positioned after LVN_BEGINLABELEDIT */
+    if (isW)
+       hedit = CreateWindowW(WC_EDITW, text, style, 0, 0, 0, 0, infoPtr->hwndSelf, 0, hinst, 0);
+    else
+       hedit = CreateWindowA(WC_EDITA, (LPCSTR)text, style, 0, 0, 0, 0, infoPtr->hwndSelf, 0, hinst, 0);
+
+    if (!hedit) return 0;
+
+    infoPtr->EditWndProc = (WNDPROC)
+       (isW ? SetWindowLongPtrW(hedit, GWLP_WNDPROC, (DWORD_PTR)EditLblWndProcW) :
+               SetWindowLongPtrA(hedit, GWLP_WNDPROC, (DWORD_PTR)EditLblWndProcA) );
+
+    SendMessageW(hedit, WM_SETFONT, (WPARAM)infoPtr->hFont, FALSE);
+    SendMessageW(hedit, EM_SETLIMITTEXT, DISP_TEXT_SIZE-1, 0);
+
+    return hedit;
+}
+
 /***
  * DESCRIPTION:
  * Begin in place editing of specified list view item
@@ -5321,21 +5915,21 @@ cleanup:
  */
 static HWND LISTVIEW_EditLabelT(LISTVIEW_INFO *infoPtr, INT nItem, BOOL isW)
 {
-    WCHAR szDispText[DISP_TEXT_SIZE] = { 0 };
+    WCHAR disptextW[DISP_TEXT_SIZE] = { 0 };
+    HWND hwndSelf = infoPtr->hwndSelf;
     NMLVDISPINFOW dispInfo;
+    HFONT hOldFont = NULL;
+    TEXTMETRICW tm;
     RECT rect;
     SIZE sz;
-    HWND hwndSelf = infoPtr->hwndSelf;
     HDC hdc;
-    HFONT hOldFont = NULL;
-    TEXTMETRICW textMetric;
 
     TRACE("(nItem=%d, isW=%d)\n", nItem, isW);
 
     if (~infoPtr->dwStyle & LVS_EDITLABELS) return 0;
 
-    /* Is the EditBox still there, if so remove it */
-    if(infoPtr->hwndEdit != 0)
+    /* remove existing edit box */
+    if (infoPtr->hwndEdit)
     {
         SetFocus(infoPtr->hwndSelf);
         infoPtr->hwndEdit = 0;
@@ -5357,11 +5951,11 @@ static HWND LISTVIEW_EditLabelT(LISTVIEW_INFO *infoPtr, INT nItem, BOOL isW)
     dispInfo.item.iItem = nItem;
     dispInfo.item.iSubItem = 0;
     dispInfo.item.stateMask = ~0;
-    dispInfo.item.pszText = szDispText;
+    dispInfo.item.pszText = disptextW;
     dispInfo.item.cchTextMax = DISP_TEXT_SIZE;
     if (!LISTVIEW_GetItemT(infoPtr, &dispInfo.item, isW)) return 0;
 
-    infoPtr->hwndEdit = CreateEditLabelT(infoPtr, dispInfo.item.pszText, WS_VISIBLE, isW);
+    infoPtr->hwndEdit = CreateEditLabelT(infoPtr, dispInfo.item.pszText, isW);
     if (!infoPtr->hwndEdit) return 0;
     
     if (notify_dispinfoT(infoPtr, LVN_BEGINLABELEDITW, &dispInfo, isW))
@@ -5373,27 +5967,36 @@ static HWND LISTVIEW_EditLabelT(LISTVIEW_INFO *infoPtr, INT nItem, BOOL isW)
        return 0;
     }
 
-    /* Now position and display edit box */
+    TRACE("disp text=%s\n", debugtext_t(dispInfo.item.pszText, isW));
+
+    /* position and display edit box */
     hdc = GetDC(infoPtr->hwndSelf);
 
-    /* Select the font to get appropriate metric dimensions */
-    if(infoPtr->hFont != 0)
+    /* select the font to get appropriate metric dimensions */
+    if (infoPtr->hFont)
         hOldFont = SelectObject(hdc, infoPtr->hFont);
 
-    /* Get String Length in pixels */
-    GetTextExtentPoint32W(hdc, dispInfo.item.pszText, lstrlenW(dispInfo.item.pszText), &sz);
+    /* use real edit box content, it could be altered during LVN_BEGINLABELEDIT notification */
+    GetWindowTextW(infoPtr->hwndEdit, disptextW, DISP_TEXT_SIZE);
+    TRACE("edit box text=%s\n", debugstr_w(disptextW));
+
+    /* get string length in pixels */
+    GetTextExtentPoint32W(hdc, disptextW, lstrlenW(disptextW), &sz);
 
-    /* Add Extra spacing for the next character */
-    GetTextMetricsW(hdc, &textMetric);
-    sz.cx += (textMetric.tmMaxCharWidth * 2);
+    /* add extra spacing for the next character */
+    GetTextMetricsW(hdc, &tm);
+    sz.cx += tm.tmMaxCharWidth * 2;
 
-    if(infoPtr->hFont != 0)
+    if (infoPtr->hFont)
         SelectObject(hdc, hOldFont);
 
     ReleaseDC(infoPtr->hwndSelf, hdc);
 
-    MoveWindow(infoPtr->hwndEdit, rect.left - 2, rect.top - 1, sz.cx,
-                                  rect.bottom - rect.top + 2, FALSE);
+    sz.cy = rect.bottom - rect.top + 2;
+    rect.left -= 2;
+    rect.top  -= 1;
+    TRACE("moving edit=(%d,%d)-(%d,%d)\n", rect.left, rect.top, sz.cx, sz.cy);
+    MoveWindow(infoPtr->hwndEdit, rect.left, rect.top, sz.cx, sz.cy, FALSE);
     ShowWindow(infoPtr->hwndEdit, SW_NORMAL);
     SetFocus(infoPtr->hwndEdit);
     SendMessageW(infoPtr->hwndEdit, EM_SETSEL, 0, -1);
@@ -5475,14 +6078,14 @@ static BOOL LISTVIEW_EnsureVisible(LISTVIEW_INFO *infoPtr, INT nItem, BOOL bPart
     {
        INT diff = nHorzDiff / nScrollPosWidth;
        if (nHorzDiff % nScrollPosWidth) diff += nHorzAdjust;
-       LISTVIEW_HScroll(infoPtr, SB_INTERNAL, diff, 0);
+       LISTVIEW_HScroll(infoPtr, SB_INTERNAL, diff);
     }
 
     if (nScrollPosHeight)
     {
        INT diff = nVertDiff / nScrollPosHeight;
        if (nVertDiff % nScrollPosHeight) diff += nVertAdjust;
-       LISTVIEW_VScroll(infoPtr, SB_INTERNAL, diff, 0);
+       LISTVIEW_VScroll(infoPtr, SB_INTERNAL, diff);
     }
 
     return TRUE;
@@ -5523,9 +6126,10 @@ static INT LISTVIEW_FindItemW(const LISTVIEW_INFO *infoPtr, INT nStart,
     }
 
     if (!lpFindInfo || nItem < 0) return -1;
-    
+
     lvItem.mask = 0;
-    if (lpFindInfo->flags & (LVFI_STRING | LVFI_PARTIAL))
+    if (lpFindInfo->flags & (LVFI_STRING | LVFI_PARTIAL) ||
+        lpFindInfo->flags &  LVFI_SUBSTRING)
     {
         lvItem.mask |= LVIF_TEXT;
         lvItem.pszText = szDispText;
@@ -5586,12 +6190,13 @@ again:
             else
                 continue;
         }
-       
+
         if (lvItem.mask & LVIF_TEXT)
        {
-            if (lpFindInfo->flags & LVFI_PARTIAL)
+            if (lpFindInfo->flags & (LVFI_PARTIAL | LVFI_SUBSTRING))
             {
-               if (strstrW(lvItem.pszText, lpFindInfo->psz) == NULL) continue;
+               WCHAR *p = strstrW(lvItem.pszText, lpFindInfo->psz);
+               if (!p || p != lvItem.pszText) continue;
             }
             else
             {
@@ -5600,7 +6205,7 @@ again:
        }
 
         if (!bNearest) return nItem;
-       
+
        /* This is very inefficient. To do a good job here,
         * we need a sorted array of (x,y) item positions */
        LISTVIEW_GetItemOrigin(infoPtr, nItem, &Position);
@@ -5645,35 +6250,18 @@ again:
 static INT LISTVIEW_FindItemA(const LISTVIEW_INFO *infoPtr, INT nStart,
                               const LVFINDINFOA *lpFindInfo)
 {
-    BOOL hasText = lpFindInfo->flags & (LVFI_STRING | LVFI_PARTIAL);
+    BOOL hasText = lpFindInfo->flags & (LVFI_STRING | LVFI_PARTIAL) ||
+                   lpFindInfo->flags &  LVFI_SUBSTRING;
     LVFINDINFOW fiw;
     INT res;
     LPWSTR strW = NULL;
 
     memcpy(&fiw, lpFindInfo, sizeof(fiw));
-    if (hasText) fiw.psz = strW = textdupTtoW((LPCWSTR)lpFindInfo->psz, FALSE);
-    res = LISTVIEW_FindItemW(infoPtr, nStart, &fiw);
-    textfreeT(strW, FALSE);
-    return res;
-}
-
-/***
- * DESCRIPTION:
- * Retrieves the background image of the listview control.
- *
- * PARAMETER(S):
- * [I] infoPtr : valid pointer to the listview structure
- * [O] lpBkImage : background image attributes
- *
- * RETURN:
- *   SUCCESS : TRUE
- *   FAILURE : FALSE
- */
-/* static BOOL LISTVIEW_GetBkImage(const LISTVIEW_INFO *infoPtr, LPLVBKIMAGE lpBkImage)   */
-/* {   */
-/*   FIXME (listview, "empty stub!\n"); */
-/*   return FALSE;   */
-/* }   */
+    if (hasText) fiw.psz = strW = textdupTtoW((LPCWSTR)lpFindInfo->psz, FALSE);
+    res = LISTVIEW_FindItemW(infoPtr, nStart, &fiw);
+    textfreeT(strW, FALSE);
+    return res;
+}
 
 /***
  * DESCRIPTION:
@@ -5842,8 +6430,13 @@ static HIMAGELIST LISTVIEW_GetImageList(const LISTVIEW_INFO *infoPtr, INT nImage
     switch (nImageList)
     {
     case LVSIL_NORMAL: return infoPtr->himlNormal;
-    case LVSIL_SMALL: return infoPtr->himlSmall;
-    case LVSIL_STATE: return infoPtr->himlState;
+    case LVSIL_SMALL:  return infoPtr->himlSmall;
+    case LVSIL_STATE:  return infoPtr->himlState;
+    case LVSIL_GROUPHEADER:
+        FIXME("LVSIL_GROUPHEADER not supported\n");
+        break;
+    default:
+        WARN("got unknown imagelist index - %d\n", nImageList);
     }
     return NULL;
 }
@@ -5892,6 +6485,7 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem,
        return FALSE;
 
     if (lpLVItem->mask == 0) return TRUE;
+    TRACE("mask=%x\n", lpLVItem->mask);
 
     /* make a local copy */
     isubitem = lpLVItem->iSubItem;
@@ -5940,7 +6534,7 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem,
            if (lpLVItem->mask & LVIF_STATE)
                dispInfo.item.stateMask = lpLVItem->stateMask & infoPtr->uCallbackMask;
            /* could be zeroed on LVIF_NORECOMPUTE case */
-           if (dispInfo.item.mask != 0)
+           if (dispInfo.item.mask)
            {
                notify_dispinfoT(infoPtr, LVN_GETDISPINFOW, &dispInfo, isW);
                dispInfo.item.stateMask = lpLVItem->stateMask;
@@ -6000,7 +6594,7 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem,
 
     if (isubitem)
     {
-       SUBITEM_INFO *lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, isubitem);
+        SUBITEM_INFO *lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, isubitem);
         pItemHdr = lpSubItem ? &lpSubItem->hdr : &callbackHdr;
         if (!lpSubItem)
         {
@@ -6036,7 +6630,7 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem,
 
     /* Apps depend on calling back for text if it is NULL or LPSTR_TEXTCALLBACKW */
     if ((lpLVItem->mask & LVIF_TEXT) && !(lpLVItem->mask & LVIF_NORECOMPUTE) &&
-        !is_textW(pItemHdr->pszText))
+        !is_text(pItemHdr->pszText))
     {
        dispInfo.item.mask |= LVIF_TEXT;
        dispInfo.item.pszText = lpLVItem->pszText;
@@ -6046,7 +6640,7 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem,
     }
 
     /* If we don't have all the requested info, query the application */
-    if (dispInfo.item.mask != 0)
+    if (dispInfo.item.mask)
     {
        dispInfo.item.iItem = lpLVItem->iItem;
        dispInfo.item.iSubItem = lpLVItem->iSubItem; /* yes: the original subitem */
@@ -6084,7 +6678,7 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem,
     else if (lpLVItem->mask & LVIF_TEXT)
     {
        /* if LVN_GETDISPINFO's disabled with LVIF_NORECOMPUTE return callback placeholder */
-       if (isW || !is_textW(pItemHdr->pszText)) lpLVItem->pszText = pItemHdr->pszText;
+       if (isW || !is_text(pItemHdr->pszText)) lpLVItem->pszText = pItemHdr->pszText;
        else textcpynT(lpLVItem->pszText, isW, pItemHdr->pszText, TRUE, lpLVItem->cchTextMax);
     }
 
@@ -6167,7 +6761,7 @@ static BOOL LISTVIEW_GetItemExtT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVIte
 
     pszText = lpLVItem->pszText;
     bResult = LISTVIEW_GetItemT(infoPtr, lpLVItem, isW);
-    if (bResult && lpLVItem->pszText != pszText)
+    if (bResult && (lpLVItem->mask & LVIF_TEXT) && lpLVItem->pszText != pszText)
     {
        if (lpLVItem->pszText != LPSTR_TEXTCALLBACKW)
            textcpynT(pszText, isW, lpLVItem->pszText, isW, lpLVItem->cchTextMax);
@@ -6384,7 +6978,7 @@ static BOOL LISTVIEW_GetItemRect(const LISTVIEW_INFO *infoPtr, INT nItem, LPRECT
  */
 static BOOL LISTVIEW_GetSubItemRect(const LISTVIEW_INFO *infoPtr, INT nItem, LPRECT lprc)
 {
-    POINT Position;
+    POINT Position, Origin;
     LVITEMW lvItem;
     INT nColumn;
     
@@ -6392,7 +6986,7 @@ static BOOL LISTVIEW_GetSubItemRect(const LISTVIEW_INFO *infoPtr, INT nItem, LPR
 
     nColumn = lprc->top;
 
-    TRACE("(nItem=%d, nSubItem=%d)\n", nItem, lprc->top);
+    TRACE("(nItem=%d, nSubItem=%d, type=%d)\n", nItem, lprc->top, lprc->left);
     /* On WinNT, a subitem of '0' calls LISTVIEW_GetItemRect */
     if (lprc->top == 0)
         return LISTVIEW_GetItemRect(infoPtr, nItem, lprc);
@@ -6418,6 +7012,7 @@ static BOOL LISTVIEW_GetSubItemRect(const LISTVIEW_INFO *infoPtr, INT nItem, LPR
     }
 
     if (!LISTVIEW_GetItemPosition(infoPtr, nItem, &Position)) return FALSE;
+    LISTVIEW_GetOrigin(infoPtr, &Origin);
 
     if (nColumn < 0 || nColumn >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return FALSE;
 
@@ -6425,7 +7020,6 @@ static BOOL LISTVIEW_GetSubItemRect(const LISTVIEW_INFO *infoPtr, INT nItem, LPR
     lvItem.iItem = nItem;
     lvItem.iSubItem = nColumn;
     
-    if (lvItem.mask && !LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE;
     switch(lprc->left)
     {
     case LVIR_ICON:
@@ -6442,37 +7036,10 @@ static BOOL LISTVIEW_GetSubItemRect(const LISTVIEW_INFO *infoPtr, INT nItem, LPR
        return FALSE;
     }
 
-    OffsetRect(lprc, 0, Position.y);
-    return TRUE;
-}
-
-
-/***
- * DESCRIPTION:
- * Retrieves the width of a label.
- *
- * PARAMETER(S):
- * [I] infoPtr : valid pointer to the listview structure
- *
- * RETURN:
- *   SUCCESS : string width (in pixels)
- *   FAILURE : zero
- */
-static INT LISTVIEW_GetLabelWidth(const LISTVIEW_INFO *infoPtr, INT nItem)
-{
-    WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
-    LVITEMW lvItem;
-
-    TRACE("(nItem=%d)\n", nItem);
+    OffsetRect(lprc, Origin.x, Position.y);
+    TRACE("return rect %s\n", wine_dbgstr_rect(lprc));
 
-    lvItem.mask = LVIF_TEXT;
-    lvItem.iItem = nItem;
-    lvItem.iSubItem = 0;
-    lvItem.pszText = szDispText;
-    lvItem.cchTextMax = DISP_TEXT_SIZE;
-    if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return 0;
-  
-    return LISTVIEW_GetStringWidthT(infoPtr, lvItem.pszText, TRUE);
+    return TRUE;
 }
 
 /***
@@ -6818,7 +7385,7 @@ static INT LISTVIEW_GetStringWidthT(const LISTVIEW_INFO *infoPtr, LPCWSTR lpszTe
     SIZE stringSize;
     
     stringSize.cx = 0;    
-    if (is_textT(lpszText, isW))
+    if (is_text(lpszText))
     {
        HFONT hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
        HDC hdc = GetDC(infoPtr->hwndSelf);
@@ -6918,6 +7485,14 @@ static INT LISTVIEW_HitTest(const LISTVIEW_INFO *infoPtr, LPLVHITTESTINFO lpht,
            }
        }
        TRACE("lpht->iSubItem=%d\n", lpht->iSubItem);
+
+       /* if we're outside horizontal columns bounds there's nothing to test further */
+       if (lpht->iSubItem == -1)
+       {
+           lpht->iItem = -1;
+           lpht->flags = LVHT_NOWHERE;
+           return -1;
+       }
     }
 
     TRACE("lpht->flags=0x%x\n", lpht->flags);
@@ -7067,9 +7642,9 @@ static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem,
         while (i < infoPtr->nItemCount)
         {
             hItem  = DPA_GetPtr( infoPtr->hdpaItems, i);
-            item_s = (ITEM_INFO*)DPA_GetPtr(hItem, 0);
+            item_s = DPA_GetPtr(hItem, 0);
 
-            cmpv = textcmpWT(item_s->hdr.pszText, lpLVItem->pszText, TRUE);
+            cmpv = textcmpWT(item_s->hdr.pszText, lpLVItem->pszText, isW);
             if (infoPtr->dwStyle & LVS_SORTDESCENDING) cmpv *= -1;
 
             if (cmpv >= 0) break;
@@ -7275,8 +7850,8 @@ static BOOL LISTVIEW_Scroll(LISTVIEW_INFO *infoPtr, INT dx, INT dy)
        break;
     }  
 
-    if (dx != 0) LISTVIEW_HScroll(infoPtr, SB_INTERNAL, dx, 0);
-    if (dy != 0) LISTVIEW_VScroll(infoPtr, SB_INTERNAL, dy, 0);
+    if (dx != 0) LISTVIEW_HScroll(infoPtr, SB_INTERNAL, dx);
+    if (dy != 0) LISTVIEW_VScroll(infoPtr, SB_INTERNAL, dy);
   
     return TRUE;
 }
@@ -7297,6 +7872,7 @@ static BOOL LISTVIEW_SetBkColor(LISTVIEW_INFO *infoPtr, COLORREF clrBk)
 {
     TRACE("(clrBk=%x)\n", clrBk);
 
+    infoPtr->bDefaultBkColor = FALSE;
     if(infoPtr->clrBk != clrBk) {
        if (infoPtr->clrBk != CLR_NONE) DeleteObject(infoPtr->hBkBrush);
        infoPtr->clrBk = clrBk;
@@ -7451,7 +8027,7 @@ static INT LISTVIEW_InsertColumnT(LISTVIEW_INFO *infoPtr, INT nColumn,
     /* insert item in header control */
     nNewColumn = SendMessageW(infoPtr->hwndHeader, 
                              isW ? HDM_INSERTITEMW : HDM_INSERTITEMA,
-                              (WPARAM)nColumn, (LPARAM)&hdi);
+                              nColumn, (LPARAM)&hdi);
     if (nNewColumn == -1) return -1;
     if (nNewColumn != nColumn) ERR("nColumn=%d, nNewColumn=%d\n", nColumn, nNewColumn);
    
@@ -7470,7 +8046,14 @@ static INT LISTVIEW_InsertColumnT(LISTVIEW_INFO *infoPtr, INT nColumn,
        SUBITEM_INFO *lpSubItem;
        HDPA hdpaSubItems;
        INT nItem, i;
-       
+       LVITEMW item;
+       BOOL changed;
+
+       item.iSubItem = nNewColumn;
+       item.mask = LVIF_TEXT | LVIF_IMAGE;
+       item.iImage = I_IMAGECALLBACK;
+       item.pszText = LPSTR_TEXTCALLBACKW;
+
        for (nItem = 0; nItem < infoPtr->nItemCount; nItem++)
        {
             hdpaSubItems = DPA_GetPtr(infoPtr->hdpaItems, nItem);
@@ -7480,6 +8063,10 @@ static INT LISTVIEW_InsertColumnT(LISTVIEW_INFO *infoPtr, INT nColumn,
                if (lpSubItem->iSubItem >= nNewColumn)
                    lpSubItem->iSubItem++;
            }
+
+           /* add new subitem for each item */
+           item.iItem = nItem;
+           set_sub_item(infoPtr, &item, isW, &changed);
        }
     }
 
@@ -7534,7 +8121,7 @@ static BOOL LISTVIEW_SetColumnT(const LISTVIEW_INFO *infoPtr, INT nColumn,
     column_fill_hditem(infoPtr, &hdi, nColumn, lpColumn, isW);
 
     /* set header item attributes */
-    bResult = SendMessageW(infoPtr->hwndHeader, isW ? HDM_SETITEMW : HDM_SETITEMA, (WPARAM)nColumn, (LPARAM)&hdi);
+    bResult = SendMessageW(infoPtr->hwndHeader, isW ? HDM_SETITEMW : HDM_SETITEMA, nColumn, (LPARAM)&hdi);
     if (!bResult) return FALSE;
 
     if (lpColumn->mask & LVCF_FMT)
@@ -7774,10 +8361,18 @@ static DWORD LISTVIEW_SetExtendedListViewStyle(LISTVIEW_INFO *infoPtr, DWORD dwM
             LISTVIEW_SetItemState(infoPtr, -1, &item);
 
             himl = LISTVIEW_CreateCheckBoxIL(infoPtr);
+            if(!(infoPtr->dwStyle & LVS_SHAREIMAGELISTS))
+                ImageList_Destroy(infoPtr->himlState);
         }
-        LISTVIEW_SetImageList(infoPtr, LVSIL_STATE, himl);
+        himl = LISTVIEW_SetImageList(infoPtr, LVSIL_STATE, himl);
+        /*   checkbox list replaces prevous custom list or... */
+        if(((infoPtr->dwLvExStyle & LVS_EX_CHECKBOXES) &&
+           !(infoPtr->dwStyle & LVS_SHAREIMAGELISTS)) ||
+            /* ...previous was checkbox list */
+            (dwOldExStyle & LVS_EX_CHECKBOXES))
+            ImageList_Destroy(himl);
     }
-    
+
     if((infoPtr->dwLvExStyle ^ dwOldExStyle) & LVS_EX_HEADERDRAGDROP)
     {
         DWORD dwStyle;
@@ -7805,6 +8400,16 @@ static DWORD LISTVIEW_SetExtendedListViewStyle(LISTVIEW_INFO *infoPtr, DWORD dwM
             LISTVIEW_SetBkColor(infoPtr, CLR_NONE);
     }
 
+    if((infoPtr->dwLvExStyle ^ dwOldExStyle) & LVS_EX_HEADERINALLVIEWS)
+    {
+        if (infoPtr->dwLvExStyle & LVS_EX_HEADERINALLVIEWS)
+            LISTVIEW_CreateHeader(infoPtr);
+        else
+            ShowWindow(infoPtr->hwndHeader, SW_HIDE);
+        LISTVIEW_UpdateSize(infoPtr);
+        LISTVIEW_UpdateScroll(infoPtr);
+    }
+
     LISTVIEW_InvalidateList(infoPtr);
     return dwOldExStyle;
 }
@@ -8105,34 +8710,35 @@ static BOOL LISTVIEW_SetItemCount(LISTVIEW_INFO *infoPtr, INT nItems, DWORD dwFl
  *   SUCCESS : TRUE
  *   FAILURE : FALSE
  */
-static BOOL LISTVIEW_SetItemPosition(LISTVIEW_INFO *infoPtr, INT nItem, POINT pt)
+static BOOL LISTVIEW_SetItemPosition(LISTVIEW_INFO *infoPtr, INT nItem, const POINT *pt)
 {
-    POINT Origin;
+    POINT Origin, Pt;
 
-    TRACE("(nItem=%d, &pt=%s\n", nItem, wine_dbgstr_point(&pt));
+    TRACE("(nItem=%d, pt=%s\n", nItem, wine_dbgstr_point(pt));
 
-    if (nItem < 0 || nItem >= infoPtr->nItemCount ||
+    if (!pt || nItem < 0 || nItem >= infoPtr->nItemCount ||
        !(infoPtr->uView == LV_VIEW_ICON || infoPtr->uView == LV_VIEW_SMALLICON)) return FALSE;
 
+    Pt = *pt;
     LISTVIEW_GetOrigin(infoPtr, &Origin);
 
     /* This point value seems to be an undocumented feature.
      * The best guess is that it means either at the origin, 
      * or at true beginning of the list. I will assume the origin. */
-    if ((pt.x == -1) && (pt.y == -1))
-       pt = Origin;
+    if ((Pt.x == -1) && (Pt.y == -1))
+       Pt = Origin;
     
     if (infoPtr->uView == LV_VIEW_ICON)
     {
-       pt.x -= (infoPtr->nItemWidth - infoPtr->iconSize.cx) / 2;
-       pt.y -= ICON_TOP_PADDING;
+       Pt.x -= (infoPtr->nItemWidth - infoPtr->iconSize.cx) / 2;
+       Pt.y -= ICON_TOP_PADDING;
     }
-    pt.x -= Origin.x;
-    pt.y -= Origin.y;
+    Pt.x -= Origin.x;
+    Pt.y -= Origin.y;
 
     infoPtr->bAutoarrange = FALSE;
 
-    return LISTVIEW_MoveIconTo(infoPtr, nItem, &pt, FALSE);
+    return LISTVIEW_MoveIconTo(infoPtr, nItem, &Pt, FALSE);
 }
 
 /***
@@ -8310,10 +8916,10 @@ static HWND LISTVIEW_SetToolTips( LISTVIEW_INFO *infoPtr, HWND hwndNewToolTip)
  * RETURN:
  *    Old Unicode Format
  */
-static BOOL LISTVIEW_SetUnicodeFormat( LISTVIEW_INFO *infoPtr, BOOL fUnicode)
+static BOOL LISTVIEW_SetUnicodeFormat( LISTVIEW_INFO *infoPtr, BOOL unicode)
 {
   SHORT rc = infoPtr->notifyFormat;
-  infoPtr->notifyFormat = (fUnicode) ? NFR_UNICODE : NFR_ANSI;
+  infoPtr->notifyFormat = (unicode) ? NFR_UNICODE : NFR_ANSI;
   return rc == NFR_UNICODE;
 }
 
@@ -8659,6 +9265,7 @@ static LRESULT LISTVIEW_NCCreate(HWND hwnd, const CREATESTRUCTW *lpcs)
   infoPtr->clrText = CLR_DEFAULT;
   infoPtr->clrTextBk = CLR_DEFAULT;
   LISTVIEW_SetBkColor(infoPtr, comctl32_color.clrWindow);
+  infoPtr->bDefaultBkColor = TRUE;
 
   /* set default values */
   infoPtr->nFocusedItem = -1;
@@ -8671,7 +9278,7 @@ static LRESULT LISTVIEW_NCCreate(HWND hwnd, const CREATESTRUCTW *lpcs)
   infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING);
   infoPtr->nEditLabelItem = -1;
   infoPtr->nLButtonDownItem = -1;
-  infoPtr->dwHoverTime = -1; /* default system hover time */
+  infoPtr->dwHoverTime = HOVER_DEFAULT; /* default system hover time */
   infoPtr->nMeasureItemHeight = 0;
   infoPtr->xTrackLine = -1;  /* no track line */
   infoPtr->itemEdit.fEnabled = FALSE;
@@ -8728,9 +9335,10 @@ static LRESULT LISTVIEW_Create(HWND hwnd, const CREATESTRUCTW *lpcs)
   map_style_view(infoPtr);
 
   infoPtr->notifyFormat = SendMessageW(infoPtr->hwndNotify, WM_NOTIFYFORMAT,
-                                       (WPARAM)infoPtr->hwndSelf, (LPARAM)NF_QUERY);
+                                       (WPARAM)infoPtr->hwndSelf, NF_QUERY);
   /* on error defaulting to ANSI notifications */
   if (infoPtr->notifyFormat == 0) infoPtr->notifyFormat = NFR_ANSI;
+  TRACE("notify format=%d\n", infoPtr->notifyFormat);
 
   if ((infoPtr->uView == LV_VIEW_DETAILS) && (lpcs->style & WS_VISIBLE))
   {
@@ -8772,10 +9380,14 @@ static LRESULT LISTVIEW_Create(HWND hwnd, const CREATESTRUCTW *lpcs)
  *   Success: 0
  *   Failure: -1
  */
-static LRESULT LISTVIEW_Destroy(const LISTVIEW_INFO *infoPtr)
+static LRESULT LISTVIEW_Destroy(LISTVIEW_INFO *infoPtr)
 {
     HTHEME theme = GetWindowTheme(infoPtr->hwndSelf);
     CloseThemeData(theme);
+
+    /* delete all items */
+    LISTVIEW_DeleteAllItems(infoPtr, TRUE);
+
     return 0;
 }
 
@@ -8791,7 +9403,7 @@ static LRESULT LISTVIEW_Destroy(const LISTVIEW_INFO *infoPtr)
  *   SUCCESS : TRUE
  *   FAILURE : FALSE
  */
-static BOOL LISTVIEW_Enable(const LISTVIEW_INFO *infoPtr, BOOL bEnable)
+static BOOL LISTVIEW_Enable(const LISTVIEW_INFO *infoPtr)
 {
     if (infoPtr->dwStyle & LVS_OWNERDRAWFIXED)
         InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
@@ -8875,7 +9487,7 @@ static void scroll_list(LISTVIEW_INFO *infoPtr, INT dx, INT dy)
  *
  */
 static LRESULT LISTVIEW_VScroll(LISTVIEW_INFO *infoPtr, INT nScrollCode, 
-                               INT nScrollDiff, HWND hScrollWnd)
+                               INT nScrollDiff)
 {
     INT nOldScrollPos, nNewScrollPos;
     SCROLLINFO scrollInfo;
@@ -8979,7 +9591,7 @@ static LRESULT LISTVIEW_VScroll(LISTVIEW_INFO *infoPtr, INT nScrollCode,
  *
  */
 static LRESULT LISTVIEW_HScroll(LISTVIEW_INFO *infoPtr, INT nScrollCode,
-                                INT nScrollDiff, HWND hScrollWnd)
+                                INT nScrollDiff)
 {
     INT nOldScrollPos, nNewScrollPos;
     SCROLLINFO scrollInfo;
@@ -9045,37 +9657,32 @@ static LRESULT LISTVIEW_HScroll(LISTVIEW_INFO *infoPtr, INT nScrollCode,
     scrollInfo.fMask = SIF_POS;
     scrollInfo.nPos = nNewScrollPos;
     nNewScrollPos = SetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &scrollInfo, TRUE);
-    
+
     /* carry on only if it really changed */
     if (nNewScrollPos == nOldScrollPos) return 0;
-    
-    if (infoPtr->uView == LV_VIEW_DETAILS)
-        LISTVIEW_UpdateHeaderSize(infoPtr, nNewScrollPos);
-      
+
+    if (infoPtr->hwndHeader) LISTVIEW_UpdateHeaderSize(infoPtr, nNewScrollPos);
+
     /* now adjust to client coordinates */
     nScrollDiff = nOldScrollPos - nNewScrollPos;
     if (infoPtr->uView == LV_VIEW_LIST) nScrollDiff *= infoPtr->nItemWidth;
-   
+
     /* and scroll the window */
     scroll_list(infoPtr, nScrollDiff, 0);
 
-  return 0;
+    return 0;
 }
 
 static LRESULT LISTVIEW_MouseWheel(LISTVIEW_INFO *infoPtr, INT wheelDelta)
 {
     INT gcWheelDelta = 0;
     INT pulScrollLines = 3;
-    SCROLLINFO scrollInfo;
 
     TRACE("(wheelDelta=%d)\n", wheelDelta);
 
     SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
     gcWheelDelta -= wheelDelta;
 
-    scrollInfo.cbSize = sizeof(SCROLLINFO);
-    scrollInfo.fMask = SIF_POS;
-
     switch(infoPtr->uView)
     {
     case LV_VIEW_ICON:
@@ -9085,7 +9692,7 @@ static LRESULT LISTVIEW_MouseWheel(LISTVIEW_INFO *infoPtr, INT wheelDelta)
         *  should be fixed in the future.
         */
         LISTVIEW_VScroll(infoPtr, SB_INTERNAL, (gcWheelDelta < 0) ?
-                -LISTVIEW_SCROLL_ICON_LINE_SIZE : LISTVIEW_SCROLL_ICON_LINE_SIZE, 0);
+                -LISTVIEW_SCROLL_ICON_LINE_SIZE : LISTVIEW_SCROLL_ICON_LINE_SIZE);
         break;
 
     case LV_VIEW_DETAILS:
@@ -9093,12 +9700,12 @@ static LRESULT LISTVIEW_MouseWheel(LISTVIEW_INFO *infoPtr, INT wheelDelta)
         {
             int cLineScroll = min(LISTVIEW_GetCountPerColumn(infoPtr), pulScrollLines);
             cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
-            LISTVIEW_VScroll(infoPtr, SB_INTERNAL, cLineScroll, 0);
+            LISTVIEW_VScroll(infoPtr, SB_INTERNAL, cLineScroll);
         }
         break;
 
     case LV_VIEW_LIST:
-        LISTVIEW_HScroll(infoPtr, (gcWheelDelta < 0) ? SB_LINELEFT : SB_LINERIGHT, 0, 0);
+        LISTVIEW_HScroll(infoPtr, (gcWheelDelta < 0) ? SB_LINELEFT : SB_LINERIGHT, 0);
         break;
     }
     return 0;
@@ -9233,7 +9840,21 @@ static LRESULT LISTVIEW_KillFocus(LISTVIEW_INFO *infoPtr)
 
     /* if we have a focus rectangle, get rid of it */
     LISTVIEW_ShowFocusRect(infoPtr, FALSE);
-    
+
+    /* if have a marquee selection, stop it */
+    if (infoPtr->bMarqueeSelect)
+    {
+        /* Remove the marquee rectangle and release our mouse capture */
+        LISTVIEW_InvalidateRect(infoPtr, &infoPtr->marqueeRect);
+        ReleaseCapture();
+
+        SetRect(&infoPtr->marqueeRect, 0, 0, 0, 0);
+
+        infoPtr->bMarqueeSelect = FALSE;
+        infoPtr->bScrolling = FALSE;
+        KillTimer(infoPtr->hwndSelf, (UINT_PTR) infoPtr);
+    }
+
     /* set window focus flag */
     infoPtr->bFocus = FALSE;
 
@@ -9259,7 +9880,7 @@ static LRESULT LISTVIEW_LButtonDblClk(LISTVIEW_INFO *infoPtr, WORD wKey, INT x,
 {
     LVHITTESTINFO htInfo;
 
-    TRACE("(key=%hu, X=%hu, Y=%hu)\n", wKey, x, y);
+    TRACE("(key=%hu, X=%u, Y=%u)\n", wKey, x, y);
     
     /* Cancel the item edition if any */
     if (infoPtr->itemEdit.fEnabled)
@@ -9303,7 +9924,7 @@ static LRESULT LISTVIEW_LButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, IN
   POINT pt = { x, y };
   INT nItem;
 
-  TRACE("(key=%hu, X=%hu, Y=%hu)\n", wKey, x, y);
+  TRACE("(key=%hu, X=%u, Y=%u)\n", wKey, x, y);
 
   /* send NM_RELEASEDCAPTURE notification */
   if (!notify(infoPtr, NM_RELEASEDCAPTURE)) return 0;
@@ -9312,6 +9933,8 @@ static LRESULT LISTVIEW_LButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, IN
   infoPtr->bLButtonDown = TRUE;
   infoPtr->ptClickPos = pt;
   infoPtr->bDragging = FALSE;
+  infoPtr->bMarqueeSelect = FALSE;
+  infoPtr->bScrolling = FALSE;
 
   lvHitTestInfo.pt.x = x;
   lvHitTestInfo.pt.y = y;
@@ -9389,6 +10012,9 @@ static LRESULT LISTVIEW_LButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, IN
   }
   else
   {
+    if (!infoPtr->bFocus)
+        SetFocus(infoPtr->hwndSelf);
+
     /* remove all selections */
     if (!(wKey & MK_CONTROL) && !(wKey & MK_SHIFT))
         LISTVIEW_DeselectAll(infoPtr);
@@ -9414,7 +10040,7 @@ static LRESULT LISTVIEW_LButtonUp(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT
 {
     LVHITTESTINFO lvHitTestInfo;
     
-    TRACE("(key=%hu, X=%hu, Y=%hu)\n", wKey, x, y);
+    TRACE("(key=%hu, X=%u, Y=%u)\n", wKey, x, y);
 
     if (!infoPtr->bLButtonDown) return 0;
 
@@ -9433,9 +10059,23 @@ static LRESULT LISTVIEW_LButtonUp(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT
         LISTVIEW_SetSelection(infoPtr, infoPtr->nLButtonDownItem);
     infoPtr->nLButtonDownItem = -1;
 
-    if (infoPtr->bDragging)
+    if (infoPtr->bDragging || infoPtr->bMarqueeSelect)
     {
+        /* Remove the marquee rectangle and release our mouse capture */
+        if (infoPtr->bMarqueeSelect)
+        {
+            LISTVIEW_InvalidateRect(infoPtr, &infoPtr->marqueeDrawRect);
+            ReleaseCapture();
+        }
+
+        SetRect(&infoPtr->marqueeRect, 0, 0, 0, 0);
+        SetRect(&infoPtr->marqueeDrawRect, 0, 0, 0, 0);
+
         infoPtr->bDragging = FALSE;
+        infoPtr->bMarqueeSelect = FALSE;
+        infoPtr->bScrolling = FALSE;
+
+        KillTimer(infoPtr->hwndSelf, (UINT_PTR) infoPtr);
         return 0;
     }
 
@@ -9471,28 +10111,27 @@ static LRESULT LISTVIEW_LButtonUp(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT
  */
 static LRESULT LISTVIEW_NCDestroy(LISTVIEW_INFO *infoPtr)
 {
-  TRACE("()\n");
+  INT i;
 
-  /* delete all items */
-  LISTVIEW_DeleteAllItems(infoPtr, TRUE);
+  TRACE("()\n");
 
   /* destroy data structure */
   DPA_Destroy(infoPtr->hdpaItems);
   DPA_Destroy(infoPtr->hdpaItemIds);
   DPA_Destroy(infoPtr->hdpaPosX);
   DPA_Destroy(infoPtr->hdpaPosY);
+  /* columns */
+  for (i = 0; i < DPA_GetPtrCount(infoPtr->hdpaColumns); i++)
+      Free(DPA_GetPtr(infoPtr->hdpaColumns, i));
   DPA_Destroy(infoPtr->hdpaColumns);
   ranges_destroy(infoPtr->selectionRanges);
 
   /* destroy image lists */
   if (!(infoPtr->dwStyle & LVS_SHAREIMAGELISTS))
   {
-      if (infoPtr->himlNormal)
-         ImageList_Destroy(infoPtr->himlNormal);
-      if (infoPtr->himlSmall)
-         ImageList_Destroy(infoPtr->himlSmall);
-      if (infoPtr->himlState)
-         ImageList_Destroy(infoPtr->himlState);
+      ImageList_Destroy(infoPtr->himlNormal);
+      ImageList_Destroy(infoPtr->himlSmall);
+      ImageList_Destroy(infoPtr->himlState);
   }
 
   /* destroy font, bkgnd brush */
@@ -9510,26 +10149,32 @@ static LRESULT LISTVIEW_NCDestroy(LISTVIEW_INFO *infoPtr)
 
 /***
  * DESCRIPTION:
- * Handles notifications from header.
+ * Handles notifications.
  *
  * PARAMETER(S):
  * [I] infoPtr : valid pointer to the listview structure
- * [I] nCtrlId : control identifier
- * [I] lpnmh : notification information
+ * [I] lpnmhdr : notification information
  *
  * RETURN:
  * Zero
  */
-static LRESULT LISTVIEW_HeaderNotification(LISTVIEW_INFO *infoPtr, const NMHEADERW *lpnmh)
+static LRESULT LISTVIEW_Notify(LISTVIEW_INFO *infoPtr, const NMHDR *lpnmhdr)
 {
     HWND hwndSelf = infoPtr->hwndSelf;
+    const NMHEADERW *lpnmh;
     
-    TRACE("(lpnmh=%p)\n", lpnmh);
+    TRACE("(lpnmhdr=%p)\n", lpnmhdr);
 
-    if (!lpnmh || lpnmh->iItem < 0 || lpnmh->iItem >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return 0;
-    
-    switch (lpnmh->hdr.code)
-    {    
+    if (!lpnmhdr || lpnmhdr->hwndFrom != infoPtr->hwndHeader) return 0;
+
+    /* remember: HDN_LAST < HDN_FIRST */
+    if (lpnmhdr->code > HDN_FIRST || lpnmhdr->code < HDN_LAST) return 0;
+    lpnmh = (const NMHEADERW *)lpnmhdr;
+
+    if (lpnmh->iItem < 0 || lpnmh->iItem >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return 0;
+
+    switch (lpnmhdr->code)
+    {
        case HDN_TRACKW:
        case HDN_TRACKA:
        {
@@ -9675,6 +10320,9 @@ static LRESULT LISTVIEW_HeaderNotification(LISTVIEW_INFO *infoPtr, const NMHEADE
 
        case HDN_DIVIDERDBLCLICKW:
        case HDN_DIVIDERDBLCLICKA:
+            /* FIXME: for LVS_EX_HEADERINALLVIEWS and not LV_VIEW_DETAILS
+                      we should use LVSCW_AUTOSIZE_USEHEADER, helper rework or
+                      split needed for that */
             LISTVIEW_SetColumnWidth(infoPtr, lpnmh->iItem, LVSCW_AUTOSIZE);
             notify_forward_header(infoPtr, lpnmh);
             break;
@@ -9704,13 +10352,14 @@ static BOOL LISTVIEW_NCPaint(const LISTVIEW_INFO *infoPtr, HRGN region)
     int cxEdge = GetSystemMetrics (SM_CXEDGE),
         cyEdge = GetSystemMetrics (SM_CYEDGE);
 
-    if (!theme) return FALSE;
+    if (!theme)
+       return DefWindowProcW (infoPtr->hwndSelf, WM_NCPAINT, (WPARAM)region, 0);
 
     GetWindowRect(infoPtr->hwndSelf, &r);
 
     cliprgn = CreateRectRgn (r.left + cxEdge, r.top + cyEdge,
         r.right - cxEdge, r.bottom - cyEdge);
-    if (region != (HRGN)1)
+    if (region > (HRGN)1)
         CombineRgn (cliprgn, cliprgn, region, RGN_AND);
     OffsetRect(&r, -r.left, -r.top);
 
@@ -9725,7 +10374,7 @@ static BOOL LISTVIEW_NCPaint(const LISTVIEW_INFO *infoPtr, HRGN region)
     /* Call default proc to get the scrollbars etc. painted */
     DefWindowProcW (infoPtr->hwndSelf, WM_NCPAINT, (WPARAM)cliprgn, 0);
 
-    return TRUE;
+    return FALSE;
 }
 
 /***
@@ -9857,7 +10506,7 @@ static LRESULT LISTVIEW_RButtonDblClk(const LISTVIEW_INFO *infoPtr, WORD wKey, I
 {
     LVHITTESTINFO lvHitTestInfo;
     
-    TRACE("(key=%hu,X=%hu,Y=%hu)\n", wKey, x, y);
+    TRACE("(key=%hu,X=%u,Y=%u)\n", wKey, x, y);
 
     /* send NM_RELEASEDCAPTURE notification */
     if (!notify(infoPtr, NM_RELEASEDCAPTURE)) return 0;
@@ -9888,7 +10537,7 @@ static LRESULT LISTVIEW_RButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, IN
     LVHITTESTINFO lvHitTestInfo;
     INT nItem;
 
-    TRACE("(key=%hu,X=%hu,Y=%hu)\n", wKey, x, y);
+    TRACE("(key=%hu,X=%u,Y=%u)\n", wKey, x, y);
 
     /* send NM_RELEASEDCAPTURE notification */
     if (!notify(infoPtr, NM_RELEASEDCAPTURE)) return 0;
@@ -9936,7 +10585,7 @@ static LRESULT LISTVIEW_RButtonUp(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT
     LVHITTESTINFO lvHitTestInfo;
     POINT pt;
 
-    TRACE("(key=%hu,X=%hu,Y=%hu)\n", wKey, x, y);
+    TRACE("(key=%hu,X=%u,Y=%u)\n", wKey, x, y);
 
     if (!infoPtr->bRButtonDown) return 0;
  
@@ -9975,20 +10624,24 @@ static LRESULT LISTVIEW_RButtonUp(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT
  * TRUE if cursor is set
  * FALSE otherwise
  */
-static BOOL LISTVIEW_SetCursor(const LISTVIEW_INFO *infoPtr, HWND hwnd, UINT nHittest, UINT wMouseMsg)
+static BOOL LISTVIEW_SetCursor(const LISTVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
 {
     LVHITTESTINFO lvHitTestInfo;
 
-    if(!(LISTVIEW_isHotTracking(infoPtr))) return FALSE;
+    if (!LISTVIEW_IsHotTracking(infoPtr)) goto forward;
 
-    if(!infoPtr->hHotCursor)  return FALSE;
+    if (!infoPtr->hHotCursor) goto forward;
 
     GetCursorPos(&lvHitTestInfo.pt);
-    if (LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, FALSE, FALSE) < 0) return FALSE;
+    if (LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, FALSE, FALSE) < 0) goto forward;
 
     SetCursor(infoPtr->hHotCursor);
 
     return TRUE;
+
+forward:
+
+    return DefWindowProcW(infoPtr->hwndSelf, WM_SETCURSOR, wParam, lParam);
 }
 
 /***
@@ -10161,7 +10814,9 @@ static void LISTVIEW_UpdateSize(LISTVIEW_INFO *infoPtr)
            infoPtr->rcList.bottom -= GetSystemMetrics(SM_CYHSCROLL);
         infoPtr->rcList.bottom = max (infoPtr->rcList.bottom - 2, 0);
     }
-    else if (infoPtr->uView == LV_VIEW_DETAILS)
+
+    /* if control created invisible header isn't created */
+    if (infoPtr->hwndHeader)
     {
        HDLAYOUT hl;
        WINDOWPOS wp;
@@ -10169,15 +10824,24 @@ static void LISTVIEW_UpdateSize(LISTVIEW_INFO *infoPtr)
        hl.prc = &infoPtr->rcList;
        hl.pwpos = &wp;
        SendMessageW( infoPtr->hwndHeader, HDM_LAYOUT, 0, (LPARAM)&hl );
-        TRACE("  wp.flags=0x%08x, wp=%d,%d (%dx%d)\n", wp.flags, wp.x, wp.y, wp.cx, wp.cy);
-       SetWindowPos(wp.hwnd, wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy,
-                    wp.flags | ((infoPtr->dwStyle & LVS_NOCOLUMNHEADER)
-                        ? SWP_HIDEWINDOW : SWP_SHOWWINDOW));
-        TRACE("  after SWP wp=%d,%d (%dx%d)\n", wp.x, wp.y, wp.cx, wp.cy);
+       TRACE("  wp.flags=0x%08x, wp=%d,%d (%dx%d)\n", wp.flags, wp.x, wp.y, wp.cx, wp.cy);
+
+       if (LISTVIEW_IsHeaderEnabled(infoPtr))
+           wp.flags |= SWP_SHOWWINDOW;
+       else
+       {
+           wp.flags |= SWP_HIDEWINDOW;
+           wp.cy = 0;
+       }
+
+       SetWindowPos(wp.hwnd, wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags);
+       TRACE("  after SWP wp=%d,%d (%dx%d)\n", wp.x, wp.y, wp.cx, wp.cy);
 
        infoPtr->rcList.top = max(wp.cy, 0);
-        infoPtr->rcList.top += (infoPtr->dwLvExStyle & LVS_EX_GRIDLINES) ? 2 : 0;
     }
+    /* extra padding for grid */
+    if (infoPtr->uView == LV_VIEW_DETAILS && infoPtr->dwLvExStyle & LVS_EX_GRIDLINES)
+       infoPtr->rcList.top += 2;
 
     TRACE("  rcList=%s\n", wine_dbgstr_rect(&infoPtr->rcList));
 }
@@ -10258,7 +10922,7 @@ static INT LISTVIEW_StyleChanged(LISTVIEW_INFO *infoPtr, WPARAM wStyleType,
        LISTVIEW_UpdateItemSize(infoPtr);
     }
 
-    if (uNewView == LVS_REPORT)
+    if (uNewView == LVS_REPORT || infoPtr->dwLvExStyle & LVS_EX_HEADERINALLVIEWS)
     {
         if ((lpss->styleOld ^ lpss->styleNew) & LVS_NOCOLUMNHEADER)
         {
@@ -10300,14 +10964,13 @@ static INT LISTVIEW_StyleChanged(LISTVIEW_INFO *infoPtr, WPARAM wStyleType,
  * Processes WM_STYLECHANGING messages.
  *
  * PARAMETER(S):
- * [I] infoPtr : valid pointer to the listview structure
  * [I] wStyleType : window style type (normal or extended)
  * [I0] lpss : window style information
  *
  * RETURN:
  * Zero
  */
-static INT LISTVIEW_StyleChanging(LISTVIEW_INFO *infoPtr, WPARAM wStyleType,
+static INT LISTVIEW_StyleChanging(WPARAM wStyleType,
                                   STYLESTRUCT *lpss)
 {
     TRACE("(styletype=%lx, styleOld=0x%08x, styleNew=0x%08x)\n",
@@ -10337,7 +11000,7 @@ static INT LISTVIEW_StyleChanging(LISTVIEW_INFO *infoPtr, WPARAM wStyleType,
  * RETURN:
  * Zero
  */
-static LRESULT LISTVIEW_ShowWindow(LISTVIEW_INFO *infoPtr, BOOL bShown, INT iStatus)
+static LRESULT LISTVIEW_ShowWindow(LISTVIEW_INFO *infoPtr, WPARAM bShown, LPARAM iStatus)
 {
   /* header delayed creation */
   if ((infoPtr->uView == LV_VIEW_DETAILS) && bShown)
@@ -10348,7 +11011,7 @@ static LRESULT LISTVIEW_ShowWindow(LISTVIEW_INFO *infoPtr, BOOL bShown, INT iSta
       ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
   }
 
-  return 0;
+  return DefWindowProcW(infoPtr->hwndSelf, WM_SHOWWINDOW, bShown, iStatus);
 }
 
 /***
@@ -10402,7 +11065,7 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongPtrW(hwnd, 0);
 
-  TRACE("(uMsg=%x wParam=%lx lParam=%lx)\n", uMsg, wParam, lParam);
+  TRACE("(hwnd=%p uMsg=%x wParam=%lx lParam=%lx)\n", hwnd, uMsg, wParam, lParam);
 
   if (!infoPtr && (uMsg != WM_NCCREATE))
     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
@@ -10430,12 +11093,10 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
   case LVM_DELETEITEM:
     return LISTVIEW_DeleteItem(infoPtr, (INT)wParam);
 
-  case LVM_EDITLABELW:
-    return (LRESULT)LISTVIEW_EditLabelT(infoPtr, (INT)wParam, TRUE);
-
   case LVM_EDITLABELA:
-    return (LRESULT)LISTVIEW_EditLabelT(infoPtr, (INT)wParam, FALSE);
-
+  case LVM_EDITLABELW:
+    return (LRESULT)LISTVIEW_EditLabelT(infoPtr, (INT)wParam,
+                                        uMsg == LVM_EDITLABELW);
   /* case LVM_ENABLEGROUPVIEW: */
 
   case LVM_ENSUREVISIBLE:
@@ -10456,10 +11117,9 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
     return infoPtr->uCallbackMask;
 
   case LVM_GETCOLUMNA:
-    return LISTVIEW_GetColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam, FALSE);
-
   case LVM_GETCOLUMNW:
-    return LISTVIEW_GetColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam, TRUE);
+    return LISTVIEW_GetColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam,
+                               uMsg == LVM_GETCOLUMNW);
 
   case LVM_GETCOLUMNORDERARRAY:
     return LISTVIEW_GetColumnOrderArray(infoPtr, (INT)wParam, (LPINT)lParam);
@@ -10507,10 +11167,8 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
     return FALSE;
 
   case LVM_GETITEMA:
-    return LISTVIEW_GetItemExtT(infoPtr, (LPLVITEMW)lParam, FALSE);
-
   case LVM_GETITEMW:
-    return LISTVIEW_GetItemExtT(infoPtr, (LPLVITEMW)lParam, TRUE);
+    return LISTVIEW_GetItemExtT(infoPtr, (LPLVITEMW)lParam, uMsg == LVM_GETITEMW);
 
   case LVM_GETITEMCOUNT:
     return infoPtr->nItemCount;
@@ -10528,10 +11186,9 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
     return LISTVIEW_GetItemState(infoPtr, (INT)wParam, (UINT)lParam);
 
   case LVM_GETITEMTEXTA:
-    return LISTVIEW_GetItemTextT(infoPtr, (INT)wParam, (LPLVITEMW)lParam, FALSE);
-
   case LVM_GETITEMTEXTW:
-    return LISTVIEW_GetItemTextT(infoPtr, (INT)wParam, (LPLVITEMW)lParam, TRUE);
+    return LISTVIEW_GetItemTextT(infoPtr, (INT)wParam, (LPLVITEMW)lParam,
+                                 uMsg == LVM_GETITEMTEXTW);
 
   case LVM_GETNEXTITEM:
     return LISTVIEW_GetNextItem(infoPtr, (INT)wParam, LOWORD(lParam));
@@ -10558,10 +11215,9 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
     return infoPtr->nSelectionMark;
 
   case LVM_GETSTRINGWIDTHA:
-    return LISTVIEW_GetStringWidthT(infoPtr, (LPCWSTR)lParam, FALSE);
-
   case LVM_GETSTRINGWIDTHW:
-    return LISTVIEW_GetStringWidthT(infoPtr, (LPCWSTR)lParam, TRUE);
+    return LISTVIEW_GetStringWidthT(infoPtr, (LPCWSTR)lParam,
+                                    uMsg == LVM_GETSTRINGWIDTHW);
 
   case LVM_GETSUBITEMRECT:
     return LISTVIEW_GetSubItemRect(infoPtr, (UINT)wParam, (LPRECT)lParam);
@@ -10603,20 +11259,17 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
     return LISTVIEW_HitTest(infoPtr, (LPLVHITTESTINFO)lParam, FALSE, TRUE);
 
   case LVM_INSERTCOLUMNA:
-    return LISTVIEW_InsertColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam, FALSE);
-
   case LVM_INSERTCOLUMNW:
-    return LISTVIEW_InsertColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam, TRUE);
+    return LISTVIEW_InsertColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam,
+                                  uMsg == LVM_INSERTCOLUMNW);
 
   /* case LVM_INSERTGROUP: */
 
   /* case LVM_INSERTGROUPSORTED: */
 
   case LVM_INSERTITEMA:
-    return LISTVIEW_InsertItemT(infoPtr, (LPLVITEMW)lParam, FALSE);
-
   case LVM_INSERTITEMW:
-    return LISTVIEW_InsertItemT(infoPtr, (LPLVITEMW)lParam, TRUE);
+    return LISTVIEW_InsertItemT(infoPtr, (LPLVITEMW)lParam, uMsg == LVM_INSERTITEMW);
 
   /* case LVM_INSERTMARKHITTEST: */
 
@@ -10655,10 +11308,9 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
     return TRUE;
 
   case LVM_SETCOLUMNA:
-    return LISTVIEW_SetColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam, FALSE);
-
   case LVM_SETCOLUMNW:
-    return LISTVIEW_SetColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam, TRUE);
+    return LISTVIEW_SetColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam,
+                               uMsg == LVM_SETCOLUMNW);
 
   case LVM_SETCOLUMNORDERARRAY:
     return LISTVIEW_SetColumnOrderArray(infoPtr, (INT)wParam, (LPINT)lParam);
@@ -10680,7 +11332,7 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
     return LISTVIEW_SetHotItem(infoPtr, (INT)wParam);
 
   case LVM_SETHOVERTIME:
-    return LISTVIEW_SetHoverTime(infoPtr, (DWORD)wParam);
+    return LISTVIEW_SetHoverTime(infoPtr, (DWORD)lParam);
 
   case LVM_SETICONSPACING:
     return LISTVIEW_SetIconSpacing(infoPtr, (short)LOWORD(lParam), (short)HIWORD(lParam));
@@ -10709,22 +11361,20 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
        POINT pt;
         pt.x = (short)LOWORD(lParam);
         pt.y = (short)HIWORD(lParam);
-        return LISTVIEW_SetItemPosition(infoPtr, (INT)wParam, pt);
+        return LISTVIEW_SetItemPosition(infoPtr, (INT)wParam, &pt);
     }
 
   case LVM_SETITEMPOSITION32:
-    if (lParam == 0) return FALSE;
-    return LISTVIEW_SetItemPosition(infoPtr, (INT)wParam, *((POINT*)lParam));
+    return LISTVIEW_SetItemPosition(infoPtr, (INT)wParam, (POINT*)lParam);
 
   case LVM_SETITEMSTATE:
     if (lParam == 0) return FALSE;
     return LISTVIEW_SetItemState(infoPtr, (INT)wParam, (LPLVITEMW)lParam);
 
   case LVM_SETITEMTEXTA:
-    return LISTVIEW_SetItemTextT(infoPtr, (INT)wParam, (LPLVITEMW)lParam, FALSE);
-
   case LVM_SETITEMTEXTW:
-    return LISTVIEW_SetItemTextT(infoPtr, (INT)wParam, (LPLVITEMW)lParam, TRUE);
+    return LISTVIEW_SetItemTextT(infoPtr, (INT)wParam, (LPLVITEMW)lParam,
+                                 uMsg == LVM_SETITEMTEXTW);
 
   /* case LVM_SETOUTLINECOLOR: */
 
@@ -10759,11 +11409,9 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
   /* case LVM_SORTGROUPS: */
 
   case LVM_SORTITEMS:
-    return LISTVIEW_SortItems(infoPtr, (PFNLVCOMPARE)lParam, (LPARAM)wParam, FALSE);
-
   case LVM_SORTITEMSEX:
-    return LISTVIEW_SortItems(infoPtr, (PFNLVCOMPARE)lParam, (LPARAM)wParam, TRUE);
-
+    return LISTVIEW_SortItems(infoPtr, (PFNLVCOMPARE)lParam, wParam,
+                              uMsg == LVM_SORTITEMSEX);
   case LVM_SUBITEMHITTEST:
     return LISTVIEW_HitTest(infoPtr, (LPLVHITTESTINFO)lParam, TRUE, FALSE);
 
@@ -10792,7 +11440,7 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
     return LISTVIEW_Destroy(infoPtr);
 
   case WM_ENABLE:
-    return LISTVIEW_Enable(infoPtr, (BOOL)wParam);
+    return LISTVIEW_Enable(infoPtr);
 
   case WM_ERASEBKGND:
     return LISTVIEW_EraseBkgnd(infoPtr, (HDC)wParam);
@@ -10804,7 +11452,7 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
     return (LRESULT)infoPtr->hFont;
 
   case WM_HSCROLL:
-    return LISTVIEW_HScroll(infoPtr, (INT)LOWORD(wParam), 0, (HWND)lParam);
+    return LISTVIEW_HScroll(infoPtr, (INT)LOWORD(wParam), 0);
 
   case WM_KEYDOWN:
     return LISTVIEW_KeyDown(infoPtr, (INT)wParam, (LONG)lParam);
@@ -10825,20 +11473,16 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
     return LISTVIEW_MouseMove (infoPtr, (WORD)wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
 
   case WM_MOUSEHOVER:
-    return LISTVIEW_MouseHover(infoPtr, (WORD)wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
+    return LISTVIEW_MouseHover(infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
 
   case WM_NCDESTROY:
     return LISTVIEW_NCDestroy(infoPtr);
 
   case WM_NCPAINT:
-    if (LISTVIEW_NCPaint(infoPtr, (HRGN)wParam))
-        return 0;
-    goto fwd_msg;
+    return LISTVIEW_NCPaint(infoPtr, (HRGN)wParam);
 
   case WM_NOTIFY:
-    if (lParam && ((LPNMHDR)lParam)->hwndFrom == infoPtr->hwndHeader)
-        return LISTVIEW_HeaderNotification(infoPtr, (LPNMHEADERW)lParam);
-    else return 0;
+    return LISTVIEW_Notify(infoPtr, (LPNMHDR)lParam);
 
   case WM_NOTIFYFORMAT:
     return LISTVIEW_NotifyFormat(infoPtr, (HWND)wParam, (INT)lParam);
@@ -10859,9 +11503,7 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
     return LISTVIEW_RButtonUp(infoPtr, (WORD)wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
 
   case WM_SETCURSOR:
-    if(LISTVIEW_SetCursor(infoPtr, (HWND)wParam, LOWORD(lParam), HIWORD(lParam)))
-      return TRUE;
-    goto fwd_msg;
+    return LISTVIEW_SetCursor(infoPtr, wParam, lParam);
 
   case WM_SETFOCUS:
     return LISTVIEW_SetFocus(infoPtr, (HWND)wParam);
@@ -10873,8 +11515,7 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
     return LISTVIEW_SetRedraw(infoPtr, (BOOL)wParam);
 
   case WM_SHOWWINDOW:
-    LISTVIEW_ShowWindow(infoPtr, (BOOL)wParam, (INT)lParam);
-    return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+    return LISTVIEW_ShowWindow(infoPtr, wParam, lParam);
 
   case WM_SIZE:
     return LISTVIEW_Size(infoPtr, (short)LOWORD(lParam), (short)HIWORD(lParam));
@@ -10883,10 +11524,15 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
     return LISTVIEW_StyleChanged(infoPtr, wParam, (LPSTYLESTRUCT)lParam);
 
   case WM_STYLECHANGING:
-    return LISTVIEW_StyleChanging(infoPtr, wParam, (LPSTYLESTRUCT)lParam);
+    return LISTVIEW_StyleChanging(wParam, (LPSTYLESTRUCT)lParam);
 
   case WM_SYSCOLORCHANGE:
     COMCTL32_RefreshSysColors();
+    if (infoPtr->bDefaultBkColor)
+    {
+        LISTVIEW_SetBkColor(infoPtr, comctl32_color.clrWindow);
+        infoPtr->bDefaultBkColor = TRUE;
+    }
     return 0;
 
 /*     case WM_TIMER: */
@@ -10894,7 +11540,7 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
     return LISTVIEW_ThemeChanged(infoPtr);
 
   case WM_VSCROLL:
-    return LISTVIEW_VScroll(infoPtr, (INT)LOWORD(wParam), 0, (HWND)lParam);
+    return LISTVIEW_VScroll(infoPtr, (INT)LOWORD(wParam), 0);
 
   case WM_MOUSEWHEEL:
       if (wParam & (MK_SHIFT | MK_CONTROL))
@@ -10923,8 +11569,6 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
     if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg))
       ERR("unknown msg %04x wp=%08lx lp=%08lx\n", uMsg, wParam, lParam);
 
-  fwd_msg:
-    /* call default window procedure */
     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
   }
 
@@ -10984,6 +11628,11 @@ void LISTVIEW_Unregister(void)
  */
 static LRESULT LISTVIEW_Command(LISTVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
 {
+
+    TRACE("(%p %x %x %lx)\n", infoPtr, HIWORD(wParam), LOWORD(wParam), lParam);
+
+    if (!infoPtr->hwndEdit) return 0;
+
     switch (HIWORD(wParam))
     {
        case EN_UPDATE:
@@ -11003,7 +11652,7 @@ static LRESULT LISTVIEW_Command(LISTVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lP
 
             /* Select font to get the right dimension of the string */
             hFont = (HFONT)SendMessageW(infoPtr->hwndEdit, WM_GETFONT, 0, 0);
-            if(hFont != 0)
+            if (hFont)
             {
                 hOldFont = SelectObject(hdc, hFont);
             }
@@ -11016,16 +11665,10 @@ static LRESULT LISTVIEW_Command(LISTVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lP
                 GetTextMetricsW(hdc, &textMetric);
                 sz.cx += (textMetric.tmMaxCharWidth * 2);
 
-               SetWindowPos (
-                   infoPtr->hwndEdit,
-                   HWND_TOP,
-                   0,
-                   0,
-                   sz.cx,
-                   rect.bottom - rect.top,
-                   SWP_DRAWFRAME|SWP_NOMOVE);
+               SetWindowPos(infoPtr->hwndEdit, NULL, 0, 0, sz.cx,
+                   rect.bottom - rect.top, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOZORDER);
            }
-            if(hFont != 0)
+            if (hFont)
                 SelectObject(hdc, hOldFont);
 
            ReleaseDC(infoPtr->hwndEdit, hdc);
@@ -11035,6 +11678,7 @@ static LRESULT LISTVIEW_Command(LISTVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lP
        case EN_KILLFOCUS:
        {
            LISTVIEW_CancelEditLabel(infoPtr);
+           break;
        }
 
        default:
@@ -11043,133 +11687,3 @@ static LRESULT LISTVIEW_Command(LISTVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lP
 
     return 0;
 }
-
-
-/***
- * DESCRIPTION:
- * Subclassed edit control windproc function
- *
- * PARAMETER(S):
- * [I] hwnd : the edit window handle
- * [I] uMsg : the message that is to be processed
- * [I] wParam : first message parameter
- * [I] lParam : second message parameter
- * [I] isW : TRUE if input is Unicode
- *
- * RETURN:
- *   Zero.
- */
-static LRESULT EditLblWndProcT(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL isW)
-{
-    LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongPtrW(GetParent(hwnd), 0);
-    BOOL save = TRUE;
-
-    TRACE("(hwnd=%p, uMsg=%x, wParam=%lx, lParam=%lx, isW=%d)\n",
-         hwnd, uMsg, wParam, lParam, isW);
-
-    switch (uMsg)
-    {
-       case WM_GETDLGCODE:
-         return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
-
-       case WM_DESTROY:
-       {
-           WNDPROC editProc = infoPtr->EditWndProc;
-           infoPtr->EditWndProc = 0;
-           SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (DWORD_PTR)editProc);
-           return CallWindowProcT(editProc, hwnd, uMsg, wParam, lParam, isW);
-       }
-
-       case WM_KEYDOWN:
-           if (VK_ESCAPE == (INT)wParam)
-           {
-               save = FALSE;
-                break;
-           }
-           else if (VK_RETURN == (INT)wParam)
-               break;
-
-       default:
-           return CallWindowProcT(infoPtr->EditWndProc, hwnd, uMsg, wParam, lParam, isW);
-    }
-
-    /* kill the edit */
-    if (infoPtr->hwndEdit)
-       LISTVIEW_EndEditLabelT(infoPtr, save, isW);
-
-    SendMessageW(hwnd, WM_CLOSE, 0, 0);
-    return 0;
-}
-
-/***
- * DESCRIPTION:
- * Subclassed edit control Unicode windproc function
- *
- * PARAMETER(S):
- * [I] hwnd : the edit window handle
- * [I] uMsg : the message that is to be processed
- * [I] wParam : first message parameter
- * [I] lParam : second message parameter
- *
- * RETURN:
- */
-static LRESULT CALLBACK EditLblWndProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
-    return EditLblWndProcT(hwnd, uMsg, wParam, lParam, TRUE);
-}
-
-/***
- * DESCRIPTION:
- * Subclassed edit control ANSI windproc function
- *
- * PARAMETER(S):
- * [I] hwnd : the edit window handle
- * [I] uMsg : the message that is to be processed
- * [I] wParam : first message parameter
- * [I] lParam : second message parameter
- *
- * RETURN:
- */
-static LRESULT CALLBACK EditLblWndProcA(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
-    return EditLblWndProcT(hwnd, uMsg, wParam, lParam, FALSE);
-}
-
-/***
- * DESCRIPTION:
- * Creates a subclassed edit control
- *
- * PARAMETER(S):
- * [I] infoPtr : valid pointer to the listview structure
- * [I] text : initial text for the edit
- * [I] style : the window style
- * [I] isW : TRUE if input is Unicode
- *
- * RETURN:
- */
-static HWND CreateEditLabelT(LISTVIEW_INFO *infoPtr, LPCWSTR text, DWORD style, BOOL isW)
-{
-    WCHAR editName[5] = { 'E', 'd', 'i', 't', '\0' };
-    HWND hedit;
-    HINSTANCE hinst = (HINSTANCE)GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_HINSTANCE);
-
-    TRACE("(text=%s, ..., isW=%d)\n", debugtext_t(text, isW), isW);
-
-    style |= WS_CHILDWINDOW|WS_CLIPSIBLINGS|ES_LEFT|ES_AUTOHSCROLL|WS_BORDER;
-
-    /* Window will be resized and positioned after LVN_BEGINLABELEDIT */
-    if (isW)
-       hedit = CreateWindowW(editName, text, style, 0, 0, 0, 0, infoPtr->hwndSelf, 0, hinst, 0);
-    else
-       hedit = CreateWindowA("Edit", (LPCSTR)text, style, 0, 0, 0, 0, infoPtr->hwndSelf, 0, hinst, 0);
-
-    if (!hedit) return 0;
-
-    infoPtr->EditWndProc = (WNDPROC)
-       (isW ? SetWindowLongPtrW(hedit, GWLP_WNDPROC, (DWORD_PTR)EditLblWndProcW) :
-               SetWindowLongPtrA(hedit, GWLP_WNDPROC, (DWORD_PTR)EditLblWndProcA) );
-
-    SendMessageW(hedit, WM_SETFONT, (WPARAM)infoPtr->hFont, FALSE);
-
-    return hedit;
-}