aboutsummaryrefslogtreecommitdiff
path: root/src/dutil/butil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/dutil/butil.cpp')
-rw-r--r--src/dutil/butil.cpp271
1 files changed, 271 insertions, 0 deletions
diff --git a/src/dutil/butil.cpp b/src/dutil/butil.cpp
new file mode 100644
index 00000000..243befce
--- /dev/null
+++ b/src/dutil/butil.cpp
@@ -0,0 +1,271 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4#include "butil.h"
5
6// constants
7// From engine/registration.h
8const LPCWSTR BUNDLE_REGISTRATION_REGISTRY_UNINSTALL_KEY = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
9const LPCWSTR BUNDLE_REGISTRATION_REGISTRY_BUNDLE_UPGRADE_CODE = L"BundleUpgradeCode";
10const LPCWSTR BUNDLE_REGISTRATION_REGISTRY_BUNDLE_PROVIDER_KEY = L"BundleProviderKey";
11
12// Forward declarations.
13static HRESULT OpenBundleKey(
14 __in LPCWSTR wzBundleId,
15 __in BUNDLE_INSTALL_CONTEXT context,
16 __inout HKEY *key);
17
18/********************************************************************
19BundleGetBundleInfo - Queries the bundle installation metadata for a given property
20
21RETURNS:
22 E_INVALIDARG
23 An invalid parameter was passed to the function.
24 HRESULT_FROM_WIN32(ERROR_UNKNOWN_PRODUCT)
25 The bundle is not installed
26 HRESULT_FROM_WIN32(ERROR_UNKNOWN_PROPERTY)
27 The property is unrecognized
28 HRESULT_FROM_WIN32(ERROR_MORE_DATA)
29 A buffer is too small to hold the requested data.
30 E_NOTIMPL:
31 Tried to read a bundle attribute for a type which has not been implemented
32
33 All other returns are unexpected returns from other dutil methods.
34********************************************************************/
35extern "C" HRESULT DAPI BundleGetBundleInfo(
36 __in LPCWSTR wzBundleId,
37 __in LPCWSTR wzAttribute,
38 __out_ecount_opt(*pcchValueBuf) LPWSTR lpValueBuf,
39 __inout_opt LPDWORD pcchValueBuf
40 )
41{
42 Assert(wzBundleId && wzAttribute);
43
44 HRESULT hr = S_OK;
45 BUNDLE_INSTALL_CONTEXT context = BUNDLE_INSTALL_CONTEXT_MACHINE;
46 LPWSTR sczValue = NULL;
47 HKEY hkBundle = NULL;
48 DWORD cchSource = 0;
49 DWORD dwType = 0;
50 DWORD dwValue = 0;
51
52 if ((lpValueBuf && !pcchValueBuf) || !wzBundleId || !wzAttribute)
53 {
54 ExitOnFailure(hr = E_INVALIDARG, "An invalid parameter was passed to the function.");
55 }
56
57 if (FAILED(hr = OpenBundleKey(wzBundleId, context = BUNDLE_INSTALL_CONTEXT_MACHINE, &hkBundle)) &&
58 FAILED(hr = OpenBundleKey(wzBundleId, context = BUNDLE_INSTALL_CONTEXT_USER, &hkBundle)))
59 {
60 ExitOnFailure(E_FILENOTFOUND == hr ? HRESULT_FROM_WIN32(ERROR_UNKNOWN_PRODUCT) : hr, "Failed to locate bundle uninstall key path.");
61 }
62
63 // If the bundle doesn't have the property defined, return ERROR_UNKNOWN_PROPERTY
64 hr = RegGetType(hkBundle, wzAttribute, &dwType);
65 ExitOnFailure(E_FILENOTFOUND == hr ? HRESULT_FROM_WIN32(ERROR_UNKNOWN_PROPERTY) : hr, "Failed to locate bundle property.");
66
67 switch (dwType)
68 {
69 case REG_SZ:
70 hr = RegReadString(hkBundle, wzAttribute, &sczValue);
71 ExitOnFailure(hr, "Failed to read string property.");
72 break;
73 case REG_DWORD:
74 hr = RegReadNumber(hkBundle, wzAttribute, &dwValue);
75 ExitOnFailure(hr, "Failed to read dword property.");
76
77 hr = StrAllocFormatted(&sczValue, L"%d", dwValue);
78 ExitOnFailure(hr, "Failed to format dword property as string.");
79 break;
80 default:
81 ExitOnFailure(hr = E_NOTIMPL, "Reading bundle info of type 0x%x not implemented.", dwType);
82
83 }
84
85 hr = ::StringCchLengthW(sczValue, STRSAFE_MAX_CCH, reinterpret_cast<UINT_PTR*>(&cchSource));
86 ExitOnFailure(hr, "Failed to calculate length of string");
87
88 if (lpValueBuf)
89 {
90 // cchSource is the length of the string not including the terminating null character
91 if (*pcchValueBuf <= cchSource)
92 {
93 *pcchValueBuf = ++cchSource;
94 ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_MORE_DATA), "A buffer is too small to hold the requested data.");
95 }
96
97 hr = ::StringCchCatNExW(lpValueBuf, *pcchValueBuf, sczValue, cchSource, NULL, NULL, STRSAFE_FILL_BEHIND_NULL);
98 ExitOnFailure(hr, "Failed to copy the property value to the output buffer.");
99
100 *pcchValueBuf = cchSource++;
101 }
102
103LExit:
104 ReleaseRegKey(hkBundle);
105 ReleaseStr(sczValue);
106
107 return hr;
108}
109
110/********************************************************************
111BundleEnumRelatedBundle - Queries the bundle installation metadata for installs with the given upgrade code
112
113NOTE: lpBundleIdBuff is a buffer to receive the bundle GUID. This buffer must be 39 characters long.
114 The first 38 characters are for the GUID, and the last character is for the terminating null character.
115RETURNS:
116 E_INVALIDARG
117 An invalid parameter was passed to the function.
118
119 All other returns are unexpected returns from other dutil methods.
120********************************************************************/
121HRESULT DAPI BundleEnumRelatedBundle(
122 __in LPCWSTR wzUpgradeCode,
123 __in BUNDLE_INSTALL_CONTEXT context,
124 __inout PDWORD pdwStartIndex,
125 __out_ecount(MAX_GUID_CHARS+1) LPWSTR lpBundleIdBuf
126 )
127{
128 HRESULT hr = S_OK;
129 HKEY hkRoot = BUNDLE_INSTALL_CONTEXT_USER == context ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
130 HKEY hkUninstall = NULL;
131 HKEY hkBundle = NULL;
132 LPWSTR sczUninstallSubKey = NULL;
133 DWORD cchUninstallSubKey = 0;
134 LPWSTR sczUninstallSubKeyPath = NULL;
135 LPWSTR sczValue = NULL;
136 DWORD dwType = 0;
137
138 LPWSTR* rgsczBundleUpgradeCodes = NULL;
139 DWORD cBundleUpgradeCodes = 0;
140 BOOL fUpgradeCodeFound = FALSE;
141
142 if (!wzUpgradeCode || !lpBundleIdBuf || !pdwStartIndex)
143 {
144 ExitOnFailure(hr = E_INVALIDARG, "An invalid parameter was passed to the function.");
145 }
146
147 hr = RegOpen(hkRoot, BUNDLE_REGISTRATION_REGISTRY_UNINSTALL_KEY, KEY_READ, &hkUninstall);
148 ExitOnFailure(hr, "Failed to open bundle uninstall key path.");
149
150 for (DWORD dwIndex = *pdwStartIndex; !fUpgradeCodeFound; dwIndex++)
151 {
152 hr = RegKeyEnum(hkUninstall, dwIndex, &sczUninstallSubKey);
153 ExitOnFailure(hr, "Failed to enumerate bundle uninstall key path.");
154
155 hr = StrAllocFormatted(&sczUninstallSubKeyPath, L"%ls\\%ls", BUNDLE_REGISTRATION_REGISTRY_UNINSTALL_KEY, sczUninstallSubKey);
156 ExitOnFailure(hr, "Failed to allocate bundle uninstall key path.");
157
158 hr = RegOpen(hkRoot, sczUninstallSubKeyPath, KEY_READ, &hkBundle);
159 ExitOnFailure(hr, "Failed to open uninstall key path.");
160
161 // If it's a bundle, it should have a BundleUpgradeCode value of type REG_SZ (old) or REG_MULTI_SZ
162 hr = RegGetType(hkBundle, BUNDLE_REGISTRATION_REGISTRY_BUNDLE_UPGRADE_CODE, &dwType);
163 if (FAILED(hr))
164 {
165 ReleaseRegKey(hkBundle);
166 ReleaseNullStr(sczUninstallSubKey);
167 ReleaseNullStr(sczUninstallSubKeyPath);
168 // Not a bundle
169 continue;
170 }
171
172 switch (dwType)
173 {
174 case REG_SZ:
175 hr = RegReadString(hkBundle, BUNDLE_REGISTRATION_REGISTRY_BUNDLE_UPGRADE_CODE, &sczValue);
176 ExitOnFailure(hr, "Failed to read BundleUpgradeCode string property.");
177 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, sczValue, -1, wzUpgradeCode, -1))
178 {
179 *pdwStartIndex = dwIndex;
180 fUpgradeCodeFound = TRUE;
181 break;
182 }
183
184 ReleaseNullStr(sczValue);
185
186 break;
187 case REG_MULTI_SZ:
188 hr = RegReadStringArray(hkBundle, BUNDLE_REGISTRATION_REGISTRY_BUNDLE_UPGRADE_CODE, &rgsczBundleUpgradeCodes, &cBundleUpgradeCodes);
189 ExitOnFailure(hr, "Failed to read BundleUpgradeCode multi-string property.");
190
191 for (DWORD i = 0; i < cBundleUpgradeCodes; i++)
192 {
193 LPWSTR wzBundleUpgradeCode = rgsczBundleUpgradeCodes[i];
194 if (wzBundleUpgradeCode && *wzBundleUpgradeCode)
195 {
196 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, wzBundleUpgradeCode, -1, wzUpgradeCode, -1))
197 {
198 *pdwStartIndex = dwIndex;
199 fUpgradeCodeFound = TRUE;
200 break;
201 }
202 }
203 }
204 ReleaseNullStrArray(rgsczBundleUpgradeCodes, cBundleUpgradeCodes);
205
206 break;
207
208 default:
209 ExitOnFailure(hr = E_NOTIMPL, "BundleUpgradeCode of type 0x%x not implemented.", dwType);
210
211 }
212
213 if (fUpgradeCodeFound)
214 {
215 if (lpBundleIdBuf)
216 {
217 hr = ::StringCchLengthW(sczUninstallSubKey, STRSAFE_MAX_CCH, reinterpret_cast<UINT_PTR*>(&cchUninstallSubKey));
218 ExitOnFailure(hr, "Failed to calculate length of string");
219
220 hr = ::StringCchCopyNExW(lpBundleIdBuf, MAX_GUID_CHARS + 1, sczUninstallSubKey, cchUninstallSubKey, NULL, NULL, STRSAFE_FILL_BEHIND_NULL);
221 ExitOnFailure(hr, "Failed to copy the property value to the output buffer.");
222 }
223
224 break;
225 }
226
227 // Cleanup before next iteration
228 ReleaseRegKey(hkBundle);
229 ReleaseNullStr(sczUninstallSubKey);
230 ReleaseNullStr(sczUninstallSubKeyPath);
231 }
232
233LExit:
234 ReleaseStr(sczValue);
235 ReleaseStr(sczUninstallSubKey);
236 ReleaseStr(sczUninstallSubKeyPath);
237 ReleaseRegKey(hkBundle);
238 ReleaseRegKey(hkUninstall);
239 ReleaseStrArray(rgsczBundleUpgradeCodes, cBundleUpgradeCodes);
240
241 return hr;
242}
243
244/********************************************************************
245OpenBundleKey - Opens the bundle uninstallation key for a given bundle
246
247NOTE: caller is responsible for closing key
248********************************************************************/
249HRESULT OpenBundleKey(
250 __in LPCWSTR wzBundleId,
251 __in BUNDLE_INSTALL_CONTEXT context,
252 __inout HKEY *key)
253{
254 Assert(key && wzBundleId);
255 AssertSz(NULL == *key, "*key should be null");
256
257 HRESULT hr = S_OK;
258 HKEY hkRoot = BUNDLE_INSTALL_CONTEXT_USER == context ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
259 LPWSTR sczKeypath = NULL;
260
261 hr = StrAllocFormatted(&sczKeypath, L"%ls\\%ls", BUNDLE_REGISTRATION_REGISTRY_UNINSTALL_KEY, wzBundleId);
262 ExitOnFailure(hr, "Failed to allocate bundle uninstall key path.");
263
264 hr = RegOpen(hkRoot, sczKeypath, KEY_READ, key);
265 ExitOnFailure(hr, "Failed to open bundle uninstall key path.");
266
267LExit:
268 ReleaseStr(sczKeypath);
269
270 return hr;
271}