aboutsummaryrefslogtreecommitdiff
path: root/src/libs/dutil/WixToolset.DUtil/deputil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/dutil/WixToolset.DUtil/deputil.cpp')
-rw-r--r--src/libs/dutil/WixToolset.DUtil/deputil.cpp699
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
22static LPCWSTR vcszVersionValue = L"Version";
23static LPCWSTR vcszDisplayNameValue = L"DisplayName";
24static LPCWSTR vcszMinVersionValue = L"MinVersion";
25static LPCWSTR vcszMaxVersionValue = L"MaxVersion";
26static LPCWSTR vcszAttributesValue = L"Attributes";
27
28enum 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.
32static LPCWSTR vsczRegistryRoot = L"Software\\Classes\\Installer\\Dependencies\\";
33static LPCWSTR vsczRegistryDependents = L"Dependents";
34
35static HRESULT AllocDependencyKeyName(
36 __in_z LPCWSTR wzName,
37 __deref_out_z LPWSTR* psczKeyName
38 );
39
40static HRESULT GetDependencyNameFromKey(
41 __in HKEY hkHive,
42 __in LPCWSTR wzKey,
43 __deref_out_z LPWSTR* psczName
44 );
45
46DAPI_(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
103LExit:
104 ReleaseRegKey(hkKey);
105 ReleaseStr(sczKey);
106
107 return hr;
108}
109
110DAPI_(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
237LExit:
238 ReleaseStr(sczName);
239 ReleaseRegKey(hkKey);
240 ReleaseStr(sczKey);
241
242 return hr;
243}
244
245DAPI_(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
311LExit:
312 ReleaseStr(sczDependentName);
313 ReleaseStr(sczDependentKey);
314 ReleaseRegKey(hkDependentsKey);
315 ReleaseRegKey(hkProviderKey);
316 ReleaseStr(sczKey);
317
318 return hr;
319}
320
321DAPI_(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
365LExit:
366 ReleaseRegKey(hkKey);
367 ReleaseStr(sczKey);
368
369 return hr;
370}
371
372DAPI_(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
392LExit:
393 ReleaseRegKey(hkDependentKey);
394 ReleaseStr(sczDependentKey);
395
396 return hr;
397}
398
399DAPI_(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
445LExit:
446 ReleaseRegKey(hkKey);
447 ReleaseStr(sczKey);
448 ReleaseRegKey(hkDependencyKey);
449 ReleaseStr(sczDependencyKey);
450
451 return hr;
452}
453
454DAPI_(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
474LExit:
475 ReleaseRegKey(hkKey);
476 ReleaseStr(sczKey);
477
478 return hr;
479}
480
481DAPI_(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
561LExit:
562 ReleaseRegKey(hkRegistryDependents);
563 ReleaseRegKey(hkDependencyProviderKey);
564 ReleaseRegKey(hkRegistryRoot);
565
566 return hr;
567}
568
569DAPI_(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
601LExit:
602 return hr;
603}
604
605DAPI_(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***************************************************************************/
623static 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
650LExit:
651 return hr;
652}
653
654/***************************************************************************
655 GetDependencyNameFromKey - Attempts to name of the dependency from the key.
656
657***************************************************************************/
658static 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
694LExit:
695 ReleaseRegKey(hkKey);
696 ReleaseStr(sczKey);
697
698 return hr;
699}