・スタートアップの種類
最初に書いた コントロールパネル →管理ツール→ サービスからSQL Server 2005 Expressの
サービスの設定のうちスタートアップの種類のコンボボックスをプルダウンしてみると 種類としては「自動」、「手動」、「無効」があることがわかります。自動はPCを起動した際に 自動的にサービスを開始し、手動はユーザがサービスを開始しなければなりません。
無効に設定されていると、この設定を変えない限りサービスは開始できません。
この3つの設定値はSystem.ServiceProcess名前空間内に
ServiceStartMode列挙定数
として定義されています。
オブジェクトブラウザ
で確認してください。
ここには Automatic = 2、 Manual = 3、 Disable = 4の定数が定義されています。 定義されているということはどこかのクラスで使われているはずですからそれを利用したいのですが、 この定数を使っているクラスはServiceInstallerで、今回の処理とはちょっと関係ないので 利用できないです。(やろうと思えばできるかもしれませんが、継承関係がややこしくなるので 今回は使わないです)
サービスのインストール時にServiceInstaller.StartTypeでスタートアップの種類を設定して いますが、どのように設定しているのでしょう?
実はこの設定は
レジストリ
に書き込まれています。レジストリも範囲が広いですが、
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\サービス名
の「Start」
に対応する値がそれにあたります。
早速、レジストリエディタでSQL Serverのサービスを 見てみます。スタート→ファイル名を指定して実行(R)からregedit.exeとタイプして実行します。 上記のパスで探すと以下のような画面があらわれます。
画面右のペインの「Start」に関連した値0x00000003がそれです。
この値はServiceStartModeの列挙体に対応しています。
ということで、スタートアップの種類を取得/変更するにはレジストリのこの値を参照/変更
すればよいことになります。
・VB 2005 での レジストリ処理
VB2005でレジストリを扱うのはVB6以前と異なり容易いです。ちゃんと対応したクラスが Microsoft.Win32名前空間にRegistry、 RegistryKeyとして用意されているのでこれを使います。 オブジェクトブラウザ で確認しておきましょう。
・スタートアップの種類の取得/変更の実装
まずは、Registry、RegistryKeyの2つのクラスを
扱いやすくするため名前空間をインポートします。
System.ServiceController名前空間をインポートした
次の行に以下のように記述します。
Imports System.ServiceProcess 'サービス関係 (この行は既にできています) Imports Microsoft.Win32 'レジストリ |
次にスタートアップの種類の設定値ですが、そのままServiceProcess名前空間のServiceStartModeを
使ってもいいのですが、サービスの状態の変更処理のときと同様に例外処理のために再定義
します。
前に定義したServiceControllerStatus列挙体の次あたりに以下のように定義してください。
'スタートアップの種類 Public Enum ServiceStartMode Automatic = 2 Manual = 3 Disable = 4 None = 0 '例外処理用 End Enum |
それでは中心になるスタートアップの変更/取得の処理をします。サービスの状態の変更のときのように 今回は「動作」というよりは「属性」なのでプロパティとして実装します。 プロパティ名はStartMode、戻値、設定値の型は上記で定義したServiceStartModeにして、 ChangeStatusメソッドの下に記述すると以下のようなスケルトンができます。
'スタートアップの種類の取得/変更
Public Property StartMode() As ServiceStartMode
Get
End Get
Set(ByVal value As ServiceStartMode)
End Set
End Property
|
まずはGet 〜 End Get内に値を取得する記述を以下のようにします。
Get Const SERVICEKEY As String = "SYSTEM\CurrentControlSet\Services\" '(A) Dim regkey As RegistryKey '(B) Dim returnval As ServiceStartMode '(B) Try regkey = Registry.LocalMachine.OpenSubKey(SERVICEKEY + ServiceName()) '(C) Try returnval = CType(regkey.GetValue( "Start", ServiceStartMode.None), ServiceStartMode) '(D) Catch ex As Exception returnval = ServiceStartMode.None Finally regkey.Close() End Try Catch ex As Exception Return ServiceStartMode.None End Try Return returnval End Get |
(A)は前述した サービスの設定が保持されているパスで固定なのでConstとします。
(B)でRegistryKey型とServiceStartMode型の変数を宣言します。
(C)でレジストリのSERVICEKY + ServiceName()で指定されるサービスの レジストリキーをオープンします。ServiceName()プロパティは基底クラスのプロパティで コンストラクタの引数で指定したサービス名を返します。ここで例外がスローされたら Catchブロックに制御が移りServiceStartMode.Noneを返して終了します。
(D)のGetValueメソッドで第一引数に指定した名前("Start")に
対応した値を取得して、CTypeの第二引数で指定した型(ServiceStartMode)に
変換してreturnvalに返します。
もし、"Start"が項目名としてないときや例外がスローされた時は、
GetValueメソッドの第二引数の値(ServiceStatrMode.None)を返し、
Finallyブロックでレジストリキーを閉じます。
次にSet 〜 End Set(値設定)を以下のように記述します。
Set(ByVal value As ServiceStartMode) Const SERVICEKEY As String = "SYSTEM\CurrentControlSet\Services\" Dim regkey As RegistryKey Try regkey = Registry.LocalMachine.OpenSubKey(SERVICEKEY + ServiceName(), True) '(a) Try regkey.SetValue( "Start", value, RegistryValueKind.DWord) '(b) Catch ex As Exception Return Finally regkey.Close() End Try Catch ex As Exception Return End Try End Set |
Property Getとの違いは(a)のOpenSubKeyメソッドで第二引数にTrueがあること、 (b)でGetValueからSetValueメソッドに変わったことです。OpenSubKeyはレジストリに書き込みを 許可するため、オーバーロード版のOpenSubKeyを使います。SetValueは値をレジストリに 書き込まないといけないのでわかりますよね。
以上ですが、終わる前にコンストラクタで
サービス名だけを指定する
バージョンだけ実装したのを覚えていますでしょうか。これはサービスを制御する対象を
ローカルコンピュータに限るためでした。
ところが、基底クラスのServiceControllerにはMachineName()プロパティがあり、
ここでリモートコンピュータを指定できてしまいます。これを防ぐためにこのプロパティを
シャドウして、さらにリードオンリーにしてしまいます。
StartModeプロパティの下にでも以下を記述してください。
Public Shadows ReadOnly Property MachineName() As String Get Return My.Computer.Name() End Get End Property |
以上でServiceControllerExクラスの実装はできましたので、Main関数で利用してみます。