VirtualBox

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

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

Cleaned up

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