2012年5月10日木曜日

分離型と言われるセルフホスト式 WMI プロバイダ

6/9 に行われる Comunity Open Day 2012 の北海道開場では、私が午後イチのセッションをやらさせてもらえることになり、ここ最近そこで話すネタについて色々調べたり遊んだりしています。その中でも今になってようやく試すことができた、WMI プロバイダの自作を行ってみました。

やってみると WMI プロバイダの実装自体はかなり簡単なものでした。ベースとなるのは MSDN の WMI プロバイダ関係の記事で、それを元にして試しています。元々は電卓かなにかの計算結果を公開するようなサンプルでしたが、ここではもっと単純にフォーム上で入力されている文字列を公開することをやってみました。

必要となるのは、入力用フォーム、WMI プロバイダとして公開するクラス、インストーラクラスの3つです。

   1: Imports System.Management.Instrumentation
   2: Imports System.ComponentModel
   3:  
   4: ''' <summary>WMI プロバイダインストーラクラス</summary>
   5: <RunInstaller(True)>
   6: Public Class SampleWMIProviderInstaller
   7:     Inherits DefaultManagementInstaller
   8:  
   9: End Class

まずインストーラクラスですが、これは System.Management.Instrumentation.DefaultManagementInstaller クラスを継承したクラスを用意するだけで、他に実装する点はありません。



   1: Imports System.Management.Instrumentation
   2:  
   3: ' アセンブリに対しての WMI 設定指定
   4: <Assembly: WmiConfiguration("root/clrh",
   5:                                             HostingModel:=ManagementHostingModel.Decoupled,
   6:                                             IdentifyLevel:=False)> 
   7:  
   8: <ManagementEntity(name:="clrh")>
   9: <ManagementQualifier("Description", Value:="サンプル WMI プロバイダで誰でも利用可能です")>
  10: Public Class SampleWMIProvider
  11:  
  12: #Region "プロパティ定義"
  13:     <ManagementKey()>
  14:     <ManagementQualifier("Description", value:="プロセス Id を取得します")>
  15:     Public Property Id As Integer
  16:  
  17:     <ManagementConfiguration()>
  18:     <ManagementQualifier("Description", value:="表示されている文字列を取得します")>
  19:     Public Property DisplayText As String
  20: #End Region
  21:  
  22: #Region "コンストラクタ"
  23:     Public Sub New(ByVal Id As Integer)
  24:         Me.Id = Id
  25:     End Sub
  26: #End Region
  27:  
  28: End Class

次に WMI プロバイダとなるクラスです。WMI プロバイダは特に何かを継承してとかではなく、属性にて WMI プロバイダとなる事を設定します。今回は値を提供するだけに限定していますので、特に処理はありませんが、WMI 上で値の設定を可能にする場合には、それなりにロジックを記述する必要も出てきます。

最初の方で <Asembly ~ とありますが、これは作成されるアセンブリに対しての属性設定で、公開する名前空間の指定や、どのホスティングモデルを利用するかなどを設定しています。今回利用しているのは分離プロバイダと呼ばれる方式で、WF でいうセルフホスト型でありホスティングしているプロセスが生きている間は、WMI にて情報を取得できるものです。当然ホストプロセスを終了すると、WMI を通して値を取得することはできなくなります。



   1: Imports System.Management.Instrumentation
   2:  
   3: Public Class Form1
   4:  
   5:     Private wmiProvider As New SampleWMIProvider(Diagnostics.Process.GetCurrentProcess.Id)
   6:     Private executeTimer As System.Threading.Timer = Nothing
   7:  
   8:     Private Sub Form1_FormClosed(sender As Object, e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
   9:         InstrumentationManager.Revoke(wmiProvider)
  10:     End Sub
  11:  
  12:     Private Sub Form1_Shown(sender As Object, e As System.EventArgs) Handles Me.Shown
  13:         'タイマーにて1秒ごとにテキストボックスの内容を出力
  14:         executeTimer = New Threading.Timer(New Threading.TimerCallback(AddressOf OutputData), Nothing, 0, 1000)
  15:         ' WMI プロバイダの公開
  16:         InstrumentationManager.Publish(wmiProvider)
  17:     End Sub
  18:  
  19:     Private Sub OutputData()
  20:         wmiProvider.DisplayText = TextBox1.Text
  21:     End Sub
  22:  
  23: End Class

最後に文字入力用のフォームです。画面上に用意した Textbox に入力した文字を、WMI プロバイダに1秒ごとに反映させています。

image

実行するとこのような入力するだけのフォームが起動し、InstrumentationManager クラスを使って WMI プロバイダを公開します。この時、管理者権限がなければ実行時に例外が発生します。

image

その後 テスト用のVBS で公開された値を参照しに行くと、上記のように取得できます。スクリプトの中身は次のようなものです。



   1: strComputer = "."
   2: Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\clrh")
   3:  
   4: Set colSettings = objWMIService.ExecQuery("Select * from clrh")
   5:  
   6: For Each objSetting in colSettings
   7:     Wscript.Echo "(" & objSetting.Id & ") : " & objSetting.DisplayText
   8: Next

0 件のコメント:

コメントを投稿