@joebigelow / wix-1 / commits / 88cd76db

Import deputil from old v4 repo.

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