VirtualBox

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

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

Reapplied 23773

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