VirtualBox

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

Last change on this file since 53517 was 51469, checked in by vboxsync, 11 years ago

VBoxTray: Logging; ripped out all custom logging.

  • 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 51469 2014-05-30 11:49:42Z vboxsync $ */
2/** @file
3 * VBoxVRDP - VBox VRDP connection notification
4 */
5
6/*
7 * Copyright (C) 2006-2014 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 _VBoxExperienceParameter
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} VBoxExperienceParameter;
72
73#define SPI_(l, a) #a, SPI_SET##a, SPI_GET##a, VRDP_EXPERIENCE_LEVEL_##l
74
75static VBoxExperienceParameter parameters[] =
76{
77 { SPI_(MEDIUM, DESKWALLPAPER), VBOX_SPI_STRING, "" },
78 { SPI_(FULL, DROPSHADOW), VBOX_SPI_BOOL_PTR, },
79 { SPI_(HIGH, FONTSMOOTHING), VBOX_SPI_BOOL, },
80 { SPI_(FULL, MENUFADE), VBOX_SPI_BOOL_PTR, },
81 { SPI_(FULL, COMBOBOXANIMATION), VBOX_SPI_BOOL_PTR, },
82 { SPI_(FULL, CURSORSHADOW), VBOX_SPI_BOOL_PTR, },
83 { SPI_(HIGH, GRADIENTCAPTIONS), VBOX_SPI_BOOL_PTR, },
84 { SPI_(FULL, LISTBOXSMOOTHSCROLLING), VBOX_SPI_BOOL_PTR, },
85 { SPI_(FULL, MENUANIMATION), VBOX_SPI_BOOL_PTR, },
86 { SPI_(FULL, SELECTIONFADE), VBOX_SPI_BOOL_PTR, },
87 { SPI_(FULL, TOOLTIPANIMATION), VBOX_SPI_BOOL_PTR, },
88 { SPI_(FULL, ANIMATION), VBOX_SPI_PTR, &animationInfoDisable, sizeof (ANIMATIONINFO) },
89 { SPI_(MEDIUM, DRAGFULLWINDOWS), VBOX_SPI_BOOL, }
90};
91
92#undef SPI_
93
94static void vboxExperienceSet (uint32_t level)
95{
96 int i;
97 for (i = 0; i < RT_ELEMENTS(parameters); i++)
98 {
99 if (parameters[i].level > level)
100 {
101 /*
102 * The parameter has to be disabled.
103 */
104 LogFlowFunc(("Saving %s\n", parameters[i].name));
105
106 /* Save the current value. */
107 switch (parameters[i].type)
108 {
109 case VBOX_SPI_STRING:
110 {
111 /* The 2nd parameter is size in characters of the buffer.
112 * The 3rd parameter points to the buffer.
113 */
114 SystemParametersInfo (parameters[i].uActionGet,
115 MAX_PATH,
116 parameters[i].achSavedValue,
117 0);
118 } break;
119
120 case VBOX_SPI_BOOL:
121 case VBOX_SPI_BOOL_PTR:
122 {
123 /* The 3rd parameter points to BOOL. */
124 SystemParametersInfo (parameters[i].uActionGet,
125 0,
126 parameters[i].achSavedValue,
127 0);
128 } break;
129
130 case VBOX_SPI_PTR:
131 {
132 /* The 3rd parameter points to the structure.
133 * The cbSize member of this structure must be set.
134 * The uiParam parameter must alos be set.
135 */
136 if (parameters[i].cbSavedValue > sizeof (parameters[i].achSavedValue))
137 {
138 LogFlowFunc(("Not enough space %d > %d\n", parameters[i].cbSavedValue, sizeof (parameters[i].achSavedValue)));
139 break;
140 }
141
142 *(UINT *)&parameters[i].achSavedValue[0] = parameters[i].cbSavedValue;
143
144 SystemParametersInfo (parameters[i].uActionGet,
145 parameters[i].cbSavedValue,
146 parameters[i].achSavedValue,
147 0);
148 } break;
149
150 default:
151 break;
152 }
153
154 LogFlowFunc(("Disabling %s\n", parameters[i].name));
155
156 /* Disable the feature. */
157 switch (parameters[i].type)
158 {
159 case VBOX_SPI_STRING:
160 {
161 /* The 3rd parameter points to the string. */
162 SystemParametersInfo (parameters[i].uActionSet,
163 0,
164 parameters[i].pvDisable,
165 SPIF_SENDCHANGE);
166 } break;
167
168 case VBOX_SPI_BOOL:
169 {
170 /* The 2nd parameter is BOOL. */
171 SystemParametersInfo (parameters[i].uActionSet,
172 FALSE,
173 NULL,
174 SPIF_SENDCHANGE);
175 } break;
176
177 case VBOX_SPI_BOOL_PTR:
178 {
179 /* The 3rd parameter is NULL to disable. */
180 SystemParametersInfo (parameters[i].uActionSet,
181 0,
182 NULL,
183 SPIF_SENDCHANGE);
184 } break;
185
186 case VBOX_SPI_PTR:
187 {
188 /* The 3rd parameter points to the structure. */
189 SystemParametersInfo (parameters[i].uActionSet,
190 0,
191 parameters[i].pvDisable,
192 SPIF_SENDCHANGE);
193 } break;
194
195 default:
196 break;
197 }
198 }
199 }
200}
201
202static void vboxExperienceRestore (uint32_t level)
203{
204 int i;
205 for (i = 0; i < RT_ELEMENTS(parameters); i++)
206 {
207 if (parameters[i].level > level)
208 {
209 LogFlowFunc(("Restoring %s\n", parameters[i].name));
210
211 /* Restore the feature. */
212 switch (parameters[i].type)
213 {
214 case VBOX_SPI_STRING:
215 {
216 /* The 3rd parameter points to the string. */
217 SystemParametersInfo (parameters[i].uActionSet,
218 0,
219 parameters[i].achSavedValue,
220 SPIF_SENDCHANGE);
221 } break;
222
223 case VBOX_SPI_BOOL:
224 {
225 /* The 2nd parameter is BOOL. */
226 SystemParametersInfo (parameters[i].uActionSet,
227 *(BOOL *)&parameters[i].achSavedValue[0],
228 NULL,
229 SPIF_SENDCHANGE);
230 } break;
231
232 case VBOX_SPI_BOOL_PTR:
233 {
234 /* The 3rd parameter is NULL to disable. */
235 BOOL fSaved = *(BOOL *)&parameters[i].achSavedValue[0];
236
237 SystemParametersInfo (parameters[i].uActionSet,
238 0,
239 fSaved? &fSaved: NULL,
240 SPIF_SENDCHANGE);
241 } break;
242
243 case VBOX_SPI_PTR:
244 {
245 /* The 3rd parameter points to the structure. */
246 SystemParametersInfo (parameters[i].uActionSet,
247 0,
248 parameters[i].achSavedValue,
249 SPIF_SENDCHANGE);
250 } break;
251
252 default:
253 break;
254 }
255 }
256 }
257}
258
259
260typedef struct _VBOXVRDPCONTEXT
261{
262 const VBOXSERVICEENV *pEnv;
263
264 uint32_t level;
265 BOOL fSavedThemeEnabled;
266
267 RTLDRMOD hModUxTheme;
268
269 HRESULT (* pfnEnableTheming)(BOOL fEnable);
270 BOOL (* pfnIsThemeActive)(VOID);
271} VBOXVRDPCONTEXT;
272
273
274static VBOXVRDPCONTEXT gCtx = {0};
275
276
277int VBoxVRDPInit(const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread)
278{
279 LogFlowFunc(("VBoxVRDPInit\n"));
280
281 gCtx.pEnv = pEnv;
282 gCtx.level = VRDP_EXPERIENCE_LEVEL_FULL;
283 gCtx.fSavedThemeEnabled = FALSE;
284
285 int rc = RTLdrLoadSystem("UxTheme.dll", false /*fNoUnload*/, &gCtx.hModUxTheme);
286 if (RT_SUCCESS(rc))
287 {
288 *(PFNRT *)&gCtx.pfnEnableTheming = RTLdrGetFunction(gCtx.hModUxTheme, "EnableTheming");
289 *(PFNRT *)&gCtx.pfnIsThemeActive = RTLdrGetFunction(gCtx.hModUxTheme, "IsThemeActive");
290 }
291 else
292 {
293 gCtx.hModUxTheme = NIL_RTLDRMOD;
294 gCtx.pfnEnableTheming = NULL;
295 gCtx.pfnIsThemeActive = NULL;
296 }
297
298 *pfStartThread = true;
299 *ppInstance = &gCtx;
300 return VINF_SUCCESS;
301}
302
303
304void VBoxVRDPDestroy(const VBOXSERVICEENV *pEnv, void *pInstance)
305{
306 LogFlowFunc(("VBoxVRDPDestroy\n"));
307 VBOXVRDPCONTEXT *pCtx = (VBOXVRDPCONTEXT *)pInstance;
308 vboxExperienceRestore (pCtx->level);
309 if (gCtx.hModUxTheme != NIL_RTLDRMOD)
310 {
311 RTLdrClose(gCtx.hModUxTheme);
312 gCtx.hModUxTheme = NIL_RTLDRMOD;
313 }
314 return;
315}
316
317/**
318 * Thread function to wait for and process mode change requests
319 */
320unsigned __stdcall VBoxVRDPThread(void *pInstance)
321{
322 VBOXVRDPCONTEXT *pCtx = (VBOXVRDPCONTEXT *)pInstance;
323 HANDLE gVBoxDriver = pCtx->pEnv->hDriver;
324 bool fTerminate = false;
325 VBoxGuestFilterMaskInfo maskInfo;
326 DWORD cbReturned;
327
328 maskInfo.u32OrMask = VMMDEV_EVENT_VRDP;
329 maskInfo.u32NotMask = 0;
330 if (DeviceIoControl (gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
331 {
332 LogFlowFunc(("DeviceIOControl(CtlMask - or) succeeded\n"));
333 }
334 else
335 {
336 LogFlowFunc(("DeviceIOControl(CtlMask) failed\n"));
337 return 0;
338 }
339
340 do
341 {
342 /* wait for the event */
343 VBoxGuestWaitEventInfo waitEvent;
344 waitEvent.u32TimeoutIn = 5000;
345 waitEvent.u32EventMaskIn = VMMDEV_EVENT_VRDP;
346 if (DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_WAITEVENT, &waitEvent, sizeof(waitEvent), &waitEvent, sizeof(waitEvent), &cbReturned, NULL))
347 {
348 LogFlowFunc(("DeviceIOControl succeeded\n"));
349
350 /* are we supposed to stop? */
351 if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 0) == WAIT_OBJECT_0)
352 break;
353
354 LogFlowFunc(("checking event\n"));
355
356 /* did we get the right event? */
357 if (waitEvent.u32EventFlagsOut & VMMDEV_EVENT_VRDP)
358 {
359 /* Call the host to get VRDP status and the experience level. */
360 VMMDevVRDPChangeRequest vrdpChangeRequest = {0};
361
362 vrdpChangeRequest.header.size = sizeof(VMMDevVRDPChangeRequest);
363 vrdpChangeRequest.header.version = VMMDEV_REQUEST_HEADER_VERSION;
364 vrdpChangeRequest.header.requestType = VMMDevReq_GetVRDPChangeRequest;
365 vrdpChangeRequest.u8VRDPActive = 0;
366 vrdpChangeRequest.u32VRDPExperienceLevel = 0;
367
368 if (DeviceIoControl (gVBoxDriver,
369 VBOXGUEST_IOCTL_VMMREQUEST(sizeof(VMMDevVRDPChangeRequest)),
370 &vrdpChangeRequest,
371 sizeof(VMMDevVRDPChangeRequest),
372 &vrdpChangeRequest,
373 sizeof(VMMDevVRDPChangeRequest),
374 &cbReturned, NULL))
375 {
376 LogFlowFunc(("u8VRDPActive = %d, level %d\n", vrdpChangeRequest.u8VRDPActive, vrdpChangeRequest.u32VRDPExperienceLevel));
377
378 if (vrdpChangeRequest.u8VRDPActive)
379 {
380 pCtx->level = vrdpChangeRequest.u32VRDPExperienceLevel;
381 vboxExperienceSet (pCtx->level);
382
383 if (pCtx->level == VRDP_EXPERIENCE_LEVEL_ZERO
384 && pCtx->pfnEnableTheming
385 && pCtx->pfnIsThemeActive)
386 {
387 pCtx->fSavedThemeEnabled = pCtx->pfnIsThemeActive ();
388
389 LogFlowFunc(("pCtx->fSavedThemeEnabled = %d\n", pCtx->fSavedThemeEnabled));
390
391 if (pCtx->fSavedThemeEnabled)
392 {
393 pCtx->pfnEnableTheming (FALSE);
394 }
395 }
396 }
397 else
398 {
399 if (pCtx->level == VRDP_EXPERIENCE_LEVEL_ZERO
400 && pCtx->pfnEnableTheming
401 && pCtx->pfnIsThemeActive)
402 {
403 if (pCtx->fSavedThemeEnabled)
404 {
405 /* @todo the call returns S_OK but theming remains disabled. */
406 HRESULT hrc = pCtx->pfnEnableTheming (TRUE);
407 LogFlowFunc(("enabling theme rc = 0x%08X\n", hrc));
408 pCtx->fSavedThemeEnabled = FALSE;
409 }
410 }
411
412 vboxExperienceRestore (pCtx->level);
413
414 pCtx->level = VRDP_EXPERIENCE_LEVEL_FULL;
415 }
416 }
417 else
418 {
419#ifndef DEBUG_andy /* Too noisy for me. */
420 LogFlowFunc(("Error from DeviceIoControl VBOXGUEST_IOCTL_VMMREQUEST\n"));
421#endif
422 /* sleep a bit to not eat too much CPU in case the above call always fails */
423 if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 10) == WAIT_OBJECT_0)
424 {
425 fTerminate = true;
426 break;
427 }
428 }
429 }
430 }
431 else
432 {
433#ifndef DEBUG_andy
434 LogFlowFunc(("Error from DeviceIoControl VBOXGUEST_IOCTL_WAITEVENT\n"));
435#endif
436 /* sleep a bit to not eat too much CPU in case the above call always fails */
437 if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 10) == WAIT_OBJECT_0)
438 {
439 fTerminate = true;
440 break;
441 }
442 }
443 } while (!fTerminate);
444
445 maskInfo.u32OrMask = 0;
446 maskInfo.u32NotMask = VMMDEV_EVENT_VRDP;
447 if (DeviceIoControl (gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
448 {
449 LogFlowFunc(("DeviceIOControl(CtlMask - not) succeeded\n"));
450 }
451 else
452 {
453 LogFlowFunc(("DeviceIOControl(CtlMask) failed\n"));
454 }
455
456 LogFlowFunc(("Finished VRDP change request thread\n"));
457 return 0;
458}
459
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