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) 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;
70 // CurrentUser - fills a buffer with the name of the current user!
72 bacService::CurrentUser(char *buffer, UINT size)
74 // How to obtain the name of the current user depends upon the OS being used
75 if ((g_platform_id == VER_PLATFORM_WIN32_NT) && bacService::RunningAsService()) {
76 // Windows NT, service-mode
78 // -=- FIRSTLY - verify that a user is logged on
80 // Get the current Window station
81 HWINSTA station = GetProcessWindowStation();
85 // Get the current user SID size
87 GetUserObjectInformation(station,
88 UOI_USER_SID, NULL, 0, &usersize);
90 // Check the required buffer size isn't zero
92 // No user is logged in - ensure we're not impersonating anyone
94 g_impersonating_user = FALSE;
96 // Return "" as the name...
97 if (strlen("") >= size)
104 // -=- SECONDLY - a user is logged on but if we're not impersonating
105 // them then we can't continue!
106 if (!g_impersonating_user) {
107 // Return "" as the name...
108 if (strlen("") >= size)
115 // -=- When we reach here, we're either running under Win9x, or we're running
116 // under NT as an application or as a service impersonating a user
117 // Either way, we should find a suitable user name.
119 switch (g_platform_id) {
121 case VER_PLATFORM_WIN32_WINDOWS:
122 case VER_PLATFORM_WIN32_NT:
123 // Just call GetCurrentUser
126 if (GetUserName(buffer, &length) == 0)
128 UINT error = GetLastError();
130 if (error == ERROR_NOT_LOGGED_ON)
133 if (strlen("") >= size)
147 // OS was not recognised!
151 // IsWin95 - returns a BOOL indicating whether the current OS is Win95
153 bacService::IsWin95()
155 return (g_platform_id == VER_PLATFORM_WIN32_WINDOWS);
158 // IsWinNT - returns a bool indicating whether the current OS is WinNT
160 bacService::IsWinNT()
162 return (g_platform_id == VER_PLATFORM_WIN32_NT);
165 // Internal routine to find the Bacula menu class window and
166 // post a message to it!
169 PostToBacula(UINT message, WPARAM wParam, LPARAM lParam)
171 // Locate the hidden Bacula menu window
172 HWND hservwnd = FindWindow(MENU_CLASS_NAME, NULL);
173 if (hservwnd == NULL)
176 // Post the message to Bacula
177 PostMessage(hservwnd, message, wParam, lParam);
182 // Static routine to show the Properties dialog for a currently-running
183 // copy of Bacula, (usually a servicified version.)
186 bacService::ShowProperties()
188 #ifdef properties_implemented
189 // Post to the Bacula menu window
190 if (!PostToBacula(MENU_PROPERTIES_SHOW, 0, 0)) {
191 MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
198 // Static routine to show the Default Properties dialog for a currently-running
199 // copy of Bacula, (usually a servicified version.)
202 bacService::ShowDefaultProperties()
204 #ifdef properties_implemented
205 // Post to the Bacula menu window
206 if (!PostToBacula(MENU_DEFAULT_PROPERTIES_SHOW, 0, 0)) {
207 MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
215 // Static routine to show the About dialog for a currently-running
216 // copy of Bacula, (usually a servicified version.)
219 bacService::ShowAboutBox()
221 // Post to the Bacula menu window
222 if (!PostToBacula(MENU_ABOUTBOX_SHOW, 0, 0)) {
223 MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
229 // Static routine to show the Status dialog for a currently-running
230 // copy of Bacula, (usually a servicified version.)
233 bacService::ShowStatus()
235 // Post to the Bacula menu window
236 if (!PostToBacula(MENU_STATUS_SHOW, 0, 0)) {
237 MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
243 // Static routine to show the Events dialog for a currently-running
244 // copy of Bacula, (usually a servicified version.)
247 bacService::ShowEvents()
249 // Post to the Bacula menu window
250 if (!PostToBacula(MENU_EVENTS_SHOW, 0, 0)) {
251 MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
258 // Static routine to tell a locally-running instance of the server
259 // to connect out to a new client
262 bacService::PostAddNewClient(unsigned long ipaddress)
264 // Post to the Bacula menu window
265 if (!PostToBacula(MENU_ADD_CLIENT_MSG, 0, ipaddress)) {
266 MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
273 // SERVICE-MODE ROUTINES
275 // Service-mode defines:
278 #define BAC_APPNAME "bacula"
280 // Internal service name
281 #define BAC_SERVICENAME "Bacula"
283 // Displayed service name
284 #define BAC_SERVICEDISPLAYNAME "Bacula File Server"
286 // List of other required services ("dependency 1\0dependency 2\0\0")
287 // *** These need filling in properly
288 #define BAC_DEPENDENCIES ""
290 // Internal service state
291 SERVICE_STATUS g_srvstatus; // current status of the service
292 SERVICE_STATUS_HANDLE g_hstatus;
294 DWORD g_servicethread = 0;
295 char* g_errortext[256];
297 // Forward defines of internal service functions
298 void WINAPI ServiceMain(DWORD argc, char **argv);
300 DWORD WINAPI ServiceWorkThread(LPVOID lpwThreadParam);
302 void WINAPI ServiceCtrl(DWORD ctrlcode);
304 bool WINAPI CtrlHandler (DWORD ctrltype);
306 BOOL ReportStatus(DWORD state, DWORD exitcode, DWORD waithint);
308 // ROUTINE TO QUERY WHETHER THIS PROCESS IS RUNNING AS A SERVICE OR NOT
310 BOOL g_servicemode = FALSE;
313 bacService::RunningAsService()
315 return g_servicemode;
319 bacService::KillRunningCopy()
321 while (PostToBacula(WM_CLOSE, 0, 0)) {
327 // ROUTINE TO POST THE HANDLE OF THE CURRENT USER TO THE RUNNING Bacula, IN ORDER
328 // THAT IT CAN LOAD THE APPROPRIATE SETTINGS. THIS IS USED ONLY BY THE SVCHELPER
329 // OPTION, WHEN RUNNING UNDER NT
331 bacService::PostUserHelperMessage()
333 // - Check the platform type
337 // - Get the current process ID
338 DWORD processId = GetCurrentProcessId();
340 // - Post it to the existing Bacula
341 if (!PostToBacula(MENU_SERVICEHELPER_MSG, 0, (LPARAM)processId))
344 // - Wait until it's been used
348 // ROUTINE TO PROCESS AN INCOMING INSTANCE OF THE ABOVE MESSAGE
350 bacService::ProcessUserHelperMessage(WPARAM wParam, LPARAM lParam) {
351 // - Check the platform type
352 if (!IsWinNT() || !bacService::RunningAsService())
355 // - Close the HKEY_CURRENT_USER key, to force NT to reload it for the new user
356 // NB: Note that this is _really_ dodgy if ANY other thread is accessing the key!
357 if (RegCloseKey(HKEY_CURRENT_USER) != ERROR_SUCCESS) {
361 // - Revert to our own identity
363 g_impersonating_user = FALSE;
365 // - Open the specified process
366 HANDLE processHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD)lParam);
367 if (processHandle == NULL) {
371 // - Get the token for the given process
372 HANDLE userToken = NULL;
373 if (!OpenProcessToken(processHandle, TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE, &userToken)) {
374 CloseHandle(processHandle);
377 CloseHandle(processHandle);
379 // - Set this thread to impersonate them
380 if (!ImpersonateLoggedOnUser(userToken)) {
381 CloseHandle(userToken);
384 CloseHandle(userToken);
386 g_impersonating_user = TRUE;
390 // SERVICE MAIN ROUTINE
392 bacService::BaculaServiceMain()
394 // Mark that we are a service
395 g_servicemode = TRUE;
397 // How to run as a service depends upon the OS being used
398 switch (g_platform_id) {
401 case VER_PLATFORM_WIN32_WINDOWS:
403 // Obtain a handle to the kernel library
404 HINSTANCE kerneldll = LoadLibrary("KERNEL32.DLL");
405 if (kerneldll == NULL) {
406 MessageBox(NULL, "KERNEL32.DLL not found: Bacula service not started",
407 "Bacula Service", MB_OK);
411 // And find the RegisterServiceProcess function
412 DWORD (*RegisterService)(DWORD, DWORD);
413 RegisterService = (DWORD (*)(DWORD, DWORD))
414 GetProcAddress(kerneldll, "RegisterServiceProcess");
415 if (RegisterService == NULL) {
416 MessageBox(NULL, "Registry service not fond: Bacula service not started",
417 "Bacula Service", MB_OK);
421 // Register this process with the OS as a service!
422 RegisterService(0, 1);
424 // Run the service itself
427 // Then remove the service from the system service table
428 RegisterService(0, 0);
430 // Free the kernel library
431 FreeLibrary(kerneldll);
433 // *** If we don't kill the process directly here, then
434 // for some reason, Bacula crashes...
439 case VER_PLATFORM_WIN32_NT:
441 // Create a service entry table
442 SERVICE_TABLE_ENTRY dispatchTable[] = {
443 {BAC_SERVICENAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain},
447 // Call the service control dispatcher with our entry table
448 if (!StartServiceCtrlDispatcher(dispatchTable))
449 LogErrorMsg("StartServiceCtrlDispatcher failed.");
456 // SERVICE MAIN ROUTINE - NT ONLY !!!
458 void WINAPI ServiceMain(DWORD argc, char **argv)
462 // Register the service control handler
463 g_hstatus = RegisterServiceCtrlHandler(BAC_SERVICENAME, ServiceCtrl);
465 if (g_hstatus == 0) {
466 MessageBox(NULL, "Contact Register Service Handler failure",
467 "Bacula service", MB_OK);
471 // Set up some standard service state values
472 g_srvstatus.dwServiceType = SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS;
473 g_srvstatus.dwServiceSpecificExitCode = 0;
475 // Give this status to the SCM
477 SERVICE_START_PENDING, // Service state
478 NO_ERROR, // Exit code type
479 15000)) // Hint as to how long Bacula should have hung before you assume error
488 // Now start the service for real
489 (void)CreateThread(NULL, 0, ServiceWorkThread, NULL, 0, &dwThreadID);
493 // SERVICE START ROUTINE - thread that calls BaculaAppMain
495 DWORD WINAPI ServiceWorkThread(LPVOID lpwThreadParam)
497 // Save the current thread identifier
498 g_servicethread = GetCurrentThreadId();
500 // report the status to the service control manager.
503 SERVICE_RUNNING, // service state
504 NO_ERROR, // exit code
506 MessageBox(NULL, "Report Service failure", "Bacula Service", MB_OK);
513 // Mark that we're no longer running
516 // Tell the service manager that we've stopped.
524 // SERVICE STOP ROUTINE - post a quit message to the relevant thread
527 // Post a quit message to the main service thread
528 if (g_servicethread != 0) {
529 PostThreadMessage(g_servicethread, WM_QUIT, 0, 0);
533 // SERVICE INSTALL ROUTINE
535 bacService::InstallService()
537 const int pathlength = 2048;
538 char path[pathlength];
539 char servicecmd[pathlength];
542 // Get the filename of this executable
543 if (GetModuleFileName(NULL, path, pathlength-(strlen(BaculaRunService)+2)) == 0) {
544 MessageBox(NULL, "Unable to install Bacula service", szAppName, MB_ICONEXCLAMATION | MB_OK);
548 // Append the service-start flag to the end of the path:
549 if ((int)strlen(path) + 20 + (int)strlen(BaculaRunService) < pathlength) {
550 sprintf(servicecmd, "\"%s\" %s -c %s", path, BaculaRunService, path);
551 len = strlen(servicecmd) - 1;
552 for ( ; len > 0; len--) {
553 if (servicecmd[len] == '\\') {
559 strcat(servicecmd, "\\bacula-fd.conf");
562 MessageBox(NULL, "Service command length too long. Service not registered.",
563 szAppName, MB_ICONEXCLAMATION | MB_OK);
567 // How to add the Bacula service depends upon the OS
568 switch (g_platform_id) {
571 case VER_PLATFORM_WIN32_WINDOWS:
572 // Locate the RunService registry entry
574 if (RegCreateKey(HKEY_LOCAL_MACHINE,
575 "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",
576 &runservices) != ERROR_SUCCESS) {
577 MessageBox(NULL, "The System Registry could not be updated - the Bacula service was not installed", szAppName, MB_ICONEXCLAMATION | MB_OK);
581 // Attempt to add a Bacula key
582 if (RegSetValueEx(runservices, szAppName, 0, REG_SZ, (unsigned char *)servicecmd, strlen(servicecmd)+1) != ERROR_SUCCESS) {
583 RegCloseKey(runservices);
584 MessageBox(NULL, "The Bacula service could not be installed", szAppName, MB_ICONEXCLAMATION | MB_OK);
588 RegCloseKey(runservices);
590 // We have successfully installed the service!
592 "The Bacula File service was successfully installed.\n"
593 "The service may be started by double clicking on the\n"
594 "Bacula \"Start\" icon and will be automatically\n"
595 "be run the next time this machine is rebooted. ",
597 MB_ICONINFORMATION | MB_OK);
600 // Run the service...
604 si.lpReserved = NULL;
605 si.lpReserved2 = NULL;
608 PROCESS_INFORMATION pi;
609 if (!CreateProcess(NULL, servicecmd, // Program name & path
610 NULL, NULL, // Security attributes
611 FALSE, // Inherit handles?
612 NORMAL_PRIORITY_CLASS, // Extra startup flags
613 NULL, // Environment table
614 NULL, // Current directory
618 MessageBox(NULL, "CreateProcess: the Bacula service failed to start", szAppName, MB_ICONSTOP | MB_OK);
625 case VER_PLATFORM_WIN32_NT:
627 SC_HANDLE hsrvmanager;
629 // Open the default, local Service Control Manager database
630 hsrvmanager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
631 if (hsrvmanager == NULL) {
633 "The Service Control Manager could not be contacted - the Bacula service was not installed",
634 szAppName, MB_ICONEXCLAMATION | MB_OK);
638 // Create an entry for the Bacula service
639 hservice = CreateService(
640 hsrvmanager, // SCManager database
641 BAC_SERVICENAME, // name of service
642 BAC_SERVICEDISPLAYNAME, // name to display
643 SERVICE_ALL_ACCESS, // desired access
644 SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
646 SERVICE_AUTO_START, // start type
647 SERVICE_ERROR_NORMAL, // error control type
648 servicecmd, // service's binary
649 NULL, // no load ordering group
650 NULL, // no tag identifier
651 BAC_DEPENDENCIES, // dependencies
652 NULL, // LocalSystem account
653 NULL); // no password
654 CloseServiceHandle(hsrvmanager);
655 if (hservice == NULL) {
657 "The Bacula service could not be installed",
658 szAppName, MB_ICONEXCLAMATION | MB_OK);
661 CloseServiceHandle(hservice);
663 // Now install the servicehelper registry setting...
664 // Locate the RunService registry entry
666 if (RegCreateKey(HKEY_LOCAL_MACHINE,
667 "Software\\Microsoft\\Windows\\CurrentVersion\\Run",
668 &runapps) != ERROR_SUCCESS) {
669 MessageBox(NULL, "WARNING: Unable to install the ServiceHelper hook\nGlobal user-specific registry settings will not be loaded",
670 szAppName, MB_ICONEXCLAMATION | MB_OK);
672 char servicehelpercmd[pathlength];
674 // Append the service-helper-start flag to the end of the path:
675 if ((int)strlen(path) + 4 + (int)strlen(BaculaRunServiceHelper) < pathlength)
676 sprintf(servicehelpercmd, "\"%s\" %s", path, BaculaRunServiceHelper);
680 // Add the upsserviceHelper entry
681 if (RegSetValueEx(runapps, szAppName, 0, REG_SZ,
682 (unsigned char *)servicehelpercmd, strlen(servicehelpercmd)+1) != ERROR_SUCCESS)
684 MessageBox(NULL, "WARNING:Unable to install the ServiceHelper hook\nGlobal user-specific registry settings will not be loaded", szAppName, MB_ICONEXCLAMATION | MB_OK);
686 RegCloseKey(runapps);
689 // Everything went fine
691 "The Bacula File service was successfully installed.\n"
692 "The service may be started from the Control Panel and will\n"
693 "automatically be run the next time this machine is rebooted.",
695 MB_ICONINFORMATION | MB_OK);
699 "Unknown Windows operating system.\n"
700 "Cannot install Bacula service.\n",
701 szAppName, MB_ICONEXCLAMATION | MB_OK);
708 // SERVICE REMOVE ROUTINE
710 bacService::RemoveService()
712 // How to remove the Bacula service depends upon the OS
713 switch (g_platform_id) {
716 case VER_PLATFORM_WIN32_WINDOWS:
717 // Locate the RunService registry entry
719 if (RegOpenKey(HKEY_LOCAL_MACHINE,
720 "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",
721 &runservices) != ERROR_SUCCESS) {
723 "Could not find registry entry.\nService probably not registerd - the Bacula service was not removed", szAppName, MB_ICONEXCLAMATION | MB_OK);
725 // Attempt to delete the Bacula key
726 if (RegDeleteValue(runservices, szAppName) != ERROR_SUCCESS) {
727 RegCloseKey(runservices);
728 MessageBox(NULL, "Could not delete Registry key.\nThe Bacula service could not be removed", szAppName, MB_ICONEXCLAMATION | MB_OK);
731 RegCloseKey(runservices);
735 // Try to kill any running copy of Bacula
736 if (!KillRunningCopy()) {
738 "Bacula could not be contacted, probably not running",
739 szAppName, MB_ICONEXCLAMATION | MB_OK);
743 // We have successfully removed the service!
744 MessageBox(NULL, "The Bacula service has been removed", szAppName, MB_ICONINFORMATION | MB_OK);
748 case VER_PLATFORM_WIN32_NT:
750 SC_HANDLE hsrvmanager;
752 // Attempt to remove the service-helper hook
754 if (RegOpenKey(HKEY_LOCAL_MACHINE,
755 "Software\\Microsoft\\Windows\\CurrentVersion\\Run",
756 &runapps) == ERROR_SUCCESS)
758 // Attempt to delete the Bacula key
759 if (RegDeleteValue(runapps, szAppName) != ERROR_SUCCESS)
761 MessageBox(NULL, "WARNING:The ServiceHelper hook entry could not be removed from the registry", szAppName, MB_ICONEXCLAMATION | MB_OK);
763 RegCloseKey(runapps);
767 hsrvmanager = OpenSCManager(
768 NULL, // machine (NULL == local)
769 NULL, // database (NULL == default)
770 SC_MANAGER_ALL_ACCESS // access required
773 hservice = OpenService(hsrvmanager, BAC_SERVICENAME, SERVICE_ALL_ACCESS);
774 if (hservice != NULL)
776 SERVICE_STATUS status;
778 // Try to stop the Bacula service
779 if (ControlService(hservice, SERVICE_CONTROL_STOP, &status))
781 while(QueryServiceStatus(hservice, &status)) {
782 if (status.dwCurrentState == SERVICE_STOP_PENDING)
788 if (status.dwCurrentState != SERVICE_STOPPED)
789 MessageBox(NULL, "The Bacula service could not be stopped", szAppName, MB_ICONEXCLAMATION | MB_OK);
792 // Now remove the service from the SCM
793 if(DeleteService(hservice))
794 MessageBox(NULL, "The Bacula service has been removed", szAppName, MB_ICONINFORMATION | MB_OK);
796 MessageBox(NULL, "The Bacula service could not be removed", szAppName, MB_ICONEXCLAMATION | MB_OK);
798 CloseServiceHandle(hservice);
801 MessageBox(NULL, "The Bacula service could not be found", szAppName, MB_ICONEXCLAMATION | MB_OK);
803 CloseServiceHandle(hsrvmanager);
806 MessageBox(NULL, "The SCM could not be contacted - the Bacula service was not removed", szAppName, MB_ICONEXCLAMATION | MB_OK);
812 // USEFUL SERVICE SUPPORT ROUTINES
814 // Service control routine
815 void WINAPI ServiceCtrl(DWORD ctrlcode)
817 // What control code have we been sent?
821 case SERVICE_CONTROL_STOP:
822 // STOP : The service must stop
823 g_srvstatus.dwCurrentState = SERVICE_STOP_PENDING;
827 case SERVICE_CONTROL_INTERROGATE:
828 // QUERY : Service control manager just wants to know our state
832 // Control code not recognised
837 // Tell the control manager what we're up to.
838 ReportStatus(g_srvstatus.dwCurrentState, NO_ERROR, 0);
841 // Service manager status reporting
842 BOOL ReportStatus(DWORD state,
846 static DWORD checkpoint = 1;
849 // If we're in the start state then we don't want the control manager
850 // sending us control messages because they'll confuse us.
851 if (state == SERVICE_START_PENDING)
852 g_srvstatus.dwControlsAccepted = 0;
854 g_srvstatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
856 // Save the new status we've been given
857 g_srvstatus.dwCurrentState = state;
858 g_srvstatus.dwWin32ExitCode = exitcode;
859 g_srvstatus.dwWaitHint = waithint;
861 // Update the checkpoint variable to let the SCM know that we
862 // haven't died if requests take a long time
863 if ((state == SERVICE_RUNNING) || (state == SERVICE_STOPPED))
864 g_srvstatus.dwCheckPoint = 0;
866 g_srvstatus.dwCheckPoint = checkpoint++;
868 // Tell the SCM our new status
869 if (!(result = SetServiceStatus(g_hstatus, &g_srvstatus)))
870 LogErrorMsg("SetServiceStatus failed");
876 void LogErrorMsg(char *message)
882 // Save the error code
883 g_error = GetLastError();
885 // Use event logging to log the error
886 heventsrc = RegisterEventSource(NULL, BAC_SERVICENAME);
888 sprintf(msgbuff, "%s error: %ld", BAC_SERVICENAME, g_error);
889 strings[0] = msgbuff;
890 strings[1] = message;
892 if (heventsrc != NULL) {
896 heventsrc, // handle of event source
897 EVENTLOG_ERROR_TYPE, // event type
900 NULL, // current user's SID
901 2, // strings in 'strings'
902 0, // no bytes of raw data
903 (const char **)strings, // array of error strings
904 NULL); // no raw data
906 DeregisterEventSource(heventsrc);