VirtualBox

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

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

Merged private draganddrop branch into trunk.

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