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