VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxVRDP.cpp@ 100765

Last change on this file since 100765 was 99828, checked in by vboxsync, 19 months ago

*: A bunch of adjustments that allows using /permissive- with Visual C++ (qt 6.x necessity).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.9 KB
Line 
1/* $Id: VBoxVRDP.cpp 99828 2023-05-17 13:48:57Z vboxsync $ */
2/** @file
3 * VBoxVRDP - VBox VRDP connection notification
4 */
5
6/*
7 * Copyright (C) 2006-2023 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#include <iprt/assert.h>
29#include <iprt/ldr.h>
30#include <VBox/log.h>
31
32/* 0x0501 for SPI_SETDROPSHADOW */
33#define _WIN32_WINNT 0x0501
34#include <iprt/win/windows.h>
35
36#include <VBox/VMMDev.h> /* for VMMDEV_EVENT_VRDP and VRDP_EXPERIENCE_LEVEL_XXX */
37
38#include "VBoxTray.h"
39#include "VBoxHelpers.h"
40#include "VBoxVRDP.h"
41
42
43
44/* The guest receives VRDP_ACTIVE/VRDP_INACTIVE notifications.
45 *
46 * When VRDP_ACTIVE is received, the guest asks host about the experience level.
47 * The experience level is an integer value, different values disable some GUI effects.
48 *
49 * On VRDP_INACTIVE the original values are restored.
50 *
51 * Note: that this is not controlled from the client, that is a per VM settings.
52 *
53 * Note: theming is disabled separately by EnableTheming.
54 */
55
56#define VBOX_SPI_STRING 0
57#define VBOX_SPI_BOOL_PTR 1
58#define VBOX_SPI_BOOL 2
59#define VBOX_SPI_PTR 3
60
61static ANIMATIONINFO animationInfoDisable =
62{
63 sizeof (ANIMATIONINFO),
64 FALSE
65};
66
67typedef struct VBOXVRDPEXPPARAM
68{
69 const char *name;
70 UINT uActionSet;
71 UINT uActionGet;
72 uint32_t level; /* The parameter remain enabled at this or higher level. */
73 int type;
74 void *pvDisable;
75 UINT cbSavedValue;
76 char achSavedValue[2 * MAX_PATH]; /* Large enough to save the bitmap path. */
77} VBOXVRDPEXPPARAM, *PVBOXVRDPEXPPARAM;
78
79typedef struct VBOXVRDPCONTEXT
80{
81 const VBOXSERVICEENV *pEnv;
82
83 uint32_t level;
84 BOOL fSavedThemeEnabled;
85
86 RTLDRMOD hModUxTheme;
87
88 HRESULT (* pfnEnableTheming)(BOOL fEnable);
89 BOOL (* pfnIsThemeActive)(VOID);
90} VBOXVRDPCONTEXT, *PVBOXVRDPCONTEXT;
91
92static VBOXVRDPCONTEXT g_Ctx = { 0 };
93
94#define SPI_(l, a) #a, SPI_SET##a, SPI_GET##a, VRDP_EXPERIENCE_LEVEL_##l
95
96static VBOXVRDPEXPPARAM s_aSPIParams[] =
97{
98 { SPI_(MEDIUM, DESKWALLPAPER), VBOX_SPI_STRING, (void *)"" },
99 { SPI_(FULL, DROPSHADOW), VBOX_SPI_BOOL_PTR, },
100 { SPI_(HIGH, FONTSMOOTHING), VBOX_SPI_BOOL, },
101 { SPI_(FULL, MENUFADE), VBOX_SPI_BOOL_PTR, },
102 { SPI_(FULL, COMBOBOXANIMATION), VBOX_SPI_BOOL_PTR, },
103 { SPI_(FULL, CURSORSHADOW), VBOX_SPI_BOOL_PTR, },
104 { SPI_(HIGH, GRADIENTCAPTIONS), VBOX_SPI_BOOL_PTR, },
105 { SPI_(FULL, LISTBOXSMOOTHSCROLLING), VBOX_SPI_BOOL_PTR, },
106 { SPI_(FULL, MENUANIMATION), VBOX_SPI_BOOL_PTR, },
107 { SPI_(FULL, SELECTIONFADE), VBOX_SPI_BOOL_PTR, },
108 { SPI_(FULL, TOOLTIPANIMATION), VBOX_SPI_BOOL_PTR, },
109 { SPI_(FULL, ANIMATION), VBOX_SPI_PTR, &animationInfoDisable, sizeof (ANIMATIONINFO) },
110 { SPI_(MEDIUM, DRAGFULLWINDOWS), VBOX_SPI_BOOL, }
111};
112
113#undef SPI_
114
115static void vboxExperienceSet(uint32_t uLevel)
116{
117 for (size_t i = 0; i < RT_ELEMENTS(s_aSPIParams); i++)
118 {
119 PVBOXVRDPEXPPARAM pParam = &s_aSPIParams[i];
120 if (pParam->level > uLevel)
121 {
122 /*
123 * The parameter has to be disabled.
124 */
125 LogFlowFunc(("Saving %s\n", pParam->name));
126
127 /* Save the current value. */
128 switch (pParam->type)
129 {
130 case VBOX_SPI_STRING:
131 {
132 /* The 2nd parameter is size in characters of the buffer.
133 * The 3rd parameter points to the buffer.
134 */
135 SystemParametersInfo (pParam->uActionGet,
136 MAX_PATH,
137 pParam->achSavedValue,
138 0);
139 } break;
140
141 case VBOX_SPI_BOOL:
142 case VBOX_SPI_BOOL_PTR:
143 {
144 /* The 3rd parameter points to BOOL. */
145 SystemParametersInfo (pParam->uActionGet,
146 0,
147 pParam->achSavedValue,
148 0);
149 } break;
150
151 case VBOX_SPI_PTR:
152 {
153 /* The 3rd parameter points to the structure.
154 * The cbSize member of this structure must be set.
155 * The uiParam parameter must alos be set.
156 */
157 if (pParam->cbSavedValue > sizeof (pParam->achSavedValue))
158 {
159 LogFlowFunc(("Not enough space %d > %d\n", pParam->cbSavedValue, sizeof (pParam->achSavedValue)));
160 break;
161 }
162
163 *(UINT *)&pParam->achSavedValue[0] = pParam->cbSavedValue;
164
165 SystemParametersInfo (s_aSPIParams[i].uActionGet,
166 s_aSPIParams[i].cbSavedValue,
167 s_aSPIParams[i].achSavedValue,
168 0);
169 } break;
170
171 default:
172 break;
173 }
174
175 LogFlowFunc(("Disabling %s\n", pParam->name));
176
177 /* Disable the feature. */
178 switch (pParam->type)
179 {
180 case VBOX_SPI_STRING:
181 {
182 /* The 3rd parameter points to the string. */
183 SystemParametersInfo (pParam->uActionSet,
184 0,
185 pParam->pvDisable,
186 SPIF_SENDCHANGE);
187 } break;
188
189 case VBOX_SPI_BOOL:
190 {
191 /* The 2nd parameter is BOOL. */
192 SystemParametersInfo (pParam->uActionSet,
193 FALSE,
194 NULL,
195 SPIF_SENDCHANGE);
196 } break;
197
198 case VBOX_SPI_BOOL_PTR:
199 {
200 /* The 3rd parameter is NULL to disable. */
201 SystemParametersInfo (pParam->uActionSet,
202 0,
203 NULL,
204 SPIF_SENDCHANGE);
205 } break;
206
207 case VBOX_SPI_PTR:
208 {
209 /* The 3rd parameter points to the structure. */
210 SystemParametersInfo (pParam->uActionSet,
211 0,
212 pParam->pvDisable,
213 SPIF_SENDCHANGE);
214 } break;
215
216 default:
217 break;
218 }
219 }
220 }
221}
222
223static void vboxExperienceRestore(uint32_t uLevel)
224{
225 int i;
226 for (i = 0; i < RT_ELEMENTS(s_aSPIParams); i++)
227 {
228 PVBOXVRDPEXPPARAM pParam = &s_aSPIParams[i];
229 if (pParam->level > uLevel)
230 {
231 LogFlowFunc(("Restoring %s\n", pParam->name));
232
233 /* Restore the feature. */
234 switch (pParam->type)
235 {
236 case VBOX_SPI_STRING:
237 {
238 /* The 3rd parameter points to the string. */
239 SystemParametersInfo (pParam->uActionSet,
240 0,
241 pParam->achSavedValue,
242 SPIF_SENDCHANGE);
243 } break;
244
245 case VBOX_SPI_BOOL:
246 {
247 /* The 2nd parameter is BOOL. */
248 SystemParametersInfo (pParam->uActionSet,
249 *(BOOL *)&pParam->achSavedValue[0],
250 NULL,
251 SPIF_SENDCHANGE);
252 } break;
253
254 case VBOX_SPI_BOOL_PTR:
255 {
256 /* The 3rd parameter is NULL to disable. */
257 BOOL fSaved = *(BOOL *)&pParam->achSavedValue[0];
258
259 SystemParametersInfo (pParam->uActionSet,
260 0,
261 fSaved? &fSaved: NULL,
262 SPIF_SENDCHANGE);
263 } break;
264
265 case VBOX_SPI_PTR:
266 {
267 /* The 3rd parameter points to the structure. */
268 SystemParametersInfo (pParam->uActionSet,
269 0,
270 pParam->achSavedValue,
271 SPIF_SENDCHANGE);
272 } break;
273
274 default:
275 break;
276 }
277 }
278 }
279}
280
281static DECLCALLBACK(int) VBoxVRDPInit(const PVBOXSERVICEENV pEnv, void **ppInstance)
282{
283 AssertPtrReturn(pEnv, VERR_INVALID_POINTER);
284 AssertPtrReturn(ppInstance, VERR_INVALID_POINTER);
285
286 LogFlowFuncEnter();
287
288 PVBOXVRDPCONTEXT pCtx = &g_Ctx; /* Only one instance at the moment. */
289 AssertPtr(pCtx);
290
291 pCtx->pEnv = pEnv;
292 pCtx->level = VRDP_EXPERIENCE_LEVEL_FULL;
293 pCtx->fSavedThemeEnabled = FALSE;
294
295 int rc = RTLdrLoadSystem("UxTheme.dll", false /*fNoUnload*/, &g_Ctx.hModUxTheme);
296 if (RT_SUCCESS(rc))
297 {
298 *(PFNRT *)&pCtx->pfnEnableTheming = RTLdrGetFunction(g_Ctx.hModUxTheme, "EnableTheming");
299 *(PFNRT *)&pCtx->pfnIsThemeActive = RTLdrGetFunction(g_Ctx.hModUxTheme, "IsThemeActive");
300
301 *ppInstance = &g_Ctx;
302 }
303 else
304 {
305 g_Ctx.hModUxTheme = NIL_RTLDRMOD;
306 g_Ctx.pfnEnableTheming = NULL;
307 g_Ctx.pfnIsThemeActive = NULL;
308 }
309
310 /* Tell the caller that the service does not work but it is OK to continue. */
311 if (RT_FAILURE(rc))
312 rc = VERR_NOT_SUPPORTED;
313
314 LogFlowFuncLeaveRC(rc);
315 return rc;
316}
317
318static DECLCALLBACK(void) VBoxVRDPDestroy(void *pInstance)
319{
320 AssertPtrReturnVoid(pInstance);
321
322 LogFlowFuncEnter();
323
324 PVBOXVRDPCONTEXT pCtx = (PVBOXVRDPCONTEXT)pInstance;
325
326 vboxExperienceRestore (pCtx->level);
327 if (pCtx->hModUxTheme != NIL_RTLDRMOD)
328 {
329 RTLdrClose(g_Ctx.hModUxTheme);
330 pCtx->hModUxTheme = NIL_RTLDRMOD;
331 }
332
333 return;
334}
335
336/**
337 * Thread function to wait for and process mode change requests
338 */
339static DECLCALLBACK(int) VBoxVRDPWorker(void *pvInstance, bool volatile *pfShutdown)
340{
341 AssertPtrReturn(pvInstance, VERR_INVALID_POINTER);
342 PVBOXVRDPCONTEXT pCtx = (PVBOXVRDPCONTEXT)pvInstance;
343
344 LogFlowFuncEnter();
345
346 /*
347 * Tell the control thread that it can continue spawning services.
348 */
349 RTThreadUserSignal(RTThreadSelf());
350
351 int rc = VbglR3CtlFilterMask(VMMDEV_EVENT_VRDP, 0 /*fNot*/);
352 if (RT_FAILURE(rc))
353 {
354 LogRel(("VbglR3CtlFilterMask(VMMDEV_EVENT_VRDP, 0) failed with %Rrc, exiting...\n"));
355 return rc;
356 }
357
358 for (;;)
359 {
360 /*
361 * Wait for the event, checking the shutdown flag both before and after the call.
362 */
363 if (*pfShutdown)
364 {
365 rc = VINF_SUCCESS;
366 break;
367 }
368
369 uint32_t fEvent = 0;
370 rc = VbglR3WaitEvent(VMMDEV_EVENT_VRDP, 5000 /*ms*/, &fEvent);
371
372 if (*pfShutdown)
373 {
374 rc = VINF_SUCCESS;
375 break;
376 }
377
378 if (RT_SUCCESS(rc))
379 {
380 /* did we get the right event? */
381 if (fEvent & VMMDEV_EVENT_VRDP)
382 {
383 bool fActive = false;
384 uint32_t uExperienceLevel = 0;
385 rc = VbglR3VrdpGetChangeRequest(&fActive, &uExperienceLevel);
386 if (RT_SUCCESS(rc))
387 {
388 LogFlowFunc(("u8VRDPActive = %d, level %d\n", fActive, uExperienceLevel));
389
390 if (fActive)
391 {
392 pCtx->level = uExperienceLevel;
393 vboxExperienceSet (pCtx->level);
394
395 if (pCtx->level == VRDP_EXPERIENCE_LEVEL_ZERO
396 && pCtx->pfnEnableTheming
397 && pCtx->pfnIsThemeActive)
398 {
399 pCtx->fSavedThemeEnabled = pCtx->pfnIsThemeActive ();
400
401 LogFlowFunc(("pCtx->fSavedThemeEnabled = %d\n", pCtx->fSavedThemeEnabled));
402
403 if (pCtx->fSavedThemeEnabled)
404 {
405 pCtx->pfnEnableTheming (FALSE);
406 }
407 }
408 }
409 else
410 {
411 if (pCtx->level == VRDP_EXPERIENCE_LEVEL_ZERO
412 && pCtx->pfnEnableTheming
413 && pCtx->pfnIsThemeActive)
414 {
415 if (pCtx->fSavedThemeEnabled)
416 {
417 /** @todo the call returns S_OK but theming remains disabled. */
418 HRESULT hrc = pCtx->pfnEnableTheming (TRUE);
419 LogFlowFunc(("enabling theme rc = 0x%08X\n", hrc)); NOREF(hrc);
420 pCtx->fSavedThemeEnabled = FALSE;
421 }
422 }
423
424 vboxExperienceRestore (pCtx->level);
425
426 pCtx->level = VRDP_EXPERIENCE_LEVEL_FULL;
427 }
428 }
429 else
430 {
431 /* sleep a bit to not eat too much CPU in case the above call always fails */
432 RTThreadSleep(10);
433 }
434 }
435 }
436 /* sleep a bit to not eat too much CPU in case the above call always fails */
437 else
438 RTThreadSleep(50);
439 }
440
441 int rc2 = VbglR3CtlFilterMask(0 /*fOr*/, VMMDEV_EVENT_VRDP);
442 if (RT_FAILURE(rc2))
443 LogRel(("VbglR3CtlFilterMask(0 /*fOr*/, VMMDEV_EVENT_VRDP) failed with %Rrc\n", rc));
444
445 LogFlowFuncLeaveRC(rc);
446 return rc;
447}
448
449/**
450 * The service description.
451 */
452VBOXSERVICEDESC g_SvcDescVRDP =
453{
454 /* pszName. */
455 "VRDP",
456 /* pszDescription. */
457 "VRDP Connection Notification",
458 /* methods */
459 VBoxVRDPInit,
460 VBoxVRDPWorker,
461 NULL /* pfnStop */,
462 VBoxVRDPDestroy
463};
464
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