Reworked how selections are kept track of in the list view. Selections
are now listed as a sorted range of paired integers.

diff --git a/dlls/comctl32/listview.c b/dlls/comctl32/listview.c
index d62d690..0f7f441 100644
--- a/dlls/comctl32/listview.c
+++ b/dlls/comctl32/listview.c
@@ -998,8 +998,409 @@
   return nItemHeight;
 }
 
+
+static void LISTVIEW_PrintSelectionRanges(hwnd)
+{
+  LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
+  LISTVIEW_SELECTION *selection;
+  INT topSelection = infoPtr->hdpaSelectionRanges->nItemCount;
+  INT i;
+
+  TRACE("Selections are:\n");
+  for (i = 0; i < topSelection; i++)
+  {
+    selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,i);
+    TRACE("     %lu - %lu\n",selection->lower,selection->upper);
+  }
+}
+
 /***
  * DESCRIPTION:
+ * A compare function for selection ranges
+ *
+ *PARAMETER(S)
+ * [I] LPVOID : Item 1;
+ * [I] LPVOID : Item 2;
+ * [I] LPARAM : flags
+ *
+ *RETURNS:
+ * >0 : if Item 1 > Item 2
+ * <0 : if Item 2 > Item 1
+ * 0 : if Item 1 == Item 2
+ */
+static INT LISTVIEW_CompareSelectionRanges(LPVOID range1, LPVOID range2, 
+                                          LPARAM flags)
+{
+  int l1 = ((LISTVIEW_SELECTION*)(range1))->lower;
+  int l2 = ((LISTVIEW_SELECTION*)(range2))->lower;
+  int u1 = ((LISTVIEW_SELECTION*)(range1))->upper;
+  int u2 = ((LISTVIEW_SELECTION*)(range2))->upper; 
+  int rc=0;
+
+  if (u1 < l2)
+    rc= -1;
+ 
+  if (u2 < l1)
+     rc= 1;
+
+  return rc;
+}
+
+/**
+* DESCRIPTION:
+* Adds a selection range.
+* 
+* PARAMETER(S):
+* [I] HWND : window handle
+* [I] INT : lower item index
+* [I] INT : upper item index 
+*
+* RETURN:
+* None
+*/
+static VOID LISTVIEW_AddSelectionRange(HWND hwnd, INT lItem, INT uItem)
+{
+ LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
+ LISTVIEW_SELECTION *selection;
+ INT topSelection = infoPtr->hdpaSelectionRanges->nItemCount;
+ BOOL lowerzero=FALSE;
+
+ selection = (LISTVIEW_SELECTION *)COMCTL32_Alloc(sizeof(LISTVIEW_SELECTION));
+ selection->lower = lItem;
+ selection->upper = uItem;
+
+ TRACE("Add range %i - %i\n",lItem,uItem);
+ if (topSelection)
+ {
+   LISTVIEW_SELECTION *checkselection,*checkselection2;
+   INT index,mergeindex;
+
+   /* find overlapping selections */
+   /* we want to catch adjacent ranges so expand our range by 1 */
+
+   selection->upper++;
+   if (selection->lower == 0)
+     lowerzero = TRUE;
+   else
+     selection->lower--;
+
+   index = DPA_Search(infoPtr->hdpaSelectionRanges, selection, 0,
+                      LISTVIEW_CompareSelectionRanges,
+                      0,0);
+   selection->upper --; 
+   if (lowerzero)
+     lowerzero=FALSE;
+   else
+     selection->lower ++;
+
+   if (index >=0)
+   {
+     checkselection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,index);
+     TRACE("Merge with index %i (%lu - %lu)\n",index,checkselection->lower,
+           checkselection->upper);
+     
+     checkselection->lower = min(selection->lower,checkselection->lower);
+     checkselection->upper = max(selection->upper,checkselection->upper);
+    
+     TRACE("New range (%lu - %lu)\n", checkselection->lower, 
+           checkselection->upper);
+
+     COMCTL32_Free(selection);    
+ 
+     /* merge now common selection ranges in the lower group*/
+     do
+     {
+        checkselection->upper ++; 
+        if (checkselection->lower == 0)
+          lowerzero = TRUE;
+        else
+          checkselection->lower --;
+
+        TRACE("search lower range (%lu - %lu)\n", checkselection->lower, 
+              checkselection->upper);
+
+        /* not sorted yet */
+        mergeindex = DPA_Search(infoPtr->hdpaSelectionRanges, checkselection, 0,
+                                LISTVIEW_CompareSelectionRanges, 0,
+                                0);
+
+        checkselection->upper --; 
+        if (lowerzero)
+          lowerzero = FALSE;
+        else
+	  checkselection->lower ++;
+
+	if (mergeindex >=0  && mergeindex != index)
+        {
+	  TRACE("Merge with index %i\n",mergeindex);
+          checkselection2 = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
+                                       mergeindex);
+          checkselection->lower = min(checkselection->lower, 
+                                      checkselection2->lower);
+          checkselection->upper = max(checkselection->upper,
+                                      checkselection2->upper);
+          COMCTL32_Free(checkselection2);
+          DPA_DeletePtr(infoPtr->hdpaSelectionRanges,mergeindex);
+          index --;
+        }
+     }
+     while (mergeindex > -1 && mergeindex <index);
+
+     /* merge now common selection ranges in the upper group*/
+    do
+    {
+       checkselection->upper ++;
+       if (checkselection->lower == 0)
+         lowerzero = TRUE;
+       else 
+         checkselection->lower --;
+
+       TRACE("search upper range %i (%lu - %lu)\n",index, 
+             checkselection->lower, checkselection->upper);
+
+       /* not sorted yet */
+       mergeindex = DPA_Search(infoPtr->hdpaSelectionRanges, checkselection,
+                               index+1,
+			       LISTVIEW_CompareSelectionRanges, 0,
+			       0);
+
+       checkselection->upper --; 
+       if (lowerzero)
+         lowerzero = FALSE;
+       else
+         checkselection->lower ++;
+
+       if (mergeindex >=0 && mergeindex !=index)
+       {
+	 TRACE("Merge with index %i\n",mergeindex);
+	 checkselection2 = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
+				      mergeindex);
+	 checkselection->lower = min(checkselection->lower, 
+				     checkselection2->lower);
+	 checkselection->upper = max(checkselection->upper,
+				     checkselection2->upper);
+	 COMCTL32_Free(checkselection2);
+	 DPA_DeletePtr(infoPtr->hdpaSelectionRanges,mergeindex);
+       }
+    }
+    while (mergeindex > -1);
+   }
+   else
+   {
+
+     index = DPA_Search(infoPtr->hdpaSelectionRanges, selection, 0,
+                       LISTVIEW_CompareSelectionRanges, 0, 
+                       DPAS_INSERTAFTER);
+
+     TRACE("Insert before index %i\n",index);
+     if (index == -1)
+       index = 0;
+     DPA_InsertPtr(infoPtr->hdpaSelectionRanges,index,selection); 
+   }
+ } 
+ else
+ {
+   DPA_InsertPtr(infoPtr->hdpaSelectionRanges,0,selection);
+ }
+ /*
+  * Incase of error 
+  */
+ DPA_Sort(infoPtr->hdpaSelectionRanges,LISTVIEW_CompareSelectionRanges,0);
+ LISTVIEW_PrintSelectionRanges(hwnd);
+}
+
+/**
+* DESCRIPTION:
+* check if a specified index is selected.
+* 
+* PARAMETER(S):
+* [I] HWND : window handle
+* [I] INT : item index 
+*
+* RETURN:
+* None
+*/
+static BOOL LISTVIEW_IsSelected(HWND hwnd, INT nItem)
+{
+  LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
+  LISTVIEW_SELECTION selection;
+  INT index;
+
+  selection.upper = nItem;
+  selection.lower = nItem;
+
+  index = DPA_Search(infoPtr->hdpaSelectionRanges, &selection, 0,
+                      LISTVIEW_CompareSelectionRanges,
+                      0,DPAS_SORTED);
+  if (index != -1)
+    return TRUE;
+  else
+    return FALSE;
+}
+
+/***
+* DESCRIPTION:
+* Removes all selection ranges
+*
+* Parameters(s):
+*   HWND: window handle
+*
+* RETURNS:
+*   SUCCESS : TRUE
+*   FAILURE : TRUE
+*/
+static LRESULT LISTVIEW_RemoveAllSelections(HWND hwnd)
+{
+ LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
+ LISTVIEW_SELECTION *selection;
+ INT i;
+
+ for (i = 0; i < infoPtr->hdpaSelectionRanges->nItemCount; i++)
+ {
+   selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,i);
+   if (selection)
+     COMCTL32_Free(selection); 
+ }
+ return  DPA_DeleteAllPtrs(infoPtr->hdpaSelectionRanges);
+}
+
+/**
+* DESCRIPTION:
+* Removes a range selections.
+* 
+* PARAMETER(S):
+* [I] HWND : window handle
+* [I] INT : lower item index
+* [I] INT : upper item index 
+*
+* RETURN:
+* None
+*/
+static VOID LISTVIEW_RemoveSelectionRange(HWND hwnd, INT lItem, INT uItem)
+{
+  LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
+  LISTVIEW_SELECTION removeselection,*checkselection;
+  INT index;
+
+  removeselection.lower = lItem;
+  removeselection.upper = uItem;
+
+  TRACE("Remove range %lu - %lu\n",removeselection.lower,removeselection.upper);
+  LISTVIEW_PrintSelectionRanges(hwnd);
+
+  index = DPA_Search(infoPtr->hdpaSelectionRanges, &removeselection, 0,
+                     LISTVIEW_CompareSelectionRanges,
+                     0,0);
+  
+  if (index == -1)
+    return;
+
+ 
+  checkselection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
+                              index);
+
+  TRACE("Matches range index %i (%lu-%lu)\n",index,checkselection->lower,
+        checkselection->upper);
+
+  /* case 1: Same */
+  if ((checkselection->upper == removeselection.upper) && 
+     (checkselection->lower == removeselection.lower))
+  {
+    DPA_DeletePtr(infoPtr->hdpaSelectionRanges,index);
+    TRACE("Case 1\n");
+  }
+  /* case 2: engulf */
+  else if (((checkselection->upper < removeselection.upper) && 
+      (checkselection->lower > removeselection.lower))||
+     ((checkselection->upper <= removeselection.upper) &&
+      (checkselection->lower > removeselection.lower)) ||
+     ((checkselection->upper < removeselection.upper) &&
+      (checkselection->lower >= removeselection.lower)))
+
+  {
+    DPA_DeletePtr(infoPtr->hdpaSelectionRanges,index);
+    /* do it again because others may also get caught */
+    TRACE("Case 2\n");
+    LISTVIEW_RemoveSelectionRange(hwnd,lItem,uItem);
+  }
+  /* case 3: overlap upper */
+  else if ((checkselection->upper < removeselection.upper) &&
+      (checkselection->lower < removeselection.lower))
+  {
+    checkselection->upper = removeselection.lower - 1;
+    TRACE("Case 3\n");
+    LISTVIEW_RemoveSelectionRange(hwnd,lItem,uItem);
+  }
+  /* case 4: overlap lower */
+  else if ((checkselection->upper > removeselection.upper) &&
+      (checkselection->lower > removeselection.lower))
+  {
+    checkselection->lower = removeselection.upper + 1;
+    TRACE("Case 4\n");
+    LISTVIEW_RemoveSelectionRange(hwnd,lItem,uItem);
+  }
+  /* case 5: fully internal */
+  else if (checkselection->upper == removeselection.upper)
+    checkselection->upper = removeselection.lower - 1;
+  else if (checkselection->lower == removeselection.lower)
+    checkselection->lower = removeselection.upper + 1;
+  else
+  {
+    /* bisect the range */
+    LISTVIEW_SELECTION *newselection;
+    
+    newselection = (LISTVIEW_SELECTION *)
+                          COMCTL32_Alloc(sizeof(LISTVIEW_SELECTION));
+    newselection -> lower = checkselection->lower;
+    newselection -> upper = removeselection.lower - 1;
+    checkselection -> lower = removeselection.upper + 1;
+    DPA_InsertPtr(infoPtr->hdpaSelectionRanges,index,newselection);
+    TRACE("Case 5\n");
+    DPA_Sort(infoPtr->hdpaSelectionRanges,LISTVIEW_CompareSelectionRanges,0);
+  }
+  LISTVIEW_PrintSelectionRanges(hwnd);
+}
+
+/**
+* DESCRIPTION:
+* shifts all selection indexs starting with the indesx specified
+* in the direction specified.
+* 
+* PARAMETER(S):
+* [I] HWND : window handle
+* [I] INT : item index 
+* [I] INT : amount and direction of shift
+*
+* RETURN:
+* None
+*/
+static VOID LISTVIEW_ShiftSelections(HWND hwnd, INT nItem, INT direction)
+{
+  LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
+  LISTVIEW_SELECTION selection,*checkselection;
+  INT index;
+
+  selection.upper = nItem;
+  selection.lower = nItem;
+
+  index = DPA_Search(infoPtr->hdpaSelectionRanges, &selection, 0,
+                     LISTVIEW_CompareSelectionRanges,
+                     0,DPAS_SORTED|DPAS_INSERTAFTER);
+
+  while ((index < infoPtr->hdpaSelectionRanges->nItemCount)&&(index != -1)) 
+  {
+    checkselection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,index);
+    if (checkselection->lower >= nItem)
+        checkselection->lower += direction;
+    if (checkselection->upper >= nItem)
+        checkselection->upper += direction;
+    index ++;
+  }
+}
+
+
+/**
+ * DESCRIPTION:
  * Adds a block of selections.
  * 
  * PARAMETER(S):
@@ -1014,21 +1415,14 @@
   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
   INT nFirst = min(infoPtr->nSelectionMark, nItem);
   INT nLast = max(infoPtr->nSelectionMark, nItem);
-  LVITEMA lvItem;
-  INT i;
 
-  lvItem.state = LVIS_SELECTED;
-  lvItem.stateMask= LVIS_SELECTED;
-  
-  for (i = nFirst; i <= nLast; i++)
-  {
-    ListView_SetItemState(hwnd, i, &lvItem);
-  }
-  
+  LISTVIEW_AddSelectionRange(hwnd,nFirst,nLast);
+
   LISTVIEW_SetItemFocus(hwnd, nItem);
   infoPtr->nSelectionMark = nItem;
 }
 
+
 /***
  * DESCRIPTION:
  * Adds a single selection.
@@ -1043,12 +1437,8 @@
 static VOID LISTVIEW_AddSelection(HWND hwnd, INT nItem)
 {
   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
-  LVITEMA lvItem;
 
-  lvItem.state = LVIS_SELECTED;
-  lvItem.stateMask= LVIS_SELECTED;
-
-  ListView_SetItemState(hwnd, nItem, &lvItem);
+  LISTVIEW_AddSelectionRange(hwnd,nItem,nItem);
 
   LISTVIEW_SetItemFocus(hwnd, nItem);
   infoPtr->nSelectionMark = nItem;
@@ -1070,20 +1460,15 @@
 {
   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
   BOOL bResult;
-  LVITEMA lvItem;
 
-  lvItem.stateMask= LVIS_SELECTED;
-
-  if (ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED)
+  if (LISTVIEW_IsSelected(hwnd,nItem))
   {
-    lvItem.state = 0;
-    ListView_SetItemState(hwnd, nItem, &lvItem);
+    LISTVIEW_RemoveSelections(hwnd,nItem,nItem);
     bResult = FALSE;
   }
   else
   {
-    lvItem.state = LVIS_SELECTED;
-    ListView_SetItemState(hwnd, nItem, &lvItem);
+    LISTVIEW_AddSelectionRange(hwnd,nItem,nItem);
     bResult = TRUE;
   }
 
@@ -1107,25 +1492,20 @@
 static VOID LISTVIEW_SetSelectionRect(HWND hwnd, RECT rcSelRect)
 {
   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
-  LVITEMA lvItem;
   POINT ptItem;
   INT i;
 
-  lvItem.stateMask = LVIS_SELECTED;
-
   for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
   {
     LISTVIEW_GetItemPosition(hwnd, i, &ptItem);
     if (PtInRect(&rcSelRect, ptItem) != FALSE)
     {
-      lvItem.state = LVIS_SELECTED;
+      LISTVIEW_AddSelectionRange(hwnd,i,i);
     }
     else
     {
-      lvItem.state = 0;
+      LISTVIEW_RemoveSelections(hwnd,i,i);
     }
-
-    ListView_SetItemState(hwnd, i, &lvItem);
   }
 }
 
@@ -1144,27 +1524,23 @@
 {
   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
   UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
-  LVITEMA lvItem;
 
   if ((uView == LVS_LIST) || (uView == LVS_REPORT))
   {
     INT i;
     INT nFirst = min(infoPtr->nSelectionMark, nItem);
     INT nLast = max(infoPtr->nSelectionMark, nItem);
-    lvItem.stateMask = LVIS_SELECTED;
-   
+
     for (i = 0; i <= GETITEMCOUNT(infoPtr); i++)
     {
       if ((i < nFirst) || (i > nLast))
       {
-        lvItem.state = 0;
+        LISTVIEW_RemoveSelections(hwnd,i,i);
       }
       else
       {
-        lvItem.state = LVIS_SELECTED;
+        LISTVIEW_AddSelectionRange(hwnd,i,i);
       }
-
-      ListView_SetItemState(hwnd, i, &lvItem);
     }
   }
   else
@@ -1242,24 +1618,17 @@
   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
   LVITEMA lvItem;
 
-  if (nItem > 0)
-  {
-    LISTVIEW_RemoveSelections(hwnd, 0, nItem - 1);
-  }
-
-  if (nItem < GETITEMCOUNT(infoPtr))
-  {
-    LISTVIEW_RemoveSelections(hwnd, nItem + 1, GETITEMCOUNT(infoPtr));
-  }
-
   ZeroMemory(&lvItem, sizeof(LVITEMA));
   lvItem.stateMask = LVIS_FOCUSED;
   ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem); 
-  
-  lvItem.state =  LVIS_SELECTED | LVIS_FOCUSED;
-  lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
+
+  lvItem.state =   LVIS_FOCUSED;
+  lvItem.stateMask = LVIS_FOCUSED;
   ListView_SetItemState(hwnd, nItem, &lvItem);
 
+  LISTVIEW_RemoveAllSelections(hwnd);
+  LISTVIEW_AddSelectionRange(hwnd,nItem,nItem);
+
   infoPtr->nFocusedItem = nItem;
   infoPtr->nSelectionMark = nItem;
 }
@@ -1404,9 +1773,22 @@
 {
   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
   RECT rcItem;
-  INT i;
-  
-  for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
+  INT i,topindex,bottomindex;
+  LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
+  UINT uView = lStyle & LVS_TYPEMASK;
+
+  topindex = ListView_GetTopIndex(hwnd);
+  if (uView == LVS_REPORT)
+  {
+    bottomindex = topindex + LISTVIEW_GetCountPerColumn(hwnd) + 1;  
+    bottomindex = min(bottomindex,GETITEMCOUNT(infoPtr));
+  }
+  else
+  {
+    bottomindex = GETITEMCOUNT(infoPtr);
+  }
+
+  for (i = topindex; i < bottomindex; i++) 
   {
     rcItem.left = LVIR_SELECTBOUNDS;
     if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) == TRUE)
@@ -1435,16 +1817,7 @@
  */
 static VOID LISTVIEW_RemoveSelections(HWND hwnd, INT nFirst, INT nLast)
 {
-  LVITEMA lvItem;
-  INT i;
-
-  lvItem.state = 0;
-  lvItem.stateMask = LVIS_SELECTED;
-
-  for (i = nFirst; i <= nLast; i++)
-  {
-    ListView_SetItemState(hwnd, i, &lvItem);
-  }
+  LISTVIEW_RemoveSelectionRange(hwnd,nFirst,nLast);
 }
 
 /***
@@ -1789,6 +2162,10 @@
   BOOL bResult = FALSE;
   HDPA hdpaSubItems;
   INT nPosition, nItem;
+  LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
+
+  if (lStyle & LVS_OWNERDATA)
+    return FALSE;
 
   if (lpLVItem != NULL)
   {
@@ -1918,18 +2295,23 @@
   if (lStyle & LVS_OWNERDATA)
   {
     if ((lpLVItem->iSubItem == 0)&&(lpLVItem->mask == LVIF_STATE))
+    {
+      if (lpLVItem->stateMask & LVIS_FOCUSED)
       {
-        hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
-        if (hdpaSubItems != NULL)
-        {
-         lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
-         if (lpItem != NULL)
-         {
-          lpItem->state = lpLVItem->state & lpLVItem->stateMask;
-          return TRUE;
-         }
-        }
+        if (lpLVItem->state & LVIS_FOCUSED)
+          infoPtr->nFocusedItem = lpLVItem->iItem;
+        else if (infoPtr->nFocusedItem == lpLVItem->iItem)
+          infoPtr->nFocusedItem = -1;
       }
+      if (lpLVItem->stateMask & LVIS_SELECTED)
+      {
+        if (lpLVItem->state & LVIS_SELECTED)
+          LISTVIEW_AddSelectionRange(hwnd,lpLVItem->iItem,lpLVItem->iItem);
+        else
+          LISTVIEW_RemoveSelections(hwnd,lpLVItem->iItem,lpLVItem->iItem);
+      }
+     return TRUE;
+    }
     return FALSE;
   }
 
@@ -1966,9 +2348,11 @@
                  */
                 if (lStyle & LVS_SINGLESEL)
                 {
-                  LISTVIEW_RemoveSelections(hwnd, 0, lpLVItem->iItem-1);
-                  LISTVIEW_RemoveSelections(hwnd, lpLVItem->iItem + 1, 
-                                            GETITEMCOUNT(infoPtr));
+		  LISTVIEW_SetSelection(hwnd,lpLVItem->iItem);
+                }
+                else
+                {
+                  LISTVIEW_AddSelection(hwnd,lpLVItem->iItem);
                 }
 	      }
 	      else if (nmlv.uNewState & LVIS_FOCUSED)
