VirtualBox

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

Last change on this file since 58306 was 57741, checked in by vboxsync, 9 years ago

Additions/VBoxTray:

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