2012年1月19日木曜日

Hyper-V ゲスト OS の動作イメージサムネイルを取得するアクティビティ

以前 Hyper-V の管理とか操作を調べていて管理ツール上の動作イメージサムネイルをどうやって取得しているのかな、と思ったら WMI を利用して取得していることを教えてもらったので、ついでにアクティビティにしてみました。

PowerShell での方法はこちらの MSDN Blog に書いてありますが、これの WF アクティビティ化したものになります。やっている事としては、Msvm_ComputerSystem に対して該当するゲスト OS の情報を取得しにいき、結果から Msvm_VirtualSystemsettingData の情報を取得。その値を元に、再度 Msvm_ComputerSystem を取得、GetVirtualSystemThumbnailImage メソッドの情報を取得した上でメソッドを呼び出す。言葉で書くと非常にわかりずらいですが、大体このような感じで実行すれば、ゲスト OS のサムネイルが取得できます。

   1: Imports System.Activities
   2: Imports System.Management
   3:  
   4: Public MustInherit Class WMIExecuteActivityBase
   5:     Inherits AsyncCodeActivity
   6:  
   7:     Protected _target As String = ""
   8:     Protected _where As String = ""
   9:     Protected _service As String = ""
  10:  
  11:     Public Property Scope As InArgument(Of ManagementScope)
  12:     Public Property Results As OutArgument(Of List(Of Hashtable))
  13:  
  14:     Protected Delegate Function asyncExecuteWMIDelegate(ByVal target As String, ByVal whereCondition As String, ByVal wmScope As ManagementScope) As List(Of Hashtable)
  15:  
  16:     Protected Overrides Function BeginExecute(context As System.Activities.AsyncCodeActivityContext, callback As System.AsyncCallback, state As Object) As System.IAsyncResult
  17:         Dim currentScope = context.GetValue(Me.Scope)
  18:  
  19:         Dim asyncExecute = New asyncExecuteWMIDelegate(AddressOf ExecuteWMI)
  20:         context.UserState = asyncExecute
  21:  
  22:         Return asyncExecute.BeginInvoke(_target, _where, currentScope, callback, state)
  23:     End Function
  24:  
  25:     Protected Overrides Sub EndExecute(context As System.Activities.AsyncCodeActivityContext, result As System.IAsyncResult)
  26:         Dim asyncExecute = TryCast(context.UserState, asyncExecuteWMIDelegate)
  27:         Dim wmiResult = asyncExecute.EndInvoke(result)
  28:  
  29:         context.SetValue(Me.Results, wmiResult)
  30:     End Sub
  31:  
  32:     Protected Overridable Function ExecuteWMI(ByVal target As String, ByVal whereCondition As String, ByVal wmScope As ManagementScope) As List(Of Hashtable)
  33:  
  34:     End Function
  35:  
  36:     Protected Function CreateScope(ByVal wmScope As ManagementScope) As ManagementScope
  37:         If wmScope Is Nothing Then
  38:             wmScope = New ManagementScope("\\" + My.Computer.Name + "\root\" + _service)
  39:         End If
  40:         If Not wmScope.IsConnected Then wmScope.Connect()
  41:         Return wmScope
  42:     End Function
  43:  
  44: End Class

これがベースとなるアクティビティで、実際にはこれを継承した形で作成しました。

   1: Imports System.Activities
   2: Imports System.Management
   3: Imports System.Drawing
   4: Imports System.IO
   5:  
   6: Public Class WMIGetVMThumbnailActivity
   7:     Inherits WMIExecuteActivityBase
   8:  
   9:     Private _imageX As Integer = 320
  10:     Private _imageY As Integer = 240
  11:     Private _imageFile As String = ""
  12:  
  13:     Public Property VMName As InArgument(Of String)
  14:     Public Property ImageFileName As InArgument(Of String)
  15:     Public Property ImageSizeX As InArgument(Of Integer)
  16:     Public Property ImageSizeY As InArgument(Of Integer)
  17:  
  18:     Protected Overrides Function BeginExecute(ByVal context As System.Activities.AsyncCodeActivityContext, ByVal callback As System.AsyncCallback, ByVal state As Object) As System.IAsyncResult
  19:         MyBase._target = "Msvm_ComputerSystem "
  20:         MyBase._where = "Caption = '仮想マシン' and ElementName = '" + context.GetValue(Me.VMName) + "'"
  21:         MyBase._service = "virtualization"
  22:  
  23:         _imageX = context.GetValue(Me.ImageSizeX)
  24:         _imageY = context.GetValue(Me.ImageSizeY)
  25:         _imageFile = context.GetValue(Me.ImageFileName)
  26:  
  27:         Return MyBase.BeginExecute(context, callback, state)
  28:     End Function
  29:  
  30:     Protected Overrides Function ExecuteWMI(ByVal target As String, ByVal whereCondition As String, ByVal wmScope As System.Management.ManagementScope) As System.Collections.Generic.List(Of System.Collections.Hashtable)
  31:         Dim result As New List(Of Hashtable)
  32:         Try
  33:             wmScope = CreateScope(wmScope)
  34:  
  35:             Dim wmQuery As New ObjectQuery("SELECT * FROM " + target + " WHERE " + whereCondition)
  36:             Dim wmSearcher As New ManagementObjectSearcher(wmScope, wmQuery)
  37:             Dim wmVirtualSystem As ManagementObject = Nothing
  38:             For Each wmRes As ManagementObject In wmSearcher.Get
  39:                 For Each wmVir As ManagementObject In wmRes.GetRelated("Msvm_VirtualSystemsettingData")
  40:                     wmVirtualSystem = wmVir
  41:                     Exit For
  42:                 Next
  43:                 Exit For
  44:             Next
  45:             If wmVirtualSystem Is Nothing Then Return result
  46:  
  47:             Dim wmVsmsQuery As New ObjectQuery("SELECT * FROM " + target + " WHERE " + whereCondition)
  48:             Dim wmVsmsSearcher As New ManagementObjectSearcher(wmScope, wmVsmsQuery)
  49:             For Each wmVsms As ManagementObject In wmVsmsSearcher.Get
  50:                 Dim inParam = wmVsms.GetMethodParameters("GetVirtualSystemThumbnailImage")
  51:                 inParam("WidthPixels") = _imageX
  52:                 inParam("HeightPixels") = _imageY
  53:                 inParam("TargetSystem") = wmVirtualSystem.Path.Path
  54:  
  55:                 Dim wmMethodResult = wmVsms.InvokeMethod("GetVirtualSystemThumbnailImage", inParam, Nothing)
  56:                 Dim wmImage() = CType(wmMethodResult("ImageData"), Byte())
  57:                 My.Computer.FileSystem.WriteAllBytes(_imageFile, wmImage, False)
  58:                 Exit For
  59:             Next
  60:  
  61:         Catch ex As Exception
  62:             result.Clear()
  63:         End Try
  64:         Return result
  65:     End Function
  66:  
  67: End Class

このようなロジックになります。ただし、注意することが 1 点だけありまして、この方法で取得したイメージ(WriteAllBytes で保存している内容)は、画像の形式で言うと RAW となりますので、一般的な画像形式に変換してあげる必要があります。

0 件のコメント:

コメントを投稿