EternalWindows
WMI / MOFファイルの作成

WMIクライアントにとって、WMIプロバイダは基本的に見えにくい存在です。 プロバイダはクライアントが使用するクラスを実装するDLLまたはEXEなのですが、 クライアントがそうしたプロバイダの情報を指定することはあまりないからです。 たとえば、次のようなインスタンスを列挙するコードでは、 クラス名は指定するけれども、プロバイダ名を指定することはありませんでした。

bstrFilter = SysAllocString(L"Win32_Process");
pNamespace->CreateInstanceEnum(bstrFilter, WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, &pEnumerator);

CreateInstanceEnumを呼び出せば第1引数のクラスのインスタンスを列挙できますが、 このためにはWMIがクラスから関連するプロバイダを特定し、 プロバイダに対してインスタンスの作成を要求できなければなりません。 これはどのようにして行われているかというと、 リポジトリ(%SystemRoot%\System32\wbem\repositoryに存在)という領域に保存されたデータを参照しています。 プロバイダの開発者は、プロバイダの情報(クラスなど)をMOFファイルに定義することになりますが、 このMOFファイルをmofcomp.exeというアプリケーションでコンパイルすると、 データがリポジトリに格納されることになります。 この状態になれば、CreateInstanceEnumでクラスを列挙できるようになります。

WMIプロバイダを開発するとは、簡単にいえば独自のクラスを定義してそれを公開するということです。 そして、そのためにはプロバイダの情報を記述したMOFファイルを作成し、 これをmofcompでコンパイルしなければなりません。 次に、今回作成するMOFファイルの内容を示します。

#pragma autorecover
#pragma namespace ("\\\\.\\root\\cimv2")

instance of __Win32Provider as $P
{
    Name = "SampProv";
    ClsId = "{BB466B74-24A8-4611-895F-88A46766E8A0}";
};

instance of __InstanceProviderRegistration
{
    provider = $P;
    SupportsEnumeration = TRUE;
};

instance of __MethodProviderRegistration
{
    provider = $P;
};

[dynamic, provider("SampProv")]
class MySampProv
{
     [key]
       uint32 id;
       string data;

     [implemented, static] 
       uint32 SampleMethod([in]string strIn, [out] string strOut);
};

#pragma autorecoverは、このMOFファイルを自動修復の対象にすることを意味します。 システムはWMIのサービスを開始するときに、リポジトリに問題がないかをチェックしますが、 このときに問題がある場合は、自動修復対象のMOFファイルが再コンパイルされます。 #pragma namespaceは、MOFファイルを括弧の中に記述された名前空間にロードすることを意味します。 #pragma namespaceを記述しない場合は"\\\\.\\Root\\default"にロードされることになりますが、 多くのMOFファイルは"\\\\.\\Root\\cimv2"にロードされているため、この名前空間を記述します。 instance ofキーワードは、クラスのインスタンスを定義する場合に使用します。 プロバイダのインスタンスは必ず必要であるため、プロバイダのクラスを表す__Win32Providerを指定します。 as $Pというのはこのインスタンスに$Pという名前を付けるということであり、 これにより他の箇所でプロバイダを参照できます。 括弧の中では、インスタンスのプロパティに対して既定値を与えることができます。 インスタンスが持つプロパティはクラスが定義しているプロパティであり、 その中でもNameとCLSIDは明示的に初期化すべきといえます。 Nameにはプロバイダの名前を指定し、CLSIDにはプロバイダのCLSIDを指定します。 CLSIDが必要なのは、プロバイダの正体がCOMサーバーであるためです。

一言にプロバイダといっても、インスタンスの列挙などをサポートするInstance providerや、 メソッドの呼び出しをサポートするMethod providerなどの種類があります。 プロバイダがInstance providerになりたい場合は、__InstanceProviderRegistrationのインスタンスを定義します。

instance of __InstanceProviderRegistration
{
    provider = $P;
    SupportsEnumeration = TRUE;
}

