visual c++に基づくwindowsコアプログラミングコード分析(9)Windowsサービスとインストール、制御を実現
私たちが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;
}