How can I detect that my window has been suppressed from the screen by the shell?

Raymond Chen

Some programs enumerate all windows in order to understand what is on the screen. For example, a “window picker” for a screen capture program, or a screen snipping tool, wants to find all the windows on the screen that are visible to the user so they can present them for selection.

The obvious test is Is­Window­Visible(), which checks whether the window and all its parents have the WS_VISIBLE window style. If a window is not visible, then it doesn’t appear on the list.

But that will still find things like windows that belong to non-current virtual desktops, or bits of the shell that are currently not visible, or some UWP apps. What’s up with that?

The shell has a concept called cloaking, in which a window is given all the trappings of visibility, without actually being presented to the user. As far as the app can tell, it seems to be visible: It still has the WS_VISIBLE window style, its coordinates are still within the bounds of the monitor, it still gets WM_PAINT messages, it has a non-empty clipping region, all the ways a traditional Win32 app has of detecting whether it is on screen say, “Yup, you’re on screen. Everything is just fine!”

If Windows didn’t play this trick, it would have to make apps no longer WS_VISIBLE or move them off-screen or assign them an empty region or some other thing to keep them from appearing on the screen.

But the apps would be able to detect those things.

Some apps would get confused: “Well, the only time I make this window hidden is when the user is printing, and I notice that the window is now visible, so I must be printing!” Now the app thinks that it’s printing when it really isn’t, and it might crash because it goes to the printing component to get the name of the target printer, and the printing component says, “What are you talking about? I’m not printing!”

Some apps would notice that they had become hidden and respond by trying to get themselves visible again. “Oh no, I was moved off screen. Let me move back on screen!” Or “Oh no, I’m not visible. Let me force myself visible!”

Inventing a brand new concept (cloaking) ensures that all old apps won’t be able to detect when they were cloaked, since the concept didn’t exist at the time they were written.

But it means that if your program wants to understand all the windows that are visible to the user, you may need to incorporate cloaking into your logic.

BOOL IsWindowCloaked(HWND hwnd)
{
 BOOL isCloaked = FALSE;
 return (SUCCEEDED(DwmGetWindowAttribute(hwnd, DWMWA_CLOAKED,
     &isCloaked, sizeof(isCloaked))) && isCloaked;
}

BOOL IsWindowVisibleOnScreen(HWND hwnd)
{
  return IsWindowVisible(hwnd) &&
         !IsWindowCloaked(hwnd);
}

 

19 comments

Discussion is closed. Login to edit/delete existing comments.

  • Joshua Hudson 0

    And that’s why MS was able to get it working well when nobody else could. It isn’t shell functionality. It’s window manager functionality.

    • GL 0

      I remember under the previous version of https://devblogs.microsoft.com/oldnewthing/20180501-00/?p=98645 (or another), someone said only MS can hide a window in some undocumented way without removing WM_VISIBLE, and Raymond replied that it was done in a documented way, by cloaking.

  • MGetz 0

    Honestly I can’t find a reason when this would be useful unless an app does CPU/GPU potentially intensive things while getting WM_PAINT messages and wants to be nice when it’s not actually visible. In most other cases the app should probably take the “Blissfully unaware” tactic and just let the OS do its thing.

    • Brian Beck 0

      Many apps do. For instance, video apps such as Windows Media Player stop rendering video when invisible.

    • Raymond ChenMicrosoft employee 0

      I gave an example in the opening paragraph. Consider a teleconferencing app that has an “app sharing” feature, and it says “Click on the app you want to share”, and you click on Excel, but the teleconferencing app mistakenly believes that you clicked on the WoW game on your “gaming” virtual desktop.

  • Alexey Badalov 0

    Ah, so that’s what I have to check now to know if I’m printing.

    • Wil Wilder Apaza Bustamante 0

      this comment has been deleted.

  • Daniel Smith 0

    I thought cloaking technology was prohibited by the Treaty of Algeron?

  • David Streeter 0

    “But the plans were on display…”
    “On display? I eventually had to go down to the cellar to find them.”
    “That’s the display department.”
    “With a flashlight.”
    “Ah, well, the lights had probably gone.”
    “So had the stairs.”
    “But look, you found the notice, didn’t you?”
    “Yes,” said Arthur, “yes I did. It was on display in the bottom of a locked filing cabinet stuck in a disused lavatory with a sign on the door saying ‘Beware of the Leopard.”

  • Robin Krom 0

    Thanks for sharing this with us, your use-case hits the nail on the head for me… I work on Greenshot, which in fact does EXACTLY what you describe in the first paragraph.

    We have some reported issues from people who are not being able to select certain windows as Greenshot thinks that another is in front, but it’s not visible. We could not explain this until now… I hope, let’s see if this fixes the issue. It might actually be virtual desktop related, I just never used them so I should definitively do some testing with it.

    It’s actually always a fun challenge to keep things working, with all the “workarounds” Windows has 😉

    • Robin Krom 0

      This seems to fix the issue, thanks for reporting it!
      If windows are on a different virtual desktop, they are cloaked. But somehow there are also other windows, I believe the search is one, which are cloaked.

      Btw. I started building an OSS library to make the Greenshot development a bit easier.
      It’s for .NET Framework and dotnet core and handles a lot of Win32 complexity, it gives a more modern API for some older concepts: https://github.com/dapplo/Dapplo.Windows

      Enumerating visible windows is one of them, Dwm support too.. The shell is somehow under represented.
      Anyway, I’ve added this to the library so the issue is solved for all applications using this.

      Btw. there was an interesting discussion about visible windows here: https://social.msdn.microsoft.com/Forums/windows/en-US/0d7419a7-1d25-40bc-909e-a0db33b109a8/iswindowvisible-fails-to-detect-if-store-app-is-visible

      • irongut 0

        Another thanks for the excellent Greenshot! I’ll have to check your library out at some point too. 🙂

    • Yukkuri Reimu 0

      Greenshot is great, cheers to you!

      • Robin Krom 0

        Thank you, and thanks to Chen it will be even better. 🙂

    • David Streeter 0

      Greenshot is great! I’ve encountered that issue with Greenshot too, on occasion. Glad it will be fixed now!

  • smf 0

    >Inventing a brand new concept (cloaking) ensures that all old apps won’t be able to detect when they were cloaked,
    >since the concept didn’t exist at the time they were written.

    What about new apps?

  • Pierre Baillargeon 0

    Begun, has the window visibility war.

    Or rather, the escalation with ill-behaved app continues.

    – I wish to complain about this window what I created not half an hour ago from this very desktop.
    – What’s wrong with it?
    – I’ll tell you what’s wrong with it, my lad. ‘E’s not visible, that’s what’s wrong with it!
    – No, no, ‘e’s uh,…he’s painting.
    – Look, matey, I know an invisible window when I don’t see one, and I’m not looking at one right now.
    – No no it’s not invisible, he’s, he’s painting’! Remarkable window, idn’it, ay? Beautiful content!
    – The content don’t enter into it. It’s stone invisible.
    etc.

    • David Streeter 0

      XD

  • Paul Jackson 0

    “and I notice that the window is now visible, so I must be printing”
    You probably meant to say “hidden” instead of “visible”?

Feedback usabilla icon