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;
72 // IsWin95 - returns a BOOL indicating whether the current OS is Win95
76 return (g_platform_id == VER_PLATFORM_WIN32_WINDOWS);
79 // IsWinNT - returns a bool indicating whether the current OS is WinNT
83 return (g_platform_id == VER_PLATFORM_WIN32_NT);
86 // Internal routine to find the Bacula menu class window and
87 // post a message to it!
90 PostToBacula(UINT message, WPARAM wParam, LPARAM lParam)
92 // Locate the hidden Bacula menu window
93 HWND hservwnd = FindWindow(MENU_CLASS_NAME, NULL);
94 if (hservwnd == NULL) {
98 // Post the message to Bacula
99 PostMessage(hservwnd, message, wParam, lParam);
104 // Static routine to show the Properties dialog for a currently-running
105 // copy of Bacula, (usually a servicified version.)
108 bacService::ShowProperties()
110 #ifdef properties_implemented
111 // Post to the Bacula menu window
112 if (!PostToBacula(MENU_PROPERTIES_SHOW, 0, 0)) {
113 MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
120 // Static routine to show the Default Properties dialog for a currently-running
121 // copy of Bacula, (usually a servicified version.)
124 bacService::ShowDefaultProperties()
126 #ifdef properties_implemented
127 // Post to the Bacula menu window
128 if (!PostToBacula(MENU_DEFAULT_PROPERTIES_SHOW, 0, 0)) {
129 MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
137 // Static routine to show the About dialog for a currently-running
138 // copy of Bacula, (usually a servicified version.)
141 bacService::ShowAboutBox()
143 // Post to the Bacula menu window
144 if (!PostToBacula(MENU_ABOUTBOX_SHOW, 0, 0)) {
145 MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
151 // Static routine to show the Status dialog for a currently-running
152 // copy of Bacula, (usually a servicified version.)
155 bacService::ShowStatus()
157 // Post to the Bacula menu window
158 if (!PostToBacula(MENU_STATUS_SHOW, 0, 0)) {
159 MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
165 // Static routine to show the Events dialog for a currently-running
166 // copy of Bacula, (usually a servicified version.)
169 bacService::ShowEvents()
171 // Post to the Bacula menu window
172 if (!PostToBacula(MENU_EVENTS_SHOW, 0, 0)) {
173 MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
180 // Static routine to tell a locally-running instance of the server
181 // to connect out to a new client
184 bacService::PostAddNewClient(unsigned long ipaddress)
186 // Post to the Bacula menu window
187 if (!PostToBacula(MENU_ADD_CLIENT_MSG, 0, ipaddress)) {
188 MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
195 // SERVICE-MODE ROUTINES
197 // Service-mode defines:
200 #define BAC_APPNAME "bacula"
202 // Internal service name
203 #define BAC_SERVICENAME "Bacula"
205 // Displayed service name
206 #define BAC_SERVICEDISPLAYNAME "Bacula File Server"
208 // List other required serves
209 #define BAC_DEPENDENCIES ""
211 // Internal service state
212 SERVICE_STATUS g_srvstatus; // current status of the service
213 SERVICE_STATUS_HANDLE g_hstatus;
215 DWORD g_servicethread = 0;
216 char* g_errortext[256];
218 // Forward defines of internal service functions
219 void WINAPI ServiceMain(DWORD argc, char **argv);
221 DWORD WINAPI ServiceWorkThread(LPVOID lpwThreadParam);
223 void WINAPI ServiceCtrl(DWORD ctrlcode);
225 bool WINAPI CtrlHandler (DWORD ctrltype);
227 BOOL ReportStatus(DWORD state, DWORD exitcode, DWORD waithint);
229 // ROUTINE TO QUERY WHETHER THIS PROCESS IS RUNNING AS A SERVICE OR NOT
231 BOOL g_servicemode = FALSE;
234 bacService::RunningAsService()
236 return g_servicemode;
240 bacService::KillRunningCopy()
242 while (PostToBacula(WM_CLOSE, 0, 0)) {
248 // ROUTINE TO POST THE HANDLE OF THE CURRENT USER TO THE RUNNING Bacula, IN ORDER
249 // THAT IT CAN LOAD THE APPROPRIATE SETTINGS. THIS IS USED ONLY BY THE SVCHELPER
250 // OPTION, WHEN RUNNING UNDER NT
252 bacService::PostUserHelperMessage()
254 // - Check the platform type
259 // - Get the current process ID
260 DWORD processId = GetCurrentProcessId();
262 // - Post it to the existing Bacula
263 if (!PostToBacula(MENU_SERVICEHELPER_MSG, 0, (LPARAM)processId)) {
267 // - Wait until it's been used
271 // ROUTINE TO PROCESS AN INCOMING INSTANCE OF THE ABOVE MESSAGE
273 bacService::ProcessUserHelperMessage(WPARAM wParam, LPARAM lParam) {
274 // - Check the platform type
275 if (!IsWinNT() || !bacService::RunningAsService()) {
279 // - Close the HKEY_CURRENT_USER key, to force NT to reload it for the new user
280 // NB: Note that this is _really_ dodgy if ANY other thread is accessing the key!
281 if (RegCloseKey(HKEY_CURRENT_USER) != ERROR_SUCCESS) {
285 // - Revert to our own identity
287 g_impersonating_user = FALSE;
289 // - Open the specified process
290 HANDLE processHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD)lParam);
291 if (processHandle == NULL) {
295 // - Get the token for the given process
296 HANDLE userToken = NULL;
297 if (!OpenProcessToken(processHandle, TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE, &userToken)) {
298 CloseHandle(processHandle);
301 CloseHandle(processHandle);
303 // - Set this thread to impersonate them
304 if (!ImpersonateLoggedOnUser(userToken)) {
305 CloseHandle(userToken);
308 CloseHandle(userToken);
310 g_impersonating_user = TRUE;
314 // SERVICE MAIN ROUTINE
316 bacService::BaculaServiceMain()
318 // Mark that we are a service
319 g_servicemode = TRUE;
321 // How to run as a service depends upon the OS being used
322 switch (g_platform_id) {
325 case VER_PLATFORM_WIN32_WINDOWS:
327 // Obtain a handle to the kernel library
328 HINSTANCE kerneldll = LoadLibrary("KERNEL32.DLL");
329 if (kerneldll == NULL) {
330 MessageBox(NULL, "KERNEL32.DLL not found: Bacula service not started",
331 "Bacula Service", MB_OK);
335 // And find the RegisterServiceProcess function
336 DWORD (*RegisterService)(DWORD, DWORD);
337 RegisterService = (DWORD (*)(DWORD, DWORD))
338 GetProcAddress(kerneldll, "RegisterServiceProcess");
339 if (RegisterService == NULL) {
340 MessageBox(NULL, "Registry service not fond: Bacula service not started",
341 "Bacula Service", MB_OK);
345 // Register this process with the OS as a service!
346 RegisterService(0, 1);
348 // Run the main program as a service
351 // Then remove the service from the system service table
352 RegisterService(0, 0);
354 // Free the kernel library
355 FreeLibrary(kerneldll);
357 // *** If we don't kill the process directly here, then
358 // for some reason, Bacula crashes...
363 case VER_PLATFORM_WIN32_NT:
365 // Create a service entry table
366 SERVICE_TABLE_ENTRY dispatchTable[] = {
367 {BAC_SERVICENAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain},
371 // Call the service control dispatcher with our entry table
372 if (!StartServiceCtrlDispatcher(dispatchTable))
373 LogErrorMsg("StartServiceCtrlDispatcher failed.");
380 // SERVICE MAIN ROUTINE - NT ONLY !!!
381 // NT/Win2K/WinXP ONLY !!!
382 void WINAPI ServiceMain(DWORD argc, char **argv)
386 // Register the service control handler
387 g_hstatus = RegisterServiceCtrlHandler(BAC_SERVICENAME, ServiceCtrl);
389 if (g_hstatus == 0) {
390 MessageBox(NULL, "Contact Register Service Handler failure",
391 "Bacula service", MB_OK);
395 // Set up some standard service state values
396 g_srvstatus.dwServiceType = SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS;
397 g_srvstatus.dwServiceSpecificExitCode = 0;
399 // Give this status to the SCM
401 SERVICE_START_PENDING, // Service state
402 NO_ERROR, // Exit code type
403 15000)) // Hint as to how long Bacula should have hung before you assume error
412 // Now start the service for real
413 (void)CreateThread(NULL, 0, ServiceWorkThread, NULL, 0, &dwThreadID);
417 // SERVICE START ROUTINE - thread that calls BaculaAppMain
419 DWORD WINAPI ServiceWorkThread(LPVOID lpwThreadParam)
422 TOKEN_PRIVILEGES tkp;
424 // Save the current thread identifier
425 g_servicethread = GetCurrentThreadId();
427 // report the status to the service control manager.
430 SERVICE_RUNNING, // service state
431 NO_ERROR, // exit code
433 MessageBox(NULL, "Report Service failure", "Bacula Service", MB_OK);
437 // Get a token for this process.
439 if (!OpenProcessToken(GetCurrentProcess(),
440 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
441 /* Forge on anyway */
444 // Get the LUID for the backup privilege.
445 LookupPrivilegeValue(NULL, SE_BACKUP_NAME,
446 &tkp.Privileges[0].Luid);
449 tkp.PrivilegeCount = 1; // one privilege to set
450 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
452 // Get the backup privilege for this process.
453 AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
454 (PTOKEN_PRIVILEGES)NULL, 0);
456 // Cannot test the return value of AdjustTokenPrivileges.
457 if (GetLastError() != ERROR_SUCCESS) {
458 // MessageBox(NULL, "System shutdown failed: AdjustTokePrivileges", "shutdown", MB_OK);
461 // Get the LUID for the restore privilege.
462 LookupPrivilegeValue(NULL, SE_RESTORE_NAME,
463 &tkp.Privileges[0].Luid);
465 tkp.PrivilegeCount = 1; // one privilege to set
466 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
468 // Get the restore privilege for this process.
469 AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
470 (PTOKEN_PRIVILEGES)NULL, 0);
472 // Cannot test the return value of AdjustTokenPrivileges.
473 if (GetLastError() != ERROR_SUCCESS) {
474 // MessageBox(NULL, "System shutdown failed: AdjustTokePrivileges", "shutdown", MB_OK);
477 /* Call Bacula main code */
480 /* Mark that we're no longer running */
483 /* Tell the service manager that we've stopped */
484 ReportStatus(SERVICE_STOPPED, g_error, 0);
488 // SERVICE STOP ROUTINE - post a quit message to the relevant thread
491 // Post a quit message to the main service thread
492 if (g_servicethread != 0) {
493 PostThreadMessage(g_servicethread, WM_QUIT, 0, 0);
497 // SERVICE INSTALL ROUTINE
499 bacService::InstallService()
501 const int pathlength = 2048;
502 char path[pathlength];
503 char servicecmd[pathlength];
506 // Get the filename of this executable
507 if (GetModuleFileName(NULL, path, pathlength-(strlen(BaculaRunService)+2)) == 0) {
508 MessageBox(NULL, "Unable to install Bacula service", szAppName, MB_ICONEXCLAMATION | MB_OK);
512 // Append the service-start flag to the end of the path:
513 if ((int)strlen(path) + 20 + (int)strlen(BaculaRunService) < pathlength) {
514 sprintf(servicecmd, "\"%s\" %s -c %s", path, BaculaRunService, path);
515 len = strlen(servicecmd) - 1;
516 for ( ; len > 0; len--) {
517 if (servicecmd[len] == '\\') {
523 strcat(servicecmd, "\\bacula-fd.conf");
526 MessageBox(NULL, "Service command length too long. Service not registered.",
527 szAppName, MB_ICONEXCLAMATION | MB_OK);
531 // How to add the Bacula service depends upon the OS
532 switch (g_platform_id) {
535 case VER_PLATFORM_WIN32_WINDOWS:
536 // Locate the RunService registry entry
538 if (RegCreateKey(HKEY_LOCAL_MACHINE,
539 "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",
540 &runservices) != ERROR_SUCCESS) {
541 MessageBox(NULL, "The System Registry could not be updated - the Bacula service was not installed", szAppName, MB_ICONEXCLAMATION | MB_OK);
545 // Attempt to add a Bacula key
546 if (RegSetValueEx(runservices, szAppName, 0, REG_SZ, (unsigned char *)servicecmd, strlen(servicecmd)+1) != ERROR_SUCCESS) {
547 RegCloseKey(runservices);
548 MessageBox(NULL, "The Bacula service could not be installed", szAppName, MB_ICONEXCLAMATION | MB_OK);
552 RegCloseKey(runservices);
554 // We have successfully installed the service!
556 "The Bacula File service was successfully installed.\n"
557 "The service may be started by double clicking on the\n"
558 "Bacula \"Start\" icon and will be automatically\n"
559 "be run the next time this machine is rebooted. ",
561 MB_ICONINFORMATION | MB_OK);
564 // Run the service...
568 si.lpReserved = NULL;
569 si.lpReserved2 = NULL;
572 PROCESS_INFORMATION pi;
573 if (!CreateProcess(NULL, servicecmd, // Program name & path
574 NULL, NULL, // Security attributes
575 FALSE, // Inherit handles?
576 NORMAL_PRIORITY_CLASS, // Extra startup flags
577 NULL, // Environment table
578 NULL, // Current directory
582 MessageBox(NULL, "CreateProcess: the Bacula service failed to start", szAppName, MB_ICONSTOP | MB_OK);
589 case VER_PLATFORM_WIN32_NT:
591 SC_HANDLE hsrvmanager;
593 // Open the default, local Service Control Manager database
594 hsrvmanager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
595 if (hsrvmanager == NULL) {
597 "The Service Control Manager could not be contacted - the Bacula service was not installed",
598 szAppName, MB_ICONEXCLAMATION | MB_OK);
602 // Create an entry for the Bacula service
603 hservice = CreateService(
604 hsrvmanager, // SCManager database
605 BAC_SERVICENAME, // name of service
606 BAC_SERVICEDISPLAYNAME, // name to display
607 SERVICE_ALL_ACCESS, // desired access
608 SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
610 SERVICE_AUTO_START, // start type
611 SERVICE_ERROR_NORMAL, // error control type
612 servicecmd, // service's binary
613 NULL, // no load ordering group
614 NULL, // no tag identifier
615 BAC_DEPENDENCIES, // dependencies
616 NULL, // LocalSystem account
617 NULL); // no password
618 CloseServiceHandle(hsrvmanager);
619 if (hservice == NULL) {
621 "The Bacula service could not be installed",
622 szAppName, MB_ICONEXCLAMATION | MB_OK);
625 CloseServiceHandle(hservice);
627 // Now install the servicehelper registry setting...
628 // Locate the RunService registry entry
630 if (RegCreateKey(HKEY_LOCAL_MACHINE,
631 "Software\\Microsoft\\Windows\\CurrentVersion\\Run",
632 &runapps) != ERROR_SUCCESS) {
633 MessageBox(NULL, "WARNING: Unable to install the ServiceHelper hook\nGlobal user-specific registry settings will not be loaded",
634 szAppName, MB_ICONEXCLAMATION | MB_OK);
636 char servicehelpercmd[pathlength];
638 // Append the service-helper-start flag to the end of the path:
639 if ((int)strlen(path) + 4 + (int)strlen(BaculaRunServiceHelper) < pathlength)
640 sprintf(servicehelpercmd, "\"%s\" %s", path, BaculaRunServiceHelper);
644 // Add the upsserviceHelper entry
645 if (RegSetValueEx(runapps, szAppName, 0, REG_SZ,
646 (unsigned char *)servicehelpercmd, strlen(servicehelpercmd)+1) != ERROR_SUCCESS)
648 MessageBox(NULL, "WARNING:Unable to install the ServiceHelper hook\nGlobal user-specific registry settings will not be loaded", szAppName, MB_ICONEXCLAMATION | MB_OK);
650 RegCloseKey(runapps);
653 // Everything went fine
655 "The Bacula File service was successfully installed.\n"
656 "The service may be started from the Control Panel and will\n"
657 "automatically be run the next time this machine is rebooted.",
659 MB_ICONINFORMATION | MB_OK);
663 "Unknown Windows operating system.\n"
664 "Cannot install Bacula service.\n",
665 szAppName, MB_ICONEXCLAMATION | MB_OK);
672 // SERVICE REMOVE ROUTINE
674 bacService::RemoveService()
676 // How to remove the Bacula service depends upon the OS
677 switch (g_platform_id) {
680 case VER_PLATFORM_WIN32_WINDOWS:
681 // Locate the RunService registry entry
683 if (RegOpenKey(HKEY_LOCAL_MACHINE,
684 "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",
685 &runservices) != ERROR_SUCCESS) {
687 "Could not find registry entry.\nService probably not registerd - the Bacula service was not removed", szAppName, MB_ICONEXCLAMATION | MB_OK);
689 // Attempt to delete the Bacula key
690 if (RegDeleteValue(runservices, szAppName) != ERROR_SUCCESS) {
691 RegCloseKey(runservices);
692 MessageBox(NULL, "Could not delete Registry key.\nThe Bacula service could not be removed", szAppName, MB_ICONEXCLAMATION | MB_OK);
695 RegCloseKey(runservices);
699 // Try to kill any running copy of Bacula
700 if (!KillRunningCopy()) {
702 "Bacula could not be contacted, probably not running",
703 szAppName, MB_ICONEXCLAMATION | MB_OK);
707 // We have successfully removed the service!
708 MessageBox(NULL, "The Bacula service has been removed", szAppName, MB_ICONINFORMATION | MB_OK);
712 case VER_PLATFORM_WIN32_NT:
714 SC_HANDLE hsrvmanager;
716 // Attempt to remove the service-helper hook
718 if (RegOpenKey(HKEY_LOCAL_MACHINE,
719 "Software\\Microsoft\\Windows\\CurrentVersion\\Run",
720 &runapps) == ERROR_SUCCESS)
722 // Attempt to delete the Bacula key
723 if (RegDeleteValue(runapps, szAppName) != ERROR_SUCCESS)
725 MessageBox(NULL, "WARNING:The ServiceHelper hook entry could not be removed from the registry", szAppName, MB_ICONEXCLAMATION | MB_OK);
727 RegCloseKey(runapps);
731 hsrvmanager = OpenSCManager(
732 NULL, // machine (NULL == local)
733 NULL, // database (NULL == default)
734 SC_MANAGER_ALL_ACCESS // access required
737 hservice = OpenService(hsrvmanager, BAC_SERVICENAME, SERVICE_ALL_ACCESS);
738 if (hservice != NULL)
740 SERVICE_STATUS status;
742 // Try to stop the Bacula service
743 if (ControlService(hservice, SERVICE_CONTROL_STOP, &status))
745 while(QueryServiceStatus(hservice, &status)) {
746 if (status.dwCurrentState == SERVICE_STOP_PENDING)
752 if (status.dwCurrentState != SERVICE_STOPPED)
753 MessageBox(NULL, "The Bacula service could not be stopped", szAppName, MB_ICONEXCLAMATION | MB_OK);
756 // Now remove the service from the SCM
757 if(DeleteService(hservice))
758 MessageBox(NULL, "The Bacula service has been removed", szAppName, MB_ICONINFORMATION | MB_OK);
760 MessageBox(NULL, "The Bacula service could not be removed", szAppName, MB_ICONEXCLAMATION | MB_OK);
762 CloseServiceHandle(hservice);
765 MessageBox(NULL, "The Bacula service could not be found", szAppName, MB_ICONEXCLAMATION | MB_OK);
767 CloseServiceHandle(hsrvmanager);
770 MessageBox(NULL, "The SCM could not be contacted - the Bacula service was not removed", szAppName, MB_ICONEXCLAMATION | MB_OK);
776 // USEFUL SERVICE SUPPORT ROUTINES
778 // Service control routine
779 void WINAPI ServiceCtrl(DWORD ctrlcode)
781 // What control code have we been sent?
785 case SERVICE_CONTROL_STOP:
786 // STOP : The service must stop
787 g_srvstatus.dwCurrentState = SERVICE_STOP_PENDING;
791 case SERVICE_CONTROL_INTERROGATE:
792 // QUERY : Service control manager just wants to know our state
796 // Control code not recognised
801 // Tell the control manager what we're up to.
802 ReportStatus(g_srvstatus.dwCurrentState, NO_ERROR, 0);
805 // Service manager status reporting
806 BOOL ReportStatus(DWORD state,
810 static DWORD checkpoint = 1;
813 // If we're in the start state then we don't want the control manager
814 // sending us control messages because they'll confuse us.
815 if (state == SERVICE_START_PENDING)
816 g_srvstatus.dwControlsAccepted = 0;
818 g_srvstatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
820 // Save the new status we've been given
821 g_srvstatus.dwCurrentState = state;
822 g_srvstatus.dwWin32ExitCode = exitcode;
823 g_srvstatus.dwWaitHint = waithint;
825 // Update the checkpoint variable to let the SCM know that we
826 // haven't died if requests take a long time
827 if ((state == SERVICE_RUNNING) || (state == SERVICE_STOPPED))
828 g_srvstatus.dwCheckPoint = 0;
830 g_srvstatus.dwCheckPoint = checkpoint++;
832 // Tell the SCM our new status
833 if (!(result = SetServiceStatus(g_hstatus, &g_srvstatus)))
834 LogErrorMsg("SetServiceStatus failed");
840 void LogErrorMsg(char *message)
846 // Save the error code
847 g_error = GetLastError();
849 // Use event logging to log the error
850 heventsrc = RegisterEventSource(NULL, BAC_SERVICENAME);
852 sprintf(msgbuff, "%s error: %ld", BAC_SERVICENAME, g_error);
853 strings[0] = msgbuff;
854 strings[1] = message;
856 if (heventsrc != NULL) {
860 heventsrc, // handle of event source
861 EVENTLOG_ERROR_TYPE, // event type
864 NULL, // current user's SID
865 2, // strings in 'strings'
866 0, // no bytes of raw data
867 (const char **)strings, // array of error strings
868 NULL); // no raw data
870 DeregisterEventSource(heventsrc);