15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2010 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/wmi.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_bstr.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_comptr.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_variant.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma comment(lib, "wbemuuid.lib")
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::win::ScopedVariant;
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace installer {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WMI::CreateLocalConnection(bool set_blanket,
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                IWbemServices** wmi_services) {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedComPtr<IWbemLocator> wmi_locator;
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = wmi_locator.CreateInstance(CLSID_WbemLocator, NULL,
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          CLSCTX_INPROC_SERVER);
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr))
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedComPtr<IWbemServices> wmi_services_r;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = wmi_locator->ConnectServer(base::win::ScopedBstr(L"ROOT\\CIMV2"),
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  NULL, NULL, 0, NULL, 0, 0,
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  wmi_services_r.Receive());
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr))
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (set_blanket) {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = ::CoSetProxyBlanket(wmi_services_r,
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             RPC_C_AUTHN_WINNT,
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             RPC_C_AUTHZ_NONE,
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             NULL,
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             RPC_C_AUTHN_LEVEL_CALL,
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             RPC_C_IMP_LEVEL_IMPERSONATE,
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             NULL,
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             EOAC_NONE);
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (FAILED(hr))
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *wmi_services = wmi_services_r.Detach();
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WMI::CreateClassMethodObject(IWbemServices* wmi_services,
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const std::wstring& class_name,
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const std::wstring& method_name,
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  IWbemClassObject** class_instance) {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We attempt to instantiate a COM object that represents a WMI object plus
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a method rolled into one entity.
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedBstr b_class_name(class_name.c_str());
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedBstr b_method_name(method_name.c_str());
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedComPtr<IWbemClassObject> class_object;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = wmi_services->GetObject(b_class_name, 0, NULL,
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               class_object.Receive(), NULL);
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr))
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedComPtr<IWbemClassObject> params_def;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = class_object->GetMethod(b_method_name, 0, params_def.Receive(), NULL);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr))
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (NULL == params_def) {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // You hit this special case if the WMI class is not a CIM class. MSDN
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // sometimes tells you this. Welcome to WMI hell.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = params_def->SpawnInstance(0, class_instance);
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return(SUCCEEDED(hr));
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SetParameter(IWbemClassObject* class_method,
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  const std::wstring& parameter_name, VARIANT* parameter) {
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = class_method->Put(parameter_name.c_str(), 0, parameter, 0);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SUCCEEDED(hr);
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The code in Launch() basically calls the Create Method of the Win32_Process
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// CIM class is documented here:
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://msdn2.microsoft.com/en-us/library/aa389388(VS.85).aspx
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// NOTE: The documentation for the Create method suggests that the ProcessId
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// parameter and return value are of type uint32, but when we call the method
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the values in the returned out_params, are VT_I4, which is int32.
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WMIProcess::Launch(const std::wstring& command_line, int* process_id) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedComPtr<IWbemServices> wmi_local;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!WMI::CreateLocalConnection(true, wmi_local.Receive()))
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const wchar_t class_name[] = L"Win32_Process";
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const wchar_t method_name[] = L"Create";
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedComPtr<IWbemClassObject> process_create;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!WMI::CreateClassMethodObject(wmi_local, class_name, method_name,
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    process_create.Receive()))
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedVariant b_command_line(command_line.c_str());
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!SetParameter(process_create, L"CommandLine", b_command_line.AsInput()))
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedComPtr<IWbemClassObject> out_params;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = wmi_local->ExecMethod(base::win::ScopedBstr(class_name),
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     base::win::ScopedBstr(method_name),
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     0, NULL, process_create,
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     out_params.Receive(), NULL);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr))
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We're only expecting int32 or uint32 values, so no need for ScopedVariant.
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VARIANT ret_value = {VT_EMPTY};
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = out_params->Get(L"ReturnValue", 0, &ret_value, NULL, 0);
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr) || 0 != V_I4(&ret_value))
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VARIANT pid = {VT_EMPTY};
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = out_params->Get(L"ProcessId", 0, &pid, NULL, 0);
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr) || 0 == V_I4(&pid))
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (process_id)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *process_id = V_I4(&pid);
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 WMIComputerSystem::GetModel() {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedComPtr<IWbemServices> services;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!WMI::CreateLocalConnection(true, services.Receive()))
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return base::string16();
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedBstr query_language(L"WQL");
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedBstr query(L"SELECT * FROM Win32_ComputerSystem");
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedComPtr<IEnumWbemClassObject> enumerator;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = services->ExecQuery(
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      query_language, query,
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL,
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      enumerator.Receive());
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr) || !enumerator)
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return base::string16();
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedComPtr<IWbemClassObject> class_object;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ULONG items_returned = 0;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = enumerator->Next(WBEM_INFINITE, 1,  class_object.Receive(),
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        &items_returned);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!items_returned)
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return base::string16();
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedVariant manufacturer;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  class_object->Get(L"Manufacturer", 0, manufacturer.Receive(), 0, 0);
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedVariant model;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  class_object->Get(L"Model", 0, model.Receive(), 0, 0);
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 model_string;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (manufacturer.type() == VT_BSTR) {
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    model_string = V_BSTR(&manufacturer);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (model.type() == VT_BSTR)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      model_string += L" ";
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (model.type() == VT_BSTR)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    model_string += V_BSTR(&model);
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return model_string;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace installer
178