VirtualBox

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

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

Implemented notification for guest about an active VRDP connection.

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