visual c++に基づくwindowsコアプログラミングコード分析(9)Windowsサービスとインストール、制御を実現


私たちがWindowsプログラミングを行うとき、Windowsサービスプログラミングに関わることがよくありますが、Windowsサービスに対してどのようにプログラミングすればいいのでしょうか.
まず、Windowsサービスを実装し、実装します.コメントコード分析を参照してください.
/*     */
#include <windows.h>
/*      */
SERVICE_STATUS          SplSrvServiceStatus; 
SERVICE_STATUS_HANDLE   SplSrvServiceStatusHandle; 
/*      */
VOID SvcDebugOut(LPSTR String, DWORD Status);
VOID WINAPI SplSrvServiceCtrlHandler (DWORD opcode); 
VOID WINAPI SplSrvServiceStart (DWORD argc, LPTSTR *argv); 
DWORD SplSrvServiceInitialization (DWORD argc, LPTSTR *argv, 
								   DWORD *specificError); 

/*************************************
* VOID WINAPI SplSrvServiceStart (DWORD argc, LPTSTR *argv)
*   	      
*
*   	   
**************************************/
VOID WINAPI SplSrvServiceStart (DWORD argc, LPTSTR *argv) 
{ 
	DWORD status; 
	DWORD specificError; 
	//   SERVICE_STATUS   
	SplSrvServiceStatus.dwServiceType        = SERVICE_WIN32; 
	SplSrvServiceStatus.dwCurrentState       
		= SERVICE_START_PENDING;		//      
	SplSrvServiceStatus.dwControlsAccepted   
		= SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE; 
	SplSrvServiceStatus.dwWin32ExitCode      = 0; 
	SplSrvServiceStatus.dwServiceSpecificExitCode = 0; 
	SplSrvServiceStatus.dwCheckPoint         = 0; 
	SplSrvServiceStatus.dwWaitHint           = 0; 
	//             
	SplSrvServiceStatusHandle = RegisterServiceCtrlHandler( 
		"Sample_Srv",	//    ,         
		// SERVICE_WIN32_OWN_PROCESS,        。
		SplSrvServiceCtrlHandler);	//         ,   

	if (SplSrvServiceStatusHandle == (SERVICE_STATUS_HANDLE)0) 
	{ 
		SvcDebugOut(" [SPLSRV_SERVICE] RegisterServiceCtrlHandler "
			"failed %d
", GetLastError()); return; } // , , status = SplSrvServiceInitialization(argc,argv, &specificError); // , if (status != NO_ERROR) { SplSrvServiceStatus.dwCurrentState = SERVICE_STOPPED; SplSrvServiceStatus.dwCheckPoint = 0; SplSrvServiceStatus.dwWaitHint = 0; SplSrvServiceStatus.dwWin32ExitCode = status; SplSrvServiceStatus.dwServiceSpecificExitCode = specificError; SetServiceStatus (SplSrvServiceStatusHandle, &SplSrvServiceStatus); return; } // , SplSrvServiceStatus.dwCurrentState = SERVICE_RUNNING; SplSrvServiceStatus.dwCheckPoint = 0; SplSrvServiceStatus.dwWaitHint = 0; if (!SetServiceStatus (SplSrvServiceStatusHandle, &SplSrvServiceStatus)) { status = GetLastError(); SvcDebugOut(" [SPLSRV_SERVICE] SetServiceStatus error %ld
",status); } // , SvcDebugOut(" [SPLSRV_SERVICE] Returning the Main Thread
",0); return; } /************************************* * DWORD SplSrvServiceInitialization(DWORD argc, * LPTSTR *argv, * DWORD *specificError) * , , * * **************************************/ DWORD SplSrvServiceInitialization(DWORD argc, LPTSTR *argv, DWORD *specificError) { return(0); } /************************************* * VOID WINAPI SplSrvServiceCtrlHandler (DWORD Opcode) * , ControlService 。 * * **************************************/ VOID WINAPI SplSrvServiceCtrlHandler (DWORD Opcode) { DWORD status; switch(Opcode) { case SERVICE_CONTROL_PAUSE: // SplSrvServiceStatus.dwCurrentState = SERVICE_PAUSED; break; case SERVICE_CONTROL_CONTINUE: // SplSrvServiceStatus.dwCurrentState = SERVICE_RUNNING; break; case SERVICE_CONTROL_STOP: // SplSrvServiceStatus.dwWin32ExitCode = 0; SplSrvServiceStatus.dwCurrentState = SERVICE_STOPPED; SplSrvServiceStatus.dwCheckPoint = 0; SplSrvServiceStatus.dwWaitHint = 0; if (!SetServiceStatus (SplSrvServiceStatusHandle, &SplSrvServiceStatus)) { status = GetLastError(); SvcDebugOut(" [SPLSRV_SERVICE] SetServiceStatus error %ld
", status); } SvcDebugOut(" [SPLSRV_SERVICE] Leaving SplSrvService
",0); return; case SERVICE_CONTROL_INTERROGATE: // , , MessageBeep(MB_OK); break; default: SvcDebugOut(" [SPLSRV_SERVICE] Unrecognized opcode %ld
", Opcode); } // if (!SetServiceStatus (SplSrvServiceStatusHandle, &SplSrvServiceStatus)) { status = GetLastError(); SvcDebugOut(" [SPLSRV_SERVICE] SetServiceStatus error %ld
", status); } return; } /************************************* * void main( ) * , 。 * * **************************************/ void main( ) { // SERVICE_TABLE_ENTRY , NULL , // StartServiceCtrlDispatcher 。 SERVICE_TABLE_ENTRY DispatchTable[] = { { "Sample_Srv", (LPSERVICE_MAIN_FUNCTION) SplSrvServiceStart }, { NULL, NULL } }; if (!StartServiceCtrlDispatcher( DispatchTable)) { SvcDebugOut(" [SPLSRV_SERVICE] StartServiceCtrlDispatcher (%d)
", GetLastError()); } } /************************************* * VOID SvcDebugOut(LPSTR String, DWORD Status) * 。 * * LPSTR String * DWORD Status **************************************/ VOID SvcDebugOut(LPSTR String, DWORD Status) { CHAR Buffer[1024]; if (strlen(String) < 1000) { wsprintf(Buffer, String, Status); OutputDebugString(Buffer); } }

その後、サービスを実現した後、インストール、サービスの削除が必要です.
具体的な実装コードは以下の通りです.コード分析を参照してください.
**************************************/
/*     */
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
/*      */
SC_HANDLE schService;
SC_HANDLE schSCManager;
LPTSTR szServiceName = TEXT("Sample_Srv");

/*************************************
* BOOL CreateSampleService(LPTSTR szPath, LPSTR szServiceName) 
*   	    
*
*   
*		SC_HANDLE schSCManager,SCM  
*		LPTSTR szPath,        
*		LPSTR szServiceName,    
**************************************/
BOOL CreateSampleService( 
						 SC_HANDLE schSCManager,
						 LPTSTR szPath,
						 LPSTR szServiceName) 
{ 
	//     
	schService = CreateService( 
		schSCManager,				// SCM   
		szServiceName,				//    
		"Service sample",           //       
		SERVICE_ALL_ACCESS,			//     
		SERVICE_WIN32_OWN_PROCESS,	//     
		SERVICE_DEMAND_START,		//     
		SERVICE_ERROR_NORMAL,		//       
		szPath,						//           
		NULL,						// no load ordering group 
		NULL,						// no tag identifier 
		NULL,						// no dependencies 
		NULL,						// LocalSystem account 
		NULL);						// no password 

	if (schService == NULL) 
	{
		printf("CreateService failed (%d)
", GetLastError()); return FALSE; } else { printf("CreateService succeeded
"); CloseServiceHandle(schService); return TRUE; } } /************************************* * BOOL DeleteSampleService(LPTSTR szNameOfService) * * * LPTSTR szNameOfService **************************************/ BOOL DeleteSampleService(LPTSTR szNameOfService) { schService = OpenService( schSCManager, // SCM szNameOfService, // DELETE); // if (schService == NULL) { printf("OpenService failed (%d)
", GetLastError()); return FALSE; } // if (! DeleteService(schService) ) { printf("DeleteService failed (%d)
", GetLastError()); return FALSE; } else printf("DeleteService succeeded
"); // CloseServiceHandle(schService); return TRUE; } /************************************* * void main( int argc, TCHAR *argv[] ) * * * **************************************/ void main( int argc, TCHAR *argv[] ) { TCHAR szBinFilePath[MAX_PATH]; PTCHAR pTemp; DWORD dwStopError; // GetModuleFileName(NULL,szBinFilePath,MAX_PATH); pTemp = szBinFilePath+lstrlen(szBinFilePath); while(*--pTemp!='\\'); lstrcpy(pTemp,TEXT("\\SplSrv.exe")); // SCM schSCManager = OpenSCManager( NULL, // local machine NULL, // ServicesActive database SC_MANAGER_ALL_ACCESS); // full access rights if (NULL == schSCManager) printf("OpenSCManager failed (%d)
", GetLastError()); // CreateSampleService(schSCManager, szBinFilePath, szServiceName); // StartSampleService(schSCManager,szServiceName); // ControlSampleService(SERVICE_CONTROL_INTERROGATE); ControlSampleService(SERVICE_CONTROL_CONTINUE); // dwStopError = StopService( schSCManager, szServiceName, TRUE, 1000); if(ERROR_SUCCESS == dwStopError) { printf("Service Stoped
"); } else { printf("Service stoped error (%u)
",dwStopError); } // DeleteSampleService(szServiceName); CloseServiceHandle(schSCManager); }

そして、サービスをどのように制御するか、サービスの起動、停止、サービスへのリクエストの送信を実現します.
 
/*     */
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
/*      */
extern SC_HANDLE schService;	//  init.c   ,  
extern SC_HANDLE schSCManager;
extern LPTSTR szServiceName;

/*************************************
* BOOL StartSampleService(SC_HANDLE schSCManager,LPTSTR szServiceName) 
*   	    
*
*   	SC_HANDLE schSCManager	SCM   
*		LPTSTR szServiceName	   
**************************************/
BOOL StartSampleService(SC_HANDLE schSCManager,LPTSTR szServiceName) 
{ 
	SC_HANDLE schService;
	SERVICE_STATUS_PROCESS ssStatus; 
	DWORD dwOldCheckPoint; 
	DWORD dwStartTickCount;
	DWORD dwWaitTime;
	DWORD dwBytesNeeded;
	//     
	schService = OpenService( 
		schSCManager,			// SCM database 
		szServiceName,          // service name
		SERVICE_ALL_ACCESS); 
	if (schService == NULL) 
	{ 
		return 0; 
	}
	//     
	if (!StartService(
		schService,  // handle to service 
		0,           // number of arguments 
		NULL) )      // no arguments 
	{
		printf("Service start error (%u).
",GetLastError()); return 0; } else { printf("Service start pending.
"); } // 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 0; } // tick count & checkpoint. dwStartTickCount = GetTickCount(); dwOldCheckPoint = ssStatus.dwCheckPoint; // , PENDING while (ssStatus.dwCurrentState == SERVICE_START_PENDING) { // dwWaitTime = ssStatus.dwWaitHint / 10; if( dwWaitTime < 1000 ) dwWaitTime = 1000; else if ( dwWaitTime > 10000 ) dwWaitTime = 10000; Sleep( dwWaitTime ); // 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 break; if ( ssStatus.dwCheckPoint > dwOldCheckPoint ) { // dwStartTickCount = GetTickCount(); dwOldCheckPoint = ssStatus.dwCheckPoint; } else { if(GetTickCount()-dwStartTickCount > ssStatus.dwWaitHint) { // WaitHint break; } } } // CloseServiceHandle(schService); // ( PENDING RUNNING) if (ssStatus.dwCurrentState == SERVICE_RUNNING) { printf("StartService SUCCESS.
"); return 1; } else { printf("
Service not started.
"); printf(" Current State: %d
", ssStatus.dwCurrentState); printf(" Exit Code: %d
", ssStatus.dwWin32ExitCode); printf(" Service Specific Exit Code: %d
", ssStatus.dwServiceSpecificExitCode); printf(" Check Point: %d
", ssStatus.dwCheckPoint); printf(" Wait Hint: %d
", ssStatus.dwWaitHint); return 0; } } /************************************* * DWORD StopService( SC_HANDLE hSCM, LPTSTR szServiceName, BOOL fStopDependencies, DWORD dwTimeout ) * * * SC_HANDLE hSCM SCM * LPTSTR szServiceName * BOOL fStopDependencies * DWORD dwTimeout **************************************/ DWORD StopService(SC_HANDLE hSCM, LPTSTR szServiceName, BOOL fStopDependencies, DWORD dwTimeout ) { SERVICE_STATUS_PROCESS ssp; SERVICE_STATUS ss; DWORD dwStartTime = GetTickCount(); DWORD dwBytesNeeded; // SC_HANDLE hService = OpenService( hSCM, // SCM szServiceName, // SERVICE_ALL_ACCESS); // , if ( !QueryServiceStatusEx( hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, sizeof(SERVICE_STATUS_PROCESS), &dwBytesNeeded ) ) { return GetLastError(); } if ( ssp.dwCurrentState == SERVICE_STOPPED ) { return ERROR_SUCCESS; } // STOP_PENDING , while ( ssp.dwCurrentState == SERVICE_STOP_PENDING ) { Sleep( ssp.dwWaitHint ); // , if ( !QueryServiceStatusEx( hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, sizeof(SERVICE_STATUS_PROCESS), &dwBytesNeeded ) ) { return GetLastError(); } if ( ssp.dwCurrentState == SERVICE_STOPPED ) { return ERROR_SUCCESS; } if ( GetTickCount() - dwStartTime > dwTimeout ) { return ERROR_TIMEOUT; } } // if ( fStopDependencies ) { DWORD i; DWORD dwBytesNeeded; DWORD dwCount; LPENUM_SERVICE_STATUS lpDependencies = NULL; ENUM_SERVICE_STATUS ess; SC_HANDLE hDepService; // 0 buf, buf // EnumDependentServices , if ( !EnumDependentServices( hService, SERVICE_ACTIVE, lpDependencies, 0, &dwBytesNeeded, &dwCount ) ) { if ( GetLastError() != ERROR_MORE_DATA ) return GetLastError(); // Unexpected error // lpDependencies = (LPENUM_SERVICE_STATUS) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBytesNeeded ); if ( !lpDependencies ) return GetLastError(); __try { // if ( !EnumDependentServices( hService, SERVICE_ACTIVE, lpDependencies, dwBytesNeeded, &dwBytesNeeded, &dwCount ) ) return GetLastError(); for ( i = 0; i < dwCount; i++ ) { ess = *(lpDependencies + i); // hDepService = OpenService( hSCM, ess.lpServiceName, SERVICE_STOP | SERVICE_QUERY_STATUS ); if ( !hDepService ) return GetLastError(); __try { // if ( !ControlService( hDepService, SERVICE_CONTROL_STOP, &ss ) ) return GetLastError(); // while ( ss.dwCurrentState != SERVICE_STOPPED ) { Sleep( ss.dwWaitHint ); if ( !QueryServiceStatusEx( hDepService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, sizeof(SERVICE_STATUS_PROCESS), &dwBytesNeeded ) ) return GetLastError(); if ( ss.dwCurrentState == SERVICE_STOPPED ) break; if ( GetTickCount() - dwStartTime > dwTimeout ) return ERROR_TIMEOUT; } } __finally { // CloseServiceHandle( hDepService ); } } } __finally { // HeapFree( GetProcessHeap(), 0, lpDependencies ); } } } // , if ( !ControlService( hService, SERVICE_CONTROL_STOP, &ss ) ) return GetLastError(); while ( ss.dwCurrentState != SERVICE_STOPPED ) { Sleep( ss.dwWaitHint ); if ( !QueryServiceStatusEx( hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, sizeof(SERVICE_STATUS_PROCESS), &dwBytesNeeded ) ) return GetLastError(); if ( ss.dwCurrentState == SERVICE_STOPPED ) break; if ( GetTickCount() - dwStartTime > dwTimeout ) return ERROR_TIMEOUT; } return ERROR_SUCCESS; } /************************************* * BOOL ControlSampleService(DWORD fdwControl) * * * DWORD fdwControl * SCM , **************************************/ BOOL ControlSampleService(DWORD fdwControl) { SERVICE_STATUS ssStatus; DWORD fdwAccess; DWORD dwStartTickCount, dwWaitTime; // Access switch (fdwControl) { case SERVICE_CONTROL_STOP: fdwAccess = SERVICE_STOP; break; case SERVICE_CONTROL_PAUSE: case SERVICE_CONTROL_CONTINUE: fdwAccess = SERVICE_PAUSE_CONTINUE; break; case SERVICE_CONTROL_INTERROGATE: fdwAccess = SERVICE_INTERROGATE; break; default: fdwAccess = SERVICE_INTERROGATE; } // schService = OpenService( schSCManager, // SCManager szServiceName, // fdwAccess); // if (schService == NULL) { printf("OpenService failed (%d)
", GetLastError()); return FALSE; } // if (! ControlService( schService, // fdwControl, // &ssStatus) ) // { printf("ControlService failed (%d)
", GetLastError()); return FALSE; } // printf("
Status of Sample_Srv:
"); printf(" Service Type: 0x%x
", ssStatus.dwServiceType); printf(" Current State: 0x%x
", ssStatus.dwCurrentState); printf(" Controls Accepted: 0x%x
", ssStatus.dwControlsAccepted); printf(" Exit Code: %d
", ssStatus.dwWin32ExitCode); printf(" Service Specific Exit Code: %d
", ssStatus.dwServiceSpecificExitCode); printf(" Check Point: %d
", ssStatus.dwCheckPoint); printf(" Wait Hint: %d
", ssStatus.dwWaitHint); return TRUE; }