わびさびサンプルソース

WindowsやHTML5などのプログラムのサンプルコードやフリーソフトを提供します。

サービス(作成と削除機能付き)

ログを出力するだけの簡単なサービスです。デバッグログは、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)






わびさびサンプルソース

WindowsやHTML5などのプログラムのサンプルコードやフリーソフトを提供します。