private void SetCurrentExtendedMultiSelectIndex(
            int newCaret, bool extendFromAnchor, bool preserveSelection, ModifySelectionAction selectCaretAction, bool select)
        {
            if (!GetStyleFlag(VTCStyleFlags.ExtendedMultiSelect) ||
                !IsHandleCreated)
            {
                return;
            }

            // We fire off a lot of messages in this routine. Go ahead and use DefWindowProc to
            // bypass all of the extra handling done in the various subclassing routines (WinForms and us)
            var hWnd      = Handle;
            var itemCount = (int)NativeMethods.SendMessage(hWnd, NativeMethods.LB_GETCOUNT, 0, 0);

            // Get the starting caret
            var startCaret = CaretIndex;

            var caretInitiallySelected = IsSelected(newCaret);

            // Get the initial anchor position
            var anchor = newCaret;

            if (extendFromAnchor)
            {
                anchor = AnchorIndex;
                if (anchor < 0)
                {
                    extendFromAnchor = false;
                    anchor           = newCaret;
                }
            }

            if ((anchor == newCaret && !preserveSelection) ||
                startCaret == newCaret)
            {
                SetSelected(newCaret, true);
            }
            else
            {
                // We're moving toward the anchor (the first two cases here), then the
                // remaining items are generally cleared with the !preverseSelection code
                // below, but we need to clear between the old and new carets even if we're
                // preserving selection elsewhere or things look really weird.
                if (newCaret >= anchor &&
                    startCaret > newCaret &&
                    startCaret > anchor)
                {
                    if (preserveSelection && extendFromAnchor)
                    {
                        SetSelectionRange(newCaret + 1, startCaret, false);
                    }
                }
                else if (newCaret <= anchor &&
                         startCaret < newCaret &&
                         startCaret < anchor)
                {
                    if (preserveSelection && extendFromAnchor)
                    {
                        SetSelectionRange(startCaret, newCaret - 1, false);
                    }
                }
                else
                {
                    // Select all items between the old and the new carets, inclusive. Not all of these
                    // items will be selectable items for multicolumn trees with blank expansions. However,
                    // these items will be filtered when the selected items are enumerated. We have to handle
                    // this state regardless because blocking the listbox from reaching this state when the
                    // user selects items with the mouse is extremely difficult (basically impossible). We
                    // could block here, but it is not worth creating the ColumnItemEnumerator.
                    SetSelectionRange(Math.Min(newCaret, startCaret), Math.Max(newCaret, startCaret), select);
                }
            }

            if (!preserveSelection)
            {
                var keepSelTop    = Math.Min(anchor, newCaret);
                var keepSelBottom = Math.Max(anchor, newCaret);
                // Use selitemrangeex with the lowest number last to clear
                if (keepSelTop > 0)
                {
                    SetSelectionRange(0, keepSelTop - 1, false);
                }
                if (keepSelBottom < itemCount - 1)
                {
                    SetSelectionRange(keepSelBottom + 1, itemCount - 1, false);
                }
            }

            switch (selectCaretAction)
            {
            case ModifySelectionAction.Clear:
                if (IsSelected(newCaret))
                {
                    SetSelected(newCaret, false);
                }
                else if (!caretInitiallySelected)
                {
                    selectCaretAction = ModifySelectionAction.None;     // nothing happened to the caret
                }
                break;

            case ModifySelectionAction.Select:
                if (!IsSelected(newCaret))
                {
                    SetSelected(newCaret, true);
                }
                else if (caretInitiallySelected)
                {
                    selectCaretAction = ModifySelectionAction.None;     // nothing happened to the caret
                }
                break;

            case ModifySelectionAction.Toggle:
                if (caretInitiallySelected)
                {
                    goto case ModifySelectionAction.Clear;
                }
                else
                {
                    goto case ModifySelectionAction.Select;
                }
            }

            // Some of the calls above will move the anchor index. Back sure it's where we want it.
            if (anchor != AnchorIndex)
            {
                AnchorIndex = anchor;
            }
            CaretIndex = newCaret;
            DoSelectionChanged();
            FireWinEventsForSelection(extendFromAnchor, preserveSelection, selectCaretAction);
        }
        /// <summary>
        ///     Fires WinEvents for given selection change.
        /// </summary>
        private void FireWinEventsForSelection(bool extendFromAnchor, bool preserveSelection, ModifySelectionAction caretAction)
        {
            if (GetStateFlag(VTCStateFlags.RestoringSelection))
            {
                return; // no events if we're restoring selection.
            }

            if (SelectionCount == 1)
            {
                // if there's currently only one thing selected, we know we should fire a regular selection event.
                if (VirtualTreeAccEvents.ShouldNotify(VirtualTreeAccEvents.eventObjectSelection, this))
                {
                    VirtualTreeAccEvents.Notify(
                        VirtualTreeAccEvents.eventObjectSelection, CurrentIndex,
                        CurrentColumn, this);
                }
            }
            else if (extendFromAnchor)
            {
                if (VirtualTreeAccEvents.ShouldNotify(VirtualTreeAccEvents.eventObjectSelectionWithin, this))
                {
                    // we extended selection from the anchor position, this constitutes a significant change in selection
                    // state, so we fire selection within from the tree control, and let clients query us for the result.
                    // UNDONE: querying currently won't work because we need a way to return an IEnumVariant from IAccessible::get_accSelection.
                    // We just fire selection for the caret instead.
                    // VirtualTreeAccEvents.Notify(VirtualTreeAccEvents.eventObjectSelectionWithin, VirtualTreeConstant.NullIndex,
                    //								 VirtualTreeConstant.NullIndex, this);
                    VirtualTreeAccEvents.Notify(
                        VirtualTreeAccEvents.eventObjectSelection, CurrentIndex,
                        CurrentColumn, this);
                }
            }
            else if (preserveSelection)
            {
                // we're preserving an original selection, which means that we fire either an add or a remove,
                // depending on what happened to the caret
                switch (caretAction)
                {
                case ModifySelectionAction.Select:
                    if (VirtualTreeAccEvents.ShouldNotify(VirtualTreeAccEvents.eventObjectSelectionAdd, this))
                    {
                        VirtualTreeAccEvents.Notify(
                            VirtualTreeAccEvents.eventObjectSelectionAdd, CurrentIndex,
                            CurrentColumn, this);
                    }
                    break;

                case ModifySelectionAction.Clear:
                    if (VirtualTreeAccEvents.ShouldNotify(VirtualTreeAccEvents.eventObjectSelectionRemove, this))
                    {
                        VirtualTreeAccEvents.Notify(
                            VirtualTreeAccEvents.eventObjectSelectionRemove, CurrentIndex,
                            CurrentColumn, this);
                    }
                    break;

                case ModifySelectionAction.Toggle:
                    if (IsSelected(CaretIndex))
                    {
                        goto case ModifySelectionAction.Select;
                    }
                    else
                    {
                        goto case ModifySelectionAction.Clear;
                    }

                case ModifySelectionAction.None:
                    // Caret position didn't change, but selection still changed overall.  This happens, for instance,
                    // during cross-column selection transfer.  We would ideally fire selection within here, for now
                    // we just fire selection at the caret position anyway.
                    if (VirtualTreeAccEvents.ShouldNotify(VirtualTreeAccEvents.eventObjectSelectionWithin, this))
                    {
                        //VirtualTreeAccEvents.Notify(VirtualTreeAccEvents.eventObjectSelectionWithin, VirtualTreeConstant.NullIndex,
                        //								VirtualTreeConstant.NullIndex, this);
                        VirtualTreeAccEvents.Notify(
                            VirtualTreeAccEvents.eventObjectSelection, CurrentIndex,
                            CurrentColumn, this);
                    }
                    break;
                }
            }
        }
 /// <summary>
 ///     Set the multi select caret index on the given item. Calling this with false, false will
 ///     make the new caret the only selected item.
 /// </summary>
 /// <param name="newCaret">The new caret position</param>
 /// <param name="extendFromAnchor">True to extend the selection from the current anchor position</param>
 /// <param name="preserveSelection">True to maintain selected items outside the anchored range</param>
 /// <param name="selectCaretAction">Specify how the selection state should be modified</param>
 public void SetCurrentExtendedMultiSelectIndex(
     int newCaret, bool extendFromAnchor, bool preserveSelection, ModifySelectionAction selectCaretAction)
 {
     SetCurrentExtendedMultiSelectIndex(newCaret, extendFromAnchor, preserveSelection, selectCaretAction, true);
 }
 /// <summary>
 ///     Locate and select an object in this control
 /// </summary>
 /// <param name="startingBranch">The branch to start the search from, or null for the root branch.</param>
 /// <param name="target">The object to locate</param>
 /// <param name="selectStyle">The object location style (sent to IBranch.LocateObject locateStyle parameter)</param>
 /// <param name="selectData">The object location data (sent to IBranch.LocateObject locateOptions parameter)</param>
 /// <param name="extendFromAnchor">Use when SelectionMode is ExtendedMultiSelect. True to extend the selection from the current anchor position</param>
 /// <param name="preserveSelection">Use when SelectionMode is ExtendedMultiSelect. True to maintain selected items outside the anchored range</param>
 /// <param name="selectCaretAction">Use when SelectionMode is ExtendedMultiSelect. Specify how the selection state should be modified</param>
 /// <returns>true if the item was selected</returns>
 public bool SelectObject(
     IBranch startingBranch, object target, int selectStyle, int selectData, bool extendFromAnchor, bool preserveSelection,
     ModifySelectionAction selectCaretAction)
 {
     if (myTree != null)
     {
         var locateTarget = myTree.LocateObject(startingBranch, target, selectStyle, selectData);
         if (locateTarget.IsValid)
         {
             var selectionColumn = mySelectionColumn;
             var targetColumn = locateTarget.Column;
             if (myColumnPermutation != null)
             {
                 targetColumn = myColumnPermutation.GetPermutedColumn(targetColumn);
                 if (targetColumn == -1)
                 {
                     // Item is not currently visible
                     return false;
                 }
             }
             if (GetStyleFlag(VTCStyleFlags.MultiSelect) && ExtendSelectionToAnchors)
             {
                 // If the target column is in the same blank expansion as the
                 // current column then we leave the selection column alone.
                 if (myTree.GetBlankExpansion(locateTarget.Row, selectionColumn, myColumnPermutation).AnchorColumn == targetColumn)
                 {
                     // Block if condition below
                     selectionColumn = targetColumn;
                 }
             }
             if (selectionColumn != targetColumn)
             {
                 SetSelectionColumn(locateTarget.Column, false);
             }
             if (GetStyleFlag(VTCStyleFlags.ExtendedMultiSelect))
             {
                 SetCurrentExtendedMultiSelectIndex(locateTarget.Row, extendFromAnchor, preserveSelection, selectCaretAction);
             }
             else
             {
                 CurrentIndex = locateTarget.Row;
             }
             return true;
         }
     }
     return false;
 }