aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2020-10-17 19:12:21 -0500
committerSean Hall <r.sean.hall@gmail.com>2020-10-24 20:07:21 -0500
commit273c69f34311f4f4e5f6b5896e71d0788f12d96a (patch)
tree4cf8f42f3ecfa9341a41686b74aa5e48068ede87
parent3f8e35223216ebbe7f6683a5031a5a97bbc66d5a (diff)
downloadwix-273c69f34311f4f4e5f6b5896e71d0788f12d96a.tar.gz
wix-273c69f34311f4f4e5f6b5896e71d0788f12d96a.tar.bz2
wix-273c69f34311f4f4e5f6b5896e71d0788f12d96a.zip
WIXFEAT:6210 Change data type of versions to strings.
-rw-r--r--src/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h12
-rw-r--r--src/WixToolset.BootstrapperCore.Native/inc/BootstrapperEngine.h8
-rw-r--r--src/WixToolset.BootstrapperCore.Native/inc/BundleExtensionEngine.h8
-rw-r--r--src/engine/EngineForApplication.cpp118
-rw-r--r--src/engine/EngineForExtension.cpp118
-rw-r--r--src/engine/condition.cpp88
-rw-r--r--src/engine/dependency.cpp10
-rw-r--r--src/engine/detect.cpp40
-rw-r--r--src/engine/elevation.cpp11
-rw-r--r--src/engine/engine.vcxproj4
-rw-r--r--src/engine/logging.cpp17
-rw-r--r--src/engine/logging.h5
-rw-r--r--src/engine/msiengine.cpp94
-rw-r--r--src/engine/package.h8
-rw-r--r--src/engine/packages.config2
-rw-r--r--src/engine/plan.cpp10
-rw-r--r--src/engine/plan.h2
-rw-r--r--src/engine/precomp.h1
-rw-r--r--src/engine/registration.cpp12
-rw-r--r--src/engine/registration.h4
-rw-r--r--src/engine/relatedbundle.cpp9
-rw-r--r--src/engine/search.cpp9
-rw-r--r--src/engine/userexperience.cpp24
-rw-r--r--src/engine/userexperience.h12
-rw-r--r--src/engine/variable.cpp75
-rw-r--r--src/engine/variable.h4
-rw-r--r--src/engine/variant.cpp71
-rw-r--r--src/engine/variant.h6
-rw-r--r--src/stub/packages.config2
-rw-r--r--src/stub/stub.vcxproj4
-rw-r--r--src/test/BurnUnitTest/BurnUnitTest.vcxproj4
-rw-r--r--src/test/BurnUnitTest/SearchTest.cpp17
-rw-r--r--src/test/BurnUnitTest/VariableHelpers.cpp34
-rw-r--r--src/test/BurnUnitTest/VariableHelpers.h4
-rw-r--r--src/test/BurnUnitTest/VariableTest.cpp32
-rw-r--r--src/test/BurnUnitTest/VariantTest.cpp52
-rw-r--r--src/test/BurnUnitTest/packages.config2
-rw-r--r--src/test/BurnUnitTest/precomp.h1
38 files changed, 505 insertions, 429 deletions
diff --git a/src/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h b/src/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h
index 36d788ca..77d5b2c6 100644
--- a/src/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h
+++ b/src/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h
@@ -416,7 +416,7 @@ struct BA_ONDETECTCOMPATIBLEMSIPACKAGE_ARGS
416 DWORD cbSize; 416 DWORD cbSize;
417 LPCWSTR wzPackageId; 417 LPCWSTR wzPackageId;
418 LPCWSTR wzCompatiblePackageId; 418 LPCWSTR wzCompatiblePackageId;
419 DWORD64 dw64CompatiblePackageVersion; 419 LPCWSTR wzCompatiblePackageVersion;
420}; 420};
421 421
422struct BA_ONDETECTCOMPATIBLEMSIPACKAGE_RESULTS 422struct BA_ONDETECTCOMPATIBLEMSIPACKAGE_RESULTS
@@ -443,7 +443,7 @@ struct BA_ONDETECTFORWARDCOMPATIBLEBUNDLE_ARGS
443 BOOTSTRAPPER_RELATION_TYPE relationType; 443 BOOTSTRAPPER_RELATION_TYPE relationType;
444 LPCWSTR wzBundleTag; 444 LPCWSTR wzBundleTag;
445 BOOL fPerMachine; 445 BOOL fPerMachine;
446 DWORD64 dw64Version; 446 LPCWSTR wzVersion;
447}; 447};
448 448
449struct BA_ONDETECTFORWARDCOMPATIBLEBUNDLE_RESULTS 449struct BA_ONDETECTFORWARDCOMPATIBLEBUNDLE_RESULTS
@@ -499,7 +499,7 @@ struct BA_ONDETECTRELATEDBUNDLE_ARGS
499 BOOTSTRAPPER_RELATION_TYPE relationType; 499 BOOTSTRAPPER_RELATION_TYPE relationType;
500 LPCWSTR wzBundleTag; 500 LPCWSTR wzBundleTag;
501 BOOL fPerMachine; 501 BOOL fPerMachine;
502 DWORD64 dw64Version; 502 LPCWSTR wzVersion;
503 BOOTSTRAPPER_RELATED_OPERATION operation; 503 BOOTSTRAPPER_RELATED_OPERATION operation;
504}; 504};
505 505
@@ -516,7 +516,7 @@ struct BA_ONDETECTRELATEDMSIPACKAGE_ARGS
516 LPCWSTR wzUpgradeCode; 516 LPCWSTR wzUpgradeCode;
517 LPCWSTR wzProductCode; 517 LPCWSTR wzProductCode;
518 BOOL fPerMachine; 518 BOOL fPerMachine;
519 DWORD64 dw64Version; 519 LPCWSTR wzVersion;
520 BOOTSTRAPPER_RELATED_OPERATION operation; 520 BOOTSTRAPPER_RELATED_OPERATION operation;
521}; 521};
522 522
@@ -545,7 +545,7 @@ struct BA_ONDETECTUPDATE_ARGS
545 DWORD cbSize; 545 DWORD cbSize;
546 LPCWSTR wzUpdateLocation; 546 LPCWSTR wzUpdateLocation;
547 DWORD64 dw64Size; 547 DWORD64 dw64Size;
548 DWORD64 dw64Version; 548 LPCWSTR wzVersion;
549 LPCWSTR wzTitle; 549 LPCWSTR wzTitle;
550 LPCWSTR wzSummary; 550 LPCWSTR wzSummary;
551 LPCWSTR wzContentType; 551 LPCWSTR wzContentType;
@@ -781,7 +781,7 @@ struct BA_ONPLANCOMPATIBLEMSIPACKAGEBEGIN_ARGS
781 DWORD cbSize; 781 DWORD cbSize;
782 LPCWSTR wzPackageId; 782 LPCWSTR wzPackageId;
783 LPCWSTR wzCompatiblePackageId; 783 LPCWSTR wzCompatiblePackageId;
784 DWORD64 dw64CompatiblePackageVersion; 784 LPCWSTR wzCompatiblePackageVersion;
785 BOOTSTRAPPER_REQUEST_STATE recommendedState; 785 BOOTSTRAPPER_REQUEST_STATE recommendedState;
786}; 786};
787 787
diff --git a/src/WixToolset.BootstrapperCore.Native/inc/BootstrapperEngine.h b/src/WixToolset.BootstrapperCore.Native/inc/BootstrapperEngine.h
index e3792177..a6a87622 100644
--- a/src/WixToolset.BootstrapperCore.Native/inc/BootstrapperEngine.h
+++ b/src/WixToolset.BootstrapperCore.Native/inc/BootstrapperEngine.h
@@ -258,8 +258,10 @@ typedef struct _BAENGINE_GETVARIABLEVERSION_ARGS
258typedef struct _BAENGINE_GETVARIABLEVERSION_RESULTS 258typedef struct _BAENGINE_GETVARIABLEVERSION_RESULTS
259{ 259{
260 DWORD cbSize; 260 DWORD cbSize;
261 // The contents of qwValue may be sensitive, if variable is hidden should keep value encrypted and SecureZeroMemory. 261 // The contents of wzValue may be sensitive, if variable is hidden should keep value encrypted and SecureZeroFree.
262 DWORD64 qwValue; 262 LPWSTR wzValue;
263 // Should be initialized to the size of wzValue.
264 DWORD cchValue;
263} BAENGINE_GETVARIABLEVERSION_RESULTS; 265} BAENGINE_GETVARIABLEVERSION_RESULTS;
264 266
265typedef struct _BAENGINE_LAUNCHAPPROVEDEXE_ARGS 267typedef struct _BAENGINE_LAUNCHAPPROVEDEXE_ARGS
@@ -410,7 +412,7 @@ typedef struct _BAENGINE_SETVARIABLEVERSION_ARGS
410{ 412{
411 DWORD cbSize; 413 DWORD cbSize;
412 LPCWSTR wzVariable; 414 LPCWSTR wzVariable;
413 DWORD64 qwValue; 415 LPCWSTR wzValue;
414} BAENGINE_SETVARIABLEVERSION_ARGS; 416} BAENGINE_SETVARIABLEVERSION_ARGS;
415 417
416typedef struct _BAENGINE_SETVARIABLEVERSION_RESULTS 418typedef struct _BAENGINE_SETVARIABLEVERSION_RESULTS
diff --git a/src/WixToolset.BootstrapperCore.Native/inc/BundleExtensionEngine.h b/src/WixToolset.BootstrapperCore.Native/inc/BundleExtensionEngine.h
index 61a55693..adcae1af 100644
--- a/src/WixToolset.BootstrapperCore.Native/inc/BundleExtensionEngine.h
+++ b/src/WixToolset.BootstrapperCore.Native/inc/BundleExtensionEngine.h
@@ -107,8 +107,10 @@ typedef struct _BUNDLE_EXTENSION_ENGINE_GETVARIABLEVERSION_ARGS
107typedef struct _BUNDLE_EXTENSION_ENGINE_GETVARIABLEVERSION_RESULTS 107typedef struct _BUNDLE_EXTENSION_ENGINE_GETVARIABLEVERSION_RESULTS
108{ 108{
109 DWORD cbSize; 109 DWORD cbSize;
110 // The contents of qwValue may be sensitive, if variable is hidden should keep value encrypted and SecureZeroMemory. 110 // The contents of wzValue may be sensitive, if variable is hidden should keep value encrypted and SecureZeroFree.
111 DWORD64 qwValue; 111 LPWSTR wzValue;
112 // Should be initialized to the size of wzValue.
113 DWORD cchValue;
112} BUNDLE_EXTENSION_ENGINE_GETVARIABLEVERSION_RESULTS; 114} BUNDLE_EXTENSION_ENGINE_GETVARIABLEVERSION_RESULTS;
113 115
114typedef struct _BUNDLE_EXTENSION_ENGINE_LOG_ARGS 116typedef struct _BUNDLE_EXTENSION_ENGINE_LOG_ARGS
@@ -152,7 +154,7 @@ typedef struct _BUNDLE_EXTENSION_ENGINE_SETVARIABLEVERSION_ARGS
152{ 154{
153 DWORD cbSize; 155 DWORD cbSize;
154 LPCWSTR wzVariable; 156 LPCWSTR wzVariable;
155 DWORD64 qwValue; 157 LPCWSTR wzValue;
156} BUNDLE_EXTENSION_ENGINE_SETVARIABLEVERSION_ARGS; 158} BUNDLE_EXTENSION_ENGINE_SETVARIABLEVERSION_ARGS;
157 159
158typedef struct _BUNDLE_EXTENSION_ENGINE_SETVARIABLEVERSION_RESULTS 160typedef struct _BUNDLE_EXTENSION_ENGINE_SETVARIABLEVERSION_RESULTS
diff --git a/src/engine/EngineForApplication.cpp b/src/engine/EngineForApplication.cpp
index 81eec2fc..d034c2bf 100644
--- a/src/engine/EngineForApplication.cpp
+++ b/src/engine/EngineForApplication.cpp
@@ -2,6 +2,13 @@
2 2
3#include "precomp.h" 3#include "precomp.h"
4 4
5
6static HRESULT CopyStringToBA(
7 __in LPWSTR wzValue,
8 __in LPWSTR wzBuffer,
9 __inout DWORD* pcchBuffer
10 );
11
5static HRESULT BAEngineGetPackageCount( 12static HRESULT BAEngineGetPackageCount(
6 __in BOOTSTRAPPER_ENGINE_CONTEXT* pContext, 13 __in BOOTSTRAPPER_ENGINE_CONTEXT* pContext,
7 __in BAENGINE_GETPACKAGECOUNT_ARGS* /*pArgs*/, 14 __in BAENGINE_GETPACKAGECOUNT_ARGS* /*pArgs*/,
@@ -46,7 +53,6 @@ static HRESULT BAEngineGetVariableString(
46{ 53{
47 HRESULT hr = S_OK; 54 HRESULT hr = S_OK;
48 LPWSTR sczValue = NULL; 55 LPWSTR sczValue = NULL;
49 size_t cchRemaining = 0;
50 LPCWSTR wzVariable = pArgs->wzVariable; 56 LPCWSTR wzVariable = pArgs->wzVariable;
51 LPWSTR wzValue = pResults->wzValue; 57 LPWSTR wzValue = pResults->wzValue;
52 DWORD* pcchValue = &pResults->cchValue; 58 DWORD* pcchValue = &pResults->cchValue;
@@ -56,24 +62,7 @@ static HRESULT BAEngineGetVariableString(
56 hr = VariableGetString(&pContext->pEngineState->variables, wzVariable, &sczValue); 62 hr = VariableGetString(&pContext->pEngineState->variables, wzVariable, &sczValue);
57 if (SUCCEEDED(hr)) 63 if (SUCCEEDED(hr))
58 { 64 {
59 if (wzValue) 65 hr = CopyStringToBA(sczValue, wzValue, pcchValue);
60 {
61 hr = ::StringCchCopyExW(wzValue, *pcchValue, sczValue, NULL, &cchRemaining, STRSAFE_FILL_BEHIND_NULL);
62 if (STRSAFE_E_INSUFFICIENT_BUFFER == hr)
63 {
64 hr = E_MOREDATA;
65
66 ::StringCchLengthW(sczValue, STRSAFE_MAX_CCH, &cchRemaining);
67 *pcchValue = cchRemaining + 1;
68 }
69 }
70 else
71 {
72 hr = E_MOREDATA;
73
74 ::StringCchLengthW(sczValue, STRSAFE_MAX_CCH, &cchRemaining);
75 *pcchValue = cchRemaining + 1;
76 }
77 } 66 }
78 } 67 }
79 else 68 else
@@ -92,18 +81,26 @@ static HRESULT BAEngineGetVariableVersion(
92 ) 81 )
93{ 82{
94 HRESULT hr = S_OK; 83 HRESULT hr = S_OK;
84 VERUTIL_VERSION* pVersion = NULL;
95 LPCWSTR wzVariable = pArgs->wzVariable; 85 LPCWSTR wzVariable = pArgs->wzVariable;
96 DWORD64* pqwValue = &pResults->qwValue; 86 LPWSTR wzValue = pResults->wzValue;
87 DWORD* pcchValue = &pResults->cchValue;
97 88
98 if (wzVariable && *wzVariable) 89 if (wzVariable && *wzVariable)
99 { 90 {
100 hr = VariableGetVersion(&pContext->pEngineState->variables, wzVariable, pqwValue); 91 hr = VariableGetVersion(&pContext->pEngineState->variables, wzVariable, &pVersion);
92 if (SUCCEEDED(hr))
93 {
94 hr = CopyStringToBA(pVersion->sczVersion, wzValue, pcchValue);
95 }
101 } 96 }
102 else 97 else
103 { 98 {
104 hr = E_INVALIDARG; 99 hr = E_INVALIDARG;
105 } 100 }
106 101
102 ReleaseVerutilVersion(pVersion);
103
107 return hr; 104 return hr;
108} 105}
109 106
@@ -115,33 +112,16 @@ static HRESULT BAEngineFormatString(
115{ 112{
116 HRESULT hr = S_OK; 113 HRESULT hr = S_OK;
117 LPWSTR sczValue = NULL; 114 LPWSTR sczValue = NULL;
118 DWORD cchValue = 0;
119 LPCWSTR wzIn = pArgs->wzIn; 115 LPCWSTR wzIn = pArgs->wzIn;
120 LPWSTR wzOut = pResults->wzOut; 116 LPWSTR wzOut = pResults->wzOut;
121 DWORD* pcchOut = &pResults->cchOut; 117 DWORD* pcchOut = &pResults->cchOut;
122 118
123 if (wzIn && *wzIn) 119 if (wzIn && *wzIn)
124 { 120 {
125 hr = VariableFormatString(&pContext->pEngineState->variables, wzIn, &sczValue, &cchValue); 121 hr = VariableFormatString(&pContext->pEngineState->variables, wzIn, &sczValue, NULL);
126 if (SUCCEEDED(hr)) 122 if (SUCCEEDED(hr))
127 { 123 {
128 if (wzOut) 124 hr = CopyStringToBA(sczValue, wzOut, pcchOut);
129 {
130 hr = ::StringCchCopyExW(wzOut, *pcchOut, sczValue, NULL, NULL, STRSAFE_FILL_BEHIND_NULL);
131 if (FAILED(hr))
132 {
133 *pcchOut = cchValue;
134 if (STRSAFE_E_INSUFFICIENT_BUFFER == hr)
135 {
136 hr = E_MOREDATA;
137 }
138 }
139 }
140 else
141 {
142 hr = E_MOREDATA;
143 *pcchOut = cchValue;
144 }
145 } 125 }
146 } 126 }
147 else 127 else
@@ -161,7 +141,6 @@ static HRESULT BAEngineEscapeString(
161{ 141{
162 HRESULT hr = S_OK; 142 HRESULT hr = S_OK;
163 LPWSTR sczValue = NULL; 143 LPWSTR sczValue = NULL;
164 size_t cchRemaining = 0;
165 LPCWSTR wzIn = pArgs->wzIn; 144 LPCWSTR wzIn = pArgs->wzIn;
166 LPWSTR wzOut = pResults->wzOut; 145 LPWSTR wzOut = pResults->wzOut;
167 DWORD* pcchOut = &pResults->cchOut; 146 DWORD* pcchOut = &pResults->cchOut;
@@ -171,21 +150,7 @@ static HRESULT BAEngineEscapeString(
171 hr = VariableEscapeString(wzIn, &sczValue); 150 hr = VariableEscapeString(wzIn, &sczValue);
172 if (SUCCEEDED(hr)) 151 if (SUCCEEDED(hr))
173 { 152 {
174 if (wzOut) 153 hr = CopyStringToBA(sczValue, wzOut, pcchOut);
175 {
176 hr = ::StringCchCopyExW(wzOut, *pcchOut, sczValue, NULL, &cchRemaining, STRSAFE_FILL_BEHIND_NULL);
177 if (STRSAFE_E_INSUFFICIENT_BUFFER == hr)
178 {
179 hr = E_MOREDATA;
180 ::StringCchLengthW(sczValue, STRSAFE_MAX_CCH, &cchRemaining);
181 *pcchOut = cchRemaining;
182 }
183 }
184 else
185 {
186 ::StringCchLengthW(sczValue, STRSAFE_MAX_CCH, &cchRemaining);
187 *pcchOut = cchRemaining;
188 }
189 } 154 }
190 } 155 }
191 else 156 else
@@ -613,11 +578,15 @@ static HRESULT BAEngineSetVariableVersion(
613{ 578{
614 HRESULT hr = S_OK; 579 HRESULT hr = S_OK;
615 LPCWSTR wzVariable = pArgs->wzVariable; 580 LPCWSTR wzVariable = pArgs->wzVariable;
616 DWORD64 qwValue = pArgs->qwValue; 581 LPCWSTR wzValue = pArgs->wzValue;
582 VERUTIL_VERSION* pVersion = NULL;
617 583
618 if (wzVariable && *wzVariable) 584 if (wzVariable && *wzVariable)
619 { 585 {
620 hr = VariableSetVersion(&pContext->pEngineState->variables, wzVariable, qwValue, FALSE); 586 hr = VerParseVersion(wzValue, 0, FALSE, &pVersion);
587 ExitOnFailure(hr, "Failed to parse new version value.");
588
589 hr = VariableSetVersion(&pContext->pEngineState->variables, wzVariable, pVersion, FALSE);
621 ExitOnFailure(hr, "Failed to set version variable."); 590 ExitOnFailure(hr, "Failed to set version variable.");
622 } 591 }
623 else 592 else
@@ -627,6 +596,8 @@ static HRESULT BAEngineSetVariableVersion(
627 } 596 }
628 597
629LExit: 598LExit:
599 ReleaseVerutilVersion(pVersion);
600
630 return hr; 601 return hr;
631} 602}
632 603
@@ -898,3 +869,34 @@ HRESULT WINAPI EngineForApplicationProc(
898LExit: 869LExit:
899 return hr; 870 return hr;
900} 871}
872
873static HRESULT CopyStringToBA(
874 __in LPWSTR wzValue,
875 __in LPWSTR wzBuffer,
876 __inout DWORD* pcchBuffer
877 )
878{
879 HRESULT hr = S_OK;
880 BOOL fTooSmall = !wzBuffer;
881
882 if (!fTooSmall)
883 {
884 hr = ::StringCchCopyExW(wzBuffer, *pcchBuffer, wzValue, NULL, NULL, STRSAFE_FILL_BEHIND_NULL);
885 if (STRSAFE_E_INSUFFICIENT_BUFFER == hr)
886 {
887 fTooSmall = TRUE;
888 }
889 }
890
891 if (fTooSmall)
892 {
893 hr = ::StringCchLengthW(wzValue, STRSAFE_MAX_CCH, reinterpret_cast<size_t*>(pcchBuffer));
894 if (SUCCEEDED(hr))
895 {
896 hr = E_MOREDATA;
897 *pcchBuffer += 1; // null terminator.
898 }
899 }
900
901 return hr;
902}
diff --git a/src/engine/EngineForExtension.cpp b/src/engine/EngineForExtension.cpp
index fdfa59b1..6ec80a0f 100644
--- a/src/engine/EngineForExtension.cpp
+++ b/src/engine/EngineForExtension.cpp
@@ -2,6 +2,13 @@
2 2
3#include "precomp.h" 3#include "precomp.h"
4 4
5
6static HRESULT CopyStringToBE(
7 __in LPWSTR wzValue,
8 __in LPWSTR wzBuffer,
9 __inout DWORD* pcchBuffer
10 );
11
5static HRESULT BEEngineEscapeString( 12static HRESULT BEEngineEscapeString(
6 __in BURN_EXTENSION_ENGINE_CONTEXT* /*pContext*/, 13 __in BURN_EXTENSION_ENGINE_CONTEXT* /*pContext*/,
7 __in BUNDLE_EXTENSION_ENGINE_ESCAPESTRING_ARGS* pArgs, 14 __in BUNDLE_EXTENSION_ENGINE_ESCAPESTRING_ARGS* pArgs,
@@ -10,7 +17,6 @@ static HRESULT BEEngineEscapeString(
10{ 17{
11 HRESULT hr = S_OK; 18 HRESULT hr = S_OK;
12 LPWSTR sczValue = NULL; 19 LPWSTR sczValue = NULL;
13 size_t cchRemaining = 0;
14 LPCWSTR wzIn = pArgs->wzIn; 20 LPCWSTR wzIn = pArgs->wzIn;
15 LPWSTR wzOut = pResults->wzOut; 21 LPWSTR wzOut = pResults->wzOut;
16 DWORD* pcchOut = &pResults->cchOut; 22 DWORD* pcchOut = &pResults->cchOut;
@@ -20,21 +26,7 @@ static HRESULT BEEngineEscapeString(
20 hr = VariableEscapeString(wzIn, &sczValue); 26 hr = VariableEscapeString(wzIn, &sczValue);
21 if (SUCCEEDED(hr)) 27 if (SUCCEEDED(hr))
22 { 28 {
23 if (wzOut) 29 hr = CopyStringToBE(sczValue, wzOut, pcchOut);
24 {
25 hr = ::StringCchCopyExW(wzOut, *pcchOut, sczValue, NULL, &cchRemaining, STRSAFE_FILL_BEHIND_NULL);
26 if (STRSAFE_E_INSUFFICIENT_BUFFER == hr)
27 {
28 hr = E_MOREDATA;
29 ::StringCchLengthW(sczValue, STRSAFE_MAX_CCH, &cchRemaining);
30 *pcchOut = cchRemaining;
31 }
32 }
33 else
34 {
35 ::StringCchLengthW(sczValue, STRSAFE_MAX_CCH, &cchRemaining);
36 *pcchOut = cchRemaining;
37 }
38 } 30 }
39 } 31 }
40 else 32 else
@@ -76,33 +68,16 @@ static HRESULT BEEngineFormatString(
76{ 68{
77 HRESULT hr = S_OK; 69 HRESULT hr = S_OK;
78 LPWSTR sczValue = NULL; 70 LPWSTR sczValue = NULL;
79 DWORD cchValue = 0;
80 LPCWSTR wzIn = pArgs->wzIn; 71 LPCWSTR wzIn = pArgs->wzIn;
81 LPWSTR wzOut = pResults->wzOut; 72 LPWSTR wzOut = pResults->wzOut;
82 DWORD* pcchOut = &pResults->cchOut; 73 DWORD* pcchOut = &pResults->cchOut;
83 74
84 if (wzIn && *wzIn) 75 if (wzIn && *wzIn)
85 { 76 {
86 hr = VariableFormatString(&pContext->pEngineState->variables, wzIn, &sczValue, &cchValue); 77 hr = VariableFormatString(&pContext->pEngineState->variables, wzIn, &sczValue, NULL);
87 if (SUCCEEDED(hr)) 78 if (SUCCEEDED(hr))
88 { 79 {
89 if (wzOut) 80 hr = CopyStringToBE(sczValue, wzOut, pcchOut);
90 {
91 hr = ::StringCchCopyExW(wzOut, *pcchOut, sczValue, NULL, NULL, STRSAFE_FILL_BEHIND_NULL);
92 if (FAILED(hr))
93 {
94 *pcchOut = cchValue;
95 if (STRSAFE_E_INSUFFICIENT_BUFFER == hr)
96 {
97 hr = E_MOREDATA;
98 }
99 }
100 }
101 else
102 {
103 hr = E_MOREDATA;
104 *pcchOut = cchValue;
105 }
106 } 81 }
107 } 82 }
108 else 83 else
@@ -144,7 +119,6 @@ static HRESULT BEEngineGetVariableString(
144{ 119{
145 HRESULT hr = S_OK; 120 HRESULT hr = S_OK;
146 LPWSTR sczValue = NULL; 121 LPWSTR sczValue = NULL;
147 size_t cchRemaining = 0;
148 LPCWSTR wzVariable = pArgs->wzVariable; 122 LPCWSTR wzVariable = pArgs->wzVariable;
149 LPWSTR wzValue = pResults->wzValue; 123 LPWSTR wzValue = pResults->wzValue;
150 DWORD* pcchValue = &pResults->cchValue; 124 DWORD* pcchValue = &pResults->cchValue;
@@ -154,24 +128,7 @@ static HRESULT BEEngineGetVariableString(
154 hr = VariableGetString(&pContext->pEngineState->variables, wzVariable, &sczValue); 128 hr = VariableGetString(&pContext->pEngineState->variables, wzVariable, &sczValue);
155 if (SUCCEEDED(hr)) 129 if (SUCCEEDED(hr))
156 { 130 {
157 if (wzValue) 131 hr = CopyStringToBE(sczValue, wzValue, pcchValue);
158 {
159 hr = ::StringCchCopyExW(wzValue, *pcchValue, sczValue, NULL, &cchRemaining, STRSAFE_FILL_BEHIND_NULL);
160 if (STRSAFE_E_INSUFFICIENT_BUFFER == hr)
161 {
162 hr = E_MOREDATA;
163
164 ::StringCchLengthW(sczValue, STRSAFE_MAX_CCH, &cchRemaining);
165 *pcchValue = cchRemaining + 1;
166 }
167 }
168 else
169 {
170 hr = E_MOREDATA;
171
172 ::StringCchLengthW(sczValue, STRSAFE_MAX_CCH, &cchRemaining);
173 *pcchValue = cchRemaining + 1;
174 }
175 } 132 }
176 } 133 }
177 else 134 else
@@ -190,18 +147,26 @@ static HRESULT BEEngineGetVariableVersion(
190 ) 147 )
191{ 148{
192 HRESULT hr = S_OK; 149 HRESULT hr = S_OK;
150 VERUTIL_VERSION* pVersion = NULL;
193 LPCWSTR wzVariable = pArgs->wzVariable; 151 LPCWSTR wzVariable = pArgs->wzVariable;
194 DWORD64* pqwValue = &pResults->qwValue; 152 LPWSTR wzValue = pResults->wzValue;
153 DWORD* pcchValue = &pResults->cchValue;
195 154
196 if (wzVariable && *wzVariable) 155 if (wzVariable && *wzVariable)
197 { 156 {
198 hr = VariableGetVersion(&pContext->pEngineState->variables, wzVariable, pqwValue); 157 hr = VariableGetVersion(&pContext->pEngineState->variables, wzVariable, &pVersion);
158 if (SUCCEEDED(hr))
159 {
160 hr = CopyStringToBE(pVersion->sczVersion, wzValue, pcchValue);
161 }
199 } 162 }
200 else 163 else
201 { 164 {
202 hr = E_INVALIDARG; 165 hr = E_INVALIDARG;
203 } 166 }
204 167
168 ReleaseVerutilVersion(pVersion);
169
205 return hr; 170 return hr;
206} 171}
207 172
@@ -303,11 +268,15 @@ static HRESULT BEEngineSetVariableVersion(
303{ 268{
304 HRESULT hr = S_OK; 269 HRESULT hr = S_OK;
305 LPCWSTR wzVariable = pArgs->wzVariable; 270 LPCWSTR wzVariable = pArgs->wzVariable;
306 DWORD64 qwValue = pArgs->qwValue; 271 LPCWSTR wzValue = pArgs->wzValue;
272 VERUTIL_VERSION* pVersion = NULL;
307 273
308 if (wzVariable && *wzVariable) 274 if (wzVariable && *wzVariable)
309 { 275 {
310 hr = VariableSetVersion(&pContext->pEngineState->variables, wzVariable, qwValue, FALSE); 276 hr = VerParseVersion(wzValue, 0, FALSE, &pVersion);
277 ExitOnFailure(hr, "Failed to parse new version value.");
278
279 hr = VariableSetVersion(&pContext->pEngineState->variables, wzVariable, pVersion, FALSE);
311 ExitOnFailure(hr, "Failed to set version variable."); 280 ExitOnFailure(hr, "Failed to set version variable.");
312 } 281 }
313 else 282 else
@@ -317,6 +286,8 @@ static HRESULT BEEngineSetVariableVersion(
317 } 286 }
318 287
319LExit: 288LExit:
289 ReleaseVerutilVersion(pVersion);
290
320 return hr; 291 return hr;
321} 292}
322 293
@@ -375,3 +346,34 @@ HRESULT WINAPI EngineForExtensionProc(
375LExit: 346LExit:
376 return hr; 347 return hr;
377} 348}
349
350static HRESULT CopyStringToBE(
351 __in LPWSTR wzValue,
352 __in LPWSTR wzBuffer,
353 __inout DWORD* pcchBuffer
354 )
355{
356 HRESULT hr = S_OK;
357 BOOL fTooSmall = !wzBuffer;
358
359 if (!fTooSmall)
360 {
361 hr = ::StringCchCopyExW(wzBuffer, *pcchBuffer, wzValue, NULL, NULL, STRSAFE_FILL_BEHIND_NULL);
362 if (STRSAFE_E_INSUFFICIENT_BUFFER == hr)
363 {
364 fTooSmall = TRUE;
365 }
366 }
367
368 if (fTooSmall)
369 {
370 hr = ::StringCchLengthW(wzValue, STRSAFE_MAX_CCH, reinterpret_cast<size_t*>(pcchBuffer));
371 if (SUCCEEDED(hr))
372 {
373 hr = E_MOREDATA;
374 *pcchBuffer += 1; // null terminator.
375 }
376 }
377
378 return hr;
379}
diff --git a/src/engine/condition.cpp b/src/engine/condition.cpp
index cd346680..32a7a0b8 100644
--- a/src/engine/condition.cpp
+++ b/src/engine/condition.cpp
@@ -123,8 +123,8 @@ static HRESULT CompareIntegerValues(
123 ); 123 );
124static HRESULT CompareVersionValues( 124static HRESULT CompareVersionValues(
125 __in BURN_SYMBOL_TYPE comparison, 125 __in BURN_SYMBOL_TYPE comparison,
126 __in DWORD64 qwLeftOperand, 126 __in VERUTIL_VERSION* pLeftOperand,
127 __in DWORD64 qwRightOperand, 127 __in VERUTIL_VERSION* pRightOperand,
128 __out BOOL* pfResult 128 __out BOOL* pfResult
129 ); 129 );
130 130
@@ -379,7 +379,7 @@ static HRESULT ParseTerm(
379 { 379 {
380 LONGLONG llValue = 0; 380 LONGLONG llValue = 0;
381 LPWSTR sczValue = NULL; 381 LPWSTR sczValue = NULL;
382 DWORD64 qwValue = 0; 382 VERUTIL_VERSION* pVersion = NULL;
383 switch (firstValue.Type) 383 switch (firstValue.Type)
384 { 384 {
385 case BURN_VARIANT_TYPE_NONE: 385 case BURN_VARIANT_TYPE_NONE:
@@ -402,12 +402,12 @@ static HRESULT ParseTerm(
402 SecureZeroMemory(&llValue, sizeof(llValue)); 402 SecureZeroMemory(&llValue, sizeof(llValue));
403 break; 403 break;
404 case BURN_VARIANT_TYPE_VERSION: 404 case BURN_VARIANT_TYPE_VERSION:
405 hr = BVariantGetVersion(&firstValue, &qwValue); 405 hr = BVariantGetVersion(&firstValue, &pVersion);
406 if (SUCCEEDED(hr)) 406 if (SUCCEEDED(hr))
407 { 407 {
408 *pf = 0 != qwValue; 408 *pf = 0 != *pVersion->sczVersion;
409 } 409 }
410 SecureZeroMemory(&llValue, sizeof(qwValue)); 410 ReleaseVerutilVersion(pVersion);
411 break; 411 break;
412 default: 412 default:
413 ExitFunction1(hr = E_UNEXPECTED); 413 ExitFunction1(hr = E_UNEXPECTED);
@@ -689,33 +689,14 @@ static HRESULT NextSymbol(
689 if (L'v' == pContext->wzRead[0] && C1_DIGIT & charType) 689 if (L'v' == pContext->wzRead[0] && C1_DIGIT & charType)
690 { 690 {
691 // version 691 // version
692 DWORD cParts = 1; 692 do
693 for (;;)
694 { 693 {
695 ++n; 694 ++n;
696 if (L'.' == pContext->wzRead[n]) 695 ::GetStringTypeW(CT_CTYPE1, &pContext->wzRead[n], 1, &charType);
697 { 696 } while (L'\0' != pContext->wzRead[n] && C1_BLANK != (C1_BLANK & charType));
698 ++cParts;
699 if (4 < cParts)
700 {
701 // error, too many parts in version
702 pContext->fError = TRUE;
703 hr = E_INVALIDDATA;
704 ExitOnRootFailure(hr, "Failed to parse condition \"%ls\". Version can have a maximum of 4 parts, at position %d.", pContext->wzCondition, iPosition);
705 }
706 }
707 else
708 {
709 ::GetStringTypeW(CT_CTYPE1, &pContext->wzRead[n], 1, &charType);
710 if (C1_DIGIT != (C1_DIGIT & charType))
711 {
712 break;
713 }
714 }
715 }
716 697
717 // Symbols don't encrypt their value, so can access the value directly. 698 // Symbols don't encrypt their value, so can access the value directly.
718 hr = FileVersionFromStringEx(&pContext->wzRead[1], n - 1, &pContext->NextSymbol.Value.qwValue); 699 hr = VerParseVersion(&pContext->wzRead[1], n - 1, FALSE, &pContext->NextSymbol.Value.pValue);
719 if (FAILED(hr)) 700 if (FAILED(hr))
720 { 701 {
721 pContext->fError = TRUE; 702 pContext->fError = TRUE;
@@ -785,10 +766,10 @@ static HRESULT CompareValues(
785{ 766{
786 HRESULT hr = S_OK; 767 HRESULT hr = S_OK;
787 LONGLONG llLeft = 0; 768 LONGLONG llLeft = 0;
788 DWORD64 qwLeft = 0; 769 VERUTIL_VERSION* pVersionLeft = 0;
789 LPWSTR sczLeft = NULL; 770 LPWSTR sczLeft = NULL;
790 LONGLONG llRight = 0; 771 LONGLONG llRight = 0;
791 DWORD64 qwRight = 0; 772 VERUTIL_VERSION* pVersionRight = 0;
792 LPWSTR sczRight = NULL; 773 LPWSTR sczRight = NULL;
793 774
794 // get values to compare based on type 775 // get values to compare based on type
@@ -810,17 +791,17 @@ static HRESULT CompareValues(
810 } 791 }
811 else if (BURN_VARIANT_TYPE_VERSION == leftOperand.Type && BURN_VARIANT_TYPE_VERSION == rightOperand.Type) 792 else if (BURN_VARIANT_TYPE_VERSION == leftOperand.Type && BURN_VARIANT_TYPE_VERSION == rightOperand.Type)
812 { 793 {
813 hr = BVariantGetVersion(&leftOperand, &qwLeft); 794 hr = BVariantGetVersion(&leftOperand, &pVersionLeft);
814 ExitOnFailure(hr, "Failed to get the left version"); 795 ExitOnFailure(hr, "Failed to get the left version");
815 hr = BVariantGetVersion(&rightOperand, &qwRight); 796 hr = BVariantGetVersion(&rightOperand, &pVersionRight);
816 ExitOnFailure(hr, "Failed to get the right version"); 797 ExitOnFailure(hr, "Failed to get the right version");
817 hr = CompareVersionValues(comparison, qwLeft, qwRight, pfResult); 798 hr = CompareVersionValues(comparison, pVersionLeft, pVersionRight, pfResult);
818 } 799 }
819 else if (BURN_VARIANT_TYPE_VERSION == leftOperand.Type && BURN_VARIANT_TYPE_STRING == rightOperand.Type) 800 else if (BURN_VARIANT_TYPE_VERSION == leftOperand.Type && BURN_VARIANT_TYPE_STRING == rightOperand.Type)
820 { 801 {
821 hr = BVariantGetVersion(&leftOperand, &qwLeft); 802 hr = BVariantGetVersion(&leftOperand, &pVersionLeft);
822 ExitOnFailure(hr, "Failed to get the left version"); 803 ExitOnFailure(hr, "Failed to get the left version");
823 hr = BVariantGetVersion(&rightOperand, &qwRight); 804 hr = BVariantGetVersion(&rightOperand, &pVersionRight);
824 if (FAILED(hr)) 805 if (FAILED(hr))
825 { 806 {
826 if (DISP_E_TYPEMISMATCH != hr) 807 if (DISP_E_TYPEMISMATCH != hr)
@@ -832,14 +813,14 @@ static HRESULT CompareValues(
832 } 813 }
833 else 814 else
834 { 815 {
835 hr = CompareVersionValues(comparison, qwLeft, qwRight, pfResult); 816 hr = CompareVersionValues(comparison, pVersionLeft, pVersionRight, pfResult);
836 } 817 }
837 } 818 }
838 else if (BURN_VARIANT_TYPE_STRING == leftOperand.Type && BURN_VARIANT_TYPE_VERSION == rightOperand.Type) 819 else if (BURN_VARIANT_TYPE_STRING == leftOperand.Type && BURN_VARIANT_TYPE_VERSION == rightOperand.Type)
839 { 820 {
840 hr = BVariantGetVersion(&rightOperand, &qwRight); 821 hr = BVariantGetVersion(&rightOperand, &pVersionRight);
841 ExitOnFailure(hr, "Failed to get the right version"); 822 ExitOnFailure(hr, "Failed to get the right version");
842 hr = BVariantGetVersion(&leftOperand, &qwLeft); 823 hr = BVariantGetVersion(&leftOperand, &pVersionLeft);
843 if (FAILED(hr)) 824 if (FAILED(hr))
844 { 825 {
845 if (DISP_E_TYPEMISMATCH != hr) 826 if (DISP_E_TYPEMISMATCH != hr)
@@ -851,7 +832,7 @@ static HRESULT CompareValues(
851 } 832 }
852 else 833 else
853 { 834 {
854 hr = CompareVersionValues(comparison, qwLeft, qwRight, pfResult); 835 hr = CompareVersionValues(comparison, pVersionLeft, pVersionRight, pfResult);
855 } 836 }
856 } 837 }
857 else if (BURN_VARIANT_TYPE_NUMERIC == leftOperand.Type && BURN_VARIANT_TYPE_STRING == rightOperand.Type) 838 else if (BURN_VARIANT_TYPE_NUMERIC == leftOperand.Type && BURN_VARIANT_TYPE_STRING == rightOperand.Type)
@@ -899,10 +880,10 @@ static HRESULT CompareValues(
899 } 880 }
900 881
901LExit: 882LExit:
902 SecureZeroMemory(&qwLeft, sizeof(DWORD64)); 883 ReleaseVerutilVersion(pVersionLeft);
903 SecureZeroMemory(&llLeft, sizeof(LONGLONG)); 884 SecureZeroMemory(&llLeft, sizeof(LONGLONG));
904 StrSecureZeroFreeString(sczLeft); 885 StrSecureZeroFreeString(sczLeft);
905 SecureZeroMemory(&qwRight, sizeof(DWORD64)); 886 ReleaseVerutilVersion(pVersionRight);
906 SecureZeroMemory(&llRight, sizeof(LONGLONG)); 887 SecureZeroMemory(&llRight, sizeof(LONGLONG));
907 StrSecureZeroFreeString(sczRight); 888 StrSecureZeroFreeString(sczRight);
908 889
@@ -1010,24 +991,25 @@ LExit:
1010// 991//
1011static HRESULT CompareVersionValues( 992static HRESULT CompareVersionValues(
1012 __in BURN_SYMBOL_TYPE comparison, 993 __in BURN_SYMBOL_TYPE comparison,
1013 __in DWORD64 qwLeftOperand, 994 __in VERUTIL_VERSION* pLeftOperand,
1014 __in DWORD64 qwRightOperand, 995 __in VERUTIL_VERSION* pRightOperand,
1015 __out BOOL* pfResult 996 __out BOOL* pfResult
1016 ) 997 )
1017{ 998{
1018 HRESULT hr = S_OK; 999 HRESULT hr = S_OK;
1000 int nResult = 0;
1001
1002 hr = VerCompareParsedVersions(pLeftOperand, pRightOperand, &nResult);
1003 ExitOnFailure(hr, "Failed to compare condition versions: '%ls', '%ls'", pLeftOperand->sczVersion, pRightOperand->sczVersion);
1019 1004
1020 switch (comparison) 1005 switch (comparison)
1021 { 1006 {
1022 case BURN_SYMBOL_TYPE_LT: *pfResult = qwLeftOperand < qwRightOperand; break; 1007 case BURN_SYMBOL_TYPE_LT: *pfResult = nResult < 0; break;
1023 case BURN_SYMBOL_TYPE_GT: *pfResult = qwLeftOperand > qwRightOperand; break; 1008 case BURN_SYMBOL_TYPE_GT: *pfResult = nResult > 0; break;
1024 case BURN_SYMBOL_TYPE_LE: *pfResult = qwLeftOperand <= qwRightOperand; break; 1009 case BURN_SYMBOL_TYPE_LE: *pfResult = nResult <= 0; break;
1025 case BURN_SYMBOL_TYPE_GE: *pfResult = qwLeftOperand >= qwRightOperand; break; 1010 case BURN_SYMBOL_TYPE_GE: *pfResult = nResult >= 0; break;
1026 case BURN_SYMBOL_TYPE_EQ: *pfResult = qwLeftOperand == qwRightOperand; break; 1011 case BURN_SYMBOL_TYPE_EQ: *pfResult = nResult == 0; break;
1027 case BURN_SYMBOL_TYPE_NE: *pfResult = qwLeftOperand != qwRightOperand; break; 1012 case BURN_SYMBOL_TYPE_NE: *pfResult = nResult != 0; break;
1028 case BURN_SYMBOL_TYPE_BAND: *pfResult = (qwLeftOperand & qwRightOperand) ? TRUE : FALSE; break;
1029 case BURN_SYMBOL_TYPE_HIEQ: *pfResult = ((qwLeftOperand >> 16) & 0xFFFF) == qwRightOperand; break;
1030 case BURN_SYMBOL_TYPE_LOEQ: *pfResult = (qwLeftOperand & 0xFFFF) == qwRightOperand; break;
1031 default: 1013 default:
1032 ExitFunction1(hr = E_INVALIDARG); 1014 ExitFunction1(hr = E_INVALIDARG);
1033 } 1015 }
diff --git a/src/engine/dependency.cpp b/src/engine/dependency.cpp
index c7c6e024..c01449b6 100644
--- a/src/engine/dependency.cpp
+++ b/src/engine/dependency.cpp
@@ -593,20 +593,14 @@ extern "C" HRESULT DependencyRegisterBundle(
593 ) 593 )
594{ 594{
595 HRESULT hr = S_OK; 595 HRESULT hr = S_OK;
596 LPWSTR sczVersion = NULL;
597 596
598 hr = FileVersionToStringEx(pRegistration->qwVersion, &sczVersion); 597 LogId(REPORT_VERBOSE, MSG_DEPENDENCY_BUNDLE_REGISTER, pRegistration->sczProviderKey, pRegistration->pVersion->sczVersion);
599 ExitOnFailure(hr, "Failed to format the registration version string.");
600
601 LogId(REPORT_VERBOSE, MSG_DEPENDENCY_BUNDLE_REGISTER, pRegistration->sczProviderKey, sczVersion);
602 598
603 // Register the bundle provider key. 599 // Register the bundle provider key.
604 hr = DepRegisterDependency(pRegistration->hkRoot, pRegistration->sczProviderKey, sczVersion, pRegistration->sczDisplayName, pRegistration->sczId, 0); 600 hr = DepRegisterDependency(pRegistration->hkRoot, pRegistration->sczProviderKey, pRegistration->pVersion->sczVersion, pRegistration->sczDisplayName, pRegistration->sczId, 0);
605 ExitOnFailure(hr, "Failed to register the bundle dependency provider."); 601 ExitOnFailure(hr, "Failed to register the bundle dependency provider.");
606 602
607LExit: 603LExit:
608 ReleaseStr(sczVersion);
609
610 return hr; 604 return hr;
611} 605}
612 606
diff --git a/src/engine/detect.cpp b/src/engine/detect.cpp
index 7953daf5..9e4681bb 100644
--- a/src/engine/detect.cpp
+++ b/src/engine/detect.cpp
@@ -90,6 +90,7 @@ extern "C" HRESULT DetectForwardCompatibleBundle(
90 HRESULT hr = S_OK; 90 HRESULT hr = S_OK;
91 BOOL fRecommendIgnore = TRUE; 91 BOOL fRecommendIgnore = TRUE;
92 BOOL fIgnoreBundle = FALSE; 92 BOOL fIgnoreBundle = FALSE;
93 int nCompareResult = 0;
93 94
94 if (pRegistration->sczDetectedProviderKeyBundleId && 95 if (pRegistration->sczDetectedProviderKeyBundleId &&
95 CSTR_EQUAL != ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pRegistration->sczDetectedProviderKeyBundleId, -1, pRegistration->sczId, -1)) 96 CSTR_EQUAL != ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pRegistration->sczDetectedProviderKeyBundleId, -1, pRegistration->sczId, -1))
@@ -122,22 +123,27 @@ extern "C" HRESULT DetectForwardCompatibleBundle(
122 fIgnoreBundle = fRecommendIgnore; 123 fIgnoreBundle = fRecommendIgnore;
123 124
124 if (BOOTSTRAPPER_RELATION_UPGRADE == pRelatedBundle->relationType && 125 if (BOOTSTRAPPER_RELATION_UPGRADE == pRelatedBundle->relationType &&
125 pRegistration->qwVersion <= pRelatedBundle->qwVersion &&
126 CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pRegistration->sczDetectedProviderKeyBundleId, -1, pRelatedBundle->package.sczId, -1)) 126 CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pRegistration->sczDetectedProviderKeyBundleId, -1, pRelatedBundle->package.sczId, -1))
127 { 127 {
128 hr = UserExperienceOnDetectForwardCompatibleBundle(pUX, pRelatedBundle->package.sczId, pRelatedBundle->relationType, pRelatedBundle->sczTag, pRelatedBundle->package.fPerMachine, pRelatedBundle->qwVersion, &fIgnoreBundle); 128 hr = VerCompareParsedVersions(pRegistration->pVersion, pRelatedBundle->pVersion, &nCompareResult);
129 ExitOnRootFailure(hr, "BA aborted detect forward compatible bundle."); 129 ExitOnFailure(hr, "Failed to compare bundle version '%ls' to related bundle version '%ls'", pRegistration->pVersion->sczVersion, pRelatedBundle->pVersion->sczVersion);
130 130
131 if (!fIgnoreBundle) 131 if (nCompareResult <= 0)
132 { 132 {
133 hr = PseudoBundleInitializePassthrough(&pRegistration->forwardCompatibleBundle, pCommand, NULL, pRegistration->sczActiveParent, pRegistration->sczAncestors, &pRelatedBundle->package); 133 hr = UserExperienceOnDetectForwardCompatibleBundle(pUX, pRelatedBundle->package.sczId, pRelatedBundle->relationType, pRelatedBundle->sczTag, pRelatedBundle->package.fPerMachine, pRelatedBundle->pVersion, &fIgnoreBundle);
134 ExitOnFailure(hr, "Failed to initialize update bundle."); 134 ExitOnRootFailure(hr, "BA aborted detect forward compatible bundle.");
135 135
136 pRegistration->fEnabledForwardCompatibleBundle = TRUE; 136 if (!fIgnoreBundle)
137 } 137 {
138 hr = PseudoBundleInitializePassthrough(&pRegistration->forwardCompatibleBundle, pCommand, NULL, pRegistration->sczActiveParent, pRegistration->sczAncestors, &pRelatedBundle->package);
139 ExitOnFailure(hr, "Failed to initialize update bundle.");
138 140
139 LogId(REPORT_STANDARD, MSG_DETECTED_FORWARD_COMPATIBLE_BUNDLE, pRelatedBundle->package.sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), LoggingPerMachineToString(pRelatedBundle->package.fPerMachine), LoggingVersionToString(pRelatedBundle->qwVersion), LoggingBoolToString(pRegistration->fEnabledForwardCompatibleBundle)); 141 pRegistration->fEnabledForwardCompatibleBundle = TRUE;
140 break; 142 }
143
144 LogId(REPORT_STANDARD, MSG_DETECTED_FORWARD_COMPATIBLE_BUNDLE, pRelatedBundle->package.sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), LoggingPerMachineToString(pRelatedBundle->package.fPerMachine), pRelatedBundle->pVersion->sczVersion, LoggingBoolToString(pRegistration->fEnabledForwardCompatibleBundle));
145 break;
146 }
141 } 147 }
142 } 148 }
143 } 149 }
@@ -154,6 +160,7 @@ extern "C" HRESULT DetectReportRelatedBundles(
154 ) 160 )
155{ 161{
156 HRESULT hr = S_OK; 162 HRESULT hr = S_OK;
163 int nCompareResult = 0;
157 164
158 for (DWORD iRelatedBundle = 0; iRelatedBundle < pRegistration->relatedBundles.cRelatedBundles; ++iRelatedBundle) 165 for (DWORD iRelatedBundle = 0; iRelatedBundle < pRegistration->relatedBundles.cRelatedBundles; ++iRelatedBundle)
159 { 166 {
@@ -165,11 +172,14 @@ extern "C" HRESULT DetectReportRelatedBundles(
165 case BOOTSTRAPPER_RELATION_UPGRADE: 172 case BOOTSTRAPPER_RELATION_UPGRADE:
166 if (BOOTSTRAPPER_RELATION_UPGRADE != relationType && BOOTSTRAPPER_ACTION_UNINSTALL < action) 173 if (BOOTSTRAPPER_RELATION_UPGRADE != relationType && BOOTSTRAPPER_ACTION_UNINSTALL < action)
167 { 174 {
168 if (pRegistration->qwVersion > pRelatedBundle->qwVersion) 175 hr = VerCompareParsedVersions(pRegistration->pVersion, pRelatedBundle->pVersion, &nCompareResult);
176 ExitOnFailure(hr, "Failed to compare bundle version '%ls' to related bundle version '%ls'", pRegistration->pVersion, pRelatedBundle->pVersion);
177
178 if (nCompareResult > 0)
169 { 179 {
170 operation = BOOTSTRAPPER_RELATED_OPERATION_MAJOR_UPGRADE; 180 operation = BOOTSTRAPPER_RELATED_OPERATION_MAJOR_UPGRADE;
171 } 181 }
172 else if (pRegistration->qwVersion < pRelatedBundle->qwVersion) 182 else if (nCompareResult < 0)
173 { 183 {
174 operation = BOOTSTRAPPER_RELATED_OPERATION_DOWNGRADE; 184 operation = BOOTSTRAPPER_RELATED_OPERATION_DOWNGRADE;
175 } 185 }
@@ -202,9 +212,9 @@ extern "C" HRESULT DetectReportRelatedBundles(
202 break; 212 break;
203 } 213 }
204 214
205 LogId(REPORT_STANDARD, MSG_DETECTED_RELATED_BUNDLE, pRelatedBundle->package.sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), LoggingPerMachineToString(pRelatedBundle->package.fPerMachine), LoggingVersionToString(pRelatedBundle->qwVersion), LoggingRelatedOperationToString(operation)); 215 LogId(REPORT_STANDARD, MSG_DETECTED_RELATED_BUNDLE, pRelatedBundle->package.sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), LoggingPerMachineToString(pRelatedBundle->package.fPerMachine), pRelatedBundle->pVersion->sczVersion, LoggingRelatedOperationToString(operation));
206 216
207 hr = UserExperienceOnDetectRelatedBundle(pUX, pRelatedBundle->package.sczId, pRelatedBundle->relationType, pRelatedBundle->sczTag, pRelatedBundle->package.fPerMachine, pRelatedBundle->qwVersion, operation); 217 hr = UserExperienceOnDetectRelatedBundle(pUX, pRelatedBundle->package.sczId, pRelatedBundle->relationType, pRelatedBundle->sczTag, pRelatedBundle->package.fPerMachine, pRelatedBundle->pVersion, operation);
208 ExitOnRootFailure(hr, "BA aborted detect related bundle."); 218 ExitOnRootFailure(hr, "BA aborted detect related bundle.");
209 } 219 }
210 220
@@ -405,7 +415,7 @@ static HRESULT DetectAtomFeedUpdate(
405 415
406 hr = UserExperienceOnDetectUpdate(pUX, pAppUpdateEntry->rgEnclosures ? pAppUpdateEntry->rgEnclosures->wzUrl : NULL, 416 hr = UserExperienceOnDetectUpdate(pUX, pAppUpdateEntry->rgEnclosures ? pAppUpdateEntry->rgEnclosures->wzUrl : NULL,
407 pAppUpdateEntry->rgEnclosures ? pAppUpdateEntry->rgEnclosures->dw64Size : 0, 417 pAppUpdateEntry->rgEnclosures ? pAppUpdateEntry->rgEnclosures->dw64Size : 0,
408 pAppUpdateEntry->dw64Version, pAppUpdateEntry->wzTitle, 418 pAppUpdateEntry->pVersion, pAppUpdateEntry->wzTitle,
409 pAppUpdateEntry->wzSummary, pAppUpdateEntry->wzContentType, pAppUpdateEntry->wzContent, &fStopProcessingUpdates); 419 pAppUpdateEntry->wzSummary, pAppUpdateEntry->wzContentType, pAppUpdateEntry->wzContent, &fStopProcessingUpdates);
410 ExitOnRootFailure(hr, "BA aborted detect update."); 420 ExitOnRootFailure(hr, "BA aborted detect update.");
411 421
diff --git a/src/engine/elevation.cpp b/src/engine/elevation.cpp
index d0652270..9ce04630 100644
--- a/src/engine/elevation.cpp
+++ b/src/engine/elevation.cpp
@@ -1087,7 +1087,7 @@ extern "C" HRESULT ElevationLoadCompatiblePackageAction(
1087 hr = BuffWriteString(&pbData, &cbData, pExecuteAction->compatiblePackage.sczInstalledProductCode); 1087 hr = BuffWriteString(&pbData, &cbData, pExecuteAction->compatiblePackage.sczInstalledProductCode);
1088 ExitOnFailure(hr, "Failed to write installed ProductCode to message buffer."); 1088 ExitOnFailure(hr, "Failed to write installed ProductCode to message buffer.");
1089 1089
1090 hr = BuffWriteNumber64(&pbData, &cbData, pExecuteAction->compatiblePackage.qwInstalledVersion); 1090 hr = BuffWriteString(&pbData, &cbData, pExecuteAction->compatiblePackage.pInstalledVersion->sczVersion);
1091 ExitOnFailure(hr, "Failed to write installed version to message buffer."); 1091 ExitOnFailure(hr, "Failed to write installed version to message buffer.");
1092 1092
1093 // Send the message. 1093 // Send the message.
@@ -2566,6 +2566,7 @@ static HRESULT OnLoadCompatiblePackage(
2566 HRESULT hr = S_OK; 2566 HRESULT hr = S_OK;
2567 SIZE_T iData = 0; 2567 SIZE_T iData = 0;
2568 LPWSTR sczPackage = NULL; 2568 LPWSTR sczPackage = NULL;
2569 LPWSTR sczVersion = NULL;
2569 BURN_EXECUTE_ACTION executeAction = { }; 2570 BURN_EXECUTE_ACTION executeAction = { };
2570 2571
2571 executeAction.type = BURN_EXECUTE_ACTION_TYPE_COMPATIBLE_PACKAGE; 2572 executeAction.type = BURN_EXECUTE_ACTION_TYPE_COMPATIBLE_PACKAGE;
@@ -2581,20 +2582,24 @@ static HRESULT OnLoadCompatiblePackage(
2581 hr = BuffReadString(pbData, cbData, &iData, &executeAction.compatiblePackage.sczInstalledProductCode); 2582 hr = BuffReadString(pbData, cbData, &iData, &executeAction.compatiblePackage.sczInstalledProductCode);
2582 ExitOnFailure(hr, "Failed to read installed ProductCode from message buffer."); 2583 ExitOnFailure(hr, "Failed to read installed ProductCode from message buffer.");
2583 2584
2584 hr = BuffReadNumber64(pbData, cbData, &iData, &executeAction.compatiblePackage.qwInstalledVersion); 2585 hr = BuffReadString(pbData, cbData, &iData, &sczVersion);
2585 ExitOnFailure(hr, "Failed to read installed version from message buffer."); 2586 ExitOnFailure(hr, "Failed to read installed version from message buffer.");
2586 2587
2588 hr = VerParseVersion(sczVersion, 0, FALSE, &executeAction.compatiblePackage.pInstalledVersion);
2589 ExitOnFailure(hr, "Failed to parse installed version from compatible package.");
2590
2587 // Copy the installed data to the reference package. 2591 // Copy the installed data to the reference package.
2588 hr = StrAllocString(&executeAction.compatiblePackage.pReferencePackage->Msi.sczInstalledProductCode, executeAction.compatiblePackage.sczInstalledProductCode, 0); 2592 hr = StrAllocString(&executeAction.compatiblePackage.pReferencePackage->Msi.sczInstalledProductCode, executeAction.compatiblePackage.sczInstalledProductCode, 0);
2589 ExitOnFailure(hr, "Failed to copy installed ProductCode."); 2593 ExitOnFailure(hr, "Failed to copy installed ProductCode.");
2590 2594
2591 executeAction.compatiblePackage.pReferencePackage->Msi.qwInstalledVersion = executeAction.compatiblePackage.qwInstalledVersion; 2595 executeAction.compatiblePackage.pReferencePackage->Msi.pInstalledVersion = executeAction.compatiblePackage.pInstalledVersion;
2592 2596
2593 // Load the compatible package and add it to the list. 2597 // Load the compatible package and add it to the list.
2594 hr = MsiEngineAddCompatiblePackage(pPackages, executeAction.compatiblePackage.pReferencePackage, NULL); 2598 hr = MsiEngineAddCompatiblePackage(pPackages, executeAction.compatiblePackage.pReferencePackage, NULL);
2595 ExitOnFailure(hr, "Failed to load compatible package."); 2599 ExitOnFailure(hr, "Failed to load compatible package.");
2596 2600
2597LExit: 2601LExit:
2602 ReleaseStr(sczVersion);
2598 ReleaseStr(sczPackage); 2603 ReleaseStr(sczPackage);
2599 PlanUninitializeExecuteAction(&executeAction); 2604 PlanUninitializeExecuteAction(&executeAction);
2600 2605
diff --git a/src/engine/engine.vcxproj b/src/engine/engine.vcxproj
index ef5c1602..d3f5b61e 100644
--- a/src/engine/engine.vcxproj
+++ b/src/engine/engine.vcxproj
@@ -2,7 +2,7 @@
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" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
5 <Import Project="..\..\packages\WixToolset.DUtil.4.0.49\build\WixToolset.DUtil.props" Condition="Exists('..\..\packages\WixToolset.DUtil.4.0.49\build\WixToolset.DUtil.props')" /> 5 <Import Project="..\..\packages\WixToolset.DUtil.4.0.55\build\WixToolset.DUtil.props" Condition="Exists('..\..\packages\WixToolset.DUtil.4.0.55\build\WixToolset.DUtil.props')" />
6 6
7 <ItemGroup Label="ProjectConfigurations"> 7 <ItemGroup Label="ProjectConfigurations">
8 <ProjectConfiguration Include="Debug|Win32"> 8 <ProjectConfiguration Include="Debug|Win32">
@@ -165,7 +165,7 @@ rc.exe -fo "$(OutDir)engine.res" "$(IntDir)engine.messages.rc"</Command>
165 <PropertyGroup> 165 <PropertyGroup>
166 <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText> 166 <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
167 </PropertyGroup> 167 </PropertyGroup>
168 <Error Condition="!Exists('..\..\packages\WixToolset.DUtil.4.0.49\build\WixToolset.DUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.DUtil.4.0.49\build\WixToolset.DUtil.props'))" /> 168 <Error Condition="!Exists('..\..\packages\WixToolset.DUtil.4.0.55\build\WixToolset.DUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.DUtil.4.0.55\build\WixToolset.DUtil.props'))" />
169 <Error Condition="!Exists('..\..\packages\Nerdbank.GitVersioning.3.1.91\build\Nerdbank.GitVersioning.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Nerdbank.GitVersioning.3.1.91\build\Nerdbank.GitVersioning.targets'))" /> 169 <Error Condition="!Exists('..\..\packages\Nerdbank.GitVersioning.3.1.91\build\Nerdbank.GitVersioning.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Nerdbank.GitVersioning.3.1.91\build\Nerdbank.GitVersioning.targets'))" />
170 </Target> 170 </Target>
171</Project> 171</Project>
diff --git a/src/engine/logging.cpp b/src/engine/logging.cpp
index 55b65336..a6412da9 100644
--- a/src/engine/logging.cpp
+++ b/src/engine/logging.cpp
@@ -583,23 +583,6 @@ extern "C" LPWSTR LoggingStringOrUnknownIfNull(
583 return wz ? wz : L"Unknown"; 583 return wz ? wz : L"Unknown";
584} 584}
585 585
586// Note: this function is not thread safe.
587extern "C" LPCSTR LoggingVersionToString(
588 __in DWORD64 dw64Version
589 )
590{
591 static CHAR szVersion[40] = { 0 };
592 HRESULT hr = S_OK;
593
594 hr = ::StringCchPrintfA(szVersion, countof(szVersion), "%I64u.%I64u.%I64u.%I64u", dw64Version >> 48 & 0xFFFF, dw64Version >> 32 & 0xFFFF, dw64Version >> 16 & 0xFFFF, dw64Version & 0xFFFF);
595 if (FAILED(hr))
596 {
597 memset(szVersion, 0, sizeof(szVersion));
598 }
599
600 return szVersion;
601}
602
603 586
604// internal function declarations 587// internal function declarations
605 588
diff --git a/src/engine/logging.h b/src/engine/logging.h
index cea4d31d..22dd54d9 100644
--- a/src/engine/logging.h
+++ b/src/engine/logging.h
@@ -133,11 +133,6 @@ LPWSTR LoggingStringOrUnknownIfNull(
133 __in LPCWSTR wz 133 __in LPCWSTR wz
134 ); 134 );
135 135
136// Note: this function is not thread safe.
137LPCSTR LoggingVersionToString(
138 __in DWORD64 dw64Version
139 );
140
141 136
142#if defined(__cplusplus) 137#if defined(__cplusplus)
143} 138}
diff --git a/src/engine/msiengine.cpp b/src/engine/msiengine.cpp
index e7cffd62..e274df28 100644
--- a/src/engine/msiengine.cpp
+++ b/src/engine/msiengine.cpp
@@ -79,7 +79,7 @@ extern "C" HRESULT MsiEngineParsePackageFromXml(
79 hr = XmlGetAttributeEx(pixnMsiPackage, L"Version", &scz); 79 hr = XmlGetAttributeEx(pixnMsiPackage, L"Version", &scz);
80 ExitOnFailure(hr, "Failed to get @Version."); 80 ExitOnFailure(hr, "Failed to get @Version.");
81 81
82 hr = FileVersionFromStringEx(scz, 0, &pPackage->Msi.qwVersion); 82 hr = VerParseVersion(scz, 0, FALSE, &pPackage->Msi.pVersion);
83 ExitOnFailure(hr, "Failed to parse @Version: %ls", scz); 83 ExitOnFailure(hr, "Failed to parse @Version: %ls", scz);
84 84
85 // @UpgradeCode 85 // @UpgradeCode
@@ -399,6 +399,7 @@ extern "C" HRESULT MsiEngineDetectPackage(
399 Trace(REPORT_STANDARD, "Detecting MSI package 0x%p", pPackage); 399 Trace(REPORT_STANDARD, "Detecting MSI package 0x%p", pPackage);
400 400
401 HRESULT hr = S_OK; 401 HRESULT hr = S_OK;
402 int nCompareResult = 0;
402 LPWSTR sczInstalledVersion = NULL; 403 LPWSTR sczInstalledVersion = NULL;
403 LPWSTR sczInstalledLanguage = NULL; 404 LPWSTR sczInstalledLanguage = NULL;
404 LPWSTR sczInstalledProductCode = NULL; 405 LPWSTR sczInstalledProductCode = NULL;
@@ -407,7 +408,7 @@ extern "C" HRESULT MsiEngineDetectPackage(
407 BOOTSTRAPPER_RELATED_OPERATION operation = BOOTSTRAPPER_RELATED_OPERATION_NONE; 408 BOOTSTRAPPER_RELATED_OPERATION operation = BOOTSTRAPPER_RELATED_OPERATION_NONE;
408 BOOTSTRAPPER_RELATED_OPERATION relatedMsiOperation = BOOTSTRAPPER_RELATED_OPERATION_NONE; 409 BOOTSTRAPPER_RELATED_OPERATION relatedMsiOperation = BOOTSTRAPPER_RELATED_OPERATION_NONE;
409 WCHAR wzProductCode[MAX_GUID_CHARS + 1] = { }; 410 WCHAR wzProductCode[MAX_GUID_CHARS + 1] = { };
410 DWORD64 qwVersion = 0; 411 VERUTIL_VERSION* pVersion = NULL;
411 UINT uLcid = 0; 412 UINT uLcid = 0;
412 BOOL fPerMachine = FALSE; 413 BOOL fPerMachine = FALSE;
413 414
@@ -416,18 +417,21 @@ extern "C" HRESULT MsiEngineDetectPackage(
416 hr = WiuGetProductInfoEx(pPackage->Msi.sczProductCode, NULL, pPackage->fPerMachine ? MSIINSTALLCONTEXT_MACHINE : MSIINSTALLCONTEXT_USERUNMANAGED, INSTALLPROPERTY_VERSIONSTRING, &sczInstalledVersion); 417 hr = WiuGetProductInfoEx(pPackage->Msi.sczProductCode, NULL, pPackage->fPerMachine ? MSIINSTALLCONTEXT_MACHINE : MSIINSTALLCONTEXT_USERUNMANAGED, INSTALLPROPERTY_VERSIONSTRING, &sczInstalledVersion);
417 if (SUCCEEDED(hr)) 418 if (SUCCEEDED(hr))
418 { 419 {
419 hr = FileVersionFromStringEx(sczInstalledVersion, 0, &pPackage->Msi.qwInstalledVersion); 420 hr = VerParseVersion(sczInstalledVersion, 0, FALSE, &pPackage->Msi.pInstalledVersion);
420 ExitOnFailure(hr, "Failed to convert version: %ls to DWORD64 for ProductCode: %ls", sczInstalledVersion, pPackage->Msi.sczProductCode); 421 ExitOnFailure(hr, "Failed to parse installed version: '%ls' for ProductCode: %ls", sczInstalledVersion, pPackage->Msi.sczProductCode);
421 422
422 // compare versions 423 // compare versions
423 if (pPackage->Msi.qwVersion < pPackage->Msi.qwInstalledVersion) 424 hr = VerCompareParsedVersions(pPackage->Msi.pVersion, pPackage->Msi.pInstalledVersion, &nCompareResult);
425 ExitOnFailure(hr, "Failed to compare version '%ls' to installed version: '%ls'", pPackage->Msi.pVersion->sczVersion, pPackage->Msi.pInstalledVersion->sczVersion);
426
427 if (nCompareResult < 0)
424 { 428 {
425 operation = BOOTSTRAPPER_RELATED_OPERATION_DOWNGRADE; 429 operation = BOOTSTRAPPER_RELATED_OPERATION_DOWNGRADE;
426 pPackage->currentState = BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED; 430 pPackage->currentState = BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED;
427 } 431 }
428 else 432 else
429 { 433 {
430 if (pPackage->Msi.qwVersion > pPackage->Msi.qwInstalledVersion) 434 if (nCompareResult > 0)
431 { 435 {
432 operation = BOOTSTRAPPER_RELATED_OPERATION_MINOR_UPDATE; 436 operation = BOOTSTRAPPER_RELATED_OPERATION_MINOR_UPDATE;
433 } 437 }
@@ -438,9 +442,9 @@ extern "C" HRESULT MsiEngineDetectPackage(
438 // Report related MSI package to BA. 442 // Report related MSI package to BA.
439 if (BOOTSTRAPPER_RELATED_OPERATION_NONE != operation) 443 if (BOOTSTRAPPER_RELATED_OPERATION_NONE != operation)
440 { 444 {
441 LogId(REPORT_STANDARD, MSG_DETECTED_RELATED_PACKAGE, pPackage->Msi.sczProductCode, LoggingPerMachineToString(pPackage->fPerMachine), LoggingVersionToString(pPackage->Msi.qwInstalledVersion), pPackage->Msi.dwLanguage, LoggingRelatedOperationToString(operation)); 445 LogId(REPORT_STANDARD, MSG_DETECTED_RELATED_PACKAGE, pPackage->Msi.sczProductCode, LoggingPerMachineToString(pPackage->fPerMachine), pPackage->Msi.pInstalledVersion->sczVersion, pPackage->Msi.dwLanguage, LoggingRelatedOperationToString(operation));
442 446
443 hr = UserExperienceOnDetectRelatedMsiPackage(pUserExperience, pPackage->sczId, pPackage->Msi.sczUpgradeCode, pPackage->Msi.sczProductCode, pPackage->fPerMachine, pPackage->Msi.qwInstalledVersion, operation); 447 hr = UserExperienceOnDetectRelatedMsiPackage(pUserExperience, pPackage->sczId, pPackage->Msi.sczUpgradeCode, pPackage->Msi.sczProductCode, pPackage->fPerMachine, pPackage->Msi.pInstalledVersion, operation);
444 ExitOnRootFailure(hr, "BA aborted detect related MSI package."); 448 ExitOnRootFailure(hr, "BA aborted detect related MSI package.");
445 } 449 }
446 } 450 }
@@ -453,21 +457,26 @@ extern "C" HRESULT MsiEngineDetectPackage(
453 hr = WiuGetProductInfoEx(sczInstalledProductCode, NULL, pPackage->fPerMachine ? MSIINSTALLCONTEXT_MACHINE : MSIINSTALLCONTEXT_USERUNMANAGED, INSTALLPROPERTY_VERSIONSTRING, &sczInstalledVersion); 457 hr = WiuGetProductInfoEx(sczInstalledProductCode, NULL, pPackage->fPerMachine ? MSIINSTALLCONTEXT_MACHINE : MSIINSTALLCONTEXT_USERUNMANAGED, INSTALLPROPERTY_VERSIONSTRING, &sczInstalledVersion);
454 if (SUCCEEDED(hr)) 458 if (SUCCEEDED(hr))
455 { 459 {
456 hr = FileVersionFromStringEx(sczInstalledVersion, 0, &qwVersion); 460 hr = VerParseVersion(sczInstalledVersion, 0, FALSE, &pVersion);
457 ExitOnFailure(hr, "Failed to convert version: %ls to DWORD64 for ProductCode: %ls", sczInstalledVersion, sczInstalledProductCode); 461 ExitOnFailure(hr, "Failed to parse dependency version: '%ls' for ProductCode: %ls", sczInstalledVersion, sczInstalledProductCode);
462
463 // compare versions
464 hr = VerCompareParsedVersions(pPackage->Msi.pVersion, pVersion, &nCompareResult);
465 ExitOnFailure(hr, "Failed to compare version '%ls' to dependency version: '%ls'", pPackage->Msi.pVersion->sczVersion, pVersion->sczVersion);
458 466
459 if (pPackage->Msi.qwVersion < qwVersion) 467 if (nCompareResult < 0)
460 { 468 {
461 LogId(REPORT_STANDARD, MSG_DETECTED_COMPATIBLE_PACKAGE_FROM_PROVIDER, pPackage->sczId, sczInstalledProviderKey, sczInstalledProductCode, sczInstalledVersion, pPackage->Msi.sczProductCode); 469 LogId(REPORT_STANDARD, MSG_DETECTED_COMPATIBLE_PACKAGE_FROM_PROVIDER, pPackage->sczId, sczInstalledProviderKey, sczInstalledProductCode, sczInstalledVersion, pPackage->Msi.sczProductCode);
462 470
463 hr = UserExperienceOnDetectCompatibleMsiPackage(pUserExperience, pPackage->sczId, sczInstalledProductCode, qwVersion); 471 hr = UserExperienceOnDetectCompatibleMsiPackage(pUserExperience, pPackage->sczId, sczInstalledProductCode, pVersion);
464 ExitOnRootFailure(hr, "BA aborted detect compatible MSI package."); 472 ExitOnRootFailure(hr, "BA aborted detect compatible MSI package.");
465 473
466 hr = StrAllocString(&pPackage->Msi.sczInstalledProductCode, sczInstalledProductCode, 0); 474 hr = StrAllocString(&pPackage->Msi.sczInstalledProductCode, sczInstalledProductCode, 0);
467 ExitOnFailure(hr, "Failed to copy the installed ProductCode to the package."); 475 ExitOnFailure(hr, "Failed to copy the installed ProductCode to the package.");
468 476
469 pPackage->Msi.qwInstalledVersion = qwVersion; 477 pPackage->Msi.pInstalledVersion = pVersion;
470 pPackage->Msi.fCompatibleInstalled = TRUE; 478 pPackage->Msi.fCompatibleInstalled = TRUE;
479 pVersion = NULL;
471 } 480 }
472 } 481 }
473 } 482 }
@@ -524,18 +533,30 @@ extern "C" HRESULT MsiEngineDetectPackage(
524 } 533 }
525 } 534 }
526 535
527 hr = FileVersionFromStringEx(sczInstalledVersion, 0, &qwVersion); 536 hr = VerParseVersion(sczInstalledVersion, 0, FALSE, &pVersion);
528 ExitOnFailure(hr, "Failed to convert version: %ls to DWORD64 for ProductCode: %ls", sczInstalledVersion, wzProductCode); 537 ExitOnFailure(hr, "Failed to parse related installed version: '%ls' for ProductCode: %ls", sczInstalledVersion, wzProductCode);
529 538
530 // compare versions 539 // compare versions
531 if (pRelatedMsi->fMinProvided && (pRelatedMsi->fMinInclusive ? (qwVersion < pRelatedMsi->qwMinVersion) : (qwVersion <= pRelatedMsi->qwMinVersion))) 540 if (pRelatedMsi->fMinProvided)
532 { 541 {
533 continue; 542 hr = VerCompareParsedVersions(pVersion, pRelatedMsi->pMinVersion, &nCompareResult);
543 ExitOnFailure(hr, "Failed to compare related installed version '%ls' to related min version: '%ls'", pVersion->sczVersion, pRelatedMsi->pMinVersion->sczVersion);
544
545 if (pRelatedMsi->fMinInclusive ? (nCompareResult < 0) : (nCompareResult <= 0))
546 {
547 continue;
548 }
534 } 549 }
535 550
536 if (pRelatedMsi->fMaxProvided && (pRelatedMsi->fMaxInclusive ? (qwVersion > pRelatedMsi->qwMaxVersion) : (qwVersion >= pRelatedMsi->qwMaxVersion))) 551 if (pRelatedMsi->fMaxProvided)
537 { 552 {
538 continue; 553 hr = VerCompareParsedVersions(pVersion, pRelatedMsi->pMaxVersion, &nCompareResult);
554 ExitOnFailure(hr, "Failed to compare related installed version '%ls' to related max version: '%ls'", pVersion->sczVersion, pRelatedMsi->pMaxVersion->sczVersion);
555
556 if (pRelatedMsi->fMaxInclusive ? (nCompareResult > 0) : (nCompareResult >= 0))
557 {
558 continue;
559 }
539 } 560 }
540 561
541 // Filter by language if necessary. 562 // Filter by language if necessary.
@@ -605,10 +626,10 @@ extern "C" HRESULT MsiEngineDetectPackage(
605 operation = BOOTSTRAPPER_RELATED_OPERATION_MAJOR_UPGRADE; 626 operation = BOOTSTRAPPER_RELATED_OPERATION_MAJOR_UPGRADE;
606 } 627 }
607 628
608 LogId(REPORT_STANDARD, MSG_DETECTED_RELATED_PACKAGE, wzProductCode, LoggingPerMachineToString(fPerMachine), LoggingVersionToString(qwVersion), uLcid, LoggingRelatedOperationToString(relatedMsiOperation)); 629 LogId(REPORT_STANDARD, MSG_DETECTED_RELATED_PACKAGE, wzProductCode, LoggingPerMachineToString(fPerMachine), pVersion->sczVersion, uLcid, LoggingRelatedOperationToString(relatedMsiOperation));
609 630
610 // Pass to BA. 631 // Pass to BA.
611 hr = UserExperienceOnDetectRelatedMsiPackage(pUserExperience, pPackage->sczId, pRelatedMsi->sczUpgradeCode, wzProductCode, fPerMachine, qwVersion, relatedMsiOperation); 632 hr = UserExperienceOnDetectRelatedMsiPackage(pUserExperience, pPackage->sczId, pRelatedMsi->sczUpgradeCode, wzProductCode, fPerMachine, pVersion, relatedMsiOperation);
612 ExitOnRootFailure(hr, "BA aborted detect related MSI package."); 633 ExitOnRootFailure(hr, "BA aborted detect related MSI package.");
613 } 634 }
614 } 635 }
@@ -667,6 +688,7 @@ LExit:
667 ReleaseStr(sczInstalledProductCode); 688 ReleaseStr(sczInstalledProductCode);
668 ReleaseStr(sczInstalledLanguage); 689 ReleaseStr(sczInstalledLanguage);
669 ReleaseStr(sczInstalledVersion); 690 ReleaseStr(sczInstalledVersion);
691 ReleaseVerutilVersion(pVersion);
670 692
671 return hr; 693 return hr;
672} 694}
@@ -684,8 +706,9 @@ extern "C" HRESULT MsiEnginePlanCalculatePackage(
684 Trace(REPORT_STANDARD, "Planning MSI package 0x%p", pPackage); 706 Trace(REPORT_STANDARD, "Planning MSI package 0x%p", pPackage);
685 707
686 HRESULT hr = S_OK; 708 HRESULT hr = S_OK;
687 DWORD64 qwVersion = pPackage->Msi.qwVersion; 709 VERUTIL_VERSION* pVersion = pPackage->Msi.pVersion;
688 DWORD64 qwInstalledVersion = pPackage->Msi.qwInstalledVersion; 710 VERUTIL_VERSION* pInstalledVersion = pPackage->Msi.pInstalledVersion;
711 int nCompareResult = 0;
689 BOOTSTRAPPER_ACTION_STATE execute = BOOTSTRAPPER_ACTION_STATE_NONE; 712 BOOTSTRAPPER_ACTION_STATE execute = BOOTSTRAPPER_ACTION_STATE_NONE;
690 BOOTSTRAPPER_ACTION_STATE rollback = BOOTSTRAPPER_ACTION_STATE_NONE; 713 BOOTSTRAPPER_ACTION_STATE rollback = BOOTSTRAPPER_ACTION_STATE_NONE;
691 BOOL fFeatureActionDelta = FALSE; 714 BOOL fFeatureActionDelta = FALSE;
@@ -739,10 +762,13 @@ extern "C" HRESULT MsiEnginePlanCalculatePackage(
739 case BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED: 762 case BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED:
740 if (BOOTSTRAPPER_REQUEST_STATE_PRESENT == pPackage->requested || BOOTSTRAPPER_REQUEST_STATE_REPAIR == pPackage->requested) 763 if (BOOTSTRAPPER_REQUEST_STATE_PRESENT == pPackage->requested || BOOTSTRAPPER_REQUEST_STATE_REPAIR == pPackage->requested)
741 { 764 {
765 hr = VerCompareParsedVersions(pVersion, pInstalledVersion, &nCompareResult);
766 ExitOnFailure(hr, "Failed to compare '%ls' to '%ls' for planning.", pVersion->sczVersion, pInstalledVersion->sczVersion);
767
742 // Take a look at the version and determine if this is a potential 768 // Take a look at the version and determine if this is a potential
743 // minor upgrade (same ProductCode newer ProductVersion), otherwise, 769 // minor upgrade (same ProductCode newer ProductVersion), otherwise,
744 // there is a newer version so no work necessary. 770 // there is a newer version so no work necessary.
745 if (qwVersion > qwInstalledVersion) 771 if (nCompareResult > 0)
746 { 772 {
747 execute = BOOTSTRAPPER_ACTION_STATE_MINOR_UPGRADE; 773 execute = BOOTSTRAPPER_ACTION_STATE_MINOR_UPGRADE;
748 } 774 }
@@ -1014,20 +1040,18 @@ extern "C" HRESULT MsiEngineAddCompatiblePackage(
1014 } 1040 }
1015 1041
1016 // Read in the compatible ProductVersion if not already available. 1042 // Read in the compatible ProductVersion if not already available.
1017 if (pPackage->Msi.qwInstalledVersion) 1043 if (pPackage->Msi.pInstalledVersion)
1018 { 1044 {
1019 pCompatiblePackage->Msi.qwVersion = pPackage->Msi.qwInstalledVersion; 1045 hr = VerCopyVersion(pPackage->Msi.pInstalledVersion, &pCompatiblePackage->Msi.pVersion);
1020 1046 ExitOnFailure(hr, "Failed to copy version for compatible package.");
1021 hr = FileVersionToStringEx(pCompatiblePackage->Msi.qwVersion, &sczInstalledVersion);
1022 ExitOnFailure(hr, "Failed to format version number string.");
1023 } 1047 }
1024 else 1048 else
1025 { 1049 {
1026 hr = WiuGetProductInfoEx(pCompatiblePackage->Msi.sczProductCode, NULL, pPackage->fPerMachine ? MSIINSTALLCONTEXT_MACHINE : MSIINSTALLCONTEXT_USERUNMANAGED, INSTALLPROPERTY_VERSIONSTRING, &sczInstalledVersion); 1050 hr = WiuGetProductInfoEx(pCompatiblePackage->Msi.sczProductCode, NULL, pPackage->fPerMachine ? MSIINSTALLCONTEXT_MACHINE : MSIINSTALLCONTEXT_USERUNMANAGED, INSTALLPROPERTY_VERSIONSTRING, &sczInstalledVersion);
1027 ExitOnFailure(hr, "Failed to read version from compatible package."); 1051 ExitOnFailure(hr, "Failed to read version from compatible package.");
1028 1052
1029 hr = FileVersionFromStringEx(sczInstalledVersion, 0, &pCompatiblePackage->Msi.qwVersion); 1053 hr = VerParseVersion(sczInstalledVersion, 0, FALSE, &pCompatiblePackage->Msi.pVersion);
1030 ExitOnFailure(hr, "Failed to convert version: %ls to DWORD64 for ProductCode: %ls", sczInstalledVersion, pCompatiblePackage->Msi.sczProductCode); 1054 ExitOnFailure(hr, "Failed to parse version: '%ls' for ProductCode: %ls", sczInstalledVersion, pCompatiblePackage->Msi.sczProductCode);
1031 } 1055 }
1032 1056
1033 // For now, copy enough information to support uninstalling the newer, compatible package. 1057 // For now, copy enough information to support uninstalling the newer, compatible package.
@@ -1046,7 +1070,7 @@ extern "C" HRESULT MsiEngineAddCompatiblePackage(
1046 ExitOnFailure(hr, "Failed to format log path variable for compatible package."); 1070 ExitOnFailure(hr, "Failed to format log path variable for compatible package.");
1047 1071
1048 // Use the default cache ID generation from the binder. 1072 // Use the default cache ID generation from the binder.
1049 hr = StrAllocFormatted(&pCompatiblePackage->sczCacheId, L"%lsv%ls", pCompatiblePackage->sczId, sczInstalledVersion); 1073 hr = StrAllocFormatted(&pCompatiblePackage->sczCacheId, L"%lsv%ls", pCompatiblePackage->sczId, pCompatiblePackage->Msi.pVersion->sczVersion);
1050 ExitOnFailure(hr, "Failed to format cache ID for compatible package."); 1074 ExitOnFailure(hr, "Failed to format cache ID for compatible package.");
1051 1075
1052 pCompatiblePackage->currentState = BOOTSTRAPPER_PACKAGE_STATE_PRESENT; 1076 pCompatiblePackage->currentState = BOOTSTRAPPER_PACKAGE_STATE_PRESENT;
@@ -1068,7 +1092,7 @@ extern "C" HRESULT MsiEngineAddCompatiblePackage(
1068 ExitOnFailure(hr, "Failed to copy the compatible provider key."); 1092 ExitOnFailure(hr, "Failed to copy the compatible provider key.");
1069 1093
1070 // Assume the package version is the same as the provider version. 1094 // Assume the package version is the same as the provider version.
1071 hr = StrAllocString(&pCompatibleProvider->sczVersion, sczInstalledVersion, 0); 1095 hr = StrAllocString(&pCompatibleProvider->sczVersion, pCompatiblePackage->Msi.pVersion->sczVersion, 0);
1072 ExitOnFailure(hr, "Failed to copy the compatible provider version."); 1096 ExitOnFailure(hr, "Failed to copy the compatible provider version.");
1073 1097
1074 // Assume provider keys are similarly authored for this package. 1098 // Assume provider keys are similarly authored for this package.
@@ -1479,7 +1503,7 @@ static HRESULT ParseRelatedMsiFromXml(
1479 { 1503 {
1480 ExitOnFailure(hr, "Failed to get @MinVersion."); 1504 ExitOnFailure(hr, "Failed to get @MinVersion.");
1481 1505
1482 hr = FileVersionFromStringEx(scz, 0, &pRelatedMsi->qwMinVersion); 1506 hr = VerParseVersion(scz, 0, FALSE, &pRelatedMsi->pMinVersion);
1483 ExitOnFailure(hr, "Failed to parse @MinVersion: %ls", scz); 1507 ExitOnFailure(hr, "Failed to parse @MinVersion: %ls", scz);
1484 1508
1485 // flag that we have a min version 1509 // flag that we have a min version
@@ -1496,7 +1520,7 @@ static HRESULT ParseRelatedMsiFromXml(
1496 { 1520 {
1497 ExitOnFailure(hr, "Failed to get @MaxVersion."); 1521 ExitOnFailure(hr, "Failed to get @MaxVersion.");
1498 1522
1499 hr = FileVersionFromStringEx(scz, 0, &pRelatedMsi->qwMaxVersion); 1523 hr = VerParseVersion(scz, 0, FALSE, &pRelatedMsi->pMaxVersion);
1500 ExitOnFailure(hr, "Failed to parse @MaxVersion: %ls", scz); 1524 ExitOnFailure(hr, "Failed to parse @MaxVersion: %ls", scz);
1501 1525
1502 // flag that we have a max version 1526 // flag that we have a max version
diff --git a/src/engine/package.h b/src/engine/package.h
index 05965a16..c5873765 100644
--- a/src/engine/package.h
+++ b/src/engine/package.h
@@ -123,8 +123,8 @@ typedef struct _BURN_MSIFEATURE
123typedef struct _BURN_RELATED_MSI 123typedef struct _BURN_RELATED_MSI
124{ 124{
125 LPWSTR sczUpgradeCode; 125 LPWSTR sczUpgradeCode;
126 DWORD64 qwMinVersion; 126 VERUTIL_VERSION* pMinVersion;
127 DWORD64 qwMaxVersion; 127 VERUTIL_VERSION* pMaxVersion;
128 BOOL fMinProvided; 128 BOOL fMinProvided;
129 BOOL fMaxProvided; 129 BOOL fMaxProvided;
130 BOOL fMinInclusive; 130 BOOL fMinInclusive;
@@ -236,9 +236,9 @@ typedef struct _BURN_PACKAGE
236 { 236 {
237 LPWSTR sczProductCode; 237 LPWSTR sczProductCode;
238 DWORD dwLanguage; 238 DWORD dwLanguage;
239 DWORD64 qwVersion; 239 VERUTIL_VERSION* pVersion;
240 LPWSTR sczInstalledProductCode; 240 LPWSTR sczInstalledProductCode;
241 DWORD64 qwInstalledVersion; 241 VERUTIL_VERSION* pInstalledVersion;
242 LPWSTR sczUpgradeCode; 242 LPWSTR sczUpgradeCode;
243 243
244 BURN_MSIPROPERTY* rgProperties; 244 BURN_MSIPROPERTY* rgProperties;
diff --git a/src/engine/packages.config b/src/engine/packages.config
index e7fa32d0..68222d34 100644
--- a/src/engine/packages.config
+++ b/src/engine/packages.config
@@ -1,5 +1,5 @@
1<?xml version="1.0" encoding="utf-8"?> 1<?xml version="1.0" encoding="utf-8"?>
2<packages> 2<packages>
3 <package id="Nerdbank.GitVersioning" version="3.1.91" targetFramework="native" developmentDependency="true" /> 3 <package id="Nerdbank.GitVersioning" version="3.1.91" targetFramework="native" developmentDependency="true" />
4 <package id="WixToolset.DUtil" version="4.0.49" targetFramework="native" /> 4 <package id="WixToolset.DUtil" version="4.0.55" targetFramework="native" />
5</packages> \ No newline at end of file 5</packages> \ No newline at end of file
diff --git a/src/engine/plan.cpp b/src/engine/plan.cpp
index 0b040bf8..f6b681b6 100644
--- a/src/engine/plan.cpp
+++ b/src/engine/plan.cpp
@@ -530,7 +530,7 @@ extern "C" HRESULT PlanPackages(
530 530
531 pAction->type = BURN_EXECUTE_ACTION_TYPE_COMPATIBLE_PACKAGE; 531 pAction->type = BURN_EXECUTE_ACTION_TYPE_COMPATIBLE_PACKAGE;
532 pAction->compatiblePackage.pReferencePackage = pPackage; 532 pAction->compatiblePackage.pReferencePackage = pPackage;
533 pAction->compatiblePackage.qwInstalledVersion = pCompatiblePackage->Msi.qwVersion; 533 pAction->compatiblePackage.pInstalledVersion = pCompatiblePackage->Msi.pVersion;
534 534
535 hr = StrAllocString(&pAction->compatiblePackage.sczInstalledProductCode, pCompatiblePackage->Msi.sczProductCode, 0); 535 hr = StrAllocString(&pAction->compatiblePackage.sczInstalledProductCode, pCompatiblePackage->Msi.sczProductCode, 0);
536 ExitOnFailure(hr, "Failed to copy installed ProductCode"); 536 ExitOnFailure(hr, "Failed to copy installed ProductCode");
@@ -880,7 +880,7 @@ static HRESULT ProcessPackage(
880 { 880 {
881 AssertSz(BURN_PACKAGE_TYPE_MSI == pPackage->type, "Currently only MSI packages have compatible packages."); 881 AssertSz(BURN_PACKAGE_TYPE_MSI == pPackage->type, "Currently only MSI packages have compatible packages.");
882 882
883 hr = UserExperienceOnPlanCompatibleMsiPackageBegin(pUX, pCompatiblePackageParent->sczId, pPackage->sczId, pPackage->Msi.qwVersion, &pPackage->requested); 883 hr = UserExperienceOnPlanCompatibleMsiPackageBegin(pUX, pCompatiblePackageParent->sczId, pPackage->sczId, pPackage->Msi.pVersion, &pPackage->requested);
884 ExitOnRootFailure(hr, "BA aborted plan compatible MSI package begin."); 884 ExitOnRootFailure(hr, "BA aborted plan compatible MSI package begin.");
885 } 885 }
886 else 886 else
@@ -1207,6 +1207,7 @@ extern "C" HRESULT PlanRelatedBundlesBegin(
1207 LPWSTR* rgsczAncestors = NULL; 1207 LPWSTR* rgsczAncestors = NULL;
1208 UINT cAncestors = 0; 1208 UINT cAncestors = 0;
1209 STRINGDICT_HANDLE sdAncestors = NULL; 1209 STRINGDICT_HANDLE sdAncestors = NULL;
1210 int nCompareResult = 0;
1210 1211
1211 if (pRegistration->sczAncestors) 1212 if (pRegistration->sczAncestors)
1212 { 1213 {
@@ -1261,7 +1262,10 @@ extern "C" HRESULT PlanRelatedBundlesBegin(
1261 case BOOTSTRAPPER_RELATION_UPGRADE: 1262 case BOOTSTRAPPER_RELATION_UPGRADE:
1262 if (BOOTSTRAPPER_RELATION_UPGRADE != relationType && BOOTSTRAPPER_ACTION_UNINSTALL < pPlan->action) 1263 if (BOOTSTRAPPER_RELATION_UPGRADE != relationType && BOOTSTRAPPER_ACTION_UNINSTALL < pPlan->action)
1263 { 1264 {
1264 pRelatedBundle->package.requested = (pRegistration->qwVersion > pRelatedBundle->qwVersion) ? BOOTSTRAPPER_REQUEST_STATE_ABSENT : BOOTSTRAPPER_REQUEST_STATE_NONE; 1265 hr = VerCompareParsedVersions(pRegistration->pVersion, pRelatedBundle->pVersion, &nCompareResult);
1266 ExitOnFailure(hr, "Failed to compare bundle version '%ls' to related bundle version '%ls'", pRegistration->pVersion, pRelatedBundle->pVersion);
1267
1268 pRelatedBundle->package.requested = (nCompareResult > 0) ? BOOTSTRAPPER_REQUEST_STATE_ABSENT : BOOTSTRAPPER_REQUEST_STATE_NONE;
1265 } 1269 }
1266 break; 1270 break;
1267 case BOOTSTRAPPER_RELATION_PATCH: __fallthrough; 1271 case BOOTSTRAPPER_RELATION_PATCH: __fallthrough;
diff --git a/src/engine/plan.h b/src/engine/plan.h
index db9745e9..4fd3380e 100644
--- a/src/engine/plan.h
+++ b/src/engine/plan.h
@@ -305,7 +305,7 @@ typedef struct _BURN_EXECUTE_ACTION
305 { 305 {
306 BURN_PACKAGE* pReferencePackage; 306 BURN_PACKAGE* pReferencePackage;
307 LPWSTR sczInstalledProductCode; 307 LPWSTR sczInstalledProductCode;
308 DWORD64 qwInstalledVersion; 308 VERUTIL_VERSION* pInstalledVersion;
309 } compatiblePackage; 309 } compatiblePackage;
310 }; 310 };
311} BURN_EXECUTE_ACTION; 311} BURN_EXECUTE_ACTION;
diff --git a/src/engine/precomp.h b/src/engine/precomp.h
index b5c5e65e..2bceab58 100644
--- a/src/engine/precomp.h
+++ b/src/engine/precomp.h
@@ -24,6 +24,7 @@
24#define DUTIL_SOURCE_DEFAULT DUTIL_SOURCE_EXTERNAL 24#define DUTIL_SOURCE_DEFAULT DUTIL_SOURCE_EXTERNAL
25 25
26#include <dutil.h> 26#include <dutil.h>
27#include <verutil.h>
27#include <aclutil.h> 28#include <aclutil.h>
28#include <apputil.h> 29#include <apputil.h>
29#include <buffutil.h> 30#include <buffutil.h>
diff --git a/src/engine/registration.cpp b/src/engine/registration.cpp
index eace62ce..3c3dc95d 100644
--- a/src/engine/registration.cpp
+++ b/src/engine/registration.cpp
@@ -133,7 +133,7 @@ extern "C" HRESULT RegistrationParseFromXml(
133 hr = XmlGetAttributeEx(pixnRegistrationNode, L"Version", &scz); 133 hr = XmlGetAttributeEx(pixnRegistrationNode, L"Version", &scz);
134 ExitOnFailure(hr, "Failed to get @Version."); 134 ExitOnFailure(hr, "Failed to get @Version.");
135 135
136 hr = FileVersionFromStringEx(scz, 0, &pRegistration->qwVersion); 136 hr = VerParseVersion(scz, 0, FALSE, &pRegistration->pVersion);
137 ExitOnFailure(hr, "Failed to parse @Version: %ls", scz); 137 ExitOnFailure(hr, "Failed to parse @Version: %ls", scz);
138 138
139 // @ProviderKey 139 // @ProviderKey
@@ -436,7 +436,7 @@ extern "C" HRESULT RegistrationSetVariables(
436 hr = VariableSetString(pVariables, BURN_BUNDLE_TAG, pRegistration->sczTag, TRUE, FALSE); 436 hr = VariableSetString(pVariables, BURN_BUNDLE_TAG, pRegistration->sczTag, TRUE, FALSE);
437 ExitOnFailure(hr, "Failed to overwrite the bundle tag built-in variable."); 437 ExitOnFailure(hr, "Failed to overwrite the bundle tag built-in variable.");
438 438
439 hr = VariableSetVersion(pVariables, BURN_BUNDLE_VERSION, pRegistration->qwVersion, TRUE); 439 hr = VariableSetVersion(pVariables, BURN_BUNDLE_VERSION, pRegistration->pVersion, TRUE);
440 ExitOnFailure(hr, "Failed to overwrite the bundle tag built-in variable."); 440 ExitOnFailure(hr, "Failed to overwrite the bundle tag built-in variable.");
441 441
442LExit: 442LExit:
@@ -630,15 +630,13 @@ extern "C" HRESULT RegistrationSessionBegin(
630 hr = RegWriteStringArray(hkRegistration, BURN_REGISTRATION_REGISTRY_BUNDLE_PATCH_CODE, pRegistration->rgsczPatchCodes, pRegistration->cPatchCodes); 630 hr = RegWriteStringArray(hkRegistration, BURN_REGISTRATION_REGISTRY_BUNDLE_PATCH_CODE, pRegistration->rgsczPatchCodes, pRegistration->cPatchCodes);
631 ExitOnFailure(hr, "Failed to write %ls value.", BURN_REGISTRATION_REGISTRY_BUNDLE_PATCH_CODE); 631 ExitOnFailure(hr, "Failed to write %ls value.", BURN_REGISTRATION_REGISTRY_BUNDLE_PATCH_CODE);
632 632
633 hr = RegWriteStringFormatted(hkRegistration, BURN_REGISTRATION_REGISTRY_BUNDLE_VERSION, L"%hu.%hu.%hu.%hu", 633 hr = RegWriteString(hkRegistration, BURN_REGISTRATION_REGISTRY_BUNDLE_VERSION, pRegistration->pVersion->sczVersion);
634 static_cast<WORD>(pRegistration->qwVersion >> 48), static_cast<WORD>(pRegistration->qwVersion >> 32),
635 static_cast<WORD>(pRegistration->qwVersion >> 16), static_cast<WORD>(pRegistration->qwVersion));
636 ExitOnFailure(hr, "Failed to write %ls value.", BURN_REGISTRATION_REGISTRY_BUNDLE_VERSION); 634 ExitOnFailure(hr, "Failed to write %ls value.", BURN_REGISTRATION_REGISTRY_BUNDLE_VERSION);
637 635
638 hr = RegWriteNumber(hkRegistration, REGISTRY_BUNDLE_VERSION_MAJOR, static_cast<WORD>(pRegistration->qwVersion >> 48)); 636 hr = RegWriteNumber(hkRegistration, REGISTRY_BUNDLE_VERSION_MAJOR, pRegistration->pVersion->dwMajor);
639 ExitOnFailure(hr, "Failed to write %ls value.", REGISTRY_BUNDLE_VERSION_MAJOR); 637 ExitOnFailure(hr, "Failed to write %ls value.", REGISTRY_BUNDLE_VERSION_MAJOR);
640 638
641 hr = RegWriteNumber(hkRegistration, REGISTRY_BUNDLE_VERSION_MINOR, static_cast<WORD>(pRegistration->qwVersion >> 32)); 639 hr = RegWriteNumber(hkRegistration, REGISTRY_BUNDLE_VERSION_MINOR, pRegistration->pVersion->dwMinor);
642 ExitOnFailure(hr, "Failed to write %ls value.", REGISTRY_BUNDLE_VERSION_MINOR); 640 ExitOnFailure(hr, "Failed to write %ls value.", REGISTRY_BUNDLE_VERSION_MINOR);
643 641
644 if (pRegistration->sczProviderKey) 642 if (pRegistration->sczProviderKey)
diff --git a/src/engine/registration.h b/src/engine/registration.h
index c830a06d..fa7be368 100644
--- a/src/engine/registration.h
+++ b/src/engine/registration.h
@@ -59,7 +59,7 @@ typedef struct _BURN_RELATED_BUNDLE
59{ 59{
60 BOOTSTRAPPER_RELATION_TYPE relationType; 60 BOOTSTRAPPER_RELATION_TYPE relationType;
61 61
62 DWORD64 qwVersion; 62 VERUTIL_VERSION* pVersion;
63 LPWSTR sczTag; 63 LPWSTR sczTag;
64 64
65 BURN_PACKAGE package; 65 BURN_PACKAGE package;
@@ -105,7 +105,7 @@ typedef struct _BURN_REGISTRATION
105 LPWSTR *rgsczPatchCodes; 105 LPWSTR *rgsczPatchCodes;
106 DWORD cPatchCodes; 106 DWORD cPatchCodes;
107 107
108 DWORD64 qwVersion; 108 VERUTIL_VERSION* pVersion;
109 LPWSTR sczActiveParent; 109 LPWSTR sczActiveParent;
110 LPWSTR sczProviderKey; 110 LPWSTR sczProviderKey;
111 LPWSTR sczExecutableName; 111 LPWSTR sczExecutableName;
diff --git a/src/engine/relatedbundle.cpp b/src/engine/relatedbundle.cpp
index 87794177..e6d6516a 100644
--- a/src/engine/relatedbundle.cpp
+++ b/src/engine/relatedbundle.cpp
@@ -396,6 +396,7 @@ static HRESULT LoadRelatedBundleFromKey(
396{ 396{
397 HRESULT hr = S_OK; 397 HRESULT hr = S_OK;
398 DWORD64 qwEngineVersion = 0; 398 DWORD64 qwEngineVersion = 0;
399 LPWSTR sczBundleVersion = NULL;
399 LPWSTR sczCachePath = NULL; 400 LPWSTR sczCachePath = NULL;
400 DWORD64 qwFileSize = 0; 401 DWORD64 qwFileSize = 0;
401 BURN_DEPENDENCY_PROVIDER dependencyProvider = { }; 402 BURN_DEPENDENCY_PROVIDER dependencyProvider = { };
@@ -407,9 +408,12 @@ static HRESULT LoadRelatedBundleFromKey(
407 hr = S_OK; 408 hr = S_OK;
408 } 409 }
409 410
410 hr = RegReadVersion(hkBundleId, BURN_REGISTRATION_REGISTRY_BUNDLE_VERSION, &pRelatedBundle->qwVersion); 411 hr = RegReadString(hkBundleId, BURN_REGISTRATION_REGISTRY_BUNDLE_VERSION, &sczBundleVersion);
411 ExitOnFailure(hr, "Failed to read version from registry for bundle: %ls", wzRelatedBundleId); 412 ExitOnFailure(hr, "Failed to read version from registry for bundle: %ls", wzRelatedBundleId);
412 413
414 hr = VerParseVersion(sczBundleVersion, 0, FALSE, &pRelatedBundle->pVersion);
415 ExitOnFailure(hr, "Failed to parse pseudo bundle version: %ls", sczBundleVersion);
416
413 hr = RegReadString(hkBundleId, BURN_REGISTRATION_REGISTRY_BUNDLE_CACHE_PATH, &sczCachePath); 417 hr = RegReadString(hkBundleId, BURN_REGISTRATION_REGISTRY_BUNDLE_CACHE_PATH, &sczCachePath);
414 ExitOnFailure(hr, "Failed to read cache path from registry for bundle: %ls", wzRelatedBundleId); 418 ExitOnFailure(hr, "Failed to read cache path from registry for bundle: %ls", wzRelatedBundleId);
415 419
@@ -423,7 +427,7 @@ static HRESULT LoadRelatedBundleFromKey(
423 427
424 dependencyProvider.fImported = TRUE; 428 dependencyProvider.fImported = TRUE;
425 429
426 hr = FileVersionToStringEx(pRelatedBundle->qwVersion, &dependencyProvider.sczVersion); 430 hr = StrAllocString(&dependencyProvider.sczVersion, pRelatedBundle->pVersion->sczVersion, 0);
427 ExitOnFailure(hr, "Failed to copy version for bundle: %ls", wzRelatedBundleId); 431 ExitOnFailure(hr, "Failed to copy version for bundle: %ls", wzRelatedBundleId);
428 432
429 hr = RegReadString(hkBundleId, BURN_REGISTRATION_REGISTRY_BUNDLE_DISPLAY_NAME, &dependencyProvider.sczDisplayName); 433 hr = RegReadString(hkBundleId, BURN_REGISTRATION_REGISTRY_BUNDLE_DISPLAY_NAME, &dependencyProvider.sczDisplayName);
@@ -452,6 +456,7 @@ static HRESULT LoadRelatedBundleFromKey(
452LExit: 456LExit:
453 DependencyUninitialize(&dependencyProvider); 457 DependencyUninitialize(&dependencyProvider);
454 ReleaseStr(sczCachePath); 458 ReleaseStr(sczCachePath);
459 ReleaseStr(sczBundleVersion);
455 460
456 return hr; 461 return hr;
457} 462}
diff --git a/src/engine/search.cpp b/src/engine/search.cpp
index 2978edd3..1dbcf56b 100644
--- a/src/engine/search.cpp
+++ b/src/engine/search.cpp
@@ -754,6 +754,7 @@ static HRESULT FileSearchVersion(
754 HRESULT hr = S_OK; 754 HRESULT hr = S_OK;
755 ULARGE_INTEGER uliVersion = { }; 755 ULARGE_INTEGER uliVersion = { };
756 LPWSTR sczPath = NULL; 756 LPWSTR sczPath = NULL;
757 VERUTIL_VERSION* pVersion = NULL;
757 758
758 // format path 759 // format path
759 hr = VariableFormatString(pVariables, pSearch->FileSearch.sczPath, &sczPath, NULL); 760 hr = VariableFormatString(pVariables, pSearch->FileSearch.sczPath, &sczPath, NULL);
@@ -767,14 +768,18 @@ static HRESULT FileSearchVersion(
767 LogStringLine(REPORT_STANDARD, "File search: %ls, did not find path: %ls", pSearch->sczKey, sczPath); 768 LogStringLine(REPORT_STANDARD, "File search: %ls, did not find path: %ls", pSearch->sczKey, sczPath);
768 ExitFunction1(hr = S_OK); 769 ExitFunction1(hr = S_OK);
769 } 770 }
770 ExitOnFailure(hr, "Failed get file version."); 771 ExitOnFailure(hr, "Failed to get file version.");
772
773 hr = VerVersionFromQword(uliVersion.QuadPart, &pVersion);
774 ExitOnFailure(hr, "Failed to create version from file version.");
771 775
772 // set variable 776 // set variable
773 hr = VariableSetVersion(pVariables, pSearch->sczVariable, uliVersion.QuadPart, FALSE); 777 hr = VariableSetVersion(pVariables, pSearch->sczVariable, pVersion, FALSE);
774 ExitOnFailure(hr, "Failed to set variable."); 778 ExitOnFailure(hr, "Failed to set variable.");
775 779
776LExit: 780LExit:
777 StrSecureZeroFreeString(sczPath); 781 StrSecureZeroFreeString(sczPath);
782 ReleaseVerutilVersion(pVersion);
778 return hr; 783 return hr;
779} 784}
780 785
diff --git a/src/engine/userexperience.cpp b/src/engine/userexperience.cpp
index 6b0e3bf5..6ab28cde 100644
--- a/src/engine/userexperience.cpp
+++ b/src/engine/userexperience.cpp
@@ -646,7 +646,7 @@ EXTERN_C BAAPI UserExperienceOnDetectCompatibleMsiPackage(
646 __in BURN_USER_EXPERIENCE* pUserExperience, 646 __in BURN_USER_EXPERIENCE* pUserExperience,
647 __in_z LPCWSTR wzPackageId, 647 __in_z LPCWSTR wzPackageId,
648 __in_z LPCWSTR wzCompatiblePackageId, 648 __in_z LPCWSTR wzCompatiblePackageId,
649 __in DWORD64 dw64CompatiblePackageVersion 649 __in VERUTIL_VERSION* pCompatiblePackageVersion
650 ) 650 )
651{ 651{
652 HRESULT hr = S_OK; 652 HRESULT hr = S_OK;
@@ -656,7 +656,7 @@ EXTERN_C BAAPI UserExperienceOnDetectCompatibleMsiPackage(
656 args.cbSize = sizeof(args); 656 args.cbSize = sizeof(args);
657 args.wzPackageId = wzPackageId; 657 args.wzPackageId = wzPackageId;
658 args.wzCompatiblePackageId = wzCompatiblePackageId; 658 args.wzCompatiblePackageId = wzCompatiblePackageId;
659 args.dw64CompatiblePackageVersion = dw64CompatiblePackageVersion; 659 args.wzCompatiblePackageVersion = pCompatiblePackageVersion->sczVersion;
660 660
661 results.cbSize = sizeof(results); 661 results.cbSize = sizeof(results);
662 662
@@ -699,7 +699,7 @@ EXTERN_C BAAPI UserExperienceOnDetectForwardCompatibleBundle(
699 __in BOOTSTRAPPER_RELATION_TYPE relationType, 699 __in BOOTSTRAPPER_RELATION_TYPE relationType,
700 __in_z LPCWSTR wzBundleTag, 700 __in_z LPCWSTR wzBundleTag,
701 __in BOOL fPerMachine, 701 __in BOOL fPerMachine,
702 __in DWORD64 dw64Version, 702 __in VERUTIL_VERSION* pVersion,
703 __inout BOOL* pfIgnoreBundle 703 __inout BOOL* pfIgnoreBundle
704 ) 704 )
705{ 705{
@@ -712,7 +712,7 @@ EXTERN_C BAAPI UserExperienceOnDetectForwardCompatibleBundle(
712 args.relationType = relationType; 712 args.relationType = relationType;
713 args.wzBundleTag = wzBundleTag; 713 args.wzBundleTag = wzBundleTag;
714 args.fPerMachine = fPerMachine; 714 args.fPerMachine = fPerMachine;
715 args.dw64Version = dw64Version; 715 args.wzVersion = pVersion->sczVersion;
716 716
717 results.cbSize = sizeof(results); 717 results.cbSize = sizeof(results);
718 results.fIgnoreBundle = *pfIgnoreBundle; 718 results.fIgnoreBundle = *pfIgnoreBundle;
@@ -817,7 +817,7 @@ EXTERN_C BAAPI UserExperienceOnDetectRelatedBundle(
817 __in BOOTSTRAPPER_RELATION_TYPE relationType, 817 __in BOOTSTRAPPER_RELATION_TYPE relationType,
818 __in_z LPCWSTR wzBundleTag, 818 __in_z LPCWSTR wzBundleTag,
819 __in BOOL fPerMachine, 819 __in BOOL fPerMachine,
820 __in DWORD64 dw64Version, 820 __in VERUTIL_VERSION* pVersion,
821 __in BOOTSTRAPPER_RELATED_OPERATION operation 821 __in BOOTSTRAPPER_RELATED_OPERATION operation
822 ) 822 )
823{ 823{
@@ -830,7 +830,7 @@ EXTERN_C BAAPI UserExperienceOnDetectRelatedBundle(
830 args.relationType = relationType; 830 args.relationType = relationType;
831 args.wzBundleTag = wzBundleTag; 831 args.wzBundleTag = wzBundleTag;
832 args.fPerMachine = fPerMachine; 832 args.fPerMachine = fPerMachine;
833 args.dw64Version = dw64Version; 833 args.wzVersion = pVersion->sczVersion;
834 args.operation = operation; 834 args.operation = operation;
835 835
836 results.cbSize = sizeof(results); 836 results.cbSize = sizeof(results);
@@ -853,7 +853,7 @@ EXTERN_C BAAPI UserExperienceOnDetectRelatedMsiPackage(
853 __in_z LPCWSTR wzUpgradeCode, 853 __in_z LPCWSTR wzUpgradeCode,
854 __in_z LPCWSTR wzProductCode, 854 __in_z LPCWSTR wzProductCode,
855 __in BOOL fPerMachine, 855 __in BOOL fPerMachine,
856 __in DWORD64 dw64Version, 856 __in VERUTIL_VERSION* pVersion,
857 __in BOOTSTRAPPER_RELATED_OPERATION operation 857 __in BOOTSTRAPPER_RELATED_OPERATION operation
858 ) 858 )
859{ 859{
@@ -866,7 +866,7 @@ EXTERN_C BAAPI UserExperienceOnDetectRelatedMsiPackage(
866 args.wzUpgradeCode = wzUpgradeCode; 866 args.wzUpgradeCode = wzUpgradeCode;
867 args.wzProductCode = wzProductCode; 867 args.wzProductCode = wzProductCode;
868 args.fPerMachine = fPerMachine; 868 args.fPerMachine = fPerMachine;
869 args.dw64Version = dw64Version; 869 args.wzVersion = pVersion->sczVersion;
870 args.operation = operation; 870 args.operation = operation;
871 871
872 results.cbSize = sizeof(results); 872 results.cbSize = sizeof(results);
@@ -917,7 +917,7 @@ EXTERN_C BAAPI UserExperienceOnDetectUpdate(
917 __in BURN_USER_EXPERIENCE* pUserExperience, 917 __in BURN_USER_EXPERIENCE* pUserExperience,
918 __in_z LPCWSTR wzUpdateLocation, 918 __in_z LPCWSTR wzUpdateLocation,
919 __in DWORD64 dw64Size, 919 __in DWORD64 dw64Size,
920 __in DWORD64 dw64Version, 920 __in VERUTIL_VERSION* pVersion,
921 __in_z_opt LPCWSTR wzTitle, 921 __in_z_opt LPCWSTR wzTitle,
922 __in_z_opt LPCWSTR wzSummary, 922 __in_z_opt LPCWSTR wzSummary,
923 __in_z_opt LPCWSTR wzContentType, 923 __in_z_opt LPCWSTR wzContentType,
@@ -932,7 +932,7 @@ EXTERN_C BAAPI UserExperienceOnDetectUpdate(
932 args.cbSize = sizeof(args); 932 args.cbSize = sizeof(args);
933 args.wzUpdateLocation = wzUpdateLocation; 933 args.wzUpdateLocation = wzUpdateLocation;
934 args.dw64Size = dw64Size; 934 args.dw64Size = dw64Size;
935 args.dw64Version = dw64Version; 935 args.wzVersion = pVersion->sczVersion;
936 args.wzTitle = wzTitle; 936 args.wzTitle = wzTitle;
937 args.wzSummary = wzSummary; 937 args.wzSummary = wzSummary;
938 args.wzContentType = wzContentType; 938 args.wzContentType = wzContentType;
@@ -1414,7 +1414,7 @@ EXTERN_C BAAPI UserExperienceOnPlanCompatibleMsiPackageBegin(
1414 __in BURN_USER_EXPERIENCE* pUserExperience, 1414 __in BURN_USER_EXPERIENCE* pUserExperience,
1415 __in_z LPCWSTR wzPackageId, 1415 __in_z LPCWSTR wzPackageId,
1416 __in_z LPCWSTR wzCompatiblePackageId, 1416 __in_z LPCWSTR wzCompatiblePackageId,
1417 __in DWORD64 dw64CompatiblePackageVersion, 1417 __in VERUTIL_VERSION* pCompatiblePackageVersion,
1418 __inout BOOTSTRAPPER_REQUEST_STATE* pRequestedState 1418 __inout BOOTSTRAPPER_REQUEST_STATE* pRequestedState
1419 ) 1419 )
1420{ 1420{
@@ -1425,7 +1425,7 @@ EXTERN_C BAAPI UserExperienceOnPlanCompatibleMsiPackageBegin(
1425 args.cbSize = sizeof(args); 1425 args.cbSize = sizeof(args);
1426 args.wzPackageId = wzPackageId; 1426 args.wzPackageId = wzPackageId;
1427 args.wzCompatiblePackageId = wzCompatiblePackageId; 1427 args.wzCompatiblePackageId = wzCompatiblePackageId;
1428 args.dw64CompatiblePackageVersion = dw64CompatiblePackageVersion; 1428 args.wzCompatiblePackageVersion = pCompatiblePackageVersion->sczVersion;
1429 args.recommendedState = *pRequestedState; 1429 args.recommendedState = *pRequestedState;
1430 1430
1431 results.cbSize = sizeof(results); 1431 results.cbSize = sizeof(results);
diff --git a/src/engine/userexperience.h b/src/engine/userexperience.h
index a5a97ffa..0ebd1b68 100644
--- a/src/engine/userexperience.h
+++ b/src/engine/userexperience.h
@@ -171,7 +171,7 @@ BAAPI UserExperienceOnDetectCompatibleMsiPackage(
171 __in BURN_USER_EXPERIENCE* pUserExperience, 171 __in BURN_USER_EXPERIENCE* pUserExperience,
172 __in_z LPCWSTR wzPackageId, 172 __in_z LPCWSTR wzPackageId,
173 __in_z LPCWSTR wzCompatiblePackageId, 173 __in_z LPCWSTR wzCompatiblePackageId,
174 __in DWORD64 dw64CompatiblePackageVersion 174 __in VERUTIL_VERSION* pCompatiblePackageVersion
175 ); 175 );
176BAAPI UserExperienceOnDetectComplete( 176BAAPI UserExperienceOnDetectComplete(
177 __in BURN_USER_EXPERIENCE* pUserExperience, 177 __in BURN_USER_EXPERIENCE* pUserExperience,
@@ -183,7 +183,7 @@ BAAPI UserExperienceOnDetectForwardCompatibleBundle(
183 __in BOOTSTRAPPER_RELATION_TYPE relationType, 183 __in BOOTSTRAPPER_RELATION_TYPE relationType,
184 __in_z LPCWSTR wzBundleTag, 184 __in_z LPCWSTR wzBundleTag,
185 __in BOOL fPerMachine, 185 __in BOOL fPerMachine,
186 __in DWORD64 dw64Version, 186 __in VERUTIL_VERSION* pVersion,
187 __inout BOOL* pfIgnoreBundle 187 __inout BOOL* pfIgnoreBundle
188 ); 188 );
189BAAPI UserExperienceOnDetectMsiFeature( 189BAAPI UserExperienceOnDetectMsiFeature(
@@ -208,7 +208,7 @@ BAAPI UserExperienceOnDetectRelatedBundle(
208 __in BOOTSTRAPPER_RELATION_TYPE relationType, 208 __in BOOTSTRAPPER_RELATION_TYPE relationType,
209 __in_z LPCWSTR wzBundleTag, 209 __in_z LPCWSTR wzBundleTag,
210 __in BOOL fPerMachine, 210 __in BOOL fPerMachine,
211 __in DWORD64 dw64Version, 211 __in VERUTIL_VERSION* pVersion,
212 __in BOOTSTRAPPER_RELATED_OPERATION operation 212 __in BOOTSTRAPPER_RELATED_OPERATION operation
213 ); 213 );
214BAAPI UserExperienceOnDetectRelatedMsiPackage( 214BAAPI UserExperienceOnDetectRelatedMsiPackage(
@@ -217,7 +217,7 @@ BAAPI UserExperienceOnDetectRelatedMsiPackage(
217 __in_z LPCWSTR wzUpgradeCode, 217 __in_z LPCWSTR wzUpgradeCode,
218 __in_z LPCWSTR wzProductCode, 218 __in_z LPCWSTR wzProductCode,
219 __in BOOL fPerMachine, 219 __in BOOL fPerMachine,
220 __in DWORD64 dw64Version, 220 __in VERUTIL_VERSION* pVersion,
221 __in BOOTSTRAPPER_RELATED_OPERATION operation 221 __in BOOTSTRAPPER_RELATED_OPERATION operation
222 ); 222 );
223BAAPI UserExperienceOnDetectTargetMsiPackage( 223BAAPI UserExperienceOnDetectTargetMsiPackage(
@@ -230,7 +230,7 @@ BAAPI UserExperienceOnDetectUpdate(
230 __in BURN_USER_EXPERIENCE* pUserExperience, 230 __in BURN_USER_EXPERIENCE* pUserExperience,
231 __in_z LPCWSTR wzUpdateLocation, 231 __in_z LPCWSTR wzUpdateLocation,
232 __in DWORD64 dw64Size, 232 __in DWORD64 dw64Size,
233 __in DWORD64 dw64Version, 233 __in VERUTIL_VERSION* pVersion,
234 __in_z_opt LPCWSTR wzTitle, 234 __in_z_opt LPCWSTR wzTitle,
235 __in_z_opt LPCWSTR wzSummary, 235 __in_z_opt LPCWSTR wzSummary,
236 __in_z_opt LPCWSTR wzContentType, 236 __in_z_opt LPCWSTR wzContentType,
@@ -333,7 +333,7 @@ BAAPI UserExperienceOnPlanCompatibleMsiPackageBegin(
333 __in BURN_USER_EXPERIENCE* pUserExperience, 333 __in BURN_USER_EXPERIENCE* pUserExperience,
334 __in_z LPCWSTR wzPackageId, 334 __in_z LPCWSTR wzPackageId,
335 __in_z LPCWSTR wzCompatiblePackageId, 335 __in_z LPCWSTR wzCompatiblePackageId,
336 __in DWORD64 dw64CompatiblePackageVersion, 336 __in VERUTIL_VERSION* pCompatiblePackageVersion,
337 __inout BOOTSTRAPPER_REQUEST_STATE* pRequestedState 337 __inout BOOTSTRAPPER_REQUEST_STATE* pRequestedState
338 ); 338 );
339BAAPI UserExperienceOnPlanCompatibleMsiPackageComplete( 339BAAPI UserExperienceOnPlanCompatibleMsiPackageComplete(
diff --git a/src/engine/variable.cpp b/src/engine/variable.cpp
index fb4b74e2..3069ccf7 100644
--- a/src/engine/variable.cpp
+++ b/src/engine/variable.cpp
@@ -268,7 +268,7 @@ extern "C" HRESULT VariableInitialize(
268 {BURN_BUNDLE_SOURCE_PROCESS_FOLDER, InitializeVariableString, NULL, FALSE, TRUE}, 268 {BURN_BUNDLE_SOURCE_PROCESS_FOLDER, InitializeVariableString, NULL, FALSE, TRUE},
269 {BURN_BUNDLE_TAG, InitializeVariableString, (DWORD_PTR)L"", FALSE, TRUE}, 269 {BURN_BUNDLE_TAG, InitializeVariableString, (DWORD_PTR)L"", FALSE, TRUE},
270 {BURN_BUNDLE_UILEVEL, InitializeVariableNumeric, 0, FALSE, TRUE}, 270 {BURN_BUNDLE_UILEVEL, InitializeVariableNumeric, 0, FALSE, TRUE},
271 {BURN_BUNDLE_VERSION, InitializeVariableVersion, 0, FALSE, TRUE}, 271 {BURN_BUNDLE_VERSION, InitializeVariableVersion, (DWORD_PTR)L"0", FALSE, TRUE},
272 }; 272 };
273 273
274 for (DWORD i = 0; i < countof(vrgBuiltInVariables); ++i) 274 for (DWORD i = 0; i < countof(vrgBuiltInVariables); ++i)
@@ -561,11 +561,11 @@ LExit:
561 return hr; 561 return hr;
562} 562}
563 563
564// The contents of pqwValue may be sensitive, if variable is hidden should keep value encrypted and SecureZeroMemory. 564// The contents of ppValue may be sensitive, if variable is hidden should keep value encrypted and SecureZeroMemory.
565extern "C" HRESULT VariableGetVersion( 565extern "C" HRESULT VariableGetVersion(
566 __in BURN_VARIABLES* pVariables, 566 __in BURN_VARIABLES* pVariables,
567 __in_z LPCWSTR wzVariable, 567 __in_z LPCWSTR wzVariable,
568 __in DWORD64* pqwValue 568 __in VERUTIL_VERSION** ppValue
569 ) 569 )
570{ 570{
571 HRESULT hr = S_OK; 571 HRESULT hr = S_OK;
@@ -584,7 +584,7 @@ extern "C" HRESULT VariableGetVersion(
584 } 584 }
585 ExitOnFailure(hr, "Failed to get value of variable: %ls", wzVariable); 585 ExitOnFailure(hr, "Failed to get value of variable: %ls", wzVariable);
586 586
587 hr = BVariantGetVersion(&pVariable->Value, pqwValue); 587 hr = BVariantGetVersion(&pVariable->Value, ppValue);
588 ExitOnFailure(hr, "Failed to get value as version for variable: %ls", wzVariable); 588 ExitOnFailure(hr, "Failed to get value as version for variable: %ls", wzVariable);
589 589
590LExit: 590LExit:
@@ -701,14 +701,14 @@ extern "C" HRESULT VariableSetString(
701extern "C" HRESULT VariableSetVersion( 701extern "C" HRESULT VariableSetVersion(
702 __in BURN_VARIABLES* pVariables, 702 __in BURN_VARIABLES* pVariables,
703 __in_z LPCWSTR wzVariable, 703 __in_z LPCWSTR wzVariable,
704 __in DWORD64 qwValue, 704 __in VERUTIL_VERSION* pValue,
705 __in BOOL fOverwriteBuiltIn 705 __in BOOL fOverwriteBuiltIn
706 ) 706 )
707{ 707{
708 BURN_VARIANT variant = { }; 708 BURN_VARIANT variant = { };
709 709
710 // We're not going to encrypt this value, so can access the value directly. 710 // We're not going to encrypt this value, so can access the value directly.
711 variant.qwValue = qwValue; 711 variant.pValue = pValue;
712 variant.Type = BURN_VARIANT_TYPE_VERSION; 712 variant.Type = BURN_VARIANT_TYPE_VERSION;
713 713
714 return SetVariableValue(pVariables, wzVariable, &variant, fOverwriteBuiltIn ? SET_VARIABLE_OVERRIDE_BUILTIN : SET_VARIABLE_NOT_BUILTIN, TRUE); 714 return SetVariableValue(pVariables, wzVariable, &variant, fOverwriteBuiltIn ? SET_VARIABLE_OVERRIDE_BUILTIN : SET_VARIABLE_NOT_BUILTIN, TRUE);
@@ -810,7 +810,6 @@ extern "C" HRESULT VariableSerialize(
810 BOOL fIncluded = FALSE; 810 BOOL fIncluded = FALSE;
811 LONGLONG ll = 0; 811 LONGLONG ll = 0;
812 LPWSTR scz = NULL; 812 LPWSTR scz = NULL;
813 DWORD64 qw = 0;
814 813
815 ::EnterCriticalSection(&pVariables->csAccess); 814 ::EnterCriticalSection(&pVariables->csAccess);
816 815
@@ -859,15 +858,7 @@ extern "C" HRESULT VariableSerialize(
859 858
860 SecureZeroMemory(&ll, sizeof(ll)); 859 SecureZeroMemory(&ll, sizeof(ll));
861 break; 860 break;
862 case BURN_VARIANT_TYPE_VERSION: 861 case BURN_VARIANT_TYPE_VERSION: __fallthrough;
863 hr = BVariantGetVersion(&pVariable->Value, &qw);
864 ExitOnFailure(hr, "Failed to get version.");
865
866 hr = BuffWriteNumber64(ppbBuffer, piBuffer, qw);
867 ExitOnFailure(hr, "Failed to write variable value as number.");
868
869 SecureZeroMemory(&qw, sizeof(qw));
870 break;
871 case BURN_VARIANT_TYPE_FORMATTED: __fallthrough; 862 case BURN_VARIANT_TYPE_FORMATTED: __fallthrough;
872 case BURN_VARIANT_TYPE_STRING: 863 case BURN_VARIANT_TYPE_STRING:
873 hr = BVariantGetString(&pVariable->Value, &scz); 864 hr = BVariantGetString(&pVariable->Value, &scz);
@@ -887,7 +878,6 @@ extern "C" HRESULT VariableSerialize(
887LExit: 878LExit:
888 ::LeaveCriticalSection(&pVariables->csAccess); 879 ::LeaveCriticalSection(&pVariables->csAccess);
889 SecureZeroMemory(&ll, sizeof(ll)); 880 SecureZeroMemory(&ll, sizeof(ll));
890 SecureZeroMemory(&qw, sizeof(qw));
891 StrSecureZeroFreeString(scz); 881 StrSecureZeroFreeString(scz);
892 882
893 return hr; 883 return hr;
@@ -908,6 +898,7 @@ extern "C" HRESULT VariableDeserialize(
908 BURN_VARIANT value = { }; 898 BURN_VARIANT value = { };
909 LPWSTR scz = NULL; 899 LPWSTR scz = NULL;
910 DWORD64 qw = 0; 900 DWORD64 qw = 0;
901 VERUTIL_VERSION* pVersion = NULL;
911 902
912 ::EnterCriticalSection(&pVariables->csAccess); 903 ::EnterCriticalSection(&pVariables->csAccess);
913 904
@@ -950,10 +941,13 @@ extern "C" HRESULT VariableDeserialize(
950 SecureZeroMemory(&qw, sizeof(qw)); 941 SecureZeroMemory(&qw, sizeof(qw));
951 break; 942 break;
952 case BURN_VARIANT_TYPE_VERSION: 943 case BURN_VARIANT_TYPE_VERSION:
953 hr = BuffReadNumber64(pbBuffer, cbBuffer, piBuffer, &qw); 944 hr = BuffReadString(pbBuffer, cbBuffer, piBuffer, &scz);
954 ExitOnFailure(hr, "Failed to read variable value as number."); 945 ExitOnFailure(hr, "Failed to read variable value as string.");
946
947 hr = VerParseVersion(scz, 0, FALSE, &pVersion);
948 ExitOnFailure(hr, "Failed to parse variable value as version.");
955 949
956 hr = BVariantSetVersion(&value, qw); 950 hr = BVariantSetVersion(&value, pVersion);
957 ExitOnFailure(hr, "Failed to set variable value."); 951 ExitOnFailure(hr, "Failed to set variable value.");
958 952
959 SecureZeroMemory(&qw, sizeof(qw)); 953 SecureZeroMemory(&qw, sizeof(qw));
@@ -984,6 +978,7 @@ extern "C" HRESULT VariableDeserialize(
984LExit: 978LExit:
985 ::LeaveCriticalSection(&pVariables->csAccess); 979 ::LeaveCriticalSection(&pVariables->csAccess);
986 980
981 ReleaseVerutilVersion(pVersion);
987 ReleaseStr(sczName); 982 ReleaseStr(sczName);
988 BVariantUninitialize(&value); 983 BVariantUninitialize(&value);
989 SecureZeroMemory(&qw, sizeof(qw)); 984 SecureZeroMemory(&qw, sizeof(qw));
@@ -1572,7 +1567,7 @@ static HRESULT SetVariableValue(
1572 break; 1567 break;
1573 1568
1574 case BURN_VARIANT_TYPE_VERSION: 1569 case BURN_VARIANT_TYPE_VERSION:
1575 LogStringLine(REPORT_STANDARD, "Setting version variable '%ls' to value '%hu.%hu.%hu.%hu'", wzVariable, (WORD)(pVariant->qwValue >> 48), (WORD)(pVariant->qwValue >> 32), (WORD)(pVariant->qwValue >> 16), (WORD)(pVariant->qwValue)); 1570 LogStringLine(REPORT_STANDARD, "Setting version variable '%ls' to value '%ls'", wzVariable, pVariant->pValue->sczVersion);
1576 break; 1571 break;
1577 1572
1578 default: 1573 default:
@@ -1609,6 +1604,7 @@ static HRESULT InitializeVariableVersionNT(
1609 RTL_GET_VERSION rtlGetVersion = NULL; 1604 RTL_GET_VERSION rtlGetVersion = NULL;
1610 RTL_OSVERSIONINFOEXW ovix = { }; 1605 RTL_OSVERSIONINFOEXW ovix = { };
1611 BURN_VARIANT value = { }; 1606 BURN_VARIANT value = { };
1607 VERUTIL_VERSION* pVersion = NULL;
1612 1608
1613 if (!::GetModuleHandleExW(0, L"ntdll", &ntdll)) 1609 if (!::GetModuleHandleExW(0, L"ntdll", &ntdll))
1614 { 1610 {
@@ -1630,12 +1626,15 @@ static HRESULT InitializeVariableVersionNT(
1630 case OS_INFO_VARIABLE_ServicePackLevel: 1626 case OS_INFO_VARIABLE_ServicePackLevel:
1631 if (0 != ovix.wServicePackMajor) 1627 if (0 != ovix.wServicePackMajor)
1632 { 1628 {
1633 value.qwValue = static_cast<DWORD64>(ovix.wServicePackMajor); 1629 value.llValue = static_cast<LONGLONG>(ovix.wServicePackMajor);
1634 value.Type = BURN_VARIANT_TYPE_NUMERIC; 1630 value.Type = BURN_VARIANT_TYPE_NUMERIC;
1635 } 1631 }
1636 break; 1632 break;
1637 case OS_INFO_VARIABLE_VersionNT: 1633 case OS_INFO_VARIABLE_VersionNT:
1638 value.qwValue = MAKEQWORDVERSION(ovix.dwMajorVersion, ovix.dwMinorVersion, 0, 0); 1634 hr = VerVersionFromQword(MAKEQWORDVERSION(ovix.dwMajorVersion, ovix.dwMinorVersion, 0, 0), &pVersion);
1635 ExitOnFailure(hr, "Failed to create VersionNT from QWORD.");
1636
1637 value.pValue = pVersion;
1639 value.Type = BURN_VARIANT_TYPE_VERSION; 1638 value.Type = BURN_VARIANT_TYPE_VERSION;
1640 break; 1639 break;
1641 case OS_INFO_VARIABLE_VersionNT64: 1640 case OS_INFO_VARIABLE_VersionNT64:
@@ -1647,13 +1646,16 @@ static HRESULT InitializeVariableVersionNT(
1647 if (fIsWow64) 1646 if (fIsWow64)
1648#endif 1647#endif
1649 { 1648 {
1650 value.qwValue = MAKEQWORDVERSION(ovix.dwMajorVersion, ovix.dwMinorVersion, 0, 0); 1649 hr = VerVersionFromQword(MAKEQWORDVERSION(ovix.dwMajorVersion, ovix.dwMinorVersion, 0, 0), &pVersion);
1650 ExitOnFailure(hr, "Failed to create VersionNT64 from QWORD.");
1651
1652 value.pValue = pVersion;
1651 value.Type = BURN_VARIANT_TYPE_VERSION; 1653 value.Type = BURN_VARIANT_TYPE_VERSION;
1652 } 1654 }
1653 } 1655 }
1654 break; 1656 break;
1655 case OS_INFO_VARIABLE_WindowsBuildNumber: 1657 case OS_INFO_VARIABLE_WindowsBuildNumber:
1656 value.qwValue = static_cast<DWORD64>(ovix.dwBuildNumber); 1658 value.llValue = static_cast<LONGLONG>(ovix.dwBuildNumber);
1657 value.Type = BURN_VARIANT_TYPE_NUMERIC; 1659 value.Type = BURN_VARIANT_TYPE_NUMERIC;
1658 default: 1660 default:
1659 AssertSz(FALSE, "Unknown OS info type."); 1661 AssertSz(FALSE, "Unknown OS info type.");
@@ -1669,6 +1671,8 @@ LExit:
1669 FreeLibrary(ntdll); 1671 FreeLibrary(ntdll);
1670 } 1672 }
1671 1673
1674 ReleaseVerutilVersion(pVersion);
1675
1672 return hr; 1676 return hr;
1673} 1677}
1674 1678
@@ -1805,15 +1809,14 @@ LExit:
1805} 1809}
1806 1810
1807static HRESULT InitializeVariableVersionMsi( 1811static HRESULT InitializeVariableVersionMsi(
1808 __in DWORD_PTR dwpData, 1812 __in DWORD_PTR /*dwpData*/,
1809 __inout BURN_VARIANT* pValue 1813 __inout BURN_VARIANT* pValue
1810 ) 1814 )
1811{ 1815{
1812 UNREFERENCED_PARAMETER(dwpData);
1813
1814 HRESULT hr = S_OK; 1816 HRESULT hr = S_OK;
1815 DLLGETVERSIONPROC pfnMsiDllGetVersion = NULL; 1817 DLLGETVERSIONPROC pfnMsiDllGetVersion = NULL;
1816 DLLVERSIONINFO msiVersionInfo = { }; 1818 DLLVERSIONINFO msiVersionInfo = { };
1819 VERUTIL_VERSION* pVersion = NULL;
1817 1820
1818 // get DllGetVersion proc address 1821 // get DllGetVersion proc address
1819 pfnMsiDllGetVersion = (DLLGETVERSIONPROC)::GetProcAddress(::GetModuleHandleW(L"msi"), "DllGetVersion"); 1822 pfnMsiDllGetVersion = (DLLGETVERSIONPROC)::GetProcAddress(::GetModuleHandleW(L"msi"), "DllGetVersion");
@@ -1824,10 +1827,15 @@ static HRESULT InitializeVariableVersionMsi(
1824 hr = pfnMsiDllGetVersion(&msiVersionInfo); 1827 hr = pfnMsiDllGetVersion(&msiVersionInfo);
1825 ExitOnFailure(hr, "Failed to get msi.dll version info."); 1828 ExitOnFailure(hr, "Failed to get msi.dll version info.");
1826 1829
1827 hr = BVariantSetVersion(pValue, MAKEQWORDVERSION(msiVersionInfo.dwMajorVersion, msiVersionInfo.dwMinorVersion, 0, 0)); 1830 hr = VerVersionFromQword(MAKEQWORDVERSION(msiVersionInfo.dwMajorVersion, msiVersionInfo.dwMinorVersion, 0, 0), &pVersion);
1831 ExitOnFailure(hr, "Failed to create msi.dll version from QWORD.");
1832
1833 hr = BVariantSetVersion(pValue, pVersion);
1828 ExitOnFailure(hr, "Failed to set variant value."); 1834 ExitOnFailure(hr, "Failed to set variant value.");
1829 1835
1830LExit: 1836LExit:
1837 ReleaseVerutilVersion(pVersion);
1838
1831 return hr; 1839 return hr;
1832} 1840}
1833 1841
@@ -2270,12 +2278,19 @@ static HRESULT InitializeVariableVersion(
2270 ) 2278 )
2271{ 2279{
2272 HRESULT hr = S_OK; 2280 HRESULT hr = S_OK;
2281 LPCWSTR wzValue = (LPCWSTR)dwpData;
2282 VERUTIL_VERSION* pVersion = NULL;
2283
2284 hr = VerParseVersion(wzValue, 0, FALSE, &pVersion);
2285 ExitOnFailure(hr, "Failed to initialize version.");
2273 2286
2274 // set value 2287 // set value
2275 hr = BVariantSetVersion(pValue, static_cast<DWORD64>(dwpData)); 2288 hr = BVariantSetVersion(pValue, pVersion);
2276 ExitOnFailure(hr, "Failed to set variant value."); 2289 ExitOnFailure(hr, "Failed to set variant value.");
2277 2290
2278LExit: 2291LExit:
2292 ReleaseVerutilVersion(pVersion);
2293
2279 return hr; 2294 return hr;
2280} 2295}
2281 2296
diff --git a/src/engine/variable.h b/src/engine/variable.h
index 648c5daf..6437c32f 100644
--- a/src/engine/variable.h
+++ b/src/engine/variable.h
@@ -85,7 +85,7 @@ HRESULT VariableGetString(
85HRESULT VariableGetVersion( 85HRESULT VariableGetVersion(
86 __in BURN_VARIABLES* pVariables, 86 __in BURN_VARIABLES* pVariables,
87 __in_z LPCWSTR wzVariable, 87 __in_z LPCWSTR wzVariable,
88 __in DWORD64* pqwValue 88 __in VERUTIL_VERSION** ppValue
89 ); 89 );
90HRESULT VariableGetVariant( 90HRESULT VariableGetVariant(
91 __in BURN_VARIABLES* pVariables, 91 __in BURN_VARIABLES* pVariables,
@@ -113,7 +113,7 @@ HRESULT VariableSetString(
113HRESULT VariableSetVersion( 113HRESULT VariableSetVersion(
114 __in BURN_VARIABLES* pVariables, 114 __in BURN_VARIABLES* pVariables,
115 __in_z LPCWSTR wzVariable, 115 __in_z LPCWSTR wzVariable,
116 __in DWORD64 qwValue, 116 __in VERUTIL_VERSION* pValue,
117 __in BOOL fOverwriteBuiltIn 117 __in BOOL fOverwriteBuiltIn
118 ); 118 );
119HRESULT VariableSetVariant( 119HRESULT VariableSetVariant(
diff --git a/src/engine/variant.cpp b/src/engine/variant.cpp
index 43bc19c4..28578691 100644
--- a/src/engine/variant.cpp
+++ b/src/engine/variant.cpp
@@ -23,7 +23,7 @@ static HRESULT BVariantRetrieveDecryptedString(
23 23
24static void BVariantRetrieveVersion( 24static void BVariantRetrieveVersion(
25 __in BURN_VARIANT* pVariant, 25 __in BURN_VARIANT* pVariant,
26 __out DWORD64* pqwValue 26 __out VERUTIL_VERSION** ppValue
27 ); 27 );
28 28
29// function definitions 29// function definitions
@@ -48,6 +48,7 @@ extern "C" HRESULT BVariantGetNumeric(
48{ 48{
49 HRESULT hr = S_OK; 49 HRESULT hr = S_OK;
50 LPWSTR sczValue = NULL; 50 LPWSTR sczValue = NULL;
51 VERUTIL_VERSION* pVersionValue = NULL;
51 52
52 switch (pVariant->Type) 53 switch (pVariant->Type)
53 { 54 {
@@ -68,7 +69,13 @@ extern "C" HRESULT BVariantGetNumeric(
68 StrSecureZeroFreeString(sczValue); 69 StrSecureZeroFreeString(sczValue);
69 break; 70 break;
70 case BURN_VARIANT_TYPE_VERSION: 71 case BURN_VARIANT_TYPE_VERSION:
71 BVariantRetrieveVersion(pVariant, (DWORD64*)pllValue); 72 BVariantRetrieveVersion(pVariant, &pVersionValue);
73
74 hr = StrStringToInt64(pVersionValue->sczVersion, 0, pllValue);
75 if (FAILED(hr))
76 {
77 hr = DISP_E_TYPEMISMATCH;
78 }
72 break; 79 break;
73 default: 80 default:
74 hr = E_INVALIDARG; 81 hr = E_INVALIDARG;
@@ -86,7 +93,7 @@ extern "C" HRESULT BVariantGetString(
86{ 93{
87 HRESULT hr = S_OK; 94 HRESULT hr = S_OK;
88 LONGLONG llValue = 0; 95 LONGLONG llValue = 0;
89 DWORD64 qwValue = 0; 96 VERUTIL_VERSION* pVersionValue = NULL;
90 97
91 switch (pVariant->Type) 98 switch (pVariant->Type)
92 { 99 {
@@ -104,17 +111,9 @@ extern "C" HRESULT BVariantGetString(
104 hr = BVariantRetrieveDecryptedString(pVariant, psczValue); 111 hr = BVariantRetrieveDecryptedString(pVariant, psczValue);
105 break; 112 break;
106 case BURN_VARIANT_TYPE_VERSION: 113 case BURN_VARIANT_TYPE_VERSION:
107 BVariantRetrieveVersion(pVariant, &qwValue); 114 BVariantRetrieveVersion(pVariant, &pVersionValue);
108 if (SUCCEEDED(hr)) 115
109 { 116 hr = StrAllocStringSecure(psczValue, pVersionValue->sczVersion, 0);
110 hr = StrAllocFormattedSecure(psczValue, L"%hu.%hu.%hu.%hu",
111 (WORD)(qwValue >> 48),
112 (WORD)(qwValue >> 32),
113 (WORD)(qwValue >> 16),
114 (WORD)qwValue);
115 ExitOnFailure(hr, "Failed to convert version to string.");
116 }
117 SecureZeroMemory(&qwValue, sizeof(qwValue));
118 break; 117 break;
119 default: 118 default:
120 hr = E_INVALIDARG; 119 hr = E_INVALIDARG;
@@ -125,26 +124,30 @@ LExit:
125 return hr; 124 return hr;
126} 125}
127 126
128// The contents of pqwValue may be sensitive, should keep encrypted and SecureZeroMemory. 127// The contents of ppValue may be sensitive, should keep encrypted and SecureZeroMemory.
129extern "C" HRESULT BVariantGetVersion( 128extern "C" HRESULT BVariantGetVersion(
130 __in BURN_VARIANT* pVariant, 129 __in BURN_VARIANT* pVariant,
131 __out DWORD64* pqwValue 130 __out VERUTIL_VERSION** ppValue
132 ) 131 )
133{ 132{
134 HRESULT hr = S_OK; 133 HRESULT hr = S_OK;
134 LONGLONG llValue = 0;
135 LPWSTR sczValue = NULL; 135 LPWSTR sczValue = NULL;
136 VERUTIL_VERSION* pValue = NULL;
136 137
137 switch (pVariant->Type) 138 switch (pVariant->Type)
138 { 139 {
139 case BURN_VARIANT_TYPE_NUMERIC: 140 case BURN_VARIANT_TYPE_NUMERIC:
140 BVariantRetrieveNumeric(pVariant, (LONGLONG*)pqwValue); 141 BVariantRetrieveNumeric(pVariant, &llValue);
142
143 hr = VerVersionFromQword(llValue, ppValue);
141 break; 144 break;
142 case BURN_VARIANT_TYPE_FORMATTED: __fallthrough; 145 case BURN_VARIANT_TYPE_FORMATTED: __fallthrough;
143 case BURN_VARIANT_TYPE_STRING: 146 case BURN_VARIANT_TYPE_STRING:
144 hr = BVariantRetrieveDecryptedString(pVariant, &sczValue); 147 hr = BVariantRetrieveDecryptedString(pVariant, &sczValue);
145 if (SUCCEEDED(hr)) 148 if (SUCCEEDED(hr))
146 { 149 {
147 hr = FileVersionFromStringEx(sczValue, 0, pqwValue); 150 hr = VerParseVersion(sczValue, 0, FALSE, ppValue);
148 if (FAILED(hr)) 151 if (FAILED(hr))
149 { 152 {
150 hr = DISP_E_TYPEMISMATCH; 153 hr = DISP_E_TYPEMISMATCH;
@@ -153,7 +156,9 @@ extern "C" HRESULT BVariantGetVersion(
153 StrSecureZeroFreeString(sczValue); 156 StrSecureZeroFreeString(sczValue);
154 break; 157 break;
155 case BURN_VARIANT_TYPE_VERSION: 158 case BURN_VARIANT_TYPE_VERSION:
156 BVariantRetrieveVersion(pVariant, pqwValue); 159 BVariantRetrieveVersion(pVariant, &pValue);
160
161 hr = VerCopyVersion(pValue, ppValue);
157 break; 162 break;
158 default: 163 default:
159 hr = E_INVALIDARG; 164 hr = E_INVALIDARG;
@@ -224,7 +229,7 @@ LExit:
224 229
225extern "C" HRESULT BVariantSetVersion( 230extern "C" HRESULT BVariantSetVersion(
226 __in BURN_VARIANT* pVariant, 231 __in BURN_VARIANT* pVariant,
227 __in DWORD64 qwValue 232 __in VERUTIL_VERSION* pValue
228 ) 233 )
229{ 234{
230 HRESULT hr = S_OK; 235 HRESULT hr = S_OK;
@@ -236,7 +241,7 @@ extern "C" HRESULT BVariantSetVersion(
236 StrSecureZeroFreeString(pVariant->sczValue); 241 StrSecureZeroFreeString(pVariant->sczValue);
237 } 242 }
238 memset(pVariant, 0, sizeof(BURN_VARIANT)); 243 memset(pVariant, 0, sizeof(BURN_VARIANT));
239 pVariant->qwValue = qwValue; 244 hr = VerCopyVersion(pValue, &pVariant->pValue);
240 pVariant->Type = BURN_VARIANT_TYPE_VERSION; 245 pVariant->Type = BURN_VARIANT_TYPE_VERSION;
241 BVariantSetEncryption(pVariant, fEncryptValue); 246 BVariantSetEncryption(pVariant, fEncryptValue);
242 247
@@ -251,7 +256,7 @@ extern "C" HRESULT BVariantSetValue(
251 HRESULT hr = S_OK; 256 HRESULT hr = S_OK;
252 LONGLONG llValue = 0; 257 LONGLONG llValue = 0;
253 LPWSTR sczValue = NULL; 258 LPWSTR sczValue = NULL;
254 DWORD64 qwValue = 0; 259 VERUTIL_VERSION* pVersionValue = NULL;
255 BOOL fEncrypt = pVariant->fEncryptString; 260 BOOL fEncrypt = pVariant->fEncryptString;
256 261
257 switch (pValue->Type) 262 switch (pValue->Type)
@@ -277,12 +282,11 @@ extern "C" HRESULT BVariantSetValue(
277 StrSecureZeroFreeString(sczValue); 282 StrSecureZeroFreeString(sczValue);
278 break; 283 break;
279 case BURN_VARIANT_TYPE_VERSION: 284 case BURN_VARIANT_TYPE_VERSION:
280 hr = BVariantGetVersion(pValue, &qwValue); 285 hr = BVariantGetVersion(pValue, &pVersionValue);
281 if (SUCCEEDED(hr)) 286 if (SUCCEEDED(hr))
282 { 287 {
283 hr = BVariantSetVersion(pVariant, qwValue); 288 hr = BVariantSetVersion(pVariant, pVersionValue);
284 } 289 }
285 SecureZeroMemory(&qwValue, sizeof(qwValue));
286 break; 290 break;
287 default: 291 default:
288 hr = E_INVALIDARG; 292 hr = E_INVALIDARG;
@@ -303,7 +307,7 @@ extern "C" HRESULT BVariantCopy(
303 HRESULT hr = S_OK; 307 HRESULT hr = S_OK;
304 LONGLONG llValue = 0; 308 LONGLONG llValue = 0;
305 LPWSTR sczValue = NULL; 309 LPWSTR sczValue = NULL;
306 DWORD64 qwValue = 0; 310 VERUTIL_VERSION* pVersionValue = 0;
307 311
308 BVariantUninitialize(pTarget); 312 BVariantUninitialize(pTarget);
309 313
@@ -329,12 +333,11 @@ extern "C" HRESULT BVariantCopy(
329 StrSecureZeroFreeString(sczValue); 333 StrSecureZeroFreeString(sczValue);
330 break; 334 break;
331 case BURN_VARIANT_TYPE_VERSION: 335 case BURN_VARIANT_TYPE_VERSION:
332 hr = BVariantGetVersion(pSource, &qwValue); 336 hr = BVariantGetVersion(pSource, &pVersionValue);
333 if (SUCCEEDED(hr)) 337 if (SUCCEEDED(hr))
334 { 338 {
335 hr = BVariantSetVersion(pTarget, qwValue); 339 hr = BVariantSetVersion(pTarget, pVersionValue);
336 } 340 }
337 SecureZeroMemory(&qwValue, sizeof(qwValue));
338 break; 341 break;
339 default: 342 default:
340 hr = E_INVALIDARG; 343 hr = E_INVALIDARG;
@@ -380,13 +383,13 @@ extern "C" HRESULT BVariantChangeType(
380 hr = BVariantGetString(pVariant, &variant.sczValue); 383 hr = BVariantGetString(pVariant, &variant.sczValue);
381 break; 384 break;
382 case BURN_VARIANT_TYPE_VERSION: 385 case BURN_VARIANT_TYPE_VERSION:
383 hr = BVariantGetVersion(pVariant, &variant.qwValue); 386 hr = BVariantGetVersion(pVariant, &variant.pValue);
384 break; 387 break;
385 default: 388 default:
386 ExitFunction1(hr = E_INVALIDARG); 389 ExitFunction1(hr = E_INVALIDARG);
387 } 390 }
388 ExitOnFailure(hr, "Failed to copy variant value.");
389 variant.Type = type; 391 variant.Type = type;
392 ExitOnFailure(hr, "Failed to copy variant value.");
390 393
391 BVariantUninitialize(pVariant); 394 BVariantUninitialize(pVariant);
392 memcpy_s(pVariant, sizeof(BURN_VARIANT), &variant, sizeof(BURN_VARIANT)); 395 memcpy_s(pVariant, sizeof(BURN_VARIANT), &variant, sizeof(BURN_VARIANT));
@@ -524,10 +527,10 @@ LExit:
524 527
525static void BVariantRetrieveVersion( 528static void BVariantRetrieveVersion(
526 __in BURN_VARIANT* pVariant, 529 __in BURN_VARIANT* pVariant,
527 __out DWORD64* pqwValue 530 __out VERUTIL_VERSION** ppValue
528 ) 531 )
529{ 532{
530 Assert(NULL != pqwValue); 533 Assert(ppValue);
531 534
532 *pqwValue = pVariant->qwValue; 535 *ppValue = pVariant->pValue;
533} 536}
diff --git a/src/engine/variant.h b/src/engine/variant.h
index 35463479..23303e02 100644
--- a/src/engine/variant.h
+++ b/src/engine/variant.h
@@ -26,7 +26,7 @@ typedef struct _BURN_VARIANT
26 union 26 union
27 { 27 {
28 LONGLONG llValue; 28 LONGLONG llValue;
29 DWORD64 qwValue; 29 VERUTIL_VERSION* pValue;
30 LPWSTR sczValue; 30 LPWSTR sczValue;
31 }; 31 };
32 BURN_VARIANT_TYPE Type; 32 BURN_VARIANT_TYPE Type;
@@ -49,7 +49,7 @@ HRESULT BVariantGetString(
49 ); 49 );
50HRESULT BVariantGetVersion( 50HRESULT BVariantGetVersion(
51 __in BURN_VARIANT* pVariant, 51 __in BURN_VARIANT* pVariant,
52 __out DWORD64* pqwValue 52 __out VERUTIL_VERSION** ppValue
53 ); 53 );
54HRESULT BVariantSetNumeric( 54HRESULT BVariantSetNumeric(
55 __in BURN_VARIANT* pVariant, 55 __in BURN_VARIANT* pVariant,
@@ -63,7 +63,7 @@ HRESULT BVariantSetString(
63 ); 63 );
64HRESULT BVariantSetVersion( 64HRESULT BVariantSetVersion(
65 __in BURN_VARIANT* pVariant, 65 __in BURN_VARIANT* pVariant,
66 __in DWORD64 qwValue 66 __in VERUTIL_VERSION* pValue
67 ); 67 );
68/******************************************************************** 68/********************************************************************
69BVariantSetValue - Convenience function that calls BVariantUninitialize, 69BVariantSetValue - Convenience function that calls BVariantUninitialize,
diff --git a/src/stub/packages.config b/src/stub/packages.config
index 6f98d413..3ece6694 100644
--- a/src/stub/packages.config
+++ b/src/stub/packages.config
@@ -4,5 +4,5 @@
4 <package id="Microsoft.SourceLink.Common" version="1.0.0" targetFramework="native" developmentDependency="true" /> 4 <package id="Microsoft.SourceLink.Common" version="1.0.0" targetFramework="native" developmentDependency="true" />
5 <package id="Microsoft.SourceLink.GitHub" version="1.0.0" targetFramework="native" developmentDependency="true" /> 5 <package id="Microsoft.SourceLink.GitHub" version="1.0.0" targetFramework="native" developmentDependency="true" />
6 <package id="Nerdbank.GitVersioning" version="3.1.91" targetFramework="native" developmentDependency="true" /> 6 <package id="Nerdbank.GitVersioning" version="3.1.91" targetFramework="native" developmentDependency="true" />
7 <package id="WixToolset.DUtil" version="4.0.49" targetFramework="native" /> 7 <package id="WixToolset.DUtil" version="4.0.55" targetFramework="native" />
8</packages> \ No newline at end of file 8</packages> \ No newline at end of file
diff --git a/src/stub/stub.vcxproj b/src/stub/stub.vcxproj
index c0d79f49..d3c1278c 100644
--- a/src/stub/stub.vcxproj
+++ b/src/stub/stub.vcxproj
@@ -5,7 +5,7 @@
5 <Import Project="..\..\packages\Microsoft.SourceLink.GitHub.1.0.0\build\Microsoft.SourceLink.GitHub.props" Condition="Exists('..\..\packages\Microsoft.SourceLink.GitHub.1.0.0\build\Microsoft.SourceLink.GitHub.props')" /> 5 <Import Project="..\..\packages\Microsoft.SourceLink.GitHub.1.0.0\build\Microsoft.SourceLink.GitHub.props" Condition="Exists('..\..\packages\Microsoft.SourceLink.GitHub.1.0.0\build\Microsoft.SourceLink.GitHub.props')" />
6 <Import Project="..\..\packages\Microsoft.SourceLink.Common.1.0.0\build\Microsoft.SourceLink.Common.props" Condition="Exists('..\..\packages\Microsoft.SourceLink.Common.1.0.0\build\Microsoft.SourceLink.Common.props')" /> 6 <Import Project="..\..\packages\Microsoft.SourceLink.Common.1.0.0\build\Microsoft.SourceLink.Common.props" Condition="Exists('..\..\packages\Microsoft.SourceLink.Common.1.0.0\build\Microsoft.SourceLink.Common.props')" />
7 <Import Project="..\..\packages\Microsoft.Build.Tasks.Git.1.0.0\build\Microsoft.Build.Tasks.Git.props" Condition="Exists('..\..\packages\Microsoft.Build.Tasks.Git.1.0.0\build\Microsoft.Build.Tasks.Git.props')" /> 7 <Import Project="..\..\packages\Microsoft.Build.Tasks.Git.1.0.0\build\Microsoft.Build.Tasks.Git.props" Condition="Exists('..\..\packages\Microsoft.Build.Tasks.Git.1.0.0\build\Microsoft.Build.Tasks.Git.props')" />
8 <Import Project="..\..\packages\WixToolset.DUtil.4.0.49\build\WixToolset.DUtil.props" Condition="Exists('..\..\packages\WixToolset.DUtil.4.0.49\build\WixToolset.DUtil.props')" /> 8 <Import Project="..\..\packages\WixToolset.DUtil.4.0.55\build\WixToolset.DUtil.props" Condition="Exists('..\..\packages\WixToolset.DUtil.4.0.55\build\WixToolset.DUtil.props')" />
9 9
10 <ItemGroup Label="ProjectConfigurations"> 10 <ItemGroup Label="ProjectConfigurations">
11 <ProjectConfiguration Include="Debug|Win32"> 11 <ProjectConfiguration Include="Debug|Win32">
@@ -107,6 +107,6 @@
107 <Error Condition="!Exists('..\..\packages\Microsoft.SourceLink.GitHub.1.0.0\build\Microsoft.SourceLink.GitHub.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.SourceLink.GitHub.1.0.0\build\Microsoft.SourceLink.GitHub.props'))" /> 107 <Error Condition="!Exists('..\..\packages\Microsoft.SourceLink.GitHub.1.0.0\build\Microsoft.SourceLink.GitHub.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.SourceLink.GitHub.1.0.0\build\Microsoft.SourceLink.GitHub.props'))" />
108 <Error Condition="!Exists('..\..\packages\Microsoft.SourceLink.GitHub.1.0.0\build\Microsoft.SourceLink.GitHub.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.SourceLink.GitHub.1.0.0\build\Microsoft.SourceLink.GitHub.targets'))" /> 108 <Error Condition="!Exists('..\..\packages\Microsoft.SourceLink.GitHub.1.0.0\build\Microsoft.SourceLink.GitHub.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.SourceLink.GitHub.1.0.0\build\Microsoft.SourceLink.GitHub.targets'))" />
109 <Error Condition="!Exists('..\..\packages\Nerdbank.GitVersioning.3.1.91\build\Nerdbank.GitVersioning.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Nerdbank.GitVersioning.3.1.91\build\Nerdbank.GitVersioning.targets'))" /> 109 <Error Condition="!Exists('..\..\packages\Nerdbank.GitVersioning.3.1.91\build\Nerdbank.GitVersioning.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Nerdbank.GitVersioning.3.1.91\build\Nerdbank.GitVersioning.targets'))" />
110 <Error Condition="!Exists('..\..\packages\WixToolset.DUtil.4.0.49\build\WixToolset.DUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.DUtil.4.0.49\build\WixToolset.DUtil.props'))" /> 110 <Error Condition="!Exists('..\..\packages\WixToolset.DUtil.4.0.55\build\WixToolset.DUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.DUtil.4.0.55\build\WixToolset.DUtil.props'))" />
111 </Target> 111 </Target>
112</Project> \ No newline at end of file 112</Project> \ No newline at end of file
diff --git a/src/test/BurnUnitTest/BurnUnitTest.vcxproj b/src/test/BurnUnitTest/BurnUnitTest.vcxproj
index fda7cb7b..cc19fa60 100644
--- a/src/test/BurnUnitTest/BurnUnitTest.vcxproj
+++ b/src/test/BurnUnitTest/BurnUnitTest.vcxproj
@@ -4,7 +4,7 @@
4 4
5<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 5<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
6 <Import Project="..\..\..\packages\WixBuildTools.TestSupport.Native.4.0.40\build\WixBuildTools.TestSupport.Native.props" Condition="Exists('..\..\..\packages\WixBuildTools.TestSupport.Native.4.0.40\build\WixBuildTools.TestSupport.Native.props')" /> 6 <Import Project="..\..\..\packages\WixBuildTools.TestSupport.Native.4.0.40\build\WixBuildTools.TestSupport.Native.props" Condition="Exists('..\..\..\packages\WixBuildTools.TestSupport.Native.4.0.40\build\WixBuildTools.TestSupport.Native.props')" />
7 <Import Project="..\..\..\packages\WixToolset.DUtil.4.0.49\build\WixToolset.DUtil.props" Condition="Exists('..\..\..\packages\WixToolset.DUtil.4.0.49\build\WixToolset.DUtil.props')" /> 7 <Import Project="..\..\..\packages\WixToolset.DUtil.4.0.55\build\WixToolset.DUtil.props" Condition="Exists('..\..\..\packages\WixToolset.DUtil.4.0.55\build\WixToolset.DUtil.props')" />
8 <ItemGroup Label="ProjectConfigurations"> 8 <ItemGroup Label="ProjectConfigurations">
9 <ProjectConfiguration Include="Debug|Win32"> 9 <ProjectConfiguration Include="Debug|Win32">
10 <Configuration>Debug</Configuration> 10 <Configuration>Debug</Configuration>
@@ -80,6 +80,6 @@
80 </PropertyGroup> 80 </PropertyGroup>
81 <Error Condition="!Exists('..\..\..\packages\WixBuildTools.TestSupport.Native.4.0.40\build\WixBuildTools.TestSupport.Native.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\WixBuildTools.TestSupport.Native.4.0.40\build\WixBuildTools.TestSupport.Native.props'))" /> 81 <Error Condition="!Exists('..\..\..\packages\WixBuildTools.TestSupport.Native.4.0.40\build\WixBuildTools.TestSupport.Native.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\WixBuildTools.TestSupport.Native.4.0.40\build\WixBuildTools.TestSupport.Native.props'))" />
82 <Error Condition="!Exists('..\..\..\packages\WixBuildTools.TestSupport.Native.4.0.40\build\WixBuildTools.TestSupport.Native.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\WixBuildTools.TestSupport.Native.4.0.40\build\WixBuildTools.TestSupport.Native.targets'))" /> 82 <Error Condition="!Exists('..\..\..\packages\WixBuildTools.TestSupport.Native.4.0.40\build\WixBuildTools.TestSupport.Native.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\WixBuildTools.TestSupport.Native.4.0.40\build\WixBuildTools.TestSupport.Native.targets'))" />
83 <Error Condition="!Exists('..\..\..\packages\WixToolset.DUtil.4.0.49\build\WixToolset.DUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\WixToolset.DUtil.4.0.49\build\WixToolset.DUtil.props'))" /> 83 <Error Condition="!Exists('..\..\..\packages\WixToolset.DUtil.4.0.55\build\WixToolset.DUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\WixToolset.DUtil.4.0.55\build\WixToolset.DUtil.props'))" />
84 </Target> 84 </Target>
85</Project> 85</Project>
diff --git a/src/test/BurnUnitTest/SearchTest.cpp b/src/test/BurnUnitTest/SearchTest.cpp
index 32107d87..d868190d 100644
--- a/src/test/BurnUnitTest/SearchTest.cpp
+++ b/src/test/BurnUnitTest/SearchTest.cpp
@@ -106,6 +106,7 @@ namespace Bootstrapper
106 BURN_SEARCHES searches = { }; 106 BURN_SEARCHES searches = { };
107 BURN_EXTENSIONS burnExtensions = { }; 107 BURN_EXTENSIONS burnExtensions = { };
108 ULARGE_INTEGER uliVersion = { }; 108 ULARGE_INTEGER uliVersion = { };
109 VERUTIL_VERSION* pVersion = NULL;
109 try 110 try
110 { 111 {
111 hr = VariableInitialize(&variables); 112 hr = VariableInitialize(&variables);
@@ -117,6 +118,9 @@ namespace Bootstrapper
117 hr = FileVersion(wzFile2, &uliVersion.HighPart, &uliVersion.LowPart); 118 hr = FileVersion(wzFile2, &uliVersion.HighPart, &uliVersion.LowPart);
118 TestThrowOnFailure(hr, L"Failed to get DLL version."); 119 TestThrowOnFailure(hr, L"Failed to get DLL version.");
119 120
121 hr = VerVersionFromQword(uliVersion.QuadPart, &pVersion);
122 NativeAssert::Succeeded(hr, "Failed to create version.");
123
120 VariableSetStringHelper(&variables, L"File1", wzFile1, FALSE); 124 VariableSetStringHelper(&variables, L"File1", wzFile1, FALSE);
121 VariableSetStringHelper(&variables, L"File2", wzFile2, FALSE); 125 VariableSetStringHelper(&variables, L"File2", wzFile2, FALSE);
122 126
@@ -140,10 +144,11 @@ namespace Bootstrapper
140 // check variable values 144 // check variable values
141 Assert::Equal(0ll, VariableGetNumericHelper(&variables, L"Variable1")); 145 Assert::Equal(0ll, VariableGetNumericHelper(&variables, L"Variable1"));
142 Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable2")); 146 Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable2"));
143 Assert::Equal(uliVersion.QuadPart, VariableGetVersionHelper(&variables, L"Variable3")); 147 Assert::Equal<String^>(gcnew String(pVersion->sczVersion), VariableGetVersionHelper(&variables, L"Variable3"));
144 } 148 }
145 finally 149 finally
146 { 150 {
151 ReleaseVerutilVersion(pVersion);
147 ReleaseObject(pixeBundle); 152 ReleaseObject(pixeBundle);
148 VariablesUninitialize(&variables); 153 VariablesUninitialize(&variables);
149 SearchesUninitialize(&searches); 154 SearchesUninitialize(&searches);
@@ -247,8 +252,8 @@ namespace Bootstrapper
247 Assert::NotEqual(gcnew String(L"String1 %TEMP%"), VariableGetStringHelper(&variables, L"Variable10")); 252 Assert::NotEqual(gcnew String(L"String1 %TEMP%"), VariableGetStringHelper(&variables, L"Variable10"));
248 Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable11")); 253 Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable11"));
249 Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable12")); 254 Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable12"));
250 Assert::Equal(MAKEQWORDVERSION(1,1,1,1), VariableGetVersionHelper(&variables, L"Variable13")); 255 Assert::Equal<String^>(gcnew String(L"1.1.1.1"), VariableGetVersionHelper(&variables, L"Variable13"));
251 Assert::Equal(MAKEQWORDVERSION(1,1,1,1), VariableGetVersionHelper(&variables, L"Variable14")); 256 Assert::Equal<String^>(gcnew String(L"1.1.1.1"), VariableGetVersionHelper(&variables, L"Variable14"));
252 Assert::Equal<String^>(gcnew String(L"String1"), VariableGetStringHelper(&variables, L"Variable15")); 257 Assert::Equal<String^>(gcnew String(L"String1"), VariableGetStringHelper(&variables, L"Variable15"));
253 Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable16")); 258 Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable16"));
254 Assert::False(VariableExistsHelper(&variables, L"Variable17")); 259 Assert::False(VariableExistsHelper(&variables, L"Variable17"));
@@ -401,11 +406,11 @@ namespace Bootstrapper
401 406
402 // check variable values 407 // check variable values
403 Assert::Equal(2ll, VariableGetNumericHelper(&variables, L"Variable1")); 408 Assert::Equal(2ll, VariableGetNumericHelper(&variables, L"Variable1"));
404 Assert::Equal(MAKEQWORDVERSION(1,0,0,0), VariableGetVersionHelper(&variables, L"Variable2")); 409 Assert::Equal<String^>(gcnew String(L"1.0.0.0"), VariableGetVersionHelper(&variables, L"Variable2"));
405 Assert::Equal(1033ll, VariableGetNumericHelper(&variables, L"Variable3")); 410 Assert::Equal(1033ll, VariableGetNumericHelper(&variables, L"Variable3"));
406 Assert::Equal(5ll, VariableGetNumericHelper(&variables, L"Variable4")); 411 Assert::Equal(5ll, VariableGetNumericHelper(&variables, L"Variable4"));
407 Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable5")); 412 Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable5"));
408 Assert::Equal(MAKEQWORDVERSION(1,0,0,0), VariableGetVersionHelper(&variables, L"Variable6")); 413 Assert::Equal<String^>(gcnew String(L"1.0.0.0"), VariableGetVersionHelper(&variables, L"Variable6"));
409 } 414 }
410 finally 415 finally
411 { 416 {
@@ -581,7 +586,7 @@ namespace Bootstrapper
581 Assert::Equal<String^>(gcnew String(L"VAL5"), VariableGetStringHelper(&variables, L"PROP5")); 586 Assert::Equal<String^>(gcnew String(L"VAL5"), VariableGetStringHelper(&variables, L"PROP5"));
582 Assert::Equal<String^>(gcnew String(L"VAL6"), VariableGetStringHelper(&variables, L"PROP6")); 587 Assert::Equal<String^>(gcnew String(L"VAL6"), VariableGetStringHelper(&variables, L"PROP6"));
583 Assert::Equal(7ll, VariableGetNumericHelper(&variables, L"PROP7")); 588 Assert::Equal(7ll, VariableGetNumericHelper(&variables, L"PROP7"));
584 Assert::Equal(MAKEQWORDVERSION(1, 1, 0, 0), VariableGetVersionHelper(&variables, L"PROP8")); 589 Assert::Equal<String^>(gcnew String(L"1.1.0.0"), VariableGetVersionHelper(&variables, L"PROP8"));
585 Assert::Equal<String^>(gcnew String(L"1.1.0.0"), VariableGetStringHelper(&variables, L"PROP8")); 590 Assert::Equal<String^>(gcnew String(L"1.1.0.0"), VariableGetStringHelper(&variables, L"PROP8"));
586 Assert::Equal<String^>(gcnew String(L"[VAL9]"), VariableGetStringHelper(&variables, L"PROP9")); 591 Assert::Equal<String^>(gcnew String(L"[VAL9]"), VariableGetStringHelper(&variables, L"PROP9"));
587 592
diff --git a/src/test/BurnUnitTest/VariableHelpers.cpp b/src/test/BurnUnitTest/VariableHelpers.cpp
index fdfb9191..99ba492a 100644
--- a/src/test/BurnUnitTest/VariableHelpers.cpp
+++ b/src/test/BurnUnitTest/VariableHelpers.cpp
@@ -33,12 +33,23 @@ namespace Bootstrapper
33 TestThrowOnFailure2(hr, L"Failed to set %s to: %I64d", wzVariable, llValue); 33 TestThrowOnFailure2(hr, L"Failed to set %s to: %I64d", wzVariable, llValue);
34 } 34 }
35 35
36 void VariableSetVersionHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable, DWORD64 qwValue) 36 void VariableSetVersionHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable, LPCWSTR wzValue)
37 { 37 {
38 HRESULT hr = S_OK; 38 HRESULT hr = S_OK;
39 VERUTIL_VERSION* pVersion = NULL;
39 40
40 hr = VariableSetVersion(pVariables, wzVariable, qwValue, FALSE); 41 try
41 TestThrowOnFailure2(hr, L"Failed to set %s to: 0x%016I64x", wzVariable, qwValue); 42 {
43 hr = VerParseVersion(wzValue, 0, FALSE, &pVersion);
44 TestThrowOnFailure1(hr, L"Failed to parse version '%ls'", wzValue);
45
46 hr = VariableSetVersion(pVariables, wzVariable, pVersion, FALSE);
47 TestThrowOnFailure2(hr, L"Failed to set %s to: '%ls'", wzVariable, wzValue);
48 }
49 finally
50 {
51 ReleaseVerutilVersion(pVersion);
52 }
42 } 53 }
43 54
44 String^ VariableGetStringHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable) 55 String^ VariableGetStringHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable)
@@ -69,15 +80,22 @@ namespace Bootstrapper
69 return llValue; 80 return llValue;
70 } 81 }
71 82
72 unsigned __int64 VariableGetVersionHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable) 83 String^ VariableGetVersionHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable)
73 { 84 {
74 HRESULT hr = S_OK; 85 HRESULT hr = S_OK;
75 DWORD64 qwValue = 0; 86 VERUTIL_VERSION* pValue = NULL;
76 87
77 hr = VariableGetVersion(pVariables, wzVariable, &qwValue); 88 try
78 TestThrowOnFailure1(hr, L"Failed to get: %s", wzVariable); 89 {
90 hr = VariableGetVersion(pVariables, wzVariable, &pValue);
91 TestThrowOnFailure1(hr, L"Failed to get: %s", wzVariable);
79 92
80 return qwValue; 93 return gcnew String(pValue->sczVersion);
94 }
95 finally
96 {
97 ReleaseVerutilVersion(pValue);
98 }
81 } 99 }
82 100
83 String^ VariableGetFormattedHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable) 101 String^ VariableGetFormattedHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable)
diff --git a/src/test/BurnUnitTest/VariableHelpers.h b/src/test/BurnUnitTest/VariableHelpers.h
index 8c2b081a..96122219 100644
--- a/src/test/BurnUnitTest/VariableHelpers.h
+++ b/src/test/BurnUnitTest/VariableHelpers.h
@@ -16,10 +16,10 @@ namespace Bootstrapper
16 16
17void VariableSetStringHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable, LPCWSTR wzValue, BOOL fFormatted); 17void VariableSetStringHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable, LPCWSTR wzValue, BOOL fFormatted);
18void VariableSetNumericHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable, LONGLONG llValue); 18void VariableSetNumericHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable, LONGLONG llValue);
19void VariableSetVersionHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable, DWORD64 qwValue); 19void VariableSetVersionHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable, LPCWSTR wzValue);
20System::String^ VariableGetStringHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable); 20System::String^ VariableGetStringHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable);
21__int64 VariableGetNumericHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable); 21__int64 VariableGetNumericHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable);
22unsigned __int64 VariableGetVersionHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable); 22System::String^ VariableGetVersionHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable);
23System::String^ VariableGetFormattedHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable); 23System::String^ VariableGetFormattedHelper(BURN_VARIABLES* pVariables, LPCWSTR wzVariable);
24System::String^ VariableFormatStringHelper(BURN_VARIABLES* pVariables, LPCWSTR wzIn); 24System::String^ VariableFormatStringHelper(BURN_VARIABLES* pVariables, LPCWSTR wzIn);
25System::String^ VariableEscapeStringHelper(LPCWSTR wzIn); 25System::String^ VariableEscapeStringHelper(LPCWSTR wzIn);
diff --git a/src/test/BurnUnitTest/VariableTest.cpp b/src/test/BurnUnitTest/VariableTest.cpp
index 0b49a530..405c8fab 100644
--- a/src/test/BurnUnitTest/VariableTest.cpp
+++ b/src/test/BurnUnitTest/VariableTest.cpp
@@ -42,7 +42,7 @@ namespace Bootstrapper
42 VariableSetStringHelper(&variables, L"PROP4", L"VAL4", FALSE); 42 VariableSetStringHelper(&variables, L"PROP4", L"VAL4", FALSE);
43 VariableSetStringHelper(&variables, L"PROP6", L"VAL6", FALSE); 43 VariableSetStringHelper(&variables, L"PROP6", L"VAL6", FALSE);
44 VariableSetStringHelper(&variables, L"PROP7", L"7", FALSE); 44 VariableSetStringHelper(&variables, L"PROP7", L"7", FALSE);
45 VariableSetVersionHelper(&variables, L"PROP8", MAKEQWORDVERSION(1,1,0,0)); 45 VariableSetVersionHelper(&variables, L"PROP8", L"1.1.0.0");
46 VariableSetStringHelper(&variables, L"PROP9", L"[VAL9]", TRUE); 46 VariableSetStringHelper(&variables, L"PROP9", L"[VAL9]", TRUE);
47 47
48 // set overwritten variables 48 // set overwritten variables
@@ -61,7 +61,7 @@ namespace Bootstrapper
61 Assert::Equal<String^>(gcnew String(L"VAL5"), VariableGetStringHelper(&variables, L"PROP5")); 61 Assert::Equal<String^>(gcnew String(L"VAL5"), VariableGetStringHelper(&variables, L"PROP5"));
62 Assert::Equal<String^>(gcnew String(L"VAL6"), VariableGetStringHelper(&variables, L"PROP6")); 62 Assert::Equal<String^>(gcnew String(L"VAL6"), VariableGetStringHelper(&variables, L"PROP6"));
63 Assert::Equal(7ll, VariableGetNumericHelper(&variables, L"PROP7")); 63 Assert::Equal(7ll, VariableGetNumericHelper(&variables, L"PROP7"));
64 Assert::Equal(MAKEQWORDVERSION(1,1,0,0), VariableGetVersionHelper(&variables, L"PROP8")); 64 Assert::Equal<String^>(gcnew String(L"1.1.0.0"), VariableGetVersionHelper(&variables, L"PROP8"));
65 Assert::Equal<String^>(gcnew String(L"1.1.0.0"), VariableGetStringHelper(&variables, L"PROP8")); 65 Assert::Equal<String^>(gcnew String(L"1.1.0.0"), VariableGetStringHelper(&variables, L"PROP8"));
66 Assert::Equal<String^>(gcnew String(L"[VAL9]"), VariableGetStringHelper(&variables, L"PROP9")); 66 Assert::Equal<String^>(gcnew String(L"[VAL9]"), VariableGetStringHelper(&variables, L"PROP9"));
67 67
@@ -110,7 +110,7 @@ namespace Bootstrapper
110 110
111 Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Var1")); 111 Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Var1"));
112 Assert::Equal<String^>(gcnew String(L"String value."), VariableGetStringHelper(&variables, L"Var2")); 112 Assert::Equal<String^>(gcnew String(L"String value."), VariableGetStringHelper(&variables, L"Var2"));
113 Assert::Equal(MAKEQWORDVERSION(1,2,3,4), VariableGetVersionHelper(&variables, L"Var3")); 113 Assert::Equal<String^>(gcnew String(L"1.2.3.4"), VariableGetVersionHelper(&variables, L"Var3"));
114 Assert::Equal<String^>(gcnew String(L"[Formatted]"), VariableGetStringHelper(&variables, L"Var6")); 114 Assert::Equal<String^>(gcnew String(L"[Formatted]"), VariableGetStringHelper(&variables, L"Var6"));
115 } 115 }
116 finally 116 finally
@@ -214,13 +214,13 @@ namespace Bootstrapper
214 VariableSetNumericHelper(&variables, L"PROP13", 0x00010000); 214 VariableSetNumericHelper(&variables, L"PROP13", 0x00010000);
215 VariableSetNumericHelper(&variables, L"PROP14", 0x00000001); 215 VariableSetNumericHelper(&variables, L"PROP14", 0x00000001);
216 VariableSetNumericHelper(&variables, L"PROP15", 0x00010001); 216 VariableSetNumericHelper(&variables, L"PROP15", 0x00010001);
217 VariableSetVersionHelper(&variables, L"PROP16", MAKEQWORDVERSION(0,0,0,0)); 217 VariableSetVersionHelper(&variables, L"PROP16", L"0.0.0.0");
218 VariableSetVersionHelper(&variables, L"PROP17", MAKEQWORDVERSION(1,0,0,0)); 218 VariableSetVersionHelper(&variables, L"PROP17", L"1.0.0.0");
219 VariableSetVersionHelper(&variables, L"PROP18", MAKEQWORDVERSION(1,1,0,0)); 219 VariableSetVersionHelper(&variables, L"PROP18", L"1.1.0.0");
220 VariableSetVersionHelper(&variables, L"PROP19", MAKEQWORDVERSION(1,1,1,0)); 220 VariableSetVersionHelper(&variables, L"PROP19", L"1.1.1.0");
221 VariableSetVersionHelper(&variables, L"PROP20", MAKEQWORDVERSION(1,1,1,1)); 221 VariableSetVersionHelper(&variables, L"PROP20", L"1.1.1.1");
222 VariableSetNumericHelper(&variables, L"vPROP21", 1); 222 VariableSetNumericHelper(&variables, L"vPROP21", 1);
223 VariableSetVersionHelper(&variables, L"PROP22", MAKEQWORDVERSION(65535,65535,65535,65535)); 223 VariableSetVersionHelper(&variables, L"PROP22", L"65535.65535.65535.65535");
224 VariableSetStringHelper(&variables, L"PROP23", L"1.1.1", FALSE); 224 VariableSetStringHelper(&variables, L"PROP23", L"1.1.1", FALSE);
225 VariableSetStringHelper(&variables, L"PROP24", L"[PROP1]", TRUE); 225 VariableSetStringHelper(&variables, L"PROP24", L"[PROP1]", TRUE);
226 VariableSetStringHelper(&variables, L"PROP25", L"[PROP7]", TRUE); 226 VariableSetStringHelper(&variables, L"PROP25", L"[PROP7]", TRUE);
@@ -233,7 +233,7 @@ namespace Bootstrapper
233 Assert::False(EvaluateConditionHelper(&variables, L"PROP7")); 233 Assert::False(EvaluateConditionHelper(&variables, L"PROP7"));
234 Assert::False(EvaluateConditionHelper(&variables, L"PROP8")); 234 Assert::False(EvaluateConditionHelper(&variables, L"PROP8"));
235 Assert::True(EvaluateConditionHelper(&variables, L"_PROP9")); 235 Assert::True(EvaluateConditionHelper(&variables, L"_PROP9"));
236 Assert::False(EvaluateConditionHelper(&variables, L"PROP16")); 236 Assert::True(EvaluateConditionHelper(&variables, L"PROP16"));
237 Assert::True(EvaluateConditionHelper(&variables, L"PROP17")); 237 Assert::True(EvaluateConditionHelper(&variables, L"PROP17"));
238 Assert::True(EvaluateConditionHelper(&variables, L"PROP24")); 238 Assert::True(EvaluateConditionHelper(&variables, L"PROP24"));
239 Assert::True(EvaluateConditionHelper(&variables, L"PROP25")); 239 Assert::True(EvaluateConditionHelper(&variables, L"PROP25"));
@@ -268,8 +268,8 @@ namespace Bootstrapper
268 Assert::True(EvaluateConditionHelper(&variables, L"PROP18 = v1.1")); 268 Assert::True(EvaluateConditionHelper(&variables, L"PROP18 = v1.1"));
269 Assert::True(EvaluateConditionHelper(&variables, L"PROP19 = v1.1.1")); 269 Assert::True(EvaluateConditionHelper(&variables, L"PROP19 = v1.1.1"));
270 Assert::True(EvaluateConditionHelper(&variables, L"PROP20 = v1.1.1.1")); 270 Assert::True(EvaluateConditionHelper(&variables, L"PROP20 = v1.1.1.1"));
271 Assert::True(EvaluateFailureConditionHelper(&variables, L"PROP20 = v1.1.1.1.0")); 271 Assert::True(EvaluateConditionHelper(&variables, L"PROP20 > v1.1.1.1.0"));
272 Assert::True(EvaluateFailureConditionHelper(&variables, L"PROP20 = v1.1.1.1.1")); 272 Assert::True(EvaluateConditionHelper(&variables, L"PROP20 > v1.1.1.1.1"));
273 Assert::True(EvaluateConditionHelper(&variables, L"vPROP21 = 1")); 273 Assert::True(EvaluateConditionHelper(&variables, L"vPROP21 = 1"));
274 Assert::True(EvaluateConditionHelper(&variables, L"PROP23 = v1.1.1")); 274 Assert::True(EvaluateConditionHelper(&variables, L"PROP23 = v1.1.1"));
275 Assert::True(EvaluateConditionHelper(&variables, L"v1.1.1 = PROP23")); 275 Assert::True(EvaluateConditionHelper(&variables, L"v1.1.1 = PROP23"));
@@ -287,8 +287,8 @@ namespace Bootstrapper
287 Assert::True(EvaluateFailureConditionHelper(&variables, L"PROP12 = -92233720368547758080000")); 287 Assert::True(EvaluateFailureConditionHelper(&variables, L"PROP12 = -92233720368547758080000"));
288 288
289 Assert::True(EvaluateConditionHelper(&variables, L"PROP22 = v65535.65535.65535.65535")); 289 Assert::True(EvaluateConditionHelper(&variables, L"PROP22 = v65535.65535.65535.65535"));
290 Assert::True(EvaluateFailureConditionHelper(&variables, L"PROP22 = v65536.65535.65535.65535")); 290 Assert::True(EvaluateConditionHelper(&variables, L"PROP22 < v65536.65535.65535.65535"));
291 Assert::True(EvaluateFailureConditionHelper(&variables, L"PROP22 = v65535.655350000.65535.65535")); 291 Assert::True(EvaluateConditionHelper(&variables, L"PROP22 < v65535.655350000.65535.65535"));
292 292
293 Assert::True(EvaluateConditionHelper(&variables, L"PROP5 < 6")); 293 Assert::True(EvaluateConditionHelper(&variables, L"PROP5 < 6"));
294 Assert::False(EvaluateConditionHelper(&variables, L"PROP5 < 5")); 294 Assert::False(EvaluateConditionHelper(&variables, L"PROP5 < 5"));
@@ -388,7 +388,7 @@ namespace Bootstrapper
388 388
389 VariableSetStringHelper(&variables1, L"PROP1", L"VAL1", FALSE); 389 VariableSetStringHelper(&variables1, L"PROP1", L"VAL1", FALSE);
390 VariableSetNumericHelper(&variables1, L"PROP2", 2); 390 VariableSetNumericHelper(&variables1, L"PROP2", 2);
391 VariableSetVersionHelper(&variables1, L"PROP3", MAKEQWORDVERSION(1,1,1,1)); 391 VariableSetVersionHelper(&variables1, L"PROP3", L"1.1.1.1");
392 VariableSetStringHelper(&variables1, L"PROP4", L"VAL4", FALSE); 392 VariableSetStringHelper(&variables1, L"PROP4", L"VAL4", FALSE);
393 VariableSetStringHelper(&variables1, L"PROP5", L"[PROP1]", TRUE); 393 VariableSetStringHelper(&variables1, L"PROP5", L"[PROP1]", TRUE);
394 394
@@ -404,7 +404,7 @@ namespace Bootstrapper
404 404
405 Assert::Equal<String^>(gcnew String(L"VAL1"), VariableGetStringHelper(&variables2, L"PROP1")); 405 Assert::Equal<String^>(gcnew String(L"VAL1"), VariableGetStringHelper(&variables2, L"PROP1"));
406 Assert::Equal(2ll, VariableGetNumericHelper(&variables2, L"PROP2")); 406 Assert::Equal(2ll, VariableGetNumericHelper(&variables2, L"PROP2"));
407 Assert::Equal(MAKEQWORDVERSION(1,1,1,1), VariableGetVersionHelper(&variables2, L"PROP3")); 407 Assert::Equal<String^>(gcnew String(L"1.1.1.1"), VariableGetVersionHelper(&variables2, L"PROP3"));
408 Assert::Equal<String^>(gcnew String(L"VAL4"), VariableGetStringHelper(&variables2, L"PROP4")); 408 Assert::Equal<String^>(gcnew String(L"VAL4"), VariableGetStringHelper(&variables2, L"PROP4"));
409 Assert::Equal<String^>(gcnew String(L"[PROP1]"), VariableGetStringHelper(&variables2, L"PROP5")); 409 Assert::Equal<String^>(gcnew String(L"[PROP1]"), VariableGetStringHelper(&variables2, L"PROP5"));
410 410
diff --git a/src/test/BurnUnitTest/VariantTest.cpp b/src/test/BurnUnitTest/VariantTest.cpp
index c982db72..34328f53 100644
--- a/src/test/BurnUnitTest/VariantTest.cpp
+++ b/src/test/BurnUnitTest/VariantTest.cpp
@@ -37,10 +37,10 @@ namespace Bootstrapper
37 { 37 {
38 InitNumericValue(expectedVariants + 0, 2, FALSE, L"PROP1", actualVariants + 0); 38 InitNumericValue(expectedVariants + 0, 2, FALSE, L"PROP1", actualVariants + 0);
39 InitStringValue(expectedVariants + 1, L"VAL2", FALSE, L"PROP2", actualVariants + 1); 39 InitStringValue(expectedVariants + 1, L"VAL2", FALSE, L"PROP2", actualVariants + 1);
40 InitVersionValue(expectedVariants + 2, MAKEQWORDVERSION(1, 1, 0, 0), FALSE, L"PROP3", actualVariants + 2); 40 InitVersionValue(expectedVariants + 2, L"1.1.0.0", FALSE, L"PROP3", actualVariants + 2);
41 InitNoneValue(expectedVariants + 3, FALSE, L"PROP4", actualVariants + 3); 41 InitNoneValue(expectedVariants + 3, FALSE, L"PROP4", actualVariants + 3);
42 InitNoneValue(expectedVariants + 4, TRUE, L"PROP5", actualVariants + 4); 42 InitNoneValue(expectedVariants + 4, TRUE, L"PROP5", actualVariants + 4);
43 InitVersionValue(expectedVariants + 5, MAKEQWORDVERSION(1, 1, 1, 0), TRUE, L"PROP6", actualVariants + 5); 43 InitVersionValue(expectedVariants + 5, L"1.1.1.0", TRUE, L"PROP6", actualVariants + 5);
44 InitStringValue(expectedVariants + 6, L"7", TRUE, L"PROP7", actualVariants + 6); 44 InitStringValue(expectedVariants + 6, L"7", TRUE, L"PROP7", actualVariants + 6);
45 InitNumericValue(expectedVariants + 7, 11, TRUE, L"PROP8", actualVariants + 7); 45 InitNumericValue(expectedVariants + 7, 11, TRUE, L"PROP8", actualVariants + 7);
46 InitFormattedValue(expectedVariants + 8, L"VAL9", FALSE, L"PROP9", actualVariants + 8); 46 InitFormattedValue(expectedVariants + 8, L"VAL9", FALSE, L"PROP9", actualVariants + 8);
@@ -143,21 +143,34 @@ namespace Bootstrapper
143 } 143 }
144 } 144 }
145 145
146 void InitVersionValue(BURN_VARIANT* pValue, DWORD64 qwValue, BOOL fHidden, LPCWSTR wz, BURN_VARIANT* pActualValue) 146 void InitVersionValue(BURN_VARIANT* pValue, LPCWSTR wzValue, BOOL fHidden, LPCWSTR wz, BURN_VARIANT* pActualValue)
147 { 147 {
148 HRESULT hr = S_OK; 148 HRESULT hr = S_OK;
149 pValue->Type = BURN_VARIANT_TYPE_VERSION; 149 VERUTIL_VERSION* pVersion = NULL;
150 pValue->qwValue = qwValue;
151 150
152 hr = BVariantCopy(pValue, pActualValue); 151 try
153 NativeAssert::Succeeded(hr, "Failed to copy variant {0}", wz);
154
155 if (fHidden)
156 { 152 {
157 hr = BVariantSetEncryption(pActualValue, TRUE); 153 hr = VerParseVersion(wzValue, 0, FALSE, &pVersion);
158 NativeAssert::Succeeded(hr, "Failed to encrypt variant {0}", wz); 154 NativeAssert::Succeeded(hr, "Failed to parse version {0}", wzValue);
159 155
160 NativeAssert::True(pActualValue->fEncryptString); 156 pValue->Type = BURN_VARIANT_TYPE_VERSION;
157 pValue->pValue = pVersion;
158 pVersion = NULL;
159
160 hr = BVariantCopy(pValue, pActualValue);
161 NativeAssert::Succeeded(hr, "Failed to copy variant {0}", wz);
162
163 if (fHidden)
164 {
165 hr = BVariantSetEncryption(pActualValue, TRUE);
166 NativeAssert::Succeeded(hr, "Failed to encrypt variant {0}", wz);
167
168 NativeAssert::True(pActualValue->fEncryptString);
169 }
170 }
171 finally
172 {
173 ReleaseVerutilVersion(pVersion);
161 } 174 }
162 } 175 }
163 176
@@ -224,14 +237,21 @@ namespace Bootstrapper
224 void VerifyVersionValue(BURN_VARIANT* pExpectedValue, BURN_VARIANT* pActualValue) 237 void VerifyVersionValue(BURN_VARIANT* pExpectedValue, BURN_VARIANT* pActualValue)
225 { 238 {
226 HRESULT hr = S_OK; 239 HRESULT hr = S_OK;
227 DWORD64 qwValue = 0; 240 VERUTIL_VERSION* pValue = NULL;
228 NativeAssert::Equal<DWORD>(BURN_VARIANT_TYPE_VERSION, pExpectedValue->Type); 241 NativeAssert::Equal<DWORD>(BURN_VARIANT_TYPE_VERSION, pExpectedValue->Type);
229 NativeAssert::Equal<DWORD>(BURN_VARIANT_TYPE_VERSION, pActualValue->Type); 242 NativeAssert::Equal<DWORD>(BURN_VARIANT_TYPE_VERSION, pActualValue->Type);
230 243
231 hr = BVariantGetVersion(pActualValue, &qwValue); 244 try
232 NativeAssert::Succeeded(hr, "Failed to get version value"); 245 {
246 hr = BVariantGetVersion(pActualValue, &pValue);
247 NativeAssert::Succeeded(hr, "Failed to get version value");
233 248
234 NativeAssert::Equal<DWORD64>(pExpectedValue->qwValue, qwValue); 249 NativeAssert::StringEqual(pExpectedValue->pValue->sczVersion, pActualValue->pValue->sczVersion);
250 }
251 finally
252 {
253 ReleaseVerutilVersion(pValue);
254 }
235 } 255 }
236 }; 256 };
237} 257}
diff --git a/src/test/BurnUnitTest/packages.config b/src/test/BurnUnitTest/packages.config
index e537bcdb..74f2523f 100644
--- a/src/test/BurnUnitTest/packages.config
+++ b/src/test/BurnUnitTest/packages.config
@@ -9,5 +9,5 @@
9 <package id="xunit.runner.visualstudio" version="2.4.1" /> 9 <package id="xunit.runner.visualstudio" version="2.4.1" />
10 <package id="WixBuildTools.TestSupport" version="4.0.40" /> 10 <package id="WixBuildTools.TestSupport" version="4.0.40" />
11 <package id="WixBuildTools.TestSupport.Native" version="4.0.40" /> 11 <package id="WixBuildTools.TestSupport.Native" version="4.0.40" />
12 <package id="WixToolset.DUtil" version="4.0.49" targetFramework="native" /> 12 <package id="WixToolset.DUtil" version="4.0.55" targetFramework="native" />
13</packages> \ No newline at end of file 13</packages> \ No newline at end of file
diff --git a/src/test/BurnUnitTest/precomp.h b/src/test/BurnUnitTest/precomp.h
index e288eb3e..fea30156 100644
--- a/src/test/BurnUnitTest/precomp.h
+++ b/src/test/BurnUnitTest/precomp.h
@@ -13,6 +13,7 @@
13#include "wininet.h" 13#include "wininet.h"
14 14
15#include <dutil.h> 15#include <dutil.h>
16#include <verutil.h>
16#include <cryputil.h> 17#include <cryputil.h>
17#include <dlutil.h> 18#include <dlutil.h>
18#include <buffutil.h> 19#include <buffutil.h>