Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(224)

Side by Side Diff: chrome/browser/conflicts/msi_util_win.cc

Issue 2854983002: Add the ThirdPartyModules.Uninstallable histogram. (Closed)
Patch Set: Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 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/browser/conflicts/msi_util_win.h"
6
7 #include <windows.h>
8
9 #include <msi.h>
10 #include <msiquery.h>
11
12 #include <utility>
13
14 #include "base/strings/string_util.h"
15 #include "base/threading/thread_restrictions.h"
16
17 namespace {
18
19 GetMsiComponentPathsOverride* g_get_msi_component_paths = nullptr;
20
21 // Retrieves the file path to the product's installer.
22 bool GetMsiPath(const base::string16& product_guid, base::string16* result) {
23 DWORD buffer_size = 0;
24 if (::MsiGetProductInfo(product_guid.c_str(), INSTALLPROPERTY_LOCALPACKAGE,
25 L"", &buffer_size) != ERROR_MORE_DATA)
26 return false;
27
28 // Must account for the null terminator.
29 buffer_size++;
30
31 return ::MsiGetProductInfo(product_guid.c_str(), INSTALLPROPERTY_LOCALPACKAGE,
32 base::WriteInto(result, buffer_size),
33 &buffer_size) == ERROR_SUCCESS;
34 }
35
36 // Returns the string value at position |index| in the given |record_handle|.
37 // Note that columns are 1-indexed.
38 bool GetRecordString(MSIHANDLE record_handle,
39 size_t index,
40 base::string16* result) {
41 DWORD buffer_size = 0;
42 if (::MsiRecordGetString(record_handle, index, L"", &buffer_size) !=
43 ERROR_MORE_DATA)
44 return false;
45
46 // Must account for the null terminator.
47 buffer_size++;
48
49 return ::MsiRecordGetString(record_handle, index,
50 base::WriteInto(result, buffer_size),
51 &buffer_size) == ERROR_SUCCESS;
52 }
53
54 // Inspects the installer file and extracts the component guids. Each .msi file
55 // is actually an SQL database.
56 bool GetMsiComponentGuids(const base::string16& msi_database_path,
57 std::vector<base::string16>* component_guids) {
58 PMSIHANDLE msi_database_handle;
59 if (::MsiOpenDatabase(msi_database_path.c_str(), MSIDBOPEN_READONLY,
60 &msi_database_handle) != ERROR_SUCCESS) {
61 return false;
62 }
63
64 PMSIHANDLE components_view_handle;
65 if (::MsiDatabaseOpenView(msi_database_handle,
66 L"SELECT ComponentId FROM Component",
67 &components_view_handle) != ERROR_SUCCESS) {
68 return false;
69 }
70
71 if (::MsiViewExecute(components_view_handle, 0) != ERROR_SUCCESS)
72 return false;
73
74 PMSIHANDLE record_handle;
75 while (::MsiViewFetch(components_view_handle, &record_handle) ==
76 ERROR_SUCCESS) {
77 // The record only have the ComponentId column, and its index is 1.
78 base::string16 component_guid;
79 if (GetRecordString(record_handle, 1, &component_guid))
80 component_guids->push_back(std::move(component_guid));
81 }
82
83 return true;
84 }
85
86 // Retrieves the |path| to the given component.
87 bool GetMsiComponentPath(const base::string16& product_guid,
88 const base::string16& component_guid,
89 base::string16* path) {
90 DWORD buffer_size = 0;
91 if (::MsiGetComponentPath(product_guid.c_str(), component_guid.c_str(), L"",
92 &buffer_size) != INSTALLSTATE_MOREDATA) {
93 return false;
94 }
95
96 // Must account for the null terminator.
97 buffer_size++;
98
99 return ::MsiGetComponentPath(product_guid.c_str(), component_guid.c_str(),
100 base::WriteInto(path, buffer_size),
101 &buffer_size) == INSTALLSTATE_LOCAL;
102 }
103
104 } // namespace
105
106 // The most efficient way to get the list of components associated to an
107 // installed product is to inspect the installer file. A copy of the installer
108 // exists somewhere on the file system because Windows needs it to uninstall the
109 // product.
110 //
111 // So this function retrieves the path to the installer, extract the component
112 // GUIDS from it, and uses those to find the path of each component.
113 bool GetMsiComponentPaths(const base::string16& product_guid,
114 std::vector<base::string16>* component_paths) {
115 base::ThreadRestrictions::AssertIOAllowed();
116
117 if (g_get_msi_component_paths)
118 return g_get_msi_component_paths->Run(product_guid, component_paths);
119
120 base::string16 msi_path;
121 if (!GetMsiPath(product_guid, &msi_path))
122 return false;
123
124 std::vector<base::string16> component_guids;
125 if (!GetMsiComponentGuids(msi_path, &component_guids))
126 return false;
127
128 for (const auto& component_guid : component_guids) {
129 base::string16 component_path;
130 if (!GetMsiComponentPath(product_guid, component_guid, &component_path))
131 continue;
132
133 component_paths->push_back(std::move(component_path));
134 }
135
136 return true;
137 }
138
139 ScopedGetMsiComponentPathsOverride::ScopedGetMsiComponentPathsOverride(
140 const GetMsiComponentPathsOverride& override)
141 : override_(override) {
142 DCHECK(!g_get_msi_component_paths);
143 g_get_msi_component_paths = &override_;
144 }
145
146 ScopedGetMsiComponentPathsOverride::~ScopedGetMsiComponentPathsOverride() {
147 DCHECK(g_get_msi_component_paths);
148 g_get_msi_component_paths = nullptr;
149 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698