@@ -2039,6 +2423,10 @@
   BOOL bResult = FALSE;
   HDPA hdpaSubItems;
   LISTVIEW_SUBITEM *lpSubItem;
+  LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
+
+  if (lStyle & LVS_OWNERDATA)
+    return FALSE;
 
   if (lpLVItem != NULL)
   {
@@ -2901,6 +3289,7 @@
 
 /* << LISTVIEW_CreateDragImage >> */
 
+
 /***
  * DESCRIPTION:
  * Removes all listview items and subitems.
@@ -2928,6 +3317,14 @@
   HDPA hdpaSubItems;
 
   TRACE("(hwnd=%x,)\n", hwnd);
+  LISTVIEW_RemoveAllSelections(hwnd);
+
+  if (lStyle & LVS_OWNERDATA)
+  {
+    infoPtr->hdpaItems->nItemCount = 0;
+    InvalidateRect(hwnd, NULL, TRUE);
+    return TRUE;
+  }
 
   if (GETITEMCOUNT(infoPtr) > 0)
   {
@@ -3035,7 +3432,7 @@
   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
   UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
   BOOL bResult = FALSE;
-  
+
   if (Header_DeleteItem(infoPtr->hwndHeader, nColumn) != FALSE)
   {
     bResult = LISTVIEW_RemoveColumn(infoPtr->hdpaItems, nColumn);
@@ -3084,6 +3481,15 @@
 
   TRACE("(hwnd=%x,nItem=%d)\n", hwnd, nItem);
 
+  LISTVIEW_ShiftSelections(hwnd,nItem,-1);
+
+  if (lStyle & LVS_OWNERDATA)
+  {
+    infoPtr->hdpaItems->nItemCount --;
+    InvalidateRect(hwnd, NULL, TRUE);
+    return TRUE;
+  }
+
   if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
   {
     /* initialize memory */
@@ -3209,14 +3615,32 @@
   LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
   HDPA hdpaSubItems;
   BOOL bUpdateItemText;
-  
-  ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
+  LISTVIEW_ITEM lvItemRef;
+  LVITEMA item;
 
-  if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
+  ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
+ 
+  if (!(lStyle & LVS_OWNERDATA))
+  {
+    if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
 	  return FALSE;
 
-  if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
+    if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
   	  return FALSE;
+  }
+  else
+  {
+    ZeroMemory(&lvItemRef,sizeof(LISTVIEW_ITEM));
+    ZeroMemory(&item,sizeof(LVITEMA));
+    item.iItem = nItem;
+    item.iSubItem = 0;
+    item.mask = LVIF_PARAM | LVIF_STATE;
+    ListView_GetItemA(hwnd,&item);
+    lvItemRef.state = item.state;
+    lvItemRef.iImage = item.iImage;
+    lvItemRef.lParam = item.lParam;
+    lpItem = &lvItemRef;
+  }
 
   dispInfo.hdr.hwndFrom = hwnd;
   dispInfo.hdr.idFrom = nCtrlId;
@@ -3269,7 +3693,9 @@
   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
   HDPA hdpaSubItems;
   CHAR szDispText[DISP_TEXT_SIZE];
-  LVITEMA lvItem;
+  LVITEMA lvItem,item;
+  LISTVIEW_ITEM lvItemRef;
+  LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
  
   if (~GetWindowLongA(hwnd, GWL_STYLE) & LVS_EDITLABELS)
       return FALSE;
@@ -3284,12 +3710,27 @@
   LISTVIEW_SetItemFocus(hwnd, nItem);
 
   ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
-  if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
-	  return 0;
-
-  if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
+  if (!(lStyle & LVS_OWNERDATA))
+  {
+    if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
   	  return 0;
 
+    if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
+  	  return 0;
+  } 
+  else
+  {
+    ZeroMemory(&lvItemRef,sizeof(LISTVIEW_ITEM));
+    ZeroMemory(&item,sizeof(LVITEMA));
+    item.iItem = nItem;
+    item.iSubItem = 0;
+    item.mask = LVIF_PARAM | LVIF_STATE;
+    ListView_GetItemA(hwnd,&item);
+    lvItemRef.iImage = item.iImage;
+    lvItemRef.state = item.state;
+    lvItemRef.lParam = item.lParam;
+    lpItem = &lvItemRef;
+  }
 
   /* get information needed for drawing the item */
   ZeroMemory(&lvItem, sizeof(LVITEMA));
@@ -4076,20 +4517,16 @@
 
     if ((lpLVItem->mask & LVIF_STATE)&&(lpLVItem->iSubItem == 0))
     {
-      hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
-      if (hdpaSubItems == NULL)
-          return FALSE;
-
-      lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
-      if (lpItem == NULL)
-          return FALSE;
-
-      lpLVItem->state = lpItem->state & lpLVItem->stateMask;
+      lpLVItem->state = 0; 
+      if (infoPtr->nFocusedItem == lpLVItem->iItem)
+        lpLVItem->state |= LVIS_FOCUSED;
+      if (LISTVIEW_IsSelected(hwnd,lpLVItem->iItem))
+        lpLVItem->state |= LVIS_SELECTED;
     }
 
     return TRUE;
   }
