Windows2000でWMIをつかってexe名からプロセスが上がっているか確認するには?

解決


どら  2009-11-20 22:58:53  No: 71126

こんにちは、いつもお世話になっております。
現在、単純にexeファイル名でプロセスが上がっているかどうか?を確認する
コンソールプログラムを作っています(開発環境Windows XP + VS.NET 2008 
Developer)。

WMIをつかって取得する方法を検討し、以下のようなソースにしたのですが、
Windows XPでは動作するのですが、Windows 2000だとExecQueryで失敗します。

ライブラリに記載されているエラーコードのどれにも当てはまらず(-1073741819)、
切り分けができずに困っている状況です。

何か原因として考えられるものなどがありましたらご指摘いただけると幸いです。

以下ソースを記載しますので、よろしくお願いいたします。

#include<windows.h>
#include<windowsx.h>
#include <comutil.h>
#include<Wbemidl.h>

//ライブラリのインポート
#pragma comment(lib, "comsuppw.lib")
#pragma comment(lib, "wbemuuid.lib")
//グローバル変数の定義

//グローバル関数の定義
int CheckProcessExists(WCHAR *ExeName);

//main関数
int main(int argc, char *argv[] )
{
  int l_ReturnValue;
  BSTR l_ExeName = NULL;

  //引数を取得(オプション引数がない場合は何もしない、多すぎても最初の一つしかみない)
  if(argc < 2)
  {
    return -99;
  }
  else
  {
    l_ExeName = _com_util::ConvertStringToBSTR(argv[1]);
  }

  //COM初期化
  if(FAILED(CoInitializeEx(0, COINIT_MULTITHREADED)))
  {
    l_ReturnValue = -1;
  }
  else
  {
    //COMのセキュリティレベルを設定
    if(FAILED(CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL)))
    {
      l_ReturnValue = -2;
    }
    else
    {
/*      if(CheckProcessExists(l_ExeName))
      {
        l_ReturnValue = 0;
      }
      else
      {
        l_ReturnValue = 1;
      }
*/
      l_ReturnValue = CheckProcessExists(l_ExeName);
    }
    //COMを閉じる
    CoUninitialize();
  }

  SysFreeString(l_ExeName);

  switch(l_ReturnValue)
  {
    case 0:
      printf("正常終了:指定されたプロセスが見つかりました。\n\n");
      break;
    case 1:
      printf("正常終了:指定されたプロセスは見つかりませんでした。\n\n");
      break;
    case -1:
      printf("エラー:COMの初期化に失敗しました。\n\n");
      break;
    case -2:
      printf("エラー:COMのセキュリティレベルの設定に失敗しました。\n\n");
      break;
    case -10:
      printf("エラー:WMI呼び出し用のバッファ確保に失敗しました。\n\n");
      break;
    case -20:
      printf("エラー:WMIロケータの取得に失敗しました。\n\n");
      break;
    case -21:
      printf("エラー:WMIの接続に失敗しました。\n\n");
      break;
    case -22:
      printf("エラー:WMIのセキュリティレベルの取得に失敗しました。\n\n");
      break;
    case -23:
      printf("エラー:WMIから情報を取得できませんでした。\n\n");
      break;
    default:
      printf("エラー:不明なエラーです\n\n");
      break;

  }

  return l_ReturnValue;
}

