summaryrefslogtreecommitdiffstats
path: root/chrome/installer/util
diff options
context:
space:
mode:
authorbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-10 20:14:48 +0000
committerbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-10 20:14:48 +0000
commit54519a4e3eb314153b0cdf9ae96a2fbaffb7a217 (patch)
tree755447f058c35530a0ed75c2b2f427d1653d4319 /chrome/installer/util
parent8bac235e7c08c21851934cf771d7d473b3beca4d (diff)
downloadchromium_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.cc4
-rw-r--r--chrome/installer/util/google_chrome_distribution_dummy.cc117
-rw-r--r--chrome/installer/util/wmi.cc152
-rw-r--r--chrome/installer/util/wmi.h78
-rw-r--r--chrome/installer/util/wmi_unittest.cc59
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