Windowsサービスの作成

概要


 Windows NT/2000/XP系に備わっているWindowsサービスのプロジェクトを作成する方法。



プロジェクト作成


 Visual Studioの「ファイル」メニューの「新規作成」にある「プロジェクト」を選択する。 新しいプロジェクトのウインドウが開いたら「Visual C++」ツリーの「ATL」から「ATLプロジ ェクト」を選択し、プロジェクト名を適当に指定して「OK」ボタンを押す。
 するとATLプロジェクトウイザードが開く。ここで「次へ」ボタンを押し、画面を「アプリケ ーションの設定」に切り替える。そしてサーバーの種類から「サービス(EXE)」を選び、「完了」 ボタンを押す。

※この手順はVisual Studio 2005 Professional Editionのものだが、他のバージョンでも 同様に操作できる。



自動的に作成されたコード


 以上の操作で例えばプロジェクト名が「xxx」の場合は「xxx.cpp」を開くと、次のようなコード が自動的に作成されている。


// xxx.cpp : WinMain の実装


#include "stdafx.h"
#include "resource.h"
#include "xxx.h"

#include 

class CxxxModule : public CAtlServiceModuleT< CxxxModule, IDS_SERVICENAME >
{
public :
	DECLARE_LIBID(LIBID_xxxLib)
	DECLARE_REGISTRY_APPID_RESOURCEID(IDR_XXX, "{8C647C38-27D3-4515-B63A-62E1C648E4B5}")
	HRESULT InitializeSecurity() throw()
	{
		// TODO : CoInitializeSecurity を呼び出し、サービスに適切なセキュリティ設定を 
		// 指定します。
		// 推奨 - PKT レベルの認証、 
		// RPC_C_IMP_LEVEL_IDENTIFY の偽装レベル、 
		// および適切な NULL 以外のセキュリティ記述子。

		return S_OK;
	}
};

CxxxModule _AtlModule;

//
extern "C" int WINAPI _tWinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, 
                                LPTSTR /*lpCmdLine*/, int nShowCmd)
{
    return _AtlModule.WinMain(nShowCmd);
}



コードの追加


 自動的に作成された、上のコードの中で太字で示したクラスに対し実際にコーディングす るための行を追加し、以下のように変更する。
 ここでincludeしているDnpService.hは「Windowsサービスの開始/停止/再起動」 で作成したクラスが定義されているファイルとしている。


// xxx.cpp : WinMain の実装


#include "stdafx.h"
#include "resource.h"
#include "xxx.h"
#include "DnpService.h"

#include 

class CxxxModule : public CAtlServiceModuleT< CxxxModule, IDS_SERVICENAME >
{
public :
	DECLARE_LIBID(LIBID_xxxLib)
	DECLARE_REGISTRY_APPID_RESOURCEID(IDR_XXX, "{8C647C38-27D3-4515-B63A-62E1C648E4B5}")
	HRESULT InitializeSecurity() throw()
	{
		// TODO : CoInitializeSecurity を呼び出し、サービスに適切なセキュリティ設定を 
		// 指定します。
		// 推奨 - PKT レベルの認証、 
		// RPC_C_IMP_LEVEL_IDENTIFY の偽装レベル、 
		// および適切な NULL 以外のセキュリティ記述子。

		return S_OK;
	}


	//
	//	コマンドラインの追加
	//
	//	以下の3つのコマンドラインオプションを追加する。
	//
	//	xxx.exe /Start		: サービス開始
	//	xxx.exe /Stop		:	サービス停止
	//	xxx.exe /Restart	:	サービス再起動
	//
	bool ParseCommandLine(LPCTSTR lpCmdLine, HRESULT* pnRetCode) throw()
	{
		if(!__super::ParseCommandLine(lpCmdLine,pnRetCode))
			return	false;

		bool		ret;
		CString		strName;
		CDnpService	cService;

		TCHAR szTokens[] = _T("-/");
		*pnRetCode = S_OK;

		LPCTSTR lpszToken = FindOneOf(lpCmdLine, szTokens);
		while (lpszToken != NULL)
		{
			if(WordCmpI(lpszToken,_T("Start")) == 0)
			{
				//サービスの開始
				strName.LoadString(IDS_SERVICENAME);
				ret = cService.EasyStart(strName);
				*pnRetCode = ret ? S_OK : E_FAIL;
				return false;
			}
			if(WordCmpI(lpszToken,_T("Stop")) == 0)
			{
				//サービスの停止
				strName.LoadString(IDS_SERVICENAME);
				ret = cService.EasyStop(strName);
				*pnRetCode = ret ? S_OK : E_FAIL;
				return false;
			}
			if(WordCmpI(lpszToken,_T("Restart")) == 0)
			{
				//サービスの再起動
				strName.LoadString(IDS_SERVICENAME);
				ret = cService.EasyRestart(strName);
				*pnRetCode = ret ? S_OK : E_FAIL;
				return false;
			}
			lpszToken = FindOneOf(lpszToken, szTokens);
		}
		return true;
	}



	//
	//	起動時処理
	//
	HRESULT PreMessageLoop(int nShowCmd) throw()
	{
		HRESULT hr = __super::PreMessageLoop(nShowCmd);

		#if _ATL_VER >= 0x0700
			if (SUCCEEDED(hr) && !m_bDelayShutdown)
				hr = CoResumeClassObjects();
		#endif

		if(SUCCEEDED(hr))
		{
			//TODO:起動時処理をコード
		}

		return hr;
	}


	//
	//	終了時処理
	//
	HRESULT PostMessageLoop()
	{
		//TODO:終了時処理をコード
		return __super::PostMessageLoop();
	}


	//
	//	サービス停止処理(SERVICE_CONTROL_STOP)
	//
	void OnStop() throw()
	{
		//TODO:サービス停止処理をコード
		__super::OnStop();
	}

	//
	//	サービス一時停止処理(SERVICE_CONTROL_PAUSE)
	//
	void OnPause() throw()
	{
		//TODO:サービス一時停止処理をコード
		__super::OnPause();
	}

	//
	//	サービス再開処理(SERVICE_CONTROL_CONTINUE)
	//
	void OnContinue() throw()
	{
		//TODO:サービス再開処理をコード
		__super::OnContinue();
	}

	//
	//	サービス問い合わせ処理(SERVICE_CONTROL_INTERROGATE)
	//
	void OnInterrogate() throw()
	{
		//TODO:サービス問い合わせ処理をコード
		__super::OnInterrogate();
	}

	//
	//	サービスシャットダウン処理(SERVICE_CONTROL_SHUTDOWN)
	//
	void OnShutdown() throw()
	{
		//TODO:サービスビスシャットダウン処理をコード
		__super::OnShutdown();
	}

	//
	//	不明なサービス処理
	//
	void OnUnknownRequest(DWORD dwOpcode) throw()
	{
		//TODO:不明なサービス処理をコード
		__super::OnUnknownRequest(dwOpcode);
	}
};

CxxxModule _AtlModule;

//
extern "C" int WINAPI _tWinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, 
                                LPTSTR /*lpCmdLine*/, int nShowCmd)
{
    return _AtlModule.WinMain(nShowCmd);
}

カテゴリー「VC++ TIPS」 のエントリー