VirtualBox

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

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

Skeleton for guest management extension

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