VirtualBox

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

Last change on this file since 95960 was 95960, checked in by vboxsync, 3 years ago

Additions/VBoxTray: More logging cleanups: don't define default stuff which is already defined by default; include files reordering (IPRT/ first, VBox/ second).

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