URL から "-MoIyadayo" を削除してトラックバックを送信してください。
トラックバックは承認後に表示されます。
このメモは, http://finn.mobilixnet.dk/delphi/service/service.htm にあった英文解説書の翻訳(ともいえぬが)である。
メニューから,ファイル/新規作成/その他を実行。新規作成ダイアログからサービス アプリケーションを選択してOKをクリック。
ServiceApp.exe /install ServiceApp.exe /uninstall
プロンプトを表示させないようにするには/silentスイッチもつける。
サービスが開始状態のままだと再コンパイルなどはできないので,修正するときはサービスを止める。アンインストールまではする必要はない。ただし,Nameプロパティ,DisplayNameプロパティを変更するときはアンインストールする必要がある。
基本的にはサービスのコードを記述する場所は2カ所ある。OnExecuteまたはOnStartイベントである。
TService.OnExecuteメソッドにコードを書く。必要ならスレッドを生成するコードを書くことも可能。
ヘルプでOnExecuteを引くと,
OnExecute イベントは,サービスに関連付けられたスレッドが起動したときに発生します。
Occurs when the thread associated with the service starts up.~
新しいスレッドを生成して,OnStart イベントハンドラで個々のサービス要求を処理しているのではない場合,OnExecute イベントがサービスを実現する場所です。OnExecute イベントハンドラが完了すると,サービススレッドは終了します。ほとんどの OnExecute イベントハンドラは,サービススレッドの ProcessRequests メソッドを呼び出すループを保持しているので,他のサービス要求はロックアウトされません。
If you are not spawning a new thread to handle individual service requests in an OnStart event handler, this is where you implement the service. When the OnExecute event handler finishes, the service thread terminates. Most OnExecute event handlers contain a loop that calls the service thread’s ProcessRequests method so that other service requests are not locked out.
実行するべきコードを書いたスレッド(TThread)を作って,このOnStartでスレッドをスタートさせる。
ヘルプでOnExecuteを引くと,
OnStartup イベントは,OnExecute イベントの前にサービスが初めて起動するときに発
生します。
OnStartup occurs when the service first starts up, before the OnExecute event.~
このイベントは,サービスを初期化するために使用します。たとえば,個別のスレッドで各サービス要求を処理する場合(要求の処理に時間がかかる場合 によい方法である),OnStart イベントハンドラで要求に対するスレッドが生成されます。サービスを起動した場合,Started を True に設定します。
This event should be used to initialize the service. For example, if each service request is handled in a separate thread (a good idea if handling the request takes much time) the thread for a request is spawned in an OnStart event handler.
どちらのメソッドを使うかはあなた次第。両方ともちゃんと動く。
次は双方のメソッドのサンプル
procedure TCompanySqlDatabaseSpecialSomething.ServiceExecute( Sender: TService); const SecBetweenRuns = 10; var Count: Integer; begin Count := 0; while not Terminated do begin Inc(Count); if Count >= SecBetweenRuns then begin Count := 0; { place your service code here } { this is where the action happens } SomeProcedureInAnotherUnit; end; Sleep(1000); ServiceThread.ProcessRequests(False); end; end;
シャットダウンとかコンパネのサービスからサービスが停止されるまで,ループを回す。この例では SomeProcedureInAnotherUnitは10秒ごとにコールされます。10秒待つのにSleep(10000)を使用しないのに注意する こと。そのやり方だとSCM(Service Control Manager)から送られたコマンドに素早く反応することができない。ここでは,その代わりに1秒だけスリープさせて SomeProcedureInAnotherUnitを最後にコールしてから何秒たったかをカウントしている。
OnExecuteイベントのかわりに,何らかの初期化をするならOnStartを使ってもよい。そうすると,初期化中になにか必要な設定がかけているのがてサービスをスタートしたくないときにStarted変数をfalseにセットすることができる。
はじめに,サービスの行う全てのコードを配置する二次的スレッドのクラスを定義する必要がある。
スレッドを作成するとき,通常はスレッドクラスを作る。ファイル/新規作成/その他からスレッドオブジェクトを選択して作成できる。
スレッドに関する経験があまりない場合は,サービス・アプリケーションについて続ける前に,スレッドに関する実用的な知識を得る必要がある。
Delphiでのスレッドプログラミングに関するチュートリアル
http://www.pergolesi.demon.co.uk/prog/threads/ToC.html
http://www.sklobovsky.com/community/index.html
http://sklobovsky.nstemp.com/community/threadmare/threadmare.htm
http://sklobovsky.nstemp.com/community/threadmare/perks.htm
http://sklobovsky.nstemp.com/community/threadmare/fixes.htm
TThread物でどう例外を扱うか--Borland Developer Support Staff:
http://community.borland.com/article/0,1410,10452,00.html
TMyServiceThread と呼ぶTThreadを作る方法を言おう。このスレッドはExecuteメソッドが終わると自動的にそれ自体を解放するように作られていなければならな い。これは簡単で,単にFreeOnTerminateプロパティをTrueにするだけ。
TServiceのPrivateセクションにスレッド変数を次のように定義する。
private { Private declarations } MyServiceThread: TMyServiceThread;
OnStartとOnStopイベントに次のように記述する
procedure TCompanySqlDatabaseSpecialSomething.ServiceStart( Sender: TService; var Started: Boolean); begin { Create an instance of the secondary thread where your service code is placed } MyServiceThread := TMyServiceThread.Create; { Set misc. properties you need (if any) in your thread } //MyServiceThread.Property1 := whatever; // and so on MyServiceThread.Resume; end; procedure TCompanySqlDatabaseSpecialSomething.ServiceStop(Sender: TService; var Stopped: Boolean); begin MyServiceThread.Terminate; end;
二次的なスレッドがOnStartで生成されて開始される。スレッドは止まれという通知を受け取るまで走り続ける。スレッドはサービスのOnStopイベントでスレッドのTerminateメソッドをコールすることで停止する。
Terminate メソッドをコールすることがそのスレッドを停止することとは限らないことに注意すること。Terminateメソッドをコールすること は,TerminatedプロパティをTrueにセットするだけで,スレッドが停止すべきかを見るために短い間隔でこれをチェックするのはスレッド次第で ある。そして,スレッドは単にスレッドのExecuteメソッドを出る時に停止する。
スレッドの非常に簡単な例
interface uses Windows, Messages, SysUtils, Classes, Graphics; type TMyServiceThread = class(TThread) private { Private declarations } protected procedure Execute; override; public constructor Create; end; implementation { Important: Methods and properties of objects in visual components can only be used in a method called using Synchronize, for example, Synchronize(UpdateCaption); and UpdateCaption could look like, procedure TMyServiceThread.UpdateCaption; begin Form1.Caption := 'Updated in a thread'; end; } { TMyServiceThread } constructor TMyServiceThread.Create; // Create the thread Suspended so that properties can be set before resuming the thread. begin FreeOnTerminate := True; inherited Create(True); end; procedure TMyServiceThread.Execute; const SecBetweenRuns = 10; var Count: Integer; begin { Place thread code here } while not Terminated do // loop around until we should stop begin Inc(Count); if Count >= SecBetweenRuns then begin Count := 0; { place your service code here } { this is where the action happens } SomeProcedureInAnotherUnit; end; Sleep(1000); end; end; end.
type TCompanySqlDatabaseSpecialSomething = class(TService) procedure ServiceStart(Sender: TService; var Started: Boolean); procedure ServiceStop(Sender: TService; var Stopped: Boolean); procedure ServiceShutdown(Sender: TService); private { Private declarations } MyServiceThread: TMyServiceThread; procedure ServiceStopShutdown; public function GetServiceController: TServiceController; override; { Public declarations } end; procedure TCompanySqlDatabaseSpecialSomething.ServiceStart(Sender: TService; var Started: Boolean); begin // Allocate resources here that you need when the service is running { Create an instance of the secondary thread where your service code is placed } MyServiceThread := TMyServiceThread.Create; { Set misc. properties you need (if any) in your thread } //MyServiceThread.Property1 := whatever; // and so on MyServiceThread.Resume; end; procedure TCompanySqlDatabaseSpecialSomething.ServiceStop(Sender: TService; var Stopped: Boolean); begin ServiceStopShutdown; end; procedure TCompanySqlDatabaseSpecialSomething.ServiceShutdown( Sender: TService); begin ServiceStopShutdown; end; procedure TCompanySqlDatabaseSpecialSomething.ServiceStopShutdown; begin // Deallocate resources here if Assigned(MyServiceThread) then begin // The TService must WaitFor the thread to finish (and free it) // otherwise the thread is simply killed when the TService ends. MyServiceThread.Terminate; MyServiceThread.WaitFor; FreeAndNil(MyServiceThread); end; end;