简体   繁体   中英

How to determine whether a Windows application is offscreen?

I am trying to debug a strange issue with users that have LogMeIn installed. After a few days, some of my dialogs that my app opens can end up offscreen. If I could reliable detect that, I could programmatically move the dialogs back where they are visible again.

Note: this has to work for multiple monitors and use the win32 API. However, if you know how to do it from .NET I can probably extrapolate from there...

Update: For the curious, the bug mentioned above has to do with wxWidgets. If you run a wxWidgets application, then walk away and let your screen saver go, then log in remotely with LogMeIn, then try to open a dialog from your app, you will have trouble if you use wxDisplay::GetFromPoint(pos) or wxWindowBase::Center() to position the dialog.

Simply use MonitorFromWindow with the MONITOR_DEFAULTTONULL flag. If the return value is null, your window is not visible. You can subsequently pass MONITOR_DEFAULTTONEAREST to be able to reposition your window on the nearest monitor.

All the basics on multiple monitor support from June 1997 Microsoft Systems Journal:

Positioning Objects on a Multiple Display Setup:

在 .NET 中,您使用 Screen.PrimaryScreen.WorkingArea 结构来获取主屏幕的边界(我认为是其他显示器的 Screen.Screens[x].WorkingArea),然后使用窗口的 Left 和 Top 属性来获取找出窗口的位置(如果它不在屏幕上,Top 和 Left 将大于 [Screen].Width 和 .Height。

In .NET, I would iterate on each Screen in Screen.AllScreen, then either call screen.Bounds.Contains() passing your form's rectangle if you want to make sure all of your window is within bounds(*), or call screen.Bounds.IntersectsWith() if you only want to make sure at least a portion of your form is visible.

(*) Not being fully within one screen bounds does not mean it's not within the total screens' bounds. You could also call Rectangle.Union on each screen bounds to create a single rectangle to test your form's rectangle against, but then you must watch out if screen bounds are not of the same size, since the englobing rectangle is not fully visible either.

That was the longer answer. The shorter one is: There is no easy way I know of.

Whatever you do, please account for multiple monitors which may have coordinates thousands of pixels away from (0,0) in any direction. I hate it when an app forces itself back into another screen, frequently messing up any full-screen games I may be in at the time.

See also How can I get the active screen dimensions?

This is the code I used in the form constructor it's a quickie to move the form to a visible screen after you undock your laptop or whatever it is you did to make some screen real estate go away. Refine for your own consumption.

if (!Screen.FromControl(this).Bounds.Contains(this.Location))
            {
                this.DesktopLocation = new Point(100,100);
            }

It looks like GetMonitorInfo() is the Win32 equivalent of Danny's suggestion. I'm not sure how you'd go about getting an HMONITOR for all of the monitors on the system, but it looks like the example linked from the documentation has some ways of doing it.

This is a long time ago now, but Marin Plante's answer got me what I needed, so I wrote a simple extension method:

public static class WindowLocation
{
    public static Boolean VisibleOnScreen(this Form form)
    {
        foreach (Screen screen in Screen.AllScreens)
        {
            if (screen.Bounds.Contains(form.Bounds)) return true;
        }

        return false;
    }
}

May help someone else!

Hmm. This might not help, but when I did VB, you could do screen.width and screen.height, and then window.x and window.y...

Of course, I don't know how that works with multiple monitors.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM