VirtualBox

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

Last change on this file since 59177 was 58307, checked in by vboxsync, 9 years ago

Additions/WINNT/VBoxGuestInternal.h: Removed empty misnamed file. VBoxGuestInternal.h is the internal header for Additions/common/VBoxGuest, not for the WINNT additions. Very confusing and pointless.

  • 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 58307 2015-10-18 23:47:59Z 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 <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 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 *pInstance, bool volatile *pfShutdown)
329{
330 AssertPtrReturn(pInstance, VERR_INVALID_POINTER);
331
332 LogFlowFuncEnter();
333
334 /*
335 * Tell the control thread that it can continue
336 * spawning services.
337 */
338 RTThreadUserSignal(RTThreadSelf());
339
340 PVBOXVRDPCONTEXT pCtx = (PVBOXVRDPCONTEXT)pInstance;
341 AssertPtr(pCtx);
342
343 HANDLE gVBoxDriver = pCtx->pEnv->hDriver;
344 bool fTerminate = false;
345 VBoxGuestFilterMaskInfo maskInfo;
346 DWORD cbReturned;
347
348 maskInfo.u32OrMask = VMMDEV_EVENT_VRDP;
349 maskInfo.u32NotMask = 0;
350 if (!DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
351 {
352 DWORD dwErr = GetLastError();
353 LogFlowFunc(("DeviceIOControl(CtlMask) failed with %ld, exiting\n", dwErr));
354 return RTErrConvertFromWin32(dwErr);
355 }
356
357 int rc = VINF_SUCCESS;
358
359 for (;;)
360 {
361 /* wait for the event */
362 VBoxGuestWaitEventInfo waitEvent;
363 waitEvent.u32TimeoutIn = 5000;
364 waitEvent.u32EventMaskIn = VMMDEV_EVENT_VRDP;
365 if (DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_WAITEVENT, &waitEvent, sizeof(waitEvent), &waitEvent, sizeof(waitEvent), &cbReturned, NULL))
366 {
367 /* are we supposed to stop? */
368 if (*pfShutdown)
369 break;
370
371 /* did we get the right event? */
372 if (waitEvent.u32EventFlagsOut & VMMDEV_EVENT_VRDP)
373 {
374 /* Call the host to get VRDP status and the experience level. */
375 VMMDevVRDPChangeRequest vrdpChangeRequest = {0};
376
377 vrdpChangeRequest.header.size = sizeof(VMMDevVRDPChangeRequest);
378 vrdpChangeRequest.header.version = VMMDEV_REQUEST_HEADER_VERSION;
379 vrdpChangeRequest.header.requestType = VMMDevReq_GetVRDPChangeRequest;
380 vrdpChangeRequest.u8VRDPActive = 0;
381 vrdpChangeRequest.u32VRDPExperienceLevel = 0;
382
383 if (DeviceIoControl (gVBoxDriver,
384 VBOXGUEST_IOCTL_VMMREQUEST(sizeof(VMMDevVRDPChangeRequest)),
385 &vrdpChangeRequest,
386 sizeof(VMMDevVRDPChangeRequest),
387 &vrdpChangeRequest,
388 sizeof(VMMDevVRDPChangeRequest),
389 &cbReturned, NULL))
390 {
391 LogFlowFunc(("u8VRDPActive = %d, level %d\n", vrdpChangeRequest.u8VRDPActive, vrdpChangeRequest.u32VRDPExperienceLevel));
392
393 if (vrdpChangeRequest.u8VRDPActive)
394 {
395 pCtx->level = vrdpChangeRequest.u32VRDPExperienceLevel;
396 vboxExperienceSet (pCtx->level);
397
398 if (pCtx->level == VRDP_EXPERIENCE_LEVEL_ZERO
399 && pCtx->pfnEnableTheming
400 && pCtx->pfnIsThemeActive)
401 {
402 pCtx->fSavedThemeEnabled = pCtx->pfnIsThemeActive ();
403
404 LogFlowFunc(("pCtx->fSavedThemeEnabled = %d\n", pCtx->fSavedThemeEnabled));
405
406 if (pCtx->fSavedThemeEnabled)
407 {
408 pCtx->pfnEnableTheming (FALSE);
409 }
410 }
411 }
412 else
413 {
414 if (pCtx->level == VRDP_EXPERIENCE_LEVEL_ZERO
415 && pCtx->pfnEnableTheming
416 && pCtx->pfnIsThemeActive)
417 {
418 if (pCtx->fSavedThemeEnabled)
419 {
420 /* @todo the call returns S_OK but theming remains disabled. */
421 HRESULT hrc = pCtx->pfnEnableTheming (TRUE);
422 LogFlowFunc(("enabling theme rc = 0x%08X\n", hrc));
423 pCtx->fSavedThemeEnabled = FALSE;
424 }
425 }
426
427 vboxExperienceRestore (pCtx->level);
428
429 pCtx->level = VRDP_EXPERIENCE_LEVEL_FULL;
430 }
431 }
432 else
433 {
434 /* sleep a bit to not eat too much CPU in case the above call always fails */
435 RTThreadSleep(10);
436
437 if (*pfShutdown)
438 break;
439 }
440 }
441 }
442 else
443 {
444 /* sleep a bit to not eat too much CPU in case the above call always fails */
445 RTThreadSleep(50);
446
447 if (*pfShutdown)
448 break;
449 }
450 }
451
452 maskInfo.u32OrMask = 0;
453 maskInfo.u32NotMask = VMMDEV_EVENT_VRDP;
454 if (!DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
455 LogFlowFunc(("DeviceIOControl(CtlMask) failed\n"));
456
457 LogFlowFuncLeaveRC(rc);
458 return rc;
459}
460
461/**
462 * The service description.
463 */
464VBOXSERVICEDESC g_SvcDescVRDP =
465{
466 /* pszName. */
467 "VRDP",
468 /* pszDescription. */
469 "VRDP Connection Notification",
470 /* methods */
471 VBoxVRDPInit,
472 VBoxVRDPWorker,
473 NULL /* pfnStop */,
474 VBoxVRDPDestroy
475};
476
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