aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2018-12-29 14:33:39 -0600
committerSean Hall <r.sean.hall@gmail.com>2018-12-29 14:37:50 -0600
commit88cd76dbbcce061f80e234489bc18450f56a6e77 (patch)
tree411572481b0854166836b46e0fa8d80ffb8db82f
parent8f18a68edca97a944b2fbfeab7a41596b159f146 (diff)
downloadwix-88cd76dbbcce061f80e234489bc18450f56a6e77.tar.gz
wix-88cd76dbbcce061f80e234489bc18450f56a6e77.tar.bz2
wix-88cd76dbbcce061f80e234489bc18450f56a6e77.zip
Import deputil from old v4 repo.
-rw-r--r--src/dutil/deputil.cpp688
-rw-r--r--src/dutil/dutil.vcxproj2
-rw-r--r--src/dutil/inc/deputil.h147
-rw-r--r--src/dutil/precomp.h1
4 files changed, 838 insertions, 0 deletions
diff --git a/src/dutil/deputil.cpp b/src/dutil/deputil.cpp
new file mode 100644
index 00000000..b2db0dd6
--- /dev/null
+++ b/src/dutil/deputil.cpp
@@ -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
7static LPCWSTR vcszVersionValue = L"Version";
8static LPCWSTR vcszDisplayNameValue = L"DisplayName";
9static LPCWSTR vcszMinVersionValue = L"MinVersion";
10static LPCWSTR vcszMaxVersionValue = L"MaxVersion";
11static LPCWSTR vcszAttributesValue = L"Attributes";
12
13enum 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.
17static LPCWSTR vsczRegistryRoot = L"Software\\Classes\\Installer\\Dependencies\\";
18static LPCWSTR vsczRegistryDependents = L"Dependents";
19
20static HRESULT AllocDependencyKeyName(
21 __in_z LPCWSTR wzName,
22 __deref_out_z LPWSTR* psczKeyName
23 );
24
25static HRESULT GetDependencyNameFromKey(
26 __in HKEY hkHive,
27 __in LPCWSTR wzKey,
28 __deref_out_z LPWSTR* psczName
29 );
30
31DAPI_(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
88LExit:
89 ReleaseRegKey(hkKey);
90 ReleaseStr(sczKey);
91
92 return hr;
93}
94
95DAPI_(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
226LExit:
227 ReleaseStr(sczName);
228 ReleaseRegKey(hkKey);
229 ReleaseStr(sczKey);
230
231 return hr;
232}
233
234DAPI_(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
300LExit:
301 ReleaseStr(sczDependentName);
302 ReleaseStr(sczDependentKey);
303 ReleaseRegKey(hkDependentsKey);
304 ReleaseRegKey(hkProviderKey);
305 ReleaseStr(sczKey);
306
307 return hr;
308}
309
310DAPI_(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
354LExit:
355 ReleaseRegKey(hkKey);
356 ReleaseStr(sczKey);
357
358 return hr;
359}
360
361DAPI_(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
381LExit:
382 ReleaseRegKey(hkDependentKey);
383 ReleaseStr(sczDependentKey);
384
385 return hr;
386}
387
388DAPI_(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
434LExit:
435 ReleaseRegKey(hkKey);
436 ReleaseStr(sczKey);
437 ReleaseRegKey(hkDependencyKey);
438 ReleaseStr(sczDependencyKey);
439
440 return hr;
441}
442
443DAPI_(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
463LExit:
464 ReleaseRegKey(hkKey);
465 ReleaseStr(sczKey);
466
467 return hr;
468}
469
470DAPI_(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
550LExit:
551 ReleaseRegKey(hkRegistryDependents);
552 ReleaseRegKey(hkDependencyProviderKey);
553 ReleaseRegKey(hkRegistryRoot);
554
555 return hr;
556}
557
558DAPI_(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
590LExit:
591 return hr;
592}
593
594DAPI_(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***************************************************************************/
612static 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
639LExit:
640 return hr;
641}
642
643/***************************************************************************
644 GetDependencyNameFromKey - Attempts to name of the dependency from the key.
645
646***************************************************************************/
647static 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
683LExit:
684 ReleaseRegKey(hkKey);
685 ReleaseStr(sczKey);
686
687 return hr;
688}
diff --git a/src/dutil/dutil.vcxproj b/src/dutil/dutil.vcxproj
index 95b90665..606eb87b 100644
--- a/src/dutil/dutil.vcxproj
+++ b/src/dutil/dutil.vcxproj
@@ -171,6 +171,7 @@
171 <ClCompile Include="condutil.cpp" /> 171 <ClCompile Include="condutil.cpp" />
172 <ClCompile Include="conutil.cpp" /> 172 <ClCompile Include="conutil.cpp" />
173 <ClCompile Include="cryputil.cpp" /> 173 <ClCompile Include="cryputil.cpp" />
174 <ClCompile Include="deputil.cpp" />
174 <ClCompile Include="dictutil.cpp" /> 175 <ClCompile Include="dictutil.cpp" />
175 <ClCompile Include="dirutil.cpp" /> 176 <ClCompile Include="dirutil.cpp" />
176 <ClCompile Include="dlutil.cpp" /> 177 <ClCompile Include="dlutil.cpp" />
@@ -238,6 +239,7 @@
238 <ClInclude Include="inc\condutil.h" /> 239 <ClInclude Include="inc\condutil.h" />
239 <ClInclude Include="inc\conutil.h" /> 240 <ClInclude Include="inc\conutil.h" />
240 <ClInclude Include="inc\cryputil.h" /> 241 <ClInclude Include="inc\cryputil.h" />
242 <ClInclude Include="inc\deputil.h" />
241 <ClInclude Include="inc\dictutil.h" /> 243 <ClInclude Include="inc\dictutil.h" />
242 <ClInclude Include="inc\dirutil.h" /> 244 <ClInclude Include="inc\dirutil.h" />
243 <ClInclude Include="inc\dlutil.h" /> 245 <ClInclude Include="inc\dlutil.h" />
diff --git a/src/dutil/inc/deputil.h b/src/dutil/inc/deputil.h
new file mode 100644
index 00000000..a08d2eb5
--- /dev/null
+++ b/src/dutil/inc/deputil.h
@@ -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
6extern "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
12typedef 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***************************************************************************/
25DAPI_(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***************************************************************************/
39DAPI_(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***************************************************************************/
55DAPI_(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***************************************************************************/
68DAPI_(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***************************************************************************/
83DAPI_(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***************************************************************************/
93DAPI_(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***************************************************************************/
108DAPI_(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 ***************************************************************************/
119DAPI_(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***************************************************************************/
129DAPI_(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***************************************************************************/
140DAPI_(void) DepDependencyArrayFree(
141 __in_ecount(cDependencies) DEPENDENCY* rgDependencies,
142 __in UINT cDependencies
143 );
144
145#ifdef __cplusplus
146}
147#endif
diff --git a/src/dutil/precomp.h b/src/dutil/precomp.h
index 3acbca43..c305573d 100644
--- a/src/dutil/precomp.h
+++ b/src/dutil/precomp.h
@@ -56,6 +56,7 @@
56#include "guidutil.h" 56#include "guidutil.h"
57#include "gdiputil.h" 57#include "gdiputil.h"
58#include "dictutil.h" 58#include "dictutil.h"
59#include "deputil.h" // NOTE: This must come after dictutil.h since it uses it.
59#include "inetutil.h" 60#include "inetutil.h"
60#include "iniutil.h" 61#include "iniutil.h"
61#include "jsonutil.h" 62#include "jsonutil.h"