使用 C++ 创建一个 WMI 应用程序

使用 C++ 创建一个 WMI 应用程序绝非易事。首先必须初始化 COM(WMI 基于 COM 技术),访问并设置 WMI 协议(调用 CoInitializeEx 和 CoInitializeSecurity 函数以访问 WMI),最后手动完成清理工作。(保持整洁始终很重要!)

以下是连接 WMI 的方法: 

通过调用 CoInitializeEx 来初始化 COM。下面的代码示例说明了如何调用 CoInitializeEx: 
HRESULT hres;

   hres = CoInitializeEx (0, COINIT_MULTITHREADED); // 初始化 COM。

   if (FAILED (hres))
   {
      cout << "初始化 COM 库失败。错误代码 = 0x" 
      << hex << hres << endl;
      return 1;
   }
      
通过调用 CoInitializeSecurity 接口设置一般 COM 安全级别。 
与 CoInitializeEx 一样,CoInitializeSecurity 是设置 COM 接口时需要调用的一个标准函数。下面是调用 CoInitializeSecurity 的方法: 

hres =  CoInitializeSecurity (NULL, -1, NULL, 
  NULL, RPC_C_AUTHN_LEVEL_CONNECT, 
  RPC_C_IMP_LEVEL_IDENTIFY, NULL, 
EOAC_NONE, 0);
   if (FAILED (hres))
{
      cout << "初始化安全性失败。错误代码 = 0x" 
      << hex << hres << endl;
      retVal = 1;
      goto CleanUp;
   }
      
对 COM 进行标准调用后,需要通过调用 IWbemLocator::ConnectServer 方法连接到 WMI。ConnectServer 方法返回 IWbemServices 接口的一个代理。 

要创建到 WMI 命名空间的连接,需要通过调用 CoCreateInstance 初始化 IWbemLocator 接口。下面的代码说明了如何初始化 IWbemLocator: 

   IWbemLocator *pLoc = 0;
   hres = CoCreateInstance (CLSID_WbemLocator, 0, 
      CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLoc);

   if (FAILED (hres))
   {
      cout << 
"创建 IWbemLocator 对象失败。错误代码 =           0x" 
<< hex << hres << endl;
      retVal = 1;
      goto CleanUp;
   }
      
通过调用 IWbemLocator::ConnectServer 方法连接到 WMI。 
ConnectServer 方法返回 IWbemServices 接口的一个代理,您可以使用它访问调用 ConnectServer 时指定的本地或远程 WMI 命名空间。调用 ConnectServer 的方法为: 

IWbemServices *pServices = NULL;
   
   // 以当前用户身份连接到 root\cimv2 名称空间。
   hres = pLoc->ConnectServer (
   _bstr_t(L"ROOT\\CIMV2"), 
   NULL,
   NULL,
   0,                                  
   NULL,
   0,                                  
   0,                                  
   &pServices
   );

   if (FAILED(hres))
   {
      cout << "无法连接。错误代码 = 0x" 
      << hex << hres << endl;
      retVal = 1;
      goto CleanUp;
   }
      
检索到 IWbemServices 代理的指针后,需要设置该代理的安全级别以通过它访问 WMI。必须设置安全级别,因为 IWbemServices 代理负责为进程外对象授权。一般来说,如果您对安全性属性的设置不正确,COM 安全性不允许一个进程访问另一个进程。

要设置 WMI 连接的安全性级别,需要通过调用 CoSetProxyBlanket 来设置 IWbemServices 代理的安全性级别。下面是调用 CoSetProxyBlanket 的常用方法:

   // 设置代理,以模拟客户。
   hres = CoSetProxyBlanket(pServices,
   RPC_C_AUTHN_WINNT,
   RPC_C_AUTHZ_NONE,
   NULL,
   RPC_C_AUTHN_LEVEL_CALL,
   RPC_C_IMP_LEVEL_IMPERSONATE,
   NULL,
   EOAC_NONE
   );

   if (FAILED(hres))
   {
      cout << "无法设置代理层。错误代码 = 0x" 
      << hex << hres << endl;
      retVal = 1;
      goto CleanUp;
   }
    
