@joebigelow / wix-1 / commits / 0afd76e4

Add DetectSHA2Support "search".

Sean Hall committed Mar 30, 2020 at 19:46 UTC 0afd76e4c5d46f237591d860e7d445e267522187
20 files changed +611 -501
nuget.config
+2
@@ -2,6 +2,8 @@
2 <configuration>
3 <packageSources>
4 <clear />
5 + <add key="wixtoolset-balutil" value="https://ci.appveyor.com/nuget/wixtoolset-balutil" />
6 + <add key="wixtoolset-bootstrappercore" value="https://ci.appveyor.com/nuget/wixtoolset-bootstrappercore" />
7 <add key="wixtoolset-data" value="https://ci.appveyor.com/nuget/wixtoolset-data" />
8 <add key="wixtoolset-extensibility" value="https://ci.appveyor.com/nuget/wixtoolset-extensibility" />
9 <add key="wixtoolset-core" value="https://ci.appveyor.com/nuget/wixtoolset-core" />
src/be/UtilBundleExtension.cpp new
+87
@@ -0,0 +1,87 @@
1 +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2 +
3 +#include "precomp.h"
4 +#include "BextBaseBundleExtension.h"
5 +
6 +class CWixUtilBundleExtension : public CBextBaseBundleExtension
7 +{
8 +public: // IBundleExtension
9 + virtual STDMETHODIMP Search(
10 + __in LPCWSTR wzId,
11 + __in LPCWSTR wzVariable
12 + )
13 + {
14 + HRESULT hr = S_OK;
15 +
16 + hr = UtilSearchExecute(&m_searches, wzId, wzVariable, m_pEngine);
17 +
18 + return hr;
19 + }
20 +
21 +public: //CBextBaseBundleExtension
22 + virtual STDMETHODIMP Initialize(
23 + __in const BUNDLE_EXTENSION_CREATE_ARGS* pCreateArgs
24 + )
25 + {
26 + HRESULT hr = S_OK;
27 + IXMLDOMDocument* pixdManifest = NULL;
28 + IXMLDOMNode* pixnBundleExtension = NULL;
29 +
30 + hr = CBextBaseBundleExtension::Initialize(pCreateArgs);
31 + ExitOnFailure(hr, "CBextBaseBundleExtension initialization failed.");
32 +
33 + hr = XmlLoadDocumentFromFile(m_sczBundleExtensionDataPath, &pixdManifest);
34 + ExitOnFailure(hr, "Failed to load bundle extension manifest from path: %ls", m_sczBundleExtensionDataPath);
35 +
36 + hr = BextGetBundleExtensionDataNode(pixdManifest, UTIL_BUNDLE_EXTENSION_ID, &pixnBundleExtension);
37 + ExitOnFailure(hr, "Failed to get BundleExtension '%ls'", UTIL_BUNDLE_EXTENSION_ID);
38 +
39 + hr = UtilSearchParseFromXml(&m_searches, pixnBundleExtension);
40 + ExitOnFailure(hr, "Failed to parse searches from bundle extension manifest.");
41 +
42 + LExit:
43 + ReleaseObject(pixnBundleExtension);
44 + ReleaseObject(pixdManifest);
45 +
46 + return hr;
47 + }
48 +
49 +public:
50 + CWixUtilBundleExtension(
51 + __in IBundleExtensionEngine* pEngine
52 + ) : CBextBaseBundleExtension(pEngine)
53 + {
54 + m_searches = { };
55 + }
56 +
57 + ~CWixUtilBundleExtension()
58 + {
59 + UtilSearchUninitialize(&m_searches);
60 + }
61 +
62 +private:
63 + UTIL_SEARCHES m_searches;
64 +};
65 +
66 +HRESULT UtilBundleExtensionCreate(
67 + __in IBundleExtensionEngine* pEngine,
68 + __in const BUNDLE_EXTENSION_CREATE_ARGS* pArgs,
69 + __out IBundleExtension** ppBundleExtension
70 + )
71 +{
72 + HRESULT hr = S_OK;
73 + CWixUtilBundleExtension* pExtension = NULL;
74 +
75 + pExtension = new CWixUtilBundleExtension(pEngine);
76 + ExitOnNull(pExtension, hr, E_OUTOFMEMORY, "Failed to create new CWixUtilBundleExtension.");
77 +
78 + hr = pExtension->Initialize(pArgs);
79 + ExitOnFailure(hr, "CWixUtilBundleExtension initialization failed");
80 +
81 + *ppBundleExtension = pExtension;
82 + pExtension = NULL;
83 +
84 +LExit:
85 + ReleaseObject(pExtension);
86 + return hr;
87 +}
src/be/UtilBundleExtension.h new
+16
@@ -0,0 +1,16 @@
1 +#pragma once
2 +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3 +
4 +
5 +// constants
6 +
7 +#define UTIL_BUNDLE_EXTENSION_ID L"WixUtilBundleExtension"
8 +
9 +
10 +// function declarations
11 +
12 +HRESULT UtilBundleExtensionCreate(
13 + __in IBundleExtensionEngine* pEngine,
14 + __in const BUNDLE_EXTENSION_CREATE_ARGS* pArgs,
15 + __out IBundleExtension** ppBundleExtension
16 + );
src/be/detectsha2support.cpp new
+58
@@ -0,0 +1,58 @@
1 +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2 +
3 +#include "precomp.h"
4 +
5 +// https://gist.github.com/navossoc/7572c7d82243e9f818989e2765e7793a
6 +HRESULT DetectSHA2Support(
7 + __out BOOL* pfSupported
8 + )
9 +{
10 + HRESULT hr = S_OK;
11 + HMODULE hModule = NULL;
12 + FARPROC pfn = NULL;
13 + DWORD er = ERROR_SUCCESS;
14 +
15 + hr = LoadSystemLibrary(L"wintrust.dll", &hModule);
16 + ExitOnFailure(hr, "Failed to load wintrust.dll");
17 +
18 + pfn = ::GetProcAddress(hModule, "CryptCATAdminAcquireContext2");
19 + if (pfn)
20 + {
21 + *pfSupported = TRUE;
22 + ExitFunction1(hr = S_OK);
23 + }
24 +
25 + er = ::GetLastError();
26 + if (er == ERROR_PROC_NOT_FOUND)
27 + {
28 + *pfSupported = FALSE;
29 + ExitFunction1(hr = S_OK);
30 + }
31 +
32 + hr = HRESULT_FROM_WIN32(er);
33 + ExitOnFailure(hr, "Failed to probe for CryptCATAdminAcquireContext2 in wintrust.dll");
34 +
35 +LExit:
36 + ::FreeLibrary(hModule);
37 +
38 + return hr;
39 +}
40 +
41 +HRESULT UtilPerformDetectSHA2Support(
42 + __in LPCWSTR wzVariable,
43 + __in UTIL_SEARCH* /*pSearch*/,
44 + __in IBundleExtensionEngine* pEngine
45 + )
46 +{
47 + HRESULT hr = S_OK;
48 + BOOL fSupported = FALSE;
49 +
50 + hr = DetectSHA2Support(&fSupported);
51 + ExitOnFailure(hr, "DetectSHA2Support failed.");
52 +
53 + hr = pEngine->SetVariableNumeric(wzVariable, fSupported ? 1 : 0);
54 + ExitOnFailure(hr, "Failed to set variable '%ls'", wzVariable);
55 +
56 +LExit:
57 + return hr;
58 +}
src/be/detectsha2support.h new
+8
@@ -0,0 +1,8 @@
1 +#pragma once
2 +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3 +
4 +HRESULT UtilPerformDetectSHA2Support(
5 + __in LPCWSTR wzVariable,
6 + __in UTIL_SEARCH* pSearch,
7 + __in IBundleExtensionEngine* pEngine
8 + );
\ No newline at end of file
src/be/packages.config
+1
@@ -1,5 +1,6 @@
1 <?xml version="1.0" encoding="utf-8"?>
2 <packages>
3 + <package id="WixToolset.BextUtil" version="4.0.16" targetFramework="native" />
4 <package id="WixToolset.BootstrapperCore.Native" version="4.0.13" targetFramework="native" />
5 <package id="WixToolset.DUtil" version="4.0.18" targetFramework="native" />
6 </packages>
\ No newline at end of file
src/be/precomp.h
+17 -6
@@ -17,9 +17,20 @@
17
18 #define MAXUINT USHRT_MAX
19
20 -#include "dutil.h"
21 -#include "memutil.h"
22 -
23 -#include "BootstrapperEngine.h"
24 -#include "BundleExtensionEngine.h"
25 -#include "BundleExtension.h"
20 +#include <dutil.h>
21 +#include <memutil.h>
22 +#include <strutil.h>
23 +#include <pathutil.h>
24 +#include <xmlutil.h>
25 +
26 +#include <BundleExtensionEngine.h>
27 +#include <BundleExtension.h>
28 +
29 +#include <IBundleExtensionEngine.h>
30 +#include <IBundleExtension.h>
31 +#include <bextutil.h>
32 +#include <BextBundleExtensionEngine.h>
33 +
34 +#include "utilsearch.h"
35 +#include "detectsha2support.h"
36 +#include "UtilBundleExtension.h"
src/be/utilbe.cpp
+25 -3
@@ -1,19 +1,41 @@
1 // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3 #include "precomp.h"
4 +#include "BextBaseBundleExtensionProc.h"
5 +
6 +static IBundleExtension* vpBundleExtension = NULL;
7
8 // function definitions
9
10 extern "C" HRESULT WINAPI BundleExtensionCreate(
8 - __in const BUNDLE_EXTENSION_CREATE_ARGS* /*pArgs*/,
9 - __inout BUNDLE_EXTENSION_CREATE_RESULTS* /*pResults*/
11 + __in const BUNDLE_EXTENSION_CREATE_ARGS* pArgs,
12 + __inout BUNDLE_EXTENSION_CREATE_RESULTS* pResults
13 )
14 {
12 - HRESULT hr = S_OK;
15 + HRESULT hr = S_OK;
16 + IBundleExtensionEngine* pEngine = NULL;
17 +
18 + hr = XmlInitialize();
19 + ExitOnFailure(hr, "Failed to initialize XML.");
20 +
21 + hr = BextInitializeFromCreateArgs(pArgs, &pEngine);
22 + ExitOnFailure(hr, "Failed to initialize bext");
23 +
24 + hr = UtilBundleExtensionCreate(pEngine, pArgs, &vpBundleExtension);
25 + BextExitOnFailure(hr, "Failed to create WixUtilBundleExtension");
26 +
27 + pResults->pfnBundleExtensionProc = BextBaseBundleExtensionProc;
28 + pResults->pvBundleExtensionProcContext = vpBundleExtension;
29 +
30 +LExit:
31 + ReleaseObject(pEngine);
32
33 return hr;
34 }
35
36 extern "C" void WINAPI BundleExtensionDestroy()
37 {
38 + BextUninitialize();
39 + ReleaseNullObject(vpBundleExtension);
40 + XmlUninitialize();
41 }
\ No newline at end of file
src/be/utilbe.vcxproj
+9 -11
@@ -1,10 +1,9 @@
1 <?xml version="1.0" encoding="utf-8"?>
2 <!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3 -
3 <Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
4 + <Import Project="..\..\packages\WixToolset.BextUtil.4.0.16\build\WixToolset.BextUtil.props" Condition="Exists('..\..\packages\WixToolset.BextUtil.4.0.16\build\WixToolset.BextUtil.props')" />
5 <Import Project="..\..\packages\WixToolset.BootstrapperCore.Native.4.0.13\build\WixToolset.BootstrapperCore.Native.props" Condition="Exists('..\..\packages\WixToolset.BootstrapperCore.Native.4.0.13\build\WixToolset.BootstrapperCore.Native.props')" />
6 <Import Project="..\..\packages\WixToolset.DUtil.4.0.18\build\WixToolset.DUtil.props" Condition="Exists('..\..\packages\WixToolset.DUtil.4.0.18\build\WixToolset.DUtil.props')" />
7 -
7 <ItemGroup Label="ProjectConfigurations">
8 <ProjectConfiguration Include="Debug|Win32">
9 <Configuration>Debug</Configuration>
@@ -15,7 +14,6 @@
14 <Platform>Win32</Platform>
15 </ProjectConfiguration>
16 </ItemGroup>
18 -
17 <PropertyGroup Label="Globals">
18 <ProjectGuid>{630C1EE7-2517-4A8C-83E3-DA1150308B58}</ProjectGuid>
19 <ConfigurationType>DynamicLibrary</ConfigurationType>
@@ -25,37 +23,37 @@
23 <ProjectModuleDefinitionFile>utilbe.def</ProjectModuleDefinitionFile>
24 <Description>WiX Toolset Util BundleExtension</Description>
25 </PropertyGroup>
28 -
26 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
27 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
31 -
28 <PropertyGroup>
29 <ProjectAdditionalLinkLibraries>msi.lib</ProjectAdditionalLinkLibraries>
30 </PropertyGroup>
35 -
31 <ItemGroup>
32 + <ClCompile Include="detectsha2support.cpp" />
33 <ClCompile Include="precomp.cpp">
34 <PrecompiledHeader>Create</PrecompiledHeader>
35 </ClCompile>
36 <ClCompile Include="utilbe.cpp" />
37 + <ClCompile Include="UtilBundleExtension.cpp" />
38 + <ClCompile Include="utilsearch.cpp" />
39 </ItemGroup>
42 -
40 <ItemGroup>
41 + <ClInclude Include="detectsha2support.h" />
42 <ClInclude Include="precomp.h" />
43 + <ClInclude Include="UtilBundleExtension.h" />
44 + <ClInclude Include="utilsearch.h" />
45 </ItemGroup>
46 -
46 <ItemGroup>
47 <None Include="packages.config" />
48 <None Include="utilbe.def" />
49 </ItemGroup>
51 -
50 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
53 -
51 <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
52 <PropertyGroup>
53 <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>
54 </PropertyGroup>
55 + <Error Condition="!Exists('..\..\packages\WixToolset.BextUtil.4.0.16\build\WixToolset.BextUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.BextUtil.4.0.16\build\WixToolset.BextUtil.props'))" />
56 <Error Condition="!Exists('..\..\packages\WixToolset.BootstrapperCore.Native.4.0.13\build\WixToolset.BootstrapperCore.Native.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.BootstrapperCore.Native.4.0.13\build\WixToolset.BootstrapperCore.Native.props'))" />
57 <Error Condition="!Exists('..\..\packages\WixToolset.DUtil.4.0.18\build\WixToolset.DUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.DUtil.4.0.18\build\WixToolset.DUtil.props'))" />
58 </Target>
61 -</Project>
59 +</Project>
\ No newline at end of file
src/be/utilsearch.cpp new
+137
@@ -0,0 +1,137 @@
1 +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2 +
3 +#include "precomp.h"
4 +
5 +
6 +STDMETHODIMP UtilSearchParseFromXml(
7 + __in UTIL_SEARCHES* pSearches,
8 + __in IXMLDOMNode* pixnBundleExtension
9 + )
10 +{
11 + HRESULT hr = S_OK;
12 + IXMLDOMNodeList* pixnNodes = NULL;
13 + IXMLDOMNode* pixnNode = NULL;
14 + DWORD cNodes = 0;
15 + BSTR bstrNodeName = NULL;
16 +
17 + // Select Util search nodes.
18 + hr = XmlSelectNodes(pixnBundleExtension, L"WixDetectSHA2Support", &pixnNodes);
19 + ExitOnFailure(hr, "Failed to select Util search nodes.");
20 +
21 + // Get Util search node count.
22 + hr = pixnNodes->get_length((long*)&cNodes);
23 + ExitOnFailure(hr, "Failed to get Util search node count.");
24 +
25 + if (!cNodes)
26 + {
27 + ExitFunction();
28 + }
29 +
30 + // Allocate memory for searches.
31 + pSearches->rgSearches = (UTIL_SEARCH*)MemAlloc(sizeof(UTIL_SEARCH) * cNodes, TRUE);
32 + ExitOnNull(pSearches->rgSearches, hr, E_OUTOFMEMORY, "Failed to allocate memory for search structs.");
33 +
34 + pSearches->cSearches = cNodes;
35 +
36 + // Parse search elements.
37 + for (DWORD i = 0; i < cNodes; ++i)
38 + {
39 + UTIL_SEARCH* pSearch = &pSearches->rgSearches[i];
40 +
41 + hr = XmlNextElement(pixnNodes, &pixnNode, &bstrNodeName);
42 + ExitOnFailure(hr, "Failed to get next node.");
43 +
44 + // @Id
45 + hr = XmlGetAttributeEx(pixnNode, L"Id", &pSearch->sczId);
46 + ExitOnFailure(hr, "Failed to get @Id.");
47 +
48 + // Read type specific attributes.
49 + if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrNodeName, -1, L"WixDetectSHA2Support", -1))
50 + {
51 + pSearch->Type = UTIL_SEARCH_TYPE_DETECT_SHA2_SUPPORT;
52 + }
53 + else
54 + {
55 + hr = E_UNEXPECTED;
56 + ExitOnFailure(hr, "Unexpected element name: %ls", bstrNodeName);
57 + }
58 +
59 + // prepare next iteration
60 + ReleaseNullObject(pixnNode);
61 + ReleaseNullBSTR(bstrNodeName);
62 + }
63 +
64 +LExit:
65 + ReleaseBSTR(bstrNodeName);
66 + ReleaseObject(pixnNode);
67 + ReleaseObject(pixnNodes);
68 +
69 + return hr;
70 +}
71 +
72 +void UtilSearchUninitialize(
73 + __in UTIL_SEARCHES* pSearches
74 + )
75 +{
76 + if (pSearches->rgSearches)
77 + {
78 + for (DWORD i = 0; i < pSearches->cSearches; ++i)
79 + {
80 + UTIL_SEARCH* pSearch = &pSearches->rgSearches[i];
81 +
82 + ReleaseStr(pSearch->sczId);
83 + }
84 + MemFree(pSearches->rgSearches);
85 + }
86 +}
87 +
88 +STDMETHODIMP UtilSearchExecute(
89 + __in UTIL_SEARCHES* pSearches,
90 + __in LPCWSTR wzSearchId,
91 + __in LPCWSTR wzVariable,
92 + __in IBundleExtensionEngine* pEngine
93 + )
94 +{
95 + HRESULT hr = S_OK;
96 + UTIL_SEARCH* pSearch = NULL;
97 +
98 + hr = UtilSearchFindById(pSearches, wzSearchId, &pSearch);
99 + ExitOnFailure(hr, "Search id '%ls' is unknown to the util extension.");
100 +
101 + switch (pSearch->Type)
102 + {
103 + case UTIL_SEARCH_TYPE_DETECT_SHA2_SUPPORT:
104 + hr = UtilPerformDetectSHA2Support(wzVariable, pSearch, pEngine);
105 + break;
106 + default:
107 + hr = E_UNEXPECTED;
108 + }
109 +
110 +LExit:
111 + return hr;
112 +}
113 +
114 +STDMETHODIMP UtilSearchFindById(
115 + __in UTIL_SEARCHES* pSearches,
116 + __in LPCWSTR wzId,
117 + __out UTIL_SEARCH** ppSearch
118 + )
119 +{
120 + HRESULT hr = S_OK;
121 +
122 + for (DWORD i = 0; i < pSearches->cSearches; ++i)
123 + {
124 + UTIL_SEARCH* pSearch = &pSearches->rgSearches[i];
125 +
126 + if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pSearch->sczId, -1, wzId, -1))
127 + {
128 + *ppSearch = pSearch;
129 + ExitFunction1(hr = S_OK);
130 + }
131 + }
132 +
133 + hr = E_NOTFOUND;
134 +
135 +LExit:
136 + return hr;
137 +}
src/be/utilsearch.h new
+52
@@ -0,0 +1,52 @@
1 +#pragma once
2 +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3 +
4 +
5 +// constants
6 +
7 +enum UTIL_SEARCH_TYPE
8 +{
9 + UTIL_SEARCH_TYPE_NONE,
10 + UTIL_SEARCH_TYPE_DETECT_SHA2_SUPPORT,
11 +};
12 +
13 +
14 +// structs
15 +
16 +typedef struct _UTIL_SEARCH
17 +{
18 + LPWSTR sczId;
19 +
20 + UTIL_SEARCH_TYPE Type;
21 +} UTIL_SEARCH;
22 +
23 +typedef struct _UTIL_SEARCHES
24 +{
25 + UTIL_SEARCH* rgSearches;
26 + DWORD cSearches;
27 +} UTIL_SEARCHES;
28 +
29 +
30 +// function declarations
31 +
32 +STDMETHODIMP UtilSearchParseFromXml(
33 + __in UTIL_SEARCHES* pSearches,
34 + __in IXMLDOMNode* pixnBundleExtension
35 + );
36 +
37 +void UtilSearchUninitialize(
38 + __in UTIL_SEARCHES* pSearches
39 + );
40 +
41 +STDMETHODIMP UtilSearchExecute(
42 + __in UTIL_SEARCHES* pSearches,
43 + __in LPCWSTR wzSearchId,
44 + __in LPCWSTR wzVariable,
45 + __in IBundleExtensionEngine* pEngine
46 + );
47 +
48 +STDMETHODIMP UtilSearchFindById(
49 + __in UTIL_SEARCHES* pSearches,
50 + __in LPCWSTR wzId,
51 + __out UTIL_SEARCH** ppSearch
52 + );
src/test/WixToolsetTest.Util/TestData/BundleWithSearches/Bundle.wxs
+5
@@ -7,6 +7,7 @@
7 <util:RegistrySearchRef Id="RegistrySearchId" />
8 <util:ProductSearchRef Id="ProductSearchId" />
9 <util:FileSearchRef Id="FileSearchId" />
10 + <util:DetectSHA2SupportRef Id="DetectSHA2SupportId" />
11
12 <Chain>
13 <MsiPackage SourceFile="test.msi">
@@ -32,4 +33,8 @@
33 <Fragment>
34 <util:FileSearch Id="FileSearchId" Variable="FileSearchVariable" Path="%windir%\System32\mscoree.dll" Result="exists" />
35 </Fragment>
36 +
37 + <Fragment>
38 + <util:DetectSHA2Support Id="DetectSHA2SupportId" Variable="IsSHA2Supported" />
39 + </Fragment>
40 </Wix>
src/test/WixToolsetTest.Util/UtilExtensionFixture.cs
+24 -31
@@ -146,6 +146,9 @@ namespace WixToolsetTest.Util
146 {
147 var baseFolder = fs.GetFolder();
148 var intermediateFolder = Path.Combine(baseFolder, "obj");
149 + var bundlePath = Path.Combine(baseFolder, @"bin\test.exe");
150 + var baFolderPath = Path.Combine(baseFolder, "ba");
151 + var extractFolderPath = Path.Combine(baseFolder, "extract");
152
153 var result = WixRunner.Execute(new[]
154 {
@@ -156,45 +159,35 @@ namespace WixToolsetTest.Util
159 "-bindpath", Path.Combine(folder, "data"),
160 "-intermediateFolder", intermediateFolder,
161 "-burnStub", burnStubPath,
159 - "-o", Path.Combine(baseFolder, @"bin\test.exe")
162 + "-o", bundlePath
163 });
164
165 result.AssertSuccess();
166
164 - Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.exe")));
167 + Assert.True(File.Exists(bundlePath));
168 #if TODO
169 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb")));
170 #endif
171
169 - var intermediate = Intermediate.Load(Path.Combine(intermediateFolder, @"test.wir"));
170 - var section = intermediate.Sections.Single();
171 -
172 - var searchTuples = section.Tuples.OfType<WixSearchTuple>().OrderBy(t => t.Id.Id).ToList();
173 - Assert.Equal(3, searchTuples.Count);
174 - Assert.Equal("FileSearchId", searchTuples[0].Id.Id);
175 - Assert.Equal("FileSearchVariable", searchTuples[0].Variable);
176 - Assert.Equal("ProductSearchId", searchTuples[1].Id.Id);
177 - Assert.Equal("ProductSearchVariable", searchTuples[1].Variable);
178 - Assert.Equal("1 & 2 < 3", searchTuples[1].Condition);
179 - Assert.Equal("RegistrySearchId", searchTuples[2].Id.Id);
180 - Assert.Equal("RegistrySearchVariable", searchTuples[2].Variable);
181 -
182 - var fileSearchTuple = section.Tuples.OfType<WixFileSearchTuple>().Single();
183 - Assert.Equal("FileSearchId", fileSearchTuple.Id.Id);
184 - Assert.Equal(@"%windir%\System32\mscoree.dll", fileSearchTuple.Path);
185 - Assert.Equal(WixFileSearchAttributes.Default | WixFileSearchAttributes.WantExists, fileSearchTuple.Attributes);
186 -
187 - var productSearchTuple = section.Tuples.OfType<WixProductSearchTuple>().Single();
188 - Assert.Equal("ProductSearchId", productSearchTuple.Id.Id);
189 - Assert.Equal("{738D02BF-E231-4370-8209-E9FD4E1BE2A1}", productSearchTuple.Guid);
190 - Assert.Equal(WixProductSearchAttributes.Version | WixProductSearchAttributes.UpgradeCode, productSearchTuple.Attributes);
191 -
192 - var registrySearchTuple = section.Tuples.OfType<WixRegistrySearchTuple>().Single();
193 - Assert.Equal("RegistrySearchId", registrySearchTuple.Id.Id);
194 - Assert.Equal(RegistryRootType.LocalMachine, registrySearchTuple.Root);
195 - Assert.Equal(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full", registrySearchTuple.Key);
196 - Assert.Equal("Release", registrySearchTuple.Value);
197 - Assert.Equal(WixRegistrySearchAttributes.WantValue | WixRegistrySearchAttributes.Raw, registrySearchTuple.Attributes);
172 + var extractResult = BundleExtractor.ExtractBAContainer(null, bundlePath, baFolderPath, extractFolderPath);
173 + extractResult.AssertSuccess();
174 +
175 + var bundleExtensionDatas = extractResult.SelectBundleExtensionDataNodes("/be:BundleExtensionData/be:BundleExtension[@Id='WixUtilBundleExtension']");
176 + Assert.Equal(1, bundleExtensionDatas.Count);
177 + Assert.Equal("<BundleExtension Id='WixUtilBundleExtension'>" +
178 + "<WixDetectSHA2Support Id='DetectSHA2SupportId' />" +
179 + "</BundleExtension>", bundleExtensionDatas[0].GetTestXml());
180 +
181 + var utilSearches = extractResult.SelectManifestNodes("/burn:BurnManifest/*[self::burn:ExtensionSearch or self::burn:FileSearch or self::burn:MsiProductSearch or self::burn:RegistrySearch]");
182 + Assert.Equal(4, utilSearches.Count);
183 + Assert.Equal("<ExtensionSearch Id='DetectSHA2SupportId' Variable='IsSHA2Supported' " +
184 + "ExtensionId='WixUtilBundleExtension' />", utilSearches[0].GetTestXml());
185 + Assert.Equal("<FileSearch Id='FileSearchId' Variable='FileSearchVariable' " +
186 + $@"Path='%windir%\System32\mscoree.dll' Type='exists' />", utilSearches[1].GetTestXml());
187 + Assert.Equal("<MsiProductSearch Id='ProductSearchId' Variable='ProductSearchVariable' Condition='1 &amp; 2 &lt; 3' " +
188 + "UpgradeCode='{738D02BF-E231-4370-8209-E9FD4E1BE2A1}' Type='version' />", utilSearches[2].GetTestXml());
189 + Assert.Equal("<RegistrySearch Id='RegistrySearchId' Variable='RegistrySearchVariable' " +
190 + @"Root='HKLM' Key='SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full' Value='Release' Type='value' VariableType='string' />", utilSearches[3].GetTestXml());
191 }
192 }
193
src/wixext/Tuples/UtilTupleDefinitions.cs
+10
@@ -4,6 +4,7 @@ namespace WixToolset.Util
4 {
5 using System;
6 using WixToolset.Data;
7 + using WixToolset.Data.Burn;
8
9 public enum UtilTupleDefinitionType
10 {
@@ -19,6 +20,7 @@ namespace WixToolset.Util
20 User,
21 UserGroup,
22 WixCloseApplication,
23 + WixDetectSHA2Support,
24 WixFormatFiles,
25 WixInternetShortcut,
26 WixRemoveFolderEx,
@@ -82,6 +84,9 @@ namespace WixToolset.Util
84 case UtilTupleDefinitionType.WixCloseApplication:
85 return UtilTupleDefinitions.WixCloseApplication;
86
87 + case UtilTupleDefinitionType.WixDetectSHA2Support:
88 + return UtilTupleDefinitions.WixDetectSHA2Support;
89 +
90 case UtilTupleDefinitionType.WixFormatFiles:
91 return UtilTupleDefinitions.WixFormatFiles;
92
@@ -107,5 +112,10 @@ namespace WixToolset.Util
112 throw new ArgumentOutOfRangeException(nameof(type));
113 }
114 }
115 +
116 + static UtilTupleDefinitions()
117 + {
118 + WixDetectSHA2Support.AddTag(BurnConstants.BundleExtensionSearchTupleDefinitionTag);
119 + }
120 }
121 }
src/wixext/Tuples/WixDetectSHA2SupportTuple.cs new
+33
@@ -0,0 +1,33 @@
1 +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2 +
3 +namespace WixToolset.Util
4 +{
5 + using WixToolset.Data;
6 + using WixToolset.Util.Tuples;
7 +
8 + public static partial class UtilTupleDefinitions
9 + {
10 + public static readonly IntermediateTupleDefinition WixDetectSHA2Support = new IntermediateTupleDefinition(
11 + UtilTupleDefinitionType.WixDetectSHA2Support.ToString(),
12 + new IntermediateFieldDefinition[0],
13 + typeof(WixDetectSHA2SupportTuple));
14 + }
15 +}
16 +
17 +namespace WixToolset.Util.Tuples
18 +{
19 + using WixToolset.Data;
20 +
21 + public class WixDetectSHA2SupportTuple : IntermediateTuple
22 + {
23 + public WixDetectSHA2SupportTuple() : base(UtilTupleDefinitions.WixDetectSHA2Support, null, null)
24 + {
25 + }
26 +
27 + public WixDetectSHA2SupportTuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilTupleDefinitions.WixDetectSHA2Support, sourceLineNumber, id)
28 + {
29 + }
30 +
31 + public IntermediateField this[GroupTupleFields index] => this.Fields[(int)index];
32 + }
33 +}
src/wixext/UtilBinder.cs deleted
-347
@@ -1,347 +0,0 @@
1 -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2 -
3 -namespace WixToolset.Extensions
4 -{
5 -#if TODO_BRINGBACK_FOR_BUNDLES
6 - using System;
7 - using System.Collections.Generic;
8 - using System.Globalization;
9 - using WixToolset.Data;
10 - using WixToolset.Extensibility;
11 -
12 - /// <summary>
13 - /// The binder for the WiX Toolset Utility Extension.
14 - /// </summary>
15 - public sealed class UtilBinder : BinderExtension
16 - {
17 - // TODO: When WixSearch is supported in Product, etc, we may need to call
18 - // ReorderWixSearch() from each of those initializers.
19 -
20 - // TODO: A general-purpose "reorder this table given these constraints"
21 - // mechanism may end up being helpful. This could be declaratively stated
22 - // in the table definitions, or exposed from the core Wix.dll and called
23 - // as-needed by any extensions.
24 -
25 - /// <summary>
26 - /// Called before bundle binding occurs.
27 - /// </summary>
28 - public override void Initialize(Output bundle)
29 - {
30 - if (OutputType.Bundle == bundle.Type)
31 - {
32 - this.ReorderWixSearch(bundle);
33 - }
34 - }
35 -
36 - /// <summary>
37 - /// Reorders Any WixSearch items.
38 - /// </summary>
39 - /// <param name="output">Output containing the tables to process.</param>
40 - private void ReorderWixSearch(Output output)
41 - {
42 - Table wixSearchTable = output.Tables["WixSearch"];
43 - if (null == wixSearchTable || wixSearchTable.Rows.Count == 0)
44 - {
45 - // nothing to do!
46 - return;
47 - }
48 -
49 - RowDictionary rowDictionary = new RowDictionary();
50 - foreach (Row row in wixSearchTable.Rows)
51 - {
52 - rowDictionary.AddRow(row);
53 - }
54 -
55 - Constraints constraints = new Constraints();
56 - Table wixSearchRelationTable = output.Tables["WixSearchRelation"];
57 - if (null != wixSearchRelationTable && wixSearchRelationTable.Rows.Count > 0)
58 - {
59 - // add relational info to our data...
60 - foreach (Row row in wixSearchRelationTable.Rows)
61 - {
62 - constraints.AddConstraint((string)row[0], (string)row[1]);
63 - }
64 - }
65 -
66 - this.FindCircularReference(constraints);
67 -
68 - if (this.Core.EncounteredError)
69 - {
70 - return;
71 - }
72 -
73 - this.FlattenDependentReferences(constraints);
74 -
75 - // Reorder by topographical sort (http://en.wikipedia.org/wiki/Topological_sorting)
76 - // We use a variation of Kahn (1962) algorithm as described in
77 - // Wikipedia, with the additional criteria that start nodes are sorted
78 - // lexicographically at each step to ensure a deterministic ordering
79 - // based on 'after' dependencies and ID.
80 - TopologicalSort sorter = new TopologicalSort();
81 - List <string> sortedIds = sorter.Sort(rowDictionary.Keys, constraints);
82 -
83 - // Now, re-write the table with the searches in order...
84 - wixSearchTable.Rows.Clear();
85 - foreach (string id in sortedIds)
86 - {
87 - wixSearchTable.Rows.Add(rowDictionary[id]);
88 - }
89 - }
90 -
91 - /// <summary>
92 - /// A dictionary of Row items, indexed by their first column.
93 - /// </summary>
94 - private class RowDictionary : Dictionary<string, Row>
95 - {
96 - public void AddRow(Row row)
97 - {
98 - this.Add((string)row[0], row);
99 - }
100 -
101 - // TODO: Hide other Add methods?
102 - }
103 -
104 - /// <summary>
105 - /// A dictionary of constraints, mapping an id to a list of ids.
106 - /// </summary>
107 - private class Constraints : Dictionary<string, List<string>>
108 - {
109 - public void AddConstraint(string id, string afterId)
110 - {
111 - if (!this.ContainsKey(id))
112 - {
113 - this.Add(id, new List<string>());
114 - }
115 -
116 - // TODO: Show warning if a constraint is seen twice?
117 - if (!this[id].Contains(afterId))
118 - {
119 - this[id].Add(afterId);
120 - }
121 - }
122 -
123 - // TODO: Hide other Add methods?
124 - }
125 -
126 - /// <summary>
127 - /// Finds circular references in the constraints.
128 - /// </summary>
129 - /// <param name="constraints">Constraints to check.</param>
130 - /// <remarks>This is not particularly performant, but it works.</remarks>
131 - private void FindCircularReference(Constraints constraints)
132 - {
133 - foreach (string id in constraints.Keys)
134 - {
135 - List<string> seenIds = new List<string>();
136 - string chain = null;
137 - if (FindCircularReference(constraints, id, id, seenIds, out chain))
138 - {
139 - // We will show a separate message for every ID that's in
140 - // the loop. We could bail after the first one, but then
141 - // we wouldn't catch disjoint loops in a single run.
142 - this.Core.OnMessage(UtilErrors.CircularSearchReference(chain));
143 - }
144 - }
145 - }
146 -
147 - /// <summary>
148 - /// Recursive function that finds circular references in the constraints.
149 - /// </summary>
150 - /// <param name="constraints">Constraints to check.</param>
151 - /// <param name="checkId">The identifier currently being looking for. (Fixed across a given run.)</param>
152 - /// <param name="currentId">The idenifier curently being tested.</param>
153 - /// <param name="seenIds">A list of identifiers seen, to ensure each identifier is only expanded once.</param>
154 - /// <param name="chain">If a circular reference is found, will contain the chain of references.</param>
155 - /// <returns>True if a circular reference is found, false otherwise.</returns>
156 - private bool FindCircularReference(Constraints constraints, string checkId, string currentId, List<string> seenIds, out string chain)
157 - {
158 - chain = null;
159 - List<string> afterList = null;
160 - if (constraints.TryGetValue(currentId, out afterList))
161 - {
162 - foreach (string afterId in afterList)
163 - {
164 - if (afterId == checkId)
165 - {
166 - chain = String.Format(CultureInfo.InvariantCulture, "{0} -> {1}", currentId, afterId);
167 - return true;
168 - }
169 -
170 - if (!seenIds.Contains(afterId))
171 - {
172 - seenIds.Add(afterId);
173 - if (FindCircularReference(constraints, checkId, afterId, seenIds, out chain))
174 - {
175 - chain = String.Format(CultureInfo.InvariantCulture, "{0} -> {1}", currentId, chain);
176 - return true;
177 - }
178 - }
179 - }
180 - }
181 -
182 - return false;
183 - }
184 -
185 - /// <summary>
186 - /// Flattens any dependency chains to simplify reordering.
187 - /// </summary>
188 - /// <param name="constraints"></param>
189 - private void FlattenDependentReferences(Constraints constraints)
190 - {
191 - foreach (string id in constraints.Keys)
192 - {
193 - List<string> flattenedIds = new List<string>();
194 - AddDependentReferences(constraints, id, flattenedIds);
195 - List<string> constraintList = constraints[id];
196 - foreach (string flattenedId in flattenedIds)
197 - {
198 - if (!constraintList.Contains(flattenedId))
199 - {
200 - constraintList.Add(flattenedId);
201 - }
202 - }
203 - }
204 - }
205 -
206 - /// <summary>
207 - /// Adds dependent references to a list.
208 - /// </summary>
209 - /// <param name="constraints"></param>
210 - /// <param name="currentId"></param>
211 - /// <param name="seenIds"></param>
212 - private void AddDependentReferences(Constraints constraints, string currentId, List<string> seenIds)
213 - {
214 - List<string> afterList = null;
215 - if (constraints.TryGetValue(currentId, out afterList))
216 - {
217 - foreach (string afterId in afterList)
218 - {
219 - if (!seenIds.Contains(afterId))
220 - {
221 - seenIds.Add(afterId);
222 - AddDependentReferences(constraints, afterId, seenIds);
223 - }
224 - }
225 - }
226 - }
227 -
228 - /// <summary>
229 - /// Reorder by topological sort
230 - /// </summary>
231 - /// <remarks>
232 - /// We use a variation of Kahn (1962) algorithm as described in
233 - /// Wikipedia (http://en.wikipedia.org/wiki/Topological_sorting), with
234 - /// the additional criteria that start nodes are sorted lexicographically
235 - /// at each step to ensure a deterministic ordering based on 'after'
236 - /// dependencies and ID.
237 - /// </remarks>
238 - private class TopologicalSort
239 - {
240 - private List<string> startIds = new List<string>();
241 - private Constraints constraints;
242 -
243 - /// <summary>
244 - /// Reorder by topological sort
245 - /// </summary>
246 - /// <param name="allIds">The complete list of IDs.</param>
247 - /// <param name="constraints">Constraints to use.</param>
248 - /// <returns>The topologically sorted list of IDs.</returns>
249 - internal List<string> Sort(IEnumerable<string> allIds, Constraints constraints)
250 - {
251 - this.startIds.Clear();
252 - this.CopyConstraints(constraints);
253 -
254 - this.FindInitialStartIds(allIds);
255 -
256 - // We always create a new sortedId list, because we return it
257 - // to the caller and don't know what its lifetime may be.
258 - List<string> sortedIds = new List<string>();
259 -
260 - while (this.startIds.Count > 0)
261 - {
262 - this.SortStartIds();
263 -
264 - string currentId = this.startIds[0];
265 - sortedIds.Add(currentId);
266 - this.startIds.RemoveAt(0);
267 -
268 - this.ResolveConstraint(currentId);
269 - }
270 -
271 - return sortedIds;
272 - }
273 -
274 - /// <summary>
275 - /// Copies a Constraints set (to prevent modifying the incoming data).
276 - /// </summary>
277 - /// <param name="constraints">Constraints to copy.</param>
278 - private void CopyConstraints(Constraints constraints)
279 - {
280 - this.constraints = new Constraints();
281 - foreach (string id in constraints.Keys)
282 - {
283 - foreach (string afterId in constraints[id])
284 - {
285 - this.constraints.AddConstraint(id, afterId);
286 - }
287 - }
288 - }
289 -
290 - /// <summary>
291 - /// Finds initial start IDs. (Those with no constraints.)
292 - /// </summary>
293 - /// <param name="allIds">The complete list of IDs.</param>
294 - private void FindInitialStartIds(IEnumerable<string> allIds)
295 - {
296 - foreach (string id in allIds)
297 - {
298 - if (!this.constraints.ContainsKey(id))
299 - {
300 - this.startIds.Add(id);
301 - }
302 - }
303 - }
304 -
305 - /// <summary>
306 - /// Sorts start IDs.
307 - /// </summary>
308 - private void SortStartIds()
309 - {
310 - this.startIds.Sort();
311 - }
312 -
313 - /// <summary>
314 - /// Removes the resolved constraint and updates the list of startIds
315 - /// with any now-valid (all constraints resolved) IDs.
316 - /// </summary>
317 - /// <param name="resolvedId">The ID to resolve from the set of constraints.</param>
318 - private void ResolveConstraint(string resolvedId)
319 - {
320 - List<string> newStartIds = new List<string>();
321 -
322 - foreach (string id in constraints.Keys)
323 - {
324 - if (this.constraints[id].Contains(resolvedId))
325 - {
326 - this.constraints[id].Remove(resolvedId);
327 -
328 - // If we just removed the last constraint for this
329 - // ID, it is now a valid start ID.
330 - if (0 == this.constraints[id].Count)
331 - {
332 - newStartIds.Add(id);
333 - }
334 - }
335 - }
336 -
337 - foreach (string id in newStartIds)
338 - {
339 - this.constraints.Remove(id);
340 - }
341 -
342 - this.startIds.AddRange(newStartIds);
343 - }
344 - }
345 - }
346 -#endif
347 -}
src/wixext/UtilCompiler.cs
+101 -97
@@ -230,6 +230,8 @@ namespace WixToolset.Util
230 break;
231 case "ComponentSearch":
232 case "ComponentSearchRef":
233 + case "DetectSHA2Support":
234 + case "DetectSHA2SupportRef":
235 case "DirectorySearch":
236 case "DirectorySearchRef":
237 case "FileSearch":
@@ -251,6 +253,12 @@ namespace WixToolset.Util
253 case "ComponentSearchRef":
254 this.ParseComponentSearchRefElement(intermediate, section, element);
255 break;
256 + case "DetectSHA2Support":
257 + this.ParseDetectSHA2SupportElement(intermediate, section, element);
258 + break;
259 + case "DetectSHA2SupportRef":
260 + this.ParseDetectSHA2SupportRefElement(intermediate, section, element);
261 + break;
262 case "DirectorySearch":
263 this.ParseDirectorySearchElement(intermediate, section, element);
264 break;
@@ -422,11 +430,6 @@ namespace WixToolset.Util
430 }
431 }
432
425 - if (null == variable)
426 - {
427 - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Variable"));
428 - }
429 -
433 if (null == guid)
434 {
435 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Guid"));
@@ -439,16 +442,10 @@ namespace WixToolset.Util
442
443 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
444
445 + this.ParseHelper.CreateWixSearchTuple(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, null);
446 +
447 if (!this.Messaging.EncounteredError)
448 {
444 - this.CreateWixSearchRow(section, sourceLineNumbers, id, variable, condition);
445 - if (after != null)
446 - {
447 - this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "WixSearch", after);
448 - // TODO: We're currently defaulting to "always run after", which we will need to change...
449 - this.CreateWixSearchRelationRow(section, sourceLineNumbers, id, after, 2);
450 - }
451 -
449 WixComponentSearchAttributes attributes = WixComponentSearchAttributes.KeyPath;
450 switch (result)
451 {
@@ -505,6 +502,89 @@ namespace WixToolset.Util
502 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
503 }
504
505 + /// <summary>
506 + /// Parses a DetectSHA2Support element.
507 + /// </summary>
508 + /// <param name="element">Element to parse.</param>
509 + private void ParseDetectSHA2SupportElement(Intermediate intermediate, IntermediateSection section, XElement element)
510 + {
511 + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
512 + Identifier id = null;
513 + string variable = null;
514 + string condition = null;
515 + string after = null;
516 +
517 + foreach (var attrib in element.Attributes())
518 + {
519 + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
520 + {
521 + switch (attrib.Name.LocalName)
522 + {
523 + case "Id":
524 + case "Variable":
525 + case "Condition":
526 + case "After":
527 + this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after);
528 + break;
529 + default:
530 + this.ParseHelper.UnexpectedAttribute(element, attrib);
531 + break;
532 + }
533 + }
534 + else
535 + {
536 + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
537 + }
538 + }
539 +
540 + if (id == null)
541 + {
542 + id = this.ParseHelper.CreateIdentifier("wds2s", variable, condition, after);
543 + }
544 +
545 + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
546 +
547 + this.ParseHelper.CreateWixSearchTuple(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, UtilConstants.UtilBundleExtensionId);
548 +
549 + if (!this.Messaging.EncounteredError)
550 + {
551 + section.Tuples.Add(new WixDetectSHA2SupportTuple(sourceLineNumbers, id));
552 + }
553 + }
554 +
555 + /// <summary>
556 + /// Parses a DetectSHA2SupportRef element
557 + /// </summary>
558 + /// <param name="element">Element to parse.</param>
559 + private void ParseDetectSHA2SupportRefElement(Intermediate intermediate, IntermediateSection section, XElement element)
560 + {
561 + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
562 + string refId = null;
563 +
564 + foreach (var attrib in element.Attributes())
565 + {
566 + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
567 + {
568 + switch (attrib.Name.LocalName)
569 + {
570 + case "Id":
571 + refId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
572 + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "WixDetectSHA2Support", refId);
573 + break;
574 + default:
575 + this.ParseHelper.UnexpectedAttribute(element, attrib);
576 + break;
577 + }
578 + }
579 + else
580 + {
581 + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
582 + }
583 + }
584 +
585 + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
586 + }
587 +
588 /// <summary>
589 /// Parses an event source element.
590 /// </summary>
@@ -868,11 +948,6 @@ namespace WixToolset.Util
948 }
949 }
950
871 - if (null == variable)
872 - {
873 - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Variable"));
874 - }
875 -
951 if (null == path)
952 {
953 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Path"));
@@ -885,16 +960,10 @@ namespace WixToolset.Util
960
961 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
962
963 + this.ParseHelper.CreateWixSearchTuple(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, null);
964 +
965 if (!this.Messaging.EncounteredError)
966 {
890 - this.CreateWixSearchRow(section, sourceLineNumbers, id, variable, condition);
891 - if (after != null)
892 - {
893 - this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "WixSearch", after);
894 - // TODO: We're currently defaulting to "always run after", which we will need to change...
895 - this.CreateWixSearchRelationRow(section, sourceLineNumbers, id, after, 2);
896 - }
897 -
967 WixFileSearchAttributes attributes = WixFileSearchAttributes.IsDirectory;
968 switch (result)
969 {
@@ -990,11 +1059,6 @@ namespace WixToolset.Util
1059 }
1060 }
1061
993 - if (null == variable)
994 - {
995 - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Variable"));
996 - }
997 -
1062 if (null == path)
1063 {
1064 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Path"));
@@ -1007,16 +1071,10 @@ namespace WixToolset.Util
1071
1072 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, node);
1073
1074 + this.ParseHelper.CreateWixSearchTuple(section, sourceLineNumbers, node.Name.LocalName, id, variable, condition, after, null);
1075 +
1076 if (!this.Messaging.EncounteredError)
1077 {
1012 - this.CreateWixSearchRow(section, sourceLineNumbers, id, variable, condition);
1013 - if (after != null)
1014 - {
1015 - this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "WixSearch", after);
1016 - // TODO: We're currently defaulting to "always run after", which we will need to change...
1017 - this.CreateWixSearchRelationRow(section, sourceLineNumbers, id, after, 2);
1018 - }
1019 -
1078 WixFileSearchAttributes attributes = WixFileSearchAttributes.Default;
1079 switch (result)
1080 {
@@ -1048,38 +1106,6 @@ namespace WixToolset.Util
1106 });
1107 }
1108
1051 - /// <summary>
1052 - /// Creates a row in the WixSearch table.
1053 - /// </summary>
1054 - /// <param name="sourceLineNumbers">Source line number for the parent element.</param>
1055 - /// <param name="id">Identifier of the search.</param>
1056 - /// <param name="variable">The Burn variable to store the result into.</param>
1057 - /// <param name="condition">A condition to test before evaluating the search.</param>
1058 - private void CreateWixSearchRow(IntermediateSection section, SourceLineNumber sourceLineNumbers, Identifier id, string variable, string condition)
1059 - {
1060 - section.Tuples.Add(new WixSearchTuple(sourceLineNumbers, id)
1061 - {
1062 - Variable = variable,
1063 - Condition = condition,
1064 - });
1065 - }
1066 -
1067 - /// <summary>
1068 - ///
1069 - /// </summary>
1070 - /// <param name="sourceLineNumbers">Source line number for the parent element.</param>
1071 - /// <param name="id">Identifier of the search (key into the WixSearch table)</param>
1072 - /// <param name="parentId">Identifier of the search that comes before (key into the WixSearch table)</param>
1073 - /// <param name="attributes">Further details about the relation between id and parentId.</param>
1074 - private void CreateWixSearchRelationRow(IntermediateSection section, SourceLineNumber sourceLineNumbers, Identifier id, string parentId, int attributes)
1075 - {
1076 - section.Tuples.Add(new WixSearchRelationTuple(sourceLineNumbers, id)
1077 - {
1078 - ParentSearchRef = parentId,
1079 - Attributes = attributes,
1080 - });
1081 - }
1082 -
1109 /// <summary>
1110 /// Parses a file share element.
1111 /// </summary>
@@ -2523,11 +2549,6 @@ namespace WixToolset.Util
2549 }
2550 }
2551
2526 - if (null == variable)
2527 - {
2528 - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Variable"));
2529 - }
2530 -
2552 if (null == upgradeCode && null == productCode)
2553 {
2554 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "ProductCode", "UpgradeCode", true));
@@ -2545,16 +2566,10 @@ namespace WixToolset.Util
2566
2567 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2568
2569 + this.ParseHelper.CreateWixSearchTuple(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, null);
2570 +
2571 if (!this.Messaging.EncounteredError)
2572 {
2550 - this.CreateWixSearchRow(section, sourceLineNumbers, id, variable, condition);
2551 - if (after != null)
2552 - {
2553 - this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "WixSearch", after);
2554 - // TODO: We're currently defaulting to "always run after", which we will need to change...
2555 - this.CreateWixSearchRelationRow(section, sourceLineNumbers, id, after, 2);
2556 - }
2557 -
2573 WixProductSearchAttributes attributes = WixProductSearchAttributes.Version;
2574 switch (result)
2575 {
@@ -2662,11 +2677,6 @@ namespace WixToolset.Util
2677 }
2678 }
2679
2665 - if (null == variable)
2666 - {
2667 - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Variable"));
2668 - }
2669 -
2680 if (!root.HasValue)
2681 {
2682 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Root"));
@@ -2726,16 +2736,10 @@ namespace WixToolset.Util
2736
2737 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2738
2739 + this.ParseHelper.CreateWixSearchTuple(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, null);
2740 +
2741 if (!this.Messaging.EncounteredError)
2742 {
2731 - this.CreateWixSearchRow(section, sourceLineNumbers, id, variable, condition);
2732 - if (after != null)
2733 - {
2734 - this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "WixSearch", after);
2735 - // TODO: We're currently defaulting to "always run after", which we will need to change...
2736 - this.CreateWixSearchRelationRow(section, sourceLineNumbers, id, after, 2);
2737 - }
2738 -
2743 section.Tuples.Add(new WixRegistrySearchTuple(sourceLineNumbers, id)
2744 {
2745 Root = (RegistryRootType)root,
src/wixext/UtilConstants.cs
+2
@@ -13,5 +13,7 @@ namespace WixToolset.Util
13 internal static readonly string[] RegistryPermissions = { "Read", "Write", "CreateSubkeys", "EnumerateSubkeys", "Notify", "CreateLink" };
14 internal static readonly string[] ServicePermissions = { "ServiceQueryConfig", "ServiceChangeConfig", "ServiceQueryStatus", "ServiceEnumerateDependents", "ServiceStart", "ServiceStop", "ServicePauseContinue", "ServiceInterrogate", "ServiceUserDefinedControl" };
15 internal static readonly string[] StandardPermissions = { "Delete", "ReadPermission", "ChangePermission", "TakeOwnership", "Synchronize" };
16 +
17 + internal const string UtilBundleExtensionId = "WixUtilBundleExtension";
18 }
19 }
src/wixext/UtilErrors.cs
-6
@@ -13,11 +13,6 @@ namespace WixToolset.Util
13 return Message(null, Ids.ArgumentRequiresValue, "The argument '{0}' does not have a value specified and it is required.", argument);
14 }
15
16 - public static Message CircularSearchReference(string chain)
17 - {
18 - return Message(null, Ids.CircularSearchReference, "A circular reference of search ordering constraints was detected: {0}. Search ordering references must form a directed acyclic graph.", chain);
19 - }
20 -
16 public static Message DirectoryNotFound(string directory)
17 {
18 return Message(null, Ids.DirectoryNotFound, "The directory '{0}' could not be found.", directory);
@@ -102,7 +97,6 @@ namespace WixToolset.Util
97 FileNotFound = 5059,
98 PerformanceCategoryNotFound = 5060,
99 UnsupportedPerformanceCounterType = 5061,
105 - CircularSearchReference = 5062,
100 InvalidRegistryObject = 5063,
101 }
102 }
src/wixext/util.xsd
+24
@@ -172,6 +172,30 @@
172 <xs:attribute name="Id" type="xs:string" use="required" />
173 </xs:complexType>
174 </xs:element>
175 + <xs:element name="DetectSHA2Support">
176 + <xs:annotation>
177 + <xs:documentation>Detects support for SHA2.</xs:documentation>
178 + <xs:appinfo>
179 + <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="Bundle" />
180 + <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="Fragment" />
181 + </xs:appinfo>
182 + </xs:annotation>
183 + <xs:complexType>
184 + <xs:attributeGroup ref="SearchCommonAttributes" />
185 + </xs:complexType>
186 + </xs:element>
187 + <xs:element name="DetectSHA2SupportRef">
188 + <xs:annotation>
189 + <xs:documentation>References a DetectSHA2Support.</xs:documentation>
190 + <xs:appinfo>
191 + <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="Bundle" />
192 + <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="Fragment" />
193 + </xs:appinfo>
194 + </xs:annotation>
195 + <xs:complexType>
196 + <xs:attribute name="Id" type="xs:string" use="required" />
197 + </xs:complexType>
198 + </xs:element>
199 <xs:element name="DirectorySearch">
200 <xs:annotation>
201 <xs:documentation>Describes a directory search.</xs:documentation>