ログを出力するだけの簡単なサービスです。デバッグログは、DebugViewで確認することができます。 サービスの登録と削除はscコマンドで行います。サービスの開始、終了、一時停止、再開はコントロールパネルのサービスから行えます。
コマンドラインで/installを指定します。
コマンドラインで/uninstallを指定します。
#include <stdio.h>
#include <tchar.h>
#include <locale.h>
#include <iostream>
#include <windows.h>
/*
デバッグログの出力
*/
void DebugLog
(
LPTSTR szFormat // フォーマット
, ... // パラメータ
)
{
TCHAR waBuf[ 4096 ] = { 0 };
va_list args;
// 可変引数の展開
va_start( args, szFormat );
_vsntprintf_s( waBuf, _countof( waBuf ), szFormat, args );
va_end( args );
// ログの出力
::OutputDebugString( waBuf );
}
// サービス名称
#define SERVICE_NAME L"TestService2"
// サービス表示名
#define SERVICE_DISP_NAME L"Test Service2"
// サービス詳細
#define SERVICE_DESC_NAME L"テストサービス2"
// サービスハンドル
SERVICE_STATUS_HANDLE hServiceStatus = NULL;
// サービス停止中フラグ
BOOL bServiceStop = FALSE;
// 一時停止中フラグ
BOOL bPause = FALSE;
/*
サービスハンドラ
*/
DWORD WINAPI ServiceHandlerProc
(
DWORD dwControl // 制御コード
, DWORD dwEventType // イベントのタイプ
, LPVOID lpEventData // イベントのデータ
, LPVOID lpContext // Context
)
{
SERVICE_STATUS tServiceStatus;
// サービスステータス
tServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
tServiceStatus.dwWin32ExitCode = NO_ERROR;
tServiceStatus.dwServiceSpecificExitCode = 0;
tServiceStatus.dwCheckPoint = 1;
tServiceStatus.dwWaitHint = 3000;
tServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
switch( dwControl ) {
case SERVICE_CONTROL_STOP:
//----------------------------------
// サービスの停止
//----------------------------------
{
DebugLog( L"SERVICE_CONTROL_STOP¥r¥n" );
/*
サービスのステータス更新(停止保留中)
*/
tServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
if ( 0 == ::SetServiceStatus ( hServiceStatus, &tServiceStatus ) ) {
// エラー
DebugLog( L"SetServiceStatus err = 0x%08x¥r¥n", ::HRESULT_FROM_WIN32( ::GetLastError() ) );
break;
}
DebugLog ( L"SERVICE_STOP_PENDING¥n" );
// SERVICE SPECIFIC STOPPING CODE HERE.
bServiceStop = TRUE;
// 停止待ち
Sleep (3 * 1000);
/*
サービスのステータス更新(停止)
*/
tServiceStatus.dwCurrentState = SERVICE_STOPPED;
tServiceStatus.dwCheckPoint = 0;
tServiceStatus.dwWaitHint = 0;
tServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
if ( 0 == ::SetServiceStatus( hServiceStatus, &tServiceStatus ) ) {
// エラー
DebugLog( L"SetServiceStatus err = 0x%08x¥r¥n", ::HRESULT_FROM_WIN32( ::GetLastError() ) );
break;
}
DebugLog ( L"SERVICE_STOPPED¥n" );
}
break;
case SERVICE_CONTROL_PAUSE:
//----------------------------------
// サービスの一時停止
//----------------------------------
{
DebugLog (TEXT("SERVICE_CONTROL_PAUSE¥n"));
/*
サービスのステータス更新(一時停止保留中)
*/
tServiceStatus.dwCurrentState = SERVICE_PAUSE_PENDING;
if ( 0 == SetServiceStatus( hServiceStatus, &tServiceStatus ) ) {
// エラー
DebugLog( L"SetServiceStatus err = 0x%08x¥r¥n", ::HRESULT_FROM_WIN32( ::GetLastError() ) );
break;
}
DebugLog ( L"SERVICE_PAUSE_PENDING¥n" );
// 一時停止中
bPause = TRUE;
/*
サービスのステータス更新(一時停止)
*/
tServiceStatus.dwCurrentState = SERVICE_PAUSED;
tServiceStatus.dwCheckPoint = 0;
tServiceStatus.dwWaitHint = 0;
tServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;
if ( 0 == SetServiceStatus( hServiceStatus, &tServiceStatus ) ) {
// エラー
DebugLog( L"SetServiceStatus err = 0x%08x¥r¥n", ::HRESULT_FROM_WIN32( ::GetLastError() ) );
break;
}
DebugLog ( L"SERVICE_PAUSED¥n" );
}
break;
case SERVICE_CONTROL_CONTINUE:
//----------------------------------
// サービスの再開
//----------------------------------
{
DebugLog ( L"SERVICE_CONTROL_CONTINUE¥n" );
/*
サービスのステータス更新(再開保留中)
*/
tServiceStatus.dwCurrentState = SERVICE_START_PENDING;
if ( 0 == ::SetServiceStatus( hServiceStatus, &tServiceStatus ) ) {
// エラー
DebugLog( L"SetServiceStatus err = 0x%08x¥r¥n", ::HRESULT_FROM_WIN32( ::GetLastError() ) );
break;
}
DebugLog ( L"SERVICE_START_PENDING¥n" );
// 実行中
bPause = FALSE;
/*
サービスのステータス更新(再開保留中)
*/
// Set RUNNING status.
tServiceStatus.dwCurrentState = SERVICE_RUNNING;
tServiceStatus.dwCheckPoint = 0;
tServiceStatus.dwWaitHint = 0;
tServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;
if ( 0 == ::SetServiceStatus( hServiceStatus, &tServiceStatus ) ) {
// エラー
DebugLog( L"SetServiceStatus err = 0x%08x¥r¥n", ::HRESULT_FROM_WIN32( ::GetLastError() ) );
break;
}
DebugLog ( L"SERVICE_RUNNING¥n" );
}
break;
default:
return ERROR_CALL_NOT_IMPLEMENTED;
}
return NO_ERROR;
}
/*
サービスメイン
*/
VOID WINAPI ServiceMain
(
DWORD dwArgc
, PTSTR* pszArgv
)
{
DebugLog ( L"SERVICE(START)¥n" );
// サービスハンドラの登録
hServiceStatus = ::RegisterServiceCtrlHandlerEx(
SERVICE_NAME // サービス名称
, ServiceHandlerProc // サービスハンドラ
, NULL // Context
);
if ( NULL == hServiceStatus ) {
// エラー
DebugLog( L"RegisterServiceCtrlHandlerEx err = 0x%08x¥r¥n", ::HRESULT_FROM_WIN32( ::GetLastError() ) );
return;
}
SERVICE_STATUS tServiceStatus;
// サービス状態
tServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
tServiceStatus.dwWin32ExitCode = NO_ERROR;
tServiceStatus.dwServiceSpecificExitCode = 0;
/*
サービスのステータス更新(開始保留中)
*/
tServiceStatus.dwCurrentState = SERVICE_START_PENDING;
tServiceStatus.dwCheckPoint = 1;
tServiceStatus.dwWaitHint = 1000;
tServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
if ( 0 == ::SetServiceStatus ( hServiceStatus, &tServiceStatus ) ) {
// エラー
DebugLog( L"SetServiceStatus err = 0x%08x¥r¥n", ::HRESULT_FROM_WIN32( ::GetLastError() ) );
return;
}
DebugLog ( L"SERVICE_START_PENDING¥n" );
/*
サービスのステータス更新(開始)
*/
tServiceStatus.dwCurrentState = SERVICE_RUNNING;
tServiceStatus.dwCheckPoint = 0;
tServiceStatus.dwWaitHint = 0;
tServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;
if ( 0 == ::SetServiceStatus ( hServiceStatus, &tServiceStatus ) ) {
// エラー
DebugLog( L"SetServiceStatus err = 0x%08x¥r¥n", ::HRESULT_FROM_WIN32( ::GetLastError() ) );
return;
}
DebugLog ( L"SERVICE_RUNNING¥n" );
/*
サービスメイン処理
*/
while( !bServiceStop ) {
// 一時停止中じゃ無ければ実行
if( !bPause ) {
// RUNの最中だけ実行
::OutputDebugString( L"SERVICE(RUN)" );
}
::Sleep( 1000 );
}
DebugLog ( L"SERVICE(END)¥n" );
}
/*
サービスのインストール
*/
int InstallService
(
)
{
// 処理結果
int nRet = 0;
// サービスデータベースハンドル
SC_HANDLE hSvcDB = NULL;
// サービスハンドル
SC_HANDLE hService = NULL;
/*
サービス制御マネージャのデータベースを開く
*/
hSvcDB = ::OpenSCManager( NULL, NULL, SC_MANAGER_CREATE_SERVICE );
if ( NULL ) {
// エラー
wprintf( L"OpenSCManager err = 0x%08x", ::HRESULT_FROM_WIN32( ::GetLastError() ) );
nRet = -1;
goto err;
}
// 実行ファイルパスの取得
TCHAR waExePath[ MAX_PATH ];
::GetModuleFileName( NULL, waExePath, _countof( waExePath ) );
/*
サービスの作成
*/
hService = ::CreateService(
hSvcDB // サービスデータベースハンドル
, SERVICE_NAME // サービス名
, SERVICE_DISP_NAME // 表示名
, SERVICE_CHANGE_CONFIG // サービスの構成を変更できるようにする
, SERVICE_WIN32_OWN_PROCESS // サービスアプリケーションが専用のプロセス内で動作
, SERVICE_DEMAND_START // StartService関数が呼び出されたときに、サービスが開始される
, SERVICE_ERROR_IGNORE // エラー発生時に、サービス開始操作を続行する
, waExePath // サービスアプリケーションの実行ファイルパス
, NULL
, NULL
, NULL
, NULL
, NULL
);
if ( NULL == hService ) {
// エラー
wprintf( L"CreateService err = 0x%08x", ::HRESULT_FROM_WIN32( ::GetLastError() ) );
nRet = -1;
goto err;
}
SERVICE_DESCRIPTION tServiceDescription;
// サービス詳細
tServiceDescription.lpDescription = SERVICE_DESC_NAME;
// サービスのオプション構成パラメータ変更
if ( 0 == ::ChangeServiceConfig2( hService, SERVICE_CONFIG_DESCRIPTION, &tServiceDescription ) ) {
// エラー
wprintf( L"ChangeServiceConfig2 err = 0x%08x", ::HRESULT_FROM_WIN32( ::GetLastError() ) );
nRet = -1;
goto err;
}
// インストール成功
std::wcout << L"Service Installed" << std::endl;
err:
// サービスクローズ
if ( NULL != hService ) {
::CloseServiceHandle( hService );
}
// データベースクローズ
if ( NULL != hSvcDB ) {
::CloseServiceHandle( hSvcDB );
}
// 処理結果
return( nRet );
}
/*
サービスのアンインストール
*/
int UninstallService
(
)
{
// 処理結果
int nRet = 0;
// サービスデータベースハンドル
SC_HANDLE hSvcDB = NULL;
// サービスハンドル
SC_HANDLE hService = NULL;
/*
サービス制御マネージャのデータベースを開く
*/
hSvcDB = ::OpenSCManager( NULL, NULL, SC_MANAGER_CONNECT );
if ( NULL ) {
// エラー
wprintf( L"OpenSCManager err = 0x%08x", ::HRESULT_FROM_WIN32( ::GetLastError() ) );
nRet = -1;
goto err;
}
// サービスのオープン
hService = ::OpenService( hSvcDB, SERVICE_NAME, DELETE );
if ( NULL == hService ) {
// エラー
wprintf( L"OpenService err = 0x%08x", ::HRESULT_FROM_WIN32( ::GetLastError() ) );
nRet = -1;
goto err;
}
// サービスの削除
if ( 0 == ::DeleteService( hService ) ) {
// エラー
wprintf( L"DeleteService err = 0x%08x", ::HRESULT_FROM_WIN32( ::GetLastError() ) );
nRet = -1;
goto err;
}
// アンインストール成功
std::wcout << L"Service Uninstalled" << std::endl;
err:
// サービスクローズ
if ( NULL != hService ) {
::CloseServiceHandle( hService );
}
// データベースクローズ
if ( NULL != hSvcDB ) {
::CloseServiceHandle( hSvcDB );
}
// 処理結果
return( nRet );
}
/*
サービス(登録と削除機能付き)
*/
int _tmain
(
int argc
, _TCHAR* argv[]
)
{
/*
コマンドライン引数チェック
*/
for ( UINT nI = 1; nI < (UINT)__argc; nI++ ) {
// サービスのインストール
if ( 0 == ::_wcsicmp( L"/install", argv[ nI ] ) ) {
return( InstallService() );
}
// サービスのアンインストール
else if ( 0 == ::_wcsicmp( L"/uninstall", argv[ nI ] ) ) {
return( UninstallService() );
}
}
/*
サービステーブル
*/
static SERVICE_TABLE_ENTRY taServiceTable[] = {
{ SERVICE_NAME, ServiceMain }
, { NULL, NULL }
};
/*
サービスプロセスのメインスレッドをサービス制御マネージャに接続し、
そのスレッドを呼び出し側プロセス用のサービス制御ディスパッチャス
レッドにする。
*/
if ( 0 == ::StartServiceCtrlDispatcher( taServiceTable ) ) {
// エラー
DebugLog( L"StartServiceCtrlDispatcher err = 0x%08x¥r¥n", ::HRESULT_FROM_WIN32( ::GetLastError() ) );
return( -1 );
}
// 処理結果を返す
return( 0 );
}
[5592] SERVICE(START) [5592] SERVICE_START_PENDING [5592] SERVICE_RUNNING [5592] SERVICE(RUN) [5592] SERVICE(RUN) [5592] SERVICE(RUN) [5592] SERVICE(RUN) [5592] SERVICE(RUN) [5592] SERVICE(RUN) [5592] SERVICE(RUN) [5592] SERVICE(RUN) [5592] SERVICE_CONTROL_STOP [5592] SERVICE_STOP_PENDING [5592] SERVICE(END) [5592] SERVICE_STOPPED [7600] SERVICE(START) [7600] SERVICE_START_PENDING [7600] SERVICE_RUNNING [7600] SERVICE(RUN) [7600] SERVICE(RUN) [7600] SERVICE(RUN) [7600] SERVICE(RUN) [7600] SERVICE(RUN) [7600] SERVICE_CONTROL_PAUSE [7600] SERVICE_PAUSE_PENDING [7600] SERVICE_PAUSED [7600] SERVICE_CONTROL_CONTINUE [7600] SERVICE_START_PENDING [7600] SERVICE_RUNNING [7600] SERVICE(RUN) [7600] SERVICE(RUN) [7600] SERVICE(RUN) [7600] SERVICE(RUN) [7600] SERVICE(RUN) [7600] SERVICE(RUN) [7600] SERVICE(RUN) [7600] SERVICE_CONTROL_STOP [7600] SERVICE_STOP_PENDING [7600] SERVICE(END)