diff --git a/checkin_notes b/checkin_notes index c7b6376748..ebd4b63e77 100755 --- a/checkin_notes +++ b/checkin_notes @@ -11814,9 +11814,9 @@ Rom April 28 2004 / set-version - /client + client/ Makefile.am - /client/win + client/win/ *.rc update* (deleted) @@ -11825,3 +11825,20 @@ David April 28 2004 client/ hostinfo_unix.C + +Rom April 28 2004 + - Fixup Windows service controls so that pause/resume/start/stop work as + expected, when running as a service log to the Windows event log. + - When attempting to change the service description use runtime dynamic + linking for the call to ChangeServiceConfig2 so that we will work even + on NT 4.0 systems. + - Some of these fixes were based on code from Mathias Walter + + client/ + cs_cmdline.C + main.C + client/win/ + win_service.cpp, .h + win_build/ + boinc_cli.vcproj + diff --git a/client/cs_cmdline.C b/client/cs_cmdline.C index 4ab09cb686..28fb590741 100644 --- a/client/cs_cmdline.C +++ b/client/cs_cmdline.C @@ -39,7 +39,7 @@ static void print_options(char* prog) { " -install install boinc as a Windows Service\n" " -uninstall uninstall boinc as a Windows Service\n" #endif - " -show_projects show attached projects\n" + " -show_projects show attached projects\n" " -detach_project URL detach from a project\n" " -reset_project URL reset (clear) a project\n" " -attach_project attach to a project (will prompt for URL, account key)\n" @@ -117,8 +117,6 @@ void CLIENT_STATE::parse_cmdline(int argc, char** argv) { else pers_giveup = atoi(argv[++i]); } else if (ARG(debug_fake_exponential_backoff)) { debug_fake_exponential_backoff = true; - } else if (ARG(win_service)) { - executing_as_windows_service = true; // the above options are private (i.e. not shown by -help) // Public options follow. diff --git a/client/main.C b/client/main.C index 7c4195d1aa..d97332a037 100644 --- a/client/main.C +++ b/client/main.C @@ -156,7 +156,7 @@ int add_new_project() { } void quit_client(int a) { - gstate.requested_exit = true; + gstate.cleanup_and_exit(); } void susp_client(int a) { @@ -306,6 +306,11 @@ int main(int argc, char** argv) { } else if ( _stricmp( "uninstall", argv[1]+1 ) == 0 ) { CmdUninstallService(); } else if ( _stricmp( "win_service", argv[1]+1 ) == 0 ) { + + // allow the system to know it is running as a Windows service + // and adjust it's diagnostics schemes accordingly. + gstate.executing_as_windows_service = true; + printf( "\nStartServiceCtrlDispatcher being called.\n" ); printf( "This may take several seconds. Please wait.\n" ); diff --git a/client/win/win_service.cpp b/client/win/win_service.cpp index 39b7405783..427a9f873d 100644 --- a/client/win/win_service.cpp +++ b/client/win/win_service.cpp @@ -22,15 +22,18 @@ #include "stdafx.h" +#include "diagnostics.h" #include "win_service.h" #include "util.h" + // internal variables SERVICE_STATUS ssStatus; // current status of the service SERVICE_STATUS_HANDLE sshStatusHandle; DWORD dwErr = 0; TCHAR szErr[1024]; + // define the execution engine start point extern int boinc_main_loop(int argc, char** argv); extern void quit_client(int a); @@ -38,9 +41,8 @@ extern void susp_client(int a); extern void resume_client(int a); - -// internal function prototypes not defined in the header -LPTSTR GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize ); +// Define API's that are going to be used through LoadLibrary calls. +typedef WINADVAPI BOOL (WINAPI *PROCCHANGESERVICECONFIG2)(SC_HANDLE, DWORD, LPCVOID); // @@ -62,36 +64,49 @@ LPTSTR GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize ); // void WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv) { + TCHAR szPath[MAX_PATH-1]; + + // SERVICE_STATUS members that don't change in example // ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; - ssStatus.dwControlsAccepted = - SERVICE_ACCEPT_STOP | - SERVICE_ACCEPT_PAUSE_CONTINUE | - SERVICE_ACCEPT_SHUTDOWN; + ssStatus.dwControlsAccepted = SERVICE_ACCEPTED_ACTIONS; ssStatus.dwServiceSpecificExitCode = 0; + // register our service control handler: // sshStatusHandle = RegisterServiceCtrlHandler( TEXT(SZSERVICENAME), service_ctrl); if (!sshStatusHandle) goto cleanup; - if (!ReportStatus( + if (!ReportStatus( SERVICE_RUNNING, // service state ERROR_SUCCESS, // exit code 0)) // wait hint goto cleanup; + + // change the current directory to the boinc install directory + if (!GetModuleFileName(NULL, szPath, (sizeof(szPath)/sizeof(TCHAR)))) + goto cleanup; + + TCHAR *pszProg = strrchr(szPath, '\\'); + if (pszProg) { + szPath[pszProg - szPath + 1] = 0; + SetCurrentDirectory(szPath); + } + dwErr = boinc_main_loop(dwArgc, lpszArgv); + cleanup: // try to report the stopped status to the service control manager. // if (sshStatusHandle) (VOID)ReportStatus( - SERVICE_STOPPED, + SERVICE_STOPPED, dwErr, 0); } @@ -125,11 +140,6 @@ VOID WINAPI service_ctrl(DWORD dwCtrlCode) // which may result in a 1053 - The Service did not respond... // error. case SERVICE_CONTROL_STOP: - ReportStatus(SERVICE_STOP_PENDING, ERROR_SUCCESS, 10000); - quit_client(NULL); - ReportStatus(SERVICE_STOPPED, ERROR_SUCCESS, 10000); - return; - case SERVICE_CONTROL_SHUTDOWN: ReportStatus(SERVICE_STOP_PENDING, ERROR_SUCCESS, 10000); quit_client(NULL); @@ -148,7 +158,7 @@ VOID WINAPI service_ctrl(DWORD dwCtrlCode) // case SERVICE_CONTROL_CONTINUE: ReportStatus(SERVICE_CONTINUE_PENDING, ERROR_SUCCESS, 10000); - susp_client(NULL); + resume_client(NULL); ReportStatus(SERVICE_RUNNING, ERROR_SUCCESS, 10000); return; @@ -195,10 +205,7 @@ BOOL ReportStatus(DWORD dwCurrentState, if (dwCurrentState == SERVICE_START_PENDING) ssStatus.dwControlsAccepted = 0; else - ssStatus.dwControlsAccepted = - SERVICE_ACCEPT_STOP | - SERVICE_ACCEPT_PAUSE_CONTINUE | - SERVICE_ACCEPT_SHUTDOWN; + ssStatus.dwControlsAccepted = SERVICE_ACCEPTED_ACTIONS; ssStatus.dwCurrentState = dwCurrentState; ssStatus.dwWin32ExitCode = dwWin32ExitCode; @@ -254,7 +261,7 @@ VOID LogEventErrorMessage(LPTSTR lpszMsg) ReportEvent(hEventSource, // handle of event source EVENTLOG_ERROR_TYPE, // event type 0, // event category - 0, // event ID + 1, // event ID NULL, // current user's SID 2, // strings in lpszStrings 0, // no bytes of raw data @@ -263,7 +270,7 @@ VOID LogEventErrorMessage(LPTSTR lpszMsg) (VOID) DeregisterEventSource(hEventSource); } -} + } // @@ -299,7 +306,7 @@ VOID LogEventWarningMessage(LPTSTR lpszMsg) ReportEvent(hEventSource, // handle of event source EVENTLOG_WARNING_TYPE,// event type 0, // event category - 0, // event ID + 1, // event ID NULL, // current user's SID 2, // strings in lpszStrings 0, // no bytes of raw data @@ -344,7 +351,7 @@ VOID LogEventInfoMessage(LPTSTR lpszMsg) ReportEvent(hEventSource, // handle of event source EVENTLOG_INFORMATION_TYPE,// event type 0, // event category - 0, // event ID + 1, // event ID NULL, // current user's SID 2, // strings in lpszStrings 0, // no bytes of raw data @@ -370,14 +377,16 @@ VOID LogEventInfoMessage(LPTSTR lpszMsg) // void CmdInstallService() { - SC_HANDLE schService; - SC_HANDLE schSCManager; + SC_HANDLE schService; + SC_HANDLE schSCManager; + HINSTANCE hinstAdvAPI32; + PROCCHANGESERVICECONFIG2 ProcChangeServiceConfig2; TCHAR szPath[512]; if ( GetModuleFileName( NULL, szPath, 512 ) == 0 ) { - _tprintf(TEXT("Unable to install %s - %s\n"), TEXT(SZSERVICEDISPLAYNAME), windows_error_string(szErr, sizeof(szErr))); + _tprintf(TEXT("Unable to install %s - %s\n"), TEXT(SZSERVICEDISPLAYNAME), windows_error_string(szErr, (sizeof(szErr)/sizeof(TCHAR)))); return; } @@ -435,23 +444,48 @@ void CmdInstallService() SERVICE_DESCRIPTION sdDescription; sdDescription.lpDescription = TEXT(SZSERVICEDESCRIPTION); - if ( ChangeServiceConfig2(schService, SERVICE_CONFIG_DESCRIPTION, &sdDescription) ){ - _tprintf(TEXT("%s service description installed.\n"), TEXT(SZSERVICEDISPLAYNAME) ); - } else { - _tprintf(TEXT("ChangeServiceConfig2 failed - %s\n"), windows_error_string(szErr, sizeof(szErr))); - } + hinstAdvAPI32 = LoadLibrary("ADVAPI32"); + + // If the handle is valid, try to get the function address. + if ( NULL != hinstAdvAPI32 ) + { +#ifdef _UNICODE + ProcChangeServiceConfig2 = (PROCCHANGESERVICECONFIG2)GetProcAddress( + hinstAdvAPI32, + TEXT("ChangeServiceConfig2W") + ); +#else + ProcChangeServiceConfig2 = (PROCCHANGESERVICECONFIG2)GetProcAddress( + hinstAdvAPI32, + TEXT("ChangeServiceConfig2A") + ); +#endif + + // If the function address is valid, call the function. + if ( NULL != ProcChangeServiceConfig2 ) + { + if ( ProcChangeServiceConfig2(schService, SERVICE_CONFIG_DESCRIPTION, &sdDescription) ){ + _tprintf(TEXT("%s service description installed.\n"), TEXT(SZSERVICEDISPLAYNAME) ); + } else { + _tprintf(TEXT("ChangeServiceConfig2 failed - %s\n"), windows_error_string(szErr, (sizeof(szErr)/sizeof(TCHAR)))); + } + } + + // Free the DLL module + FreeLibrary( hinstAdvAPI32 ); + } CloseServiceHandle(schService); } else { - _tprintf(TEXT("CreateService failed - %s\n"), windows_error_string(szErr, sizeof(szErr))); + _tprintf(TEXT("CreateService failed - %s\n"), windows_error_string(szErr, (sizeof(szErr)/sizeof(TCHAR)))); } CloseServiceHandle(schSCManager); } else - _tprintf(TEXT("OpenSCManager failed - %s\n"), windows_error_string(szErr,sizeof(szErr))); + _tprintf(TEXT("OpenSCManager failed - %s\n"), windows_error_string(szErr, (sizeof(szErr)/sizeof(TCHAR)))); } @@ -513,18 +547,18 @@ void CmdUninstallService() if( DeleteService(schService) ) _tprintf(TEXT("%s removed.\n"), TEXT(SZSERVICEDISPLAYNAME) ); else - _tprintf(TEXT("DeleteService failed - %s\n"), windows_error_string(szErr,sizeof(szErr))); + _tprintf(TEXT("DeleteService failed - %s\n"), windows_error_string(szErr, (sizeof(szErr)/sizeof(TCHAR)))); CloseServiceHandle(schService); } else - _tprintf(TEXT("OpenService failed - %s\n"), windows_error_string(szErr,sizeof(szErr))); + _tprintf(TEXT("OpenService failed - %s\n"), windows_error_string(szErr, (sizeof(szErr)/sizeof(TCHAR)))); CloseServiceHandle(schSCManager); } else - _tprintf(TEXT("OpenSCManager failed - %s\n"), windows_error_string(szErr,sizeof(szErr))); + _tprintf(TEXT("OpenSCManager failed - %s\n"), windows_error_string(szErr, (sizeof(szErr)/sizeof(TCHAR)))); } diff --git a/client/win/win_service.h b/client/win/win_service.h index 044997c449..218b1aa8e4 100644 --- a/client/win/win_service.h +++ b/client/win/win_service.h @@ -27,6 +27,7 @@ extern "C" { #endif + // internal name of the service #define SZSERVICENAME "BOINC" @@ -36,6 +37,12 @@ extern "C" { // displayed description of the service #define SZSERVICEDESCRIPTION "Berkeley Open Infrastructure for Network Computing" +// Service Accepted Actions +#define SERVICE_ACCEPTED_ACTIONS ( \ + SERVICE_ACCEPT_STOP | \ + SERVICE_ACCEPT_PAUSE_CONTINUE | \ + SERVICE_ACCEPT_SHUTDOWN ) + // Service Control Manager Routines VOID WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv); VOID WINAPI service_ctrl(DWORD dwCtrlCode); diff --git a/doc/contact.php b/doc/contact.php index 11c2cd364c..e9e121eea8 100644 --- a/doc/contact.php +++ b/doc/contact.php @@ -28,6 +28,7 @@ Sebastian Masch, Stephen Pellicer, Jens Seidler, Christian Soettrup, +Mathias Walter, Rom Walton, Oliver Wang

diff --git a/win_build/boinc_cli.vcproj b/win_build/boinc_cli.vcproj index 1e37925dfa..d075c7b868 100644 --- a/win_build/boinc_cli.vcproj +++ b/win_build/boinc_cli.vcproj @@ -26,6 +26,7 @@ PreprocessorDefinitions="WIN32;_DEBUG;_MT;_WINDOWS;_CONSOLE" BasicRuntimeChecks="3" RuntimeLibrary="1" + RuntimeTypeInfo="FALSE" UsePrecompiledHeader="2" PrecompiledHeaderThrough="../client/StdAfx.h" PrecompiledHeaderFile=".\Build\Debug\boinc_cli\obj/boinc_cli.pch" @@ -1129,9 +1130,6 @@ - -