diff options
author | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-10 20:14:48 +0000 |
---|---|---|
committer | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-10 20:14:48 +0000 |
commit | 54519a4e3eb314153b0cdf9ae96a2fbaffb7a217 (patch) | |
tree | 755447f058c35530a0ed75c2b2f427d1653d4319 /chrome/installer/util | |
parent | 8bac235e7c08c21851934cf771d7d473b3beca4d (diff) | |
download | chromium_src-54519a4e3eb314153b0cdf9ae96a2fbaffb7a217.zip chromium_src-54519a4e3eb314153b0cdf9ae96a2fbaffb7a217.tar.gz chromium_src-54519a4e3eb314153b0cdf9ae96a2fbaffb7a217.tar.bz2 |
Move wmi_util out of base and into chrome/installer/util since that's the only place where it's used.
TEST=it compiles
BUG=none
Review URL: http://codereview.chromium.org/3696001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@62123 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/installer/util')
-rw-r--r-- | chrome/installer/util/google_chrome_distribution.cc | 4 | ||||
-rw-r--r-- | chrome/installer/util/google_chrome_distribution_dummy.cc | 117 | ||||
-rw-r--r-- | chrome/installer/util/wmi.cc | 152 | ||||
-rw-r--r-- | chrome/installer/util/wmi.h | 78 | ||||
-rw-r--r-- | chrome/installer/util/wmi_unittest.cc | 59 |
5 files changed, 398 insertions, 12 deletions
diff --git a/chrome/installer/util/google_chrome_distribution.cc b/chrome/installer/util/google_chrome_distribution.cc index bb9a5a6..9715e71 100644 --- a/chrome/installer/util/google_chrome_distribution.cc +++ b/chrome/installer/util/google_chrome_distribution.cc @@ -22,7 +22,6 @@ #include "base/string_util.h" #include "base/utf_string_conversions.h" #include "base/win_util.h" -#include "base/wmi_util.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/json_value_serializer.h" #include "chrome/common/pref_names.h" @@ -33,6 +32,7 @@ #include "chrome/installer/util/google_update_settings.h" #include "chrome/installer/util/helper.h" #include "chrome/installer/util/util_constants.h" +#include "chrome/installer/util/wmi.h" #include "installer_util_strings.h" @@ -373,7 +373,7 @@ void GoogleChromeDistribution::DoPostUninstallOperations( // process runs inside a Job object controlled by the shell. As long as there // are processes running, the shell will not close the uninstall applet. WMI // allows us to escape from the Job object so the applet will close. - WMIProcessUtil::Launch(command, &pid); + installer::WMIProcess::Launch(command, &pid); } std::wstring GoogleChromeDistribution::GetAppGuid() { diff --git a/chrome/installer/util/google_chrome_distribution_dummy.cc b/chrome/installer/util/google_chrome_distribution_dummy.cc index 0f13891..b2cafe9 100644 --- a/chrome/installer/util/google_chrome_distribution_dummy.cc +++ b/chrome/installer/util/google_chrome_distribution_dummy.cc @@ -14,10 +14,110 @@ #include "base/logging.h" -bool GoogleChromeDistribution::BuildUninstallMetricsString( - DictionaryValue* uninstall_metrics_dict, std::wstring* metrics) { +GoogleChromeDistribution::GoogleChromeDistribution() { +} + +void GoogleChromeDistribution::DoPostUninstallOperations( + const installer::Version& version, + const std::wstring& local_data_path, + const std::wstring& distribution_data) { +} + +std::wstring GoogleChromeDistribution::GetAppGuid() { + NOTREACHED(); + return std::wstring(); +} + +std::wstring GoogleChromeDistribution::GetApplicationName() { + NOTREACHED(); + return std::wstring(); +} + +std::wstring GoogleChromeDistribution::GetAlternateApplicationName() { + NOTREACHED(); + return std::wstring(); +} + +std::wstring GoogleChromeDistribution::GetBrowserAppId() { + NOTREACHED(); + return std::wstring(); +} + +std::wstring GoogleChromeDistribution::GetInstallSubDir() { + NOTREACHED(); + return std::wstring(); +} + +std::wstring GoogleChromeDistribution::GetPublisherName() { + NOTREACHED(); + return std::wstring(); +} + +std::wstring GoogleChromeDistribution::GetAppDescription() { + NOTREACHED(); + return std::wstring(); +} + +std::string GoogleChromeDistribution::GetSafeBrowsingName() { + NOTREACHED(); + return std::string(); +} + +std::wstring GoogleChromeDistribution::GetStateKey() { + NOTREACHED(); + return std::wstring(); +} + +std::wstring GoogleChromeDistribution::GetStateMediumKey() { + NOTREACHED(); + return std::wstring(); +} + +std::wstring GoogleChromeDistribution::GetStatsServerURL() { + NOTREACHED(); + return std::wstring(); +} + +std::wstring GoogleChromeDistribution::GetDistributionData(RegKey* key) { + NOTREACHED(); + return std::wstring(); +} + +std::wstring GoogleChromeDistribution::GetUninstallLinkName() { + NOTREACHED(); + return std::wstring(); +} + +std::wstring GoogleChromeDistribution::GetUninstallRegPath() { + NOTREACHED(); + return std::wstring(); +} + +std::wstring GoogleChromeDistribution::GetVersionKey() { + NOTREACHED(); + return std::wstring(); +} + +std::wstring GoogleChromeDistribution::GetEnvVersionKey() { + NOTREACHED(); + return std::wstring(); +} + +void GoogleChromeDistribution::UpdateDiffInstallStatus(bool system_install, + bool incremental_install, installer_util::InstallStatus install_status) { + NOTREACHED(); +} + +void GoogleChromeDistribution::LaunchUserExperiment( + installer_util::InstallStatus status, const installer::Version& version, + bool system_install) { + NOTREACHED(); +} + +void GoogleChromeDistribution::InactiveUserToastExperiment( + int flavor, + bool system_install) { NOTREACHED(); - return false; } bool GoogleChromeDistribution::ExtractUninstallMetricsFromFile( @@ -32,12 +132,9 @@ bool GoogleChromeDistribution::ExtractUninstallMetrics( return false; } -void GoogleChromeDistribution::LaunchUserExperiment( - installer_util::InstallStatus status, const installer::Version& version, - bool system_install) { - NOTREACHED(); -} -void GoogleChromeDistribution::InactiveUserToastExperiment(int flavor, - bool system_install) { +bool GoogleChromeDistribution::BuildUninstallMetricsString( + DictionaryValue* uninstall_metrics_dict, std::wstring* metrics) { NOTREACHED(); + return false; } + diff --git a/chrome/installer/util/wmi.cc b/chrome/installer/util/wmi.cc new file mode 100644 index 0000000..957ec99 --- /dev/null +++ b/chrome/installer/util/wmi.cc @@ -0,0 +1,152 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/installer/util/wmi.h" + +#include <windows.h> + +#include "base/basictypes.h" +#include "base/scoped_bstr_win.h" +#include "base/scoped_comptr_win.h" + +#pragma comment(lib, "wbemuuid.lib") + +namespace installer { + +namespace { + +// Simple class to manage the lifetime of a variant. +// TODO(tommi): Replace this for a more useful class. +class VariantHelper : public VARIANT { + public: + VariantHelper() { + vt = VT_EMPTY; + } + explicit VariantHelper(VARTYPE type) { + vt = type; + } + ~VariantHelper() { + ::VariantClear(this); + } + private: + DISALLOW_COPY_AND_ASSIGN(VariantHelper); +}; + +} // namespace + +bool WMI::CreateLocalConnection(bool set_blanket, + IWbemServices** wmi_services) { + ScopedComPtr<IWbemLocator> wmi_locator; + HRESULT hr = wmi_locator.CreateInstance(CLSID_WbemLocator, NULL, + CLSCTX_INPROC_SERVER); + if (FAILED(hr)) + return false; + + ScopedComPtr<IWbemServices> wmi_services_r; + hr = wmi_locator->ConnectServer(StackBstr(L"ROOT\\CIMV2"), NULL, NULL, 0, + NULL, 0, 0, wmi_services_r.Receive()); + if (FAILED(hr)) + return false; + + if (set_blanket) { + hr = ::CoSetProxyBlanket(wmi_services_r, + RPC_C_AUTHN_WINNT, + RPC_C_AUTHZ_NONE, + NULL, + RPC_C_AUTHN_LEVEL_CALL, + RPC_C_IMP_LEVEL_IMPERSONATE, + NULL, + EOAC_NONE); + if (FAILED(hr)) + return false; + } + + *wmi_services = wmi_services_r.Detach(); + return true; +} + +bool WMI::CreateClassMethodObject(IWbemServices* wmi_services, + const std::wstring& class_name, + const std::wstring& method_name, + IWbemClassObject** class_instance) { + // We attempt to instantiate a COM object that represents a WMI object plus + // a method rolled into one entity. + ScopedBstr b_class_name(class_name.c_str()); + ScopedBstr b_method_name(method_name.c_str()); + ScopedComPtr<IWbemClassObject> class_object; + HRESULT hr; + hr = wmi_services->GetObject(b_class_name, 0, NULL, + class_object.Receive(), NULL); + if (FAILED(hr)) + return false; + + ScopedComPtr<IWbemClassObject> params_def; + hr = class_object->GetMethod(b_method_name, 0, params_def.Receive(), NULL); + if (FAILED(hr)) + return false; + + if (NULL == params_def) { + // You hit this special case if the WMI class is not a CIM class. MSDN + // sometimes tells you this. Welcome to WMI hell. + return false; + } + + hr = params_def->SpawnInstance(0, class_instance); + return(SUCCEEDED(hr)); +} + +bool SetParameter(IWbemClassObject* class_method, + const std::wstring& parameter_name, VARIANT* parameter) { + HRESULT hr = class_method->Put(parameter_name.c_str(), 0, parameter, 0); + return SUCCEEDED(hr); +} + + +// The code in Launch() basically calls the Create Method of the Win32_Process +// CIM class is documented here: +// http://msdn2.microsoft.com/en-us/library/aa389388(VS.85).aspx + +bool WMIProcess::Launch(const std::wstring& command_line, int* process_id) { + ScopedComPtr<IWbemServices> wmi_local; + if (!WMI::CreateLocalConnection(true, wmi_local.Receive())) + return false; + + const wchar_t class_name[] = L"Win32_Process"; + const wchar_t method_name[] = L"Create"; + ScopedComPtr<IWbemClassObject> process_create; + if (!WMI::CreateClassMethodObject(wmi_local, class_name, method_name, + process_create.Receive())) + return false; + + VariantHelper b_command_line(VT_BSTR); + b_command_line.bstrVal = ::SysAllocString(command_line.c_str()); + + if (!SetParameter(process_create, L"CommandLine", &b_command_line)) + return false; + + ScopedComPtr<IWbemClassObject> out_params; + HRESULT hr = wmi_local->ExecMethod(StackBstr(class_name), + StackBstr(method_name), 0, NULL, + process_create, out_params.Receive(), + NULL); + if (FAILED(hr)) + return false; + + VariantHelper ret_value; + hr = out_params->Get(L"ReturnValue", 0, &ret_value, NULL, 0); + if (FAILED(hr) || (0 != ret_value.uintVal)) + return false; + + VariantHelper pid; + hr = out_params->Get(L"ProcessId", 0, &pid, NULL, 0); + if (FAILED(hr) || (0 == pid.intVal)) + return false; + + if (process_id) + *process_id = pid.intVal; + + return true; +} + +} // namespace installer diff --git a/chrome/installer/util/wmi.h b/chrome/installer/util/wmi.h new file mode 100644 index 0000000..5d0a1a9 --- /dev/null +++ b/chrome/installer/util/wmi.h @@ -0,0 +1,78 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// WMI (Windows Management and Instrumentation) is a big, complex, COM-based +// API that can be used to perform all sorts of things. Sometimes is the best +// way to accomplish something under windows but its lack of an approachable +// C++ interface prevents its use. This collection of fucntions is a step in +// that direction. +// There are two classes; WMIUtil and WMIProcessUtil. The first +// one contain generic helpers and the second one contains the only +// functionality that is needed right now which is to use WMI to launch a +// process. +// To use any function on this header you must call CoInitialize or +// CoInitializeEx beforehand. +// +// For more information about WMI programming: +// http://msdn2.microsoft.com/en-us/library/aa384642(VS.85).aspx + +#ifndef CHROME_INSTALLER_UTIL_WMI_H_ +#define CHROME_INSTALLER_UTIL_WMI_H_ +#pragma once + +#include <string> +#include <wbemidl.h> + +namespace installer { + +class WMI { + public: + // Creates an instance of the WMI service connected to the local computer and + // returns its COM interface. If 'set-blanket' is set to true, the basic COM + // security blanket is applied to the returned interface. This is almost + // always desirable unless you set the parameter to false and apply a custom + // COM security blanket. + // Returns true if succeeded and 'wmi_services': the pointer to the service. + // When done with the interface you must call Release(); + static bool CreateLocalConnection(bool set_blanket, + IWbemServices** wmi_services); + + // Creates a WMI method using from a WMI class named 'class_name' that + // contains a method named 'method_name'. Only WMI classes that are CIM + // classes can be created using this function. + // Returns true if succeeded and 'class_instance' returns a pointer to the + // WMI method that you can fill with parameter values using SetParameter. + // When done with the interface you must call Release(); + static bool CreateClassMethodObject(IWbemServices* wmi_services, + const std::wstring& class_name, + const std::wstring& method_name, + IWbemClassObject** class_instance); + + // Fills a single parameter given an instanced 'class_method'. Returns true + // if operation succeeded. When all the parameters are set the method can + // be executed using IWbemServices::ExecMethod(). + static bool SetParameter(IWbemClassObject* class_method, + const std::wstring& parameter_name, + VARIANT* parameter); +}; + +// This class contains functionality of the WMI class 'Win32_Process' +// more info: http://msdn2.microsoft.com/en-us/library/aa394372(VS.85).aspx +class WMIProcess { + public: + // Creates a new process from 'command_line'. The advantage over CreateProcess + // is that it allows you to always break out from a Job object that the caller + // is attached to even if the Job object flags prevent that. + // Returns true and the process id in process_id if the process is launched + // successful. False otherwise. + // Note that a fully qualified path must be specified in most cases unless + // the program is not in the search path of winmgmt.exe. + // Processes created this way are children of wmiprvse.exe and run with the + // caller credentials. + static bool Launch(const std::wstring& command_line, int* process_id); +}; + +} // namespace installer + +#endif // CHROME_INSTALLER_UTIL_WMI_H_ diff --git a/chrome/installer/util/wmi_unittest.cc b/chrome/installer/util/wmi_unittest.cc new file mode 100644 index 0000000..591f688 --- /dev/null +++ b/chrome/installer/util/wmi_unittest.cc @@ -0,0 +1,59 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <windows.h> + +#include "chrome/installer/util/wmi.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace installer { + +TEST(WMITest, TestLocalConnectionSecurityBlanket) { + ::CoInitialize(NULL); + IWbemServices* services = NULL; + EXPECT_TRUE(WMI::CreateLocalConnection(true, &services)); + ASSERT_TRUE(NULL != services); + ULONG refs = services->Release(); + EXPECT_EQ(refs, 0); + ::CoUninitialize(); +} + +TEST(WMITest, TestLocalConnectionNoSecurityBlanket) { + ::CoInitialize(NULL); + IWbemServices* services = NULL; + EXPECT_TRUE(WMI::CreateLocalConnection(false, &services)); + ASSERT_TRUE(NULL != services); + ULONG refs = services->Release(); + EXPECT_EQ(refs, 0); + ::CoUninitialize(); +} + +TEST(WMITest, TestCreateClassMethod) { + ::CoInitialize(NULL); + IWbemServices* wmi_services = NULL; + EXPECT_TRUE(WMI::CreateLocalConnection(true, &wmi_services)); + ASSERT_TRUE(NULL != wmi_services); + IWbemClassObject* class_method = NULL; + EXPECT_TRUE(WMI::CreateClassMethodObject(wmi_services, + L"Win32_ShortcutFile", + L"Rename", &class_method)); + ASSERT_TRUE(NULL != class_method); + ULONG refs = class_method->Release(); + EXPECT_EQ(refs, 0); + refs = wmi_services->Release(); + EXPECT_EQ(refs, 0); + ::CoUninitialize(); +} + +// Creates an instance of cmd which executes 'echo' and exits immediately. +TEST(WMITest, TestLaunchProcess) { + ::CoInitialize(NULL); + int pid = 0; + bool result = WMIProcess::Launch(L"cmd.exe /c echo excelent!", &pid); + EXPECT_TRUE(result); + EXPECT_GT(pid, 0); + ::CoUninitialize(); +} + +} // namespace installer |