//------------------------------------------------------ // // Public Methods // //------------------------------------------------------ #region Public Methods // We will not always find the clickable point. There are times when it would take so long // to locate the point that it is just not worth it, so make a reason effort than quit. public static bool HitTestForClickablePoint(AutomationElement el, out Point pt) { Rect rect = el.Current.BoundingRectangle; pt = new Point(0, 0); if (rect.Left >= rect.Right || rect.Top >= rect.Bottom) return false; // if this is not on any monitor than there is no point in going on. If the element is // off the screen hit testing actually works and would end up returning a point offscreen. NativeMethods.RECT winRect = new NativeMethods.RECT((int)rect.Left, (int)rect.Top, (int)rect.Height, (int)rect.Bottom); if (SafeNativeMethods.MonitorFromRect( ref winRect, SafeNativeMethods.MONITOR_DEFAULTTONULL ) == IntPtr.Zero) return false; // try the center point first pt = new Point((rect.Left + rect.Right) / 2, (rect.Top + rect.Bottom) / 2); AutomationElement hitElement; if ( TryPoint( ref pt, el, out hitElement ) ) return true; if ( IsTopLevelWindowObscuring( el, rect, hitElement ) ) return false; // before we start hit testing more there are some control types that we know where the // clickable point is or we know does not have a clickable point so take care of those here. if ( el.Current.ControlType == ControlType.ScrollBar ) return false; // Try the mid point of all four sides pt = new Point(rect.Left + (rect.Width /2), rect.Top + 1); if ( TryPoint( ref pt, el ) ) return true; pt = new Point(rect.Left + (rect.Width /2), rect.Bottom - 1); if ( TryPoint( ref pt, el ) ) return true; pt = new Point( rect.Left + 1, rect.Top + (rect.Height /2) ); if ( TryPoint( ref pt, el) ) return true; pt = new Point( rect.Right - 1, rect.Top + (rect.Height /2) ); if ( TryPoint( ref pt, el ) ) return true; if ( TrySparsePattern( out pt, ref rect, el ) ) return true; if ( TryLinePattern( out pt, ref rect, el ) ) return true; return false; }
override protected Rect GetBoundingRectangleCore() { Window window = (Window)Owner; Rect bounds = new Rect(0,0,0,0); if(!window.IsSourceWindowNull) { NativeMethods.RECT rc = new NativeMethods.RECT(0,0,0,0); IntPtr windowHandle = window.CriticalHandle; if(windowHandle != IntPtr.Zero) //it is Zero on a window that was just closed { try { SafeNativeMethods.GetWindowRect(new HandleRef(null, windowHandle), ref rc); } // Allow empty catch statements. #pragma warning disable 56502 catch(Win32Exception) {} // Disallow empty catch statements. #pragma warning restore 56502 } bounds = new Rect(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top); } return bounds; }
/// ------------------------------------------------------------------- /// <summary> /// Get the window rect using the Win32 API GetWindowRect. If there is /// a buddy control (ie. Spinner), then take the union of the element's /// bounding rectangle, and the buddy controls bounding rectangle. /// </summary> /// ------------------------------------------------------------------- private void TS_GetWin32GetWindowRect(AutomationElement element, out Rect rectObject, CheckType checktype) { NativeMethods.RECT rcObject = new NativeMethods.RECT(); NativeMethods.RECT rcBuddy = new NativeMethods.RECT(); Rect rectBuddy = new Rect(); IntPtr intPtrElement = Helpers.CastNativeWindowHandleToIntPtr(element); if (intPtrElement == IntPtr.Zero) ThrowMe(checktype, "Could not get a window handle to the element"); // Get the AutomationElement Win32 bounding rectangle SafeNativeMethods.GetWindowRect(intPtrElement, ref rcObject); rectObject = new Rect(rcObject.left, rcObject.top, rcObject.right - rcObject.left, rcObject.bottom - rcObject.top); // If this has a buddy control, get it and it's bounding rectangle IntPtr hwndBuddy = Helpers.SendMessage(intPtrElement, NativeMethods.UDM_GETBUDDY, IntPtr.Zero, IntPtr.Zero); if (hwndBuddy != IntPtr.Zero) { SafeNativeMethods.GetWindowRect(hwndBuddy, ref rcBuddy); rectBuddy = new Rect(rcBuddy.left, rcBuddy.top, rcBuddy.right - rcBuddy.left, rcBuddy.bottom - rcBuddy.top); rectObject = Rect.Union(rectBuddy, rectObject); } m_TestStep++; }
internal static extern bool AdjustWindowRectExForDpi( [In][Out] ref NativeMethods.RECT lpRect, [In] int dwStyle, [In][MarshalAs(UnmanagedType.Bool)] bool bMenu, [In] int dwExStyle, [In] int dpi);
private NativeMethods.POINT GetWindowScreenLocation(FlowDirection flowDirection) { Debug.Assert(IsSourceWindowNull != true, "IsSourceWindowNull cannot be true here"); NativeMethods.POINT pt = new NativeMethods.POINT(0, 0); if (flowDirection == FlowDirection.RightToLeft) { NativeMethods.RECT rc = new NativeMethods.RECT(0, 0, 0, 0); // with RTL window, GetClientRect returns reversed coordinates SafeNativeMethods.GetClientRect(new HandleRef(this, CriticalHandle), ref rc); // note that we use rc.right here for the RTL case and client to screen that point pt = new NativeMethods.POINT(rc.right, rc.top); } UnsafeNativeMethods.ClientToScreen(new HandleRef(this, _sourceWindow.CriticalHandle), pt); return pt; }
private void PossiblyDeactivate(IntPtr hwndCapture, bool stillActiveIfOverSelf) { // we may have been disposed by a re-entrant call (bug 1536643). // If so, there's nothing more to do. if (null == _source || null == _source.Value ) { return; } if(_isDwmProcess) { return; } //Console.WriteLine("PossiblyDeactivate(" + hwndCapture + ")"); // We are now longer active ourselves, but it is possible that the // window the mouse is going to intereact with is in the same // Dispatcher as ourselves. If so, we don't want to deactivate the // mouse input stream because the other window hasn't activated it // yet, and it may result in the input stream "flickering" between // active/inactive/active. This is ugly, so we try to supress the // uneccesary transitions. // IntPtr hwndToCheck = hwndCapture; if(hwndToCheck == IntPtr.Zero) { NativeMethods.POINT ptCursor = new NativeMethods.POINT(); int messagePos = 0; try { messagePos = SafeNativeMethods.GetMessagePos(); } catch(System.ComponentModel.Win32Exception) { System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: GetMessagePos failed!"); } ptCursor.x = NativeMethods.SignedLOWORD(messagePos); ptCursor.y = NativeMethods.SignedHIWORD(messagePos); //Console.WriteLine(" GetMessagePos: ({0},{1})", ptCursor.x, ptCursor.y); try { hwndToCheck = UnsafeNativeMethods.WindowFromPoint(ptCursor.x, ptCursor.y); } catch(System.ComponentModel.Win32Exception) { System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: WindowFromPoint failed!"); } if (!stillActiveIfOverSelf && hwndToCheck == _source.Value.CriticalHandle) { hwndToCheck = IntPtr.Zero; } if(hwndToCheck != IntPtr.Zero) { // We need to check if the point is over the client or // non-client area. We only care about being over the // non-client area. try { NativeMethods.RECT rcClient = new NativeMethods.RECT(); SafeNativeMethods.GetClientRect(new HandleRef(this,hwndToCheck), ref rcClient); SafeNativeMethods.ScreenToClient(new HandleRef(this,hwndToCheck), ptCursor); if(ptCursor.x < rcClient.left || ptCursor.x >= rcClient.right || ptCursor.y < rcClient.top || ptCursor.y >= rcClient.bottom) { // We are not over the non-client area. We can bail out. //Console.WriteLine(" No capture, mouse outside of client area."); //Console.WriteLine(" Client Area: ({0},{1})-({2},{3})", rcClient.left, rcClient.top, rcClient.right, rcClient.bottom); //Console.WriteLine(" Mouse: ({0},{1})", ptCursor.x, ptCursor.y); hwndToCheck = IntPtr.Zero; } } catch(System.ComponentModel.Win32Exception) { System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: GetClientRect or ScreenToClient failed!"); } } } // If the window the mouse is over is ours, we'll just let it activate // without deactivating the mouse input stream for this window. This prevents // the mouse input stream from flickering. bool deactivate = !IsOurWindow(hwndToCheck); //Console.WriteLine(" Deactivate=" + deactivate); // Only deactivate the mouse input stream if needed. if(deactivate) { ReportInput(_source.Value.CriticalHandle, InputMode.Foreground, _msgTime, RawMouseActions.Deactivate, 0, 0, 0); } else { // We are not deactivating the mouse input stream because the // window that is going to provide mouse input next is one of // our Avalon windows. This optimization keeps the mouse input // stream from flickering by transitioning to null. // // But this window itself should not be active anymore. _active = false; } }
/// <summary> /// Converts a rectangle from an Avalon Rect to a Win32 RECT /// </summary> /// <remarks> /// Rounds "double" values to the nearest "int" /// </remarks> /// <param name="rect"> /// The rectangle as an Avalon Rect /// </param> /// <returns> /// The rectangle as a Win32 RECT /// </returns> internal static NativeMethods.RECT FromRect(Rect rect) { NativeMethods.RECT rc = new NativeMethods.RECT(); rc.top = DoubleUtil.DoubleToInt(rect.Y); rc.left = DoubleUtil.DoubleToInt(rect.X); rc.bottom = DoubleUtil.DoubleToInt(rect.Bottom); rc.right = DoubleUtil.DoubleToInt(rect.Right); return rc; }
/// <summary> /// Adjusts a POINT to compensate for Win32 RTL conversion logic /// </summary> /// <remarks> /// MITIGATION: AVALON_RTL_AND_WIN32RTL /// /// When a window is marked with the WS_EX_LAYOUTRTL style, Win32 /// mirrors the coordinates during the various translation APIs. /// /// Avalon also sets up mirroring transforms so that we properly /// mirror the output since we render to DirectX, not a GDI DC. /// /// Unfortunately, this means that our coordinates are already mirrored /// by Win32, and Avalon mirrors them again. To work around this /// problem, we un-mirror the coordinates from Win32 before hit-testing /// in Avalon. /// </remarks> /// <param name="pt"> /// The POINT to be adjusted /// </param> /// <param name="handleRef"> /// A HandleRef to the hwnd containing the point to be adjusted /// </param> /// <returns> /// The adjusted point /// </returns> internal static NativeMethods.POINT AdjustForRightToLeft(NativeMethods.POINT pt, HandleRef handleRef) { int windowStyle = SafeNativeMethods.GetWindowStyle(handleRef, true); if(( windowStyle & NativeMethods.WS_EX_LAYOUTRTL ) == NativeMethods.WS_EX_LAYOUTRTL) { NativeMethods.RECT rcClient = new NativeMethods.RECT(); SafeNativeMethods.GetClientRect(handleRef, ref rcClient); pt.x = rcClient.right - pt.x; } return pt; }
private void UpdateWindowPos(IntPtr lParam) { // // We need to update the window settings used by the render thread when // 1) The size or position of the render target needs to change // 2) The render target needs to be enabled or disabled. // // Further, we need to synchronize the render thread during sizing operations. // This is because some APIs that the render thread uses (such as // UpdateLayeredWindow) have the unintended side-effect of also changing the // window size. We can't let the render thread and the UI thread fight // over setting the window size. // // Generally, Windows sends our window to messages that bracket the size // operation: // 1) WM_WINDOWPOSCHANGING // Here we synchronize with the render thread, and ask the render thread // to not render to this window for a while. // 2) WM_WINDOWPOSCHANGED // This is after the window size has actually been changed, so we tell // the render thread that it can render to the window again. // // However, there are complications. Sometimes Windows will send a // WM_WINDOWPOSCHANGING without sending a WM_WINDOWPOSCHANGED. This happens // when the window size is not really going to change. Also note that // more than just size/position information is provided by these messages. // We'll get these messages when nothing but the z-order changes for instance. // // // The first order of business is to determine if the render target // size or position changed. If so, we need to pass this information to // the render thread. // NativeMethods.WINDOWPOS windowPos = (NativeMethods.WINDOWPOS)UnsafeNativeMethods.PtrToStructure(lParam, typeof(NativeMethods.WINDOWPOS)); bool isMove = (windowPos.flags & NativeMethods.SWP_NOMOVE) == 0; bool isSize = (windowPos.flags & NativeMethods.SWP_NOSIZE) == 0; bool positionChanged = (isMove || isSize); if (positionChanged) { // // We have found that sometimes we get told that the size or position // of the window has changed, when it really hasn't. So we double // check here. This is critical because we won't be given a // WM_WINDOWPOSCHANGED unless the size or position really had changed. // if (!isMove) { // This is just to avoid any possible integer overflow problems. windowPos.x = windowPos.y = 0; } if (!isSize) { // This is just to avoid any possible integer overflow problems. windowPos.cx = windowPos.cy = 0; } // // WINDOWPOS stores the window coordinates relative to its parent. // If the parent is NULL, then these are already screen coordinates. // Otherwise, we need to convert to screen coordinates. // NativeMethods.RECT windowRectInScreenCoords = new NativeMethods.RECT(windowPos.x, windowPos.y, windowPos.x + windowPos.cx, windowPos.y + windowPos.cy); IntPtr hwndParent = UnsafeNativeMethods.GetParent(new HandleRef(null, windowPos.hwnd)); if(hwndParent != IntPtr.Zero) { SafeSecurityHelper.TransformLocalRectToScreen(new HandleRef(null, hwndParent), ref windowRectInScreenCoords); } if (!isMove) { // We weren't actually moving, so the WINDOWPOS structure // did not contain valid (x,y) information. Just use our // old values. int width = (windowRectInScreenCoords.right - windowRectInScreenCoords.left); int height = (windowRectInScreenCoords.bottom - windowRectInScreenCoords.top); windowRectInScreenCoords.left = _hwndWindowRectInScreenCoords.left; windowRectInScreenCoords.right = windowRectInScreenCoords.left + width; windowRectInScreenCoords.top = _hwndWindowRectInScreenCoords.top; windowRectInScreenCoords.bottom = windowRectInScreenCoords.top + height; } if (!isSize) { // We weren't actually sizing, so the WINDOWPOS structure // did not contain valid (cx,cy) information. Just use our // old values. int width = (_hwndWindowRectInScreenCoords.right - _hwndWindowRectInScreenCoords.left); int height = (_hwndWindowRectInScreenCoords.bottom - _hwndWindowRectInScreenCoords.top); windowRectInScreenCoords.right = windowRectInScreenCoords.left + width; windowRectInScreenCoords.bottom = windowRectInScreenCoords.top + height; } positionChanged = ( _hwndWindowRectInScreenCoords.left != windowRectInScreenCoords.left || _hwndWindowRectInScreenCoords.top != windowRectInScreenCoords.top || _hwndWindowRectInScreenCoords.right != windowRectInScreenCoords.right || _hwndWindowRectInScreenCoords.bottom != windowRectInScreenCoords.bottom); } // // The second order of business is to determine whether or not the render // target should be enabled. If we are disabling the render target, then // we need to synchronize with the render thread. Basically, // a WM_WINDOWPOSCHANGED always enables the render target it the window is // visible. And a WM_WINDOWPOSCHANGING will disable the render target // unless it is not really a size/move, in which case we will not be sent // a WM_WINDOWPOSCHANGED, so we can't disable the render target. // bool enableRenderTarget = SafeNativeMethods.IsWindowVisible(_hWnd.MakeHandleRef(this)); if(enableRenderTarget) { if(_windowPosChanging && (positionChanged)) { enableRenderTarget = false; } } if (positionChanged || (enableRenderTarget != _isRenderTargetEnabled)) { UpdateWindowSettings(enableRenderTarget); } }
override protected Rect GetBoundingRectangleCore() { Rect bounds = new Rect(0,0,0,0); IntPtr hwnd = this.Hwnd; if(hwnd != IntPtr.Zero) { NativeMethods.RECT rc = new NativeMethods.RECT(0,0,0,0); try { //This method elevates via SuppressUnmanadegCodeSecurity and throws Win32Exception on GetLastError SafeNativeMethods.GetWindowRect(new HandleRef(null, hwnd), ref rc); } // Allow empty catch statements. #pragma warning disable 56502 catch(Win32Exception) {} // Disallow empty catch statements. #pragma warning restore 56502 bounds = new Rect(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top); } return bounds; }
internal static extern bool GetWindowRect(IntPtr hwnd, ref NativeMethods.RECT rect);
//------------------------------------------------------ // // Interface ITransformProvider // //------------------------------------------------------ #region Interface ITransformProvider void ITransformProvider.Move( double x, double y ) { if ( ! ((ITransformProvider)this).CanMove ) throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); int extendedStyle = GetWindowExStyle(); if ( IsBitSet(extendedStyle, SafeNativeMethods.WS_EX_MDICHILD) ) { // we always deal in screen pixels. But if its an MDI window it interprets these as // client pixels so convert them to get the expected results. NativeMethods.POINT point = new NativeMethods.POINT((int)x, (int)y); NativeMethods.HWND hwndParent = SafeNativeMethods.GetAncestor(NativeMethods.HWND.Cast(_hwnd), SafeNativeMethods.GA_PARENT); if (!MapWindowPoints(NativeMethods.HWND.NULL, hwndParent, ref point, 1)) { throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); } x = point.x; y = point.y; // Make sure the MDI child stays on the parents client area. NativeMethods.RECT currentRect = new NativeMethods.RECT(); if (!Misc.GetWindowRect(_hwnd, out currentRect)) { throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); } int currentHeight = currentRect.bottom - currentRect.top; int currentWidth = currentRect.right - currentRect.left; int dx = SafeNativeMethods.GetSystemMetrics(SafeNativeMethods.SM_CXHSCROLL); int dy = SafeNativeMethods.GetSystemMetrics(SafeNativeMethods.SM_CYHSCROLL); // If to far to the left move right edge to be visible. // Move the left edge the absalute differance of the right to the origin plus a little more to be visible. if (x + currentWidth < 0) { x += ((x + currentWidth) * -1 + dx); } // If to far off the top move bottom edge down to be visible. // Move the top edge the absalute differance of the bottom to the origin plus a little more to be visible. if (y + currentHeight < 0) { y += ((y + currentHeight) * -1 + dy); } NativeMethods.RECT parentRect = new NativeMethods.RECT(); if (!Misc.GetClientRect(hwndParent, out parentRect)) { throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); } // If to far to the right move left edge to be visible. // Move the left edge back the diffance of it and the parent's client area right side plus a little more to be visible. if (x > parentRect.right) { x -= (x - parentRect.right + dx); } // If to far off the bottome move top edge down to be visible. // Move the top edge up the diffance of it and the parent's client area bottom side plus a little more to be visible. if (y > parentRect.bottom) { y -= (y - parentRect.bottom + dy); } } // position the window keeping the zorder the same and not resizing. // We do this first so that the window is moved in terms of screen coordinates. // The WindowPlacement APIs take in to account the workarea which ends up // putting the window in the wrong place if (!Misc.SetWindowPos(_hwnd, NativeMethods.HWND.NULL, (int)x, (int)y, 0, 0, UnsafeNativeMethods.SWP_NOSIZE | UnsafeNativeMethods.SWP_NOZORDER | UnsafeNativeMethods.SWP_NOACTIVATE)) { throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); } UnsafeNativeMethods.WINDOWPLACEMENT wp = new UnsafeNativeMethods.WINDOWPLACEMENT(); wp.length = Marshal.SizeOf(typeof(UnsafeNativeMethods.WINDOWPLACEMENT)); // get the WINDOWPLACEMENT information. This includes the coordinates in // terms of the workarea. if (!Misc.GetWindowPlacement(_hwnd, ref wp)) { throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); } int style = GetWindowStyle(); if (style == 0) { throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); } if ( IsBitSet(style, SafeNativeMethods.WS_MINIMIZE) ) { // If the window is minimized the parameters have to be setup differently wp.ptMinPosition.y = (int) y; wp.ptMinPosition.x = (int) x; wp.flags = UnsafeNativeMethods.WPF_SETMINPOSITION; // Use SetWindowPlacement to move the window because it handles the case where the // window is move completly off the screen even in the multi-mon case. If this happens // it will place the window on the primary monitor at a location closest to the taget. if (!Misc.SetWindowPlacement(_hwnd, ref wp)) { throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); } } else { NativeMethods.RECT currentRect = new NativeMethods.RECT(); if (!Misc.GetWindowRect(_hwnd, out currentRect)) { throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); } // Use SetWindowPlacement to move the window because it handles the case where the // window is move completly off the screen even in the multi-mon case. If this happens // it will place the window on the primary monitor at a location closest to the taget. if (!Misc.SetWindowPlacement(_hwnd, ref wp)) { throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); } // check to make sure SetWindowPlacement has not changed the size of our window // There may be a bug in SetWindowPlacement. int currentHeight = currentRect.bottom - currentRect.top; int currentWidth = currentRect.right - currentRect.left; if (!Misc.GetWindowPlacement(_hwnd, ref wp)) { throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); } int newHeight = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top; int newWidth = wp.rcNormalPosition.right -wp.rcNormalPosition.left; if ( currentHeight != newHeight || currentWidth != newWidth ) { wp.rcNormalPosition.bottom = wp.rcNormalPosition.top + currentHeight; wp.rcNormalPosition.right = wp.rcNormalPosition.left + currentWidth; if (!Misc.SetWindowPlacement(_hwnd, ref wp)) { throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); } } } }
// Get the child window at the specified point. // Returns IntPtr.NULL on error; returns original window if point is not // on any child window. // When the returned window is a child, the out param isClientArea indicates // whether the returned point is on the client area of the returned HWND. private static NativeMethods.HWND ChildWindowFromPoint( NativeMethods.HWND hwnd, double x, double y, out bool isClientArea ) { NativeMethods.HWND hBestFitTransparent = NativeMethods.HWND.NULL; NativeMethods.RECT rcBest = new NativeMethods.RECT(); isClientArea = true; IntPtr hrgn = Misc.CreateRectRgn(0, 0, 0, 0); // NOTE: Must be deleted before returning if (hrgn == IntPtr.Zero) { return NativeMethods.HWND.NULL; } // Infinite looping is 'possible' (though unlikely) when // using GetWindow(...NEXT), so we counter-limit this loop... int SanityLoopCount = 1024; for (NativeMethods.HWND hChild = Misc.GetWindow(hwnd, SafeNativeMethods.GW_CHILD); hChild != NativeMethods.HWND.NULL && --SanityLoopCount > 0 ; hChild = Misc.GetWindow(hChild, SafeNativeMethods.GW_HWNDNEXT)) { // Skip invisible... if( ! IsWindowReallyVisible( hChild ) ) continue; // Check for rect... NativeMethods.RECT rc = new NativeMethods.RECT(); if (!Misc.GetWindowRect(hChild, out rc)) { continue; } // If on Vista, convert the incoming physical screen coords to hwndChild-relative // logical coords before using them in [logical] rect comparisons... double xLogical = x; double yLogical = y; if (Environment.OSVersion.Version.Major >= 6) { NativeMethods.HWND hwndTopLevel = SafeNativeMethods.GetAncestor(hChild, SafeNativeMethods.GA_ROOT); NativeMethods.POINT pt = new NativeMethods.POINT((int)x, (int)y); try { SafeNativeMethods.PhysicalToLogicalPoint(hwndTopLevel, ref pt); xLogical = pt.x; yLogical = pt.y; } catch (EntryPointNotFoundException) { // Ignore. } } if(!PtInRect(rc, xLogical, yLogical)) { continue; } // Skip disabled child windows with other controls beneath it. // (only a few places actually use this, // eg. the Date&Time properties window, which has a disabled edit window // over the edits/static for the time components - see WinClient#856699) int style = GetWindowStyle(hChild); if ((style & SafeNativeMethods.WS_CHILD) != 0 && (style & SafeNativeMethods.WS_DISABLED) != 0) { int x1 = (rc.left + rc.right) / 2; int y1 = (rc.top + rc.bottom) / 2; IntPtr hwndCompare = UnsafeNativeMethods.WindowFromPhysicalPoint(x1, y1); // The WindowFromPoint function does not retrieve a handle to a hidden or disabled window, // even if the point is within the window. So we should either get the parents hwnd or // the controls hwnd underneath the disabled control, if one exsists. // if (hwndCompare != (IntPtr)hwnd) { // This means that there is another child under `the disabled child, so we want to exclude // `the disabled child high in the z-order. continue; } } // Check for transparent layered windows (eg as used by menu and tooltip shadows) // (Note that WS_EX_TRANSPARENT has a specific meaning when used with WS_EX_LAYERED // that is different then when it is used alone, so we must check both flags // together.) int exStyle = GetWindowExStyle(hChild); if( ( exStyle & SafeNativeMethods.WS_EX_LAYERED ) != 0 && ( exStyle & SafeNativeMethods.WS_EX_TRANSPARENT ) != 0 ) { continue; } // If window is using a region (eg. Media Player), check whether // point is in it... if (SafeNativeMethods.GetWindowRgn(hChild.h, hrgn) == SafeNativeMethods.COMPLEXREGION) { // hrgn is relative to window (not client or screen), so offset point appropriately... if (!SafeNativeMethods.PtInRegion(hrgn, (int)xLogical - rc.left, (int)yLogical - rc.top)) { continue; } } // Try for transparency and/or non-client areas: IntPtr lr = Misc.SendMessageTimeout( hChild, UnsafeNativeMethods.WM_NCHITTEST, IntPtr.Zero, MAKELPARAM( (int)x, (int)y ) ); if( lr == UnsafeNativeMethods.HTTRANSPARENT ) { // For reasons best known to the writers of USER, statics - used // as labels - claim to be transparent. So that we do hit-test // to these, we remember the hwnd here, so if nothing better // comes along, we'll use this. // If we come accross two or more of these, we remember the // one that fits inside the other - if any. That way, // we hit-test to siblings 'within' siblings - eg. statics in // a groupbox. if( hBestFitTransparent == NativeMethods.HWND.NULL ) { hBestFitTransparent = hChild; if (!Misc.GetWindowRect(hChild, out rcBest)) { continue; } } else { // Is this child within the last remembered transparent? // If so, remember it instead. NativeMethods.RECT rcChild = new NativeMethods.RECT(); if (!Misc.GetWindowRect(hChild, out rcChild)) { continue; } if( Rect1InRect2( rcChild, rcBest ) ) { hBestFitTransparent = hChild; rcBest = rcChild; } } continue; } // Got the window! // Using the hit-test result and compairing against HTCLIENT is not good enough. The Shell_TrayWnd control, // i.e. the task bar, will never returns a value of HTCLIENT, so check to see if the point is in the client area. NativeMethods.RECT rcClient = new NativeMethods.RECT(); if (!Misc.GetClientRect(hChild, out rcClient) || !MapWindowPoints(hChild, NativeMethods.HWND.NULL, ref rcClient, 2) || !PtInRect(rcClient, xLogical, yLogical)) { isClientArea = false; } Misc.DeleteObject(hrgn); // finished with region return hChild; } Misc.DeleteObject(hrgn); // finished with region if( SanityLoopCount == 0 ) { Debug.Assert(false, "too many children or inf loop?"); return NativeMethods.HWND.NULL; } // Did we find a transparent (eg. a static) on our travels? If so, since // we couldn't find anything better, may as well use it. if( hBestFitTransparent != NativeMethods.HWND.NULL ) { return hBestFitTransparent; } // Otherwise return the original window (not NULL!) if no child found... return hwnd; }
internal Rect GetParentWindowRect() { NativeMethods.RECT rect = new NativeMethods.RECT(0, 0, 0, 0); IntPtr parent = ParentHandle; if (parent != IntPtr.Zero) { SafeNativeMethods.GetClientRect(new HandleRef(null, parent), ref rect); } return PointUtil.ToRect(rect); }
// Paramter: Point p should be the most interesting point of a pop up positioning. The top left. // Return the maximum boundingRect for the popup. // If this is not a child-popup // and the Point p passed in is inside of the Work Area then return the monitor work area rect // A tooltip opened above the taskbar will never display over/under the taskbar. // To accomodate this the work area of the screen is returned to allow the pop up to // respect the reserved area of the teskbar. // and the Point p passed in is outside of the work area then return the monitor rect // this can happen If the program is an appbar program (http://msdn.microsoft.com/en-us/library/cc144177(VS.85).aspx) // and the tooltip is in the area removed from the work area. In this case the tooltip can // be placed without regard for the work area bounds. // Else this is the BoundingRect of either the placement target's window or the parent of the popup's window. private Rect GetScreenBounds(Rect boundingBox, Point p) { if (_secHelper.IsChildPopup) { // The "monitor" is the main window for child windows. return _secHelper.GetParentWindowRect(); } NativeMethods.RECT rect = new NativeMethods.RECT(0, 0, 0, 0); NativeMethods.RECT nativeBounds = PointUtil.FromRect(boundingBox); IntPtr monitor = SafeNativeMethods.MonitorFromRect(ref nativeBounds, NativeMethods.MONITOR_DEFAULTTONEAREST); if (monitor != IntPtr.Zero) { NativeMethods.MONITORINFOEX monitorInfo = new NativeMethods.MONITORINFOEX(); monitorInfo.cbSize = Marshal.SizeOf(typeof(NativeMethods.MONITORINFOEX)); SafeNativeMethods.GetMonitorInfo(new HandleRef(null, monitor), monitorInfo); //If this is a pop up for a menu or ToolTip then respect the work area if opening in the work area. if (((this.Child is MenuBase) || (this.Child is ToolTip) || (this.TemplatedParent is MenuItem)) && ((p.X >= monitorInfo.rcWork.left) && (p.X <= monitorInfo.rcWork.right) && (p.Y >= monitorInfo.rcWork.top) && (p.Y <= monitorInfo.rcWork.bottom))) { // Context Menus, MenuItems, and ToolTips shouldn't go over the Taskbar rect = monitorInfo.rcWork; } else { rect = monitorInfo.rcMonitor; } } return PointUtil.ToRect(rect); }
private void DoPaint() { NativeMethods.PAINTSTRUCT ps = new NativeMethods.PAINTSTRUCT(); NativeMethods.HDC hdc; HandleRef handleRef = new HandleRef(this, _hWnd); hdc.h = UnsafeNativeMethods.BeginPaint(handleRef, ref ps); int retval = UnsafeNativeMethods.GetWindowLong(handleRef, NativeMethods.GWL_EXSTYLE); NativeMethods.RECT rcPaint = new NativeMethods.RECT(ps.rcPaint_left, ps.rcPaint_top, ps.rcPaint_right, ps.rcPaint_bottom); // // If we get a BeginPaint with an empty rect then check // if this is a special layered, non-redirected window // which would mean we need to do a full paint when it // won't cause a problem. // if (rcPaint.IsEmpty && ((retval & NativeMethods.WS_EX_LAYERED) != 0) && !UnsafeNativeMethods.GetLayeredWindowAttributes(_hWnd.MakeHandleRef(this), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero) && !_isSessionDisconnected && !_isMinimized && (!_isSuspended || (UnsafeNativeMethods.GetSystemMetrics(SM.REMOTESESSION) != 0))) // // notifications for the server monitor are being broad-casted when the // machine is in a non-local TS session. See Dev10 bug for more details. { rcPaint = new NativeMethods.RECT( 0, 0, _hwndClientRectInScreenCoords.right - _hwndClientRectInScreenCoords.left, _hwndClientRectInScreenCoords.bottom - _hwndClientRectInScreenCoords.top); } AdjustForRightToLeft(ref rcPaint, handleRef); if (!rcPaint.IsEmpty) { InvalidateRect(rcPaint); } UnsafeNativeMethods.EndPaint(_hWnd.MakeHandleRef(this), ref ps); }
private void GetWindowRectsInScreenCoordinates() { NativeMethods.RECT rcClient = new NativeMethods.RECT(); // // Get the window and client rectangles // SafeNativeMethods.GetWindowRect(_hWnd.MakeHandleRef(this), ref _hwndWindowRectInScreenCoords); SafeNativeMethods.GetClientRect(_hWnd.MakeHandleRef(this), ref rcClient); NativeMethods.POINT ptClientTopLeft = new NativeMethods.POINT(rcClient.left, rcClient.top); UnsafeNativeMethods.ClientToScreen(_hWnd.MakeHandleRef(this), ptClientTopLeft); NativeMethods.POINT ptClientBottomRight = new NativeMethods.POINT(rcClient.right, rcClient.bottom); UnsafeNativeMethods.ClientToScreen(_hWnd.MakeHandleRef(this), ptClientBottomRight); if(ptClientBottomRight.x >= ptClientTopLeft.x) { _hwndClientRectInScreenCoords.left = ptClientTopLeft.x; _hwndClientRectInScreenCoords.right = ptClientBottomRight.x; } else { // RTL windows will cause the right edge to be on the left... _hwndClientRectInScreenCoords.left = ptClientBottomRight.x; _hwndClientRectInScreenCoords.right = ptClientTopLeft.x; } if(ptClientBottomRight.y >= ptClientTopLeft.y) { _hwndClientRectInScreenCoords.top = ptClientTopLeft.y; _hwndClientRectInScreenCoords.bottom = ptClientBottomRight.y; } else { // RTL windows will cause the right edge to be on the left... // This doesn't affect top/bottom, but the code should be symmetrical. _hwndClientRectInScreenCoords.top = ptClientBottomRight.y; _hwndClientRectInScreenCoords.bottom = ptClientTopLeft.y; } // }
public static extern bool GetClientRect(NativeMethods.HWND hwnd, out NativeMethods.RECT rc);
public static extern bool GetWindowRect(NativeMethods.HWND hwnd, out NativeMethods.RECT rc);
public static extern bool IntGetClientRect(HandleRef hWnd, [In, Out] ref NativeMethods.RECT rect);
/// <summary> /// Adjusts a RECT to compensate for Win32 RTL conversion logic /// </summary> /// <remarks> /// MITIGATION: AVALON_RTL_AND_WIN32RTL /// /// When a window is marked with the WS_EX_LAYOUTRTL style, Win32 /// mirrors the coordinates during the various translation APIs. /// /// Avalon also sets up mirroring transforms so that we properly /// mirror the output since we render to DirectX, not a GDI DC. /// /// Unfortunately, this means that our coordinates are already mirrored /// by Win32, and Avalon mirrors them again. To work around this /// problem, we un-mirror the coordinates from Win32 before hit-testing /// in Avalon. /// </remarks> /// <param name="rc"> /// The RECT to be adjusted /// </param> /// <param name="handleRef"> /// </param> /// <returns> /// The adjusted rectangle /// </returns> internal static NativeMethods.RECT AdjustForRightToLeft(NativeMethods.RECT rc, HandleRef handleRef) { int windowStyle = SafeNativeMethods.GetWindowStyle(handleRef, true); if(( windowStyle & NativeMethods.WS_EX_LAYOUTRTL ) == NativeMethods.WS_EX_LAYOUTRTL) { NativeMethods.RECT rcClient = new NativeMethods.RECT(); SafeNativeMethods.GetClientRect(handleRef, ref rcClient); int width = rc.right - rc.left; // preserve width rc.right = rcClient.right - rc.left; // set right of rect to be as far from right of window as left of rect was from left of window rc.left = rc.right - width; // restore width by adjusting left and preserving right } return rc; }
public static extern bool IntAdjustWindowRectEx(ref NativeMethods.RECT lpRect, int dwStyle, bool bMenu, int dwExStyle);
private bool ReportInput( IntPtr hwnd, InputMode mode, int timestamp, RawMouseActions actions, int x, int y, int wheel) { // if there's no HwndSource, we shouldn't get here. But just in case... Debug.Assert(null != _source && null != _source.Value); if (_source == null || _source.Value == null) { return false; } PresentationSource source = _source.Value; CompositionTarget ct = source.CompositionTarget; // Input reports should only be generated if the window is still valid. if(_site == null || source.IsDisposed || ct == null ) { if(_active) { // We are still active, but the window is dead. Force a deactivate. actions = RawMouseActions.Deactivate; } else { return false; } } if((actions & RawMouseActions.Deactivate) == RawMouseActions.Deactivate) { // Stop tracking the mouse since we are deactivating. StopTracking(hwnd); _active = false; } else if((actions & RawMouseActions.CancelCapture) == RawMouseActions.CancelCapture) { // We have lost capture, but don't do anything else. } else if(!_active && (actions & RawMouseActions.VerticalWheelRotate) == RawMouseActions.VerticalWheelRotate) { // report mouse wheel events as if they came from the window that // is under the mouse (even though they are reported to the window // with keyboard focus) MouseDevice mouse = _site.Value.CriticalInputManager.PrimaryMouseDevice; if (mouse != null && mouse.CriticalActiveSource != null) { source = mouse.CriticalActiveSource; } } else { // If we are not active, we need to activate first. if(!_active) { // But first, check for "spurious" mouse events... // // Sometimes we get a mouse move for window "A" AFTER another // window ("B") has become active. This would cause "A" to think // that it is active, and to tell Avalon. Now both "A" and "B" think // they are active, and Avalon thinks "A" is, but REALLY, "B" is. // // Confused yet? // // To avoid this, if this window ("A") gets a mouse move, // we verify that either "A" has capture, or the mouse is over "A" IntPtr hwndToCheck = SafeNativeMethods.GetCapture(); if(hwnd != hwndToCheck) { // If we get this far, "A" does NOT have capture // - now ensure mouse is over "A" NativeMethods.POINT ptCursor = new NativeMethods.POINT(); try { UnsafeNativeMethods.GetCursorPos(ptCursor); } catch(System.ComponentModel.Win32Exception) { // Sometimes Win32 will fail this call, such as if you are // not running in the interactive desktop. For example, // a secure screen saver may be running. System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: GetCursorPos failed!"); } try { hwndToCheck = UnsafeNativeMethods.WindowFromPoint(ptCursor.x, ptCursor.y); } catch(System.ComponentModel.Win32Exception) { System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: WindowFromPoint failed!"); } if(hwnd != hwndToCheck) { // If we get this far: // - the mouse is NOT over "A" // - "A" does NOT have capture // We consider this a "spurious" mouse move and ignore it. (Win32 bug?) System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: Spurious mouse event received!"); return false; } } // We need to collect the current state of the mouse. // Include the activation action. actions |= RawMouseActions.Activate; // Remember that we are active. _active = true; _lastX = x; _lastY = y; //Console.WriteLine("Activating the mouse."); } // Make sure we are tracking the mouse so we know when it // leaves the window. StartTracking(hwnd); // Even if a move isn't explicitly reported, we still may need to // report one if the coordinates are different. This is to cover // some ugly edge cases with context menus and such. if((actions & RawMouseActions.AbsoluteMove) == 0) { if(x != _lastX || y != _lastY) { actions |= RawMouseActions.AbsoluteMove; } } else { _lastX = x; _lastY = y; } // record mouse motion so that GetIntermediatePoints has the // information it needs if ((actions & RawMouseActions.AbsoluteMove) != 0) { RecordMouseMove(x, y, _msgTime); } // MITIGATION: WIN32_AND_AVALON_RTL // // When a window is marked with the WS_EX_LAYOUTRTL style, Win32 // mirrors the coordinates received for mouse movement as well as // mirroring the output of drawing to a GDI DC. // // Avalon also sets up mirroring transforms so that we properly // mirror the output since we render to DirectX, not a GDI DC. // // Unfortunately, this means that our input is already mirrored // by Win32, and Avalon mirrors it again. To work around this // problem, we un-mirror the input from Win32 before passing // it into Avalon. // if((actions & (RawMouseActions.AbsoluteMove | RawMouseActions.Activate)) != 0) { try { //This has a SUC on it and accesses CriticalHandle int windowStyle = SafeNativeMethods.GetWindowStyle(new HandleRef(this, _source.Value.CriticalHandle), true); if((windowStyle & NativeMethods.WS_EX_LAYOUTRTL) == NativeMethods.WS_EX_LAYOUTRTL) { NativeMethods.RECT rcClient = new NativeMethods.RECT(); SafeNativeMethods.GetClientRect(new HandleRef(this,_source.Value.Handle), ref rcClient); x = rcClient.right - x; } } catch(System.ComponentModel.Win32Exception) { System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: GetWindowStyle or GetClientRect failed!"); } } } // Get the extra information sent along with the message. //There exists a SUC for this native method call IntPtr extraInformation = IntPtr.Zero; try { extraInformation = UnsafeNativeMethods.GetMessageExtraInfo(); } catch(System.ComponentModel.Win32Exception) { System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: GetMessageExtraInfo failed!"); } RawMouseInputReport report = new RawMouseInputReport(mode, timestamp, source, actions, x, y, wheel, extraInformation); bool handled = _site.Value.ReportInput(report); return handled; }
public static extern IntPtr MonitorFromRect(ref NativeMethods.RECT rect, int flags);
// Get bounding rectangle, relative to screen internal static Rect GetScreenRect( IntPtr hwnd, UIElement el ) { Rect rc = GetLocalRect( el ); // Map from local to screen coords... NativeMethods.RECT rcWin32 = new NativeMethods.RECT( (int) rc.Left, (int) rc.Top, (int) rc.Right, (int) rc.Bottom ); try { SafeSecurityHelper.TransformLocalRectToScreen(new HandleRef(null, hwnd), ref rcWin32); } catch (System.ComponentModel.Win32Exception) { return Rect.Empty; } rc = new Rect( rcWin32.left, rcWin32.top, rcWin32.right - rcWin32.left, rcWin32.bottom - rcWin32.top ); return rc; }
public static IntPtr MonitorFromRect(ref NativeMethods.RECT rect, int flags) { return(SafeNativeMethodsPrivate.MonitorFromRect(ref rect, flags)); }
private static void GetClippedPositionOffsets(TextEditor This, ITextPointer position, LogicalDirection direction, out double horizontalOffset, out double verticalOffset) { // GetCharacterRect will return the position that base on UiScope. Rect positionRect = position.GetCharacterRect(direction); // Get the base offsets for our ContextMenu. horizontalOffset = positionRect.X; verticalOffset = positionRect.Y + positionRect.Height; // Clip to the child render scope. FrameworkElement element = This.TextView.RenderScope as FrameworkElement; if (element != null) { GeneralTransform transform = element.TransformToAncestor(This.UiScope); if (transform != null) { ClipToElement(element, transform, ref horizontalOffset, ref verticalOffset); } } // Clip to parent visuals. // This is unintuitive -- you might expect parents to have increasingly // larger viewports. But any parent that behaves like a ScrollViewer // will have a smaller view port that we need to clip against. for (Visual visual = This.UiScope; visual != null; visual = VisualTreeHelper.GetParent(visual) as Visual) { element = visual as FrameworkElement; if (element != null) { GeneralTransform transform = visual.TransformToDescendant(This.UiScope); if (transform != null) { ClipToElement(element, transform, ref horizontalOffset, ref verticalOffset); } } } // Clip to the window client rect. PresentationSource source = PresentationSource.CriticalFromVisual(This.UiScope); IWin32Window window = source as IWin32Window; if (window != null) { IntPtr hwnd = IntPtr.Zero; new UIPermission(UIPermissionWindow.AllWindows).Assert(); // BlessedAssert try { hwnd = window.Handle; } finally { CodeAccessPermission.RevertAssert(); } NativeMethods.RECT rc = new NativeMethods.RECT(0, 0, 0, 0); SafeNativeMethods.GetClientRect(new HandleRef(null, hwnd), ref rc); // Convert to mil measure units. Point minPoint = new Point(rc.left, rc.top); Point maxPoint = new Point(rc.right, rc.bottom); CompositionTarget compositionTarget = source.CompositionTarget; minPoint = compositionTarget.TransformFromDevice.Transform(minPoint); maxPoint = compositionTarget.TransformFromDevice.Transform(maxPoint); // Convert to local coordinates. GeneralTransform transform = compositionTarget.RootVisual.TransformToDescendant(This.UiScope); if (transform != null) { transform.TryTransform(minPoint, out minPoint); transform.TryTransform(maxPoint, out maxPoint); // Finally, do the clip. horizontalOffset = ClipToBounds(minPoint.X, horizontalOffset, maxPoint.X); verticalOffset = ClipToBounds(minPoint.Y, verticalOffset, maxPoint.Y); } // ContextMenu code takes care of clipping to desktop. } }
private void HandleBoundingRectChange(IntPtr hwnd) { NativeMethods.HWND nativeHwnd = NativeMethods.HWND.Cast( hwnd ); NativeMethods.RECT rc32 = new NativeMethods.RECT(0,0,0,0); // if GetWindwRect fails, most likely the nativeHwnd is an invalid window, so just return. if (!Misc.GetWindowRect(nativeHwnd, out rc32)) { return; } // Filter... avoid duplicate events if (hwnd == _lastHwnd && Compare( rc32, _lastRect )) { return; } AutomationElement rawEl = AutomationElement.FromHandle(hwnd); // // AutomationPropertyChangedEventArgs e = new AutomationPropertyChangedEventArgs( AutomationElement.BoundingRectangleProperty, Rect.Empty, new Rect (rc32.left, rc32.top, rc32.right - rc32.left, rc32.bottom - rc32.top)); // ClientEventManager.RaiseEventInThisClientOnly(AutomationElement.AutomationPropertyChangedEvent, rawEl, e); // save the last hwnd/rect for filtering out duplicates _lastHwnd = hwnd; _lastRect = rc32; }