VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxSessionTracking.cpp@ 106061

Last change on this file since 106061 was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.3 KB
Line 
1/* $Id: VBoxSessionTracking.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * VBoxSessionTracking.cpp - Session tracking.
4 */
5
6/*
7 * Copyright (C) 2013-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29#include <iprt/errcore.h>
30#include <iprt/ldr.h>
31#include <iprt/log.h>
32#include <iprt/string.h>
33#include <iprt/win/windows.h>
34
35/* Default desktop state tracking */
36#include <Wtsapi32.h>
37
38#include "VBoxTray.h"
39
40
41/* St (session [state] tracking) functionality API impl */
42
43typedef struct VBOXST
44{
45 HWND hWTSAPIWnd;
46 RTLDRMOD hLdrModWTSAPI32;
47 BOOL fIsConsole;
48 WTS_CONNECTSTATE_CLASS enmConnectState;
49 UINT_PTR idDelayedInitTimer;
50 BOOL (WINAPI * pfnWTSRegisterSessionNotification)(HWND hWnd, DWORD dwFlags);
51 BOOL (WINAPI * pfnWTSUnRegisterSessionNotification)(HWND hWnd);
52 BOOL (WINAPI * pfnWTSQuerySessionInformationA)(HANDLE hServer, DWORD SessionId, WTS_INFO_CLASS WTSInfoClass, LPTSTR *ppBuffer, DWORD *pBytesReturned);
53} VBOXST;
54
55static VBOXST gVBoxSt;
56
57/** @todo r=andy Lacks documentation / Doxygen headers. What does this, and why? */
58
59int vboxStCheckState()
60{
61 int rc = VINF_SUCCESS;
62 WTS_CONNECTSTATE_CLASS *penmConnectState = NULL;
63 USHORT *pProtocolType = NULL;
64 DWORD cbBuf = 0;
65 if (gVBoxSt.pfnWTSQuerySessionInformationA(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, WTSConnectState,
66 (LPTSTR *)&penmConnectState, &cbBuf))
67 {
68 if (gVBoxSt.pfnWTSQuerySessionInformationA(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, WTSClientProtocolType,
69 (LPTSTR *)&pProtocolType, &cbBuf))
70 {
71 gVBoxSt.fIsConsole = (*pProtocolType == 0);
72 gVBoxSt.enmConnectState = *penmConnectState;
73 LogFlowFunc(("Session information: ProtocolType %d, ConnectState %d", *pProtocolType, *penmConnectState));
74 return VINF_SUCCESS;
75 }
76 else
77 {
78 DWORD dwErr = GetLastError();
79 LogWarnFunc(("WTSQuerySessionInformationA WTSClientProtocolType failed, error = %08X\n", dwErr));
80 rc = RTErrConvertFromWin32(dwErr);
81 }
82 }
83 else
84 {
85 DWORD dwErr = GetLastError();
86 LogWarnFunc(("WTSQuerySessionInformationA WTSConnectState failed, error = %08X\n", dwErr));
87 rc = RTErrConvertFromWin32(dwErr);
88 }
89
90 /* failure branch, set to "console-active" state */
91 gVBoxSt.fIsConsole = TRUE;
92 gVBoxSt.enmConnectState = WTSActive;
93
94 return rc;
95}
96
97int vboxStInit(HWND hWnd)
98{
99 RT_ZERO(gVBoxSt);
100 int rc = RTLdrLoadSystem("WTSAPI32.DLL", true /*fNoUnload*/, &gVBoxSt.hLdrModWTSAPI32);
101
102 if (RT_SUCCESS(rc))
103 {
104 rc = RTLdrGetSymbol(gVBoxSt.hLdrModWTSAPI32, "WTSRegisterSessionNotification",
105 (void **)&gVBoxSt.pfnWTSRegisterSessionNotification);
106 if (RT_SUCCESS(rc))
107 rc = RTLdrGetSymbol(gVBoxSt.hLdrModWTSAPI32, "WTSUnRegisterSessionNotification",
108 (void **)&gVBoxSt.pfnWTSUnRegisterSessionNotification);
109 if (RT_SUCCESS(rc))
110 rc = RTLdrGetSymbol(gVBoxSt.hLdrModWTSAPI32, "WTSQuerySessionInformationA",
111 (void **)&gVBoxSt.pfnWTSQuerySessionInformationA);
112
113 AssertRC(rc);
114 RTLdrClose(gVBoxSt.hLdrModWTSAPI32);
115 }
116
117 if (RT_SUCCESS(rc))
118 {
119 gVBoxSt.hWTSAPIWnd = hWnd;
120 if (gVBoxSt.pfnWTSRegisterSessionNotification(gVBoxSt.hWTSAPIWnd, NOTIFY_FOR_THIS_SESSION))
121 {
122 LogFunc(("hWnd(%p) registered for WTS session changes\n", gVBoxSt.hWTSAPIWnd));
123 vboxStCheckState();
124 }
125 else
126 {
127 DWORD dwErr = GetLastError();
128 LogRel(("WTSRegisterSessionNotification failed, error = %08X\n", dwErr));
129 if (dwErr == RPC_S_INVALID_BINDING)
130 {
131 gVBoxSt.idDelayedInitTimer = SetTimer(gVBoxSt.hWTSAPIWnd, TIMERID_VBOXTRAY_ST_DELAYED_INIT_TIMER,
132 2000, (TIMERPROC)NULL);
133 gVBoxSt.fIsConsole = TRUE;
134 gVBoxSt.enmConnectState = WTSActive;
135 rc = VINF_SUCCESS;
136 }
137 else
138 rc = RTErrConvertFromWin32(dwErr);
139 }
140
141 if (RT_SUCCESS(rc))
142 return VINF_SUCCESS;
143 }
144 else
145 {
146 LogRel(("WtsApi32.dll APIs are not available (%Rrc)\n", rc));
147 gVBoxSt.pfnWTSRegisterSessionNotification = NULL;
148 gVBoxSt.pfnWTSUnRegisterSessionNotification = NULL;
149 gVBoxSt.pfnWTSQuerySessionInformationA = NULL;
150 }
151
152 RT_ZERO(gVBoxSt);
153 gVBoxSt.fIsConsole = TRUE;
154 gVBoxSt.enmConnectState = WTSActive;
155 return rc;
156}
157
158void vboxStTerm(void)
159{
160 AssertReturnVoid(gVBoxSt.hWTSAPIWnd);
161
162 if (gVBoxSt.idDelayedInitTimer)
163 {
164 /* notification is not registered, just kill timer */
165 KillTimer(gVBoxSt.hWTSAPIWnd, gVBoxSt.idDelayedInitTimer);
166 gVBoxSt.idDelayedInitTimer = 0;
167 }
168 else
169 {
170 if (!gVBoxSt.pfnWTSUnRegisterSessionNotification(gVBoxSt.hWTSAPIWnd))
171 {
172 LogWarnFunc(("WTSAPI32 unload failed, error = %08X\n", GetLastError()));
173 }
174 }
175
176 RT_ZERO(gVBoxSt);
177}
178
179static const char* vboxStDbgGetString(DWORD val)
180{
181 switch (val)
182 {
183 RT_CASE_RET_STR(WTS_CONSOLE_CONNECT);
184 RT_CASE_RET_STR(WTS_CONSOLE_DISCONNECT);
185 RT_CASE_RET_STR(WTS_REMOTE_CONNECT);
186 RT_CASE_RET_STR(WTS_REMOTE_DISCONNECT);
187 RT_CASE_RET_STR(WTS_SESSION_LOGON);
188 RT_CASE_RET_STR(WTS_SESSION_LOGOFF);
189 RT_CASE_RET_STR(WTS_SESSION_LOCK);
190 RT_CASE_RET_STR(WTS_SESSION_UNLOCK);
191 RT_CASE_RET_STR(WTS_SESSION_REMOTE_CONTROL);
192 default:
193 LogWarnFunc(("invalid WTS state %d\n", val));
194 return "Unknown";
195 }
196}
197
198BOOL vboxStCheckTimer(WPARAM wEvent)
199{
200 if (wEvent != gVBoxSt.idDelayedInitTimer)
201 return FALSE;
202
203 if (gVBoxSt.pfnWTSRegisterSessionNotification(gVBoxSt.hWTSAPIWnd, NOTIFY_FOR_THIS_SESSION))
204 {
205 KillTimer(gVBoxSt.hWTSAPIWnd, gVBoxSt.idDelayedInitTimer);
206 gVBoxSt.idDelayedInitTimer = 0;
207 vboxStCheckState();
208 }
209 else
210 {
211 LogWarnFunc(("timer WTSRegisterSessionNotification failed, error = %08X\n", GetLastError()));
212 Assert(gVBoxSt.fIsConsole == TRUE);
213 Assert(gVBoxSt.enmConnectState == WTSActive);
214 }
215
216 return TRUE;
217}
218
219BOOL vboxStIsActiveConsole(void)
220{
221 return (gVBoxSt.enmConnectState == WTSActive && gVBoxSt.fIsConsole);
222}
223
224BOOL vboxStHandleEvent(WPARAM wEvent)
225{
226 RT_NOREF(wEvent);
227 LogFunc(("WTS Event: %s\n", vboxStDbgGetString(wEvent)));
228 BOOL fOldIsActiveConsole = vboxStIsActiveConsole();
229
230 vboxStCheckState();
231
232 return !vboxStIsActiveConsole() != !fOldIsActiveConsole;
233}
234
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette