VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxService/VBoxService-win.cpp@ 72097

Last change on this file since 72097 was 70346, checked in by vboxsync, 7 years ago

VBoxService: Needed to dynamically resolve two more APIs to make it work on NT 3.1.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.7 KB
Line 
1/* $Id: VBoxService-win.cpp 70346 2017-12-26 15:52:28Z vboxsync $ */
2/** @file
3 * VBoxService - Guest Additions Service Skeleton, Windows Specific Parts.
4 */
5
6/*
7 * Copyright (C) 2009-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#include <iprt/assert.h>
23#include <iprt/err.h>
24#include <iprt/ldr.h>
25#include <iprt/system.h> /* For querying OS version. */
26#include <VBox/VBoxGuestLib.h>
27
28#define WIN32_NO_STATUS
29#include <iprt/win/ws2tcpip.h>
30#include <iprt/win/winsock2.h>
31#undef WIN32_NO_STATUS
32#include <iprt/nt/nt-and-windows.h>
33#include <iprt/win/iphlpapi.h>
34#include <process.h>
35#include <aclapi.h>
36#include <tlhelp32.h>
37#define _NTDEF_
38#include <Ntsecapi.h>
39
40#include "VBoxServiceInternal.h"
41
42
43/*********************************************************************************************************************************
44* Internal Functions *
45*********************************************************************************************************************************/
46static void WINAPI vgsvcWinMain(DWORD argc, LPTSTR *argv);
47
48
49/*********************************************************************************************************************************
50* Global Variables *
51*********************************************************************************************************************************/
52static DWORD g_dwWinServiceLastStatus = 0;
53SERVICE_STATUS_HANDLE g_hWinServiceStatus = NULL;
54/** The semaphore for the dummy Windows service. */
55static RTSEMEVENT g_WindowsEvent = NIL_RTSEMEVENT;
56
57static SERVICE_TABLE_ENTRY const g_aServiceTable[] =
58{
59 { VBOXSERVICE_NAME, vgsvcWinMain },
60 { NULL, NULL}
61};
62
63/** @name APIs from ADVAPI32.DLL.
64 * @{ */
65decltype(RegisterServiceCtrlHandlerExA) *g_pfnRegisterServiceCtrlHandlerExA; /**< W2K+ */
66decltype(ChangeServiceConfig2A) *g_pfnChangeServiceConfig2A; /**< W2K+ */
67decltype(GetNamedSecurityInfoA) *g_pfnGetNamedSecurityInfoA; /**< NT4+ */
68decltype(SetEntriesInAclA) *g_pfnSetEntriesInAclA; /**< NT4+ */
69decltype(SetNamedSecurityInfoA) *g_pfnSetNamedSecurityInfoA; /**< NT4+ */
70decltype(LsaNtStatusToWinError) *g_pfnLsaNtStatusToWinError; /**< NT3.51+ */
71/** @} */
72
73/** @name API from KERNEL32.DLL
74 * @{ */
75decltype(CreateToolhelp32Snapshot) *g_pfnCreateToolhelp32Snapshot; /**< W2K+, but Geoff says NT4. Hmm. */
76decltype(Process32First) *g_pfnProcess32First; /**< W2K+, but Geoff says NT4. Hmm. */
77decltype(Process32Next) *g_pfnProcess32Next; /**< W2K+, but Geoff says NT4. Hmm. */
78decltype(Module32First) *g_pfnModule32First; /**< W2K+, but Geoff says NT4. Hmm. */
79decltype(Module32Next) *g_pfnModule32Next; /**< W2K+, but Geoff says NT4. Hmm. */
80decltype(GetSystemTimeAdjustment) *g_pfnGetSystemTimeAdjustment; /**< NT 3.50+ */
81decltype(SetSystemTimeAdjustment) *g_pfnSetSystemTimeAdjustment; /**< NT 3.50+ */
82/** @} */
83
84/** @name API from NTDLL.DLL
85 * @{ */
86decltype(ZwQuerySystemInformation) *g_pfnZwQuerySystemInformation; /**< NT4 (where as NtQuerySystemInformation is W2K). */
87/** @} */
88
89/** @name API from IPHLPAPI.DLL
90 * @{ */
91decltype(GetAdaptersInfo) *g_pfnGetAdaptersInfo;
92/** @} */
93
94/** @name APIs from WS2_32.DLL
95 * @note WSAIoctl is not present in wsock32.dll, so no point in trying the
96 * fallback here.
97 * @{ */
98decltype(WSAStartup) *g_pfnWSAStartup;
99decltype(WSACleanup) *g_pfnWSACleanup;
100decltype(WSASocketA) *g_pfnWSASocketA;
101decltype(WSAIoctl) *g_pfnWSAIoctl;
102decltype(WSAGetLastError) *g_pfnWSAGetLastError;
103decltype(closesocket) *g_pfnclosesocket;
104decltype(inet_ntoa) *g_pfninet_ntoa;
105
106/** @} */
107
108/**
109 * Resolve APIs not present on older windows versions.
110 */
111void VGSvcWinResolveApis(void)
112{
113 RTLDRMOD hLdrMod;
114#define RESOLVE_SYMBOL(a_fn) do { RT_CONCAT(g_pfn, a_fn) = (decltype(a_fn) *)RTLdrGetFunction(hLdrMod, #a_fn); } while (0)
115
116 /* From ADVAPI32.DLL: */
117 int rc = RTLdrLoadSystem("advapi32.dll", true /*fNoUnload*/, &hLdrMod);
118 AssertRC(rc);
119 if (RT_SUCCESS(rc))
120 {
121 RESOLVE_SYMBOL(RegisterServiceCtrlHandlerExA);
122 RESOLVE_SYMBOL(ChangeServiceConfig2A);
123 RESOLVE_SYMBOL(GetNamedSecurityInfoA);
124 RESOLVE_SYMBOL(SetEntriesInAclA);
125 RESOLVE_SYMBOL(SetNamedSecurityInfoA);
126 RESOLVE_SYMBOL(LsaNtStatusToWinError);
127 RTLdrClose(hLdrMod);
128 }
129
130 /* From KERNEL32.DLL: */
131 rc = RTLdrLoadSystem("kernel32.dll", true /*fNoUnload*/, &hLdrMod);
132 AssertRC(rc);
133 if (RT_SUCCESS(rc))
134 {
135 RESOLVE_SYMBOL(CreateToolhelp32Snapshot);
136 RESOLVE_SYMBOL(Process32First);
137 RESOLVE_SYMBOL(Process32Next);
138 RESOLVE_SYMBOL(Module32First);
139 RESOLVE_SYMBOL(Module32Next);
140 RESOLVE_SYMBOL(GetSystemTimeAdjustment);
141 RESOLVE_SYMBOL(SetSystemTimeAdjustment);
142 RTLdrClose(hLdrMod);
143 }
144
145 /* From NTDLL.DLL: */
146 rc = RTLdrLoadSystem("ntdll.dll", true /*fNoUnload*/, &hLdrMod);
147 AssertRC(rc);
148 if (RT_SUCCESS(rc))
149 {
150 RESOLVE_SYMBOL(ZwQuerySystemInformation);
151 RTLdrClose(hLdrMod);
152 }
153
154 /* From IPHLPAPI.DLL: */
155 rc = RTLdrLoadSystem("iphlpapi.dll", true /*fNoUnload*/, &hLdrMod);
156 if (RT_SUCCESS(rc))
157 {
158 RESOLVE_SYMBOL(GetAdaptersInfo);
159 RTLdrClose(hLdrMod);
160 }
161
162 /* From WS2_32.DLL: */
163 rc = RTLdrLoadSystem("ws2_32.dll", true /*fNoUnload*/, &hLdrMod);
164 if (RT_SUCCESS(rc))
165 {
166 RESOLVE_SYMBOL(WSAStartup);
167 RESOLVE_SYMBOL(WSACleanup);
168 RESOLVE_SYMBOL(WSASocketA);
169 RESOLVE_SYMBOL(WSAIoctl);
170 RESOLVE_SYMBOL(WSAGetLastError);
171 RESOLVE_SYMBOL(closesocket);
172 RESOLVE_SYMBOL(inet_ntoa);
173 RTLdrClose(hLdrMod);
174 }
175}
176
177
178/**
179 * @todo Add full unicode support.
180 * @todo Add event log capabilities / check return values.
181 */
182static int vgsvcWinAddAceToObjectsSecurityDescriptor(LPTSTR pszObjName, SE_OBJECT_TYPE enmObjectType, const char *pszTrustee,
183 TRUSTEE_FORM enmTrusteeForm, DWORD dwAccessRights, ACCESS_MODE fAccessMode,
184 DWORD dwInheritance)
185{
186 int rc;
187 if ( g_pfnGetNamedSecurityInfoA
188 && g_pfnSetEntriesInAclA
189 && g_pfnSetNamedSecurityInfoA)
190 {
191 /* Get a pointer to the existing DACL. */
192 PSECURITY_DESCRIPTOR pSD = NULL;
193 PACL pOldDACL = NULL;
194 DWORD rcWin = g_pfnGetNamedSecurityInfoA(pszObjName, enmObjectType, DACL_SECURITY_INFORMATION,
195 NULL, NULL, &pOldDACL, NULL, &pSD);
196 if (rcWin == ERROR_SUCCESS)
197 {
198 /* Initialize an EXPLICIT_ACCESS structure for the new ACE. */
199 EXPLICIT_ACCESSA ExplicitAccess;
200 RT_ZERO(ExplicitAccess);
201 ExplicitAccess.grfAccessPermissions = dwAccessRights;
202 ExplicitAccess.grfAccessMode = fAccessMode;
203 ExplicitAccess.grfInheritance = dwInheritance;
204 ExplicitAccess.Trustee.TrusteeForm = enmTrusteeForm;
205 ExplicitAccess.Trustee.ptstrName = (char *)pszTrustee;
206
207 /* Create a new ACL that merges the new ACE into the existing DACL. */
208 PACL pNewDACL = NULL;
209 rcWin = g_pfnSetEntriesInAclA(1, &ExplicitAccess, pOldDACL, &pNewDACL);
210 if (rcWin == ERROR_SUCCESS)
211 {
212 /* Attach the new ACL as the object's DACL. */
213 rcWin = g_pfnSetNamedSecurityInfoA(pszObjName, enmObjectType, DACL_SECURITY_INFORMATION,
214 NULL, NULL, pNewDACL, NULL);
215 if (rcWin == ERROR_SUCCESS)
216 rc = VINF_SUCCESS;
217 else
218 {
219 VGSvcError("AddAceToObjectsSecurityDescriptor: SetNamedSecurityInfo: Error %u\n", rcWin);
220 rc = RTErrConvertFromWin32(rcWin);
221 }
222 if (pNewDACL)
223 LocalFree(pNewDACL);
224 }
225 else
226 {
227 VGSvcError("AddAceToObjectsSecurityDescriptor: SetEntriesInAcl: Error %u\n", rcWin);
228 rc = RTErrConvertFromWin32(rcWin);
229 }
230 if (pSD)
231 LocalFree(pSD);
232 }
233 else
234 {
235 if (rcWin == ERROR_FILE_NOT_FOUND)
236 VGSvcError("AddAceToObjectsSecurityDescriptor: Object not found/installed: %s\n", pszObjName);
237 else
238 VGSvcError("AddAceToObjectsSecurityDescriptor: GetNamedSecurityInfo: Error %u\n", rcWin);
239 rc = RTErrConvertFromWin32(rcWin);
240 }
241 }
242 else
243 rc = VINF_SUCCESS; /* fake it */
244 return rc;
245}
246
247
248/** Reports our current status to the SCM. */
249static BOOL vgsvcWinSetStatus(DWORD dwStatus, DWORD dwCheckPoint)
250{
251 if (g_hWinServiceStatus == NULL) /* Program could be in testing mode, so no service environment available. */
252 return FALSE;
253
254 VGSvcVerbose(2, "Setting service status to: %ld\n", dwStatus);
255 g_dwWinServiceLastStatus = dwStatus;
256
257 SERVICE_STATUS ss;
258 RT_ZERO(ss);
259
260 ss.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
261 ss.dwCurrentState = dwStatus;
262 /* Don't accept controls when in start pending state. */
263 if (ss.dwCurrentState != SERVICE_START_PENDING)
264 {
265 ss.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
266
267 /* Don't use SERVICE_ACCEPT_SESSIONCHANGE on Windows 2000 or earlier. This makes SCM angry. */
268 char szOSVersion[32];
269 int rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOSVersion, sizeof(szOSVersion));
270 if (RT_SUCCESS(rc))
271 {
272 if (RTStrVersionCompare(szOSVersion, "5.1") >= 0)
273 ss.dwControlsAccepted |= SERVICE_ACCEPT_SESSIONCHANGE;
274 }
275 else
276 VGSvcError("Error determining OS version, rc=%Rrc\n", rc);
277 }
278
279 ss.dwWin32ExitCode = NO_ERROR;
280 ss.dwServiceSpecificExitCode = 0; /* Not used */
281 ss.dwCheckPoint = dwCheckPoint;
282 ss.dwWaitHint = 3000;
283
284 BOOL fStatusSet = SetServiceStatus(g_hWinServiceStatus, &ss);
285 if (!fStatusSet)
286 VGSvcError("Error reporting service status=%ld (controls=%x, checkpoint=%ld) to SCM: %ld\n",
287 dwStatus, ss.dwControlsAccepted, dwCheckPoint, GetLastError());
288 return fStatusSet;
289}
290
291
292/**
293 * Reports SERVICE_STOP_PENDING to SCM.
294 *
295 * @param uCheckPoint Some number.
296 */
297void VGSvcWinSetStopPendingStatus(uint32_t uCheckPoint)
298{
299 vgsvcWinSetStatus(SERVICE_STOP_PENDING, uCheckPoint);
300}
301
302
303static RTEXITCODE vgsvcWinSetDesc(SC_HANDLE hService)
304{
305 /* On W2K+ there's ChangeServiceConfig2() which lets us set some fields
306 like a longer service description. */
307 if (g_pfnChangeServiceConfig2A)
308 {
309 /** @todo On Vista+ SERVICE_DESCRIPTION also supports localized strings! */
310 SERVICE_DESCRIPTION desc;
311 desc.lpDescription = VBOXSERVICE_DESCRIPTION;
312 if (!g_pfnChangeServiceConfig2A(hService, SERVICE_CONFIG_DESCRIPTION, &desc))
313 {
314 VGSvcError("Cannot set the service description! Error: %ld\n", GetLastError());
315 return RTEXITCODE_FAILURE;
316 }
317 }
318 return RTEXITCODE_SUCCESS;
319}
320
321
322/**
323 * Installs the service.
324 */
325RTEXITCODE VGSvcWinInstall(void)
326{
327 VGSvcVerbose(1, "Installing service ...\n");
328
329 TCHAR imagePath[MAX_PATH] = { 0 };
330 GetModuleFileName(NULL, imagePath, sizeof(imagePath));
331
332 SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
333 if (hSCManager == NULL)
334 {
335 VGSvcError("Could not open SCM! Error: %ld\n", GetLastError());
336 return RTEXITCODE_FAILURE;
337 }
338
339 RTEXITCODE rc = RTEXITCODE_SUCCESS;
340 SC_HANDLE hService = CreateService(hSCManager,
341 VBOXSERVICE_NAME, VBOXSERVICE_FRIENDLY_NAME,
342 SERVICE_ALL_ACCESS,
343 SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
344 SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
345 imagePath, NULL, NULL, NULL, NULL, NULL);
346 if (hService != NULL)
347 VGSvcVerbose(0, "Service successfully installed!\n");
348 else
349 {
350 DWORD dwErr = GetLastError();
351 switch (dwErr)
352 {
353 case ERROR_SERVICE_EXISTS:
354 VGSvcVerbose(1, "Service already exists, just updating the service config.\n");
355 hService = OpenService(hSCManager, VBOXSERVICE_NAME, SERVICE_ALL_ACCESS);
356 if (hService)
357 {
358 if (ChangeServiceConfig (hService,
359 SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
360 SERVICE_DEMAND_START,
361 SERVICE_ERROR_NORMAL,
362 imagePath,
363 NULL,
364 NULL,
365 NULL,
366 NULL,
367 NULL,
368 VBOXSERVICE_FRIENDLY_NAME))
369 VGSvcVerbose(1, "The service config has been successfully updated.\n");
370 else
371 rc = VGSvcError("Could not change service config! Error: %ld\n", GetLastError());
372 }
373 else
374 rc = VGSvcError("Could not open service! Error: %ld\n", GetLastError());
375 break;
376
377 default:
378 rc = VGSvcError("Could not create service! Error: %ld\n", dwErr);
379 break;
380 }
381 }
382
383 if (rc == RTEXITCODE_SUCCESS)
384 rc = vgsvcWinSetDesc(hService);
385
386 CloseServiceHandle(hService);
387 CloseServiceHandle(hSCManager);
388 return rc;
389}
390
391/**
392 * Uninstalls the service.
393 */
394RTEXITCODE VGSvcWinUninstall(void)
395{
396 VGSvcVerbose(1, "Uninstalling service ...\n");
397
398 SC_HANDLE hSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
399 if (hSCManager == NULL)
400 {
401 VGSvcError("Could not open SCM! Error: %d\n", GetLastError());
402 return RTEXITCODE_FAILURE;
403 }
404
405 RTEXITCODE rcExit;
406 SC_HANDLE hService = OpenService(hSCManager, VBOXSERVICE_NAME, SERVICE_ALL_ACCESS );
407 if (hService != NULL)
408 {
409 if (DeleteService(hService))
410 {
411 /*
412 * ???
413 */
414 HKEY hKey = NULL;
415 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
416 "SYSTEM\\CurrentControlSet\\Services\\EventLog\\System",
417 0,
418 KEY_ALL_ACCESS,
419 &hKey)
420 == ERROR_SUCCESS)
421 {
422 RegDeleteKey(hKey, VBOXSERVICE_NAME);
423 RegCloseKey(hKey);
424 }
425
426 VGSvcVerbose(0, "Service successfully uninstalled!\n");
427 rcExit = RTEXITCODE_SUCCESS;
428 }
429 else
430 rcExit = VGSvcError("Could not remove service! Error: %d\n", GetLastError());
431 CloseServiceHandle(hService);
432 }
433 else
434 rcExit = VGSvcError("Could not open service! Error: %d\n", GetLastError());
435 CloseServiceHandle(hSCManager);
436
437 return rcExit;
438}
439
440
441static int vgsvcWinStart(void)
442{
443 int rc = VINF_SUCCESS;
444
445 /*
446 * Create a well-known SID for the "Builtin Users" group and modify the ACE
447 * for the shared folders miniport redirector DN (whatever DN means).
448 */
449 PSID pBuiltinUsersSID = NULL;
450 SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_LOCAL_SID_AUTHORITY;
451 if (AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_LOCAL_RID, 0, 0, 0, 0, 0, 0, 0, &pBuiltinUsersSID))
452 {
453 rc = vgsvcWinAddAceToObjectsSecurityDescriptor(TEXT("\\\\.\\VBoxMiniRdrDN"), SE_FILE_OBJECT,
454 (LPTSTR)pBuiltinUsersSID, TRUSTEE_IS_SID,
455 FILE_GENERIC_READ | FILE_GENERIC_WRITE, SET_ACCESS, NO_INHERITANCE);
456 /* If we don't find our "VBoxMiniRdrDN" (for Shared Folders) object above,
457 don't report an error; it just might be not installed. Otherwise this
458 would cause the SCM to hang on starting up the service. */
459 if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND)
460 rc = VINF_SUCCESS;
461
462 FreeSid(pBuiltinUsersSID);
463 }
464 else
465 rc = RTErrConvertFromWin32(GetLastError());
466 if (RT_SUCCESS(rc))
467 {
468 /*
469 * Start the service.
470 */
471 vgsvcWinSetStatus(SERVICE_START_PENDING, 0);
472
473 rc = VGSvcStartServices();
474 if (RT_SUCCESS(rc))
475 {
476 vgsvcWinSetStatus(SERVICE_RUNNING, 0);
477 VGSvcMainWait();
478 }
479 else
480 {
481 vgsvcWinSetStatus(SERVICE_STOPPED, 0);
482#if 0 /** @todo r=bird: Enable this if SERVICE_CONTROL_STOP isn't triggered automatically */
483 VGSvcStopServices();
484#endif
485 }
486 }
487 else
488 vgsvcWinSetStatus(SERVICE_STOPPED, 0);
489
490 if (RT_FAILURE(rc))
491 VGSvcError("Service failed to start with rc=%Rrc!\n", rc);
492
493 return rc;
494}
495
496
497/**
498 * Call StartServiceCtrlDispatcher.
499 *
500 * The main() thread invokes this when not started in foreground mode. It
501 * won't return till the service is being shutdown (unless start up fails).
502 *
503 * @returns RTEXITCODE_SUCCESS on normal return after service shutdown.
504 * Something else on failure, error will have been reported.
505 */
506RTEXITCODE VGSvcWinEnterCtrlDispatcher(void)
507{
508 if (!StartServiceCtrlDispatcher(&g_aServiceTable[0]))
509 return VGSvcError("StartServiceCtrlDispatcher: %u. Please start %s with option -f (foreground)!\n",
510 GetLastError(), g_pszProgName);
511 return RTEXITCODE_SUCCESS;
512}
513
514
515/**
516 * Event code to description.
517 *
518 * @returns String.
519 * @param dwEvent The event code.
520 */
521static const char *vgsvcWTSStateToString(DWORD dwEvent)
522{
523 switch (dwEvent)
524 {
525 case WTS_CONSOLE_CONNECT: return "A session was connected to the console terminal";
526 case WTS_CONSOLE_DISCONNECT: return "A session was disconnected from the console terminal";
527 case WTS_REMOTE_CONNECT: return "A session connected to the remote terminal";
528 case WTS_REMOTE_DISCONNECT: return "A session was disconnected from the remote terminal";
529 case WTS_SESSION_LOGON: return "A user has logged on to a session";
530 case WTS_SESSION_LOGOFF: return "A user has logged off the session";
531 case WTS_SESSION_LOCK: return "A session has been locked";
532 case WTS_SESSION_UNLOCK: return "A session has been unlocked";
533 case WTS_SESSION_REMOTE_CONTROL: return "A session has changed its remote controlled status";
534#ifdef WTS_SESSION_CREATE
535 case WTS_SESSION_CREATE: return "A session has been created";
536#endif
537#ifdef WTS_SESSION_TERMINATE
538 case WTS_SESSION_TERMINATE: return "The session has been terminated";
539#endif
540 default: return "Uknonwn state";
541 }
542}
543
544
545/**
546 * Common control handler.
547 *
548 * @returns Return code for NT5+.
549 * @param dwControl The control code.
550 */
551static DWORD vgsvcWinCtrlHandlerCommon(DWORD dwControl)
552{
553 DWORD rcRet = NO_ERROR;
554 switch (dwControl)
555 {
556 case SERVICE_CONTROL_INTERROGATE:
557 vgsvcWinSetStatus(g_dwWinServiceLastStatus, 0);
558 break;
559
560 case SERVICE_CONTROL_STOP:
561 case SERVICE_CONTROL_SHUTDOWN:
562 {
563 vgsvcWinSetStatus(SERVICE_STOP_PENDING, 0);
564
565 int rc2 = VGSvcStopServices();
566 if (RT_FAILURE(rc2))
567 rcRet = ERROR_GEN_FAILURE;
568 else
569 {
570 rc2 = VGSvcReportStatus(VBoxGuestFacilityStatus_Terminated);
571 AssertRC(rc2);
572 }
573
574 vgsvcWinSetStatus(SERVICE_STOPPED, 0);
575 break;
576 }
577
578 default:
579 VGSvcVerbose(1, "Control handler: Function not implemented: %#x\n", dwControl);
580 rcRet = ERROR_CALL_NOT_IMPLEMENTED;
581 break;
582 }
583
584 return rcRet;
585}
586
587
588/**
589 * Callback registered by RegisterServiceCtrlHandler on NT4 and earlier.
590 */
591static VOID WINAPI vgsvcWinCtrlHandlerNt4(DWORD dwControl)
592{
593 VGSvcVerbose(2, "Control handler (NT4): dwControl=%#x\n", dwControl);
594 vgsvcWinCtrlHandlerCommon(dwControl);
595}
596
597
598/**
599 * Callback registered by RegisterServiceCtrlHandler on NT5 and later.
600 */
601static DWORD WINAPI vgsvcWinCtrlHandlerNt5Plus(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext)
602{
603 VGSvcVerbose(2, "Control handler: dwControl=%#x, dwEventType=%#x\n", dwControl, dwEventType);
604 RT_NOREF1(lpContext);
605
606 switch (dwControl)
607 {
608 default:
609 return vgsvcWinCtrlHandlerCommon(dwControl);
610
611 case SERVICE_CONTROL_SESSIONCHANGE: /* Only Windows 2000 and up. */
612 {
613 AssertPtr(lpEventData);
614 PWTSSESSION_NOTIFICATION pNotify = (PWTSSESSION_NOTIFICATION)lpEventData;
615 Assert(pNotify->cbSize == sizeof(WTSSESSION_NOTIFICATION));
616
617 VGSvcVerbose(1, "Control handler: %s (Session=%ld, Event=%#x)\n",
618 vgsvcWTSStateToString(dwEventType), pNotify->dwSessionId, dwEventType);
619
620 /* Handle all events, regardless of dwEventType. */
621 int rc2 = VGSvcVMInfoSignal();
622 AssertRC(rc2);
623
624 return NO_ERROR;
625 }
626 }
627}
628
629
630static void WINAPI vgsvcWinMain(DWORD argc, LPTSTR *argv)
631{
632 RT_NOREF2(argc, argv);
633 VGSvcVerbose(2, "Registering service control handler ...\n");
634 if (g_pfnRegisterServiceCtrlHandlerExA)
635 g_hWinServiceStatus = g_pfnRegisterServiceCtrlHandlerExA(VBOXSERVICE_NAME, vgsvcWinCtrlHandlerNt5Plus, NULL);
636 else
637 g_hWinServiceStatus = RegisterServiceCtrlHandlerA(VBOXSERVICE_NAME, vgsvcWinCtrlHandlerNt4);
638 if (g_hWinServiceStatus != NULL)
639 {
640 VGSvcVerbose(2, "Service control handler registered.\n");
641 vgsvcWinStart();
642 }
643 else
644 {
645 DWORD dwErr = GetLastError();
646 switch (dwErr)
647 {
648 case ERROR_INVALID_NAME:
649 VGSvcError("Invalid service name!\n");
650 break;
651 case ERROR_SERVICE_DOES_NOT_EXIST:
652 VGSvcError("Service does not exist!\n");
653 break;
654 default:
655 VGSvcError("Could not register service control handle! Error: %ld\n", dwErr);
656 break;
657 }
658 }
659}
660
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