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

Raymond

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

Comments are closed. Login to edit/delete your existing comments

  • Joshua Hudson

    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.

  • MGetz

    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

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

    • Raymond ChenMicrosoft employee

      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

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

  • Daniel Smith

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

  • David Streeter

    “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

    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 😉

  • smf

    >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

    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.

  • Paul Jackson

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