Home | History | Annotate | Download | only in util
      1 // Copyright (c) 2010 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 "chrome/installer/util/wmi.h"
      6 
      7 #include <windows.h>
      8 
      9 #include "base/basictypes.h"
     10 #include "base/win/scoped_bstr.h"
     11 #include "base/win/scoped_comptr.h"
     12 #include "base/win/scoped_variant.h"
     13 
     14 #pragma comment(lib, "wbemuuid.lib")
     15 
     16 using base::win::ScopedVariant;
     17 
     18 namespace installer {
     19 
     20 bool WMI::CreateLocalConnection(bool set_blanket,
     21                                 IWbemServices** wmi_services) {
     22   base::win::ScopedComPtr<IWbemLocator> wmi_locator;
     23   HRESULT hr = wmi_locator.CreateInstance(CLSID_WbemLocator, NULL,
     24                                           CLSCTX_INPROC_SERVER);
     25   if (FAILED(hr))
     26     return false;
     27 
     28   base::win::ScopedComPtr<IWbemServices> wmi_services_r;
     29   hr = wmi_locator->ConnectServer(base::win::ScopedBstr(L"ROOT\\CIMV2"),
     30                                   NULL, NULL, 0, NULL, 0, 0,
     31                                   wmi_services_r.Receive());
     32   if (FAILED(hr))
     33     return false;
     34 
     35   if (set_blanket) {
     36     hr = ::CoSetProxyBlanket(wmi_services_r,
     37                              RPC_C_AUTHN_WINNT,
     38                              RPC_C_AUTHZ_NONE,
     39                              NULL,
     40                              RPC_C_AUTHN_LEVEL_CALL,
     41                              RPC_C_IMP_LEVEL_IMPERSONATE,
     42                              NULL,
     43                              EOAC_NONE);
     44     if (FAILED(hr))
     45       return false;
     46   }
     47 
     48   *wmi_services = wmi_services_r.Detach();
     49   return true;
     50 }
     51 
     52 bool WMI::CreateClassMethodObject(IWbemServices* wmi_services,
     53                                   const std::wstring& class_name,
     54                                   const std::wstring& method_name,
     55                                   IWbemClassObject** class_instance) {
     56   // We attempt to instantiate a COM object that represents a WMI object plus
     57   // a method rolled into one entity.
     58   base::win::ScopedBstr b_class_name(class_name.c_str());
     59   base::win::ScopedBstr b_method_name(method_name.c_str());
     60   base::win::ScopedComPtr<IWbemClassObject> class_object;
     61   HRESULT hr;
     62   hr = wmi_services->GetObject(b_class_name, 0, NULL,
     63                                class_object.Receive(), NULL);
     64   if (FAILED(hr))
     65     return false;
     66 
     67   base::win::ScopedComPtr<IWbemClassObject> params_def;
     68   hr = class_object->GetMethod(b_method_name, 0, params_def.Receive(), NULL);
     69   if (FAILED(hr))
     70     return false;
     71 
     72   if (NULL == params_def) {
     73     // You hit this special case if the WMI class is not a CIM class. MSDN
     74     // sometimes tells you this. Welcome to WMI hell.
     75     return false;
     76   }
     77 
     78   hr = params_def->SpawnInstance(0, class_instance);
     79   return(SUCCEEDED(hr));
     80 }
     81 
     82 bool SetParameter(IWbemClassObject* class_method,
     83                   const std::wstring& parameter_name, VARIANT* parameter) {
     84   HRESULT hr = class_method->Put(parameter_name.c_str(), 0, parameter, 0);
     85   return SUCCEEDED(hr);
     86 }
     87 
     88 
     89 // The code in Launch() basically calls the Create Method of the Win32_Process
     90 // CIM class is documented here:
     91 // http://msdn2.microsoft.com/en-us/library/aa389388(VS.85).aspx
     92 // NOTE: The documentation for the Create method suggests that the ProcessId
     93 // parameter and return value are of type uint32, but when we call the method
     94 // the values in the returned out_params, are VT_I4, which is int32.
     95 
     96 bool WMIProcess::Launch(const std::wstring& command_line, int* process_id) {
     97   base::win::ScopedComPtr<IWbemServices> wmi_local;
     98   if (!WMI::CreateLocalConnection(true, wmi_local.Receive()))
     99     return false;
    100 
    101   const wchar_t class_name[] = L"Win32_Process";
    102   const wchar_t method_name[] = L"Create";
    103   base::win::ScopedComPtr<IWbemClassObject> process_create;
    104   if (!WMI::CreateClassMethodObject(wmi_local, class_name, method_name,
    105                                     process_create.Receive()))
    106     return false;
    107 
    108   ScopedVariant b_command_line(command_line.c_str());
    109 
    110   if (!SetParameter(process_create, L"CommandLine", b_command_line.AsInput()))
    111     return false;
    112 
    113   base::win::ScopedComPtr<IWbemClassObject> out_params;
    114   HRESULT hr = wmi_local->ExecMethod(base::win::ScopedBstr(class_name),
    115                                      base::win::ScopedBstr(method_name),
    116                                      0, NULL, process_create,
    117                                      out_params.Receive(), NULL);
    118   if (FAILED(hr))
    119     return false;
    120 
    121   // We're only expecting int32 or uint32 values, so no need for ScopedVariant.
    122   VARIANT ret_value = {VT_EMPTY};
    123   hr = out_params->Get(L"ReturnValue", 0, &ret_value, NULL, 0);
    124   if (FAILED(hr) || 0 != V_I4(&ret_value))
    125     return false;
    126 
    127   VARIANT pid = {VT_EMPTY};
    128   hr = out_params->Get(L"ProcessId", 0, &pid, NULL, 0);
    129   if (FAILED(hr) || 0 == V_I4(&pid))
    130     return false;
    131 
    132   if (process_id)
    133     *process_id = V_I4(&pid);
    134 
    135   return true;
    136 }
    137 
    138 base::string16 WMIComputerSystem::GetModel() {
    139   base::win::ScopedComPtr<IWbemServices> services;
    140   if (!WMI::CreateLocalConnection(true, services.Receive()))
    141     return base::string16();
    142 
    143   base::win::ScopedBstr query_language(L"WQL");
    144   base::win::ScopedBstr query(L"SELECT * FROM Win32_ComputerSystem");
    145   base::win::ScopedComPtr<IEnumWbemClassObject> enumerator;
    146   HRESULT hr = services->ExecQuery(
    147       query_language, query,
    148       WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL,
    149       enumerator.Receive());
    150   if (FAILED(hr) || !enumerator)
    151     return base::string16();
    152 
    153   base::win::ScopedComPtr<IWbemClassObject> class_object;
    154   ULONG items_returned = 0;
    155   hr = enumerator->Next(WBEM_INFINITE, 1,  class_object.Receive(),
    156                         &items_returned);
    157   if (!items_returned)
    158     return base::string16();
    159 
    160   base::win::ScopedVariant manufacturer;
    161   class_object->Get(L"Manufacturer", 0, manufacturer.Receive(), 0, 0);
    162   base::win::ScopedVariant model;
    163   class_object->Get(L"Model", 0, model.Receive(), 0, 0);
    164 
    165   base::string16 model_string;
    166   if (manufacturer.type() == VT_BSTR) {
    167     model_string = V_BSTR(&manufacturer);
    168     if (model.type() == VT_BSTR)
    169       model_string += L" ";
    170   }
    171   if (model.type() == VT_BSTR)
    172     model_string += V_BSTR(&model);
    173 
    174   return model_string;
    175 }
    176 
    177 }  // namespace installer
    178