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