VirtualBox

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

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

Rewrote seamless notification handling.

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