VirtualBox

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

Last change on this file since 62679 was 62679, checked in by vboxsync, 8 years ago

Use the iprt/win/windows.h wrapper for Windows.h

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