VirtualBox

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

Last change on this file since 106945 was 106411, checked in by vboxsync, 8 weeks ago

Additions/VBoxTray: Implemented ability for easier user-controllable logging (also via verbose levels), support for running in foreground mode (with a console window attached to) and selective starting of sub services to easier pinpoint errors in release builds. Cleaned up initialization / termination code a little. See command line help for new options. bugref:10763

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.5 KB
Line 
1/* $Id: VBoxSessionTracking.cpp 106411 2024-10-17 07:44:43Z 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#include "VBoxTrayInternal.h"
40
41
42/* St (session [state] tracking) functionality API impl */
43
44typedef struct VBOXST
45{
46 HWND hWTSAPIWnd;
47 RTLDRMOD hLdrModWTSAPI32;
48 BOOL fIsConsole;
49 WTS_CONNECTSTATE_CLASS enmConnectState;
50 UINT_PTR idDelayedInitTimer;
51 BOOL (WINAPI * pfnWTSRegisterSessionNotification)(HWND hWnd, DWORD dwFlags);
52 BOOL (WINAPI * pfnWTSUnRegisterSessionNotification)(HWND hWnd);
53 BOOL (WINAPI * pfnWTSQuerySessionInformationA)(HANDLE hServer, DWORD SessionId, WTS_INFO_CLASS WTSInfoClass, LPTSTR *ppBuffer, DWORD *pBytesReturned);
54} VBOXST;
55
56static VBOXST gVBoxSt;
57
58/** @todo r=andy Lacks documentation / Doxygen headers. What does this, and why? */
59
60int vboxStCheckState()
61{
62 int rc = VINF_SUCCESS;
63 WTS_CONNECTSTATE_CLASS *penmConnectState = NULL;
64 USHORT *pProtocolType = NULL;
65 DWORD cbBuf = 0;
66 if (gVBoxSt.pfnWTSQuerySessionInformationA(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, WTSConnectState,
67 (LPTSTR *)&penmConnectState, &cbBuf))
68 {
69 if (gVBoxSt.pfnWTSQuerySessionInformationA(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, WTSClientProtocolType,
70 (LPTSTR *)&pProtocolType, &cbBuf))
71 {
72 gVBoxSt.fIsConsole = (*pProtocolType == 0);
73 gVBoxSt.enmConnectState = *penmConnectState;
74 LogFlowFunc(("Session information: ProtocolType %d, ConnectState %d", *pProtocolType, *penmConnectState));
75 return VINF_SUCCESS;
76 }
77 else
78 {
79 DWORD dwErr = GetLastError();
80 LogWarnFunc(("WTSQuerySessionInformationA WTSClientProtocolType failed, error = %08X\n", dwErr));
81 rc = RTErrConvertFromWin32(dwErr);
82 }
83 }
84 else
85 {
86 DWORD dwErr = GetLastError();
87 LogWarnFunc(("WTSQuerySessionInformationA WTSConnectState failed, error = %08X\n", dwErr));
88 rc = RTErrConvertFromWin32(dwErr);
89 }
90
91 /* failure branch, set to "console-active" state */
92 gVBoxSt.fIsConsole = TRUE;
93 gVBoxSt.enmConnectState = WTSActive;
94
95 return rc;
96}
97
98int vboxStInit(HWND hWnd)
99{
100 RT_ZERO(gVBoxSt);
101 int rc = RTLdrLoadSystem("WTSAPI32.DLL", true /*fNoUnload*/, &gVBoxSt.hLdrModWTSAPI32);
102
103 if (RT_SUCCESS(rc))
104 {
105 rc = RTLdrGetSymbol(gVBoxSt.hLdrModWTSAPI32, "WTSRegisterSessionNotification",
106 (void **)&gVBoxSt.pfnWTSRegisterSessionNotification);
107 if (RT_SUCCESS(rc))
108 rc = RTLdrGetSymbol(gVBoxSt.hLdrModWTSAPI32, "WTSUnRegisterSessionNotification",
109 (void **)&gVBoxSt.pfnWTSUnRegisterSessionNotification);
110 if (RT_SUCCESS(rc))
111 rc = RTLdrGetSymbol(gVBoxSt.hLdrModWTSAPI32, "WTSQuerySessionInformationA",
112 (void **)&gVBoxSt.pfnWTSQuerySessionInformationA);
113
114 AssertRC(rc);
115 RTLdrClose(gVBoxSt.hLdrModWTSAPI32);
116 }
117
118 if (RT_SUCCESS(rc))
119 {
120 gVBoxSt.hWTSAPIWnd = hWnd;
121 if (gVBoxSt.pfnWTSRegisterSessionNotification(gVBoxSt.hWTSAPIWnd, NOTIFY_FOR_THIS_SESSION))
122 {
123 LogFunc(("hWnd(%p) registered for WTS session changes\n", gVBoxSt.hWTSAPIWnd));
124 vboxStCheckState();
125 }
126 else
127 {
128 DWORD const dwErr = GetLastError();
129 VBoxTrayInfo("WTSRegisterSessionNotification failed, error = %08X\n", dwErr);
130 if (dwErr == RPC_S_INVALID_BINDING)
131 {
132 gVBoxSt.idDelayedInitTimer = SetTimer(gVBoxSt.hWTSAPIWnd, TIMERID_VBOXTRAY_ST_DELAYED_INIT_TIMER,
133 2000, (TIMERPROC)NULL);
134 gVBoxSt.fIsConsole = TRUE;
135 gVBoxSt.enmConnectState = WTSActive;
136 rc = VINF_SUCCESS;
137 }
138 else
139 rc = RTErrConvertFromWin32(dwErr);
140 }
141
142 if (RT_SUCCESS(rc))
143 return VINF_SUCCESS;
144 }
145 else
146 {
147 VBoxTrayInfo("WtsApi32.dll APIs are not available (%Rrc)\n", rc);
148
149 gVBoxSt.pfnWTSRegisterSessionNotification = NULL;
150 gVBoxSt.pfnWTSUnRegisterSessionNotification = NULL;
151 gVBoxSt.pfnWTSQuerySessionInformationA = NULL;
152 }
153
154 RT_ZERO(gVBoxSt);
155 gVBoxSt.fIsConsole = TRUE;
156 gVBoxSt.enmConnectState = WTSActive;
157
158 if (RT_FAILURE(rc))
159 VBoxTrayError("Initializing sessiosn tracking failed with %Rrc\n", rc);
160
161 return rc;
162}
163
164void vboxStTerm(void)
165{
166 AssertReturnVoid(gVBoxSt.hWTSAPIWnd);
167
168 if (gVBoxSt.idDelayedInitTimer)
169 {
170 /* notification is not registered, just kill timer */
171 KillTimer(gVBoxSt.hWTSAPIWnd, gVBoxSt.idDelayedInitTimer);
172 gVBoxSt.idDelayedInitTimer = 0;
173 }
174 else
175 {
176 if (!gVBoxSt.pfnWTSUnRegisterSessionNotification(gVBoxSt.hWTSAPIWnd))
177 {
178 LogWarnFunc(("WTSAPI32 unload failed, error = %08X\n", GetLastError()));
179 }
180 }
181
182 RT_ZERO(gVBoxSt);
183}
184
185static const char* vboxStDbgGetString(DWORD val)
186{
187 switch (val)
188 {
189 RT_CASE_RET_STR(WTS_CONSOLE_CONNECT);
190 RT_CASE_RET_STR(WTS_CONSOLE_DISCONNECT);
191 RT_CASE_RET_STR(WTS_REMOTE_CONNECT);
192 RT_CASE_RET_STR(WTS_REMOTE_DISCONNECT);
193 RT_CASE_RET_STR(WTS_SESSION_LOGON);
194 RT_CASE_RET_STR(WTS_SESSION_LOGOFF);
195 RT_CASE_RET_STR(WTS_SESSION_LOCK);
196 RT_CASE_RET_STR(WTS_SESSION_UNLOCK);
197 RT_CASE_RET_STR(WTS_SESSION_REMOTE_CONTROL);
198 default:
199 LogWarnFunc(("invalid WTS state %d\n", val));
200 return "Unknown";
201 }
202}
203
204BOOL vboxStCheckTimer(WPARAM wEvent)
205{
206 if (wEvent != gVBoxSt.idDelayedInitTimer)
207 return FALSE;
208
209 if (gVBoxSt.pfnWTSRegisterSessionNotification(gVBoxSt.hWTSAPIWnd, NOTIFY_FOR_THIS_SESSION))
210 {
211 KillTimer(gVBoxSt.hWTSAPIWnd, gVBoxSt.idDelayedInitTimer);
212 gVBoxSt.idDelayedInitTimer = 0;
213 vboxStCheckState();
214 }
215 else
216 {
217 LogWarnFunc(("timer WTSRegisterSessionNotification failed, error = %08X\n", GetLastError()));
218 Assert(gVBoxSt.fIsConsole == TRUE);
219 Assert(gVBoxSt.enmConnectState == WTSActive);
220 }
221
222 return TRUE;
223}
224
225BOOL vboxStIsActiveConsole(void)
226{
227 return (gVBoxSt.enmConnectState == WTSActive && gVBoxSt.fIsConsole);
228}
229
230BOOL vboxStHandleEvent(WPARAM wEvent)
231{
232 RT_NOREF(wEvent);
233 LogFunc(("WTS Event: %s\n", vboxStDbgGetString(wEvent)));
234 BOOL fOldIsActiveConsole = vboxStIsActiveConsole();
235
236 vboxStCheckState();
237
238 return !vboxStIsActiveConsole() != !fOldIsActiveConsole;
239}
240
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