VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/VBoxService/VBoxVRDP.cpp@ 8061

Last change on this file since 8061 was 5999, checked in by vboxsync, 17 years ago

The Giant CDDL Dual-License Header Change.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.0 KB
Line 
1/** @file
2 *
3 * VBoxVRDP - VBox VRDP connection notification
4 *
5 */
6
7/*
8 * Copyright (C) 2006-2007 innotek GmbH
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
19/* 0x0501 for SPI_SETDROPSHADOW */
20#define _WIN32_WINNT 0x0501
21#include <windows.h>
22#include "VBoxService.h"
23#include "VBoxVRDP.h"
24#include <VBox/VBoxDev.h>
25#include <VBoxGuestInternal.h>
26#include <iprt/assert.h>
27#include "helpers.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 < ELEMENTS(parameters); i++)
90 {
91 if (parameters[i].level > level)
92 {
93 /*
94 * The parameter has to be disabled.
95 */
96 dprintf(("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 dprintf(("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 dprintf(("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 < ELEMENTS(parameters); i++)
198 {
199 if (parameters[i].level > level)
200 {
201 dprintf(("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 HMODULE hModule;
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 dprintf(("VBoxVRDPInit\n"));
272
273 gCtx.pEnv = pEnv;
274 gCtx.level = VRDP_EXPERIENCE_LEVEL_FULL;
275 gCtx.fSavedThemeEnabled = FALSE;
276
277 gCtx.hModule = LoadLibrary("UxTheme");
278
279 if (gCtx.hModule)
280 {
281 *(uintptr_t *)&gCtx.pfnEnableTheming = (uintptr_t)GetProcAddress(gCtx.hModule, "EnableTheming");
282 *(uintptr_t *)&gCtx.pfnIsThemeActive = (uintptr_t)GetProcAddress(gCtx.hModule, "IsThemeActive");
283 }
284 else
285 {
286 gCtx.pfnEnableTheming = 0;
287 }
288
289 *pfStartThread = true;
290 *ppInstance = &gCtx;
291 return VINF_SUCCESS;
292}
293
294
295void VBoxVRDPDestroy(const VBOXSERVICEENV *pEnv, void *pInstance)
296{
297 dprintf(("VBoxVRDPDestroy\n"));
298 VBOXVRDPCONTEXT *pCtx = (VBOXVRDPCONTEXT *)pInstance;
299 vboxExperienceRestore (pCtx->level);
300 if (gCtx.hModule)
301 FreeLibrary(gCtx.hModule);
302 gCtx.hModule = 0;
303 return;
304}
305
306/**
307 * Thread function to wait for and process mode change requests
308 */
309unsigned __stdcall VBoxVRDPThread(void *pInstance)
310{
311 VBOXVRDPCONTEXT *pCtx = (VBOXVRDPCONTEXT *)pInstance;
312 HANDLE gVBoxDriver = pCtx->pEnv->hDriver;
313 bool fTerminate = false;
314 VBoxGuestFilterMaskInfo maskInfo;
315 DWORD cbReturned;
316
317 maskInfo.u32OrMask = VMMDEV_EVENT_VRDP;
318 maskInfo.u32NotMask = 0;
319 if (DeviceIoControl (gVBoxDriver, IOCTL_VBOXGUEST_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
320 {
321 dprintf(("VBoxVRDPThread: DeviceIOControl(CtlMask - or) succeeded\n"));
322 }
323 else
324 {
325 dprintf(("VBoxVRDPThread: DeviceIOControl(CtlMask) failed\n"));
326 return 0;
327 }
328
329 do
330 {
331 /* wait for the event */
332 VBoxGuestWaitEventInfo waitEvent;
333 waitEvent.u32TimeoutIn = 5000;
334 waitEvent.u32EventMaskIn = VMMDEV_EVENT_VRDP;
335 if (DeviceIoControl(gVBoxDriver, IOCTL_VBOXGUEST_WAITEVENT, &waitEvent, sizeof(waitEvent), &waitEvent, sizeof(waitEvent), &cbReturned, NULL))
336 {
337 dprintf(("VBoxVRDPThread: DeviceIOControl succeded\n"));
338
339 /* are we supposed to stop? */
340 if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 0) == WAIT_OBJECT_0)
341 break;
342
343 dprintf(("VBoxVRDPThread: checking event\n"));
344
345 /* did we get the right event? */
346 if (waitEvent.u32EventFlagsOut & VMMDEV_EVENT_VRDP)
347 {
348 /* Call the host to get VRDP status and the experience level. */
349 VMMDevVRDPChangeRequest vrdpChangeRequest = {0};
350
351 vrdpChangeRequest.header.size = sizeof(VMMDevVRDPChangeRequest);
352 vrdpChangeRequest.header.version = VMMDEV_REQUEST_HEADER_VERSION;
353 vrdpChangeRequest.header.requestType = VMMDevReq_GetVRDPChangeRequest;
354 vrdpChangeRequest.u8VRDPActive = 0;
355 vrdpChangeRequest.u32VRDPExperienceLevel = 0;
356
357 if (DeviceIoControl (gVBoxDriver,
358 IOCTL_VBOXGUEST_VMMREQUEST,
359 &vrdpChangeRequest,
360 sizeof(VMMDevVRDPChangeRequest),
361 &vrdpChangeRequest,
362 sizeof(VMMDevVRDPChangeRequest),
363 &cbReturned, NULL))
364 {
365 dprintf(("VBoxVRDPThread: u8VRDPActive = %d, level %d\n", vrdpChangeRequest.u8VRDPActive, vrdpChangeRequest.u32VRDPExperienceLevel));
366
367 if (vrdpChangeRequest.u8VRDPActive)
368 {
369 pCtx->level = vrdpChangeRequest.u32VRDPExperienceLevel;
370 vboxExperienceSet (pCtx->level);
371
372 if (pCtx->level == VRDP_EXPERIENCE_LEVEL_ZERO
373 && pCtx->pfnEnableTheming
374 && pCtx->pfnIsThemeActive)
375 {
376 pCtx->fSavedThemeEnabled = pCtx->pfnIsThemeActive ();
377
378 dprintf(("VBoxVRDPThread: pCtx->fSavedThemeEnabled = %d\n", pCtx->fSavedThemeEnabled));
379
380 if (pCtx->fSavedThemeEnabled)
381 {
382 pCtx->pfnEnableTheming (FALSE);
383 }
384 }
385 }
386 else
387 {
388 if (pCtx->level == VRDP_EXPERIENCE_LEVEL_ZERO
389 && pCtx->pfnEnableTheming
390 && pCtx->pfnIsThemeActive)
391 {
392 if (pCtx->fSavedThemeEnabled)
393 {
394 /* @todo the call returns S_OK but theming remains disabled. */
395 HRESULT hrc = pCtx->pfnEnableTheming (TRUE);
396 dprintf(("VBoxVRDPThread: enabling theme rc = 0x%08X\n", hrc));
397 pCtx->fSavedThemeEnabled = FALSE;
398 }
399 }
400
401 vboxExperienceRestore (pCtx->level);
402
403 pCtx->level = VRDP_EXPERIENCE_LEVEL_FULL;
404 }
405 }
406 else
407 {
408 dprintf(("VBoxService: error from DeviceIoControl IOCTL_VBOXGUEST_VMMREQUEST\n"));
409
410 /* sleep a bit to not eat too much CPU in case the above call always fails */
411 if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 10) == WAIT_OBJECT_0)
412 {
413 fTerminate = true;
414 break;
415 }
416 }
417 }
418 }
419 else
420 {
421 dprintf(("VBoxService: error from DeviceIoControl IOCTL_VBOXGUEST_WAITEVENT\n"));
422
423 /* sleep a bit to not eat too much CPU in case the above call always fails */
424 if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 10) == WAIT_OBJECT_0)
425 {
426 fTerminate = true;
427 break;
428 }
429 }
430 } while (!fTerminate);
431
432 maskInfo.u32OrMask = 0;
433 maskInfo.u32NotMask = VMMDEV_EVENT_VRDP;
434 if (DeviceIoControl (gVBoxDriver, IOCTL_VBOXGUEST_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
435 {
436 dprintf(("VBoxVRDPThread: DeviceIOControl(CtlMask - not) succeeded\n"));
437 }
438 else
439 {
440 dprintf(("VBoxVRDPThread: DeviceIOControl(CtlMask) failed\n"));
441 }
442
443 dprintf(("VBoxVRDPThread: finished VRDP change request thread\n"));
444 return 0;
445}
446
447
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