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