1 // Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
3 // This file is part of the VNC system.
5 // The VNC system is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20 // If the source code for the VNC system is not available from the place
21 // whence you received this file, check http://www.uk.research.att.com/vnc or contact
22 // the authors on vnc@uk.research.att.com for information on obtaining it.
24 // This file has been adapted to the Win32 version of Bacula
25 // by Kern E. Sibbald. Many thanks to ATT and James Weatherall,
26 // the original author, for providing an excellent template.
28 // Copyright (2000-2003) Kern E. Sibbald
34 // Implementation of service-oriented functionality of Bacula
35 // I.e. command line options that contact a running version of
36 // Bacula and ask it to do something (show about, show status,
41 #include "winbacula.h"
42 #include "winservice.h"
45 void set_service_description(SC_HANDLE hSCManager, SC_HANDLE hService,
49 // OS-SPECIFIC ROUTINES
51 // Create an instance of the bacService class to cause the static fields to be
52 // initialised properly
54 extern int NoGetFileAttributesEx; /* set if function no avail -- Win95 */
59 BOOL g_impersonating_user = 0;
61 bacService::bacService()
63 OSVERSIONINFO osversioninfo;
64 osversioninfo.dwOSVersionInfoSize = sizeof(osversioninfo);
66 // Get the current OS version
67 if (!GetVersionEx(&osversioninfo)) {
70 g_platform_id = osversioninfo.dwPlatformId;
72 if (osversioninfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS &&
73 osversioninfo.dwMinorVersion == 0) {
74 /* Running Win95 so no GetFileAttributesEx available */
75 NoGetFileAttributesEx = 1;
80 // IsWin95 - returns a BOOL indicating whether the current OS is Win95
84 return (g_platform_id == VER_PLATFORM_WIN32_WINDOWS);
87 // IsWinNT - returns a bool indicating whether the current OS is WinNT
91 return (g_platform_id == VER_PLATFORM_WIN32_NT);
94 // Internal routine to find the Bacula menu class window and
95 // post a message to it!
98 PostToBacula(UINT message, WPARAM wParam, LPARAM lParam)
100 // Locate the hidden Bacula menu window
101 HWND hservwnd = FindWindow(MENU_CLASS_NAME, NULL);
102 if (hservwnd == NULL) {
106 // Post the message to Bacula
107 PostMessage(hservwnd, message, wParam, lParam);
112 // Static routine to show the Properties dialog for a currently-running
113 // copy of Bacula, (usually a servicified version.)
116 bacService::ShowProperties()
118 #ifdef properties_implemented
119 // Post to the Bacula menu window
120 if (!PostToBacula(MENU_PROPERTIES_SHOW, 0, 0)) {
121 MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
128 // Static routine to show the Default Properties dialog for a currently-running
129 // copy of Bacula, (usually a servicified version.)
132 bacService::ShowDefaultProperties()
134 #ifdef properties_implemented
135 // Post to the Bacula menu window
136 if (!PostToBacula(MENU_DEFAULT_PROPERTIES_SHOW, 0, 0)) {
137 MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
145 // Static routine to show the About dialog for a currently-running
146 // copy of Bacula, (usually a servicified version.)
149 bacService::ShowAboutBox()
151 // Post to the Bacula menu window
152 if (!PostToBacula(MENU_ABOUTBOX_SHOW, 0, 0)) {
153 MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
159 // Static routine to show the Status dialog for a currently-running
160 // copy of Bacula, (usually a servicified version.)
163 bacService::ShowStatus()
165 // Post to the Bacula menu window
166 if (!PostToBacula(MENU_STATUS_SHOW, 0, 0)) {
167 MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
173 // Static routine to show the Events dialog for a currently-running
174 // copy of Bacula, (usually a servicified version.)
177 bacService::ShowEvents()
179 // Post to the Bacula menu window
180 if (!PostToBacula(MENU_EVENTS_SHOW, 0, 0)) {
181 MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
188 // Static routine to tell a locally-running instance of the server
189 // to connect out to a new client
192 bacService::PostAddNewClient(unsigned long ipaddress)
194 // Post to the Bacula menu window
195 if (!PostToBacula(MENU_ADD_CLIENT_MSG, 0, ipaddress)) {
196 MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
203 // SERVICE-MODE ROUTINES
205 // Service-mode defines:
208 #define BAC_APPNAME "bacula"
210 // Internal service name
211 #define BAC_SERVICENAME "Bacula"
213 // Displayed service name
214 #define BAC_SERVICEDISPLAYNAME "Bacula File Server"
216 // List other required serves
217 #define BAC_DEPENDENCIES ""
220 // Internal service state
221 SERVICE_STATUS g_srvstatus; // current status of the service
222 SERVICE_STATUS_HANDLE g_hstatus;
224 DWORD g_servicethread = 0;
225 char* g_errortext[256];
228 // Forward defines of internal service functions
229 void WINAPI ServiceMain(DWORD argc, char **argv);
230 DWORD WINAPI ServiceWorkThread(LPVOID lpwThreadParam);
232 void WINAPI ServiceCtrl(DWORD ctrlcode);
233 bool WINAPI CtrlHandler (DWORD ctrltype);
234 BOOL ReportStatus(DWORD state, DWORD exitcode, DWORD waithint);
236 // ROUTINE TO QUERY WHETHER THIS PROCESS IS RUNNING AS A SERVICE OR NOT
238 BOOL g_servicemode = FALSE;
241 bacService::RunningAsService()
243 return g_servicemode;
247 bacService::KillRunningCopy()
249 while (PostToBacula(WM_CLOSE, 0, 0))
255 // ROUTINE TO POST THE HANDLE OF THE CURRENT USER TO THE RUNNING Bacula, IN ORDER
256 // THAT IT CAN LOAD THE APPROPRIATE SETTINGS. THIS IS USED ONLY BY THE SVCHELPER
257 // OPTION, WHEN RUNNING UNDER NT
259 bacService::PostUserHelperMessage()
261 // - Check the platform type
266 // - Get the current process ID
267 DWORD processId = GetCurrentProcessId();
269 // - Post it to the existing Bacula
270 if (!PostToBacula(MENU_SERVICEHELPER_MSG, 0, (LPARAM)processId)) {
274 // - Wait until it's been used
278 // ROUTINE TO PROCESS AN INCOMING INSTANCE OF THE ABOVE MESSAGE
280 bacService::ProcessUserHelperMessage(WPARAM wParam, LPARAM lParam) {
281 // - Check the platform type
282 if (!IsWinNT() || !bacService::RunningAsService()) {
286 // - Close the HKEY_CURRENT_USER key, to force NT to reload it for the new user
287 // NB: Note that this is _really_ dodgy if ANY other thread is accessing the key!
288 if (RegCloseKey(HKEY_CURRENT_USER) != ERROR_SUCCESS) {
292 // - Revert to our own identity
294 g_impersonating_user = FALSE;
296 // - Open the specified process
297 HANDLE processHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD)lParam);
298 if (processHandle == NULL) {
302 // - Get the token for the given process
303 HANDLE userToken = NULL;
304 if (!OpenProcessToken(processHandle, TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE, &userToken)) {
305 CloseHandle(processHandle);
308 CloseHandle(processHandle);
310 // - Set this thread to impersonate them
311 if (!ImpersonateLoggedOnUser(userToken)) {
312 CloseHandle(userToken);
315 CloseHandle(userToken);
317 g_impersonating_user = TRUE;
321 // SERVICE MAIN ROUTINE
323 bacService::BaculaServiceMain()
325 // Mark that we are a service
326 g_servicemode = TRUE;
328 // How to run as a service depends upon the OS being used
329 switch (g_platform_id) {
332 case VER_PLATFORM_WIN32_WINDOWS:
334 // Obtain a handle to the kernel library
335 HINSTANCE kerneldll = LoadLibrary("KERNEL32.DLL");
336 if (kerneldll == NULL) {
337 MessageBox(NULL, "KERNEL32.DLL not found: Bacula service not started",
338 "Bacula Service", MB_OK);
342 // And find the RegisterServiceProcess function
343 DWORD (*RegisterService)(DWORD, DWORD);
344 RegisterService = (DWORD (*)(DWORD, DWORD))
345 GetProcAddress(kerneldll, "RegisterServiceProcess");
346 if (RegisterService == NULL) {
347 MessageBox(NULL, "Registry service not found: Bacula service not started",
348 "Bacula Service", MB_OK);
349 log_error_message("Registry service not found");
353 // Register this process with the OS as a service!
354 RegisterService(0, 1);
356 // Run the main program as a service
359 // Then remove the service from the system service table
360 RegisterService(0, 0);
362 // Free the kernel library
363 FreeLibrary(kerneldll);
369 case VER_PLATFORM_WIN32_NT:
371 // Create a service entry table
372 SERVICE_TABLE_ENTRY dispatchTable[] = {
373 {BAC_SERVICENAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain},
377 // Call the service control dispatcher with our entry table
378 if (!StartServiceCtrlDispatcher(dispatchTable)) {
379 log_error_message("StartServiceCtrlDispatcher failed.");
387 // SERVICE MAIN ROUTINE - NT ONLY !!!
388 // NT/Win2K/WinXP ONLY !!!
389 void WINAPI ServiceMain(DWORD argc, char **argv)
393 // Register the service control handler
394 g_hstatus = RegisterServiceCtrlHandler(BAC_SERVICENAME, ServiceCtrl);
396 if (g_hstatus == 0) {
397 log_error_message("RegisterServiceCtlHandler failed");
398 MessageBox(NULL, "Contact Register Service Handler failure",
399 "Bacula service", MB_OK);
403 // Set up some standard service state values
404 g_srvstatus.dwServiceType = SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS;
405 g_srvstatus.dwServiceSpecificExitCode = 0;
407 // Give this status to the SCM
409 SERVICE_START_PENDING, // Service state
410 NO_ERROR, // Exit code type
411 45000)) { // Hint as to how long Bacula should have hung before you assume error
413 ReportStatus(SERVICE_STOPPED, g_error, 0);
414 log_error_message("ReportStatus STOPPED failed 1");
418 // Now start the service for real
419 (void)CreateThread(NULL, 0, ServiceWorkThread, NULL, 0, &dwThreadID);
423 // SERVICE START ROUTINE - thread that calls BaculaAppMain
425 DWORD WINAPI ServiceWorkThread(LPVOID lpwThreadParam)
428 // Save the current thread identifier
429 g_servicethread = GetCurrentThreadId();
431 // report the status to the service control manager.
434 SERVICE_RUNNING, // service state
435 NO_ERROR, // exit code
437 MessageBox(NULL, "Report Service failure", "Bacula Service", MB_OK);
438 log_error_message("ReportStatus RUNNING failed");
442 /* Call Bacula main code */
445 /* Mark that we're no longer running */
448 /* Tell the service manager that we've stopped */
449 ReportStatus(SERVICE_STOPPED, g_error, 0);
454 // SERVICE STOP ROUTINE - post a quit message to the relevant thread
457 // Post a quit message to the main service thread
458 if (g_servicethread != 0) {
459 PostThreadMessage(g_servicethread, WM_QUIT, 0, 0);
463 // SERVICE INSTALL ROUTINE
465 bacService::InstallService()
467 const int pathlength = 2048;
468 char path[pathlength];
469 char servicecmd[pathlength];
472 // Get the filename of this executable
473 if (GetModuleFileName(NULL, path, pathlength-(strlen(BaculaRunService)+2)) == 0) {
474 MessageBox(NULL, "Unable to install Bacula service", szAppName, MB_ICONEXCLAMATION | MB_OK);
478 // Append the service-start flag to the end of the path:
479 if ((int)strlen(path) + 20 + (int)strlen(BaculaRunService) < pathlength) {
480 sprintf(servicecmd, "\"%s\" %s -c %s", path, BaculaRunService, path);
481 len = strlen(servicecmd) - 1;
482 for ( ; len > 0; len--) {
483 if (servicecmd[len] == '\\') {
489 strcat(servicecmd, "\\bacula-fd.conf");
492 log_error_message("Service command length too long");
493 MessageBox(NULL, "Service command length too long. Service not registered.",
494 szAppName, MB_ICONEXCLAMATION | MB_OK);
498 // How to add the Bacula service depends upon the OS
499 switch (g_platform_id) {
502 case VER_PLATFORM_WIN32_WINDOWS:
503 // Locate the RunService registry entry
505 if (RegCreateKey(HKEY_LOCAL_MACHINE,
506 "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",
507 &runservices) != ERROR_SUCCESS) {
508 log_error_message("Cannot write System Registry");
509 MessageBox(NULL, "The System Registry could not be updated - the Bacula service was not installed", szAppName, MB_ICONEXCLAMATION | MB_OK);
513 // Attempt to add a Bacula key
514 if (RegSetValueEx(runservices, szAppName, 0, REG_SZ, (unsigned char *)servicecmd, strlen(servicecmd)+1) != ERROR_SUCCESS) {
515 RegCloseKey(runservices);
516 log_error_message("Cannot add Bacula key to System Registry");
517 MessageBox(NULL, "The Bacula service could not be installed", szAppName, MB_ICONEXCLAMATION | MB_OK);
521 RegCloseKey(runservices);
523 // We have successfully installed the service!
525 "The Bacula File service was successfully installed.\n"
526 "The service may be started by double clicking on the\n"
527 "Bacula \"Start\" icon and will be automatically\n"
528 "be run the next time this machine is rebooted. ",
530 MB_ICONINFORMATION | MB_OK);
534 case VER_PLATFORM_WIN32_NT:
536 SC_HANDLE hsrvmanager;
538 // Open the default, local Service Control Manager database
539 hsrvmanager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
540 if (hsrvmanager == NULL) {
541 log_error_message("OpenSCManager failed");
543 "The Service Control Manager could not be contacted - the Bacula service was not installed",
544 szAppName, MB_ICONEXCLAMATION | MB_OK);
548 // Create an entry for the Bacula service
549 hservice = CreateService(
550 hsrvmanager, // SCManager database
551 BAC_SERVICENAME, // name of service
552 BAC_SERVICEDISPLAYNAME, // name to display
553 SERVICE_ALL_ACCESS, // desired access
554 SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
556 SERVICE_AUTO_START, // start type
557 SERVICE_ERROR_NORMAL, // error control type
558 servicecmd, // service's binary
559 NULL, // no load ordering group
560 NULL, // no tag identifier
561 BAC_DEPENDENCIES, // dependencies
562 NULL, // LocalSystem account
563 NULL); // no password
564 if (hservice == NULL) {
565 CloseServiceHandle(hsrvmanager);
566 log_error_message("CreateService failed");
568 "The Bacula service could not be installed",
569 szAppName, MB_ICONEXCLAMATION | MB_OK);
573 set_service_description(hsrvmanager,hservice,
574 "Provides file backup and restore services. Bacula -- the Network Backup Solution.");
576 CloseServiceHandle(hsrvmanager);
577 CloseServiceHandle(hservice);
579 // Now install the servicehelper registry setting...
580 // Locate the RunService registry entry
582 if (RegCreateKey(HKEY_LOCAL_MACHINE,
583 "Software\\Microsoft\\Windows\\CurrentVersion\\Run",
584 &runapps) != ERROR_SUCCESS) {
585 MessageBox(NULL, "WARNING: Unable to install the ServiceHelper hook\nGlobal user-specific registry settings will not be loaded",
586 szAppName, MB_ICONEXCLAMATION | MB_OK);
588 char servicehelpercmd[pathlength];
590 // Append the service-helper-start flag to the end of the path:
591 if ((int)strlen(path) + 4 + (int)strlen(BaculaRunServiceHelper) < pathlength) {
592 sprintf(servicehelpercmd, "\"%s\" %s", path, BaculaRunServiceHelper);
594 // Add the Bacula Service Helper entry
595 if (RegSetValueEx(runapps, szAppName, 0, REG_SZ,
596 (unsigned char *)servicehelpercmd, strlen(servicehelpercmd)+1) != ERROR_SUCCESS) {
597 MessageBox(NULL, "WARNING:Unable to install the ServiceHelper hook\nGlobal user-specific registry settings will not be loaded", szAppName, MB_ICONEXCLAMATION | MB_OK);
599 RegCloseKey(runapps);
603 // Everything went fine
605 "The Bacula File service was successfully installed.\n"
606 "The service may be started from the Control Panel and will\n"
607 "automatically be run the next time this machine is rebooted.",
609 MB_ICONINFORMATION | MB_OK);
612 log_error_message("Unknown Windows System version");
614 "Unknown Windows operating system.\n"
615 "Cannot install Bacula service.\n",
616 szAppName, MB_ICONEXCLAMATION | MB_OK);
624 // SERVICE REMOVE ROUTINE
626 bacService::RemoveService()
628 // How to remove the Bacula service depends upon the OS
629 switch (g_platform_id) {
632 case VER_PLATFORM_WIN32_WINDOWS:
633 // Locate the RunService registry entry
635 if (RegOpenKey(HKEY_LOCAL_MACHINE,
636 "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",
637 &runservices) != ERROR_SUCCESS) {
639 "Could not find registry entry.\nService probably not registerd - the Bacula service was not removed", szAppName, MB_ICONEXCLAMATION | MB_OK);
641 // Attempt to delete the Bacula key
642 if (RegDeleteValue(runservices, szAppName) != ERROR_SUCCESS) {
643 RegCloseKey(runservices);
644 MessageBox(NULL, "Could not delete Registry key.\nThe Bacula service could not be removed", szAppName, MB_ICONEXCLAMATION | MB_OK);
647 RegCloseKey(runservices);
651 // Try to kill any running copy of Bacula
652 if (!KillRunningCopy()) {
654 "Bacula could not be contacted, probably not running",
655 szAppName, MB_ICONEXCLAMATION | MB_OK);
659 // We have successfully removed the service!
660 MessageBox(NULL, "The Bacula service has been removed", szAppName, MB_ICONINFORMATION | MB_OK);
664 case VER_PLATFORM_WIN32_NT:
666 SC_HANDLE hsrvmanager;
668 // Attempt to remove the service-helper hook
670 if (RegOpenKey(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Run",
671 &runapps) == ERROR_SUCCESS) {
672 // Attempt to delete the Bacula key
673 if (RegDeleteValue(runapps, szAppName) != ERROR_SUCCESS) {
674 MessageBox(NULL, "WARNING:The ServiceHelper hook entry could not be removed from the registry", szAppName, MB_ICONEXCLAMATION | MB_OK);
676 RegCloseKey(runapps);
680 hsrvmanager = OpenSCManager(
681 NULL, // machine (NULL == local)
682 NULL, // database (NULL == default)
683 SC_MANAGER_ALL_ACCESS // access required
686 hservice = OpenService(hsrvmanager, BAC_SERVICENAME, SERVICE_ALL_ACCESS);
687 if (hservice != NULL) {
688 SERVICE_STATUS status;
690 // Try to stop the Bacula service
691 if (ControlService(hservice, SERVICE_CONTROL_STOP, &status)) {
692 while(QueryServiceStatus(hservice, &status)) {
693 if (status.dwCurrentState == SERVICE_STOP_PENDING) {
700 if (status.dwCurrentState != SERVICE_STOPPED) {
701 MessageBox(NULL, "The Bacula service could not be stopped", szAppName, MB_ICONEXCLAMATION | MB_OK);
705 // Now remove the service from the SCM
706 if(DeleteService(hservice)) {
707 MessageBox(NULL, "The Bacula service has been removed", szAppName, MB_ICONINFORMATION | MB_OK);
709 MessageBox(NULL, "The Bacula service could not be removed", szAppName, MB_ICONEXCLAMATION | MB_OK);
712 CloseServiceHandle(hservice);
714 MessageBox(NULL, "The Bacula service could not be found", szAppName, MB_ICONEXCLAMATION | MB_OK);
717 CloseServiceHandle(hsrvmanager);
719 MessageBox(NULL, "The SCM could not be contacted - the Bacula service was not removed", szAppName, MB_ICONEXCLAMATION | MB_OK);
726 // USEFUL SERVICE SUPPORT ROUTINES
728 // Service control routine
729 void WINAPI ServiceCtrl(DWORD ctrlcode)
731 // What control code have we been sent?
733 case SERVICE_CONTROL_STOP:
734 // STOP : The service must stop
735 g_srvstatus.dwCurrentState = SERVICE_STOP_PENDING;
739 case SERVICE_CONTROL_INTERROGATE:
740 // QUERY : Service control manager just wants to know our state
744 // Control code not recognised
749 // Tell the control manager what we're up to.
750 ReportStatus(g_srvstatus.dwCurrentState, NO_ERROR, 0);
753 // Service manager status reporting
754 BOOL ReportStatus(DWORD state,
758 static DWORD checkpoint = 1;
761 // If we're in the start state then we don't want the control manager
762 // sending us control messages because they'll confuse us.
763 if (state == SERVICE_START_PENDING) {
764 g_srvstatus.dwControlsAccepted = 0;
766 g_srvstatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
769 // Save the new status we've been given
770 g_srvstatus.dwCurrentState = state;
771 g_srvstatus.dwWin32ExitCode = exitcode;
772 g_srvstatus.dwWaitHint = waithint;
774 // Update the checkpoint variable to let the SCM know that we
775 // haven't died if requests take a long time
776 if ((state == SERVICE_RUNNING) || (state == SERVICE_STOPPED)) {
777 g_srvstatus.dwCheckPoint = 0;
779 g_srvstatus.dwCheckPoint = checkpoint++;
782 // Tell the SCM our new status
783 if (!(result = SetServiceStatus(g_hstatus, &g_srvstatus))) {
784 log_error_message("SetServiceStatus failed");
791 void LogErrorMsg(char *message, char *fname, int lineno)
798 // Get the error code
799 g_error = GetLastError();
800 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
801 FORMAT_MESSAGE_FROM_SYSTEM,
809 // Use event logging to log the error
810 heventsrc = RegisterEventSource(NULL, BAC_SERVICENAME);
812 sprintf(msgbuff, "\n\n%s error: %ld at %s:%d",
813 BAC_SERVICENAME, g_error, fname, lineno);
814 strings[0] = msgbuff;
815 strings[1] = message;
818 if (heventsrc != NULL) {
822 heventsrc, // handle of event source
823 EVENTLOG_ERROR_TYPE, // event type
826 NULL, // current user's SID
827 3, // strings in 'strings'
828 0, // no bytes of raw data
829 (const char **)strings, // array of error strings
830 NULL); // no raw data
832 DeregisterEventSource(heventsrc);
837 /* ================== Not yet implemented ===================== */
838 void set_service_description(SC_HANDLE hSCManager, SC_HANDLE hService,
842 LPQUERY_SERVICE_LOCK_STATUS lpqslsBuf;
843 SERVICE_DESCRIPTION sdBuf;
846 // Need to acquire database lock before reconfiguring.
848 sclLock = LockServiceDatabase(hSCManager);
850 // If the database cannot be locked, report the details.
852 if (sclLock == NULL) {
853 // Exit if the database is not locked by another process.
855 if (GetLastError() != ERROR_SERVICE_DATABASE_LOCKED) {
856 log_error_message("LockServiceDatabase");
860 // Allocate a buffer to get details about the lock.
861 lpqslsBuf = (LPQUERY_SERVICE_LOCK_STATUS)LocalAlloc(
862 LPTR, sizeof(QUERY_SERVICE_LOCK_STATUS)+256);
863 if (lpqslsBuf == NULL) {
864 log_error_message("LocalAlloc");
868 // Get and print the lock status information.
870 if (!QueryServiceLockStatus(
873 sizeof(QUERY_SERVICE_LOCK_STATUS)+256,
875 log_error_message("QueryServiceLockStatus");
878 if (lpqslsBuf->fIsLocked) {
879 printf("Locked by: %s, duration: %ld seconds\n",
880 lpqslsBuf->lpLockOwner,
881 lpqslsBuf->dwLockDuration);
883 printf("No longer locked\n");
886 LocalFree(lpqslsBuf);
887 log_error_message("Could not lock database");
891 // The database is locked, so it is safe to make changes.
893 sdBuf.lpDescription = lpDesc;
895 if(!ChangeServiceConfig2(
896 hService, // handle to service
897 SERVICE_CONFIG_DESCRIPTION, // change: description
898 &sdBuf) ) { // value: new description
899 log_error_message("ChangeServiceConfig2");
901 printf("ChangeServiceConfig2 SUCCESS\n");
904 // Release the database lock.
905 UnlockServiceDatabase(sclLock);