// $Id$ // // The contents of this file are subject to the BOINC Public License // Version 1.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at // http://boinc.berkeley.edu/license_1.0.txt // // Software distributed under the License is distributed on an "AS IS" // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the // License for the specific language governing rights and limitations // under the License. // // The Original Code is the Berkeley Open Infrastructure for Network Computing. // // The Initial Developer of the Original Code is the SETI@home project. // Portions created by the SETI@home project are Copyright (C) 2002 // University of California at Berkeley. All Rights Reserved. // // Contributor(s): // Craig Link, Microsoft Corp., Service Sample Template // #if defined(_WIN32) && defined(_CONSOLE) #include "boinc_win.h" #include "diagnostics.h" #include "util.h" #include "main.h" #include "win_service.h" // internal variables SERVICE_STATUS ssStatus; // current status of the service SERVICE_STATUS_HANDLE sshStatusHandle; DWORD dwErr = 0; TCHAR szErr[1024]; // // FUNCTION: service_main // // PURPOSE: To perform actual initialization of the service // // PARAMETERS: // dwArgc - number of command line arguments // lpszArgv - array of command line arguments // // RETURN VALUE: // none // // COMMENTS: // This routine performs the service initialization and then calls // the user defined main() routine to perform majority // of the work. // 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_ACCEPTED_ACTIONS; ssStatus.dwServiceSpecificExitCode = 0; // register our service control handler: // sshStatusHandle = RegisterServiceCtrlHandler( TEXT(SZSERVICENAME), service_ctrl); if (!sshStatusHandle) goto cleanup; 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, dwErr, 0); } // // FUNCTION: service_ctrl // // PURPOSE: This function is called by the SCM whenever // ControlService() is called on this service. // // PARAMETERS: // dwCtrlCode - type of control requested // // RETURN VALUE: // none // // COMMENTS: // VOID WINAPI service_ctrl(DWORD dwCtrlCode) { // Handle the requested control code. // switch(dwCtrlCode) { // Stop the service. // // SERVICE_STOP_PENDING should be reported before // setting the Stop Event - hServerStopEvent - in // ServiceStop(). This avoids a race condition // which may result in a 1053 - The Service did not respond... // error. case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: ReportStatus(SERVICE_STOP_PENDING, ERROR_SUCCESS, 10000); quit_client(); return; // Pause the service. // case SERVICE_CONTROL_PAUSE: ReportStatus(SERVICE_PAUSE_PENDING, ERROR_SUCCESS, 10000); suspend_client(); ReportStatus(SERVICE_PAUSED, ERROR_SUCCESS, 10000); return; // Continue the service. // case SERVICE_CONTROL_CONTINUE: ReportStatus(SERVICE_CONTINUE_PENDING, ERROR_SUCCESS, 10000); resume_client(); ReportStatus(SERVICE_RUNNING, ERROR_SUCCESS, 10000); return; // Update the service status. // case SERVICE_CONTROL_INTERROGATE: break; // invalid control code // default: break; } ReportStatus(ssStatus.dwCurrentState, ERROR_SUCCESS, 1000); } // // FUNCTION: ReportStatus() // // PURPOSE: Sets the current status of the service and // reports it to the Service Control Manager // // PARAMETERS: // dwCurrentState - the state of the service // dwWin32ExitCode - error code to report // dwWaitHint - worst case estimate to next checkpoint // // RETURN VALUE: // TRUE - success // FALSE - failure // // COMMENTS: // BOOL ReportStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint) { static DWORD dwCheckPoint = 1; BOOL fResult = TRUE; if (dwCurrentState == SERVICE_START_PENDING) ssStatus.dwControlsAccepted = 0; else ssStatus.dwControlsAccepted = SERVICE_ACCEPTED_ACTIONS; ssStatus.dwCurrentState = dwCurrentState; ssStatus.dwWin32ExitCode = dwWin32ExitCode; ssStatus.dwWaitHint = dwWaitHint; if ( ( dwCurrentState == SERVICE_RUNNING ) || ( dwCurrentState == SERVICE_STOPPED ) ) ssStatus.dwCheckPoint = 0; else ssStatus.dwCheckPoint = dwCheckPoint++; // Report the status of the service to the service control manager. // if (!(fResult = SetServiceStatus( sshStatusHandle, &ssStatus))) { LogEventErrorMessage(TEXT("SetServiceStatus")); } return fResult; } // // FUNCTION: LogEventErrorMessage(LPTSTR lpszMsg) // // PURPOSE: Allows any thread to log an error message // // PARAMETERS: // lpszMsg - text for message // // RETURN VALUE: // none // // COMMENTS: // VOID LogEventErrorMessage(LPTSTR lpszMsg) { TCHAR szMsg[1024]; HANDLE hEventSource; LPTSTR lpszStrings[2]; dwErr = GetLastError(); // Use event logging to log the error. // hEventSource = RegisterEventSource(NULL, TEXT(SZSERVICENAME)); _stprintf(szMsg, TEXT("%s error: %d"), TEXT(SZSERVICENAME), dwErr); lpszStrings[0] = szMsg; lpszStrings[1] = lpszMsg; if (hEventSource != NULL) { ReportEvent(hEventSource, // handle of event source EVENTLOG_ERROR_TYPE, // event type 0, // event category 1, // event ID NULL, // current user's SID 2, // strings in lpszStrings 0, // no bytes of raw data (LPCSTR*)lpszStrings, // array of error strings NULL); // no raw data (VOID) DeregisterEventSource(hEventSource); } } // // FUNCTION: LogEventWarningMessage(LPTSTR lpszMsg) // // PURPOSE: Allows any thread to log an warning message // // PARAMETERS: // lpszMsg - text for message // // RETURN VALUE: // none // // COMMENTS: // VOID LogEventWarningMessage(LPTSTR lpszMsg) { HANDLE hEventSource; LPTSTR lpszStrings[2]; // Use event logging to log the error. // hEventSource = RegisterEventSource(NULL, TEXT(SZSERVICENAME)); lpszStrings[0] = lpszMsg; lpszStrings[1] = '\0'; if (hEventSource != NULL) { ReportEvent(hEventSource, // handle of event source EVENTLOG_WARNING_TYPE,// event type 0, // event category 1, // event ID NULL, // current user's SID 2, // strings in lpszStrings 0, // no bytes of raw data (LPCSTR*)lpszStrings, // array of error strings NULL); // no raw data (VOID) DeregisterEventSource(hEventSource); } } // // FUNCTION: LogEventInfoMessage(LPTSTR lpszMsg) // // PURPOSE: Allows any thread to log an info message // // PARAMETERS: // lpszMsg - text for message // // RETURN VALUE: // none // // COMMENTS: // VOID LogEventInfoMessage(LPTSTR lpszMsg) { HANDLE hEventSource; LPTSTR lpszStrings[2]; // Use event logging to log the error. // hEventSource = RegisterEventSource(NULL, TEXT(SZSERVICENAME)); lpszStrings[0] = lpszMsg; lpszStrings[1] = '\0'; if (hEventSource != NULL) { ReportEvent(hEventSource, // handle of event source EVENTLOG_INFORMATION_TYPE,// event type 0, // event category 1, // event ID NULL, // current user's SID 2, // strings in lpszStrings 0, // no bytes of raw data (LPCSTR*)lpszStrings, // array of error strings NULL); // no raw data (VOID) DeregisterEventSource(hEventSource); } } #endif