VirtualBox

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

Last change on this file since 4595 was 4594, checked in by vboxsync, 18 years ago

Split up stats & memory balloon management

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette