VirtualBox

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

Last change on this file since 95965 was 95965, checked in by vboxsync, 22 months ago

Additions/VBoxTray: Moved the session tracking code into an own module. VBoxTray.cpp only should contain the main / sub service handling (if possible).

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

© 2023 Oracle
ContactPrivacy policyTerms of Use