ServiceBase クラス
アセンブリ: System.ServiceProcess (system.serviceprocess.dll 内)


サービス アプリケーションでサービス クラスを定義するときに、ServiceBase から派生します。すべての有効なサービスが、OnStart メソッドと OnStop メソッドをオーバーライドします。追加の機能については、サービス状態の変更に応じた特定の動作で OnPause と OnContinue をオーバーライドできます。
サービスは、ユーザー インターフェイスをサポートしない、長期間実行できる実行可能ファイルです。ログオンしたユーザー アカウントによってはサービスを実行できない場合があります。コンピュータにログオンしているユーザーがいない場合でも、サービスを実行できます。
既定では、サービスはシステム アカウントで実行されます。このシステム アカウントは、管理者アカウントとは異なります。システム アカウントの権限は変更できません。ただし、ServiceProcessInstaller を使用して、サービスを実行するときに使用するユーザー アカウントを指定できます。
実行可能ファイルには、複数のサービスを格納できますが、サービスごとに個別の ServiceInstaller を格納する必要があります。ServiceInstaller インスタンスは、システムにサービスを登録します。また、インストーラは、各サービスをサービス コマンドを記録するために使用できるイベント ログに関連付けます。実行可能ファイルの main() 関数は、実行するサービスを定義します。サービスの現在の作業ディレクトリは、実行可能ファイルが置かれているディレクトリではなくシステム ディレクトリです。
サービスを開始すると、実行可能ファイルが検索され、実行可能ファイル内にある該当サービスの OnStart メソッドが実行されます。ただし、実行可能ファイルを実行しても、サービスは実行されません。実行可能ファイルは、サービスを読み込むだけです。サービスには、サービス コントロール マネージャを使用してアクセス (開始、停止など) します。
実行可能ファイルは、サービスで最初に Start を呼び出すときに、ServiceBase 派生クラスのコンストラクタを呼び出します。OnStart コマンド処理メソッドは、コンストラクタが実行された直後に呼び出されます。コンストラクタは、サービスが読み込まれた初回にしか実行されません。このため、コンストラクタで実行される処理と OnStart で実行される処理を区別する必要があります。OnStop によって解放できるリソースは、OnStart で作成する必要があります。OnStop がリソースを解放した後にサービスを再開すると、コンストラクタでリソースを作成しても適切に作成されません。
サービス コントロール マネージャ (SCM: Service Control Manager) を使用すると、サービスを対話形式で利用できます。SCM を使用して、Start、Stop、Pause、Continue の各コマンドまたはカスタム コマンドをサービスに渡すことができます。SCM は CanStop の値および CanPauseAndContinue の値を使用して、サービスが Stop、Pause、または Continue のいずれかのコマンドを受け入れるかどうかを判断します。Stop、Pause、および Continue は、対応するプロパティである CanStop または CanPauseAndContinue がサービス クラスで true である場合に限り、SCM のコンテキスト メニューで有効になります。有効な場合、コマンドはサービスに渡され、OnStop、OnPause、または OnContinue が呼び出されます。CanStop、CanShutdown、または CanPauseAndContinue が false の場合は、対応するコマンド処理メソッド (OnStop など) を実装している場合でも、そのメソッドは処理されません。
ServiceController クラスを使用すると、ユーザー インターフェイスから SCM が実行する処理をプログラムから実行できます。コンソールで実行するタスクを自動化できます。CanStop、CanShutdown、または CanPauseAndContinue が true で、OnStop などの対応するコマンド処理メソッドを実装していない場合、システムは例外をスローし、コマンドを無視します。
OnStart、OnStop、または ServiceBase の他のメソッドを実装する必要はありません。ただし、サービスの動作は OnStart に記述されているため、最低限、このメンバはオーバーライドされる必要があります。実行可能ファイルの main() 関数のサービス名を設定する必要があります。main() で設定したサービス名は、サービス インストーラの ServiceName プロパティと完全に一致する必要があります。
InstallUtil.exe を使用して、システムにサービスをインストールできます。
![]() |
---|
アプリケーション イベント ログ以外のログはサービス呼び出しの通知を受け取るように指定できますが、AutoLog プロパティと EventLog プロパティのいずれもカスタム ログへの書き込みができません。自動的にログを記録しない場合は、AutoLog を false に設定します。 |