-   
+
 
   hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
   if (hdpaSubItems == NULL)
@@ -4194,10 +4631,20 @@
       lpLVItem->state = lpItem->state;
       lpLVItem->state &= ~dispInfo.item.stateMask;
       lpLVItem->state |= (dispInfo.item.state & dispInfo.item.stateMask);
+
+      lpLVItem->state &= ~LVIS_SELECTED;
+      if ((dispInfo.item.stateMask & LVIS_SELECTED) && 
+         (LISTVIEW_IsSelected(hwnd,dispInfo.item.iItem)))
+        lpLVItem->state |= LVIS_SELECTED;
     }
     else if (lpLVItem->mask & LVIF_STATE)
     {
       lpLVItem->state = lpItem->state & lpLVItem->stateMask;
+
+      lpLVItem->state &= ~LVIS_SELECTED;
+      if ((lpLVItem->stateMask & LVIS_SELECTED) && 
+          (LISTVIEW_IsSelected(hwnd,lpLVItem->iItem)))
+         lpLVItem->state |= LVIS_SELECTED;
     }
 
     if (lpLVItem->mask & LVIF_PARAM)
@@ -4284,7 +4731,7 @@
 
   TRACE("(hwnd=%x,nItem=%d,lpptPosition=%p)\n", hwnd, nItem, 
         lpptPosition);
