C ++からWindowsサービスにコマンドを送信するにはどうすればよいですか?同等の.NETコードは次のとおりです。
ServiceController sc = new ServiceController("MyService");
sc.ExecuteCommand(255);
C ++からWindowsサービスにコマンドを送信するにはどうすればよいですか?同等の.NETコードは次のとおりです。
ServiceController sc = new ServiceController("MyService");
sc.ExecuteCommand(255);
ネイティブ C++ から、次のことを行う必要があります。
たとえば、次のコードは時刻同期サービスを再起動します。まず、サービス ハンドルのラッパー クラスを作成し、ブロックを離れるときに自動的に閉じるようにします。
class CSC_HANDLE
{
public:
CSC_HANDLE(SC_HANDLE h) : m_h(h) { }
~CSC_HANDLE() { ::CloseServiceHandle(m_h); }
operator SC_HANDLE () { return m_h; }
private:
SC_HANDLE m_h;
};
次に、サービス コントロール マネージャー ( OpenSCManager()を使用) と、制御するサービスを開きます。OpenService()の dwDesiredAccess パラメータには、送信する各コントロールのアクセス許可を含める必要があります。そうしないと、関連するコントロール機能が失敗します。
BOOL RestartTimeService()
{
CSC_HANDLE hSCM(::OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, GENERIC_READ));
if (NULL == hSCM) return FALSE;
CSC_HANDLE hW32Time(::OpenService(hSCM, L"W32Time", SERVICE_START | SERVICE_STOP | SERVICE_QUERY_STATUS));
if (NULL == hW32Time) return FALSE;
サービスを停止するには、ControlService()を使用して SERVICE_CONTROL_STOP コードを送信し、戻り値をチェックしてコマンドが成功したことを確認します。ERROR_SERVICE_NOT_ACTIVE 以外のエラーが報告された場合、サービスの開始は成功しないと思います。
SERVICE_STATUS ss = { 0 };
::SetLastError(0);
BOOL success = ::ControlService(hW32Time, SERVICE_CONTROL_STOP, &ss);
if (!success)
{
DWORD le = ::GetLastError();
switch (le)
{
case ERROR_ACCESS_DENIED:
case ERROR_DEPENDENT_SERVICES_RUNNING:
case ERROR_INVALID_HANDLE:
case ERROR_INVALID_PARAMETER:
case ERROR_INVALID_SERVICE_CONTROL:
case ERROR_SERVICE_CANNOT_ACCEPT_CTRL:
case ERROR_SERVICE_REQUEST_TIMEOUT:
case ERROR_SHUTDOWN_IN_PROGRESS:
return FALSE;
case ERROR_SERVICE_NOT_ACTIVE:
default:
break;
}
}
サービスの停止を指示した後、サービス マネージャーが実際にサービスを停止したことを報告するのを待ちます。このコードには潜在的なバグが 2 つあります。製品コード用に修正することをお勧めします。
GetTickCount ()から返された DWORD は最終的にゼロに戻ります。この関数が待機している間にラップアラウンドすると、意図したよりも早く待機が放棄される可能性があります。
DWORD waitstart(::GetTickCount());
while (true)
{
ZeroMemory(&ss, sizeof(ss));
::QueryServiceStatus(hW32Time, &ss);
if (SERVICE_STOPPED == ss.dwCurrentState) break;
::Sleep(1000);
DWORD tick(::GetTickCount());
if ((tick < waitstart) || (tick > (waitstart + 30000))) return FALSE;
}
最後に、サービスが停止状態にあることがわかっているので、StartService()を呼び出して再度実行します。
success = ::StartService(hW32Time, 0, NULL);
if (!success) return FALSE;
return TRUE;
}
ControlServiceを使用します。 Service Control Requestsを参照してください。