WMI からPCのハードウェア情報を取得している部分の VB.Net のソースを見ていると気付いたことが。。
ソースはこんな感じでした。
Dim strComputer As String = "."Dim wbemServices As Object = GetObject("winmgmts:\\" & strComputer)
Dim wbemObjectSet As Object = wbemServices.InstancesOf("Win32_ComputerSystem")
For Each wbemObject As Object In wbemObjectSet
' PC型番
Console.WriteLine(wbemObject.Model)
Next
実はこのコードは WMI のサンプルでググると似たようなのがいっぱい見つかります。(大抵はVBscriptが多いんですが。。)
まず気になったのは2行目の GetObject メソッドとは何ぞやということです。
Microsoft.VisualBasic.Interaction クラスのメソッドなので、VB6互換の関数のようですね。
詳しくはMSDN:Interaction.GetObject メソッドを参照。
どうやらVB6時代に使ってた CreateObject 関数の親戚みたいなもので、COM コンポーネントによって提供されるオブジェクトへの参照を取得できるようです。(つまり COM オブジェクトを取得)
CreateObject との違いはMSDNによると「オブジェクトの現在のインスタンスが存在している場合、または読み込まれたファイルを使ってオブジェクトを作成する場合には、GetObject 関数を使用します。現在のインスタンスが存在せず、読み込まれたファイルを使ってオブジェクトを実行しない場合は、CreateObject 関数 (Visual Basic) を使用します。」ということらしいです。
ということで、変数 wbemServices に COM オブジェクトが入るのはわかりました。
次に不思議なのは Object 型の wbemServices で InstancesOf() とかいうメソッドを呼び出していることです。
Object 型なのにどゆこと?と思っていたら、これが VB.Net に特徴の遅延バインディングというやつらしいです。
これはVB6時代にもあったもので、データ型がわからなくてもVB6ならVariant型、VB.NETならObject型の変数に動的に生成したオブジェクト(型はなんでもOK)を代入しても、その元の型のメソッドやプロパティにアクセスできるというものです。
遅延バインディングが VB.Net でもサポートされてたのは知りませんでした。
詳しくは@IT:VB 6プログラマーのためのVB.NET入門 第27回 言語の動作を選択するオプション(後編)や@IT:動的プログラミング言語へと発展するC# 3.0とVB 9.0を参照。
ちなみに、C# ではコンパイラレベルでは遅延バインディングはサポートされてないようです。ただ、リフレクション(実行時型情報の取得)機能を使えばC#でも使えるようですが、明示的に書かないといけないため、書くコードは増えるみたいですね。
ただ、VB.Netでも Option Strict On とすると遅延バインディングが使えなくなりコンパイルできません。
(プロジェクトのコンパイル設定で Option Strict On にすると、暗黙的な変換や暗黙的型も使えなくなるようです)
また、MSDN:第 7 章 「相互運用パフォーマンスの向上」によると、遅延バインディングやリフレクションは著しくパフォーマンスを低下するみたいなので、事前バインディングを使ったほうがよさそうですね。
ということでパフォーマンスの向上とC#でも簡単に使えるようにするため、WMIの取得を事前バインディングでやってみることにしました。