/// <summary> /// Gets visible top-level window or control from point. /// </summary> /// <param name="p"> /// Coordinates. /// Tip: To specify coordinates relative to the right, bottom, work area or a non-primary screen, use <see cref="Coord.Normalize"/>, like in the example. /// </param> /// <param name="flags"></param> /// <remarks> /// Unlike API <msdn>WindowFromPhysicalPoint</msdn> etc, this function: does not skip disabled controls; always skips transparent control like group box if a smaller sibling is there. All this is not true with flag Raw. /// </remarks> /// <example> /// Find window at 100 200. /// <code><![CDATA[ /// var w = wnd.FromXY((100, 200), WXYFlags.NeedWindow); /// print.it(w); /// ]]></code> /// /// Find window or control at 50 from left and 100 from bottom of the work area. /// <code><![CDATA[ /// var w = wnd.FromXY(Coord.Normalize(50, ^100, workArea: true)); /// print.it(w); /// ]]></code> /// </example> public static wnd fromXY(POINT p, WXYFlags flags = 0) { bool needW = flags.Has(WXYFlags.NeedWindow); bool needC = flags.Has(WXYFlags.NeedControl); if (needW && needC) { throw new ArgumentException("", "flags"); } if (flags.HasAny(WXYFlags.Raw | WXYFlags.NeedWindow)) { var w = Api.WindowFromPoint(p); if (needW) { return(w.Window); } return(!needC || w.IsChild ? w : default);
//FUTURE: test when this process is not DPI-aware: // Coordinate-related API on Win7 high DPI. // AO location on Win10 with different DPI of monitors. /// <summary> /// Gets visible top-level window or control from point. /// </summary> /// <param name="p"> /// Coordinates. /// Tip: To specify coordinates relative to the right, bottom, work area or a non-primary screen, use <see cref="Coord.Normalize"/>, like in the example. /// </param> /// <param name="flags"></param> /// <remarks> /// Alternatively can be used API <msdn>WindowFromPoint</msdn>, <msdn>ChildWindowFromPointEx</msdn> or <msdn>RealChildWindowFromPoint</msdn>, but all they have various limitations and are not very useful in automation scripts. /// This function gets non-transparent controls that are behind (in the Z order) transparent controls (group button, tab control etc); supports more control types than <msdn>RealChildWindowFromPoint</msdn>. Also does not skip disabled controls. All this is not true with flag Raw. /// This function is not very fast, probably 0.3 - 1 ms. /// </remarks> /// <example> /// Find window at 100 200. /// <code><![CDATA[ /// var w = AWnd.FromXY((100, 200), WXYFlags.NeedWindow); /// AOutput.Write(w); /// ]]></code> /// /// Find window or control at 50 from left and 100 from bottom of the work area. /// <code><![CDATA[ /// var w = AWnd.FromXY(Coord.Normalize(50, Coord.Reverse(100), true)); /// AOutput.Write(w); /// ]]></code> /// </example> public static AWnd FromXY(POINT p, WXYFlags flags = 0) { bool needW = 0 != (flags & WXYFlags.NeedWindow); bool needC = 0 != (flags & WXYFlags.NeedControl); if (needW && needC) { throw new ArgumentException("", "flags"); } AWnd w; if (needW) { w = Api.RealChildWindowFromPoint(Api.GetDesktopWindow(), p); //much faster than WindowFromPoint if (!w.HasExStyle(WS2.TRANSPARENT | WS2.LAYERED)) { return(w); //fast. Windows that have both these styles are mouse-transparent. } return(Api.WindowFromPoint(p).Window); //ChildWindowFromPointEx would be faster, but less reliable //info: //WindowFromPoint is the most reliable. It skips really transparent top-level windows (TL). Unfortunately it skips disabled controls (but not TL). //ChildWindowFromPointEx with CWP_SKIPINVISIBLE|CWP_SKIPTRANSPARENT skips all with WS_EX_TRANSPARENT, although without WS_EX_LAYERED they aren't actually transparent. //RealChildWindowFromPoint does not skip transparent TL. It works like ChildWindowFromPointEx(CWP_SKIPINVISIBLE). //None of the above API prefers a really visible control that is under a transparent part of a sibling control. RealChildWindowFromPoint does it only for group buttons, but not for tab controls etc. //All API skip windows that have a hole etc in window region at that point. //None of the API uses WM_NCHITTEST+HTTRANSPARENT. Tested only with TL of other processes. //AccessibleObjectFromPoint.get_Parent in most cases gets the most correct window/control, but it is dirty, unreliable and often very slow, because sends WM_GETOBJECT etc. //speed: //RealChildWindowFromPoint is the fastest. //ChildWindowFromPointEx is slower. //WindowFromPoint is 4 times slower; .Window does not make significantly slower. //AccessibleObjectFromPoint.get_Parent often is of RealChildWindowFromPoint speed, but often much slower than all others. //IUIAutomation.FromPoint very slow. Getting window handle from it is not easy, > 0.5 ms. } w = Api.WindowFromPoint(p); if (w.Is0) { return(w); } if (0 != (flags & WXYFlags.Raw)) { if (needW) { w = w.Window; } else if (needC && w == w.Window) { w = default; } return(w); } AWnd t = w.Get.DirectParent; //need parent because need to call realchildwindowfrompoint on it, else for group box would go through the slow way of detecting transparen control if (!t.Is0) { w = t; } t = w._ChildFromXY(p, false, true); if (t.Is0) { t = w; } if (needC && t == w) { return(default);