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
16using base::win::ScopedVariant;
17
18namespace installer {
19
20bool 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
52bool 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
82bool 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
96bool 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
138base::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