-
+  
   if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && 
       (lpptPosition != NULL))
   {
@@ -5037,6 +5484,7 @@
  */
 static LRESULT LISTVIEW_GetSelectedCount(HWND hwnd)
 {
+/* REDO THIS */
   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
   INT nSelectedCount = 0;
   INT i;
@@ -5151,12 +5599,26 @@
 {
   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
   RECT rcItem;
-  INT i;
-  
+  INT i,topindex,bottomindex;
+  LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
+  UINT uView = lStyle & LVS_TYPEMASK;
+
+
   TRACE("(hwnd=%x, x=%ld, y=%ld)\n", hwnd, lpHitTestInfo->pt.x,
         lpHitTestInfo->pt.y);
 
-  for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
+  topindex = ListView_GetTopIndex(hwnd);
+  if (uView == LVS_REPORT)
+  {
+    bottomindex = topindex + LISTVIEW_GetCountPerColumn(hwnd) + 1;  
+    bottomindex = min(bottomindex,GETITEMCOUNT(infoPtr));
+  }
+  else
+  {
+    bottomindex = GETITEMCOUNT(infoPtr);
+  }
+
+  for (i = topindex; i < bottomindex; i++)
   {
     rcItem.left = LVIR_BOUNDS;
     if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
@@ -5427,42 +5889,9 @@
 
   if (lStyle & LVS_OWNERDATA)
   {
-      lpItem = (LISTVIEW_ITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM));
-      if (lpItem != NULL)
-      {
-        ZeroMemory(lpItem, sizeof(LISTVIEW_ITEM));
-        /* insert item in listview control data structure */
-        hdpaSubItems = DPA_Create(8);
-        if (hdpaSubItems != NULL)
-        {
-          nItem = DPA_InsertPtr(hdpaSubItems, 0, lpItem);
-          if (nItem != -1)
-          {
-               nItem = DPA_InsertPtr(infoPtr->hdpaItems, 1, 
-                                     hdpaSubItems);
-            /* manage item focus */
-            if ((lpLVItem)&&(lpLVItem->mask & LVIF_STATE))
-            {
-              lpItem->state &= ~(LVIS_FOCUSED|LVIS_SELECTED);
-              if (lpLVItem->stateMask & LVIS_SELECTED)
-              {
-                LISTVIEW_SetSelection(hwnd, nItem);
-              }
-              else if (lpLVItem->stateMask & LVIS_FOCUSED)
-              {
-                LISTVIEW_SetItemFocus(hwnd, nItem);
-              }           
-            }
-          }
-        }
-      }
-   /* free memory if unsuccessful */
-   if ((nItem == -1) && (lpItem != NULL))
-   {
-     COMCTL32_Free(lpItem);
-   }
-   
-   return nItem;
+    nItem = infoPtr->hdpaItems->nItemCount;
+    infoPtr->hdpaItems->nItemCount ++;
+    return nItem;
   }
 
   if (lpLVItem != NULL)
@@ -5501,6 +5930,8 @@
 	      }
               if (nItem != -1)
               {
+                LISTVIEW_ShiftSelections(hwnd,nItem,1);
+
                 /* manage item focus */
                 if (lpLVItem->mask & LVIF_STATE)
                 {
@@ -6118,19 +6549,19 @@
 
   if (GetWindowLongA(hwnd, GWL_STYLE) & LVS_OWNERDATA)
   {
-      int i;
+      int precount,topvisible;
       TRACE("LVS_OWNERDATA is set!\n");
-      if (nItems > infoPtr->hdpaItems->nItemCount)
-      {
-        for (i = infoPtr->hdpaItems->nItemCount; i<nItems; i++)
-          ListView_InsertItemA(hwnd,NULL);
-      }
-      else
-      {
-        for (i = nItems; i < infoPtr->hdpaItems->nItemCount; i++)
-          ListView_DeleteItem(hwnd,1);
-      }
-      RedrawWindow(hwnd,0,0,RDW_ERASE|RDW_INVALIDATE|RDW_UPDATENOW);
+
+      precount = infoPtr->hdpaItems->nItemCount;
+      topvisible = ListView_GetTopIndex(hwnd) +
+                   LISTVIEW_GetCountPerColumn(hwnd) + 1;
+
+      infoPtr->hdpaItems->nItemCount = nItems;
+
+      LISTVIEW_UpdateSize(hwnd);
+      LISTVIEW_UpdateScroll(hwnd);
+      if (min(precount,infoPtr->hdpaItems->nItemCount)<topvisible) 
+        InvalidateRect(hwnd, NULL, TRUE);
   }
   else
   {
@@ -6410,12 +6841,12 @@
     HDPA sortList;
     UINT lStyle = GetWindowLongA(hwnd, GWL_STYLE);
     
+    if (lStyle & LVS_OWNERDATA)
+      return FALSE;
+
     if (!infoPtr || !infoPtr->hdpaItems)
 	return FALSE;
    
-    if (lStyle & LVS_OWNERDATA)
-        return FALSE;
-    
     nCount = GETITEMCOUNT(infoPtr);
     /* if there are 0 or 1 items, there is no need to sort */
     if (nCount > 1)
@@ -6593,6 +7024,9 @@
   /* allocate memory for the data structure */
   infoPtr->hdpaItems = DPA_Create(10);
 
+  /* allocate memory for the selection ranges */
+  infoPtr->hdpaSelectionRanges = DPA_Create(10);
+
   /* initialize size of items */
   infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
   infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
@@ -7169,7 +7603,7 @@
   else
   {
     /* remove all selections */
-    LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
+    LISTVIEW_RemoveAllSelections(hwnd);
   }
 
   InvalidateRect(hwnd, NULL, TRUE);
@@ -7286,6 +7720,7 @@
 
   /* destroy data structure */
   DPA_Destroy(infoPtr->hdpaItems);
+  DPA_Destroy(infoPtr->hdpaSelectionRanges);
 
   /* destroy font */
   infoPtr->hFont = (HFONT)0;
@@ -7507,7 +7942,7 @@
   }
   else
   {
-    LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
+    LISTVIEW_RemoveAllSelections(hwnd);
   }
   
   return 0;
diff --git a/include/listview.h b/include/listview.h
index 36be26f..09572a8 100644
--- a/include/listview.h
+++ b/include/listview.h
@@ -40,6 +40,11 @@
 
 } LISTVIEW_ITEM;
 
+typedef struct tagLISTVIEW_SELECTION
+{
+  DWORD lower;
+  DWORD upper;
+} LISTVIEW_SELECTION;
 
 typedef struct tagLISTVIEW_INFO
 {
@@ -52,6 +57,7 @@
     BOOL bLButtonDown;
     BOOL bRButtonDown;
     INT nFocusedItem;
+    HDPA hdpaSelectionRanges;
     INT nItemHeight;
     INT nItemWidth;
     INT nSelectionMark;