4

I've seen some software which can detect whether or not a form is visible to the user. This might include being minimized, another screen covering it up, monitor turned off, and even when on remote desktop, knows when the remote desktop view is not visible. I'm guessing it has to do with whether or not anything is being drawn in the application. Perhaps video drivers can provide this information?

How can I make my application to detect this? Is there a Windows message I can monitor for this?

For the record, the mentioned software is one which streams multiple surveillance cameras in real-time (RTSP) which uses this ability to the advantage of pausing streaming when the screen isn't visible.

Jerry Dodge
  • 26,858
  • 31
  • 155
  • 327
  • 2
    Jerry (not sure whether this should be a comment or an answer but ...), if you're wondering how to detect from within a Delphi application whether one of it's own forms is visible on-screen, the accepted answer here may help:http://stackoverflow.com/questions/646527/how-can-i-tell-if-a-delphi-control-is-currently-visible – MartynA Nov 07 '13 at 09:28
  • @MartynA Thanks, and that will certainly contribute to my final solution. I was just under hopes that there would be something in Windows which I could monitor for this exact purpose, but I guess that would be no. – Jerry Dodge Nov 07 '13 at 17:25
  • I wouldn't try going as far as detecting remote visibility. The next step would be to find out what happens if your application is running in a VM. Then perhaps in a VM on a box connected remotely.. – Sertac Akyuz Nov 08 '13 at 00:15
  • @SertacAkyuz Well what I meant by that is if I connect to a computer via RDP, and this window is completely visible in the remote session, but the RDP window is not visible, somehow this other app detects this. – Jerry Dodge Nov 08 '13 at 00:17

2 Answers2

6

Most of the conditions do not have window messages associated with them, so you have to detect the conditions manually.

Use the TForm.WindowState property, or the Win32 API IsIconic() function, to detect your window's minimized state. You can also catch WM_SYSCOMMAND messages looking for the SC_MINIMIZE, SC_MAXIMIZE, and SC_RESTORE states.

Use the Win32 API EnumWindows() function to loop through all top-level windows, calling GetWindowRect() on each one, to detect if any areas of your window are not covered by other windows. To account for z-ordering, you may have to use GetTopWindow() and GetNextWindow() to iterate the z-order to see which window is on top of the other window.

Use MonitorFromWindow() and GetDevicePowerState() to detect the local monitor's power state. You can also catch WM_SYSCOMMAND messages looking for the SC_MONITORPOWER notification.

Detecting the Remote Desktop state is a bit trickier. You can use ProcessIdToSessionId() and WTSQuerySessionInformation(WTSIsRemoteSession) (Windows 7+) or GetSystemMetrics(SM_REMOTESESSION) to determine if your app is running inside of a Remote Desktop session, but I don't think you can detect whether the remote display is on/off (although WTSQuerySessionInformation() can query the remote display's resolution and color depth, and even if the session is locked/unlocked).

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • I was starting to wonder if the paint message could give some help in this. Perhaps the painting doesn't happen when not visible? I'm assuming that the video drivers might be able to provide this. – Jerry Dodge Nov 07 '13 at 02:28
  • How do you determine if a window, having its rectangle intersecting with yours, is covering your window? I mean the z-order? – Sertac Akyuz Nov 07 '13 at 02:51
  • 1
    @Jerry - I don't think that would work. A paint is scheduled when part of your window is uncovered, not otherwise. Even if hadn't been the case, DWM has changed the rules - not every time your window is un-obscured a paint message is scheduled. I'm not commenting on the part about the video driver of course.. – Sertac Akyuz Nov 07 '13 at 03:03
  • 1
    @Jerry - Since you accepted the answer you should have an idea... How are you gonna know from the above that, if a window is covering your window, or is it instead your window that is covering it? – Sertac Akyuz Nov 07 '13 at 13:24
  • @SertacAkyuz Well, that would be another separate question about Z order. – Jerry Dodge Nov 07 '13 at 17:23
  • @Jerry - Of course not. Currently you have no way to identify if a window is above or below yours, which your question cannot be answered without. – Sertac Akyuz Nov 07 '13 at 19:23
  • -1, this answer is incomplete. It gives no clue how to determine if an overlapping window is covering the application's form or not, which is the most crucial part of the question. – Sertac Akyuz Nov 07 '13 at 21:10
  • I don't know if I'd give -1 for that, given I wasn't even thinking of this concept in the first place. But yes, it is an important part which this does not address. The rest is good though. – Jerry Dodge Nov 07 '13 at 22:26
  • 1
    @Sertac If `EnumWindows` does not return windows from top to bottom (that's what you're saying I assume), I think [`GetTopWindow(0)`](http://msdn.microsoft.com/en-us/library/windows/desktop/ms633514(v=vs.85).aspx) and subsequently [`GetNextWindow(Result, GW_HWNDNEXT)`](http://msdn.microsoft.com/en-us/library/windows/desktop/ms633509(v=vs.85).aspx) could be used then instead? – NGLN Nov 07 '13 at 22:50
  • @NGLN - I think I could use EnumWindows for this, although enumeration in z-order is not guaranteed or documented. Or the method you mention. Or perhaps just call `GetWindowFromPoint` using a point in the intersected area which possibly wouldn't be full-proof. The point certainly needs addressing though, without that knowledge what is left is how should you know if your window is minimized and if the monitor is turned off (considering the non-remote part). – Sertac Akyuz Nov 07 '13 at 22:58
  • @SertacAkyuz: The `GetTopWindow()/GetNextWindow()` approach to determining z-order is [documented here](http://msdn.microsoft.com/en-us/library/windows/desktop/ms632599.aspx): "You can use the GetTopWindow function to search all child windows of a parent window and return a handle to the child window that is highest in z-order. The GetNextWindow function retrieves a handle to the next or previous window in z-order" [and here](http://msdn.microsoft.com/en-us/library/windows/desktop/ms633514.aspx): "If this parameter is NULL, the function returns a handle to the window at the top of the Z order" – Remy Lebeau Nov 07 '13 at 23:53
  • @Remy - Thanks for putting it into the answer, I undid the downvote. I think I'd use WindowFromPoint, erring would be on the safe side if your form does not have holes. But GetNextWindow is quite fine. – Sertac Akyuz Nov 08 '13 at 00:07
  • Using `WindowFromPoint()`, you would have to check every point in the intersected rectangle to make sure all points belong to your window, in case other windows are overlapping the same rectangle. – Remy Lebeau Nov 08 '13 at 00:24
2

I'm guessing it has to do with whether or not anything is being drawn in the application.

For partially obscured windows, Canvas.ClipRect (which is equal to the rcPaint member of PAINTSTRUCT or the result gotten from GetUpdateRect) will be the portion of the device context that has to be redrawn. GetUpdateRect can be called outside a WM_PAINT handler, Canvas.ClipRect only within.

But if you could of would solely rely on paint messages being sent, I am not sure. I think Remy's suggestions are more robust. Or a combination of all.

Community
  • 1
  • 1
NGLN
  • 43,011
  • 8
  • 105
  • 200