{"id":103507,"date":"2020-03-02T07:00:00","date_gmt":"2020-03-02T15:00:00","guid":{"rendered":"http:\/\/devblogs.microsoft.com\/oldnewthing\/?p=103507"},"modified":"2020-03-01T17:26:49","modified_gmt":"2020-03-02T01:26:49","slug":"20200302-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200302-00\/?p=103507","title":{"rendered":"How can I detect that my window has been suppressed from the screen by the shell?"},"content":{"rendered":"<p>Some programs enumerate all windows in order to understand what is on the screen. For example, a &#8220;window picker&#8221; 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.<\/p>\n<p>The obvious test is <code>Is\u00adWindow\u00adVisible()<\/code>, which checks whether the window and all its parents have the <code>WS_<code><\/code>VISIBLE<\/code> window style. If a window is not visible, then it doesn&#8217;t appear on the list.<\/p>\n<p>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&#8217;s up with that?<\/p>\n<p>The shell has a concept called <i>cloaking<\/i>, 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 <code>WS_VISIBLE<\/code> window style, its coordinates are still within the bounds of the monitor, it still gets <code>WM_<code><\/code>PAINT<\/code> messages, it has a non-empty clipping region, all the ways a traditional Win32 app has of detecting whether it is on screen say, &#8220;Yup, you&#8217;re on screen. Everything is just fine!&#8221;<\/p>\n<p>If Windows didn&#8217;t play this trick, it would have to make apps no longer <code>WS_<code><\/code>VISIBLE<\/code> or move them off-screen or assign them an empty region or some other thing to keep them from appearing on the screen.<\/p>\n<p>But the apps would be able to detect those things.<\/p>\n<p>Some apps would get confused: &#8220;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!&#8221; Now the app thinks that it&#8217;s printing when it really isn&#8217;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, &#8220;What are you talking about? I&#8217;m not printing!&#8221;<\/p>\n<p>Some apps would notice that they had become hidden and respond by trying to get themselves visible again. &#8220;Oh no, I was moved off screen. Let me move back on screen!&#8221; Or &#8220;Oh no, I&#8217;m not visible. Let me force myself visible!&#8221;<\/p>\n<p>Inventing a brand new concept (cloaking) ensures that all old apps won&#8217;t be able to detect when they were cloaked, since the concept didn&#8217;t exist at the time they were written.<\/p>\n<p>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.<\/p>\n<pre>BOOL IsWindowCloaked(HWND hwnd)\r\n{\r\n BOOL isCloaked = FALSE;\r\n return (SUCCEEDED(DwmGetWindowAttribute(hwnd, DWMWA_CLOAKED,\r\n     &amp;isCloaked, sizeof(isCloaked))) &amp;&amp; isCloaked;\r\n}\r\n\r\nBOOL IsWindowVisibleOnScreen(HWND hwnd)\r\n{\r\n  return IsWindowVisible(hwnd) &amp;&amp;\r\n         !IsWindowCloaked(hwnd);\r\n}\r\n<\/pre>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Cloak and dagger, without the dagger.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-103507","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Cloak and dagger, without the dagger.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103507","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=103507"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103507\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=103507"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=103507"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=103507"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}