// get rect of the v-scrollbar private NativeMethods.Win32Rect GetScrollbarRect() { NativeMethods.ScrollBarInfo sbi = new NativeMethods.ScrollBarInfo(); sbi.cbSize = Marshal.SizeOf(sbi.GetType()); if (Misc.GetScrollBarInfo(_hwnd, NativeMethods.OBJID_VSCROLL, ref sbi)) { return(new NativeMethods.Win32Rect(sbi.rcScrollBar.left, sbi.rcScrollBar.top, sbi.rcScrollBar.right, sbi.rcScrollBar.bottom)); } return(NativeMethods.Win32Rect.Empty); }
// ------------------------------------------------------ // // Private Methods // // ------------------------------------------------------ #region Private Methods // Create a new proxy for one of the scroll bit items private ProxySimple CreateScrollBitsItem(ScrollBarItem index) { // For Scrollbars as standalone controls, make sure that the buttons are not invisible. (office scroll bars) // Checking is done from the return value of SetScrolBarInfo. NativeMethods.ScrollBarInfo sbi = new NativeMethods.ScrollBarInfo(); sbi.cbSize = Marshal.SizeOf(sbi.GetType()); if (_sbFlag != NativeMethods.SB_CTL || Misc.GetScrollBarInfo(_hwnd, NativeMethods.OBJID_CLIENT, ref sbi)) { return(new WindowsScrollBarBits(_hwnd, this, (int)index, _sbFlag)); } return(null); }
// Check if a scroll bar is in a disabled state internal static bool IsScrollBarWithThumb(IntPtr hwnd, int sbFlag) { NativeMethods.ScrollInfo si = new NativeMethods.ScrollInfo(); si.cbSize = Marshal.SizeOf(si.GetType()); si.fMask = NativeMethods.SIF_RANGE | NativeMethods.SIF_PAGE; if (!Misc.GetScrollInfo(hwnd, sbFlag, ref si)) { return(false); } // Check for the min / max value if (si.nMax != si.nMin && si.nPage != si.nMax - si.nMin + 1) { // The scroll bar is enabled, check if we have a thumb int idObject = sbFlag == NativeMethods.SB_VERT ? NativeMethods.OBJID_VSCROLL : sbFlag == NativeMethods.SB_HORZ ? NativeMethods.OBJID_HSCROLL : NativeMethods.OBJID_CLIENT; NativeMethods.ScrollBarInfo sbi = new NativeMethods.ScrollBarInfo(); sbi.cbSize = Marshal.SizeOf(sbi.GetType()); // check that the 2 buttons can hold in the scroll bar if (Misc.GetScrollBarInfo(hwnd, idObject, ref sbi)) { // When the scroll bar is for a listbox within a combo and it is hidden, then // GetScrollBarInfo returns true but the rectangle is boggus! // 32 bits * 32 bits > 64 values long area = (sbi.rcScrollBar.right - sbi.rcScrollBar.left) * (sbi.rcScrollBar.bottom - sbi.rcScrollBar.top); if (area > 0 && area < 1000 * 1000) { NativeMethods.SIZE sizeArrow; using (ThemePart themePart = new ThemePart(hwnd, "SCROLLBAR")) { sizeArrow = themePart.Size((int)ThemePart.SCROLLBARPARTS.SBP_ARROWBTN, 0); } bool fThumbVisible = false; if (IsScrollBarVertical(hwnd, sbFlag)) { fThumbVisible = (sbi.rcScrollBar.bottom - sbi.rcScrollBar.top >= 5 * sizeArrow.cy / 2); } else { fThumbVisible = (sbi.rcScrollBar.right - sbi.rcScrollBar.left >= 5 * sizeArrow.cx / 2); } return(fThumbVisible); } } } return(false); }
// Finds if a control can be scrolled static internal bool Scrollable(IntPtr hwnd, int sbFlag) { int style = Misc.GetWindowStyle(hwnd); if ((sbFlag == NativeMethods.SB_HORZ && !Misc.IsBitSet(style, NativeMethods.WS_HSCROLL)) || (sbFlag == NativeMethods.SB_VERT && !Misc.IsBitSet(style, NativeMethods.WS_VSCROLL))) { return(false); } if (!Misc.IsEnabled(hwnd)) { return(false); } // Check if the scroll info shows the scroll bar as enabled. bool scrollBarEnabled = false; NativeMethods.ScrollBarInfo sbi = new NativeMethods.ScrollBarInfo(); sbi.cbSize = Marshal.SizeOf(sbi.GetType()); int scrollBarObjectId = (sbFlag == NativeMethods.SB_VERT) ? NativeMethods.OBJID_VSCROLL : NativeMethods.OBJID_HSCROLL; if (Misc.GetScrollBarInfo(hwnd, scrollBarObjectId, ref sbi)) { scrollBarEnabled = !Misc.IsBitSet(sbi.scrollBarInfo, NativeMethods.STATE_SYSTEM_UNAVAILABLE); } if (!scrollBarEnabled) { return(false); } // Get scroll range NativeMethods.ScrollInfo si = new NativeMethods.ScrollInfo(); si.cbSize = Marshal.SizeOf(si.GetType()); si.fMask = NativeMethods.SIF_ALL; if (!Misc.GetScrollInfo(hwnd, sbFlag, ref si)) { return(false); } return(si.nMax != si.nMin && si.nPage != si.nMax - si.nMin + 1); }
// Check if a scroll bar implements the Value Pattern private static bool HasValuePattern(IntPtr hwnd, int sbFlag) { // The scroll bar is enabled, check if we have a thumb int idObject = sbFlag == NativeMethods.SB_VERT ? NativeMethods.OBJID_VSCROLL : sbFlag == NativeMethods.SB_HORZ ? NativeMethods.OBJID_HSCROLL : NativeMethods.OBJID_CLIENT; NativeMethods.ScrollBarInfo sbi = new NativeMethods.ScrollBarInfo(); sbi.cbSize = Marshal.SizeOf(sbi.GetType()); // Scroll bars implements the Value pattern if // 1) they are owner drawn (in which case GetScrollBarInfo fails) // 2) they have a thumb (not completely squished) if (Misc.GetScrollBarInfo(hwnd, idObject, ref sbi)) { return(IsScrollBarWithThumb(hwnd, sbFlag)); } return(true); }
private bool IsEnabled() { NativeMethods.ScrollBarInfo sbi = new NativeMethods.ScrollBarInfo(); sbi.cbSize = Marshal.SizeOf(sbi.GetType()); int idObject = NativeMethods.OBJID_CLIENT; if (_sbFlag == NativeMethods.SB_VERT) { idObject = NativeMethods.OBJID_VSCROLL; } else if (_sbFlag == NativeMethods.SB_HORZ) { idObject = NativeMethods.OBJID_HSCROLL; } if (!Misc.GetScrollBarInfo(_hwnd, idObject, ref sbi)) { return(false); } return(!Misc.IsBitSet(sbi.scrollBarInfo, NativeMethods.STATE_SYSTEM_UNAVAILABLE)); }
// ------------------------------------------------------ // // Internal Methods // // ------------------------------------------------------ #region Internal Methods // Static implementation for the bounding rectangle. This is used by // ElementProviderFromPoint to avoid to have to create for a simple // boundary check // param "item", ID for the scrollbar bit // param "sbFlag", SBS_ WindowLong equivallent flag static internal Rect GetHorizontalScrollbarBitBoundingRectangle(IntPtr hwnd, WindowsScrollBar.ScrollBarItem item, NativeMethods.ScrollBarInfo sbi) { // Horizontal Scrollbar NativeMethods.Win32Rect rc = new NativeMethods.Win32Rect(sbi.xyThumbTop, sbi.rcScrollBar.top, sbi.xyThumbBottom, sbi.rcScrollBar.bottom); if (!Misc.MapWindowPoints(hwnd, IntPtr.Zero, ref rc, 2)) { return(Rect.Empty); } // Since the scrollbar position is already mapped, restore them back rc.top = sbi.rcScrollBar.top; rc.bottom = sbi.rcScrollBar.bottom; NativeMethods.SIZE sizeArrow; using (ThemePart themePart = new ThemePart(hwnd, "SCROLLBAR")) { sizeArrow = themePart.Size((int)ThemePart.SCROLLBARPARTS.SBP_ARROWBTN, 0); } // check that the 2 buttons can hold in the scroll bar bool fThumbVisible = sbi.rcScrollBar.right - sbi.rcScrollBar.left >= 5 * sizeArrow.cx / 2; if (sbi.rcScrollBar.right - sbi.rcScrollBar.left < 2 * sizeArrow.cx) { // the scroll bar is tiny, need to shrink the button sizeArrow.cx = (sbi.rcScrollBar.right - sbi.rcScrollBar.left) / 2; } // // Builds prior to Vista 5359 failed to correctly account for RTL scrollbar layouts. // if ((Environment.OSVersion.Version.Major < 6) && (Misc.IsLayoutRTL(hwnd))) { if (item == WindowsScrollBar.ScrollBarItem.UpArrow) { item = WindowsScrollBar.ScrollBarItem.DownArrow; } else if (item == WindowsScrollBar.ScrollBarItem.DownArrow) { item = WindowsScrollBar.ScrollBarItem.UpArrow; } else if (item == WindowsScrollBar.ScrollBarItem.LargeIncrement) { item = WindowsScrollBar.ScrollBarItem.LargeDecrement; } else if (item == WindowsScrollBar.ScrollBarItem.LargeDecrement) { item = WindowsScrollBar.ScrollBarItem.LargeIncrement; } } switch (item) { case WindowsScrollBar.ScrollBarItem.UpArrow: rc.left = sbi.rcScrollBar.left; rc.right = sbi.rcScrollBar.left + sizeArrow.cx; break; case WindowsScrollBar.ScrollBarItem.LargeIncrement: if (fThumbVisible) { rc.left = rc.right; rc.right = sbi.rcScrollBar.right - sizeArrow.cx; } else { rc.left = rc.right = sbi.rcScrollBar.left + sizeArrow.cx; } break; case WindowsScrollBar.ScrollBarItem.Thumb: if (!fThumbVisible) { rc.left = rc.right = sbi.rcScrollBar.left + sizeArrow.cx; } break; case WindowsScrollBar.ScrollBarItem.LargeDecrement: if (fThumbVisible) { rc.right = rc.left; rc.left = sbi.rcScrollBar.left + sizeArrow.cx; } else { rc.left = rc.right = sbi.rcScrollBar.left + sizeArrow.cx; } break; case WindowsScrollBar.ScrollBarItem.DownArrow: rc.left = sbi.rcScrollBar.right - sizeArrow.cx; rc.right = sbi.rcScrollBar.right; break; } // Don't need to normalize, OSVer conditional block converts to absolute coordinates. return(rc.ToRect(false)); }
// ------------------------------------------------------ // // Internal Methods // // ------------------------------------------------------ #region Internal Methods // Static implementation for the bounding rectangle. This is used by // ElementProviderFromPoint to avoid to have to create for a simple // boundary check // param "item", ID for the scrollbar bit // param "sbFlag", SBS_ WindowLong equivallent flag static internal Rect GetVerticalScrollbarBitBoundingRectangle(IntPtr hwnd, WindowsScrollBar.ScrollBarItem item, NativeMethods.ScrollBarInfo sbi) { NativeMethods.Win32Rect rc = new NativeMethods.Win32Rect(sbi.rcScrollBar.left, sbi.xyThumbTop, sbi.rcScrollBar.right, sbi.xyThumbBottom); if (!Misc.MapWindowPoints(hwnd, IntPtr.Zero, ref rc, 2)) { return(Rect.Empty); } // Vertical Scrollbar // Since the scrollbar position is already mapped, restore them back rc.left = sbi.rcScrollBar.left; rc.right = sbi.rcScrollBar.right; NativeMethods.SIZE sizeArrow; using (ThemePart themePart = new ThemePart(hwnd, "SCROLLBAR")) { sizeArrow = themePart.Size((int)ThemePart.SCROLLBARPARTS.SBP_ARROWBTN, 0); } // check that the 2 buttons can hold in the scroll bar bool fThumbVisible = sbi.rcScrollBar.bottom - sbi.rcScrollBar.top >= 5 * sizeArrow.cy / 2; if (sbi.rcScrollBar.bottom - sbi.rcScrollBar.top < 2 * sizeArrow.cy) { // the scroll bar is tiny, need to shrink the button sizeArrow.cy = (sbi.rcScrollBar.bottom - sbi.rcScrollBar.top) / 2; } switch (item) { case WindowsScrollBar.ScrollBarItem.UpArrow: rc.top = sbi.rcScrollBar.top; rc.bottom = sbi.rcScrollBar.top + sizeArrow.cy; break; case WindowsScrollBar.ScrollBarItem.LargeIncrement: if (fThumbVisible) { rc.top = rc.bottom; rc.bottom = sbi.rcScrollBar.bottom - sizeArrow.cy; } else { rc.top = rc.bottom = sbi.rcScrollBar.top + sizeArrow.cy; } break; case WindowsScrollBar.ScrollBarItem.Thumb: if (!fThumbVisible) { rc.top = rc.bottom = sbi.rcScrollBar.top + sizeArrow.cy; } break; case WindowsScrollBar.ScrollBarItem.LargeDecrement: if (fThumbVisible) { rc.bottom = rc.top; rc.top = sbi.rcScrollBar.top + sizeArrow.cy; } else { rc.top = rc.bottom = sbi.rcScrollBar.top + sizeArrow.cy; } break; case WindowsScrollBar.ScrollBarItem.DownArrow: rc.top = sbi.rcScrollBar.bottom - sizeArrow.cy; rc.bottom = sbi.rcScrollBar.bottom; break; } // Don't need to normalize, OSVer conditional block converts to absolute coordinates. return(rc.ToRect(false)); }
// ------------------------------------------------------ // // Internal Methods // // ------------------------------------------------------ #region Internal Methods // Static implementation for the bounding rectangle. This is used by // ElementProviderFromPoint to avoid to have to create for a simple // boundary check // param "item", ID for the scrollbar bit // param "sbFlag", SBS_ WindowLong equivallent flag static internal Rect GetBoundingRectangle(IntPtr hwnd, ProxyFragment parent, WindowsScrollBar.ScrollBarItem item, int sbFlag) { NativeMethods.ScrollInfo si = new NativeMethods.ScrollInfo(); si.cbSize = Marshal.SizeOf(si.GetType()); si.fMask = NativeMethods.SIF_RANGE; // If the scroll bar is disabled, we cannot have a thumb and large Increment/Decrement) bool fDisableScrollBar = !WindowsScrollBar.IsScrollBarWithThumb(hwnd, sbFlag); if (fDisableScrollBar && (item == WindowsScrollBar.ScrollBarItem.LargeDecrement || item == WindowsScrollBar.ScrollBarItem.Thumb || item == WindowsScrollBar.ScrollBarItem.LargeDecrement)) { return(Rect.Empty); } // If fails assume that the hwnd is invalid if (!Misc.GetScrollInfo(hwnd, sbFlag, ref si)) { return(Rect.Empty); } int idObject = sbFlag == NativeMethods.SB_VERT ? NativeMethods.OBJID_VSCROLL : sbFlag == NativeMethods.SB_HORZ ? NativeMethods.OBJID_HSCROLL : NativeMethods.OBJID_CLIENT; NativeMethods.ScrollBarInfo sbi = new NativeMethods.ScrollBarInfo(); sbi.cbSize = Marshal.SizeOf(sbi.GetType()); if (!Misc.GetScrollBarInfo(hwnd, idObject, ref sbi)) { return(Rect.Empty); } if (parent != null && parent._parent != null) { // // Builds prior to Vista 5359 failed to correctly account for RTL scrollbar layouts. // if ((Environment.OSVersion.Version.Major < 6) && (Misc.IsLayoutRTL(parent._parent._hwnd))) { // Right to left mirroring style Rect rcParent = parent._parent.BoundingRectangle; int width = sbi.rcScrollBar.right - sbi.rcScrollBar.left; if (sbFlag == NativeMethods.SB_VERT) { int offset = (int)rcParent.Right - sbi.rcScrollBar.right; sbi.rcScrollBar.left = (int)rcParent.Left + offset; sbi.rcScrollBar.right = sbi.rcScrollBar.left + width; } else { int offset = sbi.rcScrollBar.left - (int)rcParent.Left; sbi.rcScrollBar.right = (int)rcParent.Right - offset; sbi.rcScrollBar.left = sbi.rcScrollBar.right - width; } } } // When the scroll bar is for a listbox within a combo and it is hidden, then // GetScrollBarInfo returns true but the rectangle is boggus! // 32 bits * 32 bits > 64 values // // Note that this test must come after the rectangle has been normalized for RTL or it will fail // long area = (sbi.rcScrollBar.right - sbi.rcScrollBar.left) * (sbi.rcScrollBar.bottom - sbi.rcScrollBar.top); if (area <= 0 || area > 1000 * 1000) { // Ridiculous value assume error return(Rect.Empty); } if (WindowsScrollBar.IsScrollBarVertical(hwnd, sbFlag)) { return(GetVerticalScrollbarBitBoundingRectangle(hwnd, item, sbi)); } else { return(GetHorizontalScrollbarBitBoundingRectangle(hwnd, item, sbi)); } }
internal static extern bool GetScrollBarInfo(IntPtr hwnd, int fnBar, [In, Out] ref NativeMethods.ScrollBarInfo lpsi);