VirtualBox

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

Last change on this file since 35863 was 33966, checked in by vboxsync, 14 years ago

VBoxTray: Cleaning up, refactoring, grouping window messages.

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