diff options
Diffstat (limited to 'src/libs/dutil/WixToolset.DUtil/deputil.cpp')
-rw-r--r-- | src/libs/dutil/WixToolset.DUtil/deputil.cpp | 699 |
1 files changed, 699 insertions, 0 deletions
diff --git a/src/libs/dutil/WixToolset.DUtil/deputil.cpp b/src/libs/dutil/WixToolset.DUtil/deputil.cpp new file mode 100644 index 00000000..2e6d6a6c --- /dev/null +++ b/src/libs/dutil/WixToolset.DUtil/deputil.cpp | |||
@@ -0,0 +1,699 @@ | |||
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 | |||
6 | // Exit macros | ||
7 | #define DepExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_DEPUTIL, x, s, __VA_ARGS__) | ||
8 | #define DepExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_DEPUTIL, x, s, __VA_ARGS__) | ||
9 | #define DepExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_DEPUTIL, x, s, __VA_ARGS__) | ||
10 | #define DepExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_DEPUTIL, x, s, __VA_ARGS__) | ||
11 | #define DepExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_DEPUTIL, x, s, __VA_ARGS__) | ||
12 | #define DepExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_DEPUTIL, x, s, __VA_ARGS__) | ||
13 | #define DepExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_DEPUTIL, p, x, e, s, __VA_ARGS__) | ||
14 | #define DepExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_DEPUTIL, p, x, s, __VA_ARGS__) | ||
15 | #define DepExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_DEPUTIL, p, x, e, s, __VA_ARGS__) | ||
16 | #define DepExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_DEPUTIL, p, x, s, __VA_ARGS__) | ||
17 | #define DepExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_DEPUTIL, e, x, s, __VA_ARGS__) | ||
18 | #define DepExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_DEPUTIL, g, x, s, __VA_ARGS__) | ||
19 | |||
20 | #define ARRAY_GROWTH_SIZE 5 | ||
21 | |||
22 | static LPCWSTR vcszVersionValue = L"Version"; | ||
23 | static LPCWSTR vcszDisplayNameValue = L"DisplayName"; | ||
24 | static LPCWSTR vcszMinVersionValue = L"MinVersion"; | ||
25 | static LPCWSTR vcszMaxVersionValue = L"MaxVersion"; | ||
26 | static LPCWSTR vcszAttributesValue = L"Attributes"; | ||
27 | |||
28 | enum eRequiresAttributes { RequiresAttributesMinVersionInclusive = 256, RequiresAttributesMaxVersionInclusive = 512 }; | ||
29 | |||
30 | // We write to Software\Classes explicitly based on the current security context instead of HKCR. | ||
31 | // See http://msdn.microsoft.com/en-us/library/ms724475(VS.85).aspx for more information. | ||
32 | static LPCWSTR vsczRegistryRoot = L"Software\\Classes\\Installer\\Dependencies\\"; | ||
33 | static LPCWSTR vsczRegistryDependents = L"Dependents"; | ||
34 | |||
35 | static HRESULT AllocDependencyKeyName( | ||
36 | __in_z LPCWSTR wzName, | ||
37 | __deref_out_z LPWSTR* psczKeyName | ||
38 | ); | ||
39 | |||
40 | static HRESULT GetDependencyNameFromKey( | ||
41 | __in HKEY hkHive, | ||
42 | __in LPCWSTR wzKey, | ||
43 | __deref_out_z LPWSTR* psczName | ||
44 | ); | ||
45 | |||
46 | DAPI_(HRESULT) DepGetProviderInformation( | ||
47 | __in HKEY hkHive, | ||
48 | __in_z LPCWSTR wzProviderKey, | ||
49 | __deref_out_z_opt LPWSTR* psczId, | ||
50 | __deref_out_z_opt LPWSTR* psczName, | ||
51 | __deref_out_z_opt LPWSTR* psczVersion | ||
52 | ) | ||
53 | { | ||
54 | HRESULT hr = S_OK; | ||
55 | LPWSTR sczKey = NULL; | ||
56 | HKEY hkKey = NULL; | ||
57 | |||
58 | // Format the provider dependency registry key. | ||
59 | hr = AllocDependencyKeyName(wzProviderKey, &sczKey); | ||
60 | DepExitOnFailure(hr, "Failed to allocate the registry key for dependency \"%ls\".", wzProviderKey); | ||
61 | |||
62 | // Try to open the dependency key. | ||
63 | hr = RegOpen(hkHive, sczKey, KEY_READ, &hkKey); | ||
64 | if (E_FILENOTFOUND == hr) | ||
65 | { | ||
66 | ExitFunction1(hr = E_NOTFOUND); | ||
67 | } | ||
68 | DepExitOnFailure(hr, "Failed to open the registry key for the dependency \"%ls\".", wzProviderKey); | ||
69 | |||
70 | // Get the Id if requested and available. | ||
71 | if (psczId) | ||
72 | { | ||
73 | hr = RegReadString(hkKey, NULL, psczId); | ||
74 | if (E_FILENOTFOUND == hr) | ||
75 | { | ||
76 | hr = S_OK; | ||
77 | } | ||
78 | DepExitOnFailure(hr, "Failed to get the id for the dependency \"%ls\".", wzProviderKey); | ||
79 | } | ||
80 | |||
81 | // Get the DisplayName if requested and available. | ||
82 | if (psczName) | ||
83 | { | ||
84 | hr = RegReadString(hkKey, vcszDisplayNameValue, psczName); | ||
85 | if (E_FILENOTFOUND == hr) | ||
86 | { | ||
87 | hr = S_OK; | ||
88 | } | ||
89 | DepExitOnFailure(hr, "Failed to get the name for the dependency \"%ls\".", wzProviderKey); | ||
90 | } | ||
91 | |||
92 | // Get the Version if requested and available. | ||
93 | if (psczVersion) | ||
94 | { | ||
95 | hr = RegReadString(hkKey, vcszVersionValue, psczVersion); | ||
96 | if (E_FILENOTFOUND == hr) | ||
97 | { | ||
98 | hr = S_OK; | ||
99 | } | ||
100 | DepExitOnFailure(hr, "Failed to get the version for the dependency \"%ls\".", wzProviderKey); | ||
101 | } | ||
102 | |||
103 | LExit: | ||
104 | ReleaseRegKey(hkKey); | ||
105 | ReleaseStr(sczKey); | ||
106 | |||
107 | return hr; | ||
108 | } | ||
109 | |||
110 | DAPI_(HRESULT) DepCheckDependency( | ||
111 | __in HKEY hkHive, | ||
112 | __in_z LPCWSTR wzProviderKey, | ||
113 | __in_z_opt LPCWSTR wzMinVersion, | ||
114 | __in_z_opt LPCWSTR wzMaxVersion, | ||
115 | __in int iAttributes, | ||
116 | __in STRINGDICT_HANDLE sdDependencies, | ||
117 | __deref_inout_ecount_opt(*pcDependencies) DEPENDENCY** prgDependencies, | ||
118 | __inout LPUINT pcDependencies | ||
119 | ) | ||
120 | { | ||
121 | HRESULT hr = S_OK; | ||
122 | LPWSTR sczKey = NULL; | ||
123 | HKEY hkKey = NULL; | ||
124 | DWORD64 dw64Version = 0; | ||
125 | DWORD64 dw64MinVersion = 0; | ||
126 | DWORD64 dw64MaxVersion = 0; | ||
127 | BOOL fAllowEqual = FALSE; | ||
128 | LPWSTR sczName = NULL; | ||
129 | |||
130 | // Format the provider dependency registry key. | ||
131 | hr = AllocDependencyKeyName(wzProviderKey, &sczKey); | ||
132 | DepExitOnFailure(hr, "Failed to allocate the registry key for dependency \"%ls\".", wzProviderKey); | ||
133 | |||
134 | // Try to open the key. If that fails, add the missing dependency key to the dependency array if it doesn't already exist. | ||
135 | hr = RegOpen(hkHive, sczKey, KEY_READ, &hkKey); | ||
136 | if (E_FILENOTFOUND != hr) | ||
137 | { | ||
138 | DepExitOnFailure(hr, "Failed to open the registry key for dependency \"%ls\".", wzProviderKey); | ||
139 | |||
140 | // If there are no registry values, consider the key orphaned and treat it as missing. | ||
141 | hr = RegReadVersion(hkKey, vcszVersionValue, &dw64Version); | ||
142 | if (E_FILENOTFOUND != hr) | ||
143 | { | ||
144 | DepExitOnFailure(hr, "Failed to read the %ls registry value for dependency \"%ls\".", vcszVersionValue, wzProviderKey); | ||
145 | } | ||
146 | } | ||
147 | |||
148 | // If the key was not found or the Version value was not found, add the missing dependency key to the dependency array. | ||
149 | if (E_FILENOTFOUND == hr) | ||
150 | { | ||
151 | hr = DictKeyExists(sdDependencies, wzProviderKey); | ||
152 | if (E_NOTFOUND != hr) | ||
153 | { | ||
154 | DepExitOnFailure(hr, "Failed to check the dictionary for missing dependency \"%ls\".", wzProviderKey); | ||
155 | } | ||
156 | else | ||
157 | { | ||
158 | hr = DepDependencyArrayAlloc(prgDependencies, pcDependencies, wzProviderKey, NULL); | ||
159 | DepExitOnFailure(hr, "Failed to add the missing dependency \"%ls\" to the array.", wzProviderKey); | ||
160 | |||
161 | hr = DictAddKey(sdDependencies, wzProviderKey); | ||
162 | DepExitOnFailure(hr, "Failed to add the missing dependency \"%ls\" to the dictionary.", wzProviderKey); | ||
163 | } | ||
164 | |||
165 | // Exit since the check already failed. | ||
166 | ExitFunction1(hr = E_NOTFOUND); | ||
167 | } | ||
168 | |||
169 | // Check MinVersion if provided. | ||
170 | if (wzMinVersion) | ||
171 | { | ||
172 | if (*wzMinVersion) | ||
173 | { | ||
174 | hr = FileVersionFromStringEx(wzMinVersion, 0, &dw64MinVersion); | ||
175 | DepExitOnFailure(hr, "Failed to get the 64-bit version number from \"%ls\".", wzMinVersion); | ||
176 | |||
177 | fAllowEqual = iAttributes & RequiresAttributesMinVersionInclusive; | ||
178 | if (!(fAllowEqual && dw64MinVersion <= dw64Version || dw64MinVersion < dw64Version)) | ||
179 | { | ||
180 | hr = DictKeyExists(sdDependencies, wzProviderKey); | ||
181 | if (E_NOTFOUND != hr) | ||
182 | { | ||
183 | DepExitOnFailure(hr, "Failed to check the dictionary for the older dependency \"%ls\".", wzProviderKey); | ||
184 | } | ||
185 | else | ||
186 | { | ||
187 | hr = RegReadString(hkKey, vcszDisplayNameValue, &sczName); | ||
188 | DepExitOnFailure(hr, "Failed to get the display name of the older dependency \"%ls\".", wzProviderKey); | ||
189 | |||
190 | hr = DepDependencyArrayAlloc(prgDependencies, pcDependencies, wzProviderKey, sczName); | ||
191 | DepExitOnFailure(hr, "Failed to add the older dependency \"%ls\" to the dependencies array.", wzProviderKey); | ||
192 | |||
193 | hr = DictAddKey(sdDependencies, wzProviderKey); | ||
194 | DepExitOnFailure(hr, "Failed to add the older dependency \"%ls\" to the unique dependency string list.", wzProviderKey); | ||
195 | } | ||
196 | |||
197 | // Exit since the check already failed. | ||
198 | ExitFunction1(hr = E_NOTFOUND); | ||
199 | } | ||
200 | } | ||
201 | } | ||
202 | |||
203 | // Check MaxVersion if provided. | ||
204 | if (wzMaxVersion) | ||
205 | { | ||
206 | if (*wzMaxVersion) | ||
207 | { | ||
208 | hr = FileVersionFromStringEx(wzMaxVersion, 0, &dw64MaxVersion); | ||
209 | DepExitOnFailure(hr, "Failed to get the 64-bit version number from \"%ls\".", wzMaxVersion); | ||
210 | |||
211 | fAllowEqual = iAttributes & RequiresAttributesMaxVersionInclusive; | ||
212 | if (!(fAllowEqual && dw64Version <= dw64MaxVersion || dw64Version < dw64MaxVersion)) | ||
213 | { | ||
214 | hr = DictKeyExists(sdDependencies, wzProviderKey); | ||
215 | if (E_NOTFOUND != hr) | ||
216 | { | ||
217 | DepExitOnFailure(hr, "Failed to check the dictionary for the newer dependency \"%ls\".", wzProviderKey); | ||
218 | } | ||
219 | else | ||
220 | { | ||
221 | hr = RegReadString(hkKey, vcszDisplayNameValue, &sczName); | ||
222 | DepExitOnFailure(hr, "Failed to get the display name of the newer dependency \"%ls\".", wzProviderKey); | ||
223 | |||
224 | hr = DepDependencyArrayAlloc(prgDependencies, pcDependencies, wzProviderKey, sczName); | ||
225 | DepExitOnFailure(hr, "Failed to add the newer dependency \"%ls\" to the dependencies array.", wzProviderKey); | ||
226 | |||
227 | hr = DictAddKey(sdDependencies, wzProviderKey); | ||
228 | DepExitOnFailure(hr, "Failed to add the newer dependency \"%ls\" to the unique dependency string list.", wzProviderKey); | ||
229 | } | ||
230 | |||
231 | // Exit since the check already failed. | ||
232 | ExitFunction1(hr = E_NOTFOUND); | ||
233 | } | ||
234 | } | ||
235 | } | ||
236 | |||
237 | LExit: | ||
238 | ReleaseStr(sczName); | ||
239 | ReleaseRegKey(hkKey); | ||
240 | ReleaseStr(sczKey); | ||
241 | |||
242 | return hr; | ||
243 | } | ||
244 | |||
245 | DAPI_(HRESULT) DepCheckDependents( | ||
246 | __in HKEY hkHive, | ||
247 | __in_z LPCWSTR wzProviderKey, | ||
248 | __reserved int /*iAttributes*/, | ||
249 | __in C_STRINGDICT_HANDLE sdIgnoredDependents, | ||
250 | __deref_inout_ecount_opt(*pcDependents) DEPENDENCY** prgDependents, | ||
251 | __inout LPUINT pcDependents | ||
252 | ) | ||
253 | { | ||
254 | HRESULT hr = S_OK; | ||
255 | LPWSTR sczKey = NULL; | ||
256 | HKEY hkProviderKey = NULL; | ||
257 | HKEY hkDependentsKey = NULL; | ||
258 | LPWSTR sczDependentKey = NULL; | ||
259 | LPWSTR sczDependentName = NULL; | ||
260 | |||
261 | // Format the provider dependency registry key. | ||
262 | hr = AllocDependencyKeyName(wzProviderKey, &sczKey); | ||
263 | DepExitOnFailure(hr, "Failed to allocate the registry key for dependency \"%ls\".", wzProviderKey); | ||
264 | |||
265 | // Try to open the key. If that fails, the dependency information is corrupt. | ||
266 | hr = RegOpen(hkHive, sczKey, KEY_READ, &hkProviderKey); | ||
267 | DepExitOnFailure(hr, "Failed to open the registry key \"%ls\". The dependency store is corrupt.", sczKey); | ||
268 | |||
269 | // Try to open the dependencies key. If that does not exist, there are no dependents. | ||
270 | hr = RegOpen(hkProviderKey, vsczRegistryDependents, KEY_READ, &hkDependentsKey); | ||
271 | if (E_FILENOTFOUND != hr) | ||
272 | { | ||
273 | DepExitOnFailure(hr, "Failed to open the registry key for dependents of \"%ls\".", wzProviderKey); | ||
274 | } | ||
275 | else | ||
276 | { | ||
277 | ExitFunction1(hr = S_OK); | ||
278 | } | ||
279 | |||
280 | // Now enumerate the dependent keys. If they are not defined in the ignored list, add them to the array. | ||
281 | for (DWORD dwIndex = 0; ; ++dwIndex) | ||
282 | { | ||
283 | hr = RegKeyEnum(hkDependentsKey, dwIndex, &sczDependentKey); | ||
284 | if (E_NOMOREITEMS != hr) | ||
285 | { | ||
286 | DepExitOnFailure(hr, "Failed to enumerate the dependents key of \"%ls\".", wzProviderKey); | ||
287 | } | ||
288 | else | ||
289 | { | ||
290 | hr = S_OK; | ||
291 | break; | ||
292 | } | ||
293 | |||
294 | // If the key isn't ignored, add it to the dependent array. | ||
295 | hr = DictKeyExists(sdIgnoredDependents, sczDependentKey); | ||
296 | if (E_NOTFOUND != hr) | ||
297 | { | ||
298 | DepExitOnFailure(hr, "Failed to check the dictionary of ignored dependents."); | ||
299 | } | ||
300 | else | ||
301 | { | ||
302 | // Get the name of the dependent from the key. | ||
303 | hr = GetDependencyNameFromKey(hkHive, sczDependentKey, &sczDependentName); | ||
304 | DepExitOnFailure(hr, "Failed to get the name of the dependent from the key \"%ls\".", sczDependentKey); | ||
305 | |||
306 | hr = DepDependencyArrayAlloc(prgDependents, pcDependents, sczDependentKey, sczDependentName); | ||
307 | DepExitOnFailure(hr, "Failed to add the dependent key \"%ls\" to the string array.", sczDependentKey); | ||
308 | } | ||
309 | } | ||
310 | |||
311 | LExit: | ||
312 | ReleaseStr(sczDependentName); | ||
313 | ReleaseStr(sczDependentKey); | ||
314 | ReleaseRegKey(hkDependentsKey); | ||
315 | ReleaseRegKey(hkProviderKey); | ||
316 | ReleaseStr(sczKey); | ||
317 | |||
318 | return hr; | ||
319 | } | ||
320 | |||
321 | DAPI_(HRESULT) DepRegisterDependency( | ||
322 | __in HKEY hkHive, | ||
323 | __in_z LPCWSTR wzProviderKey, | ||
324 | __in_z LPCWSTR wzVersion, | ||
325 | __in_z LPCWSTR wzDisplayName, | ||
326 | __in_z_opt LPCWSTR wzId, | ||
327 | __in int iAttributes | ||
328 | ) | ||
329 | { | ||
330 | HRESULT hr = S_OK; | ||
331 | LPWSTR sczKey = NULL; | ||
332 | HKEY hkKey = NULL; | ||
333 | BOOL fCreated = FALSE; | ||
334 | |||
335 | // Format the provider dependency registry key. | ||
336 | hr = AllocDependencyKeyName(wzProviderKey, &sczKey); | ||
337 | DepExitOnFailure(hr, "Failed to allocate the registry key for dependency \"%ls\".", wzProviderKey); | ||
338 | |||
339 | // Create the dependency key (or open it if it already exists). | ||
340 | hr = RegCreateEx(hkHive, sczKey, KEY_WRITE, FALSE, NULL, &hkKey, &fCreated); | ||
341 | DepExitOnFailure(hr, "Failed to create the dependency registry key \"%ls\".", sczKey); | ||
342 | |||
343 | // Set the id if it was provided. | ||
344 | if (wzId) | ||
345 | { | ||
346 | hr = RegWriteString(hkKey, NULL, wzId); | ||
347 | DepExitOnFailure(hr, "Failed to set the %ls registry value to \"%ls\".", L"default", wzId); | ||
348 | } | ||
349 | |||
350 | // Set the version. | ||
351 | hr = RegWriteString(hkKey, vcszVersionValue, wzVersion); | ||
352 | DepExitOnFailure(hr, "Failed to set the %ls registry value to \"%ls\".", vcszVersionValue, wzVersion); | ||
353 | |||
354 | // Set the display name. | ||
355 | hr = RegWriteString(hkKey, vcszDisplayNameValue, wzDisplayName); | ||
356 | DepExitOnFailure(hr, "Failed to set the %ls registry value to \"%ls\".", vcszDisplayNameValue, wzDisplayName); | ||
357 | |||
358 | // Set the attributes if non-zero. | ||
359 | if (0 != iAttributes) | ||
360 | { | ||
361 | hr = RegWriteNumber(hkKey, vcszAttributesValue, static_cast<DWORD>(iAttributes)); | ||
362 | DepExitOnFailure(hr, "Failed to set the %ls registry value to %d.", vcszAttributesValue, iAttributes); | ||
363 | } | ||
364 | |||
365 | LExit: | ||
366 | ReleaseRegKey(hkKey); | ||
367 | ReleaseStr(sczKey); | ||
368 | |||
369 | return hr; | ||
370 | } | ||
371 | |||
372 | DAPI_(HRESULT) DepDependentExists( | ||
373 | __in HKEY hkHive, | ||
374 | __in_z LPCWSTR wzDependencyProviderKey, | ||
375 | __in_z LPCWSTR wzProviderKey | ||
376 | ) | ||
377 | { | ||
378 | HRESULT hr = S_OK; | ||
379 | LPWSTR sczDependentKey = NULL; | ||
380 | HKEY hkDependentKey = NULL; | ||
381 | |||
382 | // Format the provider dependents registry key. | ||
383 | hr = StrAllocFormatted(&sczDependentKey, L"%ls%ls\\%ls\\%ls", vsczRegistryRoot, wzDependencyProviderKey, vsczRegistryDependents, wzProviderKey); | ||
384 | DepExitOnFailure(hr, "Failed to format registry key to dependent."); | ||
385 | |||
386 | hr = RegOpen(hkHive, sczDependentKey, KEY_READ, &hkDependentKey); | ||
387 | if (E_FILENOTFOUND != hr) | ||
388 | { | ||
389 | DepExitOnFailure(hr, "Failed to open the dependent registry key at: \"%ls\".", sczDependentKey); | ||
390 | } | ||
391 | |||
392 | LExit: | ||
393 | ReleaseRegKey(hkDependentKey); | ||
394 | ReleaseStr(sczDependentKey); | ||
395 | |||
396 | return hr; | ||
397 | } | ||
398 | |||
399 | DAPI_(HRESULT) DepRegisterDependent( | ||
400 | __in HKEY hkHive, | ||
401 | __in_z LPCWSTR wzDependencyProviderKey, | ||
402 | __in_z LPCWSTR wzProviderKey, | ||
403 | __in_z_opt LPCWSTR wzMinVersion, | ||
404 | __in_z_opt LPCWSTR wzMaxVersion, | ||
405 | __in int iAttributes | ||
406 | ) | ||
407 | { | ||
408 | HRESULT hr = S_OK; | ||
409 | LPWSTR sczDependencyKey = NULL; | ||
410 | HKEY hkDependencyKey = NULL; | ||
411 | LPWSTR sczKey = NULL; | ||
412 | HKEY hkKey = NULL; | ||
413 | BOOL fCreated = FALSE; | ||
414 | |||
415 | // Format the provider dependency registry key. | ||
416 | hr = AllocDependencyKeyName(wzDependencyProviderKey, &sczDependencyKey); | ||
417 | DepExitOnFailure(hr, "Failed to allocate the registry key for dependency \"%ls\".", wzDependencyProviderKey); | ||
418 | |||
419 | // Create the dependency key (or open it if it already exists). | ||
420 | hr = RegCreateEx(hkHive, sczDependencyKey, KEY_WRITE, FALSE, NULL, &hkDependencyKey, &fCreated); | ||
421 | DepExitOnFailure(hr, "Failed to create the dependency registry key \"%ls\".", sczDependencyKey); | ||
422 | |||
423 | // Create the subkey to register the dependent. | ||
424 | hr = StrAllocFormatted(&sczKey, L"%ls\\%ls", vsczRegistryDependents, wzProviderKey); | ||
425 | DepExitOnFailure(hr, "Failed to allocate dependent subkey \"%ls\" under dependency \"%ls\".", wzProviderKey, wzDependencyProviderKey); | ||
426 | |||
427 | hr = RegCreateEx(hkDependencyKey, sczKey, KEY_WRITE, FALSE, NULL, &hkKey, &fCreated); | ||
428 | DepExitOnFailure(hr, "Failed to create the dependency subkey \"%ls\".", sczKey); | ||
429 | |||
430 | // Set the minimum version if not NULL. | ||
431 | hr = RegWriteString(hkKey, vcszMinVersionValue, wzMinVersion); | ||
432 | DepExitOnFailure(hr, "Failed to set the %ls registry value to \"%ls\".", vcszMinVersionValue, wzMinVersion); | ||
433 | |||
434 | // Set the maximum version if not NULL. | ||
435 | hr = RegWriteString(hkKey, vcszMaxVersionValue, wzMaxVersion); | ||
436 | DepExitOnFailure(hr, "Failed to set the %ls registry value to \"%ls\".", vcszMaxVersionValue, wzMaxVersion); | ||
437 | |||
438 | // Set the attributes if non-zero. | ||
439 | if (0 != iAttributes) | ||
440 | { | ||
441 | hr = RegWriteNumber(hkKey, vcszAttributesValue, static_cast<DWORD>(iAttributes)); | ||
442 | DepExitOnFailure(hr, "Failed to set the %ls registry value to %d.", vcszAttributesValue, iAttributes); | ||
443 | } | ||
444 | |||
445 | LExit: | ||
446 | ReleaseRegKey(hkKey); | ||
447 | ReleaseStr(sczKey); | ||
448 | ReleaseRegKey(hkDependencyKey); | ||
449 | ReleaseStr(sczDependencyKey); | ||
450 | |||
451 | return hr; | ||
452 | } | ||
453 | |||
454 | DAPI_(HRESULT) DepUnregisterDependency( | ||
455 | __in HKEY hkHive, | ||
456 | __in_z LPCWSTR wzProviderKey | ||
457 | ) | ||
458 | { | ||
459 | HRESULT hr = S_OK; | ||
460 | LPWSTR sczKey = NULL; | ||
461 | HKEY hkKey = NULL; | ||
462 | |||
463 | // Format the provider dependency registry key. | ||
464 | hr = AllocDependencyKeyName(wzProviderKey, &sczKey); | ||
465 | DepExitOnFailure(hr, "Failed to allocate the registry key for dependency \"%ls\".", wzProviderKey); | ||
466 | |||
467 | // Delete the entire key including all sub-keys. | ||
468 | hr = RegDelete(hkHive, sczKey, REG_KEY_DEFAULT, TRUE); | ||
469 | if (E_FILENOTFOUND != hr) | ||
470 | { | ||
471 | DepExitOnFailure(hr, "Failed to delete the key \"%ls\".", sczKey); | ||
472 | } | ||
473 | |||
474 | LExit: | ||
475 | ReleaseRegKey(hkKey); | ||
476 | ReleaseStr(sczKey); | ||
477 | |||
478 | return hr; | ||
479 | } | ||
480 | |||
481 | DAPI_(HRESULT) DepUnregisterDependent( | ||
482 | __in HKEY hkHive, | ||
483 | __in_z LPCWSTR wzDependencyProviderKey, | ||
484 | __in_z LPCWSTR wzProviderKey | ||
485 | ) | ||
486 | { | ||
487 | HRESULT hr = S_OK; | ||
488 | HKEY hkRegistryRoot = NULL; | ||
489 | HKEY hkDependencyProviderKey = NULL; | ||
490 | HKEY hkRegistryDependents = NULL; | ||
491 | DWORD cSubKeys = 0; | ||
492 | DWORD cValues = 0; | ||
493 | |||
494 | // Open the root key. We may delete the wzDependencyProviderKey during clean up. | ||
495 | hr = RegOpen(hkHive, vsczRegistryRoot, KEY_READ, &hkRegistryRoot); | ||
496 | if (E_FILENOTFOUND != hr) | ||
497 | { | ||
498 | DepExitOnFailure(hr, "Failed to open root registry key \"%ls\".", vsczRegistryRoot); | ||
499 | } | ||
500 | else | ||
501 | { | ||
502 | ExitFunction(); | ||
503 | } | ||
504 | |||
505 | // Try to open the dependency key. If that does not exist, simply return. | ||
506 | hr = RegOpen(hkRegistryRoot, wzDependencyProviderKey, KEY_READ, &hkDependencyProviderKey); | ||
507 | if (E_FILENOTFOUND != hr) | ||
508 | { | ||
509 | DepExitOnFailure(hr, "Failed to open the registry key for the dependency \"%ls\".", wzDependencyProviderKey); | ||
510 | } | ||
511 | else | ||
512 | { | ||
513 | ExitFunction(); | ||
514 | } | ||
515 | |||
516 | // Try to open the dependents subkey to enumerate. | ||
517 | hr = RegOpen(hkDependencyProviderKey, vsczRegistryDependents, KEY_READ, &hkRegistryDependents); | ||
518 | if (E_FILENOTFOUND != hr) | ||
519 | { | ||
520 | DepExitOnFailure(hr, "Failed to open the dependents subkey under the dependency \"%ls\".", wzDependencyProviderKey); | ||
521 | } | ||
522 | else | ||
523 | { | ||
524 | ExitFunction(); | ||
525 | } | ||
526 | |||
527 | // Delete the wzProviderKey dependent sub-key. | ||
528 | hr = RegDelete(hkRegistryDependents, wzProviderKey, REG_KEY_DEFAULT, TRUE); | ||
529 | DepExitOnFailure(hr, "Failed to delete the dependent \"%ls\" under the dependency \"%ls\".", wzProviderKey, wzDependencyProviderKey); | ||
530 | |||
531 | // If there are no remaining dependents, delete the Dependents subkey. | ||
532 | hr = RegQueryKey(hkRegistryDependents, &cSubKeys, NULL); | ||
533 | DepExitOnFailure(hr, "Failed to get the number of dependent subkeys under the dependency \"%ls\".", wzDependencyProviderKey); | ||
534 | |||
535 | if (0 < cSubKeys) | ||
536 | { | ||
537 | ExitFunction(); | ||
538 | } | ||
539 | |||
540 | // Release the handle to make sure it's deleted immediately. | ||
541 | ReleaseRegKey(hkRegistryDependents); | ||
542 | |||
543 | // Fail if there are any subkeys since we just checked. | ||
544 | hr = RegDelete(hkDependencyProviderKey, vsczRegistryDependents, REG_KEY_DEFAULT, FALSE); | ||
545 | DepExitOnFailure(hr, "Failed to delete the dependents subkey under the dependency \"%ls\".", wzDependencyProviderKey); | ||
546 | |||
547 | // If there are no values, delete the provider dependency key. | ||
548 | hr = RegQueryKey(hkDependencyProviderKey, NULL, &cValues); | ||
549 | DepExitOnFailure(hr, "Failed to get the number of values under the dependency \"%ls\".", wzDependencyProviderKey); | ||
550 | |||
551 | if (0 == cValues) | ||
552 | { | ||
553 | // Release the handle to make sure it's deleted immediately. | ||
554 | ReleaseRegKey(hkDependencyProviderKey); | ||
555 | |||
556 | // Fail if there are any subkeys since we just checked. | ||
557 | hr = RegDelete(hkRegistryRoot, wzDependencyProviderKey, REG_KEY_DEFAULT, FALSE); | ||
558 | DepExitOnFailure(hr, "Failed to delete the dependency \"%ls\".", wzDependencyProviderKey); | ||
559 | } | ||
560 | |||
561 | LExit: | ||
562 | ReleaseRegKey(hkRegistryDependents); | ||
563 | ReleaseRegKey(hkDependencyProviderKey); | ||
564 | ReleaseRegKey(hkRegistryRoot); | ||
565 | |||
566 | return hr; | ||
567 | } | ||
568 | |||
569 | DAPI_(HRESULT) DepDependencyArrayAlloc( | ||
570 | __deref_inout_ecount_opt(*pcDependencies) DEPENDENCY** prgDependencies, | ||
571 | __inout LPUINT pcDependencies, | ||
572 | __in_z LPCWSTR wzKey, | ||
573 | __in_z_opt LPCWSTR wzName | ||
574 | ) | ||
575 | { | ||
576 | HRESULT hr = S_OK; | ||
577 | UINT cRequired = 0; | ||
578 | DEPENDENCY* pDependency = NULL; | ||
579 | |||
580 | hr = ::UIntAdd(*pcDependencies, 1, &cRequired); | ||
581 | DepExitOnFailure(hr, "Failed to increment the number of elements required in the dependency array."); | ||
582 | |||
583 | hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(prgDependencies), cRequired, sizeof(DEPENDENCY), ARRAY_GROWTH_SIZE); | ||
584 | DepExitOnFailure(hr, "Failed to allocate memory for the dependency array."); | ||
585 | |||
586 | pDependency = static_cast<DEPENDENCY*>(&(*prgDependencies)[*pcDependencies]); | ||
587 | DepExitOnNull(pDependency, hr, E_POINTER, "The dependency element in the array is invalid."); | ||
588 | |||
589 | hr = StrAllocString(&(pDependency->sczKey), wzKey, 0); | ||
590 | DepExitOnFailure(hr, "Failed to allocate the string key in the dependency array."); | ||
591 | |||
592 | if (wzName) | ||
593 | { | ||
594 | hr = StrAllocString(&(pDependency->sczName), wzName, 0); | ||
595 | DepExitOnFailure(hr, "Failed to allocate the string name in the dependency array."); | ||
596 | } | ||
597 | |||
598 | // Update the number of current elements in the dependency array. | ||
599 | *pcDependencies = cRequired; | ||
600 | |||
601 | LExit: | ||
602 | return hr; | ||
603 | } | ||
604 | |||
605 | DAPI_(void) DepDependencyArrayFree( | ||
606 | __in_ecount(cDependencies) DEPENDENCY* rgDependencies, | ||
607 | __in UINT cDependencies | ||
608 | ) | ||
609 | { | ||
610 | for (UINT i = 0; i < cDependencies; ++i) | ||
611 | { | ||
612 | ReleaseStr(rgDependencies[i].sczKey); | ||
613 | ReleaseStr(rgDependencies[i].sczName); | ||
614 | } | ||
615 | |||
616 | ReleaseMem(rgDependencies); | ||
617 | } | ||
618 | |||
619 | /*************************************************************************** | ||
620 | AllocDependencyKeyName - Allocates and formats the root registry key name. | ||
621 | |||
622 | ***************************************************************************/ | ||
623 | static HRESULT AllocDependencyKeyName( | ||
624 | __in_z LPCWSTR wzName, | ||
625 | __deref_out_z LPWSTR* psczKeyName | ||
626 | ) | ||
627 | { | ||
628 | HRESULT hr = S_OK; | ||
629 | size_t cchName = 0; | ||
630 | size_t cchKeyName = 0; | ||
631 | |||
632 | // Get the length of the static registry root once. | ||
633 | static size_t cchRegistryRoot = ::lstrlenW(vsczRegistryRoot); | ||
634 | |||
635 | // Get the length of the dependency, and add to the length of the root. | ||
636 | hr = ::StringCchLengthW(wzName, STRSAFE_MAX_CCH, &cchName); | ||
637 | DepExitOnFailure(hr, "Failed to get string length of dependency name."); | ||
638 | |||
639 | // Add the sizes together to allocate memory once (callee will add space for nul). | ||
640 | hr = ::SizeTAdd(cchRegistryRoot, cchName, &cchKeyName); | ||
641 | DepExitOnFailure(hr, "Failed to add the string lengths together."); | ||
642 | |||
643 | // Allocate and concat the strings together. | ||
644 | hr = StrAllocString(psczKeyName, vsczRegistryRoot, cchKeyName); | ||
645 | DepExitOnFailure(hr, "Failed to allocate string for dependency registry root."); | ||
646 | |||
647 | hr = StrAllocConcat(psczKeyName, wzName, cchName); | ||
648 | DepExitOnFailure(hr, "Failed to concatenate the dependency key name."); | ||
649 | |||
650 | LExit: | ||
651 | return hr; | ||
652 | } | ||
653 | |||
654 | /*************************************************************************** | ||
655 | GetDependencyNameFromKey - Attempts to name of the dependency from the key. | ||
656 | |||
657 | ***************************************************************************/ | ||
658 | static HRESULT GetDependencyNameFromKey( | ||
659 | __in HKEY hkHive, | ||
660 | __in LPCWSTR wzProviderKey, | ||
661 | __deref_out_z LPWSTR* psczName | ||
662 | ) | ||
663 | { | ||
664 | HRESULT hr = S_OK; | ||
665 | LPWSTR sczKey = NULL; | ||
666 | HKEY hkKey = NULL; | ||
667 | |||
668 | // Format the provider dependency registry key. | ||
669 | hr = AllocDependencyKeyName(wzProviderKey, &sczKey); | ||
670 | DepExitOnFailure(hr, "Failed to allocate the registry key for dependency \"%ls\".", wzProviderKey); | ||
671 | |||
672 | // Try to open the dependency key. | ||
673 | hr = RegOpen(hkHive, sczKey, KEY_READ, &hkKey); | ||
674 | if (E_FILENOTFOUND != hr) | ||
675 | { | ||
676 | DepExitOnFailure(hr, "Failed to open the registry key for the dependency \"%ls\".", wzProviderKey); | ||
677 | } | ||
678 | else | ||
679 | { | ||
680 | ExitFunction1(hr = S_OK); | ||
681 | } | ||
682 | |||
683 | // Get the DisplayName if available. | ||
684 | hr = RegReadString(hkKey, vcszDisplayNameValue, psczName); | ||
685 | if (E_FILENOTFOUND != hr) | ||
686 | { | ||
687 | DepExitOnFailure(hr, "Failed to get the dependency name for the dependency \"%ls\".", wzProviderKey); | ||
688 | } | ||
689 | else | ||
690 | { | ||
691 | ExitFunction1(hr = S_OK); | ||
692 | } | ||
693 | |||
694 | LExit: | ||
695 | ReleaseRegKey(hkKey); | ||
696 | ReleaseStr(sczKey); | ||
697 | |||
698 | return hr; | ||
699 | } | ||