簡単なサービス実装を ServiceBase クラスから派生する例を次に示します。このサービスは、Stop、Start、Pause、Continue、カスタム コマンドなどのさまざまなサービス コマンドを処理します。
// Turn on logging to the event log. #define LOGEVENTS using System; using System.IO; using System.Threading; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.ServiceProcess; using System.Text; using Microsoft.Win32; using System.Runtime.InteropServices; using System.Windows.Forms; namespace ServiceSample { // Define custom commands for the SimpleService. public enum SimpleServiceCustomCommands { StopWorker = 128, RestartWorker, CheckWorker }; [StructLayout(LayoutKind.Sequential)] public struct SERVICE_STATUS { public int serviceType; public int currentState; public int controlsAccepted; public int win32ExitCode; public int serviceSpecificExitCode; public int checkPoint; public int waitHint; } public enum State { SERVICE_STOPPED = 0x00000001, SERVICE_START_PENDING = 0x00000002, SERVICE_STOP_PENDING = 0x00000003, SERVICE_RUNNING = 0x00000004, SERVICE_CONTINUE_PENDING = 0x00000005, SERVICE_PAUSE_PENDING = 0x00000006, SERVICE_PAUSED = 0x00000007, } // Define a simple service implementation. public class SimpleService : System.ServiceProcess.ServiceBase { private static int userCount = 0; private static ManualResetEvent pause = new ManualResetEvent(false); [DllImport("ADVAPI32.DLL", EntryPoint = "SetServiceStatus")] public static extern bool SetServiceStatus( IntPtr hServiceStatus, SERVICE_STATUS lpServiceStatus ); private SERVICE_STATUS myServiceStatus; private Thread workerThread = null; public SimpleService() { CanPauseAndContinue = true; CanHandleSessionChangeEvent = true; ServiceName = "SimpleService"; } static void Main() { #if LOGEVENTS EventLog.WriteEntry("SimpleService.Main", DateTime.Now.ToLongTimeString() + " - Service main method starting..."); #endif // Load the service into memory. System.ServiceProcess.ServiceBase.Run(new SimpleService()); #if LOGEVENTS EventLog.WriteEntry("SimpleService.Main", DateTime.Now.ToLongTimeString() + " - Service main method exiting..."); #endif } private void InitializeComponent() { // Initialize the operating properties for the service. this.CanPauseAndContinue = true; this.CanShutdown = true; this.CanHandleSessionChangeEvent = true; this.ServiceName = "SimpleService"; } // Start the service. protected override void OnStart(string[] args) { IntPtr handle = this.ServiceHandle; myServiceStatus.currentState = (int)State.SERVICE_START_PENDING; SetServiceStatus(handle, myServiceStatus); // Start a separate thread that does the actual work. if ((workerThread == null) || ((workerThread.ThreadState & (System.Threading.ThreadState.Unstarted | System.Threading.ThreadState.Stopped)) != 0)) { #if LOGEVENTS EventLog.WriteEntry("SimpleService.OnStart", DateTime.Now.ToLongTimeString() + " - Starting the service worker thread."); #endif workerThread = new Thread(new ThreadStart(ServiceWorkerMethod)); workerThread.Start(); } if (workerThread != null) { #if LOGEVENTS EventLog.WriteEntry("SimpleService.OnStart", DateTime.Now.ToLongTimeString() + " - Worker thread state = " + workerThread.ThreadState.ToString()); #endif } myServiceStatus.currentState = (int)State.SERVICE_RUNNING; SetServiceStatus(handle, myServiceStatus); } // Stop this service. protected override void OnStop() { // New in .NET Framework version 2.0. this.RequestAdditionalTime(4000); // Signal the worker thread to exit. if ((workerThread != null) && (workerThread.IsAlive)) { #if LOGEVENTS EventLog.WriteEntry("SimpleService.OnStop", DateTime.Now.ToLongTimeString() + " - Stopping the service worker thread."); #endif pause.Reset(); Thread.Sleep(5000); workerThread.Abort(); } if (workerThread != null) { #if LOGEVENTS EventLog.WriteEntry("SimpleService.OnStop", DateTime.Now.ToLongTimeString() + " - OnStop Worker thread state = " + workerThread.ThreadState.ToString()); #endif } // Indicate a successful exit. this.ExitCode = 0; } // Pause the service. protected override void OnPause() { // Pause the worker thread. if ((workerThread != null) && (workerThread.IsAlive) && ((workerThread.ThreadState & (System.Threading.ThreadState.Suspended | System.Threading.ThreadState.SuspendRequested)) == 0)) { #if LOGEVENTS EventLog.WriteEntry("SimpleService.OnPause", DateTime.Now.ToLongTimeString() + " - Pausing the service worker thread."); #endif pause.Reset(); Thread.Sleep(5000); } if (workerThread != null) { #if LOGEVENTS EventLog.WriteEntry("SimpleService.OnPause", DateTime.Now.ToLongTimeString() + " OnPause - Worker thread state = " + workerThread.ThreadState.ToString()); #endif } } // Continue a paused service. protected override void OnContinue() { // Signal the worker thread to continue. if ((workerThread != null) && ((workerThread.ThreadState & (System.Threading.ThreadState.Suspended | System.Threading.ThreadState.SuspendRequested)) != 0)) { #if LOGEVENTS EventLog.WriteEntry("SimpleService.OnContinue", DateTime.Now.ToLongTimeString() + " - Resuming the service worker thread."); #endif pause.Set(); } if (workerThread != null) { #if LOGEVENTS EventLog.WriteEntry("SimpleService.OnContinue", DateTime.Now.ToLongTimeString() + " OnContinue - Worker thread state = " + workerThread.ThreadState.ToString()); #endif } } // Handle a custom command. protected override void OnCustomCommand(int command) { #if LOGEVENTS EventLog.WriteEntry("SimpleService.OnCustomCommand", DateTime.Now.ToLongTimeString() + " - Custom command received: " + command.ToString()); #endif // If the custom command is recognized, // signal the worker thread appropriately. switch (command) { case (int)SimpleServiceCustomCommands.StopWorker: // Signal the worker thread to terminate. // For this custom command, the main service // continues to run without a worker thread. OnStop(); break; case (int)SimpleServiceCustomCommands.RestartWorker: // Restart the worker thread if necessary. OnStart(null); break; case (int)SimpleServiceCustomCommands.CheckWorker: #if LOGEVENTS // Log the current worker thread state. EventLog.WriteEntry("SimpleService.OnCustomCommand" , DateTime.Now.ToLongTimeString() + " OnCustomCommand - Worker thread state = " + workerThread.ThreadState.ToString()); #endif break; default: #if LOGEVENTS EventLog.WriteEntry("SimpleService.OnCustomCommand" , DateTime.Now.ToLongTimeString()); #endif break; } } // Handle a session change notice protected override void OnSessionChange(SessionChangeDescription changeDescription) { #if LOGEVENTS EventLog.WriteEntry("SimpleService.OnSessionChange", DateTime.Now.ToLongTimeString() + " - Session change notice received: " + changeDescription.Reason.ToString() + " Session ID: " + changeDescription.SessionId.ToString()); #endif switch (changeDescription.Reason) { case SessionChangeReason.SessionLogon: userCount += 1; #if LOGEVENTS EventLog.WriteEntry("SimpleService.OnSessionChange", DateTime.Now.ToLongTimeString() + " SessionLogon, total users: " + userCount.ToString()); #endif break; case SessionChangeReason.SessionLogoff: userCount -= 1; #if LOGEVENTS EventLog.WriteEntry("SimpleService.OnSessionChange", DateTime.Now.ToLongTimeString() + " SessionLogoff, total users: " + userCount.ToString()); #endif break; case SessionChangeReason.RemoteConnect: userCount += 1; #if LOGEVENTS EventLog.WriteEntry("SimpleService.OnSessionChange", DateTime.Now.ToLongTimeString() + " RemoteConnect, total users: " + userCount.ToString()); #endif break; case SessionChangeReason.RemoteDisconnect: userCount -= 1; #if LOGEVENTS EventLog.WriteEntry("SimpleService.OnSessionChange", DateTime.Now.ToLongTimeString() + " RemoteDisconnect, total users: " + userCount.ToString()); #endif break; case SessionChangeReason.SessionLock: #if LOGEVENTS EventLog.WriteEntry("SimpleService.OnSessionChange", DateTime.Now.ToLongTimeString() + " SessionLock"); #endif break; case SessionChangeReason.SessionUnlock: #if LOGEVENTS EventLog.WriteEntry("SimpleService.OnSessionChange", DateTime.Now.ToLongTimeString() + " SessionUnlock"); #endif break; default: break; } } // Define a simple method that runs as the worker thread for // the service. public void ServiceWorkerMethod() { #if LOGEVENTS EventLog.WriteEntry("SimpleService.WorkerThread", DateTime.Now.ToLongTimeString() + " - Starting the service worker thread."); #endif try { do { // Simulate 4 seconds of work. Thread.Sleep(4000); // Block if the service is paused or is shutting down. pause.WaitOne(); #if LOGEVENTS EventLog.WriteEntry("SimpleService.WorkerThread", DateTime.Now.ToLongTimeString() + " - heartbeat cycle."); #endif } while (true); } catch (ThreadAbortException) { // Another thread has signalled that this worker // thread must terminate. Typically, this occurs when // the main service thread receives a service stop // command. // Write a trace line indicating that the worker thread // is exiting. Notice that this simple thread does // not have any local objects or data to clean up. #if LOGEVENTS EventLog.WriteEntry("SimpleService.WorkerThread", DateTime.Now.ToLongTimeString() + " - Thread abort signaled."); #endif } #if LOGEVENTS EventLog.WriteEntry("SimpleService.WorkerThread", DateTime.Now.ToLongTimeString() + " - Exiting the service worker thread."); #endif } } }
// Turn on the constant for trace output. #define TRACE #using <System.ServiceProcess.dll> #using <System.dll> using namespace System; using namespace System::ComponentModel; using namespace System::IO; using namespace System::ServiceProcess; using namespace System::Threading; using namespace System::Diagnostics; // Define custom commands for the SimpleService. public enum class SimpleServiceCustomCommands { StopWorker = 128, RestartWorker, CheckWorker }; // Define a simple service implementation. public ref class SimpleService: public System::ServiceProcess::ServiceBase { private: Thread^ workerThread; int userCount; public: SimpleService() { CanPauseAndContinue = true; ServiceName = "SimpleService"; workerThread = nullptr; CanHandleSessionChangeEvent = true; } private: void InitializeComponent() { // Initialize the operating properties for the service. this->CanPauseAndContinue = true; this->CanShutdown = true; this->ServiceName = "SimpleService"; this->CanHandleSessionChangeEvent = true; } // Start the service. protected: virtual void OnStart( array<String^>^ ) override { // Start a separate thread that does the actual work. if ( (workerThread == nullptr) || ((workerThread->ThreadState & (System::Threading::ThreadState::Unstarted | System::Threading::ThreadState::Stopped)) != (System::Threading::ThreadState)0) ) { Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Starting the service worker thread.", "OnStart" ); workerThread = gcnew Thread( gcnew ThreadStart( this,&SimpleService::ServiceWorkerMethod ) ); workerThread->Start(); } if ( workerThread != nullptr ) { Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Worker thread state = " + workerThread->ThreadState.ToString(), "OnStart" ); } } // Stop this service. protected: virtual void OnStop() override { // Signal the worker thread to exit. if ( (workerThread != nullptr) && (workerThread->IsAlive) ) { Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Stopping the service worker thread.", "OnStop" ); workerThread->Abort(); // Wait up to 500 milliseconds for the thread to terminate. workerThread->Join( 500 ); } if ( workerThread != nullptr ) { Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Worker thread state = " + workerThread->ThreadState.ToString(), "OnStop" ); } } // Pause the service. protected: virtual void OnPause() override { // Pause the worker thread. if ( (workerThread != nullptr) && (workerThread->IsAlive) && ((workerThread->ThreadState & (System::Threading::ThreadState::Suspended | System::Threading::ThreadState::SuspendRequested)) == (System::Threading::ThreadState)0) ) { Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Suspending the service worker thread.", "OnPause" ); workerThread->Suspend(); } if ( workerThread != nullptr ) { Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Worker thread state = " + workerThread->ThreadState.ToString(), "OnPause" ); } } // Continue a paused service. protected: virtual void OnContinue() override { // Signal the worker thread to continue. if ( (workerThread != nullptr) && ((workerThread->ThreadState & (System::Threading::ThreadState::Suspended | System::Threading::ThreadState::SuspendRequested)) != (System::Threading::ThreadState)0) ) { Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Resuming the service worker thread.", "OnContinue" ); workerThread->Resume(); } if ( workerThread != nullptr ) { Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Worker thread state = " + workerThread->ThreadState.ToString(), "OnContinue" ); } } // Handle a custom command. protected: virtual void OnCustomCommand( int command ) override { Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Custom command received: " + command, "OnCustomCommand" ); // If the custom command is recognized, // signal the worker thread appropriately. switch ( command ) { case (int)SimpleServiceCustomCommands::StopWorker: // Signal the worker thread to terminate. // For this custom command, the main service // continues to run without a worker thread. OnStop(); break; case (int)SimpleServiceCustomCommands::RestartWorker: // Restart the worker thread if necessary. OnStart( nullptr ); break; case (int)SimpleServiceCustomCommands::CheckWorker: // Log the current worker thread state. Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Worker thread state = " + workerThread->ThreadState.ToString(), "OnCustomCommand" ); break; default: Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Unrecognized custom command ignored!", "OnCustomCommand" ); break; } } protected: virtual void OnSessionChange(SessionChangeDescription changeDescription) override { Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Change description received: " + changeDescription.ToString(), "OnSessionChange" ); switch (changeDescription.Reason) { case SessionChangeReason::SessionLogon: userCount += 1; Trace::WriteLine( DateTime::Now.ToLongTimeString() + " SessionLogon, total users: " + userCount.ToString(), "OnSessionChange" ); break; case SessionChangeReason::SessionLogoff: userCount -= 1; Trace::WriteLine( DateTime::Now.ToLongTimeString() + " SessionLogoff, total users: " + userCount.ToString(), "OnSessionChange" ); break; case SessionChangeReason::RemoteConnect: userCount += 1; Trace::WriteLine( DateTime::Now.ToLongTimeString() + " RemoteConnect, total users: " + userCount.ToString(), "OnSessionChange" ); break; case SessionChangeReason::RemoteDisconnect: userCount -= 1; Trace::WriteLine( DateTime::Now.ToLongTimeString() + " RemoteDisconnect, total users: " + userCount.ToString(), "OnSessionChange" ); break; case SessionChangeReason::SessionLock: Trace::WriteLine( DateTime::Now.ToLongTimeString() + " SessionLock", "OnSessionChange" ); break; case SessionChangeReason::SessionUnlock: Trace::WriteLine( DateTime::Now.ToLongTimeString() + " SessionUnlock", "OnSessionChange" ); break; default: Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Unhandled session change event.", "OnSessionChange" ); break; } } // Define a simple method that runs as the worker thread for // the service. public: void ServiceWorkerMethod() { Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Starting the service worker thread.", "Worker" ); try { for ( ; ; ) { // Wake up every 10 seconds and write // a message to the trace output. Thread::Sleep( 10000 ); Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - heartbeat cycle.", "Worker" ); } } catch ( ThreadAbortException^ ) { // Another thread has signalled that this worker // thread must terminate. Typically, this occurs when // the main service thread receives a service stop // command. // Write a trace line indicating that the worker thread // is exiting. Notice that this simple thread does // not have any local objects or data to clean up. Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Thread abort signaled.", "Worker" ); } Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Exiting the service worker thread.", "Worker" ); } }; int main() { String^ logFile = "C:\\service_log.txt"; TextWriterTraceListener^ serviceTraceListener = nullptr; // Create a log file for trace output. // A new file is created each time. If a // previous log file exists, it is overwritten. StreamWriter^ myFile = File::CreateText( logFile ); // Create a new trace listener that writes to the text file, // and add it to the collection of trace listeners. serviceTraceListener = gcnew TextWriterTraceListener( myFile ); Trace::Listeners->Add( serviceTraceListener ); Trace::AutoFlush = true; Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Service main method starting...", "Main" ); // Load the service into memory. System::ServiceProcess::ServiceBase::Run( gcnew SimpleService ); Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Service main method exiting...", "Main" ); // Remove and close the trace listener for this service. Trace::Listeners->Remove( serviceTraceListener ); serviceTraceListener->Close(); serviceTraceListener = nullptr; myFile->Close(); }

System.MarshalByRefObject
System.ComponentModel.Component
System.ServiceProcess.ServiceBase


Windows 98, Windows 2000 SP4, Windows Server 2003, Windows XP Media Center Edition, Windows XP Professional x64 Edition, Windows XP SP2, Windows XP Starter Edition
開発プラットフォームの中には、.NET Framework によってサポートされていないバージョンがあります。サポートされているバージョンについては、「システム要件」を参照してください。


- ServiceBase クラスのページへのリンク