/******************************************************************************* * * 模 块 名:DBService 文件名:DBService.c * 相关文件:DBService.h * 提交日期:2012.2.1 作 者:Alex * 版 本:0.1 * 模块描述: * 本模块提供了Service程序的框架 * main(int argc, char **argv); * service_ctrl(DWORD dwCtrlCode); * service_main(DWORD dwArgc, LPTSTR *lpszArgv); * CmdInstallService(); * CmdRemoveService(); * CmdDebugService(int argc, char **argv); * ControlHandler ( DWORD dwCtrlType ); * GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize ); * 修改记录: * 日 期 版本 修改人 修改内容 * * *******************************************************************************/ #ifdef _WIN32 #include #include #include #include #include #define _DBSERVICE_C #include "DBService.h" #undef _DBSERVICE_C // internal variables SERVICE_STATUS ssStatus; // current status of the service SERVICE_STATUS_HANDLE sshStatusHandle; DWORD dwErr = 0; TCHAR szErr[256]; char SZDEPENDENCIES[10] = ""; // internal function prototypes VOID WINAPI service_ctrl(DWORD dwCtrlCode); VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv); VOID CmdInstallService(); VOID CmdRemoveService(); VOID CmdDebugService(int argc, char **argv); BOOL WINAPI ControlHandler ( DWORD dwCtrlType ); // main() either performs the command line task, or // call StartServiceCtrlDispatcher to register the // main service thread. When the this call returns, // the service has stopped, so exit. // //void _CRTAPI1 main(int argc, char **argv) int __cdecl _tmain(int argc, TCHAR *argv[]) { SERVICE_TABLE_ENTRY dispatchTable[] = { { TEXT(SZSERVICENAME), (LPSERVICE_MAIN_FUNCTION)ServiceMain }, { NULL, NULL } }; if ( (argc > 1) &&((*argv[1] == '-') || (*argv[1] == '/')) ){ int cmd = 0; if ( _stricmp( "install", argv[1]+1 ) == 0 ){ if( argc>2 ){ strcpy( SZDEPENDENCIES, argv[2] ); } cmd = 1; } else if ( _stricmp( "remove", argv[1]+1 ) == 0 ){ cmd = 2; } else if ( _stricmp( "debug", argv[1]+1 ) == 0 ){ g_eDebug = 4; if( argc>2 ){ if ( _stricmp( "f", argv[2] ) == 0 ){ g_eDebug = 1; } else if ( _stricmp( "n", argv[2] ) == 0 ){ g_eDebug = 2; } else if ( _stricmp( "s", argv[2] ) == 0 ){ g_eDebug = 3; } } cmd = 3; } else if( _stricmp( "check", argv[1]+1 ) == 0 && argc>2 ){ g_iChkStyle = atoi(argv[2]); if( g_iChkStyle>0 ){ g_eDebug = 3; cmd = 3; } } if( cmd==1 ){ CmdInstallService(); } else if( cmd==2 ){ CmdRemoveService(); } else if( cmd==3 ){ CmdDebugService(argc, argv); } else{ // this is just to be friendly printf( "%s -install to install the service\n", SZAPPNAME ); printf( "%s -remove to remove the service\n", SZAPPNAME ); printf( "%s -debug to run as a console app for debugging\n", SZAPPNAME ); printf( "%s -check to run as a console app for check style\n", SZAPPNAME ); printf( "\nStartServiceCtrlDispatcher being called.\n" ); printf( "This may take several seconds. Please wait.\n" ); } return 0; } // if it doesn't match any of the above parameters // the service control manager may be starting the service // so we must call StartServiceCtrlDispatcher if (!StartServiceCtrlDispatcher(dispatchTable)) AddToMessageLog(TEXT("StartServiceCtrlDispatcher failed.")); return 0; } // This routine performs the service initialization and then calls // the user defined ServiceStart() routine to perform majority // of the work. // void WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv) { // register our service control handler: sshStatusHandle = RegisterServiceCtrlHandler( TEXT(SZSERVICENAME), service_ctrl); if (!sshStatusHandle) goto cleanup; // SERVICE_STATUS members that don't change in example ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; ssStatus.dwServiceSpecificExitCode = 0; // report the status to the service control manager. if (!ReportStatusToSCMgr( SERVICE_START_PENDING, // service state NO_ERROR, // exit code 3000)) // wait hint goto cleanup; ServiceStart( dwArgc, lpszArgv ); cleanup: // try to report the stopped status to the service control manager. if (sshStatusHandle) (VOID)ReportStatusToSCMgr( SERVICE_STOPPED, dwErr, 0); printf( "%s stopped the service\n", SZAPPNAME ); // getchar(); return; } //This function is called by the SCM whenever //ControlService() is called on this service. 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: ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 0); ServiceStop(); return; // Update the service status. case SERVICE_CONTROL_INTERROGATE: break; // invalid control code default: break; } ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0); } //Sets the current status of the service and //reports it to the Service Control Manager BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint) { static DWORD dwCheckPoint = 1; BOOL fResult = TRUE; if( g_eDebug==0 ){ if (dwCurrentState == SERVICE_START_PENDING) ssStatus.dwControlsAccepted = 0; else ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; 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))){ AddToMessageLog(TEXT("SetServiceStatus")); } } return fResult; } //Allows any thread to log an error message VOID AddToMessageLog(LPTSTR lpszMsg) { TCHAR szMsg[256]; HANDLE hEventSource; LPCTSTR lpszStrings[2]; // if ( g_eDebug<0 ){ 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 0, // event ID NULL, // current user's SID 2, // strings in lpszStrings 0, // no bytes of raw data lpszStrings, // array of error strings NULL); // no raw data (VOID) DeregisterEventSource(hEventSource); } // } } //Installs the service void CmdInstallService() { SC_HANDLE schService; SC_HANDLE schSCManager; TCHAR szPath[512]; DWORD dwBytesNeeded; if ( GetModuleFileName( NULL, szPath, 512 ) == 0 ){ _tprintf(TEXT("Unable to install %s - %s\n"), TEXT(SZSERVICEDISPLAYNAME), GetLastErrorText(szErr, 256)); return; } schSCManager = OpenSCManager( NULL, // machine (NULL == local) NULL, // database (NULL == default) SC_MANAGER_ALL_ACCESS // access required ); if ( schSCManager ){ schService = CreateService( schSCManager, // SCManager database TEXT(SZSERVICENAME), // name of service TEXT(SZSERVICEDISPLAYNAME), // name to display SERVICE_ALL_ACCESS, // desired access SERVICE_WIN32_OWN_PROCESS, // service type SERVICE_AUTO_START, // start type SERVICE_ERROR_NORMAL, // error control type szPath, // service's binary NULL, // no load ordering group NULL, // no tag identifier TEXT(SZDEPENDENCIES), // dependencies NULL, // LocalSystem account NULL); // no password if ( schService ){ _tprintf(TEXT("%s installed.\n"), TEXT(SZSERVICEDISPLAYNAME) ); if( !StartService(schService, 0, NULL) ){ printf("StartService failed (%d)\n", GetLastError()); CloseServiceHandle(schService); CloseServiceHandle(schSCManager); return; } if (!QueryServiceStatusEx( schService, // handle to service SC_STATUS_PROCESS_INFO, // info level (LPBYTE) &ssStatus, // address of structure sizeof(SERVICE_STATUS_PROCESS), // size of structure &dwBytesNeeded ) ) // if buffer too small { return; } CloseServiceHandle(schService); } else{ _tprintf(TEXT("CreateService failed - %s\n"), GetLastErrorText(szErr, 256)); } CloseServiceHandle(schSCManager); } else _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256)); } // PURPOSE: Stops and removes the service void CmdRemoveService() { SC_HANDLE schService; SC_HANDLE schSCManager; schSCManager = OpenSCManager( NULL, // machine (NULL == local) NULL, // database (NULL == default) SC_MANAGER_ALL_ACCESS // access required ); if ( schSCManager ){ schService = OpenService(schSCManager, TEXT(SZSERVICENAME), SERVICE_ALL_ACCESS); if (schService){ // try to stop the service if ( ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus ) ){ _tprintf(TEXT("Stopping %s."), TEXT(SZSERVICEDISPLAYNAME)); Sleep( 1000 ); while( QueryServiceStatus( schService, &ssStatus ) ){ if ( ssStatus.dwCurrentState == SERVICE_STOP_PENDING ){ _tprintf(TEXT(".")); Sleep( 1000 ); } else break; } if ( ssStatus.dwCurrentState == SERVICE_STOPPED ) _tprintf(TEXT("\n%s stopped.\n"), TEXT(SZSERVICEDISPLAYNAME) ); else _tprintf(TEXT("\n%s failed to stop.\n"), TEXT(SZSERVICEDISPLAYNAME) ); } // now remove the service if( DeleteService(schService) ) _tprintf(TEXT("%s removed.\n"), TEXT(SZSERVICEDISPLAYNAME) ); else _tprintf(TEXT("DeleteService failed - %s\n"), GetLastErrorText(szErr,256)); CloseServiceHandle(schService); } else _tprintf(TEXT("OpenService failed - %s\n"), GetLastErrorText(szErr,256)); CloseServiceHandle(schSCManager); } else _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256)); } //Runs the service as a console application void CmdDebugService(int argc, char ** argv) { DWORD dwArgc; LPTSTR *lpszArgv; #ifdef UNICODE lpszArgv = CommandLineToArgvW(GetCommandLineW(), &(dwArgc) ); #else dwArgc = (DWORD) argc; lpszArgv = argv; #endif _tprintf(TEXT("Debugging %s.\n"), TEXT(SZSERVICEDISPLAYNAME)); _tprintf(TEXT("Press Ctl+C to stop %s...\n"), TEXT(SZSERVICEDISPLAYNAME)); SetConsoleCtrlHandler( ControlHandler, TRUE ); ServiceStart( dwArgc, lpszArgv ); } //Handled console control events BOOL WINAPI ControlHandler ( DWORD dwCtrlType ) { switch( dwCtrlType ){ case CTRL_BREAK_EVENT: // use Ctrl+C or Ctrl+Break to simulate case CTRL_C_EVENT: // SERVICE_CONTROL_STOP in debug mode _tprintf(TEXT("Stopping %s.\n"), TEXT(SZSERVICEDISPLAYNAME)); ServiceStop(); return TRUE; break; } return FALSE; } //copies error message text to string LPTSTR GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize ) { DWORD dwRet; LPTSTR lpszTemp = NULL; dwRet = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY, NULL, GetLastError(), LANG_NEUTRAL, (LPTSTR)&lpszTemp, 0, NULL ); // supplied buffer is not long enough if ( !dwRet || ( (long)dwSize < (long)dwRet+14 ) ) lpszBuf[0] = TEXT('\0'); else{ lpszTemp[lstrlen(lpszTemp)-2] = TEXT('\0'); //remove cr and newline character _stprintf( lpszBuf, TEXT("%s (0x%x)"), lpszTemp, GetLastError() ); } if ( lpszTemp ) LocalFree((HLOCAL) lpszTemp ); return lpszBuf; } #endif