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 // Error message logging
46 void LogErrorMsg(char *message);
48 // OS-SPECIFIC ROUTINES
50 // Create an instance of the bacService class to cause the static fields to be
51 // initialised properly
56 BOOL g_impersonating_user = 0;
58 bacService::bacService()
60 OSVERSIONINFO osversioninfo;
61 osversioninfo.dwOSVersionInfoSize = sizeof(osversioninfo);
63 // Get the current OS version
64 if (!GetVersionEx(&osversioninfo))
67 g_platform_id = osversioninfo.dwPlatformId;
71 // IsWin95 - returns a BOOL indicating whether the current OS is Win95
75 return (g_platform_id == VER_PLATFORM_WIN32_WINDOWS);
78 // IsWinNT - returns a bool indicating whether the current OS is WinNT
82 return (g_platform_id == VER_PLATFORM_WIN32_NT);
85 // Internal routine to find the Bacula menu class window and
86 // post a message to it!
89 PostToBacula(UINT message, WPARAM wParam, LPARAM lParam)
91 // Locate the hidden Bacula menu window
92 HWND hservwnd = FindWindow(MENU_CLASS_NAME, NULL);
96 // Post the message to Bacula
97 PostMessage(hservwnd, message, wParam, lParam);
102 // Static routine to show the Properties dialog for a currently-running
103 // copy of Bacula, (usually a servicified version.)
106 bacService::ShowProperties()
108 #ifdef properties_implemented
109 // Post to the Bacula menu window
110 if (!PostToBacula(MENU_PROPERTIES_SHOW, 0, 0)) {
111 MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
118 // Static routine to show the Default Properties dialog for a currently-running
119 // copy of Bacula, (usually a servicified version.)
122 bacService::ShowDefaultProperties()
124 #ifdef properties_implemented
125 // Post to the Bacula menu window
126 if (!PostToBacula(MENU_DEFAULT_PROPERTIES_SHOW, 0, 0)) {
127 MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
135 // Static routine to show the About dialog for a currently-running
136 // copy of Bacula, (usually a servicified version.)
139 bacService::ShowAboutBox()
141 // Post to the Bacula menu window
142 if (!PostToBacula(MENU_ABOUTBOX_SHOW, 0, 0)) {
143 MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
149 // Static routine to show the Status dialog for a currently-running
150 // copy of Bacula, (usually a servicified version.)
153 bacService::ShowStatus()
155 // Post to the Bacula menu window
156 if (!PostToBacula(MENU_STATUS_SHOW, 0, 0)) {
157 MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
163 // Static routine to show the Events dialog for a currently-running
164 // copy of Bacula, (usually a servicified version.)
167 bacService::ShowEvents()
169 // Post to the Bacula menu window
170 if (!PostToBacula(MENU_EVENTS_SHOW, 0, 0)) {
171 MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
178 // Static routine to tell a locally-running instance of the server
179 // to connect out to a new client
182 bacService::PostAddNewClient(unsigned long ipaddress)
184 // Post to the Bacula menu window
185 if (!PostToBacula(MENU_ADD_CLIENT_MSG, 0, ipaddress)) {
186 MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
193 // SERVICE-MODE ROUTINES
195 // Service-mode defines:
198 #define BAC_APPNAME "bacula"
200 // Internal service name
201 #define BAC_SERVICENAME "Bacula"
203 // Displayed service name
204 #define BAC_SERVICEDISPLAYNAME "Bacula File Server"
206 // List of other required services ("dependency 1\0dependency 2\0\0")
207 // *** These need filling in properly
208 #define BAC_DEPENDENCIES ""
210 // Internal service state
211 SERVICE_STATUS g_srvstatus; // current status of the service
212 SERVICE_STATUS_HANDLE g_hstatus;
214 DWORD g_servicethread = 0;
215 char* g_errortext[256];
217 // Forward defines of internal service functions
218 void WINAPI ServiceMain(DWORD argc, char **argv);
220 DWORD WINAPI ServiceWorkThread(LPVOID lpwThreadParam);
222 void WINAPI ServiceCtrl(DWORD ctrlcode);
224 bool WINAPI CtrlHandler (DWORD ctrltype);
226 BOOL ReportStatus(DWORD state, DWORD exitcode, DWORD waithint);
228 // ROUTINE TO QUERY WHETHER THIS PROCESS IS RUNNING AS A SERVICE OR NOT
230 BOOL g_servicemode = FALSE;
233 bacService::RunningAsService()
235 return g_servicemode;
239 bacService::KillRunningCopy()
241 while (PostToBacula(WM_CLOSE, 0, 0)) {
247 // ROUTINE TO POST THE HANDLE OF THE CURRENT USER TO THE RUNNING Bacula, IN ORDER
248 // THAT IT CAN LOAD THE APPROPRIATE SETTINGS. THIS IS USED ONLY BY THE SVCHELPER
249 // OPTION, WHEN RUNNING UNDER NT
251 bacService::PostUserHelperMessage()
253 // - Check the platform type
257 // - Get the current process ID
258 DWORD processId = GetCurrentProcessId();
260 // - Post it to the existing Bacula
261 if (!PostToBacula(MENU_SERVICEHELPER_MSG, 0, (LPARAM)processId))
264 // - Wait until it's been used
268 // ROUTINE TO PROCESS AN INCOMING INSTANCE OF THE ABOVE MESSAGE
270 bacService::ProcessUserHelperMessage(WPARAM wParam, LPARAM lParam) {
271 // - Check the platform type
272 if (!IsWinNT() || !bacService::RunningAsService())
275 // - Close the HKEY_CURRENT_USER key, to force NT to reload it for the new user
276 // NB: Note that this is _really_ dodgy if ANY other thread is accessing the key!
277 if (RegCloseKey(HKEY_CURRENT_USER) != ERROR_SUCCESS) {
281 // - Revert to our own identity
283 g_impersonating_user = FALSE;
285 // - Open the specified process
286 HANDLE processHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD)lParam);
287 if (processHandle == NULL) {
291 // - Get the token for the given process
292 HANDLE userToken = NULL;
293 if (!OpenProcessToken(processHandle, TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE, &userToken)) {
294 CloseHandle(processHandle);
297 CloseHandle(processHandle);
299 // - Set this thread to impersonate them
300 if (!ImpersonateLoggedOnUser(userToken)) {
301 CloseHandle(userToken);
304 CloseHandle(userToken);
306 g_impersonating_user = TRUE;
310 // SERVICE MAIN ROUTINE
312 bacService::BaculaServiceMain()
314 // Mark that we are a service
315 g_servicemode = TRUE;
317 // How to run as a service depends upon the OS being used
318 switch (g_platform_id) {
321 case VER_PLATFORM_WIN32_WINDOWS:
323 // Obtain a handle to the kernel library
324 HINSTANCE kerneldll = LoadLibrary("KERNEL32.DLL");
325 if (kerneldll == NULL) {
326 MessageBox(NULL, "KERNEL32.DLL not found: Bacula service not started",
327 "Bacula Service", MB_OK);
331 // And find the RegisterServiceProcess function
332 DWORD (*RegisterService)(DWORD, DWORD);
333 RegisterService = (DWORD (*)(DWORD, DWORD))
334 GetProcAddress(kerneldll, "RegisterServiceProcess");
335 if (RegisterService == NULL) {
336 MessageBox(NULL, "Registry service not fond: Bacula service not started",
337 "Bacula Service", MB_OK);
341 // Register this process with the OS as a service!
342 RegisterService(0, 1);
344 // Run the service itself
347 // Then remove the service from the system service table
348 RegisterService(0, 0);
350 // Free the kernel library
351 FreeLibrary(kerneldll);
353 // *** If we don't kill the process directly here, then
354 // for some reason, Bacula crashes...
359 case VER_PLATFORM_WIN32_NT:
361 // Create a service entry table
362 SERVICE_TABLE_ENTRY dispatchTable[] = {
363 {BAC_SERVICENAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain},
367 // Call the service control dispatcher with our entry table
368 if (!StartServiceCtrlDispatcher(dispatchTable))
369 LogErrorMsg("StartServiceCtrlDispatcher failed.");
376 // SERVICE MAIN ROUTINE - NT ONLY !!!
378 void WINAPI ServiceMain(DWORD argc, char **argv)
382 // Register the service control handler
383 g_hstatus = RegisterServiceCtrlHandler(BAC_SERVICENAME, ServiceCtrl);
385 if (g_hstatus == 0) {
386 MessageBox(NULL, "Contact Register Service Handler failure",
387 "Bacula service", MB_OK);
391 // Set up some standard service state values
392 g_srvstatus.dwServiceType = SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS;
393 g_srvstatus.dwServiceSpecificExitCode = 0;
395 // Give this status to the SCM
397 SERVICE_START_PENDING, // Service state
398 NO_ERROR, // Exit code type
399 15000)) // Hint as to how long Bacula should have hung before you assume error
408 // Now start the service for real
409 (void)CreateThread(NULL, 0, ServiceWorkThread, NULL, 0, &dwThreadID);
413 // SERVICE START ROUTINE - thread that calls BaculaAppMain
415 DWORD WINAPI ServiceWorkThread(LPVOID lpwThreadParam)
418 TOKEN_PRIVILEGES tkp;
420 // Save the current thread identifier
421 g_servicethread = GetCurrentThreadId();
423 // report the status to the service control manager.
426 SERVICE_RUNNING, // service state
427 NO_ERROR, // exit code
429 MessageBox(NULL, "Report Service failure", "Bacula Service", MB_OK);
433 // Get a token for this process.
435 if (!OpenProcessToken(GetCurrentProcess(),
436 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
437 // Forge onward anyway in the hopes of succeeding.
438 // MessageBox(NULL, "System shutdown failed: OpenProcessToken", "shutdown", MB_OK);
442 // Get the LUID for the backup privilege.
444 LookupPrivilegeValue(NULL, SE_BACKUP_NAME,
445 &tkp.Privileges[0].Luid);
448 tkp.PrivilegeCount = 1; // one privilege to set
449 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
451 // Get the shutdown privilege for this process.
453 AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
454 (PTOKEN_PRIVILEGES)NULL, 0);
456 // Cannot test the return value of AdjustTokenPrivileges.
458 if (GetLastError() != ERROR_SUCCESS) {
459 // MessageBox(NULL, "System shutdown failed: AdjustTokePrivileges", "shutdown", MB_OK);
462 // Get the LUID for the restore privilege.
464 LookupPrivilegeValue(NULL, SE_RESTORE_NAME,
465 &tkp.Privileges[0].Luid);
468 tkp.PrivilegeCount = 1; // one privilege to set
469 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
471 // Get the shutdown privilege for this process.
473 AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
474 (PTOKEN_PRIVILEGES)NULL, 0);
476 // Cannot test the return value of AdjustTokenPrivileges.
478 if (GetLastError() != ERROR_SUCCESS) {
479 // MessageBox(NULL, "System shutdown failed: AdjustTokePrivileges", "shutdown", MB_OK);
482 /* Call Bacula main code */
485 // Mark that we're no longer running
488 // Tell the service manager that we've stopped.
496 // SERVICE STOP ROUTINE - post a quit message to the relevant thread
499 // Post a quit message to the main service thread
500 if (g_servicethread != 0) {
501 PostThreadMessage(g_servicethread, WM_QUIT, 0, 0);
505 // SERVICE INSTALL ROUTINE
507 bacService::InstallService()
509 const int pathlength = 2048;
510 char path[pathlength];
511 char servicecmd[pathlength];
514 // Get the filename of this executable
515 if (GetModuleFileName(NULL, path, pathlength-(strlen(BaculaRunService)+2)) == 0) {
516 MessageBox(NULL, "Unable to install Bacula service", szAppName, MB_ICONEXCLAMATION | MB_OK);
520 // Append the service-start flag to the end of the path:
521 if ((int)strlen(path) + 20 + (int)strlen(BaculaRunService) < pathlength) {
522 sprintf(servicecmd, "\"%s\" %s -c %s", path, BaculaRunService, path);
523 len = strlen(servicecmd) - 1;
524 for ( ; len > 0; len--) {
525 if (servicecmd[len] == '\\') {
531 strcat(servicecmd, "\\bacula-fd.conf");
534 MessageBox(NULL, "Service command length too long. Service not registered.",
535 szAppName, MB_ICONEXCLAMATION | MB_OK);
539 // How to add the Bacula service depends upon the OS
540 switch (g_platform_id) {
543 case VER_PLATFORM_WIN32_WINDOWS:
544 // Locate the RunService registry entry
546 if (RegCreateKey(HKEY_LOCAL_MACHINE,
547 "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",
548 &runservices) != ERROR_SUCCESS) {
549 MessageBox(NULL, "The System Registry could not be updated - the Bacula service was not installed", szAppName, MB_ICONEXCLAMATION | MB_OK);
553 // Attempt to add a Bacula key
554 if (RegSetValueEx(runservices, szAppName, 0, REG_SZ, (unsigned char *)servicecmd, strlen(servicecmd)+1) != ERROR_SUCCESS) {
555 RegCloseKey(runservices);
556 MessageBox(NULL, "The Bacula service could not be installed", szAppName, MB_ICONEXCLAMATION | MB_OK);
560 RegCloseKey(runservices);
562 // We have successfully installed the service!
564 "The Bacula File service was successfully installed.\n"
565 "The service may be started by double clicking on the\n"
566 "Bacula \"Start\" icon and will be automatically\n"
567 "be run the next time this machine is rebooted. ",
569 MB_ICONINFORMATION | MB_OK);
572 // Run the service...
576 si.lpReserved = NULL;
577 si.lpReserved2 = NULL;
580 PROCESS_INFORMATION pi;
581 if (!CreateProcess(NULL, servicecmd, // Program name & path
582 NULL, NULL, // Security attributes
583 FALSE, // Inherit handles?
584 NORMAL_PRIORITY_CLASS, // Extra startup flags
585 NULL, // Environment table
586 NULL, // Current directory
590 MessageBox(NULL, "CreateProcess: the Bacula service failed to start", szAppName, MB_ICONSTOP | MB_OK);
597 case VER_PLATFORM_WIN32_NT:
599 SC_HANDLE hsrvmanager;
601 // Open the default, local Service Control Manager database
602 hsrvmanager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
603 if (hsrvmanager == NULL) {
605 "The Service Control Manager could not be contacted - the Bacula service was not installed",
606 szAppName, MB_ICONEXCLAMATION | MB_OK);
610 // Create an entry for the Bacula service
611 hservice = CreateService(
612 hsrvmanager, // SCManager database
613 BAC_SERVICENAME, // name of service
614 BAC_SERVICEDISPLAYNAME, // name to display
615 SERVICE_ALL_ACCESS, // desired access
616 SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
618 SERVICE_AUTO_START, // start type
619 SERVICE_ERROR_NORMAL, // error control type
620 servicecmd, // service's binary
621 NULL, // no load ordering group
622 NULL, // no tag identifier
623 BAC_DEPENDENCIES, // dependencies
624 NULL, // LocalSystem account
625 NULL); // no password
626 CloseServiceHandle(hsrvmanager);
627 if (hservice == NULL) {
629 "The Bacula service could not be installed",
630 szAppName, MB_ICONEXCLAMATION | MB_OK);
633 CloseServiceHandle(hservice);
635 // Now install the servicehelper registry setting...
636 // Locate the RunService registry entry
638 if (RegCreateKey(HKEY_LOCAL_MACHINE,
639 "Software\\Microsoft\\Windows\\CurrentVersion\\Run",
640 &runapps) != ERROR_SUCCESS) {
641 MessageBox(NULL, "WARNING: Unable to install the ServiceHelper hook\nGlobal user-specific registry settings will not be loaded",
642 szAppName, MB_ICONEXCLAMATION | MB_OK);
644 char servicehelpercmd[pathlength];
646 // Append the service-helper-start flag to the end of the path:
647 if ((int)strlen(path) + 4 + (int)strlen(BaculaRunServiceHelper) < pathlength)
648 sprintf(servicehelpercmd, "\"%s\" %s", path, BaculaRunServiceHelper);
652 // Add the upsserviceHelper entry
653 if (RegSetValueEx(runapps, szAppName, 0, REG_SZ,
654 (unsigned char *)servicehelpercmd, strlen(servicehelpercmd)+1) != ERROR_SUCCESS)
656 MessageBox(NULL, "WARNING:Unable to install the ServiceHelper hook\nGlobal user-specific registry settings will not be loaded", szAppName, MB_ICONEXCLAMATION | MB_OK);
658 RegCloseKey(runapps);
661 // Everything went fine
663 "The Bacula File service was successfully installed.\n"
664 "The service may be started from the Control Panel and will\n"
665 "automatically be run the next time this machine is rebooted.",
667 MB_ICONINFORMATION | MB_OK);
671 "Unknown Windows operating system.\n"
672 "Cannot install Bacula service.\n",
673 szAppName, MB_ICONEXCLAMATION | MB_OK);
680 // SERVICE REMOVE ROUTINE
682 bacService::RemoveService()
684 // How to remove the Bacula service depends upon the OS
685 switch (g_platform_id) {
688 case VER_PLATFORM_WIN32_WINDOWS:
689 // Locate the RunService registry entry
691 if (RegOpenKey(HKEY_LOCAL_MACHINE,
692 "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",
693 &runservices) != ERROR_SUCCESS) {
695 "Could not find registry entry.\nService probably not registerd - the Bacula service was not removed", szAppName, MB_ICONEXCLAMATION | MB_OK);
697 // Attempt to delete the Bacula key
698 if (RegDeleteValue(runservices, szAppName) != ERROR_SUCCESS) {
699 RegCloseKey(runservices);
700 MessageBox(NULL, "Could not delete Registry key.\nThe Bacula service could not be removed", szAppName, MB_ICONEXCLAMATION | MB_OK);
703 RegCloseKey(runservices);
707 // Try to kill any running copy of Bacula
708 if (!KillRunningCopy()) {
710 "Bacula could not be contacted, probably not running",
711 szAppName, MB_ICONEXCLAMATION | MB_OK);
715 // We have successfully removed the service!
716 MessageBox(NULL, "The Bacula service has been removed", szAppName, MB_ICONINFORMATION | MB_OK);
720 case VER_PLATFORM_WIN32_NT:
722 SC_HANDLE hsrvmanager;
724 // Attempt to remove the service-helper hook
726 if (RegOpenKey(HKEY_LOCAL_MACHINE,
727 "Software\\Microsoft\\Windows\\CurrentVersion\\Run",
728 &runapps) == ERROR_SUCCESS)
730 // Attempt to delete the Bacula key
731 if (RegDeleteValue(runapps, szAppName) != ERROR_SUCCESS)
733 MessageBox(NULL, "WARNING:The ServiceHelper hook entry could not be removed from the registry", szAppName, MB_ICONEXCLAMATION | MB_OK);
735 RegCloseKey(runapps);
739 hsrvmanager = OpenSCManager(
740 NULL, // machine (NULL == local)
741 NULL, // database (NULL == default)
742 SC_MANAGER_ALL_ACCESS // access required
745 hservice = OpenService(hsrvmanager, BAC_SERVICENAME, SERVICE_ALL_ACCESS);
746 if (hservice != NULL)
748 SERVICE_STATUS status;
750 // Try to stop the Bacula service
751 if (ControlService(hservice, SERVICE_CONTROL_STOP, &status))
753 while(QueryServiceStatus(hservice, &status)) {
754 if (status.dwCurrentState == SERVICE_STOP_PENDING)
760 if (status.dwCurrentState != SERVICE_STOPPED)
761 MessageBox(NULL, "The Bacula service could not be stopped", szAppName, MB_ICONEXCLAMATION | MB_OK);
764 // Now remove the service from the SCM
765 if(DeleteService(hservice))
766 MessageBox(NULL, "The Bacula service has been removed", szAppName, MB_ICONINFORMATION | MB_OK);
768 MessageBox(NULL, "The Bacula service could not be removed", szAppName, MB_ICONEXCLAMATION | MB_OK);
770 CloseServiceHandle(hservice);
773 MessageBox(NULL, "The Bacula service could not be found", szAppName, MB_ICONEXCLAMATION | MB_OK);
775 CloseServiceHandle(hsrvmanager);
778 MessageBox(NULL, "The SCM could not be contacted - the Bacula service was not removed", szAppName, MB_ICONEXCLAMATION | MB_OK);
784 // USEFUL SERVICE SUPPORT ROUTINES
786 // Service control routine
787 void WINAPI ServiceCtrl(DWORD ctrlcode)
789 // What control code have we been sent?
793 case SERVICE_CONTROL_STOP:
794 // STOP : The service must stop
795 g_srvstatus.dwCurrentState = SERVICE_STOP_PENDING;
799 case SERVICE_CONTROL_INTERROGATE:
800 // QUERY : Service control manager just wants to know our state
804 // Control code not recognised
809 // Tell the control manager what we're up to.
810 ReportStatus(g_srvstatus.dwCurrentState, NO_ERROR, 0);
813 // Service manager status reporting
814 BOOL ReportStatus(DWORD state,
818 static DWORD checkpoint = 1;
821 // If we're in the start state then we don't want the control manager
822 // sending us control messages because they'll confuse us.
823 if (state == SERVICE_START_PENDING)
824 g_srvstatus.dwControlsAccepted = 0;
826 g_srvstatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
828 // Save the new status we've been given
829 g_srvstatus.dwCurrentState = state;
830 g_srvstatus.dwWin32ExitCode = exitcode;
831 g_srvstatus.dwWaitHint = waithint;
833 // Update the checkpoint variable to let the SCM know that we
834 // haven't died if requests take a long time
835 if ((state == SERVICE_RUNNING) || (state == SERVICE_STOPPED))
836 g_srvstatus.dwCheckPoint = 0;
838 g_srvstatus.dwCheckPoint = checkpoint++;
840 // Tell the SCM our new status
841 if (!(result = SetServiceStatus(g_hstatus, &g_srvstatus)))
842 LogErrorMsg("SetServiceStatus failed");
848 void LogErrorMsg(char *message)
854 // Save the error code
855 g_error = GetLastError();
857 // Use event logging to log the error
858 heventsrc = RegisterEventSource(NULL, BAC_SERVICENAME);
860 sprintf(msgbuff, "%s error: %ld", BAC_SERVICENAME, g_error);
861 strings[0] = msgbuff;
862 strings[1] = message;
864 if (heventsrc != NULL) {
868 heventsrc, // handle of event source
869 EVENTLOG_ERROR_TYPE, // event type
872 NULL, // current user's SID
873 2, // strings in 'strings'
874 0, // no bytes of raw data
875 (const char **)strings, // array of error strings
876 NULL); // no raw data
878 DeregisterEventSource(heventsrc);