{"id":104504,"date":"2020-12-02T07:00:00","date_gmt":"2020-12-02T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=104504"},"modified":"2020-12-02T07:23:02","modified_gmt":"2020-12-02T15:23:02","slug":"20201202-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20201202-00\/?p=104504","title":{"rendered":"How can I check whether the user has disconnected from the session?"},"content":{"rendered":"<p>If another user signs onto a Windows system without the previous user signing out, then the previous user goes into a state known as Disconnected. Programs in the previous user&#8217;s session continue to run, but what if you want your program to check whether the session has been disconnected?<\/p>\n<p>You can subscribe to session state changes by using the <code>WTS\u00adRegister\u00adSession\u00adNotification<\/code> function, passing a window handle to receive the <code>WM_<\/code><code>WTS\u00adSESSION_<\/code><code>CHANGE<\/code> message. The <code>wParam<\/code> of the message describes the what happened, and you can use that value to decide to, say, pause various operations while the session is disconnected.<\/p>\n<p>If you would rather poll, you can call <code>WTS\u00adQuery\u00adSession\u00adInformation<\/code> and ask for the <code>WTS\u00adConnect\u00adState<\/code>.<\/p>\n<p>Or you can go a completely different route and ask whether the current desktop is the target of user input.<\/p>\n<pre>bool IsOnInputDesktop()\r\n{\r\n auto desktop = GetThreadDesktop(GetCurrentThreadId());\r\n if (!desktop) return false;\r\n\r\n BOOL input = FALSE;\r\n if (!GetUserObjectInformation(desktop, UOI_IO,\r\n         &amp;input, sizeof(input), nullptr)) return false;\r\n\r\n return !!input;\r\n}\r\n<\/pre>\n<p>Note that the handle returned by <code>Get\u00adThread\u00adDesktop<\/code> does not need to be (and shouldn&#8217;t be) closed.<\/p>\n<p>Note that this is not the same as disconnectedness. For example, if the user has hit <kbd>Ctrl<\/kbd>+<kbd>Alt<\/kbd>+<kbd>Del<\/kbd>, then there is an input desktop switch to the secure desktop, but the session is not disconnected.<\/p>\n<p>If you are a batch file or a PowerShell script, then your options are more limited. There&#8217;s a little program with the presumptuous name <code>query<\/code> that displays information about Terminal Services. In particular you can say <code>query session<\/code> to get a list of sessions, who is signed into each session, and whether the session is connected.<\/p>\n<p>There is a PowerShell module called <a href=\"https:\/\/archive.codeplex.com\/?p=psterminalservices\"> PSTerminalServices<\/a> that parses the output of <code>query session<\/code> into PowerShell objects.<\/p>\n<p>A customer was hoping for an environment variable that provided this information so it could be consumed from their batch file. Even without doing a <code>SET<\/code> in a command prompt, you should be able to determine that no such variable exists: Environment variables are captured at process creation and are private to the process. The only way an environment variable can change is if the process changes it.<\/p>\n<p>The customer didn&#8217;t realize that environment variables are local to the process, but if they thought about it, they may have realized that they were relying on it without realizing it: If environment variables could be globally modified, then their own batch files would stop working! When their batch file performs a <code>SET MYVAR=42<\/code>, they don&#8217;t expect the variable <code>MYVAR<\/code> to be set globally. They want the batch file to have a variable named <code>MYVAR<\/code>, different from the <code>MYVAR<\/code> variable in an unrelated command prompt.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>You&#8217;ll have to ask Terminal Services.<\/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-104504","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>You&#8217;ll have to ask Terminal Services.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104504","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=104504"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104504\/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=104504"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=104504"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=104504"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}