int CheckProcessExists(WCHAR *ExeName)
{
  IWbemLocator *l_pLoc = NULL;                //IWbemLocator インターフェイス
  IWbemServices *l_pSvc = NULL;                //IWbemServices インターフェイス
  IEnumWbemClassObject *l_pEnumerator = NULL;          //IEnumWbemClassObject インターフェイス
  IWbemClassObject *l_pclsObj = NULL;              //IWbemClassObject インターフェイス
  ULONG l_uReturn;                      //ULONG型の関数の戻り値を格納
  ULONG l_cntProcess;                      //プロセス数を格納
  WCHAR *l_WQLString = NULL;                  //WQL文字列
  int  l_lenWQLString;                      //↑の長さ

  //WQL文字列の格納
  l_lenWQLString = lstrlen(L"SELECT * FROM WIN32_Process WHERE Caption = ''") + lstrlen(ExeName);
  l_WQLString = new WCHAR[l_lenWQLString + 1];
  if(l_WQLString == NULL)
  {
    return -10;
  }
  wsprintf(l_WQLString, L"SELECT * FROM WIN32_Process WHERE Caption = '%s'", ExeName);

  //WMI初期ロケータの取得
  if(FAILED(CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *)&l_pLoc)))
  {
    if(l_WQLString != NULL)
    {
      delete[] l_WQLString;
      l_WQLString = NULL;
    }
    return -20;
  }

  //コンピュータのWMIに接続
  if(FAILED(l_pLoc->ConnectServer(L"ROOT\\CIMV2", NULL, NULL, 0, NULL, 0, 0, &l_pSvc)))
  {
    if(l_WQLString != NULL)
    {
      delete[] l_WQLString;
      l_WQLString = NULL;
    }
    if(l_pLoc != NULL)
    {
      l_pLoc->Release();
      l_pLoc = NULL;
    }
    return -21;
  }

  //WMIセキュリティレベル設定
  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)))
  {
    if(l_WQLString != NULL)
    {
      delete[] l_WQLString;
      l_WQLString = NULL;
    }
    if(l_pSvc != NULL)
    {
      l_pSvc->Release();
      l_pSvc = NULL;
    }
    if(l_pLoc != NULL)
    {
      l_pLoc->Release();
      l_pLoc = NULL;
    }
    return -22;
  }

  //WMIの要求
  if(FAILED(l_pSvc->ExecQuery(L"WQL", l_WQLString, WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &l_pEnumerator)))
  {
    if(l_WQLString != NULL)
    {
      delete[] l_WQLString;
      l_WQLString = NULL;
    }
    if(l_pSvc != NULL)
    {
      l_pSvc->Release();
      l_pSvc = NULL;
    }
    if(l_pLoc != NULL)
    {
      l_pLoc->Release();
      l_pLoc = NULL;
    }
    return -23;
  }

  if(l_WQLString != NULL)
  {
    delete[] l_WQLString;
    l_WQLString = NULL;
  }

  l_cntProcess = 0;
  while(l_pEnumerator)
  {
    l_pEnumerator->Next(WBEM_INFINITE, 1, &l_pclsObj, &l_uReturn);
    if(0 == l_uReturn)
    {
      if(l_pclsObj != NULL)
      {
        l_pclsObj->Release();
        l_pclsObj = NULL;
      }
      break;
    }
    if(l_pclsObj != NULL)
    {
      l_pclsObj->Release();
      l_pclsObj = NULL;
    }
    l_cntProcess++;
  }

  if(l_cntProcess > 0)
  {
    return 0;
  }

  return 1;

}


オショウ  2009-11-21 07:47:09  No: 71127

Win2000の問題として・・・
http://support.microsoft.com/kb/306497/ja
http://support.microsoft.com/kb/300038/ja

こういうものがありました。
エラーコードが同じなので・・・

Win2000のサービスパックは何でしょう?

それによっては、解決の方法に至るかも・・・です。

以上。


どら  2009-11-24 18:10:36  No: 71128

オショウさん

いつもありがとうございます。
Windows 2000のSPは・・・残念ながら4なんですT_T
なんなんでしょうね・・・
同じことをVBScriptで実行させると問題ないのが悔しいです(ユーザ側に置く
為、ソースの見えるVBScriptではなく、exeで作りたくて作成しているのです)

私もあのエラーコードを調べてみたのですが「-1073741819」は「STATUS_ACCESS_VIOLATION 」
だとか・・・

もう少し調べてみます。


オショウ  2009-11-24 20:18:13  No: 71129

であれば・・・

WMIでのアクセスで、やり取りする際に使用する変数は、VARIANT宣言
したもので行いますが、掲載されたコードには、使っておられません
よネ?!

インターネットで検索した際のいろいろな掲載されているコードを
参考に、VARIANT宣言した変数で受け渡すよう修正してみては?

以上。参考まで


どら  2009-11-24 20:34:33  No: 71130

解決したっぽいです。

【修正前】
//コンピュータのWMIに接続
if(FAILED(l_pLoc->ConnectServer(L"ROOT\\CIMV2", NULL, NULL, 0, NULL, 0, 0, &l_pSvc)))
{
・・・・
//WMIの要求
if(FAILED(l_pSvc->ExecQuery(L"WQL", l_WQLString, WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &l_pEnumerator)))
{
・・・

【修正後】
//コンピュータのWMIに接続
if(FAILED(l_pLoc->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), NULL, NULL, 0, NULL, 0, 0, &l_pSvc)))
{
・・・・
//WMIの要求
if(FAILED(l_pSvc->ExecQuery(_bstr_t(L"WQL"), _bstr_t(l_WQLString), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &l_pEnumerator)))
{
・・・

と、WCHAR型でそのまま突っ込んでいたものを_bstr_t()でちゃんと変換してい
なかった?のがいけなかったみたいです。

お騒がせしました^^;


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加