internal void DrawScroller(Graphics g)
        {
            if ((leftRightImages == null) || (leftRightImages.Images.Count != 4))
                return;

            Rectangle clientArea = this.ClientRectangle;

              Win32.RECT r0 = new Win32.RECT();
            Win32.GetClientRect(scroller.Handle, ref r0);

              // Fill background of the scroller. Decrease width and height by 1 to
              // account for right and bottom borders which should not be used in drawing.
              r0.Right--;
              r0.Bottom--;
              Rectangle scrollerRect = new Rectangle(r0.Location, r0.Size);
            using (Brush br = new SolidBrush(SystemColors.Control))
            g.FillRectangle(br, scrollerRect);

              // Make a small outer border.
            using (Pen border = new Pen(SystemColors.ControlDark))
              {
            Rectangle rborder = scrollerRect;
            rborder.Inflate(-1, -1);
            g.DrawRectangle(border, rborder);
              }

            int nMiddle = (r0.Width / 2);
            int nTop = (r0.Height - leftRightImages.ImageSize.Height) / 2 + 1;
            int nLeft = (nMiddle - leftRightImages.ImageSize.Width) / 2;

            Rectangle r1 = new Rectangle(new Point(nLeft, nTop), leftRightImages.ImageSize);
            Rectangle r2 = new Rectangle(new Point(nMiddle + nLeft, nTop), leftRightImages.ImageSize);

            // Finally draw the buttons.
            Image img = leftRightImages.Images[1];
            if (img != null)
            {
                if (TabCount > 0)
                {
                    Rectangle r3 = this.GetTabRect(0);
                    if (r3.Left < clientArea.Left)
                        g.DrawImage(img, r1);
                    else
                    {
                        img = leftRightImages.Images[3];
                        if (img != null)
                            g.DrawImage(img, r1);
                    }
                }
            }

            img = leftRightImages.Images[0];
            if (img != null)
            {
                if (this.TabCount > 0)
                {
                    Rectangle r3 = this.GetTabRect(this.TabCount - 1);
                    if (r3.Right > (clientArea.Width - r0.Width))
                        g.DrawImage(img, r2);
                    else
                    {
                        img = leftRightImages.Images[2];
                        if (img != null)
                            g.DrawImage(img, r2);
                    }
                }
            }
        }
        /// <summary>
        /// Adjusts the scroll offset so that the given tab is in the visible area.
        /// </summary>
        /// <param name="index">The index of the tab to make visible.</param>
        /// <returns>True if an adjustment was necessary, otherwise False.</returns>
        public bool ScrollIntoView(int index)
        {
            bool result = false;
              if (index < 0 || index >= TabCount)
            return result;

              // If our bounds are empty then the application is likely minimized and we delay setting
              // the horizontal offset until we are restored.
              if (Width == 0 && Height == 0)
              {
            pendingScrollIntoViewIndex = index;
            return result;
              }

              Rectangle area = GetTabRect(index);
              if (area.Left < 0)
              {
            scrollOffset -= area.Left;
            result = true;
              }
              else
              {
            Win32.RECT rect = new Win32.RECT();
            if (scroller != null)
              Win32.GetClientRect(scroller.Handle, ref rect);

            int rightBorder = ClientSize.Width - Margin.Right - rect.Width - scrollerSpacing;
            if (area.Right > rightBorder)
            {
              scrollOffset -= area.Right - rightBorder;
              result = true;
            }
              }

              if (result && scroller != null)
            Win32.SendMessage(scroller.Handle, (int)UDM.SETPOS32, IntPtr.Zero, new IntPtr(-scrollOffset / scrollScaleFactor));
              return result;
        }
        private int ScrollerWndProc(ref Message m)
        {
            switch ((WM) m.Msg)
              {
            case WM.ERASEBKGND:
              m.Result = new IntPtr(1);
              break;

            case WM.PAINT:
              {
            IntPtr hDC = Win32.GetDC(m.HWnd);
            Graphics g = Graphics.FromHdc(hDC);
            DrawScroller(g);
            g.Dispose();
            Win32.ReleaseDC(m.HWnd, hDC);

            Win32.RECT clientArea = new Win32.RECT();
            Win32.GetClientRect(m.HWnd, ref clientArea);
            Win32.ValidateRect(m.HWnd, ref clientArea);

            // return 0 (processed)
            m.Result = IntPtr.Zero;

              }
              return 1;

            case (WM) UDM.SETRANGE:
              // The systab control sends this message when it wants to update the scroller, however
              // that works diametrically opposed to our own intents, so it is simply switched off here.
              // Our implementation uses UDM_SETRANGE32.
              m.Result = new IntPtr(1);
              return 1;

              }

              return 0;
        }
        private void UpdateScroller()
        {
            // Seems the scroll is sometimes re-created, so also check for a 0 handle.
              if (scroller == null || scroller.Handle == IntPtr.Zero)
            FindScroller();

              if (scroller != null)
              {
            if (tabStyle == TabStyleType.NoTabs)
            {
              scrollOffset = 0;
              Win32.ShowWindow(scroller.Handle, (int)SW.HIDE);
              return;
            }

            Win32.RECT rect = new Win32.RECT();
            Win32.GetClientRect(scroller.Handle, ref rect);
            int totalTabWidth = GetTotalTabWidth();

            int availableWidth = ClientSize.Width - Margin.Horizontal;
            if (totalTabWidth > availableWidth)
            {
              // Decrease available space also by that used of the scroller now.
              availableWidth -= rect.Width;
              Win32.ShowWindow(scroller.Handle, (int)SW.SHOWNOACTIVATE);

              // The scroll range is the number of steps (scaled pixels) we need to scroll over the full tab space.
              int scrollRange = (int) Math.Ceiling((totalTabWidth - availableWidth) / (float) scrollScaleFactor) +
            (int) ((scrollerSpacing / (float) scrollScaleFactor));
              Win32.SendMessage(scroller.Handle, (int) UDM.SETRANGE32, IntPtr.Zero, new IntPtr(scrollRange));

              // Make sure the scroll position is still ok before setting it in the scroller.
              // Always scroll so that the right border stays close to the scroller.
              Rectangle bounds = GetTabRect(TabCount - 1);
              if (bounds.Right < ClientSize.Width - Margin.Right - scrollerSpacing - rect.Width)
            scrollOffset += ClientSize.Width - Margin.Right - scrollerSpacing - rect.Width - bounds.Right;
              Win32.SendMessage(scroller.Handle, (int)UDM.SETPOS32, IntPtr.Zero, new IntPtr(-scrollOffset / scrollScaleFactor));

              // Disable scroll acceleration by setting a single scroll increment.
              Win32.UDACCEL acceleration = new Win32.UDACCEL();
              acceleration.nInc = 5;
              acceleration.nSec = 0;
              IntPtr parameter = Marshal.AllocHGlobal(Marshal.SizeOf(acceleration));
              Marshal.StructureToPtr(acceleration, parameter, true);
              Win32.SendMessage(scroller.Handle, (int)UDM.SETACCEL, new IntPtr(1), parameter);
              Marshal.FreeHGlobal(parameter);
            }
            else
            {
              scrollOffset = 0;
              Win32.ShowWindow(scroller.Handle, (int)SW.HIDE);
            }

            Win32.InvalidateRect(scroller.Handle, ref rect, true);
            int scrollerWidth = rect.Width;
            rect.Left = Width - scrollerWidth - Margin.Right;
            rect.Right = rect.Left + scrollerWidth;

            if (tabStyle == TabStyleType.BottomNormal)
              rect.Top = ClientSize.Height - ItemSize.Height - Margin.Bottom;
            else
              rect.Top = Margin.Top;

            rect.Bottom = rect.Top + ItemSize.Height;
            Win32.MoveWindow(scroller.Handle, rect.Left, rect.Top, rect.Width, rect.Height, true);
              }
        }
        protected override void OnSelectedIndexChanged(EventArgs e)
        {
            base.OnSelectedIndexChanged(e);

              ScrollIntoView(SelectedIndex);
              if (scroller != null)
              {
            Win32.RECT clientArea = new Win32.RECT();
            Win32.GetClientRect(scroller.Handle, ref clientArea);
            Win32.InvalidateRect(scroller.Handle, ref clientArea, false);
              }
            Invalidate();	// We need to update border and background colors.
        }