こんにちは。
WMIをつかって、特定のインターフェイスのネットワークの設定を変更するツ
ールを作成しようとしています。
単純にWMIからメソッドを実行する方法についてはMSDNの
http://msdn2.microsoft.com/en-us/library/aa390421(VS.85).aspx
を参考に実現できたのですが、Win32_NetworkAdapterConfigurationのように、
メソッドを実行するインターフェイスを指定しなければならない場合、どのよ
うにすればよいかわからず・・・。
VBScriptなどは
Set objShare = objWMIService.Get("Win32_NetworkAdapterConfiguration.Index='12'")
といったようにIndexを指定してメソッドを実行できるみたいですが・・・
試しに
IWbemLocator *l_pLoc = NULL;
IWbemServices *l_pSvc = NULL;
IWbemClassObject *l_pclsObj = NULL;
IWbemClassObject *l_pInParamsDefinition = NULL;
BSTR l_Class = SysAllocString(L"Win32_NetworkAdapterConfiguration.Index='1'");
BSTR l_Method = SysAllocString(L"EnableDHCP");
if(FAILED(CoInitializeEx(0, COINIT_MULTITHREADED)))
{
SysFreeString(l_Method);
SysFreeString(l_Class);
return FALSE;
}
else
{
if(FAILED(CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL)))
{
CoUninitialize();
SysFreeString(l_Method);
SysFreeString(l_Class);
return FALSE;
}
}
if(FAILED(CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &l_pLoc)))
{
CoUninitialize();
SysFreeString(l_Method);
SysFreeString(l_Class);
return FALSE;
}
//WMIに接続
if(FAILED(l_pLoc->ConnectServer( _bstr_t(L"ROOT\\CIMV2"), NULL, NULL, _bstr_t(L"MS_409"), NULL, 0, 0, &l_pSvc)))
{
InitObj(l_pLoc); //オブジェクトをReleaseするためのマクロを定義しています
CoUninitialize();
SysFreeString(l_Method);
SysFreeString(l_Class);
return FALSE;
}
if(FAILED(CoSetProxyBlanket(l_pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE)))
{
InitObj(l_pSvc);
InitObj(l_pLoc);
CoUninitialize();
SysFreeString(l_Method);
SysFreeString(l_Class);
return FALSE;
}
if(FAILED(l_pSvc->GetObject(l_Class, 0, NULL, &l_pclsObj, NULL)))
{
InitObj(l_pclsObj);
InitObj(l_pSvc);
InitObj(l_pLoc);
SysFreeString(l_Method);
SysFreeString(l_Class);
return FALSE;
}
if(FAILED(l_pclsObj->GetMethod(l_Method, 0, &l_pInParamsDefinition, NULL)))
{
InitObj(l_pInParamsDefinition);
InitObj(l_pclsObj);
InitObj(l_pSvc);
InitObj(l_pLoc);
SysFreeString(l_Method);
SysFreeString(l_Class);
return FALSE;
}
・・・・もろもろの処理
CoUninitialize();
というように作成しているのですが(中途半端にはしょっていてすみません)、
GetMethodの部分で失敗してしまいます。
戻り値を確認したところ-2147217378となっていました。
http://msdn2.microsoft.com/en-us/library/aa391443(VS.85).aspx
にあるGetMethodの戻り値と比較してみたのですが、該当する値が見つからず
・・・。
このようなあるWMIオブジェクトにおいて「特定の」ものに対してのみメソッ
ドを実行する場合はどのようにすればよいのでしょうか?
参考になるURLなどだけでもよいので、ご存じの方いらっしゃいましたらご教
授いただけますでしょうか?
開発環境はWindows XP Pro With SP4、Visual Studio.NET 2003 Enterprise
です。
お手数をおかけしますが、よろしくおねがいいたします。
> 単純にWMIからメソッドを実行する方法についてはMSDNの
> http://msdn2.microsoft.com/en-us/library/aa390421(VS.85).aspx
> を参考に実現できたのですが、
そのページにあるサンプルコード
// Execute Method
IWbemClassObject* pOutParams = NULL;
hres = pSvc->ExecMethod(ClassName, MethodName, 0,
NULL, pClassInstance, &pOutParams, NULL);
VARIANT varReturnValue;
hres = pOutParams->Get(_bstr_t(L"ReturnValue"), 0,
&varReturnValue, NULL, 0);
がそのまま使えましたよ。
GetObject も GetMethod も必要ありません。
CoSetProxyBlanket の後に上記のコードを入れてみてください。
変数名は適宜書き換えてね。
シャノンさん
ありがとうございます。
EnableDHCPはできました!!
これって、引数を必要なメソッドの場合のみ、GetObject以降が必要になるん
ですかね?
(GetObject→GetMethod→SpawnInstance→Put(引数を入れる)→ExecMethod)
引数のあるメソッドでも試してみて、うまくいったら解決にしようと思います。
> これって、引数を必要なメソッドの場合のみ、GetObject以降が必要になるんですかね?
そのようですね。
GetMethod でメソッドの引数の情報を取得して、SpawnInstance で引数オブジェクトのインスタンスを作って、実際の引数は引数オブジェクトのプロパティに設定しているんですね。
クラスもインスタンスも引数もすべて IWbemClassObject なんですね。ややこしいなぁ。
さて、最初に提示されたコードが失敗した理由です。
上記のように、クラスもインスタンスも IWbemClassObject で表されますが、メソッドを持っているのはクラスだけです。
Win32_NetworkAdapterConfiguration.Index='12' という文字列は、Index プロパティでインスタンスを特定していますから、この文字列から GetObject で得られるのはインスタンスです。
インスタンスはメソッドを持たないので失敗していたのですね。
ちなみに、-2147217378 は WBEM_E_ILLEGAL_OPERATION です。
ですから、GetMethod を成功させるためには、クラス名にインスタンスを特定するプロパティをつけず、Win32_NetworkAdapterConfiguration を渡してやればいいわけです。
が、ExecMethod はインスタンスを要求しますから、ExecMethod の第一引数には .Index='XX' をつけてやる必要があります。
その場合に、どのインスタンスに対してメソッドを実行するかを決定するには、何らかの方法でインスタンスを列挙する必要がありますね。
たぶん、IWbemServices::CreateInstanceEnum を使うんだと思います。
シャノンさん、丁寧な説明、ありがとうございます!!
見事にうまくいけました。
ご存じだったらついでに教えてください。
MSDN上で、メソッドの引数の型が「string」の時は
VARIANT l_varCommand;
l_varCommand.vt = VT_BSTR;
l_varCommand.pbstrVal = SysAllocString(L"hikisuu");
l_pClassInstance->Put(L"DNSServerSearchOrder", 0, &l_varCommand, 0)
で、よいみたいなのですが、「string[]」の場合(SetDNSServerSearchOrder
等)はどの型を使えばよいのかご存じですか?
単純にBSTR型の配列を用意して、
BSTR l_DNSOrder[] SysAllocString(L"hikisuu"), SysAllocString(L"hikisuu2")};
l_varCommand.vt = VT_BYREF | VT_BSTR;
l_varCommand.pbstrVal = l_DNSOrder;
l_pClassInstance->Put(L"DNSServerSearchOrder", 0, &l_varCommand, 0)
とやってみたところ、WBEM_E_TYPE_MISMATCHのエラーで終了してしまいました。
ご存じでしたら教えてください。
(別スレにしなくてすみません)
正直、俺も WMI なんて初めて触るので手探りなんだけれども、どうやら SafeArray を使うらしい。
SAFEARRAY * psa = SafeArrayCreateVector( VT_BSTR, 0, 2 );
LONG index = 0;
SafeArrayPutElement( psa, &index, SysAllocString(L"192.168.0.1") );
index = 1;
SafeArrayPutElement( psa, &index, SysAllocString(L"192.168.0.2") );
VARIANT var;
VariantInit( &var );
V_VT(&var) = VT_BSTR | VT_ARRAY;
V_ARRAY( &var ) = psa;
hr = pInParameters->Put(L"DNSServerSearchOrder", 0, &var, V_VT( &var ) );
hr = pService->ExecMethod(strInstancePath, strMethodName, 0, NULL, pInParameters, NULL, NULL);
VariantClear( &var );
で設定はできた。
シャノンさん
おぉ!!SafeArrayですか。
できました。
何から何までありがとうございました!!
ツイート | ![]() |