VirtualBox

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

Last change on this file since 27991 was 26493, checked in by vboxsync, 15 years ago

Additions: whitespace cleanup

  • 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 26493 2010-02-14 07:50:58Z vboxsync $ */
2/** @file
3 * VBoxVRDP - VBox VRDP connection notification
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/* 0x0501 for SPI_SETDROPSHADOW */
23#define _WIN32_WINNT 0x0501
24#include <windows.h>
25#include "VBoxTray.h"
26#include "VBoxVRDP.h"
27#include <VBox/VMMDev.h>
28#include <VBoxGuestInternal.h>
29#include <iprt/assert.h>
30#include "helpers.h"
31
32
33/* The guest receives VRDP_ACTIVE/VRDP_INACTIVE notifications.
34 *
35 * When VRDP_ACTIVE is received, the guest asks host about the experience level.
36 * The experience level is an integer value, different values disable some GUI effects.
37 *
38 * On VRDP_INACTIVE the original values are restored.
39 *
40 * Note: that this is not controlled from the client, that is a per VM settings.
41 *
42 * Note: theming is disabled separately by EnableTheming.
43 */
44
45#define VBOX_SPI_STRING 0
46#define VBOX_SPI_BOOL_PTR 1
47#define VBOX_SPI_BOOL 2
48#define VBOX_SPI_PTR 3
49
50static ANIMATIONINFO animationInfoDisable =
51{
52 sizeof (ANIMATIONINFO),
53 FALSE
54};
55
56typedef struct _VBoxExperienceParameter
57{
58 const char *name;
59 UINT uActionSet;
60 UINT uActionGet;
61 uint32_t level; /* The parameter remain enabled at this or higher level. */
62 int type;
63 void *pvDisable;
64 UINT cbSavedValue;
65 char achSavedValue[2 * MAX_PATH]; /* Large enough to save the bitmap path. */
66} VBoxExperienceParameter;
67
68#define SPI_(l, a) #a, SPI_SET##a, SPI_GET##a, VRDP_EXPERIENCE_LEVEL_##l
69
70static VBoxExperienceParameter parameters[] =
71{
72 { SPI_(MEDIUM, DESKWALLPAPER), VBOX_SPI_STRING, "" },
73 { SPI_(FULL, DROPSHADOW), VBOX_SPI_BOOL_PTR, },
74 { SPI_(HIGH, FONTSMOOTHING), VBOX_SPI_BOOL, },
75 { SPI_(FULL, MENUFADE), VBOX_SPI_BOOL_PTR, },
76 { SPI_(FULL, COMBOBOXANIMATION), VBOX_SPI_BOOL_PTR, },
77 { SPI_(FULL, CURSORSHADOW), VBOX_SPI_BOOL_PTR, },
78 { SPI_(HIGH, GRADIENTCAPTIONS), VBOX_SPI_BOOL_PTR, },
79 { SPI_(FULL, LISTBOXSMOOTHSCROLLING), VBOX_SPI_BOOL_PTR, },
80 { SPI_(FULL, MENUANIMATION), VBOX_SPI_BOOL_PTR, },
81 { SPI_(FULL, SELECTIONFADE), VBOX_SPI_BOOL_PTR, },
82 { SPI_(FULL, TOOLTIPANIMATION), VBOX_SPI_BOOL_PTR, },
83 { SPI_(FULL, ANIMATION), VBOX_SPI_PTR, &animationInfoDisable, sizeof (ANIMATIONINFO) },
84 { SPI_(MEDIUM, DRAGFULLWINDOWS), VBOX_SPI_BOOL, }
85};
86
87#undef SPI_
88
89static void vboxExperienceSet (uint32_t level)
90{
91 int i;
92 for (i = 0; i < RT_ELEMENTS(parameters); i++)
93 {
94 if (parameters[i].level > level)
95 {
96 /*
97 * The parameter has to be disabled.
98 */
99 Log(("VBoxTray: vboxExperienceSet: Saving %s\n", parameters[i].name));
100
101 /* Save the current value. */
102 switch (parameters[i].type)
103 {
104 case VBOX_SPI_STRING:
105 {
106 /* The 2nd parameter is size in characters of the buffer.
107 * The 3rd parameter points to the buffer.
108 */
109 SystemParametersInfo (parameters[i].uActionGet,
110 MAX_PATH,
111 parameters[i].achSavedValue,
112 0);
113 } break;
114
115 case VBOX_SPI_BOOL:
116 case VBOX_SPI_BOOL_PTR:
117 {
118 /* The 3rd parameter points to BOOL. */
119 SystemParametersInfo (parameters[i].uActionGet,
120 0,
121 parameters[i].achSavedValue,
122 0);
123 } break;
124
125 case VBOX_SPI_PTR:
126 {
127 /* The 3rd parameter points to the structure.
128 * The cbSize member of this structure must be set.
129 * The uiParam parameter must alos be set.
130 */
131 if (parameters[i].cbSavedValue > sizeof (parameters[i].achSavedValue))
132 {
133 Log(("VBoxTray: vboxExperienceSet: Not enough space %d > %d\n", parameters[i].cbSavedValue, sizeof (parameters[i].achSavedValue)));
134 break;
135 }
136
137 *(UINT *)&parameters[i].achSavedValue[0] = parameters[i].cbSavedValue;
138
139 SystemParametersInfo (parameters[i].uActionGet,
140 parameters[i].cbSavedValue,
141 parameters[i].achSavedValue,
142 0);
143 } break;
144
145 default:
146 break;
147 }
148
149 Log(("VBoxTray: vboxExperienceSet: Disabling %s\n", parameters[i].name));
150
151 /* Disable the feature. */
152 switch (parameters[i].type)
153 {
154 case VBOX_SPI_STRING:
155 {
156 /* The 3rd parameter points to the string. */
157 SystemParametersInfo (parameters[i].uActionSet,
158 0,
159 parameters[i].pvDisable,
160 SPIF_SENDCHANGE);
161 } break;
162
163 case VBOX_SPI_BOOL:
164 {
165 /* The 2nd parameter is BOOL. */
166 SystemParametersInfo (parameters[i].uActionSet,
167 FALSE,
168 NULL,
169 SPIF_SENDCHANGE);
170 } break;
171
172 case VBOX_SPI_BOOL_PTR:
173 {
174 /* The 3rd parameter is NULL to disable. */
175 SystemParametersInfo (parameters[i].uActionSet,
176 0,
177 NULL,
178 SPIF_SENDCHANGE);
179 } break;
180
181 case VBOX_SPI_PTR:
182 {
183 /* The 3rd parameter points to the structure. */
184 SystemParametersInfo (parameters[i].uActionSet,
185 0,
186 parameters[i].pvDisable,
187 SPIF_SENDCHANGE);
188 } break;
189
190 default:
191 break;
192 }
193 }
194 }
195}
196
197static void vboxExperienceRestore (uint32_t level)
198{
199 int i;
200 for (i = 0; i < RT_ELEMENTS(parameters); i++)
201 {
202 if (parameters[i].level > level)
203 {
204 Log(("VBoxTray: vboxExperienceRestore: Restoring %s\n", parameters[i].name));
205
206 /* Restore the feature. */
207 switch (parameters[i].type)
208 {
209 case VBOX_SPI_STRING:
210 {
211 /* The 3rd parameter points to the string. */
212 SystemParametersInfo (parameters[i].uActionSet,
213 0,
214 parameters[i].achSavedValue,
215 SPIF_SENDCHANGE);
216 } break;
217
218 case VBOX_SPI_BOOL:
219 {
220 /* The 2nd parameter is BOOL. */
221 SystemParametersInfo (parameters[i].uActionSet,
222 *(BOOL *)&parameters[i].achSavedValue[0],
223 NULL,
224 SPIF_SENDCHANGE);
225 } break;
226
227 case VBOX_SPI_BOOL_PTR:
228 {
229 /* The 3rd parameter is NULL to disable. */
230 BOOL fSaved = *(BOOL *)&parameters[i].achSavedValue[0];
231
232 SystemParametersInfo (parameters[i].uActionSet,
233 0,
234 fSaved? &fSaved: NULL,
235 SPIF_SENDCHANGE);
236 } break;
237
238 case VBOX_SPI_PTR:
239 {
240 /* The 3rd parameter points to the structure. */
241 SystemParametersInfo (parameters[i].uActionSet,
242 0,
243 parameters[i].achSavedValue,
244 SPIF_SENDCHANGE);
245 } break;
246
247 default:
248 break;
249 }
250 }
251 }
252}
253
254
255typedef struct _VBOXVRDPCONTEXT
256{
257 const VBOXSERVICEENV *pEnv;
258
259 uint32_t level;
260 BOOL fSavedThemeEnabled;
261
262 HMODULE hModule;
263
264 HRESULT (* pfnEnableTheming)(BOOL fEnable);
265 BOOL (* pfnIsThemeActive)(VOID);
266} VBOXVRDPCONTEXT;
267
268
269static VBOXVRDPCONTEXT gCtx = {0};
270
271
272int VBoxVRDPInit(const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread)
273{
274 Log(("VBoxTray: VBoxVRDPInit\n"));
275
276 gCtx.pEnv = pEnv;
277 gCtx.level = VRDP_EXPERIENCE_LEVEL_FULL;
278 gCtx.fSavedThemeEnabled = FALSE;
279
280 gCtx.hModule = LoadLibrary("UxTheme");
281
282 if (gCtx.hModule)
283 {
284 *(uintptr_t *)&gCtx.pfnEnableTheming = (uintptr_t)GetProcAddress(gCtx.hModule, "EnableTheming");
285 *(uintptr_t *)&gCtx.pfnIsThemeActive = (uintptr_t)GetProcAddress(gCtx.hModule, "IsThemeActive");
286 }
287 else
288 {
289 gCtx.pfnEnableTheming = 0;
290 }
291
292 *pfStartThread = true;
293 *ppInstance = &gCtx;
294 return VINF_SUCCESS;
295}
296
297
298void VBoxVRDPDestroy(const VBOXSERVICEENV *pEnv, void *pInstance)
299{
300 Log(("VBoxTray: VBoxVRDPDestroy\n"));
301 VBOXVRDPCONTEXT *pCtx = (VBOXVRDPCONTEXT *)pInstance;
302 vboxExperienceRestore (pCtx->level);
303 if (gCtx.hModule)
304 FreeLibrary(gCtx.hModule);
305 gCtx.hModule = 0;
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 succeded\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 Log(("VBoxTray: VBoxVRDPThread: Error from DeviceIoControl VBOXGUEST_IOCTL_VMMREQUEST\n"));
412
413 /* sleep a bit to not eat too much CPU in case the above call always fails */
414 if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 10) == WAIT_OBJECT_0)
415 {
416 fTerminate = true;
417 break;
418 }
419 }
420 }
421 }
422 else
423 {
424 Log(("VBoxTray: VBoxVRDPThread: Error from DeviceIoControl VBOXGUEST_IOCTL_WAITEVENT\n"));
425
426 /* sleep a bit to not eat too much CPU in case the above call always fails */
427 if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 10) == WAIT_OBJECT_0)
428 {
429 fTerminate = true;
430 break;
431 }
432 }
433 } while (!fTerminate);
434
435 maskInfo.u32OrMask = 0;
436 maskInfo.u32NotMask = VMMDEV_EVENT_VRDP;
437 if (DeviceIoControl (gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
438 {
439 Log(("VBoxTray: VBoxVRDPThread: DeviceIOControl(CtlMask - not) succeeded\n"));
440 }
441 else
442 {
443 Log(("VBoxTray: VBoxVRDPThread: DeviceIOControl(CtlMask) failed\n"));
444 }
445
446 Log(("VBoxTray: VBoxVRDPThread: Finished VRDP change request thread\n"));
447 return 0;
448}
449
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