Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <windows.h>
      6 #include "base/basictypes.h"
      7 #include "base/scoped_bstr_win.h"
      8 #include "base/scoped_comptr_win.h"
      9 
     10 #pragma comment(lib, "wbemuuid.lib")
     11 
     12 #include "base/wmi_util.h"
     13 
     14 namespace {
     15 // Simple class to manage the lifetime of a variant.
     16 // TODO(tommi): Replace this for a more useful class.
     17 class VariantHelper : public VARIANT {
     18  public:
     19   VariantHelper() {
     20     vt = VT_EMPTY;
     21   }
     22   explicit VariantHelper(VARTYPE type) {
     23     vt = type;
     24   }
     25   ~VariantHelper() {
     26     ::VariantClear(this);
     27   }
     28  private:
     29   DISALLOW_COPY_AND_ASSIGN(VariantHelper);
     30 };
     31 
     32 }  // namespace
     33 
     34 bool WMIUtil::CreateLocalConnection(bool set_blanket,
     35                                     IWbemServices** wmi_services) {
     36   ScopedComPtr<IWbemLocator> wmi_locator;
     37   HRESULT hr = wmi_locator.CreateInstance(CLSID_WbemLocator, NULL,
     38                                           CLSCTX_INPROC_SERVER);
     39   if (FAILED(hr))
     40     return false;
     41 
     42   ScopedComPtr<IWbemServices> wmi_services_r;
     43   hr = wmi_locator->ConnectServer(StackBstr(L"ROOT\\CIMV2"), NULL, NULL, 0,
     44                                   NULL, 0, 0, wmi_services_r.Receive());
     45   if (FAILED(hr))
     46     return false;
     47 
     48   if (set_blanket) {
     49     hr = ::CoSetProxyBlanket(wmi_services_r,
     50                              RPC_C_AUTHN_WINNT,
     51                              RPC_C_AUTHZ_NONE,
     52                              NULL,
     53                              RPC_C_AUTHN_LEVEL_CALL,
     54                              RPC_C_IMP_LEVEL_IMPERSONATE,
     55                              NULL,
     56                              EOAC_NONE);
     57     if (FAILED(hr))
     58       return false;
     59   }
     60 
     61   *wmi_services = wmi_services_r.Detach();
     62   return true;
     63 }
     64 
     65 bool WMIUtil::CreateClassMethodObject(IWbemServices* wmi_services,
     66                                       const std::wstring& class_name,
     67                                       const std::wstring& method_name,
     68                                       IWbemClassObject** class_instance) {
     69   // We attempt to instantiate a COM object that represents a WMI object plus
     70   // a method rolled into one entity.
     71   ScopedBstr b_class_name(class_name.c_str());
     72   ScopedBstr b_method_name(method_name.c_str());
     73   ScopedComPtr<IWbemClassObject> class_object;
     74   HRESULT hr;
     75   hr = wmi_services->GetObject(b_class_name, 0, NULL,
     76                                class_object.Receive(), NULL);
     77   if (FAILED(hr))
     78     return false;
     79 
     80   ScopedComPtr<IWbemClassObject> params_def;
     81   hr = class_object->GetMethod(b_method_name, 0, params_def.Receive(), NULL);
     82   if (FAILED(hr))
     83     return false;
     84 
     85   if (NULL == params_def) {
     86     // You hit this special case if the WMI class is not a CIM class. MSDN
     87     // sometimes tells you this. Welcome to WMI hell.
     88     return false;
     89   }
     90 
     91   hr = params_def->SpawnInstance(0, class_instance);
     92   return(SUCCEEDED(hr));
     93 }
     94 
     95 bool SetParameter(IWbemClassObject* class_method,
     96                   const std::wstring& parameter_name, VARIANT* parameter) {
     97   HRESULT hr = class_method->Put(parameter_name.c_str(), 0, parameter, 0);
     98   return SUCCEEDED(hr);
     99 }
    100 
    101 
    102 // The code in Launch() basically calls the Create Method of the Win32_Process
    103 // CIM class is documented here:
    104 // http://msdn2.microsoft.com/en-us/library/aa389388(VS.85).aspx
    105 
    106 bool WMIProcessUtil::Launch(const std::wstring& command_line, int* process_id) {
    107   ScopedComPtr<IWbemServices> wmi_local;
    108   if (!WMIUtil::CreateLocalConnection(true, wmi_local.Receive()))
    109     return false;
    110 
    111   const wchar_t class_name[] = L"Win32_Process";
    112   const wchar_t method_name[] = L"Create";
    113   ScopedComPtr<IWbemClassObject> process_create;
    114   if (!WMIUtil::CreateClassMethodObject(wmi_local, class_name, method_name,
    115                                         process_create.Receive()))
    116     return false;
    117 
    118   VariantHelper b_command_line(VT_BSTR);
    119   b_command_line.bstrVal = ::SysAllocString(command_line.c_str());
    120 
    121   if (!SetParameter(process_create, L"CommandLine", &b_command_line))
    122     return false;
    123 
    124   ScopedComPtr<IWbemClassObject> out_params;
    125   HRESULT hr = wmi_local->ExecMethod(StackBstr(class_name),
    126                                      StackBstr(method_name), 0, NULL,
    127                                      process_create, out_params.Receive(),
    128                                      NULL);
    129   if (FAILED(hr))
    130     return false;
    131 
    132   VariantHelper ret_value;
    133   hr = out_params->Get(L"ReturnValue", 0, &ret_value, NULL, 0);
    134   if (FAILED(hr) || (0 != ret_value.uintVal))
    135     return false;
    136 
    137   VariantHelper pid;
    138   hr = out_params->Get(L"ProcessId", 0, &pid, NULL, 0);
    139   if (FAILED(hr) || (0 == pid.intVal))
    140     return false;
    141 
    142   if (process_id)
    143     *process_id = pid.intVal;
    144 
    145   return true;
    146 }
    147