VirtualBox

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

最後變更 在這個檔案從95855是 95855,由 vboxsync 提交於 3 年 前

VBoxService/win: Drop unused process.h from win source file. bugref:10261

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette