VirtualBox

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

Last change on this file since 10759 was 10552, checked in by vboxsync, 16 years ago

More IOCTLs.

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