aboutsummaryrefslogtreecommitdiff
path: root/src/burn
diff options
context:
space:
mode:
Diffstat (limited to 'src/burn')
-rw-r--r--src/burn/burn.sln63
-rw-r--r--src/burn/burn.slnx13
-rw-r--r--src/burn/engine/approvedexe.cpp107
-rw-r--r--src/burn/engine/approvedexe.h4
-rw-r--r--src/burn/engine/bootstrapperapplication.cpp2
-rw-r--r--src/burn/engine/bundlepackageengine.cpp14
-rw-r--r--src/burn/engine/burnextension.cpp2
-rw-r--r--src/burn/engine/burnpipe.cpp8
-rw-r--r--src/burn/engine/cabextract.cpp8
-rw-r--r--src/burn/engine/cache.cpp24
-rw-r--r--src/burn/engine/condition.cpp16
-rw-r--r--src/burn/engine/container.cpp2
-rw-r--r--src/burn/engine/core.cpp105
-rw-r--r--src/burn/engine/core.h2
-rw-r--r--src/burn/engine/dependency.cpp28
-rw-r--r--src/burn/engine/detect.cpp2
-rw-r--r--src/burn/engine/elevation.cpp16
-rw-r--r--src/burn/engine/engine.cpp3
-rw-r--r--src/burn/engine/engine.mc6
-rw-r--r--src/burn/engine/engine.vcxproj2
-rw-r--r--src/burn/engine/exeengine.cpp43
-rw-r--r--src/burn/engine/logging.cpp7
-rw-r--r--src/burn/engine/manifest.cpp2
-rw-r--r--src/burn/engine/msiengine.cpp81
-rw-r--r--src/burn/engine/mspengine.cpp6
-rw-r--r--src/burn/engine/msuengine.cpp2
-rw-r--r--src/burn/engine/package.cpp28
-rw-r--r--src/burn/engine/payload.cpp4
-rw-r--r--src/burn/engine/plan.cpp39
-rw-r--r--src/burn/engine/pseudobundle.cpp11
-rw-r--r--src/burn/engine/registration.cpp22
-rw-r--r--src/burn/engine/relatedbundle.cpp8
-rw-r--r--src/burn/engine/search.cpp80
-rw-r--r--src/burn/engine/search.h1
-rw-r--r--src/burn/engine/splashscreen.cpp1
-rw-r--r--src/burn/engine/variable.cpp14
-rw-r--r--src/burn/engine/variant.cpp45
-rw-r--r--src/burn/stub/WixToolset.Burn.props2
-rw-r--r--src/burn/stub/precomp.h1
-rw-r--r--src/burn/stub/stub.cpp2
-rw-r--r--src/burn/stub/stub.vcxproj2
-rw-r--r--src/burn/test/BurnUnitTest/ApprovedExeTest.cpp312
-rw-r--r--src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj3
-rw-r--r--src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj.filters7
-rw-r--r--src/burn/test/BurnUnitTest/PlanTest.cpp16
-rw-r--r--src/burn/test/BurnUnitTest/SearchTest.cpp4
-rw-r--r--src/burn/test/BurnUnitTest/precomp.h1
47 files changed, 846 insertions, 325 deletions
diff --git a/src/burn/burn.sln b/src/burn/burn.sln
deleted file mode 100644
index c820a467..00000000
--- a/src/burn/burn.sln
+++ /dev/null
@@ -1,63 +0,0 @@
1
2Microsoft Visual Studio Solution File, Format Version 12.00
3# Visual Studio Version 17
4VisualStudioVersion = 17.0.32014.148
5MinimumVisualStudioVersion = 15.0.26124.0
6Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "engine", "engine\engine.vcxproj", "{8119537D-E1D9-6591-D51A-49768A2F9C37}"
7EndProject
8Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stub", "stub\stub.vcxproj", "{C38373AA-882F-4F55-B03F-2AAB4BFBE3F1}"
9EndProject
10Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BurnUnitTest", "test\BurnUnitTest\BurnUnitTest.vcxproj", "{9D1F1BA3-9393-4833-87A3-D5F1FC08EF67}"
11EndProject
12Global
13 GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 Debug|ARM64 = Debug|ARM64
15 Debug|x64 = Debug|x64
16 Debug|x86 = Debug|x86
17 Release|ARM64 = Release|ARM64
18 Release|x64 = Release|x64
19 Release|x86 = Release|x86
20 EndGlobalSection
21 GlobalSection(ProjectConfigurationPlatforms) = postSolution
22 {8119537D-E1D9-6591-D51A-49768A2F9C37}.Debug|ARM64.ActiveCfg = Debug|ARM64
23 {8119537D-E1D9-6591-D51A-49768A2F9C37}.Debug|ARM64.Build.0 = Debug|ARM64
24 {8119537D-E1D9-6591-D51A-49768A2F9C37}.Debug|x64.ActiveCfg = Debug|x64
25 {8119537D-E1D9-6591-D51A-49768A2F9C37}.Debug|x64.Build.0 = Debug|x64
26 {8119537D-E1D9-6591-D51A-49768A2F9C37}.Debug|x86.ActiveCfg = Debug|Win32
27 {8119537D-E1D9-6591-D51A-49768A2F9C37}.Debug|x86.Build.0 = Debug|Win32
28 {8119537D-E1D9-6591-D51A-49768A2F9C37}.Release|ARM64.ActiveCfg = Release|ARM64
29 {8119537D-E1D9-6591-D51A-49768A2F9C37}.Release|ARM64.Build.0 = Release|ARM64
30 {8119537D-E1D9-6591-D51A-49768A2F9C37}.Release|x64.ActiveCfg = Release|x64
31 {8119537D-E1D9-6591-D51A-49768A2F9C37}.Release|x64.Build.0 = Release|x64
32 {8119537D-E1D9-6591-D51A-49768A2F9C37}.Release|x86.ActiveCfg = Release|Win32
33 {8119537D-E1D9-6591-D51A-49768A2F9C37}.Release|x86.Build.0 = Release|Win32
34 {C38373AA-882F-4F55-B03F-2AAB4BFBE3F1}.Debug|ARM64.ActiveCfg = Debug|ARM64
35 {C38373AA-882F-4F55-B03F-2AAB4BFBE3F1}.Debug|ARM64.Build.0 = Debug|ARM64
36 {C38373AA-882F-4F55-B03F-2AAB4BFBE3F1}.Debug|x64.ActiveCfg = Debug|x64
37 {C38373AA-882F-4F55-B03F-2AAB4BFBE3F1}.Debug|x64.Build.0 = Debug|x64
38 {C38373AA-882F-4F55-B03F-2AAB4BFBE3F1}.Debug|x86.ActiveCfg = Debug|Win32
39 {C38373AA-882F-4F55-B03F-2AAB4BFBE3F1}.Debug|x86.Build.0 = Debug|Win32
40 {C38373AA-882F-4F55-B03F-2AAB4BFBE3F1}.Release|ARM64.ActiveCfg = Release|ARM64
41 {C38373AA-882F-4F55-B03F-2AAB4BFBE3F1}.Release|ARM64.Build.0 = Release|ARM64
42 {C38373AA-882F-4F55-B03F-2AAB4BFBE3F1}.Release|x64.ActiveCfg = Release|x64
43 {C38373AA-882F-4F55-B03F-2AAB4BFBE3F1}.Release|x64.Build.0 = Release|x64
44 {C38373AA-882F-4F55-B03F-2AAB4BFBE3F1}.Release|x86.ActiveCfg = Release|Win32
45 {C38373AA-882F-4F55-B03F-2AAB4BFBE3F1}.Release|x86.Build.0 = Release|Win32
46 {9D1F1BA3-9393-4833-87A3-D5F1FC08EF67}.Debug|ARM64.ActiveCfg = Debug|x64
47 {9D1F1BA3-9393-4833-87A3-D5F1FC08EF67}.Debug|x64.ActiveCfg = Debug|x64
48 {9D1F1BA3-9393-4833-87A3-D5F1FC08EF67}.Debug|x64.Build.0 = Debug|x64
49 {9D1F1BA3-9393-4833-87A3-D5F1FC08EF67}.Debug|x86.ActiveCfg = Debug|Win32
50 {9D1F1BA3-9393-4833-87A3-D5F1FC08EF67}.Debug|x86.Build.0 = Debug|Win32
51 {9D1F1BA3-9393-4833-87A3-D5F1FC08EF67}.Release|ARM64.ActiveCfg = Release|x64
52 {9D1F1BA3-9393-4833-87A3-D5F1FC08EF67}.Release|x64.ActiveCfg = Release|x64
53 {9D1F1BA3-9393-4833-87A3-D5F1FC08EF67}.Release|x64.Build.0 = Release|x64
54 {9D1F1BA3-9393-4833-87A3-D5F1FC08EF67}.Release|x86.ActiveCfg = Release|Win32
55 {9D1F1BA3-9393-4833-87A3-D5F1FC08EF67}.Release|x86.Build.0 = Release|Win32
56 EndGlobalSection
57 GlobalSection(SolutionProperties) = preSolution
58 HideSolutionNode = FALSE
59 EndGlobalSection
60 GlobalSection(ExtensibilityGlobals) = postSolution
61 SolutionGuid = {A35910C5-8A89-473E-9578-E084172DD3C9}
62 EndGlobalSection
63EndGlobal
diff --git a/src/burn/burn.slnx b/src/burn/burn.slnx
new file mode 100644
index 00000000..76a93036
--- /dev/null
+++ b/src/burn/burn.slnx
@@ -0,0 +1,13 @@
1<Solution>
2 <Configurations>
3 <Platform Name="ARM64" />
4 <Platform Name="x64" />
5 <Platform Name="x86" />
6 </Configurations>
7 <Project Path="engine/engine.vcxproj" Id="8119537d-e1d9-6591-d51a-49768a2f9c37" />
8 <Project Path="stub/stub.vcxproj" Id="c38373aa-882f-4f55-b03f-2aab4bfbe3f1" />
9 <Project Path="test/BurnUnitTest/BurnUnitTest.vcxproj" Id="9d1f1ba3-9393-4833-87a3-d5f1fc08ef67">
10 <Platform Solution="*|ARM64" Project="x64" />
11 <Build Solution="*|ARM64" Project="false" />
12 </Project>
13</Solution>
diff --git a/src/burn/engine/approvedexe.cpp b/src/burn/engine/approvedexe.cpp
index 28b26d6d..27ec2adc 100644
--- a/src/burn/engine/approvedexe.cpp
+++ b/src/burn/engine/approvedexe.cpp
@@ -3,6 +3,13 @@
3#include "precomp.h" 3#include "precomp.h"
4 4
5 5
6// internal function declarations
7
8static HRESULT IsRunDll32(
9 __in BURN_VARIABLES* pVariables,
10 __in LPCWSTR wzExecutablePath
11 );
12
6// function definitions 13// function definitions
7 14
8extern "C" HRESULT ApprovedExesParseFromXml( 15extern "C" HRESULT ApprovedExesParseFromXml(
@@ -122,7 +129,7 @@ extern "C" HRESULT ApprovedExesFindById(
122 { 129 {
123 pApprovedExe = &pApprovedExes->rgApprovedExes[i]; 130 pApprovedExe = &pApprovedExes->rgApprovedExes[i];
124 131
125 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pApprovedExe->sczId, -1, wzId, -1)) 132 if (CSTR_EQUAL == ::CompareStringOrdinal(pApprovedExe->sczId, -1, wzId, -1, FALSE))
126 { 133 {
127 *ppApprovedExe = pApprovedExe; 134 *ppApprovedExe = pApprovedExe;
128 ExitFunction1(hr = S_OK); 135 ExitFunction1(hr = S_OK);
@@ -221,12 +228,15 @@ LExit:
221extern "C" HRESULT ApprovedExesVerifySecureLocation( 228extern "C" HRESULT ApprovedExesVerifySecureLocation(
222 __in BURN_CACHE* pCache, 229 __in BURN_CACHE* pCache,
223 __in BURN_VARIABLES* pVariables, 230 __in BURN_VARIABLES* pVariables,
224 __in LPCWSTR wzExecutablePath 231 __in LPCWSTR wzExecutablePath,
232 __in int argc,
233 __in LPCWSTR* argv
225 ) 234 )
226{ 235{
227 HRESULT hr = S_OK; 236 HRESULT hr = S_OK;
228 LPWSTR scz = NULL; 237 LPWSTR scz = NULL;
229 LPWSTR sczSecondary = NULL; 238 LPWSTR sczSecondary = NULL;
239 LPWSTR sczRunDll32Param = NULL;
230 240
231 const LPCWSTR vrgSecureFolderVariables[] = { 241 const LPCWSTR vrgSecureFolderVariables[] = {
232 L"ProgramFiles64Folder", 242 L"ProgramFiles64Folder",
@@ -273,11 +283,104 @@ extern "C" HRESULT ApprovedExesVerifySecureLocation(
273 ExitFunction(); 283 ExitFunction();
274 } 284 }
275 285
286 // Test if executable is rundll32.exe, and it's target is in a secure location
287 // Example for CUDA UninstallString: "C:\WINDOWS\SysWOW64\RunDll32.EXE" "C:\Program Files\NVIDIA Corporation\Installer2\InstallerCore\NVI2.DLL",UninstallPackage CUDAToolkit_12.8
288 if (argc && argv && argv[0] && *argv[0])
289 {
290 hr = IsRunDll32(pVariables, wzExecutablePath);
291 ExitOnFailure(hr, "Failed to test whether executable is rundll32");
292
293 if (hr == S_OK)
294 {
295 LPCWSTR szComma = wcschr(argv[0], L',');
296 if (szComma && *szComma)
297 {
298 hr = StrAllocString(&sczRunDll32Param, argv[0], szComma - argv[0]);
299 ExitOnFailure(hr, "Failed to allocate string");
300 }
301 else
302 {
303 hr = StrAllocString(&sczRunDll32Param, argv[0], 0);
304 ExitOnFailure(hr, "Failed to allocate string");
305 }
306
307 hr = ApprovedExesVerifySecureLocation(pCache, pVariables, sczRunDll32Param, 0, NULL);
308 ExitOnFailure(hr, "Failed to test whether rundll32's parameter, '%ls', is in a secure location", sczRunDll32Param);
309 if (hr == S_OK)
310 {
311 ExitFunction();
312 }
313 }
314 }
315
276 hr = S_FALSE; 316 hr = S_FALSE;
277 317
278LExit: 318LExit:
279 ReleaseStr(scz); 319 ReleaseStr(scz);
280 ReleaseStr(sczSecondary); 320 ReleaseStr(sczSecondary);
321 ReleaseStr(sczRunDll32Param);
322
323 return hr;
324}
325
326static HRESULT IsRunDll32(
327 __in BURN_VARIABLES* pVariables,
328 __in LPCWSTR wzExecutablePath
329 )
330{
331 HRESULT hr = S_OK;
332 LPWSTR sczFolder = NULL;
333 LPWSTR sczFullPath = NULL;
334 BOOL fEqual = FALSE;
335
336 hr = VariableGetString(pVariables, L"SystemFolder", &sczFolder);
337 ExitOnFailure(hr, "Failed to get the variable: SystemFolder");
338
339 hr = PathConcat(sczFolder, L"rundll32.exe", &sczFullPath);
340 ExitOnFailure(hr, "Failed to combine paths");
341
342 hr = PathCompareCanonicalized(wzExecutablePath, sczFullPath, &fEqual);
343 ExitOnFailure(hr, "Failed to compare paths");
344 if (fEqual)
345 {
346 hr = S_OK;
347 ExitFunction();
348 }
349
350 hr = VariableGetString(pVariables, L"System64Folder", &sczFolder);
351 ExitOnFailure(hr, "Failed to get the variable: System64Folder");
352
353 hr = PathConcat(sczFolder, L"rundll32.exe", &sczFullPath);
354 ExitOnFailure(hr, "Failed to combine paths");
355
356 hr = PathCompareCanonicalized(wzExecutablePath, sczFullPath, &fEqual);
357 ExitOnFailure(hr, "Failed to compare paths");
358 if (fEqual)
359 {
360 hr = S_OK;
361 ExitFunction();
362 }
363
364 // Sysnative
365 hr = PathSystemWindowsSubdirectory(L"SysNative\\", &sczFolder);
366 ExitOnFailure(hr, "Failed to append SysNative directory.");
367
368 hr = PathConcat(sczFolder, L"rundll32.exe", &sczFullPath);
369 ExitOnFailure(hr, "Failed to combine paths");
370
371 hr = PathCompareCanonicalized(wzExecutablePath, sczFullPath, &fEqual);
372 ExitOnFailure(hr, "Failed to compare paths");
373 if (fEqual)
374 {
375 hr = S_OK;
376 ExitFunction();
377 }
378
379 hr = S_FALSE;
380
381LExit:
382 ReleaseStr(sczFolder);
383 ReleaseStr(sczFullPath);
281 384
282 return hr; 385 return hr;
283} 386}
diff --git a/src/burn/engine/approvedexe.h b/src/burn/engine/approvedexe.h
index 7a68c174..0f441485 100644
--- a/src/burn/engine/approvedexe.h
+++ b/src/burn/engine/approvedexe.h
@@ -58,7 +58,9 @@ HRESULT ApprovedExesLaunch(
58HRESULT ApprovedExesVerifySecureLocation( 58HRESULT ApprovedExesVerifySecureLocation(
59 __in BURN_CACHE* pCache, 59 __in BURN_CACHE* pCache,
60 __in BURN_VARIABLES* pVariables, 60 __in BURN_VARIABLES* pVariables,
61 __in LPCWSTR wzExecutablePath 61 __in LPCWSTR wzExecutablePath,
62 __in int argc,
63 __in LPCWSTR* argv
62 ); 64 );
63 65
64 66
diff --git a/src/burn/engine/bootstrapperapplication.cpp b/src/burn/engine/bootstrapperapplication.cpp
index dc3bd5da..346c47a5 100644
--- a/src/burn/engine/bootstrapperapplication.cpp
+++ b/src/burn/engine/bootstrapperapplication.cpp
@@ -674,7 +674,7 @@ static HRESULT VerifyPipeSecret(
674 hr = StrAlloc(&sczVerificationSecret, cbVerificationSecret / sizeof(WCHAR) + 1); 674 hr = StrAlloc(&sczVerificationSecret, cbVerificationSecret / sizeof(WCHAR) + 1);
675 ExitOnFailure(hr, "Failed to allocate buffer for bootstrapper application verification secret."); 675 ExitOnFailure(hr, "Failed to allocate buffer for bootstrapper application verification secret.");
676 676
677 FileReadHandle(hPipe, reinterpret_cast<LPBYTE>(sczVerificationSecret), cbVerificationSecret); 677 hr = FileReadHandle(hPipe, reinterpret_cast<LPBYTE>(sczVerificationSecret), cbVerificationSecret);
678 ExitOnFailure(hr, "Failed to read verification secret from bootstrapper application pipe."); 678 ExitOnFailure(hr, "Failed to read verification secret from bootstrapper application pipe.");
679 679
680 // Verify the secrets match. 680 // Verify the secrets match.
diff --git a/src/burn/engine/bundlepackageengine.cpp b/src/burn/engine/bundlepackageengine.cpp
index 612da389..7ada5f6a 100644
--- a/src/burn/engine/bundlepackageengine.cpp
+++ b/src/burn/engine/bundlepackageengine.cpp
@@ -146,7 +146,7 @@ extern "C" HRESULT BundlePackageEngineParseRelatedCodes(
146 hr = XmlGetAttributeEx(pixnElement, L"Code", &sczCode); 146 hr = XmlGetAttributeEx(pixnElement, L"Code", &sczCode);
147 ExitOnFailure(hr, "Failed to get @Code."); 147 ExitOnFailure(hr, "Failed to get @Code.");
148 148
149 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Detect", -1)) 149 if (CSTR_EQUAL == ::CompareStringOrdinal(sczAction, -1, L"Detect", -1, FALSE))
150 { 150 {
151 hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczDetectCodes), *pcDetectCodes, 1, sizeof(LPWSTR), 5); 151 hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczDetectCodes), *pcDetectCodes, 1, sizeof(LPWSTR), 5);
152 ExitOnFailure(hr, "Failed to resize Detect code array"); 152 ExitOnFailure(hr, "Failed to resize Detect code array");
@@ -155,7 +155,7 @@ extern "C" HRESULT BundlePackageEngineParseRelatedCodes(
155 sczCode = NULL; 155 sczCode = NULL;
156 *pcDetectCodes += 1; 156 *pcDetectCodes += 1;
157 } 157 }
158 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Upgrade", -1)) 158 else if (CSTR_EQUAL == ::CompareStringOrdinal(sczAction, -1, L"Upgrade", -1, FALSE))
159 { 159 {
160 hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczUpgradeCodes), *pcUpgradeCodes, 1, sizeof(LPWSTR), 5); 160 hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczUpgradeCodes), *pcUpgradeCodes, 1, sizeof(LPWSTR), 5);
161 ExitOnFailure(hr, "Failed to resize Upgrade code array"); 161 ExitOnFailure(hr, "Failed to resize Upgrade code array");
@@ -164,7 +164,7 @@ extern "C" HRESULT BundlePackageEngineParseRelatedCodes(
164 sczCode = NULL; 164 sczCode = NULL;
165 *pcUpgradeCodes += 1; 165 *pcUpgradeCodes += 1;
166 } 166 }
167 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Addon", -1)) 167 else if (CSTR_EQUAL == ::CompareStringOrdinal(sczAction, -1, L"Addon", -1, FALSE))
168 { 168 {
169 hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczAddonCodes), *pcAddonCodes, 1, sizeof(LPWSTR), 5); 169 hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczAddonCodes), *pcAddonCodes, 1, sizeof(LPWSTR), 5);
170 ExitOnFailure(hr, "Failed to resize Addon code array"); 170 ExitOnFailure(hr, "Failed to resize Addon code array");
@@ -173,7 +173,7 @@ extern "C" HRESULT BundlePackageEngineParseRelatedCodes(
173 sczCode = NULL; 173 sczCode = NULL;
174 *pcAddonCodes += 1; 174 *pcAddonCodes += 1;
175 } 175 }
176 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Patch", -1)) 176 else if (CSTR_EQUAL == ::CompareStringOrdinal(sczAction, -1, L"Patch", -1, FALSE))
177 { 177 {
178 hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczPatchCodes), *pcPatchCodes, 1, sizeof(LPWSTR), 5); 178 hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczPatchCodes), *pcPatchCodes, 1, sizeof(LPWSTR), 5);
179 ExitOnFailure(hr, "Failed to resize Patch code array"); 179 ExitOnFailure(hr, "Failed to resize Patch code array");
@@ -686,7 +686,7 @@ static BUNDLE_QUERY_CALLBACK_RESULT CALLBACK QueryRelatedBundlesCallback(
686 BOOTSTRAPPER_RELATION_TYPE relationType = RelatedBundleConvertRelationType(pBundle->relationType); 686 BOOTSTRAPPER_RELATION_TYPE relationType = RelatedBundleConvertRelationType(pBundle->relationType);
687 BOOL fPerMachine = BUNDLE_INSTALL_CONTEXT_MACHINE == pBundle->installContext; 687 BOOL fPerMachine = BUNDLE_INSTALL_CONTEXT_MACHINE == pBundle->installContext;
688 688
689 if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pBundle->wzBundleCode, -1, pPackage->Bundle.sczBundleCode, -1) && 689 if (CSTR_EQUAL == ::CompareStringOrdinal(pBundle->wzBundleCode, -1, pPackage->Bundle.sczBundleCode, -1, TRUE) &&
690 pPackage->Bundle.fWin64 == (REG_KEY_64BIT == pBundle->regBitness)) 690 pPackage->Bundle.fWin64 == (REG_KEY_64BIT == pBundle->regBitness))
691 { 691 {
692 Assert(BOOTSTRAPPER_RELATION_UPGRADE == relationType); 692 Assert(BOOTSTRAPPER_RELATION_UPGRADE == relationType);
@@ -817,7 +817,7 @@ static HRESULT ExecuteBundle(
817 817
818 if (pPackage->fPerMachine) 818 if (pPackage->fPerMachine)
819 { 819 {
820 hr = ApprovedExesVerifySecureLocation(pCache, pVariables, sczExecutablePath); 820 hr = ApprovedExesVerifySecureLocation(pCache, pVariables, sczExecutablePath, argcArp - 1, (argcArp > 1) ? const_cast<LPCWSTR*>(argvArp + 1) : NULL);
821 ExitOnFailure(hr, "Failed to verify the QuietUninstallString executable path is in a secure location: %ls", sczExecutablePath); 821 ExitOnFailure(hr, "Failed to verify the QuietUninstallString executable path is in a secure location: %ls", sczExecutablePath);
822 if (S_FALSE == hr) 822 if (S_FALSE == hr)
823 { 823 {
@@ -940,7 +940,7 @@ static HRESULT ExecuteBundle(
940 940
941 if (wzRelationTypeCommandLine) 941 if (wzRelationTypeCommandLine)
942 { 942 {
943 hr = StrAllocConcatFormatted(&sczBaseCommand, L" -%ls", wzRelationTypeCommandLine); 943 hr = StrAllocConcatFormatted(&sczBaseCommand, L" -quiet -%ls", wzRelationTypeCommandLine);
944 ExitOnFailure(hr, "Failed to append relation type argument."); 944 ExitOnFailure(hr, "Failed to append relation type argument.");
945 } 945 }
946 946
diff --git a/src/burn/engine/burnextension.cpp b/src/burn/engine/burnextension.cpp
index 536dbcc9..50657f32 100644
--- a/src/burn/engine/burnextension.cpp
+++ b/src/burn/engine/burnextension.cpp
@@ -214,7 +214,7 @@ EXTERN_C HRESULT BurnExtensionFindById(
214 { 214 {
215 pExtension = &pBurnExtensions->rgExtensions[i]; 215 pExtension = &pBurnExtensions->rgExtensions[i];
216 216
217 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pExtension->sczId, -1, wzId, -1)) 217 if (CSTR_EQUAL == ::CompareStringOrdinal(pExtension->sczId, -1, wzId, -1, FALSE))
218 { 218 {
219 *ppExtension = pExtension; 219 *ppExtension = pExtension;
220 ExitFunction1(hr = S_OK); 220 ExitFunction1(hr = S_OK);
diff --git a/src/burn/engine/burnpipe.cpp b/src/burn/engine/burnpipe.cpp
index 25d602b1..102ccb4f 100644
--- a/src/burn/engine/burnpipe.cpp
+++ b/src/burn/engine/burnpipe.cpp
@@ -446,11 +446,11 @@ extern "C" HRESULT BurnPipeChildConnect(
446 446
447 // Try to connect to the parent. 447 // Try to connect to the parent.
448 hr = PipeClientConnect(pConnection->sczName, &pConnection->hPipe); 448 hr = PipeClientConnect(pConnection->sczName, &pConnection->hPipe);
449 ExitOnRootFailure(hr, "Failed to open parent pipe: %ls", sczPipeName) 449 ExitOnRootFailure(hr, "Failed to open parent pipe: %ls", pConnection->sczName)
450 450
451 // Verify the parent and notify it that the child connected. 451 // Verify the parent and notify it that the child connected.
452 hr = ChildPipeConnected(pConnection->hPipe, pConnection->sczSecret, &pConnection->dwProcessId); 452 hr = ChildPipeConnected(pConnection->hPipe, pConnection->sczSecret, &pConnection->dwProcessId);
453 ExitOnFailure(hr, "Failed to verify parent pipe: %ls", sczPipeName); 453 ExitOnFailure(hr, "Failed to verify parent pipe: %ls", pConnection->sczName);
454 454
455 if (fCompanion) 455 if (fCompanion)
456 { 456 {
@@ -511,11 +511,11 @@ static HRESULT ChildPipeConnected(
511 hr = StrAlloc(&sczVerificationSecret, cbVerificationSecret / sizeof(WCHAR) + 1); 511 hr = StrAlloc(&sczVerificationSecret, cbVerificationSecret / sizeof(WCHAR) + 1);
512 ExitOnFailure(hr, "Failed to allocate buffer for verification secret."); 512 ExitOnFailure(hr, "Failed to allocate buffer for verification secret.");
513 513
514 FileReadHandle(hPipe, reinterpret_cast<LPBYTE>(sczVerificationSecret), cbVerificationSecret); 514 hr = FileReadHandle(hPipe, reinterpret_cast<LPBYTE>(sczVerificationSecret), cbVerificationSecret);
515 ExitOnFailure(hr, "Failed to read verification secret from parent pipe."); 515 ExitOnFailure(hr, "Failed to read verification secret from parent pipe.");
516 516
517 // Verify the secrets match. 517 // Verify the secrets match.
518 if (CSTR_EQUAL != ::CompareStringW(LOCALE_NEUTRAL, 0, sczVerificationSecret, -1, wzSecret, -1)) 518 if (CSTR_EQUAL != ::CompareStringOrdinal(sczVerificationSecret, -1, wzSecret, -1, FALSE))
519 { 519 {
520 hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); 520 hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
521 ExitOnRootFailure(hr, "Verification secret from parent does not match."); 521 ExitOnRootFailure(hr, "Verification secret from parent does not match.");
diff --git a/src/burn/engine/cabextract.cpp b/src/burn/engine/cabextract.cpp
index 5663c3f7..2140130d 100644
--- a/src/burn/engine/cabextract.cpp
+++ b/src/burn/engine/cabextract.cpp
@@ -833,9 +833,13 @@ static UINT FAR DIAMONDAPI CabWrite(
833 833
834 case BURN_CAB_OPERATION_STREAM_TO_BUFFER: 834 case BURN_CAB_OPERATION_STREAM_TO_BUFFER:
835 // copy to target buffer 835 // copy to target buffer
836 memcpy_s(pContext->Cabinet.pbTargetBuffer + pContext->Cabinet.iTargetBuffer, pContext->Cabinet.cbTargetBuffer - pContext->Cabinet.iTargetBuffer, pv, cb); 836 if (memcpy_s(pContext->Cabinet.pbTargetBuffer + pContext->Cabinet.iTargetBuffer, pContext->Cabinet.cbTargetBuffer - pContext->Cabinet.iTargetBuffer, pv, cb))
837 pContext->Cabinet.iTargetBuffer += cb; 837 {
838 hr = E_INSUFFICIENT_BUFFER;
839 ExitOnRootFailure(hr, "Failed to copy data to target buffer during cabinet extraction.");
840 }
838 841
842 pContext->Cabinet.iTargetBuffer += cb;
839 cbWrite = cb; 843 cbWrite = cb;
840 break; 844 break;
841 845
diff --git a/src/burn/engine/cache.cpp b/src/burn/engine/cache.cpp
index 16db4a81..c85a1be4 100644
--- a/src/burn/engine/cache.cpp
+++ b/src/burn/engine/cache.cpp
@@ -260,6 +260,9 @@ extern "C" HRESULT CacheInitializeSources(
260 hr = PathForCurrentProcess(&sczCurrentPath, NULL); 260 hr = PathForCurrentProcess(&sczCurrentPath, NULL);
261 ExitOnFailure(hr, "Failed to get current process path."); 261 ExitOnFailure(hr, "Failed to get current process path.");
262 262
263 hr = VariableSetString(pVariables, BURN_BUNDLE_SOURCE_PROCESS_PATH, sczCurrentPath, FALSE, FALSE);
264 ExitOnFailure(hr, "Failed to set %ls variable.", BURN_BUNDLE_SOURCE_PROCESS_PATH);
265
263 // Determine if we are running from the package cache or not. 266 // Determine if we are running from the package cache or not.
264 hr = CacheGetCompletedPath(pCache, pRegistration->fPerMachine, pRegistration->sczCode, &sczCompletedFolder); 267 hr = CacheGetCompletedPath(pCache, pRegistration->fPerMachine, pRegistration->sczCode, &sczCompletedFolder);
265 ExitOnFailure(hr, "Failed to get completed path for bundle."); 268 ExitOnFailure(hr, "Failed to get completed path for bundle.");
@@ -275,6 +278,9 @@ extern "C" HRESULT CacheInitializeSources(
275 hr = PathGetDirectory(sczCurrentPath, &pCache->sczSourceProcessFolder); 278 hr = PathGetDirectory(sczCurrentPath, &pCache->sczSourceProcessFolder);
276 ExitOnFailure(hr, "Failed to initialize cache source folder."); 279 ExitOnFailure(hr, "Failed to initialize cache source folder.");
277 280
281 hr = VariableSetString(pVariables, BURN_BUNDLE_SOURCE_PROCESS_FOLDER, pCache->sczSourceProcessFolder, FALSE, FALSE);
282 ExitOnFailure(hr, "Failed to set %ls variable.", BURN_BUNDLE_SOURCE_PROCESS_FOLDER);
283
278 // If we're not running from the cache, ensure the original source is set. 284 // If we're not running from the cache, ensure the original source is set.
279 if (!pCache->fRunningFromCache) 285 if (!pCache->fRunningFromCache)
280 { 286 {
@@ -357,6 +363,8 @@ extern "C" HRESULT CacheEnsureBaseWorkingFolder(
357 } 363 }
358 364
359 pWorkingFolderAcl = reinterpret_cast<LPSECURITY_ATTRIBUTES>(MemAlloc(sizeof(SECURITY_ATTRIBUTES), TRUE)); 365 pWorkingFolderAcl = reinterpret_cast<LPSECURITY_ATTRIBUTES>(MemAlloc(sizeof(SECURITY_ATTRIBUTES), TRUE));
366 ExitOnNull(pWorkingFolderAcl, hr, E_OUTOFMEMORY, "Failed to allocate security attributes.");
367
360 pWorkingFolderAcl->nLength = sizeof(SECURITY_ATTRIBUTES); 368 pWorkingFolderAcl->nLength = sizeof(SECURITY_ATTRIBUTES);
361 pWorkingFolderAcl->lpSecurityDescriptor = psd; 369 pWorkingFolderAcl->lpSecurityDescriptor = psd;
362 pWorkingFolderAcl->bInheritHandle = FALSE; 370 pWorkingFolderAcl->bInheritHandle = FALSE;
@@ -613,8 +621,8 @@ extern "C" HRESULT CacheGetLocalSourcePaths(
613 621
614 hr = GetLastUsedSourceFolder(pVariables, &sczLastSourceFolder); 622 hr = GetLastUsedSourceFolder(pVariables, &sczLastSourceFolder);
615 fPreferSourcePathLocation = !pCache->fRunningFromCache || FAILED(hr); 623 fPreferSourcePathLocation = !pCache->fRunningFromCache || FAILED(hr);
616 fTryLastFolder = SUCCEEDED(hr) && sczLastSourceFolder && *sczLastSourceFolder && CSTR_EQUAL != ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pCache->sczSourceProcessFolder, -1, sczLastSourceFolder, -1); 624 fTryLastFolder = SUCCEEDED(hr) && sczLastSourceFolder && *sczLastSourceFolder && CSTR_EQUAL != ::CompareStringOrdinal(pCache->sczSourceProcessFolder, -1, sczLastSourceFolder, -1, TRUE);
617 fTryRelativePath = CSTR_EQUAL != ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, wzSourcePath, -1, wzRelativePath, -1); 625 fTryRelativePath = CSTR_EQUAL != ::CompareStringOrdinal(wzSourcePath, -1, wzRelativePath, -1, TRUE);
618 fSourceIsAbsolute = PathIsRooted(wzSourcePath); 626 fSourceIsAbsolute = PathIsRooted(wzSourcePath);
619 627
620 // If the source path provided is a full path, try that first. 628 // If the source path provided is a full path, try that first.
@@ -791,7 +799,7 @@ extern "C" HRESULT CacheSetLastUsedSource(
791 799
792 // If the source path ends with the relative path then this source could be a new path. 800 // If the source path ends with the relative path then this source could be a new path.
793 iSourceRelativePath = cchSourcePath - cchRelativePath; 801 iSourceRelativePath = cchSourcePath - cchRelativePath;
794 if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, wzSourcePath + iSourceRelativePath, -1, wzRelativePath, -1)) 802 if (CSTR_EQUAL == ::CompareStringOrdinal(wzSourcePath + iSourceRelativePath, -1, wzRelativePath, -1, TRUE))
795 { 803 {
796 hr = StrAllocString(&sczSourceFolder, wzSourcePath, iSourceRelativePath); 804 hr = StrAllocString(&sczSourceFolder, wzSourcePath, iSourceRelativePath);
797 ExitOnFailure(hr, "Failed to trim source folder."); 805 ExitOnFailure(hr, "Failed to trim source folder.");
@@ -799,7 +807,7 @@ extern "C" HRESULT CacheSetLastUsedSource(
799 hr = VariableGetString(pVariables, BURN_BUNDLE_LAST_USED_SOURCE, &sczLastSourceFolder); 807 hr = VariableGetString(pVariables, BURN_BUNDLE_LAST_USED_SOURCE, &sczLastSourceFolder);
800 if (SUCCEEDED(hr)) 808 if (SUCCEEDED(hr))
801 { 809 {
802 nCompare = ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, sczSourceFolder, -1, sczLastSourceFolder, -1); 810 nCompare = ::CompareStringOrdinal(sczSourceFolder, -1, sczLastSourceFolder, -1, TRUE);
803 } 811 }
804 else if (E_NOTFOUND == hr) 812 else if (E_NOTFOUND == hr)
805 { 813 {
@@ -851,6 +859,7 @@ extern "C" HRESULT CacheSendProgressCallback(
851 case PROGRESS_STOP: 859 case PROGRESS_STOP:
852 hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT); 860 hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT);
853 ExitOnRootFailure(hr, "UX aborted on download progress."); 861 ExitOnRootFailure(hr, "UX aborted on download progress.");
862 break;
854 863
855 case PROGRESS_QUIET: // Not actually an error, just an indication to the caller to stop requesting progress. 864 case PROGRESS_QUIET: // Not actually an error, just an indication to the caller to stop requesting progress.
856 pCallback->pfnProgress = NULL; 865 pCallback->pfnProgress = NULL;
@@ -860,6 +869,7 @@ extern "C" HRESULT CacheSendProgressCallback(
860 default: 869 default:
861 hr = E_UNEXPECTED; 870 hr = E_UNEXPECTED;
862 ExitOnRootFailure(hr, "Invalid return code from progress routine."); 871 ExitOnRootFailure(hr, "Invalid return code from progress routine.");
872 break;
863 } 873 }
864 } 874 }
865 875
@@ -1025,7 +1035,7 @@ extern "C" HRESULT CacheCompleteBundle(
1025 ExitOnFailure(hr, "Failed to combine completed path with engine file name."); 1035 ExitOnFailure(hr, "Failed to combine completed path with engine file name.");
1026 1036
1027 // We can't just use wzExecutablePath because we needed to call CreateCompletedPath to ensure that the destination was secured. 1037 // We can't just use wzExecutablePath because we needed to call CreateCompletedPath to ensure that the destination was secured.
1028 Assert(CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, wzExecutablePath, -1, sczTargetPath, -1)); 1038 Assert(CSTR_EQUAL == ::CompareStringOrdinal(wzExecutablePath, -1, sczTargetPath, -1, TRUE));
1029 1039
1030 // If the bundle is running out of the package cache then we don't need to copy it there 1040 // If the bundle is running out of the package cache then we don't need to copy it there
1031 // (and don't want to since it'll be in use) so bail. 1041 // (and don't want to since it'll be in use) so bail.
@@ -1429,8 +1439,8 @@ extern "C" void CacheUninitialize(
1429 ReleaseStr(pCache->sczBaseWorkingFolder); 1439 ReleaseStr(pCache->sczBaseWorkingFolder);
1430 ReleaseStr(pCache->sczAcquisitionFolder); 1440 ReleaseStr(pCache->sczAcquisitionFolder);
1431 ReleaseStr(pCache->sczSourceProcessFolder); 1441 ReleaseStr(pCache->sczSourceProcessFolder);
1432 ReleaseStr(pCache->sczBundleEngineWorkingPath) 1442 ReleaseStr(pCache->sczBundleEngineWorkingPath);
1433 ReleaseFileHandle(pCache->hBundleEngineWorkingFile) 1443 ReleaseFileHandle(pCache->hBundleEngineWorkingFile);
1434 1444
1435 memset(pCache, 0, sizeof(BURN_CACHE)); 1445 memset(pCache, 0, sizeof(BURN_CACHE));
1436} 1446}
diff --git a/src/burn/engine/condition.cpp b/src/burn/engine/condition.cpp
index 8fa62f16..3719ce79 100644
--- a/src/burn/engine/condition.cpp
+++ b/src/burn/engine/condition.cpp
@@ -740,17 +740,17 @@ static HRESULT NextSymbol(
740 ::GetStringTypeW(CT_CTYPE1, &pContext->wzRead[n], 1, &charType); 740 ::GetStringTypeW(CT_CTYPE1, &pContext->wzRead[n], 1, &charType);
741 } while (C1_ALPHA & charType || C1_DIGIT & charType || L'_' == pContext->wzRead[n]); 741 } while (C1_ALPHA & charType || C1_DIGIT & charType || L'_' == pContext->wzRead[n]);
742 742
743 if (2 == n && CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pContext->wzRead, 2, L"OR", 2)) 743 if (2 == n && CSTR_EQUAL == ::CompareStringOrdinal(pContext->wzRead, 2, L"OR", 2, TRUE))
744 { 744 {
745 // OR 745 // OR
746 pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_OR; 746 pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_OR;
747 } 747 }
748 else if (3 == n && CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pContext->wzRead, 3, L"AND", 3)) 748 else if (3 == n && CSTR_EQUAL == ::CompareStringOrdinal(pContext->wzRead, 3, L"AND", 3, TRUE))
749 { 749 {
750 // AND 750 // AND
751 pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_AND; 751 pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_AND;
752 } 752 }
753 else if (3 == n && CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pContext->wzRead, 3, L"NOT", 3)) 753 else if (3 == n && CSTR_EQUAL == ::CompareStringOrdinal(pContext->wzRead, 3, L"NOT", 3, TRUE))
754 { 754 {
755 // NOT 755 // NOT
756 pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_NOT; 756 pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_NOT;
@@ -928,7 +928,7 @@ static HRESULT CompareStringValues(
928 ) 928 )
929{ 929{
930 HRESULT hr = S_OK; 930 HRESULT hr = S_OK;
931 DWORD dwCompareString = (comparison & INSENSITIVE) ? NORM_IGNORECASE : 0; 931 BOOL fIgnoreCase = (comparison & INSENSITIVE) ? TRUE : FALSE;
932 size_t cchLeftSize = 0; 932 size_t cchLeftSize = 0;
933 size_t cchRightSize = 0; 933 size_t cchRightSize = 0;
934 int cchLeft = 0; 934 int cchLeft = 0;
@@ -958,7 +958,7 @@ static HRESULT CompareStringValues(
958 case BURN_SYMBOL_TYPE_EQ_I: 958 case BURN_SYMBOL_TYPE_EQ_I:
959 case BURN_SYMBOL_TYPE_NE_I: 959 case BURN_SYMBOL_TYPE_NE_I:
960 { 960 {
961 int i = ::CompareStringW(LOCALE_INVARIANT, dwCompareString, wzLeftOperand, cchLeft, wzRightOperand, cchRight); 961 int i = ::CompareStringOrdinal(wzLeftOperand, cchLeft, wzRightOperand, cchRight, fIgnoreCase);
962 hr = CompareIntegerValues(comparison, i, CSTR_EQUAL, pfResult); 962 hr = CompareIntegerValues(comparison, i, CSTR_EQUAL, pfResult);
963 } 963 }
964 break; 964 break;
@@ -967,7 +967,7 @@ static HRESULT CompareStringValues(
967 // test if left string contains right string 967 // test if left string contains right string
968 for (int i = 0; (i + cchRight) <= cchLeft; ++i) 968 for (int i = 0; (i + cchRight) <= cchLeft; ++i)
969 { 969 {
970 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, dwCompareString, wzLeftOperand + i, cchRight, wzRightOperand, cchRight)) 970 if (CSTR_EQUAL == ::CompareStringOrdinal(wzLeftOperand + i, cchRight, wzRightOperand, cchRight, fIgnoreCase))
971 { 971 {
972 *pfResult = TRUE; 972 *pfResult = TRUE;
973 ExitFunction(); 973 ExitFunction();
@@ -978,12 +978,12 @@ static HRESULT CompareStringValues(
978 case BURN_SYMBOL_TYPE_HIEQ: 978 case BURN_SYMBOL_TYPE_HIEQ:
979 case BURN_SYMBOL_TYPE_HIEQ_I: 979 case BURN_SYMBOL_TYPE_HIEQ_I:
980 // test if left string starts with right string 980 // test if left string starts with right string
981 *pfResult = cchLeft >= cchRight && CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, dwCompareString, wzLeftOperand, cchRight, wzRightOperand, cchRight); 981 *pfResult = cchLeft >= cchRight && CSTR_EQUAL == ::CompareStringOrdinal(wzLeftOperand, cchRight, wzRightOperand, cchRight, fIgnoreCase);
982 break; 982 break;
983 case BURN_SYMBOL_TYPE_LOEQ: 983 case BURN_SYMBOL_TYPE_LOEQ:
984 case BURN_SYMBOL_TYPE_LOEQ_I: 984 case BURN_SYMBOL_TYPE_LOEQ_I:
985 // test if left string ends with right string 985 // test if left string ends with right string
986 *pfResult = cchLeft >= cchRight && CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, dwCompareString, wzLeftOperand + (cchLeft - cchRight), cchRight, wzRightOperand, cchRight); 986 *pfResult = cchLeft >= cchRight && CSTR_EQUAL == ::CompareStringOrdinal(wzLeftOperand + (cchLeft - cchRight), cchRight, wzRightOperand, cchRight, fIgnoreCase);
987 break; 987 break;
988 default: 988 default:
989 ExitFunction1(hr = E_INVALIDARG); 989 ExitFunction1(hr = E_INVALIDARG);
diff --git a/src/burn/engine/container.cpp b/src/burn/engine/container.cpp
index fad010cf..41ab0919 100644
--- a/src/burn/engine/container.cpp
+++ b/src/burn/engine/container.cpp
@@ -400,7 +400,7 @@ extern "C" HRESULT ContainerFindById(
400 { 400 {
401 pContainer = &pContainers->rgContainers[i]; 401 pContainer = &pContainers->rgContainers[i];
402 402
403 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pContainer->sczId, -1, wzId, -1)) 403 if (CSTR_EQUAL == ::CompareStringOrdinal(pContainer->sczId, -1, wzId, -1, FALSE))
404 { 404 {
405 *ppContainer = pContainer; 405 *ppContainer = pContainer;
406 ExitFunction1(hr = S_OK); 406 ExitFunction1(hr = S_OK);
diff --git a/src/burn/engine/core.cpp b/src/burn/engine/core.cpp
index b20f7f0c..2dfa4857 100644
--- a/src/burn/engine/core.cpp
+++ b/src/burn/engine/core.cpp
@@ -1215,8 +1215,8 @@ HRESULT CoreAppendLogToCommandLine(
1215 if (rgszArgs[i][0] == L'-' || rgszArgs[i][0] == L'/') 1215 if (rgszArgs[i][0] == L'-' || rgszArgs[i][0] == L'/')
1216 { 1216 {
1217 // Now looking for 'log' or 'l' 1217 // Now looking for 'log' or 'l'
1218 if ((CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &rgszArgs[i][1], -1, L"log", -1)) 1218 if ((CSTR_EQUAL == ::CompareStringOrdinal(&rgszArgs[i][1], -1, L"log", -1, TRUE))
1219 || (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &rgszArgs[i][1], -1, L"l", -1))) 1219 || (CSTR_EQUAL == ::CompareStringOrdinal(&rgszArgs[i][1], -1, L"l", -1, TRUE)))
1220 { 1220 {
1221 ExitFunction1(hr = S_FALSE); 1221 ExitFunction1(hr = S_FALSE);
1222 } 1222 }
@@ -1232,8 +1232,11 @@ HRESULT CoreAppendLogToCommandLine(
1232 hr = StrAllocConcat(psczCommandLine, szLogArgFormatted, 0); 1232 hr = StrAllocConcat(psczCommandLine, szLogArgFormatted, 0);
1233 ExitOnFailure(hr, "Failed concatenating '-log' to command line"); 1233 ExitOnFailure(hr, "Failed concatenating '-log' to command line");
1234 1234
1235 hr = StrAllocConcat(psczObfuscatedCommandLine, szLogArgFormatted, 0); 1235 if (psczObfuscatedCommandLine)
1236 ExitOnFailure(hr, "Failed concatenating '-log' to obfuscated command line"); 1236 {
1237 hr = StrAllocConcat(psczObfuscatedCommandLine, szLogArgFormatted, 0);
1238 ExitOnFailure(hr, "Failed concatenating '-log' to obfuscated command line");
1239 }
1237 1240
1238LExit: 1241LExit:
1239 if (rgszArgs) 1242 if (rgszArgs)
@@ -1360,13 +1363,13 @@ extern "C" HRESULT CoreParseCommandLine(
1360 1363
1361 if (argv[i][0] == L'-' || argv[i][0] == L'/') 1364 if (argv[i][0] == L'-' || argv[i][0] == L'/')
1362 { 1365 {
1363 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"l", -1) || 1366 if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, L"l", -1, TRUE) ||
1364 CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"log", -1) || 1367 CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, L"log", -1, TRUE) ||
1365 CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"xlog", -1)) 1368 CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, L"xlog", -1, TRUE))
1366 { 1369 {
1367 pInternalCommand->dwLoggingAttributes &= ~BURN_LOGGING_ATTRIBUTE_APPEND; 1370 pInternalCommand->dwLoggingAttributes &= ~BURN_LOGGING_ATTRIBUTE_APPEND;
1368 1371
1369 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], 1, L"x", 1)) 1372 if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], 1, L"x", 1, TRUE))
1370 { 1373 {
1371 pInternalCommand->dwLoggingAttributes |= BURN_LOGGING_ATTRIBUTE_VERBOSE | BURN_LOGGING_ATTRIBUTE_EXTRADEBUG; 1374 pInternalCommand->dwLoggingAttributes |= BURN_LOGGING_ATTRIBUTE_VERBOSE | BURN_LOGGING_ATTRIBUTE_EXTRADEBUG;
1372 } 1375 }
@@ -1382,24 +1385,24 @@ extern "C" HRESULT CoreParseCommandLine(
1382 hr = PathExpand(&pInternalCommand->sczLogFile, argv[i], PATH_EXPAND_FULLPATH); 1385 hr = PathExpand(&pInternalCommand->sczLogFile, argv[i], PATH_EXPAND_FULLPATH);
1383 ExitOnFailure(hr, "Failed to copy log file path."); 1386 ExitOnFailure(hr, "Failed to copy log file path.");
1384 } 1387 }
1385 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"?", -1) || 1388 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, L"?", -1, TRUE) ||
1386 CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"h", -1) || 1389 CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, L"h", -1, TRUE) ||
1387 CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"help", -1)) 1390 CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, L"help", -1, TRUE))
1388 { 1391 {
1389 pCommand->action = BOOTSTRAPPER_ACTION_HELP; 1392 pCommand->action = BOOTSTRAPPER_ACTION_HELP;
1390 } 1393 }
1391 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"q", -1) || 1394 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, L"q", -1, TRUE) ||
1392 CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"quiet", -1) || 1395 CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, L"quiet", -1, TRUE) ||
1393 CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"s", -1) || 1396 CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, L"s", -1, TRUE) ||
1394 CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"silent", -1)) 1397 CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, L"silent", -1, TRUE))
1395 { 1398 {
1396 pCommand->display = BOOTSTRAPPER_DISPLAY_NONE; 1399 pCommand->display = BOOTSTRAPPER_DISPLAY_NONE;
1397 } 1400 }
1398 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"passive", -1)) 1401 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, L"passive", -1, TRUE))
1399 { 1402 {
1400 pCommand->display = BOOTSTRAPPER_DISPLAY_PASSIVE; 1403 pCommand->display = BOOTSTRAPPER_DISPLAY_PASSIVE;
1401 } 1404 }
1402 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"layout", -1)) 1405 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, L"layout", -1, TRUE))
1403 { 1406 {
1404 if (BOOTSTRAPPER_ACTION_HELP != pCommand->action) 1407 if (BOOTSTRAPPER_ACTION_HELP != pCommand->action)
1405 { 1408 {
@@ -1415,47 +1418,47 @@ extern "C" HRESULT CoreParseCommandLine(
1415 ExitOnFailure(hr, "Failed to copy path for layout directory."); 1418 ExitOnFailure(hr, "Failed to copy path for layout directory.");
1416 } 1419 }
1417 } 1420 }
1418 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"unsafeuninstall", -1)) 1421 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, L"unsafeuninstall", -1, TRUE))
1419 { 1422 {
1420 if (BOOTSTRAPPER_ACTION_HELP != pCommand->action) 1423 if (BOOTSTRAPPER_ACTION_HELP != pCommand->action)
1421 { 1424 {
1422 pCommand->action = BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL; 1425 pCommand->action = BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL;
1423 } 1426 }
1424 } 1427 }
1425 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"uninstall", -1)) 1428 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, L"uninstall", -1, TRUE))
1426 { 1429 {
1427 if (BOOTSTRAPPER_ACTION_HELP != pCommand->action) 1430 if (BOOTSTRAPPER_ACTION_HELP != pCommand->action)
1428 { 1431 {
1429 pCommand->action = BOOTSTRAPPER_ACTION_UNINSTALL; 1432 pCommand->action = BOOTSTRAPPER_ACTION_UNINSTALL;
1430 } 1433 }
1431 } 1434 }
1432 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"repair", -1)) 1435 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, L"repair", -1, TRUE))
1433 { 1436 {
1434 if (BOOTSTRAPPER_ACTION_HELP != pCommand->action) 1437 if (BOOTSTRAPPER_ACTION_HELP != pCommand->action)
1435 { 1438 {
1436 pCommand->action = BOOTSTRAPPER_ACTION_REPAIR; 1439 pCommand->action = BOOTSTRAPPER_ACTION_REPAIR;
1437 } 1440 }
1438 } 1441 }
1439 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"modify", -1)) 1442 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, L"modify", -1, TRUE))
1440 { 1443 {
1441 if (BOOTSTRAPPER_ACTION_HELP != pCommand->action) 1444 if (BOOTSTRAPPER_ACTION_HELP != pCommand->action)
1442 { 1445 {
1443 pCommand->action = BOOTSTRAPPER_ACTION_MODIFY; 1446 pCommand->action = BOOTSTRAPPER_ACTION_MODIFY;
1444 } 1447 }
1445 } 1448 }
1446 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"package", -1) || 1449 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, L"package", -1, TRUE) ||
1447 CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"update", -1)) 1450 CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, L"update", -1, TRUE))
1448 { 1451 {
1449 if (BOOTSTRAPPER_ACTION_UNKNOWN == pCommand->action) 1452 if (BOOTSTRAPPER_ACTION_UNKNOWN == pCommand->action)
1450 { 1453 {
1451 pCommand->action = BOOTSTRAPPER_ACTION_INSTALL; 1454 pCommand->action = BOOTSTRAPPER_ACTION_INSTALL;
1452 } 1455 }
1453 } 1456 }
1454 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"noaupause", -1)) 1457 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, L"noaupause", -1, TRUE))
1455 { 1458 {
1456 pInternalCommand->automaticUpdates = BURN_AU_PAUSE_ACTION_NONE; 1459 pInternalCommand->automaticUpdates = BURN_AU_PAUSE_ACTION_NONE;
1457 } 1460 }
1458 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"keepaupaused", -1)) 1461 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, L"keepaupaused", -1, TRUE))
1459 { 1462 {
1460 // Switch /noaupause takes precedence. 1463 // Switch /noaupause takes precedence.
1461 if (BURN_AU_PAUSE_ACTION_NONE != pInternalCommand->automaticUpdates) 1464 if (BURN_AU_PAUSE_ACTION_NONE != pInternalCommand->automaticUpdates)
@@ -1463,11 +1466,11 @@ extern "C" HRESULT CoreParseCommandLine(
1463 pInternalCommand->automaticUpdates = BURN_AU_PAUSE_ACTION_IFELEVATED_NORESUME; 1466 pInternalCommand->automaticUpdates = BURN_AU_PAUSE_ACTION_IFELEVATED_NORESUME;
1464 } 1467 }
1465 } 1468 }
1466 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"disablesystemrestore", -1)) 1469 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, L"disablesystemrestore", -1, TRUE))
1467 { 1470 {
1468 pInternalCommand->fDisableSystemRestore = TRUE; 1471 pInternalCommand->fDisableSystemRestore = TRUE;
1469 } 1472 }
1470 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"originalsource", -1)) 1473 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, L"originalsource", -1, TRUE))
1471 { 1474 {
1472 if (i + 1 >= argc) 1475 if (i + 1 >= argc)
1473 { 1476 {
@@ -1479,7 +1482,7 @@ extern "C" HRESULT CoreParseCommandLine(
1479 hr = PathExpand(&pInternalCommand->sczOriginalSource, argv[i], PATH_EXPAND_FULLPATH); 1482 hr = PathExpand(&pInternalCommand->sczOriginalSource, argv[i], PATH_EXPAND_FULLPATH);
1480 ExitOnFailure(hr, "Failed to copy last used source."); 1483 ExitOnFailure(hr, "Failed to copy last used source.");
1481 } 1484 }
1482 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, BURN_COMMANDLINE_SWITCH_PARENT, -1)) 1485 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, BURN_COMMANDLINE_SWITCH_PARENT, -1, TRUE))
1483 { 1486 {
1484 if (i + 1 >= argc) 1487 if (i + 1 >= argc)
1485 { 1488 {
@@ -1492,12 +1495,12 @@ extern "C" HRESULT CoreParseCommandLine(
1492 hr = StrAllocString(&pInternalCommand->sczActiveParent, argv[i], 0); 1495 hr = StrAllocString(&pInternalCommand->sczActiveParent, argv[i], 0);
1493 ExitOnFailure(hr, "Failed to copy parent."); 1496 ExitOnFailure(hr, "Failed to copy parent.");
1494 } 1497 }
1495 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, BURN_COMMANDLINE_SWITCH_PARENT_NONE, -1)) 1498 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, BURN_COMMANDLINE_SWITCH_PARENT_NONE, -1, TRUE))
1496 { 1499 {
1497 hr = StrAllocString(&pInternalCommand->sczActiveParent, L"", 0); 1500 hr = StrAllocString(&pInternalCommand->sczActiveParent, L"", 0);
1498 ExitOnFailure(hr, "Failed to initialize parent to none."); 1501 ExitOnFailure(hr, "Failed to initialize parent to none.");
1499 } 1502 }
1500 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, BURN_COMMANDLINE_SWITCH_LOG_APPEND, -1)) 1503 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, BURN_COMMANDLINE_SWITCH_LOG_APPEND, -1, TRUE))
1501 { 1504 {
1502 if (i + 1 >= argc) 1505 if (i + 1 >= argc)
1503 { 1506 {
@@ -1512,7 +1515,7 @@ extern "C" HRESULT CoreParseCommandLine(
1512 1515
1513 pInternalCommand->dwLoggingAttributes |= BURN_LOGGING_ATTRIBUTE_APPEND; 1516 pInternalCommand->dwLoggingAttributes |= BURN_LOGGING_ATTRIBUTE_APPEND;
1514 } 1517 }
1515 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_LOG_MODE), BURN_COMMANDLINE_SWITCH_LOG_MODE, -1)) 1518 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_LOG_MODE), BURN_COMMANDLINE_SWITCH_LOG_MODE, -1, TRUE))
1516 { 1519 {
1517 // Get a pointer to the next character after the switch. 1520 // Get a pointer to the next character after the switch.
1518 LPCWSTR wzParam = &argv[i][2 + lstrlenW(BURN_COMMANDLINE_SWITCH_LOG_MODE)]; 1521 LPCWSTR wzParam = &argv[i][2 + lstrlenW(BURN_COMMANDLINE_SWITCH_LOG_MODE)];
@@ -1541,7 +1544,7 @@ extern "C" HRESULT CoreParseCommandLine(
1541 } 1544 }
1542 } 1545 }
1543 } 1546 }
1544 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, BURN_COMMANDLINE_SWITCH_ELEVATED, -1)) 1547 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, BURN_COMMANDLINE_SWITCH_ELEVATED, -1, TRUE))
1545 { 1548 {
1546 if (i + 3 >= argc) 1549 if (i + 3 >= argc)
1547 { 1550 {
@@ -1579,7 +1582,7 @@ extern "C" HRESULT CoreParseCommandLine(
1579 1582
1580 i += 2; 1583 i += 2;
1581 } 1584 }
1582 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_SYSTEM_COMPONENT), BURN_COMMANDLINE_SWITCH_SYSTEM_COMPONENT, lstrlenW(BURN_COMMANDLINE_SWITCH_SYSTEM_COMPONENT))) 1585 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_SYSTEM_COMPONENT), BURN_COMMANDLINE_SWITCH_SYSTEM_COMPONENT, lstrlenW(BURN_COMMANDLINE_SWITCH_SYSTEM_COMPONENT), TRUE))
1583 { 1586 {
1584 // Get a pointer to the next character after the switch. 1587 // Get a pointer to the next character after the switch.
1585 LPCWSTR wzParam = &argv[i][1 + lstrlenW(BURN_COMMANDLINE_SWITCH_SYSTEM_COMPONENT)]; 1588 LPCWSTR wzParam = &argv[i][1 + lstrlenW(BURN_COMMANDLINE_SWITCH_SYSTEM_COMPONENT)];
@@ -1602,7 +1605,7 @@ extern "C" HRESULT CoreParseCommandLine(
1602 pInternalCommand->fArpSystemComponent = TRUE; 1605 pInternalCommand->fArpSystemComponent = TRUE;
1603 } 1606 }
1604 } 1607 }
1605 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, BURN_COMMANDLINE_SWITCH_EMBEDDED, -1)) 1608 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, BURN_COMMANDLINE_SWITCH_EMBEDDED, -1, TRUE))
1606 { 1609 {
1607 if (i + 3 >= argc) 1610 if (i + 3 >= argc)
1608 { 1611 {
@@ -1633,59 +1636,59 @@ extern "C" HRESULT CoreParseCommandLine(
1633 1636
1634 i += 2; 1637 i += 2;
1635 } 1638 }
1636 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, BURN_COMMANDLINE_SWITCH_RELATED_DETECT, -1)) 1639 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, BURN_COMMANDLINE_SWITCH_RELATED_DETECT, -1, TRUE))
1637 { 1640 {
1638 pCommand->relationType = BOOTSTRAPPER_RELATION_DETECT; 1641 pCommand->relationType = BOOTSTRAPPER_RELATION_DETECT;
1639 1642
1640 LogId(REPORT_STANDARD, MSG_BURN_RUN_BY_RELATED_BUNDLE, LoggingRelationTypeToString(pCommand->relationType)); 1643 LogId(REPORT_STANDARD, MSG_BURN_RUN_BY_RELATED_BUNDLE, LoggingRelationTypeToString(pCommand->relationType));
1641 } 1644 }
1642 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, BURN_COMMANDLINE_SWITCH_RELATED_UPGRADE, -1)) 1645 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, BURN_COMMANDLINE_SWITCH_RELATED_UPGRADE, -1, TRUE))
1643 { 1646 {
1644 pCommand->relationType = BOOTSTRAPPER_RELATION_UPGRADE; 1647 pCommand->relationType = BOOTSTRAPPER_RELATION_UPGRADE;
1645 1648
1646 LogId(REPORT_STANDARD, MSG_BURN_RUN_BY_RELATED_BUNDLE, LoggingRelationTypeToString(pCommand->relationType)); 1649 LogId(REPORT_STANDARD, MSG_BURN_RUN_BY_RELATED_BUNDLE, LoggingRelationTypeToString(pCommand->relationType));
1647 } 1650 }
1648 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, BURN_COMMANDLINE_SWITCH_RELATED_ADDON, -1)) 1651 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, BURN_COMMANDLINE_SWITCH_RELATED_ADDON, -1, TRUE))
1649 { 1652 {
1650 pCommand->relationType = BOOTSTRAPPER_RELATION_ADDON; 1653 pCommand->relationType = BOOTSTRAPPER_RELATION_ADDON;
1651 1654
1652 LogId(REPORT_STANDARD, MSG_BURN_RUN_BY_RELATED_BUNDLE, LoggingRelationTypeToString(pCommand->relationType)); 1655 LogId(REPORT_STANDARD, MSG_BURN_RUN_BY_RELATED_BUNDLE, LoggingRelationTypeToString(pCommand->relationType));
1653 } 1656 }
1654 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, BURN_COMMANDLINE_SWITCH_RELATED_DEPENDENT_ADDON, -1)) 1657 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, BURN_COMMANDLINE_SWITCH_RELATED_DEPENDENT_ADDON, -1, TRUE))
1655 { 1658 {
1656 pCommand->relationType = BOOTSTRAPPER_RELATION_DEPENDENT_ADDON; 1659 pCommand->relationType = BOOTSTRAPPER_RELATION_DEPENDENT_ADDON;
1657 1660
1658 LogId(REPORT_STANDARD, MSG_BURN_RUN_BY_RELATED_BUNDLE, LoggingRelationTypeToString(pCommand->relationType)); 1661 LogId(REPORT_STANDARD, MSG_BURN_RUN_BY_RELATED_BUNDLE, LoggingRelationTypeToString(pCommand->relationType));
1659 } 1662 }
1660 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, BURN_COMMANDLINE_SWITCH_RELATED_PATCH, -1)) 1663 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, BURN_COMMANDLINE_SWITCH_RELATED_PATCH, -1, TRUE))
1661 { 1664 {
1662 pCommand->relationType = BOOTSTRAPPER_RELATION_PATCH; 1665 pCommand->relationType = BOOTSTRAPPER_RELATION_PATCH;
1663 1666
1664 LogId(REPORT_STANDARD, MSG_BURN_RUN_BY_RELATED_BUNDLE, LoggingRelationTypeToString(pCommand->relationType)); 1667 LogId(REPORT_STANDARD, MSG_BURN_RUN_BY_RELATED_BUNDLE, LoggingRelationTypeToString(pCommand->relationType));
1665 } 1668 }
1666 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, BURN_COMMANDLINE_SWITCH_RELATED_DEPENDENT_PATCH, -1)) 1669 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, BURN_COMMANDLINE_SWITCH_RELATED_DEPENDENT_PATCH, -1, TRUE))
1667 { 1670 {
1668 pCommand->relationType = BOOTSTRAPPER_RELATION_DEPENDENT_PATCH; 1671 pCommand->relationType = BOOTSTRAPPER_RELATION_DEPENDENT_PATCH;
1669 1672
1670 LogId(REPORT_STANDARD, MSG_BURN_RUN_BY_RELATED_BUNDLE, LoggingRelationTypeToString(pCommand->relationType)); 1673 LogId(REPORT_STANDARD, MSG_BURN_RUN_BY_RELATED_BUNDLE, LoggingRelationTypeToString(pCommand->relationType));
1671 } 1674 }
1672 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, BURN_COMMANDLINE_SWITCH_RELATED_UPDATE, -1)) 1675 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, BURN_COMMANDLINE_SWITCH_RELATED_UPDATE, -1, TRUE))
1673 { 1676 {
1674 pCommand->relationType = BOOTSTRAPPER_RELATION_UPDATE; 1677 pCommand->relationType = BOOTSTRAPPER_RELATION_UPDATE;
1675 1678
1676 LogId(REPORT_STANDARD, MSG_BURN_RUN_BY_RELATED_BUNDLE, LoggingRelationTypeToString(pCommand->relationType)); 1679 LogId(REPORT_STANDARD, MSG_BURN_RUN_BY_RELATED_BUNDLE, LoggingRelationTypeToString(pCommand->relationType));
1677 } 1680 }
1678 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, BURN_COMMANDLINE_SWITCH_RELATED_CHAIN_PACKAGE, -1)) 1681 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, BURN_COMMANDLINE_SWITCH_RELATED_CHAIN_PACKAGE, -1, TRUE))
1679 { 1682 {
1680 pCommand->relationType = BOOTSTRAPPER_RELATION_CHAIN_PACKAGE; 1683 pCommand->relationType = BOOTSTRAPPER_RELATION_CHAIN_PACKAGE;
1681 1684
1682 LogId(REPORT_STANDARD, MSG_BURN_RUN_BY_RELATED_BUNDLE, LoggingRelationTypeToString(pCommand->relationType)); 1685 LogId(REPORT_STANDARD, MSG_BURN_RUN_BY_RELATED_BUNDLE, LoggingRelationTypeToString(pCommand->relationType));
1683 } 1686 }
1684 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, BURN_COMMANDLINE_SWITCH_PASSTHROUGH, -1)) 1687 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, BURN_COMMANDLINE_SWITCH_PASSTHROUGH, -1, TRUE))
1685 { 1688 {
1686 pCommand->fPassthrough = TRUE; 1689 pCommand->fPassthrough = TRUE;
1687 } 1690 }
1688 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, BURN_COMMANDLINE_SWITCH_RUNONCE, -1)) 1691 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, BURN_COMMANDLINE_SWITCH_RUNONCE, -1, TRUE))
1689 { 1692 {
1690 switch (pInternalCommand->mode) 1693 switch (pInternalCommand->mode)
1691 { 1694 {
@@ -1698,7 +1701,7 @@ extern "C" HRESULT CoreParseCommandLine(
1698 TraceLog(E_INVALIDARG, "Multiple mode command-line switches were provided."); 1701 TraceLog(E_INVALIDARG, "Multiple mode command-line switches were provided.");
1699 } 1702 }
1700 } 1703 }
1701 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_IGNOREDEPENDENCIES), BURN_COMMANDLINE_SWITCH_IGNOREDEPENDENCIES, lstrlenW(BURN_COMMANDLINE_SWITCH_IGNOREDEPENDENCIES))) 1704 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_IGNOREDEPENDENCIES), BURN_COMMANDLINE_SWITCH_IGNOREDEPENDENCIES, lstrlenW(BURN_COMMANDLINE_SWITCH_IGNOREDEPENDENCIES), TRUE))
1702 { 1705 {
1703 // Get a pointer to the next character after the switch. 1706 // Get a pointer to the next character after the switch.
1704 LPCWSTR wzParam = &argv[i][1 + lstrlenW(BURN_COMMANDLINE_SWITCH_IGNOREDEPENDENCIES)]; 1707 LPCWSTR wzParam = &argv[i][1 + lstrlenW(BURN_COMMANDLINE_SWITCH_IGNOREDEPENDENCIES)];
@@ -1713,7 +1716,7 @@ extern "C" HRESULT CoreParseCommandLine(
1713 ExitOnFailure(hr, "Failed to allocate the list of dependencies to ignore."); 1716 ExitOnFailure(hr, "Failed to allocate the list of dependencies to ignore.");
1714 } 1717 }
1715 } 1718 }
1716 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_ANCESTORS), BURN_COMMANDLINE_SWITCH_ANCESTORS, lstrlenW(BURN_COMMANDLINE_SWITCH_ANCESTORS))) 1719 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_ANCESTORS), BURN_COMMANDLINE_SWITCH_ANCESTORS, lstrlenW(BURN_COMMANDLINE_SWITCH_ANCESTORS), TRUE))
1717 { 1720 {
1718 // Get a pointer to the next character after the switch. 1721 // Get a pointer to the next character after the switch.
1719 LPCWSTR wzParam = &argv[i][1 + lstrlenW(BURN_COMMANDLINE_SWITCH_ANCESTORS)]; 1722 LPCWSTR wzParam = &argv[i][1 + lstrlenW(BURN_COMMANDLINE_SWITCH_ANCESTORS)];
@@ -1728,7 +1731,7 @@ extern "C" HRESULT CoreParseCommandLine(
1728 ExitOnFailure(hr, "Failed to allocate the list of ancestors."); 1731 ExitOnFailure(hr, "Failed to allocate the list of ancestors.");
1729 } 1732 }
1730 } 1733 }
1731 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_WORKING_DIRECTORY), BURN_COMMANDLINE_SWITCH_WORKING_DIRECTORY, lstrlenW(BURN_COMMANDLINE_SWITCH_WORKING_DIRECTORY))) 1734 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_WORKING_DIRECTORY), BURN_COMMANDLINE_SWITCH_WORKING_DIRECTORY, lstrlenW(BURN_COMMANDLINE_SWITCH_WORKING_DIRECTORY), TRUE))
1732 { 1735 {
1733 // Get a pointer to the next character after the switch. 1736 // Get a pointer to the next character after the switch.
1734 LPCWSTR wzParam = &argv[i][1 + lstrlenW(BURN_COMMANDLINE_SWITCH_WORKING_DIRECTORY)]; 1737 LPCWSTR wzParam = &argv[i][1 + lstrlenW(BURN_COMMANDLINE_SWITCH_WORKING_DIRECTORY)];
@@ -1743,7 +1746,7 @@ extern "C" HRESULT CoreParseCommandLine(
1743 ExitOnFailure(hr, "Failed to store the custom working directory."); 1746 ExitOnFailure(hr, "Failed to store the custom working directory.");
1744 } 1747 }
1745 } 1748 }
1746 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED), BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED, lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED))) 1749 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED), BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED, lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED), TRUE))
1747 { 1750 {
1748 LPCWSTR wzParam = &argv[i][2 + lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED)]; 1751 LPCWSTR wzParam = &argv[i][2 + lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED)];
1749 if (L'=' != wzParam[-1] || L'\0' == wzParam[0]) 1752 if (L'=' != wzParam[-1] || L'\0' == wzParam[0])
@@ -1765,7 +1768,7 @@ extern "C" HRESULT CoreParseCommandLine(
1765 } 1768 }
1766 } 1769 }
1767 } 1770 }
1768 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF), BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF, lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF))) 1771 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF), BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF, lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF), TRUE))
1769 { 1772 {
1770 LPCWSTR wzParam = &argv[i][2 + lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF)]; 1773 LPCWSTR wzParam = &argv[i][2 + lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF)];
1771 if (L'=' != wzParam[-1] || L'\0' == wzParam[0]) 1774 if (L'=' != wzParam[-1] || L'\0' == wzParam[0])
@@ -1787,7 +1790,7 @@ extern "C" HRESULT CoreParseCommandLine(
1787 } 1790 }
1788 } 1791 }
1789 } 1792 }
1790 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_SPLASH_SCREEN), BURN_COMMANDLINE_SWITCH_SPLASH_SCREEN, lstrlenW(BURN_COMMANDLINE_SWITCH_SPLASH_SCREEN))) 1793 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_SPLASH_SCREEN), BURN_COMMANDLINE_SWITCH_SPLASH_SCREEN, lstrlenW(BURN_COMMANDLINE_SWITCH_SPLASH_SCREEN), TRUE))
1791 { 1794 {
1792 LPCWSTR wzParam = &argv[i][2 + lstrlenW(BURN_COMMANDLINE_SWITCH_SPLASH_SCREEN)]; 1795 LPCWSTR wzParam = &argv[i][2 + lstrlenW(BURN_COMMANDLINE_SWITCH_SPLASH_SCREEN)];
1793 if (L'=' != wzParam[-1] || L'\0' == wzParam[0]) 1796 if (L'=' != wzParam[-1] || L'\0' == wzParam[0])
@@ -1809,7 +1812,7 @@ extern "C" HRESULT CoreParseCommandLine(
1809 } 1812 }
1810 } 1813 }
1811 } 1814 }
1812 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_PREFIX), BURN_COMMANDLINE_SWITCH_PREFIX, lstrlenW(BURN_COMMANDLINE_SWITCH_PREFIX))) 1815 else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_PREFIX), BURN_COMMANDLINE_SWITCH_PREFIX, lstrlenW(BURN_COMMANDLINE_SWITCH_PREFIX), TRUE))
1813 { 1816 {
1814 // Skip (but log) any other private burn switches we don't recognize, so that 1817 // Skip (but log) any other private burn switches we don't recognize, so that
1815 // adding future private variables doesn't break old bundles 1818 // adding future private variables doesn't break old bundles
diff --git a/src/burn/engine/core.h b/src/burn/engine/core.h
index c5d0a370..cf615e35 100644
--- a/src/burn/engine/core.h
+++ b/src/burn/engine/core.h
@@ -46,6 +46,8 @@ const LPCWSTR BURN_BUNDLE_FORCED_RESTART_PACKAGE = L"WixBundleForcedRestartPacka
46const LPCWSTR BURN_BUNDLE_INSTALLED = L"WixBundleInstalled"; 46const LPCWSTR BURN_BUNDLE_INSTALLED = L"WixBundleInstalled";
47const LPCWSTR BURN_BUNDLE_ELEVATED = L"WixBundleElevated"; 47const LPCWSTR BURN_BUNDLE_ELEVATED = L"WixBundleElevated";
48const LPCWSTR BURN_BUNDLE_PROVIDER_KEY = L"WixBundleProviderKey"; 48const LPCWSTR BURN_BUNDLE_PROVIDER_KEY = L"WixBundleProviderKey";
49const LPCWSTR BURN_BUNDLE_SOURCE_PROCESS_PATH = L"WixBundleSourceProcessPath";
50const LPCWSTR BURN_BUNDLE_SOURCE_PROCESS_FOLDER = L"WixBundleSourceProcessFolder";
49const LPCWSTR BURN_BUNDLE_TAG = L"WixBundleTag"; 51const LPCWSTR BURN_BUNDLE_TAG = L"WixBundleTag";
50const LPCWSTR BURN_BUNDLE_UILEVEL = L"WixBundleUILevel"; 52const LPCWSTR BURN_BUNDLE_UILEVEL = L"WixBundleUILevel";
51const LPCWSTR BURN_BUNDLE_VERSION = L"WixBundleVersion"; 53const LPCWSTR BURN_BUNDLE_VERSION = L"WixBundleVersion";
diff --git a/src/burn/engine/dependency.cpp b/src/burn/engine/dependency.cpp
index f398a070..94a8a1e4 100644
--- a/src/burn/engine/dependency.cpp
+++ b/src/burn/engine/dependency.cpp
@@ -263,7 +263,7 @@ extern "C" HRESULT DependencyDetectProviderKeyBundleCode(
263 hr = StrAllocString(&pRegistration->sczDetectedProviderKeyBundleCode, pRegistration->sczProviderKey, 0); 263 hr = StrAllocString(&pRegistration->sczDetectedProviderKeyBundleCode, pRegistration->sczProviderKey, 0);
264 ExitOnFailure(hr, "Failed to initialize provider key bundle code."); 264 ExitOnFailure(hr, "Failed to initialize provider key bundle code.");
265 } 265 }
266 else if (CSTR_EQUAL != ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pRegistration->sczCode, -1, pRegistration->sczDetectedProviderKeyBundleCode, -1)) 266 else if (CSTR_EQUAL != ::CompareStringOrdinal(pRegistration->sczCode, -1, pRegistration->sczDetectedProviderKeyBundleCode, -1, TRUE))
267 { 267 {
268 pRegistration->fDetectedForeignProviderKeyBundleCode = TRUE; 268 pRegistration->fDetectedForeignProviderKeyBundleCode = TRUE;
269 LogId(REPORT_STANDARD, MSG_DETECTED_FOREIGN_BUNDLE_PROVIDER_REGISTRATION, pRegistration->sczProviderKey, pRegistration->sczDetectedProviderKeyBundleCode); 269 LogId(REPORT_STANDARD, MSG_DETECTED_FOREIGN_BUNDLE_PROVIDER_REGISTRATION, pRegistration->sczProviderKey, pRegistration->sczDetectedProviderKeyBundleCode);
@@ -293,12 +293,12 @@ extern "C" HRESULT DependencyDetectBundle(
293 { 293 {
294 DEPENDENCY* pDependent = pRegistration->rgDependents + i; 294 DEPENDENCY* pDependent = pRegistration->rgDependents + i;
295 295
296 if (pDependencies->fActiveParent && CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pDependencies->wzActiveParent, -1, pDependent->sczKey, -1)) 296 if (pDependencies->fActiveParent && CSTR_EQUAL == ::CompareStringOrdinal(pDependencies->wzActiveParent, -1, pDependent->sczKey, -1, TRUE))
297 { 297 {
298 pRegistration->fParentRegisteredAsDependent = TRUE; 298 pRegistration->fParentRegisteredAsDependent = TRUE;
299 } 299 }
300 300
301 if (pDependencies->fSelfDependent && CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pDependencies->wzSelfDependent, -1, pDependent->sczKey, -1)) 301 if (pDependencies->fSelfDependent && CSTR_EQUAL == ::CompareStringOrdinal(pDependencies->wzSelfDependent, -1, pDependent->sczKey, -1, TRUE))
302 { 302 {
303 pRegistration->fSelfRegisteredAsDependent = TRUE; 303 pRegistration->fSelfRegisteredAsDependent = TRUE;
304 } 304 }
@@ -419,6 +419,7 @@ extern "C" HRESULT DependencyPlanPackageBegin(
419 STRINGDICT_HANDLE sdIgnoredDependents = NULL; 419 STRINGDICT_HANDLE sdIgnoredDependents = NULL;
420 BURN_DEPENDENCY_ACTION dependencyExecuteAction = BURN_DEPENDENCY_ACTION_NONE; 420 BURN_DEPENDENCY_ACTION dependencyExecuteAction = BURN_DEPENDENCY_ACTION_NONE;
421 BURN_DEPENDENCY_ACTION dependencyRollbackAction = BURN_DEPENDENCY_ACTION_NONE; 421 BURN_DEPENDENCY_ACTION dependencyRollbackAction = BURN_DEPENDENCY_ACTION_NONE;
422 BOOL fDependenciesForcedAbsent = FALSE;
422 BOOL fDependentBlocksUninstall = FALSE; 423 BOOL fDependentBlocksUninstall = FALSE;
423 BOOL fAttemptingUninstall = BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pPackage->execute || pPackage->compatiblePackage.fRemove; 424 BOOL fAttemptingUninstall = BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pPackage->execute || pPackage->compatiblePackage.fRemove;
424 425
@@ -467,7 +468,16 @@ extern "C" HRESULT DependencyPlanPackageBegin(
467 { 468 {
468 hr = S_OK; 469 hr = S_OK;
469 470
470 if (!fDependentBlocksUninstall) 471 if (BOOTSTRAPPER_REQUEST_STATE_FORCE_ABSENT == pPackage->requested)
472 {
473 if (!fDependenciesForcedAbsent)
474 {
475 fDependenciesForcedAbsent = TRUE;
476
477 LogId(REPORT_STANDARD, MSG_DEPENDENCY_PACKAGE_DEPENDENTS_OVERRIDDEN, pPackage->sczId);
478 }
479 }
480 else if (!fDependentBlocksUninstall)
471 { 481 {
472 fDependentBlocksUninstall = TRUE; 482 fDependentBlocksUninstall = TRUE;
473 483
@@ -591,8 +601,8 @@ extern "C" HRESULT DependencyPlanPackageBegin(
591 pProvider->dependentExecute = BURN_DEPENDENCY_ACTION_NONE; 601 pProvider->dependentExecute = BURN_DEPENDENCY_ACTION_NONE;
592 } 602 }
593 603
594 if (BURN_DEPENDENCY_ACTION_UNREGISTER == pProvider->dependentRollback && pProvider->fBundleRegisteredAsDependent || 604 if ((BURN_DEPENDENCY_ACTION_UNREGISTER == pProvider->dependentRollback && pProvider->fBundleRegisteredAsDependent) ||
595 BURN_DEPENDENCY_ACTION_REGISTER == pProvider->dependentRollback && !pProvider->fBundleRegisteredAsDependent) 605 (BURN_DEPENDENCY_ACTION_REGISTER == pProvider->dependentRollback && !pProvider->fBundleRegisteredAsDependent))
596 { 606 {
597 pProvider->dependentRollback = BURN_DEPENDENCY_ACTION_NONE; 607 pProvider->dependentRollback = BURN_DEPENDENCY_ACTION_NONE;
598 } 608 }
@@ -905,7 +915,7 @@ extern "C" HRESULT DependencyDetectCompatibleEntry(
905 continue; 915 continue;
906 } 916 }
907 } 917 }
908 else if (sczId && CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, wzPackageProviderId, -1, sczId, -1)) 918 else if (sczId && CSTR_EQUAL == ::CompareStringOrdinal(wzPackageProviderId, -1, sczId, -1, TRUE))
909 { 919 {
910 continue; 920 continue;
911 } 921 }
@@ -969,7 +979,7 @@ static HRESULT DetectPackageDependents(
969 { 979 {
970 DEPENDENCY* pDependent = pProvider->rgDependents + iDependent; 980 DEPENDENCY* pDependent = pProvider->rgDependents + iDependent;
971 981
972 if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pRegistration->sczCode, -1, pDependent->sczKey, -1)) 982 if (CSTR_EQUAL == ::CompareStringOrdinal(pRegistration->sczCode, -1, pDependent->sczKey, -1, TRUE))
973 { 983 {
974 pProvider->fBundleRegisteredAsDependent = TRUE; 984 pProvider->fBundleRegisteredAsDependent = TRUE;
975 fBundleRegisteredAsDependent = TRUE; 985 fBundleRegisteredAsDependent = TRUE;
@@ -1043,7 +1053,7 @@ static HRESULT SplitIgnoreDependencies(
1043 hr = DictAddKey(sdIgnoreDependencies, wzToken); 1053 hr = DictAddKey(sdIgnoreDependencies, wzToken);
1044 ExitOnFailure(hr, "Failed to add \"%ls\" to the string dictionary.", wzToken); 1054 ExitOnFailure(hr, "Failed to add \"%ls\" to the string dictionary.", wzToken);
1045 1055
1046 if (!*pfIgnoreAll && CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, L"ALL", -1, wzToken, -1)) 1056 if (!*pfIgnoreAll && CSTR_EQUAL == ::CompareStringOrdinal(L"ALL", -1, wzToken, -1, TRUE))
1047 { 1057 {
1048 *pfIgnoreAll = TRUE; 1058 *pfIgnoreAll = TRUE;
1049 } 1059 }
diff --git a/src/burn/engine/detect.cpp b/src/burn/engine/detect.cpp
index 08f6b57c..c19d382c 100644
--- a/src/burn/engine/detect.cpp
+++ b/src/burn/engine/detect.cpp
@@ -130,7 +130,7 @@ extern "C" HRESULT DetectForwardCompatibleBundles(
130 BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgRelatedBundles + iRelatedBundle; 130 BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgRelatedBundles + iRelatedBundle;
131 131
132 if (BOOTSTRAPPER_RELATION_UPGRADE == pRelatedBundle->detectRelationType && 132 if (BOOTSTRAPPER_RELATION_UPGRADE == pRelatedBundle->detectRelationType &&
133 CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pRegistration->sczDetectedProviderKeyBundleCode, -1, pRelatedBundle->package.sczId, -1)) 133 CSTR_EQUAL == ::CompareStringOrdinal(pRegistration->sczDetectedProviderKeyBundleCode, -1, pRelatedBundle->package.sczId, -1, TRUE))
134 { 134 {
135 hr = VerCompareParsedVersions(pRegistration->pVersion, pRelatedBundle->pVersion, &nCompareResult); 135 hr = VerCompareParsedVersions(pRegistration->pVersion, pRelatedBundle->pVersion, &nCompareResult);
136 ExitOnFailure(hr, "Failed to compare bundle version '%ls' to related bundle version '%ls'", pRegistration->pVersion->sczVersion, pRelatedBundle->pVersion->sczVersion); 136 ExitOnFailure(hr, "Failed to compare bundle version '%ls' to related bundle version '%ls'", pRegistration->pVersion->sczVersion, pRelatedBundle->pVersion->sczVersion);
diff --git a/src/burn/engine/elevation.cpp b/src/burn/engine/elevation.cpp
index 90e9db01..ef87841f 100644
--- a/src/burn/engine/elevation.cpp
+++ b/src/burn/engine/elevation.cpp
@@ -1452,9 +1452,9 @@ extern "C" HRESULT ElevationExecutePackageDependencyAction(
1452 ExitOnFailure(hr, "Failed to write bundle dependency key to message buffer."); 1452 ExitOnFailure(hr, "Failed to write bundle dependency key to message buffer.");
1453 1453
1454 // Dependent actions. 1454 // Dependent actions.
1455 for (DWORD i = 0; i < pExecuteAction->packageProvider.pPackage->cDependencyProviders; ++i) 1455 for (DWORD i = 0; i < pExecuteAction->packageDependency.pPackage->cDependencyProviders; ++i)
1456 { 1456 {
1457 BURN_DEPENDENCY_PROVIDER* pProvider = pExecuteAction->packageProvider.pPackage->rgDependencyProviders + i; 1457 BURN_DEPENDENCY_PROVIDER* pProvider = pExecuteAction->packageDependency.pPackage->rgDependencyProviders + i;
1458 BURN_DEPENDENCY_ACTION* pAction = fRollback ? &pProvider->dependentRollback : &pProvider->dependentExecute; 1458 BURN_DEPENDENCY_ACTION* pAction = fRollback ? &pProvider->dependentRollback : &pProvider->dependentExecute;
1459 hr = BuffWriteNumber(&pbData, &cbData, (DWORD)*pAction); 1459 hr = BuffWriteNumber(&pbData, &cbData, (DWORD)*pAction);
1460 ExitOnFailure(hr, "Failed to write dependent action to message buffer."); 1460 ExitOnFailure(hr, "Failed to write dependent action to message buffer.");
@@ -2824,7 +2824,7 @@ LExit:
2824 // TODO: do the right thing here. 2824 // TODO: do the right thing here.
2825 //DependencyUninitializeRegistrationAction(&action); 2825 //DependencyUninitializeRegistrationAction(&action);
2826 ReleaseStr(action.sczDependentProviderKey); 2826 ReleaseStr(action.sczDependentProviderKey);
2827 ReleaseStr(action.sczBundleCode) 2827 ReleaseStr(action.sczBundleCode);
2828 2828
2829 return hr; 2829 return hr;
2830} 2830}
@@ -3380,7 +3380,7 @@ static HRESULT OnUninstallMsiCompatiblePackage(
3380 } 3380 }
3381 3381
3382 if (!sczCompatiblePackageId || !*sczCompatiblePackageId || 3382 if (!sczCompatiblePackageId || !*sczCompatiblePackageId ||
3383 CSTR_EQUAL != ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pCompatiblePackage->compatibleEntry.sczId, -1, sczCompatiblePackageId, -1)) 3383 CSTR_EQUAL != ::CompareStringOrdinal(pCompatiblePackage->compatibleEntry.sczId, -1, sczCompatiblePackageId, -1, TRUE))
3384 { 3384 {
3385 ExitWithRootFailure(hr, E_INVALIDARG, "Package '%ls' has no compatible package with id: %ls", sczPackageId, sczCompatiblePackageId); 3385 ExitWithRootFailure(hr, E_INVALIDARG, "Package '%ls' has no compatible package with id: %ls", sczPackageId, sczCompatiblePackageId);
3386 } 3386 }
@@ -3486,9 +3486,9 @@ static HRESULT OnExecutePackageDependencyAction(
3486 ExitOnFailure(hr, "Failed to read bundle dependency key from message buffer."); 3486 ExitOnFailure(hr, "Failed to read bundle dependency key from message buffer.");
3487 3487
3488 // Read dependent actions. 3488 // Read dependent actions.
3489 for (DWORD i = 0; i < executeAction.packageProvider.pPackage->cDependencyProviders; ++i) 3489 for (DWORD i = 0; i < executeAction.packageDependency.pPackage->cDependencyProviders; ++i)
3490 { 3490 {
3491 BURN_DEPENDENCY_PROVIDER* pProvider = executeAction.packageProvider.pPackage->rgDependencyProviders + i; 3491 BURN_DEPENDENCY_PROVIDER* pProvider = executeAction.packageDependency.pPackage->rgDependencyProviders + i;
3492 BURN_DEPENDENCY_ACTION* pAction = fRollback ? &pProvider->dependentRollback : &pProvider->dependentExecute; 3492 BURN_DEPENDENCY_ACTION* pAction = fRollback ? &pProvider->dependentRollback : &pProvider->dependentExecute;
3493 hr = BuffReadNumber(pbData, cbData, &iData, (DWORD*)pAction); 3493 hr = BuffReadNumber(pbData, cbData, &iData, (DWORD*)pAction);
3494 ExitOnFailure(hr, "Failed to read dependent action."); 3494 ExitOnFailure(hr, "Failed to read dependent action.");
@@ -3792,7 +3792,7 @@ static HRESULT OnCleanCompatiblePackage(
3792 } 3792 }
3793 3793
3794 if (!sczCompatiblePackageId || !*sczCompatiblePackageId || 3794 if (!sczCompatiblePackageId || !*sczCompatiblePackageId ||
3795 CSTR_EQUAL != ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pCompatiblePackage->compatibleEntry.sczId, -1, sczCompatiblePackageId, -1)) 3795 CSTR_EQUAL != ::CompareStringOrdinal(pCompatiblePackage->compatibleEntry.sczId, -1, sczCompatiblePackageId, -1, TRUE))
3796 { 3796 {
3797 ExitWithRootFailure(hr, E_INVALIDARG, "Package '%ls' has no compatible package with id: %ls", sczPackageId, sczCompatiblePackageId); 3797 ExitWithRootFailure(hr, E_INVALIDARG, "Package '%ls' has no compatible package with id: %ls", sczPackageId, sczCompatiblePackageId);
3798 } 3798 }
@@ -3876,7 +3876,7 @@ static HRESULT OnLaunchApprovedExe(
3876 hr = RegReadString(hKey, pApprovedExe->sczValueName, &pLaunchApprovedExe->sczExecutablePath); 3876 hr = RegReadString(hKey, pApprovedExe->sczValueName, &pLaunchApprovedExe->sczExecutablePath);
3877 ExitOnFailure(hr, "Failed to read the value for the approved exe path."); 3877 ExitOnFailure(hr, "Failed to read the value for the approved exe path.");
3878 3878
3879 hr = ApprovedExesVerifySecureLocation(pCache, pVariables, pLaunchApprovedExe->sczExecutablePath); 3879 hr = ApprovedExesVerifySecureLocation(pCache, pVariables, pLaunchApprovedExe->sczExecutablePath, 0, NULL);
3880 ExitOnFailure(hr, "Failed to verify the executable path is in a secure location: %ls", pLaunchApprovedExe->sczExecutablePath); 3880 ExitOnFailure(hr, "Failed to verify the executable path is in a secure location: %ls", pLaunchApprovedExe->sczExecutablePath);
3881 if (S_FALSE == hr) 3881 if (S_FALSE == hr)
3882 { 3882 {
diff --git a/src/burn/engine/engine.cpp b/src/burn/engine/engine.cpp
index c372772c..d432f732 100644
--- a/src/burn/engine/engine.cpp
+++ b/src/burn/engine/engine.cpp
@@ -379,7 +379,8 @@ static HRESULT InitializeEngineState(
379 BurnPipeConnectionInitialize(&pEngineState->embeddedConnection); 379 BurnPipeConnectionInitialize(&pEngineState->embeddedConnection);
380 380
381 // Retain whether bundle was initially run elevated. 381 // Retain whether bundle was initially run elevated.
382 ProcElevated(::GetCurrentProcess(), &pEngineState->internalCommand.fInitiallyElevated); 382 hr = ProcIsHighIntegrity(::GetCurrentProcess(), &pEngineState->internalCommand.fInitiallyElevated);
383 ExitOnFailure(hr, "Failed to determine if process is running elevated.");
383 384
384 // Parse command line. 385 // Parse command line.
385 hr = CoreParseCommandLine(&pEngineState->internalCommand, &pEngineState->command, &pEngineState->companionConnection, &pEngineState->embeddedConnection, &hSectionFile, &hSourceEngineFile); 386 hr = CoreParseCommandLine(&pEngineState->internalCommand, &pEngineState->command, &pEngineState->companionConnection, &pEngineState->embeddedConnection, &hSectionFile, &hSourceEngineFile);
diff --git a/src/burn/engine/engine.mc b/src/burn/engine/engine.mc
index c7a07385..776f7832 100644
--- a/src/burn/engine/engine.mc
+++ b/src/burn/engine/engine.mc
@@ -1282,3 +1282,9 @@ Language=English
1282Skipping MSI property '%1!ls!' because condition '%2!ls!' evaluates to %3!hs!. 1282Skipping MSI property '%1!ls!' because condition '%2!ls!' evaluates to %3!hs!.
1283. 1283.
1284 1284
1285MessageId=701
1286Severity=Warning
1287SymbolicName=MSG_DEPENDENCY_PACKAGE_DEPENDENTS_OVERRIDDEN
1288Language=English
1289BA requested to uninstall package: %1!ls!, despite dependents:
1290.
diff --git a/src/burn/engine/engine.vcxproj b/src/burn/engine/engine.vcxproj
index 249f8eef..98556ea6 100644
--- a/src/burn/engine/engine.vcxproj
+++ b/src/burn/engine/engine.vcxproj
@@ -1,7 +1,7 @@
1<?xml version="1.0" encoding="utf-8"?> 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. --> 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 3
4<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 4<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
5 <ItemGroup Label="ProjectConfigurations"> 5 <ItemGroup Label="ProjectConfigurations">
6 <ProjectConfiguration Include="Debug|Win32"> 6 <ProjectConfiguration Include="Debug|Win32">
7 <Configuration>Debug</Configuration> 7 <Configuration>Debug</Configuration>
diff --git a/src/burn/engine/exeengine.cpp b/src/burn/engine/exeengine.cpp
index 85168943..c001e563 100644
--- a/src/burn/engine/exeengine.cpp
+++ b/src/burn/engine/exeengine.cpp
@@ -25,15 +25,15 @@ extern "C" HRESULT ExeEngineParsePackageFromXml(
25 hr = XmlGetAttributeEx(pixnExePackage, L"DetectionType", &scz); 25 hr = XmlGetAttributeEx(pixnExePackage, L"DetectionType", &scz);
26 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @DetectionType."); 26 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @DetectionType.");
27 27
28 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"condition", -1)) 28 if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"condition", -1, FALSE))
29 { 29 {
30 pPackage->Exe.detectionType = BURN_EXE_DETECTION_TYPE_CONDITION; 30 pPackage->Exe.detectionType = BURN_EXE_DETECTION_TYPE_CONDITION;
31 } 31 }
32 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"arp", -1)) 32 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"arp", -1, FALSE))
33 { 33 {
34 pPackage->Exe.detectionType = BURN_EXE_DETECTION_TYPE_ARP; 34 pPackage->Exe.detectionType = BURN_EXE_DETECTION_TYPE_ARP;
35 } 35 }
36 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"none", -1)) 36 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"none", -1, FALSE))
37 { 37 {
38 pPackage->Exe.detectionType = BURN_EXE_DETECTION_TYPE_NONE; 38 pPackage->Exe.detectionType = BURN_EXE_DETECTION_TYPE_NONE;
39 } 39 }
@@ -114,15 +114,15 @@ extern "C" HRESULT ExeEngineParsePackageFromXml(
114 114
115 if (fFoundXml) 115 if (fFoundXml)
116 { 116 {
117 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"burn", -1)) 117 if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"burn", -1, FALSE))
118 { 118 {
119 pPackage->Exe.protocol = BURN_EXE_PROTOCOL_TYPE_BURN; 119 pPackage->Exe.protocol = BURN_EXE_PROTOCOL_TYPE_BURN;
120 } 120 }
121 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"netfx4", -1)) 121 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"netfx4", -1, FALSE))
122 { 122 {
123 pPackage->Exe.protocol = BURN_EXE_PROTOCOL_TYPE_NETFX4; 123 pPackage->Exe.protocol = BURN_EXE_PROTOCOL_TYPE_NETFX4;
124 } 124 }
125 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"none", -1)) 125 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"none", -1, FALSE))
126 { 126 {
127 pPackage->Exe.protocol = BURN_EXE_PROTOCOL_TYPE_NONE; 127 pPackage->Exe.protocol = BURN_EXE_PROTOCOL_TYPE_NONE;
128 } 128 }
@@ -449,7 +449,7 @@ extern "C" HRESULT ExeEngineExecutePackage(
449 449
450 if (BURN_EXE_DETECTION_TYPE_ARP == pPackage->Exe.detectionType && 450 if (BURN_EXE_DETECTION_TYPE_ARP == pPackage->Exe.detectionType &&
451 (BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pExecuteAction->exePackage.action || 451 (BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pExecuteAction->exePackage.action ||
452 BOOTSTRAPPER_ACTION_STATE_INSTALL == pExecuteAction->exePackage.action && fRollback)) 452 (BOOTSTRAPPER_ACTION_STATE_INSTALL == pExecuteAction->exePackage.action && fRollback)))
453 { 453 {
454 hr = DetectArpEntry(pPackage, &applyState, &sczArpUninstallString); 454 hr = DetectArpEntry(pPackage, &applyState, &sczArpUninstallString);
455 ExitOnFailure(hr, "Failed to query ArpEntry for %hs.", BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pExecuteAction->exePackage.action ? "uninstall" : "install"); 455 ExitOnFailure(hr, "Failed to query ArpEntry for %hs.", BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pExecuteAction->exePackage.action ? "uninstall" : "install");
@@ -489,29 +489,30 @@ extern "C" HRESULT ExeEngineExecutePackage(
489 } 489 }
490 else if (BURN_EXE_DETECTION_TYPE_ARP == pPackage->Exe.detectionType && BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pExecuteAction->exePackage.action) 490 else if (BURN_EXE_DETECTION_TYPE_ARP == pPackage->Exe.detectionType && BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pExecuteAction->exePackage.action)
491 { 491 {
492 ExitOnNull(sczArpUninstallString, hr, E_INVALIDARG, "%hs is null.", pPackage->Exe.fArpUseUninstallString ? "UninstallString" : "QuietUninstallString"); 492 LPCWSTR szRegName = pPackage->Exe.fArpUseUninstallString ? L"UninstallString" : L"QuietUninstallString";
493 ExitOnNull(sczArpUninstallString, hr, E_INVALIDARG, "%ls is null.", szRegName);
493 494
494 hr = AppParseCommandLine(sczArpUninstallString, &argcArp, &argvArp); 495 hr = AppParseCommandLine(sczArpUninstallString, &argcArp, &argvArp);
495 ExitOnFailure(hr, "Failed to parse QuietUninstallString: %ls.", sczArpUninstallString); 496 ExitOnFailure(hr, "Failed to parse %ls: %ls.", szRegName, sczArpUninstallString);
496 497
497 ExitOnNull(argcArp, hr, E_INVALIDARG, "QuietUninstallString must contain an executable path."); 498 ExitOnNull(argcArp, hr, E_INVALIDARG, "%ls must contain an executable path.", szRegName);
498 499
499 hr = StrAllocString(&sczExecutablePath, argvArp[0], 0); 500 hr = StrAllocString(&sczExecutablePath, argvArp[0], 0);
500 ExitOnFailure(hr, "Failed to copy executable path."); 501 ExitOnFailure(hr, "Failed to copy executable path.");
501 502
502 if (pPackage->fPerMachine) 503 if (pPackage->fPerMachine)
503 { 504 {
504 hr = ApprovedExesVerifySecureLocation(pCache, pVariables, sczExecutablePath); 505 hr = ApprovedExesVerifySecureLocation(pCache, pVariables, sczExecutablePath, argcArp - 1, (argcArp > 1) ? const_cast<LPCWSTR*>(argvArp + 1) : NULL);
505 ExitOnFailure(hr, "Failed to verify the QuietUninstallString executable path is in a secure location: %ls", sczExecutablePath); 506 ExitOnFailure(hr, "Failed to verify the %ls executable path is in a secure location: %ls", szRegName, sczExecutablePath);
506 if (S_FALSE == hr) 507 if (S_FALSE == hr)
507 { 508 {
508 LogStringLine(REPORT_STANDARD, "The QuietUninstallString executable path is not in a secure location: %ls", sczExecutablePath); 509 LogStringLine(REPORT_STANDARD, "The %ls executable path is not in a secure location: %ls", szRegName, sczExecutablePath);
509 ExitFunction1(hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)); 510 ExitFunction1(hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED));
510 } 511 }
511 } 512 }
512 513
513 hr = PathGetDirectory(sczExecutablePath, &sczCachedDirectory); 514 hr = PathGetDirectory(sczExecutablePath, &sczCachedDirectory);
514 ExitOnFailure(hr, "Failed to get parent directory for QuietUninstallString executable path: %ls", sczExecutablePath); 515 ExitOnFailure(hr, "Failed to get parent directory for %ls executable path: %ls", szRegName, sczExecutablePath);
515 } 516 }
516 else 517 else
517 { 518 {
@@ -587,13 +588,15 @@ extern "C" HRESULT ExeEngineExecutePackage(
587 } 588 }
588 589
589 // build base command 590 // build base command
590 hr = StrAllocFormatted(&sczBaseCommand, L"\"%ls\"", sczExecutablePath); 591 if (sczArpUninstallString && *sczArpUninstallString)
591 ExitOnFailure(hr, "Failed to allocate base command."); 592 {
592 593 hr = StrAllocString(&sczBaseCommand, sczArpUninstallString, 0);
593 for (int i = 1; i < argcArp; ++i) 594 ExitOnFailure(hr, "Failed to allocate base command.");
595 }
596 else
594 { 597 {
595 hr = AppAppendCommandLineArgument(&sczBaseCommand, argvArp[i]); 598 hr = StrAllocFormatted(&sczBaseCommand, L"\"%ls\"", sczExecutablePath);
596 ExitOnFailure(hr, "Failed to append argument from ARP."); 599 ExitOnFailure(hr, "Failed to allocate base command.");
597 } 600 }
598 601
599 if (pPackage->Exe.fBundle) 602 if (pPackage->Exe.fBundle)
diff --git a/src/burn/engine/logging.cpp b/src/burn/engine/logging.cpp
index 60c16c01..52123499 100644
--- a/src/burn/engine/logging.cpp
+++ b/src/burn/engine/logging.cpp
@@ -322,15 +322,17 @@ extern "C" HRESULT LoggingSetPackageVariable(
322 ExitFunction(); 322 ExitFunction();
323 } 323 }
324 324
325 // For burn packages we'll add logging even it it wasn't explictly specified 325 // For burn packages we'll add logging even it it wasn't explictly specified.
326 if (BURN_PACKAGE_TYPE_BUNDLE == pPackage->type || (BURN_PACKAGE_TYPE_EXE == pPackage->type && BURN_EXE_PROTOCOL_TYPE_BURN == pPackage->Exe.protocol)) 326 if (BURN_PACKAGE_TYPE_BUNDLE == pPackage->type || (BURN_PACKAGE_TYPE_EXE == pPackage->type && BURN_EXE_PROTOCOL_TYPE_BURN == pPackage->Exe.protocol))
327 { 327 {
328 if (!fRollback && (!pPackage->sczLogPathVariable || !*pPackage->sczLogPathVariable)) 328 if (!fRollback && (!pPackage->sczLogPathVariable || !*pPackage->sczLogPathVariable))
329 { 329 {
330 // Best effort, no need to fail if we can't set the logging path.
330 StrAllocFormatted(&pPackage->sczLogPathVariable, L"WixBundleLog_%ls", pPackage->sczId); 331 StrAllocFormatted(&pPackage->sczLogPathVariable, L"WixBundleLog_%ls", pPackage->sczId);
331 } 332 }
332 else if (fRollback && (!pPackage->sczRollbackLogPathVariable || !*pPackage->sczRollbackLogPathVariable)) 333 else if (fRollback && (!pPackage->sczRollbackLogPathVariable || !*pPackage->sczRollbackLogPathVariable))
333 { 334 {
335 // Best effort, no need to fail if we can't set the logging path.
334 StrAllocFormatted(&pPackage->sczRollbackLogPathVariable, L"WixBundleRollbackLog_%ls", pPackage->sczId); 336 StrAllocFormatted(&pPackage->sczRollbackLogPathVariable, L"WixBundleRollbackLog_%ls", pPackage->sczId);
335 } 337 }
336 } 338 }
@@ -1052,7 +1054,8 @@ static HRESULT GetNonSessionSpecificTempFolder(
1052 hr = ::StringCchLengthW(sczSessionId, STRSAFE_MAX_CCH, reinterpret_cast<size_t*>(&cchSessionId)); 1054 hr = ::StringCchLengthW(sczSessionId, STRSAFE_MAX_CCH, reinterpret_cast<size_t*>(&cchSessionId));
1053 ExitOnFailure(hr, "Failed to get length of session id string."); 1055 ExitOnFailure(hr, "Failed to get length of session id string.");
1054 1056
1055 if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, sczTempFolder + cchTempFolder - cchSessionId, static_cast<DWORD>(cchSessionId), sczSessionId, static_cast<DWORD>(cchSessionId))) 1057 if (cchTempFolder >= cchSessionId &&
1058 CSTR_EQUAL == ::CompareStringOrdinal(sczTempFolder + cchTempFolder - cchSessionId, static_cast<DWORD>(cchSessionId), sczSessionId, static_cast<DWORD>(cchSessionId), FALSE))
1056 { 1059 {
1057 cchTempFolder -= cchSessionId; 1060 cchTempFolder -= cchSessionId;
1058 } 1061 }
diff --git a/src/burn/engine/manifest.cpp b/src/burn/engine/manifest.cpp
index 266d1987..b2680387 100644
--- a/src/burn/engine/manifest.cpp
+++ b/src/burn/engine/manifest.cpp
@@ -177,7 +177,7 @@ static void ValidateHarvestingAttributes(
177 hr = XmlGetYesNoAttribute(pixeBundle, L"Win64", &fWin64); 177 hr = XmlGetYesNoAttribute(pixeBundle, L"Win64", &fWin64);
178 ExitOnRequiredXmlQueryFailure(hr, "Failed to get BurnManifest/@Win64 attribute."); 178 ExitOnRequiredXmlQueryFailure(hr, "Failed to get BurnManifest/@Win64 attribute.");
179 179
180 Assert(CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczEngineVersion, -1, wzVerMajorMinorBuild, -1)); 180 Assert(CSTR_EQUAL == ::CompareStringOrdinal(sczEngineVersion, -1, wzVerMajorMinorBuild, -1, FALSE));
181 181
182 Assert(BURN_PROTOCOL_VERSION == dwProtocolVersion); 182 Assert(BURN_PROTOCOL_VERSION == dwProtocolVersion);
183 183
diff --git a/src/burn/engine/msiengine.cpp b/src/burn/engine/msiengine.cpp
index d5268b17..a1379054 100644
--- a/src/burn/engine/msiengine.cpp
+++ b/src/burn/engine/msiengine.cpp
@@ -50,7 +50,9 @@ static void RegisterSourceDirectory(
50 __in BURN_PACKAGE* pPackage, 50 __in BURN_PACKAGE* pPackage,
51 __in_z LPCWSTR wzCacheDirectory 51 __in_z LPCWSTR wzCacheDirectory
52 ); 52 );
53 53static BOOL PackageHasAppliedPatch(
54 __in BURN_PACKAGE* pPackage
55 );
54 56
55// function definitions 57// function definitions
56 58
@@ -523,7 +525,7 @@ extern "C" HRESULT MsiEngineDetectPackage(
523 ExitOnFailure(hr, "Failed to enum related products."); 525 ExitOnFailure(hr, "Failed to enum related products.");
524 526
525 // If we found ourselves, skip because saying that a package is related to itself is nonsensical. 527 // If we found ourselves, skip because saying that a package is related to itself is nonsensical.
526 if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pPackage->Msi.sczProductCode, -1, wzProductCode, -1)) 528 if (CSTR_EQUAL == ::CompareStringOrdinal(pPackage->Msi.sczProductCode, -1, wzProductCode, -1, TRUE))
527 { 529 {
528 continue; 530 continue;
529 } 531 }
@@ -631,7 +633,7 @@ extern "C" HRESULT MsiEngineDetectPackage(
631 } 633 }
632 // It can't be a downgrade if the upgrade codes aren't the same. 634 // It can't be a downgrade if the upgrade codes aren't the same.
633 else if (BOOTSTRAPPER_PACKAGE_STATE_ABSENT == pPackage->currentState && 635 else if (BOOTSTRAPPER_PACKAGE_STATE_ABSENT == pPackage->currentState &&
634 pPackage->Msi.sczUpgradeCode && CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pPackage->Msi.sczUpgradeCode, -1, pRelatedMsi->sczUpgradeCode, -1)) 636 pPackage->Msi.sczUpgradeCode && CSTR_EQUAL == ::CompareStringOrdinal(pPackage->Msi.sczUpgradeCode, -1, pRelatedMsi->sczUpgradeCode, -1, TRUE))
635 { 637 {
636 relatedMsiOperation = BOOTSTRAPPER_RELATED_OPERATION_DOWNGRADE; 638 relatedMsiOperation = BOOTSTRAPPER_RELATED_OPERATION_DOWNGRADE;
637 pPackage->Msi.operation = BOOTSTRAPPER_RELATED_OPERATION_DOWNGRADE; 639 pPackage->Msi.operation = BOOTSTRAPPER_RELATED_OPERATION_DOWNGRADE;
@@ -904,7 +906,22 @@ extern "C" HRESULT MsiEnginePlanCalculatePackage(
904 else if ((BOOTSTRAPPER_REQUEST_STATE_ABSENT == pPackage->requested || BOOTSTRAPPER_REQUEST_STATE_CACHE == pPackage->requested) && 906 else if ((BOOTSTRAPPER_REQUEST_STATE_ABSENT == pPackage->requested || BOOTSTRAPPER_REQUEST_STATE_CACHE == pPackage->requested) &&
905 !pPackage->fPermanent) // removing a package that should be removed. 907 !pPackage->fPermanent) // removing a package that should be removed.
906 { 908 {
907 execute = BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED == pPackage->currentState ? BOOTSTRAPPER_ACTION_STATE_NONE : BOOTSTRAPPER_ACTION_STATE_UNINSTALL; 909 if (BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED == pPackage->currentState)
910 {
911 // If the package is superseded, check to see if there's a patch installed.
912 // A minor upgrade patch could be (usually is) the cause of the
913 // supersedence. In that case, we should ignore the supersedence that would
914 // normally prevent the uninstall. There is a gap in this logic: If a minor
915 // upgrade package were installed without a bundle, then a small update patch
916 // (which by definition doesn't change the version number) were installed,
917 // this check would allow the uninstall. If the minor upgrade were installed
918 // by a bundle, dependencies would keep the package installed.
919 execute = PackageHasAppliedPatch(pPackage) ? BOOTSTRAPPER_ACTION_STATE_UNINSTALL : BOOTSTRAPPER_ACTION_STATE_NONE;
920 }
921 else
922 {
923 execute = BOOTSTRAPPER_ACTION_STATE_UNINSTALL;
924 }
908 } 925 }
909 else if (BOOTSTRAPPER_REQUEST_STATE_FORCE_ABSENT == pPackage->requested) 926 else if (BOOTSTRAPPER_REQUEST_STATE_FORCE_ABSENT == pPackage->requested)
910 { 927 {
@@ -2141,7 +2158,7 @@ static HRESULT ConcatFeatureActionProperties(
2141 2158
2142 if (sczAddLocal) 2159 if (sczAddLocal)
2143 { 2160 {
2144 hr = StrAllocFormatted(&scz, L" ADDLOCAL=\"%s\"", sczAddLocal, 0); 2161 hr = StrAllocFormatted(&scz, L" ADDLOCAL=\"%s\"", sczAddLocal);
2145 ExitOnFailure(hr, "Failed to format ADDLOCAL string."); 2162 ExitOnFailure(hr, "Failed to format ADDLOCAL string.");
2146 2163
2147 hr = StrAllocConcatSecure(psczArguments, scz, 0); 2164 hr = StrAllocConcatSecure(psczArguments, scz, 0);
@@ -2150,7 +2167,7 @@ static HRESULT ConcatFeatureActionProperties(
2150 2167
2151 if (sczAddSource) 2168 if (sczAddSource)
2152 { 2169 {
2153 hr = StrAllocFormatted(&scz, L" ADDSOURCE=\"%s\"", sczAddSource, 0); 2170 hr = StrAllocFormatted(&scz, L" ADDSOURCE=\"%s\"", sczAddSource);
2154 ExitOnFailure(hr, "Failed to format ADDSOURCE string."); 2171 ExitOnFailure(hr, "Failed to format ADDSOURCE string.");
2155 2172
2156 hr = StrAllocConcatSecure(psczArguments, scz, 0); 2173 hr = StrAllocConcatSecure(psczArguments, scz, 0);
@@ -2159,7 +2176,7 @@ static HRESULT ConcatFeatureActionProperties(
2159 2176
2160 if (sczAddDefault) 2177 if (sczAddDefault)
2161 { 2178 {
2162 hr = StrAllocFormatted(&scz, L" ADDDEFAULT=\"%s\"", sczAddDefault, 0); 2179 hr = StrAllocFormatted(&scz, L" ADDDEFAULT=\"%s\"", sczAddDefault);
2163 ExitOnFailure(hr, "Failed to format ADDDEFAULT string."); 2180 ExitOnFailure(hr, "Failed to format ADDDEFAULT string.");
2164 2181
2165 hr = StrAllocConcatSecure(psczArguments, scz, 0); 2182 hr = StrAllocConcatSecure(psczArguments, scz, 0);
@@ -2168,7 +2185,7 @@ static HRESULT ConcatFeatureActionProperties(
2168 2185
2169 if (sczReinstall) 2186 if (sczReinstall)
2170 { 2187 {
2171 hr = StrAllocFormatted(&scz, L" REINSTALL=\"%s\"", sczReinstall, 0); 2188 hr = StrAllocFormatted(&scz, L" REINSTALL=\"%s\"", sczReinstall);
2172 ExitOnFailure(hr, "Failed to format REINSTALL string."); 2189 ExitOnFailure(hr, "Failed to format REINSTALL string.");
2173 2190
2174 hr = StrAllocConcatSecure(psczArguments, scz, 0); 2191 hr = StrAllocConcatSecure(psczArguments, scz, 0);
@@ -2177,7 +2194,7 @@ static HRESULT ConcatFeatureActionProperties(
2177 2194
2178 if (sczAdvertise) 2195 if (sczAdvertise)
2179 { 2196 {
2180 hr = StrAllocFormatted(&scz, L" ADVERTISE=\"%s\"", sczAdvertise, 0); 2197 hr = StrAllocFormatted(&scz, L" ADVERTISE=\"%s\"", sczAdvertise);
2181 ExitOnFailure(hr, "Failed to format ADVERTISE string."); 2198 ExitOnFailure(hr, "Failed to format ADVERTISE string.");
2182 2199
2183 hr = StrAllocConcatSecure(psczArguments, scz, 0); 2200 hr = StrAllocConcatSecure(psczArguments, scz, 0);
@@ -2186,7 +2203,7 @@ static HRESULT ConcatFeatureActionProperties(
2186 2203
2187 if (sczRemove) 2204 if (sczRemove)
2188 { 2205 {
2189 hr = StrAllocFormatted(&scz, L" REMOVE=\"%s\"", sczRemove, 0); 2206 hr = StrAllocFormatted(&scz, L" REMOVE=\"%s\"", sczRemove);
2190 ExitOnFailure(hr, "Failed to format REMOVE string."); 2207 ExitOnFailure(hr, "Failed to format REMOVE string.");
2191 2208
2192 hr = StrAllocConcatSecure(psczArguments, scz, 0); 2209 hr = StrAllocConcatSecure(psczArguments, scz, 0);
@@ -2265,6 +2282,7 @@ LExit:
2265 ReleaseStr(sczMspPath); 2282 ReleaseStr(sczMspPath);
2266 ReleaseStr(sczCachedDirectory); 2283 ReleaseStr(sczCachedDirectory);
2267 ReleaseStr(sczPatches); 2284 ReleaseStr(sczPatches);
2285
2268 return hr; 2286 return hr;
2269} 2287}
2270 2288
@@ -2289,6 +2307,47 @@ static void RegisterSourceDirectory(
2289 2307
2290LExit: 2308LExit:
2291 ReleaseStr(sczMsiDirectory); 2309 ReleaseStr(sczMsiDirectory);
2310}
2311
2312static BOOL PackageHasAppliedPatch(
2313 __in BURN_PACKAGE* pPackage
2314)
2315{
2316 HRESULT hr = S_OK;
2317 BOOL fPatched = FALSE;
2318 UINT er = ERROR_SUCCESS;
2319 DWORD iPatch = 0;
2320 WCHAR wzPatchCode[MAX_GUID_CHARS + 1] = {};
2321 WCHAR wzTransforms[MAX_PATH] = {};
2322 DWORD cchTransforms = countof(wzTransforms);
2323 WCHAR wzPatchState[2] = {};
2324 DWORD cchPatchState = countof(wzPatchState);
2325
2326 for (;;)
2327 {
2328 er = ::MsiEnumPatchesW(pPackage->Msi.sczProductCode, iPatch, wzPatchCode, wzTransforms, &cchTransforms);
2329
2330 if (ERROR_NO_MORE_ITEMS == er)
2331 {
2332 ExitFunction();
2333 }
2334 ExitOnWin32Error(er, hr, "Failed to enumerate patches for package %ls, product code %ls.", pPackage->sczId, pPackage->Msi.sczProductCode);
2335
2336 er = ::MsiGetPatchInfoExW(wzPatchCode, pPackage->Msi.sczProductCode, NULL, pPackage->fPerMachine ? MSIINSTALLCONTEXT_MACHINE : MSIINSTALLCONTEXT_USERUNMANAGED
2337 , INSTALLPROPERTY_PATCHSTATE, wzPatchState, &cchPatchState);
2338 ExitOnWin32Error(er, hr, "Failed to get patch info for patch %ls.", wzPatchCode);
2339
2340 if ('1' == wzPatchState[0])
2341 {
2342 fPatched = TRUE;
2343
2344 ExitFunction();
2345 }
2346
2347 ++iPatch;
2348 }
2349
2350LExit:
2351 return fPatched;
2292 2352
2293 return;
2294} 2353}
diff --git a/src/burn/engine/mspengine.cpp b/src/burn/engine/mspengine.cpp
index c057c06d..e8ef7fcb 100644
--- a/src/burn/engine/mspengine.cpp
+++ b/src/burn/engine/mspengine.cpp
@@ -771,7 +771,7 @@ extern "C" void MspEngineUpdateInstallRegistrationState(
771 { 771 {
772 pTargetProduct = pPackage->Msp.rgTargetProducts + j; 772 pTargetProduct = pPackage->Msp.rgTargetProducts + j;
773 if (pAction->mspTarget.fPerMachineTarget == (MSIINSTALLCONTEXT_MACHINE == pTargetProduct->context) && 773 if (pAction->mspTarget.fPerMachineTarget == (MSIINSTALLCONTEXT_MACHINE == pTargetProduct->context) &&
774 CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, pAction->mspTarget.sczTargetProductCode, -1, pTargetProduct->wzTargetProductCode, -1)) 774 CSTR_EQUAL == ::CompareStringOrdinal(pAction->mspTarget.sczTargetProductCode, -1, pTargetProduct->wzTargetProductCode, -1, FALSE))
775 { 775 {
776 break; 776 break;
777 } 777 }
@@ -1069,7 +1069,7 @@ static HRESULT DeterminePatchChainedTarget(
1069 { 1069 {
1070 BURN_PACKAGE* pPackage = pPackages->rgPackages + iPackage; 1070 BURN_PACKAGE* pPackage = pPackages->rgPackages + iPackage;
1071 1071
1072 if (BURN_PACKAGE_TYPE_MSI == pPackage->type && CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzTargetProductCode, -1, pPackage->Msi.sczProductCode, -1)) 1072 if (BURN_PACKAGE_TYPE_MSI == pPackage->type && CSTR_EQUAL == ::CompareStringOrdinal(wzTargetProductCode, -1, pPackage->Msi.sczProductCode, -1, FALSE))
1073 { 1073 {
1074 pTargetProduct->pChainedTargetPackage = pPackage; 1074 pTargetProduct->pChainedTargetPackage = pPackage;
1075 1075
@@ -1123,7 +1123,7 @@ static HRESULT PlanTargetProduct(
1123 if (BURN_EXECUTE_ACTION_TYPE_MSP_TARGET == pAction->type && 1123 if (BURN_EXECUTE_ACTION_TYPE_MSP_TARGET == pAction->type &&
1124 pAction->mspTarget.action == actionState && 1124 pAction->mspTarget.action == actionState &&
1125 pAction->mspTarget.fPerMachineTarget == (MSIINSTALLCONTEXT_MACHINE == pTargetProduct->context) && 1125 pAction->mspTarget.fPerMachineTarget == (MSIINSTALLCONTEXT_MACHINE == pTargetProduct->context) &&
1126 CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, pAction->mspTarget.sczTargetProductCode, -1, pTargetProduct->wzTargetProductCode, -1)) 1126 CSTR_EQUAL == ::CompareStringOrdinal(pAction->mspTarget.sczTargetProductCode, -1, pTargetProduct->wzTargetProductCode, -1, FALSE))
1127 { 1127 {
1128 dwInsertSequence = i; 1128 dwInsertSequence = i;
1129 break; 1129 break;
diff --git a/src/burn/engine/msuengine.cpp b/src/burn/engine/msuengine.cpp
index 43f5f76c..d31691a5 100644
--- a/src/burn/engine/msuengine.cpp
+++ b/src/burn/engine/msuengine.cpp
@@ -313,6 +313,8 @@ LExit:
313 SetServiceStartType(schWu, SERVICE_DISABLED); 313 SetServiceStartType(schWu, SERVICE_DISABLED);
314 } 314 }
315 315
316 ReleaseServiceHandle(schWu);
317
316 // Best effort to clear the execute package cache folder variable. 318 // Best effort to clear the execute package cache folder variable.
317 VariableSetString(pVariables, BURN_BUNDLE_EXECUTE_PACKAGE_CACHE_FOLDER, NULL, TRUE, FALSE); 319 VariableSetString(pVariables, BURN_BUNDLE_EXECUTE_PACKAGE_CACHE_FOLDER, NULL, TRUE, FALSE);
318 320
diff --git a/src/burn/engine/package.cpp b/src/burn/engine/package.cpp
index fe8af497..3bf676ba 100644
--- a/src/burn/engine/package.cpp
+++ b/src/burn/engine/package.cpp
@@ -123,15 +123,15 @@ extern "C" HRESULT PackagesParseFromXml(
123 123
124 if (fFoundXml) 124 if (fFoundXml)
125 { 125 {
126 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"remove", -1)) 126 if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"remove", -1, FALSE))
127 { 127 {
128 pPackage->authoredCacheType = BOOTSTRAPPER_CACHE_TYPE_REMOVE; 128 pPackage->authoredCacheType = BOOTSTRAPPER_CACHE_TYPE_REMOVE;
129 } 129 }
130 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"keep", -1)) 130 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"keep", -1, FALSE))
131 { 131 {
132 pPackage->authoredCacheType = BOOTSTRAPPER_CACHE_TYPE_KEEP; 132 pPackage->authoredCacheType = BOOTSTRAPPER_CACHE_TYPE_KEEP;
133 } 133 }
134 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"force", -1)) 134 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"force", -1, FALSE))
135 { 135 {
136 pPackage->authoredCacheType = BOOTSTRAPPER_CACHE_TYPE_FORCE; 136 pPackage->authoredCacheType = BOOTSTRAPPER_CACHE_TYPE_FORCE;
137 } 137 }
@@ -210,28 +210,28 @@ extern "C" HRESULT PackagesParseFromXml(
210 } 210 }
211 211
212 // read type specific attributes 212 // read type specific attributes
213 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrNodeName, -1, L"BundlePackage", -1)) 213 if (CSTR_EQUAL == ::CompareStringOrdinal(bstrNodeName, -1, L"BundlePackage", -1, FALSE))
214 { 214 {
215 pPackage->type = BURN_PACKAGE_TYPE_BUNDLE; 215 pPackage->type = BURN_PACKAGE_TYPE_BUNDLE;
216 216
217 hr = BundlePackageEngineParsePackageFromXml(pixnNode, pPackage); // TODO: Modularization 217 hr = BundlePackageEngineParsePackageFromXml(pixnNode, pPackage); // TODO: Modularization
218 ExitOnFailure(hr, "Failed to parse BUNDLE package."); 218 ExitOnFailure(hr, "Failed to parse BUNDLE package.");
219 } 219 }
220 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrNodeName, -1, L"ExePackage", -1)) 220 else if (CSTR_EQUAL == ::CompareStringOrdinal(bstrNodeName, -1, L"ExePackage", -1, FALSE))
221 { 221 {
222 pPackage->type = BURN_PACKAGE_TYPE_EXE; 222 pPackage->type = BURN_PACKAGE_TYPE_EXE;
223 223
224 hr = ExeEngineParsePackageFromXml(pixnNode, pPackage); // TODO: Modularization 224 hr = ExeEngineParsePackageFromXml(pixnNode, pPackage); // TODO: Modularization
225 ExitOnFailure(hr, "Failed to parse EXE package."); 225 ExitOnFailure(hr, "Failed to parse EXE package.");
226 } 226 }
227 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrNodeName, -1, L"MsiPackage", -1)) 227 else if (CSTR_EQUAL == ::CompareStringOrdinal(bstrNodeName, -1, L"MsiPackage", -1, FALSE))
228 { 228 {
229 pPackage->type = BURN_PACKAGE_TYPE_MSI; 229 pPackage->type = BURN_PACKAGE_TYPE_MSI;
230 230
231 hr = MsiEngineParsePackageFromXml(pixnNode, pPackage); // TODO: Modularization 231 hr = MsiEngineParsePackageFromXml(pixnNode, pPackage); // TODO: Modularization
232 ExitOnFailure(hr, "Failed to parse MSI package."); 232 ExitOnFailure(hr, "Failed to parse MSI package.");
233 } 233 }
234 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrNodeName, -1, L"MspPackage", -1)) 234 else if (CSTR_EQUAL == ::CompareStringOrdinal(bstrNodeName, -1, L"MspPackage", -1, FALSE))
235 { 235 {
236 pPackage->type = BURN_PACKAGE_TYPE_MSP; 236 pPackage->type = BURN_PACKAGE_TYPE_MSP;
237 237
@@ -240,7 +240,7 @@ extern "C" HRESULT PackagesParseFromXml(
240 240
241 ++cMspPackages; 241 ++cMspPackages;
242 } 242 }
243 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrNodeName, -1, L"MsuPackage", -1)) 243 else if (CSTR_EQUAL == ::CompareStringOrdinal(bstrNodeName, -1, L"MsuPackage", -1, FALSE))
244 { 244 {
245 pPackage->type = BURN_PACKAGE_TYPE_MSU; 245 pPackage->type = BURN_PACKAGE_TYPE_MSU;
246 246
@@ -315,7 +315,7 @@ extern "C" HRESULT PackagesParseFromXml(
315 { 315 {
316 for (DWORD k = 0; k < pMsiPackage->Msi.cSlipstreamMspPackages; ++k) 316 for (DWORD k = 0; k < pMsiPackage->Msi.cSlipstreamMspPackages; ++k)
317 { 317 {
318 if (pMsiPackage->Msi.rgsczSlipstreamMspPackageIds[k] && CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pPackage->sczId, -1, pMsiPackage->Msi.rgsczSlipstreamMspPackageIds[k], -1)) 318 if (pMsiPackage->Msi.rgsczSlipstreamMspPackageIds[k] && CSTR_EQUAL == ::CompareStringOrdinal(pPackage->sczId, -1, pMsiPackage->Msi.rgsczSlipstreamMspPackageIds[k], -1, FALSE))
319 { 319 {
320 BURN_SLIPSTREAM_MSP* pSlipstreamMsp = pMsiPackage->Msi.rgSlipstreamMsps + k; 320 BURN_SLIPSTREAM_MSP* pSlipstreamMsp = pMsiPackage->Msi.rgSlipstreamMsps + k;
321 pSlipstreamMsp->pMspPackage = pPackage; 321 pSlipstreamMsp->pMspPackage = pPackage;
@@ -486,7 +486,7 @@ extern "C" HRESULT PackageFindById(
486 { 486 {
487 pPackage = &pPackages->rgPackages[i]; 487 pPackage = &pPackages->rgPackages[i];
488 488
489 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pPackage->sczId, -1, wzId, -1)) 489 if (CSTR_EQUAL == ::CompareStringOrdinal(pPackage->sczId, -1, wzId, -1, FALSE))
490 { 490 {
491 *ppPackage = pPackage; 491 *ppPackage = pPackage;
492 ExitFunction1(hr = S_OK); 492 ExitFunction1(hr = S_OK);
@@ -508,7 +508,7 @@ extern "C" HRESULT PackageFindRelatedById(
508{ 508{
509 HRESULT hr = S_OK; 509 HRESULT hr = S_OK;
510 BURN_RELATED_BUNDLE* pRelatedBundle = NULL; 510 BURN_RELATED_BUNDLE* pRelatedBundle = NULL;
511 511
512 hr = RelatedBundleFindById(pRelatedBundles, wzId, &pRelatedBundle); 512 hr = RelatedBundleFindById(pRelatedBundles, wzId, &pRelatedBundle);
513 *ppPackage = FAILED(hr) ? NULL : &pRelatedBundle->package; 513 *ppPackage = FAILED(hr) ? NULL : &pRelatedBundle->package;
514 514
@@ -551,7 +551,7 @@ extern "C" HRESULT PackageGetProperty(
551 { 551 {
552 const BURN_MSIPROPERTY* pProperty = &rgProperties[i]; 552 const BURN_MSIPROPERTY* pProperty = &rgProperties[i];
553 553
554 if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, pProperty->sczId, -1, wzProperty, -1)) 554 if (CSTR_EQUAL == ::CompareStringOrdinal(pProperty->sczId, -1, wzProperty, -1, FALSE))
555 { 555 {
556 if (psczValue) 556 if (psczValue)
557 { 557 {
@@ -580,7 +580,7 @@ extern "C" HRESULT PackageFindRollbackBoundaryById(
580 { 580 {
581 pRollbackBoundary = &pPackages->rgRollbackBoundaries[i]; 581 pRollbackBoundary = &pPackages->rgRollbackBoundaries[i];
582 582
583 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pRollbackBoundary->sczId, -1, wzId, -1)) 583 if (CSTR_EQUAL == ::CompareStringOrdinal(pRollbackBoundary->sczId, -1, wzId, -1, FALSE))
584 { 584 {
585 *ppRollbackBoundary = pRollbackBoundary; 585 *ppRollbackBoundary = pRollbackBoundary;
586 ExitFunction1(hr = S_OK); 586 ExitFunction1(hr = S_OK);
@@ -730,7 +730,7 @@ static HRESULT FindRollbackBoundaryById(
730 { 730 {
731 pRollbackBoundary = &pPackages->rgRollbackBoundaries[i]; 731 pRollbackBoundary = &pPackages->rgRollbackBoundaries[i];
732 732
733 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pRollbackBoundary->sczId, -1, wzId, -1)) 733 if (CSTR_EQUAL == ::CompareStringOrdinal(pRollbackBoundary->sczId, -1, wzId, -1, FALSE))
734 { 734 {
735 *ppRollbackBoundary = pRollbackBoundary; 735 *ppRollbackBoundary = pRollbackBoundary;
736 ExitFunction1(hr = S_OK); 736 ExitFunction1(hr = S_OK);
diff --git a/src/burn/engine/payload.cpp b/src/burn/engine/payload.cpp
index 270da6aa..a2649f97 100644
--- a/src/burn/engine/payload.cpp
+++ b/src/burn/engine/payload.cpp
@@ -80,11 +80,11 @@ extern "C" HRESULT PayloadsParseFromXml(
80 hr = XmlGetAttributeEx(pixnNode, L"Packaging", &scz); 80 hr = XmlGetAttributeEx(pixnNode, L"Packaging", &scz);
81 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Packaging."); 81 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Packaging.");
82 82
83 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"embedded", -1)) 83 if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"embedded", -1, FALSE))
84 { 84 {
85 pPayload->packaging = BURN_PAYLOAD_PACKAGING_EMBEDDED; 85 pPayload->packaging = BURN_PAYLOAD_PACKAGING_EMBEDDED;
86 } 86 }
87 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"external", -1)) 87 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"external", -1, FALSE))
88 { 88 {
89 pPayload->packaging = BURN_PAYLOAD_PACKAGING_EXTERNAL; 89 pPayload->packaging = BURN_PAYLOAD_PACKAGING_EXTERNAL;
90 } 90 }
diff --git a/src/burn/engine/plan.cpp b/src/burn/engine/plan.cpp
index 7994dd32..edc09033 100644
--- a/src/burn/engine/plan.cpp
+++ b/src/burn/engine/plan.cpp
@@ -376,20 +376,6 @@ extern "C" HRESULT PlanDefaultPackageRequestState(
376 break; 376 break;
377 } 377 }
378 } 378 }
379 else if (BOOTSTRAPPER_RELATION_PATCH == relationType && BURN_PACKAGE_TYPE_MSP == packageType)
380 {
381 // For patch related bundles, only install a patch if currently absent during install, modify, or repair.
382 if (BOOTSTRAPPER_PACKAGE_STATE_ABSENT != currentState)
383 {
384 *pRequestState = BOOTSTRAPPER_REQUEST_STATE_NONE;
385 }
386 else if (BOOTSTRAPPER_ACTION_INSTALL == action ||
387 BOOTSTRAPPER_ACTION_MODIFY == action ||
388 BOOTSTRAPPER_ACTION_REPAIR == action)
389 {
390 *pRequestState = BOOTSTRAPPER_REQUEST_STATE_PRESENT;
391 }
392 }
393 else // pick the best option for the action state and install condition. 379 else // pick the best option for the action state and install condition.
394 { 380 {
395 hr = GetActionDefaultRequestState(action, currentState, &defaultRequestState); 381 hr = GetActionDefaultRequestState(action, currentState, &defaultRequestState);
@@ -397,12 +383,28 @@ extern "C" HRESULT PlanDefaultPackageRequestState(
397 383
398 if (BOOTSTRAPPER_ACTION_UNINSTALL != action && BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL != action) 384 if (BOOTSTRAPPER_ACTION_UNINSTALL != action && BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL != action)
399 { 385 {
386 // For patch related bundles, only install a patch if currently absent during install, modify, or repair.
387 if (BOOTSTRAPPER_RELATION_PATCH == relationType && BURN_PACKAGE_TYPE_MSP == packageType)
388 {
389 if (BOOTSTRAPPER_PACKAGE_STATE_ABSENT != currentState)
390 {
391 defaultRequestState = BOOTSTRAPPER_REQUEST_STATE_NONE;
392 }
393 else if (BOOTSTRAPPER_ACTION_INSTALL == action ||
394 BOOTSTRAPPER_ACTION_MODIFY == action ||
395 BOOTSTRAPPER_ACTION_REPAIR == action)
396 {
397 defaultRequestState = BOOTSTRAPPER_REQUEST_STATE_PRESENT;
398 }
399 }
400
400 // If we're not doing an uninstall, use the install condition 401 // If we're not doing an uninstall, use the install condition
401 // to determine whether to use the default request state or make the package absent. 402 // to determine whether to use the default request state or make the package absent.
402 if (BOOTSTRAPPER_PACKAGE_CONDITION_FALSE == installCondition) 403 if (BOOTSTRAPPER_PACKAGE_CONDITION_FALSE == installCondition)
403 { 404 {
404 defaultRequestState = BOOTSTRAPPER_REQUEST_STATE_ABSENT; 405 defaultRequestState = BOOTSTRAPPER_REQUEST_STATE_ABSENT;
405 } 406 }
407
406 // Obsolete means the package is not on the machine and should not be installed, 408 // Obsolete means the package is not on the machine and should not be installed,
407 // *except* patches can be obsolete and present. 409 // *except* patches can be obsolete and present.
408 // Superseded means the package is on the machine but not active, so only uninstall operations are allowed. 410 // Superseded means the package is on the machine but not active, so only uninstall operations are allowed.
@@ -1540,7 +1542,7 @@ extern "C" HRESULT PlanRelatedBundlesComplete(
1540 1542
1541 if (fBundle && BOOTSTRAPPER_ACTION_STATE_NONE != packageAction) 1543 if (fBundle && BOOTSTRAPPER_ACTION_STATE_NONE != packageAction)
1542 { 1544 {
1543 if (pPackage->cDependencyProviders) 1545 if (pPackage && pPackage->cDependencyProviders)
1544 { 1546 {
1545 // Bundles only support a single provider key. 1547 // Bundles only support a single provider key.
1546 const BURN_DEPENDENCY_PROVIDER* pProvider = pPackage->rgDependencyProviders; 1548 const BURN_DEPENDENCY_PROVIDER* pProvider = pPackage->rgDependencyProviders;
@@ -1554,7 +1556,7 @@ extern "C" HRESULT PlanRelatedBundlesComplete(
1554 1556
1555 for (DWORD i = 0; i < pRegistration->relatedBundles.cRelatedBundles; ++i) 1557 for (DWORD i = 0; i < pRegistration->relatedBundles.cRelatedBundles; ++i)
1556 { 1558 {
1557 DWORD *pdwInsertIndex = NULL; 1559 DWORD* pdwInsertIndex = NULL;
1558 BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgpPlanSortedRelatedBundles[i]; 1560 BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgpPlanSortedRelatedBundles[i];
1559 BOOL fDependent = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DEPENDENT_ADDON == pRelatedBundle->planRelationType || 1561 BOOL fDependent = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DEPENDENT_ADDON == pRelatedBundle->planRelationType ||
1560 BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DEPENDENT_PATCH == pRelatedBundle->planRelationType; 1562 BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DEPENDENT_PATCH == pRelatedBundle->planRelationType;
@@ -2013,6 +2015,7 @@ extern "C" HRESULT PlanRollbackBoundaryComplete(
2013 2015
2014 // Add checkpoints. 2016 // Add checkpoints.
2015 hr = PlanExecuteCheckpoint(pPlan); 2017 hr = PlanExecuteCheckpoint(pPlan);
2018 ExitOnFailure(hr, "Failed to append execute checkpoint for rollback boundary complete.");
2016 2019
2017 // Add complete rollback boundary to execute plan. 2020 // Add complete rollback boundary to execute plan.
2018 hr = PlanAppendExecuteAction(pPlan, &pExecuteAction); 2021 hr = PlanAppendExecuteAction(pPlan, &pExecuteAction);
@@ -2948,9 +2951,9 @@ static void ExecuteActionLog(
2948 2951
2949 case BURN_EXECUTE_ACTION_TYPE_PACKAGE_DEPENDENCY: 2952 case BURN_EXECUTE_ACTION_TYPE_PACKAGE_DEPENDENCY:
2950 LogStringLine(PlanDumpLevel, "%ls action[%u]: PACKAGE_DEPENDENCY package id: %ls, bundle provider key: %ls", wzBase, iAction, pAction->packageDependency.pPackage->sczId, pAction->packageDependency.sczBundleProviderKey); 2953 LogStringLine(PlanDumpLevel, "%ls action[%u]: PACKAGE_DEPENDENCY package id: %ls, bundle provider key: %ls", wzBase, iAction, pAction->packageDependency.pPackage->sczId, pAction->packageDependency.sczBundleProviderKey);
2951 for (DWORD j = 0; j < pAction->packageProvider.pPackage->cDependencyProviders; ++j) 2954 for (DWORD j = 0; j < pAction->packageDependency.pPackage->cDependencyProviders; ++j)
2952 { 2955 {
2953 const BURN_DEPENDENCY_PROVIDER* pProvider = pAction->packageProvider.pPackage->rgDependencyProviders + j; 2956 const BURN_DEPENDENCY_PROVIDER* pProvider = pAction->packageDependency.pPackage->rgDependencyProviders + j;
2954 LogStringLine(PlanDumpLevel, " Provider[%u]: key: %ls, action: %hs", j, pProvider->sczKey, LoggingDependencyActionToString(fRollback ? pProvider->dependentRollback : pProvider->dependentExecute)); 2957 LogStringLine(PlanDumpLevel, " Provider[%u]: key: %ls, action: %hs", j, pProvider->sczKey, LoggingDependencyActionToString(fRollback ? pProvider->dependentRollback : pProvider->dependentExecute));
2955 } 2958 }
2956 break; 2959 break;
diff --git a/src/burn/engine/pseudobundle.cpp b/src/burn/engine/pseudobundle.cpp
index f0d67068..ff7f185c 100644
--- a/src/burn/engine/pseudobundle.cpp
+++ b/src/burn/engine/pseudobundle.cpp
@@ -127,8 +127,8 @@ extern "C" HRESULT PseudoBundleInitializePassthrough(
127 ExitOnFailure(hr, "Failed to copy cache id for passthrough pseudo bundle."); 127 ExitOnFailure(hr, "Failed to copy cache id for passthrough pseudo bundle.");
128 128
129 // Log variables - best effort 129 // Log variables - best effort
130 StrAllocFormatted(&pPackage->sczLogPathVariable, L"WixBundleLog_%ls", pPackage->sczId); 130 StrAllocFormatted(&pPassthroughPackage->sczLogPathVariable, L"WixBundleLog_%ls", pPackage->sczId);
131 StrAllocFormatted(&pPackage->sczRollbackLogPathVariable, L"WixBundleRollbackLog_%ls", pPackage->sczId); 131 StrAllocFormatted(&pPassthroughPackage->sczRollbackLogPathVariable, L"WixBundleRollbackLog_%ls", pPackage->sczId);
132 132
133 hr = CoreCreatePassthroughBundleCommandLine(&sczArguments, pInternalCommand, pCommand); 133 hr = CoreCreatePassthroughBundleCommandLine(&sczArguments, pInternalCommand, pCommand);
134 ExitOnFailure(hr, "Failed to create command-line arguments."); 134 ExitOnFailure(hr, "Failed to create command-line arguments.");
@@ -155,6 +155,8 @@ extern "C" HRESULT PseudoBundleInitializeUpdateBundle(
155{ 155{
156 HRESULT hr = S_OK; 156 HRESULT hr = S_OK;
157 BURN_PAYLOAD* pPayload = NULL; 157 BURN_PAYLOAD* pPayload = NULL;
158 BYTE* rgbHash = NULL;
159 DWORD cbHash = 0;
158 160
159 // Initialize the single payload, and fill out all the necessary fields 161 // Initialize the single payload, and fill out all the necessary fields
160 pPackage->payloads.rgItems = (BURN_PAYLOAD_GROUP_ITEM*)MemAlloc(sizeof(BURN_PAYLOAD_GROUP_ITEM), TRUE); 162 pPackage->payloads.rgItems = (BURN_PAYLOAD_GROUP_ITEM*)MemAlloc(sizeof(BURN_PAYLOAD_GROUP_ITEM), TRUE);
@@ -185,9 +187,6 @@ extern "C" HRESULT PseudoBundleInitializeUpdateBundle(
185 187
186 if (wzHash && *wzHash) 188 if (wzHash && *wzHash)
187 { 189 {
188 BYTE* rgbHash = NULL;
189 DWORD cbHash = 0;
190
191 hr = StrAllocHexDecode(wzHash, &rgbHash, &cbHash); 190 hr = StrAllocHexDecode(wzHash, &rgbHash, &cbHash);
192 ExitOnFailure(hr, "Failed to decode hash string: %ls.", wzHash); 191 ExitOnFailure(hr, "Failed to decode hash string: %ls.", wzHash);
193 192
@@ -223,5 +222,7 @@ extern "C" HRESULT PseudoBundleInitializeUpdateBundle(
223 ExitOnFailure(hr, "Failed to copy install arguments for update bundle package"); 222 ExitOnFailure(hr, "Failed to copy install arguments for update bundle package");
224 223
225LExit: 224LExit:
225 ReleaseStr(rgbHash);
226
226 return hr; 227 return hr;
227} 228}
diff --git a/src/burn/engine/registration.cpp b/src/burn/engine/registration.cpp
index 85c006f7..9733e92c 100644
--- a/src/burn/engine/registration.cpp
+++ b/src/burn/engine/registration.cpp
@@ -223,15 +223,15 @@ extern "C" HRESULT RegistrationParseFromXml(
223 223
224 if (fFoundXml) 224 if (fFoundXml)
225 { 225 {
226 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"button", -1)) 226 if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"button", -1, FALSE))
227 { 227 {
228 pRegistration->modify = BURN_REGISTRATION_MODIFY_DISABLE_BUTTON; 228 pRegistration->modify = BURN_REGISTRATION_MODIFY_DISABLE_BUTTON;
229 } 229 }
230 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"yes", -1)) 230 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"yes", -1, FALSE))
231 { 231 {
232 pRegistration->modify = BURN_REGISTRATION_MODIFY_DISABLE; 232 pRegistration->modify = BURN_REGISTRATION_MODIFY_DISABLE;
233 } 233 }
234 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"no", -1)) 234 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"no", -1, FALSE))
235 { 235 {
236 pRegistration->modify = BURN_REGISTRATION_MODIFY_ENABLED; 236 pRegistration->modify = BURN_REGISTRATION_MODIFY_ENABLED;
237 } 237 }
@@ -808,13 +808,6 @@ extern "C" HRESULT RegistrationSessionBegin(
808 ExitOnFailure(hr, "Failed to write software tags."); 808 ExitOnFailure(hr, "Failed to write software tags.");
809 } 809 }
810 810
811 // Update registration.
812 if (pRegistration->update.fRegisterUpdate)
813 {
814 hr = WriteUpdateRegistration(pRegistration, pVariables);
815 ExitOnFailure(hr, "Failed to write update registration.");
816 }
817
818 // Only set install date and initial estimated size here for the first time. 811 // Only set install date and initial estimated size here for the first time.
819 // Estimated size will always get updated at the end of the session. 812 // Estimated size will always get updated at the end of the session.
820 if (fCreated) 813 if (fCreated)
@@ -904,6 +897,13 @@ extern "C" HRESULT RegistrationSessionEnd(
904 897
905 hr = UpdateEstimatedSize(hkRegistration, qwEstimatedSize); 898 hr = UpdateEstimatedSize(hkRegistration, qwEstimatedSize);
906 ExitOnFailure(hr, "Failed to update estimated size."); 899 ExitOnFailure(hr, "Failed to update estimated size.");
900
901 // Update registration.
902 if (pRegistration->update.fRegisterUpdate)
903 {
904 hr = WriteUpdateRegistration(pRegistration, pVariables);
905 ExitOnFailure(hr, "Failed to write update registration.");
906 }
907 } 907 }
908 908
909 // Update resume mode. 909 // Update resume mode.
@@ -1512,7 +1512,7 @@ static HRESULT RemoveUpdateRegistration(
1512 hr = RegReadString(hkKey, L"PackageVersion", &sczPackageVersion); 1512 hr = RegReadString(hkKey, L"PackageVersion", &sczPackageVersion);
1513 if (SUCCEEDED(hr)) 1513 if (SUCCEEDED(hr))
1514 { 1514 {
1515 if (CSTR_EQUAL != ::CompareStringW(LOCALE_INVARIANT, 0, sczPackageVersion, -1, pRegistration->sczDisplayVersion, -1)) 1515 if (CSTR_EQUAL != ::CompareStringOrdinal(sczPackageVersion, -1, pRegistration->sczDisplayVersion, -1, FALSE))
1516 { 1516 {
1517 fDeleteRegKey = FALSE; 1517 fDeleteRegKey = FALSE;
1518 } 1518 }
diff --git a/src/burn/engine/relatedbundle.cpp b/src/burn/engine/relatedbundle.cpp
index 938b24d7..c9aa7170 100644
--- a/src/burn/engine/relatedbundle.cpp
+++ b/src/burn/engine/relatedbundle.cpp
@@ -116,7 +116,7 @@ extern "C" HRESULT RelatedBundleFindById(
116 pRelatedBundle = pRelatedBundles->rgRelatedBundles + i; 116 pRelatedBundle = pRelatedBundles->rgRelatedBundles + i;
117 pPackage = &pRelatedBundle->package; 117 pPackage = &pRelatedBundle->package;
118 118
119 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pPackage->sczId, -1, wzId, -1)) 119 if (CSTR_EQUAL == ::CompareStringOrdinal(pPackage->sczId, -1, wzId, -1, FALSE))
120 { 120 {
121 *ppRelatedBundle = pRelatedBundle; 121 *ppRelatedBundle = pRelatedBundle;
122 ExitFunction1(hr = S_OK); 122 ExitFunction1(hr = S_OK);
@@ -206,7 +206,7 @@ static __callback int __cdecl CompareRelatedBundlesDetect(
206 VerCompareParsedVersions(pBundleLeft->pVersion, pBundleRight->pVersion, &ret); 206 VerCompareParsedVersions(pBundleLeft->pVersion, pBundleRight->pVersion, &ret);
207 if (0 == ret) 207 if (0 == ret)
208 { 208 {
209 ret = ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pBundleLeft->package.sczId, -1, pBundleRight->package.sczId, -1) - 2; 209 ret = ::CompareStringOrdinal(pBundleLeft->package.sczId, -1, pBundleRight->package.sczId, -1, TRUE) - 2;
210 } 210 }
211 } 211 }
212 212
@@ -249,7 +249,7 @@ static __callback int __cdecl CompareRelatedBundlesPlan(
249 VerCompareParsedVersions(pBundleLeft->pVersion, pBundleRight->pVersion, &ret); 249 VerCompareParsedVersions(pBundleLeft->pVersion, pBundleRight->pVersion, &ret);
250 if (0 == ret) 250 if (0 == ret)
251 { 251 {
252 ret = ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pBundleLeft->package.sczId, -1, pBundleRight->package.sczId, -1) - 2; 252 ret = ::CompareStringOrdinal(pBundleLeft->package.sczId, -1, pBundleRight->package.sczId, -1, TRUE) - 2;
253 } 253 }
254 } 254 }
255 255
@@ -284,7 +284,7 @@ static HRESULT LoadIfRelatedBundle(
284 BURN_RELATED_BUNDLE* pRelatedBundle = NULL; 284 BURN_RELATED_BUNDLE* pRelatedBundle = NULL;
285 285
286 // If we found our bundle code, it's not a related bundle. 286 // If we found our bundle code, it's not a related bundle.
287 if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pBundle->wzBundleCode, -1, pRegistration->sczCode, -1)) 287 if (CSTR_EQUAL == ::CompareStringOrdinal(pBundle->wzBundleCode, -1, pRegistration->sczCode, -1, TRUE))
288 { 288 {
289 ExitFunction1(hr = S_FALSE); 289 ExitFunction1(hr = S_FALSE);
290 } 290 }
diff --git a/src/burn/engine/search.cpp b/src/burn/engine/search.cpp
index a1b6b74a..a60215fe 100644
--- a/src/burn/engine/search.cpp
+++ b/src/burn/engine/search.cpp
@@ -106,7 +106,7 @@ extern "C" HRESULT SearchesParseFromXml(
106 ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get @Condition."); 106 ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get @Condition.");
107 107
108 // read type specific attributes 108 // read type specific attributes
109 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrNodeName, -1, L"DirectorySearch", -1)) 109 if (CSTR_EQUAL == ::CompareStringOrdinal(bstrNodeName, -1, L"DirectorySearch", -1, FALSE))
110 { 110 {
111 pSearch->Type = BURN_SEARCH_TYPE_DIRECTORY; 111 pSearch->Type = BURN_SEARCH_TYPE_DIRECTORY;
112 112
@@ -118,11 +118,11 @@ extern "C" HRESULT SearchesParseFromXml(
118 hr = XmlGetAttributeEx(pixnNode, L"Type", &scz); 118 hr = XmlGetAttributeEx(pixnNode, L"Type", &scz);
119 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Type."); 119 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Type.");
120 120
121 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"exists", -1)) 121 if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"exists", -1, FALSE))
122 { 122 {
123 pSearch->DirectorySearch.Type = BURN_DIRECTORY_SEARCH_TYPE_EXISTS; 123 pSearch->DirectorySearch.Type = BURN_DIRECTORY_SEARCH_TYPE_EXISTS;
124 } 124 }
125 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"path", -1)) 125 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"path", -1, FALSE))
126 { 126 {
127 pSearch->DirectorySearch.Type = BURN_DIRECTORY_SEARCH_TYPE_PATH; 127 pSearch->DirectorySearch.Type = BURN_DIRECTORY_SEARCH_TYPE_PATH;
128 } 128 }
@@ -131,7 +131,7 @@ extern "C" HRESULT SearchesParseFromXml(
131 ExitWithRootFailure(hr, E_INVALIDARG, "Invalid value for @Type: %ls", scz); 131 ExitWithRootFailure(hr, E_INVALIDARG, "Invalid value for @Type: %ls", scz);
132 } 132 }
133 } 133 }
134 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrNodeName, -1, L"FileSearch", -1)) 134 else if (CSTR_EQUAL == ::CompareStringOrdinal(bstrNodeName, -1, L"FileSearch", -1, FALSE))
135 { 135 {
136 pSearch->Type = BURN_SEARCH_TYPE_FILE; 136 pSearch->Type = BURN_SEARCH_TYPE_FILE;
137 137
@@ -147,15 +147,15 @@ extern "C" HRESULT SearchesParseFromXml(
147 hr = XmlGetAttributeEx(pixnNode, L"Type", &scz); 147 hr = XmlGetAttributeEx(pixnNode, L"Type", &scz);
148 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Type."); 148 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Type.");
149 149
150 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"exists", -1)) 150 if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"exists", -1, FALSE))
151 { 151 {
152 pSearch->FileSearch.Type = BURN_FILE_SEARCH_TYPE_EXISTS; 152 pSearch->FileSearch.Type = BURN_FILE_SEARCH_TYPE_EXISTS;
153 } 153 }
154 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"version", -1)) 154 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"version", -1, FALSE))
155 { 155 {
156 pSearch->FileSearch.Type = BURN_FILE_SEARCH_TYPE_VERSION; 156 pSearch->FileSearch.Type = BURN_FILE_SEARCH_TYPE_VERSION;
157 } 157 }
158 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"path", -1)) 158 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"path", -1, FALSE))
159 { 159 {
160 pSearch->FileSearch.Type = BURN_FILE_SEARCH_TYPE_PATH; 160 pSearch->FileSearch.Type = BURN_FILE_SEARCH_TYPE_PATH;
161 } 161 }
@@ -164,7 +164,7 @@ extern "C" HRESULT SearchesParseFromXml(
164 ExitWithRootFailure(hr, E_INVALIDARG, "Invalid value for @Type: %ls", scz); 164 ExitWithRootFailure(hr, E_INVALIDARG, "Invalid value for @Type: %ls", scz);
165 } 165 }
166 } 166 }
167 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrNodeName, -1, L"RegistrySearch", -1)) 167 else if (CSTR_EQUAL == ::CompareStringOrdinal(bstrNodeName, -1, L"RegistrySearch", -1, FALSE))
168 { 168 {
169 pSearch->Type = BURN_SEARCH_TYPE_REGISTRY; 169 pSearch->Type = BURN_SEARCH_TYPE_REGISTRY;
170 170
@@ -172,19 +172,19 @@ extern "C" HRESULT SearchesParseFromXml(
172 hr = XmlGetAttributeEx(pixnNode, L"Root", &scz); 172 hr = XmlGetAttributeEx(pixnNode, L"Root", &scz);
173 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Root."); 173 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Root.");
174 174
175 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"HKCR", -1)) 175 if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"HKCR", -1, FALSE))
176 { 176 {
177 pSearch->RegistrySearch.hRoot = HKEY_CLASSES_ROOT; 177 pSearch->RegistrySearch.hRoot = HKEY_CLASSES_ROOT;
178 } 178 }
179 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"HKCU", -1)) 179 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"HKCU", -1, FALSE))
180 { 180 {
181 pSearch->RegistrySearch.hRoot = HKEY_CURRENT_USER; 181 pSearch->RegistrySearch.hRoot = HKEY_CURRENT_USER;
182 } 182 }
183 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"HKLM", -1)) 183 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"HKLM", -1, FALSE))
184 { 184 {
185 pSearch->RegistrySearch.hRoot = HKEY_LOCAL_MACHINE; 185 pSearch->RegistrySearch.hRoot = HKEY_LOCAL_MACHINE;
186 } 186 }
187 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"HKU", -1)) 187 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"HKU", -1, FALSE))
188 { 188 {
189 pSearch->RegistrySearch.hRoot = HKEY_USERS; 189 pSearch->RegistrySearch.hRoot = HKEY_USERS;
190 } 190 }
@@ -208,11 +208,11 @@ extern "C" HRESULT SearchesParseFromXml(
208 hr = XmlGetYesNoAttribute(pixnNode, L"Win64", &pSearch->RegistrySearch.fWin64); 208 hr = XmlGetYesNoAttribute(pixnNode, L"Win64", &pSearch->RegistrySearch.fWin64);
209 ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get Win64 attribute."); 209 ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get Win64 attribute.");
210 210
211 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"exists", -1)) 211 if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"exists", -1, FALSE))
212 { 212 {
213 pSearch->RegistrySearch.Type = BURN_REGISTRY_SEARCH_TYPE_EXISTS; 213 pSearch->RegistrySearch.Type = BURN_REGISTRY_SEARCH_TYPE_EXISTS;
214 } 214 }
215 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"value", -1)) 215 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"value", -1, FALSE))
216 { 216 {
217 pSearch->RegistrySearch.Type = BURN_REGISTRY_SEARCH_TYPE_VALUE; 217 pSearch->RegistrySearch.Type = BURN_REGISTRY_SEARCH_TYPE_VALUE;
218 218
@@ -224,19 +224,19 @@ extern "C" HRESULT SearchesParseFromXml(
224 hr = XmlGetAttributeEx(pixnNode, L"VariableType", &scz); 224 hr = XmlGetAttributeEx(pixnNode, L"VariableType", &scz);
225 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @VariableType."); 225 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @VariableType.");
226 226
227 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"formatted", -1)) 227 if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"formatted", -1, FALSE))
228 { 228 {
229 pSearch->RegistrySearch.VariableType = BURN_VARIANT_TYPE_FORMATTED; 229 pSearch->RegistrySearch.VariableType = BURN_VARIANT_TYPE_FORMATTED;
230 } 230 }
231 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"numeric", -1)) 231 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"numeric", -1, FALSE))
232 { 232 {
233 pSearch->RegistrySearch.VariableType = BURN_VARIANT_TYPE_NUMERIC; 233 pSearch->RegistrySearch.VariableType = BURN_VARIANT_TYPE_NUMERIC;
234 } 234 }
235 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"string", -1)) 235 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"string", -1, FALSE))
236 { 236 {
237 pSearch->RegistrySearch.VariableType = BURN_VARIANT_TYPE_STRING; 237 pSearch->RegistrySearch.VariableType = BURN_VARIANT_TYPE_STRING;
238 } 238 }
239 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"version", -1)) 239 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"version", -1, FALSE))
240 { 240 {
241 pSearch->RegistrySearch.VariableType = BURN_VARIANT_TYPE_VERSION; 241 pSearch->RegistrySearch.VariableType = BURN_VARIANT_TYPE_VERSION;
242 } 242 }
@@ -250,7 +250,7 @@ extern "C" HRESULT SearchesParseFromXml(
250 ExitWithRootFailure(hr, E_INVALIDARG, "Invalid value for @Type: %ls", scz); 250 ExitWithRootFailure(hr, E_INVALIDARG, "Invalid value for @Type: %ls", scz);
251 } 251 }
252 } 252 }
253 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrNodeName, -1, L"MsiComponentSearch", -1)) 253 else if (CSTR_EQUAL == ::CompareStringOrdinal(bstrNodeName, -1, L"MsiComponentSearch", -1, FALSE))
254 { 254 {
255 pSearch->Type = BURN_SEARCH_TYPE_MSI_COMPONENT; 255 pSearch->Type = BURN_SEARCH_TYPE_MSI_COMPONENT;
256 256
@@ -266,15 +266,15 @@ extern "C" HRESULT SearchesParseFromXml(
266 hr = XmlGetAttributeEx(pixnNode, L"Type", &scz); 266 hr = XmlGetAttributeEx(pixnNode, L"Type", &scz);
267 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Type."); 267 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Type.");
268 268
269 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"keyPath", -1)) 269 if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"keyPath", -1, FALSE))
270 { 270 {
271 pSearch->MsiComponentSearch.Type = BURN_MSI_COMPONENT_SEARCH_TYPE_KEYPATH; 271 pSearch->MsiComponentSearch.Type = BURN_MSI_COMPONENT_SEARCH_TYPE_KEYPATH;
272 } 272 }
273 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"state", -1)) 273 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"state", -1, FALSE))
274 { 274 {
275 pSearch->MsiComponentSearch.Type = BURN_MSI_COMPONENT_SEARCH_TYPE_STATE; 275 pSearch->MsiComponentSearch.Type = BURN_MSI_COMPONENT_SEARCH_TYPE_STATE;
276 } 276 }
277 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"directory", -1)) 277 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"directory", -1, FALSE))
278 { 278 {
279 pSearch->MsiComponentSearch.Type = BURN_MSI_COMPONENT_SEARCH_TYPE_DIRECTORY; 279 pSearch->MsiComponentSearch.Type = BURN_MSI_COMPONENT_SEARCH_TYPE_DIRECTORY;
280 } 280 }
@@ -283,7 +283,7 @@ extern "C" HRESULT SearchesParseFromXml(
283 ExitWithRootFailure(hr, E_INVALIDARG, "Invalid value for @Type: %ls", scz); 283 ExitWithRootFailure(hr, E_INVALIDARG, "Invalid value for @Type: %ls", scz);
284 } 284 }
285 } 285 }
286 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrNodeName, -1, L"MsiProductSearch", -1)) 286 else if (CSTR_EQUAL == ::CompareStringOrdinal(bstrNodeName, -1, L"MsiProductSearch", -1, FALSE))
287 { 287 {
288 pSearch->Type = BURN_SEARCH_TYPE_MSI_PRODUCT; 288 pSearch->Type = BURN_SEARCH_TYPE_MSI_PRODUCT;
289 pSearch->MsiProductSearch.GuidType = BURN_MSI_PRODUCT_SEARCH_GUID_TYPE_NONE; 289 pSearch->MsiProductSearch.GuidType = BURN_MSI_PRODUCT_SEARCH_GUID_TYPE_NONE;
@@ -318,28 +318,32 @@ extern "C" HRESULT SearchesParseFromXml(
318 hr = XmlGetAttributeEx(pixnNode, L"Type", &scz); 318 hr = XmlGetAttributeEx(pixnNode, L"Type", &scz);
319 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Type."); 319 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Type.");
320 320
321 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"version", -1)) 321 if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"version", -1, FALSE))
322 { 322 {
323 pSearch->MsiProductSearch.Type = BURN_MSI_PRODUCT_SEARCH_TYPE_VERSION; 323 pSearch->MsiProductSearch.Type = BURN_MSI_PRODUCT_SEARCH_TYPE_VERSION;
324 } 324 }
325 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"language", -1)) 325 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"language", -1, FALSE))
326 { 326 {
327 pSearch->MsiProductSearch.Type = BURN_MSI_PRODUCT_SEARCH_TYPE_LANGUAGE; 327 pSearch->MsiProductSearch.Type = BURN_MSI_PRODUCT_SEARCH_TYPE_LANGUAGE;
328 } 328 }
329 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"state", -1)) 329 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"state", -1, FALSE))
330 { 330 {
331 pSearch->MsiProductSearch.Type = BURN_MSI_PRODUCT_SEARCH_TYPE_STATE; 331 pSearch->MsiProductSearch.Type = BURN_MSI_PRODUCT_SEARCH_TYPE_STATE;
332 } 332 }
333 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"assignment", -1)) 333 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"assignment", -1, FALSE))
334 { 334 {
335 pSearch->MsiProductSearch.Type = BURN_MSI_PRODUCT_SEARCH_TYPE_ASSIGNMENT; 335 pSearch->MsiProductSearch.Type = BURN_MSI_PRODUCT_SEARCH_TYPE_ASSIGNMENT;
336 } 336 }
337 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"exists", -1, FALSE))
338 {
339 pSearch->MsiProductSearch.Type = BURN_MSI_PRODUCT_SEARCH_TYPE_EXISTS;
340 }
337 else 341 else
338 { 342 {
339 ExitWithRootFailure(hr, E_INVALIDARG, "Invalid value for @Type: %ls", scz); 343 ExitWithRootFailure(hr, E_INVALIDARG, "Invalid value for @Type: %ls", scz);
340 } 344 }
341 } 345 }
342 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrNodeName, -1, L"ExtensionSearch", -1)) 346 else if (CSTR_EQUAL == ::CompareStringOrdinal(bstrNodeName, -1, L"ExtensionSearch", -1, FALSE))
343 { 347 {
344 pSearch->Type = BURN_SEARCH_TYPE_EXTENSION; 348 pSearch->Type = BURN_SEARCH_TYPE_EXTENSION;
345 349
@@ -350,7 +354,7 @@ extern "C" HRESULT SearchesParseFromXml(
350 hr = BurnExtensionFindById(pBurnExtensions, scz, &pSearch->ExtensionSearch.pExtension); 354 hr = BurnExtensionFindById(pBurnExtensions, scz, &pSearch->ExtensionSearch.pExtension);
351 ExitOnRootFailure(hr, "Failed to find extension '%ls' for search '%ls'", scz, pSearch->sczKey); 355 ExitOnRootFailure(hr, "Failed to find extension '%ls' for search '%ls'", scz, pSearch->sczKey);
352 } 356 }
353 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrNodeName, -1, L"SetVariable", -1)) 357 else if (CSTR_EQUAL == ::CompareStringOrdinal(bstrNodeName, -1, L"SetVariable", -1, FALSE))
354 { 358 {
355 pSearch->Type = BURN_SEARCH_TYPE_SET_VARIABLE; 359 pSearch->Type = BURN_SEARCH_TYPE_SET_VARIABLE;
356 360
@@ -367,19 +371,19 @@ extern "C" HRESULT SearchesParseFromXml(
367 hr = XmlGetAttributeEx(pixnNode, L"Type", &scz); 371 hr = XmlGetAttributeEx(pixnNode, L"Type", &scz);
368 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Type."); 372 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Type.");
369 373
370 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"formatted", -1)) 374 if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"formatted", -1, FALSE))
371 { 375 {
372 pSearch->SetVariable.targetType = BURN_VARIANT_TYPE_FORMATTED; 376 pSearch->SetVariable.targetType = BURN_VARIANT_TYPE_FORMATTED;
373 } 377 }
374 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"numeric", -1)) 378 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"numeric", -1, FALSE))
375 { 379 {
376 pSearch->SetVariable.targetType = BURN_VARIANT_TYPE_NUMERIC; 380 pSearch->SetVariable.targetType = BURN_VARIANT_TYPE_NUMERIC;
377 } 381 }
378 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"string", -1)) 382 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"string", -1, FALSE))
379 { 383 {
380 pSearch->SetVariable.targetType = BURN_VARIANT_TYPE_STRING; 384 pSearch->SetVariable.targetType = BURN_VARIANT_TYPE_STRING;
381 } 385 }
382 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"version", -1)) 386 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"version", -1, FALSE))
383 { 387 {
384 pSearch->SetVariable.targetType = BURN_VARIANT_TYPE_VERSION; 388 pSearch->SetVariable.targetType = BURN_VARIANT_TYPE_VERSION;
385 } 389 }
@@ -1144,6 +1148,7 @@ static HRESULT MsiProductSearch(
1144 case BURN_MSI_PRODUCT_SEARCH_TYPE_LANGUAGE: 1148 case BURN_MSI_PRODUCT_SEARCH_TYPE_LANGUAGE:
1145 wzProperty = INSTALLPROPERTY_LANGUAGE; 1149 wzProperty = INSTALLPROPERTY_LANGUAGE;
1146 break; 1150 break;
1151 case BURN_MSI_PRODUCT_SEARCH_TYPE_EXISTS: __fallthrough;
1147 case BURN_MSI_PRODUCT_SEARCH_TYPE_STATE: 1152 case BURN_MSI_PRODUCT_SEARCH_TYPE_STATE:
1148 wzProperty = INSTALLPROPERTY_PRODUCTSTATE; 1153 wzProperty = INSTALLPROPERTY_PRODUCTSTATE;
1149 break; 1154 break;
@@ -1218,6 +1223,7 @@ static HRESULT MsiProductSearch(
1218 case BURN_MSI_PRODUCT_SEARCH_TYPE_LANGUAGE: 1223 case BURN_MSI_PRODUCT_SEARCH_TYPE_LANGUAGE:
1219 // is supposed to remain empty 1224 // is supposed to remain empty
1220 break; 1225 break;
1226 case BURN_MSI_PRODUCT_SEARCH_TYPE_EXISTS: __fallthrough;
1221 case BURN_MSI_PRODUCT_SEARCH_TYPE_STATE: 1227 case BURN_MSI_PRODUCT_SEARCH_TYPE_STATE:
1222 value.Type = BURN_VARIANT_TYPE_NUMERIC; 1228 value.Type = BURN_VARIANT_TYPE_NUMERIC;
1223 value.llValue = INSTALLSTATE_ABSENT; 1229 value.llValue = INSTALLSTATE_ABSENT;
@@ -1237,6 +1243,7 @@ static HRESULT MsiProductSearch(
1237 case BURN_MSI_PRODUCT_SEARCH_TYPE_LANGUAGE: 1243 case BURN_MSI_PRODUCT_SEARCH_TYPE_LANGUAGE:
1238 type = BURN_VARIANT_TYPE_STRING; 1244 type = BURN_VARIANT_TYPE_STRING;
1239 break; 1245 break;
1246 case BURN_MSI_PRODUCT_SEARCH_TYPE_EXISTS: __fallthrough;
1240 case BURN_MSI_PRODUCT_SEARCH_TYPE_STATE: __fallthrough; 1247 case BURN_MSI_PRODUCT_SEARCH_TYPE_STATE: __fallthrough;
1241 case BURN_MSI_PRODUCT_SEARCH_TYPE_ASSIGNMENT: 1248 case BURN_MSI_PRODUCT_SEARCH_TYPE_ASSIGNMENT:
1242 type = BURN_VARIANT_TYPE_NUMERIC; 1249 type = BURN_VARIANT_TYPE_NUMERIC;
@@ -1245,6 +1252,13 @@ static HRESULT MsiProductSearch(
1245 hr = BVariantChangeType(&value, type); 1252 hr = BVariantChangeType(&value, type);
1246 ExitOnFailure(hr, "Failed to change value type."); 1253 ExitOnFailure(hr, "Failed to change value type.");
1247 1254
1255 // When testing if a product exists, replace the value with a numeric "true" or "false"
1256 // based on the calculated install state.
1257 if (BURN_MSI_PRODUCT_SEARCH_TYPE_EXISTS == pSearch->MsiProductSearch.Type)
1258 {
1259 value.llValue = (value.llValue == INSTALLSTATE_ABSENT) ? 0 : 1;
1260 }
1261
1248 // Set variable. 1262 // Set variable.
1249 hr = VariableSetVariant(pVariables, pSearch->sczVariable, &value); 1263 hr = VariableSetVariant(pVariables, pSearch->sczVariable, &value);
1250 ExitOnFailure(hr, "Failed to set variable."); 1264 ExitOnFailure(hr, "Failed to set variable.");
diff --git a/src/burn/engine/search.h b/src/burn/engine/search.h
index 341fe1aa..e70645c5 100644
--- a/src/burn/engine/search.h
+++ b/src/burn/engine/search.h
@@ -58,6 +58,7 @@ enum BURN_MSI_PRODUCT_SEARCH_TYPE
58 BURN_MSI_PRODUCT_SEARCH_TYPE_LANGUAGE, 58 BURN_MSI_PRODUCT_SEARCH_TYPE_LANGUAGE,
59 BURN_MSI_PRODUCT_SEARCH_TYPE_STATE, 59 BURN_MSI_PRODUCT_SEARCH_TYPE_STATE,
60 BURN_MSI_PRODUCT_SEARCH_TYPE_ASSIGNMENT, 60 BURN_MSI_PRODUCT_SEARCH_TYPE_ASSIGNMENT,
61 BURN_MSI_PRODUCT_SEARCH_TYPE_EXISTS,
61}; 62};
62 63
63enum BURN_MSI_PRODUCT_SEARCH_GUID_TYPE 64enum BURN_MSI_PRODUCT_SEARCH_GUID_TYPE
diff --git a/src/burn/engine/splashscreen.cpp b/src/burn/engine/splashscreen.cpp
index 0bfa00aa..21ddfa98 100644
--- a/src/burn/engine/splashscreen.cpp
+++ b/src/burn/engine/splashscreen.cpp
@@ -371,6 +371,7 @@ static void OnEraseBkgnd(
371 HDC hdc = reinterpret_cast<HDC>(wParam); 371 HDC hdc = reinterpret_cast<HDC>(wParam);
372 HDC hdcMem = ::CreateCompatibleDC(hdc); 372 HDC hdcMem = ::CreateCompatibleDC(hdc);
373 HBITMAP hDefaultBitmap = static_cast<HBITMAP>(::SelectObject(hdcMem, pSplashScreen->hBitmap)); 373 HBITMAP hDefaultBitmap = static_cast<HBITMAP>(::SelectObject(hdcMem, pSplashScreen->hBitmap));
374 ::SetStretchBltMode(hdc, HALFTONE);
374 ::StretchBlt(hdc, 0, 0, pSplashScreen->size.cx, pSplashScreen->size.cy, hdcMem, 0, 0, pSplashScreen->defaultDpiSize.cx, pSplashScreen->defaultDpiSize.cy, SRCCOPY); 375 ::StretchBlt(hdc, 0, 0, pSplashScreen->size.cx, pSplashScreen->size.cy, hdcMem, 0, 0, pSplashScreen->defaultDpiSize.cx, pSplashScreen->defaultDpiSize.cy, SRCCOPY);
375 ::SelectObject(hdcMem, hDefaultBitmap); 376 ::SelectObject(hdcMem, hDefaultBitmap);
376 ::DeleteDC(hdcMem); 377 ::DeleteDC(hdcMem);
diff --git a/src/burn/engine/variable.cpp b/src/burn/engine/variable.cpp
index 9d0aec52..a795d76c 100644
--- a/src/burn/engine/variable.cpp
+++ b/src/burn/engine/variable.cpp
@@ -397,7 +397,7 @@ extern "C" HRESULT VariablesParseFromXml(
397 hr = XmlGetAttributeEx(pixnNode, L"Type", &scz); 397 hr = XmlGetAttributeEx(pixnNode, L"Type", &scz);
398 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Type."); 398 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Type.");
399 399
400 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"formatted", -1)) 400 if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"formatted", -1, FALSE))
401 { 401 {
402 if (!fHidden) 402 if (!fHidden)
403 { 403 {
@@ -405,7 +405,7 @@ extern "C" HRESULT VariablesParseFromXml(
405 } 405 }
406 valueType = BURN_VARIANT_TYPE_FORMATTED; 406 valueType = BURN_VARIANT_TYPE_FORMATTED;
407 } 407 }
408 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"numeric", -1)) 408 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"numeric", -1, FALSE))
409 { 409 {
410 if (!fHidden) 410 if (!fHidden)
411 { 411 {
@@ -413,7 +413,7 @@ extern "C" HRESULT VariablesParseFromXml(
413 } 413 }
414 valueType = BURN_VARIANT_TYPE_NUMERIC; 414 valueType = BURN_VARIANT_TYPE_NUMERIC;
415 } 415 }
416 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"string", -1)) 416 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"string", -1, FALSE))
417 { 417 {
418 if (!fHidden) 418 if (!fHidden)
419 { 419 {
@@ -421,7 +421,7 @@ extern "C" HRESULT VariablesParseFromXml(
421 } 421 }
422 valueType = BURN_VARIANT_TYPE_STRING; 422 valueType = BURN_VARIANT_TYPE_STRING;
423 } 423 }
424 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"version", -1)) 424 else if (CSTR_EQUAL == ::CompareStringOrdinal(scz, -1, L"version", -1, FALSE))
425 { 425 {
426 if (!fHidden) 426 if (!fHidden)
427 { 427 {
@@ -1144,7 +1144,7 @@ extern "C" BOOL VariableIsHiddenCommandLine(
1144 { 1144 {
1145 pVariable = pVariables->rgVariables + i; 1145 pVariable = pVariables->rgVariables + i;
1146 1146
1147 if (pVariable->fHidden && CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pVariable->sczName, -1, wzVariable, -1)) 1147 if (pVariable->fHidden && CSTR_EQUAL == ::CompareStringOrdinal(pVariable->sczName, -1, wzVariable, -1, TRUE))
1148 { 1148 {
1149 fHidden = TRUE; 1149 fHidden = TRUE;
1150 break; 1150 break;
@@ -1556,7 +1556,7 @@ static HRESULT FindVariableIndexByName(
1556 DWORD iPosition = cRangeLength / 2; 1556 DWORD iPosition = cRangeLength / 2;
1557 BURN_VARIABLE* pVariable = &pVariables->rgVariables[iRangeFirst + iPosition]; 1557 BURN_VARIABLE* pVariable = &pVariables->rgVariables[iRangeFirst + iPosition];
1558 1558
1559 switch (::CompareStringW(LOCALE_INVARIANT, SORT_STRINGSORT, wzVariable, -1, pVariable->sczName, -1)) 1559 switch (::CompareStringOrdinal(wzVariable, -1, pVariable->sczName, -1, FALSE))
1560 { 1560 {
1561 case CSTR_LESS_THAN: 1561 case CSTR_LESS_THAN:
1562 // restrict range to elements before the current 1562 // restrict range to elements before the current
@@ -1591,7 +1591,7 @@ static HRESULT InsertUserVariable(
1591{ 1591{
1592 HRESULT hr = S_OK; 1592 HRESULT hr = S_OK;
1593 1593
1594 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, wzVariable, 3, L"Wix", 3)) 1594 if (CSTR_EQUAL == ::CompareStringOrdinal(wzVariable, 3, L"Wix", 3, FALSE))
1595 { 1595 {
1596 ExitWithRootFailure(hr, E_INVALIDARG, "Attempted to insert variable with reserved prefix: %ls", wzVariable); 1596 ExitWithRootFailure(hr, E_INVALIDARG, "Attempted to insert variable with reserved prefix: %ls", wzVariable);
1597 } 1597 }
diff --git a/src/burn/engine/variant.cpp b/src/burn/engine/variant.cpp
index 2267ee7b..3fc02aa8 100644
--- a/src/burn/engine/variant.cpp
+++ b/src/burn/engine/variant.cpp
@@ -10,6 +10,9 @@ static HRESULT GetVersionInternal(
10 __in BOOL fSilent, 10 __in BOOL fSilent,
11 __out VERUTIL_VERSION** ppValue 11 __out VERUTIL_VERSION** ppValue
12 ); 12 );
13static void FreeVariantValue(
14 __in BURN_VARIANT* pVariant
15 );
13 16
14// function definitions 17// function definitions
15 18
@@ -17,12 +20,7 @@ extern "C" void BVariantUninitialize(
17 __in BURN_VARIANT* pVariant 20 __in BURN_VARIANT* pVariant
18 ) 21 )
19{ 22{
20 if (BURN_VARIANT_TYPE_FORMATTED == pVariant->Type || 23 FreeVariantValue(pVariant);
21 BURN_VARIANT_TYPE_STRING == pVariant->Type)
22 {
23 StrSecureZeroFreeString(pVariant->sczValue);
24 }
25 SecureZeroMemory(pVariant, sizeof(BURN_VARIANT));
26} 24}
27 25
28extern "C" HRESULT BVariantGetNumeric( 26extern "C" HRESULT BVariantGetNumeric(
@@ -164,12 +162,8 @@ extern "C" HRESULT BVariantSetNumeric(
164{ 162{
165 HRESULT hr = S_OK; 163 HRESULT hr = S_OK;
166 164
167 if (BURN_VARIANT_TYPE_FORMATTED == pVariant->Type || 165 FreeVariantValue(pVariant);
168 BURN_VARIANT_TYPE_STRING == pVariant->Type) 166
169 {
170 StrSecureZeroFreeString(pVariant->sczValue);
171 }
172 memset(pVariant, 0, sizeof(BURN_VARIANT));
173 pVariant->llValue = llValue; 167 pVariant->llValue = llValue;
174 pVariant->Type = BURN_VARIANT_TYPE_NUMERIC; 168 pVariant->Type = BURN_VARIANT_TYPE_NUMERIC;
175 169
@@ -194,7 +188,7 @@ extern "C" HRESULT BVariantSetString(
194 if (BURN_VARIANT_TYPE_FORMATTED != pVariant->Type && 188 if (BURN_VARIANT_TYPE_FORMATTED != pVariant->Type &&
195 BURN_VARIANT_TYPE_STRING != pVariant->Type) 189 BURN_VARIANT_TYPE_STRING != pVariant->Type)
196 { 190 {
197 memset(pVariant, 0, sizeof(BURN_VARIANT)); 191 FreeVariantValue(pVariant);
198 } 192 }
199 193
200 hr = StrAllocStringSecure(&pVariant->sczValue, wzValue, cchValue); 194 hr = StrAllocStringSecure(&pVariant->sczValue, wzValue, cchValue);
@@ -220,12 +214,8 @@ extern "C" HRESULT BVariantSetVersion(
220 } 214 }
221 else // assign the value. 215 else // assign the value.
222 { 216 {
223 if (BURN_VARIANT_TYPE_FORMATTED == pVariant->Type || 217 FreeVariantValue(pVariant);
224 BURN_VARIANT_TYPE_STRING == pVariant->Type) 218
225 {
226 StrSecureZeroFreeString(pVariant->sczValue);
227 }
228 memset(pVariant, 0, sizeof(BURN_VARIANT));
229 hr = VerCopyVersion(pValue, &pVariant->pValue); 219 hr = VerCopyVersion(pValue, &pVariant->pValue);
230 pVariant->Type = BURN_VARIANT_TYPE_VERSION; 220 pVariant->Type = BURN_VARIANT_TYPE_VERSION;
231 } 221 }
@@ -319,3 +309,20 @@ extern "C" HRESULT BVariantChangeType(
319LExit: 309LExit:
320 return hr; 310 return hr;
321} 311}
312
313static void FreeVariantValue(
314 __in BURN_VARIANT* pVariant
315 )
316{
317 if ((BURN_VARIANT_TYPE_FORMATTED == pVariant->Type || BURN_VARIANT_TYPE_STRING == pVariant->Type) &&
318 pVariant->sczValue)
319 {
320 StrSecureZeroFreeString(pVariant->sczValue);
321 }
322 else if (BURN_VARIANT_TYPE_VERSION == pVariant->Type && pVariant->pValue)
323 {
324 VerFreeVersion(pVariant->pValue);
325 }
326
327 SecureZeroMemory(pVariant, sizeof(BURN_VARIANT));
328}
diff --git a/src/burn/stub/WixToolset.Burn.props b/src/burn/stub/WixToolset.Burn.props
index 38cd333e..debcffd0 100644
--- a/src/burn/stub/WixToolset.Burn.props
+++ b/src/burn/stub/WixToolset.Burn.props
@@ -1,7 +1,7 @@
1<?xml version="1.0" encoding="utf-8"?> 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. --> 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 3
4<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0"> 4<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
5 <ItemGroup> 5 <ItemGroup>
6 <BurnExes Include="$(MSBuildThisFileDirectory)..\tools\**\burn.exe" /> 6 <BurnExes Include="$(MSBuildThisFileDirectory)..\tools\**\burn.exe" />
7 <None Include="@(BurnExes)"> 7 <None Include="@(BurnExes)">
diff --git a/src/burn/stub/precomp.h b/src/burn/stub/precomp.h
index 46239a6c..b72cd012 100644
--- a/src/burn/stub/precomp.h
+++ b/src/burn/stub/precomp.h
@@ -13,6 +13,7 @@
13#include <strutil.h> 13#include <strutil.h>
14#include <fileutil.h> 14#include <fileutil.h>
15#include <pathutil.h> 15#include <pathutil.h>
16#include <polcutil.h>
16#include <logutil.h> 17#include <logutil.h>
17 18
18#include "engine.h" 19#include "engine.h"
diff --git a/src/burn/stub/stub.cpp b/src/burn/stub/stub.cpp
index d8cee9f1..ea5d88f0 100644
--- a/src/burn/stub/stub.cpp
+++ b/src/burn/stub/stub.cpp
@@ -34,6 +34,8 @@ int WINAPI wWinMain(
34 L"feclient.dll", // unsafely loaded by DecryptFile(). 34 L"feclient.dll", // unsafely loaded by DecryptFile().
35 }; 35 };
36 36
37 AppSetDefaultProcessMitigationPolicy(POLICY_BURN_REGISTRY_PATH);
38
37 // Best effort attempt to get our file handle as soon as possible. 39 // Best effort attempt to get our file handle as soon as possible.
38 hr = PathForCurrentProcess(&sczPath, NULL); 40 hr = PathForCurrentProcess(&sczPath, NULL);
39 if (SUCCEEDED(hr)) 41 if (SUCCEEDED(hr))
diff --git a/src/burn/stub/stub.vcxproj b/src/burn/stub/stub.vcxproj
index d07b8da7..54825b95 100644
--- a/src/burn/stub/stub.vcxproj
+++ b/src/burn/stub/stub.vcxproj
@@ -1,7 +1,7 @@
1<?xml version="1.0" encoding="utf-8"?> 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. --> 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 3
4<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 4<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
5 <ItemGroup Label="ProjectConfigurations"> 5 <ItemGroup Label="ProjectConfigurations">
6 <ProjectConfiguration Include="Debug|Win32"> 6 <ProjectConfiguration Include="Debug|Win32">
7 <Configuration>Debug</Configuration> 7 <Configuration>Debug</Configuration>
diff --git a/src/burn/test/BurnUnitTest/ApprovedExeTest.cpp b/src/burn/test/BurnUnitTest/ApprovedExeTest.cpp
new file mode 100644
index 00000000..da51f1f8
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/ApprovedExeTest.cpp
@@ -0,0 +1,312 @@
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
5namespace Microsoft
6{
7namespace Tools
8{
9namespace WindowsInstallerXml
10{
11namespace Test
12{
13namespace Bootstrapper
14{
15 using namespace System;
16 using namespace System::IO;
17 using namespace Xunit;
18
19 public ref class ApprovedExeTest : BurnUnitTest
20 {
21 public:
22 ApprovedExeTest(BurnTestFixture^ fixture) : BurnUnitTest(fixture)
23 {
24 }
25
26 [Fact]
27 void ApprovedExesVerifyPFilesTest()
28 {
29 HRESULT hr = S_OK;
30 BURN_CACHE cache = { };
31 BURN_ENGINE_COMMAND internalCommand = { };
32 BURN_VARIABLES variables = { };
33 LPWSTR scz = NULL;
34 LPWSTR scz2 = NULL;
35
36 try
37 {
38 hr = VariableInitialize(&variables);
39 NativeAssert::Succeeded(hr, L"Failed to initialize variables.");
40
41 hr = CacheInitialize(&cache, &internalCommand);
42 NativeAssert::Succeeded(hr, "Failed to initialize cache.");
43
44 hr = VariableGetString(&variables, L"ProgramFilesFolder", &scz);
45 NativeAssert::Succeeded(hr, "Failed to get variable ProgramFilesFolder.");
46
47 hr = PathConcat(scz, L"a.exe", &scz2);
48 NativeAssert::Succeeded(hr, "Failed to combine paths");
49
50 hr = ApprovedExesVerifySecureLocation(&cache, &variables, scz2, 0, NULL);
51 NativeAssert::Succeeded(hr, "Failed to test secure location under ProgramFilesFolder");
52 Assert::True((hr == S_OK), "Path under ProgramFilesFolder was expected to be safe");
53 }
54 finally
55 {
56 ReleaseStr(internalCommand.sczEngineWorkingDirectory);
57 ReleaseStr(scz);
58 ReleaseStr(scz2);
59
60 CacheUninitialize(&cache);
61 VariablesUninitialize(&variables);
62 }
63 }
64
65 [Fact]
66 void ApprovedExesVerifyPFilesWithRelativeTest()
67 {
68 HRESULT hr = S_OK;
69 BURN_CACHE cache = { };
70 BURN_ENGINE_COMMAND internalCommand = { };
71 BURN_VARIABLES variables = { };
72 LPWSTR scz = NULL;
73 LPWSTR scz2 = NULL;
74
75 try
76 {
77 hr = VariableInitialize(&variables);
78 NativeAssert::Succeeded(hr, L"Failed to initialize variables.");
79
80 hr = CacheInitialize(&cache, &internalCommand);
81 NativeAssert::Succeeded(hr, "Failed to initialize cache.");
82 cache.fPerMachineCacheRootVerified = TRUE;
83 cache.fOriginalPerMachineCacheRootVerified = TRUE;
84
85 hr = VariableGetString(&variables, L"ProgramFilesFolder", &scz);
86 NativeAssert::Succeeded(hr, "Failed to get variable ProgramFilesFolder.");
87
88 hr = PathConcat(scz, L"..\\a.exe", &scz2);
89 NativeAssert::Succeeded(hr, "Failed to combine paths");
90
91 hr = ApprovedExesVerifySecureLocation(&cache, &variables, scz2, 0, NULL);
92 NativeAssert::Succeeded(hr, "Failed to test secure location under ProgramFilesFolder");
93 Assert::True((hr == S_FALSE), "Path pretending to be under ProgramFilesFolder was expected to be unsafe");
94 }
95 finally
96 {
97 ReleaseStr(internalCommand.sczEngineWorkingDirectory);
98 ReleaseStr(scz);
99 ReleaseStr(scz2);
100
101 CacheUninitialize(&cache);
102 VariablesUninitialize(&variables);
103 }
104 }
105
106 [Fact]
107 void ApprovedExesVerifyPFiles64Test()
108 {
109 HRESULT hr = S_OK;
110 BURN_CACHE cache = { };
111 BURN_ENGINE_COMMAND internalCommand = { };
112 BURN_VARIABLES variables = { };
113 LPWSTR scz = NULL;
114 LPWSTR scz2 = NULL;
115
116 try
117 {
118 hr = VariableInitialize(&variables);
119 NativeAssert::Succeeded(hr, L"Failed to initialize variables.");
120
121 hr = CacheInitialize(&cache, &internalCommand);
122 NativeAssert::Succeeded(hr, "Failed to initialize cache.");
123
124 hr = VariableGetString(&variables, L"ProgramFiles64Folder", &scz);
125 NativeAssert::Succeeded(hr, "Failed to get variable ProgramFiles64Folder.");
126
127 hr = PathConcat(scz, L"a.exe", &scz2);
128 NativeAssert::Succeeded(hr, "Failed to combine paths");
129
130 hr = ApprovedExesVerifySecureLocation(&cache, &variables, scz2, 0, NULL);
131 NativeAssert::Succeeded(hr, "Failed to test secure location under ProgramFiles64Folder");
132 Assert::True((hr == S_OK), "Path under ProgramFiles64Folder was expected to be safe");
133 }
134 finally
135 {
136 ReleaseStr(internalCommand.sczEngineWorkingDirectory);
137 ReleaseStr(scz);
138 ReleaseStr(scz2);
139
140 CacheUninitialize(&cache);
141 VariablesUninitialize(&variables);
142 }
143 }
144
145 [Fact]
146 void ApprovedExesVerifySys64FolderTest()
147 {
148 HRESULT hr = S_OK;
149 BURN_CACHE cache = { };
150 BURN_ENGINE_COMMAND internalCommand = { };
151 BURN_VARIABLES variables = { };
152 LPWSTR scz = NULL;
153 LPWSTR scz2 = NULL;
154
155 try
156 {
157 hr = VariableInitialize(&variables);
158 NativeAssert::Succeeded(hr, L"Failed to initialize variables.");
159
160 hr = CacheInitialize(&cache, &internalCommand);
161 NativeAssert::Succeeded(hr, "Failed to initialize cache.");
162 cache.fPerMachineCacheRootVerified = TRUE;
163 cache.fOriginalPerMachineCacheRootVerified = TRUE;
164
165 hr = VariableGetString(&variables, L"System64Folder", &scz);
166 NativeAssert::Succeeded(hr, "Failed to get variable System64Folder.");
167
168 hr = PathConcat(scz, L"a.exe", &scz2);
169 NativeAssert::Succeeded(hr, "Failed to combine paths");
170
171 hr = ApprovedExesVerifySecureLocation(&cache, &variables, scz2, 0, NULL);
172 NativeAssert::Succeeded(hr, "Failed to test secure location under System64Folder");
173 Assert::True((hr == S_FALSE), "Path under System64Folder was expected to be unsafe");
174 }
175 finally
176 {
177 ReleaseStr(internalCommand.sczEngineWorkingDirectory);
178 ReleaseStr(scz);
179 ReleaseStr(scz2);
180
181 CacheUninitialize(&cache);
182 VariablesUninitialize(&variables);
183 }
184 }
185
186 [Fact]
187 void ApprovedExesVerifySys64Rundll32UnsafeTest()
188 {
189 HRESULT hr = S_OK;
190 BURN_CACHE cache = { };
191 BURN_ENGINE_COMMAND internalCommand = { };
192 BURN_VARIABLES variables = { };
193 LPWSTR scz = NULL;
194 LPWSTR scz2 = NULL;
195 LPWSTR szArgs = NULL;
196
197 try
198 {
199 hr = VariableInitialize(&variables);
200 NativeAssert::Succeeded(hr, L"Failed to initialize variables.");
201
202 hr = CacheInitialize(&cache, &internalCommand);
203 NativeAssert::Succeeded(hr, "Failed to initialize cache.");
204 cache.fPerMachineCacheRootVerified = TRUE;
205 cache.fOriginalPerMachineCacheRootVerified = TRUE;
206
207 hr = VariableGetString(&variables, L"System64Folder", &scz);
208 NativeAssert::Succeeded(hr, "Failed to get variable System64Folder.");
209
210 hr = PathConcat(scz, L"rundll32.exe", &scz2);
211 NativeAssert::Succeeded(hr, "Failed to combine paths");
212
213 hr = ApprovedExesVerifySecureLocation(&cache, &variables, scz2, 1, const_cast<LPCWSTR*>(&scz2));
214 NativeAssert::Succeeded(hr, "Failed to test secure location under System64Folder");
215 Assert::True((hr == S_FALSE), "Path under System64Folder was expected to be unsafe for rundll32 target");
216 }
217 finally
218 {
219 ReleaseStr(internalCommand.sczEngineWorkingDirectory);
220 ReleaseStr(scz);
221 ReleaseStr(scz2);
222 ReleaseStr(szArgs);
223
224 CacheUninitialize(&cache);
225 VariablesUninitialize(&variables);
226 }
227 }
228
229 [Fact]
230 void ApprovedExesVerifySys64Rundll32SafeTest()
231 {
232 HRESULT hr = S_OK;
233 BURN_CACHE cache = { };
234 BURN_ENGINE_COMMAND internalCommand = { };
235 BURN_VARIABLES variables = { };
236 LPWSTR scz = NULL;
237 LPWSTR scz2 = NULL;
238 LPWSTR scz3 = NULL;
239
240 try
241 {
242 hr = VariableInitialize(&variables);
243 NativeAssert::Succeeded(hr, L"Failed to initialize variables.");
244
245 hr = CacheInitialize(&cache, &internalCommand);
246 NativeAssert::Succeeded(hr, "Failed to initialize cache.");
247 cache.fPerMachineCacheRootVerified = TRUE;
248 cache.fOriginalPerMachineCacheRootVerified = TRUE;
249
250 // System64Folder
251 hr = VariableGetString(&variables, L"System64Folder", &scz);
252 NativeAssert::Succeeded(hr, "Failed to get variable System64Folder.");
253
254 hr = PathConcat(scz, L"rundll32.exe", &scz2);
255 NativeAssert::Succeeded(hr, "Failed to combine paths");
256
257 hr = VariableGetString(&variables, L"ProgramFiles64Folder", &scz);
258 NativeAssert::Succeeded(hr, "Failed to get variable ProgramFiles64Folder.");
259
260 hr = PathConcat(scz, L"a.dll", &scz3);
261 NativeAssert::Succeeded(hr, "Failed to combine paths");
262
263 hr = ApprovedExesVerifySecureLocation(&cache, &variables, scz2, 1, const_cast<LPCWSTR*>(&scz3));
264 NativeAssert::Succeeded(hr, "Failed to test secure location under ProgramFiles64Folder for System64Folder/rundll32 target");
265 Assert::True((hr == S_OK), "Path under ProgramFiles64Folder was expected to be safe for System64Folder/rundll32 target");
266
267 hr = PathConcat(scz, L"a.dll,somthing else", &scz3);
268 NativeAssert::Succeeded(hr, "Failed to combine paths");
269
270 hr = ApprovedExesVerifySecureLocation(&cache, &variables, scz2, 1, const_cast<LPCWSTR*>(&scz3));
271 NativeAssert::Succeeded(hr, "Failed to test secure location under ProgramFiles64Folder for rundll32 target");
272 Assert::True((hr == S_OK), "Path under ProgramFiles64Folder was expected to be safe for System64Folder/rundll32 target");
273
274 // SystemFolder
275 hr = VariableGetString(&variables, L"SystemFolder", &scz);
276 NativeAssert::Succeeded(hr, "Failed to get variable System64Folder.");
277
278 hr = PathConcat(scz, L"rundll32.exe", &scz2);
279 NativeAssert::Succeeded(hr, "Failed to combine paths");
280
281 hr = ApprovedExesVerifySecureLocation(&cache, &variables, scz2, 1, const_cast<LPCWSTR*>(&scz3));
282 NativeAssert::Succeeded(hr, "Failed to test secure location under ProgramFiles64Folder for SystemFolder/rundll32 target");
283 Assert::True((hr == S_OK), "Path under ProgramFiles64Folder was expected to be safe for SystemFolder/rundll32 target");
284
285 // Sysnative
286 hr = PathSystemWindowsSubdirectory(L"SysNative\\", &scz);
287 NativeAssert::Succeeded(hr, "Failed to get SysNative Folder.");
288
289 hr = PathConcat(scz, L"rundll32.exe", &scz2);
290 NativeAssert::Succeeded(hr, "Failed to combine paths");
291
292 hr = ApprovedExesVerifySecureLocation(&cache, &variables, scz2, 1, const_cast<LPCWSTR*>(&scz3));
293 NativeAssert::Succeeded(hr, "Failed to test secure location under ProgramFiles64Folder for Sysnative/rundll32 target");
294 Assert::True((hr == S_OK), "Path under ProgramFiles64Folder was expected to be safe for Sysnative/rundll32 target");
295 }
296 finally
297 {
298 ReleaseStr(internalCommand.sczEngineWorkingDirectory);
299 ReleaseStr(scz);
300 ReleaseStr(scz2);
301 ReleaseStr(scz3);
302
303 CacheUninitialize(&cache);
304 VariablesUninitialize(&variables);
305 }
306 }
307 };
308}
309}
310}
311}
312}
diff --git a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj
index 331d237b..9704efa5 100644
--- a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj
+++ b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj
@@ -1,7 +1,7 @@
1<?xml version="1.0" encoding="utf-8"?> 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. --> 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 3
4<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 4<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
5 <Import Project="..\..\..\internal\WixInternal.TestSupport.Native\build\WixInternal.TestSupport.Native.props" /> 5 <Import Project="..\..\..\internal\WixInternal.TestSupport.Native\build\WixInternal.TestSupport.Native.props" />
6 6
7 <ItemGroup Label="ProjectConfigurations"> 7 <ItemGroup Label="ProjectConfigurations">
@@ -45,6 +45,7 @@
45 45
46 <ItemGroup> 46 <ItemGroup>
47 <ClCompile Include="AssemblyInfo.cpp" /> 47 <ClCompile Include="AssemblyInfo.cpp" />
48 <ClCompile Include="ApprovedExeTest.cpp" />
48 <ClCompile Include="CacheTest.cpp" /> 49 <ClCompile Include="CacheTest.cpp" />
49 <ClCompile Include="ElevationTest.cpp" /> 50 <ClCompile Include="ElevationTest.cpp" />
50 <ClCompile Include="EmbeddedTest.cpp" /> 51 <ClCompile Include="EmbeddedTest.cpp" />
diff --git a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj.filters b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj.filters
index 82725436..aac5ab8b 100644
--- a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj.filters
+++ b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj.filters
@@ -1,5 +1,5 @@
1<?xml version="1.0" encoding="utf-8"?> 1<?xml version="1.0" encoding="utf-8"?>
2<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 2<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <ItemGroup> 3 <ItemGroup>
4 <Filter Include="Source Files"> 4 <Filter Include="Source Files">
5 <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> 5 <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
@@ -66,6 +66,9 @@
66 <ClCompile Include="VariantTest.cpp"> 66 <ClCompile Include="VariantTest.cpp">
67 <Filter>Source Files</Filter> 67 <Filter>Source Files</Filter>
68 </ClCompile> 68 </ClCompile>
69 <ClCompile Include="ApprovedExeTest.cpp">
70 <Filter>Source Files</Filter>
71 </ClCompile>
69 </ItemGroup> 72 </ItemGroup>
70 <ItemGroup> 73 <ItemGroup>
71 <ClInclude Include="BurnTestException.h"> 74 <ClInclude Include="BurnTestException.h">
@@ -95,4 +98,4 @@
95 <Filter>Resource Files</Filter> 98 <Filter>Resource Files</Filter>
96 </ResourceCompile> 99 </ResourceCompile>
97 </ItemGroup> 100 </ItemGroup>
98</Project> \ No newline at end of file 101</Project>
diff --git a/src/burn/test/BurnUnitTest/PlanTest.cpp b/src/burn/test/BurnUnitTest/PlanTest.cpp
index e426cb09..e2850a62 100644
--- a/src/burn/test/BurnUnitTest/PlanTest.cpp
+++ b/src/burn/test/BurnUnitTest/PlanTest.cpp
@@ -2990,6 +2990,18 @@ namespace Bootstrapper
2990 ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[1], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT); 2990 ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[1], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT);
2991 } 2991 }
2992 2992
2993 [Fact]
2994 void ValidateCacheVariables()
2995 {
2996 BURN_ENGINE_STATE engineState = { };
2997 BURN_ENGINE_STATE* pEngineState = &engineState;
2998
2999 InitializeEngineStateForCorePlan(wzSlipstreamModifiedManifestFileName, pEngineState);
3000
3001 Assert::EndsWith(gcnew String(L".exe"), VariableGetStringHelper(&pEngineState->variables, BURN_BUNDLE_SOURCE_PROCESS_PATH));
3002 Assert::EndsWith(gcnew String(L"\\"), VariableGetStringHelper(&pEngineState->variables, BURN_BUNDLE_SOURCE_PROCESS_FOLDER));
3003 }
3004
2993 private: 3005 private:
2994 // This doesn't initialize everything, just enough for CorePlan to work. 3006 // This doesn't initialize everything, just enough for CorePlan to work.
2995 void InitializeEngineStateForCorePlan(LPCWSTR wzManifestFileName, BURN_ENGINE_STATE* pEngineState) 3007 void InitializeEngineStateForCorePlan(LPCWSTR wzManifestFileName, BURN_ENGINE_STATE* pEngineState)
@@ -3149,12 +3161,12 @@ namespace Bootstrapper
3149 3161
3150 if (pDependencies->fSelfDependent || pDependencies->fActiveParent) 3162 if (pDependencies->fSelfDependent || pDependencies->fActiveParent)
3151 { 3163 {
3152 if (pDependencies->fActiveParent && CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pDependencies->wzActiveParent, -1, wzId, -1)) 3164 if (pDependencies->fActiveParent && CSTR_EQUAL == ::CompareStringOrdinal(pDependencies->wzActiveParent, -1, wzId, -1, TRUE))
3153 { 3165 {
3154 pRegistration->fParentRegisteredAsDependent = TRUE; 3166 pRegistration->fParentRegisteredAsDependent = TRUE;
3155 } 3167 }
3156 3168
3157 if (pDependencies->fSelfDependent && CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pDependencies->wzSelfDependent, -1, wzId, -1)) 3169 if (pDependencies->fSelfDependent && CSTR_EQUAL == ::CompareStringOrdinal(pDependencies->wzSelfDependent, -1, wzId, -1, TRUE))
3158 { 3170 {
3159 pRegistration->fSelfRegisteredAsDependent = TRUE; 3171 pRegistration->fSelfRegisteredAsDependent = TRUE;
3160 } 3172 }
diff --git a/src/burn/test/BurnUnitTest/SearchTest.cpp b/src/burn/test/BurnUnitTest/SearchTest.cpp
index a8e397c2..e3c714cb 100644
--- a/src/burn/test/BurnUnitTest/SearchTest.cpp
+++ b/src/burn/test/BurnUnitTest/SearchTest.cpp
@@ -410,6 +410,8 @@ namespace Bootstrapper
410 L" <MsiProductSearch Id='Search4' Type='state' ProductCode='{600D0000-0000-0000-0000-000000000000}' Variable='Variable4' />" 410 L" <MsiProductSearch Id='Search4' Type='state' ProductCode='{600D0000-0000-0000-0000-000000000000}' Variable='Variable4' />"
411 L" <MsiProductSearch Id='Search5' Type='assignment' ProductCode='{600D0000-0000-0000-0000-000000000000}' Variable='Variable5' />" 411 L" <MsiProductSearch Id='Search5' Type='assignment' ProductCode='{600D0000-0000-0000-0000-000000000000}' Variable='Variable5' />"
412 L" <MsiProductSearch Id='Search6' Type='version' ProductCode='{600D0000-1000-0000-0000-000000000000}' Variable='Variable6' />" 412 L" <MsiProductSearch Id='Search6' Type='version' ProductCode='{600D0000-1000-0000-0000-000000000000}' Variable='Variable6' />"
413 L" <MsiProductSearch Id='Search7' Type='exists' ProductCode='{600D0000-0000-0000-0000-000000000000}' Variable='Variable7' />"
414 L" <MsiProductSearch Id='Search8' Type='exists' ProductCode='{BAD00000-0000-0000-0000-000000000000}' Variable='Variable8' />"
413 L"</Bundle>"; 415 L"</Bundle>";
414 416
415 // load XML document 417 // load XML document
@@ -429,6 +431,8 @@ namespace Bootstrapper
429 Assert::Equal(5ll, VariableGetNumericHelper(&variables, L"Variable4")); 431 Assert::Equal(5ll, VariableGetNumericHelper(&variables, L"Variable4"));
430 Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable5")); 432 Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable5"));
431 Assert::Equal<String^>(gcnew String(L"1.0.0.0"), VariableGetVersionHelper(&variables, L"Variable6")); 433 Assert::Equal<String^>(gcnew String(L"1.0.0.0"), VariableGetVersionHelper(&variables, L"Variable6"));
434 Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable7"));
435 Assert::Equal(0ll, VariableGetNumericHelper(&variables, L"Variable8"));
432 } 436 }
433 finally 437 finally
434 { 438 {
diff --git a/src/burn/test/BurnUnitTest/precomp.h b/src/burn/test/BurnUnitTest/precomp.h
index f07f5968..ec6fb7d1 100644
--- a/src/burn/test/BurnUnitTest/precomp.h
+++ b/src/burn/test/BurnUnitTest/precomp.h
@@ -74,6 +74,7 @@
74#include "splashscreen.h" 74#include "splashscreen.h"
75#include "detect.h" 75#include "detect.h"
76#include "externalengine.h" 76#include "externalengine.h"
77#include "approvedexe.h"
77 78
78#include "engine.version.h" 79#include "engine.version.h"
79 80