aboutsummaryrefslogtreecommitdiff
path: root/src/ca
diff options
context:
space:
mode:
Diffstat (limited to 'src/ca')
-rw-r--r--src/ca/dllmain.cpp27
-rw-r--r--src/ca/precomp.h18
-rw-r--r--src/ca/wixdepca.cpp516
-rw-r--r--src/ca/wixdepca.def8
-rw-r--r--src/ca/wixdepca.vcxproj57
-rw-r--r--src/ca/wixdepca.vcxproj.filters40
6 files changed, 666 insertions, 0 deletions
diff --git a/src/ca/dllmain.cpp b/src/ca/dllmain.cpp
new file mode 100644
index 00000000..7d299feb
--- /dev/null
+++ b/src/ca/dllmain.cpp
@@ -0,0 +1,27 @@
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/********************************************************************
6DllMain - standard entry point for all WiX custom actions.
7
8********************************************************************/
9extern "C" BOOL WINAPI DllMain(
10 IN HINSTANCE hInstance,
11 IN ULONG ulReason,
12 IN LPVOID)
13{
14 switch(ulReason)
15 {
16 case DLL_PROCESS_ATTACH:
17 WcaGlobalInitialize(hInstance);
18 ::DisableThreadLibraryCalls(hInstance);
19 break;
20
21 case DLL_PROCESS_DETACH:
22 WcaGlobalFinalize();
23 break;
24 }
25
26 return TRUE;
27}
diff --git a/src/ca/precomp.h b/src/ca/precomp.h
new file mode 100644
index 00000000..5fd06cff
--- /dev/null
+++ b/src/ca/precomp.h
@@ -0,0 +1,18 @@
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#include <windows.h>
6#include <msiquery.h>
7#include <intsafe.h>
8#include <strsafe.h>
9
10#include "wcautil.h"
11#include "fileutil.h"
12#include "strutil.h"
13#include "memutil.h"
14#include "regutil.h"
15#include "dictutil.h"
16#include "deputil.h"
17
18#include "CustomMsiErrors.h"
diff --git a/src/ca/wixdepca.cpp b/src/ca/wixdepca.cpp
new file mode 100644
index 00000000..154b73f2
--- /dev/null
+++ b/src/ca/wixdepca.cpp
@@ -0,0 +1,516 @@
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 IDNOACTION 0
6#define INITIAL_STRINGDICT_SIZE 4
7
8LPCWSTR vcsDependencyProviderQuery =
9 L"SELECT `WixDependencyProvider`.`WixDependencyProvider`, `WixDependencyProvider`.`Component_`, `WixDependencyProvider`.`ProviderKey`, `WixDependencyProvider`.`Attributes` "
10 L"FROM `WixDependencyProvider`";
11enum eDependencyProviderQuery { dpqId = 1, dpqComponent, dpqProviderKey, dpqAttributes };
12
13LPCWSTR vcsDependencyQuery =
14 L"SELECT `WixDependency`.`WixDependency`, `WixDependencyProvider`.`Component_`, `WixDependency`.`ProviderKey`, `WixDependency`.`MinVersion`, `WixDependency`.`MaxVersion`, `WixDependency`.`Attributes` "
15 L"FROM `WixDependencyProvider`, `WixDependency`, `WixDependencyRef` "
16 L"WHERE `WixDependency`.`WixDependency` = `WixDependencyRef`.`WixDependency_` AND `WixDependencyProvider`.`WixDependencyProvider` = `WixDependencyRef`.`WixDependencyProvider_`";
17enum eDependencyComponentQuery { dqId = 1, dqComponent, dqProviderKey, dqMinVersion, dqMaxVersion, dqAttributes };
18
19static HRESULT EnsureRequiredDependencies(
20 __in MSIHANDLE hInstall,
21 __in BOOL fMachineContext
22 );
23
24static HRESULT EnsureAbsentDependents(
25 __in MSIHANDLE hInstall,
26 __in BOOL fMachineContext
27 );
28
29static HRESULT SplitIgnoredDependents(
30 __deref_inout STRINGDICT_HANDLE* psdIgnoredDependents
31 );
32
33static HRESULT CreateDependencyRecord(
34 __in int iMessageId,
35 __in_ecount(cDependencies) const DEPENDENCY* rgDependencies,
36 __in UINT cDependencies,
37 __out MSIHANDLE *phRecord
38 );
39
40static LPCWSTR LogDependencyName(
41 __in_z LPCWSTR wzName
42 );
43
44/***************************************************************************
45 WixDependencyRequire - Checks that all required dependencies are installed.
46
47***************************************************************************/
48extern "C" UINT __stdcall WixDependencyRequire(
49 __in MSIHANDLE hInstall
50 )
51{
52 HRESULT hr = S_OK;
53 UINT er = ERROR_SUCCESS;
54 BOOL fMachineContext = FALSE;
55
56 hr = WcaInitialize(hInstall, "WixDependencyRequire");
57 ExitOnFailure(hr, "Failed to initialize.");
58
59 hr = RegInitialize();
60 ExitOnFailure(hr, "Failed to initialize the registry functions.");
61
62 // Determine whether we're installing per-user or per-machine.
63 fMachineContext = WcaIsPropertySet("ALLUSERS");
64
65 // Check for any provider components being (re)installed that their requirements are already installed.
66 hr = EnsureRequiredDependencies(hInstall, fMachineContext);
67 ExitOnFailure(hr, "Failed to ensure required dependencies for (re)installing components.");
68
69LExit:
70 RegUninitialize();
71
72 er = FAILED(hr) ? ERROR_INSTALL_FAILURE : ERROR_SUCCESS;
73 return WcaFinalize(er);
74}
75
76/***************************************************************************
77 WixDependencyCheck - Check dependencies based on component state.
78
79 Note: may return ERROR_NO_MORE_ITEMS to terminate the session early.
80***************************************************************************/
81extern "C" UINT __stdcall WixDependencyCheck(
82 __in MSIHANDLE hInstall
83 )
84{
85 HRESULT hr = S_OK;
86 UINT er = ERROR_SUCCESS;
87 BOOL fMachineContext = FALSE;
88
89 hr = WcaInitialize(hInstall, "WixDependencyCheck");
90 ExitOnFailure(hr, "Failed to initialize.");
91
92 hr = RegInitialize();
93 ExitOnFailure(hr, "Failed to initialize the registry functions.");
94
95 // Determine whether we're installing per-user or per-machine.
96 fMachineContext = WcaIsPropertySet("ALLUSERS");
97
98 // Check for any dependents of provider components being uninstalled.
99 hr = EnsureAbsentDependents(hInstall, fMachineContext);
100 ExitOnFailure(hr, "Failed to ensure absent dependents for uninstalling components.");
101
102LExit:
103 RegUninitialize();
104
105 er = FAILED(hr) ? ERROR_INSTALL_FAILURE : ERROR_SUCCESS;
106 return WcaFinalize(er);
107}
108
109/***************************************************************************
110 EnsureRequiredDependencies - Check that dependencies are installed for
111 any provider component that is being installed or reinstalled.
112
113 Note: Skipped if DISABLEDEPENDENCYCHECK is set.
114***************************************************************************/
115static HRESULT EnsureRequiredDependencies(
116 __in MSIHANDLE /*hInstall*/,
117 __in BOOL fMachineContext
118 )
119{
120 HRESULT hr = S_OK;
121 DWORD er = ERROR_SUCCESS;
122 STRINGDICT_HANDLE sdDependencies = NULL;
123 HKEY hkHive = NULL;
124 PMSIHANDLE hView = NULL;
125 PMSIHANDLE hRec = NULL;
126 LPWSTR sczId = NULL;
127 LPWSTR sczComponent = NULL;
128 LPWSTR sczProviderKey = NULL;
129 LPWSTR sczMinVersion = NULL;
130 LPWSTR sczMaxVersion = NULL;
131 int iAttributes = 0;
132 WCA_TODO tComponentAction = WCA_TODO_UNKNOWN;
133 DEPENDENCY* rgDependencies = NULL;
134 UINT cDependencies = 0;
135 PMSIHANDLE hDependencyRec = NULL;
136
137 // Skip the dependency check if the WixDependency table is missing (no dependencies to check for).
138 hr = WcaTableExists(L"WixDependency");
139 if (S_FALSE == hr)
140 {
141 WcaLog(LOGMSG_STANDARD, "Skipping the dependency check since no dependencies are authored.");
142 ExitFunction1(hr = S_OK);
143 }
144
145 // If the table exists but not the others, the database was not authored correctly.
146 ExitOnFailure(hr, "Failed to check if the WixDependency table exists.");
147
148 // Initialize the dictionary to keep track of unique dependency keys.
149 hr = DictCreateStringList(&sdDependencies, INITIAL_STRINGDICT_SIZE, DICT_FLAG_CASEINSENSITIVE);
150 ExitOnFailure(hr, "Failed to initialize the unique dependency string list.");
151
152 // Set the registry hive to use depending on install context.
153 hkHive = fMachineContext ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
154
155 // Loop over the provider components.
156 hr = WcaOpenExecuteView(vcsDependencyQuery, &hView);
157 ExitOnFailure(hr, "Failed to open the query view for dependencies.");
158
159 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
160 {
161 hr = WcaGetRecordString(hRec, dqId, &sczId);
162 ExitOnFailure(hr, "Failed to get WixDependency.WixDependency.");
163
164 hr = WcaGetRecordString(hRec, dqComponent, &sczComponent);
165 ExitOnFailure(hr, "Failed to get WixDependencyProvider.Component_.");
166
167 // Skip the current component if its not being installed or reinstalled.
168 tComponentAction = WcaGetComponentToDo(sczComponent);
169 if (WCA_TODO_INSTALL != tComponentAction && WCA_TODO_REINSTALL != tComponentAction)
170 {
171 WcaLog(LOGMSG_STANDARD, "Skipping dependency check for %ls because the component %ls is not being (re)installed.", sczId, sczComponent);
172 continue;
173 }
174
175 hr = WcaGetRecordString(hRec, dqProviderKey, &sczProviderKey);
176 ExitOnFailure(hr, "Failed to get WixDependency.ProviderKey.");
177
178 hr = WcaGetRecordString(hRec, dqMinVersion, &sczMinVersion);
179 ExitOnFailure(hr, "Failed to get WixDependency.MinVersion.");
180
181 hr = WcaGetRecordString(hRec, dqMaxVersion, &sczMaxVersion);
182 ExitOnFailure(hr, "Failed to get WixDependency.MaxVersion.");
183
184 hr = WcaGetRecordInteger(hRec, dqAttributes, &iAttributes);
185 ExitOnFailure(hr, "Failed to get WixDependency.Attributes.");
186
187 // Check the registry to see if the required providers (dependencies) exist.
188 hr = DepCheckDependency(hkHive, sczProviderKey, sczMinVersion, sczMaxVersion, iAttributes, sdDependencies, &rgDependencies, &cDependencies);
189 if (E_NOTFOUND != hr)
190 {
191 ExitOnFailure(hr, "Failed dependency check for %ls.", sczId);
192 }
193 }
194
195 if (E_NOMOREITEMS != hr)
196 {
197 ExitOnFailure(hr, "Failed to enumerate all of the rows in the dependency query view.");
198 }
199 else
200 {
201 hr = S_OK;
202 }
203
204 // If we collected any dependencies in the previous check, pump a message and prompt the user.
205 if (0 < cDependencies)
206 {
207 hr = CreateDependencyRecord(msierrDependencyMissingDependencies, rgDependencies, cDependencies, &hDependencyRec);
208 ExitOnFailure(hr, "Failed to create the dependency record for message %d.", msierrDependencyMissingDependencies);
209
210 // Send a yes/no message with a warning icon since continuing could be detrimental.
211 // This is sent as a USER message to better detect whether a user or dependency-aware bootstrapper is responding
212 // or if Windows Installer or a dependency-unaware boostrapper is returning a typical default response.
213 er = WcaProcessMessage(static_cast<INSTALLMESSAGE>(INSTALLMESSAGE_USER | MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2), hDependencyRec);
214 switch (er)
215 {
216 // Only a user or dependency-aware bootstrapper that prompted the user should return IDYES to continue anyway.
217 case IDYES:
218 ExitFunction1(hr = S_OK);
219
220 // Only a user or dependency-aware bootstrapper that prompted the user should return IDNO to terminate the operation.
221 case IDNO:
222 WcaSetReturnValue(ERROR_INSTALL_USEREXIT);
223 ExitFunction1(hr = S_OK);
224
225 // A dependency-aware bootstrapper should return IDCANCEL if running silently and the operation should be canceled.
226 case IDCANCEL:
227 __fallthrough;
228
229 // Bootstrappers which are not dependency-aware may return IDOK for unhandled messages.
230 case IDOK:
231 __fallthrough;
232
233 // Windows Installer returns 0 for USER messages when silent or passive, or when a bootstrapper does not handle the message.
234 case IDNOACTION:
235 WcaSetReturnValue(ERROR_INSTALL_FAILURE);
236 ExitFunction1(hr = S_OK);
237
238 default:
239 ExitOnFailure(hr = E_UNEXPECTED, "Unexpected message response %d from user or bootstrapper application.", er);
240 }
241 }
242
243LExit:
244 ReleaseDependencyArray(rgDependencies, cDependencies);
245 ReleaseStr(sczId);
246 ReleaseStr(sczComponent);
247 ReleaseStr(sczProviderKey);
248 ReleaseStr(sczMinVersion);
249 ReleaseStr(sczMaxVersion);
250 ReleaseDict(sdDependencies);
251
252 return hr;
253}
254
255/***************************************************************************
256 EnsureAbsentDependents - Checks that there are no dependents
257 registered for providers that are being uninstalled.
258
259 Note: Skipped if UPGRADINGPRODUCTCODE is set.
260***************************************************************************/
261static HRESULT EnsureAbsentDependents(
262 __in MSIHANDLE /*hInstall*/,
263 __in BOOL fMachineContext
264 )
265{
266 HRESULT hr = S_OK;
267 DWORD er = ERROR_SUCCESS;
268 STRINGDICT_HANDLE sdIgnoredDependents = NULL;
269 HKEY hkHive = NULL;
270 PMSIHANDLE hView = NULL;
271 PMSIHANDLE hRec = NULL;
272 LPWSTR sczId = NULL;
273 LPWSTR sczComponent = NULL;
274 LPWSTR sczProviderKey = NULL;
275 int iAttributes = 0;
276 WCA_TODO tComponentAction = WCA_TODO_UNKNOWN;
277 DEPENDENCY* rgDependents = NULL;
278 UINT cDependents = 0;
279 PMSIHANDLE hDependencyRec = NULL;
280
281 // Split the IGNOREDEPENDENCIES property for use below if set. If it is "ALL", then quit now.
282 hr = SplitIgnoredDependents(&sdIgnoredDependents);
283 ExitOnFailure(hr, "Failed to get the ignored dependents.");
284
285 hr = DictKeyExists(sdIgnoredDependents, L"ALL");
286 if (E_NOTFOUND != hr)
287 {
288 ExitOnFailure(hr, "Failed to check if \"ALL\" was set in IGNOREDEPENDENCIES.");
289
290 // Otherwise...
291 WcaLog(LOGMSG_STANDARD, "Skipping the dependencies check since IGNOREDEPENDENCIES contains \"ALL\".");
292 ExitFunction();
293 }
294 else
295 {
296 // Key was not found, so proceed.
297 hr = S_OK;
298 }
299
300 // Skip the dependent check if the WixDependencyProvider table is missing (no dependency providers).
301 hr = WcaTableExists(L"WixDependencyProvider");
302 if (S_FALSE == hr)
303 {
304 WcaLog(LOGMSG_STANDARD, "Skipping the dependents check since no dependency providers are authored.");
305 ExitFunction();
306 }
307
308 ExitOnFailure(hr, "Failed to check if the WixDependencyProvider table exists.");
309
310 // Set the registry hive to use depending on install context.
311 hkHive = fMachineContext ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
312
313 // Loop over the provider components.
314 hr = WcaOpenExecuteView(vcsDependencyProviderQuery, &hView);
315 ExitOnFailure(hr, "Failed to open the query view for dependency providers.");
316
317 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
318 {
319 hr = WcaGetRecordString(hRec, dpqId, &sczId);
320 ExitOnFailure(hr, "Failed to get WixDependencyProvider.WixDependencyProvider.");
321
322 hr = WcaGetRecordString(hRec, dpqComponent, &sczComponent);
323 ExitOnFailure(hr, "Failed to get WixDependencyProvider.Component.");
324
325 // Skip the current component if its not being uninstalled.
326 tComponentAction = WcaGetComponentToDo(sczComponent);
327 if (WCA_TODO_UNINSTALL != tComponentAction)
328 {
329 WcaLog(LOGMSG_STANDARD, "Skipping dependents check for %ls because the component %ls is not being uninstalled.", sczId, sczComponent);
330 continue;
331 }
332
333 hr = WcaGetRecordString(hRec, dpqProviderKey, &sczProviderKey);
334 ExitOnFailure(hr, "Failed to get WixDependencyProvider.ProviderKey.");
335
336 hr = WcaGetRecordInteger(hRec, dpqAttributes, &iAttributes);
337 ExitOnFailure(hr, "Failed to get WixDependencyProvider.Attributes.");
338
339 // Check the registry to see if the provider has any dependents registered.
340 hr = DepCheckDependents(hkHive, sczProviderKey, iAttributes, sdIgnoredDependents, &rgDependents, &cDependents);
341 ExitOnFailure(hr, "Failed dependents check for %ls.", sczId);
342 }
343
344 if (E_NOMOREITEMS != hr)
345 {
346 ExitOnFailure(hr, "Failed to enumerate all of the rows in the dependency provider query view.");
347 }
348 else
349 {
350 hr = S_OK;
351 }
352
353 // If we collected any providers with dependents in the previous check, pump a message and prompt the user.
354 if (0 < cDependents)
355 {
356 hr = CreateDependencyRecord(msierrDependencyHasDependents, rgDependents, cDependents, &hDependencyRec);
357 ExitOnFailure(hr, "Failed to create the dependency record for message %d.", msierrDependencyHasDependents);
358
359 // Send a yes/no message with a warning icon since continuing could be detrimental.
360 // This is sent as a USER message to better detect whether a user or dependency-aware bootstrapper is responding
361 // or if Windows Installer or a dependency-unaware boostrapper is returning a typical default response.
362 er = WcaProcessMessage(static_cast<INSTALLMESSAGE>(INSTALLMESSAGE_USER | MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2), hDependencyRec);
363 switch (er)
364 {
365 // Only a user or dependency-aware bootstrapper that prompted the user should return IDYES to continue anyway.
366 case IDYES:
367 ExitFunction1(hr = S_OK);
368
369 // Only a user or dependency-aware bootstrapper that prompted the user should return IDNO to terminate the operation.
370 case IDNO:
371 __fallthrough;
372
373 // Bootstrappers which are not dependency-aware may return IDOK for unhandled messages.
374 case IDOK:
375 __fallthrough;
376
377 // Windows Installer returns 0 for USER messages when silent or passive, or when a bootstrapper does not handle the message.
378 case IDNOACTION:
379 WcaSetReturnValue(ERROR_NO_MORE_ITEMS);
380 ExitFunction1(hr = S_OK);
381
382 // A dependency-aware bootstrapper should return IDCANCEL if running silently and the operation should be canceled.
383 case IDCANCEL:
384 WcaSetReturnValue(ERROR_INSTALL_FAILURE);
385 ExitFunction1(hr = S_OK);
386
387 default:
388 hr = E_UNEXPECTED;
389 ExitOnFailure(hr, "Unexpected message response %d from user or bootstrapper application.", er);
390 }
391 }
392
393LExit:
394 ReleaseDependencyArray(rgDependents, cDependents);
395 ReleaseStr(sczId);
396 ReleaseStr(sczComponent);
397 ReleaseStr(sczProviderKey);
398
399 return hr;
400}
401
402/***************************************************************************
403 SplitIgnoredDependents - Splits the IGNOREDEPENDENCIES property into a map.
404
405***************************************************************************/
406static HRESULT SplitIgnoredDependents(
407 __deref_inout STRINGDICT_HANDLE* psdIgnoredDependents
408 )
409{
410 HRESULT hr = S_OK;
411 LPWSTR sczIgnoreDependencies = NULL;
412 LPCWSTR wzDelim = L";";
413 LPWSTR wzContext = NULL;
414
415 hr = WcaGetProperty(L"IGNOREDEPENDENCIES", &sczIgnoreDependencies);
416 ExitOnFailure(hr, "Failed to get the string value of the IGNOREDEPENDENCIES property.");
417
418 hr = DictCreateStringList(psdIgnoredDependents, INITIAL_STRINGDICT_SIZE, DICT_FLAG_CASEINSENSITIVE);
419 ExitOnFailure(hr, "Failed to create the string dictionary.");
420
421 // Parse through the semicolon-delimited tokens and add to the string dictionary.
422 for (LPCWSTR wzToken = ::wcstok_s(sczIgnoreDependencies, wzDelim, &wzContext); wzToken; wzToken = ::wcstok_s(NULL, wzDelim, &wzContext))
423 {
424 hr = DictAddKey(*psdIgnoredDependents, wzToken);
425 ExitOnFailure(hr, "Failed to ignored dependency \"%ls\" to the string dictionary.", wzToken);
426 }
427
428LExit:
429 ReleaseStr(sczIgnoreDependencies);
430
431 return hr;
432}
433
434/***************************************************************************
435 CreateDependencyRecord - Creates a record containing the message template
436 and records to send to the UI handler.
437
438 Notes: Callers should call WcaProcessMessage and handle return codes.
439***************************************************************************/
440static HRESULT CreateDependencyRecord(
441 __in int iMessageId,
442 __in_ecount(cDependencies) const DEPENDENCY* rgDependencies,
443 __in UINT cDependencies,
444 __out MSIHANDLE *phRecord
445 )
446{
447 HRESULT hr = S_OK;
448 UINT er = ERROR_SUCCESS;
449 UINT cParams = 0;
450 UINT iParam = 0;
451
452 // Should not be PMSIHANDLE.
453 MSIHANDLE hRec = NULL;
454
455 // Calculate the number of parameters based on the format:
456 // msgId, count, key1, name1, key2, name2, etc.
457 cParams = 2 + 2 * cDependencies;
458
459 hRec = ::MsiCreateRecord(cParams);
460 ExitOnNull(hRec, hr, E_OUTOFMEMORY, "Not enough memory to create the message record.");
461
462 er = ::MsiRecordSetInteger(hRec, ++iParam, iMessageId);
463 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to set the message identifier into the message record.");
464
465 er = ::MsiRecordSetInteger(hRec, ++iParam, cDependencies);
466 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to set the number of dependencies into the message record.");
467
468 // Now loop through each dependency and add the key and name to the record.
469 for (UINT i = 0; i < cDependencies; i++)
470 {
471 const DEPENDENCY* pDependency = &rgDependencies[i];
472
473 // Log message type-specific information.
474 switch (iMessageId)
475 {
476 // Send a user message when installing a component that is missing some dependencies.
477 case msierrDependencyMissingDependencies:
478 WcaLog(LOGMSG_VERBOSE, "The dependency \"%ls\" is missing or is not the required version.", pDependency->sczKey);
479 break;
480
481 // Send a user message when uninstalling a component that still has registered dependents.
482 case msierrDependencyHasDependents:
483 WcaLog(LOGMSG_VERBOSE, "Found dependent \"%ls\", name: \"%ls\".", pDependency->sczKey, LogDependencyName(pDependency->sczName));
484 break;
485 }
486
487 er = ::MsiRecordSetStringW(hRec, ++iParam, pDependency->sczKey);
488 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to set the dependency key \"%ls\" into the message record.", pDependency->sczKey);
489
490 er = ::MsiRecordSetStringW(hRec, ++iParam, pDependency->sczName);
491 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to set the dependency name \"%ls\" into the message record.", pDependency->sczName);
492 }
493
494 // Only assign the out parameter if successful to this point.
495 *phRecord = hRec;
496 hRec = NULL;
497
498LExit:
499 if (hRec)
500 {
501 ::MsiCloseHandle(hRec);
502 }
503
504 return hr;
505}
506
507/***************************************************************************
508 LogDependencyName - Returns the dependency name or "Unknown" if null.
509
510***************************************************************************/
511static LPCWSTR LogDependencyName(
512 __in_z LPCWSTR wzName
513 )
514{
515 return wzName ? wzName : L"Unknown";
516}
diff --git a/src/ca/wixdepca.def b/src/ca/wixdepca.def
new file mode 100644
index 00000000..df50e992
--- /dev/null
+++ b/src/ca/wixdepca.def
@@ -0,0 +1,8 @@
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
4LIBRARY "wixdepca"
5
6EXPORTS
7 WixDependencyRequire
8 WixDependencyCheck
diff --git a/src/ca/wixdepca.vcxproj b/src/ca/wixdepca.vcxproj
new file mode 100644
index 00000000..b757a35f
--- /dev/null
+++ b/src/ca/wixdepca.vcxproj
@@ -0,0 +1,57 @@
1<?xml version="1.0" encoding="utf-8"?>
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<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
6 <ItemGroup Label="ProjectConfigurations">
7 <ProjectConfiguration Include="Debug|Win32">
8 <Configuration>Debug</Configuration>
9 <Platform>Win32</Platform>
10 </ProjectConfiguration>
11 <ProjectConfiguration Include="Release|Win32">
12 <Configuration>Release</Configuration>
13 <Platform>Win32</Platform>
14 </ProjectConfiguration>
15 </ItemGroup>
16 <ItemGroup Label="ProjectConfigurations">
17 <ProjectConfiguration Include="Debug|ARM">
18 <Configuration>Debug</Configuration>
19 <Platform>ARM</Platform>
20 </ProjectConfiguration>
21 <ProjectConfiguration Include="Release|ARM">
22 <Configuration>Release</Configuration>
23 <Platform>ARM</Platform>
24 </ProjectConfiguration>
25 </ItemGroup>
26
27 <PropertyGroup Label="Globals">
28 <ProjectGuid>{B86AF46C-0F90-49CC-923F-A800B088D015}</ProjectGuid>
29 <ConfigurationType>DynamicLibrary</ConfigurationType>
30 <CharacterSet>Unicode</CharacterSet>
31 <TargetName>WixDepCA</TargetName>
32 <ProjectModuleDefinitionFile>wixdepca.def</ProjectModuleDefinitionFile>
33 </PropertyGroup>
34
35 <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), wix.proj))\tools\WixBuild.props" />
36
37 <PropertyGroup>
38 <ProjectAdditionalIncludeDirectories>$(WixRoot)src\libs\dutil\inc;$(WixRoot)src\libs\wcautil;$(WixRoot)src\libs\deputil\inc</ProjectAdditionalIncludeDirectories>
39 <ProjectAdditionalLinkLibraries>msi.lib;dutil.lib;deputil.lib;wcautil.lib</ProjectAdditionalLinkLibraries>
40 </PropertyGroup>
41
42 <ItemGroup>
43 <ClCompile Include="dllmain.cpp" />
44 <ClCompile Include="wixdepca.cpp" />
45 </ItemGroup>
46 <ItemGroup>
47 <ClInclude Include="precomp.h" />
48 </ItemGroup>
49 <ItemGroup>
50 <None Include="wixdepca.def" />
51 </ItemGroup>
52 <ItemGroup>
53 <ResourceCompile Include="wixdepca.rc" />
54 </ItemGroup>
55
56 <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), wix.proj))\tools\WixBuild.targets" />
57</Project>
diff --git a/src/ca/wixdepca.vcxproj.filters b/src/ca/wixdepca.vcxproj.filters
new file mode 100644
index 00000000..1fdb0236
--- /dev/null
+++ b/src/ca/wixdepca.vcxproj.filters
@@ -0,0 +1,40 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <ItemGroup>
4 <Filter Include="Source Files">
5 <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
6 <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
7 </Filter>
8 <Filter Include="Header Files">
9 <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
10 <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
11 </Filter>
12 <Filter Include="Resource Files">
13 <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
14 <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
15 </Filter>
16 </ItemGroup>
17 <ItemGroup>
18 <ClCompile Include="wixdepca.cpp">
19 <Filter>Source Files</Filter>
20 </ClCompile>
21 <ClCompile Include="dllmain.cpp">
22 <Filter>Source Files</Filter>
23 </ClCompile>
24 </ItemGroup>
25 <ItemGroup>
26 <ClInclude Include="precomp.h">
27 <Filter>Header Files</Filter>
28 </ClInclude>
29 </ItemGroup>
30 <ItemGroup>
31 <ResourceCompile Include="wixdepca.rc">
32 <Filter>Resource Files</Filter>
33 </ResourceCompile>
34 </ItemGroup>
35 <ItemGroup>
36 <None Include="wixdepca.def">
37 <Filter>Source Files</Filter>
38 </None>
39 </ItemGroup>
40</Project> \ No newline at end of file