要枚举系统中的所有 Job 对象,GUI 医生通常使用如下代码:

// 枚举 Win32_NamedJobObject 类的实例
   IEnumWbemClassObject *pEnumWbemClsObj;
   BSTR bstrClsName = SysAllocString (L"Win32_NamedJobObject");

      Hres = pServices->CreateInstanceEnum(bstrClsName, 
WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, 
NULL, &pEnumWbemClsObj);
   
SysFreeString(bstrClsName);

   if (FAILED(hres))
   {
      cout << "无法枚举 = 0x" 
      << hex << hres << endl;
      retVal = 1;
      goto CleanUp;
   }

   IWbemClassObject *pclsObj;
   ULONG uReturn = 0;
   cout << "系统中存在的 Job 对象包括:" << endl;

   while(pEnumWbemClsObj)
   {
            HRESULT hr = pEnumWbemClsObj->Next (WBEM_INFINITE, 
1, &pclsObj, &uReturn);

      if (0 == uReturn)
      {
         break;
      }

      VARIANT vtProp;
      VariantInit(&vtProp);
      hr = pclsObj->Get (L"CollectionID", 0, &vtProp, 0, 0);
      CHString str(vtProp.bstrVal);
wcout << "Name: " << (LPCWSTR) str.Mid (1, str.GetLength ()) << endl;
      VariantClear (&vtProp);
}
    
IWbemServices::CreateInstanceEnum 方法将创建一个枚举器,它可以根据用户指定的选择标准返回指定类的实例。将类名指定为 Win32_NamedJobObject 以枚举 Job 对象。Win32_NamedJobObject WMI 类表示用来分组进程以控制 Job 对象中进程的资源和寿命的核心对象。

您还需要获得与进程相关的 Job 对象(名称或句柄)。下面的代码可以帮助您从进程 ID 中查找 Job 对象名称或 Job 对象句柄:

   // 枚举与 Job 对象 
   // Win32_NamedJobObjectProcess
   // 相关的所有进程
   SAFE_INTERFACE_RELEASE (pEnumWbemClsObj);
   bstrClsName = SysAllocString (L"Win32_NamedJobObjectProcess");

hres = pServices->CreateInstanceEnum (bstrClsName, 
 WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, 
NULL, &pEnumWbemClsObj);
   SysFreeString (bstrClsName);

   if (FAILED(hres))
   {
      cout << "无法枚举 = 0x" 
      << hex << hres << endl;
      retVal = 1;
      goto CleanUp;
   }
   SAFE_INTERFACE_RELEASE (pclsObj);
   uReturn = 0;

   cout << endl;

   while (pEnumWbemClsObj)
   {
            HRESULT hr = pEnumWbemClsObj->Next (WBEM_INFINITE, 
1, &pclsObj, &uReturn);
      
            if (0 == uReturn)
      {
         goto CleanUp;
      }
      
            VARIANT vtProp;
      VariantInit (&vtProp);
      hr = pclsObj->Get (L"Member", 0, &vtProp, 0, 0);
      CHString str (vtProp.bstrVal);
      int i = str.GetLength()-1;
      str = str.Right (i - str.Find (L"\""));
      str = str.Mid (0, (str.GetLength () - 1));
            
      // argv[1] 是进程 ID,要寻找与其
            // 相关的 Job 对象。
            if (str.Compare (argv[1]) == 0) //str.Compare("Process ID")
      {
         VariantClear (&vtProp);
         hr = pclsObj->Get (L"Collection", 0, &vtProp, 0, 0);
         str = vtProp.bstrVal;
         int i = str.GetLength ()-1;
         str = str.Right (i - (str.Find (L"\"") + 2));
         i = str.GetLength ()-1;
         str = str.Left (i);
         
         VariantClear (&vtProp);
                  wcout << "Process ID: " << argv[1] << 
"  is attached with Job ID: " << (LPCWSTR)str << endl;
      }

      VariantClear (&vtProp);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值