VirtualBox

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

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

config file cleanup + small copyright year update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.3 KB
Line 
1/** @file
2 * VBoxTray - Guest Additions Tray Application
3 */
4
5/*
6 * Copyright (C) 2006-2009 Sun Microsystems, Inc.
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 *
16 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
17 * Clara, CA 95054 USA or visit http://www.sun.com if you need
18 * additional information or have any questions.
19 */
20
21#include "VBoxTray.h"
22#include "VBoxSeamless.h"
23#include "VBoxClipboard.h"
24#include "VBoxDisplay.h"
25#include "VBoxRestore.h"
26#include "VBoxVRDP.h"
27#include "VBoxStatistics.h"
28#include "VBoxMemBalloon.h"
29#include <VBoxHook.h>
30#include "resource.h"
31#include <malloc.h>
32#include <VBoxGuestInternal.h>
33
34#include "helpers.h"
35#include <sddl.h>
36
37/* global variables */
38HANDLE gVBoxDriver;
39HANDLE gStopSem;
40HANDLE ghSeamlessNotifyEvent = 0;
41SERVICE_STATUS gVBoxServiceStatus;
42SERVICE_STATUS_HANDLE gVBoxServiceStatusHandle;
43HINSTANCE gInstance;
44HWND gToolWindow;
45
46/* Prototypes */
47VOID DisplayChangeThread(void *dummy);
48LRESULT CALLBACK VBoxToolWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
49
50/* The service table. */
51static VBOXSERVICEINFO vboxServiceTable[] =
52{
53 {
54 "Display",
55 VBoxDisplayInit,
56 VBoxDisplayThread,
57 VBoxDisplayDestroy,
58 },
59 {
60 "Shared Clipboard",
61 VBoxClipboardInit,
62 VBoxClipboardThread,
63 VBoxClipboardDestroy
64 },
65 {
66 "Seamless Windows",
67 VBoxSeamlessInit,
68 VBoxSeamlessThread,
69 VBoxSeamlessDestroy
70 },
71#ifdef VBOX_WITH_MANAGEMENT
72 {
73 "Memory Balloon",
74 VBoxMemBalloonInit,
75 VBoxMemBalloonThread,
76 VBoxMemBalloonDestroy,
77 },
78 {
79 "Guest Statistics",
80 VBoxStatsInit,
81 VBoxStatsThread,
82 VBoxStatsDestroy,
83 },
84#endif
85#ifdef VBOX_WITH_VRDP_SESSION_HANDLING
86 {
87 "Restore",
88 VBoxRestoreInit,
89 VBoxRestoreThread,
90 VBoxRestoreDestroy,
91 },
92#endif
93 {
94 "VRDP",
95 VBoxVRDPInit,
96 VBoxVRDPThread,
97 VBoxVRDPDestroy,
98 },
99 {
100 NULL
101 }
102};
103
104static int vboxStartServices (VBOXSERVICEENV *pEnv, VBOXSERVICEINFO *pTable)
105{
106 Log(("VBoxTray: Starting services...\n"));
107
108 pEnv->hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
109
110 if (!pEnv->hStopEvent)
111 {
112 /* Could not create event. */
113 return VERR_NOT_SUPPORTED;
114 }
115
116 while (pTable->pszName)
117 {
118 Log(("Starting %s...\n", pTable->pszName));
119
120 int rc = VINF_SUCCESS;
121
122 bool fStartThread = false;
123
124 pTable->hThread = (HANDLE)0;
125 pTable->pInstance = NULL;
126 pTable->fStarted = false;
127
128 if (pTable->pfnInit)
129 {
130 rc = pTable->pfnInit (pEnv, &pTable->pInstance, &fStartThread);
131 }
132
133 if (RT_FAILURE (rc))
134 {
135 Log(("Failed to initialize rc = %Rrc.\n", rc));
136 }
137 else
138 {
139 if (pTable->pfnThread && fStartThread)
140 {
141 unsigned threadid;
142
143 pTable->hThread = (HANDLE)_beginthreadex (NULL, /* security */
144 0, /* stacksize */
145 pTable->pfnThread,
146 pTable->pInstance,
147 0, /* initflag */
148 &threadid);
149
150 if (pTable->hThread == (HANDLE)(0))
151 {
152 rc = VERR_NOT_SUPPORTED;
153 }
154 }
155
156 if (RT_FAILURE (rc))
157 {
158 Log(("Failed to start the thread.\n"));
159
160 if (pTable->pfnDestroy)
161 {
162 pTable->pfnDestroy (pEnv, pTable->pInstance);
163 }
164 }
165 else
166 {
167 pTable->fStarted = true;
168 }
169 }
170
171 /* Advance to next table element. */
172 pTable++;
173 }
174
175 return VINF_SUCCESS;
176}
177
178static void vboxStopServices (VBOXSERVICEENV *pEnv, VBOXSERVICEINFO *pTable)
179{
180 if (!pEnv->hStopEvent)
181 {
182 return;
183 }
184
185 /* Signal to all threads. */
186 SetEvent(pEnv->hStopEvent);
187
188 while (pTable->pszName)
189 {
190 if (pTable->fStarted)
191 {
192 if (pTable->pfnThread)
193 {
194 /* There is a thread, wait for termination. */
195 WaitForSingleObject(pTable->hThread, INFINITE);
196
197 CloseHandle (pTable->hThread);
198 pTable->hThread = 0;
199 }
200
201 if (pTable->pfnDestroy)
202 {
203 pTable->pfnDestroy (pEnv, pTable->pInstance);
204 }
205
206 pTable->fStarted = false;
207 }
208
209 /* Advance to next table element. */
210 pTable++;
211 }
212
213 CloseHandle (pEnv->hStopEvent);
214}
215
216
217void WINAPI VBoxServiceStart(void)
218{
219 Log(("VBoxTray: Leaving service main function"));
220
221 VBOXSERVICEENV svcEnv;
222
223 DWORD status = NO_ERROR;
224
225 /* open VBox guest driver */
226 gVBoxDriver = CreateFile(VBOXGUEST_DEVICE_NAME,
227 GENERIC_READ | GENERIC_WRITE,
228 FILE_SHARE_READ | FILE_SHARE_WRITE,
229 NULL,
230 OPEN_EXISTING,
231 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
232 NULL);
233 if (gVBoxDriver == INVALID_HANDLE_VALUE)
234 {
235 LogRel(("VBoxTray: Could not open VirtualBox Guest Additions driver! Please install / start it first! rc = %d\n", GetLastError()));
236 status = ERROR_GEN_FAILURE;
237 }
238
239 Log(("VBoxTray: Driver Handle = %p, Status = %p\n", gVBoxDriver, status));
240
241 if (status == NO_ERROR)
242 {
243 /* create a custom window class */
244 WNDCLASS windowClass = {0};
245 windowClass.style = CS_NOCLOSE;
246 windowClass.lpfnWndProc = (WNDPROC)VBoxToolWndProc;
247 windowClass.hInstance = gInstance;
248 windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
249 windowClass.lpszClassName = "VirtualBoxTool";
250 if (!RegisterClass(&windowClass))
251 status = GetLastError();
252 }
253
254 Log(("VBoxTray: Class st %p\n", status));
255
256 if (status == NO_ERROR)
257 {
258 /* create our window */
259 gToolWindow = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
260 "VirtualBoxTool", "VirtualBoxTool",
261 WS_POPUPWINDOW,
262 -200, -200, 100, 100, NULL, NULL, gInstance, NULL);
263 if (!gToolWindow)
264 status = GetLastError();
265 else
266 {
267 /* move the window beneach the mouse pointer so that we get access to it */
268 POINT mousePos;
269 GetCursorPos(&mousePos);
270 SetWindowPos(gToolWindow, HWND_TOPMOST, mousePos.x - 10, mousePos.y - 10, 0, 0,
271 SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
272 /* change the mouse pointer so that we can go for a hardware shape */
273 SetCursor(LoadCursor(NULL, IDC_APPSTARTING));
274 SetCursor(LoadCursor(NULL, IDC_ARROW));
275 /* move back our tool window */
276 SetWindowPos(gToolWindow, HWND_TOPMOST, -200, -200, 0, 0,
277 SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
278 }
279 }
280
281 Log(("VBoxTray: Window Handle = %p, Status = %p\n", gToolWindow, status));
282
283 if (status == NO_ERROR)
284 {
285 gStopSem = CreateEvent(NULL, TRUE, FALSE, NULL);
286 if (gStopSem == NULL)
287 {
288 Log(("VBoxTray: CreateEvent for Stopping failed: rc = %d\n", GetLastError()));
289 return;
290 }
291
292 /* We need to setup a security descriptor to allow other processes modify access to the seamless notification event semaphore */
293 SECURITY_ATTRIBUTES SecAttr;
294 OSVERSIONINFO info;
295 char secDesc[SECURITY_DESCRIPTOR_MIN_LENGTH];
296 DWORD dwMajorVersion = 5; /* default XP */
297 BOOL ret;
298
299 SecAttr.nLength = sizeof(SecAttr);
300 SecAttr.bInheritHandle = FALSE;
301 SecAttr.lpSecurityDescriptor = &secDesc;
302 InitializeSecurityDescriptor(SecAttr.lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
303 ret = SetSecurityDescriptorDacl(SecAttr.lpSecurityDescriptor, TRUE, 0, FALSE);
304 if (!ret)
305 Log(("VBoxTray: SetSecurityDescriptorDacl failed with %d\n", GetLastError()));
306
307 info.dwOSVersionInfoSize = sizeof(info);
308 if (GetVersionEx(&info))
309 {
310 Log(("VBoxTray: Windows version major %d minor %d\n", info.dwMajorVersion, info.dwMinorVersion));
311 dwMajorVersion = info.dwMajorVersion;
312 }
313
314 /* For Vista and up we need to change the integrity of the security descriptor too */
315 if (dwMajorVersion >= 6)
316 {
317 HMODULE hModule;
318
319 BOOL (WINAPI * pfnConvertStringSecurityDescriptorToSecurityDescriptorA)(LPCSTR StringSecurityDescriptor, DWORD StringSDRevision, PSECURITY_DESCRIPTOR *SecurityDescriptor, PULONG SecurityDescriptorSize);
320
321 hModule = LoadLibrary("ADVAPI32.DLL");
322 if (hModule)
323 {
324 PSECURITY_DESCRIPTOR pSD;
325 PACL pSacl = NULL;
326 BOOL fSaclPresent = FALSE;
327 BOOL fSaclDefaulted = FALSE;
328
329 *(uintptr_t *)&pfnConvertStringSecurityDescriptorToSecurityDescriptorA = (uintptr_t)GetProcAddress(hModule, "ConvertStringSecurityDescriptorToSecurityDescriptorA");
330
331 Log(("VBoxTray: pfnConvertStringSecurityDescriptorToSecurityDescriptorA = %x\n", pfnConvertStringSecurityDescriptorToSecurityDescriptorA));
332 if (pfnConvertStringSecurityDescriptorToSecurityDescriptorA)
333 {
334 ret = pfnConvertStringSecurityDescriptorToSecurityDescriptorA("S:(ML;;NW;;;LW)", /* this means "low integrity" */
335 SDDL_REVISION_1, &pSD, NULL);
336 if (!ret)
337 Log(("VBoxTray: ConvertStringSecurityDescriptorToSecurityDescriptorA failed with %d\n", GetLastError()));
338
339 ret = GetSecurityDescriptorSacl(pSD, &fSaclPresent, &pSacl, &fSaclDefaulted);
340 if (!ret)
341 Log(("VBoxTray: GetSecurityDescriptorSacl failed with %d\n", GetLastError()));
342
343 ret = SetSecurityDescriptorSacl(SecAttr.lpSecurityDescriptor, TRUE, pSacl, FALSE);
344 if (!ret)
345 Log(("VBoxTray: SetSecurityDescriptorSacl failed with %d\n", GetLastError()));
346 }
347 }
348 }
349
350 if (dwMajorVersion >= 5) /* Only for W2K and up ... */
351 {
352 ghSeamlessNotifyEvent = CreateEvent(&SecAttr, FALSE, FALSE, VBOXHOOK_GLOBAL_EVENT_NAME);
353 if (ghSeamlessNotifyEvent == NULL)
354 {
355 Log(("VBoxTray: CreateEvent for Seamless failed: rc = %d\n", GetLastError()));
356 return;
357 }
358 }
359 }
360
361 /*
362 * Start services listed in the vboxServiceTable.
363 */
364 svcEnv.hInstance = gInstance;
365 svcEnv.hDriver = gVBoxDriver;
366
367 if (status == NO_ERROR)
368 {
369 int rc = vboxStartServices (&svcEnv, vboxServiceTable);
370
371 if (RT_FAILURE (rc))
372 {
373 status = ERROR_GEN_FAILURE;
374 }
375 }
376
377 /* terminate service if something went wrong */
378 if (status != NO_ERROR)
379 {
380 vboxStopServices (&svcEnv, vboxServiceTable);
381 return;
382 }
383
384 BOOL fTrayIconCreated = false;
385
386 /* prepare the system tray icon */
387 NOTIFYICONDATA ndata;
388 memset (&ndata, 0, sizeof (ndata));
389 ndata.cbSize = NOTIFYICONDATA_V1_SIZE; // sizeof(NOTIFYICONDATA);
390 ndata.hWnd = gToolWindow;
391 ndata.uID = 2000;
392 ndata.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
393 ndata.uCallbackMessage = WM_USER;
394 ndata.hIcon = LoadIcon(gInstance, MAKEINTRESOURCE(IDI_VIRTUALBOX));
395 sprintf(ndata.szTip, "Sun VirtualBox Guest Additions %d.%d.%dr%d", VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV);
396
397 Log(("VBoxTray: ndata.hWnd %08X, ndata.hIcon = %p\n", ndata.hWnd, ndata.hIcon));
398
399 /* Boost thread priority to make sure we wake up early for seamless window notifications (not sure if it actually makes any difference though) */
400 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
401
402 /*
403 * Main execution loop
404 * Wait for the stop semaphore to be posted or a window event to arrive
405 */
406
407 DWORD dwEventCount = 2;
408 HANDLE hWaitEvent[2] = {gStopSem, ghSeamlessNotifyEvent};
409
410 if (0 == ghSeamlessNotifyEvent) /* If seamless mode is not active / supported, reduce event array count */
411 dwEventCount = 1;
412
413 Log(("VBoxTray: Number of events to wait in main loop: %ld\n", dwEventCount));
414
415 while(true)
416 {
417 DWORD waitResult = MsgWaitForMultipleObjectsEx(dwEventCount, hWaitEvent, 500, QS_ALLINPUT, 0);
418 waitResult = waitResult - WAIT_OBJECT_0;
419
420 Log(("VBoxTray: Wait result = %ld.\n", waitResult));
421
422 if (waitResult == 0)
423 {
424 Log(("VBoxTray: Event 'Exit' triggered.\n"));
425 /* exit */
426 break;
427 }
428 else if ((waitResult == 1) && (ghSeamlessNotifyEvent!=0)) /* Only jump in, if seamless is active! */
429 {
430 Log(("VBoxTray: Event 'Seamless' triggered.\n"));
431
432 /* seamless window notification */
433 VBoxSeamlessCheckWindows();
434 }
435 else
436 {
437 /* timeout or a window message, handle it */
438 MSG msg;
439 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
440 {
441 Log(("VBoxTray: msg %p\n", msg.message));
442 if (msg.message == WM_QUIT)
443 {
444 Log(("VBoxTray: WM_QUIT!\n"));
445 SetEvent(gStopSem);
446 continue;
447 }
448 TranslateMessage(&msg);
449 DispatchMessage(&msg);
450 }
451 /* we might have to repeat this operation because the shell might not be loaded yet */
452 if (!fTrayIconCreated)
453 {
454 fTrayIconCreated = Shell_NotifyIcon(NIM_ADD, &ndata);
455 Log(("VBoxTray: fTrayIconCreated = %d, err %08X\n", fTrayIconCreated, GetLastError ()));
456 }
457 }
458 }
459
460 Log(("VBoxTray: Returned from main loop, exiting ...\n"));
461
462 /* remove the system tray icon */
463 Shell_NotifyIcon(NIM_DELETE, &ndata);
464
465 Log(("VBoxTray: waiting for display change thread ...\n"));
466
467 vboxStopServices (&svcEnv, vboxServiceTable);
468
469 Log(("VBoxTray: Destroying tool window ...\n"));
470
471 /* destroy the tool window */
472 DestroyWindow(gToolWindow);
473
474 UnregisterClass("VirtualBoxTool", gInstance);
475
476 CloseHandle(gVBoxDriver);
477 CloseHandle(gStopSem);
478 CloseHandle(ghSeamlessNotifyEvent);
479
480 Log(("VBoxTray: Leaving service main function\n"));
481
482 return;
483}
484
485
486/**
487 * Main function
488 */
489int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
490{
491 /* Do not use a global namespace ("Global\\") for mutex name here, will blow up NT4 compatibility! */
492 HANDLE hMutexAppRunning = CreateMutex (NULL, FALSE, "VBoxTray");
493 if ( (hMutexAppRunning != NULL)
494 && (GetLastError() == ERROR_ALREADY_EXISTS))
495 {
496 /* Close the mutex for this application instance. */
497 CloseHandle (hMutexAppRunning);
498 hMutexAppRunning = NULL;
499 return 0;
500 }
501
502 int rc = RTR3Init();
503 if (RT_FAILURE(rc))
504 return rc;
505
506 rc = VbglR3Init();
507 if (RT_FAILURE(rc))
508 return rc;
509
510 LogRel(("VBoxTray: Started.\n"));
511
512 gInstance = hInstance;
513 VBoxServiceStart();
514
515 LogRel(("VBoxTray: Ended.\n"));
516
517 /* Release instance mutex. */
518 if (hMutexAppRunning != NULL) {
519 CloseHandle (hMutexAppRunning);
520 hMutexAppRunning = NULL;
521 }
522
523 VbglR3Term();
524 return 0;
525}
526
527/**
528 * Window procedure for our tool window
529 */
530LRESULT CALLBACK VBoxToolWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
531{
532 switch (msg)
533 {
534 case WM_CLOSE:
535 break;
536
537 case WM_DESTROY:
538 break;
539
540 case WM_VBOX_INSTALL_SEAMLESS_HOOK:
541 VBoxSeamlessInstallHook();
542 break;
543
544 case WM_VBOX_REMOVE_SEAMLESS_HOOK:
545 VBoxSeamlessRemoveHook();
546 break;
547
548 case WM_VBOX_SEAMLESS_UPDATE:
549 VBoxSeamlessCheckWindows();
550 break;
551
552 case WM_VBOX_RESTORED:
553 VBoxRestoreSession();
554 break;
555
556 case WM_VBOX_CHECK_VRDP:
557 VBoxRestoreCheckVRDP();
558 break;
559
560 default:
561 return DefWindowProc(hwnd, msg, wParam, lParam);
562 }
563 return 0;
564}
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