サービスを再起動させてみます。唐突ですが、そういう必要が生じたので。
Visual Studio 2008 にて、C++ の Win32 コンソール アプリケーションです。PSDK API を使うので、C++。
説明するのが面倒なので、さくっと行きます。
サービスを制御するには、まず、サービス マネージャにアクセスします。このとき、いくつかの特権が必要です。今回は、考えないことにします。
「再起動」すなわち、「停止してから起動」というコマンドは、無いようです。そこで、「停止する」というコマンドと、「起動する」というコマンドを発行します。
コマンドを発行するには、OpenService 関数で、サービスのハンドラを捕まえ、ControlService 関数を使用します。起動は、StartService 関数です。
サービスは、Windows Service を作成したことがある方ならおわかりだと思いますが、起動指示から30秒以内に起動状態にならなければなりません。逆に言うと、起動を指示したからといってすぐに起動するわけではありません。停止も同じ。よって、停止を指示してから、完全に停止するまで待つ必要があります。また、起動も同じく、完全に起動するまで待ちます。待っている間、QueryServiceStatus 関数で現在のステータスを取ります。
サービス マネージャにアクセスする。
指定のサービスにアクセスする。
停止信号を送る。
停止するまで待つ。
状態を見る。
SERVICE_STOPPED でなければ1秒待つ。
SERVICE_STOPPED なら戻る。
累積で30秒待っていれば、タイムアウトとする。
そうでなければ繰り返す。
起動する。
起動するまで待つ。
状態を見る。
SERVICE_RUNNING でなければ1秒待つ。
SERVICE_RUNNING なら戻る。
累積で30秒待っていれば、タイムアウトとする。
そうでなければ繰り返す。
そんなこんなで、次のようなコード。タイトルにカッコがついているのは、これで終われないから。
このコードでは、破棄しなければならないリソースを確保したら、次の関数を呼び出す様にしました。これにより、リソースを使うところ=次の関数内では、何らかのエラーが発生したら遠慮なしに return することができます。なぜこんな作りにしてあるかというと、本当は .c なコードで使っているから(涙)
で、こいつを元に、「C++(あるいはオブジェクト指向言語)って、C に比べてこんな利点があるんだよ。」ってことが説明できるかな、と。。。セッション資料作った方が面白いような気もしてきた。
// RestartService.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//
#include "stdafx.h"
#include
DWORD RestartService(LPCTSTR serviceName);
DWORD StopThenStartService(SC_HANDLE manager, LPCTSTR serviceName);
DWORD StopServiceWithWaiting(SC_HANDLE service);
DWORD StartServiceWithWaiting(SC_HANDLE service);
DWORD WaitServiceUntilStatus(SC_HANDLE service, DWORD state, int timeout = 30);
int _tmain(int argc, _TCHAR* argv[])
{
_tsetlocale(LC_ALL, _T("japanese_japan"));
if (argc < 2) {
_putts(_T("引数で、サービス名を指定してください。\n"));
return ERROR_BAD_ARGUMENTS;
} else {
_tprintf(_T("サービス \"%s\" の起動・停止結果 : %d\n")
, argv[1]
,RestartService(argv[1]));
}
return 0;
}
// 指定されたサービスを再起動する。
// serviceName : サービス名
DWORD RestartService(LPCTSTR serviceName)
{
if (serviceName == NULL) { return ERROR_BAD_ARGUMENTS; }
SC_HANDLE manager;
manager = OpenSCManager(NULL /* ローカル コンピュータ */
, NULL /* 規定のマネージャ */
, SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE | GENERIC_EXECUTE
);
if (manager != NULL) {
DWORD result;
result = StopThenStartService(manager, serviceName);
(void) CloseServiceHandle(manager);
return result;
} else {
return GetLastError();
}
}
// 指定されたサービスを停止させ、起動する。
// manager : サービス マネージャ
// serviceName : サービス名
DWORD StopThenStartService(SC_HANDLE manager, LPCTSTR serviceName)
{
if (manager == NULL || serviceName == NULL) { return ERROR_BAD_ARGUMENTS; }
SC_HANDLE service;
service = OpenService(manager, serviceName, GENERIC_EXECUTE | GENERIC_READ);
if (service != NULL) {
DWORD result;
// サービスを停止する
if ((result = StopServiceWithWaiting(service)) == ERROR_SUCCESS) {
// サービスを起動する
result = StartServiceWithWaiting(service);
}
(void) CloseServiceHandle(service);
return result;
} else {
return GetLastError();
}
}
// 指定のサービスを停止させ、停止するまで待つ。
// service : サービスのハンドラ
DWORD StopServiceWithWaiting(SC_HANDLE service)
{
if (service == NULL) { return ERROR_BAD_ARGUMENTS; }
SERVICE_STATUS status;
BOOL ret = ControlService(service, SERVICE_CONTROL_STOP, &status);
DWORD result = GetLastError();
if (ret == TRUE || result == ERROR_SERVICE_NOT_ACTIVE) {
result = WaitServiceUntilStatus(service, SERVICE_STOPPED);
}
return result;
}
// 指定のサービスを起動させ、起動するまで待つ。
// service : サービスのハンドラ
DWORD StartServiceWithWaiting(SC_HANDLE service)
{
if (service == NULL) { return ERROR_BAD_ARGUMENTS; }
BOOL ret = StartService(service, 0, NULL);
DWORD result = GetLastError();
if (ret == TRUE || result == ERROR_SERVICE_ALREADY_RUNNING) {
result = WaitServiceUntilStatus(service, SERVICE_RUNNING);
}
return result;
}
// サービスが、指定の状態になるまで待つ。
// service : サービスのハンドラ
// state : 期待する状態
// timeout : 期待する状態になるまで待機する秒数(既定値 30)
DWORD WaitServiceUntilStatus(SC_HANDLE service, DWORD state, int timeout)
{
DWORD result;
SERVICE_STATUS status;
int count = 0;
while (TRUE) {
if (QueryServiceStatus(service, &status)) {
if (status.dwCurrentState == state) {
result = ERROR_SUCCESS;
break;
}
if (++count > timeout) {
result = ERROR_SERVICE_REQUEST_TIMEOUT;
break;
}
} else {
result = GetLastError();
break;
}
Sleep(1000);
}
return result;
}
投稿日時 : 2008年8月29日 22:55