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

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

Issue 2854143005: Add a utility class to retrieve the components of an MSI product (Closed)
Patch Set: Basing the patch on another cl 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
« no previous file with comments | « chrome/browser/conflicts/msi_util_win.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 // Retrieves the file path to the product's installer.
20 bool GetMsiPath(const base::string16& product_guid, base::string16* result) {
21 DWORD buffer_size = 0;
22 if (::MsiGetProductInfo(product_guid.c_str(), INSTALLPROPERTY_LOCALPACKAGE,
chrisha1 2017/05/05 20:01:40 Document that you're querying first for the requir
Patrick Monette 2017/05/06 00:54:37 Done. Let me know if you have any idea to make the
23 L"", &buffer_size) != ERROR_MORE_DATA)
24 return false;
25
26 // Must account for the null terminator.
27 buffer_size++;
28
29 return ::MsiGetProductInfo(product_guid.c_str(), INSTALLPROPERTY_LOCALPACKAGE,
30 base::WriteInto(result, buffer_size),
31 &buffer_size) == ERROR_SUCCESS;
32 }
33
34 // Returns the string value at position |index| in the given |record_handle|.
35 // Note that columns are 1-indexed.
36 bool GetRecordString(MSIHANDLE record_handle,
37 size_t index,
38 base::string16* result) {
39 DWORD buffer_size = 0;
40 if (::MsiRecordGetString(record_handle, index, L"", &buffer_size) !=
41 ERROR_MORE_DATA)
42 return false;
43
44 // Must account for the null terminator.
45 buffer_size++;
chrisha1 2017/05/05 20:01:40 Ditto for this read. If you have reason to believe
Patrick Monette 2017/05/06 00:54:37 Done.
46
47 return ::MsiRecordGetString(record_handle, index,
48 base::WriteInto(result, buffer_size),
49 &buffer_size) == ERROR_SUCCESS;
50 }
51
52 // Inspects the installer file and extracts the component guids. Each .msi file
53 // is actually an SQL database.
54 bool GetMsiComponentGuids(const base::string16& msi_database_path,
55 std::vector<base::string16>* component_guids) {
56 PMSIHANDLE msi_database_handle;
57 if (::MsiOpenDatabase(msi_database_path.c_str(), MSIDBOPEN_READONLY,
58 &msi_database_handle) != ERROR_SUCCESS) {
59 return false;
60 }
61
62 PMSIHANDLE components_view_handle;
63 if (::MsiDatabaseOpenView(msi_database_handle,
64 L"SELECT ComponentId FROM Component",
65 &components_view_handle) != ERROR_SUCCESS) {
66 return false;
67 }
68
69 if (::MsiViewExecute(components_view_handle, 0) != ERROR_SUCCESS)
70 return false;
71
72 PMSIHANDLE record_handle;
73 while (::MsiViewFetch(components_view_handle, &record_handle) ==
74 ERROR_SUCCESS) {
75 // The record only have the ComponentId column, and its index is 1.
76 base::string16 component_guid;
77 if (GetRecordString(record_handle, 1, &component_guid))
78 component_guids->push_back(std::move(component_guid));
79 }
80
81 return true;
82 }
83
84 // Retrieves the |path| to the given component.
85 bool GetMsiComponentPath(const base::string16& product_guid,
86 const base::string16& component_guid,
87 base::string16* path) {
88 DWORD buffer_size = 0;
89 if (::MsiGetComponentPath(product_guid.c_str(), component_guid.c_str(), L"",
chrisha1 2017/05/05 20:01:40 Ditto.
Patrick Monette 2017/05/06 00:54:37 Done.
90 &buffer_size) != INSTALLSTATE_MOREDATA) {
91 return false;
92 }
93
94 // Must account for the null terminator.
95 buffer_size++;
96
97 return ::MsiGetComponentPath(product_guid.c_str(), component_guid.c_str(),
98 base::WriteInto(path, buffer_size),
99 &buffer_size) == INSTALLSTATE_LOCAL;
100 }
101
102 } // namespace
103
104 // The most efficient way to get the list of components associated to an
105 // installed product is to inspect the installer file. A copy of the installer
106 // exists somewhere on the file system because Windows needs it to uninstall the
107 // product.
108 //
109 // So this function retrieves the path to the installer, extract the component
chrisha1 2017/05/05 20:01:40 extracts*
Patrick Monette 2017/05/06 00:54:37 Done.
110 // GUIDS from it, and uses those to find the path of each component.
111 bool MsiUtil::GetMsiComponentPaths(
112 const base::string16& product_guid,
113 std::vector<base::string16>* component_paths) {
114 base::ThreadRestrictions::AssertIOAllowed();
115
116 base::string16 msi_path;
117 if (!GetMsiPath(product_guid, &msi_path))
118 return false;
119
120 std::vector<base::string16> component_guids;
121 if (!GetMsiComponentGuids(msi_path, &component_guids))
122 return false;
123
124 for (const auto& component_guid : component_guids) {
125 base::string16 component_path;
126 if (!GetMsiComponentPath(product_guid, component_guid, &component_path))
127 continue;
128
129 component_paths->push_back(std::move(component_path));
130 }
131
132 return true;
133 }
OLDNEW
« no previous file with comments | « chrome/browser/conflicts/msi_util_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698