括弧の中には、__InstanceProviderRegistrationのクラスのプロパティを記述できます。 SupportsEnumerationというプロパティは既定でFALSEになっていますが、 これをTRUEにすることで、クライアントがCreateInstanceEnumで取得したIEnumWbemClassObjectで、 インスタンスを列挙できるようになります。 もし、FALSEであるならばIEnumWbemClassObject::NextでWBEM_E_PROVIDER_NOT_CAPABLEが返ることになり、 インスタンス列挙の通知がプロバイダに送られません。 $Pは既に示したように、プロバイダを示す指標です。

プロバイダはInstance providerになると同時に、Method providerになるようなことも可能です。 この場合は、次の記述を行います。 今回作成することになるプロバイダは、メソッドの呼び出しにも対応することになっています。 つまり、クライアントがIWbemServices::ExecMethodを呼び出した場合は、 プロバイダが何らかの処理を行うことを意味します。 こうした呼び出しに対応するには、MOFファイルに次の文字列を記述します。

instance of __MethodProviderRegistration
{
    provider = $P;
};

これにより、プロバイダはメソッドの呼び出しにも対応できます。

クラスの定義は、次のようになっています。

[dynamic, provider("SampProv")]
class MySampProv
{
     [key]
       uint32 id;
       string data;

     [implemented, static] 
       uint32 SampleMethod([in]string strIn, [out] string strOut);
};

class MySampProvというのが、クラスの定義になります。 定義の前に存在するdynamicは、クラスのインスタンスを動的に作成することを意味します。 providerは、クラスとプロバイダを関連付けるために記述しています。 括弧の中身はプロバイダの名前でなければなりません。 uint32 idというのは、uint32型のidというプロパティの定義です。 keyという修飾子を指定した場合は、このプロパティがインスタンスを一意に識別することを意味します。 string dataは、string型のidというプロパティの定義です。 プログラム内では、uint32型はVARIANT構造体のVT_I4で表され、 string型はVARIANT構造体のVT_BSTRで表されます。

メソッドに対して、2つのStandard WMI Qualifierが指定されています。 Implementedはこのメソッドが、プロバイダによって実装されていることを意味します。 クラスは別クラスを継承することが可能になっていますが、 その別クラスのメソッドの実装をそのまま使うわけではないときは必須です。 Staticはこのメソッドがインスタンスから呼び出せないことを意味します。 プロトタイプの部分については、C言語における定義とほぼ同じ要領です。 第1引数がstring型のstrInであり、第2引数がstring型のstrOutです。 第1引数は[in]が指定されているため、この引数は呼び出し側が初期化することになり、 第2引数は[out]が指定されているため、この引数はプロバイダがメソッド内で初期化します。

MOFファイルを作成したら、mofcomp.exeでコンパイルすることになります。 これは、コマンドラインを通じて行うのが一般的です。

mofcomp C:\sample.mof

MOFファイルの中身に問題がなければコンパイルは成功し、リポジトリにデータが格納されることになります。 これによって、WMIはプロバイダのクラスやインスタンスが使用される際に、リポジトリからプロバイダのCLSIDを特定できますが、 このCLSIDを基にプロバイダをロードしたり起動したりするためには、 プロバイダがレジストリに別途登録されている必要があります。

プロバイダが正しく登録され、MOFファイルにも問題がなければ、 クラスを列挙できるようになるはずです。 System32\Wbemに存在するwbemtest.exeを使用して、これを確認してみましょう。

wbemtestを起動して「接続」という名前のボタンを押せば、上記のダイアログが表示されます。 ダイアログの設定については上記の通りで特に問題ないため、「接続」ボタンを押下します。 すると、次のように各種ボタンを使用できるようになります。

クラスを列挙したい場合は、「クラスの列挙」というボタンを押します。 すると、下図のようなダイアログが表示されます。

エディットコントロールには、列挙したいクラスの継承元であるクラスを入力できます。 しかし、今回定義したクラスは他クラスを継承していないため、何も入力せずにOKボタンを押します。 すると、一連のクラスが列挙されるようになります。

上図のように、MySampProvという独自のクラスが表示されていれば成功です。 管理者としてwbemtestを起動しているならば、不要になったクラスを削除することもできます。 項目をダブルクリックすれば、クラスの詳細を確認できます。


戻る