VirtualBox

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

Last change on this file since 70344 was 70267, checked in by vboxsync, 7 years ago

VBoxService/win: Don't unload modules we dynamically resolve APIs from. Duh.

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