aboutsummaryrefslogtreecommitdiff
path: root/src/ext
diff options
context:
space:
mode:
Diffstat (limited to 'src/ext')
-rw-r--r--src/ext/Bal/Bal.wixext.sln319
-rw-r--r--src/ext/Bal/CSharp.Build.props13
-rw-r--r--src/ext/Bal/Cpp.Build.props94
-rw-r--r--src/ext/Bal/Custom.Build.props11
-rw-r--r--src/ext/Bal/CustomizedNativeRecommendedRules.ruleset8
-rw-r--r--src/ext/Bal/Directory.Build.props29
-rw-r--r--src/ext/Bal/Directory.Build.targets56
-rw-r--r--src/ext/Bal/README.md2
-rw-r--r--src/ext/Bal/Samples/bafunctions/Readme.txt85
-rw-r--r--src/ext/Bal/Samples/bafunctions/WixSampleBAFunctions.cpp95
-rw-r--r--src/ext/Bal/Samples/bafunctions/bafunctions.cpp46
-rw-r--r--src/ext/Bal/Samples/bafunctions/bafunctions.def6
-rw-r--r--src/ext/Bal/Samples/bafunctions/bafunctions.vcxproj81
-rw-r--r--src/ext/Bal/Samples/bafunctions/packages.config7
-rw-r--r--src/ext/Bal/Samples/bafunctions/precomp.h52
-rw-r--r--src/ext/Bal/Samples/bafunctions/resource.h15
-rw-r--r--src/ext/Bal/WixToolset.Dnc.Host/BootstrapperApplicationFactory.cs89
-rw-r--r--src/ext/Bal/WixToolset.Dnc.Host/DnchostAssemblyLoadContext.cs58
-rw-r--r--src/ext/Bal/WixToolset.Dnc.Host/Exceptions.cs145
-rw-r--r--src/ext/Bal/WixToolset.Dnc.Host/IBootstrapperApplicationFactory.cs16
-rw-r--r--src/ext/Bal/WixToolset.Dnc.Host/NativeMethods.cs18
-rw-r--r--src/ext/Bal/WixToolset.Dnc.Host/WixToolset.Dnc.Host.csproj44
-rw-r--r--src/ext/Bal/WixToolset.Mba.Host/BootstrapperApplicationFactory.cs86
-rw-r--r--src/ext/Bal/WixToolset.Mba.Host/BootstrapperSectionGroup.cs29
-rw-r--r--src/ext/Bal/WixToolset.Mba.Host/Exceptions.cs145
-rw-r--r--src/ext/Bal/WixToolset.Mba.Host/HostSection.cs47
-rw-r--r--src/ext/Bal/WixToolset.Mba.Host/NativeMethods.cs18
-rw-r--r--src/ext/Bal/WixToolset.Mba.Host/SupportedFrameworkElement.cs47
-rw-r--r--src/ext/Bal/WixToolset.Mba.Host/SupportedFrameworkElementCollection.cs36
-rw-r--r--src/ext/Bal/WixToolset.Mba.Host/WixToolset.Mba.Host.config26
-rw-r--r--src/ext/Bal/WixToolset.Mba.Host/WixToolset.Mba.Host.csproj54
-rw-r--r--src/ext/Bal/WixToolset.Mba.Host/WixToolset.Mba.Host.nuspec23
-rw-r--r--src/ext/Bal/appveyor.cmd17
-rw-r--r--src/ext/Bal/appveyor.yml40
-rw-r--r--src/ext/Bal/dnchost/coreclrhost.h137
-rw-r--r--src/ext/Bal/dnchost/dnchost.cpp309
-rw-r--r--src/ext/Bal/dnchost/dnchost.def6
-rw-r--r--src/ext/Bal/dnchost/dnchost.h35
-rw-r--r--src/ext/Bal/dnchost/dnchost.vcxproj106
-rw-r--r--src/ext/Bal/dnchost/dncutil.cpp411
-rw-r--r--src/ext/Bal/dnchost/dncutil.h38
-rw-r--r--src/ext/Bal/dnchost/packages.config13
-rw-r--r--src/ext/Bal/dnchost/precomp.cpp3
-rw-r--r--src/ext/Bal/dnchost/precomp.h31
-rw-r--r--src/ext/Bal/mbahost/mbahost.cpp649
-rw-r--r--src/ext/Bal/mbahost/mbahost.def6
-rw-r--r--src/ext/Bal/mbahost/mbahost.vcxproj106
-rw-r--r--src/ext/Bal/mbahost/packages.config10
-rw-r--r--src/ext/Bal/mbahost/precomp.cpp3
-rw-r--r--src/ext/Bal/mbahost/precomp.h25
-rw-r--r--src/ext/Bal/nuget.config19
-rw-r--r--src/ext/Bal/test/WixToolsetTest.Bal/BalExtensionFixture.cs133
-rw-r--r--src/ext/Bal/test/WixToolsetTest.Bal/TestData/MBA/Bundle.wxs12
-rw-r--r--src/ext/Bal/test/WixToolsetTest.Bal/TestData/Overridable/Bundle.wxs13
-rw-r--r--src/ext/Bal/test/WixToolsetTest.Bal/TestData/WixStdBa/Bundle.wxs12
-rw-r--r--src/ext/Bal/test/WixToolsetTest.Bal/TestData/WixStdBa/Data/test.msibin0 -> 32768 bytes
-rw-r--r--src/ext/Bal/test/WixToolsetTest.Bal/TestData/WixStdBa/DisplayInternalUIConditionBundle.wxs12
-rw-r--r--src/ext/Bal/test/WixToolsetTest.Bal/WixToolsetTest.Bal.csproj43
-rw-r--r--src/ext/Bal/test/WixToolsetTest.Bal/WixToolsetTest.Bal.v3.ncrunchproject5
-rw-r--r--src/ext/Bal/test/WixToolsetTest.ManagedHost/DncHostFixture.cs209
-rw-r--r--src/ext/Bal/test/WixToolsetTest.ManagedHost/MbaHostFixture.cs94
-rw-r--r--src/ext/Bal/test/WixToolsetTest.ManagedHost/README.md5
-rw-r--r--src/ext/Bal/test/WixToolsetTest.ManagedHost/TestEngine.cs74
-rw-r--r--src/ext/Bal/test/WixToolsetTest.ManagedHost/TestEngineResult.cs12
-rw-r--r--src/ext/Bal/test/WixToolsetTest.ManagedHost/WixToolsetTest.ManagedHost.csproj25
-rw-r--r--src/ext/Bal/test/examples/Directory.Build.props6
-rw-r--r--src/ext/Bal/test/examples/Directory.Build.targets6
-rw-r--r--src/ext/Bal/test/examples/EarliestCoreBundleFDD/EarliestCoreBundleFDD.wixproj2
-rw-r--r--src/ext/Bal/test/examples/EarliestCoreBundleFDD/FrameworkDependentBundle.wxs16
-rw-r--r--src/ext/Bal/test/examples/EarliestCoreBundleSCD/EarliestCoreBundleSCD.wixproj10
-rw-r--r--src/ext/Bal/test/examples/EarliestCoreBundleSCD/SelfContainedBundle.wxs11
-rw-r--r--src/ext/Bal/test/examples/EarliestCoreBundleSCD/ba.xslt20
-rw-r--r--src/ext/Bal/test/examples/EarliestCoreBundleTrimmedSCD/EarliestCoreBundleTrimmedSCD.wixproj10
-rw-r--r--src/ext/Bal/test/examples/EarliestCoreBundleTrimmedSCD/TrimmedSelfContainedBundle.wxs11
-rw-r--r--src/ext/Bal/test/examples/EarliestCoreBundleTrimmedSCD/ba.xslt20
-rw-r--r--src/ext/Bal/test/examples/EarliestCoreMBA/EarliestCoreBA.cs34
-rw-r--r--src/ext/Bal/test/examples/EarliestCoreMBA/EarliestCoreBAFactory.cs22
-rw-r--r--src/ext/Bal/test/examples/EarliestCoreMBA/Example.EarliestCoreMBA.csproj18
-rw-r--r--src/ext/Bal/test/examples/FullFramework2Bundle/Bundle.wxs14
-rw-r--r--src/ext/Bal/test/examples/FullFramework2Bundle/FullFramework2Bundle.wixproj2
-rw-r--r--src/ext/Bal/test/examples/FullFramework2MBA/Example.FullFramework2MBA.csproj20
-rw-r--r--src/ext/Bal/test/examples/FullFramework2MBA/FullFramework2BA.cs34
-rw-r--r--src/ext/Bal/test/examples/FullFramework2MBA/FullFramework2BAFactory.cs22
-rw-r--r--src/ext/Bal/test/examples/FullFramework2MBA/WixToolset.Mba.Host.config20
-rw-r--r--src/ext/Bal/test/examples/FullFramework4Bundle/Bundle.wxs14
-rw-r--r--src/ext/Bal/test/examples/FullFramework4Bundle/FullFramework4Bundle.wixproj2
-rw-r--r--src/ext/Bal/test/examples/FullFramework4MBA/Example.FullFramework4MBA.csproj19
-rw-r--r--src/ext/Bal/test/examples/FullFramework4MBA/FullFramework4BA.cs34
-rw-r--r--src/ext/Bal/test/examples/FullFramework4MBA/FullFramework4BAFactory.cs22
-rw-r--r--src/ext/Bal/test/examples/FullFramework4MBA/WixToolset.Mba.Host.config17
-rw-r--r--src/ext/Bal/test/examples/LatestCoreBundleFDD/FrameworkDependentBundle.wxs16
-rw-r--r--src/ext/Bal/test/examples/LatestCoreBundleFDD/LatestCoreBundleFDD.wixproj2
-rw-r--r--src/ext/Bal/test/examples/LatestCoreBundleSCD/LatestCoreBundleSCD.wixproj10
-rw-r--r--src/ext/Bal/test/examples/LatestCoreBundleSCD/SelfContainedBundle.wxs11
-rw-r--r--src/ext/Bal/test/examples/LatestCoreBundleSCD/ba.xslt20
-rw-r--r--src/ext/Bal/test/examples/LatestCoreBundleTrimmedSCD/LatestCoreBundleTrimmedSCD.wixproj10
-rw-r--r--src/ext/Bal/test/examples/LatestCoreBundleTrimmedSCD/TrimmedSelfContainedBundle.wxs11
-rw-r--r--src/ext/Bal/test/examples/LatestCoreBundleTrimmedSCD/ba.xslt20
-rw-r--r--src/ext/Bal/test/examples/LatestCoreMBA/Example.LatestCoreMBA.csproj21
-rw-r--r--src/ext/Bal/test/examples/LatestCoreMBA/LatestCoreBA.cs33
-rw-r--r--src/ext/Bal/test/examples/LatestCoreMBA/LatestCoreBAFactory.cs22
-rw-r--r--src/ext/Bal/test/examples/TestEngine/Example.TestEngine.vcxproj83
-rw-r--r--src/ext/Bal/test/examples/TestEngine/ExampleTestEngine.cpp53
-rw-r--r--src/ext/Bal/test/examples/TestEngine/ReloadEngine.cpp55
-rw-r--r--src/ext/Bal/test/examples/TestEngine/ReloadEngine.h8
-rw-r--r--src/ext/Bal/test/examples/TestEngine/ShutdownEngine.cpp38
-rw-r--r--src/ext/Bal/test/examples/TestEngine/ShutdownEngine.h8
-rw-r--r--src/ext/Bal/test/examples/TestEngine/TestEngine.cpp256
-rw-r--r--src/ext/Bal/test/examples/TestEngine/TestEngine.h80
-rw-r--r--src/ext/Bal/test/examples/TestEngine/WaitForQuitEngine.cpp35
-rw-r--r--src/ext/Bal/test/examples/TestEngine/WaitForQuitEngine.h8
-rw-r--r--src/ext/Bal/test/examples/TestEngine/packages.config7
-rw-r--r--src/ext/Bal/test/examples/TestEngine/precomp.cpp3
-rw-r--r--src/ext/Bal/test/examples/TestEngine/precomp.h20
-rw-r--r--src/ext/Bal/test/examples/WPFCoreBundleFDD/FrameworkDependentBundle.wxs16
-rw-r--r--src/ext/Bal/test/examples/WPFCoreBundleFDD/WPFCoreBundleFDD.wixproj2
-rw-r--r--src/ext/Bal/test/examples/WPFCoreMBA/AssemblyInfo.cs12
-rw-r--r--src/ext/Bal/test/examples/WPFCoreMBA/Example.WPFCoreMBA.csproj16
-rw-r--r--src/ext/Bal/test/examples/WPFCoreMBA/MainWindow.xaml16
-rw-r--r--src/ext/Bal/test/examples/WPFCoreMBA/MainWindow.xaml.cs17
-rw-r--r--src/ext/Bal/test/examples/WPFCoreMBA/WPFCoreBA.cs42
-rw-r--r--src/ext/Bal/test/examples/WPFCoreMBA/WPFCoreBAFactory.cs22
-rw-r--r--src/ext/Bal/test/examples/Wix.Build.props10
-rw-r--r--src/ext/Bal/test/examples/Wix.Build.targets8
-rw-r--r--src/ext/Bal/test/examples/examples.proj50
-rw-r--r--src/ext/Bal/wix.snkbin0 -> 596 bytes
-rw-r--r--src/ext/Bal/wixext/BalBurnBackendExtension.cs171
-rw-r--r--src/ext/Bal/wixext/BalCompiler.cs923
-rw-r--r--src/ext/Bal/wixext/BalErrors.cs61
-rw-r--r--src/ext/Bal/wixext/BalExtensionData.cs30
-rw-r--r--src/ext/Bal/wixext/BalExtensionFactory.cs18
-rw-r--r--src/ext/Bal/wixext/BalWarnings.cs31
-rw-r--r--src/ext/Bal/wixext/Symbols/BalSymbolDefinitions.cs80
-rw-r--r--src/ext/Bal/wixext/Symbols/WixBalBAFactoryAssemblySymbol.cs55
-rw-r--r--src/ext/Bal/wixext/Symbols/WixBalBAFunctionsSymbol.cs47
-rw-r--r--src/ext/Bal/wixext/Symbols/WixBalConditionSymbol.cs55
-rw-r--r--src/ext/Bal/wixext/Symbols/WixBalPackageInfoSymbol.cs55
-rw-r--r--src/ext/Bal/wixext/Symbols/WixDncOptionsSymbol.cs47
-rw-r--r--src/ext/Bal/wixext/Symbols/WixMbaPrereqInformationSymbol.cs63
-rw-r--r--src/ext/Bal/wixext/Symbols/WixStdbaOptionsSymbol.cs79
-rw-r--r--src/ext/Bal/wixext/Symbols/WixStdbaOverridableVariableSymbol.cs47
-rw-r--r--src/ext/Bal/wixext/WixToolset.Bal.wixext.csproj39
-rw-r--r--src/ext/Bal/wixext/WixToolset.Bal.wixext.nuspec26
-rw-r--r--src/ext/Bal/wixext/WixToolset.Bal.wixext.targets11
-rw-r--r--src/ext/Bal/wixlib/BalExtension_arm64.wxs7
-rw-r--r--src/ext/Bal/wixlib/BalExtension_platform.wxi69
-rw-r--r--src/ext/Bal/wixlib/BalExtension_x64.wxs7
-rw-r--r--src/ext/Bal/wixlib/BalExtension_x86.wxs7
-rw-r--r--src/ext/Bal/wixlib/Dnc.wxs20
-rw-r--r--src/ext/Bal/wixlib/Mba.wxs43
-rw-r--r--src/ext/Bal/wixlib/bal.wixproj36
-rw-r--r--src/ext/Bal/wixlib/caDecor.wxi39
-rw-r--r--src/ext/Bal/wixlib/wixstdba.wxs92
-rw-r--r--src/ext/Bal/wixstdba/Resources/1028/mbapreq.wxl27
-rw-r--r--src/ext/Bal/wixstdba/Resources/1029/mbapreq.wxl30
-rw-r--r--src/ext/Bal/wixstdba/Resources/1030/mbapreq.wxl30
-rw-r--r--src/ext/Bal/wixstdba/Resources/1031/mbapreq.wxl33
-rw-r--r--src/ext/Bal/wixstdba/Resources/1032/mbapreq.wxl32
-rw-r--r--src/ext/Bal/wixstdba/Resources/1035/mbapreq.wxl30
-rw-r--r--src/ext/Bal/wixstdba/Resources/1036/mbapreq.wxl30
-rw-r--r--src/ext/Bal/wixstdba/Resources/1038/mbapreq.wxl30
-rw-r--r--src/ext/Bal/wixstdba/Resources/1040/mbapreq.wxl31
-rw-r--r--src/ext/Bal/wixstdba/Resources/1041/mbapreq.wxl27
-rw-r--r--src/ext/Bal/wixstdba/Resources/1042/mbapreq.wxl27
-rw-r--r--src/ext/Bal/wixstdba/Resources/1043/mbapreq.wxl30
-rw-r--r--src/ext/Bal/wixstdba/Resources/1044/mbapreq.wxl30
-rw-r--r--src/ext/Bal/wixstdba/Resources/1045/mbapreq.wxl30
-rw-r--r--src/ext/Bal/wixstdba/Resources/1046/mbapreq.wxl29
-rw-r--r--src/ext/Bal/wixstdba/Resources/1049/mbapreq.wxl29
-rw-r--r--src/ext/Bal/wixstdba/Resources/1051/mbapreq.wxl30
-rw-r--r--src/ext/Bal/wixstdba/Resources/1053/mbapreq.wxl30
-rw-r--r--src/ext/Bal/wixstdba/Resources/1055/mbapreq.wxl30
-rw-r--r--src/ext/Bal/wixstdba/Resources/1060/mbapreq.wxl30
-rw-r--r--src/ext/Bal/wixstdba/Resources/2052/mbapreq.wxl27
-rw-r--r--src/ext/Bal/wixstdba/Resources/2070/mbapreq.wxl29
-rw-r--r--src/ext/Bal/wixstdba/Resources/3082/mbapreq.wxl31
-rw-r--r--src/ext/Bal/wixstdba/Resources/HyperlinkLargeTheme.xml109
-rw-r--r--src/ext/Bal/wixstdba/Resources/HyperlinkSidebarTheme.xml120
-rw-r--r--src/ext/Bal/wixstdba/Resources/HyperlinkTheme.wxl61
-rw-r--r--src/ext/Bal/wixstdba/Resources/HyperlinkTheme.xml106
-rw-r--r--src/ext/Bal/wixstdba/Resources/LoremIpsumLicense.rtfbin0 -> 4908 bytes
-rw-r--r--src/ext/Bal/wixstdba/Resources/RtfLargeTheme.xml108
-rw-r--r--src/ext/Bal/wixstdba/Resources/RtfTheme.wxl58
-rw-r--r--src/ext/Bal/wixstdba/Resources/RtfTheme.xml106
-rw-r--r--src/ext/Bal/wixstdba/Resources/dncpreq.thm47
-rw-r--r--src/ext/Bal/wixstdba/Resources/dncpreq.wxl29
-rw-r--r--src/ext/Bal/wixstdba/Resources/logo.pngbin0 -> 852 bytes
-rw-r--r--src/ext/Bal/wixstdba/Resources/logoSide.pngbin0 -> 3477 bytes
-rw-r--r--src/ext/Bal/wixstdba/Resources/mbapreq.pngbin0 -> 797 bytes
-rw-r--r--src/ext/Bal/wixstdba/Resources/mbapreq.thm47
-rw-r--r--src/ext/Bal/wixstdba/Resources/mbapreq.wxl29
-rw-r--r--src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp4264
-rw-r--r--src/ext/Bal/wixstdba/packages.config10
-rw-r--r--src/ext/Bal/wixstdba/precomp.cpp3
-rw-r--r--src/ext/Bal/wixstdba/precomp.h58
-rw-r--r--src/ext/Bal/wixstdba/resource.h15
-rw-r--r--src/ext/Bal/wixstdba/wixstdba.cpp144
-rw-r--r--src/ext/Bal/wixstdba/wixstdba.def10
-rw-r--r--src/ext/Bal/wixstdba/wixstdba.mc73
-rw-r--r--src/ext/Bal/wixstdba/wixstdba.vcxproj101
-rw-r--r--src/ext/Util/CustomizedNativeRecommendedRules.ruleset8
-rw-r--r--src/ext/Util/Directory.Build.props27
-rw-r--r--src/ext/Util/Directory.Build.targets51
-rw-r--r--src/ext/Util/Directory.csproj.props13
-rw-r--r--src/ext/Util/Directory.csproj.targets26
-rw-r--r--src/ext/Util/Directory.vcxproj.props97
-rw-r--r--src/ext/Util/README.md3
-rw-r--r--src/ext/Util/Util.wixext.sln87
-rw-r--r--src/ext/Util/Util.wixext.v3.ncrunchsolution6
-rw-r--r--src/ext/Util/appveyor.cmd19
-rw-r--r--src/ext/Util/appveyor.yml40
-rw-r--r--src/ext/Util/be/UtilBundleExtension.cpp87
-rw-r--r--src/ext/Util/be/UtilBundleExtension.h16
-rw-r--r--src/ext/Util/be/beDecor.h13
-rw-r--r--src/ext/Util/be/detectsha2support.cpp58
-rw-r--r--src/ext/Util/be/detectsha2support.h8
-rw-r--r--src/ext/Util/be/precomp.cpp3
-rw-r--r--src/ext/Util/be/precomp.h37
-rw-r--r--src/ext/Util/be/utilbe.cpp41
-rw-r--r--src/ext/Util/be/utilbe.def8
-rw-r--r--src/ext/Util/be/utilbe.vcxproj80
-rw-r--r--src/ext/Util/be/utilsearch.cpp160
-rw-r--r--src/ext/Util/be/utilsearch.h65
-rw-r--r--src/ext/Util/ca/BroadcastSettingChange.cpp45
-rw-r--r--src/ext/Util/ca/CheckReboot.cpp36
-rw-r--r--src/ext/Util/ca/CloseApps.cpp568
-rw-r--r--src/ext/Util/ca/CustomMsiErrors.h32
-rw-r--r--src/ext/Util/ca/FormatFiles.cpp221
-rw-r--r--src/ext/Util/ca/OsInfo.cpp487
-rw-r--r--src/ext/Util/ca/RemoveFoldersEx.cpp243
-rw-r--r--src/ext/Util/ca/RemoveRegistryKeysEx.cpp114
-rw-r--r--src/ext/Util/ca/RestartManager.cpp185
-rw-r--r--src/ext/Util/ca/TouchFile.cpp308
-rw-r--r--src/ext/Util/ca/XmlConfig.cpp1130
-rw-r--r--src/ext/Util/ca/XmlFile.cpp940
-rw-r--r--src/ext/Util/ca/caDecor.h13
-rw-r--r--src/ext/Util/ca/cost.h9
-rw-r--r--src/ext/Util/ca/dllmain.cpp26
-rw-r--r--src/ext/Util/ca/exitearlywithsuccess.cpp27
-rw-r--r--src/ext/Util/ca/netshortcuts.cpp437
-rw-r--r--src/ext/Util/ca/precomp.h54
-rw-r--r--src/ext/Util/ca/qtexecca.cpp316
-rw-r--r--src/ext/Util/ca/sca.h19
-rw-r--r--src/ext/Util/ca/scacost.h18
-rw-r--r--src/ext/Util/ca/scaexec.cpp1082
-rw-r--r--src/ext/Util/ca/scamanifest.cpp377
-rw-r--r--src/ext/Util/ca/scaperf.cpp310
-rw-r--r--src/ext/Util/ca/scaperfexec.cpp423
-rw-r--r--src/ext/Util/ca/scasched.cpp127
-rw-r--r--src/ext/Util/ca/scasmb.h46
-rw-r--r--src/ext/Util/ca/scasmbexec.cpp316
-rw-r--r--src/ext/Util/ca/scasmbexec.h27
-rw-r--r--src/ext/Util/ca/scasmbsched.cpp639
-rw-r--r--src/ext/Util/ca/scauser.cpp709
-rw-r--r--src/ext/Util/ca/scauser.h67
-rw-r--r--src/ext/Util/ca/secureobj.cpp915
-rw-r--r--src/ext/Util/ca/serviceconfig.cpp821
-rw-r--r--src/ext/Util/ca/shellexecca.cpp271
-rw-r--r--src/ext/Util/ca/test.cpp269
-rw-r--r--src/ext/Util/ca/utilca.cpp3
-rw-r--r--src/ext/Util/ca/utilca.def91
-rw-r--r--src/ext/Util/ca/utilca.vcxproj106
-rw-r--r--src/ext/Util/nuget.config18
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/.Data/burn.exebin0 -> 463360 bytes
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/Bundle.en-us.wxl8
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/Bundle.wxs52
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/MsiPackage/Shared.dll1
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/MsiPackage/test.txt1
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/fakeba.dll1
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/test.msibin0 -> 32768 bytes
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/CloseApplication/Package.en-us.wxl9
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/CloseApplication/Package.wxs17
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/CloseApplication/PackageComponents.wxs9
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/CloseApplication/example.txt1
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/EventManifest/Package.en-us.wxl9
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/EventManifest/Package.wxs15
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/EventManifest/PackageComponents.wxs11
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/EventManifest/example.txt1
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcut/Package.en-us.wxl9
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcut/Package.icobin0 -> 83899 bytes
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcut/Package.wxs15
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcut/PackageComponents.wxs11
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcut/example.txt1
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcutModule/Module.wxs13
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcutModule/ModuleComponents.wxs11
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcutModule/Package.icobin0 -> 83899 bytes
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/PermissionEx/Package.en-us.wxl9
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/PermissionEx/Package.wxs15
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/PermissionEx/PackageComponents.wxs23
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/PermissionEx/example.txt1
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/Queries/Package.en-us.wxl9
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/Queries/Package.wxs23
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/Queries/PackageComponents.wxs9
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/Queries/example.txt1
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/RemoveFolderEx/Module.wxs13
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/RemoveFolderEx/ModuleComponents.wxs10
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/RemoveRegistryKeyEx/Module.wxs13
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/RemoveRegistryKeyEx/ModuleComponents.wxs10
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/UsingFileShare/Package.en-us.wxl9
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/UsingFileShare/Package.wxs15
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/UsingFileShare/PackageComponents.wxs14
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/UsingFileShare/example.txt1
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/XmlConfig/Package.en-us.wxl9
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/XmlConfig/Package.wxs17
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/XmlConfigModule/Module.wxs19
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/TestData/XmlConfigModule/my.xml1
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs317
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/WixToolsetTest.Util.csproj38
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/WixToolsetTest.Util.v3.ncrunchproject5
-rw-r--r--src/ext/Util/wix.snkbin0 -> 596 bytes
-rw-r--r--src/ext/Util/wixext/PerformanceCounterType.cs192
-rw-r--r--src/ext/Util/wixext/Symbols/EventManifestSymbol.cs55
-rw-r--r--src/ext/Util/wixext/Symbols/FileSharePermissionsSymbol.cs63
-rw-r--r--src/ext/Util/wixext/Symbols/FileShareSymbol.cs71
-rw-r--r--src/ext/Util/wixext/Symbols/GroupSymbol.cs63
-rw-r--r--src/ext/Util/wixext/Symbols/PerfmonManifestSymbol.cs63
-rw-r--r--src/ext/Util/wixext/Symbols/PerfmonSymbol.cs63
-rw-r--r--src/ext/Util/wixext/Symbols/PerformanceCategorySymbol.cs71
-rw-r--r--src/ext/Util/wixext/Symbols/SecureObjectsSymbol.cs103
-rw-r--r--src/ext/Util/wixext/Symbols/ServiceConfigSymbol.cs119
-rw-r--r--src/ext/Util/wixext/Symbols/UserGroupSymbol.cs55
-rw-r--r--src/ext/Util/wixext/Symbols/UserSymbol.cs79
-rw-r--r--src/ext/Util/wixext/Symbols/UtilSymbolDefinitions.cs125
-rw-r--r--src/ext/Util/wixext/Symbols/WixCloseApplicationSymbol.cs103
-rw-r--r--src/ext/Util/wixext/Symbols/WixFormatFilesSymbol.cs55
-rw-r--r--src/ext/Util/wixext/Symbols/WixInternetShortcutSymbol.cs95
-rw-r--r--src/ext/Util/wixext/Symbols/WixRemoveFolderExSymbol.cs78
-rw-r--r--src/ext/Util/wixext/Symbols/WixRemoveRegistryKeyExSymbol.cs86
-rw-r--r--src/ext/Util/wixext/Symbols/WixRestartResourceSymbol.cs71
-rw-r--r--src/ext/Util/wixext/Symbols/WixTouchFileSymbol.cs63
-rw-r--r--src/ext/Util/wixext/Symbols/WixWindowsFeatureSearchSymbol.cs47
-rw-r--r--src/ext/Util/wixext/Symbols/XmlConfigSymbol.cs111
-rw-r--r--src/ext/Util/wixext/Symbols/XmlFileSymbol.cs95
-rw-r--r--src/ext/Util/wixext/UtilCompiler.cs3889
-rw-r--r--src/ext/Util/wixext/UtilConstants.cs17
-rw-r--r--src/ext/Util/wixext/UtilDecompiler.cs1543
-rw-r--r--src/ext/Util/wixext/UtilErrors.cs49
-rw-r--r--src/ext/Util/wixext/UtilExtensionData.cs23
-rw-r--r--src/ext/Util/wixext/UtilExtensionFactory.cs18
-rw-r--r--src/ext/Util/wixext/UtilTableDefinitions.cs319
-rw-r--r--src/ext/Util/wixext/UtilWarnings.cs37
-rw-r--r--src/ext/Util/wixext/UtilWindowsInstallerBackendExtension.cs13
-rw-r--r--src/ext/Util/wixext/WixToolset.Util.wixext.csproj31
-rw-r--r--src/ext/Util/wixext/WixToolset.Util.wixext.nuspec25
-rw-r--r--src/ext/Util/wixext/WixToolset.Util.wixext.targets11
-rw-r--r--src/ext/Util/wixext/WixToolset.Util.wixext.v3.ncrunchproject7
-rw-r--r--src/ext/Util/wixlib/UtilBundleExtension_Platform.wxi10
-rw-r--r--src/ext/Util/wixlib/UtilBundleExtension_arm64.wxs7
-rw-r--r--src/ext/Util/wixlib/UtilBundleExtension_x64.wxs7
-rw-r--r--src/ext/Util/wixlib/UtilBundleExtension_x86.wxs7
-rw-r--r--src/ext/Util/wixlib/UtilExtension.wxs64
-rw-r--r--src/ext/Util/wixlib/UtilExtension_Platform.wxi360
-rw-r--r--src/ext/Util/wixlib/UtilExtension_arm64.wxs7
-rw-r--r--src/ext/Util/wixlib/UtilExtension_x64.wxs7
-rw-r--r--src/ext/Util/wixlib/UtilExtension_x86.wxs7
-rw-r--r--src/ext/Util/wixlib/caDecor.wxi39
-rw-r--r--src/ext/Util/wixlib/caerr.wxi96
-rw-r--r--src/ext/Util/wixlib/de-de.wxl32
-rw-r--r--src/ext/Util/wixlib/en-us.wxl32
-rw-r--r--src/ext/Util/wixlib/es-es.wxl31
-rw-r--r--src/ext/Util/wixlib/fr-fr.wxl31
-rw-r--r--src/ext/Util/wixlib/it-it.wxl32
-rw-r--r--src/ext/Util/wixlib/ja-jp.wxl32
-rw-r--r--src/ext/Util/wixlib/pt-br.wxl26
-rw-r--r--src/ext/Util/wixlib/util.v3.ncrunchproject5
-rw-r--r--src/ext/Util/wixlib/util.wixproj27
-rw-r--r--src/ext/global.json3
367 files changed, 36542 insertions, 0 deletions
diff --git a/src/ext/Bal/Bal.wixext.sln b/src/ext/Bal/Bal.wixext.sln
new file mode 100644
index 00000000..0b4c5afa
--- /dev/null
+++ b/src/ext/Bal/Bal.wixext.sln
@@ -0,0 +1,319 @@
1
2Microsoft Visual Studio Solution File, Format Version 12.00
3# Visual Studio Version 16
4VisualStudioVersion = 16.0.29503.13
5MinimumVisualStudioVersion = 10.0.40219.1
6Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{C70E3534-A018-4D0A-A340-916C9777EEF7}"
7EndProject
8Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bafunctions", "src\Samples\bafunctions\bafunctions.vcxproj", "{EB0A7D51-2133-4EE7-B6CA-87DBEAC67E02}"
9EndProject
10Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mbahost", "src\mbahost\mbahost.vcxproj", "{12C87C77-3547-44F8-8134-29BC915CB19D}"
11EndProject
12Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wixstdba", "src\wixstdba\wixstdba.vcxproj", "{41085A22-E6AA-4E8B-AB1B-DDEE0DC89DFA}"
13EndProject
14Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "bal", "src\wixlib\bal.wixproj", "{3444D952-F21C-496F-AB6B-56435BFD0787}"
15EndProject
16Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolset.Bal.wixext", "src\wixext\WixToolset.Bal.wixext.csproj", "{BF720A63-9D7B-456E-B60C-8122852D9FED}"
17EndProject
18Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolset.Dnc.Host", "src\WixToolset.Dnc.Host\WixToolset.Dnc.Host.csproj", "{0D780900-C2FF-4FA2-8CB5-8A19768724C5}"
19EndProject
20Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WixToolset.Mba.Host", "src\WixToolset.Mba.Host\WixToolset.Mba.Host.csproj", "{F2BA1935-70FA-4156-B161-FD03850B4FAA}"
21EndProject
22Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.FullFramework2MBA", "src\test\examples\FullFramework2MBA\Example.FullFramework2MBA.csproj", "{CC4236FC-226E-4232-AB50-24CBEC4D314D}"
23EndProject
24Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Example.TestEngine", "src\test\examples\TestEngine\Example.TestEngine.vcxproj", "{3D44B67D-A475-49BA-8310-E39F6C117CC9}"
25EndProject
26Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolsetTest.ManagedHost", "src\test\WixToolsetTest.ManagedHost\WixToolsetTest.ManagedHost.csproj", "{FED9D707-E5C3-4867-87B0-FABDB5EB0823}"
27EndProject
28Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.FullFramework4MBA", "src\test\examples\FullFramework4MBA\Example.FullFramework4MBA.csproj", "{44297646-706D-4508-8E96-1B35B109694C}"
29EndProject
30Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolsetTest.Bal", "src\test\WixToolsetTest.Bal\WixToolsetTest.Bal.csproj", "{89D479FC-20DA-44D8-AE38-48F063223498}"
31EndProject
32Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.EarliestCoreMBA", "src\test\examples\EarliestCoreMBA\Example.EarliestCoreMBA.csproj", "{1E86D8DF-DABD-4B6E-A812-64CD2040C73A}"
33EndProject
34Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dnchost", "src\dnchost\dnchost.vcxproj", "{B6F70281-6583-4138-BB7F-AABFEBBB3CA2}"
35EndProject
36Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.LatestCoreMBA", "src\test\examples\LatestCoreMBA\Example.LatestCoreMBA.csproj", "{A4247D9D-3CC9-4BE1-B23A-BEC166AF3618}"
37EndProject
38Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.WPFCoreMBA", "src\test\examples\WPFCoreMBA\Example.WPFCoreMBA.csproj", "{8E707BF2-FD72-4649-8727-BA5955D48D40}"
39EndProject
40Global
41 GlobalSection(SolutionConfigurationPlatforms) = preSolution
42 Debug|Any CPU = Debug|Any CPU
43 Debug|ARM64 = Debug|ARM64
44 Debug|x64 = Debug|x64
45 Debug|x86 = Debug|x86
46 Release|Any CPU = Release|Any CPU
47 Release|ARM64 = Release|ARM64
48 Release|x64 = Release|x64
49 Release|x86 = Release|x86
50 EndGlobalSection
51 GlobalSection(ProjectConfigurationPlatforms) = postSolution
52 {EB0A7D51-2133-4EE7-B6CA-87DBEAC67E02}.Debug|Any CPU.ActiveCfg = Debug|Win32
53 {EB0A7D51-2133-4EE7-B6CA-87DBEAC67E02}.Debug|Any CPU.Build.0 = Debug|Win32
54 {EB0A7D51-2133-4EE7-B6CA-87DBEAC67E02}.Debug|ARM64.ActiveCfg = Debug|ARM64
55 {EB0A7D51-2133-4EE7-B6CA-87DBEAC67E02}.Debug|ARM64.Build.0 = Debug|ARM64
56 {EB0A7D51-2133-4EE7-B6CA-87DBEAC67E02}.Debug|x64.ActiveCfg = Debug|x64
57 {EB0A7D51-2133-4EE7-B6CA-87DBEAC67E02}.Debug|x64.Build.0 = Debug|x64
58 {EB0A7D51-2133-4EE7-B6CA-87DBEAC67E02}.Debug|x86.ActiveCfg = Debug|Win32
59 {EB0A7D51-2133-4EE7-B6CA-87DBEAC67E02}.Debug|x86.Build.0 = Debug|Win32
60 {EB0A7D51-2133-4EE7-B6CA-87DBEAC67E02}.Release|Any CPU.ActiveCfg = Release|Win32
61 {EB0A7D51-2133-4EE7-B6CA-87DBEAC67E02}.Release|Any CPU.Build.0 = Release|Win32
62 {EB0A7D51-2133-4EE7-B6CA-87DBEAC67E02}.Release|ARM64.ActiveCfg = Release|ARM64
63 {EB0A7D51-2133-4EE7-B6CA-87DBEAC67E02}.Release|ARM64.Build.0 = Release|ARM64
64 {EB0A7D51-2133-4EE7-B6CA-87DBEAC67E02}.Release|x64.ActiveCfg = Release|x64
65 {EB0A7D51-2133-4EE7-B6CA-87DBEAC67E02}.Release|x64.Build.0 = Release|x64
66 {EB0A7D51-2133-4EE7-B6CA-87DBEAC67E02}.Release|x86.ActiveCfg = Release|Win32
67 {EB0A7D51-2133-4EE7-B6CA-87DBEAC67E02}.Release|x86.Build.0 = Release|Win32
68 {12C87C77-3547-44F8-8134-29BC915CB19D}.Debug|Any CPU.ActiveCfg = Debug|Win32
69 {12C87C77-3547-44F8-8134-29BC915CB19D}.Debug|Any CPU.Build.0 = Debug|Win32
70 {12C87C77-3547-44F8-8134-29BC915CB19D}.Debug|ARM64.ActiveCfg = Debug|ARM64
71 {12C87C77-3547-44F8-8134-29BC915CB19D}.Debug|ARM64.Build.0 = Debug|ARM64
72 {12C87C77-3547-44F8-8134-29BC915CB19D}.Debug|x64.ActiveCfg = Debug|x64
73 {12C87C77-3547-44F8-8134-29BC915CB19D}.Debug|x64.Build.0 = Debug|x64
74 {12C87C77-3547-44F8-8134-29BC915CB19D}.Debug|x86.ActiveCfg = Debug|Win32
75 {12C87C77-3547-44F8-8134-29BC915CB19D}.Debug|x86.Build.0 = Debug|Win32
76 {12C87C77-3547-44F8-8134-29BC915CB19D}.Release|Any CPU.ActiveCfg = Release|Win32
77 {12C87C77-3547-44F8-8134-29BC915CB19D}.Release|Any CPU.Build.0 = Release|Win32
78 {12C87C77-3547-44F8-8134-29BC915CB19D}.Release|ARM64.ActiveCfg = Release|ARM64
79 {12C87C77-3547-44F8-8134-29BC915CB19D}.Release|ARM64.Build.0 = Release|ARM64
80 {12C87C77-3547-44F8-8134-29BC915CB19D}.Release|x64.ActiveCfg = Release|x64
81 {12C87C77-3547-44F8-8134-29BC915CB19D}.Release|x64.Build.0 = Release|x64
82 {12C87C77-3547-44F8-8134-29BC915CB19D}.Release|x86.ActiveCfg = Release|Win32
83 {12C87C77-3547-44F8-8134-29BC915CB19D}.Release|x86.Build.0 = Release|Win32
84 {41085A22-E6AA-4E8B-AB1B-DDEE0DC89DFA}.Debug|Any CPU.ActiveCfg = Debug|Win32
85 {41085A22-E6AA-4E8B-AB1B-DDEE0DC89DFA}.Debug|Any CPU.Build.0 = Debug|Win32
86 {41085A22-E6AA-4E8B-AB1B-DDEE0DC89DFA}.Debug|ARM64.ActiveCfg = Debug|ARM64
87 {41085A22-E6AA-4E8B-AB1B-DDEE0DC89DFA}.Debug|ARM64.Build.0 = Debug|ARM64
88 {41085A22-E6AA-4E8B-AB1B-DDEE0DC89DFA}.Debug|x64.ActiveCfg = Debug|x64
89 {41085A22-E6AA-4E8B-AB1B-DDEE0DC89DFA}.Debug|x64.Build.0 = Debug|x64
90 {41085A22-E6AA-4E8B-AB1B-DDEE0DC89DFA}.Debug|x86.ActiveCfg = Debug|Win32
91 {41085A22-E6AA-4E8B-AB1B-DDEE0DC89DFA}.Debug|x86.Build.0 = Debug|Win32
92 {41085A22-E6AA-4E8B-AB1B-DDEE0DC89DFA}.Release|Any CPU.ActiveCfg = Release|Win32
93 {41085A22-E6AA-4E8B-AB1B-DDEE0DC89DFA}.Release|Any CPU.Build.0 = Release|Win32
94 {41085A22-E6AA-4E8B-AB1B-DDEE0DC89DFA}.Release|ARM64.ActiveCfg = Release|ARM64
95 {41085A22-E6AA-4E8B-AB1B-DDEE0DC89DFA}.Release|ARM64.Build.0 = Release|ARM64
96 {41085A22-E6AA-4E8B-AB1B-DDEE0DC89DFA}.Release|x64.ActiveCfg = Release|x64
97 {41085A22-E6AA-4E8B-AB1B-DDEE0DC89DFA}.Release|x64.Build.0 = Release|x64
98 {41085A22-E6AA-4E8B-AB1B-DDEE0DC89DFA}.Release|x86.ActiveCfg = Release|Win32
99 {41085A22-E6AA-4E8B-AB1B-DDEE0DC89DFA}.Release|x86.Build.0 = Release|Win32
100 {3444D952-F21C-496F-AB6B-56435BFD0787}.Debug|Any CPU.ActiveCfg = Debug|x86
101 {3444D952-F21C-496F-AB6B-56435BFD0787}.Debug|Any CPU.Build.0 = Debug|x86
102 {3444D952-F21C-496F-AB6B-56435BFD0787}.Debug|ARM64.ActiveCfg = Debug|x86
103 {3444D952-F21C-496F-AB6B-56435BFD0787}.Debug|x64.ActiveCfg = Debug|x86
104 {3444D952-F21C-496F-AB6B-56435BFD0787}.Debug|x86.ActiveCfg = Debug|x86
105 {3444D952-F21C-496F-AB6B-56435BFD0787}.Debug|x86.Build.0 = Debug|x86
106 {3444D952-F21C-496F-AB6B-56435BFD0787}.Release|Any CPU.ActiveCfg = Release|x86
107 {3444D952-F21C-496F-AB6B-56435BFD0787}.Release|Any CPU.Build.0 = Release|x86
108 {3444D952-F21C-496F-AB6B-56435BFD0787}.Release|ARM64.ActiveCfg = Release|x86
109 {3444D952-F21C-496F-AB6B-56435BFD0787}.Release|x64.ActiveCfg = Release|x86
110 {3444D952-F21C-496F-AB6B-56435BFD0787}.Release|x86.ActiveCfg = Release|x86
111 {3444D952-F21C-496F-AB6B-56435BFD0787}.Release|x86.Build.0 = Release|x86
112 {BF720A63-9D7B-456E-B60C-8122852D9FED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
113 {BF720A63-9D7B-456E-B60C-8122852D9FED}.Debug|Any CPU.Build.0 = Debug|Any CPU
114 {BF720A63-9D7B-456E-B60C-8122852D9FED}.Debug|ARM64.ActiveCfg = Debug|Any CPU
115 {BF720A63-9D7B-456E-B60C-8122852D9FED}.Debug|ARM64.Build.0 = Debug|Any CPU
116 {BF720A63-9D7B-456E-B60C-8122852D9FED}.Debug|x64.ActiveCfg = Debug|Any CPU
117 {BF720A63-9D7B-456E-B60C-8122852D9FED}.Debug|x64.Build.0 = Debug|Any CPU
118 {BF720A63-9D7B-456E-B60C-8122852D9FED}.Debug|x86.ActiveCfg = Debug|Any CPU
119 {BF720A63-9D7B-456E-B60C-8122852D9FED}.Debug|x86.Build.0 = Debug|Any CPU
120 {BF720A63-9D7B-456E-B60C-8122852D9FED}.Release|Any CPU.ActiveCfg = Release|Any CPU
121 {BF720A63-9D7B-456E-B60C-8122852D9FED}.Release|Any CPU.Build.0 = Release|Any CPU
122 {BF720A63-9D7B-456E-B60C-8122852D9FED}.Release|ARM64.ActiveCfg = Release|Any CPU
123 {BF720A63-9D7B-456E-B60C-8122852D9FED}.Release|ARM64.Build.0 = Release|Any CPU
124 {BF720A63-9D7B-456E-B60C-8122852D9FED}.Release|x64.ActiveCfg = Release|Any CPU
125 {BF720A63-9D7B-456E-B60C-8122852D9FED}.Release|x64.Build.0 = Release|Any CPU
126 {BF720A63-9D7B-456E-B60C-8122852D9FED}.Release|x86.ActiveCfg = Release|Any CPU
127 {BF720A63-9D7B-456E-B60C-8122852D9FED}.Release|x86.Build.0 = Release|Any CPU
128 {0D780900-C2FF-4FA2-8CB5-8A19768724C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
129 {0D780900-C2FF-4FA2-8CB5-8A19768724C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
130 {0D780900-C2FF-4FA2-8CB5-8A19768724C5}.Debug|ARM64.ActiveCfg = Debug|Any CPU
131 {0D780900-C2FF-4FA2-8CB5-8A19768724C5}.Debug|ARM64.Build.0 = Debug|Any CPU
132 {0D780900-C2FF-4FA2-8CB5-8A19768724C5}.Debug|x64.ActiveCfg = Debug|Any CPU
133 {0D780900-C2FF-4FA2-8CB5-8A19768724C5}.Debug|x64.Build.0 = Debug|Any CPU
134 {0D780900-C2FF-4FA2-8CB5-8A19768724C5}.Debug|x86.ActiveCfg = Debug|Any CPU
135 {0D780900-C2FF-4FA2-8CB5-8A19768724C5}.Debug|x86.Build.0 = Debug|Any CPU
136 {0D780900-C2FF-4FA2-8CB5-8A19768724C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
137 {0D780900-C2FF-4FA2-8CB5-8A19768724C5}.Release|Any CPU.Build.0 = Release|Any CPU
138 {0D780900-C2FF-4FA2-8CB5-8A19768724C5}.Release|ARM64.ActiveCfg = Release|Any CPU
139 {0D780900-C2FF-4FA2-8CB5-8A19768724C5}.Release|ARM64.Build.0 = Release|Any CPU
140 {0D780900-C2FF-4FA2-8CB5-8A19768724C5}.Release|x64.ActiveCfg = Release|Any CPU
141 {0D780900-C2FF-4FA2-8CB5-8A19768724C5}.Release|x64.Build.0 = Release|Any CPU
142 {0D780900-C2FF-4FA2-8CB5-8A19768724C5}.Release|x86.ActiveCfg = Release|Any CPU
143 {0D780900-C2FF-4FA2-8CB5-8A19768724C5}.Release|x86.Build.0 = Release|Any CPU
144 {F2BA1935-70FA-4156-B161-FD03850B4FAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
145 {F2BA1935-70FA-4156-B161-FD03850B4FAA}.Debug|Any CPU.Build.0 = Debug|Any CPU
146 {F2BA1935-70FA-4156-B161-FD03850B4FAA}.Debug|ARM64.ActiveCfg = Debug|Any CPU
147 {F2BA1935-70FA-4156-B161-FD03850B4FAA}.Debug|ARM64.Build.0 = Debug|Any CPU
148 {F2BA1935-70FA-4156-B161-FD03850B4FAA}.Debug|x64.ActiveCfg = Debug|Any CPU
149 {F2BA1935-70FA-4156-B161-FD03850B4FAA}.Debug|x64.Build.0 = Debug|Any CPU
150 {F2BA1935-70FA-4156-B161-FD03850B4FAA}.Debug|x86.ActiveCfg = Debug|Any CPU
151 {F2BA1935-70FA-4156-B161-FD03850B4FAA}.Debug|x86.Build.0 = Debug|Any CPU
152 {F2BA1935-70FA-4156-B161-FD03850B4FAA}.Release|Any CPU.ActiveCfg = Release|Any CPU
153 {F2BA1935-70FA-4156-B161-FD03850B4FAA}.Release|Any CPU.Build.0 = Release|Any CPU
154 {F2BA1935-70FA-4156-B161-FD03850B4FAA}.Release|ARM64.ActiveCfg = Release|Any CPU
155 {F2BA1935-70FA-4156-B161-FD03850B4FAA}.Release|ARM64.Build.0 = Release|Any CPU
156 {F2BA1935-70FA-4156-B161-FD03850B4FAA}.Release|x64.ActiveCfg = Release|Any CPU
157 {F2BA1935-70FA-4156-B161-FD03850B4FAA}.Release|x64.Build.0 = Release|Any CPU
158 {F2BA1935-70FA-4156-B161-FD03850B4FAA}.Release|x86.ActiveCfg = Release|Any CPU
159 {F2BA1935-70FA-4156-B161-FD03850B4FAA}.Release|x86.Build.0 = Release|Any CPU
160 {CC4236FC-226E-4232-AB50-24CBEC4D314D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
161 {CC4236FC-226E-4232-AB50-24CBEC4D314D}.Debug|Any CPU.Build.0 = Debug|Any CPU
162 {CC4236FC-226E-4232-AB50-24CBEC4D314D}.Debug|ARM64.ActiveCfg = Debug|Any CPU
163 {CC4236FC-226E-4232-AB50-24CBEC4D314D}.Debug|ARM64.Build.0 = Debug|Any CPU
164 {CC4236FC-226E-4232-AB50-24CBEC4D314D}.Debug|x64.ActiveCfg = Debug|Any CPU
165 {CC4236FC-226E-4232-AB50-24CBEC4D314D}.Debug|x64.Build.0 = Debug|Any CPU
166 {CC4236FC-226E-4232-AB50-24CBEC4D314D}.Debug|x86.ActiveCfg = Debug|Any CPU
167 {CC4236FC-226E-4232-AB50-24CBEC4D314D}.Debug|x86.Build.0 = Debug|Any CPU
168 {CC4236FC-226E-4232-AB50-24CBEC4D314D}.Release|Any CPU.ActiveCfg = Release|Any CPU
169 {CC4236FC-226E-4232-AB50-24CBEC4D314D}.Release|Any CPU.Build.0 = Release|Any CPU
170 {CC4236FC-226E-4232-AB50-24CBEC4D314D}.Release|ARM64.ActiveCfg = Release|Any CPU
171 {CC4236FC-226E-4232-AB50-24CBEC4D314D}.Release|ARM64.Build.0 = Release|Any CPU
172 {CC4236FC-226E-4232-AB50-24CBEC4D314D}.Release|x64.ActiveCfg = Release|Any CPU
173 {CC4236FC-226E-4232-AB50-24CBEC4D314D}.Release|x64.Build.0 = Release|Any CPU
174 {CC4236FC-226E-4232-AB50-24CBEC4D314D}.Release|x86.ActiveCfg = Release|Any CPU
175 {CC4236FC-226E-4232-AB50-24CBEC4D314D}.Release|x86.Build.0 = Release|Any CPU
176 {3D44B67D-A475-49BA-8310-E39F6C117CC9}.Debug|Any CPU.ActiveCfg = Debug|Win32
177 {3D44B67D-A475-49BA-8310-E39F6C117CC9}.Debug|Any CPU.Build.0 = Debug|Win32
178 {3D44B67D-A475-49BA-8310-E39F6C117CC9}.Debug|ARM64.ActiveCfg = Debug|ARM64
179 {3D44B67D-A475-49BA-8310-E39F6C117CC9}.Debug|ARM64.Build.0 = Debug|ARM64
180 {3D44B67D-A475-49BA-8310-E39F6C117CC9}.Debug|x64.ActiveCfg = Debug|x64
181 {3D44B67D-A475-49BA-8310-E39F6C117CC9}.Debug|x64.Build.0 = Debug|x64
182 {3D44B67D-A475-49BA-8310-E39F6C117CC9}.Debug|x86.ActiveCfg = Debug|Win32
183 {3D44B67D-A475-49BA-8310-E39F6C117CC9}.Debug|x86.Build.0 = Debug|Win32
184 {3D44B67D-A475-49BA-8310-E39F6C117CC9}.Release|Any CPU.ActiveCfg = Release|Win32
185 {3D44B67D-A475-49BA-8310-E39F6C117CC9}.Release|Any CPU.Build.0 = Release|Win32
186 {3D44B67D-A475-49BA-8310-E39F6C117CC9}.Release|ARM64.ActiveCfg = Release|ARM64
187 {3D44B67D-A475-49BA-8310-E39F6C117CC9}.Release|ARM64.Build.0 = Release|ARM64
188 {3D44B67D-A475-49BA-8310-E39F6C117CC9}.Release|x64.ActiveCfg = Release|x64
189 {3D44B67D-A475-49BA-8310-E39F6C117CC9}.Release|x64.Build.0 = Release|x64
190 {3D44B67D-A475-49BA-8310-E39F6C117CC9}.Release|x86.ActiveCfg = Release|Win32
191 {3D44B67D-A475-49BA-8310-E39F6C117CC9}.Release|x86.Build.0 = Release|Win32
192 {FED9D707-E5C3-4867-87B0-FABDB5EB0823}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
193 {FED9D707-E5C3-4867-87B0-FABDB5EB0823}.Debug|Any CPU.Build.0 = Debug|Any CPU
194 {FED9D707-E5C3-4867-87B0-FABDB5EB0823}.Debug|ARM64.ActiveCfg = Debug|Any CPU
195 {FED9D707-E5C3-4867-87B0-FABDB5EB0823}.Debug|ARM64.Build.0 = Debug|Any CPU
196 {FED9D707-E5C3-4867-87B0-FABDB5EB0823}.Debug|x64.ActiveCfg = Debug|Any CPU
197 {FED9D707-E5C3-4867-87B0-FABDB5EB0823}.Debug|x64.Build.0 = Debug|Any CPU
198 {FED9D707-E5C3-4867-87B0-FABDB5EB0823}.Debug|x86.ActiveCfg = Debug|Any CPU
199 {FED9D707-E5C3-4867-87B0-FABDB5EB0823}.Debug|x86.Build.0 = Debug|Any CPU
200 {FED9D707-E5C3-4867-87B0-FABDB5EB0823}.Release|Any CPU.ActiveCfg = Release|Any CPU
201 {FED9D707-E5C3-4867-87B0-FABDB5EB0823}.Release|Any CPU.Build.0 = Release|Any CPU
202 {FED9D707-E5C3-4867-87B0-FABDB5EB0823}.Release|ARM64.ActiveCfg = Release|Any CPU
203 {FED9D707-E5C3-4867-87B0-FABDB5EB0823}.Release|ARM64.Build.0 = Release|Any CPU
204 {FED9D707-E5C3-4867-87B0-FABDB5EB0823}.Release|x64.ActiveCfg = Release|Any CPU
205 {FED9D707-E5C3-4867-87B0-FABDB5EB0823}.Release|x64.Build.0 = Release|Any CPU
206 {FED9D707-E5C3-4867-87B0-FABDB5EB0823}.Release|x86.ActiveCfg = Release|Any CPU
207 {FED9D707-E5C3-4867-87B0-FABDB5EB0823}.Release|x86.Build.0 = Release|Any CPU
208 {44297646-706D-4508-8E96-1B35B109694C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
209 {44297646-706D-4508-8E96-1B35B109694C}.Debug|Any CPU.Build.0 = Debug|Any CPU
210 {44297646-706D-4508-8E96-1B35B109694C}.Debug|ARM64.ActiveCfg = Debug|Any CPU
211 {44297646-706D-4508-8E96-1B35B109694C}.Debug|ARM64.Build.0 = Debug|Any CPU
212 {44297646-706D-4508-8E96-1B35B109694C}.Debug|x64.ActiveCfg = Debug|Any CPU
213 {44297646-706D-4508-8E96-1B35B109694C}.Debug|x64.Build.0 = Debug|Any CPU
214 {44297646-706D-4508-8E96-1B35B109694C}.Debug|x86.ActiveCfg = Debug|Any CPU
215 {44297646-706D-4508-8E96-1B35B109694C}.Debug|x86.Build.0 = Debug|Any CPU
216 {44297646-706D-4508-8E96-1B35B109694C}.Release|Any CPU.ActiveCfg = Release|Any CPU
217 {44297646-706D-4508-8E96-1B35B109694C}.Release|Any CPU.Build.0 = Release|Any CPU
218 {44297646-706D-4508-8E96-1B35B109694C}.Release|ARM64.ActiveCfg = Release|Any CPU
219 {44297646-706D-4508-8E96-1B35B109694C}.Release|ARM64.Build.0 = Release|Any CPU
220 {44297646-706D-4508-8E96-1B35B109694C}.Release|x64.ActiveCfg = Release|Any CPU
221 {44297646-706D-4508-8E96-1B35B109694C}.Release|x64.Build.0 = Release|Any CPU
222 {44297646-706D-4508-8E96-1B35B109694C}.Release|x86.ActiveCfg = Release|Any CPU
223 {44297646-706D-4508-8E96-1B35B109694C}.Release|x86.Build.0 = Release|Any CPU
224 {89D479FC-20DA-44D8-AE38-48F063223498}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
225 {89D479FC-20DA-44D8-AE38-48F063223498}.Debug|Any CPU.Build.0 = Debug|Any CPU
226 {89D479FC-20DA-44D8-AE38-48F063223498}.Debug|ARM64.ActiveCfg = Debug|Any CPU
227 {89D479FC-20DA-44D8-AE38-48F063223498}.Debug|ARM64.Build.0 = Debug|Any CPU
228 {89D479FC-20DA-44D8-AE38-48F063223498}.Debug|x64.ActiveCfg = Debug|Any CPU
229 {89D479FC-20DA-44D8-AE38-48F063223498}.Debug|x64.Build.0 = Debug|Any CPU
230 {89D479FC-20DA-44D8-AE38-48F063223498}.Debug|x86.ActiveCfg = Debug|Any CPU
231 {89D479FC-20DA-44D8-AE38-48F063223498}.Debug|x86.Build.0 = Debug|Any CPU
232 {89D479FC-20DA-44D8-AE38-48F063223498}.Release|Any CPU.ActiveCfg = Release|Any CPU
233 {89D479FC-20DA-44D8-AE38-48F063223498}.Release|Any CPU.Build.0 = Release|Any CPU
234 {89D479FC-20DA-44D8-AE38-48F063223498}.Release|ARM64.ActiveCfg = Release|Any CPU
235 {89D479FC-20DA-44D8-AE38-48F063223498}.Release|ARM64.Build.0 = Release|Any CPU
236 {89D479FC-20DA-44D8-AE38-48F063223498}.Release|x64.ActiveCfg = Release|Any CPU
237 {89D479FC-20DA-44D8-AE38-48F063223498}.Release|x64.Build.0 = Release|Any CPU
238 {89D479FC-20DA-44D8-AE38-48F063223498}.Release|x86.ActiveCfg = Release|Any CPU
239 {89D479FC-20DA-44D8-AE38-48F063223498}.Release|x86.Build.0 = Release|Any CPU
240 {1E86D8DF-DABD-4B6E-A812-64CD2040C73A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
241 {1E86D8DF-DABD-4B6E-A812-64CD2040C73A}.Debug|Any CPU.Build.0 = Debug|Any CPU
242 {1E86D8DF-DABD-4B6E-A812-64CD2040C73A}.Debug|ARM64.ActiveCfg = Debug|Any CPU
243 {1E86D8DF-DABD-4B6E-A812-64CD2040C73A}.Debug|ARM64.Build.0 = Debug|Any CPU
244 {1E86D8DF-DABD-4B6E-A812-64CD2040C73A}.Debug|x64.ActiveCfg = Debug|Any CPU
245 {1E86D8DF-DABD-4B6E-A812-64CD2040C73A}.Debug|x64.Build.0 = Debug|Any CPU
246 {1E86D8DF-DABD-4B6E-A812-64CD2040C73A}.Debug|x86.ActiveCfg = Debug|Any CPU
247 {1E86D8DF-DABD-4B6E-A812-64CD2040C73A}.Debug|x86.Build.0 = Debug|Any CPU
248 {1E86D8DF-DABD-4B6E-A812-64CD2040C73A}.Release|Any CPU.ActiveCfg = Release|Any CPU
249 {1E86D8DF-DABD-4B6E-A812-64CD2040C73A}.Release|Any CPU.Build.0 = Release|Any CPU
250 {1E86D8DF-DABD-4B6E-A812-64CD2040C73A}.Release|ARM64.ActiveCfg = Release|Any CPU
251 {1E86D8DF-DABD-4B6E-A812-64CD2040C73A}.Release|ARM64.Build.0 = Release|Any CPU
252 {1E86D8DF-DABD-4B6E-A812-64CD2040C73A}.Release|x64.ActiveCfg = Release|Any CPU
253 {1E86D8DF-DABD-4B6E-A812-64CD2040C73A}.Release|x64.Build.0 = Release|Any CPU
254 {1E86D8DF-DABD-4B6E-A812-64CD2040C73A}.Release|x86.ActiveCfg = Release|Any CPU
255 {1E86D8DF-DABD-4B6E-A812-64CD2040C73A}.Release|x86.Build.0 = Release|Any CPU
256 {B6F70281-6583-4138-BB7F-AABFEBBB3CA2}.Debug|Any CPU.ActiveCfg = Debug|Win32
257 {B6F70281-6583-4138-BB7F-AABFEBBB3CA2}.Debug|Any CPU.Build.0 = Debug|Win32
258 {B6F70281-6583-4138-BB7F-AABFEBBB3CA2}.Debug|ARM64.ActiveCfg = Debug|ARM64
259 {B6F70281-6583-4138-BB7F-AABFEBBB3CA2}.Debug|ARM64.Build.0 = Debug|ARM64
260 {B6F70281-6583-4138-BB7F-AABFEBBB3CA2}.Debug|x64.ActiveCfg = Debug|x64
261 {B6F70281-6583-4138-BB7F-AABFEBBB3CA2}.Debug|x64.Build.0 = Debug|x64
262 {B6F70281-6583-4138-BB7F-AABFEBBB3CA2}.Debug|x86.ActiveCfg = Debug|Win32
263 {B6F70281-6583-4138-BB7F-AABFEBBB3CA2}.Debug|x86.Build.0 = Debug|Win32
264 {B6F70281-6583-4138-BB7F-AABFEBBB3CA2}.Release|Any CPU.ActiveCfg = Release|Win32
265 {B6F70281-6583-4138-BB7F-AABFEBBB3CA2}.Release|Any CPU.Build.0 = Release|Win32
266 {B6F70281-6583-4138-BB7F-AABFEBBB3CA2}.Release|ARM64.ActiveCfg = Release|ARM64
267 {B6F70281-6583-4138-BB7F-AABFEBBB3CA2}.Release|ARM64.Build.0 = Release|ARM64
268 {B6F70281-6583-4138-BB7F-AABFEBBB3CA2}.Release|x64.ActiveCfg = Release|x64
269 {B6F70281-6583-4138-BB7F-AABFEBBB3CA2}.Release|x64.Build.0 = Release|x64
270 {B6F70281-6583-4138-BB7F-AABFEBBB3CA2}.Release|x86.ActiveCfg = Release|Win32
271 {B6F70281-6583-4138-BB7F-AABFEBBB3CA2}.Release|x86.Build.0 = Release|Win32
272 {A4247D9D-3CC9-4BE1-B23A-BEC166AF3618}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
273 {A4247D9D-3CC9-4BE1-B23A-BEC166AF3618}.Debug|Any CPU.Build.0 = Debug|Any CPU
274 {A4247D9D-3CC9-4BE1-B23A-BEC166AF3618}.Debug|ARM64.ActiveCfg = Debug|Any CPU
275 {A4247D9D-3CC9-4BE1-B23A-BEC166AF3618}.Debug|ARM64.Build.0 = Debug|Any CPU
276 {A4247D9D-3CC9-4BE1-B23A-BEC166AF3618}.Debug|x64.ActiveCfg = Debug|Any CPU
277 {A4247D9D-3CC9-4BE1-B23A-BEC166AF3618}.Debug|x64.Build.0 = Debug|Any CPU
278 {A4247D9D-3CC9-4BE1-B23A-BEC166AF3618}.Debug|x86.ActiveCfg = Debug|Any CPU
279 {A4247D9D-3CC9-4BE1-B23A-BEC166AF3618}.Debug|x86.Build.0 = Debug|Any CPU
280 {A4247D9D-3CC9-4BE1-B23A-BEC166AF3618}.Release|Any CPU.ActiveCfg = Release|Any CPU
281 {A4247D9D-3CC9-4BE1-B23A-BEC166AF3618}.Release|Any CPU.Build.0 = Release|Any CPU
282 {A4247D9D-3CC9-4BE1-B23A-BEC166AF3618}.Release|ARM64.ActiveCfg = Release|Any CPU
283 {A4247D9D-3CC9-4BE1-B23A-BEC166AF3618}.Release|ARM64.Build.0 = Release|Any CPU
284 {A4247D9D-3CC9-4BE1-B23A-BEC166AF3618}.Release|x64.ActiveCfg = Release|Any CPU
285 {A4247D9D-3CC9-4BE1-B23A-BEC166AF3618}.Release|x64.Build.0 = Release|Any CPU
286 {A4247D9D-3CC9-4BE1-B23A-BEC166AF3618}.Release|x86.ActiveCfg = Release|Any CPU
287 {A4247D9D-3CC9-4BE1-B23A-BEC166AF3618}.Release|x86.Build.0 = Release|Any CPU
288 {8E707BF2-FD72-4649-8727-BA5955D48D40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
289 {8E707BF2-FD72-4649-8727-BA5955D48D40}.Debug|Any CPU.Build.0 = Debug|Any CPU
290 {8E707BF2-FD72-4649-8727-BA5955D48D40}.Debug|ARM64.ActiveCfg = Debug|Any CPU
291 {8E707BF2-FD72-4649-8727-BA5955D48D40}.Debug|ARM64.Build.0 = Debug|Any CPU
292 {8E707BF2-FD72-4649-8727-BA5955D48D40}.Debug|x64.ActiveCfg = Debug|Any CPU
293 {8E707BF2-FD72-4649-8727-BA5955D48D40}.Debug|x64.Build.0 = Debug|Any CPU
294 {8E707BF2-FD72-4649-8727-BA5955D48D40}.Debug|x86.ActiveCfg = Debug|Any CPU
295 {8E707BF2-FD72-4649-8727-BA5955D48D40}.Debug|x86.Build.0 = Debug|Any CPU
296 {8E707BF2-FD72-4649-8727-BA5955D48D40}.Release|Any CPU.ActiveCfg = Release|Any CPU
297 {8E707BF2-FD72-4649-8727-BA5955D48D40}.Release|Any CPU.Build.0 = Release|Any CPU
298 {8E707BF2-FD72-4649-8727-BA5955D48D40}.Release|ARM64.ActiveCfg = Release|Any CPU
299 {8E707BF2-FD72-4649-8727-BA5955D48D40}.Release|ARM64.Build.0 = Release|Any CPU
300 {8E707BF2-FD72-4649-8727-BA5955D48D40}.Release|x64.ActiveCfg = Release|Any CPU
301 {8E707BF2-FD72-4649-8727-BA5955D48D40}.Release|x64.Build.0 = Release|Any CPU
302 {8E707BF2-FD72-4649-8727-BA5955D48D40}.Release|x86.ActiveCfg = Release|Any CPU
303 {8E707BF2-FD72-4649-8727-BA5955D48D40}.Release|x86.Build.0 = Release|Any CPU
304 EndGlobalSection
305 GlobalSection(SolutionProperties) = preSolution
306 HideSolutionNode = FALSE
307 EndGlobalSection
308 GlobalSection(NestedProjects) = preSolution
309 {CC4236FC-226E-4232-AB50-24CBEC4D314D} = {C70E3534-A018-4D0A-A340-916C9777EEF7}
310 {3D44B67D-A475-49BA-8310-E39F6C117CC9} = {C70E3534-A018-4D0A-A340-916C9777EEF7}
311 {44297646-706D-4508-8E96-1B35B109694C} = {C70E3534-A018-4D0A-A340-916C9777EEF7}
312 {1E86D8DF-DABD-4B6E-A812-64CD2040C73A} = {C70E3534-A018-4D0A-A340-916C9777EEF7}
313 {A4247D9D-3CC9-4BE1-B23A-BEC166AF3618} = {C70E3534-A018-4D0A-A340-916C9777EEF7}
314 {8E707BF2-FD72-4649-8727-BA5955D48D40} = {C70E3534-A018-4D0A-A340-916C9777EEF7}
315 EndGlobalSection
316 GlobalSection(ExtensibilityGlobals) = postSolution
317 SolutionGuid = {74046961-48BF-467A-A6C2-F886C75CE0BE}
318 EndGlobalSection
319EndGlobal
diff --git a/src/ext/Bal/CSharp.Build.props b/src/ext/Bal/CSharp.Build.props
new file mode 100644
index 00000000..81d24ad1
--- /dev/null
+++ b/src/ext/Bal/CSharp.Build.props
@@ -0,0 +1,13 @@
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 Do NOT modify this file. Update the canonical version in Home\repo-template\src\CSharp.Build.props
4 then update all of the repos.
5-->
6<Project>
7 <PropertyGroup>
8 <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
9 <SignAssembly>true</SignAssembly>
10 <AssemblyOriginatorKeyFile>$([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)wix.snk))</AssemblyOriginatorKeyFile>
11 <NBGV_EmitThisAssemblyClass>false</NBGV_EmitThisAssemblyClass>
12 </PropertyGroup>
13</Project>
diff --git a/src/ext/Bal/Cpp.Build.props b/src/ext/Bal/Cpp.Build.props
new file mode 100644
index 00000000..e7bba117
--- /dev/null
+++ b/src/ext/Bal/Cpp.Build.props
@@ -0,0 +1,94 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4<Project>
5 <PropertyGroup>
6 <Platform Condition=" '$(Platform)' == '' OR '$(Platform)' == 'AnyCPU' ">Win32</Platform>
7 <IntDir>$(BaseIntermediateOutputPath)$(Configuration)\$(Platform)\</IntDir>
8 <OutDir>$(OutputPath)$(Platform)\</OutDir>
9
10 <!-- NBGV properties -->
11 <AssemblyCompany>$(Company)</AssemblyCompany>
12 <AssemblyCopyright>$(Copyright)</AssemblyCopyright>
13 </PropertyGroup>
14
15 <PropertyGroup Condition="'$(WindowsTargetPlatformVersion)'=='' AND '$(VisualStudioVersion)'>='15.0'">
16 <WindowsTargetPlatformVersion>$([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0'))</WindowsTargetPlatformVersion>
17 </PropertyGroup>
18
19 <PropertyGroup>
20 <CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)CustomizedNativeRecommendedRules.ruleset</CodeAnalysisRuleSet>
21 </PropertyGroup>
22
23 <ItemDefinitionGroup>
24 <ClCompile>
25 <DisableSpecificWarnings>$(DisableSpecificCompilerWarnings)</DisableSpecificWarnings>
26 <WarningLevel>Level4</WarningLevel>
27 <AdditionalIncludeDirectories>$(ProjectDir)inc;$(MSBuildProjectDirectory);$(IntDir);$(SqlCESdkIncludePath);$(ProjectAdditionalIncludeDirectories);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
28 <PreprocessorDefinitions>WIN32;_WINDOWS;_WIN32_MSI=500;_WIN32_WINNT=0x0501;$(ArmPreprocessorDefinitions);$(UnicodePreprocessorDefinitions);_CRT_STDIO_LEGACY_WIDE_SPECIFIERS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
29 <PrecompiledHeader>Use</PrecompiledHeader>
30 <PrecompiledHeaderFile>precomp.h</PrecompiledHeaderFile>
31 <CallingConvention Condition="'$(Platform)'=='Win32'">StdCall</CallingConvention>
32 <TreatWarningAsError>true</TreatWarningAsError>
33 <ExceptionHandling>false</ExceptionHandling>
34 <AdditionalOptions>-YlprecompDefine</AdditionalOptions>
35 <AdditionalOptions Condition=" $(PlatformToolset.StartsWith('v14')) ">/Zc:threadSafeInit- %(AdditionalOptions)</AdditionalOptions>
36 <MultiProcessorCompilation Condition=" $(NUMBER_OF_PROCESSORS) &gt; 4 ">true</MultiProcessorCompilation>
37 </ClCompile>
38 <ResourceCompile>
39 <PreprocessorDefinitions>$(ArmPreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
40 <AdditionalIncludeDirectories>$(ProjectAdditionalResourceIncludeDirectories);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
41 </ResourceCompile>
42 <Lib>
43 <AdditionalLibraryDirectories>$(OutDir);$(AdditionalMultiTargetLibraryPath);$(ProjectAdditionalLibraryDirectories);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
44 </Lib>
45 <Link>
46 <SubSystem>$(ProjectSubSystem)</SubSystem>
47 <ModuleDefinitionFile>$(ProjectModuleDefinitionFile)</ModuleDefinitionFile>
48 <NoEntryPoint>$(ResourceOnlyDll)</NoEntryPoint>
49 <GenerateDebugInformation>true</GenerateDebugInformation>
50 <AdditionalDependencies>$(ProjectAdditionalLinkLibraries);advapi32.lib;comdlg32.lib;user32.lib;oleaut32.lib;gdi32.lib;shell32.lib;ole32.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
51 <AdditionalLibraryDirectories>$(OutDir);$(AdditionalMultiTargetLibraryPath);$(ArmLibraryDirectories);$(ProjectAdditionalLinkLibraryDirectories);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
52 <AdditionalOptions Condition=" $(PlatformToolset.StartsWith('v14')) ">/IGNORE:4099 %(AdditionalOptions)</AdditionalOptions>
53 </Link>
54 </ItemDefinitionGroup>
55
56 <ItemDefinitionGroup Condition=" '$(Platform)'=='Win32' and '$(PlatformToolset)'!='v100'">
57 <ClCompile>
58 <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
59 </ClCompile>
60 </ItemDefinitionGroup>
61 <ItemDefinitionGroup Condition=" '$(Platform)'=='arm' ">
62 <ClCompile>
63 <CallingConvention>CDecl</CallingConvention>
64 </ClCompile>
65 </ItemDefinitionGroup>
66 <ItemDefinitionGroup Condition=" '$(ConfigurationType)'=='StaticLibrary' ">
67 <ClCompile>
68 <DebugInformationFormat>OldStyle</DebugInformationFormat>
69 <OmitDefaultLibName>true</OmitDefaultLibName>
70 <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
71 </ClCompile>
72 </ItemDefinitionGroup>
73 <ItemDefinitionGroup Condition=" '$(Configuration)'=='Debug' ">
74 <ClCompile>
75 <Optimization>Disabled</Optimization>
76 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
77 <PreprocessorDefinitions>_DEBUG;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
78 <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
79 </ClCompile>
80 </ItemDefinitionGroup>
81 <ItemDefinitionGroup Condition=" '$(Configuration)'=='Release' ">
82 <ClCompile>
83 <Optimization>MinSpace</Optimization>
84 <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
85 <FunctionLevelLinking>true</FunctionLevelLinking>
86 <IntrinsicFunctions>true</IntrinsicFunctions>
87 <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
88 </ClCompile>
89 <Link>
90 <EnableCOMDATFolding>true</EnableCOMDATFolding>
91 <OptimizeReferences>true</OptimizeReferences>
92 </Link>
93 </ItemDefinitionGroup>
94</Project>
diff --git a/src/ext/Bal/Custom.Build.props b/src/ext/Bal/Custom.Build.props
new file mode 100644
index 00000000..66e74d81
--- /dev/null
+++ b/src/ext/Bal/Custom.Build.props
@@ -0,0 +1,11 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
5 <PropertyGroup Condition="$(ProjectName.StartsWith('Example.')) And '$(MSBuildProjectExtension)'=='.csproj' ">
6 <OutputPath>$(OutputPath)examples\$(ProjectName)\</OutputPath>
7 </PropertyGroup>
8 <PropertyGroup Condition="$(ProjectName.StartsWith('Example.')) And '$(MSBuildProjectExtension)'=='.vcxproj' ">
9 <OutDir>$(OutDir)examples\$(ProjectName)\</OutDir>
10 </PropertyGroup>
11</Project>
diff --git a/src/ext/Bal/CustomizedNativeRecommendedRules.ruleset b/src/ext/Bal/CustomizedNativeRecommendedRules.ruleset
new file mode 100644
index 00000000..142b141c
--- /dev/null
+++ b/src/ext/Bal/CustomizedNativeRecommendedRules.ruleset
@@ -0,0 +1,8 @@
1<?xml version="1.0" encoding="utf-8"?>
2<RuleSet Name="Customized Microsoft Native Recommended Rules" Description="Microsoft Native Recommended Rules, -C26812" ToolsVersion="16.0">
3 <Include Path="nativerecommendedrules.ruleset" Action="Default" />
4 <Rules AnalyzerId="Microsoft.Analyzers.NativeCodeAnalysis" RuleNamespace="Microsoft.Rules.Native">
5 <!-- We need C style enums since we support BAs written in C -->
6 <Rule Id="C26812" Action="None" />
7 </Rules>
8</RuleSet> \ No newline at end of file
diff --git a/src/ext/Bal/Directory.Build.props b/src/ext/Bal/Directory.Build.props
new file mode 100644
index 00000000..f83cc154
--- /dev/null
+++ b/src/ext/Bal/Directory.Build.props
@@ -0,0 +1,29 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3<!--
4 Do NOT modify this file. Update the canonical version in Home\repo-template\src\Directory.Build.props
5 then update all of the repos.
6-->
7<Project>
8 <PropertyGroup>
9 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
10 <EnableSourceLink Condition=" '$(NCrunch)' == '1' ">false</EnableSourceLink>
11 <MSBuildWarningsAsMessages>MSB3246</MSBuildWarningsAsMessages>
12
13 <ProjectName Condition=" '$(ProjectName)' == '' ">$(MSBuildProjectName)</ProjectName>
14 <BaseOutputPath>$([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)..\build\))</BaseOutputPath>
15 <BaseIntermediateOutputPath>$(BaseOutputPath)obj\$(ProjectName)\</BaseIntermediateOutputPath>
16 <OutputPath>$(BaseOutputPath)$(Configuration)\</OutputPath>
17
18 <Authors>WiX Toolset Team</Authors>
19 <Company>WiX Toolset</Company>
20 <Copyright>Copyright (c) .NET Foundation and contributors. All rights reserved.</Copyright>
21 <PackageLicenseExpression>MS-RL</PackageLicenseExpression>
22 <Product>WiX Toolset</Product>
23 </PropertyGroup>
24
25 <Import Project="CSharp.Build.props" Condition=" '$(MSBuildProjectExtension)'=='.csproj' and Exists('CSharp.Build.props') " />
26 <Import Project="Cpp.Build.props" Condition=" Exists('Cpp.Build.props') And '$(MSBuildProjectExtension)'=='.vcxproj' " />
27 <Import Project="Wix.Build.props" Condition=" Exists('Wix.Build.props') And '$(MSBuildProjectExtension)'=='.wixproj' " />
28 <Import Project="Custom.Build.props" Condition=" Exists('Custom.Build.props') " />
29</Project>
diff --git a/src/ext/Bal/Directory.Build.targets b/src/ext/Bal/Directory.Build.targets
new file mode 100644
index 00000000..cb988931
--- /dev/null
+++ b/src/ext/Bal/Directory.Build.targets
@@ -0,0 +1,56 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3<!--
4 Do NOT modify this file. Update the canonical version in Home\repo-template\src\Directory.Build.targets
5 then update all of the repos.
6-->
7<!--
8 Replace PackageReferences with ProjectReferences when the projects can be found in .sln.
9 See the original here: https://github.com/dotnet/sdk/issues/1151#issuecomment-385133284
10-->
11<Project>
12 <PropertyGroup>
13 <CreateDocumentation Condition=" '$(CreateDocumentationFile)'!='true' ">false</CreateDocumentation>
14 <DocumentationFile Condition=" '$(CreateDocumentationFile)'=='true' ">$(OutputPath)\$(AssemblyName).xml</DocumentationFile>
15 </PropertyGroup>
16
17 <PropertyGroup>
18 <ReplacePackageReferences>true</ReplacePackageReferences>
19 <TheSolutionPath Condition=" '$(NCrunch)'=='' ">$(SolutionPath)</TheSolutionPath>
20 <TheSolutionPath Condition=" '$(NCrunch)'=='1' ">$(NCrunchOriginalSolutionPath)</TheSolutionPath>
21 </PropertyGroup>
22
23 <Choose>
24 <When Condition="$(ReplacePackageReferences) AND '$(TheSolutionPath)' != '' AND '$(TheSolutionPath)' != '*undefined*' AND Exists('$(TheSolutionPath)')">
25
26 <PropertyGroup>
27 <SolutionFileContent>$([System.IO.File]::ReadAllText($(TheSolutionPath)))</SolutionFileContent>
28 <SmartSolutionDir>$([System.IO.Path]::GetDirectoryName( $(TheSolutionPath) ))</SmartSolutionDir>
29 <RegexPattern>(?&lt;="[PackageName]", ")(.*)(?=", ")</RegexPattern>
30 </PropertyGroup>
31
32 <ItemGroup>
33 <!-- Keep the identity of the PackageReference -->
34 <SmartPackageReference Include="@(PackageReference)">
35 <PackageName>%(Identity)</PackageName>
36 <InSolution>$(SolutionFileContent.Contains('\%(Identity).csproj'))</InSolution>
37 </SmartPackageReference>
38
39 <!-- Filter them by mapping them to another ItemGroup using the WithMetadataValue item function -->
40 <PackageInSolution Include="@(SmartPackageReference->WithMetadataValue('InSolution', True))">
41 <Pattern>$(RegexPattern.Replace('[PackageName]','%(PackageName)') )</Pattern>
42 <SmartPath>$([System.Text.RegularExpressions.Regex]::Match('$(SolutionFileContent)', '%(Pattern)'))</SmartPath>
43 </PackageInSolution>
44
45 <ProjectReference Include="@(PackageInSolution->'$(SmartSolutionDir)\%(SmartPath)' )"/>
46
47 <!-- Remove the package references that are now referenced as projects -->
48 <PackageReference Remove="@(PackageInSolution->'%(PackageName)' )"/>
49 </ItemGroup>
50
51 </When>
52 </Choose>
53
54 <Import Project="Wix.Build.targets" Condition=" Exists('Wix.Build.targets') And '$(MSBuildProjectExtension)'=='.wixproj' " />
55 <Import Project="Custom.Build.targets" Condition=" Exists('Custom.Build.targets') " />
56</Project>
diff --git a/src/ext/Bal/README.md b/src/ext/Bal/README.md
new file mode 100644
index 00000000..cc5d9b34
--- /dev/null
+++ b/src/ext/Bal/README.md
@@ -0,0 +1,2 @@
1# Bal.wixext
2WixToolset.Bal.wixext - Bootstrapper Application Layer WiX Toolset Extension
diff --git a/src/ext/Bal/Samples/bafunctions/Readme.txt b/src/ext/Bal/Samples/bafunctions/Readme.txt
new file mode 100644
index 00000000..517d0d4c
--- /dev/null
+++ b/src/ext/Bal/Samples/bafunctions/Readme.txt
@@ -0,0 +1,85 @@
1
2This is a sample project showing how to create a BA function assembly.
3
4The four interfaces are in the WixSampleBAFunctions.cpp file.
5
6
7Example code:
8~~~~~~~~~~~~~
9
10
11 HRESULT hr = S_OK;
12 HKEY hkKey = NULL;
13 LPWSTR sczValue = NULL;
14 LPWSTR sczFormatedValue = NULL;
15
16
17 //---------------------------------------------------------------------------------------------
18 // Example of BA function failure
19 hr = E_NOTIMPL;
20 BalExitOnFailure(hr, "Test failure.");
21 //---------------------------------------------------------------------------------------------
22
23 //---------------------------------------------------------------------------------------------
24 // Example of setting a variables
25 hr = m_pEngine->SetVariableString(L"Variable1", L"String value");
26 BalExitOnFailure(hr, "Failed to set variable.");
27 hr = m_pEngine->SetVariableNumeric(L"Variable2", 1234);
28 BalExitOnFailure(hr, "Failed to set variable.");
29 //---------------------------------------------------------------------------------------------
30
31 //---------------------------------------------------------------------------------------------
32 // Example of reading burn variable.
33 BalGetStringVariable(L"WixBundleName", &sczValue);
34 BalExitOnFailure(hr, "Failed to get variable.");
35
36 hr = m_pEngine->SetVariableString(L"Variable4", sczValue);
37 BalExitOnFailure(hr, "Failed to set variable.");
38 //---------------------------------------------------------------------------------------------
39
40 ReleaseNullStr(sczValue); // Release string so it can be re-used
41
42 //---------------------------------------------------------------------------------------------
43 // Examples of reading burn variable and formatting it.
44 BalGetStringVariable(L"InstallFolder", &sczValue);
45 BalExitOnFailure(hr, "Failed to get variable.");
46
47 hr = m_pEngine->SetVariableString(L"Variable5", sczValue);
48 BalExitOnFailure(hr, "Failed to set variable.");
49
50 BalFormatString(sczValue, &sczFormatedValue);
51 BalExitOnFailure(hr, "Failed to format variable.");
52
53 hr = m_pEngine->SetVariableString(L"Variable6", sczFormatedValue);
54 BalExitOnFailure(hr, "Failed to set variable.");
55 //---------------------------------------------------------------------------------------------
56
57 ReleaseNullStr(sczValue); // Release string so it can be re-used
58
59 //---------------------------------------------------------------------------------------------
60 // Example of reading 64 bit registry and setting the InstallFolder variable to the value read.
61 hr = RegOpen(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v3.5", KEY_READ | KEY_WOW64_64KEY, &hkKey);
62 BalExitOnFailure(hr, "Failed to open registry key.");
63
64 hr = RegReadString(hkKey, L"InstallPath", &sczValue);
65 BalExitOnFailure(hr, "Failed to read registry value.");
66
67 // Example of function call
68 PathBackslashTerminate(&sczValue);
69
70 hr = m_pEngine->SetVariableString(L"InstallFolder", sczValue);
71 BalExitOnFailure(hr, "Failed to set variable.");
72 //---------------------------------------------------------------------------------------------
73
74 ReleaseNullStr(sczValue); // Release string so it can be re-used
75
76 //---------------------------------------------------------------------------------------------
77 // Example of calling a function that return HRESULT
78 hr = GetFileVersion();
79 BalExitOnFailure(hr, "Failed to get version.");
80 //---------------------------------------------------------------------------------------------
81
82 LExit:
83 ReleaseRegKey(hkKey);
84 ReleaseStr(sczValue);
85 ReleaseStr(sczFormatedValue);
diff --git a/src/ext/Bal/Samples/bafunctions/WixSampleBAFunctions.cpp b/src/ext/Bal/Samples/bafunctions/WixSampleBAFunctions.cpp
new file mode 100644
index 00000000..531b86a3
--- /dev/null
+++ b/src/ext/Bal/Samples/bafunctions/WixSampleBAFunctions.cpp
@@ -0,0 +1,95 @@
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 "BalBaseBAFunctions.h"
5#include "BalBaseBAFunctionsProc.h"
6
7class CWixSampleBAFunctions : public CBalBaseBAFunctions
8{
9public: // IBootstrapperApplication
10 virtual STDMETHODIMP OnDetectBegin(
11 __in BOOL fInstalled,
12 __in DWORD cPackages,
13 __inout BOOL* pfCancel
14 )
15 {
16 HRESULT hr = S_OK;
17
18 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Running detect begin BA function. fInstalled=%d, cPackages=%u, fCancel=%d", fInstalled, cPackages, *pfCancel);
19
20 //-------------------------------------------------------------------------------------------------
21 // YOUR CODE GOES HERE
22 BalExitOnFailure(hr, "Change this message to represent real error handling.");
23 //-------------------------------------------------------------------------------------------------
24
25 LExit:
26 return hr;
27 }
28
29public: // IBAFunctions
30 virtual STDMETHODIMP OnPlanBegin(
31 __in DWORD cPackages,
32 __inout BOOL* pfCancel
33 )
34 {
35 HRESULT hr = S_OK;
36
37 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Running plan begin BA function. cPackages=%u, fCancel=%d", cPackages, *pfCancel);
38
39 //-------------------------------------------------------------------------------------------------
40 // YOUR CODE GOES HERE
41 BalExitOnFailure(hr, "Change this message to represent real error handling.");
42 //-------------------------------------------------------------------------------------------------
43
44 LExit:
45 return hr;
46 }
47
48public:
49 //
50 // Constructor - initialize member variables.
51 //
52 CWixSampleBAFunctions(
53 __in HMODULE hModule,
54 __in IBootstrapperEngine* pEngine,
55 __in const BA_FUNCTIONS_CREATE_ARGS* pArgs
56 ) : CBalBaseBAFunctions(hModule, pEngine, pArgs)
57 {
58 }
59
60 //
61 // Destructor - release member variables.
62 //
63 ~CWixSampleBAFunctions()
64 {
65 }
66};
67
68
69HRESULT WINAPI CreateBAFunctions(
70 __in HMODULE hModule,
71 __in const BA_FUNCTIONS_CREATE_ARGS* pArgs,
72 __inout BA_FUNCTIONS_CREATE_RESULTS* pResults
73 )
74{
75 HRESULT hr = S_OK;
76 CWixSampleBAFunctions* pBAFunctions = NULL;
77 IBootstrapperEngine* pEngine = NULL;
78
79 // This is required to enable logging functions.
80 hr = BalInitializeFromCreateArgs(pArgs->pBootstrapperCreateArgs, &pEngine);
81 ExitOnFailure(hr, "Failed to initialize Bal.");
82
83 pBAFunctions = new CWixSampleBAFunctions(hModule, pEngine, pArgs);
84 ExitOnNull(pBAFunctions, hr, E_OUTOFMEMORY, "Failed to create new CWixSampleBAFunctions object.");
85
86 pResults->pfnBAFunctionsProc = BalBaseBAFunctionsProc;
87 pResults->pvBAFunctionsProcContext = pBAFunctions;
88 pBAFunctions = NULL;
89
90LExit:
91 ReleaseObject(pBAFunctions);
92 ReleaseObject(pEngine);
93
94 return hr;
95}
diff --git a/src/ext/Bal/Samples/bafunctions/bafunctions.cpp b/src/ext/Bal/Samples/bafunctions/bafunctions.cpp
new file mode 100644
index 00000000..b20f4230
--- /dev/null
+++ b/src/ext/Bal/Samples/bafunctions/bafunctions.cpp
@@ -0,0 +1,46 @@
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
5static HINSTANCE vhInstance = NULL;
6
7extern "C" BOOL WINAPI DllMain(
8 IN HINSTANCE hInstance,
9 IN DWORD dwReason,
10 IN LPVOID /* pvReserved */
11 )
12{
13 switch (dwReason)
14 {
15 case DLL_PROCESS_ATTACH:
16 ::DisableThreadLibraryCalls(hInstance);
17 vhInstance = hInstance;
18 break;
19
20 case DLL_PROCESS_DETACH:
21 vhInstance = NULL;
22 break;
23 }
24
25 return TRUE;
26}
27
28extern "C" HRESULT WINAPI BAFunctionsCreate(
29 __in const BA_FUNCTIONS_CREATE_ARGS* pArgs,
30 __inout BA_FUNCTIONS_CREATE_RESULTS* pResults
31 )
32{
33 HRESULT hr = S_OK;
34
35 hr = CreateBAFunctions(vhInstance, pArgs, pResults);
36 BalExitOnFailure(hr, "Failed to create BAFunctions interface.");
37
38LExit:
39 return hr;
40}
41
42extern "C" void WINAPI BAFunctionsDestroy(
43 )
44{
45 BalUninitialize();
46}
diff --git a/src/ext/Bal/Samples/bafunctions/bafunctions.def b/src/ext/Bal/Samples/bafunctions/bafunctions.def
new file mode 100644
index 00000000..6e016dad
--- /dev/null
+++ b/src/ext/Bal/Samples/bafunctions/bafunctions.def
@@ -0,0 +1,6 @@
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
4EXPORTS
5 BAFunctionsCreate
6 BAFunctionsDestroy
diff --git a/src/ext/Bal/Samples/bafunctions/bafunctions.vcxproj b/src/ext/Bal/Samples/bafunctions/bafunctions.vcxproj
new file mode 100644
index 00000000..640c812d
--- /dev/null
+++ b/src/ext/Bal/Samples/bafunctions/bafunctions.vcxproj
@@ -0,0 +1,81 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
5 <Import Project="..\..\..\packages\WixToolset.BalUtil.4.0.58\build\WixToolset.BalUtil.props" Condition="Exists('..\..\..\packages\WixToolset.BalUtil.4.0.58\build\WixToolset.BalUtil.props')" />
6 <Import Project="..\..\..\packages\WixToolset.BootstrapperCore.Native.4.0.141\build\WixToolset.BootstrapperCore.Native.props" Condition="Exists('..\..\..\packages\WixToolset.BootstrapperCore.Native.4.0.141\build\WixToolset.BootstrapperCore.Native.props')" />
7 <Import Project="..\..\..\packages\WixToolset.DUtil.4.0.72\build\WixToolset.DUtil.props" Condition="Exists('..\..\..\packages\WixToolset.DUtil.4.0.72\build\WixToolset.DUtil.props')" />
8
9 <ItemGroup Label="ProjectConfigurations">
10 <ProjectConfiguration Include="Debug|ARM64">
11 <Configuration>Debug</Configuration>
12 <Platform>ARM64</Platform>
13 </ProjectConfiguration>
14 <ProjectConfiguration Include="Release|ARM64">
15 <Configuration>Release</Configuration>
16 <Platform>ARM64</Platform>
17 </ProjectConfiguration>
18 <ProjectConfiguration Include="Debug|Win32">
19 <Configuration>Debug</Configuration>
20 <Platform>Win32</Platform>
21 </ProjectConfiguration>
22 <ProjectConfiguration Include="Release|Win32">
23 <Configuration>Release</Configuration>
24 <Platform>Win32</Platform>
25 </ProjectConfiguration>
26 <ProjectConfiguration Include="Debug|x64">
27 <Configuration>Debug</Configuration>
28 <Platform>x64</Platform>
29 </ProjectConfiguration>
30 <ProjectConfiguration Include="Release|x64">
31 <Configuration>Release</Configuration>
32 <Platform>x64</Platform>
33 </ProjectConfiguration>
34 </ItemGroup>
35
36 <PropertyGroup Label="Globals">
37 <ProjectGuid>{EB0A7D51-2133-4EE7-B6CA-87DBEAC67E02}</ProjectGuid>
38 <ConfigurationType>DynamicLibrary</ConfigurationType>
39 <PlatformToolset>v142</PlatformToolset>
40 <CharacterSet>Unicode</CharacterSet>
41 <TargetName>BAFunctions</TargetName>
42 <ProjectModuleDefinitionFile>bafunctions.def</ProjectModuleDefinitionFile>
43 </PropertyGroup>
44
45 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
46 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
47
48 <PropertyGroup>
49 <ProjectAdditionalLinkLibraries>comctl32.lib;gdiplus.lib;msimg32.lib;shlwapi.lib;wininet.lib</ProjectAdditionalLinkLibraries>
50 </PropertyGroup>
51 <ItemGroup>
52 <ClCompile Include="WixSampleBAFunctions.cpp" />
53 <ClCompile Include="bafunctions.cpp">
54 <PrecompiledHeader>Create</PrecompiledHeader>
55 </ClCompile>
56 </ItemGroup>
57 <ItemGroup>
58 <ClInclude Include="precomp.h" />
59 <ClInclude Include="resource.h" />
60 </ItemGroup>
61 <ItemGroup>
62 <None Include="bafunctions.def" />
63 <None Include="Readme.txt" />
64 </ItemGroup>
65
66 <ItemGroup>
67 <None Include="packages.config" />
68 </ItemGroup>
69
70 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
71 <Import Project="..\..\..\packages\Nerdbank.GitVersioning.3.3.37\build\Nerdbank.GitVersioning.targets" Condition="Exists('..\..\..\packages\Nerdbank.GitVersioning.3.3.37\build\Nerdbank.GitVersioning.targets')" />
72 <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
73 <PropertyGroup>
74 <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>
75 </PropertyGroup>
76 <Error Condition="!Exists('..\..\..\packages\WixToolset.BalUtil.4.0.58\build\WixToolset.BalUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\WixToolset.BalUtil.4.0.58\build\WixToolset.BalUtil.props'))" />
77 <Error Condition="!Exists('..\..\..\packages\WixToolset.BootstrapperCore.Native.4.0.141\build\WixToolset.BootstrapperCore.Native.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\WixToolset.BootstrapperCore.Native.4.0.141\build\WixToolset.BootstrapperCore.Native.props'))" />
78 <Error Condition="!Exists('..\..\..\packages\WixToolset.DUtil.4.0.72\build\WixToolset.DUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\WixToolset.DUtil.4.0.72\build\WixToolset.DUtil.props'))" />
79 <Error Condition="!Exists('..\..\..\packages\Nerdbank.GitVersioning.3.3.37\build\Nerdbank.GitVersioning.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Nerdbank.GitVersioning.3.3.37\build\Nerdbank.GitVersioning.targets'))" />
80 </Target>
81</Project>
diff --git a/src/ext/Bal/Samples/bafunctions/packages.config b/src/ext/Bal/Samples/bafunctions/packages.config
new file mode 100644
index 00000000..548ddb48
--- /dev/null
+++ b/src/ext/Bal/Samples/bafunctions/packages.config
@@ -0,0 +1,7 @@
1<?xml version="1.0" encoding="utf-8"?>
2<packages>
3 <package id="Nerdbank.GitVersioning" version="3.3.37" targetFramework="native" developmentDependency="true" />
4 <package id="WixToolset.BootstrapperCore.Native" version="4.0.141" targetFramework="native" />
5 <package id="WixToolset.BalUtil" version="4.0.58" targetFramework="native" />
6 <package id="WixToolset.DUtil" version="4.0.72" targetFramework="native" />
7</packages> \ No newline at end of file
diff --git a/src/ext/Bal/Samples/bafunctions/precomp.h b/src/ext/Bal/Samples/bafunctions/precomp.h
new file mode 100644
index 00000000..9d2fe726
--- /dev/null
+++ b/src/ext/Bal/Samples/bafunctions/precomp.h
@@ -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#include <windows.h>
6
7#pragma warning(push)
8#pragma warning(disable:4458) // declaration of 'xxx' hides class member
9#include <gdiplus.h>
10#pragma warning(pop)
11
12#include <msiquery.h>
13#include <objbase.h>
14#include <shlobj.h>
15#include <shlwapi.h>
16#include <stdlib.h>
17#include <strsafe.h>
18#include <CommCtrl.h>
19
20// Standard WiX header files, include as required
21#include "dutil.h"
22//#include "memutil.h"
23//#include "dictutil.h"
24//#include "dirutil.h"
25#include "fileutil.h"
26#include "locutil.h"
27//#include "logutil.h"
28#include "pathutil.h"
29//#include "resrutil.h"
30//#include "shelutil.h"
31#include "strutil.h"
32#include "thmutil.h"
33//#include "uriutil.h"
34//#include "xmlutil.h"
35#include "regutil.h"
36
37//#include "IBootstrapperEngine.h"
38//#include "IBootstrapperApplication.h"
39
40#include "BalBaseBootstrapperApplication.h"
41//#include "balinfo.h"
42//#include "balcondition.h"
43#include "balutil.h"
44
45#include "BAFunctions.h"
46#include "IBAFunctions.h"
47
48HRESULT WINAPI CreateBAFunctions(
49 __in HMODULE hModule,
50 __in const BA_FUNCTIONS_CREATE_ARGS* pArgs,
51 __inout BA_FUNCTIONS_CREATE_RESULTS* pResults
52 );
diff --git a/src/ext/Bal/Samples/bafunctions/resource.h b/src/ext/Bal/Samples/bafunctions/resource.h
new file mode 100644
index 00000000..149a8ff4
--- /dev/null
+++ b/src/ext/Bal/Samples/bafunctions/resource.h
@@ -0,0 +1,15 @@
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#define IDC_STATIC -1
4
5
6// Next default values for new objects
7//
8#ifdef APSTUDIO_INVOKED
9#ifndef APSTUDIO_READONLY_SYMBOLS
10#define _APS_NEXT_RESOURCE_VALUE 102
11#define _APS_NEXT_COMMAND_VALUE 40001
12#define _APS_NEXT_CONTROL_VALUE 1003
13#define _APS_NEXT_SYMED_VALUE 101
14#endif
15#endif
diff --git a/src/ext/Bal/WixToolset.Dnc.Host/BootstrapperApplicationFactory.cs b/src/ext/Bal/WixToolset.Dnc.Host/BootstrapperApplicationFactory.cs
new file mode 100644
index 00000000..d38fd1a9
--- /dev/null
+++ b/src/ext/Bal/WixToolset.Dnc.Host/BootstrapperApplicationFactory.cs
@@ -0,0 +1,89 @@
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
3namespace WixToolset.Dnc.Host
4{
5 using System;
6 using System.Linq;
7 using System.Reflection;
8 using System.Runtime.InteropServices;
9
10 delegate IBootstrapperApplicationFactory StaticEntryDelegate([MarshalAs(UnmanagedType.LPWStr)] string baFactoryAssemblyName, [MarshalAs(UnmanagedType.LPWStr)] string baFactoryAssemblyPath);
11
12 /// <summary>
13 /// Entry point for the .NET Core host to create and return the BA to the engine.
14 /// Reflection is used instead of referencing WixToolset.Mba.Core directly to avoid requiring it in the AssemblyLoadContext.
15 /// </summary>
16 public sealed class BootstrapperApplicationFactory : IBootstrapperApplicationFactory
17 {
18 private string baFactoryAssemblyName;
19 private string baFactoryAssemblyPath;
20
21 public BootstrapperApplicationFactory(string baFactoryAssemblyName, string baFactoryAssemblyPath)
22 {
23 this.baFactoryAssemblyName = baFactoryAssemblyName;
24 this.baFactoryAssemblyPath = baFactoryAssemblyPath;
25 }
26
27 /// <summary>
28 /// Loads the bootstrapper application assembly and calls its IBootstrapperApplicationFactory.Create method.
29 /// </summary>
30 /// <param name="pArgs">Pointer to BOOTSTRAPPER_CREATE_ARGS struct.</param>
31 /// <param name="pResults">Pointer to BOOTSTRAPPER_CREATE_RESULTS struct.</param>
32 /// <exception cref="MissingAttributeException">The bootstrapper application assembly
33 /// does not define the <see cref="BootstrapperApplicationFactoryAttribute"/>.</exception>
34 public void Create(IntPtr pArgs, IntPtr pResults)
35 {
36 // Load the BA's IBootstrapperApplicationFactory.
37 var baFactoryType = BootstrapperApplicationFactory.GetBAFactoryTypeFromAssembly(this.baFactoryAssemblyName, this.baFactoryAssemblyPath);
38 var baFactory = Activator.CreateInstance(baFactoryType);
39 if (null == baFactory)
40 {
41 throw new InvalidBootstrapperApplicationFactoryException();
42 }
43
44 var createMethod = baFactoryType.GetMethod(nameof(Create), new[] { typeof(IntPtr), typeof(IntPtr) });
45 if (null == createMethod)
46 {
47 throw new InvalidBootstrapperApplicationFactoryException();
48 }
49 createMethod.Invoke(baFactory, new object[] { pArgs, pResults });
50 }
51
52 /// <summary>
53 /// Locates the <see cref="BootstrapperApplicationFactoryAttribute"/> and returns the specified type.
54 /// </summary>
55 /// <param name="assemblyName">The assembly that defines the IBootstrapperApplicationFactory implementation.</param>
56 /// <returns>The bootstrapper application factory <see cref="Type"/>.</returns>
57 private static Type GetBAFactoryTypeFromAssembly(string assemblyName, string assemblyPath)
58 {
59 // The default ALC shouldn't need help loading the assembly, since the host should have provided the deps.json
60 // when starting the runtime. But it doesn't hurt so keep this in case an isolated ALC is ever needed.
61 var alc = new DnchostAssemblyLoadContext(assemblyPath, false);
62 var asm = alc.LoadFromAssemblyName(new AssemblyName(assemblyName));
63
64 var attr = asm.GetCustomAttributes()
65 .Where(a => a.GetType().FullName == "WixToolset.Mba.Core.BootstrapperApplicationFactoryAttribute")
66 .SingleOrDefault();
67
68 if (null == attr)
69 {
70 throw new MissingAttributeException();
71 }
72
73 var baFactoryTypeProperty = attr.GetType().GetProperty("BootstrapperApplicationFactoryType", typeof(Type));
74 if (baFactoryTypeProperty == null || baFactoryTypeProperty.GetMethod == null)
75 {
76 throw new MissingAttributeException();
77 }
78
79 var baFactoryType = (Type)baFactoryTypeProperty.GetMethod.Invoke(attr, null);
80 return baFactoryType;
81 }
82
83 // Entry point for the DNC host.
84 public static IBootstrapperApplicationFactory CreateBAFactory([MarshalAs(UnmanagedType.LPWStr)] string baFactoryAssemblyName, [MarshalAs(UnmanagedType.LPWStr)] string baFactoryAssemblyPath)
85 {
86 return new BootstrapperApplicationFactory(baFactoryAssemblyName, baFactoryAssemblyPath);
87 }
88 }
89}
diff --git a/src/ext/Bal/WixToolset.Dnc.Host/DnchostAssemblyLoadContext.cs b/src/ext/Bal/WixToolset.Dnc.Host/DnchostAssemblyLoadContext.cs
new file mode 100644
index 00000000..1a383058
--- /dev/null
+++ b/src/ext/Bal/WixToolset.Dnc.Host/DnchostAssemblyLoadContext.cs
@@ -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
3namespace WixToolset.Dnc.Host
4{
5 using System;
6 using System.Reflection;
7 using System.Runtime.Loader;
8
9 public sealed class DnchostAssemblyLoadContext : AssemblyLoadContext
10 {
11 private readonly AssemblyDependencyResolver resolver;
12
13 public DnchostAssemblyLoadContext(string assemblyPath, bool isolateFromDefault)
14 : base(nameof(DnchostAssemblyLoadContext), isolateFromDefault)
15 {
16 this.resolver = new AssemblyDependencyResolver(assemblyPath);
17
18 if (!this.IsCollectible)
19 {
20 AssemblyLoadContext.Default.Resolving += this.ResolveAssembly;
21 AssemblyLoadContext.Default.ResolvingUnmanagedDll += this.ResolveUnmanagedDll;
22 }
23 }
24
25 private Assembly ResolveAssembly(AssemblyLoadContext defaultAlc, AssemblyName assemblyName)
26 {
27 var path = this.resolver.ResolveAssemblyToPath(assemblyName);
28 if (path != null)
29 {
30 var targetAlc = this.IsCollectible ? this : defaultAlc;
31 return targetAlc.LoadFromAssemblyPath(path);
32 }
33
34 return null;
35 }
36
37 private IntPtr ResolveUnmanagedDll(Assembly assembly, string unmanagedDllName)
38 {
39 var path = this.resolver.ResolveUnmanagedDllToPath(unmanagedDllName);
40 if (path != null)
41 {
42 return this.LoadUnmanagedDllFromPath(path);
43 }
44
45 return IntPtr.Zero;
46 }
47
48 protected override Assembly Load(AssemblyName assemblyName)
49 {
50 return this.ResolveAssembly(AssemblyLoadContext.Default, assemblyName);
51 }
52
53 protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
54 {
55 return this.ResolveUnmanagedDll(null, unmanagedDllName);
56 }
57 }
58}
diff --git a/src/ext/Bal/WixToolset.Dnc.Host/Exceptions.cs b/src/ext/Bal/WixToolset.Dnc.Host/Exceptions.cs
new file mode 100644
index 00000000..32d4d4c5
--- /dev/null
+++ b/src/ext/Bal/WixToolset.Dnc.Host/Exceptions.cs
@@ -0,0 +1,145 @@
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
3namespace WixToolset.Dnc.Host
4{
5 using System;
6 using System.Runtime.Serialization;
7
8 /// <summary>
9 /// Base class for exception returned to the bootstrapper application host.
10 /// </summary>
11 [Serializable]
12 public abstract class BootstrapperException : Exception
13 {
14 /// <summary>
15 /// Creates an instance of the <see cref="BootstrapperException"/> base class with the given HRESULT.
16 /// </summary>
17 /// <param name="hr">The HRESULT for the exception that is used by the bootstrapper application host.</param>
18 public BootstrapperException(int hr)
19 {
20 this.HResult = hr;
21 }
22
23 /// <summary>
24 /// Initializes a new instance of the <see cref="BootstrapperException"/> class.
25 /// </summary>
26 /// <param name="message">Exception message.</param>
27 public BootstrapperException(string message)
28 : base(message)
29 {
30 }
31
32 /// <summary>
33 /// Initializes a new instance of the <see cref="BootstrapperException"/> class.
34 /// </summary>
35 /// <param name="message">Exception message</param>
36 /// <param name="innerException">Inner exception associated with this one</param>
37 public BootstrapperException(string message, Exception innerException)
38 : base(message, innerException)
39 {
40 }
41
42 /// <summary>
43 /// Initializes a new instance of the <see cref="BootstrapperException"/> class.
44 /// </summary>
45 /// <param name="info">Serialization information for this exception</param>
46 /// <param name="context">Streaming context to serialize to</param>
47 protected BootstrapperException(SerializationInfo info, StreamingContext context)
48 : base(info, context)
49 {
50 }
51 }
52
53 /// <summary>
54 /// The bootstrapper application assembly loaded by the host does not contain exactly one instance of the
55 /// <see cref="Core.BootstrapperApplicationFactoryAttribute"/> class.
56 /// </summary>
57 /// <seealso cref="Core.BootstrapperApplicationFactoryAttribute"/>
58 [Serializable]
59 public class MissingAttributeException : BootstrapperException
60 {
61 /// <summary>
62 /// Creates a new instance of the <see cref="MissingAttributeException"/> class.
63 /// </summary>
64 public MissingAttributeException()
65 : base(NativeMethods.E_NOTFOUND)
66 {
67 }
68
69 /// <summary>
70 /// Initializes a new instance of the <see cref="MissingAttributeException"/> class.
71 /// </summary>
72 /// <param name="message">Exception message.</param>
73 public MissingAttributeException(string message)
74 : base(message)
75 {
76 }
77
78 /// <summary>
79 /// Initializes a new instance of the <see cref="MissingAttributeException"/> class.
80 /// </summary>
81 /// <param name="message">Exception message</param>
82 /// <param name="innerException">Inner exception associated with this one</param>
83 public MissingAttributeException(string message, Exception innerException)
84 : base(message, innerException)
85 {
86 }
87
88 /// <summary>
89 /// Initializes a new instance of the <see cref="MissingAttributeException"/> class.
90 /// </summary>
91 /// <param name="info">Serialization information for this exception</param>
92 /// <param name="context">Streaming context to serialize to</param>
93 protected MissingAttributeException(SerializationInfo info, StreamingContext context)
94 : base(info, context)
95 {
96 }
97 }
98
99 /// <summary>
100 /// The bootstrapper application factory specified by the <see cref="Core.BootstrapperApplicationFactoryAttribute"/>
101 /// does not extend the <see cref="Core.IBootstrapperApplicationFactory"/> base class.
102 /// </summary>
103 /// <seealso cref="Core.BaseBootstrapperApplicationFactory"/>
104 /// <seealso cref="Core.BootstrapperApplicationFactoryAttribute"/>
105 [Serializable]
106 public class InvalidBootstrapperApplicationFactoryException : BootstrapperException
107 {
108 /// <summary>
109 /// Creates a new instance of the <see cref="InvalidBootstrapperApplicationFactoryException"/> class.
110 /// </summary>
111 public InvalidBootstrapperApplicationFactoryException()
112 : base(NativeMethods.E_UNEXPECTED)
113 {
114 }
115
116 /// <summary>
117 /// Initializes a new instance of the <see cref="InvalidBootstrapperApplicationFactoryException"/> class.
118 /// </summary>
119 /// <param name="message">Exception message.</param>
120 public InvalidBootstrapperApplicationFactoryException(string message)
121 : base(message)
122 {
123 }
124
125 /// <summary>
126 /// Initializes a new instance of the <see cref="InvalidBootstrapperApplicationFactoryException"/> class.
127 /// </summary>
128 /// <param name="message">Exception message</param>
129 /// <param name="innerException">Inner exception associated with this one</param>
130 public InvalidBootstrapperApplicationFactoryException(string message, Exception innerException)
131 : base(message, innerException)
132 {
133 }
134
135 /// <summary>
136 /// Initializes a new instance of the <see cref="InvalidBootstrapperApplicationFactoryException"/> class.
137 /// </summary>
138 /// <param name="info">Serialization information for this exception</param>
139 /// <param name="context">Streaming context to serialize to</param>
140 protected InvalidBootstrapperApplicationFactoryException(SerializationInfo info, StreamingContext context)
141 : base(info, context)
142 {
143 }
144 }
145}
diff --git a/src/ext/Bal/WixToolset.Dnc.Host/IBootstrapperApplicationFactory.cs b/src/ext/Bal/WixToolset.Dnc.Host/IBootstrapperApplicationFactory.cs
new file mode 100644
index 00000000..96731192
--- /dev/null
+++ b/src/ext/Bal/WixToolset.Dnc.Host/IBootstrapperApplicationFactory.cs
@@ -0,0 +1,16 @@
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
3namespace WixToolset.Dnc.Host
4{
5 using System;
6 using System.Runtime.InteropServices;
7
8 [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
9 public interface IBootstrapperApplicationFactory
10 {
11 void Create(
12 IntPtr pArgs,
13 IntPtr pResults
14 );
15 }
16}
diff --git a/src/ext/Bal/WixToolset.Dnc.Host/NativeMethods.cs b/src/ext/Bal/WixToolset.Dnc.Host/NativeMethods.cs
new file mode 100644
index 00000000..6dc393c6
--- /dev/null
+++ b/src/ext/Bal/WixToolset.Dnc.Host/NativeMethods.cs
@@ -0,0 +1,18 @@
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
3namespace WixToolset.Dnc.Host
4{
5 using System;
6 using System.Runtime.InteropServices;
7
8 /// <summary>
9 /// Contains native constants, functions, and structures for this assembly.
10 /// </summary>
11 internal static class NativeMethods
12 {
13 #region Error Constants
14 internal const int E_NOTFOUND = unchecked((int)0x80070490);
15 internal const int E_UNEXPECTED = unchecked((int)0x8000ffff);
16 #endregion
17 }
18}
diff --git a/src/ext/Bal/WixToolset.Dnc.Host/WixToolset.Dnc.Host.csproj b/src/ext/Bal/WixToolset.Dnc.Host/WixToolset.Dnc.Host.csproj
new file mode 100644
index 00000000..f347ca0b
--- /dev/null
+++ b/src/ext/Bal/WixToolset.Dnc.Host/WixToolset.Dnc.Host.csproj
@@ -0,0 +1,44 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4<Project Sdk="Microsoft.NET.Sdk">
5 <PropertyGroup>
6 <TargetFramework>netcoreapp3.1</TargetFramework>
7 <RootNamespace>WixToolset.Dnc.Host</RootNamespace>
8 <Description>WiX Toolset .NET Core BA Host</Description>
9 <Title>WiX Toolset .NET Core BA Host</Title>
10 <DebugType>embedded</DebugType>
11 <PlatformTarget>AnyCPU</PlatformTarget>
12 </PropertyGroup>
13
14 <ItemGroup>
15 <HeaderPath Include="$(BaseOutputPath)obj\$(AssemblyName).h">
16 <Visible>False</Visible>
17 </HeaderPath>
18 </ItemGroup>
19
20 <Target Name="GenerateIdentityHeader" AfterTargets="Build" Inputs="$(TargetPath)" Outputs="@(HeaderPath)">
21 <GetAssemblyIdentity AssemblyFiles="$(TargetPath)">
22 <Output TaskParameter="Assemblies" ItemName="AssemblyIdentity" />
23 </GetAssemblyIdentity>
24 <ItemGroup>
25 <Line Include='#define DNC_ASSEMBLY_FILE_NAME L"$(AssemblyName).dll"' />
26 <Line Include='#define DNC_ASSEMBLY_FULL_NAME "%(AssemblyIdentity.Identity)"' />
27 <Line Include='#define DNC_ENTRY_TYPE "$(RootNamespace).BootstrapperApplicationFactory"' />
28 <Line Include='#define DNC_ENTRY_TYPEW L"$(RootNamespace).BootstrapperApplicationFactory,$(AssemblyName)"' />
29 <Line Include='#define DNC_STATIC_ENTRY_METHOD "CreateBAFactory"' />
30 <Line Include='#define DNC_STATIC_ENTRY_METHODW L"CreateBAFactory"' />
31 <Line Include='#define DNC_STATIC_ENTRY_DELEGATEW L"$(RootNamespace).StaticEntryDelegate,$(AssemblyName)"' />
32 </ItemGroup>
33 <Message Importance="normal" Text="Generating identity definitions into @(HeaderPath->'%(FullPath)')" />
34 <WriteLinesToFile File="@(HeaderPath)" Lines="@(Line)" Overwrite="True" />
35 <ItemGroup>
36 <FileWrites Include="@(HeaderPath)" />
37 </ItemGroup>
38 </Target>
39
40 <ItemGroup>
41 <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="all" />
42 <PackageReference Include="Nerdbank.GitVersioning" Version="3.3.37" PrivateAssets="all" />
43 </ItemGroup>
44</Project>
diff --git a/src/ext/Bal/WixToolset.Mba.Host/BootstrapperApplicationFactory.cs b/src/ext/Bal/WixToolset.Mba.Host/BootstrapperApplicationFactory.cs
new file mode 100644
index 00000000..78e68bd9
--- /dev/null
+++ b/src/ext/Bal/WixToolset.Mba.Host/BootstrapperApplicationFactory.cs
@@ -0,0 +1,86 @@
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
3namespace WixToolset.Mba.Host
4{
5 using System;
6 using System.Configuration;
7 using System.Reflection;
8 using System.Runtime.InteropServices;
9 using WixToolset.Mba.Core;
10
11 /// <summary>
12 /// Entry point for the managed host to create and return the BA to the engine.
13 /// </summary>
14 [ClassInterface(ClassInterfaceType.None)]
15 public sealed class BootstrapperApplicationFactory : MarshalByRefObject, IBootstrapperApplicationFactory
16 {
17 /// <summary>
18 /// Creates a new instance of the <see cref="BootstrapperApplicationFactory"/> class.
19 /// Entry point for the MBA host.
20 /// </summary>
21 public BootstrapperApplicationFactory()
22 {
23 }
24
25 /// <summary>
26 /// Loads the bootstrapper application assembly and calls its IBootstrapperApplicationFactory.Create method.
27 /// </summary>
28 /// <param name="pArgs">Pointer to BOOTSTRAPPER_CREATE_ARGS struct.</param>
29 /// <param name="pResults">Pointer to BOOTSTRAPPER_CREATE_RESULTS struct.</param>
30 /// <exception cref="MissingAttributeException">The bootstrapper application assembly
31 /// does not define the <see cref="BootstrapperApplicationFactoryAttribute"/>.</exception>
32 public void Create(IntPtr pArgs, IntPtr pResults)
33 {
34 // Get the wix.boostrapper section group to get the name of the bootstrapper application assembly to host.
35 var section = ConfigurationManager.GetSection("wix.bootstrapper/host") as HostSection;
36 if (null == section)
37 {
38 throw new MissingAttributeException(); // TODO: throw a more specific exception than this.
39 }
40
41 // Load the BA's IBootstrapperApplicationFactory.
42 var baFactoryType = BootstrapperApplicationFactory.GetBAFactoryTypeFromAssembly(section.AssemblyName);
43 var baFactory = (IBootstrapperApplicationFactory)Activator.CreateInstance(baFactoryType);
44 if (null == baFactory)
45 {
46 throw new InvalidBootstrapperApplicationFactoryException();
47 }
48
49 baFactory.Create(pArgs, pResults);
50 }
51
52 /// <summary>
53 /// Locates the <see cref="BootstrapperApplicationFactoryAttribute"/> and returns the specified type.
54 /// </summary>
55 /// <param name="assemblyName">The assembly that defines the IBootstrapperApplicationFactory implementation.</param>
56 /// <returns>The bootstrapper application factory <see cref="Type"/>.</returns>
57 private static Type GetBAFactoryTypeFromAssembly(string assemblyName)
58 {
59 Type baFactoryType = null;
60
61 // Load the requested assembly.
62 Assembly asm = AppDomain.CurrentDomain.Load(assemblyName);
63
64 // If an assembly was loaded and is not the current assembly, check for the required attribute.
65 // This is done to avoid using the BootstrapperApplicationFactoryAttribute which we use at build time
66 // to specify the BootstrapperApplicationFactory assembly in the manifest.
67 if (!Assembly.GetExecutingAssembly().Equals(asm))
68 {
69 // There must be one and only one BootstrapperApplicationFactoryAttribute.
70 // The attribute prevents multiple declarations already.
71 var attrs = (BootstrapperApplicationFactoryAttribute[])asm.GetCustomAttributes(typeof(BootstrapperApplicationFactoryAttribute), false);
72 if (null != attrs)
73 {
74 baFactoryType = attrs[0].BootstrapperApplicationFactoryType;
75 }
76 }
77
78 if (null == baFactoryType)
79 {
80 throw new MissingAttributeException();
81 }
82
83 return baFactoryType;
84 }
85 }
86}
diff --git a/src/ext/Bal/WixToolset.Mba.Host/BootstrapperSectionGroup.cs b/src/ext/Bal/WixToolset.Mba.Host/BootstrapperSectionGroup.cs
new file mode 100644
index 00000000..5cf1bc9c
--- /dev/null
+++ b/src/ext/Bal/WixToolset.Mba.Host/BootstrapperSectionGroup.cs
@@ -0,0 +1,29 @@
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
3namespace WixToolset.Mba.Host
4{
5 using System;
6 using System.Configuration;
7
8 /// <summary>
9 /// Handler for the wix.bootstrapper configuration section group.
10 /// </summary>
11 public class BootstrapperSectionGroup : ConfigurationSectionGroup
12 {
13 /// <summary>
14 /// Creates a new instance of the <see cref="BootstrapperSectionGroup"/> class.
15 /// </summary>
16 public BootstrapperSectionGroup()
17 {
18 }
19
20 /// <summary>
21 /// Gets the <see cref="HostSection"/> handler for the mba configuration section.
22 /// </summary>
23 [ConfigurationProperty("host")]
24 public HostSection Host
25 {
26 get { return (HostSection)base.Sections["host"]; }
27 }
28 }
29}
diff --git a/src/ext/Bal/WixToolset.Mba.Host/Exceptions.cs b/src/ext/Bal/WixToolset.Mba.Host/Exceptions.cs
new file mode 100644
index 00000000..c68951f0
--- /dev/null
+++ b/src/ext/Bal/WixToolset.Mba.Host/Exceptions.cs
@@ -0,0 +1,145 @@
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
3namespace WixToolset.Mba.Host
4{
5 using System;
6 using System.Runtime.Serialization;
7
8 /// <summary>
9 /// Base class for exception returned to the bootstrapper application host.
10 /// </summary>
11 [Serializable]
12 public abstract class BootstrapperException : Exception
13 {
14 /// <summary>
15 /// Creates an instance of the <see cref="BootstrapperException"/> base class with the given HRESULT.
16 /// </summary>
17 /// <param name="hr">The HRESULT for the exception that is used by the bootstrapper application host.</param>
18 public BootstrapperException(int hr)
19 {
20 this.HResult = hr;
21 }
22
23 /// <summary>
24 /// Initializes a new instance of the <see cref="BootstrapperException"/> class.
25 /// </summary>
26 /// <param name="message">Exception message.</param>
27 public BootstrapperException(string message)
28 : base(message)
29 {
30 }
31
32 /// <summary>
33 /// Initializes a new instance of the <see cref="BootstrapperException"/> class.
34 /// </summary>
35 /// <param name="message">Exception message</param>
36 /// <param name="innerException">Inner exception associated with this one</param>
37 public BootstrapperException(string message, Exception innerException)
38 : base(message, innerException)
39 {
40 }
41
42 /// <summary>
43 /// Initializes a new instance of the <see cref="BootstrapperException"/> class.
44 /// </summary>
45 /// <param name="info">Serialization information for this exception</param>
46 /// <param name="context">Streaming context to serialize to</param>
47 protected BootstrapperException(SerializationInfo info, StreamingContext context)
48 : base(info, context)
49 {
50 }
51 }
52
53 /// <summary>
54 /// The bootstrapper application assembly loaded by the host does not contain exactly one instance of the
55 /// <see cref="Core.BootstrapperApplicationFactoryAttribute"/> class.
56 /// </summary>
57 /// <seealso cref="Core.BootstrapperApplicationFactoryAttribute"/>
58 [Serializable]
59 public class MissingAttributeException : BootstrapperException
60 {
61 /// <summary>
62 /// Creates a new instance of the <see cref="MissingAttributeException"/> class.
63 /// </summary>
64 public MissingAttributeException()
65 : base(NativeMethods.E_NOTFOUND)
66 {
67 }
68
69 /// <summary>
70 /// Initializes a new instance of the <see cref="MissingAttributeException"/> class.
71 /// </summary>
72 /// <param name="message">Exception message.</param>
73 public MissingAttributeException(string message)
74 : base(message)
75 {
76 }
77
78 /// <summary>
79 /// Initializes a new instance of the <see cref="MissingAttributeException"/> class.
80 /// </summary>
81 /// <param name="message">Exception message</param>
82 /// <param name="innerException">Inner exception associated with this one</param>
83 public MissingAttributeException(string message, Exception innerException)
84 : base(message, innerException)
85 {
86 }
87
88 /// <summary>
89 /// Initializes a new instance of the <see cref="MissingAttributeException"/> class.
90 /// </summary>
91 /// <param name="info">Serialization information for this exception</param>
92 /// <param name="context">Streaming context to serialize to</param>
93 protected MissingAttributeException(SerializationInfo info, StreamingContext context)
94 : base(info, context)
95 {
96 }
97 }
98
99 /// <summary>
100 /// The bootstrapper application factory specified by the <see cref="Core.BootstrapperApplicationFactoryAttribute"/>
101 /// does not extend the <see cref="Core.IBootstrapperApplicationFactory"/> base class.
102 /// </summary>
103 /// <seealso cref="Core.BaseBootstrapperApplicationFactory"/>
104 /// <seealso cref="Core.BootstrapperApplicationFactoryAttribute"/>
105 [Serializable]
106 public class InvalidBootstrapperApplicationFactoryException : BootstrapperException
107 {
108 /// <summary>
109 /// Creates a new instance of the <see cref="InvalidBootstrapperApplicationFactoryException"/> class.
110 /// </summary>
111 public InvalidBootstrapperApplicationFactoryException()
112 : base(NativeMethods.E_UNEXPECTED)
113 {
114 }
115
116 /// <summary>
117 /// Initializes a new instance of the <see cref="InvalidBootstrapperApplicationFactoryException"/> class.
118 /// </summary>
119 /// <param name="message">Exception message.</param>
120 public InvalidBootstrapperApplicationFactoryException(string message)
121 : base(message)
122 {
123 }
124
125 /// <summary>
126 /// Initializes a new instance of the <see cref="InvalidBootstrapperApplicationFactoryException"/> class.
127 /// </summary>
128 /// <param name="message">Exception message</param>
129 /// <param name="innerException">Inner exception associated with this one</param>
130 public InvalidBootstrapperApplicationFactoryException(string message, Exception innerException)
131 : base(message, innerException)
132 {
133 }
134
135 /// <summary>
136 /// Initializes a new instance of the <see cref="InvalidBootstrapperApplicationFactoryException"/> class.
137 /// </summary>
138 /// <param name="info">Serialization information for this exception</param>
139 /// <param name="context">Streaming context to serialize to</param>
140 protected InvalidBootstrapperApplicationFactoryException(SerializationInfo info, StreamingContext context)
141 : base(info, context)
142 {
143 }
144 }
145}
diff --git a/src/ext/Bal/WixToolset.Mba.Host/HostSection.cs b/src/ext/Bal/WixToolset.Mba.Host/HostSection.cs
new file mode 100644
index 00000000..632025c7
--- /dev/null
+++ b/src/ext/Bal/WixToolset.Mba.Host/HostSection.cs
@@ -0,0 +1,47 @@
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
3namespace WixToolset.Mba.Host
4{
5 using System;
6 using System.Configuration;
7
8 /// <summary>
9 /// Handler for the Host configuration section.
10 /// </summary>
11 public sealed class HostSection : ConfigurationSection
12 {
13 private static readonly ConfigurationProperty assemblyNameProperty = new ConfigurationProperty("assemblyName", typeof(string), null, ConfigurationPropertyOptions.IsRequired);
14 private static readonly ConfigurationProperty supportedFrameworksProperty = new ConfigurationProperty("", typeof(SupportedFrameworkElementCollection), null, ConfigurationPropertyOptions.IsDefaultCollection);
15
16 /// <summary>
17 /// Creates a new instance of the <see cref="HostSection"/> class.
18 /// </summary>
19 public HostSection()
20 {
21 }
22
23 /// <summary>
24 /// Gets the name of the assembly that contians the <see cref="Core.IBootstrapperApplicationFactory"/> child class.
25 /// </summary>
26 /// <remarks>
27 /// The assembly specified by this name must contain the <see cref="Core.BootstrapperApplicationFactoryAttribute"/> to identify
28 /// the type of the <see cref="Core.IBootstrapperApplicationFactory"/> child class.
29 /// </remarks>
30 [ConfigurationProperty("assemblyName", IsRequired = true)]
31 public string AssemblyName
32 {
33 get { return (string)base[assemblyNameProperty]; }
34 set { base[assemblyNameProperty] = value; }
35 }
36
37 /// <summary>
38 /// Gets the <see cref="SupportedFrameworkElementCollection"/> of supported frameworks for the host configuration.
39 /// </summary>
40 [ConfigurationProperty("", IsDefaultCollection = true)]
41 [ConfigurationCollection(typeof(SupportedFrameworkElement))]
42 public SupportedFrameworkElementCollection SupportedFrameworks
43 {
44 get { return (SupportedFrameworkElementCollection)base[supportedFrameworksProperty]; }
45 }
46 }
47}
diff --git a/src/ext/Bal/WixToolset.Mba.Host/NativeMethods.cs b/src/ext/Bal/WixToolset.Mba.Host/NativeMethods.cs
new file mode 100644
index 00000000..b9fc85a0
--- /dev/null
+++ b/src/ext/Bal/WixToolset.Mba.Host/NativeMethods.cs
@@ -0,0 +1,18 @@
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
3namespace WixToolset.Mba.Host
4{
5 using System;
6 using System.Runtime.InteropServices;
7
8 /// <summary>
9 /// Contains native constants, functions, and structures for this assembly.
10 /// </summary>
11 internal static class NativeMethods
12 {
13 #region Error Constants
14 internal const int E_NOTFOUND = unchecked((int)0x80070490);
15 internal const int E_UNEXPECTED = unchecked((int)0x8000ffff);
16 #endregion
17 }
18}
diff --git a/src/ext/Bal/WixToolset.Mba.Host/SupportedFrameworkElement.cs b/src/ext/Bal/WixToolset.Mba.Host/SupportedFrameworkElement.cs
new file mode 100644
index 00000000..fe7fd2eb
--- /dev/null
+++ b/src/ext/Bal/WixToolset.Mba.Host/SupportedFrameworkElement.cs
@@ -0,0 +1,47 @@
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
3namespace WixToolset.Mba.Host
4{
5 using System;
6 using System.Configuration;
7
8 /// <summary>
9 /// Handler for the supportedFramework configuration section.
10 /// </summary>
11 public sealed class SupportedFrameworkElement : ConfigurationElement
12 {
13 private static readonly ConfigurationProperty versionProperty = new ConfigurationProperty("version", typeof(string), null, ConfigurationPropertyOptions.IsRequired);
14 private static readonly ConfigurationProperty runtimeVersionProperty = new ConfigurationProperty("runtimeVersion", typeof(string));
15
16 /// <summary>
17 /// Creates a new instance of the <see cref="SupportedFrameworkElement"/> class.
18 /// </summary>
19 public SupportedFrameworkElement()
20 {
21 }
22
23 /// <summary>
24 /// Gets the version of the supported framework.
25 /// </summary>
26 /// <remarks>
27 /// The assembly specified by this name must contain a value matching the NETFX version registry key under
28 /// "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP".
29 /// </remarks>
30 [ConfigurationProperty("version", IsRequired = true)]
31 public string Version
32 {
33 get { return (string)base[versionProperty]; }
34 set { base[versionProperty] = value; }
35 }
36
37 /// <summary>
38 /// Gets the runtime version required by this supported framework.
39 /// </summary>
40 [ConfigurationProperty("runtimeVersion", IsRequired = false)]
41 public string RuntimeVersion
42 {
43 get { return (string)base[runtimeVersionProperty]; }
44 set { base[runtimeVersionProperty] = value; }
45 }
46 }
47}
diff --git a/src/ext/Bal/WixToolset.Mba.Host/SupportedFrameworkElementCollection.cs b/src/ext/Bal/WixToolset.Mba.Host/SupportedFrameworkElementCollection.cs
new file mode 100644
index 00000000..12c7cf3e
--- /dev/null
+++ b/src/ext/Bal/WixToolset.Mba.Host/SupportedFrameworkElementCollection.cs
@@ -0,0 +1,36 @@
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
3namespace WixToolset.Mba.Host
4{
5 using System;
6 using System.Configuration;
7 using System.Diagnostics.CodeAnalysis;
8
9 /// <summary>
10 /// Handler for the supportedFramework collection.
11 /// </summary>
12 [SuppressMessage("Microsoft.Design", "CA1010:CollectionsShouldImplementGenericInterface")]
13 [ConfigurationCollection(typeof(SupportedFrameworkElement), AddItemName = "supportedFramework", CollectionType = ConfigurationElementCollectionType.BasicMap)]
14 public sealed class SupportedFrameworkElementCollection : ConfigurationElementCollection
15 {
16 public override ConfigurationElementCollectionType CollectionType
17 {
18 get { return ConfigurationElementCollectionType.BasicMap; }
19 }
20
21 protected override string ElementName
22 {
23 get { return "supportedFramework"; }
24 }
25
26 protected override ConfigurationElement CreateNewElement()
27 {
28 return new SupportedFrameworkElement();
29 }
30
31 protected override object GetElementKey(ConfigurationElement element)
32 {
33 return (element as SupportedFrameworkElement).Version;
34 }
35 }
36}
diff --git a/src/ext/Bal/WixToolset.Mba.Host/WixToolset.Mba.Host.config b/src/ext/Bal/WixToolset.Mba.Host/WixToolset.Mba.Host.config
new file mode 100644
index 00000000..a19b66f1
--- /dev/null
+++ b/src/ext/Bal/WixToolset.Mba.Host/WixToolset.Mba.Host.config
@@ -0,0 +1,26 @@
1<?xml version="1.0" encoding="utf-8" ?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<configuration>
6 <configSections>
7 <sectionGroup name="wix.bootstrapper" type="WixToolset.Mba.Host.BootstrapperSectionGroup, WixToolset.Mba.Host">
8 <section name="host" type="WixToolset.Mba.Host.HostSection, WixToolset.Mba.Host" />
9 </sectionGroup>
10 </configSections>
11 <startup useLegacyV2RuntimeActivationPolicy="true">
12 <supportedRuntime version="v4.0" />
13 <supportedRuntime version="v2.0.50727" />
14 </startup>
15 <wix.bootstrapper>
16 <!-- Example only. Use only if the startup/supportedRuntime above cannot discern supported frameworks. -->
17 <!--
18 <supportedFramework version="v4\Client" />
19 <supportedFramework version="v3.5" />
20 <supportedFramework version="v3.0" />
21 -->
22
23 <!-- Example only. Replace the host/@assemblyName attribute with assembly that implements IBootstrapperApplicationFactory. -->
24 <host assemblyName="AssemblyWithClassThatInheritsFromBootstrapperApplicationFactory" />
25 </wix.bootstrapper>
26</configuration>
diff --git a/src/ext/Bal/WixToolset.Mba.Host/WixToolset.Mba.Host.csproj b/src/ext/Bal/WixToolset.Mba.Host/WixToolset.Mba.Host.csproj
new file mode 100644
index 00000000..3ee0ad1e
--- /dev/null
+++ b/src/ext/Bal/WixToolset.Mba.Host/WixToolset.Mba.Host.csproj
@@ -0,0 +1,54 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4<Project Sdk="Microsoft.NET.Sdk">
5 <PropertyGroup>
6 <AssemblyName>WixToolset.Mba.Host</AssemblyName>
7 <RootNamespace>WixToolset.Mba.Host</RootNamespace>
8 <TargetFrameworks>net20</TargetFrameworks>
9 <Description>Managed Bootstrapper Application entry point</Description>
10 <DebugType>embedded</DebugType>
11 <NuspecFile>$(MSBuildThisFileName).nuspec</NuspecFile>
12 <PlatformTarget>AnyCPU</PlatformTarget>
13 </PropertyGroup>
14
15 <ItemGroup>
16 <None Include="WixToolset.Mba.Host.config" CopyToOutputDirectory="PreserveNewest" />
17 </ItemGroup>
18 <ItemGroup>
19 <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
20 <PackageReference Include="Nerdbank.GitVersioning" Version="3.3.37" PrivateAssets="All" />
21 <PackageReference Include="WixToolset.Mba.Core" Version="4.0.*" />
22 </ItemGroup>
23 <ItemGroup>
24 <Reference Include="System.Configuration" />
25 </ItemGroup>
26 <ItemGroup>
27 <HeaderPath Include="$(BaseOutputPath)obj\$(AssemblyName).h">
28 <Visible>False</Visible>
29 </HeaderPath>
30 </ItemGroup>
31
32 <Target Name="GenerateIdentityHeader" AfterTargets="Build" Inputs="$(TargetPath)" Outputs="@(HeaderPath)">
33 <GetAssemblyIdentity AssemblyFiles="$(TargetPath)">
34 <Output TaskParameter="Assemblies" ItemName="AssemblyIdentity" />
35 </GetAssemblyIdentity>
36 <ItemGroup>
37 <Line Include='#define MBA_ASSEMBLY_FULL_NAME L"%(AssemblyIdentity.Identity)"' />
38 <Line Include='#define MBA_CONFIG_FILE_NAME L"$(AssemblyName).config"' />
39 <Line Include='#define MBA_ENTRY_TYPE L"$(RootNamespace).BootstrapperApplicationFactory"' />
40 </ItemGroup>
41 <Message Importance="normal" Text="Generating identity definitions into @(HeaderPath->'%(FullPath)')" />
42 <WriteLinesToFile File="@(HeaderPath)" Lines="@(Line)" Overwrite="True" />
43 <ItemGroup>
44 <FileWrites Include="@(HeaderPath)" />
45 </ItemGroup>
46 </Target>
47
48 <Target Name="SetNuspecProperties" DependsOnTargets="InitializeSourceControlInformation" AfterTargets="GetBuildVersion">
49 <PropertyGroup>
50 <NuspecBasePath>$(OutputPath)</NuspecBasePath>
51 <NuspecProperties>Id=$(AssemblyName);Version=$(BuildVersionSimple);Authors=$(Authors);Copyright=$(Copyright);Description=$(Description);RepositoryCommit=$(SourceRevisionId);RepositoryType=$(RepositoryType);RepositoryUrl=$(PrivateRepositoryUrl)</NuspecProperties>
52 </PropertyGroup>
53 </Target>
54</Project> \ No newline at end of file
diff --git a/src/ext/Bal/WixToolset.Mba.Host/WixToolset.Mba.Host.nuspec b/src/ext/Bal/WixToolset.Mba.Host/WixToolset.Mba.Host.nuspec
new file mode 100644
index 00000000..00fd21ac
--- /dev/null
+++ b/src/ext/Bal/WixToolset.Mba.Host/WixToolset.Mba.Host.nuspec
@@ -0,0 +1,23 @@
1<?xml version="1.0"?>
2<package >
3 <metadata>
4 <id>$id$</id>
5 <version>$version$</version>
6 <authors>WiX Toolset Team</authors>
7 <owners>WiX Toolset Team</owners>
8 <license type="expression">MS-RL</license>
9 <projectUrl>https://github.com/wixtoolset/Bal.wixext</projectUrl>
10 <requireLicenseAcceptance>false</requireLicenseAcceptance>
11 <description>$description$</description>
12 <copyright>$copyright$</copyright>
13 <repository type="$repositorytype$" url="$repositoryurl$" commit="$repositorycommit$" />
14 <dependencies>
15 <group targetFramework=".NETFramework2.0" />
16 </dependencies>
17 </metadata>
18
19 <files>
20 <file src="net20\$id$.config" target="samples" />
21 <file src="net20\$id$.dll" target="lib\net20" />
22 </files>
23</package>
diff --git a/src/ext/Bal/appveyor.cmd b/src/ext/Bal/appveyor.cmd
new file mode 100644
index 00000000..f4e9c26e
--- /dev/null
+++ b/src/ext/Bal/appveyor.cmd
@@ -0,0 +1,17 @@
1@setlocal
2@pushd %~dp0
3@set _C=Release
4
5nuget restore || exit /b
6
7msbuild -p:Configuration=%_C% -Restore || exit /b
8msbuild -p:Configuration=%_C% src\test\examples\examples.proj || exit /b
9
10dotnet test -c %_C% --no-build src\test\WixToolsetTest.Bal || exit /b
11dotnet test -c %_C% --no-build src\test\WixToolsetTest.ManagedHost || exit /b
12
13msbuild -p:Configuration=%_C% -p:NoBuild=true -t:Pack src\wixext\WixToolset.Bal.wixext.csproj || exit /b
14msbuild -p:Configuration=%_C% -p:NoBuild=true -t:Pack src\WixToolset.Mba.Host\WixToolset.Mba.Host.csproj || exit /b
15
16@popd
17@endlocal
diff --git a/src/ext/Bal/appveyor.yml b/src/ext/Bal/appveyor.yml
new file mode 100644
index 00000000..7c686b04
--- /dev/null
+++ b/src/ext/Bal/appveyor.yml
@@ -0,0 +1,40 @@
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# Do NOT modify this file. Update the canonical version in Home\repo-template\src\appveyor.yml
4# then update all of the repos.
5
6branches:
7 only:
8 - master
9 - develop
10
11image: Visual Studio 2019
12
13version: 0.0.0.{build}
14configuration: Release
15
16environment:
17 DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
18 DOTNET_CLI_TELEMETRY_OPTOUT: 1
19 NUGET_XMLDOC_MODE: skip
20
21build_script:
22 - appveyor.cmd
23
24pull_requests:
25 do_not_increment_build_number: true
26
27nuget:
28 disable_publish_on_pr: true
29
30skip_branch_with_pr: true
31skip_tags: true
32
33artifacts:
34- path: build\Release\**\*.nupkg
35 name: nuget
36
37notifications:
38- provider: Slack
39 incoming_webhook:
40 secure: p5xuu+4x2JHfwGDMDe5KcG1k7gZxqYc4jWVwvyNZv5cvkubPD2waJs5yXMAXZNN7Z63/3PWHb7q4KoY/99AjauYa1nZ4c5qYqRPFRBKTHfA=
diff --git a/src/ext/Bal/dnchost/coreclrhost.h b/src/ext/Bal/dnchost/coreclrhost.h
new file mode 100644
index 00000000..07f28735
--- /dev/null
+++ b/src/ext/Bal/dnchost/coreclrhost.h
@@ -0,0 +1,137 @@
1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5
6
7// ***** ABOUT THIS HEADER *****
8// **************************************************************************************
9//
10// This is the version on 2019-12-22 from
11// https://github.com/dotnet/runtime/blob/master/src/coreclr/src/coreclr/hosts/inc/coreclrhost.h
12//
13// **************************************************************************************
14// ****************************
15
16
17//
18// APIs for hosting CoreCLR
19//
20
21#ifndef __CORECLR_HOST_H__
22#define __CORECLR_HOST_H__
23
24#if defined(_WIN32) && defined(_M_IX86)
25#define CORECLR_CALLING_CONVENTION __stdcall
26#else
27#define CORECLR_CALLING_CONVENTION
28#endif
29
30// For each hosting API, we define a function prototype and a function pointer
31// The prototype is useful for implicit linking against the dynamic coreclr
32// library and the pointer for explicit dynamic loading (dlopen, LoadLibrary)
33#define CORECLR_HOSTING_API(function, ...) \
34 extern "C" int CORECLR_CALLING_CONVENTION function(__VA_ARGS__); \
35 typedef int (CORECLR_CALLING_CONVENTION *function##_ptr)(__VA_ARGS__)
36
37//
38// Initialize the CoreCLR. Creates and starts CoreCLR host and creates an app domain
39//
40// Parameters:
41// exePath - Absolute path of the executable that invoked the ExecuteAssembly (the native host application)
42// appDomainFriendlyName - Friendly name of the app domain that will be created to execute the assembly
43// propertyCount - Number of properties (elements of the following two arguments)
44// propertyKeys - Keys of properties of the app domain
45// propertyValues - Values of properties of the app domain
46// hostHandle - Output parameter, handle of the created host
47// domainId - Output parameter, id of the created app domain
48//
49// Returns:
50// HRESULT indicating status of the operation. S_OK if the assembly was successfully executed
51//
52CORECLR_HOSTING_API(coreclr_initialize,
53 const char* exePath,
54 const char* appDomainFriendlyName,
55 int propertyCount,
56 const char** propertyKeys,
57 const char** propertyValues,
58 void** hostHandle,
59 unsigned int* domainId);
60
61//
62// Shutdown CoreCLR. It unloads the app domain and stops the CoreCLR host.
63//
64// Parameters:
65// hostHandle - Handle of the host
66// domainId - Id of the domain
67//
68// Returns:
69// HRESULT indicating status of the operation. S_OK if the assembly was successfully executed
70//
71CORECLR_HOSTING_API(coreclr_shutdown,
72 void* hostHandle,
73 unsigned int domainId);
74
75//
76// Shutdown CoreCLR. It unloads the app domain and stops the CoreCLR host.
77//
78// Parameters:
79// hostHandle - Handle of the host
80// domainId - Id of the domain
81// latchedExitCode - Latched exit code after domain unloaded
82//
83// Returns:
84// HRESULT indicating status of the operation. S_OK if the assembly was successfully executed
85//
86CORECLR_HOSTING_API(coreclr_shutdown_2,
87 void* hostHandle,
88 unsigned int domainId,
89 int* latchedExitCode);
90
91//
92// Create a native callable function pointer for a managed method.
93//
94// Parameters:
95// hostHandle - Handle of the host
96// domainId - Id of the domain
97// entryPointAssemblyName - Name of the assembly which holds the custom entry point
98// entryPointTypeName - Name of the type which holds the custom entry point
99// entryPointMethodName - Name of the method which is the custom entry point
100// delegate - Output parameter, the function stores a native callable function pointer to the delegate at the specified address
101//
102// Returns:
103// HRESULT indicating status of the operation. S_OK if the assembly was successfully executed
104//
105CORECLR_HOSTING_API(coreclr_create_delegate,
106 void* hostHandle,
107 unsigned int domainId,
108 const char* entryPointAssemblyName,
109 const char* entryPointTypeName,
110 const char* entryPointMethodName,
111 void** delegate);
112
113//
114// Execute a managed assembly with given arguments
115//
116// Parameters:
117// hostHandle - Handle of the host
118// domainId - Id of the domain
119// argc - Number of arguments passed to the executed assembly
120// argv - Array of arguments passed to the executed assembly
121// managedAssemblyPath - Path of the managed assembly to execute (or NULL if using a custom entrypoint).
122// exitCode - Exit code returned by the executed assembly
123//
124// Returns:
125// HRESULT indicating status of the operation. S_OK if the assembly was successfully executed
126//
127CORECLR_HOSTING_API(coreclr_execute_assembly,
128 void* hostHandle,
129 unsigned int domainId,
130 int argc,
131 const char** argv,
132 const char* managedAssemblyPath,
133 unsigned int* exitCode);
134
135#undef CORECLR_HOSTING_API
136
137#endif // __CORECLR_HOST_H__ \ No newline at end of file
diff --git a/src/ext/Bal/dnchost/dnchost.cpp b/src/ext/Bal/dnchost/dnchost.cpp
new file mode 100644
index 00000000..8ca326fc
--- /dev/null
+++ b/src/ext/Bal/dnchost/dnchost.cpp
@@ -0,0 +1,309 @@
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
5static DNCSTATE vstate = { };
6
7
8// internal function declarations
9
10static HRESULT LoadModulePaths(
11 __in DNCSTATE* pState
12 );
13static HRESULT LoadDncConfiguration(
14 __in DNCSTATE* pState,
15 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs
16 );
17static HRESULT LoadRuntime(
18 __in DNCSTATE* pState
19 );
20static HRESULT LoadManagedBootstrapperApplicationFactory(
21 __in DNCSTATE* pState
22 );
23static HRESULT CreatePrerequisiteBA(
24 __in HRESULT hrHostInitialization,
25 __in IBootstrapperEngine* pEngine,
26 __in LPCWSTR wzAppBase,
27 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
28 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults
29 );
30
31
32// function definitions
33
34extern "C" BOOL WINAPI DllMain(
35 IN HINSTANCE hInstance,
36 IN DWORD dwReason,
37 IN LPVOID /* pvReserved */
38 )
39{
40 switch (dwReason)
41 {
42 case DLL_PROCESS_ATTACH:
43 ::DisableThreadLibraryCalls(hInstance);
44 vstate.hInstance = hInstance;
45 break;
46
47 case DLL_PROCESS_DETACH:
48 vstate.hInstance = NULL;
49 break;
50 }
51
52 return TRUE;
53}
54
55extern "C" HRESULT WINAPI BootstrapperApplicationCreate(
56 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
57 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults
58 )
59{
60 HRESULT hr = S_OK;
61 HRESULT hrHostInitialization = S_OK;
62 IBootstrapperEngine* pEngine = NULL;
63
64 // coreclr.dll doesn't support unloading, so the rest of the .NET Core hosting stack doesn't support it either.
65 // This means we also can't unload.
66 pResults->fDisableUnloading = TRUE;
67
68 hr = BalInitializeFromCreateArgs(pArgs, &pEngine);
69 ExitOnFailure(hr, "Failed to initialize Bal.");
70
71 if (!vstate.fInitialized)
72 {
73 hr = XmlInitialize();
74 BalExitOnFailure(hr, "Failed to initialize XML.");
75
76 hr = LoadModulePaths(&vstate);
77 BalExitOnFailure(hr, "Failed to get the host base path.");
78
79 hr = LoadDncConfiguration(&vstate, pArgs);
80 BalExitOnFailure(hr, "Failed to get the dnc configuration.");
81
82 vstate.fInitialized = TRUE;
83 }
84
85 if (!vstate.fInitializedRuntime)
86 {
87 hr = LoadRuntime(&vstate);
88
89 vstate.fInitializedRuntime = SUCCEEDED(hr);
90 }
91
92 if (vstate.fInitializedRuntime)
93 {
94 if (!vstate.pAppFactory)
95 {
96 hr = LoadManagedBootstrapperApplicationFactory(&vstate);
97 BalExitOnFailure(hr, "Failed to create the .NET Core bootstrapper application factory.");
98 }
99
100 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Loading .NET Core %ls bootstrapper application.", DNCHOSTTYPE_FDD == vstate.type ? L"FDD" : L"SCD");
101
102 hr = vstate.pAppFactory->Create(pArgs, pResults);
103 BalExitOnFailure(hr, "Failed to create the .NET Core bootstrapper application.");
104 }
105 else // fallback to the prerequisite BA.
106 {
107 if (DNCHOSTTYPE_SCD == vstate.type)
108 {
109 hrHostInitialization = E_DNCHOST_SCD_RUNTIME_FAILURE;
110 BalLogError(hr, "The self-contained .NET Core runtime failed to load. This is an unrecoverable error.");
111 }
112 else
113 {
114 hrHostInitialization = S_OK;
115 }
116 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Loading prerequisite bootstrapper application because .NET Core host could not be loaded, error: 0x%08x.", hr);
117
118 hr = CreatePrerequisiteBA(hrHostInitialization, pEngine, vstate.sczAppBase, pArgs, pResults);
119 BalExitOnFailure(hr, "Failed to create the pre-requisite bootstrapper application.");
120 }
121
122LExit:
123 ReleaseNullObject(pEngine);
124
125 return hr;
126}
127
128extern "C" void WINAPI BootstrapperApplicationDestroy()
129{
130 if (vstate.hMbapreqModule)
131 {
132 PFN_BOOTSTRAPPER_APPLICATION_DESTROY pfnDestroy = reinterpret_cast<PFN_BOOTSTRAPPER_APPLICATION_DESTROY>(::GetProcAddress(vstate.hMbapreqModule, "DncPrereqBootstrapperApplicationDestroy"));
133 if (pfnDestroy)
134 {
135 (*pfnDestroy)();
136 }
137
138 ::FreeLibrary(vstate.hMbapreqModule);
139 vstate.hMbapreqModule = NULL;
140 }
141
142 BalUninitialize();
143}
144
145static HRESULT LoadModulePaths(
146 __in DNCSTATE* pState
147 )
148{
149 HRESULT hr = S_OK;
150
151 hr = PathForCurrentProcess(&pState->sczModuleFullPath, pState->hInstance);
152 BalExitOnFailure(hr, "Failed to get the full host path.");
153
154 hr = PathGetDirectory(pState->sczModuleFullPath, &pState->sczAppBase);
155 BalExitOnFailure(hr, "Failed to get the directory of the full process path.");
156
157 hr = PathConcat(pState->sczAppBase, DNC_ASSEMBLY_FILE_NAME, &pState->sczManagedHostPath);
158 BalExitOnFailure(hr, "Failed to create managed host path.");
159
160LExit:
161 return hr;
162}
163
164static HRESULT LoadDncConfiguration(
165 __in DNCSTATE* pState,
166 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs
167 )
168{
169 HRESULT hr = S_OK;
170 IXMLDOMDocument* pixdManifest = NULL;
171 IXMLDOMNode* pixnHost = NULL;
172 LPWSTR sczPayloadName = NULL;
173 DWORD dwBool = 0;
174
175 hr = XmlLoadDocumentFromFile(pArgs->pCommand->wzBootstrapperApplicationDataPath, &pixdManifest);
176 BalExitOnFailure(hr, "Failed to load BalManifest '%ls'", pArgs->pCommand->wzBootstrapperApplicationDataPath);
177
178 hr = XmlSelectSingleNode(pixdManifest, L"/BootstrapperApplicationData/WixBalBAFactoryAssembly", &pixnHost);
179 BalExitOnFailure(hr, "Failed to get WixBalBAFactoryAssembly element.");
180
181 if (S_FALSE == hr)
182 {
183 hr = E_NOTFOUND;
184 BalExitOnRootFailure(hr, "Failed to find WixBalBAFactoryAssembly element in bootstrapper application config.");
185 }
186
187 hr = XmlGetAttributeEx(pixnHost, L"FilePath", &sczPayloadName);
188 BalExitOnFailure(hr, "Failed to get WixBalBAFactoryAssembly/@FilePath.");
189
190 hr = PathConcat(pArgs->pCommand->wzBootstrapperWorkingFolder, sczPayloadName, &pState->sczBaFactoryAssemblyPath);
191 BalExitOnFailure(hr, "Failed to create BaFactoryAssemblyPath.");
192
193 LPCWSTR wzFileName = PathFile(pState->sczBaFactoryAssemblyPath);
194 LPCWSTR wzExtension = PathExtension(pState->sczBaFactoryAssemblyPath);
195 if (!wzExtension)
196 {
197 BalExitOnFailure(hr = E_FAIL, "BaFactoryAssemblyPath has no extension.");
198 }
199
200 hr = StrAllocString(&pState->sczBaFactoryAssemblyName, wzFileName, wzExtension - wzFileName);
201 BalExitOnFailure(hr, "Failed to copy BAFactoryAssembly payload Name.");
202
203 hr = StrAllocString(&pState->sczBaFactoryDepsJsonPath, pState->sczBaFactoryAssemblyPath, wzExtension - pState->sczBaFactoryAssemblyPath);
204 BalExitOnFailure(hr, "Failed to initialize deps json path.");
205
206 hr = StrAllocString(&pState->sczBaFactoryRuntimeConfigPath, pState->sczBaFactoryDepsJsonPath, 0);
207 BalExitOnFailure(hr, "Failed to initialize runtime config path.");
208
209 hr = StrAllocConcat(&pState->sczBaFactoryDepsJsonPath, L".deps.json", 0);
210 BalExitOnFailure(hr, "Failed to concat extension to deps json path.");
211
212 hr = StrAllocConcat(&pState->sczBaFactoryRuntimeConfigPath, L".runtimeconfig.json", 0);
213 BalExitOnFailure(hr, "Failed to concat extension to runtime config path.");
214
215 pState->type = DNCHOSTTYPE_FDD;
216
217 hr = XmlSelectSingleNode(pixdManifest, L"/BootstrapperApplicationData/WixDncOptions", &pixnHost);
218 if (S_FALSE == hr)
219 {
220 ExitFunction1(hr = S_OK);
221 }
222 BalExitOnFailure(hr, "Failed to find WixDncOptions element in bootstrapper application config.");
223
224 hr = XmlGetAttributeNumber(pixnHost, L"SelfContainedDeployment", &dwBool);
225 if (S_FALSE == hr)
226 {
227 hr = S_OK;
228 }
229 else if (SUCCEEDED(hr) && dwBool)
230 {
231 pState->type = DNCHOSTTYPE_SCD;
232 }
233 BalExitOnFailure(hr, "Failed to get SelfContainedDeployment value.");
234
235LExit:
236 ReleaseStr(sczPayloadName);
237 ReleaseObject(pixnHost);
238 ReleaseObject(pixdManifest);
239
240 return hr;
241}
242
243static HRESULT LoadRuntime(
244 __in DNCSTATE* pState
245 )
246{
247 HRESULT hr = S_OK;
248
249 hr = DnchostLoadRuntime(
250 &pState->hostfxrState,
251 pState->sczModuleFullPath,
252 pState->sczManagedHostPath,
253 pState->sczBaFactoryDepsJsonPath,
254 pState->sczBaFactoryRuntimeConfigPath);
255
256 return hr;
257}
258
259static HRESULT LoadManagedBootstrapperApplicationFactory(
260 __in DNCSTATE* pState
261 )
262{
263 HRESULT hr = S_OK;
264
265 hr = DnchostCreateFactory(
266 &pState->hostfxrState,
267 pState->sczBaFactoryAssemblyName,
268 pState->sczBaFactoryAssemblyPath,
269 &pState->pAppFactory);
270
271 return hr;
272}
273
274static HRESULT CreatePrerequisiteBA(
275 __in HRESULT hrHostInitialization,
276 __in IBootstrapperEngine* pEngine,
277 __in LPCWSTR wzAppBase,
278 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
279 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults
280 )
281{
282 HRESULT hr = S_OK;
283 LPWSTR sczDncpreqPath = NULL;
284 HMODULE hModule = NULL;
285
286 hr = PathConcat(wzAppBase, L"dncpreq.dll", &sczDncpreqPath);
287 BalExitOnFailure(hr, "Failed to get path to pre-requisite BA.");
288
289 hModule = ::LoadLibraryW(sczDncpreqPath);
290 BalExitOnNullWithLastError(hModule, hr, "Failed to load pre-requisite BA DLL.");
291
292 PFN_DNCPREQ_BOOTSTRAPPER_APPLICATION_CREATE pfnCreate = reinterpret_cast<PFN_DNCPREQ_BOOTSTRAPPER_APPLICATION_CREATE>(::GetProcAddress(hModule, "DncPrereqBootstrapperApplicationCreate"));
293 BalExitOnNullWithLastError(pfnCreate, hr, "Failed to get DncPrereqBootstrapperApplicationCreate entry-point from: %ls", sczDncpreqPath);
294
295 hr = pfnCreate(hrHostInitialization, pEngine, pArgs, pResults);
296 BalExitOnFailure(hr, "Failed to create prequisite bootstrapper app.");
297
298 vstate.hMbapreqModule = hModule;
299 hModule = NULL;
300
301LExit:
302 if (hModule)
303 {
304 ::FreeLibrary(hModule);
305 }
306 ReleaseStr(sczDncpreqPath);
307
308 return hr;
309}
diff --git a/src/ext/Bal/dnchost/dnchost.def b/src/ext/Bal/dnchost/dnchost.def
new file mode 100644
index 00000000..4488df94
--- /dev/null
+++ b/src/ext/Bal/dnchost/dnchost.def
@@ -0,0 +1,6 @@
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
4EXPORTS
5 BootstrapperApplicationCreate
6 BootstrapperApplicationDestroy
diff --git a/src/ext/Bal/dnchost/dnchost.h b/src/ext/Bal/dnchost/dnchost.h
new file mode 100644
index 00000000..22fd8f5e
--- /dev/null
+++ b/src/ext/Bal/dnchost/dnchost.h
@@ -0,0 +1,35 @@
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
5enum DNCHOSTTYPE
6{
7 DNCHOSTTYPE_UNKNOWN,
8 DNCHOSTTYPE_FDD,
9 DNCHOSTTYPE_SCD,
10};
11
12extern "C" typedef HRESULT(WINAPI* PFN_DNCPREQ_BOOTSTRAPPER_APPLICATION_CREATE)(
13 __in HRESULT hrHostInitialization,
14 __in IBootstrapperEngine* pEngine,
15 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
16 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults
17 );
18
19struct DNCSTATE
20{
21 BOOL fInitialized;
22 BOOL fInitializedRuntime;
23 HINSTANCE hInstance;
24 LPWSTR sczModuleFullPath;
25 LPWSTR sczAppBase;
26 LPWSTR sczManagedHostPath;
27 LPWSTR sczBaFactoryAssemblyName;
28 LPWSTR sczBaFactoryAssemblyPath;
29 LPWSTR sczBaFactoryDepsJsonPath;
30 LPWSTR sczBaFactoryRuntimeConfigPath;
31 DNCHOSTTYPE type;
32 HOSTFXR_STATE hostfxrState;
33 IBootstrapperApplicationFactory* pAppFactory;
34 HMODULE hMbapreqModule;
35};
diff --git a/src/ext/Bal/dnchost/dnchost.vcxproj b/src/ext/Bal/dnchost/dnchost.vcxproj
new file mode 100644
index 00000000..bef3f77e
--- /dev/null
+++ b/src/ext/Bal/dnchost/dnchost.vcxproj
@@ -0,0 +1,106 @@
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<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
4 <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.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.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\WixToolset.BalUtil.4.0.58\build\WixToolset.BalUtil.props" Condition="Exists('..\..\packages\WixToolset.BalUtil.4.0.58\build\WixToolset.BalUtil.props')" />
8 <Import Project="..\..\packages\WixToolset.BootstrapperCore.Native.4.0.141\build\WixToolset.BootstrapperCore.Native.props" Condition="Exists('..\..\packages\WixToolset.BootstrapperCore.Native.4.0.141\build\WixToolset.BootstrapperCore.Native.props')" />
9 <Import Project="..\..\packages\WixToolset.DUtil.4.0.72\build\WixToolset.DUtil.props" Condition="Exists('..\..\packages\WixToolset.DUtil.4.0.72\build\WixToolset.DUtil.props')" />
10 <ItemGroup Label="ProjectConfigurations">
11 <ProjectConfiguration Include="Debug|ARM64">
12 <Configuration>Debug</Configuration>
13 <Platform>ARM64</Platform>
14 </ProjectConfiguration>
15 <ProjectConfiguration Include="Release|ARM64">
16 <Configuration>Release</Configuration>
17 <Platform>ARM64</Platform>
18 </ProjectConfiguration>
19 <ProjectConfiguration Include="Debug|Win32">
20 <Configuration>Debug</Configuration>
21 <Platform>Win32</Platform>
22 </ProjectConfiguration>
23 <ProjectConfiguration Include="Release|Win32">
24 <Configuration>Release</Configuration>
25 <Platform>Win32</Platform>
26 </ProjectConfiguration>
27 <ProjectConfiguration Include="Debug|x64">
28 <Configuration>Debug</Configuration>
29 <Platform>x64</Platform>
30 </ProjectConfiguration>
31 <ProjectConfiguration Include="Release|x64">
32 <Configuration>Release</Configuration>
33 <Platform>x64</Platform>
34 </ProjectConfiguration>
35 </ItemGroup>
36 <PropertyGroup Label="Globals">
37 <ProjectGuid>{B6F70281-6583-4138-BB7F-AABFEBBB3CA2}</ProjectGuid>
38 <ConfigurationType>DynamicLibrary</ConfigurationType>
39 <PlatformToolset>v142</PlatformToolset>
40 <CharacterSet>Unicode</CharacterSet>
41 <TargetName>dnchost</TargetName>
42 <ProjectModuleDefinitionFile>dnchost.def</ProjectModuleDefinitionFile>
43 </PropertyGroup>
44 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
45 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
46 <PropertyGroup>
47 <NetHostPlatform>$(Platform)</NetHostPlatform>
48 <NetHostPlatform Condition=" '$(NetHostPlatform)'=='Win32' ">x86</NetHostPlatform>
49 <NetHostPath>..\..\packages\runtime.win-$(NetHostPlatform).Microsoft.NETCore.DotNetAppHost.5.0.0\runtimes\win-$(NetHostPlatform)\native\</NetHostPath>
50 <ProjectAdditionalLinkLibraries>shlwapi.lib;$(NetHostPath)libnethost.lib</ProjectAdditionalLinkLibraries>
51 </PropertyGroup>
52 <ItemGroup>
53 <ClCompile Include="dnchost.cpp" />
54 <ClCompile Include="dncutil.cpp" />
55 <ClCompile Include="precomp.cpp">
56 <PrecompiledHeader>Create</PrecompiledHeader>
57 </ClCompile>
58 </ItemGroup>
59 <ItemGroup>
60 <ClInclude Include="coreclrhost.h" />
61 <ClInclude Include="dnchost.h" />
62 <ClInclude Include="dncutil.h" />
63 <ClInclude Include="precomp.h" />
64 </ItemGroup>
65 <ItemGroup>
66 <None Include="dnchost.def" />
67 </ItemGroup>
68 <ItemGroup>
69 <None Include="packages.config" />
70 </ItemGroup>
71 <ItemDefinitionGroup>
72 <ClCompile>
73 <AdditionalIncludeDirectories>$(BaseOutputPath)obj;$(NetHostPath);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
74 </ClCompile>
75 <Link>
76 <AdditionalOptions>/LTCG %(AdditionalOptions)</AdditionalOptions>
77 </Link>
78 </ItemDefinitionGroup>
79 <ItemGroup>
80 <ProjectReference Include="..\WixToolset.Dnc.Host\WixToolset.Dnc.Host.csproj">
81 <Project>{0D780900-C2FF-4FA2-8CB5-8A19768724C5}</Project>
82 <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
83 <SkipGetTargetFrameworkProperties>true</SkipGetTargetFrameworkProperties>
84 </ProjectReference>
85 </ItemGroup>
86 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
87 <Import Project="..\..\packages\Microsoft.Build.Tasks.Git.1.0.0\build\Microsoft.Build.Tasks.Git.targets" Condition="Exists('..\..\packages\Microsoft.Build.Tasks.Git.1.0.0\build\Microsoft.Build.Tasks.Git.targets')" />
88 <Import Project="..\..\packages\Microsoft.SourceLink.Common.1.0.0\build\Microsoft.SourceLink.Common.targets" Condition="Exists('..\..\packages\Microsoft.SourceLink.Common.1.0.0\build\Microsoft.SourceLink.Common.targets')" />
89 <Import Project="..\..\packages\Microsoft.SourceLink.GitHub.1.0.0\build\Microsoft.SourceLink.GitHub.targets" Condition="Exists('..\..\packages\Microsoft.SourceLink.GitHub.1.0.0\build\Microsoft.SourceLink.GitHub.targets')" />
90 <Import Project="..\..\packages\Nerdbank.GitVersioning.3.3.37\build\Nerdbank.GitVersioning.targets" Condition="Exists('..\..\packages\Nerdbank.GitVersioning.3.3.37\build\Nerdbank.GitVersioning.targets')" />
91 <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
92 <PropertyGroup>
93 <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>
94 </PropertyGroup>
95 <Error Condition="!Exists('..\..\packages\Microsoft.Build.Tasks.Git.1.0.0\build\Microsoft.Build.Tasks.Git.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Build.Tasks.Git.1.0.0\build\Microsoft.Build.Tasks.Git.props'))" />
96 <Error Condition="!Exists('..\..\packages\Microsoft.Build.Tasks.Git.1.0.0\build\Microsoft.Build.Tasks.Git.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Build.Tasks.Git.1.0.0\build\Microsoft.Build.Tasks.Git.targets'))" />
97 <Error Condition="!Exists('..\..\packages\Microsoft.SourceLink.Common.1.0.0\build\Microsoft.SourceLink.Common.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.SourceLink.Common.1.0.0\build\Microsoft.SourceLink.Common.props'))" />
98 <Error Condition="!Exists('..\..\packages\Microsoft.SourceLink.Common.1.0.0\build\Microsoft.SourceLink.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.SourceLink.Common.1.0.0\build\Microsoft.SourceLink.Common.targets'))" />
99 <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'))" />
100 <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'))" />
101 <Error Condition="!Exists('..\..\packages\Nerdbank.GitVersioning.3.3.37\build\Nerdbank.GitVersioning.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Nerdbank.GitVersioning.3.3.37\build\Nerdbank.GitVersioning.targets'))" />
102 <Error Condition="!Exists('..\..\packages\WixToolset.BalUtil.4.0.58\build\WixToolset.BalUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.BalUtil.4.0.58\build\WixToolset.BalUtil.props'))" />
103 <Error Condition="!Exists('..\..\packages\WixToolset.BootstrapperCore.Native.4.0.141\build\WixToolset.BootstrapperCore.Native.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.BootstrapperCore.Native.4.0.141\build\WixToolset.BootstrapperCore.Native.props'))" />
104 <Error Condition="!Exists('..\..\packages\WixToolset.DUtil.4.0.72\build\WixToolset.DUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.DUtil.4.0.72\build\WixToolset.DUtil.props'))" />
105 </Target>
106</Project> \ No newline at end of file
diff --git a/src/ext/Bal/dnchost/dncutil.cpp b/src/ext/Bal/dnchost/dncutil.cpp
new file mode 100644
index 00000000..34d14911
--- /dev/null
+++ b/src/ext/Bal/dnchost/dncutil.cpp
@@ -0,0 +1,411 @@
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://github.com/dotnet/runtime/blob/master/src/installer/corehost/error_codes.h
6#define InvalidArgFailure 0x80008081
7#define HostApiBufferTooSmall 0x80008098
8#define HostApiUnsupportedVersion 0x800080a2
9
10// internal function declarations
11
12static HRESULT GetHostfxrPath(
13 __in HOSTFXR_STATE* pState,
14 __in LPCWSTR wzNativeHostPath
15 );
16static HRESULT LoadHostfxr(
17 __in HOSTFXR_STATE* pState
18 );
19static HRESULT InitializeHostfxr(
20 __in HOSTFXR_STATE* pState,
21 __in LPCWSTR wzManagedHostPath,
22 __in LPCWSTR wzDepsJsonPath,
23 __in LPCWSTR wzRuntimeConfigPath
24 );
25static HRESULT InitializeCoreClr(
26 __in HOSTFXR_STATE* pState,
27 __in LPCWSTR wzNativeHostPath
28 );
29static HRESULT InitializeCoreClrPre5(
30 __in HOSTFXR_STATE* pState,
31 __in LPCWSTR wzNativeHostPath
32 );
33static HRESULT LoadCoreClr(
34 __in HOSTFXR_STATE* pState,
35 __in LPCWSTR wzCoreClrPath
36 );
37static HRESULT StartCoreClr(
38 __in HOSTFXR_STATE* pState,
39 __in LPCWSTR wzNativeHostPath,
40 __in DWORD cProperties,
41 __in LPCWSTR* propertyKeys,
42 __in LPCWSTR* propertyValues
43 );
44
45
46// function definitions
47
48HRESULT DnchostLoadRuntime(
49 __in HOSTFXR_STATE* pState,
50 __in LPCWSTR wzNativeHostPath,
51 __in LPCWSTR wzManagedHostPath,
52 __in LPCWSTR wzDepsJsonPath,
53 __in LPCWSTR wzRuntimeConfigPath
54 )
55{
56 HRESULT hr = S_OK;
57
58 hr = GetHostfxrPath(pState, wzNativeHostPath);
59 BalExitOnFailure(hr, "Failed to find hostfxr.");
60
61 hr = LoadHostfxr(pState);
62 BalExitOnFailure(hr, "Failed to load hostfxr.");
63
64 hr = InitializeHostfxr(pState, wzManagedHostPath, wzDepsJsonPath, wzRuntimeConfigPath);
65 BalExitOnFailure(hr, "Failed to initialize hostfxr.");
66
67 hr = InitializeCoreClr(pState, wzNativeHostPath);
68 BalExitOnFailure(hr, "Failed to initialize coreclr.");
69
70LExit:
71 return hr;
72}
73
74HRESULT DnchostCreateFactory(
75 __in HOSTFXR_STATE* pState,
76 __in LPCWSTR wzBaFactoryAssemblyName,
77 __in LPCWSTR wzBaFactoryAssemblyPath,
78 __out IBootstrapperApplicationFactory** ppAppFactory
79 )
80{
81 HRESULT hr = S_OK;
82 PFNCREATEBAFACTORY pfnCreateBAFactory = NULL;
83
84 if (pState->pfnGetFunctionPointer)
85 {
86 hr = pState->pfnGetFunctionPointer(
87 DNC_ENTRY_TYPEW,
88 DNC_STATIC_ENTRY_METHODW,
89 DNC_STATIC_ENTRY_DELEGATEW,
90 NULL,
91 NULL,
92 reinterpret_cast<void**>(&pfnCreateBAFactory));
93 BalExitOnFailure(hr, "Failed to create delegate through GetFunctionPointer.");
94 }
95 else
96 {
97 hr = pState->pfnCoreclrCreateDelegate(
98 pState->pClrHandle,
99 pState->dwDomainId,
100 DNC_ASSEMBLY_FULL_NAME,
101 DNC_ENTRY_TYPE,
102 DNC_STATIC_ENTRY_METHOD,
103 reinterpret_cast<void**>(&pfnCreateBAFactory));
104 BalExitOnFailure(hr, "Failed to create delegate in app domain.");
105 }
106
107 *ppAppFactory = pfnCreateBAFactory(wzBaFactoryAssemblyName, wzBaFactoryAssemblyPath);
108
109LExit:
110 return hr;
111}
112
113static HRESULT GetHostfxrPath(
114 __in HOSTFXR_STATE* pState,
115 __in LPCWSTR wzNativeHostPath
116 )
117{
118 HRESULT hr = S_OK;
119 get_hostfxr_parameters getHostfxrParameters = { };
120 int nrc = 0;
121 size_t cchHostFxrPath = MAX_PATH;
122
123 getHostfxrParameters.size = sizeof(get_hostfxr_parameters);
124 getHostfxrParameters.assembly_path = wzNativeHostPath;
125
126 // get_hostfxr_path does a full search on every call, so
127 // minimize the number of calls
128 // need to loop
129 for (;;)
130 {
131 cchHostFxrPath *= 2;
132 hr = StrAlloc(&pState->sczHostfxrPath, cchHostFxrPath);
133 BalExitOnFailure(hr, "Failed to allocate hostFxrPath.");
134
135 nrc = get_hostfxr_path(pState->sczHostfxrPath, &cchHostFxrPath, &getHostfxrParameters);
136 if (HostApiBufferTooSmall != nrc)
137 {
138 break;
139 }
140 }
141 if (0 != nrc)
142 {
143 BalExitOnFailure(hr = nrc, "GetHostfxrPath failed");
144 }
145
146LExit:
147 return hr;
148}
149
150static HRESULT LoadHostfxr(
151 __in HOSTFXR_STATE* pState
152 )
153{
154 HRESULT hr = S_OK;
155 HMODULE hHostfxr;
156
157 hHostfxr = ::LoadLibraryExW(pState->sczHostfxrPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
158 BalExitOnNullWithLastError(hHostfxr, hr, "Failed to load hostfxr from '%ls'.", pState->sczHostfxrPath);
159
160 pState->pfnHostfxrInitializeForApp = reinterpret_cast<hostfxr_initialize_for_dotnet_command_line_fn>(::GetProcAddress(hHostfxr, "hostfxr_initialize_for_dotnet_command_line"));
161 BalExitOnNullWithLastError(pState->pfnHostfxrInitializeForApp, hr, "Failed to get procedure address for hostfxr_initialize_for_dotnet_command_line.");
162
163 pState->pfnHostfxrGetRuntimeProperties = reinterpret_cast<hostfxr_get_runtime_properties_fn>(::GetProcAddress(hHostfxr, "hostfxr_get_runtime_properties"));
164 BalExitOnNullWithLastError(pState->pfnHostfxrGetRuntimeProperties, hr, "Failed to get procedure address for hostfxr_get_runtime_properties.");
165
166 pState->pfnHostfxrSetErrorWriter = reinterpret_cast<hostfxr_set_error_writer_fn>(::GetProcAddress(hHostfxr, "hostfxr_set_error_writer"));
167 BalExitOnNullWithLastError(pState->pfnHostfxrSetErrorWriter, hr, "Failed to get procedure address for hostfxr_set_error_writer.");
168
169 pState->pfnHostfxrClose = reinterpret_cast<hostfxr_close_fn>(::GetProcAddress(hHostfxr, "hostfxr_close"));
170 BalExitOnNullWithLastError(pState->pfnHostfxrClose, hr, "Failed to get procedure address for hostfxr_close.");
171
172 pState->pfnHostfxrGetRuntimeDelegate = reinterpret_cast<hostfxr_get_runtime_delegate_fn>(::GetProcAddress(hHostfxr, "hostfxr_get_runtime_delegate"));
173 BalExitOnNullWithLastError(pState->pfnHostfxrGetRuntimeDelegate, hr, "Failed to get procedure address for hostfxr_get_runtime_delegate.");
174
175LExit:
176 // Never unload the module since it isn't meant to be unloaded.
177
178 return hr;
179}
180
181static void HOSTFXR_CALLTYPE DnchostErrorWriter(
182 __in LPCWSTR wzMessage
183 )
184{
185 BOOTSTRAPPER_LOG_LEVEL level = BOOTSTRAPPER_LOG_LEVEL_ERROR;
186
187 if (CSTR_EQUAL == ::CompareString(LOCALE_INVARIANT, 0, wzMessage, -1, L"The requested delegate type is not available in the target framework.", -1))
188 {
189 level = BOOTSTRAPPER_LOG_LEVEL_DEBUG;
190 }
191
192 BalLog(level, "error from hostfxr: %ls", wzMessage);
193}
194
195static HRESULT InitializeHostfxr(
196 __in HOSTFXR_STATE* pState,
197 __in LPCWSTR wzManagedHostPath,
198 __in LPCWSTR wzDepsJsonPath,
199 __in LPCWSTR wzRuntimeConfigPath
200 )
201{
202 HRESULT hr = S_OK;
203
204 pState->pfnHostfxrSetErrorWriter(static_cast<hostfxr_error_writer_fn>(&DnchostErrorWriter));
205
206 LPCWSTR argv[] = {
207 L"exec",
208 L"--depsfile",
209 wzDepsJsonPath,
210 L"--runtimeconfig",
211 wzRuntimeConfigPath,
212 wzManagedHostPath,
213 };
214 hr = pState->pfnHostfxrInitializeForApp(sizeof(argv)/sizeof(LPWSTR), argv, NULL, &pState->hostContextHandle);
215 BalExitOnFailure(hr, "HostfxrInitializeForApp failed");
216
217LExit:
218 return hr;
219}
220
221static HRESULT InitializeCoreClr(
222 __in HOSTFXR_STATE* pState,
223 __in LPCWSTR wzNativeHostPath
224 )
225{
226 HRESULT hr = S_OK;
227
228 hr = pState->pfnHostfxrGetRuntimeDelegate(pState->hostContextHandle, hdt_get_function_pointer, reinterpret_cast<void**>(&pState->pfnGetFunctionPointer));
229 if (InvalidArgFailure == hr || // old versions of hostfxr don't allow calling GetRuntimeDelegate from InitializeForApp.
230 HostApiUnsupportedVersion == hr) // hdt_get_function_pointer was added in .NET 5.
231 {
232 hr = InitializeCoreClrPre5(pState, wzNativeHostPath);
233 }
234 else
235 {
236 ExitOnFailure(hr, "HostfxrGetRuntimeDelegate failed");
237 }
238
239LExit:
240 return hr;
241}
242
243static HRESULT InitializeCoreClrPre5(
244 __in HOSTFXR_STATE* pState,
245 __in LPCWSTR wzNativeHostPath
246 )
247{
248 HRESULT hr = S_OK;
249 int32_t rc = 0;
250 LPCWSTR* rgPropertyKeys = NULL;
251 LPCWSTR* rgPropertyValues = NULL;
252 size_t cProperties = 0;
253 LPWSTR* rgDirectories = NULL;
254 UINT cDirectories = 0;
255 LPWSTR sczCoreClrPath = NULL;
256
257 // We are not using hostfxr as it was intended to be used. We need to initialize hostfxr so that it properly initializes hostpolicy -
258 // there are pieces of the framework such as AssemblyDependencyResolver that won't work without that. We also need hostfxr to find a
259 // compatible framework for framework-dependent deployed BAs. We had to use hostfxr_initialize_for_dotnet_command_line since
260 // hostfxr_initialize_for_runtime_config doesn't currently (3.x) support self-contained deployed BAs. That means we're supposed to
261 // start the runtime through hostfxr_run_app, but that method shuts down the runtime before returning. We actually want to call
262 // hostfxr_get_runtime_delegate, but that method currently requires hostfxr to be initialized through
263 // hostfxr_initialize_for_runtime_config. So we're forced to locate coreclr.dll and manually load the runtime ourselves.
264
265 // Unfortunately, that's not the only problem. hostfxr has global state that tracks whether it started the runtime. While we keep our
266 // hostfxr_handle open, everyone that calls the hostfxr_initialize_* methods will block until we have started the runtime through
267 // hostfxr or closed our handle. If we close the handle, then hostfxr could potentially try to load a second runtime into the
268 // process, which is not supported. We're going to just keep our handle open since no one else in the process should be trying to
269 // start the runtime anyway.
270
271 rc = pState->pfnHostfxrGetRuntimeProperties(pState->hostContextHandle, &cProperties, rgPropertyKeys, rgPropertyValues);
272 if (HostApiBufferTooSmall != rc)
273 {
274 BalExitOnFailure(hr = rc, "HostfxrGetRuntimeProperties failed to return required size.");
275 }
276
277 rgPropertyKeys = static_cast<LPCWSTR*>(MemAlloc(sizeof(LPWSTR) * cProperties, TRUE));
278 rgPropertyValues = static_cast<LPCWSTR*>(MemAlloc(sizeof(LPWSTR) * cProperties, TRUE));
279 if (!rgPropertyKeys || !rgPropertyValues)
280 {
281 BalExitOnFailure(hr = E_OUTOFMEMORY, "Failed to allocate buffers for runtime properties.");
282 }
283
284 hr = pState->pfnHostfxrGetRuntimeProperties(pState->hostContextHandle, &cProperties, rgPropertyKeys, rgPropertyValues);
285 BalExitOnFailure(hr, "HostfxrGetRuntimeProperties failed.");
286
287 for (DWORD i = 0; i < cProperties; ++i)
288 {
289 if (CSTR_EQUAL == ::CompareString(LOCALE_INVARIANT, 0, rgPropertyKeys[i], -1, L"NATIVE_DLL_SEARCH_DIRECTORIES", -1))
290 {
291 hr = StrSplitAllocArray(&rgDirectories, &cDirectories, rgPropertyValues[i], L";");
292 BalExitOnFailure(hr, "Failed to split NATIVE_DLL_SEARCH_DIRECTORIES '%ls'", rgPropertyValues[i]);
293 }
294 }
295
296 for (DWORD i = 0; i < cDirectories; ++i)
297 {
298 hr = PathConcat(rgDirectories[i], L"coreclr.dll", &sczCoreClrPath);
299 BalExitOnFailure(hr, "Failed to allocate path to coreclr.");
300
301 if (::PathFileExists(sczCoreClrPath))
302 {
303 break;
304 }
305 else
306 {
307 ReleaseNullStr(sczCoreClrPath);
308 }
309 }
310
311 if (!sczCoreClrPath)
312 {
313 for (DWORD i = 0; i < cProperties; ++i)
314 {
315 BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "%ls: %ls", rgPropertyKeys[i], rgPropertyValues[i]);
316 }
317 BalExitOnFailure(hr = E_FILENOTFOUND, "Failed to locate coreclr.dll.");
318 }
319
320 hr = LoadCoreClr(pState, sczCoreClrPath);
321 BalExitOnFailure(hr, "Failed to load coreclr.");
322
323 hr = StartCoreClr(pState, wzNativeHostPath, (DWORD)cProperties, rgPropertyKeys, rgPropertyValues);
324 BalExitOnFailure(hr, "Failed to start coreclr.");
325
326LExit:
327 MemFree(rgDirectories);
328 MemFree(rgPropertyValues);
329 MemFree(rgPropertyKeys);
330 ReleaseStr(sczCoreClrPath);
331
332 return hr;
333}
334
335static HRESULT LoadCoreClr(
336 __in HOSTFXR_STATE* pState,
337 __in LPCWSTR wzCoreClrPath
338 )
339{
340 HRESULT hr = S_OK;
341 HMODULE hModule = NULL;
342
343 hModule = ::LoadLibraryExW(wzCoreClrPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
344 BalExitOnNullWithLastError(hModule, hr, "Failed to load coreclr.dll from '%ls'.", wzCoreClrPath);
345
346 pState->pfnCoreclrInitialize = reinterpret_cast<coreclr_initialize_ptr>(::GetProcAddress(hModule, "coreclr_initialize"));
347 BalExitOnNullWithLastError(pState->pfnCoreclrInitialize, hr, "Failed to get procedure address for coreclr_initialize.");
348
349 pState->pfnCoreclrCreateDelegate = reinterpret_cast<coreclr_create_delegate_ptr>(::GetProcAddress(hModule, "coreclr_create_delegate"));
350 BalExitOnNullWithLastError(pState->pfnCoreclrCreateDelegate, hr, "Failed to get procedure address for coreclr_create_delegate.");
351
352LExit:
353 // Never unload the module since coreclr doesn't support it.
354
355 return hr;
356}
357
358static HRESULT StartCoreClr(
359 __in HOSTFXR_STATE* pState,
360 __in LPCWSTR wzNativeHostPath,
361 __in DWORD cProperties,
362 __in LPCWSTR* propertyKeys,
363 __in LPCWSTR* propertyValues
364 )
365{
366 HRESULT hr = S_OK;
367 LPSTR szNativeHostPath = NULL;
368 LPSTR* rgPropertyKeys = NULL;
369 LPSTR* rgPropertyValues = NULL;
370
371 rgPropertyKeys = static_cast<LPSTR*>(MemAlloc(sizeof(LPSTR) * cProperties, TRUE));
372 rgPropertyValues = static_cast<LPSTR*>(MemAlloc(sizeof(LPSTR) * cProperties, TRUE));
373 if (!rgPropertyKeys || !rgPropertyValues)
374 {
375 BalExitOnFailure(hr = E_OUTOFMEMORY, "Failed to allocate buffers for runtime properties.");
376 }
377
378 hr = StrAnsiAllocString(&szNativeHostPath, wzNativeHostPath, 0, CP_UTF8);
379 BalExitOnFailure(hr, "Failed to convert module path to UTF8: %ls", wzNativeHostPath);
380
381 for (DWORD i = 0; i < cProperties; ++i)
382 {
383 hr = StrAnsiAllocString(&rgPropertyKeys[i], propertyKeys[i], 0, CP_UTF8);
384 BalExitOnFailure(hr, "Failed to convert property key to UTF8: %ls", propertyKeys[i]);
385
386 hr = StrAnsiAllocString(&rgPropertyValues[i], propertyValues[i], 0, CP_UTF8);
387 BalExitOnFailure(hr, "Failed to convert property value to UTF8: %ls", propertyValues[i]);
388 }
389
390 hr = pState->pfnCoreclrInitialize(szNativeHostPath, "MBA", cProperties, (LPCSTR*)rgPropertyKeys, (LPCSTR*)rgPropertyValues, &pState->pClrHandle, &pState->dwDomainId);
391 BalExitOnFailure(hr, "CoreclrInitialize failed.");
392
393LExit:
394 for (DWORD i = 0; i < cProperties; ++i)
395 {
396 if (rgPropertyKeys)
397 {
398 ReleaseStr(rgPropertyKeys[i]);
399 }
400
401 if (rgPropertyValues)
402 {
403 ReleaseStr(rgPropertyValues[i]);
404 }
405 }
406 ReleaseMem(rgPropertyValues);
407 ReleaseMem(rgPropertyKeys);
408 ReleaseStr(szNativeHostPath);
409
410 return hr;
411}
diff --git a/src/ext/Bal/dnchost/dncutil.h b/src/ext/Bal/dnchost/dncutil.h
new file mode 100644
index 00000000..85eda3b2
--- /dev/null
+++ b/src/ext/Bal/dnchost/dncutil.h
@@ -0,0 +1,38 @@
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
4typedef IBootstrapperApplicationFactory* (STDMETHODCALLTYPE* PFNCREATEBAFACTORY)(
5 __in LPCWSTR wzBaFactoryAssemblyName,
6 __in LPCWSTR wzBaFactoryAssemblyPath
7 );
8
9struct HOSTFXR_STATE
10{
11 LPWSTR sczHostfxrPath;
12 hostfxr_handle hostContextHandle;
13 hostfxr_initialize_for_dotnet_command_line_fn pfnHostfxrInitializeForApp;
14 hostfxr_get_runtime_properties_fn pfnHostfxrGetRuntimeProperties;
15 hostfxr_set_error_writer_fn pfnHostfxrSetErrorWriter;
16 hostfxr_close_fn pfnHostfxrClose;
17 hostfxr_get_runtime_delegate_fn pfnHostfxrGetRuntimeDelegate;
18 get_function_pointer_fn pfnGetFunctionPointer;
19 coreclr_initialize_ptr pfnCoreclrInitialize;
20 coreclr_create_delegate_ptr pfnCoreclrCreateDelegate;
21 void* pClrHandle;
22 UINT dwDomainId;
23};
24
25HRESULT DnchostLoadRuntime(
26 __in HOSTFXR_STATE* pState,
27 __in LPCWSTR wzNativeHostPath,
28 __in LPCWSTR wzManagedHostPath,
29 __in LPCWSTR wzDepsJsonPath,
30 __in LPCWSTR wzRuntimeConfigPath
31 );
32
33HRESULT DnchostCreateFactory(
34 __in HOSTFXR_STATE* pState,
35 __in LPCWSTR wzBaFactoryAssemblyName,
36 __in LPCWSTR wzBaFactoryAssemblyPath,
37 __out IBootstrapperApplicationFactory** ppAppFactory
38 );
diff --git a/src/ext/Bal/dnchost/packages.config b/src/ext/Bal/dnchost/packages.config
new file mode 100644
index 00000000..6c369364
--- /dev/null
+++ b/src/ext/Bal/dnchost/packages.config
@@ -0,0 +1,13 @@
1<?xml version="1.0" encoding="utf-8"?>
2<packages>
3 <package id="Microsoft.Build.Tasks.Git" 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" />
6 <package id="Nerdbank.GitVersioning" version="3.3.37" targetFramework="native" developmentDependency="true" />
7 <package id="runtime.win-arm64.Microsoft.NETCore.DotNetAppHost" version="5.0.0" targetFramework="native" />
8 <package id="runtime.win-x64.Microsoft.NETCore.DotNetAppHost" version="5.0.0" targetFramework="native" />
9 <package id="runtime.win-x86.Microsoft.NETCore.DotNetAppHost" version="5.0.0" targetFramework="native" />
10 <package id="WixToolset.BalUtil" version="4.0.58" targetFramework="native" />
11 <package id="WixToolset.BootstrapperCore.Native" version="4.0.141" targetFramework="native" />
12 <package id="WixToolset.DUtil" version="4.0.72" targetFramework="native" />
13</packages> \ No newline at end of file
diff --git a/src/ext/Bal/dnchost/precomp.cpp b/src/ext/Bal/dnchost/precomp.cpp
new file mode 100644
index 00000000..37664a1c
--- /dev/null
+++ b/src/ext/Bal/dnchost/precomp.cpp
@@ -0,0 +1,3 @@
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"
diff --git a/src/ext/Bal/dnchost/precomp.h b/src/ext/Bal/dnchost/precomp.h
new file mode 100644
index 00000000..84ff6424
--- /dev/null
+++ b/src/ext/Bal/dnchost/precomp.h
@@ -0,0 +1,31 @@
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#include <windows.h>
5#include <msiquery.h>
6#include <corerror.h>
7#include <Shlwapi.h>
8
9#include <dutil.h>
10#include <memutil.h>
11#include <pathutil.h>
12#include <strutil.h>
13#include <xmlutil.h>
14
15#include <BootstrapperEngine.h>
16#include <BootstrapperApplication.h>
17
18#include <IBootstrapperEngine.h>
19#include <IBootstrapperApplication.h>
20#include <IBootstrapperApplicationFactory.h>
21#include <balutil.h>
22
23#include <WixToolset.Dnc.Host.h>
24#define NETHOST_USE_AS_STATIC
25#include <nethost.h>
26#include <hostfxr.h>
27#include <coreclr_delegates.h>
28
29#include "coreclrhost.h"
30#include "dncutil.h"
31#include "dnchost.h"
diff --git a/src/ext/Bal/mbahost/mbahost.cpp b/src/ext/Bal/mbahost/mbahost.cpp
new file mode 100644
index 00000000..735f9f21
--- /dev/null
+++ b/src/ext/Bal/mbahost/mbahost.cpp
@@ -0,0 +1,649 @@
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 <WixToolset.Mba.Host.h> // includes the generated assembly name macros.
5
6static const DWORD NET452_RELEASE = 379893;
7
8using namespace mscorlib;
9
10extern "C" typedef HRESULT (WINAPI *PFN_CORBINDTOCURRENTRUNTIME)(
11 __in LPCWSTR pwszFileName,
12 __in REFCLSID rclsid,
13 __in REFIID riid,
14 __out LPVOID *ppv
15 );
16
17extern "C" typedef HRESULT(WINAPI *PFN_MBAPREQ_BOOTSTRAPPER_APPLICATION_CREATE)(
18 __in HRESULT hrHostInitialization,
19 __in IBootstrapperEngine* pEngine,
20 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
21 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults
22 );
23
24static HINSTANCE vhInstance = NULL;
25static ICorRuntimeHost *vpCLRHost = NULL;
26static _AppDomain *vpAppDomain = NULL;
27static HMODULE vhMbapreqModule = NULL;
28
29
30// internal function declarations
31
32static HRESULT GetAppDomain(
33 __out _AppDomain** ppAppDomain
34 );
35static HRESULT GetAppBase(
36 __out LPWSTR* psczAppBase
37 );
38static HRESULT CheckSupportedFrameworks(
39 __in LPCWSTR wzConfigPath
40 );
41static HRESULT UpdateSupportedRuntime(
42 __in IXMLDOMDocument* pixdManifest,
43 __in IXMLDOMNode* pixnSupportedFramework,
44 __out BOOL* pfUpdatedManifest
45 );
46static HRESULT GetCLRHost(
47 __in LPCWSTR wzConfigPath,
48 __out ICorRuntimeHost** ppCLRHost
49 );
50static HRESULT CreateManagedBootstrapperApplication(
51 __in _AppDomain* pAppDomain,
52 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
53 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults
54 );
55static HRESULT CreateManagedBootstrapperApplicationFactory(
56 __in _AppDomain* pAppDomain,
57 __out IBootstrapperApplicationFactory** ppAppFactory
58 );
59static HRESULT CreatePrerequisiteBA(
60 __in HRESULT hrHostInitialization,
61 __in IBootstrapperEngine* pEngine,
62 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
63 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults
64 );
65static HRESULT VerifyNET4RuntimeIsSupported(
66 );
67
68
69// function definitions
70
71extern "C" BOOL WINAPI DllMain(
72 IN HINSTANCE hInstance,
73 IN DWORD dwReason,
74 IN LPVOID /* pvReserved */
75 )
76{
77 switch (dwReason)
78 {
79 case DLL_PROCESS_ATTACH:
80 ::DisableThreadLibraryCalls(hInstance);
81 vhInstance = hInstance;
82 break;
83
84 case DLL_PROCESS_DETACH:
85 vhInstance = NULL;
86 break;
87 }
88
89 return TRUE;
90}
91
92// Note: This function assumes that COM was already initialized on the thread.
93extern "C" HRESULT WINAPI BootstrapperApplicationCreate(
94 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
95 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults
96 )
97{
98 HRESULT hr = S_OK;
99 HRESULT hrHostInitialization = S_OK;
100 IBootstrapperEngine* pEngine = NULL;
101
102 hr = BalInitializeFromCreateArgs(pArgs, &pEngine);
103 ExitOnFailure(hr, "Failed to initialize Bal.");
104
105 hr = GetAppDomain(&vpAppDomain);
106 if (SUCCEEDED(hr))
107 {
108 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Loading managed bootstrapper application.");
109
110 hr = CreateManagedBootstrapperApplication(vpAppDomain, pArgs, pResults);
111 BalExitOnFailure(hr, "Failed to create the managed bootstrapper application.");
112 }
113 else // fallback to the prerequisite BA.
114 {
115 if (E_MBAHOST_NET452_ON_WIN7RTM == hr)
116 {
117 BalLogError(hr, "The Burn engine cannot run with an MBA under the .NET 4 CLR on Windows 7 RTM with .NET 4.5.2 (or greater) installed.");
118 hrHostInitialization = hr;
119 }
120 else
121 {
122 hrHostInitialization = S_OK;
123 }
124
125 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Loading prerequisite bootstrapper application because managed host could not be loaded, error: 0x%08x.", hr);
126
127 hr = CreatePrerequisiteBA(hrHostInitialization, pEngine, pArgs, pResults);
128 BalExitOnFailure(hr, "Failed to create the pre-requisite bootstrapper application.");
129 }
130
131LExit:
132 ReleaseNullObject(pEngine);
133
134 return hr;
135}
136
137extern "C" void WINAPI BootstrapperApplicationDestroy()
138{
139 if (vpAppDomain)
140 {
141 HRESULT hr = vpCLRHost->UnloadDomain(vpAppDomain);
142 if (FAILED(hr))
143 {
144 BalLogError(hr, "Failed to unload app domain.");
145 }
146
147 vpAppDomain->Release();
148 }
149
150 if (vpCLRHost)
151 {
152 vpCLRHost->Stop();
153 vpCLRHost->Release();
154 }
155
156 if (vhMbapreqModule)
157 {
158 PFN_BOOTSTRAPPER_APPLICATION_DESTROY pfnDestroy = reinterpret_cast<PFN_BOOTSTRAPPER_APPLICATION_DESTROY>(::GetProcAddress(vhMbapreqModule, "MbaPrereqBootstrapperApplicationDestroy"));
159 if (pfnDestroy)
160 {
161 (*pfnDestroy)();
162 }
163
164 ::FreeLibrary(vhMbapreqModule);
165 vhMbapreqModule = NULL;
166 }
167
168 BalUninitialize();
169}
170
171// Gets the custom AppDomain for loading managed BA.
172static HRESULT GetAppDomain(
173 __out _AppDomain **ppAppDomain
174 )
175{
176 HRESULT hr = S_OK;
177 ICorRuntimeHost *pCLRHost = NULL;
178 IUnknown *pUnk = NULL;
179 LPWSTR sczAppBase = NULL;
180 LPWSTR sczConfigPath = NULL;
181 IAppDomainSetup *pAppDomainSetup;
182 BSTR bstrAppBase = NULL;
183 BSTR bstrConfigPath = NULL;
184
185 hr = GetAppBase(&sczAppBase);
186 ExitOnFailure(hr, "Failed to get the host base path.");
187
188 hr = PathConcat(sczAppBase, MBA_CONFIG_FILE_NAME, &sczConfigPath);
189 ExitOnFailure(hr, "Failed to get the full path to the application configuration file.");
190
191 // Check that the supported framework is installed.
192 hr = CheckSupportedFrameworks(sczConfigPath);
193 ExitOnFailure(hr, "Failed to find supported framework.");
194
195 // Load the CLR.
196 hr = GetCLRHost(sczConfigPath, &pCLRHost);
197 ExitOnFailure(hr, "Failed to create the CLR host.");
198
199 hr = pCLRHost->Start();
200 ExitOnRootFailure(hr, "Failed to start the CLR host.");
201
202 // Create the setup information for a new AppDomain to set the app base and config.
203 hr = pCLRHost->CreateDomainSetup(&pUnk);
204 ExitOnRootFailure(hr, "Failed to create the AppDomainSetup object.");
205
206 hr = pUnk->QueryInterface(__uuidof(IAppDomainSetup), reinterpret_cast<LPVOID*>(&pAppDomainSetup));
207 ExitOnRootFailure(hr, "Failed to query for the IAppDomainSetup interface.");
208 ReleaseNullObject(pUnk);
209
210 // Set properties on the AppDomainSetup object.
211 bstrAppBase = ::SysAllocString(sczAppBase);
212 ExitOnNull(bstrAppBase, hr, E_OUTOFMEMORY, "Failed to allocate the application base path for the AppDomainSetup.");
213
214 hr = pAppDomainSetup->put_ApplicationBase(bstrAppBase);
215 ExitOnRootFailure(hr, "Failed to set the application base path for the AppDomainSetup.");
216
217 bstrConfigPath = ::SysAllocString(sczConfigPath);
218 ExitOnNull(bstrConfigPath, hr, E_OUTOFMEMORY, "Failed to allocate the application configuration file for the AppDomainSetup.");
219
220 hr = pAppDomainSetup->put_ConfigurationFile(bstrConfigPath);
221 ExitOnRootFailure(hr, "Failed to set the configuration file path for the AppDomainSetup.");
222
223 // Create the AppDomain to load the factory type.
224 hr = pCLRHost->CreateDomainEx(L"MBA", pAppDomainSetup, NULL, &pUnk);
225 ExitOnRootFailure(hr, "Failed to create the MBA AppDomain.");
226
227 hr = pUnk->QueryInterface(__uuidof(_AppDomain), reinterpret_cast<LPVOID*>(ppAppDomain));
228 ExitOnRootFailure(hr, "Failed to query for the _AppDomain interface.");
229
230LExit:
231 ReleaseBSTR(bstrConfigPath);
232 ReleaseBSTR(bstrAppBase);
233 ReleaseStr(sczConfigPath);
234 ReleaseStr(sczAppBase);
235 ReleaseNullObject(pUnk);
236 ReleaseNullObject(pCLRHost);
237
238 return hr;
239}
240
241static HRESULT GetAppBase(
242 __out LPWSTR *psczAppBase
243 )
244{
245 HRESULT hr = S_OK;
246 LPWSTR sczFullPath = NULL;
247
248 hr = PathForCurrentProcess(&sczFullPath, vhInstance);
249 ExitOnFailure(hr, "Failed to get the full host path.");
250
251 hr = PathGetDirectory(sczFullPath, psczAppBase);
252 ExitOnFailure(hr, "Failed to get the directory of the full process path.");
253
254LExit:
255 ReleaseStr(sczFullPath);
256
257 return hr;
258}
259
260// Checks whether at least one of required supported frameworks is installed via the NETFX registry keys.
261static HRESULT CheckSupportedFrameworks(
262 __in LPCWSTR wzConfigPath
263 )
264{
265 HRESULT hr = S_OK;
266 IXMLDOMDocument* pixdManifest = NULL;
267 IXMLDOMNodeList* pNodeList = NULL;
268 IXMLDOMNode* pNode = NULL;
269 DWORD cSupportedFrameworks = 0;
270 LPWSTR sczSupportedFrameworkVersion = NULL;
271 LPWSTR sczFrameworkRegistryKey = NULL;
272 HKEY hkFramework = NULL;
273 DWORD dwFrameworkInstalled = 0;
274 BOOL fUpdatedManifest = FALSE;
275
276 hr = XmlInitialize();
277 ExitOnFailure(hr, "Failed to initialize XML.");
278
279 hr = XmlLoadDocumentFromFile(wzConfigPath, &pixdManifest);
280 ExitOnFailure(hr, "Failed to load bootstrapper config file from path: %ls", wzConfigPath);
281
282 hr = XmlSelectNodes(pixdManifest, L"/configuration/wix.bootstrapper/host/supportedFramework", &pNodeList);
283 ExitOnFailure(hr, "Failed to select all supportedFramework elements.");
284
285 hr = pNodeList->get_length(reinterpret_cast<long*>(&cSupportedFrameworks));
286 ExitOnFailure(hr, "Failed to get the supported framework count.");
287
288 if (cSupportedFrameworks)
289 {
290 while (S_OK == (hr = XmlNextElement(pNodeList, &pNode, NULL)))
291 {
292 hr = XmlGetAttributeEx(pNode, L"version", &sczSupportedFrameworkVersion);
293 ExitOnFailure(hr, "Failed to get supportedFramework/@version.");
294
295 hr = StrAllocFormatted(&sczFrameworkRegistryKey, L"SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\%ls", sczSupportedFrameworkVersion);
296 ExitOnFailure(hr, "Failed to allocate path to supported framework Install registry key.");
297
298 hr = RegOpen(HKEY_LOCAL_MACHINE, sczFrameworkRegistryKey, KEY_READ, &hkFramework);
299 if (SUCCEEDED(hr))
300 {
301 hr = RegReadNumber(hkFramework, L"Install", &dwFrameworkInstalled);
302 if (dwFrameworkInstalled)
303 {
304 hr = S_OK;
305 break;
306 }
307 }
308
309 ReleaseNullObject(pNode);
310 }
311
312 // If we looped through all the supported frameworks but didn't find anything, ensure we return a failure.
313 if (S_FALSE == hr)
314 {
315 hr = E_NOTFOUND;
316 ExitOnRootFailure(hr, "Failed to find a supported framework.");
317 }
318
319 hr = UpdateSupportedRuntime(pixdManifest, pNode, &fUpdatedManifest);
320 ExitOnFailure(hr, "Failed to update supportedRuntime.");
321 }
322 // else no supported frameworks specified, so the startup/supportedRuntime must be enough.
323
324 if (fUpdatedManifest)
325 {
326 hr = XmlSaveDocument(pixdManifest, wzConfigPath);
327 ExitOnFailure(hr, "Failed to save updated manifest over config file: %ls", wzConfigPath);
328 }
329
330LExit:
331 ReleaseRegKey(hkFramework);
332 ReleaseStr(sczFrameworkRegistryKey);
333 ReleaseStr(sczSupportedFrameworkVersion);
334 ReleaseObject(pNode);
335 ReleaseObject(pNodeList);
336 ReleaseObject(pixdManifest);
337
338 XmlUninitialize();
339
340 return hr;
341}
342
343// Fixes the supportedRuntime element if necessary.
344static HRESULT UpdateSupportedRuntime(
345 __in IXMLDOMDocument* pixdManifest,
346 __in IXMLDOMNode* pixnSupportedFramework,
347 __out BOOL* pfUpdatedManifest
348 )
349{
350 HRESULT hr = S_OK;
351 LPWSTR sczSupportedRuntimeVersion = NULL;
352 IXMLDOMNode* pixnStartup = NULL;
353 IXMLDOMNode* pixnSupportedRuntime = NULL;
354
355 *pfUpdatedManifest = FALSE;
356
357 // If the runtime version attribute is not specified, don't update the manifest.
358 hr = XmlGetAttributeEx(pixnSupportedFramework, L"runtimeVersion", &sczSupportedRuntimeVersion);
359 if (E_NOTFOUND == hr)
360 {
361 ExitFunction1(hr = S_OK);
362 }
363 ExitOnFailure(hr, "Failed to get supportedFramework/@runtimeVersion.");
364
365 // Get the startup element. Fail if we can't find it since it'll be necessary to load the
366 // correct runtime.
367 hr = XmlSelectSingleNode(pixdManifest, L"/configuration/startup", &pixnStartup);
368 ExitOnFailure(hr, "Failed to get startup element.");
369
370 if (S_FALSE == hr)
371 {
372 hr = E_NOTFOUND;
373 ExitOnRootFailure(hr, "Failed to find startup element in bootstrapper application config.");
374 }
375
376 // Remove any pre-existing supported runtimes because they'll just get in the way and create our new one.
377 hr = XmlRemoveChildren(pixnStartup, L"supportedRuntime");
378 ExitOnFailure(hr, "Failed to remove pre-existing supportedRuntime elements.");
379
380 hr = XmlCreateChild(pixnStartup, L"supportedRuntime", &pixnSupportedRuntime);
381 ExitOnFailure(hr, "Failed to create supportedRuntime element.");
382
383 hr = XmlSetAttribute(pixnSupportedRuntime, L"version", sczSupportedRuntimeVersion);
384 ExitOnFailure(hr, "Failed to set supportedRuntime/@version to '%ls'.", sczSupportedRuntimeVersion);
385
386 *pfUpdatedManifest = TRUE;
387
388LExit:
389 ReleaseObject(pixnSupportedRuntime);
390 ReleaseObject(pixnStartup);
391 ReleaseStr(sczSupportedRuntimeVersion);
392
393 return hr;
394}
395
396// Gets the CLR host and caches it.
397static HRESULT GetCLRHost(
398 __in LPCWSTR wzConfigPath,
399 __out ICorRuntimeHost **ppCLRHost
400 )
401{
402 HRESULT hr = S_OK;
403 UINT uiMode = 0;
404 HMODULE hModule = NULL;
405 BOOL fFallbackToCorBindToCurrentRuntime = TRUE;
406 CLRCreateInstanceFnPtr pfnCLRCreateInstance = NULL;
407 ICLRMetaHostPolicy* pCLRMetaHostPolicy = NULL;
408 IStream* pCfgStream = NULL;
409 LPWSTR pwzVersion = NULL;
410 DWORD cchVersion = 0;
411 DWORD dwConfigFlags = 0;
412 ICLRRuntimeInfo* pCLRRuntimeInfo = NULL;
413 PFN_CORBINDTOCURRENTRUNTIME pfnCorBindToCurrentRuntime = NULL;
414
415 // Always set the error mode because we will always restore it below.
416 uiMode = ::SetErrorMode(0);
417
418 // Cache the CLR host to be shutdown later. This can occur on a different thread.
419 if (!vpCLRHost)
420 {
421 // Disable message boxes from being displayed on error and blocking execution.
422 ::SetErrorMode(uiMode | SEM_FAILCRITICALERRORS);
423
424 hr = LoadSystemLibrary(L"mscoree.dll", &hModule);
425 ExitOnFailure(hr, "Failed to load mscoree.dll");
426
427 pfnCLRCreateInstance = reinterpret_cast<CLRCreateInstanceFnPtr>(::GetProcAddress(hModule, "CLRCreateInstance"));
428
429 if (pfnCLRCreateInstance)
430 {
431 hr = pfnCLRCreateInstance(CLSID_CLRMetaHostPolicy, IID_ICLRMetaHostPolicy, reinterpret_cast<LPVOID*>(&pCLRMetaHostPolicy));
432 if (E_NOTIMPL != hr)
433 {
434 ExitOnRootFailure(hr, "Failed to create instance of ICLRMetaHostPolicy.");
435
436 fFallbackToCorBindToCurrentRuntime = FALSE;
437 }
438 }
439
440 if (fFallbackToCorBindToCurrentRuntime)
441 {
442 pfnCorBindToCurrentRuntime = reinterpret_cast<PFN_CORBINDTOCURRENTRUNTIME>(::GetProcAddress(hModule, "CorBindToCurrentRuntime"));
443 ExitOnNullWithLastError(pfnCorBindToCurrentRuntime, hr, "Failed to get procedure address for CorBindToCurrentRuntime.");
444
445 hr = pfnCorBindToCurrentRuntime(wzConfigPath, CLSID_CorRuntimeHost, IID_ICorRuntimeHost, reinterpret_cast<LPVOID*>(&vpCLRHost));
446 ExitOnRootFailure(hr, "Failed to create the CLR host using the application configuration file path.");
447 }
448 else
449 {
450
451 hr = SHCreateStreamOnFileEx(wzConfigPath, STGM_READ | STGM_SHARE_DENY_WRITE, 0, FALSE, NULL, &pCfgStream);
452 ExitOnFailure(hr, "Failed to load bootstrapper config file from path: %ls", wzConfigPath);
453
454 hr = pCLRMetaHostPolicy->GetRequestedRuntime(METAHOST_POLICY_HIGHCOMPAT, NULL, pCfgStream, NULL, &cchVersion, NULL, NULL, &dwConfigFlags, IID_ICLRRuntimeInfo, reinterpret_cast<LPVOID*>(&pCLRRuntimeInfo));
455 ExitOnRootFailure(hr, "Failed to get the CLR runtime info using the application configuration file path.");
456
457 // .NET 4 RTM had a bug where it wouldn't set pcchVersion if pwzVersion was NULL.
458 if (!cchVersion)
459 {
460 hr = pCLRRuntimeInfo->GetVersionString(NULL, &cchVersion);
461 if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr)
462 {
463 ExitOnFailure(hr, "Failed to get the length of the CLR version string.");
464 }
465 }
466
467 hr = StrAlloc(&pwzVersion, cchVersion);
468 ExitOnFailure(hr, "Failed to allocate the CLR version string.");
469
470 hr = pCLRRuntimeInfo->GetVersionString(pwzVersion, &cchVersion);
471 ExitOnFailure(hr, "Failed to get the CLR version string.");
472
473 if (CSTR_EQUAL == CompareString(LOCALE_NEUTRAL, 0, L"v4.0.30319", -1, pwzVersion, cchVersion))
474 {
475 hr = VerifyNET4RuntimeIsSupported();
476 ExitOnFailure(hr, "Found unsupported .NET 4 Runtime.");
477 }
478
479 if (METAHOST_CONFIG_FLAGS_LEGACY_V2_ACTIVATION_POLICY_TRUE == (METAHOST_CONFIG_FLAGS_LEGACY_V2_ACTIVATION_POLICY_MASK & dwConfigFlags))
480 {
481 hr = pCLRRuntimeInfo->BindAsLegacyV2Runtime();
482 ExitOnRootFailure(hr, "Failed to bind as legacy V2 runtime.");
483 }
484
485 hr = pCLRRuntimeInfo->GetInterface(CLSID_CorRuntimeHost, IID_ICorRuntimeHost, reinterpret_cast<LPVOID*>(&vpCLRHost));
486 ExitOnRootFailure(hr, "Failed to get instance of ICorRuntimeHost.");
487
488 // TODO: use ICLRRuntimeHost instead of ICorRuntimeHost on .NET 4 since the former is faster and the latter is deprecated
489 //hr = pCLRRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, reinterpret_cast<LPVOID*>(&pCLRRuntimeHost));
490 //ExitOnRootFailure(hr, "Failed to get instance of ICLRRuntimeHost.");
491 }
492 }
493
494 vpCLRHost->AddRef();
495 *ppCLRHost = vpCLRHost;
496
497LExit:
498 ReleaseStr(pwzVersion);
499 ReleaseNullObject(pCLRRuntimeInfo);
500 ReleaseNullObject(pCfgStream);
501 ReleaseNullObject(pCLRMetaHostPolicy);
502
503 // Unload the module so it's not in use when we install .NET.
504 if (FAILED(hr))
505 {
506 ::FreeLibrary(hModule);
507 }
508
509 ::SetErrorMode(uiMode); // restore the previous error mode.
510
511 return hr;
512}
513
514// Creates the bootstrapper app and returns it for the engine.
515static HRESULT CreateManagedBootstrapperApplication(
516 __in _AppDomain* pAppDomain,
517 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
518 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults
519 )
520{
521 HRESULT hr = S_OK;
522 IBootstrapperApplicationFactory* pAppFactory = NULL;
523
524 hr = CreateManagedBootstrapperApplicationFactory(pAppDomain, &pAppFactory);
525 ExitOnFailure(hr, "Failed to create the factory to create the bootstrapper application.");
526
527 hr = pAppFactory->Create(pArgs, pResults);
528 ExitOnFailure(hr, "Failed to create the bootstrapper application.");
529
530LExit:
531 ReleaseNullObject(pAppFactory);
532
533 return hr;
534}
535
536// Creates the app factory to create the managed app in the default AppDomain.
537static HRESULT CreateManagedBootstrapperApplicationFactory(
538 __in _AppDomain* pAppDomain,
539 __out IBootstrapperApplicationFactory** ppAppFactory
540 )
541{
542 HRESULT hr = S_OK;
543 BSTR bstrAssemblyName = NULL;
544 BSTR bstrTypeName = NULL;
545 _ObjectHandle* pObj = NULL;
546 VARIANT vtBAFactory;
547
548 ::VariantInit(&vtBAFactory);
549
550 bstrAssemblyName = ::SysAllocString(MBA_ASSEMBLY_FULL_NAME);
551 ExitOnNull(bstrAssemblyName, hr, E_OUTOFMEMORY, "Failed to allocate the full assembly name for the bootstrapper application factory.");
552
553 bstrTypeName = ::SysAllocString(MBA_ENTRY_TYPE);
554 ExitOnNull(bstrTypeName, hr, E_OUTOFMEMORY, "Failed to allocate the full type name for the BA factory.");
555
556 hr = pAppDomain->CreateInstance(bstrAssemblyName, bstrTypeName, &pObj);
557 ExitOnRootFailure(hr, "Failed to create the BA factory object.");
558
559 hr = pObj->Unwrap(&vtBAFactory);
560 ExitOnRootFailure(hr, "Failed to unwrap the BA factory object into the host domain.");
561 ExitOnNull(vtBAFactory.punkVal, hr, E_UNEXPECTED, "The variant did not contain the expected IUnknown pointer.");
562
563 hr = vtBAFactory.punkVal->QueryInterface(__uuidof(IBootstrapperApplicationFactory), reinterpret_cast<LPVOID*>(ppAppFactory));
564 ExitOnRootFailure(hr, "Failed to query for the bootstrapper app factory interface.");
565
566LExit:
567 ReleaseVariant(vtBAFactory);
568 ReleaseNullObject(pObj);
569 ReleaseBSTR(bstrTypeName);
570 ReleaseBSTR(bstrAssemblyName);
571
572 return hr;
573}
574
575static HRESULT CreatePrerequisiteBA(
576 __in HRESULT hrHostInitialization,
577 __in IBootstrapperEngine* pEngine,
578 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
579 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults
580 )
581{
582 HRESULT hr = S_OK;
583 LPWSTR sczMbapreqPath = NULL;
584 HMODULE hModule = NULL;
585
586 hr = PathRelativeToModule(&sczMbapreqPath, L"mbapreq.dll", vhInstance);
587 ExitOnFailure(hr, "Failed to get path to pre-requisite BA.");
588
589 hModule = ::LoadLibraryW(sczMbapreqPath);
590 ExitOnNullWithLastError(hModule, hr, "Failed to load pre-requisite BA DLL.");
591
592 PFN_MBAPREQ_BOOTSTRAPPER_APPLICATION_CREATE pfnCreate = reinterpret_cast<PFN_MBAPREQ_BOOTSTRAPPER_APPLICATION_CREATE>(::GetProcAddress(hModule, "MbaPrereqBootstrapperApplicationCreate"));
593 ExitOnNullWithLastError(pfnCreate, hr, "Failed to get MbaPrereqBootstrapperApplicationCreate entry-point from: %ls", sczMbapreqPath);
594
595 hr = pfnCreate(hrHostInitialization, pEngine, pArgs, pResults);
596 ExitOnFailure(hr, "Failed to create prequisite bootstrapper app.");
597
598 vhMbapreqModule = hModule;
599 hModule = NULL;
600
601LExit:
602 if (hModule)
603 {
604 ::FreeLibrary(hModule);
605 }
606 ReleaseStr(sczMbapreqPath);
607
608 return hr;
609}
610
611static HRESULT VerifyNET4RuntimeIsSupported(
612 )
613{
614 HRESULT hr = S_OK;
615 OS_VERSION osv = OS_VERSION_UNKNOWN;
616 DWORD dwServicePack = 0;
617 HKEY hKey = NULL;
618 DWORD er = ERROR_SUCCESS;
619 DWORD dwRelease = 0;
620 DWORD cchRelease = sizeof(dwRelease);
621
622 OsGetVersion(&osv, &dwServicePack);
623 if (OS_VERSION_WIN7 == osv && 0 == dwServicePack)
624 {
625 hr = RegOpen(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4\\Full", KEY_QUERY_VALUE, &hKey);
626 if (E_FILENOTFOUND == hr)
627 {
628 ExitFunction1(hr = S_OK);
629 }
630 ExitOnFailure(hr, "Failed to open registry key for .NET 4.");
631
632 er = ::RegQueryValueExW(hKey, L"Release", NULL, NULL, reinterpret_cast<LPBYTE>(&dwRelease), &cchRelease);
633 if (ERROR_FILE_NOT_FOUND == er)
634 {
635 ExitFunction1(hr = S_OK);
636 }
637 ExitOnWin32Error(er, hr, "Failed to get Release value.");
638
639 if (NET452_RELEASE <= dwRelease)
640 {
641 hr = E_MBAHOST_NET452_ON_WIN7RTM;
642 }
643 }
644
645LExit:
646 ReleaseRegKey(hKey);
647
648 return hr;
649}
diff --git a/src/ext/Bal/mbahost/mbahost.def b/src/ext/Bal/mbahost/mbahost.def
new file mode 100644
index 00000000..4488df94
--- /dev/null
+++ b/src/ext/Bal/mbahost/mbahost.def
@@ -0,0 +1,6 @@
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
4EXPORTS
5 BootstrapperApplicationCreate
6 BootstrapperApplicationDestroy
diff --git a/src/ext/Bal/mbahost/mbahost.vcxproj b/src/ext/Bal/mbahost/mbahost.vcxproj
new file mode 100644
index 00000000..6457b4e0
--- /dev/null
+++ b/src/ext/Bal/mbahost/mbahost.vcxproj
@@ -0,0 +1,106 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
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')" />
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.BalUtil.4.0.58\build\WixToolset.BalUtil.props" Condition="Exists('..\..\packages\WixToolset.BalUtil.4.0.58\build\WixToolset.BalUtil.props')" />
9 <Import Project="..\..\packages\WixToolset.BootstrapperCore.Native.4.0.141\build\WixToolset.BootstrapperCore.Native.props" Condition="Exists('..\..\packages\WixToolset.BootstrapperCore.Native.4.0.141\build\WixToolset.BootstrapperCore.Native.props')" />
10 <Import Project="..\..\packages\WixToolset.DUtil.4.0.72\build\WixToolset.DUtil.props" Condition="Exists('..\..\packages\WixToolset.DUtil.4.0.72\build\WixToolset.DUtil.props')" />
11
12 <ItemGroup Label="ProjectConfigurations">
13 <ProjectConfiguration Include="Debug|ARM64">
14 <Configuration>Debug</Configuration>
15 <Platform>ARM64</Platform>
16 </ProjectConfiguration>
17 <ProjectConfiguration Include="Release|ARM64">
18 <Configuration>Release</Configuration>
19 <Platform>ARM64</Platform>
20 </ProjectConfiguration>
21 <ProjectConfiguration Include="Debug|Win32">
22 <Configuration>Debug</Configuration>
23 <Platform>Win32</Platform>
24 </ProjectConfiguration>
25 <ProjectConfiguration Include="Release|Win32">
26 <Configuration>Release</Configuration>
27 <Platform>Win32</Platform>
28 </ProjectConfiguration>
29 <ProjectConfiguration Include="Debug|x64">
30 <Configuration>Debug</Configuration>
31 <Platform>x64</Platform>
32 </ProjectConfiguration>
33 <ProjectConfiguration Include="Release|x64">
34 <Configuration>Release</Configuration>
35 <Platform>x64</Platform>
36 </ProjectConfiguration>
37 </ItemGroup>
38
39 <PropertyGroup Label="Globals">
40 <ProjectGuid>{12C87C77-3547-44F8-8134-29BC915CB19D}</ProjectGuid>
41 <ConfigurationType>DynamicLibrary</ConfigurationType>
42 <PlatformToolset>v142</PlatformToolset>
43 <CharacterSet>Unicode</CharacterSet>
44 <TargetName>mbahost</TargetName>
45 <ProjectModuleDefinitionFile>mbahost.def</ProjectModuleDefinitionFile>
46 </PropertyGroup>
47
48 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
49 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
50
51 <PropertyGroup>
52 <ProjectAdditionalLinkLibraries>shlwapi.lib</ProjectAdditionalLinkLibraries>
53 </PropertyGroup>
54
55 <ItemGroup>
56 <ClCompile Include="mbahost.cpp" />
57 <ClCompile Include="precomp.cpp">
58 <PrecompiledHeader>Create</PrecompiledHeader>
59 </ClCompile>
60 </ItemGroup>
61 <ItemGroup>
62 <ClInclude Include="precomp.h" />
63 </ItemGroup>
64 <ItemGroup>
65 <None Include="mbahost.def" />
66 </ItemGroup>
67
68 <ItemGroup>
69 <None Include="packages.config" />
70 </ItemGroup>
71
72 <ItemDefinitionGroup>
73 <ClCompile>
74 <AdditionalIncludeDirectories>$(BaseOutputPath)obj;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
75 </ClCompile>
76 </ItemDefinitionGroup>
77
78 <ItemGroup>
79 <ProjectReference Include="..\WixToolset.Mba.Host\WixToolset.Mba.Host.csproj">
80 <Project>{f2ba1935-70fa-4156-b161-fd03850b4faa}</Project>
81 <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
82 <SkipGetTargetFrameworkProperties>true</SkipGetTargetFrameworkProperties>
83 </ProjectReference>
84 </ItemGroup>
85
86 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
87 <Import Project="..\..\packages\Microsoft.Build.Tasks.Git.1.0.0\build\Microsoft.Build.Tasks.Git.targets" Condition="Exists('..\..\packages\Microsoft.Build.Tasks.Git.1.0.0\build\Microsoft.Build.Tasks.Git.targets')" />
88 <Import Project="..\..\packages\Microsoft.SourceLink.Common.1.0.0\build\Microsoft.SourceLink.Common.targets" Condition="Exists('..\..\packages\Microsoft.SourceLink.Common.1.0.0\build\Microsoft.SourceLink.Common.targets')" />
89 <Import Project="..\..\packages\Microsoft.SourceLink.GitHub.1.0.0\build\Microsoft.SourceLink.GitHub.targets" Condition="Exists('..\..\packages\Microsoft.SourceLink.GitHub.1.0.0\build\Microsoft.SourceLink.GitHub.targets')" />
90 <Import Project="..\..\packages\Nerdbank.GitVersioning.3.3.37\build\Nerdbank.GitVersioning.targets" Condition="Exists('..\..\packages\Nerdbank.GitVersioning.3.3.37\build\Nerdbank.GitVersioning.targets')" />
91 <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
92 <PropertyGroup>
93 <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>
94 </PropertyGroup>
95 <Error Condition="!Exists('..\..\packages\Microsoft.Build.Tasks.Git.1.0.0\build\Microsoft.Build.Tasks.Git.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Build.Tasks.Git.1.0.0\build\Microsoft.Build.Tasks.Git.props'))" />
96 <Error Condition="!Exists('..\..\packages\Microsoft.Build.Tasks.Git.1.0.0\build\Microsoft.Build.Tasks.Git.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Build.Tasks.Git.1.0.0\build\Microsoft.Build.Tasks.Git.targets'))" />
97 <Error Condition="!Exists('..\..\packages\Microsoft.SourceLink.Common.1.0.0\build\Microsoft.SourceLink.Common.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.SourceLink.Common.1.0.0\build\Microsoft.SourceLink.Common.props'))" />
98 <Error Condition="!Exists('..\..\packages\Microsoft.SourceLink.Common.1.0.0\build\Microsoft.SourceLink.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.SourceLink.Common.1.0.0\build\Microsoft.SourceLink.Common.targets'))" />
99 <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'))" />
100 <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'))" />
101 <Error Condition="!Exists('..\..\packages\Nerdbank.GitVersioning.3.3.37\build\Nerdbank.GitVersioning.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Nerdbank.GitVersioning.3.3.37\build\Nerdbank.GitVersioning.targets'))" />
102 <Error Condition="!Exists('..\..\packages\WixToolset.BalUtil.4.0.58\build\WixToolset.BalUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.BalUtil.4.0.58\build\WixToolset.BalUtil.props'))" />
103 <Error Condition="!Exists('..\..\packages\WixToolset.BootstrapperCore.Native.4.0.141\build\WixToolset.BootstrapperCore.Native.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.BootstrapperCore.Native.4.0.141\build\WixToolset.BootstrapperCore.Native.props'))" />
104 <Error Condition="!Exists('..\..\packages\WixToolset.DUtil.4.0.72\build\WixToolset.DUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.DUtil.4.0.72\build\WixToolset.DUtil.props'))" />
105 </Target>
106</Project> \ No newline at end of file
diff --git a/src/ext/Bal/mbahost/packages.config b/src/ext/Bal/mbahost/packages.config
new file mode 100644
index 00000000..071284ac
--- /dev/null
+++ b/src/ext/Bal/mbahost/packages.config
@@ -0,0 +1,10 @@
1<?xml version="1.0" encoding="utf-8"?>
2<packages>
3 <package id="Microsoft.Build.Tasks.Git" 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" />
6 <package id="Nerdbank.GitVersioning" version="3.3.37" targetFramework="native" developmentDependency="true" />
7 <package id="WixToolset.BalUtil" version="4.0.58" targetFramework="native" />
8 <package id="WixToolset.BootstrapperCore.Native" version="4.0.141" targetFramework="native" />
9 <package id="WixToolset.DUtil" version="4.0.72" targetFramework="native" />
10</packages> \ No newline at end of file
diff --git a/src/ext/Bal/mbahost/precomp.cpp b/src/ext/Bal/mbahost/precomp.cpp
new file mode 100644
index 00000000..37664a1c
--- /dev/null
+++ b/src/ext/Bal/mbahost/precomp.cpp
@@ -0,0 +1,3 @@
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"
diff --git a/src/ext/Bal/mbahost/precomp.h b/src/ext/Bal/mbahost/precomp.h
new file mode 100644
index 00000000..d29a23f3
--- /dev/null
+++ b/src/ext/Bal/mbahost/precomp.h
@@ -0,0 +1,25 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5#include <windows.h>
6#include <msiquery.h>
7#include <metahost.h>
8#include <shlwapi.h>
9
10#import <mscorlib.tlb> raw_interfaces_only rename("ReportEvent", "mscorlib_ReportEvent")
11
12#include <dutil.h>
13#include <osutil.h>
14#include <pathutil.h>
15#include <regutil.h>
16#include <strutil.h>
17#include <xmlutil.h>
18
19#include "BootstrapperEngine.h"
20#include "BootstrapperApplication.h"
21#include "IBootstrapperEngine.h"
22#include "IBootstrapperApplication.h"
23#include "IBootstrapperApplicationFactory.h"
24
25#include "balutil.h"
diff --git a/src/ext/Bal/nuget.config b/src/ext/Bal/nuget.config
new file mode 100644
index 00000000..f3277bc4
--- /dev/null
+++ b/src/ext/Bal/nuget.config
@@ -0,0 +1,19 @@
1<?xml version="1.0" encoding="utf-8"?>
2<configuration>
3 <packageSources>
4 <clear />
5 <add key="wixtoolset-burn" value="https://ci.appveyor.com/nuget/wixtoolset-burn" />
6 <add key="wixtoolset-data" value="https://ci.appveyor.com/nuget/wixtoolset-data" />
7 <add key="wixtoolset-extensibility" value="https://ci.appveyor.com/nuget/wixtoolset-extensibility" />
8 <add key="wixtoolset-core" value="https://ci.appveyor.com/nuget/wixtoolset-core" />
9 <add key="wixtoolset-core-native" value="https://ci.appveyor.com/nuget/wixtoolset-core-native" />
10 <add key="wixtoolset-dtf" value="https://ci.appveyor.com/nuget/wixtoolset-dtf" />
11 <add key="wixtoolset-balutil" value="https://ci.appveyor.com/nuget/wixtoolset-balutil" />
12 <add key="wixtoolset-dutil" value="https://ci.appveyor.com/nuget/wixtoolset-dutil" />
13 <add key="wixtoolset-netfx-wixext" value="https://ci.appveyor.com/nuget/wixtoolset-netfx-wixext" />
14 <add key="wixtoolset-wcautil" value="https://ci.appveyor.com/nuget/wixtoolset-wcautil" />
15 <add key="wixtoolset-tools" value="https://ci.appveyor.com/nuget/wixtoolset-tools" />
16 <add key="wixbuildtools" value="https://ci.appveyor.com/nuget/wixbuildtools" />
17 <add key="api.nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
18 </packageSources>
19</configuration> \ No newline at end of file
diff --git a/src/ext/Bal/test/WixToolsetTest.Bal/BalExtensionFixture.cs b/src/ext/Bal/test/WixToolsetTest.Bal/BalExtensionFixture.cs
new file mode 100644
index 00000000..2ff57c55
--- /dev/null
+++ b/src/ext/Bal/test/WixToolsetTest.Bal/BalExtensionFixture.cs
@@ -0,0 +1,133 @@
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
3namespace WixToolsetTest.Bal
4{
5 using System.IO;
6 using System.Linq;
7 using System.Xml;
8 using WixBuildTools.TestSupport;
9 using WixToolset.Core.TestPackage;
10 using Xunit;
11
12 public class BalExtensionFixture
13 {
14 [Fact]
15 public void CanBuildUsingDisplayInternalUICondition()
16 {
17 using (var fs = new DisposableFileSystem())
18 {
19 var baseFolder = fs.GetFolder();
20 var bundleFile = Path.Combine(baseFolder, "bin", "test.exe");
21 var bundleSourceFolder = TestData.Get(@"TestData\WixStdBa");
22 var intermediateFolder = Path.Combine(baseFolder, "obj");
23 var baFolderPath = Path.Combine(baseFolder, "ba");
24 var extractFolderPath = Path.Combine(baseFolder, "extract");
25
26 var compileResult = WixRunner.Execute(new[]
27 {
28 "build",
29 Path.Combine(bundleSourceFolder, "DisplayInternalUIConditionBundle.wxs"),
30 "-ext", TestData.Get(@"WixToolset.Bal.wixext.dll"),
31 "-intermediateFolder", intermediateFolder,
32 "-bindpath", Path.Combine(bundleSourceFolder, "data"),
33 "-o", bundleFile,
34 });
35 compileResult.AssertSuccess();
36
37 Assert.True(File.Exists(bundleFile));
38
39 var extractResult = BundleExtractor.ExtractBAContainer(null, bundleFile, baFolderPath, extractFolderPath);
40 extractResult.AssertSuccess();
41
42 var balPackageInfos = extractResult.SelectBADataNodes("/ba:BootstrapperApplicationData/ba:WixBalPackageInfo");
43 var balPackageInfo = (XmlNode)Assert.Single(balPackageInfos);
44 Assert.Equal("<WixBalPackageInfo PackageId='test.msi' DisplayInternalUICondition='1' />", balPackageInfo.GetTestXml());
45
46 Assert.True(File.Exists(Path.Combine(baFolderPath, "thm.wxl")));
47 }
48 }
49
50 [Fact]
51 public void CanBuildUsingOverridable()
52 {
53 using (var fs = new DisposableFileSystem())
54 {
55 var baseFolder = fs.GetFolder();
56 var bundleFile = Path.Combine(baseFolder, "bin", "test.exe");
57 var bundleSourceFolder = TestData.Get(@"TestData\Overridable");
58 var intermediateFolder = Path.Combine(baseFolder, "obj");
59 var baFolderPath = Path.Combine(baseFolder, "ba");
60 var extractFolderPath = Path.Combine(baseFolder, "extract");
61
62 var compileResult = WixRunner.Execute(new[]
63 {
64 "build",
65 Path.Combine(bundleSourceFolder, "Bundle.wxs"),
66 "-ext", TestData.Get(@"WixToolset.Bal.wixext.dll"),
67 "-intermediateFolder", intermediateFolder,
68 "-o", bundleFile,
69 });
70 compileResult.AssertSuccess();
71
72 Assert.True(File.Exists(bundleFile));
73
74 var extractResult = BundleExtractor.ExtractBAContainer(null, bundleFile, baFolderPath, extractFolderPath);
75 extractResult.AssertSuccess();
76
77 var balOverridableVariables = extractResult.SelectBADataNodes("/ba:BootstrapperApplicationData/ba:WixStdbaOverridableVariable");
78 var balOverridableVariable = (XmlNode)Assert.Single(balOverridableVariables);
79 Assert.Equal("<WixStdbaOverridableVariable Name='Test1' />", balOverridableVariable.GetTestXml());
80 }
81 }
82
83 [Fact]
84 public void CanBuildUsingWixStdBa()
85 {
86 using (var fs = new DisposableFileSystem())
87 {
88 var baseFolder = fs.GetFolder();
89 var bundleFile = Path.Combine(baseFolder, "bin", "test.exe");
90 var bundleSourceFolder = TestData.Get(@"TestData\WixStdBa");
91 var intermediateFolder = Path.Combine(baseFolder, "obj");
92
93 var compileResult = WixRunner.Execute(new[]
94 {
95 "build",
96 Path.Combine(bundleSourceFolder, "Bundle.wxs"),
97 "-ext", TestData.Get(@"WixToolset.Bal.wixext.dll"),
98 "-intermediateFolder", intermediateFolder,
99 "-o", bundleFile,
100 });
101 compileResult.AssertSuccess();
102
103 Assert.True(File.Exists(bundleFile));
104 }
105 }
106
107 [Fact]
108 public void CantBuildUsingMBAWithNoPrereqs()
109 {
110 using (var fs = new DisposableFileSystem())
111 {
112 var baseFolder = fs.GetFolder();
113 var bundleFile = Path.Combine(baseFolder, "bin", "test.exe");
114 var bundleSourceFolder = TestData.Get(@"TestData\MBA");
115 var intermediateFolder = Path.Combine(baseFolder, "obj");
116
117 var compileResult = WixRunner.Execute(new[]
118 {
119 "build",
120 Path.Combine(bundleSourceFolder, "Bundle.wxs"),
121 "-ext", TestData.Get(@"WixToolset.Bal.wixext.dll"),
122 "-intermediateFolder", intermediateFolder,
123 "-o", bundleFile,
124 });
125 Assert.Equal(6802, compileResult.ExitCode);
126 Assert.Equal("There must be at least one PrereqPackage when using the ManagedBootstrapperApplicationHost.\nThis is typically done by using the WixNetFxExtension and referencing one of the NetFxAsPrereq package groups.", compileResult.Messages[0].ToString());
127
128 Assert.False(File.Exists(bundleFile));
129 Assert.False(File.Exists(Path.Combine(intermediateFolder, "test.exe")));
130 }
131 }
132 }
133}
diff --git a/src/ext/Bal/test/WixToolsetTest.Bal/TestData/MBA/Bundle.wxs b/src/ext/Bal/test/WixToolsetTest.Bal/TestData/MBA/Bundle.wxs
new file mode 100644
index 00000000..ba1aefba
--- /dev/null
+++ b/src/ext/Bal/test/WixToolsetTest.Bal/TestData/MBA/Bundle.wxs
@@ -0,0 +1,12 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
3 xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
4 <Bundle Name="WixStdBa" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="75D5D534-E177-4689-AAE9-CAC1C39002C2">
5 <BootstrapperApplication>
6 <bal:WixManagedBootstrapperApplicationHost />
7 </BootstrapperApplication>
8 <Chain>
9 <ExePackage Permanent="yes" DetectCondition="none" SourceFile="runtimes\win-x86\native\wixnative.exe" />
10 </Chain>
11 </Bundle>
12</Wix>
diff --git a/src/ext/Bal/test/WixToolsetTest.Bal/TestData/Overridable/Bundle.wxs b/src/ext/Bal/test/WixToolsetTest.Bal/TestData/Overridable/Bundle.wxs
new file mode 100644
index 00000000..91380c69
--- /dev/null
+++ b/src/ext/Bal/test/WixToolsetTest.Bal/TestData/Overridable/Bundle.wxs
@@ -0,0 +1,13 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
3 xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
4 <Bundle Name="WixStdBa" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="75D5D534-E177-4689-AAE9-CAC1C39002C2">
5 <BootstrapperApplication>
6 <bal:WixStandardBootstrapperApplication LicenseUrl="http://wixtoolset.org/about/license/" Theme="hyperlinkLicense" />
7 </BootstrapperApplication>
8 <Variable Name="Test1" bal:Overridable="yes" />
9 <Chain>
10 <ExePackage Permanent="yes" DetectCondition="none" SourceFile="runtimes\win-x86\native\wixnative.exe" />
11 </Chain>
12 </Bundle>
13</Wix>
diff --git a/src/ext/Bal/test/WixToolsetTest.Bal/TestData/WixStdBa/Bundle.wxs b/src/ext/Bal/test/WixToolsetTest.Bal/TestData/WixStdBa/Bundle.wxs
new file mode 100644
index 00000000..c17b53ff
--- /dev/null
+++ b/src/ext/Bal/test/WixToolsetTest.Bal/TestData/WixStdBa/Bundle.wxs
@@ -0,0 +1,12 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
3 xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
4 <Bundle Name="WixStdBa" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="75D5D534-E177-4689-AAE9-CAC1C39002C2">
5 <BootstrapperApplication>
6 <bal:WixStandardBootstrapperApplication LicenseUrl="http://wixtoolset.org/about/license/" Theme="hyperlinkLicense" />
7 </BootstrapperApplication>
8 <Chain>
9 <ExePackage Permanent="yes" DetectCondition="none" SourceFile="runtimes\win-x86\native\wixnative.exe" />
10 </Chain>
11 </Bundle>
12</Wix>
diff --git a/src/ext/Bal/test/WixToolsetTest.Bal/TestData/WixStdBa/Data/test.msi b/src/ext/Bal/test/WixToolsetTest.Bal/TestData/WixStdBa/Data/test.msi
new file mode 100644
index 00000000..94aacd1a
--- /dev/null
+++ b/src/ext/Bal/test/WixToolsetTest.Bal/TestData/WixStdBa/Data/test.msi
Binary files differ
diff --git a/src/ext/Bal/test/WixToolsetTest.Bal/TestData/WixStdBa/DisplayInternalUIConditionBundle.wxs b/src/ext/Bal/test/WixToolsetTest.Bal/TestData/WixStdBa/DisplayInternalUIConditionBundle.wxs
new file mode 100644
index 00000000..f08cfe6a
--- /dev/null
+++ b/src/ext/Bal/test/WixToolsetTest.Bal/TestData/WixStdBa/DisplayInternalUIConditionBundle.wxs
@@ -0,0 +1,12 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
3 xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
4 <Bundle Name="WixStdBa" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="75D5D534-E177-4689-AAE9-CAC1C39002C2">
5 <BootstrapperApplication>
6 <bal:WixStandardBootstrapperApplication LicenseUrl="http://wixtoolset.org/about/license/" Theme="hyperlinkLicense" />
7 </BootstrapperApplication>
8 <Chain>
9 <MsiPackage SourceFile="test.msi" bal:DisplayInternalUICondition="1" />
10 </Chain>
11 </Bundle>
12</Wix>
diff --git a/src/ext/Bal/test/WixToolsetTest.Bal/WixToolsetTest.Bal.csproj b/src/ext/Bal/test/WixToolsetTest.Bal/WixToolsetTest.Bal.csproj
new file mode 100644
index 00000000..c9ab4219
--- /dev/null
+++ b/src/ext/Bal/test/WixToolsetTest.Bal/WixToolsetTest.Bal.csproj
@@ -0,0 +1,43 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4<Project Sdk="Microsoft.NET.Sdk">
5 <PropertyGroup>
6 <TargetFramework>netcoreapp3.1</TargetFramework>
7 <IsPackable>false</IsPackable>
8 </PropertyGroup>
9
10 <ItemGroup>
11 <Content Include="TestData\MBA\Bundle.wxs" CopyToOutputDirectory="PreserveNewest" />
12 <Content Include="TestData\Overridable\Bundle.wxs" CopyToOutputDirectory="PreserveNewest" />
13 <Content Include="TestData\WixStdBa\Bundle.wxs" CopyToOutputDirectory="PreserveNewest" />
14 <Content Include="TestData\WixStdBa\Data\test.msi" CopyToOutputDirectory="PreserveNewest" />
15 <Content Include="TestData\WixStdBa\DisplayInternalUIConditionBundle.wxs" CopyToOutputDirectory="PreserveNewest" />
16 </ItemGroup>
17
18 <Target Name="CopyExtensions" AfterTargets="Build">
19 <Copy DestinationFolder="$(OutputPath)" SourceFiles="@(WixExtension)" />
20 </Target>
21
22 <ItemGroup>
23 <ProjectReference Include="..\..\wixext\WixToolset.Bal.wixext.csproj" />
24 </ItemGroup>
25
26 <ItemGroup>
27 <PackageReference Include="WixToolset.Core" Version="4.0.*" />
28 <PackageReference Include="WixToolset.Core.Burn" Version="4.0.*" />
29 <PackageReference Include="WixToolset.Core.WindowsInstaller" Version="4.0.*" />
30 <PackageReference Include="WixToolset.Core.TestPackage" Version="4.0.*" />
31 <PackageReference Include="WixToolset.Data" Version="4.0.*" />
32 </ItemGroup>
33
34 <ItemGroup>
35 <PackageReference Include="WixBuildTools.TestSupport" Version="4.0.*" />
36 </ItemGroup>
37
38 <ItemGroup>
39 <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
40 <PackageReference Include="xunit" Version="2.4.1" />
41 <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" PrivateAssets="All" />
42 </ItemGroup>
43</Project>
diff --git a/src/ext/Bal/test/WixToolsetTest.Bal/WixToolsetTest.Bal.v3.ncrunchproject b/src/ext/Bal/test/WixToolsetTest.Bal/WixToolsetTest.Bal.v3.ncrunchproject
new file mode 100644
index 00000000..7b5b2139
--- /dev/null
+++ b/src/ext/Bal/test/WixToolsetTest.Bal/WixToolsetTest.Bal.v3.ncrunchproject
@@ -0,0 +1,5 @@
1<ProjectConfiguration>
2 <Settings>
3 <CopyReferencedAssembliesToWorkspace>True</CopyReferencedAssembliesToWorkspace>
4 </Settings>
5</ProjectConfiguration> \ No newline at end of file
diff --git a/src/ext/Bal/test/WixToolsetTest.ManagedHost/DncHostFixture.cs b/src/ext/Bal/test/WixToolsetTest.ManagedHost/DncHostFixture.cs
new file mode 100644
index 00000000..af5f2543
--- /dev/null
+++ b/src/ext/Bal/test/WixToolsetTest.ManagedHost/DncHostFixture.cs
@@ -0,0 +1,209 @@
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
3namespace WixToolsetTest.ManagedHost
4{
5 using System.IO;
6 using WixBuildTools.TestSupport;
7 using WixToolset.Core.TestPackage;
8 using Xunit;
9
10 public class DncHostFixture
11 {
12 static readonly string bundleBasePath = TestData.Get("..", "examples");
13
14 [Fact]
15 public void CanLoadFDDEarliestCoreMBA()
16 {
17 using (var fs = new DisposableFileSystem())
18 {
19 var baseFolder = fs.GetFolder();
20 var bundleFile = TestData.Get(bundleBasePath, "EarliestCoreBundleFDD.exe");
21 var testEngine = new TestEngine();
22
23 var result = testEngine.RunShutdownEngine(bundleFile, baseFolder);
24 var logMessages = result.Output;
25 Assert.Equal("Loading .NET Core FDD bootstrapper application.", logMessages[0]);
26 Assert.Equal("Creating BA thread to run asynchronously.", logMessages[1]);
27 Assert.Equal("EarliestCoreBA", logMessages[2]);
28 Assert.Equal("Shutdown,ReloadBootstrapper,0", logMessages[3]);
29 }
30 }
31
32 [Fact]
33 public void CanLoadSCDEarliestCoreMBA()
34 {
35 using (var fs = new DisposableFileSystem())
36 {
37 var baseFolder = fs.GetFolder();
38 var bundleFile = TestData.Get(bundleBasePath, "EarliestCoreBundleSCD.exe");
39 var testEngine = new TestEngine();
40
41 var result = testEngine.RunShutdownEngine(bundleFile, baseFolder);
42 var logMessages = result.Output;
43 Assert.Equal("Loading .NET Core SCD bootstrapper application.", logMessages[0]);
44 Assert.Equal("Creating BA thread to run asynchronously.", logMessages[1]);
45 Assert.Equal("EarliestCoreBA", logMessages[2]);
46 Assert.Equal("Shutdown,ReloadBootstrapper,0", logMessages[3]);
47 }
48 }
49
50 [Fact]
51 public void CanLoadTrimmedSCDEarliestCoreMBA()
52 {
53 using (var fs = new DisposableFileSystem())
54 {
55 var baseFolder = fs.GetFolder();
56 var bundleFile = TestData.Get(bundleBasePath, "EarliestCoreBundleTrimmedSCD.exe");
57 var testEngine = new TestEngine();
58
59 var result = testEngine.RunShutdownEngine(bundleFile, baseFolder);
60 var logMessages = result.Output;
61 Assert.Equal("Loading .NET Core SCD bootstrapper application.", logMessages[0]);
62 Assert.Equal("Creating BA thread to run asynchronously.", logMessages[1]);
63 Assert.Equal("EarliestCoreBA", logMessages[2]);
64 Assert.Equal("Shutdown,ReloadBootstrapper,0", logMessages[3]);
65 }
66 }
67
68 [Fact]
69 public void CanReloadSCDEarliestCoreMBA()
70 {
71 using (var fs = new DisposableFileSystem())
72 {
73 var baseFolder = fs.GetFolder();
74 var bundleFile = TestData.Get(bundleBasePath, "EarliestCoreBundleSCD.exe");
75 var testEngine = new TestEngine();
76
77 var result = testEngine.RunReloadEngine(bundleFile, baseFolder);
78 var logMessages = result.Output;
79 Assert.Equal("Loading .NET Core SCD bootstrapper application.", logMessages[0]);
80 Assert.Equal("Creating BA thread to run asynchronously.", logMessages[1]);
81 Assert.Equal("EarliestCoreBA", logMessages[2]);
82 Assert.Equal("Shutdown,ReloadBootstrapper,0", logMessages[3]);
83 Assert.Equal("Loading .NET Core SCD bootstrapper application.", logMessages[4]);
84 Assert.Equal("Reloaded 1 time(s)", logMessages[5]); // dnchost doesn't currently support unloading
85 Assert.Equal("Creating BA thread to run asynchronously.", logMessages[6]);
86 Assert.Equal("EarliestCoreBA", logMessages[7]);
87 Assert.Equal("Shutdown,Restart,0", logMessages[8]);
88 }
89 }
90
91 [Fact]
92 public void CanLoadFDDLatestCoreMBA()
93 {
94 using (var fs = new DisposableFileSystem())
95 {
96 var baseFolder = fs.GetFolder();
97 var bundleFile = TestData.Get(bundleBasePath, "LatestCoreBundleFDD.exe");
98 var testEngine = new TestEngine();
99
100 var result = testEngine.RunShutdownEngine(bundleFile, baseFolder);
101 var logMessages = result.Output;
102 Assert.Equal("Loading .NET Core FDD bootstrapper application.", logMessages[0]);
103 Assert.Equal("Creating BA thread to run asynchronously.", logMessages[1]);
104 Assert.Equal("LatestCoreBA", logMessages[2]);
105 Assert.Equal("Shutdown,ReloadBootstrapper,0", logMessages[3]);
106 }
107 }
108
109 [Fact]
110 public void CanReloadFDDLatestCoreMBA()
111 {
112 using (var fs = new DisposableFileSystem())
113 {
114 var baseFolder = fs.GetFolder();
115 var bundleFile = TestData.Get(bundleBasePath, "LatestCoreBundleFDD.exe");
116 var testEngine = new TestEngine();
117
118 var result = testEngine.RunReloadEngine(bundleFile, baseFolder);
119 var logMessages = result.Output;
120 Assert.Equal("Loading .NET Core FDD bootstrapper application.", logMessages[0]);
121 Assert.Equal("Creating BA thread to run asynchronously.", logMessages[1]);
122 Assert.Equal("LatestCoreBA", logMessages[2]);
123 Assert.Equal("Shutdown,ReloadBootstrapper,0", logMessages[3]);
124 Assert.Equal("Loading .NET Core FDD bootstrapper application.", logMessages[4]);
125 Assert.Equal("Reloaded 1 time(s)", logMessages[5]); // dnchost doesn't currently support unloading
126 Assert.Equal("Creating BA thread to run asynchronously.", logMessages[6]);
127 Assert.Equal("LatestCoreBA", logMessages[7]);
128 Assert.Equal("Shutdown,Restart,0", logMessages[8]);
129 }
130 }
131
132 [Fact]
133 public void CanLoadSCDLatestCoreMBA()
134 {
135 using (var fs = new DisposableFileSystem())
136 {
137 var baseFolder = fs.GetFolder();
138 var bundleFile = TestData.Get(bundleBasePath, "LatestCoreBundleSCD.exe");
139 var testEngine = new TestEngine();
140
141 var result = testEngine.RunShutdownEngine(bundleFile, baseFolder);
142 var logMessages = result.Output;
143 Assert.Equal("Loading .NET Core SCD bootstrapper application.", logMessages[0]);
144 Assert.Equal("Creating BA thread to run asynchronously.", logMessages[1]);
145 Assert.Equal("LatestCoreBA", logMessages[2]);
146 Assert.Equal("Shutdown,ReloadBootstrapper,0", logMessages[3]);
147 }
148 }
149
150 [Fact]
151 public void CanLoadTrimmedSCDLatestCoreMBA()
152 {
153 using (var fs = new DisposableFileSystem())
154 {
155 var baseFolder = fs.GetFolder();
156 var bundleFile = TestData.Get(bundleBasePath, "LatestCoreBundleTrimmedSCD.exe");
157 var testEngine = new TestEngine();
158
159 var result = testEngine.RunShutdownEngine(bundleFile, baseFolder);
160 var logMessages = result.Output;
161 Assert.Equal("Loading .NET Core SCD bootstrapper application.", logMessages[0]);
162 Assert.Equal("Creating BA thread to run asynchronously.", logMessages[1]);
163 Assert.Equal("LatestCoreBA", logMessages[2]);
164 Assert.Equal("Shutdown,ReloadBootstrapper,0", logMessages[3]);
165 }
166 }
167
168 [Fact]
169 public void CanReloadSCDLatestCoreMBA()
170 {
171 using (var fs = new DisposableFileSystem())
172 {
173 var baseFolder = fs.GetFolder();
174 var bundleFile = TestData.Get(bundleBasePath, "LatestCoreBundleSCD.exe");
175 var testEngine = new TestEngine();
176
177 var result = testEngine.RunReloadEngine(bundleFile, baseFolder);
178 var logMessages = result.Output;
179 Assert.Equal("Loading .NET Core SCD bootstrapper application.", logMessages[0]);
180 Assert.Equal("Creating BA thread to run asynchronously.", logMessages[1]);
181 Assert.Equal("LatestCoreBA", logMessages[2]);
182 Assert.Equal("Shutdown,ReloadBootstrapper,0", logMessages[3]);
183 Assert.Equal("Loading .NET Core SCD bootstrapper application.", logMessages[4]);
184 Assert.Equal("Reloaded 1 time(s)", logMessages[5]); // dnchost doesn't currently support unloading
185 Assert.Equal("Creating BA thread to run asynchronously.", logMessages[6]);
186 Assert.Equal("LatestCoreBA", logMessages[7]);
187 Assert.Equal("Shutdown,Restart,0", logMessages[8]);
188 }
189 }
190
191 [Fact]
192 public void CanLoadFDDWPFCoreMBA()
193 {
194 using (var fs = new DisposableFileSystem())
195 {
196 var baseFolder = fs.GetFolder();
197 var bundleFile = TestData.Get(bundleBasePath, "WPFCoreBundleFDD.exe");
198 var testEngine = new TestEngine();
199
200 var result = testEngine.RunShutdownEngine(bundleFile, baseFolder);
201 var logMessages = result.Output;
202 Assert.Equal("Loading .NET Core FDD bootstrapper application.", logMessages[0]);
203 Assert.Equal("Creating BA thread to run asynchronously.", logMessages[1]);
204 Assert.Equal("WPFCoreBA", logMessages[2]);
205 Assert.Equal("Shutdown,ReloadBootstrapper,0", logMessages[3]);
206 }
207 }
208 }
209}
diff --git a/src/ext/Bal/test/WixToolsetTest.ManagedHost/MbaHostFixture.cs b/src/ext/Bal/test/WixToolsetTest.ManagedHost/MbaHostFixture.cs
new file mode 100644
index 00000000..dd37ee58
--- /dev/null
+++ b/src/ext/Bal/test/WixToolsetTest.ManagedHost/MbaHostFixture.cs
@@ -0,0 +1,94 @@
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
3namespace WixToolsetTest.ManagedHost
4{
5 using System.IO;
6 using WixBuildTools.TestSupport;
7 using WixToolset.Core.TestPackage;
8 using Xunit;
9
10 public class MbaHostFixture
11 {
12 static readonly string bundleBasePath = TestData.Get("..", "examples");
13
14 [Fact]
15 public void CanLoadFullFramework2MBA()
16 {
17 using (var fs = new DisposableFileSystem())
18 {
19 var baseFolder = fs.GetFolder();
20 var bundleFile = TestData.Get(bundleBasePath, "FullFramework2Bundle.exe");
21 var testEngine = new TestEngine();
22
23 var result = testEngine.RunShutdownEngine(bundleFile, baseFolder);
24 var logMessages = result.Output;
25 Assert.Equal("Loading managed bootstrapper application.", logMessages[0]);
26 Assert.Equal("Creating BA thread to run asynchronously.", logMessages[1]);
27 Assert.Equal("FullFramework2BA", logMessages[2]);
28 Assert.Equal("Shutdown,ReloadBootstrapper,0", logMessages[3]);
29 }
30 }
31
32 [Fact]
33 public void CanLoadFullFramework4MBA()
34 {
35 using (var fs = new DisposableFileSystem())
36 {
37 var baseFolder = fs.GetFolder();
38 var bundleFile = TestData.Get(bundleBasePath, "FullFramework4Bundle.exe");
39 var testEngine = new TestEngine();
40
41 var result = testEngine.RunShutdownEngine(bundleFile, baseFolder);
42 var logMessages = result.Output;
43 Assert.Equal("Loading managed bootstrapper application.", logMessages[0]);
44 Assert.Equal("Creating BA thread to run asynchronously.", logMessages[1]);
45 Assert.Equal("FullFramework4BA", logMessages[2]);
46 Assert.Equal("Shutdown,ReloadBootstrapper,0", logMessages[3]);
47 }
48 }
49
50 [Fact]
51 public void CanReloadFullFramework2MBA()
52 {
53 using (var fs = new DisposableFileSystem())
54 {
55 var baseFolder = fs.GetFolder();
56 var bundleFile = TestData.Get(bundleBasePath, "FullFramework2Bundle.exe");
57 var testEngine = new TestEngine();
58
59 var result = testEngine.RunReloadEngine(bundleFile, baseFolder);
60 var logMessages = result.Output;
61 Assert.Equal("Loading managed bootstrapper application.", logMessages[0]);
62 Assert.Equal("Creating BA thread to run asynchronously.", logMessages[1]);
63 Assert.Equal("FullFramework2BA", logMessages[2]);
64 Assert.Equal("Shutdown,ReloadBootstrapper,0", logMessages[3]);
65 Assert.Equal("Loading managed bootstrapper application.", logMessages[4]);
66 Assert.Equal("Creating BA thread to run asynchronously.", logMessages[5]);
67 Assert.Equal("FullFramework2BA", logMessages[6]);
68 Assert.Equal("Shutdown,Restart,0", logMessages[7]);
69 }
70 }
71
72 [Fact]
73 public void CanReloadFullFramework4MBA()
74 {
75 using (var fs = new DisposableFileSystem())
76 {
77 var baseFolder = fs.GetFolder();
78 var bundleFile = TestData.Get(bundleBasePath, "FullFramework4Bundle.exe");
79 var testEngine = new TestEngine();
80
81 var result = testEngine.RunReloadEngine(bundleFile, baseFolder);
82 var logMessages = result.Output;
83 Assert.Equal("Loading managed bootstrapper application.", logMessages[0]);
84 Assert.Equal("Creating BA thread to run asynchronously.", logMessages[1]);
85 Assert.Equal("FullFramework4BA", logMessages[2]);
86 Assert.Equal("Shutdown,ReloadBootstrapper,0", logMessages[3]);
87 Assert.Equal("Loading managed bootstrapper application.", logMessages[4]);
88 Assert.Equal("Creating BA thread to run asynchronously.", logMessages[5]);
89 Assert.Equal("FullFramework4BA", logMessages[6]);
90 Assert.Equal("Shutdown,Restart,0", logMessages[7]);
91 }
92 }
93 }
94}
diff --git a/src/ext/Bal/test/WixToolsetTest.ManagedHost/README.md b/src/ext/Bal/test/WixToolsetTest.ManagedHost/README.md
new file mode 100644
index 00000000..d7e73df2
--- /dev/null
+++ b/src/ext/Bal/test/WixToolsetTest.ManagedHost/README.md
@@ -0,0 +1,5 @@
1In order to properly test dnchost and mbahost,
2the managed BAs need to be published and a bundle needs to be built for each scenario.
3Making this happen on every build for the solution takes too long,
4so this project relies on manually running appveyor.cmd to publish everything before the tests can be run.
5appveyor.cmd needs to be ran again every time changes are made in other projects. \ No newline at end of file
diff --git a/src/ext/Bal/test/WixToolsetTest.ManagedHost/TestEngine.cs b/src/ext/Bal/test/WixToolsetTest.ManagedHost/TestEngine.cs
new file mode 100644
index 00000000..44538227
--- /dev/null
+++ b/src/ext/Bal/test/WixToolsetTest.ManagedHost/TestEngine.cs
@@ -0,0 +1,74 @@
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
3namespace WixToolsetTest.ManagedHost
4{
5 using System.Collections.Generic;
6 using System.Diagnostics;
7 using System.IO;
8 using WixBuildTools.TestSupport;
9 using WixToolset.Core.TestPackage;
10
11 public class TestEngine
12 {
13 private static readonly string TestEngineFile = TestData.Get(@"..\Win32\examples\Example.TestEngine\Example.TestEngine.exe");
14
15 public TestEngineResult RunReloadEngine(string bundleFilePath, string tempFolderPath)
16 {
17 return this.RunTestEngine("reload", bundleFilePath, tempFolderPath);
18 }
19
20 public TestEngineResult RunShutdownEngine(string bundleFilePath, string tempFolderPath)
21 {
22 return this.RunTestEngine("shutdown", bundleFilePath, tempFolderPath);
23 }
24
25 private TestEngineResult RunTestEngine(string engineMode, string bundleFilePath, string tempFolderPath)
26 {
27 var baFolderPath = Path.Combine(tempFolderPath, "ba");
28 var extractFolderPath = Path.Combine(tempFolderPath, "extract");
29 var extractResult = BundleExtractor.ExtractBAContainer(null, bundleFilePath, baFolderPath, extractFolderPath);
30 extractResult.AssertSuccess();
31
32 var args = new string[] {
33 engineMode,
34 '"' + bundleFilePath + '"',
35 '"' + extractResult.GetBAFilePath(baFolderPath) + '"',
36 };
37 return RunProcessCaptureOutput(TestEngineFile, args);
38 }
39
40 private static TestEngineResult RunProcessCaptureOutput(string executablePath, string[] arguments = null, string workingFolder = null)
41 {
42 var startInfo = new ProcessStartInfo(executablePath)
43 {
44 Arguments = string.Join(' ', arguments),
45 CreateNoWindow = true,
46 RedirectStandardError = true,
47 RedirectStandardOutput = true,
48 UseShellExecute = false,
49 WorkingDirectory = workingFolder,
50 };
51
52 var exitCode = 0;
53 var output = new List<string>();
54
55 using (var process = Process.Start(startInfo))
56 {
57 process.OutputDataReceived += (s, e) => { if (e.Data != null) { output.Add(e.Data); } };
58 process.ErrorDataReceived += (s, e) => { if (e.Data != null) { output.Add(e.Data); } };
59
60 process.BeginErrorReadLine();
61 process.BeginOutputReadLine();
62
63 process.WaitForExit();
64 exitCode = process.ExitCode;
65 }
66
67 return new TestEngineResult
68 {
69 ExitCode = exitCode,
70 Output = output,
71 };
72 }
73 }
74}
diff --git a/src/ext/Bal/test/WixToolsetTest.ManagedHost/TestEngineResult.cs b/src/ext/Bal/test/WixToolsetTest.ManagedHost/TestEngineResult.cs
new file mode 100644
index 00000000..63f6f7f5
--- /dev/null
+++ b/src/ext/Bal/test/WixToolsetTest.ManagedHost/TestEngineResult.cs
@@ -0,0 +1,12 @@
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
3namespace WixToolsetTest.ManagedHost
4{
5 using System.Collections.Generic;
6
7 public class TestEngineResult
8 {
9 public int ExitCode { get; set; }
10 public List<string> Output { get; set; }
11 }
12}
diff --git a/src/ext/Bal/test/WixToolsetTest.ManagedHost/WixToolsetTest.ManagedHost.csproj b/src/ext/Bal/test/WixToolsetTest.ManagedHost/WixToolsetTest.ManagedHost.csproj
new file mode 100644
index 00000000..38c8926c
--- /dev/null
+++ b/src/ext/Bal/test/WixToolsetTest.ManagedHost/WixToolsetTest.ManagedHost.csproj
@@ -0,0 +1,25 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4<Project Sdk="Microsoft.NET.Sdk">
5 <PropertyGroup>
6 <TargetFramework>netcoreapp3.1</TargetFramework>
7 </PropertyGroup>
8
9 <ItemGroup>
10 <ProjectReference Include="..\examples\TestEngine\Example.TestEngine.vcxproj" />
11 </ItemGroup>
12
13 <ItemGroup>
14 <PackageReference Include="WixBuildTools.TestSupport" Version="4.0.*" />
15 <PackageReference Include="WixToolset.Core.Burn" Version="4.0.*" />
16 <PackageReference Include="WixToolset.Core.WindowsInstaller" Version="4.0.*" />
17 <PackageReference Include="WixToolset.Core.TestPackage" Version="4.0.*" />
18 </ItemGroup>
19
20 <ItemGroup>
21 <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
22 <PackageReference Include="xunit" Version="2.4.1" />
23 <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" PrivateAssets="All" />
24 </ItemGroup>
25</Project>
diff --git a/src/ext/Bal/test/examples/Directory.Build.props b/src/ext/Bal/test/examples/Directory.Build.props
new file mode 100644
index 00000000..3d5870a5
--- /dev/null
+++ b/src/ext/Bal/test/examples/Directory.Build.props
@@ -0,0 +1,6 @@
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<Project>
4 <Import Project="..\..\Directory.Build.props" />
5 <Import Project="Wix.Build.props" Condition=" '$(MSBuildProjectExtension)'=='.wixproj' " />
6</Project>
diff --git a/src/ext/Bal/test/examples/Directory.Build.targets b/src/ext/Bal/test/examples/Directory.Build.targets
new file mode 100644
index 00000000..6dcf402b
--- /dev/null
+++ b/src/ext/Bal/test/examples/Directory.Build.targets
@@ -0,0 +1,6 @@
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<Project>
4 <Import Project="..\..\Directory.Build.targets" />
5 <Import Project="Wix.Build.targets" Condition=" '$(MSBuildProjectExtension)'=='.wixproj' " />
6</Project>
diff --git a/src/ext/Bal/test/examples/EarliestCoreBundleFDD/EarliestCoreBundleFDD.wixproj b/src/ext/Bal/test/examples/EarliestCoreBundleFDD/EarliestCoreBundleFDD.wixproj
new file mode 100644
index 00000000..ba75a9ff
--- /dev/null
+++ b/src/ext/Bal/test/examples/EarliestCoreBundleFDD/EarliestCoreBundleFDD.wixproj
@@ -0,0 +1,2 @@
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<Project Sdk="WixToolset.Sdk" />
diff --git a/src/ext/Bal/test/examples/EarliestCoreBundleFDD/FrameworkDependentBundle.wxs b/src/ext/Bal/test/examples/EarliestCoreBundleFDD/FrameworkDependentBundle.wxs
new file mode 100644
index 00000000..d146845c
--- /dev/null
+++ b/src/ext/Bal/test/examples/EarliestCoreBundleFDD/FrameworkDependentBundle.wxs
@@ -0,0 +1,16 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
2 <Bundle Name="FDDEarliestCoreMBA" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="5CE5B5C7-4B6B-4B95-B297-731F1F956533">
3 <BootstrapperApplication>
4 <Payload SourceFile="publish\Example.EarliestCoreMBA\fdd\Example.EarliestCoreMBA.deps.json" Name="Example.EarliestCoreMBA.deps.json" />
5 <Payload SourceFile="publish\Example.EarliestCoreMBA\fdd\Example.EarliestCoreMBA.dll" Name="Example.EarliestCoreMBA.dll" bal:BAFactoryAssembly="yes" />
6 <Payload SourceFile="publish\Example.EarliestCoreMBA\fdd\Example.EarliestCoreMBA.pdb" Name="Example.EarliestCoreMBA.pdb" />
7 <Payload SourceFile="publish\Example.EarliestCoreMBA\fdd\Example.EarliestCoreMBA.runtimeconfig.json" Name="Example.EarliestCoreMBA.runtimeconfig.json" />
8 <Payload SourceFile="publish\Example.EarliestCoreMBA\fdd\mbanative.dll" Name="mbanative.dll" />
9 <Payload SourceFile="publish\Example.EarliestCoreMBA\fdd\WixToolset.Mba.Core.dll" Name="WixToolset.Mba.Core.dll" />
10 <bal:WixDotNetCoreBootstrapperApplicationHost />
11 </BootstrapperApplication>
12 <Chain>
13 <ExePackage DetectCondition="none" SourceFile="c:\windows\system32\kernel32.dll" bal:PrereqPackage="yes" />
14 </Chain>
15 </Bundle>
16</Wix>
diff --git a/src/ext/Bal/test/examples/EarliestCoreBundleSCD/EarliestCoreBundleSCD.wixproj b/src/ext/Bal/test/examples/EarliestCoreBundleSCD/EarliestCoreBundleSCD.wixproj
new file mode 100644
index 00000000..ebeebff2
--- /dev/null
+++ b/src/ext/Bal/test/examples/EarliestCoreBundleSCD/EarliestCoreBundleSCD.wixproj
@@ -0,0 +1,10 @@
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<Project Sdk="WixToolset.Sdk">
3 <ItemGroup>
4 <BindInputPaths Include="$(OutputPath)publish\Example.EarliestCoreMBA\scd" />
5 <HarvestDirectory Include="$(OutputPath)publish\Example.EarliestCoreMBA\scd">
6 <DirectoryRefId>publish.Example.EarliestCoreMBA.scd</DirectoryRefId>
7 <Transforms>ba.xslt</Transforms>
8 </HarvestDirectory>
9 </ItemGroup>
10</Project>
diff --git a/src/ext/Bal/test/examples/EarliestCoreBundleSCD/SelfContainedBundle.wxs b/src/ext/Bal/test/examples/EarliestCoreBundleSCD/SelfContainedBundle.wxs
new file mode 100644
index 00000000..4d872317
--- /dev/null
+++ b/src/ext/Bal/test/examples/EarliestCoreBundleSCD/SelfContainedBundle.wxs
@@ -0,0 +1,11 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
2 <Bundle Name="SCDEarliestCoreMBA" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="5CE5B5C7-4B6B-4B95-B297-731F1F956533">
3 <BootstrapperApplication>
4 <bal:WixDotNetCoreBootstrapperApplicationHost SelfContainedDeployment="yes" />
5 <PayloadGroupRef Id="publish.Example.EarliestCoreMBA.scd" />
6 </BootstrapperApplication>
7 <Chain>
8 <ExePackage DetectCondition="none" SourceFile="c:\windows\system32\kernel32.dll" PerMachine="yes" />
9 </Chain>
10 </Bundle>
11</Wix>
diff --git a/src/ext/Bal/test/examples/EarliestCoreBundleSCD/ba.xslt b/src/ext/Bal/test/examples/EarliestCoreBundleSCD/ba.xslt
new file mode 100644
index 00000000..06b84256
--- /dev/null
+++ b/src/ext/Bal/test/examples/EarliestCoreBundleSCD/ba.xslt
@@ -0,0 +1,20 @@
1<?xml version="1.0" encoding="utf-8"?>
2<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
3 xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
4 xmlns:wix="http://wixtoolset.org/schemas/v4/wxs"
5>
6 <xsl:output method="xml" indent="yes"/>
7
8 <xsl:template match="@* | node()">
9 <xsl:copy>
10 <xsl:apply-templates select="@* | node()"/>
11 </xsl:copy>
12 </xsl:template>
13
14 <xsl:template match="wix:Payload[@SourceFile='SourceDir\Example.EarliestCoreMBA.dll']" >
15 <xsl:copy>
16 <xsl:attribute name="BAFactoryAssembly" namespace="http://wixtoolset.org/schemas/v4/wxs/bal">yes</xsl:attribute>
17 <xsl:apply-templates select="@* | node()"/>
18 </xsl:copy>
19 </xsl:template>
20</xsl:stylesheet>
diff --git a/src/ext/Bal/test/examples/EarliestCoreBundleTrimmedSCD/EarliestCoreBundleTrimmedSCD.wixproj b/src/ext/Bal/test/examples/EarliestCoreBundleTrimmedSCD/EarliestCoreBundleTrimmedSCD.wixproj
new file mode 100644
index 00000000..a6b56460
--- /dev/null
+++ b/src/ext/Bal/test/examples/EarliestCoreBundleTrimmedSCD/EarliestCoreBundleTrimmedSCD.wixproj
@@ -0,0 +1,10 @@
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<Project Sdk="WixToolset.Sdk">
3 <ItemGroup>
4 <BindInputPaths Include="$(OutputPath)publish\Example.EarliestCoreMBA\trimmedscd" />
5 <HarvestDirectory Include="$(OutputPath)publish\Example.EarliestCoreMBA\trimmedscd">
6 <DirectoryRefId>publish.Example.EarliestCoreMBA.trimmedscd</DirectoryRefId>
7 <Transforms>ba.xslt</Transforms>
8 </HarvestDirectory>
9 </ItemGroup>
10</Project>
diff --git a/src/ext/Bal/test/examples/EarliestCoreBundleTrimmedSCD/TrimmedSelfContainedBundle.wxs b/src/ext/Bal/test/examples/EarliestCoreBundleTrimmedSCD/TrimmedSelfContainedBundle.wxs
new file mode 100644
index 00000000..ba7dce25
--- /dev/null
+++ b/src/ext/Bal/test/examples/EarliestCoreBundleTrimmedSCD/TrimmedSelfContainedBundle.wxs
@@ -0,0 +1,11 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
2 <Bundle Name="TrimmedSCDEarliestCoreMBA" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="5CE5B5C7-4B6B-4B95-B297-731F1F956533">
3 <BootstrapperApplication>
4 <bal:WixDotNetCoreBootstrapperApplicationHost SelfContainedDeployment="yes" />
5 <PayloadGroupRef Id="publish.Example.EarliestCoreMBA.trimmedscd" />
6 </BootstrapperApplication>
7 <Chain>
8 <ExePackage DetectCondition="none" SourceFile="c:\windows\system32\kernel32.dll" PerMachine="yes" />
9 </Chain>
10 </Bundle>
11</Wix>
diff --git a/src/ext/Bal/test/examples/EarliestCoreBundleTrimmedSCD/ba.xslt b/src/ext/Bal/test/examples/EarliestCoreBundleTrimmedSCD/ba.xslt
new file mode 100644
index 00000000..06b84256
--- /dev/null
+++ b/src/ext/Bal/test/examples/EarliestCoreBundleTrimmedSCD/ba.xslt
@@ -0,0 +1,20 @@
1<?xml version="1.0" encoding="utf-8"?>
2<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
3 xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
4 xmlns:wix="http://wixtoolset.org/schemas/v4/wxs"
5>
6 <xsl:output method="xml" indent="yes"/>
7
8 <xsl:template match="@* | node()">
9 <xsl:copy>
10 <xsl:apply-templates select="@* | node()"/>
11 </xsl:copy>
12 </xsl:template>
13
14 <xsl:template match="wix:Payload[@SourceFile='SourceDir\Example.EarliestCoreMBA.dll']" >
15 <xsl:copy>
16 <xsl:attribute name="BAFactoryAssembly" namespace="http://wixtoolset.org/schemas/v4/wxs/bal">yes</xsl:attribute>
17 <xsl:apply-templates select="@* | node()"/>
18 </xsl:copy>
19 </xsl:template>
20</xsl:stylesheet>
diff --git a/src/ext/Bal/test/examples/EarliestCoreMBA/EarliestCoreBA.cs b/src/ext/Bal/test/examples/EarliestCoreMBA/EarliestCoreBA.cs
new file mode 100644
index 00000000..c9291a7f
--- /dev/null
+++ b/src/ext/Bal/test/examples/EarliestCoreMBA/EarliestCoreBA.cs
@@ -0,0 +1,34 @@
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
3namespace Example.EarliestCoreMBA
4{
5 using WixToolset.Mba.Core;
6
7 public class EarliestCoreBA : BootstrapperApplication
8 {
9 public EarliestCoreBA(IEngine engine)
10 : base(engine)
11 {
12
13 }
14
15 protected override void Run()
16 {
17 }
18
19 protected override void OnStartup(StartupEventArgs args)
20 {
21 base.OnStartup(args);
22
23 this.engine.Log(LogLevel.Standard, nameof(EarliestCoreBA));
24 }
25
26 protected override void OnShutdown(ShutdownEventArgs args)
27 {
28 base.OnShutdown(args);
29
30 var message = "Shutdown," + args.Action.ToString() + "," + args.HResult.ToString();
31 this.engine.Log(LogLevel.Standard, message);
32 }
33 }
34}
diff --git a/src/ext/Bal/test/examples/EarliestCoreMBA/EarliestCoreBAFactory.cs b/src/ext/Bal/test/examples/EarliestCoreMBA/EarliestCoreBAFactory.cs
new file mode 100644
index 00000000..672e17ee
--- /dev/null
+++ b/src/ext/Bal/test/examples/EarliestCoreMBA/EarliestCoreBAFactory.cs
@@ -0,0 +1,22 @@
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[assembly: WixToolset.Mba.Core.BootstrapperApplicationFactory(typeof(Example.EarliestCoreMBA.EarliestCoreBAFactory))]
4namespace Example.EarliestCoreMBA
5{
6 using WixToolset.Mba.Core;
7
8 public class EarliestCoreBAFactory : BaseBootstrapperApplicationFactory
9 {
10 private static int loadCount = 0;
11
12 protected override IBootstrapperApplication Create(IEngine engine, IBootstrapperCommand bootstrapperCommand)
13 {
14 if (loadCount > 0)
15 {
16 engine.Log(LogLevel.Standard, $"Reloaded {loadCount} time(s)");
17 }
18 ++loadCount;
19 return new EarliestCoreBA(engine);
20 }
21 }
22}
diff --git a/src/ext/Bal/test/examples/EarliestCoreMBA/Example.EarliestCoreMBA.csproj b/src/ext/Bal/test/examples/EarliestCoreMBA/Example.EarliestCoreMBA.csproj
new file mode 100644
index 00000000..cb66c138
--- /dev/null
+++ b/src/ext/Bal/test/examples/EarliestCoreMBA/Example.EarliestCoreMBA.csproj
@@ -0,0 +1,18 @@
1<Project Sdk="Microsoft.NET.Sdk">
2
3 <PropertyGroup>
4 <TargetFramework>netcoreapp3.1</TargetFramework>
5 <RuntimeIdentifiers>win-x86;win-x64</RuntimeIdentifiers>
6 <EnableDynamicLoading>true</EnableDynamicLoading>
7 <Description>Earliest .NET Core MBA</Description>
8 </PropertyGroup>
9
10 <ItemGroup>
11 <TrimmerRootAssembly Include="System.Runtime.Loader" />
12 </ItemGroup>
13
14 <ItemGroup>
15 <PackageReference Include="Nerdbank.GitVersioning" Version="3.3.37" PrivateAssets="all" />
16 <PackageReference Include="WixToolset.Mba.Core" Version="4.0.*" />
17 </ItemGroup>
18</Project> \ No newline at end of file
diff --git a/src/ext/Bal/test/examples/FullFramework2Bundle/Bundle.wxs b/src/ext/Bal/test/examples/FullFramework2Bundle/Bundle.wxs
new file mode 100644
index 00000000..f0af975c
--- /dev/null
+++ b/src/ext/Bal/test/examples/FullFramework2Bundle/Bundle.wxs
@@ -0,0 +1,14 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
2 <Bundle Name="FullFramework2MBA" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="5CE5B5C7-4B6B-4B95-B297-731F1F956533">
3 <BootstrapperApplication>
4 <Payload SourceFile="Example.FullFramework2MBA\net20\win-x86\Example.FullFramework2MBA.dll" />
5 <Payload SourceFile="Example.FullFramework2MBA\net20\win-x86\mbanative.dll" />
6 <Payload SourceFile="Example.FullFramework2MBA\net20\win-x86\WixToolset.Mba.Core.dll" />
7 <Payload SourceFile="Example.FullFramework2MBA\net20\win-x86\WixToolset.Mba.Host.config" />
8 <bal:WixManagedBootstrapperApplicationHost />
9 </BootstrapperApplication>
10 <Chain>
11 <ExePackage DetectCondition="none" SourceFile="c:\windows\system32\kernel32.dll" bal:PrereqPackage="yes" />
12 </Chain>
13 </Bundle>
14</Wix>
diff --git a/src/ext/Bal/test/examples/FullFramework2Bundle/FullFramework2Bundle.wixproj b/src/ext/Bal/test/examples/FullFramework2Bundle/FullFramework2Bundle.wixproj
new file mode 100644
index 00000000..ba75a9ff
--- /dev/null
+++ b/src/ext/Bal/test/examples/FullFramework2Bundle/FullFramework2Bundle.wixproj
@@ -0,0 +1,2 @@
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<Project Sdk="WixToolset.Sdk" />
diff --git a/src/ext/Bal/test/examples/FullFramework2MBA/Example.FullFramework2MBA.csproj b/src/ext/Bal/test/examples/FullFramework2MBA/Example.FullFramework2MBA.csproj
new file mode 100644
index 00000000..21079ed1
--- /dev/null
+++ b/src/ext/Bal/test/examples/FullFramework2MBA/Example.FullFramework2MBA.csproj
@@ -0,0 +1,20 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4<Project Sdk="Microsoft.NET.Sdk">
5 <PropertyGroup>
6 <TargetFramework>net20</TargetFramework>
7 <AssemblyName>Example.FullFramework2MBA</AssemblyName>
8 <RootNamespace>Example.FullFramework2MBA</RootNamespace>
9 <DebugType>embedded</DebugType>
10 <RuntimeIdentifier>win-x86</RuntimeIdentifier>
11 </PropertyGroup>
12
13 <ItemGroup>
14 <Content Include="WixToolset.Mba.Host.config" CopyToOutputDirectory="PreserveNewest" />
15 </ItemGroup>
16
17 <ItemGroup>
18 <PackageReference Include="WixToolset.Mba.Core" Version="4.0.*" />
19 </ItemGroup>
20</Project> \ No newline at end of file
diff --git a/src/ext/Bal/test/examples/FullFramework2MBA/FullFramework2BA.cs b/src/ext/Bal/test/examples/FullFramework2MBA/FullFramework2BA.cs
new file mode 100644
index 00000000..32cd19c8
--- /dev/null
+++ b/src/ext/Bal/test/examples/FullFramework2MBA/FullFramework2BA.cs
@@ -0,0 +1,34 @@
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
3namespace Example.FullFramework2MBA
4{
5 using WixToolset.Mba.Core;
6
7 public class FullFramework2BA : BootstrapperApplication
8 {
9 public FullFramework2BA(IEngine engine)
10 : base(engine)
11 {
12
13 }
14
15 protected override void Run()
16 {
17 }
18
19 protected override void OnStartup(StartupEventArgs args)
20 {
21 base.OnStartup(args);
22
23 this.engine.Log(LogLevel.Standard, nameof(FullFramework2BA));
24 }
25
26 protected override void OnShutdown(ShutdownEventArgs args)
27 {
28 base.OnShutdown(args);
29
30 var message = "Shutdown," + args.Action.ToString() + "," + args.HResult.ToString();
31 this.engine.Log(LogLevel.Standard, message);
32 }
33 }
34}
diff --git a/src/ext/Bal/test/examples/FullFramework2MBA/FullFramework2BAFactory.cs b/src/ext/Bal/test/examples/FullFramework2MBA/FullFramework2BAFactory.cs
new file mode 100644
index 00000000..647c2040
--- /dev/null
+++ b/src/ext/Bal/test/examples/FullFramework2MBA/FullFramework2BAFactory.cs
@@ -0,0 +1,22 @@
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[assembly: WixToolset.Mba.Core.BootstrapperApplicationFactory(typeof(Example.FullFramework2MBA.FullFramework2BAFactory))]
4namespace Example.FullFramework2MBA
5{
6 using WixToolset.Mba.Core;
7
8 public class FullFramework2BAFactory : BaseBootstrapperApplicationFactory
9 {
10 private static int loadCount = 0;
11
12 protected override IBootstrapperApplication Create(IEngine engine, IBootstrapperCommand bootstrapperCommand)
13 {
14 if (loadCount > 0)
15 {
16 engine.Log(LogLevel.Standard, $"Reloaded {loadCount} time(s)");
17 }
18 ++loadCount;
19 return new FullFramework2BA(engine);
20 }
21 }
22}
diff --git a/src/ext/Bal/test/examples/FullFramework2MBA/WixToolset.Mba.Host.config b/src/ext/Bal/test/examples/FullFramework2MBA/WixToolset.Mba.Host.config
new file mode 100644
index 00000000..be450a4f
--- /dev/null
+++ b/src/ext/Bal/test/examples/FullFramework2MBA/WixToolset.Mba.Host.config
@@ -0,0 +1,20 @@
1<?xml version="1.0" encoding="utf-8" ?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<configuration>
6 <configSections>
7 <sectionGroup name="wix.bootstrapper" type="WixToolset.Mba.Host.BootstrapperSectionGroup, WixToolset.Mba.Host">
8 <section name="host" type="WixToolset.Mba.Host.HostSection, WixToolset.Mba.Host" />
9 </sectionGroup>
10 </configSections>
11 <startup>
12 <supportedRuntime version="v2.0.50727" />
13 </startup>
14 <wix.bootstrapper>
15
16 <host assemblyName="Example.FullFramework2MBA">
17 <supportedFramework version="v3.5" />
18 </host>
19 </wix.bootstrapper>
20</configuration>
diff --git a/src/ext/Bal/test/examples/FullFramework4Bundle/Bundle.wxs b/src/ext/Bal/test/examples/FullFramework4Bundle/Bundle.wxs
new file mode 100644
index 00000000..7b7cbf57
--- /dev/null
+++ b/src/ext/Bal/test/examples/FullFramework4Bundle/Bundle.wxs
@@ -0,0 +1,14 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
2 <Bundle Name="FullFramework4MBA" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="E08068E0-4FBA-439D-A1C8-4CD1FE27093F">
3 <BootstrapperApplication>
4 <Payload SourceFile="Example.FullFramework4MBA\net48\win-x86\Example.FullFramework4MBA.dll" />
5 <Payload SourceFile="Example.FullFramework4MBA\net48\win-x86\mbanative.dll" />
6 <Payload SourceFile="Example.FullFramework4MBA\net48\win-x86\WixToolset.Mba.Core.dll" />
7 <Payload SourceFile="Example.FullFramework4MBA\net48\win-x86\WixToolset.Mba.Host.config" />
8 <bal:WixManagedBootstrapperApplicationHost />
9 </BootstrapperApplication>
10 <Chain>
11 <ExePackage DetectCondition="none" SourceFile="c:\windows\system32\kernel32.dll" bal:PrereqPackage="yes" />
12 </Chain>
13 </Bundle>
14</Wix>
diff --git a/src/ext/Bal/test/examples/FullFramework4Bundle/FullFramework4Bundle.wixproj b/src/ext/Bal/test/examples/FullFramework4Bundle/FullFramework4Bundle.wixproj
new file mode 100644
index 00000000..ba75a9ff
--- /dev/null
+++ b/src/ext/Bal/test/examples/FullFramework4Bundle/FullFramework4Bundle.wixproj
@@ -0,0 +1,2 @@
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<Project Sdk="WixToolset.Sdk" />
diff --git a/src/ext/Bal/test/examples/FullFramework4MBA/Example.FullFramework4MBA.csproj b/src/ext/Bal/test/examples/FullFramework4MBA/Example.FullFramework4MBA.csproj
new file mode 100644
index 00000000..a05e7888
--- /dev/null
+++ b/src/ext/Bal/test/examples/FullFramework4MBA/Example.FullFramework4MBA.csproj
@@ -0,0 +1,19 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4<Project Sdk="Microsoft.NET.Sdk">
5 <PropertyGroup>
6 <TargetFramework>net48</TargetFramework>
7 <Description>Full Framework v4 MBA</Description>
8 <RuntimeIdentifier>win-x86</RuntimeIdentifier>
9 </PropertyGroup>
10
11 <ItemGroup>
12 <PackageReference Include="Nerdbank.GitVersioning" Version="3.3.37" PrivateAssets="all" />
13 <PackageReference Include="WixToolset.Mba.Core" Version="4.0.*" PrivateAssets="All" />
14 </ItemGroup>
15
16 <ItemGroup>
17 <Content Include="WixToolset.Mba.Host.config" CopyToOutputDirectory="PreserveNewest" />
18 </ItemGroup>
19</Project> \ No newline at end of file
diff --git a/src/ext/Bal/test/examples/FullFramework4MBA/FullFramework4BA.cs b/src/ext/Bal/test/examples/FullFramework4MBA/FullFramework4BA.cs
new file mode 100644
index 00000000..8ee3bd19
--- /dev/null
+++ b/src/ext/Bal/test/examples/FullFramework4MBA/FullFramework4BA.cs
@@ -0,0 +1,34 @@
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
3namespace Example.FullFramework4MBA
4{
5 using WixToolset.Mba.Core;
6
7 public class FullFramework4BA : BootstrapperApplication
8 {
9 public FullFramework4BA(IEngine engine)
10 : base(engine)
11 {
12
13 }
14
15 protected override void Run()
16 {
17 }
18
19 protected override void OnStartup(StartupEventArgs args)
20 {
21 base.OnStartup(args);
22
23 this.engine.Log(LogLevel.Standard, nameof(FullFramework4BA));
24 }
25
26 protected override void OnShutdown(ShutdownEventArgs args)
27 {
28 base.OnShutdown(args);
29
30 var message = "Shutdown," + args.Action.ToString() + "," + args.HResult.ToString();
31 this.engine.Log(LogLevel.Standard, message);
32 }
33 }
34}
diff --git a/src/ext/Bal/test/examples/FullFramework4MBA/FullFramework4BAFactory.cs b/src/ext/Bal/test/examples/FullFramework4MBA/FullFramework4BAFactory.cs
new file mode 100644
index 00000000..6a571a54
--- /dev/null
+++ b/src/ext/Bal/test/examples/FullFramework4MBA/FullFramework4BAFactory.cs
@@ -0,0 +1,22 @@
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[assembly: WixToolset.Mba.Core.BootstrapperApplicationFactory(typeof(Example.FullFramework4MBA.FullFramework4BAFactory))]
4namespace Example.FullFramework4MBA
5{
6 using WixToolset.Mba.Core;
7
8 public class FullFramework4BAFactory : BaseBootstrapperApplicationFactory
9 {
10 private static int loadCount = 0;
11
12 protected override IBootstrapperApplication Create(IEngine engine, IBootstrapperCommand bootstrapperCommand)
13 {
14 if (loadCount > 0)
15 {
16 engine.Log(LogLevel.Standard, $"Reloaded {loadCount} time(s)");
17 }
18 ++loadCount;
19 return new FullFramework4BA(engine);
20 }
21 }
22}
diff --git a/src/ext/Bal/test/examples/FullFramework4MBA/WixToolset.Mba.Host.config b/src/ext/Bal/test/examples/FullFramework4MBA/WixToolset.Mba.Host.config
new file mode 100644
index 00000000..96678cda
--- /dev/null
+++ b/src/ext/Bal/test/examples/FullFramework4MBA/WixToolset.Mba.Host.config
@@ -0,0 +1,17 @@
1<?xml version="1.0" encoding="utf-8" ?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<configuration>
6 <configSections>
7 <sectionGroup name="wix.bootstrapper" type="WixToolset.Mba.Host.BootstrapperSectionGroup, WixToolset.Mba.Host">
8 <section name="host" type="WixToolset.Mba.Host.HostSection, WixToolset.Mba.Host" />
9 </sectionGroup>
10 </configSections>
11 <startup>
12 <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
13 </startup>
14 <wix.bootstrapper>
15 <host assemblyName="Example.FullFramework4MBA" />
16 </wix.bootstrapper>
17</configuration>
diff --git a/src/ext/Bal/test/examples/LatestCoreBundleFDD/FrameworkDependentBundle.wxs b/src/ext/Bal/test/examples/LatestCoreBundleFDD/FrameworkDependentBundle.wxs
new file mode 100644
index 00000000..d5b543e8
--- /dev/null
+++ b/src/ext/Bal/test/examples/LatestCoreBundleFDD/FrameworkDependentBundle.wxs
@@ -0,0 +1,16 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
2 <Bundle Name="FDDLatestCoreMBA" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="5CE5B5C7-4B6B-4B95-B297-731F1F956533">
3 <BootstrapperApplication>
4 <Payload SourceFile="publish\Example.LatestCoreMBA\fdd\Example.LatestCoreMBA.deps.json" Name="Example.LatestCoreMBA.deps.json" />
5 <Payload SourceFile="publish\Example.LatestCoreMBA\fdd\Example.LatestCoreMBA.dll" Name="Example.LatestCoreMBA.dll" bal:BAFactoryAssembly="yes" />
6 <Payload SourceFile="publish\Example.LatestCoreMBA\fdd\Example.LatestCoreMBA.pdb" Name="Example.LatestCoreMBA.pdb" />
7 <Payload SourceFile="publish\Example.LatestCoreMBA\fdd\Example.LatestCoreMBA.runtimeconfig.json" Name="Example.LatestCoreMBA.runtimeconfig.json" />
8 <Payload SourceFile="publish\Example.LatestCoreMBA\fdd\mbanative.dll" Name="mbanative.dll" />
9 <Payload SourceFile="publish\Example.LatestCoreMBA\fdd\WixToolset.Mba.Core.dll" Name="WixToolset.Mba.Core.dll" />
10 <bal:WixDotNetCoreBootstrapperApplicationHost />
11 </BootstrapperApplication>
12 <Chain>
13 <ExePackage DetectCondition="none" SourceFile="c:\windows\system32\kernel32.dll" bal:PrereqPackage="yes" />
14 </Chain>
15 </Bundle>
16</Wix>
diff --git a/src/ext/Bal/test/examples/LatestCoreBundleFDD/LatestCoreBundleFDD.wixproj b/src/ext/Bal/test/examples/LatestCoreBundleFDD/LatestCoreBundleFDD.wixproj
new file mode 100644
index 00000000..ba75a9ff
--- /dev/null
+++ b/src/ext/Bal/test/examples/LatestCoreBundleFDD/LatestCoreBundleFDD.wixproj
@@ -0,0 +1,2 @@
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<Project Sdk="WixToolset.Sdk" />
diff --git a/src/ext/Bal/test/examples/LatestCoreBundleSCD/LatestCoreBundleSCD.wixproj b/src/ext/Bal/test/examples/LatestCoreBundleSCD/LatestCoreBundleSCD.wixproj
new file mode 100644
index 00000000..30a860ab
--- /dev/null
+++ b/src/ext/Bal/test/examples/LatestCoreBundleSCD/LatestCoreBundleSCD.wixproj
@@ -0,0 +1,10 @@
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<Project Sdk="WixToolset.Sdk">
3 <ItemGroup>
4 <BindInputPaths Include="$(OutputPath)publish\Example.LatestCoreMBA\scd" />
5 <HarvestDirectory Include="$(OutputPath)publish\Example.LatestCoreMBA\scd">
6 <DirectoryRefId>publish.Example.LatestCoreMBA.scd</DirectoryRefId>
7 <Transforms>ba.xslt</Transforms>
8 </HarvestDirectory>
9 </ItemGroup>
10</Project>
diff --git a/src/ext/Bal/test/examples/LatestCoreBundleSCD/SelfContainedBundle.wxs b/src/ext/Bal/test/examples/LatestCoreBundleSCD/SelfContainedBundle.wxs
new file mode 100644
index 00000000..bedf0326
--- /dev/null
+++ b/src/ext/Bal/test/examples/LatestCoreBundleSCD/SelfContainedBundle.wxs
@@ -0,0 +1,11 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
2 <Bundle Name="SCDLatestCoreMBA" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="5CE5B5C7-4B6B-4B95-B297-731F1F956533">
3 <BootstrapperApplication>
4 <bal:WixDotNetCoreBootstrapperApplicationHost SelfContainedDeployment="yes" />
5 <PayloadGroupRef Id="publish.Example.LatestCoreMBA.scd" />
6 </BootstrapperApplication>
7 <Chain>
8 <ExePackage DetectCondition="none" SourceFile="c:\windows\system32\kernel32.dll" PerMachine="yes" />
9 </Chain>
10 </Bundle>
11</Wix>
diff --git a/src/ext/Bal/test/examples/LatestCoreBundleSCD/ba.xslt b/src/ext/Bal/test/examples/LatestCoreBundleSCD/ba.xslt
new file mode 100644
index 00000000..acc7474c
--- /dev/null
+++ b/src/ext/Bal/test/examples/LatestCoreBundleSCD/ba.xslt
@@ -0,0 +1,20 @@
1<?xml version="1.0" encoding="utf-8"?>
2<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
3 xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
4 xmlns:wix="http://wixtoolset.org/schemas/v4/wxs"
5>
6 <xsl:output method="xml" indent="yes"/>
7
8 <xsl:template match="@* | node()">
9 <xsl:copy>
10 <xsl:apply-templates select="@* | node()"/>
11 </xsl:copy>
12 </xsl:template>
13
14 <xsl:template match="wix:Payload[@SourceFile='SourceDir\Example.LatestCoreMBA.dll']" >
15 <xsl:copy>
16 <xsl:attribute name="BAFactoryAssembly" namespace="http://wixtoolset.org/schemas/v4/wxs/bal">yes</xsl:attribute>
17 <xsl:apply-templates select="@* | node()"/>
18 </xsl:copy>
19 </xsl:template>
20</xsl:stylesheet>
diff --git a/src/ext/Bal/test/examples/LatestCoreBundleTrimmedSCD/LatestCoreBundleTrimmedSCD.wixproj b/src/ext/Bal/test/examples/LatestCoreBundleTrimmedSCD/LatestCoreBundleTrimmedSCD.wixproj
new file mode 100644
index 00000000..5ce89b64
--- /dev/null
+++ b/src/ext/Bal/test/examples/LatestCoreBundleTrimmedSCD/LatestCoreBundleTrimmedSCD.wixproj
@@ -0,0 +1,10 @@
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<Project Sdk="WixToolset.Sdk">
3 <ItemGroup>
4 <BindInputPaths Include="$(OutputPath)publish\Example.LatestCoreMBA\trimmedscd" />
5 <HarvestDirectory Include="$(OutputPath)publish\Example.LatestCoreMBA\trimmedscd">
6 <DirectoryRefId>publish.Example.LatestCoreMBA.trimmedscd</DirectoryRefId>
7 <Transforms>ba.xslt</Transforms>
8 </HarvestDirectory>
9 </ItemGroup>
10</Project>
diff --git a/src/ext/Bal/test/examples/LatestCoreBundleTrimmedSCD/TrimmedSelfContainedBundle.wxs b/src/ext/Bal/test/examples/LatestCoreBundleTrimmedSCD/TrimmedSelfContainedBundle.wxs
new file mode 100644
index 00000000..6059f8c1
--- /dev/null
+++ b/src/ext/Bal/test/examples/LatestCoreBundleTrimmedSCD/TrimmedSelfContainedBundle.wxs
@@ -0,0 +1,11 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
2 <Bundle Name="TrimmedSCDLatestCoreMBA" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="5CE5B5C7-4B6B-4B95-B297-731F1F956533">
3 <BootstrapperApplication>
4 <bal:WixDotNetCoreBootstrapperApplicationHost SelfContainedDeployment="yes" />
5 <PayloadGroupRef Id="publish.Example.LatestCoreMBA.trimmedscd" />
6 </BootstrapperApplication>
7 <Chain>
8 <ExePackage DetectCondition="none" SourceFile="c:\windows\system32\kernel32.dll" PerMachine="yes" />
9 </Chain>
10 </Bundle>
11</Wix>
diff --git a/src/ext/Bal/test/examples/LatestCoreBundleTrimmedSCD/ba.xslt b/src/ext/Bal/test/examples/LatestCoreBundleTrimmedSCD/ba.xslt
new file mode 100644
index 00000000..acc7474c
--- /dev/null
+++ b/src/ext/Bal/test/examples/LatestCoreBundleTrimmedSCD/ba.xslt
@@ -0,0 +1,20 @@
1<?xml version="1.0" encoding="utf-8"?>
2<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
3 xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
4 xmlns:wix="http://wixtoolset.org/schemas/v4/wxs"
5>
6 <xsl:output method="xml" indent="yes"/>
7
8 <xsl:template match="@* | node()">
9 <xsl:copy>
10 <xsl:apply-templates select="@* | node()"/>
11 </xsl:copy>
12 </xsl:template>
13
14 <xsl:template match="wix:Payload[@SourceFile='SourceDir\Example.LatestCoreMBA.dll']" >
15 <xsl:copy>
16 <xsl:attribute name="BAFactoryAssembly" namespace="http://wixtoolset.org/schemas/v4/wxs/bal">yes</xsl:attribute>
17 <xsl:apply-templates select="@* | node()"/>
18 </xsl:copy>
19 </xsl:template>
20</xsl:stylesheet>
diff --git a/src/ext/Bal/test/examples/LatestCoreMBA/Example.LatestCoreMBA.csproj b/src/ext/Bal/test/examples/LatestCoreMBA/Example.LatestCoreMBA.csproj
new file mode 100644
index 00000000..9f3f02d9
--- /dev/null
+++ b/src/ext/Bal/test/examples/LatestCoreMBA/Example.LatestCoreMBA.csproj
@@ -0,0 +1,21 @@
1<Project Sdk="Microsoft.NET.Sdk">
2
3 <PropertyGroup>
4 <TargetFramework>net5.0</TargetFramework>
5 <RuntimeIdentifiers>win-x86;win-x64</RuntimeIdentifiers>
6 <EnableDynamicLoading>true</EnableDynamicLoading>
7 <Description>Latest .NET Core MBA</Description>
8 </PropertyGroup>
9
10 <ItemGroup>
11 <TrimmerRootAssembly Include="System.Diagnostics.Tools" />
12 <TrimmerRootAssembly Include="System.Runtime" />
13 <TrimmerRootAssembly Include="System.Runtime.InteropServices" />
14 <TrimmerRootAssembly Include="System.Runtime.Loader" />
15 </ItemGroup>
16
17 <ItemGroup>
18 <PackageReference Include="Nerdbank.GitVersioning" Version="3.3.37" PrivateAssets="all" />
19 <PackageReference Include="WixToolset.Mba.Core" Version="4.0.*" />
20 </ItemGroup>
21</Project> \ No newline at end of file
diff --git a/src/ext/Bal/test/examples/LatestCoreMBA/LatestCoreBA.cs b/src/ext/Bal/test/examples/LatestCoreMBA/LatestCoreBA.cs
new file mode 100644
index 00000000..50386a87
--- /dev/null
+++ b/src/ext/Bal/test/examples/LatestCoreMBA/LatestCoreBA.cs
@@ -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
3namespace Example.LatestCoreMBA
4{
5 using WixToolset.Mba.Core;
6
7 public class LatestCoreBA : BootstrapperApplication
8 {
9 public LatestCoreBA(IEngine engine)
10 : base(engine)
11 {
12 }
13
14 protected override void Run()
15 {
16 }
17
18 protected override void OnStartup(StartupEventArgs args)
19 {
20 base.OnStartup(args);
21
22 this.engine.Log(LogLevel.Standard, nameof(LatestCoreBA));
23 }
24
25 protected override void OnShutdown(ShutdownEventArgs args)
26 {
27 base.OnShutdown(args);
28
29 var message = "Shutdown," + args.Action.ToString() + "," + args.HResult.ToString();
30 this.engine.Log(LogLevel.Standard, message);
31 }
32 }
33}
diff --git a/src/ext/Bal/test/examples/LatestCoreMBA/LatestCoreBAFactory.cs b/src/ext/Bal/test/examples/LatestCoreMBA/LatestCoreBAFactory.cs
new file mode 100644
index 00000000..fff3b5c5
--- /dev/null
+++ b/src/ext/Bal/test/examples/LatestCoreMBA/LatestCoreBAFactory.cs
@@ -0,0 +1,22 @@
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[assembly: WixToolset.Mba.Core.BootstrapperApplicationFactory(typeof(Example.LatestCoreMBA.LatestCoreBAFactory))]
4namespace Example.LatestCoreMBA
5{
6 using WixToolset.Mba.Core;
7
8 public class LatestCoreBAFactory : BaseBootstrapperApplicationFactory
9 {
10 private static int loadCount = 0;
11
12 protected override IBootstrapperApplication Create(IEngine engine, IBootstrapperCommand bootstrapperCommand)
13 {
14 if (loadCount > 0)
15 {
16 engine.Log(LogLevel.Standard, $"Reloaded {loadCount} time(s)");
17 }
18 ++loadCount;
19 return new LatestCoreBA(engine);
20 }
21 }
22}
diff --git a/src/ext/Bal/test/examples/TestEngine/Example.TestEngine.vcxproj b/src/ext/Bal/test/examples/TestEngine/Example.TestEngine.vcxproj
new file mode 100644
index 00000000..99eb917e
--- /dev/null
+++ b/src/ext/Bal/test/examples/TestEngine/Example.TestEngine.vcxproj
@@ -0,0 +1,83 @@
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<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
4 <Import Project="..\..\..\..\packages\WixToolset.BalUtil.4.0.58\build\WixToolset.BalUtil.props" Condition="Exists('..\..\..\..\packages\WixToolset.BalUtil.4.0.58\build\WixToolset.BalUtil.props')" />
5 <Import Project="..\..\..\..\packages\WixToolset.BootstrapperCore.Native.4.0.141\build\WixToolset.BootstrapperCore.Native.props" Condition="Exists('..\..\..\..\packages\WixToolset.BootstrapperCore.Native.4.0.141\build\WixToolset.BootstrapperCore.Native.props')" />
6 <Import Project="..\..\..\..\packages\WixToolset.DUtil.4.0.72\build\WixToolset.DUtil.props" Condition="Exists('..\..\..\..\packages\WixToolset.DUtil.4.0.72\build\WixToolset.DUtil.props')" />
7 <ItemGroup Label="ProjectConfigurations">
8 <ProjectConfiguration Include="Debug|ARM64">
9 <Configuration>Debug</Configuration>
10 <Platform>ARM64</Platform>
11 </ProjectConfiguration>
12 <ProjectConfiguration Include="Release|ARM64">
13 <Configuration>Release</Configuration>
14 <Platform>ARM64</Platform>
15 </ProjectConfiguration>
16 <ProjectConfiguration Include="Debug|Win32">
17 <Configuration>Debug</Configuration>
18 <Platform>Win32</Platform>
19 </ProjectConfiguration>
20 <ProjectConfiguration Include="Release|Win32">
21 <Configuration>Release</Configuration>
22 <Platform>Win32</Platform>
23 </ProjectConfiguration>
24 <ProjectConfiguration Include="Debug|x64">
25 <Configuration>Debug</Configuration>
26 <Platform>x64</Platform>
27 </ProjectConfiguration>
28 <ProjectConfiguration Include="Release|x64">
29 <Configuration>Release</Configuration>
30 <Platform>x64</Platform>
31 </ProjectConfiguration>
32 </ItemGroup>
33 <PropertyGroup Label="Globals">
34 <ProjectGuid>{3D44B67D-A475-49BA-8310-E39F6C117CC9}</ProjectGuid>
35 <ConfigurationType>Application</ConfigurationType>
36 <ProjectSubSystem>Console</ProjectSubSystem>
37 <TargetName>Example.TestEngine</TargetName>
38 <PlatformToolset>v142</PlatformToolset>
39 <CharacterSet>Unicode</CharacterSet>
40 <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
41 </PropertyGroup>
42 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
43 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
44 <ImportGroup Label="ExtensionSettings">
45 </ImportGroup>
46 <ImportGroup Label="Shared">
47 <Import Project="..\..\..\..\packages\Nerdbank.GitVersioning.3.3.37\build\Nerdbank.GitVersioning.targets" Condition="Exists('..\..\..\..\packages\Nerdbank.GitVersioning.3.3.37\build\Nerdbank.GitVersioning.targets')" />
48 </ImportGroup>
49 <PropertyGroup>
50 <ProjectAdditionalLinkLibraries>
51 </ProjectAdditionalLinkLibraries>
52 </PropertyGroup>
53 <ItemGroup>
54 <ClCompile Include="precomp.cpp">
55 <PrecompiledHeader>Create</PrecompiledHeader>
56 </ClCompile>
57 <ClCompile Include="ReloadEngine.cpp" />
58 <ClCompile Include="ShutdownEngine.cpp" />
59 <ClCompile Include="ExampleTestEngine.cpp" />
60 <ClCompile Include="TestEngine.cpp" />
61 <ClCompile Include="WaitForQuitEngine.cpp" />
62 </ItemGroup>
63 <ItemGroup>
64 <ClInclude Include="precomp.h" />
65 <ClInclude Include="ReloadEngine.h" />
66 <ClInclude Include="ShutdownEngine.h" />
67 <ClInclude Include="TestEngine.h" />
68 <ClInclude Include="WaitForQuitEngine.h" />
69 </ItemGroup>
70 <ItemGroup>
71 <None Include="packages.config" />
72 </ItemGroup>
73 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
74 <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
75 <PropertyGroup>
76 <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>
77 </PropertyGroup>
78 <Error Condition="!Exists('..\..\..\..\packages\Nerdbank.GitVersioning.3.3.37\build\Nerdbank.GitVersioning.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Nerdbank.GitVersioning.3.3.37\build\Nerdbank.GitVersioning.targets'))" />
79 <Error Condition="!Exists('..\..\..\..\packages\WixToolset.BalUtil.4.0.58\build\WixToolset.BalUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\WixToolset.BalUtil.4.0.58\build\WixToolset.BalUtil.props'))" />
80 <Error Condition="!Exists('..\..\..\..\packages\WixToolset.BootstrapperCore.Native.4.0.141\build\WixToolset.BootstrapperCore.Native.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\WixToolset.BootstrapperCore.Native.4.0.141\build\WixToolset.BootstrapperCore.Native.props'))" />
81 <Error Condition="!Exists('..\..\..\..\packages\WixToolset.DUtil.4.0.72\build\WixToolset.DUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\WixToolset.DUtil.4.0.72\build\WixToolset.DUtil.props'))" />
82 </Target>
83</Project> \ No newline at end of file
diff --git a/src/ext/Bal/test/examples/TestEngine/ExampleTestEngine.cpp b/src/ext/Bal/test/examples/TestEngine/ExampleTestEngine.cpp
new file mode 100644
index 00000000..fc1938fe
--- /dev/null
+++ b/src/ext/Bal/test/examples/TestEngine/ExampleTestEngine.cpp
@@ -0,0 +1,53 @@
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
5int __cdecl wmain(int argc, LPWSTR argv[])
6{
7 HRESULT hr = S_OK;
8 BOOL fComInitialized = FALSE;
9 BOOL fShowUsage = FALSE;
10
11 // initialize COM
12 hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
13 ExitOnFailure(hr, "Failed to initialize COM.");
14 fComInitialized = TRUE;
15
16 ConsoleInitialize();
17
18 if (argc != 4)
19 {
20 fShowUsage = TRUE;
21 }
22 else if (CSTR_EQUAL == ::CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, argv[1], -1, L"reload", -1))
23 {
24 hr = RunReloadEngine(argv[2], argv[3]);
25 }
26 else if (CSTR_EQUAL == ::CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, argv[1], -1, L"shutdown", -1))
27 {
28 hr = RunShutdownEngine(argv[2], argv[3]);
29 }
30 else if (CSTR_EQUAL == ::CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, argv[1], -1, L"waitforquit", -1))
31 {
32 hr = RunWaitForQuitEngine(argv[2], argv[3]);
33 }
34 else
35 {
36 fShowUsage = TRUE;
37 }
38
39 if (fShowUsage)
40 {
41 ConsoleWriteError(hr = E_INVALIDARG, CONSOLE_COLOR_RED, "Usage: Example.TestEngine.exe {reload|shutdown|waitforquit} Bundle.exe BA.dll");
42 }
43
44 ConsoleUninitialize();
45
46LExit:
47 if (fComInitialized)
48 {
49 ::CoUninitialize();
50 }
51
52 return hr;
53}
diff --git a/src/ext/Bal/test/examples/TestEngine/ReloadEngine.cpp b/src/ext/Bal/test/examples/TestEngine/ReloadEngine.cpp
new file mode 100644
index 00000000..46fd9afa
--- /dev/null
+++ b/src/ext/Bal/test/examples/TestEngine/ReloadEngine.cpp
@@ -0,0 +1,55 @@
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
5HRESULT RunReloadEngine(
6 __in LPCWSTR wzBundleFilePath,
7 __in LPCWSTR wzBAFilePath
8 )
9{
10 HRESULT hr = S_OK;
11 TestEngine* pTestEngine = NULL;
12
13 pTestEngine = new TestEngine();
14 ConsoleExitOnNull(pTestEngine, hr, E_OUTOFMEMORY, CONSOLE_COLOR_RED, "Failed to create new test engine.");
15
16 hr = pTestEngine->Initialize(wzBundleFilePath);
17 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to initialize engine.");
18
19 hr = pTestEngine->LoadBA(wzBAFilePath);
20 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to load BA.");
21
22 hr = pTestEngine->SendStartupEvent();
23 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "BA returned failure for OnStartup.");
24
25 hr = pTestEngine->SimulateQuit(0);
26 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to simulate quit.");
27
28 hr = pTestEngine->RunApplication();
29 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to run engine.");
30
31 hr = pTestEngine->SendShutdownEvent(BOOTSTRAPPER_SHUTDOWN_ACTION_RELOAD_BOOTSTRAPPER);
32 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "BA returned failure for OnShutdown.");
33
34 pTestEngine->UnloadBA();
35
36 hr = pTestEngine->LoadBA(wzBAFilePath);
37 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to load BA.");
38
39 hr = pTestEngine->SendStartupEvent();
40 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "BA returned failure for OnStartup.");
41
42 hr = pTestEngine->SimulateQuit(0);
43 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to simulate quit.");
44
45 hr = pTestEngine->RunApplication();
46 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to run engine.");
47
48 hr = pTestEngine->SendShutdownEvent(BOOTSTRAPPER_SHUTDOWN_ACTION_RESTART);
49 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "BA returned failure for OnShutdown.");
50
51 pTestEngine->UnloadBA();
52
53LExit:
54 return hr;
55}
diff --git a/src/ext/Bal/test/examples/TestEngine/ReloadEngine.h b/src/ext/Bal/test/examples/TestEngine/ReloadEngine.h
new file mode 100644
index 00000000..0e8456af
--- /dev/null
+++ b/src/ext/Bal/test/examples/TestEngine/ReloadEngine.h
@@ -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
5HRESULT RunReloadEngine(
6 __in LPCWSTR wzBundleFilePath,
7 __in LPCWSTR wzBAFilePath
8 );
diff --git a/src/ext/Bal/test/examples/TestEngine/ShutdownEngine.cpp b/src/ext/Bal/test/examples/TestEngine/ShutdownEngine.cpp
new file mode 100644
index 00000000..3b876e4e
--- /dev/null
+++ b/src/ext/Bal/test/examples/TestEngine/ShutdownEngine.cpp
@@ -0,0 +1,38 @@
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
5HRESULT RunShutdownEngine(
6 __in LPCWSTR wzBundleFilePath,
7 __in LPCWSTR wzBAFilePath
8 )
9{
10 HRESULT hr = S_OK;
11 TestEngine* pTestEngine = NULL;
12
13 pTestEngine = new TestEngine();
14 ConsoleExitOnNull(pTestEngine, hr, E_OUTOFMEMORY, CONSOLE_COLOR_RED, "Failed to create new test engine.");
15
16 hr = pTestEngine->Initialize(wzBundleFilePath);
17 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to initialize engine.");
18
19 hr = pTestEngine->LoadBA(wzBAFilePath);
20 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to load BA.");
21
22 hr = pTestEngine->SendStartupEvent();
23 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "BA returned failure for OnStartup.");
24
25 hr = pTestEngine->SimulateQuit(0);
26 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to simulate quit.");
27
28 hr = pTestEngine->RunApplication();
29 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to run engine.");
30
31 hr = pTestEngine->SendShutdownEvent(BOOTSTRAPPER_SHUTDOWN_ACTION_RELOAD_BOOTSTRAPPER);
32 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "BA returned failure for OnShutdown.");
33
34 pTestEngine->UnloadBA();
35
36LExit:
37 return hr;
38}
diff --git a/src/ext/Bal/test/examples/TestEngine/ShutdownEngine.h b/src/ext/Bal/test/examples/TestEngine/ShutdownEngine.h
new file mode 100644
index 00000000..0cfa147a
--- /dev/null
+++ b/src/ext/Bal/test/examples/TestEngine/ShutdownEngine.h
@@ -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
5HRESULT RunShutdownEngine(
6 __in LPCWSTR wzBundleFilePath,
7 __in LPCWSTR wzBAFilePath
8 );
diff --git a/src/ext/Bal/test/examples/TestEngine/TestEngine.cpp b/src/ext/Bal/test/examples/TestEngine/TestEngine.cpp
new file mode 100644
index 00000000..4c7ec1c3
--- /dev/null
+++ b/src/ext/Bal/test/examples/TestEngine/TestEngine.cpp
@@ -0,0 +1,256 @@
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
5HRESULT TestEngine::Initialize(
6 __in LPCWSTR wzBundleFilePath
7 )
8{
9 HRESULT hr = S_OK;
10 MSG msg = { };
11
12 LogInitialize(::GetModuleHandleW(NULL));
13
14 hr = LogOpen(NULL, PathFile(wzBundleFilePath), NULL, L"txt", FALSE, FALSE, NULL);
15 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to open log.");
16
17 ::PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
18
19LExit:
20 return hr;
21}
22
23HRESULT TestEngine::LoadBA(
24 __in LPCWSTR wzBAFilePath
25 )
26{
27 HRESULT hr = S_OK;
28 BOOTSTRAPPER_COMMAND command = { };
29 BOOTSTRAPPER_CREATE_ARGS args = { };
30 PFN_BOOTSTRAPPER_APPLICATION_CREATE pfnCreate = NULL;
31
32 if (m_pCreateResults || m_hBAModule)
33 {
34 ExitFunction1(hr = E_INVALIDSTATE);
35 }
36
37 m_pCreateResults = static_cast<BOOTSTRAPPER_CREATE_RESULTS*>(MemAlloc(sizeof(BOOTSTRAPPER_CREATE_RESULTS), TRUE));
38
39 command.cbSize = sizeof(BOOTSTRAPPER_COMMAND);
40
41 hr = PathGetDirectory(wzBAFilePath, &command.wzBootstrapperWorkingFolder);
42 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to allocate wzBootstrapperWorkingFolder");
43
44 hr = PathConcat(command.wzBootstrapperWorkingFolder, L"BootstrapperApplicationData.xml", &command.wzBootstrapperApplicationDataPath);
45 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to allocate wzBootstrapperApplicationDataPath");
46
47 args.cbSize = sizeof(BOOTSTRAPPER_CREATE_ARGS);
48 args.pCommand = &command;
49 args.pfnBootstrapperEngineProc = TestEngine::EngineProc;
50 args.pvBootstrapperEngineProcContext = this;
51 args.qwEngineAPIVersion = MAKEQWORDVERSION(0, 0, 0, 1);
52
53 m_pCreateResults->cbSize = sizeof(BOOTSTRAPPER_CREATE_RESULTS);
54
55 m_hBAModule = ::LoadLibraryExW(wzBAFilePath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
56 ConsoleExitOnNullWithLastError(m_hBAModule, hr, CONSOLE_COLOR_RED, "Failed to load BA dll.");
57
58 pfnCreate = (PFN_BOOTSTRAPPER_APPLICATION_CREATE)::GetProcAddress(m_hBAModule, "BootstrapperApplicationCreate");
59 ConsoleExitOnNull(pfnCreate, hr, E_OUTOFMEMORY, CONSOLE_COLOR_RED, "Failed to get address for BootstrapperApplicationCreate.");
60
61 hr = pfnCreate(&args, m_pCreateResults);
62 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "BA returned failure on BootstrapperApplicationCreate.");
63
64LExit:
65 ReleaseStr(command.wzBootstrapperApplicationDataPath);
66 ReleaseStr(command.wzBootstrapperWorkingFolder);
67
68 return hr;
69}
70
71HRESULT TestEngine::Log(
72 __in BOOTSTRAPPER_LOG_LEVEL level,
73 __in LPCWSTR wzMessage
74 )
75{
76 switch (level)
77 {
78 case BOOTSTRAPPER_LOG_LEVEL_NONE:
79 case BOOTSTRAPPER_LOG_LEVEL_DEBUG:
80 return S_OK;
81 default:
82 LogStringLine(REPORT_STANDARD, "%ls", wzMessage);
83 return ConsoleWriteLine(CONSOLE_COLOR_NORMAL, "%ls", wzMessage);
84 }
85}
86
87HRESULT TestEngine::RunApplication()
88{
89 HRESULT hr = S_OK;
90 MSG msg = { };
91 BOOL fRet = FALSE;
92
93 // Enter the message pump.
94 while (0 != (fRet = ::GetMessageW(&msg, NULL, 0, 0)))
95 {
96 if (-1 == fRet)
97 {
98 ConsoleExitOnFailure(hr = E_UNEXPECTED, CONSOLE_COLOR_RED, "Unexpected return value from message pump.");
99 }
100 else
101 {
102 ProcessBAMessage(&msg);
103 }
104 }
105
106LExit:
107 return hr;
108}
109
110HRESULT TestEngine::SendShutdownEvent(
111 __in BOOTSTRAPPER_SHUTDOWN_ACTION defaultAction
112 )
113{
114 HRESULT hr = S_OK;
115 BA_ONSHUTDOWN_ARGS shutdownArgs = { };
116 BA_ONSHUTDOWN_RESULTS shutdownResults = { };
117 shutdownArgs.cbSize = sizeof(BA_ONSHUTDOWN_ARGS);
118 shutdownResults.action = defaultAction;
119 shutdownResults.cbSize = sizeof(BA_ONSHUTDOWN_RESULTS);
120 hr = m_pCreateResults->pfnBootstrapperApplicationProc(BOOTSTRAPPER_APPLICATION_MESSAGE_ONSHUTDOWN, &shutdownArgs, &shutdownResults, m_pCreateResults->pvBootstrapperApplicationProcContext);
121 return hr;
122}
123
124HRESULT TestEngine::SendStartupEvent()
125{
126 HRESULT hr = S_OK;
127 BA_ONSTARTUP_ARGS startupArgs = { };
128 BA_ONSTARTUP_RESULTS startupResults = { };
129 startupArgs.cbSize = sizeof(BA_ONSTARTUP_ARGS);
130 startupResults.cbSize = sizeof(BA_ONSTARTUP_RESULTS);
131 hr = m_pCreateResults->pfnBootstrapperApplicationProc(BOOTSTRAPPER_APPLICATION_MESSAGE_ONSTARTUP, &startupArgs, &startupResults, m_pCreateResults->pvBootstrapperApplicationProcContext);
132 return hr;
133}
134
135HRESULT TestEngine::SimulateQuit(
136 __in DWORD dwExitCode
137 )
138{
139 BAENGINE_QUIT_ARGS args = { };
140 BAENGINE_QUIT_RESULTS results = { };
141
142 args.cbSize = sizeof(BAENGINE_QUIT_ARGS);
143 args.dwExitCode = dwExitCode;
144
145 results.cbSize = sizeof(BAENGINE_QUIT_RESULTS);
146
147 return BAEngineQuit(&args, &results);
148}
149
150void TestEngine::UnloadBA()
151{
152 PFN_BOOTSTRAPPER_APPLICATION_DESTROY pfnDestroy = NULL;
153 BOOL fDisableUnloading = m_pCreateResults && m_pCreateResults->fDisableUnloading;
154
155 ReleaseNullMem(m_pCreateResults);
156
157 pfnDestroy = (PFN_BOOTSTRAPPER_APPLICATION_DESTROY)::GetProcAddress(m_hBAModule, "BootstrapperApplicationDestroy");
158
159 if (pfnDestroy)
160 {
161 pfnDestroy();
162 }
163
164 if (m_hBAModule)
165 {
166 if (!fDisableUnloading)
167 {
168 ::FreeLibrary(m_hBAModule);
169 }
170
171 m_hBAModule = NULL;
172 }
173}
174
175HRESULT TestEngine::BAEngineLog(
176 __in BAENGINE_LOG_ARGS* pArgs,
177 __in BAENGINE_LOG_RESULTS* /*pResults*/
178 )
179{
180 return Log(pArgs->level, pArgs->wzMessage);
181}
182
183HRESULT TestEngine::BAEngineQuit(
184 __in BAENGINE_QUIT_ARGS* pArgs,
185 __in BAENGINE_QUIT_RESULTS* /*pResults*/
186 )
187{
188 HRESULT hr = S_OK;
189
190 if (!::PostThreadMessageW(m_dwThreadId, WM_TESTENG_QUIT, static_cast<WPARAM>(pArgs->dwExitCode), 0))
191 {
192 ConsoleExitWithLastError(hr, CONSOLE_COLOR_RED, "Failed to post shutdown message.");
193 }
194
195LExit:
196 return hr;
197}
198
199HRESULT WINAPI TestEngine::EngineProc(
200 __in BOOTSTRAPPER_ENGINE_MESSAGE message,
201 __in const LPVOID pvArgs,
202 __inout LPVOID pvResults,
203 __in_opt LPVOID pvContext
204 )
205{
206 HRESULT hr = S_OK;
207 TestEngine* pContext = (TestEngine*)pvContext;
208
209 if (!pContext || !pvArgs || !pvResults)
210 {
211 ExitFunction1(hr = E_INVALIDARG);
212 }
213
214 switch (message)
215 {
216 case BOOTSTRAPPER_ENGINE_MESSAGE_LOG:
217 hr = pContext->BAEngineLog(reinterpret_cast<BAENGINE_LOG_ARGS*>(pvArgs), reinterpret_cast<BAENGINE_LOG_RESULTS*>(pvResults));
218 break;
219 case BOOTSTRAPPER_ENGINE_MESSAGE_QUIT:
220 hr = pContext->BAEngineQuit(reinterpret_cast<BAENGINE_QUIT_ARGS*>(pvArgs), reinterpret_cast<BAENGINE_QUIT_RESULTS*>(pvResults));
221 default:
222 hr = E_NOTIMPL;
223 break;
224 }
225
226LExit:
227 return hr;
228}
229
230HRESULT TestEngine::ProcessBAMessage(
231 __in const MSG* pmsg
232 )
233{
234 HRESULT hr = S_OK;
235
236 switch (pmsg->message)
237 {
238 case WM_TESTENG_QUIT:
239 ::PostQuitMessage(static_cast<int>(pmsg->wParam)); // go bye-bye.
240 break;
241 }
242
243 return hr;
244}
245
246TestEngine::TestEngine()
247{
248 m_hBAModule = NULL;
249 m_pCreateResults = NULL;
250 m_dwThreadId = ::GetCurrentThreadId();
251}
252
253TestEngine::~TestEngine()
254{
255 ReleaseMem(m_pCreateResults);
256}
diff --git a/src/ext/Bal/test/examples/TestEngine/TestEngine.h b/src/ext/Bal/test/examples/TestEngine/TestEngine.h
new file mode 100644
index 00000000..44e813bd
--- /dev/null
+++ b/src/ext/Bal/test/examples/TestEngine/TestEngine.h
@@ -0,0 +1,80 @@
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
5enum WM_TESTENG
6{
7 WM_TESTENG_FIRST = WM_APP + 0xFFF, // this enum value must always be first.
8
9 WM_TESTENG_DETECT,
10 WM_TESTENG_PLAN,
11 WM_TESTENG_ELEVATE,
12 WM_TESTENG_APPLY,
13 WM_TESTENG_LAUNCH_APPROVED_EXE,
14 WM_TESTENG_QUIT,
15
16 WM_TESTENG_LAST, // this enum value must always be last.
17};
18
19class TestEngine
20{
21public:
22 HRESULT Initialize(
23 __in LPCWSTR wzBundleFilePath
24 );
25
26 HRESULT LoadBA(
27 __in LPCWSTR wzBAFilePath
28 );
29
30 HRESULT Log(
31 __in BOOTSTRAPPER_LOG_LEVEL level,
32 __in LPCWSTR wzMessage
33 );
34
35 HRESULT RunApplication();
36
37 HRESULT SendShutdownEvent(
38 __in BOOTSTRAPPER_SHUTDOWN_ACTION defaultAction
39 );
40
41 HRESULT SendStartupEvent();
42
43 HRESULT SimulateQuit(
44 __in DWORD dwExitCode
45 );
46
47 void UnloadBA();
48
49private:
50 HRESULT BAEngineLog(
51 __in BAENGINE_LOG_ARGS* pArgs,
52 __in BAENGINE_LOG_RESULTS* pResults
53 );
54
55 HRESULT BAEngineQuit(
56 __in BAENGINE_QUIT_ARGS* pArgs,
57 __in BAENGINE_QUIT_RESULTS* pResults
58 );
59
60 static HRESULT WINAPI EngineProc(
61 __in BOOTSTRAPPER_ENGINE_MESSAGE message,
62 __in const LPVOID pvArgs,
63 __inout LPVOID pvResults,
64 __in_opt LPVOID pvContext
65 );
66
67 HRESULT ProcessBAMessage(
68 __in const MSG* pmsg
69 );
70
71public:
72 TestEngine();
73
74 ~TestEngine();
75
76private:
77 HMODULE m_hBAModule;
78 BOOTSTRAPPER_CREATE_RESULTS* m_pCreateResults;
79 DWORD m_dwThreadId;
80}; \ No newline at end of file
diff --git a/src/ext/Bal/test/examples/TestEngine/WaitForQuitEngine.cpp b/src/ext/Bal/test/examples/TestEngine/WaitForQuitEngine.cpp
new file mode 100644
index 00000000..2f80ba75
--- /dev/null
+++ b/src/ext/Bal/test/examples/TestEngine/WaitForQuitEngine.cpp
@@ -0,0 +1,35 @@
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
5HRESULT RunWaitForQuitEngine(
6 __in LPCWSTR wzBundleFilePath,
7 __in LPCWSTR wzBAFilePath
8 )
9{
10 HRESULT hr = S_OK;
11 TestEngine* pTestEngine = NULL;
12
13 pTestEngine = new TestEngine();
14 ConsoleExitOnNull(pTestEngine, hr, E_OUTOFMEMORY, CONSOLE_COLOR_RED, "Failed to create new test engine.");
15
16 hr = pTestEngine->Initialize(wzBundleFilePath);
17 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to initialize engine.");
18
19 hr = pTestEngine->LoadBA(wzBAFilePath);
20 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to load BA.");
21
22 hr = pTestEngine->SendStartupEvent();
23 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "BA returned failure for OnStartup.");
24
25 hr = pTestEngine->RunApplication();
26 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to run engine.");
27
28 hr = pTestEngine->SendShutdownEvent(BOOTSTRAPPER_SHUTDOWN_ACTION_RELOAD_BOOTSTRAPPER);
29 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "BA returned failure for OnShutdown.");
30
31 pTestEngine->UnloadBA();
32
33LExit:
34 return hr;
35}
diff --git a/src/ext/Bal/test/examples/TestEngine/WaitForQuitEngine.h b/src/ext/Bal/test/examples/TestEngine/WaitForQuitEngine.h
new file mode 100644
index 00000000..99e3f63c
--- /dev/null
+++ b/src/ext/Bal/test/examples/TestEngine/WaitForQuitEngine.h
@@ -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
5HRESULT RunWaitForQuitEngine(
6 __in LPCWSTR wzBundleFilePath,
7 __in LPCWSTR wzBAFilePath
8 );
diff --git a/src/ext/Bal/test/examples/TestEngine/packages.config b/src/ext/Bal/test/examples/TestEngine/packages.config
new file mode 100644
index 00000000..548ddb48
--- /dev/null
+++ b/src/ext/Bal/test/examples/TestEngine/packages.config
@@ -0,0 +1,7 @@
1<?xml version="1.0" encoding="utf-8"?>
2<packages>
3 <package id="Nerdbank.GitVersioning" version="3.3.37" targetFramework="native" developmentDependency="true" />
4 <package id="WixToolset.BootstrapperCore.Native" version="4.0.141" targetFramework="native" />
5 <package id="WixToolset.BalUtil" version="4.0.58" targetFramework="native" />
6 <package id="WixToolset.DUtil" version="4.0.72" targetFramework="native" />
7</packages> \ No newline at end of file
diff --git a/src/ext/Bal/test/examples/TestEngine/precomp.cpp b/src/ext/Bal/test/examples/TestEngine/precomp.cpp
new file mode 100644
index 00000000..37664a1c
--- /dev/null
+++ b/src/ext/Bal/test/examples/TestEngine/precomp.cpp
@@ -0,0 +1,3 @@
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"
diff --git a/src/ext/Bal/test/examples/TestEngine/precomp.h b/src/ext/Bal/test/examples/TestEngine/precomp.h
new file mode 100644
index 00000000..f943f420
--- /dev/null
+++ b/src/ext/Bal/test/examples/TestEngine/precomp.h
@@ -0,0 +1,20 @@
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#include <windows.h>
5#include <MsiQuery.h>
6
7#include "dutil.h"
8#include "conutil.h"
9#include "logutil.h"
10#include "memutil.h"
11#include "pathutil.h"
12#include "strutil.h"
13
14#include "BootstrapperEngine.h"
15#include "BootstrapperApplication.h"
16
17#include "TestEngine.h"
18#include "ReloadEngine.h"
19#include "ShutdownEngine.h"
20#include "WaitForQuitEngine.h"
diff --git a/src/ext/Bal/test/examples/WPFCoreBundleFDD/FrameworkDependentBundle.wxs b/src/ext/Bal/test/examples/WPFCoreBundleFDD/FrameworkDependentBundle.wxs
new file mode 100644
index 00000000..68d742b0
--- /dev/null
+++ b/src/ext/Bal/test/examples/WPFCoreBundleFDD/FrameworkDependentBundle.wxs
@@ -0,0 +1,16 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
2 <Bundle Name="FDDWPFCoreMBA" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="5CE5B5C7-4B6B-4B95-B297-731F1F956533">
3 <BootstrapperApplication>
4 <Payload SourceFile="publish\Example.WPFCoreMBA\fdd\Example.WPFCoreMBA.deps.json" Name="Example.WPFCoreMBA.deps.json" />
5 <Payload SourceFile="publish\Example.WPFCoreMBA\fdd\Example.WPFCoreMBA.dll" Name="Example.WPFCoreMBA.dll" bal:BAFactoryAssembly="yes" />
6 <Payload SourceFile="publish\Example.WPFCoreMBA\fdd\Example.WPFCoreMBA.pdb" Name="Example.WPFCoreMBA.pdb" />
7 <Payload SourceFile="publish\Example.WPFCoreMBA\fdd\Example.WPFCoreMBA.runtimeconfig.json" Name="Example.WPFCoreMBA.runtimeconfig.json" />
8 <Payload SourceFile="publish\Example.WPFCoreMBA\fdd\mbanative.dll" Name="mbanative.dll" />
9 <Payload SourceFile="publish\Example.WPFCoreMBA\fdd\WixToolset.Mba.Core.dll" Name="WixToolset.Mba.Core.dll" />
10 <bal:WixDotNetCoreBootstrapperApplicationHost />
11 </BootstrapperApplication>
12 <Chain>
13 <ExePackage DetectCondition="none" SourceFile="c:\windows\system32\kernel32.dll" bal:PrereqPackage="yes" />
14 </Chain>
15 </Bundle>
16</Wix>
diff --git a/src/ext/Bal/test/examples/WPFCoreBundleFDD/WPFCoreBundleFDD.wixproj b/src/ext/Bal/test/examples/WPFCoreBundleFDD/WPFCoreBundleFDD.wixproj
new file mode 100644
index 00000000..ba75a9ff
--- /dev/null
+++ b/src/ext/Bal/test/examples/WPFCoreBundleFDD/WPFCoreBundleFDD.wixproj
@@ -0,0 +1,2 @@
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<Project Sdk="WixToolset.Sdk" />
diff --git a/src/ext/Bal/test/examples/WPFCoreMBA/AssemblyInfo.cs b/src/ext/Bal/test/examples/WPFCoreMBA/AssemblyInfo.cs
new file mode 100644
index 00000000..03a5c7fa
--- /dev/null
+++ b/src/ext/Bal/test/examples/WPFCoreMBA/AssemblyInfo.cs
@@ -0,0 +1,12 @@
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
3using System.Windows;
4
5[assembly:ThemeInfo(
6 ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
7 //(used if a resource is not found in the page,
8 // or application resource dictionaries)
9 ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
10 //(used if a resource is not found in the page,
11 // app, or any theme specific resource dictionaries)
12)]
diff --git a/src/ext/Bal/test/examples/WPFCoreMBA/Example.WPFCoreMBA.csproj b/src/ext/Bal/test/examples/WPFCoreMBA/Example.WPFCoreMBA.csproj
new file mode 100644
index 00000000..296e5be9
--- /dev/null
+++ b/src/ext/Bal/test/examples/WPFCoreMBA/Example.WPFCoreMBA.csproj
@@ -0,0 +1,16 @@
1<Project Sdk="Microsoft.NET.Sdk">
2
3 <PropertyGroup>
4 <TargetFramework>net5.0-windows</TargetFramework>
5 <RuntimeIdentifiers>win-x86;win-x64</RuntimeIdentifiers>
6 <EnableDynamicLoading>true</EnableDynamicLoading>
7 <Description>WPF .NET Core MBA</Description>
8 <UseWPF>true</UseWPF>
9 </PropertyGroup>
10
11
12 <ItemGroup>
13 <PackageReference Include="Nerdbank.GitVersioning" Version="3.3.37" PrivateAssets="all" />
14 <PackageReference Include="WixToolset.Mba.Core" Version="4.0.*" />
15 </ItemGroup>
16</Project> \ No newline at end of file
diff --git a/src/ext/Bal/test/examples/WPFCoreMBA/MainWindow.xaml b/src/ext/Bal/test/examples/WPFCoreMBA/MainWindow.xaml
new file mode 100644
index 00000000..40a27a06
--- /dev/null
+++ b/src/ext/Bal/test/examples/WPFCoreMBA/MainWindow.xaml
@@ -0,0 +1,16 @@
1<?xml version="1.0" encoding="utf-8" ?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<Window x:Class="Example.WPFCoreMBA.MainWindow"
6 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
7 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
8 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
9 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
10 xmlns:local="clr-namespace:Example.WPFCoreMBA"
11 mc:Ignorable="d"
12 Title="MainWindow" Height="450" Width="800">
13 <Grid>
14
15 </Grid>
16</Window>
diff --git a/src/ext/Bal/test/examples/WPFCoreMBA/MainWindow.xaml.cs b/src/ext/Bal/test/examples/WPFCoreMBA/MainWindow.xaml.cs
new file mode 100644
index 00000000..4f61b807
--- /dev/null
+++ b/src/ext/Bal/test/examples/WPFCoreMBA/MainWindow.xaml.cs
@@ -0,0 +1,17 @@
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
3namespace Example.WPFCoreMBA
4{
5 using System.Windows;
6
7 /// <summary>
8 /// Interaction logic for MainWindow.xaml
9 /// </summary>
10 public partial class MainWindow : Window
11 {
12 public MainWindow()
13 {
14 this.InitializeComponent();
15 }
16 }
17}
diff --git a/src/ext/Bal/test/examples/WPFCoreMBA/WPFCoreBA.cs b/src/ext/Bal/test/examples/WPFCoreMBA/WPFCoreBA.cs
new file mode 100644
index 00000000..d50be813
--- /dev/null
+++ b/src/ext/Bal/test/examples/WPFCoreMBA/WPFCoreBA.cs
@@ -0,0 +1,42 @@
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
3namespace Example.WPFCoreMBA
4{
5 using System.Windows.Threading;
6 using WixToolset.Mba.Core;
7
8 public class WPFCoreBA : BootstrapperApplication
9 {
10 public WPFCoreBA(IEngine engine)
11 : base(engine)
12 {
13 }
14
15 public Dispatcher BADispatcher { get; private set; }
16
17 protected override void Run()
18 {
19 this.BADispatcher = Dispatcher.CurrentDispatcher;
20 var window = new MainWindow();
21 window.Closed += (s, e) => this.BADispatcher.InvokeShutdown();
22 //window.Show();
23 //Dispatcher.Run();
24 //this.engine.Quit(0);
25 }
26
27 protected override void OnStartup(StartupEventArgs args)
28 {
29 base.OnStartup(args);
30
31 this.engine.Log(LogLevel.Standard, nameof(WPFCoreBA));
32 }
33
34 protected override void OnShutdown(ShutdownEventArgs args)
35 {
36 base.OnShutdown(args);
37
38 var message = "Shutdown," + args.Action.ToString() + "," + args.HResult.ToString();
39 this.engine.Log(LogLevel.Standard, message);
40 }
41 }
42}
diff --git a/src/ext/Bal/test/examples/WPFCoreMBA/WPFCoreBAFactory.cs b/src/ext/Bal/test/examples/WPFCoreMBA/WPFCoreBAFactory.cs
new file mode 100644
index 00000000..a3ccdf9f
--- /dev/null
+++ b/src/ext/Bal/test/examples/WPFCoreMBA/WPFCoreBAFactory.cs
@@ -0,0 +1,22 @@
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[assembly: WixToolset.Mba.Core.BootstrapperApplicationFactory(typeof(Example.WPFCoreMBA.WPFCoreBAFactory))]
4namespace Example.WPFCoreMBA
5{
6 using WixToolset.Mba.Core;
7
8 public class WPFCoreBAFactory : BaseBootstrapperApplicationFactory
9 {
10 private static int loadCount = 0;
11
12 protected override IBootstrapperApplication Create(IEngine engine, IBootstrapperCommand bootstrapperCommand)
13 {
14 if (loadCount > 0)
15 {
16 engine.Log(LogLevel.Standard, $"Reloaded {loadCount} time(s)");
17 }
18 ++loadCount;
19 return new WPFCoreBA(engine);
20 }
21 }
22}
diff --git a/src/ext/Bal/test/examples/Wix.Build.props b/src/ext/Bal/test/examples/Wix.Build.props
new file mode 100644
index 00000000..aad94bb6
--- /dev/null
+++ b/src/ext/Bal/test/examples/Wix.Build.props
@@ -0,0 +1,10 @@
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<Project>
4 <PropertyGroup>
5 <OutputType>Bundle</OutputType>
6 <TargetExt>.exe</TargetExt>
7 <HarvestDirectoryAdditionalOptions>-generate payloadgroup</HarvestDirectoryAdditionalOptions>
8 <OutputPath>$(OutputPath)examples\</OutputPath>
9 </PropertyGroup>
10</Project>
diff --git a/src/ext/Bal/test/examples/Wix.Build.targets b/src/ext/Bal/test/examples/Wix.Build.targets
new file mode 100644
index 00000000..7e6fe9f2
--- /dev/null
+++ b/src/ext/Bal/test/examples/Wix.Build.targets
@@ -0,0 +1,8 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3<Project>
4 <ItemGroup>
5 <BindInputPaths Include="$(OutputPath)" />
6 <WixExtension Include="$(OutputPath)..\netstandard2.0\WixToolset.Bal.wixext.dll" />
7 </ItemGroup>
8</Project>
diff --git a/src/ext/Bal/test/examples/examples.proj b/src/ext/Bal/test/examples/examples.proj
new file mode 100644
index 00000000..08cb7511
--- /dev/null
+++ b/src/ext/Bal/test/examples/examples.proj
@@ -0,0 +1,50 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
6 <Import Project="..\..\Directory.Build.props" />
7
8 <PropertyGroup>
9 <EarliestCoreMBAProjectPath>EarliestCoreMBA\Example.EarliestCoreMBA.csproj</EarliestCoreMBAProjectPath>
10 <FullFramework2MBAProjectPath>FullFramework2MBA\Example.FullFramework2MBA.csproj</FullFramework2MBAProjectPath>
11 <FullFramework4MBAProjectPath>FullFramework4MBA\Example.FullFramework4MBA.csproj</FullFramework4MBAProjectPath>
12 <LatestCoreMBAProjectPath>LatestCoreMBA\Example.LatestCoreMBA.csproj</LatestCoreMBAProjectPath>
13 <WPFCoreMBAProjectPath>WPFCoreMBA\Example.WPFCoreMBA.csproj</WPFCoreMBAProjectPath>
14 <MBAPublishPath>$(OutputPath)examples\publish\</MBAPublishPath>
15 </PropertyGroup>
16
17 <ItemGroup>
18 <CoreMBAProject Include="$(EarliestCoreMBAProjectPath)">
19 <PublishPath>$(MBAPublishPath)Example.EarliestCoreMBA</PublishPath>
20 </CoreMBAProject>
21 <CoreMBAProject Include="$(LatestCoreMBAProjectPath)">
22 <PublishPath>$(MBAPublishPath)Example.LatestCoreMBA</PublishPath>
23 </CoreMBAProject>
24 <CoreMBAProject Include="$(WPFCoreMBAProjectPath)">
25 <PublishPath>$(MBAPublishPath)Example.WPFCoreMBA</PublishPath>
26 <SkipSCD>true</SkipSCD>
27 <SkipTrimmedSCD>true</SkipTrimmedSCD>
28 </CoreMBAProject>
29
30 <FullMBAProject Include="$(FullFramework2MBAProjectPath)" />
31 <FullMBAProject Include="$(FullFramework4MBAProjectPath)" />
32
33 <ExampleBundleProject Include="**\*.wixproj" />
34 </ItemGroup>
35
36 <Target Name="PublishCoreExamples">
37 <Exec Command='dotnet publish -o "%(CoreMBAProject.PublishPath)\fdd" -r win-x86 -c $(Configuration) --self-contained false "%(CoreMBAProject.Identity)"'
38 Condition="'%(CoreMBAProject.SkipFDD)'==''" />
39 <Exec Command='dotnet publish -o "%(CoreMBAProject.PublishPath)\scd" -r win-x86 -c $(Configuration) --self-contained true "%(CoreMBAProject.Identity)"'
40 Condition="'%(CoreMBAProject.SkipSCD)'==''" />
41 <Exec Command='dotnet publish -o "%(CoreMBAProject.PublishPath)\trimmedscd" -r win-x86 -c $(Configuration) --self-contained true -p:PublishTrimmed=true "%(CoreMBAProject.Identity)"'
42 Condition="'%(CoreMBAProject.SkipTrimmedSCD)'==''" />
43 </Target>
44
45 <Target Name="Build" DependsOnTargets="PublishCoreExamples">
46 <MSBuild Projects="%(ExampleBundleProject.Identity)" />
47 </Target>
48
49 <Import Project="..\..\Directory.Build.targets" />
50</Project> \ No newline at end of file
diff --git a/src/ext/Bal/wix.snk b/src/ext/Bal/wix.snk
new file mode 100644
index 00000000..3908a66a
--- /dev/null
+++ b/src/ext/Bal/wix.snk
Binary files differ
diff --git a/src/ext/Bal/wixext/BalBurnBackendExtension.cs b/src/ext/Bal/wixext/BalBurnBackendExtension.cs
new file mode 100644
index 00000000..e8dc7a3e
--- /dev/null
+++ b/src/ext/Bal/wixext/BalBurnBackendExtension.cs
@@ -0,0 +1,171 @@
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
3namespace WixToolset.Bal
4{
5 using System;
6 using System.Collections.Generic;
7 using System.Linq;
8 using WixToolset.Bal.Symbols;
9 using WixToolset.Data;
10 using WixToolset.Data.Burn;
11 using WixToolset.Data.Symbols;
12 using WixToolset.Extensibility;
13
14 public class BalBurnBackendExtension : BaseBurnBackendBinderExtension
15 {
16 private static readonly IntermediateSymbolDefinition[] BurnSymbolDefinitions =
17 {
18 BalSymbolDefinitions.WixBalBAFactoryAssembly,
19 BalSymbolDefinitions.WixBalBAFunctions,
20 BalSymbolDefinitions.WixBalCondition,
21 BalSymbolDefinitions.WixBalPackageInfo,
22 BalSymbolDefinitions.WixDncOptions,
23 BalSymbolDefinitions.WixMbaPrereqInformation,
24 BalSymbolDefinitions.WixStdbaOptions,
25 BalSymbolDefinitions.WixStdbaOverridableVariable,
26 };
27
28 protected override IReadOnlyCollection<IntermediateSymbolDefinition> SymbolDefinitions => BurnSymbolDefinitions;
29
30 public override void SymbolsFinalized(IntermediateSection section)
31 {
32 base.SymbolsFinalized(section);
33
34 var baSymbol = section.Symbols.OfType<WixBootstrapperApplicationDllSymbol>().SingleOrDefault();
35 var baId = baSymbol?.Id?.Id;
36 if (null == baId)
37 {
38 return;
39 }
40
41 var isStdBA = baId.StartsWith("WixStandardBootstrapperApplication");
42 var isMBA = baId.StartsWith("WixManagedBootstrapperApplicationHost");
43 var isDNC = baId.StartsWith("WixDotNetCoreBootstrapperApplicationHost");
44 var isSCD = isDNC && this.VerifySCD(section);
45
46 if (isDNC)
47 {
48 this.FinalizeBAFactorySymbol(section);
49 }
50
51 if (isStdBA || isMBA || isDNC)
52 {
53 this.VerifyBAFunctions(section);
54 }
55
56 if (isMBA || (isDNC && !isSCD))
57 {
58 this.VerifyPrereqPackages(section, isDNC);
59 }
60 }
61
62 private void FinalizeBAFactorySymbol(IntermediateSection section)
63 {
64 var factorySymbol = section.Symbols.OfType<WixBalBAFactoryAssemblySymbol>().SingleOrDefault();
65 if (null == factorySymbol)
66 {
67 return;
68 }
69
70 var factoryPayloadSymbol = section.Symbols.OfType<WixBundlePayloadSymbol>()
71 .Where(p => p.Id.Id == factorySymbol.PayloadId)
72 .SingleOrDefault();
73 if (null == factoryPayloadSymbol)
74 {
75 return;
76 }
77
78 factorySymbol.FilePath = factoryPayloadSymbol.Name;
79 }
80
81 private void VerifyBAFunctions(IntermediateSection section)
82 {
83 WixBalBAFunctionsSymbol baFunctionsSymbol = null;
84 foreach (var symbol in section.Symbols.OfType<WixBalBAFunctionsSymbol>())
85 {
86 if (null == baFunctionsSymbol)
87 {
88 baFunctionsSymbol = symbol;
89 }
90 else
91 {
92 this.Messaging.Write(BalErrors.MultipleBAFunctions(symbol.SourceLineNumbers));
93 }
94 }
95
96 var payloadPropertiesSymbols = section.Symbols.OfType<WixBundlePayloadSymbol>().ToList();
97 if (null == baFunctionsSymbol)
98 {
99 foreach (var payloadPropertiesSymbol in payloadPropertiesSymbols)
100 {
101 if (string.Equals(payloadPropertiesSymbol.Name, "bafunctions.dll", StringComparison.OrdinalIgnoreCase) &&
102 BurnConstants.BurnUXContainerName == payloadPropertiesSymbol.ContainerRef)
103 {
104 this.Messaging.Write(BalWarnings.UnmarkedBAFunctionsDLL(payloadPropertiesSymbol.SourceLineNumbers));
105 }
106 }
107 }
108 else
109 {
110 var payloadId = baFunctionsSymbol.Id;
111 var bundlePayloadSymbol = payloadPropertiesSymbols.Single(x => payloadId == x.Id);
112 if (BurnConstants.BurnUXContainerName != bundlePayloadSymbol.ContainerRef)
113 {
114 this.Messaging.Write(BalErrors.BAFunctionsPayloadRequiredInUXContainer(baFunctionsSymbol.SourceLineNumbers));
115 }
116 }
117 }
118
119 private void VerifyPrereqPackages(IntermediateSection section, bool isDNC)
120 {
121 var prereqInfoSymbols = section.Symbols.OfType<WixMbaPrereqInformationSymbol>().ToList();
122 if (prereqInfoSymbols.Count == 0)
123 {
124 var message = isDNC ? BalErrors.MissingDNCPrereq() : BalErrors.MissingMBAPrereq();
125 this.Messaging.Write(message);
126 return;
127 }
128
129 var foundLicenseFile = false;
130 var foundLicenseUrl = false;
131
132 foreach (var prereqInfoSymbol in prereqInfoSymbols)
133 {
134 if (null != prereqInfoSymbol.LicenseFile)
135 {
136 if (foundLicenseFile || foundLicenseUrl)
137 {
138 this.Messaging.Write(BalErrors.MultiplePrereqLicenses(prereqInfoSymbol.SourceLineNumbers));
139 return;
140 }
141
142 foundLicenseFile = true;
143 }
144
145 if (null != prereqInfoSymbol.LicenseUrl)
146 {
147 if (foundLicenseFile || foundLicenseUrl)
148 {
149 this.Messaging.Write(BalErrors.MultiplePrereqLicenses(prereqInfoSymbol.SourceLineNumbers));
150 return;
151 }
152
153 foundLicenseUrl = true;
154 }
155 }
156 }
157
158 private bool VerifySCD(IntermediateSection section)
159 {
160 var isSCD = false;
161
162 var dncOptions = section.Symbols.OfType<WixDncOptionsSymbol>().SingleOrDefault();
163 if (dncOptions != null)
164 {
165 isSCD = dncOptions.SelfContainedDeployment != 0;
166 }
167
168 return isSCD;
169 }
170 }
171}
diff --git a/src/ext/Bal/wixext/BalCompiler.cs b/src/ext/Bal/wixext/BalCompiler.cs
new file mode 100644
index 00000000..267345e7
--- /dev/null
+++ b/src/ext/Bal/wixext/BalCompiler.cs
@@ -0,0 +1,923 @@
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
3namespace WixToolset.Bal
4{
5 using System;
6 using System.Collections.Generic;
7 using System.Xml.Linq;
8 using WixToolset.Bal.Symbols;
9 using WixToolset.Data;
10 using WixToolset.Data.Symbols;
11 using WixToolset.Extensibility;
12 using WixToolset.Extensibility.Data;
13
14 /// <summary>
15 /// The compiler for the WiX Toolset Bal Extension.
16 /// </summary>
17 public sealed class BalCompiler : BaseCompilerExtension
18 {
19 private readonly Dictionary<string, WixMbaPrereqInformationSymbol> prereqInfoSymbolsByPackageId;
20
21 private enum WixDotNetCoreBootstrapperApplicationHostTheme
22 {
23 Unknown,
24 None,
25 Standard,
26 }
27
28 private enum WixManagedBootstrapperApplicationHostTheme
29 {
30 Unknown,
31 None,
32 Standard,
33 }
34
35 private enum WixStandardBootstrapperApplicationTheme
36 {
37 Unknown,
38 HyperlinkLargeLicense,
39 HyperlinkLicense,
40 HyperlinkSidebarLicense,
41 None,
42 RtfLargeLicense,
43 RtfLicense,
44 }
45
46 /// <summary>
47 /// Instantiate a new BalCompiler.
48 /// </summary>
49 public BalCompiler()
50 {
51 this.prereqInfoSymbolsByPackageId = new Dictionary<string, WixMbaPrereqInformationSymbol>();
52 }
53
54 public override XNamespace Namespace => "http://wixtoolset.org/schemas/v4/wxs/bal";
55
56 /// <summary>
57 /// Processes an element for the Compiler.
58 /// </summary>
59 /// <param name="intermediate"></param>
60 /// <param name="section"></param>
61 /// <param name="parentElement">Parent element of element to process.</param>
62 /// <param name="element">Element to process.</param>
63 /// <param name="context">Extra information about the context in which this element is being parsed.</param>
64 public override void ParseElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, IDictionary<string, string> context)
65 {
66 switch (parentElement.Name.LocalName)
67 {
68 case "Bundle":
69 case "Fragment":
70 switch (element.Name.LocalName)
71 {
72 case "Condition":
73 this.ParseConditionElement(intermediate, section, element);
74 break;
75 case "ManagedBootstrapperApplicationPrereqInformation":
76 this.ParseMbaPrereqInfoElement(intermediate, section, element);
77 break;
78 default:
79 this.ParseHelper.UnexpectedElement(parentElement, element);
80 break;
81 }
82 break;
83 case "BootstrapperApplication":
84 switch (element.Name.LocalName)
85 {
86 case "WixStandardBootstrapperApplication":
87 this.ParseWixStandardBootstrapperApplicationElement(intermediate, section, element);
88 break;
89 case "WixManagedBootstrapperApplicationHost":
90 this.ParseWixManagedBootstrapperApplicationHostElement(intermediate, section, element);
91 break;
92 case "WixDotNetCoreBootstrapperApplicationHost":
93 this.ParseWixDotNetCoreBootstrapperApplicationHostElement(intermediate, section, element);
94 break;
95 default:
96 this.ParseHelper.UnexpectedElement(parentElement, element);
97 break;
98 }
99 break;
100 default:
101 this.ParseHelper.UnexpectedElement(parentElement, element);
102 break;
103 }
104 }
105
106 /// <summary>
107 /// Processes an attribute for the Compiler.
108 /// </summary>
109 /// <param name="sourceLineNumbers">Source line number for the parent element.</param>
110 /// <param name="parentElement">Parent element of element to process.</param>
111 /// <param name="attribute">Attribute to process.</param>
112 /// <param name="context">Extra information about the context in which this element is being parsed.</param>
113 public override void ParseAttribute(Intermediate intermediate, IntermediateSection section, XElement parentElement, XAttribute attribute, IDictionary<string, string> context)
114 {
115 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(parentElement);
116 WixMbaPrereqInformationSymbol prereqInfo;
117
118 switch (parentElement.Name.LocalName)
119 {
120 case "ExePackage":
121 case "MsiPackage":
122 case "MspPackage":
123 case "MsuPackage":
124 string packageId;
125 if (!context.TryGetValue("PackageId", out packageId) || String.IsNullOrEmpty(packageId))
126 {
127 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, parentElement.Name.LocalName, "Id", attribute.Name.LocalName));
128 }
129 else
130 {
131 switch (attribute.Name.LocalName)
132 {
133 case "DisplayInternalUICondition":
134 switch (parentElement.Name.LocalName)
135 {
136 case "MsiPackage":
137 case "MspPackage":
138 var displayInternalUICondition = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attribute);
139 section.AddSymbol(new WixBalPackageInfoSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, packageId))
140 {
141 PackageId = packageId,
142 DisplayInternalUICondition = displayInternalUICondition,
143 });
144 break;
145 default:
146 this.ParseHelper.UnexpectedAttribute(parentElement, attribute);
147 break;
148 }
149 break;
150 case "PrereqLicenseFile":
151
152 if (!this.prereqInfoSymbolsByPackageId.TryGetValue(packageId, out prereqInfo))
153 {
154 // at the time the extension attribute is parsed, the compiler might not yet have
155 // parsed the PrereqPackage attribute, so we need to get it directly from the parent element.
156 var prereqPackage = parentElement.Attribute(this.Namespace + "PrereqPackage");
157
158 if (null != prereqPackage && YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, prereqPackage))
159 {
160 prereqInfo = section.AddSymbol(new WixMbaPrereqInformationSymbol(sourceLineNumbers)
161 {
162 PackageId = packageId,
163 });
164
165 this.prereqInfoSymbolsByPackageId.Add(packageId, prereqInfo);
166 }
167 else
168 {
169 this.Messaging.Write(BalErrors.AttributeRequiresPrereqPackage(sourceLineNumbers, parentElement.Name.LocalName, "PrereqLicenseFile"));
170 break;
171 }
172 }
173
174 if (null != prereqInfo.LicenseUrl)
175 {
176 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, parentElement.Name.LocalName, "PrereqLicenseFile", "PrereqLicenseUrl"));
177 }
178 else
179 {
180 prereqInfo.LicenseFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attribute);
181 }
182 break;
183 case "PrereqLicenseUrl":
184
185 if (!this.prereqInfoSymbolsByPackageId.TryGetValue(packageId, out prereqInfo))
186 {
187 // at the time the extension attribute is parsed, the compiler might not yet have
188 // parsed the PrereqPackage attribute, so we need to get it directly from the parent element.
189 var prereqPackage = parentElement.Attribute(this.Namespace + "PrereqPackage");
190
191 if (null != prereqPackage && YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, prereqPackage))
192 {
193 prereqInfo = section.AddSymbol(new WixMbaPrereqInformationSymbol(sourceLineNumbers)
194 {
195 PackageId = packageId,
196 });
197
198 this.prereqInfoSymbolsByPackageId.Add(packageId, prereqInfo);
199 }
200 else
201 {
202 this.Messaging.Write(BalErrors.AttributeRequiresPrereqPackage(sourceLineNumbers, parentElement.Name.LocalName, "PrereqLicenseUrl"));
203 break;
204 }
205 }
206
207 if (null != prereqInfo.LicenseFile)
208 {
209 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, parentElement.Name.LocalName, "PrereqLicenseUrl", "PrereqLicenseFile"));
210 }
211 else
212 {
213 prereqInfo.LicenseUrl = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attribute);
214 }
215 break;
216 case "PrereqPackage":
217 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attribute))
218 {
219 if (!this.prereqInfoSymbolsByPackageId.TryGetValue(packageId, out prereqInfo))
220 {
221 prereqInfo = section.AddSymbol(new WixMbaPrereqInformationSymbol(sourceLineNumbers)
222 {
223 PackageId = packageId,
224 });
225
226 this.prereqInfoSymbolsByPackageId.Add(packageId, prereqInfo);
227 }
228 }
229 break;
230 default:
231 this.ParseHelper.UnexpectedAttribute(parentElement, attribute);
232 break;
233 }
234 }
235 break;
236 case "Payload":
237 string payloadId;
238 if (!context.TryGetValue("Id", out payloadId) || String.IsNullOrEmpty(payloadId))
239 {
240 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, parentElement.Name.LocalName, "Id", attribute.Name.LocalName));
241 }
242 else
243 {
244 switch (attribute.Name.LocalName)
245 {
246 case "BAFactoryAssembly":
247 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attribute))
248 {
249 // There can only be one.
250 var id = new Identifier(AccessModifier.Global, "TheBAFactoryAssembly");
251 section.AddSymbol(new WixBalBAFactoryAssemblySymbol(sourceLineNumbers, id)
252 {
253 PayloadId = payloadId,
254 });
255 }
256 break;
257 case "BAFunctions":
258 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attribute))
259 {
260 section.AddSymbol(new WixBalBAFunctionsSymbol(sourceLineNumbers)
261 {
262 PayloadId = payloadId,
263 });
264 }
265 break;
266 default:
267 this.ParseHelper.UnexpectedAttribute(parentElement, attribute);
268 break;
269 }
270 }
271 break;
272 case "Variable":
273 // at the time the extension attribute is parsed, the compiler might not yet have
274 // parsed the Name attribute, so we need to get it directly from the parent element.
275 var variableName = parentElement.Attribute("Name");
276 if (null == variableName)
277 {
278 this.Messaging.Write(ErrorMessages.ExpectedParentWithAttribute(sourceLineNumbers, "Variable", "Overridable", "Name"));
279 }
280 else
281 {
282 switch (attribute.Name.LocalName)
283 {
284 case "Overridable":
285 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attribute))
286 {
287 section.AddSymbol(new WixStdbaOverridableVariableSymbol(sourceLineNumbers)
288 {
289 Name = variableName.Value,
290 });
291 }
292 break;
293 default:
294 this.ParseHelper.UnexpectedAttribute(parentElement, attribute);
295 break;
296 }
297 }
298 break;
299 }
300 }
301
302 /// <summary>
303 /// Parses a Condition element for Bundles.
304 /// </summary>
305 /// <param name="node">The element to parse.</param>
306 private void ParseConditionElement(Intermediate intermediate, IntermediateSection section, XElement node)
307 {
308 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node);
309 string condition = null;
310 string message = null;
311
312 foreach (var attrib in node.Attributes())
313 {
314 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
315 {
316 switch (attrib.Name.LocalName)
317 {
318 case "Message":
319 message = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
320 break;
321 case "Condition":
322 condition = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
323 break;
324 default:
325 this.ParseHelper.UnexpectedAttribute(node, attrib);
326 break;
327 }
328 }
329 else
330 {
331 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib);
332 }
333 }
334
335 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, node);
336
337 // Error check the values.
338 if (String.IsNullOrEmpty(condition))
339 {
340 this.Messaging.Write(ErrorMessages.ConditionExpected(sourceLineNumbers, node.Name.LocalName));
341 }
342
343 if (null == message)
344 {
345 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Message"));
346 }
347
348 if (!this.Messaging.EncounteredError)
349 {
350 section.AddSymbol(new WixBalConditionSymbol(sourceLineNumbers)
351 {
352 Condition = condition,
353 Message = message,
354 });
355 }
356 }
357
358 /// <summary>
359 /// Parses a Condition element for Bundles.
360 /// </summary>
361 /// <param name="node">The element to parse.</param>
362 private void ParseMbaPrereqInfoElement(Intermediate intermediate, IntermediateSection section, XElement node)
363 {
364 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node);
365 string packageId = null;
366 string licenseFile = null;
367 string licenseUrl = null;
368
369 foreach (var attrib in node.Attributes())
370 {
371 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
372 {
373 switch (attrib.Name.LocalName)
374 {
375 case "LicenseFile":
376 licenseFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
377 break;
378 case "LicenseUrl":
379 licenseUrl = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
380 break;
381 case "PackageId":
382 packageId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
383 break;
384 default:
385 this.ParseHelper.UnexpectedAttribute(node, attrib);
386 break;
387 }
388 }
389 else
390 {
391 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib);
392 }
393 }
394
395 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, node);
396
397 if (null == packageId)
398 {
399 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "PackageId"));
400 }
401
402 if (null == licenseFile && null == licenseUrl ||
403 null != licenseFile && null != licenseUrl)
404 {
405 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "LicenseFile", "LicenseUrl", true));
406 }
407
408 if (!this.Messaging.EncounteredError)
409 {
410 section.AddSymbol(new WixMbaPrereqInformationSymbol(sourceLineNumbers)
411 {
412 PackageId = packageId,
413 LicenseFile = licenseFile,
414 LicenseUrl = licenseUrl,
415 });
416 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.WixBundlePackage, packageId);
417 }
418 }
419
420 /// <summary>
421 /// Parses a WixStandardBootstrapperApplication element for Bundles.
422 /// </summary>
423 /// <param name="node">The element to parse.</param>
424 private void ParseWixStandardBootstrapperApplicationElement(Intermediate intermediate, IntermediateSection section, XElement node)
425 {
426 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node);
427 string launchTarget = null;
428 string launchTargetElevatedId = null;
429 string launchArguments = null;
430 var launchHidden = YesNoType.NotSet;
431 string launchWorkingDir = null;
432 string licenseFile = null;
433 string licenseUrl = null;
434 string logoFile = null;
435 string logoSideFile = null;
436 WixStandardBootstrapperApplicationTheme? theme = null;
437 string themeFile = null;
438 string localizationFile = null;
439 var suppressOptionsUI = YesNoType.NotSet;
440 var suppressDowngradeFailure = YesNoType.NotSet;
441 var suppressRepair = YesNoType.NotSet;
442 var showVersion = YesNoType.NotSet;
443 var supportCacheOnly = YesNoType.NotSet;
444
445 foreach (var attrib in node.Attributes())
446 {
447 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
448 {
449 switch (attrib.Name.LocalName)
450 {
451 case "LaunchTarget":
452 launchTarget = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
453 break;
454 case "LaunchTargetElevatedId":
455 launchTargetElevatedId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
456 break;
457 case "LaunchArguments":
458 launchArguments = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
459 break;
460 case "LaunchHidden":
461 launchHidden = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
462 break;
463 case "LaunchWorkingFolder":
464 launchWorkingDir = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
465 break;
466 case "LicenseFile":
467 licenseFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
468 break;
469 case "LicenseUrl":
470 licenseUrl = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty);
471 break;
472 case "LogoFile":
473 logoFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
474 break;
475 case "LogoSideFile":
476 logoSideFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
477 break;
478 case "ThemeFile":
479 themeFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
480 break;
481 case "LocalizationFile":
482 localizationFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
483 break;
484 case "SuppressOptionsUI":
485 suppressOptionsUI = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
486 break;
487 case "SuppressDowngradeFailure":
488 suppressDowngradeFailure = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
489 break;
490 case "SuppressRepair":
491 suppressRepair = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
492 break;
493 case "ShowVersion":
494 showVersion = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
495 break;
496 case "SupportCacheOnly":
497 supportCacheOnly = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
498 break;
499 case "Theme":
500 var themeValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
501 switch (themeValue)
502 {
503 case "hyperlinkLargeLicense":
504 theme = WixStandardBootstrapperApplicationTheme.HyperlinkLargeLicense;
505 break;
506 case "hyperlinkLicense":
507 theme = WixStandardBootstrapperApplicationTheme.HyperlinkLicense;
508 break;
509 case "hyperlinkSidebarLicense":
510 theme = WixStandardBootstrapperApplicationTheme.HyperlinkSidebarLicense;
511 break;
512 case "none":
513 theme = WixStandardBootstrapperApplicationTheme.None;
514 break;
515 case "rtfLargeLicense":
516 theme = WixStandardBootstrapperApplicationTheme.RtfLargeLicense;
517 break;
518 case "rtfLicense":
519 theme = WixStandardBootstrapperApplicationTheme.RtfLicense;
520 break;
521 default:
522 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Theme", themeValue, "hyperlinkLargeLicense", "hyperlinkLicense", "hyperlinkSidebarLicense", "none", "rtfLargeLicense", "rtfLicense"));
523 theme = WixStandardBootstrapperApplicationTheme.Unknown; // set a value to prevent expected attribute error below.
524 break;
525 }
526 break;
527 default:
528 this.ParseHelper.UnexpectedAttribute(node, attrib);
529 break;
530 }
531 }
532 else
533 {
534 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib);
535 }
536 }
537
538 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, node);
539
540 if (!theme.HasValue)
541 {
542 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Theme"));
543 }
544
545 if (theme != WixStandardBootstrapperApplicationTheme.None && String.IsNullOrEmpty(licenseFile) && null == licenseUrl)
546 {
547 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "LicenseFile", "LicenseUrl", true));
548 }
549
550 if (!this.Messaging.EncounteredError)
551 {
552 if (!String.IsNullOrEmpty(launchTarget))
553 {
554 section.AddSymbol(new WixBundleVariableSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "LaunchTarget"))
555 {
556 Value = launchTarget,
557 Type = WixBundleVariableType.Formatted,
558 });
559 }
560
561 if (!String.IsNullOrEmpty(launchTargetElevatedId))
562 {
563 section.AddSymbol(new WixBundleVariableSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "LaunchTargetElevatedId"))
564 {
565 Value = launchTargetElevatedId,
566 Type = WixBundleVariableType.Formatted,
567 });
568 }
569
570 if (!String.IsNullOrEmpty(launchArguments))
571 {
572 section.AddSymbol(new WixBundleVariableSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "LaunchArguments"))
573 {
574 Value = launchArguments,
575 Type = WixBundleVariableType.Formatted,
576 });
577 }
578
579 if (YesNoType.Yes == launchHidden)
580 {
581 section.AddSymbol(new WixBundleVariableSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "LaunchHidden"))
582 {
583 Value = "yes",
584 Type = WixBundleVariableType.Formatted,
585 });
586 }
587
588
589 if (!String.IsNullOrEmpty(launchWorkingDir))
590 {
591 section.AddSymbol(new WixBundleVariableSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "LaunchWorkingFolder"))
592 {
593 Value = launchWorkingDir,
594 Type = WixBundleVariableType.Formatted,
595 });
596 }
597
598 if (!String.IsNullOrEmpty(licenseFile))
599 {
600 section.AddSymbol(new WixVariableSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "WixStdbaLicenseRtf"))
601 {
602 Value = licenseFile,
603 });
604 }
605
606 if (null != licenseUrl)
607 {
608 section.AddSymbol(new WixVariableSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "WixStdbaLicenseUrl"))
609 {
610 Value = licenseUrl,
611 });
612 }
613
614 if (!String.IsNullOrEmpty(logoFile))
615 {
616 section.AddSymbol(new WixVariableSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "WixStdbaLogo"))
617 {
618 Value = logoFile,
619 });
620 }
621
622 if (!String.IsNullOrEmpty(logoSideFile))
623 {
624 section.AddSymbol(new WixVariableSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "WixStdbaLogoSide"))
625 {
626 Value = logoSideFile,
627 });
628 }
629
630 if (!String.IsNullOrEmpty(themeFile))
631 {
632 section.AddSymbol(new WixVariableSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "WixStdbaThemeXml"))
633 {
634 Value = themeFile,
635 });
636 }
637
638 if (!String.IsNullOrEmpty(localizationFile))
639 {
640 section.AddSymbol(new WixVariableSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "WixStdbaThemeWxl"))
641 {
642 Value = localizationFile,
643 });
644 }
645
646 if (YesNoType.Yes == suppressOptionsUI || YesNoType.Yes == suppressDowngradeFailure || YesNoType.Yes == suppressRepair || YesNoType.Yes == showVersion || YesNoType.Yes == supportCacheOnly)
647 {
648 var symbol = section.AddSymbol(new WixStdbaOptionsSymbol(sourceLineNumbers));
649 if (YesNoType.Yes == suppressOptionsUI)
650 {
651 symbol.SuppressOptionsUI = 1;
652 }
653
654 if (YesNoType.Yes == suppressDowngradeFailure)
655 {
656 symbol.SuppressDowngradeFailure = 1;
657 }
658
659 if (YesNoType.Yes == suppressRepair)
660 {
661 symbol.SuppressRepair = 1;
662 }
663
664 if (YesNoType.Yes == showVersion)
665 {
666 symbol.ShowVersion = 1;
667 }
668
669 if (YesNoType.Yes == supportCacheOnly)
670 {
671 symbol.SupportCacheOnly = 1;
672 }
673 }
674
675 var baId = "WixStandardBootstrapperApplication";
676 switch (theme)
677 {
678 case WixStandardBootstrapperApplicationTheme.HyperlinkLargeLicense:
679 baId = "WixStandardBootstrapperApplication.HyperlinkLargeLicense";
680 break;
681 case WixStandardBootstrapperApplicationTheme.HyperlinkLicense:
682 baId = "WixStandardBootstrapperApplication.HyperlinkLicense";
683 break;
684 case WixStandardBootstrapperApplicationTheme.HyperlinkSidebarLicense:
685 baId = "WixStandardBootstrapperApplication.HyperlinkSidebarLicense";
686 break;
687 case WixStandardBootstrapperApplicationTheme.RtfLargeLicense:
688 baId = "WixStandardBootstrapperApplication.RtfLargeLicense";
689 break;
690 case WixStandardBootstrapperApplicationTheme.RtfLicense:
691 baId = "WixStandardBootstrapperApplication.RtfLicense";
692 break;
693 }
694
695 this.CreateBARef(section, sourceLineNumbers, node, baId);
696 }
697 }
698
699 /// <summary>
700 /// Parses a WixManagedBootstrapperApplicationHost element for Bundles.
701 /// </summary>
702 /// <param name="node">The element to parse.</param>
703 private void ParseWixManagedBootstrapperApplicationHostElement(Intermediate intermediate, IntermediateSection section, XElement node)
704 {
705 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node);
706 string logoFile = null;
707 string themeFile = null;
708 string localizationFile = null;
709 WixManagedBootstrapperApplicationHostTheme? theme = null;
710
711 foreach (var attrib in node.Attributes())
712 {
713 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
714 {
715 switch (attrib.Name.LocalName)
716 {
717 case "LogoFile":
718 logoFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
719 break;
720 case "ThemeFile":
721 themeFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
722 break;
723 case "LocalizationFile":
724 localizationFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
725 break;
726 case "Theme":
727 var themeValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
728 switch (themeValue)
729 {
730 case "none":
731 theme = WixManagedBootstrapperApplicationHostTheme.None;
732 break;
733 case "standard":
734 theme = WixManagedBootstrapperApplicationHostTheme.Standard;
735 break;
736 default:
737 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Theme", themeValue, "none", "standard"));
738 theme = WixManagedBootstrapperApplicationHostTheme.Unknown;
739 break;
740 }
741 break;
742 default:
743 this.ParseHelper.UnexpectedAttribute(node, attrib);
744 break;
745 }
746 }
747 else
748 {
749 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib);
750 }
751 }
752
753 if (!theme.HasValue)
754 {
755 theme = WixManagedBootstrapperApplicationHostTheme.Standard;
756 }
757
758 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, node);
759
760 if (!this.Messaging.EncounteredError)
761 {
762 if (!String.IsNullOrEmpty(logoFile))
763 {
764 section.AddSymbol(new WixVariableSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "PreqbaLogo"))
765 {
766 Value = logoFile,
767 });
768 }
769
770 if (!String.IsNullOrEmpty(themeFile))
771 {
772 section.AddSymbol(new WixVariableSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "PreqbaThemeXml"))
773 {
774 Value = themeFile,
775 });
776 }
777
778 if (!String.IsNullOrEmpty(localizationFile))
779 {
780 section.AddSymbol(new WixVariableSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "PreqbaThemeWxl"))
781 {
782 Value = localizationFile,
783 });
784 }
785
786 var baId = "WixManagedBootstrapperApplicationHost";
787 switch (theme)
788 {
789 case WixManagedBootstrapperApplicationHostTheme.Standard:
790 baId = "WixManagedBootstrapperApplicationHost.Standard";
791 break;
792 }
793
794 this.CreateBARef(section, sourceLineNumbers, node, baId);
795 }
796 }
797
798 /// <summary>
799 /// Parses a WixDotNetCoreBootstrapperApplication element for Bundles.
800 /// </summary>
801 /// <param name="node">The element to parse.</param>
802 private void ParseWixDotNetCoreBootstrapperApplicationHostElement(Intermediate intermediate, IntermediateSection section, XElement node)
803 {
804 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node);
805 string logoFile = null;
806 string themeFile = null;
807 string localizationFile = null;
808 var selfContainedDeployment = YesNoType.NotSet;
809 WixDotNetCoreBootstrapperApplicationHostTheme? theme = null;
810
811 foreach (var attrib in node.Attributes())
812 {
813 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
814 {
815 switch (attrib.Name.LocalName)
816 {
817 case "LogoFile":
818 logoFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
819 break;
820 case "ThemeFile":
821 themeFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
822 break;
823 case "LocalizationFile":
824 localizationFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
825 break;
826 case "SelfContainedDeployment":
827 selfContainedDeployment = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
828 break;
829 case "Theme":
830 var themeValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
831 switch (themeValue)
832 {
833 case "none":
834 theme = WixDotNetCoreBootstrapperApplicationHostTheme.None;
835 break;
836 case "standard":
837 theme = WixDotNetCoreBootstrapperApplicationHostTheme.Standard;
838 break;
839 default:
840 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Theme", themeValue, "none", "standard"));
841 theme = WixDotNetCoreBootstrapperApplicationHostTheme.Unknown;
842 break;
843 }
844 break;
845 default:
846 this.ParseHelper.UnexpectedAttribute(node, attrib);
847 break;
848 }
849 }
850 else
851 {
852 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib);
853 }
854 }
855
856 if (!theme.HasValue)
857 {
858 theme = WixDotNetCoreBootstrapperApplicationHostTheme.Standard;
859 }
860
861 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, node);
862
863 if (!this.Messaging.EncounteredError)
864 {
865 if (!String.IsNullOrEmpty(logoFile))
866 {
867 section.AddSymbol(new WixVariableSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "DncPreqbaLogo"))
868 {
869 Value = logoFile,
870 });
871 }
872
873 if (!String.IsNullOrEmpty(themeFile))
874 {
875 section.AddSymbol(new WixVariableSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "DncPreqbaThemeXml"))
876 {
877 Value = themeFile,
878 });
879 }
880
881 if (!String.IsNullOrEmpty(localizationFile))
882 {
883 section.AddSymbol(new WixVariableSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "DncPreqbaThemeWxl"))
884 {
885 Value = localizationFile,
886 });
887 }
888
889 if (YesNoType.Yes == selfContainedDeployment)
890 {
891 section.AddSymbol(new WixDncOptionsSymbol(sourceLineNumbers)
892 {
893 SelfContainedDeployment = 1,
894 });
895 }
896
897 var baId = "WixDotNetCoreBootstrapperApplicationHost";
898 switch (theme)
899 {
900 case WixDotNetCoreBootstrapperApplicationHostTheme.Standard:
901 baId = "WixDotNetCoreBootstrapperApplicationHost.Standard";
902 break;
903 }
904
905 this.CreateBARef(section, sourceLineNumbers, node, baId);
906 }
907 }
908
909 private void CreateBARef(IntermediateSection section, SourceLineNumber sourceLineNumbers, XElement node, string name)
910 {
911 var id = this.ParseHelper.CreateIdentifierValueFromPlatform(name, this.Context.Platform, BurnPlatforms.X86 | BurnPlatforms.X64 | BurnPlatforms.ARM64);
912 if (id == null)
913 {
914 this.Messaging.Write(ErrorMessages.UnsupportedPlatformForElement(sourceLineNumbers, this.Context.Platform.ToString(), node.Name.LocalName));
915 }
916
917 if (!this.Messaging.EncounteredError)
918 {
919 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.WixBootstrapperApplication, id);
920 }
921 }
922 }
923}
diff --git a/src/ext/Bal/wixext/BalErrors.cs b/src/ext/Bal/wixext/BalErrors.cs
new file mode 100644
index 00000000..bc0186c1
--- /dev/null
+++ b/src/ext/Bal/wixext/BalErrors.cs
@@ -0,0 +1,61 @@
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
3namespace WixToolset.Bal
4{
5 using System;
6 using System.Resources;
7 using WixToolset.Data;
8
9 public static class BalErrors
10 {
11 public static Message AttributeRequiresPrereqPackage(SourceLineNumber sourceLineNumbers, string elementName, string attributeName)
12 {
13 return Message(sourceLineNumbers, Ids.AttributeRequiresPrereqPackage, "When the {0}/@{1} attribute is specified, the {0}/@PrereqPackage attribute must be set to \"yes\".", elementName, attributeName);
14 }
15
16 public static Message BAFunctionsPayloadRequiredInUXContainer(SourceLineNumber sourceLineNumbers)
17 {
18 return Message(sourceLineNumbers, Ids.BAFunctionsPayloadRequiredInUXContainer, "The BAFunctions DLL Payload element must be located inside the BootstrapperApplication container.");
19 }
20
21 public static Message MissingDNCPrereq()
22 {
23 return Message(null, Ids.MissingDNCPrereq, "There must be at least one PrereqPackage when using the DotNetCoreBootstrapperApplicationHost with SelfContainedDeployment set to \"no\".");
24 }
25
26 public static Message MissingMBAPrereq()
27 {
28 return Message(null, Ids.MissingMBAPrereq, "There must be at least one PrereqPackage when using the ManagedBootstrapperApplicationHost.\nThis is typically done by using the WixNetFxExtension and referencing one of the NetFxAsPrereq package groups.");
29 }
30
31 public static Message MultipleBAFunctions(SourceLineNumber sourceLineNumbers)
32 {
33 return Message(sourceLineNumbers, Ids.MultipleBAFunctions, "WixStandardBootstrapperApplication doesn't support multiple BAFunctions DLLs.");
34 }
35
36 public static Message MultiplePrereqLicenses(SourceLineNumber sourceLineNumbers)
37 {
38 return Message(sourceLineNumbers, Ids.MultiplePrereqLicenses, "There may only be one package in the bundle that has either the PrereqLicenseFile attribute or the PrereqLicenseUrl attribute.");
39 }
40
41 private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args)
42 {
43 return new Message(sourceLineNumber, MessageLevel.Error, (int)id, format, args);
44 }
45
46 private static Message Message(SourceLineNumber sourceLineNumber, Ids id, ResourceManager resourceManager, string resourceName, params object[] args)
47 {
48 return new Message(sourceLineNumber, MessageLevel.Error, (int)id, resourceManager, resourceName, args);
49 }
50
51 public enum Ids
52 {
53 AttributeRequiresPrereqPackage = 6801,
54 MissingMBAPrereq = 6802,
55 MultiplePrereqLicenses = 6803,
56 MultipleBAFunctions = 6804,
57 BAFunctionsPayloadRequiredInUXContainer = 6805,
58 MissingDNCPrereq = 6806,
59 }
60 }
61}
diff --git a/src/ext/Bal/wixext/BalExtensionData.cs b/src/ext/Bal/wixext/BalExtensionData.cs
new file mode 100644
index 00000000..55daf005
--- /dev/null
+++ b/src/ext/Bal/wixext/BalExtensionData.cs
@@ -0,0 +1,30 @@
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
3namespace WixToolset.Bal
4{
5 using WixToolset.Data;
6 using WixToolset.Extensibility;
7
8 /// <summary>
9 /// The WiX Toolset Bal Extension.
10 /// </summary>
11 public sealed class BalExtensionData : BaseExtensionData
12 {
13 /// <summary>
14 /// Gets the default culture.
15 /// </summary>
16 /// <value>The default culture.</value>
17 public override string DefaultCulture => "en-US";
18
19 public override bool TryGetSymbolDefinitionByName(string name, out IntermediateSymbolDefinition symbolDefinition)
20 {
21 symbolDefinition = BalSymbolDefinitions.ByName(name);
22 return symbolDefinition != null;
23 }
24
25 public override Intermediate GetLibrary(ISymbolDefinitionCreator symbolDefinitions)
26 {
27 return Intermediate.Load(typeof(BalExtensionData).Assembly, "WixToolset.Bal.bal.wixlib", symbolDefinitions);
28 }
29 }
30}
diff --git a/src/ext/Bal/wixext/BalExtensionFactory.cs b/src/ext/Bal/wixext/BalExtensionFactory.cs
new file mode 100644
index 00000000..0bfb6c5f
--- /dev/null
+++ b/src/ext/Bal/wixext/BalExtensionFactory.cs
@@ -0,0 +1,18 @@
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
3namespace WixToolset.Bal
4{
5 using System;
6 using System.Collections.Generic;
7 using WixToolset.Extensibility;
8
9 public class BalExtensionFactory : BaseExtensionFactory
10 {
11 protected override IReadOnlyCollection<Type> ExtensionTypes => new[]
12 {
13 typeof(BalCompiler),
14 typeof(BalExtensionData),
15 typeof(BalBurnBackendExtension),
16 };
17 }
18}
diff --git a/src/ext/Bal/wixext/BalWarnings.cs b/src/ext/Bal/wixext/BalWarnings.cs
new file mode 100644
index 00000000..18b25062
--- /dev/null
+++ b/src/ext/Bal/wixext/BalWarnings.cs
@@ -0,0 +1,31 @@
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
3namespace WixToolset.Bal
4{
5 using System;
6 using System.Resources;
7 using WixToolset.Data;
8
9 public static class BalWarnings
10 {
11 public static Message UnmarkedBAFunctionsDLL(SourceLineNumber sourceLineNumbers)
12 {
13 return Message(sourceLineNumbers, Ids.UnmarkedBAFunctionsDLL, "WixStandardBootstrapperApplication doesn't automatically load BAFunctions.dll. Use the bal:BAFunctions attribute to indicate that it should be loaded.");
14 }
15
16 private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args)
17 {
18 return new Message(sourceLineNumber, MessageLevel.Warning, (int)id, format, args);
19 }
20
21 private static Message Message(SourceLineNumber sourceLineNumber, Ids id, ResourceManager resourceManager, string resourceName, params object[] args)
22 {
23 return new Message(sourceLineNumber, MessageLevel.Warning, (int)id, resourceManager, resourceName, args);
24 }
25
26 public enum Ids
27 {
28 UnmarkedBAFunctionsDLL = 6501,
29 }
30 }
31}
diff --git a/src/ext/Bal/wixext/Symbols/BalSymbolDefinitions.cs b/src/ext/Bal/wixext/Symbols/BalSymbolDefinitions.cs
new file mode 100644
index 00000000..90865621
--- /dev/null
+++ b/src/ext/Bal/wixext/Symbols/BalSymbolDefinitions.cs
@@ -0,0 +1,80 @@
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
3namespace WixToolset.Bal
4{
5 using System;
6 using WixToolset.Data;
7 using WixToolset.Data.Burn;
8
9 public enum BalSymbolDefinitionType
10 {
11 WixBalBAFactoryAssembly,
12 WixBalBAFunctions,
13 WixBalCondition,
14 WixBalPackageInfo,
15 WixDncOptions,
16 WixMbaPrereqInformation,
17 WixStdbaOptions,
18 WixStdbaOverridableVariable,
19 }
20
21 public static partial class BalSymbolDefinitions
22 {
23 public static readonly Version Version = new Version("4.0.0");
24
25 public static IntermediateSymbolDefinition ByName(string name)
26 {
27 if (!Enum.TryParse(name, out BalSymbolDefinitionType type))
28 {
29 return null;
30 }
31
32 return ByType(type);
33 }
34
35 public static IntermediateSymbolDefinition ByType(BalSymbolDefinitionType type)
36 {
37 switch (type)
38 {
39 case BalSymbolDefinitionType.WixBalBAFactoryAssembly:
40 return BalSymbolDefinitions.WixBalBAFactoryAssembly;
41
42 case BalSymbolDefinitionType.WixBalBAFunctions:
43 return BalSymbolDefinitions.WixBalBAFunctions;
44
45 case BalSymbolDefinitionType.WixBalCondition:
46 return BalSymbolDefinitions.WixBalCondition;
47
48 case BalSymbolDefinitionType.WixBalPackageInfo:
49 return BalSymbolDefinitions.WixBalPackageInfo;
50
51 case BalSymbolDefinitionType.WixDncOptions:
52 return BalSymbolDefinitions.WixDncOptions;
53
54 case BalSymbolDefinitionType.WixMbaPrereqInformation:
55 return BalSymbolDefinitions.WixMbaPrereqInformation;
56
57 case BalSymbolDefinitionType.WixStdbaOptions:
58 return BalSymbolDefinitions.WixStdbaOptions;
59
60 case BalSymbolDefinitionType.WixStdbaOverridableVariable:
61 return BalSymbolDefinitions.WixStdbaOverridableVariable;
62
63 default:
64 throw new ArgumentOutOfRangeException(nameof(type));
65 }
66 }
67
68 static BalSymbolDefinitions()
69 {
70 WixBalBAFactoryAssembly.AddTag(BurnConstants.BootstrapperApplicationDataSymbolDefinitionTag);
71 WixBalBAFunctions.AddTag(BurnConstants.BootstrapperApplicationDataSymbolDefinitionTag);
72 WixBalCondition.AddTag(BurnConstants.BootstrapperApplicationDataSymbolDefinitionTag);
73 WixBalPackageInfo.AddTag(BurnConstants.BootstrapperApplicationDataSymbolDefinitionTag);
74 WixDncOptions.AddTag(BurnConstants.BootstrapperApplicationDataSymbolDefinitionTag);
75 WixMbaPrereqInformation.AddTag(BurnConstants.BootstrapperApplicationDataSymbolDefinitionTag);
76 WixStdbaOptions.AddTag(BurnConstants.BootstrapperApplicationDataSymbolDefinitionTag);
77 WixStdbaOverridableVariable.AddTag(BurnConstants.BootstrapperApplicationDataSymbolDefinitionTag);
78 }
79 }
80}
diff --git a/src/ext/Bal/wixext/Symbols/WixBalBAFactoryAssemblySymbol.cs b/src/ext/Bal/wixext/Symbols/WixBalBAFactoryAssemblySymbol.cs
new file mode 100644
index 00000000..52042e4c
--- /dev/null
+++ b/src/ext/Bal/wixext/Symbols/WixBalBAFactoryAssemblySymbol.cs
@@ -0,0 +1,55 @@
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
3namespace WixToolset.Bal
4{
5 using WixToolset.Data;
6 using WixToolset.Bal.Symbols;
7
8 public static partial class BalSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition WixBalBAFactoryAssembly = new IntermediateSymbolDefinition(
11 BalSymbolDefinitionType.WixBalBAFactoryAssembly.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(WixBalBAFactorySymbolFields.PayloadId), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(WixBalBAFactorySymbolFields.FilePath), IntermediateFieldType.String),
16 },
17 typeof(WixBalBAFactoryAssemblySymbol));
18 }
19}
20
21namespace WixToolset.Bal.Symbols
22{
23 using WixToolset.Data;
24
25 public enum WixBalBAFactorySymbolFields
26 {
27 PayloadId,
28 FilePath,
29 }
30
31 public class WixBalBAFactoryAssemblySymbol : IntermediateSymbol
32 {
33 public WixBalBAFactoryAssemblySymbol() : base(BalSymbolDefinitions.WixBalBAFactoryAssembly, null, null)
34 {
35 }
36
37 public WixBalBAFactoryAssemblySymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(BalSymbolDefinitions.WixBalBAFactoryAssembly, sourceLineNumber, id)
38 {
39 }
40
41 public IntermediateField this[WixBalBAFactorySymbolFields index] => this.Fields[(int)index];
42
43 public string PayloadId
44 {
45 get => this.Fields[(int)WixBalBAFactorySymbolFields.PayloadId].AsString();
46 set => this.Set((int)WixBalBAFactorySymbolFields.PayloadId, value);
47 }
48
49 public string FilePath
50 {
51 get => this.Fields[(int)WixBalBAFactorySymbolFields.FilePath].AsString();
52 set => this.Set((int)WixBalBAFactorySymbolFields.FilePath, value);
53 }
54 }
55} \ No newline at end of file
diff --git a/src/ext/Bal/wixext/Symbols/WixBalBAFunctionsSymbol.cs b/src/ext/Bal/wixext/Symbols/WixBalBAFunctionsSymbol.cs
new file mode 100644
index 00000000..19c7602d
--- /dev/null
+++ b/src/ext/Bal/wixext/Symbols/WixBalBAFunctionsSymbol.cs
@@ -0,0 +1,47 @@
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
3namespace WixToolset.Bal
4{
5 using WixToolset.Data;
6 using WixToolset.Bal.Symbols;
7
8 public static partial class BalSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition WixBalBAFunctions = new IntermediateSymbolDefinition(
11 BalSymbolDefinitionType.WixBalBAFunctions.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(WixBalBAFunctionsSymbolFields.PayloadId), IntermediateFieldType.String),
15 },
16 typeof(WixBalBAFunctionsSymbol));
17 }
18}
19
20namespace WixToolset.Bal.Symbols
21{
22 using WixToolset.Data;
23
24 public enum WixBalBAFunctionsSymbolFields
25 {
26 PayloadId,
27 }
28
29 public class WixBalBAFunctionsSymbol : IntermediateSymbol
30 {
31 public WixBalBAFunctionsSymbol() : base(BalSymbolDefinitions.WixBalBAFunctions, null, null)
32 {
33 }
34
35 public WixBalBAFunctionsSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(BalSymbolDefinitions.WixBalBAFunctions, sourceLineNumber, id)
36 {
37 }
38
39 public IntermediateField this[WixBalBAFunctionsSymbolFields index] => this.Fields[(int)index];
40
41 public string PayloadId
42 {
43 get => this.Fields[(int)WixBalBAFunctionsSymbolFields.PayloadId].AsString();
44 set => this.Set((int)WixBalBAFunctionsSymbolFields.PayloadId, value);
45 }
46 }
47} \ No newline at end of file
diff --git a/src/ext/Bal/wixext/Symbols/WixBalConditionSymbol.cs b/src/ext/Bal/wixext/Symbols/WixBalConditionSymbol.cs
new file mode 100644
index 00000000..c2527fbc
--- /dev/null
+++ b/src/ext/Bal/wixext/Symbols/WixBalConditionSymbol.cs
@@ -0,0 +1,55 @@
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
3namespace WixToolset.Bal
4{
5 using WixToolset.Data;
6 using WixToolset.Bal.Symbols;
7
8 public static partial class BalSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition WixBalCondition = new IntermediateSymbolDefinition(
11 BalSymbolDefinitionType.WixBalCondition.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(WixBalConditionSymbolFields.Condition), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(WixBalConditionSymbolFields.Message), IntermediateFieldType.String),
16 },
17 typeof(WixBalConditionSymbol));
18 }
19}
20
21namespace WixToolset.Bal.Symbols
22{
23 using WixToolset.Data;
24
25 public enum WixBalConditionSymbolFields
26 {
27 Condition,
28 Message,
29 }
30
31 public class WixBalConditionSymbol : IntermediateSymbol
32 {
33 public WixBalConditionSymbol() : base(BalSymbolDefinitions.WixBalCondition, null, null)
34 {
35 }
36
37 public WixBalConditionSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(BalSymbolDefinitions.WixBalCondition, sourceLineNumber, id)
38 {
39 }
40
41 public IntermediateField this[WixBalConditionSymbolFields index] => this.Fields[(int)index];
42
43 public string Condition
44 {
45 get => this.Fields[(int)WixBalConditionSymbolFields.Condition].AsString();
46 set => this.Set((int)WixBalConditionSymbolFields.Condition, value);
47 }
48
49 public string Message
50 {
51 get => this.Fields[(int)WixBalConditionSymbolFields.Message].AsString();
52 set => this.Set((int)WixBalConditionSymbolFields.Message, value);
53 }
54 }
55} \ No newline at end of file
diff --git a/src/ext/Bal/wixext/Symbols/WixBalPackageInfoSymbol.cs b/src/ext/Bal/wixext/Symbols/WixBalPackageInfoSymbol.cs
new file mode 100644
index 00000000..b09cb191
--- /dev/null
+++ b/src/ext/Bal/wixext/Symbols/WixBalPackageInfoSymbol.cs
@@ -0,0 +1,55 @@
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
3namespace WixToolset.Bal
4{
5 using WixToolset.Data;
6 using WixToolset.Bal.Symbols;
7
8 public static partial class BalSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition WixBalPackageInfo = new IntermediateSymbolDefinition(
11 BalSymbolDefinitionType.WixBalPackageInfo.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(WixBalPackageInfoSymbolFields.PackageId), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(WixBalPackageInfoSymbolFields.DisplayInternalUICondition), IntermediateFieldType.String),
16 },
17 typeof(WixBalPackageInfoSymbol));
18 }
19}
20
21namespace WixToolset.Bal.Symbols
22{
23 using WixToolset.Data;
24
25 public enum WixBalPackageInfoSymbolFields
26 {
27 PackageId,
28 DisplayInternalUICondition,
29 }
30
31 public class WixBalPackageInfoSymbol : IntermediateSymbol
32 {
33 public WixBalPackageInfoSymbol() : base(BalSymbolDefinitions.WixBalPackageInfo, null, null)
34 {
35 }
36
37 public WixBalPackageInfoSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(BalSymbolDefinitions.WixBalPackageInfo, sourceLineNumber, id)
38 {
39 }
40
41 public IntermediateField this[WixBalPackageInfoSymbolFields index] => this.Fields[(int)index];
42
43 public string PackageId
44 {
45 get => this.Fields[(int)WixBalPackageInfoSymbolFields.PackageId].AsString();
46 set => this.Set((int)WixBalPackageInfoSymbolFields.PackageId, value);
47 }
48
49 public string DisplayInternalUICondition
50 {
51 get => this.Fields[(int)WixBalPackageInfoSymbolFields.DisplayInternalUICondition].AsString();
52 set => this.Set((int)WixBalPackageInfoSymbolFields.DisplayInternalUICondition, value);
53 }
54 }
55}
diff --git a/src/ext/Bal/wixext/Symbols/WixDncOptionsSymbol.cs b/src/ext/Bal/wixext/Symbols/WixDncOptionsSymbol.cs
new file mode 100644
index 00000000..b9a41c21
--- /dev/null
+++ b/src/ext/Bal/wixext/Symbols/WixDncOptionsSymbol.cs
@@ -0,0 +1,47 @@
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
3namespace WixToolset.Bal
4{
5 using WixToolset.Data;
6 using WixToolset.Bal.Symbols;
7
8 public static partial class BalSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition WixDncOptions = new IntermediateSymbolDefinition(
11 BalSymbolDefinitionType.WixDncOptions.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(WixDncOptionsSymbolFields.SelfContainedDeployment), IntermediateFieldType.Number),
15 },
16 typeof(WixDncOptionsSymbol));
17 }
18}
19
20namespace WixToolset.Bal.Symbols
21{
22 using WixToolset.Data;
23
24 public enum WixDncOptionsSymbolFields
25 {
26 SelfContainedDeployment,
27 }
28
29 public class WixDncOptionsSymbol : IntermediateSymbol
30 {
31 public WixDncOptionsSymbol() : base(BalSymbolDefinitions.WixDncOptions, null, null)
32 {
33 }
34
35 public WixDncOptionsSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(BalSymbolDefinitions.WixDncOptions, sourceLineNumber, id)
36 {
37 }
38
39 public IntermediateField this[WixDncOptionsSymbolFields index] => this.Fields[(int)index];
40
41 public int SelfContainedDeployment
42 {
43 get => this.Fields[(int)WixDncOptionsSymbolFields.SelfContainedDeployment].AsNumber();
44 set => this.Set((int)WixDncOptionsSymbolFields.SelfContainedDeployment, value);
45 }
46 }
47} \ No newline at end of file
diff --git a/src/ext/Bal/wixext/Symbols/WixMbaPrereqInformationSymbol.cs b/src/ext/Bal/wixext/Symbols/WixMbaPrereqInformationSymbol.cs
new file mode 100644
index 00000000..e4d78da0
--- /dev/null
+++ b/src/ext/Bal/wixext/Symbols/WixMbaPrereqInformationSymbol.cs
@@ -0,0 +1,63 @@
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
3namespace WixToolset.Bal
4{
5 using WixToolset.Data;
6 using WixToolset.Bal.Symbols;
7
8 public static partial class BalSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition WixMbaPrereqInformation = new IntermediateSymbolDefinition(
11 BalSymbolDefinitionType.WixMbaPrereqInformation.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(WixMbaPrereqInformationSymbolFields.PackageId), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(WixMbaPrereqInformationSymbolFields.LicenseFile), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(WixMbaPrereqInformationSymbolFields.LicenseUrl), IntermediateFieldType.String),
17 },
18 typeof(WixMbaPrereqInformationSymbol));
19 }
20}
21
22namespace WixToolset.Bal.Symbols
23{
24 using WixToolset.Data;
25
26 public enum WixMbaPrereqInformationSymbolFields
27 {
28 PackageId,
29 LicenseFile,
30 LicenseUrl,
31 }
32
33 public class WixMbaPrereqInformationSymbol : IntermediateSymbol
34 {
35 public WixMbaPrereqInformationSymbol() : base(BalSymbolDefinitions.WixMbaPrereqInformation, null, null)
36 {
37 }
38
39 public WixMbaPrereqInformationSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(BalSymbolDefinitions.WixMbaPrereqInformation, sourceLineNumber, id)
40 {
41 }
42
43 public IntermediateField this[WixMbaPrereqInformationSymbolFields index] => this.Fields[(int)index];
44
45 public string PackageId
46 {
47 get => this.Fields[(int)WixMbaPrereqInformationSymbolFields.PackageId].AsString();
48 set => this.Set((int)WixMbaPrereqInformationSymbolFields.PackageId, value);
49 }
50
51 public string LicenseFile
52 {
53 get => this.Fields[(int)WixMbaPrereqInformationSymbolFields.LicenseFile].AsString();
54 set => this.Set((int)WixMbaPrereqInformationSymbolFields.LicenseFile, value);
55 }
56
57 public string LicenseUrl
58 {
59 get => this.Fields[(int)WixMbaPrereqInformationSymbolFields.LicenseUrl].AsString();
60 set => this.Set((int)WixMbaPrereqInformationSymbolFields.LicenseUrl, value);
61 }
62 }
63} \ No newline at end of file
diff --git a/src/ext/Bal/wixext/Symbols/WixStdbaOptionsSymbol.cs b/src/ext/Bal/wixext/Symbols/WixStdbaOptionsSymbol.cs
new file mode 100644
index 00000000..cb2694da
--- /dev/null
+++ b/src/ext/Bal/wixext/Symbols/WixStdbaOptionsSymbol.cs
@@ -0,0 +1,79 @@
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
3namespace WixToolset.Bal
4{
5 using WixToolset.Data;
6 using WixToolset.Bal.Symbols;
7
8 public static partial class BalSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition WixStdbaOptions = new IntermediateSymbolDefinition(
11 BalSymbolDefinitionType.WixStdbaOptions.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(WixStdbaOptionsSymbolFields.SuppressOptionsUI), IntermediateFieldType.Number),
15 new IntermediateFieldDefinition(nameof(WixStdbaOptionsSymbolFields.SuppressDowngradeFailure), IntermediateFieldType.Number),
16 new IntermediateFieldDefinition(nameof(WixStdbaOptionsSymbolFields.SuppressRepair), IntermediateFieldType.Number),
17 new IntermediateFieldDefinition(nameof(WixStdbaOptionsSymbolFields.ShowVersion), IntermediateFieldType.Number),
18 new IntermediateFieldDefinition(nameof(WixStdbaOptionsSymbolFields.SupportCacheOnly), IntermediateFieldType.Number),
19 },
20 typeof(WixStdbaOptionsSymbol));
21 }
22}
23
24namespace WixToolset.Bal.Symbols
25{
26 using WixToolset.Data;
27
28 public enum WixStdbaOptionsSymbolFields
29 {
30 SuppressOptionsUI,
31 SuppressDowngradeFailure,
32 SuppressRepair,
33 ShowVersion,
34 SupportCacheOnly,
35 }
36
37 public class WixStdbaOptionsSymbol : IntermediateSymbol
38 {
39 public WixStdbaOptionsSymbol() : base(BalSymbolDefinitions.WixStdbaOptions, null, null)
40 {
41 }
42
43 public WixStdbaOptionsSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(BalSymbolDefinitions.WixStdbaOptions, sourceLineNumber, id)
44 {
45 }
46
47 public IntermediateField this[WixStdbaOptionsSymbolFields index] => this.Fields[(int)index];
48
49 public int SuppressOptionsUI
50 {
51 get => this.Fields[(int)WixStdbaOptionsSymbolFields.SuppressOptionsUI].AsNumber();
52 set => this.Set((int)WixStdbaOptionsSymbolFields.SuppressOptionsUI, value);
53 }
54
55 public int SuppressDowngradeFailure
56 {
57 get => this.Fields[(int)WixStdbaOptionsSymbolFields.SuppressDowngradeFailure].AsNumber();
58 set => this.Set((int)WixStdbaOptionsSymbolFields.SuppressDowngradeFailure, value);
59 }
60
61 public int SuppressRepair
62 {
63 get => this.Fields[(int)WixStdbaOptionsSymbolFields.SuppressRepair].AsNumber();
64 set => this.Set((int)WixStdbaOptionsSymbolFields.SuppressRepair, value);
65 }
66
67 public int ShowVersion
68 {
69 get => this.Fields[(int)WixStdbaOptionsSymbolFields.ShowVersion].AsNumber();
70 set => this.Set((int)WixStdbaOptionsSymbolFields.ShowVersion, value);
71 }
72
73 public int SupportCacheOnly
74 {
75 get => this.Fields[(int)WixStdbaOptionsSymbolFields.SupportCacheOnly].AsNumber();
76 set => this.Set((int)WixStdbaOptionsSymbolFields.SupportCacheOnly, value);
77 }
78 }
79} \ No newline at end of file
diff --git a/src/ext/Bal/wixext/Symbols/WixStdbaOverridableVariableSymbol.cs b/src/ext/Bal/wixext/Symbols/WixStdbaOverridableVariableSymbol.cs
new file mode 100644
index 00000000..1d84d1aa
--- /dev/null
+++ b/src/ext/Bal/wixext/Symbols/WixStdbaOverridableVariableSymbol.cs
@@ -0,0 +1,47 @@
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
3namespace WixToolset.Bal
4{
5 using WixToolset.Data;
6 using WixToolset.Bal.Symbols;
7
8 public static partial class BalSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition WixStdbaOverridableVariable = new IntermediateSymbolDefinition(
11 BalSymbolDefinitionType.WixStdbaOverridableVariable.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(WixStdbaOverridableVariableSymbolFields.Name), IntermediateFieldType.String),
15 },
16 typeof(WixStdbaOverridableVariableSymbol));
17 }
18}
19
20namespace WixToolset.Bal.Symbols
21{
22 using WixToolset.Data;
23
24 public enum WixStdbaOverridableVariableSymbolFields
25 {
26 Name,
27 }
28
29 public class WixStdbaOverridableVariableSymbol : IntermediateSymbol
30 {
31 public WixStdbaOverridableVariableSymbol() : base(BalSymbolDefinitions.WixStdbaOverridableVariable, null, null)
32 {
33 }
34
35 public WixStdbaOverridableVariableSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(BalSymbolDefinitions.WixStdbaOverridableVariable, sourceLineNumber, id)
36 {
37 }
38
39 public IntermediateField this[WixStdbaOverridableVariableSymbolFields index] => this.Fields[(int)index];
40
41 public string Name
42 {
43 get => this.Fields[(int)WixStdbaOverridableVariableSymbolFields.Name].AsString();
44 set => this.Set((int)WixStdbaOverridableVariableSymbolFields.Name, value);
45 }
46 }
47} \ No newline at end of file
diff --git a/src/ext/Bal/wixext/WixToolset.Bal.wixext.csproj b/src/ext/Bal/wixext/WixToolset.Bal.wixext.csproj
new file mode 100644
index 00000000..00451403
--- /dev/null
+++ b/src/ext/Bal/wixext/WixToolset.Bal.wixext.csproj
@@ -0,0 +1,39 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4<Project Sdk="Microsoft.NET.Sdk">
5 <PropertyGroup>
6 <TargetFramework>netstandard2.0</TargetFramework>
7 <RootNamespace>WixToolset.Bal</RootNamespace>
8 <Description>WiX Toolset Bal Extension</Description>
9 <Title>WiX Toolset Bal Extension</Title>
10 <DebugType>embedded</DebugType>
11 <NuspecFile>$(MSBuildThisFileName).nuspec</NuspecFile>
12 <IncludeSymbols>true</IncludeSymbols>
13 <NuspecProperties>Id=$(MSBuildThisFileName);Authors=$(Authors);Copyright=$(Copyright);Description=$(Description);Title=$(Title)</NuspecProperties>
14 </PropertyGroup>
15 <ItemGroup>
16 <Content Include="$(MSBuildThisFileName).targets" />
17 <EmbeddedResource Include="$(OutputPath)..\bal.wixlib" />
18 </ItemGroup>
19 <ItemGroup>
20 <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="all" />
21 <PackageReference Include="WixToolset.Data" Version="4.0.*" PrivateAssets="all" />
22 <PackageReference Include="WixToolset.Extensibility" Version="4.0.*" PrivateAssets="all" />
23 </ItemGroup>
24
25 <ItemGroup>
26 <ProjectReference Include="..\wixlib\bal.wixproj" ReferenceOutputAssembly="false" Condition=" '$(NCrunch)'=='' " />
27 </ItemGroup>
28
29 <ItemGroup>
30 <PackageReference Include="Nerdbank.GitVersioning" Version="3.3.37" PrivateAssets="all" />
31 </ItemGroup>
32
33 <Target Name="SetNuspecProperties" DependsOnTargets="InitializeSourceControlInformation" AfterTargets="GetBuildVersion">
34 <PropertyGroup>
35 <NuspecBasePath>$(OutputPath)..\</NuspecBasePath>
36 <NuspecProperties>$(NuspecProperties);Version=$(BuildVersionSimple);RepositoryCommit=$(SourceRevisionId);RepositoryType=$(RepositoryType);RepositoryUrl=$(PrivateRepositoryUrl);ProjectFolder=$(MSBuildThisFileDirectory)</NuspecProperties>
37 </PropertyGroup>
38 </Target>
39</Project>
diff --git a/src/ext/Bal/wixext/WixToolset.Bal.wixext.nuspec b/src/ext/Bal/wixext/WixToolset.Bal.wixext.nuspec
new file mode 100644
index 00000000..d9e704ae
--- /dev/null
+++ b/src/ext/Bal/wixext/WixToolset.Bal.wixext.nuspec
@@ -0,0 +1,26 @@
1<?xml version="1.0"?>
2<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
3 <metadata minClientVersion="4.0">
4 <id>$id$</id>
5 <version>$version$</version>
6 <authors>$authors$</authors>
7 <owners>$authors$</owners>
8 <license type="expression">MS-RL</license>
9 <projectUrl>https://github.com/wixtoolset/Bal.wixext</projectUrl>
10 <requireLicenseAcceptance>false</requireLicenseAcceptance>
11 <title>$title$</title>
12 <description>$description$</description>
13 <copyright>$copyright$</copyright>
14 <repository type="$repositorytype$" url="$repositoryurl$" commit="$repositorycommit$" />
15 </metadata>
16
17 <files>
18 <file src="$projectFolder$$id$.targets" target="build" />
19
20 <file src="netstandard2.0\$id$.dll" target="tools" />
21
22 <file src="x86\*.pdb" target="pdbs\x86" />
23 <file src="x64\*.pdb" target="pdbs\x64" />
24 <file src="ARM64\*.pdb" target="pdbs\ARM64" />
25 </files>
26</package>
diff --git a/src/ext/Bal/wixext/WixToolset.Bal.wixext.targets b/src/ext/Bal/wixext/WixToolset.Bal.wixext.targets
new file mode 100644
index 00000000..70c5a19c
--- /dev/null
+++ b/src/ext/Bal/wixext/WixToolset.Bal.wixext.targets
@@ -0,0 +1,11 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
5 <PropertyGroup>
6 <WixToolsetBalWixextPath Condition=" '$(WixToolsetBalWixextPath)' == '' ">$(MSBuildThisFileDirectory)..\tools\WixToolset.Bal.wixext.dll</WixToolsetBalWixextPath>
7 </PropertyGroup>
8 <ItemGroup>
9 <WixExtension Include="$(WixToolsetBalWixextPath)" />
10 </ItemGroup>
11</Project>
diff --git a/src/ext/Bal/wixlib/BalExtension_arm64.wxs b/src/ext/Bal/wixlib/BalExtension_arm64.wxs
new file mode 100644
index 00000000..1b9e11d2
--- /dev/null
+++ b/src/ext/Bal/wixlib/BalExtension_arm64.wxs
@@ -0,0 +1,7 @@
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
4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <?define platform=arm64 ?>
6 <?include BalExtension_platform.wxi ?>
7</Wix>
diff --git a/src/ext/Bal/wixlib/BalExtension_platform.wxi b/src/ext/Bal/wixlib/BalExtension_platform.wxi
new file mode 100644
index 00000000..33122fb2
--- /dev/null
+++ b/src/ext/Bal/wixlib/BalExtension_platform.wxi
@@ -0,0 +1,69 @@
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
4<Include xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <?include caDecor.wxi ?>
6 <Fragment>
7 <BootstrapperApplication Id="WixDotNetCoreBootstrapperApplicationHost$(var.Suffix)">
8 <BootstrapperApplicationDll Id="WixDotNetCoreBootstrapperApplicationHost" SourceFile="!(bindpath.$(var.platform))\dnchost.dll" />
9 <Payload SourceFile="!(bindpath.$(var.platform))\wixstdba.dll" Name="dncpreq.dll" />
10 <PayloadGroupRef Id="WixDotNetCoreBootstrapperApplicationHostManagedPayloads" />
11 </BootstrapperApplication>
12 </Fragment>
13 <Fragment>
14 <BootstrapperApplication Id="WixDotNetCoreBootstrapperApplicationHost.Standard$(var.Suffix)">
15 <PayloadGroupRef Id="DncPreqStandardPayloads" />
16 </BootstrapperApplication>
17 <BootstrapperApplicationRef Id="WixDotNetCoreBootstrapperApplicationHost$(var.Suffix)" />
18 </Fragment>
19
20 <Fragment>
21 <BootstrapperApplication Id="WixManagedBootstrapperApplicationHost$(var.Suffix)">
22 <BootstrapperApplicationDll Id="WixManagedBootstrapperApplicationHost" SourceFile="!(bindpath.$(var.platform))\mbahost.dll" />
23 <Payload SourceFile="!(bindpath.$(var.platform))\wixstdba.dll" Name="mbapreq.dll" />
24 <PayloadGroupRef Id="WixManagedBootstrapperApplicationHostManagedPayloads" />
25 </BootstrapperApplication>
26 </Fragment>
27 <Fragment>
28 <BootstrapperApplication Id="WixManagedBootstrapperApplicationHost.Standard$(var.Suffix)">
29 <PayloadGroupRef Id="MbaPreqStandardPayloads" />
30 </BootstrapperApplication>
31 <BootstrapperApplicationRef Id="WixManagedBootstrapperApplicationHost$(var.Suffix)" />
32 </Fragment>
33
34 <Fragment>
35 <BootstrapperApplication Id="WixStandardBootstrapperApplication$(var.Suffix)">
36 <BootstrapperApplicationDll Id="WixStandardBootstrapperApplication" SourceFile="!(bindpath.$(var.platform))\wixstdba.dll" />
37 </BootstrapperApplication>
38 </Fragment>
39 <Fragment>
40 <BootstrapperApplication Id="WixStandardBootstrapperApplication.RtfLicense$(var.Suffix)">
41 <PayloadGroupRef Id="WixStdbaRtfLicensePayloads" />
42 </BootstrapperApplication>
43 <BootstrapperApplicationRef Id="WixStandardBootstrapperApplication$(var.Suffix)" />
44 </Fragment>
45 <Fragment>
46 <BootstrapperApplication Id="WixStandardBootstrapperApplication.RtfLargeLicense$(var.Suffix)">
47 <PayloadGroupRef Id="WixStdbaRtfLargeLicensePayloads" />
48 </BootstrapperApplication>
49 <BootstrapperApplicationRef Id="WixStandardBootstrapperApplication$(var.Suffix)" />
50 </Fragment>
51 <Fragment>
52 <BootstrapperApplication Id="WixStandardBootstrapperApplication.HyperlinkLicense$(var.Suffix)">
53 <PayloadGroupRef Id="WixStdbaHyperlinkLicensePayloads" />
54 </BootstrapperApplication>
55 <BootstrapperApplicationRef Id="WixStandardBootstrapperApplication$(var.Suffix)" />
56 </Fragment>
57 <Fragment>
58 <BootstrapperApplication Id="WixStandardBootstrapperApplication.HyperlinkLargeLicense$(var.Suffix)">
59 <PayloadGroupRef Id="WixStdbaHyperlinkLargeLicensePayloads" />
60 </BootstrapperApplication>
61 <BootstrapperApplicationRef Id="WixStandardBootstrapperApplication$(var.Suffix)" />
62 </Fragment>
63 <Fragment>
64 <BootstrapperApplication Id="WixStandardBootstrapperApplication.HyperlinkSidebarLicense$(var.Suffix)">
65 <PayloadGroupRef Id="WixStdbaHyperlinkSidebarLicensePayloads" />
66 </BootstrapperApplication>
67 <BootstrapperApplicationRef Id="WixStandardBootstrapperApplication$(var.Suffix)" />
68 </Fragment>
69</Include>
diff --git a/src/ext/Bal/wixlib/BalExtension_x64.wxs b/src/ext/Bal/wixlib/BalExtension_x64.wxs
new file mode 100644
index 00000000..69a597ae
--- /dev/null
+++ b/src/ext/Bal/wixlib/BalExtension_x64.wxs
@@ -0,0 +1,7 @@
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
4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <?define platform=x64 ?>
6 <?include BalExtension_platform.wxi ?>
7</Wix>
diff --git a/src/ext/Bal/wixlib/BalExtension_x86.wxs b/src/ext/Bal/wixlib/BalExtension_x86.wxs
new file mode 100644
index 00000000..3cdd4015
--- /dev/null
+++ b/src/ext/Bal/wixlib/BalExtension_x86.wxs
@@ -0,0 +1,7 @@
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
4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <?define platform=x86 ?>
6 <?include BalExtension_platform.wxi ?>
7</Wix>
diff --git a/src/ext/Bal/wixlib/Dnc.wxs b/src/ext/Bal/wixlib/Dnc.wxs
new file mode 100644
index 00000000..d777c473
--- /dev/null
+++ b/src/ext/Bal/wixlib/Dnc.wxs
@@ -0,0 +1,20 @@
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
4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <!--
6 Dnc.wxs - .NET Core BA resources.
7 -->
8 <Fragment>
9 <PayloadGroup Id="WixDotNetCoreBootstrapperApplicationHostManagedPayloads">
10 <Payload SourceFile="WixToolset.Dnc.Host.dll" />
11 </PayloadGroup>
12 </Fragment>
13 <Fragment>
14 <PayloadGroup Id="DncPreqStandardPayloads">
15 <Payload Name="mbapreq.thm" SourceFile="!(wix.DncPreqbaThemeXml=SourceDir\dncpreq.thm)" />
16 <Payload Name="mbapreq.png" SourceFile="!(wix.DncPreqbaLogo=SourceDir\mbapreq.png)" />
17 <Payload Name="mbapreq.wxl" SourceFile="!(wix.DncPreqbaThemeWxl=SourceDir\dncpreq.wxl)" />
18 </PayloadGroup>
19 </Fragment>
20</Wix>
diff --git a/src/ext/Bal/wixlib/Mba.wxs b/src/ext/Bal/wixlib/Mba.wxs
new file mode 100644
index 00000000..2d407c88
--- /dev/null
+++ b/src/ext/Bal/wixlib/Mba.wxs
@@ -0,0 +1,43 @@
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
4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <!--
6 Mba.wxs - Managed BA resources.
7 -->
8 <Fragment>
9 <PayloadGroup Id="WixManagedBootstrapperApplicationHostManagedPayloads">
10 <Payload SourceFile="WixToolset.Mba.Host.dll" />
11 </PayloadGroup>
12 </Fragment>
13 <Fragment>
14 <PayloadGroup Id="MbaPreqStandardPayloads">
15 <Payload Name="mbapreq.thm" SourceFile="!(wix.PreqbaThemeXml=SourceDir\mbapreq.thm)" />
16 <Payload Name="mbapreq.png" SourceFile="!(wix.PreqbaLogo=SourceDir\mbapreq.png)" />
17 <Payload Name="mbapreq.wxl" SourceFile="!(wix.PreqbaThemeWxl=SourceDir\mbapreq.wxl)" />
18 <Payload Name="1028\mbapreq.wxl" SourceFile="!(wix.PreqbaThemeWxl1028=SourceDir\1028\mbapreq.wxl)" />
19 <Payload Name="1029\mbapreq.wxl" SourceFile="!(wix.PreqbaThemeWxl1029=SourceDir\1029\mbapreq.wxl)" />
20 <Payload Name="1030\mbapreq.wxl" SourceFile="!(wix.PreqbaThemeWxl1030=SourceDir\1030\mbapreq.wxl)" />
21 <Payload Name="1031\mbapreq.wxl" SourceFile="!(wix.PreqbaThemeWxl1031=SourceDir\1031\mbapreq.wxl)" />
22 <Payload Name="1032\mbapreq.wxl" SourceFile="!(wix.PreqbaThemeWxl1032=SourceDir\1032\mbapreq.wxl)" />
23 <Payload Name="1035\mbapreq.wxl" SourceFile="!(wix.PreqbaThemeWxl1035=SourceDir\1035\mbapreq.wxl)" />
24 <Payload Name="1036\mbapreq.wxl" SourceFile="!(wix.PreqbaThemeWxl1036=SourceDir\1036\mbapreq.wxl)" />
25 <Payload Name="1038\mbapreq.wxl" SourceFile="!(wix.PreqbaThemeWxl1038=SourceDir\1038\mbapreq.wxl)" />
26 <Payload Name="1040\mbapreq.wxl" SourceFile="!(wix.PreqbaThemeWxl1040=SourceDir\1040\mbapreq.wxl)" />
27 <Payload Name="1041\mbapreq.wxl" SourceFile="!(wix.PreqbaThemeWxl1041=SourceDir\1041\mbapreq.wxl)" />
28 <Payload Name="1042\mbapreq.wxl" SourceFile="!(wix.PreqbaThemeWxl1042=SourceDir\1042\mbapreq.wxl)" />
29 <Payload Name="1043\mbapreq.wxl" SourceFile="!(wix.PreqbaThemeWxl1043=SourceDir\1043\mbapreq.wxl)" />
30 <Payload Name="1044\mbapreq.wxl" SourceFile="!(wix.PreqbaThemeWxl1044=SourceDir\1044\mbapreq.wxl)" />
31 <Payload Name="1045\mbapreq.wxl" SourceFile="!(wix.PreqbaThemeWxl1045=SourceDir\1045\mbapreq.wxl)" />
32 <Payload Name="1046\mbapreq.wxl" SourceFile="!(wix.PreqbaThemeWxl1046=SourceDir\1046\mbapreq.wxl)" />
33 <Payload Name="1049\mbapreq.wxl" SourceFile="!(wix.PreqbaThemeWxl1049=SourceDir\1049\mbapreq.wxl)" />
34 <Payload Name="1051\mbapreq.wxl" SourceFile="!(wix.PreqbaThemeWxl1051=SourceDir\1051\mbapreq.wxl)" />
35 <Payload Name="1053\mbapreq.wxl" SourceFile="!(wix.PreqbaThemeWxl1053=SourceDir\1053\mbapreq.wxl)" />
36 <Payload Name="1055\mbapreq.wxl" SourceFile="!(wix.PreqbaThemeWxl1055=SourceDir\1055\mbapreq.wxl)" />
37 <Payload Name="1060\mbapreq.wxl" SourceFile="!(wix.PreqbaThemeWxl1060=SourceDir\1060\mbapreq.wxl)" />
38 <Payload Name="2052\mbapreq.wxl" SourceFile="!(wix.PreqbaThemeWxl2052=SourceDir\2052\mbapreq.wxl)" />
39 <Payload Name="2070\mbapreq.wxl" SourceFile="!(wix.PreqbaThemeWxl2070=SourceDir\2070\mbapreq.wxl)" />
40 <Payload Name="3082\mbapreq.wxl" SourceFile="!(wix.PreqbaThemeWxl3082=SourceDir\3082\mbapreq.wxl)" />
41 </PayloadGroup>
42 </Fragment>
43</Wix>
diff --git a/src/ext/Bal/wixlib/bal.wixproj b/src/ext/Bal/wixlib/bal.wixproj
new file mode 100644
index 00000000..fdcc7475
--- /dev/null
+++ b/src/ext/Bal/wixlib/bal.wixproj
@@ -0,0 +1,36 @@
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<Project Sdk="WixToolset.Sdk" ToolsVersion="4.0">
3 <PropertyGroup>
4 <OutputType>Library</OutputType>
5 <BindFiles>true</BindFiles>
6 <Cultures>en-us</Cultures>
7 </PropertyGroup>
8 <ItemGroup>
9 <BindInputPaths Include="..\wixstdba\Resources\" />
10 <BindInputPaths Include="$(OutputPath)netcoreapp3.1" />
11 <BindInputPaths Include="$(OutputPath)net20" />
12 <BindInputPaths Include="$(OutputPath)x86" BindName="x86" />
13 <BindInputPaths Include="$(OutputPath)x64" BindName="x64" />
14 <BindInputPaths Include="$(OutputPath)arm64" BindName="arm64" />
15 </ItemGroup>
16 <ItemGroup>
17 <ProjectReference Include="..\dnchost\dnchost.vcxproj" Properties="Platform=ARM64" />
18 <ProjectReference Include="..\mbahost\mbahost.vcxproj" Properties="Platform=ARM64" />
19 <ProjectReference Include="..\wixstdba\wixstdba.vcxproj" Properties="Platform=ARM64" />
20 <ProjectReference Include="..\dnchost\dnchost.vcxproj" Properties="Platform=x86" />
21 <ProjectReference Include="..\mbahost\mbahost.vcxproj" Properties="Platform=x86" />
22 <ProjectReference Include="..\wixstdba\wixstdba.vcxproj" Properties="Platform=x86" />
23 <ProjectReference Include="..\dnchost\dnchost.vcxproj" Properties="Platform=x64" />
24 <ProjectReference Include="..\mbahost\mbahost.vcxproj" Properties="Platform=x64" />
25 <ProjectReference Include="..\wixstdba\wixstdba.vcxproj" Properties="Platform=x64" />
26 </ItemGroup>
27 <ItemGroup>
28 <PackageReference Include="Nerdbank.GitVersioning" Version="3.3.37" PrivateAssets="All" />
29 </ItemGroup>
30 <!-- Workaround for bug in ProjectReferenceDefineConstants, they're not needed for this project anyway -->
31 <Target Name="ClearProjectReferenceDefineConstants" AfterTargets="CalculateDefineConstants">
32 <PropertyGroup>
33 <ProjectReferenceDefineConstants></ProjectReferenceDefineConstants>
34 </PropertyGroup>
35 </Target>
36</Project> \ No newline at end of file
diff --git a/src/ext/Bal/wixlib/caDecor.wxi b/src/ext/Bal/wixlib/caDecor.wxi
new file mode 100644
index 00000000..b1711518
--- /dev/null
+++ b/src/ext/Bal/wixlib/caDecor.wxi
@@ -0,0 +1,39 @@
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
4<Include xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <?ifdef Prefix ?>
6 <?undef Prefix ?>
7 <?endif?>
8
9 <?define Prefix="Wix4" ?>
10
11 <?ifndef platform ?>
12 <?define platform="x86" ?>
13 <?endif?>
14
15 <?if $(var.platform)="" ?>
16 <?undef platform ?>
17 <?define platform="x86" ?>
18 <?endif?>
19
20 <?ifdef Suffix ?>
21 <?undef Suffix ?>
22 <?endif?>
23
24 <?if $(var.platform)~="x86" ?>
25 <?define Suffix="_X86" ?>
26 <?endif?>
27
28 <?if $(var.platform)~="x64" ?>
29 <?define Suffix="_X64" ?>
30 <?endif?>
31
32 <?if $(var.platform)~="arm" ?>
33 <?define Suffix="_A32" ?>
34 <?endif?>
35
36 <?if $(var.platform)~="arm64" ?>
37 <?define Suffix="_A64" ?>
38 <?endif?>
39</Include>
diff --git a/src/ext/Bal/wixlib/wixstdba.wxs b/src/ext/Bal/wixlib/wixstdba.wxs
new file mode 100644
index 00000000..8181b9b4
--- /dev/null
+++ b/src/ext/Bal/wixlib/wixstdba.wxs
@@ -0,0 +1,92 @@
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
4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <!-- RTF License Payload Group -->
6 <Fragment>
7 <PayloadGroup Id="WixStdbaRtfLicensePayloads">
8 <Payload Name="thm.xml" Compressed="yes" SourceFile="!(wix.WixStdbaThemeXml=RtfTheme.xml)" />
9 <Payload Name="thm.wxl" Compressed="yes" SourceFile="!(wix.WixStdbaThemeWxl=RtfTheme.wxl)" />
10 <Payload Name="logo.png" Compressed="yes" SourceFile="!(wix.WixStdbaLogo=logo.png)" />
11
12 <Payload Name="!(wix.WixStdbaLicenseRtfName=license.rtf)" Compressed="yes" SourceFile="!(wix.WixStdbaLicenseRtf=LoremIpsumLicense.rtf)" />
13 </PayloadGroup>
14
15 <BundleCustomDataRef Id="WixStdbaInformation">
16 <BundleElement>
17 <BundleAttribute Id="LicenseFile" Value="!(wix.WixStdbaLicenseRtfName=license.rtf)" />
18 </BundleElement>
19 </BundleCustomDataRef>
20 </Fragment>
21
22 <!-- RTF Large License Payload Group -->
23 <Fragment>
24 <PayloadGroup Id="WixStdbaRtfLargeLicensePayloads">
25 <Payload Name="thm.xml" Compressed="yes" SourceFile="!(wix.WixStdbaThemeXml=RtfLargeTheme.xml)" />
26 <Payload Name="thm.wxl" Compressed="yes" SourceFile="!(wix.WixStdbaThemeWxl=RtfTheme.wxl)" />
27 <Payload Name="logo.png" Compressed="yes" SourceFile="!(wix.WixStdbaLogo=logo.png)" />
28
29 <Payload Name="!(wix.WixStdbaLicenseRtfName=license.rtf)" Compressed="yes" SourceFile="!(wix.WixStdbaLicenseRtf=LoremIpsumLicense.rtf)" />
30 </PayloadGroup>
31
32 <BundleCustomDataRef Id="WixStdbaInformation">
33 <BundleElement>
34 <BundleAttribute Id="LicenseFile" Value="!(wix.WixStdbaLicenseRtfName=license.rtf)" />
35 </BundleElement>
36 </BundleCustomDataRef>
37 </Fragment>
38
39 <!-- Hyperlink License Payload Group -->
40 <Fragment>
41 <PayloadGroup Id="WixStdbaHyperlinkLicensePayloads">
42 <Payload Name="thm.xml" Compressed="yes" SourceFile="!(wix.WixStdbaThemeXml=HyperlinkTheme.xml)" />
43 <Payload Name="thm.wxl" Compressed="yes" SourceFile="!(wix.WixStdbaThemeWxl=HyperlinkTheme.wxl)" />
44 <Payload Name="logo.png" Compressed="yes" SourceFile="!(wix.WixStdbaLogo=logo.png)" />
45 </PayloadGroup>
46
47 <BundleCustomDataRef Id="WixStdbaInformation">
48 <BundleElement>
49 <BundleAttribute Id="LicenseUrl" Value="!(wix.WixStdbaLicenseUrl)" />
50 </BundleElement>
51 </BundleCustomDataRef>
52 </Fragment>
53
54 <!-- Hyperlink Large License Payload Group -->
55 <Fragment>
56 <PayloadGroup Id="WixStdbaHyperlinkLargeLicensePayloads">
57 <Payload Name="thm.xml" Compressed="yes" SourceFile="!(wix.WixStdbaThemeXml=HyperlinkLargeTheme.xml)" />
58 <Payload Name="thm.wxl" Compressed="yes" SourceFile="!(wix.WixStdbaThemeWxl=HyperlinkTheme.wxl)" />
59 <Payload Name="logo.png" Compressed="yes" SourceFile="!(wix.WixStdbaLogo=logo.png)" />
60 </PayloadGroup>
61
62 <BundleCustomDataRef Id="WixStdbaInformation">
63 <BundleElement>
64 <BundleAttribute Id="LicenseUrl" Value="!(wix.WixStdbaLicenseUrl)" />
65 </BundleElement>
66 </BundleCustomDataRef>
67 </Fragment>
68
69 <!-- HyperlinkSidebar License Payload Group -->
70 <Fragment>
71 <PayloadGroup Id="WixStdbaHyperlinkSidebarLicensePayloads">
72 <Payload Name="thm.xml" Compressed="yes" SourceFile="!(wix.WixStdbaThemeXml=HyperlinkSidebarTheme.xml)" />
73 <Payload Name="thm.wxl" Compressed="yes" SourceFile="!(wix.WixStdbaThemeWxl=HyperlinkTheme.wxl)" />
74 <Payload Name="logo.png" Compressed="yes" SourceFile="!(wix.WixStdbaLogo=logo.png)" />
75 <Payload Name="logoside.png" Compressed="yes" SourceFile="!(wix.WixStdbaLogoSide=logoside.png)" />
76 </PayloadGroup>
77
78 <BundleCustomDataRef Id="WixStdbaInformation">
79 <BundleElement>
80 <BundleAttribute Id="LicenseUrl" Value="!(wix.WixStdbaLicenseUrl)" />
81 </BundleElement>
82 </BundleCustomDataRef>
83 </Fragment>
84
85 <!-- BootstrapperApplicationData tables definition -->
86 <Fragment>
87 <BundleCustomData Id="WixStdbaInformation">
88 <BundleAttributeDefinition Id="LicenseFile" />
89 <BundleAttributeDefinition Id="LicenseUrl" />
90 </BundleCustomData>
91 </Fragment>
92</Wix>
diff --git a/src/ext/Bal/wixstdba/Resources/1028/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1028/mbapreq.wxl
new file mode 100644
index 00000000..abd35ac7
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/1028/mbapreq.wxl
@@ -0,0 +1,27 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<WixLocalization Culture="zh-tw" Language="1028" xmlns="http://schemas.microsoft.com/wix/2006/localization">
6 <String Id="Caption">[WixBundleName] 安裝程式</String>
7 <String Id="Title">[WixBundleName] 安裝程式需要 Microsoft .NET Framework</String>
8 <String Id="ConfirmCancelMessage">您確定要取消嗎?</String>
9 <String Id="HelpHeader">安裝程式說明</String>
10 <String Id="HelpText">/passive | /quiet - 顯示最基本的 UI 但不顯示提示,或者不顯示 UI 也
11 不顯示提示。預設會顯示 UI 和所有提示。
12
13/norestart - 隱藏任何重新啟動嘗試。根據預設,UI 會在重新啟動之前提示。
14/log log.txt - 記錄至特定檔案。預設會在 %TEMP% 建立記錄檔。</String>
15 <String Id="HelpCloseButton">關閉(&amp;C)</String>
16 <String Id="InstallLicenseTerms">請按一下 「接受並安裝」5D; 按鈕,接受 Microsoft .NET Framework &lt;a href="#"&gt;授權合約&lt;/a&gt;。</String>
17 <String Id="InstallAcceptAndInstallButton">接受並安裝(&amp;A)</String>
18 <String Id="InstallDeclineButton">拒絕(&amp;D)</String>
19 <String Id="ProgressHeader">安裝進度</String>
20 <String Id="ProgressLabel">正在處理:</String>
21 <String Id="ProgressCancelButton">取消(&amp;)</String>
22 <String Id="FailureHeader">安裝失敗</String>
23 <String Id="FailureLogLinkText">一或多個問題導致安裝失敗。請修正這些問題,然後再重試安裝。如需詳細資訊,請查看&lt;a href="#"&gt;記錄檔&lt;/a&gt;。</String>
24 <String Id="FailureRestartText">必須重新啟動電腦,才能完成軟體的復原。</String>
25 <String Id="FailureRestartButton">重新啟動(&amp;R)</String>
26 <String Id="FailureCloseButton">關閉(&amp;C)</String>
27</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1029/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1029/mbapreq.wxl
new file mode 100644
index 00000000..e28b4f74
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/1029/mbapreq.wxl
@@ -0,0 +1,30 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<WixLocalization Culture="cs-cz" Language="1029" xmlns="http://schemas.microsoft.com/wix/2006/localization">
6 <String Id="Caption">Instalace produktu [WixBundleName]</String>
7 <String Id="Title">Pro instalaci produktu [WixBundleName] je vyžadováno rozhraní Microsoft .NET Framework.</String>
8 <String Id="ConfirmCancelMessage">Opravdu chcete akci zrušit?</String>
9 <String Id="HelpHeader">Nápověda k instalaci</String>
10 <String Id="HelpText">/passive | /quiet - Zobrazí minimální uživatelské rozhraní bez jakýchkoli
11 výzev, nebo nezobrazí žádné uživatelské rozhraní ani žádné výzvy. Ve výchozím
12 nastavení se jak uživatelské rozhraní, tak i všechny výzvy zobrazují.
13
14/norestart - Potlačí jakékoli pokusy o restartování. Ve výchozím nastavení
15 se v uživatelském rozhraní před restartováním zobrazí výzva.
16/log log.txt - Nastaví, že se má zapisovat do konkrétního souboru protokolu.
17 Ve výchozím nastavení je soubor protokolu vytvořen v umístění %TEMP%.</String>
18 <String Id="HelpCloseButton">&amp;Zavřít</String>
19 <String Id="InstallLicenseTerms">Kliknutím na tlačítko Přijmout a nainstalovat přijmete &lt;a href="#"&gt;licenční podmínky&lt;/a&gt; rozhraní Microsoft .NET Framework.</String>
20 <String Id="InstallAcceptAndInstallButton">&amp;Přijmout a instalovat</String>
21 <String Id="InstallDeclineButton">&amp;Odmítnout</String>
22 <String Id="ProgressHeader">Průběh instalace</String>
23 <String Id="ProgressLabel">Probíhá zpracování:</String>
24 <String Id="ProgressCancelButton">&amp;Storno</String>
25 <String Id="FailureHeader">Instalace se nezdařila</String>
26 <String Id="FailureLogLinkText">Byly zjištěny problémy, kvůli kterým se instalaci nepodařilo dokončit. Odstraňte tyto problémy a potom instalaci opakujte. Další informace naleznete v &lt;a href="#"&gt;souboru protokolu&lt;/a&gt;.</String>
27 <String Id="FailureRestartText">Aby bylo možné zrušení instalace softwaru dokončit, je nutné počítač restartovat.</String>
28 <String Id="FailureRestartButton">&amp;Restartovat</String>
29 <String Id="FailureCloseButton">&amp;Zavřít</String>
30</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1030/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1030/mbapreq.wxl
new file mode 100644
index 00000000..a531467a
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/1030/mbapreq.wxl
@@ -0,0 +1,30 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<WixLocalization Culture="da-dk" Language="1030" xmlns="http://schemas.microsoft.com/wix/2006/localization">
6 <String Id="Caption">Installation af [WixBundleName]</String>
7 <String Id="Title">Microsoft .NET Framework skal være installeret i forbindelse med Installationen af [WixBundleName]</String>
8 <String Id="ConfirmCancelMessage">Er du sikker på, at du vil annullere?</String>
9 <String Id="HelpHeader">Hjælp til installation</String>
10 <String Id="HelpText">/passive | /quiet - viser en minimal brugergrænseflade uden prompter eller
11 viser ingen brugergrænseflade og ingen prompter.
12 Brugergrænsefladen og alle prompter vises som standard.
13
14/norestart - skjuler forsøg på genstart. Der vises som standard en
15 forespørgsel i brugergrænsefladen, før der genstartes.
16/log log.txt - logfører til en bestemt fil. Der oprettes som standard en
17 logfil i %TEMP%.</String>
18 <String Id="HelpCloseButton">&amp;Luk</String>
19 <String Id="InstallLicenseTerms">Klik på knappen "Acceptér og installér" for at acceptere &lt;a href="#"&gt;licensvilkårene&lt;/a&gt; for Microsoft .NET Framework.</String>
20 <String Id="InstallAcceptAndInstallButton">&amp;Acceptér og installér</String>
21 <String Id="InstallDeclineButton">&amp;Afvis</String>
22 <String Id="ProgressHeader">Status for installation</String>
23 <String Id="ProgressLabel">Behandler:</String>
24 <String Id="ProgressCancelButton">&amp;Annuller</String>
25 <String Id="FailureHeader">Installationen blev ikke gennemført</String>
26 <String Id="FailureLogLinkText">Installationen blev ikke gennemført på grund af et eller flere problemer. Løs problemerne, og prøv derefter at installere igen. Se &lt;a href="#"&gt;logfilen&lt;/a&gt; for at få flere oplysninger.</String>
27 <String Id="FailureRestartText">Du skal genstarte computeren for at fuldføre annulleringen af opdateringen af softwaren.</String>
28 <String Id="FailureRestartButton">&amp;Genstart</String>
29 <String Id="FailureCloseButton">&amp;Luk</String>
30</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1031/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1031/mbapreq.wxl
new file mode 100644
index 00000000..ff8111f9
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/1031/mbapreq.wxl
@@ -0,0 +1,33 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<WixLocalization Culture="de-de" Language="1031" xmlns="http://schemas.microsoft.com/wix/2006/localization">
6 <UI Control="InstallButton" Width="180" />
7
8 <String Id="Caption">[WixBundleName]-Setup</String>
9 <String Id="Title">Für das [WixBundleName]-Setup ist Microsoft .NET Framework erforderlich.</String>
10 <String Id="ConfirmCancelMessage">Sind Sie sicher, dass Sie den Vorgang abbrechen möchten?</String>
11 <String Id="HelpHeader">Setup-Hilfe</String>
12 <String Id="HelpText">/passive | /quiet - zeigt eine minimale Benutzeroberfläche ohne
13 Eingabeaufforderungen oder keine Benutzeroberfläche und keine
14 Eingabeaufforderungen an. Standardmäßig werden die Benutzeroberfläche und
15 alle Eingabeaufforderungen angezeigt.
16
17/norestart - unterdrückt alle Neustartversuche. Standardmäßig fordert die
18 Benutzeroberfläche zum Bestätigen eines Neustarts auf.
19/log log.txt - erstellt das Protokoll in einer bestimmten Datei.
20 Standardmäßig wird die Protokolldatei in "%TEMP%" erstellt.</String>
21 <String Id="HelpCloseButton">&amp;Schließen</String>
22 <String Id="InstallLicenseTerms">Klicken Sie auf die Schaltfläche "Akzeptieren und installieren", um den Microsoft .NET Framework &lt;a href="#"&gt;-Lizenzbedingungen&lt;/a&gt; zuzustimmen.</String>
23 <String Id="InstallAcceptAndInstallButton">&amp;Akzeptieren und installieren</String>
24 <String Id="InstallDeclineButton">&amp;Ablehnen</String>
25 <String Id="ProgressHeader">Setup-Status</String>
26 <String Id="ProgressLabel">Verarbeitung:</String>
27 <String Id="ProgressCancelButton">&amp;Abbrechen</String>
28 <String Id="FailureHeader">Setup-Fehler</String>
29 <String Id="FailureLogLinkText">Beim Setup ist aufgrund mindestens eines Problems ein Fehler aufgetreten. Beheben Sie die Probleme, und wiederholen Sie das Setup. Weitere Informationen finden Sie in der &lt;a href="#"&gt;Protokolldatei&lt;/a&gt;.</String>
30 <String Id="FailureRestartText">Sie müssen den Computer neu starten, um das Zurücksetzen der Software abzuschließen.</String>
31 <String Id="FailureRestartButton">&amp;Neu starten</String>
32 <String Id="FailureCloseButton">&amp;Schließen</String>
33</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1032/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1032/mbapreq.wxl
new file mode 100644
index 00000000..bc3703a3
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/1032/mbapreq.wxl
@@ -0,0 +1,32 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<WixLocalization Culture="el-gr" Language="1032" xmlns="http://schemas.microsoft.com/wix/2006/localization">
6 <String Id="Caption">Εγκατάσταση του [WixBundleName]</String>
7 <String Id="Title">Για την εγκατάσταση του [WixBundleName] απαιτείται το Microsoft .NET Framework</String>
8 <String Id="ConfirmCancelMessage">Είστε βέβαιοι ότι θέλετε να γίνει ακύρωση;</String>
9 <String Id="HelpHeader">Βοήθεια για την εγκατάσταση</String>
10 <String Id="HelpText">/passive | /quiet - εμφανίζει ελάχιστο περιεχόμενο του περιβάλλοντος εργασίας
11 χρήστη χωρίς μηνύματα ή δεν εμφανίζει περιβάλλον εργασίας χρήστη και
12 μηνύματα. Από προεπιλογή, εμφανίζονται όλα τα μηνύματα και το περιβάλλον
13 εργασίας χρήστη.
14
15/norestart - αποκρύπτει οποιεσδήποτε προσπάθειες για επανεκκίνηση. Από
16 προεπιλογή, το περιβάλλον εργασίας χρήστη θα εμφανίσει μήνυμα πριν από την
17 επανεκκίνηση.
18/log log.txt - πραγματοποιεί καταγραφή σε ένα συγκεκριμένο αρχείο. Από
19 προεπιλογή, δημιουργείται ένα αρχείο καταγραφής στο %TEMP%.</String>
20 <String Id="HelpCloseButton">&amp;Κλείσιμο</String>
21 <String Id="InstallLicenseTerms">Κάντε κλικ στο κουμπί "Αποδοχή και εγκατάσταση" για να αποδεχτείτε τους &lt;a href="#"&gt;όρους της άδειας χρήσης&lt;/a&gt; του Microsoft .NET Framework.</String>
22 <String Id="InstallAcceptAndInstallButton">&amp;Αποδοχή και εγκατάσταση</String>
23 <String Id="InstallDeclineButton">&amp;Απόρριψη</String>
24 <String Id="ProgressHeader">Πρόοδος εγκατάστασης</String>
25 <String Id="ProgressLabel">Επεξεργασία:</String>
26 <String Id="ProgressCancelButton">&amp;Άκυρο</String>
27 <String Id="FailureHeader">Αποτυχία εγκατάστασης</String>
28 <String Id="FailureLogLinkText">Ένα ή περισσότερα προβλήματα προκάλεσαν την αποτυχία της εγκατάστασης. Διορθώστε τα προβλήματα και μετά επαναλάβετε την εγκατάσταση. Για περισσότερες πληροφορίες, ανατρέξτε στο &lt;a href="#"&gt;αρχείο καταγραφής&lt;/a&gt;.</String>
29 <String Id="FailureRestartText">Για να ολοκληρωθεί η επαναφορά του λογισμικού, πρέπει να κάνετε επανεκκίνηση του υπολογιστή.</String>
30 <String Id="FailureRestartButton">&amp;Επανεκκίνηση</String>
31 <String Id="FailureCloseButton">&amp;Κλείσιμο</String>
32</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1035/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1035/mbapreq.wxl
new file mode 100644
index 00000000..859e5b23
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/1035/mbapreq.wxl
@@ -0,0 +1,30 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<WixLocalization Culture="fi-fi" Language="1035" xmlns="http://schemas.microsoft.com/wix/2006/localization">
6 <String Id="Caption">[WixBundleName] -asennus</String>
7 <String Id="Title">Microsoft .NET Framework tarvitaan [WixBundleName] -asennusta varten</String>
8 <String Id="ConfirmCancelMessage">Haluatko varmasti peruuttaa?</String>
9 <String Id="HelpHeader">Asennusohjelman ohje</String>
10 <String Id="HelpText">/passive | /quiet - näyttää mahdollisimman vähän käyttöliittymästä; ei
11 kehotteita tai ei käyttöliittymää ja kehotteita. Oletusarvoisesti
12 käyttöliittymä ja kaikki kehotteet näytetään.
13
14/norestart - estää uudelleenkäynnistysyritykset. Oletusarvoisesti
15 käyttöliittymä kysyy ennen uudelleenkäynnistystä.
16/log loki.txt - kirjaa lokitiedot erityiseen tiedostoon. Oletusarvoisesti
17 lokitiedosto luodaan %TEMP%-kansioon.</String>
18 <String Id="HelpCloseButton">&amp;Sulje</String>
19 <String Id="InstallLicenseTerms">Hyväksy Microsoft .NET Framework -ohjelman &lt;a href="#"&gt;käyttöoikeusehdot&lt;/a&gt; valitsemalla Hyväksy ja asenna.</String>
20 <String Id="InstallAcceptAndInstallButton">&amp;Hyväksy ja asenna</String>
21 <String Id="InstallDeclineButton">&amp;Hylkää</String>
22 <String Id="ProgressHeader">Asennuksen edistyminen</String>
23 <String Id="ProgressLabel">Käsitellään:</String>
24 <String Id="ProgressCancelButton">&amp;Peruuta</String>
25 <String Id="FailureHeader">Asennus epäonnistui</String>
26 <String Id="FailureLogLinkText">Asennus epäonnistui yhdestä tai useammasta syystä. Korjaa ongelmat ja yritä suorittaa asennus sitten uudelleen. Lisätietoja on &lt;a href="#"&gt;lokitiedostossa&lt;/a&gt;.</String>
27 <String Id="FailureRestartText">Tietokone täytyy käynnistää uudelleen ohjelmiston palautuksen viimeistelemiseksi.</String>
28 <String Id="FailureRestartButton">&amp;Käynnistä uudelleen</String>
29 <String Id="FailureCloseButton">&amp;Sulje</String>
30</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1036/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1036/mbapreq.wxl
new file mode 100644
index 00000000..f67dfa8e
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/1036/mbapreq.wxl
@@ -0,0 +1,30 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<WixLocalization Culture="fr-fr" Language="1036" xmlns="http://schemas.microsoft.com/wix/2006/localization">
6 <String Id="Caption">Installation de [WixBundleName]</String>
7 <String Id="Title">Microsoft .NET Framework requis pour l'installation de [WixBundleName]</String>
8 <String Id="ConfirmCancelMessage">Êtes-vous sûr de vouloir annuler ?</String>
9 <String Id="HelpHeader">Aide de l'installation</String>
10 <String Id="HelpText">/passive | /quiet - affiche une interface minimale sans invites ou n'affiche
11 aucune interface ni aucune invite. Par défaut, l'interface et toutes les
12 invites sont affichées.
13
14/norestart - annule toute tentative de redémarrage. Par défaut, l'interface
15 affiche une invite avant de redémarrer.
16/log journal.txt - consigne les entrées de journal dans un fichier spécifique.
17 Par défaut, un fichier journal est créé dans %TEMP%.</String>
18 <String Id="HelpCloseButton">&amp;Fermer</String>
19 <String Id="InstallLicenseTerms">Cliquez sur le bouton « Accepter et installer » pour accepter les &lt;a href="#"&gt;termes du contrat de licence&lt;/a&gt; Microsoft .NET Framework.</String>
20 <String Id="InstallAcceptAndInstallButton">&amp;Accepter et installer</String>
21 <String Id="InstallDeclineButton">&amp;Refuser</String>
22 <String Id="ProgressHeader">Progression de l'installation</String>
23 <String Id="ProgressLabel">Traitement en cours :</String>
24 <String Id="ProgressCancelButton">&amp;Annuler</String>
25 <String Id="FailureHeader">L'installation a échoué</String>
26 <String Id="FailureLogLinkText">L'installation a échoué pour une ou plusieurs raisons. Corrigez les problèmes et recommencez l'installation. Pour plus d'informations, consultez le &lt;a href="#"&gt;fichier journal&lt;/a&gt;.</String>
27 <String Id="FailureRestartText">Vous devez redémarrer votre ordinateur pour effectuer la restauration du logiciel.</String>
28 <String Id="FailureRestartButton">&amp;Redémarrer</String>
29 <String Id="FailureCloseButton">&amp;Fermer</String>
30</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1038/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1038/mbapreq.wxl
new file mode 100644
index 00000000..6a4b109d
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/1038/mbapreq.wxl
@@ -0,0 +1,30 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<WixLocalization Culture="hu-hu" Language="1038" xmlns="http://schemas.microsoft.com/wix/2006/localization">
6 <String Id="Caption">[WixBundleName] telepítő</String>
7 <String Id="Title">A(z) [WixBundleName] telepítéséhez Microsoft .NET-keretrendszer szükséges</String>
8 <String Id="ConfirmCancelMessage">Biztosan megszakítja?</String>
9 <String Id="HelpHeader">A telepítő súgója</String>
10 <String Id="HelpText">/passive | /quiet - Minimális felhasználói felület megjelenítése kérdések
11 nélkül, illetve felhasználói felület és kérdések megjelenítése nélküli
12 telepítés. Alapesetben a felhasználói felület és minden kérdés megjelenik.
13
14/norestart - Az újraindítási kérések elrejtése. Alapesetben a felhasználói
15 felületen megjelennek az újraindítási kérések.
16/log naplo.txt - Naplózás a megadott fájlba. Alapesetben a naplófájl a %TEMP%
17 könyvtárban jön létre.</String>
18 <String Id="HelpCloseButton">&amp;Bezárás</String>
19 <String Id="InstallLicenseTerms">A Microsoft .NET-keretrendszer &lt;a href="#"&gt;licencszerződésének&lt;/a&gt; elfogadásához kattintson az „Elfogadás és telepítés” gombra.</String>
20 <String Id="InstallAcceptAndInstallButton">&amp;Elfogadás és telepítés</String>
21 <String Id="InstallDeclineButton">&amp;Elutasítás</String>
22 <String Id="ProgressHeader">Telepítési folyamat</String>
23 <String Id="ProgressLabel">Feldolgozás:</String>
24 <String Id="ProgressCancelButton">&amp;Mégse</String>
25 <String Id="FailureHeader">A telepítés nem sikerült</String>
26 <String Id="FailureLogLinkText">Legalább egy olyan hiba lépett fel, amely a telepítés meghiúsulását okozta. Hárítsa el a hibákat, majd futtassa újra a telepítőt. További információt a &lt;a href="#"&gt;naplófájlban &lt;/a&gt; talál.</String>
27 <String Id="FailureRestartText">A szoftver visszaállításának befejezéséhez újra kell indítania a számítógépet.</String>
28 <String Id="FailureRestartButton">&amp;Újraindítás</String>
29 <String Id="FailureCloseButton">&amp;Bezárás</String>
30</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1040/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1040/mbapreq.wxl
new file mode 100644
index 00000000..f57d58e5
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/1040/mbapreq.wxl
@@ -0,0 +1,31 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<WixLocalization Culture="it-it" Language="1040" xmlns="http://schemas.microsoft.com/wix/2006/localization">
6 <String Id="Caption">Installazione di [WixBundleName]</String>
7 <String Id="Title">Microsoft .NET Framework necessario per l'installazione di [WixBundleName]</String>
8 <String Id="ConfirmCancelMessage">Annullare?</String>
9 <String Id="HelpHeader">Guida dell'installazione</String>
10 <String Id="HelpText">/passive | /quiet - visualizza l'interfaccia utente minima senza istruzioni
11 oppure non visualizza né l'interfaccia utente né le istruzioni. Per
12 impostazione predefinita vengono visualizzate interfaccia utente e
13 istruzioni.
14
15/norestart - elimina eventuali tentativi di riavvio. Per impostazione
16 predefinita l'interfaccia utente chiede istruzioni prima del riavvio.
17/log log.txt - registra in un file specifico. Per impostazione predefinita un
18 file di log viene creato in %TEMP%.</String>
19 <String Id="HelpCloseButton">&amp;Chiudi</String>
20 <String Id="InstallLicenseTerms">Fare clic sul pulsante "Accetta e installa" per accettare le &lt;a href="#"&gt;condizioni di licenza&lt;/a&gt; di Microsoft .NET Framework.</String>
21 <String Id="InstallAcceptAndInstallButton">&amp;Accetta e installa</String>
22 <String Id="InstallDeclineButton">&amp;Rifiuta</String>
23 <String Id="ProgressHeader">Stato installazione</String>
24 <String Id="ProgressLabel">Elaborazione in corso:</String>
25 <String Id="ProgressCancelButton">&amp;Annulla</String>
26 <String Id="FailureHeader">Installazione non riuscita</String>
27 <String Id="FailureLogLinkText">L'installazione non è riuscita a causa di uno o più problemi. Risolvere i problemi e provare di nuovo l'installazione. Per ulteriori informazioni vedere il &lt;a href="#"&gt;file di log&lt;/a&gt;.</String>
28 <String Id="FailureRestartText">È necessario riavviare il computer per completare il rollback del software.</String>
29 <String Id="FailureRestartButton">&amp;Riavvia</String>
30 <String Id="FailureCloseButton">&amp;Chiudi</String>
31</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1041/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1041/mbapreq.wxl
new file mode 100644
index 00000000..3fe7b9b3
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/1041/mbapreq.wxl
@@ -0,0 +1,27 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<WixLocalization Culture="ja-jp" Language="1041" xmlns="http://schemas.microsoft.com/wix/2006/localization">
6 <String Id="Caption">[WixBundleName] セットアップ</String>
7 <String Id="Title">[WixBundleName] セットアップには Microsoft .NET Framework が必要です</String>
8 <String Id="ConfirmCancelMessage">取り消しますか?</String>
9 <String Id="HelpHeader">セットアップのヘルプ</String>
10 <String Id="HelpText">/passive | /quiet - 最小の UI だけを表示してプロンプトは表示しないか、UI
11 もプロンプトも表示しません。 既定では、UI とすべてのプロンプトが表示されます。
12
13/norestart - 再起動の試みをすべて抑制します。既定では、再起動の前に UI によりプロンプトが表示されます。
14/log log.txt - 特定のファイルにログを記録します。既定では、%TEMP% にログ ファイルが作成されます。</String>
15 <String Id="HelpCloseButton">閉じる(&amp;C)</String>
16 <String Id="InstallLicenseTerms">Microsoft .NET Framework の&lt;a href="#"&gt;ライセンス条項&lt;/a&gt;に同意する場合は、[同意してインストール]5D; ボタンをクリックします。</String>
17 <String Id="InstallAcceptAndInstallButton">同意してインストール(&amp;A)</String>
18 <String Id="InstallDeclineButton">同意しない(&amp;)</String>
19 <String Id="ProgressHeader">セットアップの進行状況</String>
20 <String Id="ProgressLabel">処理中:</String>
21 <String Id="ProgressCancelButton">キャンセル(&amp;C)</String>
22 <String Id="FailureHeader">セットアップに失敗しました</String>
23 <String Id="FailureLogLinkText">1 つ以上の問題が原因でセットアップに失敗しました。問題を解決してからセットアップをやり直してください。詳細については、&lt;a href="#"&gt;ログ ファイル&lt;/a&gt;を参照してください。</String>
24 <String Id="FailureRestartText">ソフトウェアのロールバックを完了するには、コンピューターを再起動する必要があります。</String>
25 <String Id="FailureRestartButton">再起動(&amp;R)</String>
26 <String Id="FailureCloseButton">閉じる(&amp;C)</String>
27</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1042/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1042/mbapreq.wxl
new file mode 100644
index 00000000..0f53dcc3
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/1042/mbapreq.wxl
@@ -0,0 +1,27 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<WixLocalization Culture="ko-kr" Language="1042" xmlns="http://schemas.microsoft.com/wix/2006/localization">
6 <String Id="Caption">[WixBundleName] 설치</String>
7 <String Id="Title">[WixBundleName] 설치에 필요한 Microsoft .NET Framework</String>
8 <String Id="ConfirmCancelMessage">취소하시겠습니까?</String>
9 <String Id="HelpHeader">설치 도움말</String>
10 <String Id="HelpText">/passive | /quiet - 메시지 없이 최소 UI를 표시하거나 UI와 메시지를 전혀
11 표시하지 않습니다. 기본적으로 UI 및 모든 메시지는 표시됩니다.
12
13/norestart - 다시 시작하려는 시도를 무시합니다. 기본적으로 UI는 다시 시작하기 전에 메시지를 표시합니다.
14/log log.txt - 특정 파일에 기록합니다. 기본적으로 로그 파일이 %TEMP%에 생성됩니다.</String>
15 <String Id="HelpCloseButton">닫기(&amp;C)</String>
16 <String Id="InstallLicenseTerms">Microsoft .NET Framework &lt;a href="#"&gt;사용 조건&lt;/a&gt;에 동의하려면 "동의 및 설치"를 클릭하십시오.</String>
17 <String Id="InstallAcceptAndInstallButton">동의 및 설치(&amp;A)</String>
18 <String Id="InstallDeclineButton">동의 안 함(&amp;D)</String>
19 <String Id="ProgressHeader">설치 진행률</String>
20 <String Id="ProgressLabel">처리 중:</String>
21 <String Id="ProgressCancelButton">취소(&amp;C)</String>
22 <String Id="FailureHeader">설치 실패</String>
23 <String Id="FailureLogLinkText">하나 이상의 문제로 인해 설치에 실패했습니다. 문제를 수정하고 설치를 다시 시도하십시오. 자세한 내용은 &lt;a href="#"&gt;로그 파일&lt;/a&gt;을 참조하십시오.</String>
24 <String Id="FailureRestartText">소프트웨어의 롤백을 완료하려면 컴퓨터를 다시 시작해야 합니다.</String>
25 <String Id="FailureRestartButton">다시 시작(&amp;R)</String>
26 <String Id="FailureCloseButton">닫기(&amp;C)</String>
27</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1043/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1043/mbapreq.wxl
new file mode 100644
index 00000000..f4a2c78c
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/1043/mbapreq.wxl
@@ -0,0 +1,30 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<WixLocalization Culture="nl-nl" Language="1043" xmlns="http://schemas.microsoft.com/wix/2006/localization">
6 <String Id="Caption">[WixBundleName] Installatie</String>
7 <String Id="Title">Microsoft .NET Framework is vereist voor installatie [WixBundleName]</String>
8 <String Id="ConfirmCancelMessage">Weet u zeker dat u de installatie wilt annuleren?</String>
9 <String Id="HelpHeader">Help bij Setup</String>
10 <String Id="HelpText">/passive | /quiet - geeft een minimale gebruikersinterface weer zonder prompts
11 of geeft geen gebruikersinterface en geen prompts weer. Gebruikersinterface
12 en alle prompts worden standaard weergegeven.
13
14/norestart - pogingen tot opnieuw opstarten onderdrukken.
15 Gebruikersinterface vraagt standaard alvorens opnieuw op te starten.
16/log log.txt - registreert gegevens in een specifiek bestand. Een logbestand
17 wordt standaard in %TEMP% gemaakt.</String>
18 <String Id="HelpCloseButton">&amp;Sluiten</String>
19 <String Id="InstallLicenseTerms">Klik op de knop 'Accepteren en installeren' om de &lt;a href="#"&gt;licentievoorwaarden&lt;/a&gt; van het Microsoft .NET Framework te accepteren.</String>
20 <String Id="InstallAcceptAndInstallButton">&amp;Accepteren en installeren</String>
21 <String Id="InstallDeclineButton">&amp;Weigeren</String>
22 <String Id="ProgressHeader">Voortgang van de installatie</String>
23 <String Id="ProgressLabel">Verwerken:</String>
24 <String Id="ProgressCancelButton">&amp;Annuleren</String>
25 <String Id="FailureHeader">Installatie mislukt</String>
26 <String Id="FailureLogLinkText">Er zijn een of meer fouten opgetreden waardoor de installatie is mislukt. Corrigeer de problemen en voer Setup opnieuw uit. Raadpleeg het &lt;a href="#"&gt;log boekbestand&lt;/a&gt; voor meer informatie.</String>
27 <String Id="FailureRestartText">U moet uw computer opnieuw opstarten om het terugdraaien van de software te voltooien.</String>
28 <String Id="FailureRestartButton">&amp;Opnieuw opstarten</String>
29 <String Id="FailureCloseButton">&amp;Sluiten</String>
30</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1044/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1044/mbapreq.wxl
new file mode 100644
index 00000000..da5c8283
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/1044/mbapreq.wxl
@@ -0,0 +1,30 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<WixLocalization Culture="nb-no" Language="1044" xmlns="http://schemas.microsoft.com/wix/2006/localization">
6 <String Id="Caption">[WixBundleName] Installasjonsprogram</String>
7 <String Id="Title">Microsoft .NET Framework kreves for [WixBundleName]-installasjon</String>
8 <String Id="ConfirmCancelMessage">Er du sikker på at du vil avbryte?</String>
9 <String Id="HelpHeader">Installasjonshjelp</String>
10 <String Id="HelpText">/passive | /quiet - viser minimalt brukergrensesnitt uten ledetekster, eller
11 ikke noe brukergrensesnitt og ingen ledetekster. Som standard vises
12 brukergrensesnitt og alle ledetekster.
13
14/norestart - undertrykker alle forsøk på omstart. Som standard spør
15 brukergrensesnittet før omstart.
16/log log.txt - skriver logg til en bestemt fil. Som standard opprettes en
17 loggfil i %TEMP%.</String>
18 <String Id="HelpCloseButton">&amp;Lukk</String>
19 <String Id="InstallLicenseTerms">Klikk Godta og installer for å godta&lt;a href="#"&gt;lisensvilkårene&lt;/a&gt; for Microsoft .NET Framework.</String>
20 <String Id="InstallAcceptAndInstallButton">&amp;Godta og installer</String>
21 <String Id="InstallDeclineButton">&amp;Avslå</String>
22 <String Id="ProgressHeader">Fremdrift for installasjon</String>
23 <String Id="ProgressLabel">Behandler:</String>
24 <String Id="ProgressCancelButton">&amp;Avbryt</String>
25 <String Id="FailureHeader">Installasjon mislyktes</String>
26 <String Id="FailureLogLinkText">Ett eller flere problemer var årsak til at installasjonen mislyktes. Løs problemene, og installer på nytt. Du finner flere opplysninger i &lt;a href="#"&gt;loggfilen&lt;/a&gt;.</String>
27 <String Id="FailureRestartText">Du må starte datamaskinen på nytt for å fullføre tilbakerullingen av programvaren.</String>
28 <String Id="FailureRestartButton">&amp;Start på nytt</String>
29 <String Id="FailureCloseButton">&amp;Lukk</String>
30</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1045/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1045/mbapreq.wxl
new file mode 100644
index 00000000..7aca87c2
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/1045/mbapreq.wxl
@@ -0,0 +1,30 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<WixLocalization Culture="pl-pl" Language="1045" xmlns="http://schemas.microsoft.com/wix/2006/localization">
6 <String Id="Caption">Instalator programu [WixBundleName]</String>
7 <String Id="Title">Do zainstalowania programu [WixBundleName] jest wymagany program Microsoft .NET Framework</String>
8 <String Id="ConfirmCancelMessage">Czy na pewno chcesz anulować?</String>
9 <String Id="HelpHeader">Pomoc instalatora</String>
10 <String Id="HelpText">/passive | /quiet - wyświetla minimalny interfejs użytkownika bez monitów
11 lub nie wyświetla interfejsu użytkownika ani monitów. Domyślnie jest
12 wyświetlany interfejs użytkownika i wszystkie monity.
13
14/norestart - pomija wszelkie próby ponownego uruchomienia. Domyślnie
15 interfejs użytkownika będzie wyświetlał monit przed ponownym uruchomieniem.
16/log log.txt - zapisuje wpisy dziennika do określonego pliku.
17 Domyślnie plik dziennika jest tworzony w folderze %TEMP%.</String>
18 <String Id="HelpCloseButton">&amp;Zamknij</String>
19 <String Id="InstallLicenseTerms">Kliknij przycisk Zaakceptuj i zainstaluj, aby zaakceptować &lt;a href="#"&gt;warunki licencji&lt;/a&gt; programu Microsoft .NET Framework.</String>
20 <String Id="InstallAcceptAndInstallButton">&amp;Zaakceptuj i zainstaluj</String>
21 <String Id="InstallDeclineButton">&amp;Odrzuć</String>
22 <String Id="ProgressHeader">Postęp instalacji</String>
23 <String Id="ProgressLabel">Trwa przetwarzanie:</String>
24 <String Id="ProgressCancelButton">&amp;Anuluj</String>
25 <String Id="FailureHeader">Instalacja nie powiodła się</String>
26 <String Id="FailureLogLinkText">Co najmniej jeden problem spowodował niepowodzenie instalacji. Usuń problemy, a następnie ponów próbę instalacji. Aby uzyskać więcej informacji można znaleźć w &lt;a href="#"&gt;pliku dziennika&lt;/a&gt;.</String>
27 <String Id="FailureRestartText">Aby zakończyć wycofywanie oprogramowania, musisz ponownie uruchomić komputer.</String>
28 <String Id="FailureRestartButton">&amp;Uruchom ponownie</String>
29 <String Id="FailureCloseButton">&amp;Zamknij</String>
30</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1046/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1046/mbapreq.wxl
new file mode 100644
index 00000000..be185502
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/1046/mbapreq.wxl
@@ -0,0 +1,29 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<WixLocalization Culture="pt-br" Language="1046" xmlns="http://schemas.microsoft.com/wix/2006/localization">
6 <String Id="Caption">[WixBundleName] Instalação</String>
7 <String Id="Title">Microsoft .NET Framework é necessário para instalação do [WixBundleName]</String>
8 <String Id="ConfirmCancelMessage">Tem certeza de que deseja cancelar?</String>
9 <String Id="HelpHeader">Ajuda da Instalação</String>
10 <String Id="HelpText">/passive | /quiet - exibe UI mínima sem avisos ou exibe sem UI e
11 sem avisos. Por padrão a UI e todos avisos são exibidos.
12
13/norestart - suprime qualquer tentativa de reinicialização. Por padrão a UI
14 irá solicitar antes de reiniciar.
15/log log.txt - logs para um arquivo específico. Por padrão um arquivo de log é
16 criado em %TEMP%.</String>
17 <String Id="HelpCloseButton">&amp;Fechar</String>
18 <String Id="InstallLicenseTerms">Clique o botão "Aceitar e Instalar" para aceitar os termos de licença do Microsoft .NET Framework &lt;a href="#"&gt;&lt;/a&gt;.</String>
19 <String Id="InstallAcceptAndInstallButton">&amp;Aceitar e Instalar</String>
20 <String Id="InstallDeclineButton">&amp;Recusar</String>
21 <String Id="ProgressHeader">Progresso da Instalação</String>
22 <String Id="ProgressLabel">Processando:</String>
23 <String Id="ProgressCancelButton">&amp;Cancelar</String>
24 <String Id="FailureHeader">Falha na Instalação</String>
25 <String Id="FailureLogLinkText">Um ou mais problemas causaram falha na instalação. Corrija os problemas e tente a instalação novamente. Para mais informações consulte o &lt;a href="#"&gt;arquivo de log&lt;/a&gt;.</String>
26 <String Id="FailureRestartText">Você deve reiniciar o computador para completar a reversão do software. </String>
27 <String Id="FailureRestartButton">&amp;Reiniciar</String>
28 <String Id="FailureCloseButton">&amp;Fechar</String>
29</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1049/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1049/mbapreq.wxl
new file mode 100644
index 00000000..a1aec7ed
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/1049/mbapreq.wxl
@@ -0,0 +1,29 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<WixLocalization Culture="ru-ru" Language="1049" xmlns="http://schemas.microsoft.com/wix/2006/localization">
6 <String Id="Caption">Установка [WixBundleName]</String>
7 <String Id="Title">Для установки [WixBundleName] требуется Microsoft .NET Framework</String>
8 <String Id="ConfirmCancelMessage">Вы действительно хотите отменить операцию?</String>
9 <String Id="HelpHeader">Справка по установке</String>
10 <String Id="HelpText">/passive | /quiet - отображение минимального ИП без запросов или работа без ИП
11 и беззапросов. По умолчанию отображаются ИП и все запросы.
12
13/norestart - отключение всех попыток перезагрузки. По умолчанию в ИП перед
14 перезагрузкой отображается запрос.
15/log log.txt - запись журнала в указанный файл. По умолчанию файл журнала
16 создается в папке %TEMP%.</String>
17 <String Id="HelpCloseButton">&amp;Закрыть</String>
18 <String Id="InstallLicenseTerms">Нажмите кнопку "Принять и установить", чтобы принять &lt;a href="#"&gt;условия лицензии&lt;/a&gt; Microsoft .NET Framework.</String>
19 <String Id="InstallAcceptAndInstallButton">&amp;Принять и установить</String>
20 <String Id="InstallDeclineButton">&amp;Отклонить</String>
21 <String Id="ProgressHeader">Выполнение установки</String>
22 <String Id="ProgressLabel">Обработка:</String>
23 <String Id="ProgressCancelButton">&amp;Отмена</String>
24 <String Id="FailureHeader">Сбой установки</String>
25 <String Id="FailureLogLinkText">Не удалось выполнить установку из-за одной или нескольких проблем. Устраните эти проблемы, а затем снова запустите программу установки. Дополнительные сведения см. в &lt;a href="#"&gt;файле журнала&lt;/a&gt;.</String>
26 <String Id="FailureRestartText">Необходимо перезагрузить компьютер, чтобы завершить откат программного обеспечения.</String>
27 <String Id="FailureRestartButton">&amp;Перезагрузить</String>
28 <String Id="FailureCloseButton">&amp;Закрыть</String>
29</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1051/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1051/mbapreq.wxl
new file mode 100644
index 00000000..9f0b4711
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/1051/mbapreq.wxl
@@ -0,0 +1,30 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<WixLocalization Culture="sk-sk" Language="1051" xmlns="http://schemas.microsoft.com/wix/2006/localization">
6 <String Id="Caption">[WixBundleName] – inštalácia</String>
7 <String Id="Title">Na inštaláciu aplikácie [WixBundleName] sa vyžaduje súčasť Microsoft .NET Framework</String>
8 <String Id="ConfirmCancelMessage">Naozaj chcete zrušiť operáciu?</String>
9 <String Id="HelpHeader">Pomocník pre inštaláciu</String>
10 <String Id="HelpText">/passive | /quiet – zobrazí minimálne používateľské rozhranie bez výziev alebo
11 nezobrazí žiadne používateľské rozhranie ani výzvy. Predvolene sa
12 zobrazuje používateľské rozhranie aj všetky výzvy.
13
14/norestart – zruší všetky pokusy o reštart. Používateľské rozhranie
15 predvolene zobrazí pred reštartom výzvu.
16/log log.txt – urobí záznam do určeného súboru. Súbor denníka sa predvolene
17 vytvorí v priečinku %TEMP%.</String>
18 <String Id="HelpCloseButton">&amp;Zavrieť</String>
19 <String Id="InstallLicenseTerms">Kliknutím na tlačidlo Súhlasiť a inštalovať vyjadrite svoj súhlas s &lt;a href="#"&gt;licenčnými podmienkami&lt;/a&gt; súčasti Microsoft .NET Framework.</String>
20 <String Id="InstallAcceptAndInstallButton">&amp;Súhlasiť a inštalovať</String>
21 <String Id="InstallDeclineButton">&amp;Odmietnuť</String>
22 <String Id="ProgressHeader">Priebeh inštalácie</String>
23 <String Id="ProgressLabel">Spracúva sa:</String>
24 <String Id="ProgressCancelButton">&amp;Zrušiť</String>
25 <String Id="FailureHeader">Inštalácia zlyhala</String>
26 <String Id="FailureLogLinkText">Inštalácia zlyhala pre jednu alebo viac príčin. Odstráňte problémy a skúste znova spustiť inštaláciu. Ďalšie informácie nájdete v &lt;a href="#"&gt;súbore denníka&lt;/a&gt;.</String>
27 <String Id="FailureRestartText">Dokončenie všetkých zmien softvéru vyžaduje reštart počítača.</String>
28 <String Id="FailureRestartButton">&amp;Reštartovať</String>
29 <String Id="FailureCloseButton">&amp;Zavrieť</String>
30</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1053/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1053/mbapreq.wxl
new file mode 100644
index 00000000..72961409
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/1053/mbapreq.wxl
@@ -0,0 +1,30 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<WixLocalization Culture="sv-se" Language="1053" xmlns="http://schemas.microsoft.com/wix/2006/localization">
6 <String Id="Caption">[WixBundleName]-installation</String>
7 <String Id="Title">Microsoft .NET Framework krävs för installation av [WixBundleName]</String>
8 <String Id="ConfirmCancelMessage">Vill du avbryta?</String>
9 <String Id="HelpHeader">Installationshjälp</String>
10 <String Id="HelpText">/passive | /quiet - visar ett minimalt användargränssnitt utan prompter,
11 alternativt inget användargränssnitt och inga prompter. Som standard visas
12 användargränssnitt och samtliga prompter.
13
14/norestart - hejdar omstart. Som standard visar användargränssnittet en
15 prompt före omstart.
16/log log.txt - skapar logg till en specifik fil. Som standard skapas loggfilen
17 i %TEMP%.</String>
18 <String Id="HelpCloseButton">&amp;Stäng</String>
19 <String Id="InstallLicenseTerms">Klicka på knappen "Godkänn och installera" för att godkänna &lt;a href="#"&gt;licensvillkoren&lt;/a&gt; för Microsoft .NET Framework.</String>
20 <String Id="InstallAcceptAndInstallButton">&amp;Godkänn och installera</String>
21 <String Id="InstallDeclineButton">&amp;Avbryt</String>
22 <String Id="ProgressHeader">Installationsförlopp</String>
23 <String Id="ProgressLabel">Bearbetar:</String>
24 <String Id="ProgressCancelButton">&amp;Avbryt</String>
25 <String Id="FailureHeader">Installationen misslyckades</String>
26 <String Id="FailureLogLinkText">Installationen misslyckades på grund av ett eller flera problem. Åtgärda problemen och försök igen. Se &lt;a href="#"&gt;loggfilen&lt;/a&gt; för mer information.</String>
27 <String Id="FailureRestartText">Starta om datorn för att återställa programmet.</String>
28 <String Id="FailureRestartButton">&amp;Starta om</String>
29 <String Id="FailureCloseButton">&amp;Stäng</String>
30</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1055/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1055/mbapreq.wxl
new file mode 100644
index 00000000..ee52da98
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/1055/mbapreq.wxl
@@ -0,0 +1,30 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<WixLocalization Culture="tr-tr" Language="1055" xmlns="http://schemas.microsoft.com/wix/2006/localization">
6 <String Id="Caption">[WixBundleName] Kurulumu</String>
7 <String Id="Title">[WixBundleName] kurulumu için Microsoft .NET Framework gerekir</String>
8 <String Id="ConfirmCancelMessage">İptal etmek istediğinizden emin misiniz?</String>
9 <String Id="HelpHeader">Kurulum Yardımı</String>
10 <String Id="HelpText">/passive | /quiet - komut istemi olmayan olabildiğince küçük bir UI
11 görüntüler veya komut istemi ve UI görüntülemez. Varsayılan olarak UI
12 ve tüm komut istemleri görüntülenir.
13
14/norestart - yeniden başlatma denemelerini engeller. Varsayılan
15 olarak UI yeniden başlatmadan önce komut isteyecektir.
16/log log.txt - belirli bir dosyayı günlük dosyası olarak kullanır.
17 Varsayılan olarak %TEMP% konumunda bir günlük dosyası oluşturulur.</String>
18 <String Id="HelpCloseButton">&amp;Kapat</String>
19 <String Id="InstallLicenseTerms">Microsoft .NET Framework &lt;a href="#"&gt;lisans şartlarını&lt;/a&gt; kabul etmek için "Kabul Et ve Yükle" düğmesini tıklatın.</String>
20 <String Id="InstallAcceptAndInstallButton">&amp;Kabul Et ve Yükle</String>
21 <String Id="InstallDeclineButton">&amp;Reddet</String>
22 <String Id="ProgressHeader">Kurulum İlerleme Durumu</String>
23 <String Id="ProgressLabel">İşleniyor:</String>
24 <String Id="ProgressCancelButton">&amp;İptal</String>
25 <String Id="FailureHeader">Kurulum Başarısız</String>
26 <String Id="FailureLogLinkText">Bir veya daha fazla sorun kurulumun başarısız olmasına neden oldu. Lütfen sorunları çözün ve kurulumu yeniden deneyin. Daha fazla bilgi için &lt;a href="#"&gt;günlük dosyasına&lt;/a&gt; bakın.</String>
27 <String Id="FailureRestartText">Yazılım geri alma işlemini tamamlamak için bilgisayarınızı yeniden başlatmanız gerekir.</String>
28 <String Id="FailureRestartButton">&amp;Yeniden Başlat</String>
29 <String Id="FailureCloseButton">&amp;Kapat</String>
30</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/1060/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/1060/mbapreq.wxl
new file mode 100644
index 00000000..f3b4bfe5
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/1060/mbapreq.wxl
@@ -0,0 +1,30 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<WixLocalization Culture="sl-si" Language="1060" xmlns="http://schemas.microsoft.com/wix/2006/localization">
6 <String Id="Caption">[WixBundleName] Namestitev</String>
7 <String Id="Title">Microsoft .NET Framework, potreben za namestitev paketa [WixBundleName]</String>
8 <String Id="ConfirmCancelMessage">Ali ste prepričani, da želite preklicati?</String>
9 <String Id="HelpHeader">Pomoč za namestitev</String>
10 <String Id="HelpText">/passive | /quiet - prikaže minimalni uporabniški vmesnik brez pozivov ali ne prikaže
11 uporabniškega vmesnika in pozivov. Privzeto so prikazani uporabniški vmesnik in
12 vsi pozivi.
13
14/norestart - skrije vse možnosti za vnovicni zagon. Privzeto uporabniški vmesnik
15 prikaže poziv pred ponovnim zagonom.
16/log log.txt - beleži vnose v dnevnik v doloceno datoteko. Privzeto je datoteko
17 ustvarjena v mapi %TEMP%.</String>
18 <String Id="HelpCloseButton">&amp;Zapri</String>
19 <String Id="InstallLicenseTerms">Kliknite »Sprejmi in namesti« in sprejmite &lt;a href="#"&gt;licenčne pogoje&lt;/a&gt; za Microsoft .NET Framework.</String>
20 <String Id="InstallAcceptAndInstallButton">&amp;Sprejmi in namesti</String>
21 <String Id="InstallDeclineButton">&amp;Zavrni</String>
22 <String Id="ProgressHeader">Potek namestitve</String>
23 <String Id="ProgressLabel">Obdelovanje:</String>
24 <String Id="ProgressCancelButton">&amp;Prekliči</String>
25 <String Id="FailureHeader">Namestitev ni uspela</String>
26 <String Id="FailureLogLinkText">Namestitev ni uspela zaradi ene ali več težav. Odpravite težave in ponovno zaženite namestitev. Za več informacij glejte &lt;a href="#"&gt;dnevniško datoteko&lt;/a&gt;.</String>
27 <String Id="FailureRestartText">Za povrnitev prejšnjega stanja programske opreme morate ponovno zagnati računalnik.</String>
28 <String Id="FailureRestartButton">&amp;Ponovni zagon</String>
29 <String Id="FailureCloseButton">&amp;Zapri</String>
30</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/2052/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/2052/mbapreq.wxl
new file mode 100644
index 00000000..63cdb418
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/2052/mbapreq.wxl
@@ -0,0 +1,27 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<WixLocalization Culture="zh-ch" Language="2052" xmlns="http://schemas.microsoft.com/wix/2006/localization">
6 <String Id="Caption">[WixBundleName] 安装</String>
7 <String Id="Title">[WixBundleName] 安装需要 Microsoft .NET Framework</String>
8 <String Id="ConfirmCancelMessage">是否确实要取消?</String>
9 <String Id="HelpHeader">安装程序帮助</String>
10 <String Id="HelpText">/passive | /quiet - 显示最小的 UI 且无提示,或者不显示 UI 且
11 无提示。默认情况下显示 UI 和所有提示。
12
13/norestart - 隐藏任何重启提示。默认情况下 UI 会在重启前提示。
14/log log.txt - 记录到特定文件。默认情况下在 %TEMP% 中创建日志文件。</String>
15 <String Id="HelpCloseButton">关闭(&amp;C)</String>
16 <String Id="InstallLicenseTerms">单击“接受并安装”按钮以接受 Microsoft .NET Framework &lt;a href="#"&gt;许可证条款&lt;/a&gt;。</String>
17 <String Id="InstallAcceptAndInstallButton">接受并安装(&amp;A)</String>
18 <String Id="InstallDeclineButton">拒绝(&amp;D)</String>
19 <String Id="ProgressHeader">安装进度</String>
20 <String Id="ProgressLabel">正在处理:</String>
21 <String Id="ProgressCancelButton">取消(&amp;C)</String>
22 <String Id="FailureHeader">安装失败</String>
23 <String Id="FailureLogLinkText">一个或多个问题导致安装失败。请解决问题,然后重新尝试安装。有关详情,请查看&lt;a href="#"&gt;日志文件&lt;/a&gt;。</String>
24 <String Id="FailureRestartText">必须重启计算机才能完成软件的回滚。</String>
25 <String Id="FailureRestartButton">重启(&amp;R)</String>
26 <String Id="FailureCloseButton">关闭(&amp;C)</String>
27</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/2070/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/2070/mbapreq.wxl
new file mode 100644
index 00000000..6a49ca31
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/2070/mbapreq.wxl
@@ -0,0 +1,29 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<WixLocalization Culture="pt-pt" Language="2070" xmlns="http://schemas.microsoft.com/wix/2006/localization">
6 <String Id="Caption">Configuração do [WixBundleName]</String>
7 <String Id="Title">O Microsoft .NET Framework é necessário para a configuração do [WixBundleName]</String>
8 <String Id="ConfirmCancelMessage">Tem a certeza de que pretende cancelar?</String>
9 <String Id="HelpHeader">Ajuda da Configuração</String>
10 <String Id="HelpText">/passive | /quiet - apresenta IU mínima sem mensagens ou não apresenta IU nem
11 mensagens. Por predefinição, são apresentadas a IU e todas as mensagens.
12
13/norestart - suprimir qualquer tentativa de reinício. Por predefinição, a IU
14 avisará antes de reiniciar.
15/log log.txt - regista num ficheiro específico. Por predefinição, é criado um
16 ficheiro de registo em %TEMP%.</String>
17 <String Id="HelpCloseButton">&amp;Fechar</String>
18 <String Id="InstallLicenseTerms">Clique no botão "Aceitar e Instalar" para aceitar os &lt;a href="#"&gt;termos de licenciamento&lt;/a&gt; do Microsoft .NET Framework.</String>
19 <String Id="InstallAcceptAndInstallButton">&amp;Aceitar e Instalar</String>
20 <String Id="InstallDeclineButton">&amp;Recusar</String>
21 <String Id="ProgressHeader">Progresso da Configuração</String>
22 <String Id="ProgressLabel">A processar:</String>
23 <String Id="ProgressCancelButton">&amp;Cancelar</String>
24 <String Id="FailureHeader">Falha da Configuração</String>
25 <String Id="FailureLogLinkText">Um ou mais problemas provocaram a falha da configuração. Corrija os problemas e repita a configuração. Para mais informações, consulte o &lt;a href="#"&gt;ficheiro de registo&lt;/a&gt;.</String>
26 <String Id="FailureRestartText">Tem de reiniciar o computador para concluir a reversão do software.</String>
27 <String Id="FailureRestartButton">&amp;Reiniciar</String>
28 <String Id="FailureCloseButton">&amp;Fechar</String>
29</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/3082/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/3082/mbapreq.wxl
new file mode 100644
index 00000000..0290624c
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/3082/mbapreq.wxl
@@ -0,0 +1,31 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<WixLocalization Culture="es-es" Language="3082" xmlns="http://schemas.microsoft.com/wix/2006/localization">
6 <String Id="Caption">Instalación de [WixBundleName]</String>
7 <String Id="Title">La instalación de [WixBundleName] requiere Microsoft .NET Framework</String>
8 <String Id="ConfirmCancelMessage">¿Está seguro de que desea cancelar?</String>
9 <String Id="HelpHeader">Ayuda del programa de instalación</String>
10 <String Id="HelpText">/passive | /quiet - muestra una interfaz de usuario mínima y no realiza
11 preguntas, o bien no muestra interfaz de usuario y no realiza preguntas.
12 De manera predeterminada se muestra la interfaz de usuario completa y se
13 realizan todas las preguntas necesarias.
14
15/norestart - suprime cualquier intento de reinicio. De manera predeterminada,
16 la interfaz de usuario preguntará si se desea reiniciar.
17/log log.txt - registra los datos de instalación en un archivo específico.
18 De manera predeterminada se crea un archivo de registro en %TEMP%.</String>
19 <String Id="HelpCloseButton">&amp;Cerrar</String>
20 <String Id="InstallLicenseTerms">Haga clic en el botón "Aceptar e instalar" para aceptar los &lt;a href="#"&gt;términos de licencia&lt;/a&gt; de Microsoft .NET Framework.</String>
21 <String Id="InstallAcceptAndInstallButton">&amp;Aceptar e instalar</String>
22 <String Id="InstallDeclineButton">&amp;Rechazar</String>
23 <String Id="ProgressHeader">Progreso de la instalación</String>
24 <String Id="ProgressLabel">Procesando:</String>
25 <String Id="ProgressCancelButton">&amp;Cancelar</String>
26 <String Id="FailureHeader">Error de la instalación</String>
27 <String Id="FailureLogLinkText">No se pudo completar la instalación a causa de uno o varios problemas. Corrija los problemas y vuelva a intentar la instalación. Para más información, vea el &lt;a href="#"&gt;archivo de registro&lt;/a&gt;.</String>
28 <String Id="FailureRestartText">Debe reiniciar el equipo para completar la reversión del software.</String>
29 <String Id="FailureRestartButton">&amp;Reiniciar</String>
30 <String Id="FailureCloseButton">&amp;Cerrar</String>
31</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/HyperlinkLargeTheme.xml b/src/ext/Bal/wixstdba/Resources/HyperlinkLargeTheme.xml
new file mode 100644
index 00000000..39a38ee0
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/HyperlinkLargeTheme.xml
@@ -0,0 +1,109 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<Theme xmlns="http://wixtoolset.org/schemas/v4/thmutil">
6 <Font Id="0" Height="-12" Weight="500" Foreground="windowtext" Background="window">Segoe UI</Font>
7 <Font Id="1" Height="-24" Weight="500" Foreground="windowtext">Segoe UI</Font>
8 <Font Id="2" Height="-22" Weight="500" Foreground="graytext">Segoe UI</Font>
9 <Font Id="3" Height="-12" Weight="500" Foreground="windowtext" Background="window">Segoe UI</Font>
10
11 <Window Width="500" Height="390" HexStyle="100a0000" FontId="0" Caption="#(loc.Caption)">
12 <ImageControl X="11" Y="11" Width="64" Height="64" ImageFile="logo.png" Visible="yes"/>
13 <Label X="80" Y="11" Width="-11" Height="64" FontId="1" Visible="yes" DisablePrefix="yes">#(loc.Title)</Label>
14
15 <Page Name="Help">
16 <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.HelpHeader)</Label>
17 <Label X="11" Y="112" Width="-11" Height="-35" FontId="3" DisablePrefix="yes">#(loc.HelpText)</Label>
18 <Button Name="HelpCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
19 <Text>#(loc.HelpCloseButton)</Text>
20 <CloseWindowAction />
21 </Button>
22 </Page>
23 <Page Name="Install">
24 <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.InstallHeader)</Label>
25 <Label X="11" Y="121" Width="-11" Height="-129" FontId="3" DisablePrefix="yes">#(loc.InstallMessage)</Label>
26 <Hypertext Name="EulaHyperlink" X="11" Y="-107" Width="-11" Height="17" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.InstallLicenseLinkText)</Hypertext>
27 <Label Name="InstallVersion" X="11" Y="-73" Width="246" Height="17" FontId="3" DisablePrefix="yes" VisibleCondition="WixStdBAShowVersion">#(loc.InstallVersion)</Label>
28 <Checkbox Name="EulaAcceptCheckbox" X="-11" Y="-41" Width="260" Height="17" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.InstallAcceptCheckbox)</Checkbox>
29 <Button Name="OptionsButton" X="-171" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" VisibleCondition="NOT WixStdBASuppressOptionsUI">
30 <Text>#(loc.InstallOptionsButton)</Text>
31 <ChangePageAction Page="Options" />
32 </Button>
33 <Button Name="InstallButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.InstallInstallButton)</Button>
34 <Button Name="InstallCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
35 <Text>#(loc.InstallCancelButton)</Text>
36 <CloseWindowAction />
37 </Button>
38 </Page>
39 <Page Name="Options">
40 <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.OptionsHeader)</Label>
41 <Label X="11" Y="121" Width="-11" Height="17" FontId="3" DisablePrefix="yes">#(loc.OptionsLocationLabel)</Label>
42 <Editbox Name="InstallFolder" X="11" Y="143" Width="-91" Height="21" TabStop="yes" FontId="3" FileSystemAutoComplete="yes" />
43 <Button Name="BrowseButton" X="-11" Y="142" Width="75" Height="23" TabStop="yes" FontId="0">
44 <Text>#(loc.OptionsBrowseButton)</Text>
45 <BrowseDirectoryAction VariableName="InstallFolder" />
46 </Button>
47 <Button Name="OptionsOkButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
48 <Text>#(loc.OptionsOkButton)</Text>
49 <ChangePageAction Page="Install" />
50 </Button>
51 <Button Name="OptionsCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
52 <Text>#(loc.OptionsCancelButton)</Text>
53 <ChangePageAction Page="Install" Cancel="yes" />
54 </Button>
55 </Page>
56 <Page Name="Progress">
57 <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.ProgressHeader)</Label>
58 <Label X="11" Y="121" Width="70" Height="17" FontId="3" DisablePrefix="yes">#(loc.ProgressLabel)</Label>
59 <Label Name="OverallProgressPackageText" X="85" Y="121" Width="-11" Height="17" FontId="3" DisablePrefix="yes">#(loc.OverallProgressPackageText)</Label>
60 <Progressbar Name="OverallCalculatedProgressbar" X="11" Y="143" Width="-11" Height="15" />
61 <Button Name="ProgressCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.ProgressCancelButton)</Button>
62 </Page>
63 <Page Name="Modify">
64 <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.ModifyHeader)</Label>
65 <Button Name="RepairButton" X="-171" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.ModifyRepairButton)</Button>
66 <Button Name="UninstallButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.ModifyUninstallButton)</Button>
67 <Button Name="ModifyCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
68 <Text>#(loc.ModifyCancelButton)</Text>
69 <CloseWindowAction />
70 </Button>
71 </Page>
72 <Page Name="Success">
73 <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">
74 <Text>#(loc.SuccessHeader)</Text>
75 <Text Condition="WixBundleAction = 2">#(loc.SuccessLayoutHeader)</Text>
76 <Text Condition="WixBundleAction = 3">#(loc.SuccessUninstallHeader)</Text>
77 <Text Condition="WixBundleAction = 5">#(loc.SuccessInstallHeader)</Text>
78 <Text Condition="WixBundleAction = 7">#(loc.SuccessRepairHeader)</Text>
79 </Label>
80 <Button Name="LaunchButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.SuccessLaunchButton)</Button>
81 <Label X="-11" Y="-51" Width="400" Height="34" FontId="3" DisablePrefix="yes" VisibleCondition="WixStdBARestartRequired">
82 <Text>#(loc.SuccessRestartText)</Text>
83 <Text Condition="WixBundleAction = 3">#(loc.SuccessUninstallRestartText)</Text>
84 </Label>
85 <Button Name="SuccessRestartButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.SuccessRestartButton)</Button>
86 <Button Name="SuccessCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
87 <Text>#(loc.SuccessCloseButton)</Text>
88 <CloseWindowAction />
89 </Button>
90 </Page>
91 <Page Name="Failure">
92 <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">
93 <Text>#(loc.FailureHeader)</Text>
94 <Text Condition="WixBundleAction = 2">#(loc.FailureLayoutHeader)</Text>
95 <Text Condition="WixBundleAction = 3">#(loc.FailureUninstallHeader)</Text>
96 <Text Condition="WixBundleAction = 5">#(loc.FailureInstallHeader)</Text>
97 <Text Condition="WixBundleAction = 7">#(loc.FailureRepairHeader)</Text>
98 </Label>
99 <Hypertext Name="FailureLogFileLink" X="11" Y="121" Width="-11" Height="42" FontId="3" TabStop="yes" HideWhenDisabled="yes">#(loc.FailureHyperlinkLogText)</Hypertext>
100 <Hypertext Name="FailureMessageText" X="22" Y="163" Width="-11" Height="51" FontId="3" TabStop="yes" HideWhenDisabled="yes" />
101 <Label X="-11" Y="-51" Width="400" Height="34" FontId="3" DisablePrefix="yes" VisibleCondition="WixStdBARestartRequired">#(loc.FailureRestartText)</Label>
102 <Button Name="FailureRestartButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.FailureRestartButton)</Button>
103 <Button Name="FailureCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
104 <Text>#(loc.FailureCloseButton)</Text>
105 <CloseWindowAction />
106 </Button>
107 </Page>
108 </Window>
109</Theme>
diff --git a/src/ext/Bal/wixstdba/Resources/HyperlinkSidebarTheme.xml b/src/ext/Bal/wixstdba/Resources/HyperlinkSidebarTheme.xml
new file mode 100644
index 00000000..1dff9d7e
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/HyperlinkSidebarTheme.xml
@@ -0,0 +1,120 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<Theme xmlns="http://wixtoolset.org/schemas/v4/thmutil">
6 <Font Id="0" Height="-12" Weight="500" Foreground="windowtext" Background="window">Segoe UI</Font>
7 <Font Id="1" Height="-24" Weight="500" Foreground="windowtext">Segoe UI</Font>
8 <Font Id="2" Height="-22" Weight="500" Foreground="graytext">Segoe UI</Font>
9 <Font Id="3" Height="-12" Weight="500" Foreground="windowtext" Background="window">Segoe UI</Font>
10
11 <Window Width="600" Height="450" HexStyle="100a0000" FontId="0" Caption="#(loc.Caption)">
12 <Page Name="Help">
13 <Label X="80" Y="11" Width="-11" Height="32" FontId="1" DisablePrefix="yes">#(loc.Title)</Label>
14 <ImageControl X="11" Y="11" Width="64" Height="64" ImageFile="logo.png"/>
15 <Label X="11" Y="80" Width="-11" Height="32" FontId="2" DisablePrefix="yes">#(loc.HelpHeader)</Label>
16 <Label X="11" Y="121" Width="-11" Height="-35" FontId="3" DisablePrefix="yes">#(loc.HelpText)</Label>
17 <Button Name="HelpCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
18 <Text>#(loc.HelpCloseButton)</Text>
19 <CloseWindowAction />
20 </Button>
21 </Page>
22 <Page Name="Install">
23 <Label X="185" Y="11" Width="-11" Height="32" FontId="1" DisablePrefix="yes">#(loc.Title)</Label>
24 <ImageControl X="11" Y="11" Width="165" Height="400" ImageFile="logoside.png"/>
25 <Label X="185" Y="50" Width="-11" Height="32" FontId="2" DisablePrefix="yes">#(loc.InstallHeader)</Label>
26 <Label X="185" Y="91" Width="-11" Height="64" FontId="3" DisablePrefix="yes">#(loc.InstallMessage)</Label>
27 <Hypertext Name="EulaHyperlink" X="185" Y="-111" Width="-11" Height="17" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.InstallLicenseLinkText)</Hypertext>
28 <Label Name="InstallVersion" X="185" Y="-81" Width="-11" Height="17" FontId="3" DisablePrefix="yes" VisibleCondition="WixStdBAShowVersion">#(loc.InstallVersion)</Label>
29 <Checkbox Name="EulaAcceptCheckbox" X="185" Y="-51" Width="-11" Height="17" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.InstallAcceptCheckbox)</Checkbox>
30 <Button Name="OptionsButton" X="-171" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" VisibleCondition="NOT WixStdBASuppressOptionsUI">
31 <Text>#(loc.InstallOptionsButton)</Text>
32 <ChangePageAction Page="Options" />
33 </Button>
34 <Button Name="InstallButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.InstallInstallButton)</Button>
35 <Button Name="InstallCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
36 <Text>#(loc.InstallCancelButton)</Text>
37 <CloseWindowAction />
38 </Button>
39 </Page>
40 <Page Name="Options">
41 <Label X="80" Y="11" Width="-11" Height="32" FontId="1" DisablePrefix="yes">#(loc.Title)</Label>
42 <ImageControl X="11" Y="11" Width="64" Height="64" ImageFile="logo.png"/>
43 <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.OptionsHeader)</Label>
44 <Label X="11" Y="121" Width="-11" Height="17" FontId="3">#(loc.OptionsLocationLabel)</Label>
45 <Editbox Name="InstallFolder" X="11" Y="143" Width="-91" Height="21" TabStop="yes" FontId="3" FileSystemAutoComplete="yes" />
46 <Button Name="BrowseButton" X="-11" Y="142" Width="75" Height="23" TabStop="yes" FontId="3">
47 <Text>#(loc.OptionsBrowseButton)</Text>
48 <BrowseDirectoryAction VariableName="InstallFolder" />
49 </Button>
50 <Button Name="OptionsOkButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
51 <Text>#(loc.OptionsOkButton)</Text>
52 <ChangePageAction Page="Install" />
53 </Button>
54 <Button Name="OptionsCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
55 <Text>#(loc.OptionsCancelButton)</Text>
56 <ChangePageAction Page="Install" Cancel="yes" />
57 </Button>
58 </Page>
59 <Page Name="Progress">
60 <Label X="80" Y="11" Width="-11" Height="32" FontId="1" DisablePrefix="yes">#(loc.Title)</Label>
61 <ImageControl X="11" Y="11" Width="64" Height="64" ImageFile="logo.png"/>
62 <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.ProgressHeader)</Label>
63 <Label X="11" Y="141" Width="70" Height="17" FontId="3" DisablePrefix="yes">#(loc.ProgressLabel)</Label>
64 <Label Name="OverallProgressPackageText" X="85" Y="141" Width="-11" Height="17" FontId="3" DisablePrefix="yes">#(loc.OverallProgressPackageText)</Label>
65 <Progressbar Name="OverallCalculatedProgressbar" X="11" Y="163" Width="-11" Height="20" />
66 <Button Name="ProgressCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.ProgressCancelButton)</Button>
67 </Page>
68 <Page Name="Modify">
69 <Label X="185" Y="11" Width="-11" Height="32" FontId="1" DisablePrefix="yes">#(loc.Title)</Label>
70 <ImageControl X="11" Y="11" Width="165" Height="400" ImageFile="logoside.png"/>
71 <Label X="185" Y="50" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.ModifyHeader)</Label>
72 <Button Name="RepairButton" X="-171" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.ModifyRepairButton)</Button>
73 <Button Name="UninstallButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.ModifyUninstallButton)</Button>
74 <Button Name="ModifyCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
75 <Text>#(loc.ModifyCancelButton)</Text>
76 <CloseWindowAction />
77 </Button>
78 </Page>
79 <Page Name="Success">
80 <Label X="185" Y="11" Width="-11" Height="32" FontId="1" DisablePrefix="yes">#(loc.Title)</Label>
81 <ImageControl X="11" Y="11" Width="165" Height="400" ImageFile="logoside.png"/>
82 <Label X="185" Y="50" Width="-11" Height="30" FontId="2" DisablePrefix="yes">
83 <Text>#(loc.SuccessHeader)</Text>
84 <Text Condition="WixBundleAction = 2">#(loc.SuccessLayoutHeader)</Text>
85 <Text Condition="WixBundleAction = 3">#(loc.SuccessUninstallHeader)</Text>
86 <Text Condition="WixBundleAction = 5">#(loc.SuccessInstallHeader)</Text>
87 <Text Condition="WixBundleAction = 7">#(loc.SuccessRepairHeader)</Text>
88 </Label>
89 <Button Name="LaunchButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.SuccessLaunchButton)</Button>
90 <Label X="185" Y="-51" Width="400" Height="34" FontId="3" DisablePrefix="yes" VisibleCondition="WixStdBARestartRequired">
91 <Text>#(loc.SuccessRestartText)</Text>
92 <Text Condition="WixBundleAction = 3">#(loc.SuccessUninstallRestartText)</Text>
93 </Label>
94 <Button Name="SuccessRestartButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.SuccessRestartButton)</Button>
95 <Button Name="SuccessCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
96 <Text>#(loc.SuccessCloseButton)</Text>
97 <CloseWindowAction />
98 </Button>
99 </Page>
100 <Page Name="Failure">
101 <Label X="185" Y="11" Width="-11" Height="32" FontId="1" DisablePrefix="yes">#(loc.Title)</Label>
102 <ImageControl X="11" Y="11" Width="165" Height="400" ImageFile="logoside.png"/>
103 <Label X="185" Y="50" Width="-11" Height="30" FontId="2" DisablePrefix="yes">
104 <Text>#(loc.FailureHeader)</Text>
105 <Text Condition="WixBundleAction = 2">#(loc.FailureLayoutHeader)</Text>
106 <Text Condition="WixBundleAction = 3">#(loc.FailureUninstallHeader)</Text>
107 <Text Condition="WixBundleAction = 5">#(loc.FailureInstallHeader)</Text>
108 <Text Condition="WixBundleAction = 7">#(loc.FailureRepairHeader)</Text>
109 </Label>
110 <Hypertext Name="FailureLogFileLink" X="185" Y="121" Width="-11" Height="68" FontId="3" TabStop="yes" HideWhenDisabled="yes">#(loc.FailureHyperlinkLogText)</Hypertext>
111 <Hypertext Name="FailureMessageText" X="185" Y="-115" Width="-11" Height="80" FontId="3" TabStop="yes" HideWhenDisabled="yes" />
112 <Label X="185" Y="-57" Width="-11" Height="80" FontId="3" DisablePrefix="yes" VisibleCondition="WixStdBARestartRequired">#(loc.FailureRestartText)</Label>
113 <Button Name="FailureRestartButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.FailureRestartButton)</Button>
114 <Button Name="FailureCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
115 <Text>#(loc.FailureCloseButton)</Text>
116 <CloseWindowAction />
117 </Button>
118 </Page>
119 </Window>
120</Theme>
diff --git a/src/ext/Bal/wixstdba/Resources/HyperlinkTheme.wxl b/src/ext/Bal/wixstdba/Resources/HyperlinkTheme.wxl
new file mode 100644
index 00000000..e6e3f8ab
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/HyperlinkTheme.wxl
@@ -0,0 +1,61 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<WixLocalization Culture="en-us" Language="1033" xmlns="http://wixtoolset.org/schemas/v4/wxl">
6 <String Id="Caption">[WixBundleName] Setup</String>
7 <String Id="Title">[WixBundleName]</String>
8 <String Id="InstallHeader">Welcome</String>
9 <String Id="InstallMessage">Setup will install [WixBundleName] on your computer. Click install to continue, options to set the install directory or Close to exit.</String>
10 <String Id="InstallVersion">Version [WixBundleVersion]</String>
11 <String Id="ConfirmCancelMessage">Are you sure you want to cancel?</String>
12 <String Id="ExecuteUpgradeRelatedBundleMessage">Previous version</String>
13 <String Id="HelpHeader">Setup Help</String>
14 <String Id="HelpText">/install | /repair | /uninstall | /layout [directory] - installs, repairs, uninstalls or
15 creates a complete local copy of the bundle in directory. Install is the default.
16
17/passive | /quiet - displays minimal UI with no prompts or displays no UI and
18 no prompts. By default UI and all prompts are displayed.
19
20/norestart - suppress any attempts to restart. By default UI will prompt before restart.
21/log log.txt - logs to a specific file. By default a log file is created in %TEMP%.</String>
22 <String Id="HelpCloseButton">&amp;Close</String>
23 <String Id="InstallLicenseLinkText">[WixBundleName] &lt;a href="#"&gt;license terms&lt;/a&gt;.</String>
24 <String Id="InstallAcceptCheckbox">I &amp;agree to the license terms and conditions</String>
25 <String Id="InstallOptionsButton">&amp;Options</String>
26 <String Id="InstallInstallButton">&amp;Install</String>
27 <String Id="InstallCancelButton">&amp;Cancel</String>
28 <String Id="OptionsHeader">Setup Options</String>
29 <String Id="OptionsLocationLabel">Install location:</String>
30 <String Id="OptionsBrowseButton">&amp;Browse</String>
31 <String Id="OptionsOkButton">&amp;OK</String>
32 <String Id="OptionsCancelButton">&amp;Cancel</String>
33 <String Id="ProgressHeader">Setup Progress</String>
34 <String Id="ProgressLabel">Processing:</String>
35 <String Id="OverallProgressPackageText">Initializing...</String>
36 <String Id="ProgressCancelButton">&amp;Cancel</String>
37 <String Id="ModifyHeader">Modify Setup</String>
38 <String Id="ModifyRepairButton">&amp;Repair</String>
39 <String Id="ModifyUninstallButton">&amp;Uninstall</String>
40 <String Id="ModifyCancelButton">&amp;Cancel</String>
41 <String Id="SuccessHeader">Setup Successful</String>
42 <String Id="SuccessInstallHeader">Installation Successfully Completed</String>
43 <String Id="SuccessLayoutHeader">Layout Successfully Completed</String>
44 <String Id="SuccessRepairHeader">Repair Successfully Completed</String>
45 <String Id="SuccessUninstallHeader">Uninstall Successfully Completed</String>
46 <String Id="SuccessLaunchButton">&amp;Launch</String>
47 <String Id="SuccessRestartText">You must restart your computer before you can use the software.</String>
48 <String Id="SuccessUninstallRestartText">You must restart your computer to complete the removal of the software.</String>
49 <String Id="SuccessRestartButton">&amp;Restart</String>
50 <String Id="SuccessCloseButton">&amp;Close</String>
51 <String Id="FailureHeader">Setup Failed</String>
52 <String Id="FailureInstallHeader">Setup Failed</String>
53 <String Id="FailureLayoutHeader">Layout Failed</String>
54 <String Id="FailureRepairHeader">Repair Failed</String>
55 <String Id="FailureUninstallHeader">Uninstall Failed</String>
56 <String Id="FailureHyperlinkLogText">One or more issues caused the setup to fail. Please fix the issues and then retry setup. For more information see the &lt;a href="#"&gt;log file&lt;/a&gt;.</String>
57 <String Id="FailureRestartText">You must restart your computer to complete the rollback of the software.</String>
58 <String Id="FailureRestartButton">&amp;Restart</String>
59 <String Id="FailureCloseButton">&amp;Close</String>
60 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
61</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/HyperlinkTheme.xml b/src/ext/Bal/wixstdba/Resources/HyperlinkTheme.xml
new file mode 100644
index 00000000..657db34b
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/HyperlinkTheme.xml
@@ -0,0 +1,106 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<Theme xmlns="http://wixtoolset.org/schemas/v4/thmutil">
6 <Font Id="0" Height="-12" Weight="500" Foreground="windowtext" Background="window">Segoe UI</Font>
7 <Font Id="1" Height="-24" Weight="500" Foreground="windowtext">Segoe UI</Font>
8 <Font Id="2" Height="-22" Weight="500" Foreground="graytext">Segoe UI</Font>
9 <Font Id="3" Height="-12" Weight="500" Foreground="windowtext" Background="window">Segoe UI</Font>
10
11 <Window Width="485" Height="300" HexStyle="100a0000" FontId="0" Caption="#(loc.Caption)">
12 <ImageControl X="11" Y="11" Width="64" Height="64" ImageFile="logo.png" Visible="yes"/>
13 <Label X="80" Y="11" Width="-11" Height="64" FontId="1" Visible="yes" DisablePrefix="yes">#(loc.Title)</Label>
14
15 <Page Name="Help">
16 <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.HelpHeader)</Label>
17 <Label X="11" Y="112" Width="-11" Height="-35" FontId="3" DisablePrefix="yes">#(loc.HelpText)</Label>
18 <Button Name="HelpCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
19 <Text>#(loc.HelpCloseButton)</Text>
20 <CloseWindowAction />
21 </Button>
22 </Page>
23 <Page Name="Install">
24 <Hypertext Name="EulaHyperlink" X="11" Y="121" Width="-11" Height="51" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.InstallLicenseLinkText)</Hypertext>
25 <Checkbox Name="EulaAcceptCheckbox" X="-11" Y="-41" Width="260" Height="17" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.InstallAcceptCheckbox)</Checkbox>
26 <Button Name="OptionsButton" X="-171" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" VisibleCondition="NOT WixStdBASuppressOptionsUI">
27 <Text>#(loc.InstallOptionsButton)</Text>
28 <ChangePageAction Page="Options" />
29 </Button>
30 <Button Name="InstallButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.InstallInstallButton)</Button>
31 <Button Name="InstallCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
32 <Text>#(loc.InstallCancelButton)</Text>
33 <CloseWindowAction />
34 </Button>
35 </Page>
36 <Page Name="Options">
37 <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.OptionsHeader)</Label>
38 <Label X="11" Y="121" Width="-11" Height="17" FontId="3" DisablePrefix="yes">#(loc.OptionsLocationLabel)</Label>
39 <Editbox Name="InstallFolder" X="11" Y="143" Width="-91" Height="21" TabStop="yes" FontId="3" FileSystemAutoComplete="yes" />
40 <Button Name="BrowseButton" X="-11" Y="142" Width="75" Height="23" TabStop="yes" FontId="3">
41 <Text>#(loc.OptionsBrowseButton)</Text>
42 <BrowseDirectoryAction VariableName="InstallFolder" />
43 </Button>
44 <Button Name="OptionsOkButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
45 <Text>#(loc.OptionsOkButton)</Text>
46 <ChangePageAction Page="Install" />
47 </Button>
48 <Button Name="OptionsCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
49 <Text>#(loc.OptionsCancelButton)</Text>
50 <ChangePageAction Page="Install" Cancel="yes" />
51 </Button>
52 </Page>
53 <Page Name="Progress">
54 <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.ProgressHeader)</Label>
55 <Label X="11" Y="121" Width="70" Height="17" FontId="3" DisablePrefix="yes">#(loc.ProgressLabel)</Label>
56 <Label Name="OverallProgressPackageText" X="85" Y="121" Width="-11" Height="17" FontId="3" DisablePrefix="yes">#(loc.OverallProgressPackageText)</Label>
57 <Progressbar Name="OverallCalculatedProgressbar" X="11" Y="143" Width="-11" Height="15" />
58 <Button Name="ProgressCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.ProgressCancelButton)</Button>
59 </Page>
60 <Page Name="Modify">
61 <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.ModifyHeader)</Label>
62 <Button Name="RepairButton" X="-171" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.ModifyRepairButton)</Button>
63 <Button Name="UninstallButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.ModifyUninstallButton)</Button>
64 <Button Name="ModifyCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
65 <Text>#(loc.ModifyCancelButton)</Text>
66 <CloseWindowAction />
67 </Button>
68 </Page>
69 <Page Name="Success">
70 <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">
71 <Text>#(loc.SuccessHeader)</Text>
72 <Text Condition="WixBundleAction = 2">#(loc.SuccessLayoutHeader)</Text>
73 <Text Condition="WixBundleAction = 3">#(loc.SuccessUninstallHeader)</Text>
74 <Text Condition="WixBundleAction = 5">#(loc.SuccessInstallHeader)</Text>
75 <Text Condition="WixBundleAction = 7">#(loc.SuccessRepairHeader)</Text>
76 </Label>
77 <Button Name="LaunchButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.SuccessLaunchButton)</Button>
78 <Label X="-11" Y="-51" Width="400" Height="34" FontId="3" DisablePrefix="yes" VisibleCondition="WixStdBARestartRequired">
79 <Text>#(loc.SuccessRestartText)</Text>
80 <Text Condition="WixBundleAction = 3">#(loc.SuccessUninstallRestartText)</Text>
81 </Label>
82 <Button Name="SuccessRestartButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.SuccessRestartButton)</Button>
83 <Button Name="SuccessCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
84 <Text>#(loc.SuccessCloseButton)</Text>
85 <CloseWindowAction />
86 </Button>
87 </Page>
88 <Page Name="Failure">
89 <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">
90 <Text>#(loc.FailureHeader)</Text>
91 <Text Condition="WixBundleAction = 2">#(loc.FailureLayoutHeader)</Text>
92 <Text Condition="WixBundleAction = 3">#(loc.FailureUninstallHeader)</Text>
93 <Text Condition="WixBundleAction = 5">#(loc.FailureInstallHeader)</Text>
94 <Text Condition="WixBundleAction = 7">#(loc.FailureRepairHeader)</Text>
95 </Label>
96 <Hypertext Name="FailureLogFileLink" X="11" Y="121" Width="-11" Height="42" FontId="3" TabStop="yes" HideWhenDisabled="yes">#(loc.FailureHyperlinkLogText)</Hypertext>
97 <Hypertext Name="FailureMessageText" X="22" Y="163" Width="-11" Height="51" FontId="3" TabStop="yes" HideWhenDisabled="yes" />
98 <Label X="-11" Y="-51" Width="400" Height="34" FontId="3" DisablePrefix="yes" VisibleCondition="WixStdBARestartRequired">#(loc.FailureRestartText)</Label>
99 <Button Name="FailureRestartButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.FailureRestartButton)</Button>
100 <Button Name="FailureCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
101 <Text>#(loc.FailureCloseButton)</Text>
102 <CloseWindowAction />
103 </Button>
104 </Page>
105 </Window>
106</Theme>
diff --git a/src/ext/Bal/wixstdba/Resources/LoremIpsumLicense.rtf b/src/ext/Bal/wixstdba/Resources/LoremIpsumLicense.rtf
new file mode 100644
index 00000000..1a183236
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/LoremIpsumLicense.rtf
Binary files differ
diff --git a/src/ext/Bal/wixstdba/Resources/RtfLargeTheme.xml b/src/ext/Bal/wixstdba/Resources/RtfLargeTheme.xml
new file mode 100644
index 00000000..3571e13a
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/RtfLargeTheme.xml
@@ -0,0 +1,108 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<Theme xmlns="http://wixtoolset.org/schemas/v4/thmutil">
6 <Font Id="0" Height="-12" Weight="500" Foreground="windowtext" Background="window">Segoe UI</Font>
7 <Font Id="1" Height="-24" Weight="500" Foreground="windowtext">Segoe UI</Font>
8 <Font Id="2" Height="-22" Weight="500" Foreground="graytext">Segoe UI</Font>
9 <Font Id="3" Height="-12" Weight="500" Foreground="windowtext" Background="window">Segoe UI</Font>
10
11 <Window Width="500" Height="390" HexStyle="100a0000" FontId="0" Caption="#(loc.Caption)">
12 <ImageControl X="11" Y="11" Width="64" Height="64" ImageFile="logo.png" Visible="yes"/>
13 <Label X="80" Y="11" Width="-11" Height="64" FontId="1" Visible="yes" DisablePrefix="yes">#(loc.Title)</Label>
14
15 <Page Name="Help">
16 <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.HelpHeader)</Label>
17 <Label X="11" Y="112" Width="-11" Height="-35" FontId="3" DisablePrefix="yes">#(loc.HelpText)</Label>
18 <Button Name="HelpCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
19 <Text>#(loc.HelpCloseButton)</Text>
20 <CloseWindowAction />
21 </Button>
22 </Page>
23 <Page Name="Install">
24 <Label X="11" Y="80" Width="-11" Height="-70" TabStop="no" FontId="2" HexStyle="800000" DisablePrefix="yes" />
25 <Richedit Name="EulaRichedit" X="12" Y="81" Width="-12" Height="-71" TabStop="yes" FontId="0" />
26 <Label Name="InstallVersion" X="11" Y="-41" Width="210" Height="17" FontId="3" DisablePrefix="yes" VisibleCondition="WixStdBAShowVersion">#(loc.InstallVersion)</Label>
27 <Checkbox Name="EulaAcceptCheckbox" X="-11" Y="-41" Width="260" Height="17" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.InstallAcceptCheckbox)</Checkbox>
28 <Button Name="OptionsButton" X="-171" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" VisibleCondition="NOT WixStdBASuppressOptionsUI">
29 <Text>#(loc.InstallOptionsButton)</Text>
30 <ChangePageAction Page="Options" />
31 </Button>
32 <Button Name="InstallButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.InstallInstallButton)</Button>
33 <Button Name="InstallCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
34 <Text>#(loc.InstallCancelButton)</Text>
35 <CloseWindowAction />
36 </Button>
37 </Page>
38 <Page Name="Options">
39 <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.OptionsHeader)</Label>
40 <Label X="11" Y="121" Width="-11" Height="17" FontId="3" DisablePrefix="yes">#(loc.OptionsLocationLabel)</Label>
41 <Editbox Name="InstallFolder" X="11" Y="143" Width="-91" Height="21" TabStop="yes" FontId="3" FileSystemAutoComplete="yes" />
42 <Button Name="BrowseButton" X="-11" Y="142" Width="75" Height="23" TabStop="yes" FontId="3">
43 <Text>#(loc.OptionsBrowseButton)</Text>
44 <BrowseDirectoryAction VariableName="InstallFolder" />
45 </Button>
46 <Button Name="OptionsOkButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
47 <Text>#(loc.OptionsOkButton)</Text>
48 <ChangePageAction Page="Install" />
49 </Button>
50 <Button Name="OptionsCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
51 <Text>#(loc.OptionsCancelButton)</Text>
52 <ChangePageAction Page="Install" Cancel="yes" />
53 </Button>
54 </Page>
55 <Page Name="Progress">
56 <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.ProgressHeader)</Label>
57 <Label X="11" Y="121" Width="70" Height="17" FontId="3" DisablePrefix="yes">#(loc.ProgressLabel)</Label>
58 <Label Name="OverallProgressPackageText" X="85" Y="121" Width="-11" Height="17" FontId="3" DisablePrefix="yes">#(loc.OverallProgressPackageText)</Label>
59 <Progressbar Name="OverallCalculatedProgressbar" X="11" Y="143" Width="-11" Height="15" />
60 <Button Name="ProgressCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.ProgressCancelButton)</Button>
61 </Page>
62 <Page Name="Modify">
63 <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.ModifyHeader)</Label>
64 <Button Name="RepairButton" X="-171" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.ModifyRepairButton)</Button>
65 <Button Name="UninstallButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.ModifyUninstallButton)</Button>
66 <Button Name="ModifyCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
67 <Text>#(loc.ModifyCancelButton)</Text>
68 <CloseWindowAction />
69 </Button>
70 </Page>
71 <Page Name="Success">
72 <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">
73 <Text>#(loc.SuccessHeader)</Text>
74 <Text Condition="WixBundleAction = 2">#(loc.SuccessLayoutHeader)</Text>
75 <Text Condition="WixBundleAction = 3">#(loc.SuccessUninstallHeader)</Text>
76 <Text Condition="WixBundleAction = 5">#(loc.SuccessInstallHeader)</Text>
77 <Text Condition="WixBundleAction = 7">#(loc.SuccessRepairHeader)</Text>
78 </Label>
79 <Button Name="LaunchButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.SuccessLaunchButton)</Button>
80 <Label X="-11" Y="-51" Width="400" Height="34" FontId="3" DisablePrefix="yes" VisibleCondition="WixStdBARestartRequired">
81 <Text>#(loc.SuccessRestartText)</Text>
82 <Text Condition="WixBundleAction = 3">#(loc.SuccessUninstallRestartText)</Text>
83 </Label>
84 <Button Name="SuccessRestartButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.SuccessRestartButton)</Button>
85 <Button Name="SuccessCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
86 <Text>#(loc.SuccessCloseButton)</Text>
87 <CloseWindowAction />
88 </Button>
89 </Page>
90 <Page Name="Failure">
91 <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">
92 <Text>#(loc.FailureHeader)</Text>
93 <Text Condition="WixBundleAction = 2">#(loc.FailureLayoutHeader)</Text>
94 <Text Condition="WixBundleAction = 3">#(loc.FailureUninstallHeader)</Text>
95 <Text Condition="WixBundleAction = 5">#(loc.FailureInstallHeader)</Text>
96 <Text Condition="WixBundleAction = 7">#(loc.FailureRepairHeader)</Text>
97 </Label>
98 <Hypertext Name="FailureLogFileLink" X="11" Y="121" Width="-11" Height="42" FontId="3" TabStop="yes" HideWhenDisabled="yes">#(loc.FailureHyperlinkLogText)</Hypertext>
99 <Hypertext Name="FailureMessageText" X="22" Y="163" Width="-11" Height="51" FontId="3" TabStop="yes" HideWhenDisabled="yes" />
100 <Label Name="FailureRestartText" X="-11" Y="-51" Width="400" Height="34" FontId="3" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.FailureRestartText)</Label>
101 <Button Name="FailureRestartButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.FailureRestartButton)</Button>
102 <Button Name="FailureCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
103 <Text>#(loc.FailureCloseButton)</Text>
104 <CloseWindowAction />
105 </Button>
106 </Page>
107 </Window>
108</Theme>
diff --git a/src/ext/Bal/wixstdba/Resources/RtfTheme.wxl b/src/ext/Bal/wixstdba/Resources/RtfTheme.wxl
new file mode 100644
index 00000000..f73fb994
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/RtfTheme.wxl
@@ -0,0 +1,58 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<WixLocalization Culture="en-us" Language="1033" xmlns="http://wixtoolset.org/schemas/v4/wxl">
6 <String Id="Caption">[WixBundleName] Setup</String>
7 <String Id="Title">[WixBundleName]</String>
8 <String Id="InstallVersion">Version [WixBundleVersion]</String>
9 <String Id="ConfirmCancelMessage">Are you sure you want to cancel?</String>
10 <String Id="ExecuteUpgradeRelatedBundleMessage">Previous version</String>
11 <String Id="HelpHeader">Setup Help</String>
12 <String Id="HelpText">/install | /repair | /uninstall | /layout [directory] - installs, repairs, uninstalls or
13 creates a complete local copy of the bundle in directory. Install is the default.
14
15/passive | /quiet - displays minimal UI with no prompts or displays no UI and
16 no prompts. By default UI and all prompts are displayed.
17
18/norestart - suppress any attempts to restart. By default UI will prompt before restart.
19/log log.txt - logs to a specific file. By default a log file is created in %TEMP%.</String>
20 <String Id="HelpCloseButton">&amp;Close</String>
21 <String Id="InstallAcceptCheckbox">I &amp;agree to the license terms and conditions</String>
22 <String Id="InstallOptionsButton">&amp;Options</String>
23 <String Id="InstallInstallButton">&amp;Install</String>
24 <String Id="InstallCancelButton">&amp;Cancel</String>
25 <String Id="OptionsHeader">Setup Options</String>
26 <String Id="OptionsLocationLabel">Install location:</String>
27 <String Id="OptionsBrowseButton">&amp;Browse</String>
28 <String Id="OptionsOkButton">&amp;OK</String>
29 <String Id="OptionsCancelButton">&amp;Cancel</String>
30 <String Id="ProgressHeader">Setup Progress</String>
31 <String Id="ProgressLabel">Processing:</String>
32 <String Id="OverallProgressPackageText">Initializing...</String>
33 <String Id="ProgressCancelButton">&amp;Cancel</String>
34 <String Id="ModifyHeader">Modify Setup</String>
35 <String Id="ModifyRepairButton">&amp;Repair</String>
36 <String Id="ModifyUninstallButton">&amp;Uninstall</String>
37 <String Id="ModifyCancelButton">&amp;Cancel</String>
38 <String Id="SuccessHeader">Setup Successful</String>
39 <String Id="SuccessInstallHeader">Installation Successfully Completed</String>
40 <String Id="SuccessLayoutHeader">Layout Successfully Completed</String>
41 <String Id="SuccessRepairHeader">Repair Successfully Completed</String>
42 <String Id="SuccessUninstallHeader">Uninstall Successfully Completed</String>
43 <String Id="SuccessLaunchButton">&amp;Launch</String>
44 <String Id="SuccessRestartText">You must restart your computer before you can use the software.</String>
45 <String Id="SuccessUninstallRestartText">You must restart your computer to complete the removal of the software.</String>
46 <String Id="SuccessRestartButton">&amp;Restart</String>
47 <String Id="SuccessCloseButton">&amp;Close</String>
48 <String Id="FailureHeader">Setup Failed</String>
49 <String Id="FailureInstallHeader">Setup Failed</String>
50 <String Id="FailureLayoutHeader">Layout Failed</String>
51 <String Id="FailureRepairHeader">Repair Failed</String>
52 <String Id="FailureUninstallHeader">Uninstall Failed</String>
53 <String Id="FailureHyperlinkLogText">One or more issues caused the setup to fail. Please fix the issues and then retry setup. For more information see the &lt;a href="#"&gt;log file&lt;/a&gt;.</String>
54 <String Id="FailureRestartText">You must restart your computer to complete the rollback of the software.</String>
55 <String Id="FailureRestartButton">&amp;Restart</String>
56 <String Id="FailureCloseButton">&amp;Close</String>
57 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
58</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/RtfTheme.xml b/src/ext/Bal/wixstdba/Resources/RtfTheme.xml
new file mode 100644
index 00000000..d6535bac
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/RtfTheme.xml
@@ -0,0 +1,106 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<Theme xmlns="http://wixtoolset.org/schemas/v4/thmutil">
6 <Font Id="0" Height="-12" Weight="500" Foreground="windowtext" Background="window">Segoe UI</Font>
7 <Font Id="1" Height="-24" Weight="500" Foreground="windowtext">Segoe UI</Font>
8 <Font Id="2" Height="-22" Weight="500" Foreground="graytext">Segoe UI</Font>
9 <Font Id="3" Height="-12" Weight="500" Foreground="windowtext" Background="window">Segoe UI</Font>
10
11 <Window Width="485" Height="300" HexStyle="100a0000" FontId="0" Caption="#(loc.Caption)">
12 <ImageControl X="11" Y="11" Width="64" Height="64" ImageFile="logo.png" Visible="yes"/>
13 <Label X="80" Y="11" Width="-11" Height="64" FontId="1" Visible="yes" DisablePrefix="yes">#(loc.Title)</Label>
14
15 <Page Name="Help">
16 <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.HelpHeader)</Label>
17 <Label X="11" Y="112" Width="-11" Height="-35" FontId="3" DisablePrefix="yes">#(loc.HelpText)</Label>
18 <Button Name="HelpCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
19 <Text>#(loc.HelpCloseButton)</Text>
20 <CloseWindowAction />
21 </Button>
22 </Page>
23 <Page Name="Install">
24 <Richedit Name="EulaRichedit" X="11" Y="80" Width="-11" Height="-70" TabStop="yes" FontId="0" HexStyle="800000" />
25 <Checkbox Name="EulaAcceptCheckbox" X="-11" Y="-41" Width="260" Height="17" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.InstallAcceptCheckbox)</Checkbox>
26 <Button Name="OptionsButton" X="-171" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" VisibleCondition="NOT WixStdBASuppressOptionsUI">
27 <Text>#(loc.InstallOptionsButton)</Text>
28 <ChangePageAction Page="Options" />
29 </Button>
30 <Button Name="InstallButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.InstallInstallButton)</Button>
31 <Button Name="InstallCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
32 <Text>#(loc.InstallCancelButton)</Text>
33 <CloseWindowAction />
34 </Button>
35 </Page>
36 <Page Name="Options">
37 <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.OptionsHeader)</Label>
38 <Label X="11" Y="121" Width="-11" Height="17" FontId="3" DisablePrefix="yes">#(loc.OptionsLocationLabel)</Label>
39 <Editbox Name="InstallFolder" X="11" Y="143" Width="-91" Height="21" TabStop="yes" FontId="3" FileSystemAutoComplete="yes" />
40 <Button Name="BrowseButton" X="-11" Y="142" Width="75" Height="23" TabStop="yes" FontId="3">
41 <Text>#(loc.OptionsBrowseButton)</Text>
42 <BrowseDirectoryAction VariableName="InstallFolder" />
43 </Button>
44 <Button Name="OptionsOkButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
45 <Text>#(loc.OptionsOkButton)</Text>
46 <ChangePageAction Page="Install" />
47 </Button>
48 <Button Name="OptionsCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
49 <Text>#(loc.OptionsCancelButton)</Text>
50 <ChangePageAction Page="Install" Cancel="yes" />
51 </Button>
52 </Page>
53 <Page Name="Progress">
54 <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.ProgressHeader)</Label>
55 <Label X="11" Y="121" Width="70" Height="17" FontId="3" DisablePrefix="yes">#(loc.ProgressLabel)</Label>
56 <Label Name="OverallProgressPackageText" X="85" Y="121" Width="-11" Height="17" FontId="3" DisablePrefix="yes">#(loc.OverallProgressPackageText)</Label>
57 <Progressbar Name="OverallCalculatedProgressbar" X="11" Y="143" Width="-11" Height="15" />
58 <Button Name="ProgressCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.ProgressCancelButton)</Button>
59 </Page>
60 <Page Name="Modify">
61 <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.ModifyHeader)</Label>
62 <Button Name="RepairButton" X="-171" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.ModifyRepairButton)</Button>
63 <Button Name="UninstallButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.ModifyUninstallButton)</Button>
64 <Button Name="ModifyCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
65 <Text>#(loc.ModifyCancelButton)</Text>
66 <CloseWindowAction />
67 </Button>
68 </Page>
69 <Page Name="Success">
70 <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">
71 <Text>#(loc.SuccessHeader)</Text>
72 <Text Condition="WixBundleAction = 2">#(loc.SuccessLayoutHeader)</Text>
73 <Text Condition="WixBundleAction = 3">#(loc.SuccessUninstallHeader)</Text>
74 <Text Condition="WixBundleAction = 5">#(loc.SuccessInstallHeader)</Text>
75 <Text Condition="WixBundleAction = 7">#(loc.SuccessRepairHeader)</Text>
76 </Label>
77 <Button Name="LaunchButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.SuccessLaunchButton)</Button>
78 <Label X="-11" Y="-51" Width="400" Height="34" FontId="3" DisablePrefix="yes" VisibleCondition="WixStdBARestartRequired">
79 <Text>#(loc.SuccessRestartText)</Text>
80 <Text Condition="WixBundleAction = 3">#(loc.SuccessUninstallRestartText)</Text>
81 </Label>
82 <Button Name="SuccessRestartButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.SuccessRestartButton)</Button>
83 <Button Name="SuccessCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
84 <Text>#(loc.SuccessCloseButton)</Text>
85 <CloseWindowAction />
86 </Button>
87 </Page>
88 <Page Name="Failure">
89 <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">
90 <Text>#(loc.FailureHeader)</Text>
91 <Text Condition="WixBundleAction = 2">#(loc.FailureLayoutHeader)</Text>
92 <Text Condition="WixBundleAction = 3">#(loc.FailureUninstallHeader)</Text>
93 <Text Condition="WixBundleAction = 5">#(loc.FailureInstallHeader)</Text>
94 <Text Condition="WixBundleAction = 7">#(loc.FailureRepairHeader)</Text>
95 </Label>
96 <Hypertext Name="FailureLogFileLink" X="11" Y="121" Width="-11" Height="42" FontId="3" TabStop="yes" HideWhenDisabled="yes">#(loc.FailureHyperlinkLogText)</Hypertext>
97 <Hypertext Name="FailureMessageText" X="22" Y="163" Width="-11" Height="51" FontId="3" TabStop="yes" HideWhenDisabled="yes" />
98 <Label X="-11" Y="-51" Width="400" Height="34" FontId="3" DisablePrefix="yes" VisibleCondition="WixStdBARestartRequired">#(loc.FailureRestartText)</Label>
99 <Button Name="FailureRestartButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.FailureRestartButton)</Button>
100 <Button Name="FailureCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
101 <Text>#(loc.FailureCloseButton)</Text>
102 <CloseWindowAction />
103 </Button>
104 </Page>
105 </Window>
106</Theme>
diff --git a/src/ext/Bal/wixstdba/Resources/dncpreq.thm b/src/ext/Bal/wixstdba/Resources/dncpreq.thm
new file mode 100644
index 00000000..4ae61819
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/dncpreq.thm
@@ -0,0 +1,47 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Theme xmlns="http://wixtoolset.org/schemas/v4/thmutil">
3 <Font Id="0" Height="-12" Weight="500" Foreground="windowtext" Background="window">Segoe UI</Font>
4 <Font Id="1" Height="-24" Weight="500" Foreground="windowtext">Segoe UI</Font>
5 <Font Id="2" Height="-22" Weight="500" Foreground="graytext">Segoe UI</Font>
6 <Font Id="3" Height="-12" Weight="500" Foreground="windowtext" Background="window">Segoe UI</Font>
7
8 <Window Width="485" Height="300" HexStyle="100a0000" FontId="0" Caption="#(loc.Caption)">
9 <ImageControl X="11" Y="11" Width="64" Height="64" ImageFile="mbapreq.png" Visible="yes"/>
10 <Label X="80" Y="11" Width="-11" Height="96" FontId="1" Visible="yes" DisablePrefix="yes">#(loc.Title)</Label>
11
12 <Page Name="Help">
13 <Label X="11" Y="112" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.HelpHeader)</Label>
14 <Label X="11" Y="153" Width="-11" Height="-35" FontId="3" DisablePrefix="yes">#(loc.HelpText)</Label>
15 <Button Name="HelpCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
16 <Text>#(loc.HelpCloseButton)</Text>
17 <CloseWindowAction />
18 </Button>
19 </Page>
20 <Page Name="Install">
21 <Hypertext Name="EulaHyperlink" X="11" Y="121" Width="-11" Height="34" TabStop="yes" FontId="3">#(loc.InstallLicenseTerms)</Hypertext>
22 <Button Name="InstallButton" X="-91" Y="-11" Width="130" Height="23" TabStop="yes" FontId="0">#(loc.InstallAcceptAndInstallButton)</Button>
23 <Button Name="InstallDeclineButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
24 <Text>#(loc.InstallDeclineButton)</Text>
25 <CloseWindowAction />
26 </Button>
27 </Page>
28 <Page Name="Progress">
29 <Label X="11" Y="112" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.ProgressHeader)</Label>
30 <Label X="11" Y="153" Width="70" Height="17" FontId="3" DisablePrefix="yes">#(loc.ProgressLabel)</Label>
31 <Label Name="OverallProgressPackageText" X="85" Y="153" Width="-11" Height="17" FontId="3" DisablePrefix="yes">[ProgressPackageName]</Label>
32 <Progressbar Name="OverallCalculatedProgressbar" X="11" Y="175" Width="-11" Height="15" />
33 <Button Name="ProgressCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.ProgressCancelButton)</Button>
34 </Page>
35 <Page Name="Failure">
36 <Label X="11" Y="112" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.FailureHeader)</Label>
37 <Hypertext Name="FailureLogFileLink" X="11" Y="153" Width="-11" Height="51" FontId="3" TabStop="yes" HideWhenDisabled="yes">#(loc.FailureLogLinkText)</Hypertext>
38 <Hypertext Name="FailureMessageText" X="22" Y="190" Width="-11" Height="51" FontId="3" TabStop="yes" HideWhenDisabled="yes"/>
39 <Label X="-11" Y="-20" Width="400" Height="34" FontId="3" DisablePrefix="yes" VisibleCondition="WixStdBARestartRequired">#(loc.FailureRestartText)</Label>
40 <Button Name="FailureRestartButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.FailureRestartButton)</Button>
41 <Button Name="FailureCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
42 <Text>#(loc.FailureCloseButton)</Text>
43 <CloseWindowAction />
44 </Button>
45 </Page>
46 </Window>
47</Theme>
diff --git a/src/ext/Bal/wixstdba/Resources/dncpreq.wxl b/src/ext/Bal/wixstdba/Resources/dncpreq.wxl
new file mode 100644
index 00000000..d6b73b5f
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/dncpreq.wxl
@@ -0,0 +1,29 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<WixLocalization Culture="en-us" Language="1033" xmlns="http://wixtoolset.org/schemas/v4/wxl">
6 <String Id="Caption">[WixBundleName] Setup</String>
7 <String Id="Title">Microsoft .NET Core required for [WixBundleName] setup</String>
8 <String Id="ConfirmCancelMessage">Are you sure you want to cancel?</String>
9 <String Id="HelpHeader">Setup Help</String>
10 <String Id="HelpText">/passive | /quiet - displays minimal UI with no prompts or displays no UI and
11 no prompts. By default UI and all prompts are displayed.
12
13/norestart - suppress any attempts to restart. By default UI will prompt before restart.
14/log log.txt - logs to a specific file. By default a log file is created in %TEMP%.</String>
15 <String Id="HelpCloseButton">&amp;Close</String>
16 <String Id="InstallLicenseTerms">Click the "Accept and Install" button to accept the Microsoft .NET Core &lt;a href="#"&gt;license terms&lt;/a&gt;.</String>
17 <String Id="InstallAcceptAndInstallButton">&amp;Accept and Install</String>
18 <String Id="InstallDeclineButton">&amp;Decline</String>
19 <String Id="ProgressHeader">Setup Progress</String>
20 <String Id="ProgressLabel">Processing:</String>
21 <String Id="ProgressCancelButton">&amp;Cancel</String>
22 <String Id="FailureHeader">Setup Failed</String>
23 <String Id="FailureLogLinkText">One or more issues caused the setup to fail. Please fix the issues and then retry setup. For more information see the &lt;a href="#"&gt;log file&lt;/a&gt;.</String>
24 <String Id="FailureRestartText">You must restart your computer to complete the rollback of the software.</String>
25 <String Id="FailureRestartButton">&amp;Restart</String>
26 <String Id="FailureCloseButton">&amp;Close</String>
27 <String Id="SCDRUNTIMEFAILUREErrorMessage">[WixBundleName] cannot run on this machine. Install the latest updates and/or the latest OS to run in a supported environment.</String>
28 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
29</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/Resources/logo.png b/src/ext/Bal/wixstdba/Resources/logo.png
new file mode 100644
index 00000000..7adc6e11
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/logo.png
Binary files differ
diff --git a/src/ext/Bal/wixstdba/Resources/logoSide.png b/src/ext/Bal/wixstdba/Resources/logoSide.png
new file mode 100644
index 00000000..308841c5
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/logoSide.png
Binary files differ
diff --git a/src/ext/Bal/wixstdba/Resources/mbapreq.png b/src/ext/Bal/wixstdba/Resources/mbapreq.png
new file mode 100644
index 00000000..c6e9527b
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/mbapreq.png
Binary files differ
diff --git a/src/ext/Bal/wixstdba/Resources/mbapreq.thm b/src/ext/Bal/wixstdba/Resources/mbapreq.thm
new file mode 100644
index 00000000..4ae61819
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/mbapreq.thm
@@ -0,0 +1,47 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Theme xmlns="http://wixtoolset.org/schemas/v4/thmutil">
3 <Font Id="0" Height="-12" Weight="500" Foreground="windowtext" Background="window">Segoe UI</Font>
4 <Font Id="1" Height="-24" Weight="500" Foreground="windowtext">Segoe UI</Font>
5 <Font Id="2" Height="-22" Weight="500" Foreground="graytext">Segoe UI</Font>
6 <Font Id="3" Height="-12" Weight="500" Foreground="windowtext" Background="window">Segoe UI</Font>
7
8 <Window Width="485" Height="300" HexStyle="100a0000" FontId="0" Caption="#(loc.Caption)">
9 <ImageControl X="11" Y="11" Width="64" Height="64" ImageFile="mbapreq.png" Visible="yes"/>
10 <Label X="80" Y="11" Width="-11" Height="96" FontId="1" Visible="yes" DisablePrefix="yes">#(loc.Title)</Label>
11
12 <Page Name="Help">
13 <Label X="11" Y="112" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.HelpHeader)</Label>
14 <Label X="11" Y="153" Width="-11" Height="-35" FontId="3" DisablePrefix="yes">#(loc.HelpText)</Label>
15 <Button Name="HelpCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
16 <Text>#(loc.HelpCloseButton)</Text>
17 <CloseWindowAction />
18 </Button>
19 </Page>
20 <Page Name="Install">
21 <Hypertext Name="EulaHyperlink" X="11" Y="121" Width="-11" Height="34" TabStop="yes" FontId="3">#(loc.InstallLicenseTerms)</Hypertext>
22 <Button Name="InstallButton" X="-91" Y="-11" Width="130" Height="23" TabStop="yes" FontId="0">#(loc.InstallAcceptAndInstallButton)</Button>
23 <Button Name="InstallDeclineButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
24 <Text>#(loc.InstallDeclineButton)</Text>
25 <CloseWindowAction />
26 </Button>
27 </Page>
28 <Page Name="Progress">
29 <Label X="11" Y="112" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.ProgressHeader)</Label>
30 <Label X="11" Y="153" Width="70" Height="17" FontId="3" DisablePrefix="yes">#(loc.ProgressLabel)</Label>
31 <Label Name="OverallProgressPackageText" X="85" Y="153" Width="-11" Height="17" FontId="3" DisablePrefix="yes">[ProgressPackageName]</Label>
32 <Progressbar Name="OverallCalculatedProgressbar" X="11" Y="175" Width="-11" Height="15" />
33 <Button Name="ProgressCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.ProgressCancelButton)</Button>
34 </Page>
35 <Page Name="Failure">
36 <Label X="11" Y="112" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.FailureHeader)</Label>
37 <Hypertext Name="FailureLogFileLink" X="11" Y="153" Width="-11" Height="51" FontId="3" TabStop="yes" HideWhenDisabled="yes">#(loc.FailureLogLinkText)</Hypertext>
38 <Hypertext Name="FailureMessageText" X="22" Y="190" Width="-11" Height="51" FontId="3" TabStop="yes" HideWhenDisabled="yes"/>
39 <Label X="-11" Y="-20" Width="400" Height="34" FontId="3" DisablePrefix="yes" VisibleCondition="WixStdBARestartRequired">#(loc.FailureRestartText)</Label>
40 <Button Name="FailureRestartButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.FailureRestartButton)</Button>
41 <Button Name="FailureCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
42 <Text>#(loc.FailureCloseButton)</Text>
43 <CloseWindowAction />
44 </Button>
45 </Page>
46 </Window>
47</Theme>
diff --git a/src/ext/Bal/wixstdba/Resources/mbapreq.wxl b/src/ext/Bal/wixstdba/Resources/mbapreq.wxl
new file mode 100644
index 00000000..95e3a6ae
--- /dev/null
+++ b/src/ext/Bal/wixstdba/Resources/mbapreq.wxl
@@ -0,0 +1,29 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4
5<WixLocalization Culture="en-us" Language="1033" xmlns="http://wixtoolset.org/schemas/v4/wxl">
6 <String Id="Caption">[WixBundleName] Setup</String>
7 <String Id="Title">Microsoft .NET Framework required for [WixBundleName] setup</String>
8 <String Id="ConfirmCancelMessage">Are you sure you want to cancel?</String>
9 <String Id="HelpHeader">Setup Help</String>
10 <String Id="HelpText">/passive | /quiet - displays minimal UI with no prompts or displays no UI and
11 no prompts. By default UI and all prompts are displayed.
12
13/norestart - suppress any attempts to restart. By default UI will prompt before restart.
14/log log.txt - logs to a specific file. By default a log file is created in %TEMP%.</String>
15 <String Id="HelpCloseButton">&amp;Close</String>
16 <String Id="InstallLicenseTerms">Click the "Accept and Install" button to accept the Microsoft .NET Framework &lt;a href="#"&gt;license terms&lt;/a&gt;.</String>
17 <String Id="InstallAcceptAndInstallButton">&amp;Accept and Install</String>
18 <String Id="InstallDeclineButton">&amp;Decline</String>
19 <String Id="ProgressHeader">Setup Progress</String>
20 <String Id="ProgressLabel">Processing:</String>
21 <String Id="ProgressCancelButton">&amp;Cancel</String>
22 <String Id="FailureHeader">Setup Failed</String>
23 <String Id="FailureLogLinkText">One or more issues caused the setup to fail. Please fix the issues and then retry setup. For more information see the &lt;a href="#"&gt;log file&lt;/a&gt;.</String>
24 <String Id="FailureRestartText">You must restart your computer to complete the rollback of the software.</String>
25 <String Id="FailureRestartButton">&amp;Restart</String>
26 <String Id="FailureCloseButton">&amp;Close</String>
27 <String Id="NET452WIN7RTMErrorMessage">[WixBundleName] cannot run on Windows 7 RTM with .NET 4.5.2 installed. Install Windows 7 SP1 to run in a supported environment.</String>
28 <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
29</WixLocalization>
diff --git a/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp b/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp
new file mode 100644
index 00000000..d4bf7b43
--- /dev/null
+++ b/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp
@@ -0,0 +1,4264 @@
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 "BalBaseBootstrapperApplicationProc.h"
5#include "BalBaseBootstrapperApplication.h"
6
7static const LPCWSTR WIXBUNDLE_VARIABLE_ELEVATED = L"WixBundleElevated";
8
9static const LPCWSTR WIXSTDBA_WINDOW_CLASS = L"WixStdBA";
10
11static const LPCWSTR WIXSTDBA_VARIABLE_INSTALL_FOLDER = L"InstallFolder";
12static const LPCWSTR WIXSTDBA_VARIABLE_LAUNCH_TARGET_PATH = L"LaunchTarget";
13static const LPCWSTR WIXSTDBA_VARIABLE_LAUNCH_TARGET_ELEVATED_ID = L"LaunchTargetElevatedId";
14static const LPCWSTR WIXSTDBA_VARIABLE_LAUNCH_ARGUMENTS = L"LaunchArguments";
15static const LPCWSTR WIXSTDBA_VARIABLE_LAUNCH_HIDDEN = L"LaunchHidden";
16static const LPCWSTR WIXSTDBA_VARIABLE_LAUNCH_WORK_FOLDER = L"LaunchWorkingFolder";
17
18static const DWORD WIXSTDBA_ACQUIRE_PERCENTAGE = 30;
19
20static const LPCWSTR WIXSTDBA_VARIABLE_BUNDLE_FILE_VERSION = L"WixBundleFileVersion";
21static const LPCWSTR WIXSTDBA_VARIABLE_LANGUAGE_ID = L"WixStdBALanguageId";
22static const LPCWSTR WIXSTDBA_VARIABLE_RESTART_REQUIRED = L"WixStdBARestartRequired";
23static const LPCWSTR WIXSTDBA_VARIABLE_SHOW_VERSION = L"WixStdBAShowVersion";
24static const LPCWSTR WIXSTDBA_VARIABLE_SUPPRESS_OPTIONS_UI = L"WixStdBASuppressOptionsUI";
25
26enum WIXSTDBA_STATE
27{
28 WIXSTDBA_STATE_INITIALIZING,
29 WIXSTDBA_STATE_INITIALIZED,
30 WIXSTDBA_STATE_HELP,
31 WIXSTDBA_STATE_DETECTING,
32 WIXSTDBA_STATE_DETECTED,
33 WIXSTDBA_STATE_PLANNING,
34 WIXSTDBA_STATE_PLANNED,
35 WIXSTDBA_STATE_APPLYING,
36 WIXSTDBA_STATE_CACHING,
37 WIXSTDBA_STATE_CACHED,
38 WIXSTDBA_STATE_EXECUTING,
39 WIXSTDBA_STATE_EXECUTED,
40 WIXSTDBA_STATE_APPLIED,
41 WIXSTDBA_STATE_FAILED,
42};
43
44enum WM_WIXSTDBA
45{
46 WM_WIXSTDBA_SHOW_HELP = WM_APP + 100,
47 WM_WIXSTDBA_DETECT_PACKAGES,
48 WM_WIXSTDBA_PLAN_PACKAGES,
49 WM_WIXSTDBA_APPLY_PACKAGES,
50 WM_WIXSTDBA_CHANGE_STATE,
51 WM_WIXSTDBA_SHOW_FAILURE,
52};
53
54// This enum must be kept in the same order as the vrgwzPageNames array.
55enum WIXSTDBA_PAGE
56{
57 WIXSTDBA_PAGE_LOADING,
58 WIXSTDBA_PAGE_HELP,
59 WIXSTDBA_PAGE_INSTALL,
60 WIXSTDBA_PAGE_MODIFY,
61 WIXSTDBA_PAGE_PROGRESS,
62 WIXSTDBA_PAGE_PROGRESS_PASSIVE,
63 WIXSTDBA_PAGE_SUCCESS,
64 WIXSTDBA_PAGE_FAILURE,
65 COUNT_WIXSTDBA_PAGE,
66};
67
68// This array must be kept in the same order as the WIXSTDBA_PAGE enum.
69static LPCWSTR vrgwzPageNames[] = {
70 L"Loading",
71 L"Help",
72 L"Install",
73 L"Modify",
74 L"Progress",
75 L"ProgressPassive",
76 L"Success",
77 L"Failure",
78};
79
80enum WIXSTDBA_CONTROL
81{
82 // Welcome page
83 WIXSTDBA_CONTROL_INSTALL_BUTTON = THEME_FIRST_ASSIGN_CONTROL_ID,
84 WIXSTDBA_CONTROL_EULA_RICHEDIT,
85 WIXSTDBA_CONTROL_EULA_LINK,
86 WIXSTDBA_CONTROL_EULA_ACCEPT_CHECKBOX,
87
88 // Modify page
89 WIXSTDBA_CONTROL_REPAIR_BUTTON,
90 WIXSTDBA_CONTROL_UNINSTALL_BUTTON,
91
92 // Progress page
93 WIXSTDBA_CONTROL_CACHE_PROGRESS_PACKAGE_TEXT,
94 WIXSTDBA_CONTROL_CACHE_PROGRESS_BAR,
95 WIXSTDBA_CONTROL_CACHE_PROGRESS_TEXT,
96
97 WIXSTDBA_CONTROL_EXECUTE_PROGRESS_PACKAGE_TEXT,
98 WIXSTDBA_CONTROL_EXECUTE_PROGRESS_BAR,
99 WIXSTDBA_CONTROL_EXECUTE_PROGRESS_TEXT,
100 WIXSTDBA_CONTROL_EXECUTE_PROGRESS_ACTIONDATA_TEXT,
101
102 WIXSTDBA_CONTROL_OVERALL_PROGRESS_PACKAGE_TEXT,
103 WIXSTDBA_CONTROL_OVERALL_PROGRESS_BAR,
104 WIXSTDBA_CONTROL_OVERALL_CALCULATED_PROGRESS_BAR,
105 WIXSTDBA_CONTROL_OVERALL_PROGRESS_TEXT,
106
107 WIXSTDBA_CONTROL_PROGRESS_CANCEL_BUTTON,
108
109 // Success page
110 WIXSTDBA_CONTROL_LAUNCH_BUTTON,
111 WIXSTDBA_CONTROL_SUCCESS_RESTART_BUTTON,
112
113 // Failure page
114 WIXSTDBA_CONTROL_FAILURE_LOGFILE_LINK,
115 WIXSTDBA_CONTROL_FAILURE_MESSAGE_TEXT,
116 WIXSTDBA_CONTROL_FAILURE_RESTART_BUTTON,
117};
118
119static THEME_ASSIGN_CONTROL_ID vrgInitControls[] = {
120 { WIXSTDBA_CONTROL_INSTALL_BUTTON, L"InstallButton" },
121 { WIXSTDBA_CONTROL_EULA_RICHEDIT, L"EulaRichedit" },
122 { WIXSTDBA_CONTROL_EULA_LINK, L"EulaHyperlink" },
123 { WIXSTDBA_CONTROL_EULA_ACCEPT_CHECKBOX, L"EulaAcceptCheckbox" },
124
125 { WIXSTDBA_CONTROL_REPAIR_BUTTON, L"RepairButton" },
126 { WIXSTDBA_CONTROL_UNINSTALL_BUTTON, L"UninstallButton" },
127
128 { WIXSTDBA_CONTROL_CACHE_PROGRESS_PACKAGE_TEXT, L"CacheProgressPackageText" },
129 { WIXSTDBA_CONTROL_CACHE_PROGRESS_BAR, L"CacheProgressbar" },
130 { WIXSTDBA_CONTROL_CACHE_PROGRESS_TEXT, L"CacheProgressText" },
131 { WIXSTDBA_CONTROL_EXECUTE_PROGRESS_PACKAGE_TEXT, L"ExecuteProgressPackageText" },
132 { WIXSTDBA_CONTROL_EXECUTE_PROGRESS_BAR, L"ExecuteProgressbar" },
133 { WIXSTDBA_CONTROL_EXECUTE_PROGRESS_TEXT, L"ExecuteProgressText" },
134 { WIXSTDBA_CONTROL_EXECUTE_PROGRESS_ACTIONDATA_TEXT, L"ExecuteProgressActionDataText"},
135 { WIXSTDBA_CONTROL_OVERALL_PROGRESS_PACKAGE_TEXT, L"OverallProgressPackageText" },
136 { WIXSTDBA_CONTROL_OVERALL_PROGRESS_BAR, L"OverallProgressbar" },
137 { WIXSTDBA_CONTROL_OVERALL_CALCULATED_PROGRESS_BAR, L"OverallCalculatedProgressbar" },
138 { WIXSTDBA_CONTROL_OVERALL_PROGRESS_TEXT, L"OverallProgressText" },
139 { WIXSTDBA_CONTROL_PROGRESS_CANCEL_BUTTON, L"ProgressCancelButton" },
140
141 { WIXSTDBA_CONTROL_LAUNCH_BUTTON, L"LaunchButton" },
142 { WIXSTDBA_CONTROL_SUCCESS_RESTART_BUTTON, L"SuccessRestartButton" },
143
144 { WIXSTDBA_CONTROL_FAILURE_LOGFILE_LINK, L"FailureLogFileLink" },
145 { WIXSTDBA_CONTROL_FAILURE_MESSAGE_TEXT, L"FailureMessageText" },
146 { WIXSTDBA_CONTROL_FAILURE_RESTART_BUTTON, L"FailureRestartButton" },
147};
148
149typedef struct _WIXSTDBA_PACKAGE_INFO
150{
151 LPWSTR sczPackageId;
152 BOOL fWasAlreadyInstalled;
153 BOOL fPlannedToBeInstalled;
154 BOOL fSuccessfullyInstalled;
155} WIXSTDBA_PACKAGE_INFO;
156
157
158static HRESULT DAPI EvaluateVariableConditionCallback(
159 __in_z LPCWSTR wzCondition,
160 __out BOOL* pf,
161 __in_opt LPVOID pvContext
162 );
163static HRESULT DAPI FormatVariableStringCallback(
164 __in_z LPCWSTR wzFormat,
165 __inout LPWSTR* psczOut,
166 __in_opt LPVOID pvContext
167 );
168static HRESULT DAPI GetVariableNumericCallback(
169 __in_z LPCWSTR wzVariable,
170 __out LONGLONG* pllValue,
171 __in_opt LPVOID pvContext
172 );
173static HRESULT DAPI SetVariableNumericCallback(
174 __in_z LPCWSTR wzVariable,
175 __in LONGLONG llValue,
176 __in_opt LPVOID pvContext
177 );
178static HRESULT DAPI GetVariableStringCallback(
179 __in_z LPCWSTR wzVariable,
180 __inout LPWSTR* psczValue,
181 __in_opt LPVOID pvContext
182 );
183static HRESULT DAPI SetVariableStringCallback(
184 __in_z LPCWSTR wzVariable,
185 __in_z_opt LPCWSTR wzValue,
186 __in BOOL fFormatted,
187 __in_opt LPVOID pvContext
188 );
189static LPCSTR LoggingRequestStateToString(
190 __in BOOTSTRAPPER_REQUEST_STATE requestState
191 );
192static LPCSTR LoggingMsiFeatureStateToString(
193 __in BOOTSTRAPPER_FEATURE_STATE featureState
194 );
195
196
197class CWixStandardBootstrapperApplication : public CBalBaseBootstrapperApplication
198{
199public: // IBootstrapperApplication
200 virtual STDMETHODIMP OnStartup()
201 {
202 HRESULT hr = S_OK;
203 DWORD dwUIThreadId = 0;
204
205 // create UI thread
206 m_hUiThread = ::CreateThread(NULL, 0, UiThreadProc, this, 0, &dwUIThreadId);
207 if (!m_hUiThread)
208 {
209 ExitWithLastError(hr, "Failed to create UI thread.");
210 }
211
212 LExit:
213 return hr;
214 }
215
216
217 virtual STDMETHODIMP OnShutdown(
218 __inout BOOTSTRAPPER_SHUTDOWN_ACTION* pAction
219 )
220 {
221 HRESULT hr = S_OK;
222
223 // wait for UI thread to terminate
224 if (m_hUiThread)
225 {
226 ::WaitForSingleObject(m_hUiThread, INFINITE);
227 ReleaseHandle(m_hUiThread);
228 }
229
230 // If a restart was required.
231 if (m_fRestartRequired)
232 {
233 if (m_fAllowRestart)
234 {
235 *pAction = BOOTSTRAPPER_SHUTDOWN_ACTION_RESTART;
236 }
237
238 if (m_fPrereq)
239 {
240 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, m_fAllowRestart ? "The prerequisites scheduled a restart. The bootstrapper application will be reloaded after the computer is restarted."
241 : "A restart is required by the prerequisites but the user delayed it. The bootstrapper application will be reloaded after the computer is restarted.");
242 }
243 }
244 else if (m_fPrereqInstalled)
245 {
246 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "The prerequisites were successfully installed. The bootstrapper application will be reloaded.");
247 *pAction = BOOTSTRAPPER_SHUTDOWN_ACTION_RELOAD_BOOTSTRAPPER;
248 }
249 else if (m_fPrereqAlreadyInstalled)
250 {
251 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "The prerequisites were already installed. The bootstrapper application will not be reloaded to prevent an infinite loop.");
252 }
253 else if (m_fPrereq)
254 {
255 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "The prerequisites were not successfully installed, error: 0x%x. The bootstrapper application will be not reloaded.", m_hrFinal);
256 }
257
258 return hr;
259 }
260
261
262 virtual STDMETHODIMP OnDetectRelatedBundle(
263 __in LPCWSTR wzBundleId,
264 __in BOOTSTRAPPER_RELATION_TYPE relationType,
265 __in LPCWSTR wzBundleTag,
266 __in BOOL fPerMachine,
267 __in LPCWSTR wzVersion,
268 __in BOOTSTRAPPER_RELATED_OPERATION operation,
269 __in BOOL fMissingFromCache,
270 __inout BOOL* pfCancel
271 )
272 {
273 BAL_INFO_PACKAGE* pPackage = NULL;
274
275 if (!fMissingFromCache)
276 {
277 if (SUCCEEDED(BalInfoAddRelatedBundleAsPackage(&m_Bundle.packages, wzBundleId, relationType, fPerMachine, &pPackage)))
278 {
279 InitializePackageInfoForPackage(pPackage);
280 }
281
282 // If we're not doing a prerequisite install, remember when our bundle would cause a downgrade.
283 if (!m_fPrereq && BOOTSTRAPPER_RELATED_OPERATION_DOWNGRADE == operation)
284 {
285 m_fDowngrading = TRUE;
286 }
287 }
288
289 return CBalBaseBootstrapperApplication::OnDetectRelatedBundle(wzBundleId, relationType, wzBundleTag, fPerMachine, wzVersion, operation, fMissingFromCache, pfCancel);
290 }
291
292
293 virtual STDMETHODIMP OnDetectPackageComplete(
294 __in LPCWSTR wzPackageId,
295 __in HRESULT /*hrStatus*/,
296 __in BOOTSTRAPPER_PACKAGE_STATE state
297 )
298 {
299 WIXSTDBA_PACKAGE_INFO* pPackageInfo = NULL;
300 BAL_INFO_PACKAGE* pPackage = NULL;
301
302 if (BOOTSTRAPPER_PACKAGE_STATE_PRESENT == state &&
303 SUCCEEDED(GetPackageInfo(wzPackageId, &pPackageInfo, &pPackage)) &&
304 pPackageInfo)
305 {
306 // If the package is already installed, remember that.
307 pPackageInfo->fWasAlreadyInstalled = TRUE;
308 }
309
310 return S_OK;
311 }
312
313
314 virtual STDMETHODIMP OnDetectComplete(
315 __in HRESULT hrStatus,
316 __in BOOL /*fEligibleForCleanup*/
317 )
318 {
319 HRESULT hr = S_OK;
320 // If we're not interacting with the user or we're doing a layout or we're resuming just after a force restart
321 // then automatically start planning.
322 BOOL fSkipToPlan = SUCCEEDED(hrStatus) &&
323 (BOOTSTRAPPER_DISPLAY_FULL > m_command.display ||
324 BOOTSTRAPPER_ACTION_LAYOUT == m_command.action ||
325 BOOTSTRAPPER_RESUME_TYPE_REBOOT == m_command.resumeType);
326 // If we're requiring user input (which currently means Install, Repair, or Uninstall)
327 // or if we're skipping to an action that modifies machine state
328 // then evaluate conditions.
329 BOOL fEvaluateConditions = SUCCEEDED(hrStatus) &&
330 (!fSkipToPlan || BOOTSTRAPPER_ACTION_LAYOUT < m_command.action && BOOTSTRAPPER_ACTION_UPDATE_REPLACE > m_command.action);
331
332 if (fEvaluateConditions)
333 {
334 hrStatus = EvaluateConditions();
335 }
336
337 if (FAILED(hrStatus))
338 {
339 fSkipToPlan = FALSE;
340 }
341 else
342 {
343 if (m_fPrereq)
344 {
345 m_fPrereqAlreadyInstalled = TRUE;
346
347 // At this point we have to assume that all prerequisite packages need to be installed, so set to false if any of them aren't installed.
348 for (DWORD i = 0; i < m_Bundle.packages.cPackages; ++i)
349 {
350 BAL_INFO_PACKAGE* pPackage = &m_Bundle.packages.rgPackages[i];
351 WIXSTDBA_PACKAGE_INFO* pPackageInfo = reinterpret_cast<WIXSTDBA_PACKAGE_INFO*>(pPackage->pvCustomData);
352 if (pPackage->fPrereqPackage && pPackageInfo && !pPackageInfo->fWasAlreadyInstalled)
353 {
354 m_fPrereqAlreadyInstalled = FALSE;
355 break;
356 }
357 }
358 }
359 }
360
361 SetState(WIXSTDBA_STATE_DETECTED, hrStatus);
362
363 if (fSkipToPlan)
364 {
365 ::PostMessageW(m_hWnd, WM_WIXSTDBA_PLAN_PACKAGES, 0, m_command.action);
366 }
367
368 return hr;
369 }
370
371
372 virtual STDMETHODIMP OnPlanRelatedBundle(
373 __in_z LPCWSTR wzBundleId,
374 __in BOOTSTRAPPER_REQUEST_STATE recommendedState,
375 __inout_z BOOTSTRAPPER_REQUEST_STATE* pRequestedState,
376 __inout BOOL* pfCancel
377 )
378 {
379 // If we're only installing prerequisites, do not touch related bundles.
380 if (m_fPrereq)
381 {
382 *pRequestedState = BOOTSTRAPPER_REQUEST_STATE_NONE;
383 }
384
385 return CBalBaseBootstrapperApplication::OnPlanRelatedBundle(wzBundleId, recommendedState, pRequestedState, pfCancel);
386 }
387
388
389 virtual STDMETHODIMP OnPlanPackageBegin(
390 __in_z LPCWSTR wzPackageId,
391 __in BOOTSTRAPPER_PACKAGE_STATE state,
392 __in BOOL fCached,
393 __in BOOTSTRAPPER_PACKAGE_CONDITION_RESULT installCondition,
394 __in BOOTSTRAPPER_REQUEST_STATE recommendedState,
395 __in BOOTSTRAPPER_CACHE_TYPE recommendedCacheType,
396 __inout BOOTSTRAPPER_REQUEST_STATE* pRequestState,
397 __inout BOOTSTRAPPER_CACHE_TYPE* pRequestedCacheType,
398 __inout BOOL* pfCancel
399 )
400 {
401 HRESULT hr = S_OK;
402 WIXSTDBA_PACKAGE_INFO* pPackageInfo = NULL;
403 BAL_INFO_PACKAGE* pPackage = NULL;
404
405 // If we're planning to install prerequisites, install them. The prerequisites need to be installed
406 // in all cases (even uninstall!) so the BA can load next.
407 if (m_fPrereq)
408 {
409 // Only install prerequisite packages, and check the InstallCondition on them.
410 BOOL fInstall = FALSE;
411 hr = GetPackageInfo(wzPackageId, &pPackageInfo, &pPackage);
412 if (SUCCEEDED(hr) && pPackage->fPrereqPackage && pPackageInfo)
413 {
414 pPackageInfo->fPlannedToBeInstalled = fInstall = BOOTSTRAPPER_PACKAGE_CONDITION_FALSE != installCondition;
415 }
416
417 if (fInstall)
418 {
419 *pRequestState = BOOTSTRAPPER_REQUEST_STATE_PRESENT;
420 }
421 else
422 {
423 *pRequestState = BOOTSTRAPPER_REQUEST_STATE_NONE;
424 }
425
426 // Don't force cache packages while installing prerequisites.
427 if (BOOTSTRAPPER_CACHE_TYPE_FORCE == *pRequestedCacheType)
428 {
429 *pRequestedCacheType = BOOTSTRAPPER_CACHE_TYPE_KEEP;
430 }
431 }
432 else if (m_sczAfterForcedRestartPackage) // after force restart, skip packages until after the package that caused the restart.
433 {
434 // After restart we need to finish the dependency registration for our package so allow the package
435 // to go present.
436 if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzPackageId, -1, m_sczAfterForcedRestartPackage, -1))
437 {
438 // Do not allow a repair because that could put us in a perpetual restart loop.
439 if (BOOTSTRAPPER_REQUEST_STATE_REPAIR == *pRequestState)
440 {
441 *pRequestState = BOOTSTRAPPER_REQUEST_STATE_PRESENT;
442 }
443
444 ReleaseNullStr(m_sczAfterForcedRestartPackage); // no more skipping now.
445 }
446 else // not the matching package, so skip it.
447 {
448 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Skipping package: %ls, after restart because it was applied before the restart.", wzPackageId);
449
450 *pRequestState = BOOTSTRAPPER_REQUEST_STATE_NONE;
451 }
452 }
453
454 return CBalBaseBootstrapperApplication::OnPlanPackageBegin(wzPackageId, state, fCached, installCondition, recommendedState, recommendedCacheType, pRequestState, pRequestedCacheType, pfCancel);
455 }
456
457
458 virtual STDMETHODIMP OnPlanMsiPackage(
459 __in_z LPCWSTR wzPackageId,
460 __in BOOL fExecute,
461 __in BOOTSTRAPPER_ACTION_STATE action,
462 __inout BOOL* pfCancel,
463 __inout BURN_MSI_PROPERTY* pActionMsiProperty,
464 __inout INSTALLUILEVEL* pUiLevel,
465 __inout BOOL* pfDisableExternalUiHandler
466 )
467 {
468 HRESULT hr = S_OK;
469 WIXSTDBA_PACKAGE_INFO* pPackageInfo = NULL;
470 BAL_INFO_PACKAGE* pPackage = NULL;
471 BOOL fShowInternalUI = FALSE;
472 INSTALLUILEVEL uiLevel = INSTALLUILEVEL_NOCHANGE;
473
474 switch (m_command.display)
475 {
476 case BOOTSTRAPPER_DISPLAY_FULL:
477 uiLevel = INSTALLUILEVEL_FULL;
478 break;
479
480 case BOOTSTRAPPER_DISPLAY_PASSIVE:
481 uiLevel = INSTALLUILEVEL_REDUCED;
482 break;
483 }
484
485 if (INSTALLUILEVEL_NOCHANGE != uiLevel)
486 {
487 hr = GetPackageInfo(wzPackageId, &pPackageInfo, &pPackage);
488 if (SUCCEEDED(hr) && pPackage->sczDisplayInternalUICondition)
489 {
490 hr = BalEvaluateCondition(pPackage->sczDisplayInternalUICondition, &fShowInternalUI);
491 BalExitOnFailure(hr, "Failed to evaluate condition for package '%ls': %ls", wzPackageId, pPackage->sczDisplayInternalUICondition);
492
493 if (fShowInternalUI)
494 {
495 *pUiLevel = uiLevel;
496 }
497 }
498 }
499
500 LExit:
501 return __super::OnPlanMsiPackage(wzPackageId, fExecute, action, pfCancel, pActionMsiProperty, pUiLevel, pfDisableExternalUiHandler);
502 }
503
504
505 virtual STDMETHODIMP OnPlanComplete(
506 __in HRESULT hrStatus
507 )
508 {
509 HRESULT hr = S_OK;
510
511 if (m_fPrereq)
512 {
513 m_fPrereqAlreadyInstalled = TRUE;
514
515 // Now that we've planned the packages, we can focus on the prerequisite packages that are supposed to be installed.
516 for (DWORD i = 0; i < m_Bundle.packages.cPackages; ++i)
517 {
518 BAL_INFO_PACKAGE* pPackage = &m_Bundle.packages.rgPackages[i];
519 WIXSTDBA_PACKAGE_INFO* pPackageInfo = reinterpret_cast<WIXSTDBA_PACKAGE_INFO*>(pPackage->pvCustomData);
520 if (pPackage->fPrereqPackage && pPackageInfo && !pPackageInfo->fWasAlreadyInstalled && pPackageInfo->fPlannedToBeInstalled)
521 {
522 m_fPrereqAlreadyInstalled = FALSE;
523 break;
524 }
525 }
526 }
527
528 SetState(WIXSTDBA_STATE_PLANNED, hrStatus);
529
530 if (SUCCEEDED(hrStatus))
531 {
532 ::PostMessageW(m_hWnd, WM_WIXSTDBA_APPLY_PACKAGES, 0, 0);
533 }
534
535 m_fStartedExecution = FALSE;
536 m_dwCalculatedCacheProgress = 0;
537 m_dwCalculatedExecuteProgress = 0;
538
539 return hr;
540 }
541
542
543 virtual STDMETHODIMP OnPauseAutomaticUpdatesBegin(
544 )
545 {
546 HRESULT hr = S_OK;
547 LOC_STRING* pLocString = NULL;
548 LPWSTR sczFormattedString = NULL;
549 LPCWSTR wz = NULL;
550
551 hr = __super::OnPauseAutomaticUpdatesBegin();
552
553 LocGetString(m_pWixLoc, L"#(loc.PauseAutomaticUpdatesMessage)", &pLocString);
554
555 if (pLocString)
556 {
557 BalFormatString(pLocString->wzText, &sczFormattedString);
558 }
559
560 wz = sczFormattedString ? sczFormattedString : L"Pausing Windows automatic updates";
561
562 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_OVERALL_PROGRESS_PACKAGE_TEXT, wz);
563
564 ReleaseStr(sczFormattedString);
565 return hr;
566 }
567
568
569 virtual STDMETHODIMP OnSystemRestorePointBegin(
570 )
571 {
572 HRESULT hr = S_OK;
573 LOC_STRING* pLocString = NULL;
574 LPWSTR sczFormattedString = NULL;
575 LPCWSTR wz = NULL;
576
577 hr = __super::OnSystemRestorePointBegin();
578
579 LocGetString(m_pWixLoc, L"#(loc.SystemRestorePointMessage)", &pLocString);
580
581 if (pLocString)
582 {
583 BalFormatString(pLocString->wzText, &sczFormattedString);
584 }
585
586 wz = sczFormattedString ? sczFormattedString : L"Creating system restore point";
587
588 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_OVERALL_PROGRESS_PACKAGE_TEXT, wz);
589
590 ReleaseStr(sczFormattedString);
591 return hr;
592 }
593
594
595 virtual STDMETHODIMP OnCachePackageBegin(
596 __in_z LPCWSTR wzPackageId,
597 __in DWORD cCachePayloads,
598 __in DWORD64 dw64PackageCacheSize,
599 __inout BOOL* pfCancel
600 )
601 {
602 if (wzPackageId && *wzPackageId)
603 {
604 BAL_INFO_PACKAGE* pPackage = NULL;
605 HRESULT hr = BalInfoFindPackageById(&m_Bundle.packages, wzPackageId, &pPackage);
606 LPCWSTR wz = (SUCCEEDED(hr) && pPackage->sczDisplayName) ? pPackage->sczDisplayName : wzPackageId;
607
608 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_CACHE_PROGRESS_PACKAGE_TEXT, wz);
609
610 // If something started executing, leave it in the overall progress text.
611 if (!m_fStartedExecution)
612 {
613 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_OVERALL_PROGRESS_PACKAGE_TEXT, wz);
614 }
615 }
616
617 return __super::OnCachePackageBegin(wzPackageId, cCachePayloads, dw64PackageCacheSize, pfCancel);
618 }
619
620
621 virtual STDMETHODIMP OnCacheAcquireProgress(
622 __in_z LPCWSTR wzPackageOrContainerId,
623 __in_z_opt LPCWSTR wzPayloadId,
624 __in DWORD64 dw64Progress,
625 __in DWORD64 dw64Total,
626 __in DWORD dwOverallPercentage,
627 __inout BOOL* pfCancel
628 )
629 {
630#ifdef DEBUG
631 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "WIXSTDBA: OnCacheAcquireProgress() - container/package: %ls, payload: %ls, progress: %I64u, total: %I64u, overall progress: %u%%", wzPackageOrContainerId, wzPayloadId, dw64Progress, dw64Total, dwOverallPercentage);
632#endif
633
634 UpdateCacheProgress(dwOverallPercentage);
635
636 return __super::OnCacheAcquireProgress(wzPackageOrContainerId, wzPayloadId, dw64Progress, dw64Total, dwOverallPercentage, pfCancel);
637 }
638
639
640 virtual STDMETHODIMP OnCacheContainerOrPayloadVerifyProgress(
641 __in_z LPCWSTR wzPackageOrContainerId,
642 __in_z_opt LPCWSTR wzPayloadId,
643 __in DWORD64 dw64Progress,
644 __in DWORD64 dw64Total,
645 __in DWORD dwOverallPercentage,
646 __inout BOOL* pfCancel
647 )
648 {
649#ifdef DEBUG
650 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "WIXSTDBA: OnCacheContainerOrPayloadVerifyProgress() - container/package: %ls, payload: %ls, progress: %I64u, total: %I64u, overall progress: %u%%", wzPackageOrContainerId, wzPayloadId, dw64Progress, dw64Total, dwOverallPercentage);
651#endif
652
653 UpdateCacheProgress(dwOverallPercentage);
654
655 return __super::OnCacheContainerOrPayloadVerifyProgress(wzPackageOrContainerId, wzPayloadId, dw64Progress, dw64Total, dwOverallPercentage, pfCancel);
656 }
657
658
659 virtual STDMETHODIMP OnCachePayloadExtractProgress(
660 __in_z LPCWSTR wzPackageOrContainerId,
661 __in_z_opt LPCWSTR wzPayloadId,
662 __in DWORD64 dw64Progress,
663 __in DWORD64 dw64Total,
664 __in DWORD dwOverallPercentage,
665 __inout BOOL* pfCancel
666 )
667 {
668#ifdef DEBUG
669 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "WIXSTDBA: OnCachePayloadExtractProgress() - container/package: %ls, payload: %ls, progress: %I64u, total: %I64u, overall progress: %u%%", wzPackageOrContainerId, wzPayloadId, dw64Progress, dw64Total, dwOverallPercentage);
670#endif
671
672 UpdateCacheProgress(dwOverallPercentage);
673
674 return __super::OnCachePayloadExtractProgress(wzPackageOrContainerId, wzPayloadId, dw64Progress, dw64Total, dwOverallPercentage, pfCancel);
675 }
676
677
678 virtual STDMETHODIMP OnCacheVerifyProgress(
679 __in_z LPCWSTR wzPackageOrContainerId,
680 __in_z_opt LPCWSTR wzPayloadId,
681 __in DWORD64 dw64Progress,
682 __in DWORD64 dw64Total,
683 __in DWORD dwOverallPercentage,
684 __in BOOTSTRAPPER_CACHE_VERIFY_STEP verifyStep,
685 __inout BOOL* pfCancel
686 )
687 {
688#ifdef DEBUG
689 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "WIXSTDBA: OnCacheVerifyProgress() - container/package: %ls, payload: %ls, progress: %I64u, total: %I64u, overall progress: %u%%, step: %u", wzPackageOrContainerId, wzPayloadId, dw64Progress, dw64Total, dwOverallPercentage, verifyStep);
690#endif
691
692 UpdateCacheProgress(dwOverallPercentage);
693
694 return __super::OnCacheVerifyProgress(wzPackageOrContainerId, wzPayloadId, dw64Progress, dw64Total, dwOverallPercentage, verifyStep, pfCancel);
695 }
696
697
698 virtual STDMETHODIMP OnCacheAcquireComplete(
699 __in_z LPCWSTR wzPackageOrContainerId,
700 __in_z_opt LPCWSTR wzPayloadId,
701 __in HRESULT hrStatus,
702 __in BOOTSTRAPPER_CACHEACQUIRECOMPLETE_ACTION recommendation,
703 __inout BOOTSTRAPPER_CACHEACQUIRECOMPLETE_ACTION* pAction
704 )
705 {
706 SetProgressState(hrStatus);
707 return __super::OnCacheAcquireComplete(wzPackageOrContainerId, wzPayloadId, hrStatus, recommendation, pAction);
708 }
709
710
711 virtual STDMETHODIMP OnCacheContainerOrPayloadVerifyComplete(
712 __in_z LPCWSTR wzPackageOrContainerId,
713 __in_z_opt LPCWSTR wzPayloadId,
714 __in HRESULT hrStatus
715 )
716 {
717 SetProgressState(hrStatus);
718 return __super::OnCacheContainerOrPayloadVerifyComplete(wzPackageOrContainerId, wzPayloadId, hrStatus);
719 }
720
721
722 virtual STDMETHODIMP OnCachePayloadExtractComplete(
723 __in_z LPCWSTR wzPackageOrContainerId,
724 __in_z_opt LPCWSTR wzPayloadId,
725 __in HRESULT hrStatus
726 )
727 {
728 SetProgressState(hrStatus);
729 return __super::OnCachePayloadExtractComplete(wzPackageOrContainerId, wzPayloadId, hrStatus);
730 }
731
732
733 virtual STDMETHODIMP OnCacheVerifyComplete(
734 __in_z LPCWSTR wzPackageId,
735 __in_z LPCWSTR wzPayloadId,
736 __in HRESULT hrStatus,
737 __in BOOTSTRAPPER_CACHEVERIFYCOMPLETE_ACTION recommendation,
738 __inout BOOTSTRAPPER_CACHEVERIFYCOMPLETE_ACTION* pAction
739 )
740 {
741 SetProgressState(hrStatus);
742 return __super::OnCacheVerifyComplete(wzPackageId, wzPayloadId, hrStatus, recommendation, pAction);
743 }
744
745
746 virtual STDMETHODIMP OnCacheComplete(
747 __in HRESULT hrStatus
748 )
749 {
750 UpdateCacheProgress(SUCCEEDED(hrStatus) ? 100 : 0);
751 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_CACHE_PROGRESS_PACKAGE_TEXT, L"");
752 SetState(WIXSTDBA_STATE_CACHED, S_OK); // we always return success here and let OnApplyComplete() deal with the error.
753 return __super::OnCacheComplete(hrStatus);
754 }
755
756
757 virtual STDMETHODIMP OnError(
758 __in BOOTSTRAPPER_ERROR_TYPE errorType,
759 __in LPCWSTR wzPackageId,
760 __in DWORD dwCode,
761 __in_z LPCWSTR wzError,
762 __in DWORD dwUIHint,
763 __in DWORD /*cData*/,
764 __in_ecount_z_opt(cData) LPCWSTR* /*rgwzData*/,
765 __in int /*nRecommendation*/,
766 __inout int* pResult
767 )
768 {
769 HRESULT hr = S_OK;
770 int nResult = *pResult;
771 LPWSTR sczError = NULL;
772
773 if (BOOTSTRAPPER_DISPLAY_EMBEDDED == m_command.display)
774 {
775 hr = m_pEngine->SendEmbeddedError(dwCode, wzError, dwUIHint, &nResult);
776 if (FAILED(hr))
777 {
778 nResult = IDERROR;
779 }
780 }
781 else if (BOOTSTRAPPER_DISPLAY_FULL == m_command.display)
782 {
783 // If this is an authentication failure, let the engine try to handle it for us.
784 if (BOOTSTRAPPER_ERROR_TYPE_HTTP_AUTH_SERVER == errorType || BOOTSTRAPPER_ERROR_TYPE_HTTP_AUTH_PROXY == errorType)
785 {
786 nResult = IDTRYAGAIN;
787 }
788 else // show a generic error message box.
789 {
790 BalRetryErrorOccurred(wzPackageId, dwCode);
791
792 if (!m_fShowingInternalUiThisPackage)
793 {
794 // If no error message was provided, use the error code to try and get an error message.
795 if (!wzError || !*wzError || BOOTSTRAPPER_ERROR_TYPE_WINDOWS_INSTALLER != errorType)
796 {
797 hr = StrAllocFromError(&sczError, dwCode, NULL);
798 if (FAILED(hr) || !sczError || !*sczError)
799 {
800 // special case for ERROR_FAIL_NOACTION_REBOOT: use loc string for Windows XP
801 if (ERROR_FAIL_NOACTION_REBOOT == dwCode)
802 {
803 LOC_STRING* pLocString = NULL;
804 hr = LocGetString(m_pWixLoc, L"#(loc.ErrorFailNoActionReboot)", &pLocString);
805 if (SUCCEEDED(hr))
806 {
807 StrAllocString(&sczError, pLocString->wzText, 0);
808 }
809 else
810 {
811 StrAllocFormatted(&sczError, L"0x%x", dwCode);
812 }
813 }
814 else
815 {
816 StrAllocFormatted(&sczError, L"0x%x", dwCode);
817 }
818 }
819 hr = S_OK;
820 }
821
822 nResult = ::MessageBoxW(m_hWnd, sczError ? sczError : wzError, m_pTheme->sczCaption, dwUIHint);
823 }
824 }
825
826 SetProgressState(HRESULT_FROM_WIN32(dwCode));
827 }
828 else // just take note of the error code and let things continue.
829 {
830 BalRetryErrorOccurred(wzPackageId, dwCode);
831 }
832
833 ReleaseStr(sczError);
834 *pResult = nResult;
835 return hr;
836 }
837
838
839 virtual STDMETHODIMP OnExecuteMsiMessage(
840 __in_z LPCWSTR wzPackageId,
841 __in INSTALLMESSAGE messageType,
842 __in DWORD dwUIHint,
843 __in_z LPCWSTR wzMessage,
844 __in DWORD cData,
845 __in_ecount_z_opt(cData) LPCWSTR* rgwzData,
846 __in int nRecommendation,
847 __inout int* pResult
848 )
849 {
850#ifdef DEBUG
851 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "WIXSTDBA: OnExecuteMsiMessage() - package: %ls, message: %ls", wzPackageId, wzMessage);
852#endif
853 if (BOOTSTRAPPER_DISPLAY_FULL == m_command.display && (INSTALLMESSAGE_WARNING == messageType || INSTALLMESSAGE_USER == messageType))
854 {
855 if (!m_fShowingInternalUiThisPackage)
856 {
857 int nResult = ::MessageBoxW(m_hWnd, wzMessage, m_pTheme->sczCaption, dwUIHint);
858 return nResult;
859 }
860 }
861
862 if (INSTALLMESSAGE_ACTIONSTART == messageType)
863 {
864 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_EXECUTE_PROGRESS_ACTIONDATA_TEXT, wzMessage);
865 }
866
867 return __super::OnExecuteMsiMessage(wzPackageId, messageType, dwUIHint, wzMessage, cData, rgwzData, nRecommendation, pResult);
868 }
869
870
871 virtual STDMETHODIMP OnProgress(
872 __in DWORD dwProgressPercentage,
873 __in DWORD dwOverallProgressPercentage,
874 __inout BOOL* pfCancel
875 )
876 {
877 WCHAR wzProgress[5] = { };
878
879#ifdef DEBUG
880 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "WIXSTDBA: OnProgress() - progress: %u%%, overall progress: %u%%", dwProgressPercentage, dwOverallProgressPercentage);
881#endif
882
883 ::StringCchPrintfW(wzProgress, countof(wzProgress), L"%u%%", dwOverallProgressPercentage);
884 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_OVERALL_PROGRESS_TEXT, wzProgress);
885
886 ThemeSetProgressControl(m_pTheme, WIXSTDBA_CONTROL_OVERALL_PROGRESS_BAR, dwOverallProgressPercentage);
887 SetTaskbarButtonProgress(dwOverallProgressPercentage);
888
889 return __super::OnProgress(dwProgressPercentage, dwOverallProgressPercentage, pfCancel);
890 }
891
892
893 virtual STDMETHODIMP OnExecutePackageBegin(
894 __in_z LPCWSTR wzPackageId,
895 __in BOOL fExecute,
896 __in BOOTSTRAPPER_ACTION_STATE action,
897 __in INSTALLUILEVEL uiLevel,
898 __in BOOL fDisableExternalUiHandler,
899 __inout BOOL* pfCancel
900 )
901 {
902 HRESULT hr = S_OK;
903 LPWSTR sczFormattedString = NULL;
904 BOOL fShowingInternalUiThisPackage = FALSE;
905
906 m_fStartedExecution = TRUE;
907
908 if (wzPackageId && *wzPackageId)
909 {
910 BAL_INFO_PACKAGE* pPackage = NULL;
911 BalInfoFindPackageById(&m_Bundle.packages, wzPackageId, &pPackage);
912
913 LPCWSTR wz = wzPackageId;
914 if (pPackage)
915 {
916 LOC_STRING* pLocString = NULL;
917
918 switch (pPackage->type)
919 {
920 case BAL_INFO_PACKAGE_TYPE_BUNDLE_ADDON:
921 LocGetString(m_pWixLoc, L"#(loc.ExecuteAddonRelatedBundleMessage)", &pLocString);
922 break;
923
924 case BAL_INFO_PACKAGE_TYPE_BUNDLE_PATCH:
925 LocGetString(m_pWixLoc, L"#(loc.ExecutePatchRelatedBundleMessage)", &pLocString);
926 break;
927
928 case BAL_INFO_PACKAGE_TYPE_BUNDLE_UPGRADE:
929 LocGetString(m_pWixLoc, L"#(loc.ExecuteUpgradeRelatedBundleMessage)", &pLocString);
930 break;
931 }
932
933 if (pLocString)
934 {
935 // If the wix developer is showing a hidden variable in the UI, then obviously they don't care about keeping it safe
936 // so don't go down the rabbit hole of making sure that this is securely freed.
937 BalFormatString(pLocString->wzText, &sczFormattedString);
938 }
939
940 wz = sczFormattedString ? sczFormattedString : pPackage->sczDisplayName ? pPackage->sczDisplayName : wzPackageId;
941 }
942
943 fShowingInternalUiThisPackage = INSTALLUILEVEL_NONE != (INSTALLUILEVEL_NONE & uiLevel);
944
945 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_EXECUTE_PROGRESS_PACKAGE_TEXT, wz);
946 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_OVERALL_PROGRESS_PACKAGE_TEXT, wz);
947 }
948
949 ::EnterCriticalSection(&m_csShowingInternalUiThisPackage);
950 m_fShowingInternalUiThisPackage = fShowingInternalUiThisPackage;
951 hr = __super::OnExecutePackageBegin(wzPackageId, fExecute, action, uiLevel, fDisableExternalUiHandler, pfCancel);
952 ::LeaveCriticalSection(&m_csShowingInternalUiThisPackage);
953
954 ReleaseStr(sczFormattedString);
955 return hr;
956 }
957
958
959 virtual STDMETHODIMP OnExecuteProgress(
960 __in_z LPCWSTR wzPackageId,
961 __in DWORD dwProgressPercentage,
962 __in DWORD dwOverallProgressPercentage,
963 __inout BOOL* pfCancel
964 )
965 {
966 WCHAR wzProgress[5] = { };
967
968#ifdef DEBUG
969 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "WIXSTDBA: OnExecuteProgress() - package: %ls, progress: %u%%, overall progress: %u%%", wzPackageId, dwProgressPercentage, dwOverallProgressPercentage);
970#endif
971
972 ::StringCchPrintfW(wzProgress, countof(wzProgress), L"%u%%", dwOverallProgressPercentage);
973 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_EXECUTE_PROGRESS_TEXT, wzProgress);
974
975 ThemeSetProgressControl(m_pTheme, WIXSTDBA_CONTROL_EXECUTE_PROGRESS_BAR, dwOverallProgressPercentage);
976
977 m_dwCalculatedExecuteProgress = dwOverallProgressPercentage * (100 - WIXSTDBA_ACQUIRE_PERCENTAGE) / 100;
978 ThemeSetProgressControl(m_pTheme, WIXSTDBA_CONTROL_OVERALL_CALCULATED_PROGRESS_BAR, m_dwCalculatedCacheProgress + m_dwCalculatedExecuteProgress);
979
980 SetTaskbarButtonProgress(m_dwCalculatedCacheProgress + m_dwCalculatedExecuteProgress);
981
982 return __super::OnExecuteProgress(wzPackageId, dwProgressPercentage, dwOverallProgressPercentage, pfCancel);
983 }
984
985
986 virtual STDMETHODIMP OnExecutePackageComplete(
987 __in_z LPCWSTR wzPackageId,
988 __in HRESULT hrStatus,
989 __in BOOTSTRAPPER_APPLY_RESTART restart,
990 __in BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION recommendation,
991 __inout BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION* pAction
992 )
993 {
994 HRESULT hr = S_OK;
995 SetProgressState(hrStatus);
996
997 hr = __super::OnExecutePackageComplete(wzPackageId, hrStatus, restart, recommendation, pAction);
998
999 WIXSTDBA_PACKAGE_INFO* pPackageInfo = NULL;
1000 BAL_INFO_PACKAGE* pPackage;
1001 HRESULT hrPrereq = GetPackageInfo(wzPackageId, &pPackageInfo, &pPackage);
1002 if (SUCCEEDED(hrPrereq) && pPackageInfo)
1003 {
1004 pPackageInfo->fSuccessfullyInstalled = SUCCEEDED(hrStatus);
1005
1006 // If the prerequisite required a restart (any restart) then do an immediate
1007 // restart to ensure that the bundle will get launched again post reboot.
1008 if (m_fPrereq && pPackage->fPrereqPackage && BOOTSTRAPPER_APPLY_RESTART_NONE != restart)
1009 {
1010 *pAction = BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION_RESTART;
1011 }
1012 }
1013
1014 return hr;
1015 }
1016
1017
1018 virtual STDMETHODIMP OnExecuteComplete(
1019 __in HRESULT hrStatus
1020 )
1021 {
1022 HRESULT hr = S_OK;
1023
1024 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_EXECUTE_PROGRESS_PACKAGE_TEXT, L"");
1025 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_EXECUTE_PROGRESS_ACTIONDATA_TEXT, L"");
1026 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_OVERALL_PROGRESS_PACKAGE_TEXT, L"");
1027 ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_PROGRESS_CANCEL_BUTTON, FALSE); // no more cancel.
1028 m_fShowingInternalUiThisPackage = FALSE;
1029
1030 SetState(WIXSTDBA_STATE_EXECUTED, S_OK); // we always return success here and let OnApplyComplete() deal with the error.
1031 SetProgressState(hrStatus);
1032
1033 return hr;
1034 }
1035
1036
1037 virtual STDMETHODIMP OnCacheAcquireResolving(
1038 __in_z_opt LPCWSTR wzPackageOrContainerId,
1039 __in_z_opt LPCWSTR wzPayloadId,
1040 __in_z LPCWSTR* rgSearchPaths,
1041 __in DWORD /*cSearchPaths*/,
1042 __in BOOL /*fFoundLocal*/,
1043 __in DWORD dwRecommendedSearchPath,
1044 __in_z_opt LPCWSTR /*wzDownloadUrl*/,
1045 __in_z_opt LPCWSTR /*wzPayloadContainerId*/,
1046 __in BOOTSTRAPPER_CACHE_RESOLVE_OPERATION /*recommendation*/,
1047 __inout DWORD* /*pdwChosenSearchPath*/,
1048 __inout BOOTSTRAPPER_CACHE_RESOLVE_OPERATION* pAction,
1049 __inout BOOL* pfCancel
1050 )
1051 {
1052 HRESULT hr = S_OK;
1053
1054 if (BOOTSTRAPPER_CACHE_RESOLVE_NONE == *pAction && BOOTSTRAPPER_DISPLAY_FULL == m_command.display) // prompt to change the source location.
1055 {
1056 OPENFILENAMEW ofn = { };
1057 WCHAR wzFile[MAX_PATH] = { };
1058
1059 ::StringCchCopyW(wzFile, countof(wzFile), rgSearchPaths[dwRecommendedSearchPath]);
1060
1061 ofn.lStructSize = sizeof(ofn);
1062 ofn.hwndOwner = m_hWnd;
1063 ofn.lpstrFile = wzFile;
1064 ofn.nMaxFile = countof(wzFile);
1065 ofn.lpstrFilter = L"All Files\0*.*\0";
1066 ofn.nFilterIndex = 1;
1067 ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
1068 ofn.lpstrTitle = m_pTheme->sczCaption;
1069
1070 if (::GetOpenFileNameW(&ofn))
1071 {
1072 hr = m_pEngine->SetLocalSource(wzPackageOrContainerId, wzPayloadId, ofn.lpstrFile);
1073 *pAction = BOOTSTRAPPER_CACHE_RESOLVE_RETRY;
1074 }
1075 else
1076 {
1077 *pfCancel = TRUE;
1078 }
1079 }
1080 // else there's nothing more we can do in non-interactive mode
1081
1082 *pfCancel |= CheckCanceled();
1083 return hr;
1084 }
1085
1086
1087 virtual STDMETHODIMP OnApplyComplete(
1088 __in HRESULT hrStatus,
1089 __in BOOTSTRAPPER_APPLY_RESTART restart,
1090 __in BOOTSTRAPPER_APPLYCOMPLETE_ACTION recommendation,
1091 __inout BOOTSTRAPPER_APPLYCOMPLETE_ACTION* pAction
1092 )
1093 {
1094 HRESULT hr = S_OK;
1095
1096 __super::OnApplyComplete(hrStatus, restart, recommendation, pAction);
1097
1098 m_restartResult = restart; // remember the restart result so we return the correct error code no matter what the user chooses to do in the UI.
1099
1100 // If a restart was encountered and we are not suppressing restarts, then restart is required.
1101 m_fRestartRequired = (BOOTSTRAPPER_APPLY_RESTART_NONE != restart && BOOTSTRAPPER_RESTART_NEVER < m_command.restart);
1102 BalSetStringVariable(WIXSTDBA_VARIABLE_RESTART_REQUIRED, m_fRestartRequired ? L"1" : NULL, FALSE);
1103
1104 // If a restart is required and we're not displaying a UI or we are not supposed to prompt for restart then allow the restart.
1105 m_fAllowRestart = m_fRestartRequired && (BOOTSTRAPPER_DISPLAY_FULL > m_command.display || BOOTSTRAPPER_RESTART_PROMPT < m_command.restart);
1106
1107 if (m_fPrereq)
1108 {
1109 m_fPrereqInstalled = TRUE;
1110 BOOL fInstalledAPackage = FALSE;
1111
1112 for (DWORD i = 0; i < m_Bundle.packages.cPackages; ++i)
1113 {
1114 BAL_INFO_PACKAGE* pPackage = &m_Bundle.packages.rgPackages[i];
1115 WIXSTDBA_PACKAGE_INFO* pPackageInfo = reinterpret_cast<WIXSTDBA_PACKAGE_INFO*>(pPackage->pvCustomData);
1116 if (pPackage->fPrereqPackage && pPackageInfo && pPackageInfo->fPlannedToBeInstalled && !pPackageInfo->fWasAlreadyInstalled)
1117 {
1118 if (pPackageInfo->fSuccessfullyInstalled)
1119 {
1120 fInstalledAPackage = TRUE;
1121 }
1122 else
1123 {
1124 m_fPrereqInstalled = FALSE;
1125 break;
1126 }
1127 }
1128 }
1129
1130 m_fPrereqInstalled = m_fPrereqInstalled && fInstalledAPackage;
1131 }
1132
1133 // If we are showing UI, wait a beat before moving to the final screen.
1134 if (BOOTSTRAPPER_DISPLAY_NONE < m_command.display)
1135 {
1136 ::Sleep(250);
1137 }
1138
1139 SetState(WIXSTDBA_STATE_APPLIED, hrStatus);
1140 SetTaskbarButtonProgress(100); // show full progress bar, green, yellow, or red
1141
1142 *pAction = BOOTSTRAPPER_APPLYCOMPLETE_ACTION_NONE;
1143
1144 return hr;
1145 }
1146
1147 virtual STDMETHODIMP OnLaunchApprovedExeComplete(
1148 __in HRESULT hrStatus,
1149 __in DWORD /*processId*/
1150 )
1151 {
1152 HRESULT hr = S_OK;
1153
1154 if (HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) == hrStatus)
1155 {
1156 //try with ShelExec next time
1157 OnClickLaunchButton();
1158 }
1159 else
1160 {
1161 ::PostMessageW(m_hWnd, WM_CLOSE, 0, 0);
1162 }
1163
1164 return hr;
1165 }
1166
1167 virtual STDMETHODIMP_(void) BAProcFallback(
1168 __in BOOTSTRAPPER_APPLICATION_MESSAGE message,
1169 __in const LPVOID pvArgs,
1170 __inout LPVOID pvResults,
1171 __inout HRESULT* phr,
1172 __in_opt LPVOID /*pvContext*/
1173 )
1174 {
1175 if (!m_pfnBAFunctionsProc || FAILED(*phr))
1176 {
1177 return;
1178 }
1179
1180 // Always log before and after so we don't get blamed when BAFunctions changes something.
1181 switch (message)
1182 {
1183 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTBEGIN:
1184 OnDetectBeginFallback(reinterpret_cast<BA_ONDETECTBEGIN_ARGS*>(pvArgs), reinterpret_cast<BA_ONDETECTBEGIN_RESULTS*>(pvResults));
1185 break;
1186 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTCOMPLETE:
1187 OnDetectCompleteFallback(reinterpret_cast<BA_ONDETECTCOMPLETE_ARGS*>(pvArgs), reinterpret_cast<BA_ONDETECTCOMPLETE_RESULTS*>(pvResults));
1188 break;
1189 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANBEGIN:
1190 OnPlanBeginFallback(reinterpret_cast<BA_ONPLANBEGIN_ARGS*>(pvArgs), reinterpret_cast<BA_ONPLANBEGIN_RESULTS*>(pvResults));
1191 break;
1192 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANCOMPLETE:
1193 OnPlanCompleteFallback(reinterpret_cast<BA_ONPLANCOMPLETE_ARGS*>(pvArgs), reinterpret_cast<BA_ONPLANCOMPLETE_RESULTS*>(pvResults));
1194 break;
1195 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONSTARTUP: // BAFunctions is loaded during this event on a separate thread so it's not possible to forward it.
1196 break;
1197 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONSHUTDOWN:
1198 OnShutdownFallback(reinterpret_cast<BA_ONSHUTDOWN_ARGS*>(pvArgs), reinterpret_cast<BA_ONSHUTDOWN_RESULTS*>(pvResults));
1199 break;
1200 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONSYSTEMSHUTDOWN:
1201 OnSystemShutdownFallback(reinterpret_cast<BA_ONSYSTEMSHUTDOWN_ARGS*>(pvArgs), reinterpret_cast<BA_ONSYSTEMSHUTDOWN_RESULTS*>(pvResults));
1202 break;
1203 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTFORWARDCOMPATIBLEBUNDLE:
1204 OnDetectForwardCompatibleBundleFallback(reinterpret_cast<BA_ONDETECTFORWARDCOMPATIBLEBUNDLE_ARGS*>(pvArgs), reinterpret_cast<BA_ONDETECTFORWARDCOMPATIBLEBUNDLE_RESULTS*>(pvResults));
1205 break;
1206 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTUPDATEBEGIN:
1207 OnDetectUpdateBeginFallback(reinterpret_cast<BA_ONDETECTUPDATEBEGIN_ARGS*>(pvArgs), reinterpret_cast<BA_ONDETECTUPDATEBEGIN_RESULTS*>(pvResults));
1208 break;
1209 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTUPDATE:
1210 OnDetectUpdateFallback(reinterpret_cast<BA_ONDETECTUPDATE_ARGS*>(pvArgs), reinterpret_cast<BA_ONDETECTUPDATE_RESULTS*>(pvResults));
1211 break;
1212 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTUPDATECOMPLETE:
1213 OnDetectUpdateCompleteFallback(reinterpret_cast<BA_ONDETECTUPDATECOMPLETE_ARGS*>(pvArgs), reinterpret_cast<BA_ONDETECTUPDATECOMPLETE_RESULTS*>(pvResults));
1214 break;
1215 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTRELATEDBUNDLE:
1216 OnDetectRelatedBundleFallback(reinterpret_cast<BA_ONDETECTRELATEDBUNDLE_ARGS*>(pvArgs), reinterpret_cast<BA_ONDETECTRELATEDBUNDLE_RESULTS*>(pvResults));
1217 break;
1218 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTPACKAGEBEGIN:
1219 OnDetectPackageBeginFallback(reinterpret_cast<BA_ONDETECTPACKAGEBEGIN_ARGS*>(pvArgs), reinterpret_cast<BA_ONDETECTPACKAGEBEGIN_RESULTS*>(pvResults));
1220 break;
1221 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTRELATEDMSIPACKAGE:
1222 OnDetectRelatedMsiPackageFallback(reinterpret_cast<BA_ONDETECTRELATEDMSIPACKAGE_ARGS*>(pvArgs), reinterpret_cast<BA_ONDETECTRELATEDMSIPACKAGE_RESULTS*>(pvResults));
1223 break;
1224 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTPATCHTARGET:
1225 OnDetectPatchTargetFallback(reinterpret_cast<BA_ONDETECTPATCHTARGET_ARGS*>(pvArgs), reinterpret_cast<BA_ONDETECTPATCHTARGET_RESULTS*>(pvResults));
1226 break;
1227 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTMSIFEATURE:
1228 OnDetectMsiFeatureFallback(reinterpret_cast<BA_ONDETECTMSIFEATURE_ARGS*>(pvArgs), reinterpret_cast<BA_ONDETECTMSIFEATURE_RESULTS*>(pvResults));
1229 break;
1230 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTPACKAGECOMPLETE:
1231 OnDetectPackageCompleteFallback(reinterpret_cast<BA_ONDETECTPACKAGECOMPLETE_ARGS*>(pvArgs), reinterpret_cast<BA_ONDETECTPACKAGECOMPLETE_RESULTS*>(pvResults));
1232 break;
1233 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANRELATEDBUNDLE:
1234 OnPlanRelatedBundleFallback(reinterpret_cast<BA_ONPLANRELATEDBUNDLE_ARGS*>(pvArgs), reinterpret_cast<BA_ONPLANRELATEDBUNDLE_RESULTS*>(pvResults));
1235 break;
1236 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANPACKAGEBEGIN:
1237 OnPlanPackageBeginFallback(reinterpret_cast<BA_ONPLANPACKAGEBEGIN_ARGS*>(pvArgs), reinterpret_cast<BA_ONPLANPACKAGEBEGIN_RESULTS*>(pvResults));
1238 break;
1239 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANPATCHTARGET:
1240 OnPlanPatchTargetFallback(reinterpret_cast<BA_ONPLANPATCHTARGET_ARGS*>(pvArgs), reinterpret_cast<BA_ONPLANPATCHTARGET_RESULTS*>(pvResults));
1241 break;
1242 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANMSIFEATURE:
1243 OnPlanMsiFeatureFallback(reinterpret_cast<BA_ONPLANMSIFEATURE_ARGS*>(pvArgs), reinterpret_cast<BA_ONPLANMSIFEATURE_RESULTS*>(pvResults));
1244 break;
1245 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANPACKAGECOMPLETE:
1246 OnPlanPackageCompleteFallback(reinterpret_cast<BA_ONPLANPACKAGECOMPLETE_ARGS*>(pvArgs), reinterpret_cast<BA_ONPLANPACKAGECOMPLETE_RESULTS*>(pvResults));
1247 break;
1248 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONAPPLYBEGIN:
1249 OnApplyBeginFallback(reinterpret_cast<BA_ONAPPLYBEGIN_ARGS*>(pvArgs), reinterpret_cast<BA_ONAPPLYBEGIN_RESULTS*>(pvResults));
1250 break;
1251 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONELEVATEBEGIN:
1252 OnElevateBeginFallback(reinterpret_cast<BA_ONELEVATEBEGIN_ARGS*>(pvArgs), reinterpret_cast<BA_ONELEVATEBEGIN_RESULTS*>(pvResults));
1253 break;
1254 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONELEVATECOMPLETE:
1255 OnElevateCompleteFallback(reinterpret_cast<BA_ONELEVATECOMPLETE_ARGS*>(pvArgs), reinterpret_cast<BA_ONELEVATECOMPLETE_RESULTS*>(pvResults));
1256 break;
1257 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONPROGRESS:
1258 OnProgressFallback(reinterpret_cast<BA_ONPROGRESS_ARGS*>(pvArgs), reinterpret_cast<BA_ONPROGRESS_RESULTS*>(pvResults));
1259 break;
1260 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONERROR:
1261 OnErrorFallback(reinterpret_cast<BA_ONERROR_ARGS*>(pvArgs), reinterpret_cast<BA_ONERROR_RESULTS*>(pvResults));
1262 break;
1263 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONREGISTERBEGIN:
1264 OnRegisterBeginFallback(reinterpret_cast<BA_ONREGISTERBEGIN_ARGS*>(pvArgs), reinterpret_cast<BA_ONREGISTERBEGIN_RESULTS*>(pvResults));
1265 break;
1266 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONREGISTERCOMPLETE:
1267 OnRegisterCompleteFallback(reinterpret_cast<BA_ONREGISTERCOMPLETE_ARGS*>(pvArgs), reinterpret_cast<BA_ONREGISTERCOMPLETE_RESULTS*>(pvResults));
1268 break;
1269 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEBEGIN:
1270 OnCacheBeginFallback(reinterpret_cast<BA_ONCACHEBEGIN_ARGS*>(pvArgs), reinterpret_cast<BA_ONCACHEBEGIN_RESULTS*>(pvResults));
1271 break;
1272 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEPACKAGEBEGIN:
1273 OnCachePackageBeginFallback(reinterpret_cast<BA_ONCACHEPACKAGEBEGIN_ARGS*>(pvArgs), reinterpret_cast<BA_ONCACHEPACKAGEBEGIN_RESULTS*>(pvResults));
1274 break;
1275 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEACQUIREBEGIN:
1276 OnCacheAcquireBeginFallback(reinterpret_cast<BA_ONCACHEACQUIREBEGIN_ARGS*>(pvArgs), reinterpret_cast<BA_ONCACHEACQUIREBEGIN_RESULTS*>(pvResults));
1277 break;
1278 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEACQUIREPROGRESS:
1279 OnCacheAcquireProgressFallback(reinterpret_cast<BA_ONCACHEACQUIREPROGRESS_ARGS*>(pvArgs), reinterpret_cast<BA_ONCACHEACQUIREPROGRESS_RESULTS*>(pvResults));
1280 break;
1281 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEACQUIRERESOLVING:
1282 OnCacheAcquireResolvingFallback(reinterpret_cast<BA_ONCACHEACQUIRERESOLVING_ARGS*>(pvArgs), reinterpret_cast<BA_ONCACHEACQUIRERESOLVING_RESULTS*>(pvResults));
1283 break;
1284 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEACQUIRECOMPLETE:
1285 OnCacheAcquireCompleteFallback(reinterpret_cast<BA_ONCACHEACQUIRECOMPLETE_ARGS*>(pvArgs), reinterpret_cast<BA_ONCACHEACQUIRECOMPLETE_RESULTS*>(pvResults));
1286 break;
1287 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEVERIFYBEGIN:
1288 OnCacheVerifyBeginFallback(reinterpret_cast<BA_ONCACHEVERIFYBEGIN_ARGS*>(pvArgs), reinterpret_cast<BA_ONCACHEVERIFYBEGIN_RESULTS*>(pvResults));
1289 break;
1290 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEVERIFYCOMPLETE:
1291 OnCacheVerifyCompleteFallback(reinterpret_cast<BA_ONCACHEVERIFYCOMPLETE_ARGS*>(pvArgs), reinterpret_cast<BA_ONCACHEVERIFYCOMPLETE_RESULTS*>(pvResults));
1292 break;
1293 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEPACKAGECOMPLETE:
1294 OnCachePackageCompleteFallback(reinterpret_cast<BA_ONCACHEPACKAGECOMPLETE_ARGS*>(pvArgs), reinterpret_cast<BA_ONCACHEPACKAGECOMPLETE_RESULTS*>(pvResults));
1295 break;
1296 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHECOMPLETE:
1297 OnCacheCompleteFallback(reinterpret_cast<BA_ONCACHECOMPLETE_ARGS*>(pvArgs), reinterpret_cast<BA_ONCACHECOMPLETE_RESULTS*>(pvResults));
1298 break;
1299 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONEXECUTEBEGIN:
1300 OnExecuteBeginFallback(reinterpret_cast<BA_ONEXECUTEBEGIN_ARGS*>(pvArgs), reinterpret_cast<BA_ONEXECUTEBEGIN_RESULTS*>(pvResults));
1301 break;
1302 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONEXECUTEPACKAGEBEGIN:
1303 OnExecutePackageBeginFallback(reinterpret_cast<BA_ONEXECUTEPACKAGEBEGIN_ARGS*>(pvArgs), reinterpret_cast<BA_ONEXECUTEPACKAGEBEGIN_RESULTS*>(pvResults));
1304 break;
1305 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONEXECUTEPATCHTARGET:
1306 OnExecutePatchTargetFallback(reinterpret_cast<BA_ONEXECUTEPATCHTARGET_ARGS*>(pvArgs), reinterpret_cast<BA_ONEXECUTEPATCHTARGET_RESULTS*>(pvResults));
1307 break;
1308 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONEXECUTEPROGRESS:
1309 OnExecuteProgressFallback(reinterpret_cast<BA_ONEXECUTEPROGRESS_ARGS*>(pvArgs), reinterpret_cast<BA_ONEXECUTEPROGRESS_RESULTS*>(pvResults));
1310 break;
1311 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONEXECUTEMSIMESSAGE:
1312 OnExecuteMsiMessageFallback(reinterpret_cast<BA_ONEXECUTEMSIMESSAGE_ARGS*>(pvArgs), reinterpret_cast<BA_ONEXECUTEMSIMESSAGE_RESULTS*>(pvResults));
1313 break;
1314 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONEXECUTEFILESINUSE:
1315 OnExecuteFilesInUseFallback(reinterpret_cast<BA_ONEXECUTEFILESINUSE_ARGS*>(pvArgs), reinterpret_cast<BA_ONEXECUTEFILESINUSE_RESULTS*>(pvResults));
1316 break;
1317 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONEXECUTEPACKAGECOMPLETE:
1318 OnExecutePackageCompleteFallback(reinterpret_cast<BA_ONEXECUTEPACKAGECOMPLETE_ARGS*>(pvArgs), reinterpret_cast<BA_ONEXECUTEPACKAGECOMPLETE_RESULTS*>(pvResults));
1319 break;
1320 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONEXECUTECOMPLETE:
1321 OnExecuteCompleteFallback(reinterpret_cast<BA_ONEXECUTECOMPLETE_ARGS*>(pvArgs), reinterpret_cast<BA_ONEXECUTECOMPLETE_RESULTS*>(pvResults));
1322 break;
1323 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONUNREGISTERBEGIN:
1324 OnUnregisterBeginFallback(reinterpret_cast<BA_ONUNREGISTERBEGIN_ARGS*>(pvArgs), reinterpret_cast<BA_ONUNREGISTERBEGIN_RESULTS*>(pvResults));
1325 break;
1326 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONUNREGISTERCOMPLETE:
1327 OnUnregisterCompleteFallback(reinterpret_cast<BA_ONUNREGISTERCOMPLETE_ARGS*>(pvArgs), reinterpret_cast<BA_ONUNREGISTERCOMPLETE_RESULTS*>(pvResults));
1328 break;
1329 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONAPPLYCOMPLETE:
1330 OnApplyCompleteFallback(reinterpret_cast<BA_ONAPPLYCOMPLETE_ARGS*>(pvArgs), reinterpret_cast<BA_ONAPPLYCOMPLETE_RESULTS*>(pvResults));
1331 break;
1332 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONLAUNCHAPPROVEDEXEBEGIN:
1333 OnLaunchApprovedExeBeginFallback(reinterpret_cast<BA_ONLAUNCHAPPROVEDEXEBEGIN_ARGS*>(pvArgs), reinterpret_cast<BA_ONLAUNCHAPPROVEDEXEBEGIN_RESULTS*>(pvResults));
1334 break;
1335 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONLAUNCHAPPROVEDEXECOMPLETE:
1336 OnLaunchApprovedExeCompleteFallback(reinterpret_cast<BA_ONLAUNCHAPPROVEDEXECOMPLETE_ARGS*>(pvArgs), reinterpret_cast<BA_ONLAUNCHAPPROVEDEXECOMPLETE_RESULTS*>(pvResults));
1337 break;
1338 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANMSIPACKAGE:
1339 OnPlanMsiPackageFallback(reinterpret_cast<BA_ONPLANMSIPACKAGE_ARGS*>(pvArgs), reinterpret_cast<BA_ONPLANMSIPACKAGE_RESULTS*>(pvResults));
1340 break;
1341 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONBEGINMSITRANSACTIONBEGIN:
1342 OnBeginMsiTransactionBeginFallback(reinterpret_cast<BA_ONBEGINMSITRANSACTIONBEGIN_ARGS*>(pvArgs), reinterpret_cast<BA_ONBEGINMSITRANSACTIONBEGIN_RESULTS*>(pvResults));
1343 break;
1344 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONBEGINMSITRANSACTIONCOMPLETE:
1345 OnBeginMsiTransactionCompleteFallback(reinterpret_cast<BA_ONBEGINMSITRANSACTIONCOMPLETE_ARGS*>(pvArgs), reinterpret_cast<BA_ONBEGINMSITRANSACTIONCOMPLETE_RESULTS*>(pvResults));
1346 break;
1347 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONCOMMITMSITRANSACTIONBEGIN:
1348 OnCommitMsiTransactionBeginFallback(reinterpret_cast<BA_ONCOMMITMSITRANSACTIONBEGIN_ARGS*>(pvArgs), reinterpret_cast<BA_ONCOMMITMSITRANSACTIONBEGIN_RESULTS*>(pvResults));
1349 break;
1350 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONCOMMITMSITRANSACTIONCOMPLETE:
1351 OnCommitMsiTransactionCompleteFallback(reinterpret_cast<BA_ONCOMMITMSITRANSACTIONCOMPLETE_ARGS*>(pvArgs), reinterpret_cast<BA_ONCOMMITMSITRANSACTIONCOMPLETE_RESULTS*>(pvResults));
1352 break;
1353 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONROLLBACKMSITRANSACTIONBEGIN:
1354 OnRollbackMsiTransactionBeginFallback(reinterpret_cast<BA_ONROLLBACKMSITRANSACTIONBEGIN_ARGS*>(pvArgs), reinterpret_cast<BA_ONROLLBACKMSITRANSACTIONBEGIN_RESULTS*>(pvResults));
1355 break;
1356 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONROLLBACKMSITRANSACTIONCOMPLETE:
1357 OnRollbackMsiTransactionCompleteFallback(reinterpret_cast<BA_ONROLLBACKMSITRANSACTIONCOMPLETE_ARGS*>(pvArgs), reinterpret_cast<BA_ONROLLBACKMSITRANSACTIONCOMPLETE_RESULTS*>(pvResults));
1358 break;
1359 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONPAUSEAUTOMATICUPDATESBEGIN:
1360 OnPauseAutomaticUpdatesBeginFallback(reinterpret_cast<BA_ONPAUSEAUTOMATICUPDATESBEGIN_ARGS*>(pvArgs), reinterpret_cast<BA_ONPAUSEAUTOMATICUPDATESBEGIN_RESULTS*>(pvResults));
1361 break;
1362 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONPAUSEAUTOMATICUPDATESCOMPLETE:
1363 OnPauseAutomaticUpdatesCompleteFallback(reinterpret_cast<BA_ONPAUSEAUTOMATICUPDATESCOMPLETE_ARGS*>(pvArgs), reinterpret_cast<BA_ONPAUSEAUTOMATICUPDATESCOMPLETE_RESULTS*>(pvResults));
1364 break;
1365 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONSYSTEMRESTOREPOINTBEGIN:
1366 OnSystemRestorePointBeginFallback(reinterpret_cast<BA_ONSYSTEMRESTOREPOINTBEGIN_ARGS*>(pvArgs), reinterpret_cast<BA_ONSYSTEMRESTOREPOINTBEGIN_RESULTS*>(pvResults));
1367 break;
1368 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONSYSTEMRESTOREPOINTCOMPLETE:
1369 OnSystemRestorePointCompleteFallback(reinterpret_cast<BA_ONSYSTEMRESTOREPOINTCOMPLETE_ARGS*>(pvArgs), reinterpret_cast<BA_ONSYSTEMRESTOREPOINTCOMPLETE_RESULTS*>(pvResults));
1370 break;
1371 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANNEDPACKAGE:
1372 OnPlannedPackageFallback(reinterpret_cast<BA_ONPLANNEDPACKAGE_ARGS*>(pvArgs), reinterpret_cast<BA_ONPLANNEDPACKAGE_RESULTS*>(pvResults));
1373 break;
1374 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEVERIFYPROGRESS:
1375 OnCacheVerifyProgressFallback(reinterpret_cast<BA_ONCACHEVERIFYPROGRESS_ARGS*>(pvArgs), reinterpret_cast<BA_ONCACHEVERIFYPROGRESS_RESULTS*>(pvResults));
1376 break;
1377 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHECONTAINERORPAYLOADVERIFYBEGIN:
1378 OnCacheContainerOrPayloadVerifyBeginFallback(reinterpret_cast<BA_ONCACHECONTAINERORPAYLOADVERIFYBEGIN_ARGS*>(pvArgs), reinterpret_cast<BA_ONCACHECONTAINERORPAYLOADVERIFYBEGIN_RESULTS*>(pvResults));
1379 break;
1380 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHECONTAINERORPAYLOADVERIFYCOMPLETE:
1381 OnCacheContainerOrPayloadVerifyCompleteFallback(reinterpret_cast<BA_ONCACHECONTAINERORPAYLOADVERIFYCOMPLETE_ARGS*>(pvArgs), reinterpret_cast<BA_ONCACHECONTAINERORPAYLOADVERIFYCOMPLETE_RESULTS*>(pvResults));
1382 break;
1383 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHECONTAINERORPAYLOADVERIFYPROGRESS:
1384 OnCacheContainerOrPayloadVerifyProgressFallback(reinterpret_cast<BA_ONCACHECONTAINERORPAYLOADVERIFYPROGRESS_ARGS*>(pvArgs), reinterpret_cast<BA_ONCACHECONTAINERORPAYLOADVERIFYPROGRESS_RESULTS*>(pvResults));
1385 break;
1386 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEPAYLOADEXTRACTBEGIN:
1387 OnCachePayloadExtractBeginFallback(reinterpret_cast<BA_ONCACHEPAYLOADEXTRACTBEGIN_ARGS*>(pvArgs), reinterpret_cast<BA_ONCACHEPAYLOADEXTRACTBEGIN_RESULTS*>(pvResults));
1388 break;
1389 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEPAYLOADEXTRACTCOMPLETE:
1390 OnCachePayloadExtractCompleteFallback(reinterpret_cast<BA_ONCACHEPAYLOADEXTRACTCOMPLETE_ARGS*>(pvArgs), reinterpret_cast<BA_ONCACHEPAYLOADEXTRACTCOMPLETE_RESULTS*>(pvResults));
1391 break;
1392 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEPAYLOADEXTRACTPROGRESS:
1393 OnCachePayloadExtractProgressFallback(reinterpret_cast<BA_ONCACHEPAYLOADEXTRACTPROGRESS_ARGS*>(pvArgs), reinterpret_cast<BA_ONCACHEPAYLOADEXTRACTPROGRESS_RESULTS*>(pvResults));
1394 break;
1395 default:
1396#ifdef DEBUG
1397 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "WIXSTDBA: Forwarding unknown BA message: %d", message);
1398#endif
1399 m_pfnBAFunctionsProc((BA_FUNCTIONS_MESSAGE)message, pvArgs, pvResults, m_pvBAFunctionsProcContext);
1400 break;
1401 }
1402 }
1403
1404
1405private: // privates
1406 void OnDetectBeginFallback(
1407 __in BA_ONDETECTBEGIN_ARGS* pArgs,
1408 __inout BA_ONDETECTBEGIN_RESULTS* pResults
1409 )
1410 {
1411 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONDETECTBEGIN, pArgs, pResults, m_pvBAFunctionsProcContext);
1412 }
1413
1414 void OnDetectCompleteFallback(
1415 __in BA_ONDETECTCOMPLETE_ARGS* pArgs,
1416 __inout BA_ONDETECTCOMPLETE_RESULTS* pResults
1417 )
1418 {
1419 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONDETECTCOMPLETE, pArgs, pResults, m_pvBAFunctionsProcContext);
1420 }
1421
1422 void OnPlanBeginFallback(
1423 __in BA_ONPLANBEGIN_ARGS* pArgs,
1424 __inout BA_ONPLANBEGIN_RESULTS* pResults
1425 )
1426 {
1427 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONPLANBEGIN, pArgs, pResults, m_pvBAFunctionsProcContext);
1428 }
1429
1430 void OnPlanCompleteFallback(
1431 __in BA_ONPLANCOMPLETE_ARGS* pArgs,
1432 __inout BA_ONPLANCOMPLETE_RESULTS* pResults
1433 )
1434 {
1435 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONPLANCOMPLETE, pArgs, pResults, m_pvBAFunctionsProcContext);
1436 }
1437
1438 void OnShutdownFallback(
1439 __in BA_ONSHUTDOWN_ARGS* pArgs,
1440 __inout BA_ONSHUTDOWN_RESULTS* pResults
1441 )
1442 {
1443 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONSHUTDOWN, pArgs, pResults, m_pvBAFunctionsProcContext);
1444 }
1445
1446 void OnSystemShutdownFallback(
1447 __in BA_ONSYSTEMSHUTDOWN_ARGS* pArgs,
1448 __inout BA_ONSYSTEMSHUTDOWN_RESULTS* pResults
1449 )
1450 {
1451 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONSYSTEMSHUTDOWN, pArgs, pResults, m_pvBAFunctionsProcContext);
1452 }
1453
1454 void OnDetectForwardCompatibleBundleFallback(
1455 __in BA_ONDETECTFORWARDCOMPATIBLEBUNDLE_ARGS* pArgs,
1456 __inout BA_ONDETECTFORWARDCOMPATIBLEBUNDLE_RESULTS* pResults
1457 )
1458 {
1459 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONDETECTFORWARDCOMPATIBLEBUNDLE, pArgs, pResults, m_pvBAFunctionsProcContext);
1460 }
1461
1462 void OnDetectUpdateBeginFallback(
1463 __in BA_ONDETECTUPDATEBEGIN_ARGS* pArgs,
1464 __inout BA_ONDETECTUPDATEBEGIN_RESULTS* pResults
1465 )
1466 {
1467 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONDETECTUPDATEBEGIN, pArgs, pResults, m_pvBAFunctionsProcContext);
1468 }
1469
1470 void OnDetectUpdateFallback(
1471 __in BA_ONDETECTUPDATE_ARGS* pArgs,
1472 __inout BA_ONDETECTUPDATE_RESULTS* pResults
1473 )
1474 {
1475 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONDETECTUPDATE, pArgs, pResults, m_pvBAFunctionsProcContext);
1476 }
1477
1478 void OnDetectUpdateCompleteFallback(
1479 __in BA_ONDETECTUPDATECOMPLETE_ARGS* pArgs,
1480 __inout BA_ONDETECTUPDATECOMPLETE_RESULTS* pResults
1481 )
1482 {
1483 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONDETECTUPDATECOMPLETE, pArgs, pResults, m_pvBAFunctionsProcContext);
1484 }
1485
1486 void OnDetectRelatedBundleFallback(
1487 __in BA_ONDETECTRELATEDBUNDLE_ARGS* pArgs,
1488 __inout BA_ONDETECTRELATEDBUNDLE_RESULTS* pResults
1489 )
1490 {
1491 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONDETECTRELATEDBUNDLE, pArgs, pResults, m_pvBAFunctionsProcContext);
1492 }
1493
1494 void OnDetectPackageBeginFallback(
1495 __in BA_ONDETECTPACKAGEBEGIN_ARGS* pArgs,
1496 __inout BA_ONDETECTPACKAGEBEGIN_RESULTS* pResults
1497 )
1498 {
1499 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONDETECTPACKAGEBEGIN, pArgs, pResults, m_pvBAFunctionsProcContext);
1500 }
1501
1502 void OnDetectRelatedMsiPackageFallback(
1503 __in BA_ONDETECTRELATEDMSIPACKAGE_ARGS* pArgs,
1504 __inout BA_ONDETECTRELATEDMSIPACKAGE_RESULTS* pResults
1505 )
1506 {
1507 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONDETECTRELATEDMSIPACKAGE, pArgs, pResults, m_pvBAFunctionsProcContext);
1508 }
1509
1510 void OnDetectPatchTargetFallback(
1511 __in BA_ONDETECTPATCHTARGET_ARGS* pArgs,
1512 __inout BA_ONDETECTPATCHTARGET_RESULTS* pResults
1513 )
1514 {
1515 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONDETECTPATCHTARGET, pArgs, pResults, m_pvBAFunctionsProcContext);
1516 }
1517
1518 void OnDetectMsiFeatureFallback(
1519 __in BA_ONDETECTMSIFEATURE_ARGS* pArgs,
1520 __inout BA_ONDETECTMSIFEATURE_RESULTS* pResults
1521 )
1522 {
1523 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONDETECTMSIFEATURE, pArgs, pResults, m_pvBAFunctionsProcContext);
1524 }
1525
1526 void OnDetectPackageCompleteFallback(
1527 __in BA_ONDETECTPACKAGECOMPLETE_ARGS* pArgs,
1528 __inout BA_ONDETECTPACKAGECOMPLETE_RESULTS* pResults
1529 )
1530 {
1531 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONDETECTPACKAGECOMPLETE, pArgs, pResults, m_pvBAFunctionsProcContext);
1532 }
1533
1534 void OnPlanRelatedBundleFallback(
1535 __in BA_ONPLANRELATEDBUNDLE_ARGS* pArgs,
1536 __inout BA_ONPLANRELATEDBUNDLE_RESULTS* pResults
1537 )
1538 {
1539 BOOTSTRAPPER_REQUEST_STATE requestedState = pResults->requestedState;
1540 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONPLANRELATEDBUNDLE, pArgs, pResults, m_pvBAFunctionsProcContext);
1541 BalLogId(BOOTSTRAPPER_LOG_LEVEL_STANDARD, MSG_WIXSTDBA_PLANNED_RELATED_BUNDLE, m_hModule, pArgs->wzBundleId, LoggingRequestStateToString(requestedState), LoggingRequestStateToString(pResults->requestedState));
1542 }
1543
1544 void OnPlanPackageBeginFallback(
1545 __in BA_ONPLANPACKAGEBEGIN_ARGS* pArgs,
1546 __inout BA_ONPLANPACKAGEBEGIN_RESULTS* pResults
1547 )
1548 {
1549 BOOTSTRAPPER_REQUEST_STATE requestedState = pResults->requestedState;
1550 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONPLANPACKAGEBEGIN, pArgs, pResults, m_pvBAFunctionsProcContext);
1551 BalLogId(BOOTSTRAPPER_LOG_LEVEL_STANDARD, MSG_WIXSTDBA_PLANNED_PACKAGE, m_hModule, pArgs->wzPackageId, LoggingRequestStateToString(requestedState), LoggingRequestStateToString(pResults->requestedState));
1552 }
1553
1554 void OnPlanPatchTargetFallback(
1555 __in BA_ONPLANPATCHTARGET_ARGS* pArgs,
1556 __inout BA_ONPLANPATCHTARGET_RESULTS* pResults
1557 )
1558 {
1559 BOOTSTRAPPER_REQUEST_STATE requestedState = pResults->requestedState;
1560 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONPLANPATCHTARGET, pArgs, pResults, m_pvBAFunctionsProcContext);
1561 BalLogId(BOOTSTRAPPER_LOG_LEVEL_STANDARD, MSG_WIXSTDBA_PLANNED_TARGET_MSI_PACKAGE, m_hModule, pArgs->wzPackageId, pArgs->wzProductCode, LoggingRequestStateToString(requestedState), LoggingRequestStateToString(pResults->requestedState));
1562 }
1563
1564 void OnPlanMsiFeatureFallback(
1565 __in BA_ONPLANMSIFEATURE_ARGS* pArgs,
1566 __inout BA_ONPLANMSIFEATURE_RESULTS* pResults
1567 )
1568 {
1569 BOOTSTRAPPER_FEATURE_STATE requestedState = pResults->requestedState;
1570 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONPLANMSIFEATURE, pArgs, pResults, m_pvBAFunctionsProcContext);
1571 BalLogId(BOOTSTRAPPER_LOG_LEVEL_STANDARD, MSG_WIXSTDBA_PLANNED_MSI_FEATURE, m_hModule, pArgs->wzPackageId, pArgs->wzFeatureId, LoggingMsiFeatureStateToString(requestedState), LoggingMsiFeatureStateToString(pResults->requestedState));
1572 }
1573
1574 void OnPlanPackageCompleteFallback(
1575 __in BA_ONPLANPACKAGECOMPLETE_ARGS* pArgs,
1576 __inout BA_ONPLANPACKAGECOMPLETE_RESULTS* pResults
1577 )
1578 {
1579 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONPLANPACKAGECOMPLETE, pArgs, pResults, m_pvBAFunctionsProcContext);
1580 }
1581
1582 void OnPlannedPackageFallback(
1583 __in BA_ONPLANNEDPACKAGE_ARGS* pArgs,
1584 __inout BA_ONPLANNEDPACKAGE_RESULTS* pResults
1585 )
1586 {
1587 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONPLANNEDPACKAGE, pArgs, pResults, m_pvBAFunctionsProcContext);
1588 }
1589
1590 void OnApplyBeginFallback(
1591 __in BA_ONAPPLYBEGIN_ARGS* pArgs,
1592 __inout BA_ONAPPLYBEGIN_RESULTS* pResults
1593 )
1594 {
1595 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONAPPLYBEGIN, pArgs, pResults, m_pvBAFunctionsProcContext);
1596 }
1597
1598 void OnElevateBeginFallback(
1599 __in BA_ONELEVATEBEGIN_ARGS* pArgs,
1600 __inout BA_ONELEVATEBEGIN_RESULTS* pResults
1601 )
1602 {
1603 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONELEVATEBEGIN, pArgs, pResults, m_pvBAFunctionsProcContext);
1604 }
1605
1606 void OnElevateCompleteFallback(
1607 __in BA_ONELEVATECOMPLETE_ARGS* pArgs,
1608 __inout BA_ONELEVATECOMPLETE_RESULTS* pResults
1609 )
1610 {
1611 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONELEVATECOMPLETE, pArgs, pResults, m_pvBAFunctionsProcContext);
1612 }
1613
1614 void OnProgressFallback(
1615 __in BA_ONPROGRESS_ARGS* pArgs,
1616 __inout BA_ONPROGRESS_RESULTS* pResults
1617 )
1618 {
1619 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONPROGRESS, pArgs, pResults, m_pvBAFunctionsProcContext);
1620 }
1621
1622 void OnErrorFallback(
1623 __in BA_ONERROR_ARGS* pArgs,
1624 __inout BA_ONERROR_RESULTS* pResults
1625 )
1626 {
1627 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONERROR, pArgs, pResults, m_pvBAFunctionsProcContext);
1628 }
1629
1630 void OnRegisterBeginFallback(
1631 __in BA_ONREGISTERBEGIN_ARGS* pArgs,
1632 __inout BA_ONREGISTERBEGIN_RESULTS* pResults
1633 )
1634 {
1635 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONREGISTERBEGIN, pArgs, pResults, m_pvBAFunctionsProcContext);
1636 }
1637
1638 void OnRegisterCompleteFallback(
1639 __in BA_ONREGISTERCOMPLETE_ARGS* pArgs,
1640 __inout BA_ONREGISTERCOMPLETE_RESULTS* pResults
1641 )
1642 {
1643 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONREGISTERCOMPLETE, pArgs, pResults, m_pvBAFunctionsProcContext);
1644 }
1645
1646 void OnCacheBeginFallback(
1647 __in BA_ONCACHEBEGIN_ARGS* pArgs,
1648 __inout BA_ONCACHEBEGIN_RESULTS* pResults
1649 )
1650 {
1651 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONCACHEBEGIN, pArgs, pResults, m_pvBAFunctionsProcContext);
1652 }
1653
1654 void OnCachePackageBeginFallback(
1655 __in BA_ONCACHEPACKAGEBEGIN_ARGS* pArgs,
1656 __inout BA_ONCACHEPACKAGEBEGIN_RESULTS* pResults
1657 )
1658 {
1659 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONCACHEPACKAGEBEGIN, pArgs, pResults, m_pvBAFunctionsProcContext);
1660 }
1661
1662 void OnCacheAcquireBeginFallback(
1663 __in BA_ONCACHEACQUIREBEGIN_ARGS* pArgs,
1664 __inout BA_ONCACHEACQUIREBEGIN_RESULTS* pResults
1665 )
1666 {
1667 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONCACHEACQUIREBEGIN, pArgs, pResults, m_pvBAFunctionsProcContext);
1668 }
1669
1670 void OnCacheAcquireProgressFallback(
1671 __in BA_ONCACHEACQUIREPROGRESS_ARGS* pArgs,
1672 __inout BA_ONCACHEACQUIREPROGRESS_RESULTS* pResults
1673 )
1674 {
1675 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONCACHEACQUIREPROGRESS, pArgs, pResults, m_pvBAFunctionsProcContext);
1676 }
1677
1678 void OnCacheAcquireResolvingFallback(
1679 __in BA_ONCACHEACQUIRERESOLVING_ARGS* pArgs,
1680 __inout BA_ONCACHEACQUIRERESOLVING_RESULTS* pResults
1681 )
1682 {
1683 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONCACHEACQUIRERESOLVING, pArgs, pResults, m_pvBAFunctionsProcContext);
1684 }
1685
1686 void OnCacheAcquireCompleteFallback(
1687 __in BA_ONCACHEACQUIRECOMPLETE_ARGS* pArgs,
1688 __inout BA_ONCACHEACQUIRECOMPLETE_RESULTS* pResults
1689 )
1690 {
1691 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONCACHEACQUIRECOMPLETE, pArgs, pResults, m_pvBAFunctionsProcContext);
1692 }
1693
1694 void OnCacheVerifyBeginFallback(
1695 __in BA_ONCACHEVERIFYBEGIN_ARGS* pArgs,
1696 __inout BA_ONCACHEVERIFYBEGIN_RESULTS* pResults
1697 )
1698 {
1699 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONCACHEVERIFYBEGIN, pArgs, pResults, m_pvBAFunctionsProcContext);
1700 }
1701
1702 void OnCacheVerifyCompleteFallback(
1703 __in BA_ONCACHEVERIFYCOMPLETE_ARGS* pArgs,
1704 __inout BA_ONCACHEVERIFYCOMPLETE_RESULTS* pResults
1705 )
1706 {
1707 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONCACHEVERIFYCOMPLETE, pArgs, pResults, m_pvBAFunctionsProcContext);
1708 }
1709
1710 void OnCachePackageCompleteFallback(
1711 __in BA_ONCACHEPACKAGECOMPLETE_ARGS* pArgs,
1712 __inout BA_ONCACHEPACKAGECOMPLETE_RESULTS* pResults
1713 )
1714 {
1715 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONCACHEPACKAGECOMPLETE, pArgs, pResults, m_pvBAFunctionsProcContext);
1716 }
1717
1718 void OnCacheCompleteFallback(
1719 __in BA_ONCACHECOMPLETE_ARGS* pArgs,
1720 __inout BA_ONCACHECOMPLETE_RESULTS* pResults
1721 )
1722 {
1723 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONCACHECOMPLETE, pArgs, pResults, m_pvBAFunctionsProcContext);
1724 }
1725
1726 void OnExecuteBeginFallback(
1727 __in BA_ONEXECUTEBEGIN_ARGS* pArgs,
1728 __inout BA_ONEXECUTEBEGIN_RESULTS* pResults
1729 )
1730 {
1731 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONEXECUTEBEGIN, pArgs, pResults, m_pvBAFunctionsProcContext);
1732 }
1733
1734 void OnExecutePackageBeginFallback(
1735 __in BA_ONEXECUTEPACKAGEBEGIN_ARGS* pArgs,
1736 __inout BA_ONEXECUTEPACKAGEBEGIN_RESULTS* pResults
1737 )
1738 {
1739 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONEXECUTEPACKAGEBEGIN, pArgs, pResults, m_pvBAFunctionsProcContext);
1740 }
1741
1742 void OnExecutePatchTargetFallback(
1743 __in BA_ONEXECUTEPATCHTARGET_ARGS* pArgs,
1744 __inout BA_ONEXECUTEPATCHTARGET_RESULTS* pResults
1745 )
1746 {
1747 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONEXECUTEPATCHTARGET, pArgs, pResults, m_pvBAFunctionsProcContext);
1748 }
1749
1750 void OnExecuteProgressFallback(
1751 __in BA_ONEXECUTEPROGRESS_ARGS* pArgs,
1752 __inout BA_ONEXECUTEPROGRESS_RESULTS* pResults
1753 )
1754 {
1755 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONEXECUTEPROGRESS, pArgs, pResults, m_pvBAFunctionsProcContext);
1756 }
1757
1758 void OnExecuteMsiMessageFallback(
1759 __in BA_ONEXECUTEMSIMESSAGE_ARGS* pArgs,
1760 __inout BA_ONEXECUTEMSIMESSAGE_RESULTS* pResults
1761 )
1762 {
1763 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONEXECUTEMSIMESSAGE, pArgs, pResults, m_pvBAFunctionsProcContext);
1764 }
1765
1766 void OnExecuteFilesInUseFallback(
1767 __in BA_ONEXECUTEFILESINUSE_ARGS* pArgs,
1768 __inout BA_ONEXECUTEFILESINUSE_RESULTS* pResults
1769 )
1770 {
1771 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONEXECUTEFILESINUSE, pArgs, pResults, m_pvBAFunctionsProcContext);
1772 }
1773
1774 void OnExecutePackageCompleteFallback(
1775 __in BA_ONEXECUTEPACKAGECOMPLETE_ARGS* pArgs,
1776 __inout BA_ONEXECUTEPACKAGECOMPLETE_RESULTS* pResults
1777 )
1778 {
1779 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONEXECUTEPACKAGECOMPLETE, pArgs, pResults, m_pvBAFunctionsProcContext);
1780 }
1781
1782 void OnExecuteCompleteFallback(
1783 __in BA_ONEXECUTECOMPLETE_ARGS* pArgs,
1784 __inout BA_ONEXECUTECOMPLETE_RESULTS* pResults
1785 )
1786 {
1787 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONEXECUTECOMPLETE, pArgs, pResults, m_pvBAFunctionsProcContext);
1788 }
1789
1790 void OnUnregisterBeginFallback(
1791 __in BA_ONUNREGISTERBEGIN_ARGS* pArgs,
1792 __inout BA_ONUNREGISTERBEGIN_RESULTS* pResults
1793 )
1794 {
1795 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONUNREGISTERBEGIN, pArgs, pResults, m_pvBAFunctionsProcContext);
1796 }
1797
1798 void OnUnregisterCompleteFallback(
1799 __in BA_ONUNREGISTERCOMPLETE_ARGS* pArgs,
1800 __inout BA_ONUNREGISTERCOMPLETE_RESULTS* pResults
1801 )
1802 {
1803 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONUNREGISTERCOMPLETE, pArgs, pResults, m_pvBAFunctionsProcContext);
1804 }
1805
1806 void OnApplyCompleteFallback(
1807 __in BA_ONAPPLYCOMPLETE_ARGS* pArgs,
1808 __inout BA_ONAPPLYCOMPLETE_RESULTS* pResults
1809 )
1810 {
1811 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONAPPLYCOMPLETE, pArgs, pResults, m_pvBAFunctionsProcContext);
1812 }
1813
1814 void OnLaunchApprovedExeBeginFallback(
1815 __in BA_ONLAUNCHAPPROVEDEXEBEGIN_ARGS* pArgs,
1816 __inout BA_ONLAUNCHAPPROVEDEXEBEGIN_RESULTS* pResults
1817 )
1818 {
1819 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONLAUNCHAPPROVEDEXEBEGIN, pArgs, pResults, m_pvBAFunctionsProcContext);
1820 }
1821
1822 void OnLaunchApprovedExeCompleteFallback(
1823 __in BA_ONLAUNCHAPPROVEDEXECOMPLETE_ARGS* pArgs,
1824 __inout BA_ONLAUNCHAPPROVEDEXECOMPLETE_RESULTS* pResults
1825 )
1826 {
1827 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONLAUNCHAPPROVEDEXECOMPLETE, pArgs, pResults, m_pvBAFunctionsProcContext);
1828 }
1829
1830 void OnPlanMsiPackageFallback(
1831 __in BA_ONPLANMSIPACKAGE_ARGS* pArgs,
1832 __inout BA_ONPLANMSIPACKAGE_RESULTS* pResults
1833 )
1834 {
1835 BURN_MSI_PROPERTY actionMsiProperty = pResults->actionMsiProperty;
1836 INSTALLUILEVEL uiLevel = pResults->uiLevel;
1837 BOOL fDisableExternalUiHandler = pResults->fDisableExternalUiHandler;
1838 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONPLANMSIPACKAGE, pArgs, pResults, m_pvBAFunctionsProcContext);
1839 BalLogId(BOOTSTRAPPER_LOG_LEVEL_STANDARD, MSG_WIXSTDBA_PLANNED_MSI_PACKAGE, m_hModule, pArgs->wzPackageId, actionMsiProperty, uiLevel, fDisableExternalUiHandler ? "yes" : "no", pResults->actionMsiProperty, pResults->uiLevel, pResults->fDisableExternalUiHandler ? "yes" : "no");
1840 }
1841
1842 void OnBeginMsiTransactionBeginFallback(
1843 __in BA_ONBEGINMSITRANSACTIONBEGIN_ARGS* pArgs,
1844 __inout BA_ONBEGINMSITRANSACTIONBEGIN_RESULTS* pResults
1845 )
1846 {
1847 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONBEGINMSITRANSACTIONBEGIN, pArgs, pResults, m_pvBAFunctionsProcContext);
1848 }
1849
1850 void OnBeginMsiTransactionCompleteFallback(
1851 __in BA_ONBEGINMSITRANSACTIONCOMPLETE_ARGS* pArgs,
1852 __inout BA_ONBEGINMSITRANSACTIONCOMPLETE_RESULTS* pResults
1853 )
1854 {
1855 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONBEGINMSITRANSACTIONCOMPLETE, pArgs, pResults, m_pvBAFunctionsProcContext);
1856 }
1857
1858 void OnCommitMsiTransactionBeginFallback(
1859 __in BA_ONCOMMITMSITRANSACTIONBEGIN_ARGS* pArgs,
1860 __inout BA_ONCOMMITMSITRANSACTIONBEGIN_RESULTS* pResults
1861 )
1862 {
1863 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONCOMMITMSITRANSACTIONBEGIN, pArgs, pResults, m_pvBAFunctionsProcContext);
1864 }
1865
1866 void OnCommitMsiTransactionCompleteFallback(
1867 __in BA_ONCOMMITMSITRANSACTIONCOMPLETE_ARGS* pArgs,
1868 __inout BA_ONCOMMITMSITRANSACTIONCOMPLETE_RESULTS* pResults
1869 )
1870 {
1871 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONCOMMITMSITRANSACTIONCOMPLETE, pArgs, pResults, m_pvBAFunctionsProcContext);
1872 }
1873
1874 void OnRollbackMsiTransactionBeginFallback(
1875 __in BA_ONROLLBACKMSITRANSACTIONBEGIN_ARGS* pArgs,
1876 __inout BA_ONROLLBACKMSITRANSACTIONBEGIN_RESULTS* pResults
1877 )
1878 {
1879 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONROLLBACKMSITRANSACTIONBEGIN, pArgs, pResults, m_pvBAFunctionsProcContext);
1880 }
1881
1882 void OnRollbackMsiTransactionCompleteFallback(
1883 __in BA_ONROLLBACKMSITRANSACTIONCOMPLETE_ARGS* pArgs,
1884 __inout BA_ONROLLBACKMSITRANSACTIONCOMPLETE_RESULTS* pResults
1885 )
1886 {
1887 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONROLLBACKMSITRANSACTIONCOMPLETE, pArgs, pResults, m_pvBAFunctionsProcContext);
1888 }
1889
1890 void OnPauseAutomaticUpdatesBeginFallback(
1891 __in BA_ONPAUSEAUTOMATICUPDATESBEGIN_ARGS* pArgs,
1892 __inout BA_ONPAUSEAUTOMATICUPDATESBEGIN_RESULTS* pResults
1893 )
1894 {
1895 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONPAUSEAUTOMATICUPDATESBEGIN, pArgs, pResults, m_pvBAFunctionsProcContext);
1896 }
1897
1898 void OnPauseAutomaticUpdatesCompleteFallback(
1899 __in BA_ONPAUSEAUTOMATICUPDATESCOMPLETE_ARGS* pArgs,
1900 __inout BA_ONPAUSEAUTOMATICUPDATESCOMPLETE_RESULTS* pResults
1901 )
1902 {
1903 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONPAUSEAUTOMATICUPDATESCOMPLETE, pArgs, pResults, m_pvBAFunctionsProcContext);
1904 }
1905
1906 void OnSystemRestorePointBeginFallback(
1907 __in BA_ONSYSTEMRESTOREPOINTBEGIN_ARGS* pArgs,
1908 __inout BA_ONSYSTEMRESTOREPOINTBEGIN_RESULTS* pResults
1909 )
1910 {
1911 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONSYSTEMRESTOREPOINTBEGIN, pArgs, pResults, m_pvBAFunctionsProcContext);
1912 }
1913
1914 void OnSystemRestorePointCompleteFallback(
1915 __in BA_ONSYSTEMRESTOREPOINTCOMPLETE_ARGS* pArgs,
1916 __inout BA_ONSYSTEMRESTOREPOINTCOMPLETE_RESULTS* pResults
1917 )
1918 {
1919 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONSYSTEMRESTOREPOINTCOMPLETE, pArgs, pResults, m_pvBAFunctionsProcContext);
1920 }
1921
1922 void OnPlanForwardCompatibleBundleFallback(
1923 __in BA_ONPLANFORWARDCOMPATIBLEBUNDLE_ARGS* pArgs,
1924 __inout BA_ONPLANFORWARDCOMPATIBLEBUNDLE_RESULTS* pResults
1925 )
1926 {
1927 BOOL fIgnoreBundle = pResults->fIgnoreBundle;
1928 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONPLANFORWARDCOMPATIBLEBUNDLE, pArgs, pResults, m_pvBAFunctionsProcContext);
1929 BalLogId(BOOTSTRAPPER_LOG_LEVEL_STANDARD, MSG_WIXSTDBA_PLANNED_FORWARD_COMPATIBLE_BUNDLE, m_hModule, pArgs->wzBundleId, fIgnoreBundle ? "ignore" : "enable", pResults->fIgnoreBundle ? "ignore" : "enable");
1930 }
1931
1932 void OnCacheVerifyProgressFallback(
1933 __in BA_ONCACHEVERIFYPROGRESS_ARGS* pArgs,
1934 __inout BA_ONCACHEVERIFYPROGRESS_RESULTS* pResults
1935 )
1936 {
1937 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONCACHEVERIFYPROGRESS, pArgs, pResults, m_pvBAFunctionsProcContext);
1938 }
1939
1940 void OnCacheContainerOrPayloadVerifyBeginFallback(
1941 __in BA_ONCACHECONTAINERORPAYLOADVERIFYBEGIN_ARGS* pArgs,
1942 __inout BA_ONCACHECONTAINERORPAYLOADVERIFYBEGIN_RESULTS* pResults
1943 )
1944 {
1945 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONCACHECONTAINERORPAYLOADVERIFYBEGIN, pArgs, pResults, m_pvBAFunctionsProcContext);
1946 }
1947
1948 void OnCacheContainerOrPayloadVerifyCompleteFallback(
1949 __in BA_ONCACHECONTAINERORPAYLOADVERIFYCOMPLETE_ARGS* pArgs,
1950 __inout BA_ONCACHECONTAINERORPAYLOADVERIFYCOMPLETE_RESULTS* pResults
1951 )
1952 {
1953 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONCACHECONTAINERORPAYLOADVERIFYCOMPLETE, pArgs, pResults, m_pvBAFunctionsProcContext);
1954 }
1955
1956 void OnCacheContainerOrPayloadVerifyProgressFallback(
1957 __in BA_ONCACHECONTAINERORPAYLOADVERIFYPROGRESS_ARGS* pArgs,
1958 __inout BA_ONCACHECONTAINERORPAYLOADVERIFYPROGRESS_RESULTS* pResults
1959 )
1960 {
1961 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONCACHECONTAINERORPAYLOADVERIFYPROGRESS, pArgs, pResults, m_pvBAFunctionsProcContext);
1962 }
1963
1964 void OnCachePayloadExtractBeginFallback(
1965 __in BA_ONCACHEPAYLOADEXTRACTBEGIN_ARGS* pArgs,
1966 __inout BA_ONCACHEPAYLOADEXTRACTBEGIN_RESULTS* pResults
1967 )
1968 {
1969 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONCACHEPAYLOADEXTRACTBEGIN, pArgs, pResults, m_pvBAFunctionsProcContext);
1970 }
1971
1972 void OnCachePayloadExtractCompleteFallback(
1973 __in BA_ONCACHEPAYLOADEXTRACTCOMPLETE_ARGS* pArgs,
1974 __inout BA_ONCACHEPAYLOADEXTRACTCOMPLETE_RESULTS* pResults
1975 )
1976 {
1977 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONCACHEPAYLOADEXTRACTCOMPLETE, pArgs, pResults, m_pvBAFunctionsProcContext);
1978 }
1979
1980 void OnCachePayloadExtractProgressFallback(
1981 __in BA_ONCACHEPAYLOADEXTRACTPROGRESS_ARGS* pArgs,
1982 __inout BA_ONCACHEPAYLOADEXTRACTPROGRESS_RESULTS* pResults
1983 )
1984 {
1985 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONCACHEPAYLOADEXTRACTPROGRESS, pArgs, pResults, m_pvBAFunctionsProcContext);
1986 }
1987
1988 //
1989 // UiThreadProc - entrypoint for UI thread.
1990 //
1991 static DWORD WINAPI UiThreadProc(
1992 __in LPVOID pvContext
1993 )
1994 {
1995 HRESULT hr = S_OK;
1996 CWixStandardBootstrapperApplication* pThis = (CWixStandardBootstrapperApplication*)pvContext;
1997 BOOL fComInitialized = FALSE;
1998 BOOL fRet = FALSE;
1999 MSG msg = { };
2000
2001 // Initialize COM and theme.
2002 hr = ::CoInitialize(NULL);
2003 BalExitOnFailure(hr, "Failed to initialize COM.");
2004 fComInitialized = TRUE;
2005
2006 hr = ThemeInitialize(pThis->m_hModule);
2007 BalExitOnFailure(hr, "Failed to initialize theme manager.");
2008
2009 hr = pThis->InitializeData();
2010 BalExitOnFailure(hr, "Failed to initialize data in bootstrapper application.");
2011
2012 // Create main window.
2013 pThis->InitializeTaskbarButton();
2014 hr = pThis->CreateMainWindow();
2015 BalExitOnFailure(hr, "Failed to create main window.");
2016
2017 if (FAILED(pThis->m_hrFinal))
2018 {
2019 pThis->SetState(WIXSTDBA_STATE_FAILED, hr);
2020 ::PostMessageW(pThis->m_hWnd, WM_WIXSTDBA_SHOW_FAILURE, 0, 0);
2021 }
2022 else
2023 {
2024 // Okay, we're ready for packages now.
2025 pThis->SetState(WIXSTDBA_STATE_INITIALIZED, hr);
2026 ::PostMessageW(pThis->m_hWnd, BOOTSTRAPPER_ACTION_HELP == pThis->m_command.action ? WM_WIXSTDBA_SHOW_HELP : WM_WIXSTDBA_DETECT_PACKAGES, 0, 0);
2027 }
2028
2029 // message pump
2030 while (0 != (fRet = ::GetMessageW(&msg, NULL, 0, 0)))
2031 {
2032 if (-1 == fRet)
2033 {
2034 hr = E_UNEXPECTED;
2035 BalExitOnFailure(hr, "Unexpected return value from message pump.");
2036 }
2037 else if (!ThemeHandleKeyboardMessage(pThis->m_pTheme, msg.hwnd, &msg))
2038 {
2039 ::TranslateMessage(&msg);
2040 ::DispatchMessageW(&msg);
2041 }
2042 }
2043
2044 // Succeeded thus far, check to see if anything went wrong while actually
2045 // executing changes.
2046 if (FAILED(pThis->m_hrFinal))
2047 {
2048 hr = pThis->m_hrFinal;
2049 }
2050 else if (pThis->CheckCanceled())
2051 {
2052 hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT);
2053 }
2054
2055 LExit:
2056 // destroy main window
2057 pThis->DestroyMainWindow();
2058 pThis->UninitializeTaskbarButton();
2059
2060 // initiate engine shutdown
2061 DWORD dwQuit = HRESULT_CODE(hr);
2062 if (BOOTSTRAPPER_APPLY_RESTART_INITIATED == pThis->m_restartResult)
2063 {
2064 dwQuit = ERROR_SUCCESS_REBOOT_INITIATED;
2065 }
2066 else if (BOOTSTRAPPER_APPLY_RESTART_REQUIRED == pThis->m_restartResult)
2067 {
2068 dwQuit = ERROR_SUCCESS_REBOOT_REQUIRED;
2069 }
2070 pThis->m_pEngine->Quit(dwQuit);
2071
2072 ReleaseTheme(pThis->m_pTheme);
2073 ThemeUninitialize();
2074
2075 // uninitialize COM
2076 if (fComInitialized)
2077 {
2078 ::CoUninitialize();
2079 }
2080
2081 return hr;
2082 }
2083
2084
2085 //
2086 // InitializeData - initializes all the package and prerequisite information.
2087 //
2088 HRESULT InitializeData()
2089 {
2090 HRESULT hr = S_OK;
2091 LPWSTR sczModulePath = NULL;
2092 IXMLDOMDocument *pixdManifest = NULL;
2093
2094 hr = BalManifestLoad(m_hModule, &pixdManifest);
2095 BalExitOnFailure(hr, "Failed to load bootstrapper application manifest.");
2096
2097 hr = ParseOverridableVariablesFromXml(pixdManifest);
2098 BalExitOnFailure(hr, "Failed to read overridable variables.");
2099
2100 hr = ProcessCommandLine(&m_sczLanguage);
2101 ExitOnFailure(hr, "Unknown commandline parameters.");
2102
2103 hr = PathRelativeToModule(&sczModulePath, NULL, m_hModule);
2104 BalExitOnFailure(hr, "Failed to get module path.");
2105
2106 hr = LoadLocalization(sczModulePath, m_sczLanguage);
2107 ExitOnFailure(hr, "Failed to load localization.");
2108
2109 hr = LoadTheme(sczModulePath, m_sczLanguage);
2110 ExitOnFailure(hr, "Failed to load theme.");
2111
2112 hr = BalInfoParseFromXml(&m_Bundle, pixdManifest);
2113 BalExitOnFailure(hr, "Failed to load bundle information.");
2114
2115 hr = BalConditionsParseFromXml(&m_Conditions, pixdManifest, m_pWixLoc);
2116 BalExitOnFailure(hr, "Failed to load conditions from XML.");
2117
2118 hr = LoadBAFunctions(pixdManifest);
2119 BalExitOnFailure(hr, "Failed to load bootstrapper functions.");
2120
2121 GetBundleFileVersion();
2122 // don't fail if we couldn't get the version info; best-effort only
2123
2124 hr = InitializePackageInfo();
2125 BalExitOnFailure(hr, "Failed to initialize wixstdba package information.");
2126
2127 if (m_fPrereq)
2128 {
2129 hr = InitializePrerequisiteInformation();
2130 BalExitOnFailure(hr, "Failed to initialize prerequisite information.");
2131 }
2132 else
2133 {
2134 hr = ParseBootstrapperApplicationDataFromXml(pixdManifest);
2135 BalExitOnFailure(hr, "Failed to read bootstrapper application data.");
2136 }
2137
2138 if (BOOTSTRAPPER_ACTION_CACHE == m_plannedAction)
2139 {
2140 if (m_fSupportCacheOnly)
2141 {
2142 // Doesn't make sense to prompt the user if cache only is requested.
2143 if (BOOTSTRAPPER_DISPLAY_PASSIVE < m_command.display)
2144 {
2145 m_command.display = BOOTSTRAPPER_DISPLAY_PASSIVE;
2146 }
2147
2148 m_command.action = BOOTSTRAPPER_ACTION_CACHE;
2149 }
2150 else
2151 {
2152 BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "Ignoring attempt to only cache a bundle that does not explicitly support it.");
2153 m_plannedAction = BOOTSTRAPPER_ACTION_UNKNOWN;
2154 }
2155 }
2156
2157 LExit:
2158 ReleaseObject(pixdManifest);
2159 ReleaseStr(sczModulePath);
2160
2161 return hr;
2162 }
2163
2164
2165 //
2166 // ProcessCommandLine - process the provided command line arguments.
2167 //
2168 HRESULT ProcessCommandLine(
2169 __inout LPWSTR* psczLanguage
2170 )
2171 {
2172 HRESULT hr = S_OK;
2173 int argc = 0;
2174 LPWSTR* argv = NULL;
2175 LPWSTR sczVariableName = NULL;
2176 LPWSTR sczVariableValue = NULL;
2177
2178 if (m_command.wzCommandLine && *m_command.wzCommandLine)
2179 {
2180 hr = AppParseCommandLine(m_command.wzCommandLine, &argc, &argv);
2181 ExitOnFailure(hr, "Failed to parse command line.");
2182
2183 for (int i = 0; i < argc; ++i)
2184 {
2185 if (argv[i][0] == L'-' || argv[i][0] == L'/')
2186 {
2187 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"lang", -1))
2188 {
2189 if (i + 1 >= argc)
2190 {
2191 hr = E_INVALIDARG;
2192 BalExitOnFailure(hr, "Must specify a language.");
2193 }
2194
2195 ++i;
2196
2197 hr = StrAllocString(psczLanguage, &argv[i][0], 0);
2198 BalExitOnFailure(hr, "Failed to copy language.");
2199 }
2200 }
2201 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"cache", -1))
2202 {
2203 m_plannedAction = BOOTSTRAPPER_ACTION_CACHE;
2204 }
2205 else if (m_sdOverridableVariables)
2206 {
2207 const wchar_t* pwc = wcschr(argv[i], L'=');
2208 if (pwc)
2209 {
2210 hr = StrAllocString(&sczVariableName, argv[i], pwc - argv[i]);
2211 BalExitOnFailure(hr, "Failed to copy variable name.");
2212
2213 hr = DictKeyExists(m_sdOverridableVariables, sczVariableName);
2214 if (E_NOTFOUND == hr)
2215 {
2216 BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "Ignoring attempt to set non-overridable variable: '%ls'.", sczVariableName);
2217 hr = S_OK;
2218 continue;
2219 }
2220 ExitOnFailure(hr, "Failed to check the dictionary of overridable variables.");
2221
2222 hr = StrAllocString(&sczVariableValue, ++pwc, 0);
2223 BalExitOnFailure(hr, "Failed to copy variable value.");
2224
2225 hr = m_pEngine->SetVariableString(sczVariableName, sczVariableValue, FALSE);
2226 BalExitOnFailure(hr, "Failed to set variable.");
2227 }
2228 else
2229 {
2230 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Ignoring unknown argument: %ls", argv[i]);
2231 }
2232 }
2233 }
2234 }
2235
2236 LExit:
2237 if (argv)
2238 {
2239 AppFreeCommandLineArgs(argv);
2240 }
2241
2242 ReleaseStr(sczVariableName);
2243 ReleaseStr(sczVariableValue);
2244
2245 return hr;
2246 }
2247
2248 HRESULT LoadLocalization(
2249 __in_z LPCWSTR wzModulePath,
2250 __in_z_opt LPCWSTR wzLanguage
2251 )
2252 {
2253 HRESULT hr = S_OK;
2254 LPWSTR sczLocPath = NULL;
2255 LPWSTR sczFormatted = NULL;
2256 LPCWSTR wzLocFileName = m_fPrereq ? L"mbapreq.wxl" : L"thm.wxl";
2257
2258 // Find and load .wxl file.
2259 hr = LocProbeForFile(wzModulePath, wzLocFileName, wzLanguage, &sczLocPath);
2260 BalExitOnFailure(hr, "Failed to probe for loc file: %ls in path: %ls", wzLocFileName, wzModulePath);
2261
2262 hr = LocLoadFromFile(sczLocPath, &m_pWixLoc);
2263 BalExitOnFailure(hr, "Failed to load loc file from path: %ls", sczLocPath);
2264
2265 // Set WixStdBALanguageId to .wxl language id.
2266 if (WIX_LOCALIZATION_LANGUAGE_NOT_SET != m_pWixLoc->dwLangId)
2267 {
2268 ::SetThreadLocale(m_pWixLoc->dwLangId);
2269
2270 hr = m_pEngine->SetVariableNumeric(WIXSTDBA_VARIABLE_LANGUAGE_ID, m_pWixLoc->dwLangId);
2271 BalExitOnFailure(hr, "Failed to set WixStdBALanguageId variable.");
2272 }
2273
2274 // Load ConfirmCancelMessage.
2275 hr = StrAllocString(&m_sczConfirmCloseMessage, L"#(loc.ConfirmCancelMessage)", 0);
2276 ExitOnFailure(hr, "Failed to initialize confirm message loc identifier.");
2277
2278 hr = LocLocalizeString(m_pWixLoc, &m_sczConfirmCloseMessage);
2279 BalExitOnFailure(hr, "Failed to localize confirm close message: %ls", m_sczConfirmCloseMessage);
2280
2281 hr = BalFormatString(m_sczConfirmCloseMessage, &sczFormatted);
2282 if (SUCCEEDED(hr))
2283 {
2284 ReleaseStr(m_sczConfirmCloseMessage);
2285 m_sczConfirmCloseMessage = sczFormatted;
2286 sczFormatted = NULL;
2287 }
2288
2289 LExit:
2290 ReleaseStr(sczFormatted);
2291 ReleaseStr(sczLocPath);
2292
2293 return hr;
2294 }
2295
2296
2297 HRESULT LoadTheme(
2298 __in_z LPCWSTR wzModulePath,
2299 __in_z_opt LPCWSTR wzLanguage
2300 )
2301 {
2302 HRESULT hr = S_OK;
2303 LPWSTR sczThemePath = NULL;
2304 LPCWSTR wzThemeFileName = m_fPrereq ? L"mbapreq.thm" : L"thm.xml";
2305
2306 hr = LocProbeForFile(wzModulePath, wzThemeFileName, wzLanguage, &sczThemePath);
2307 BalExitOnFailure(hr, "Failed to probe for theme file: %ls in path: %ls", wzThemeFileName, wzModulePath);
2308
2309 hr = ThemeLoadFromFile(sczThemePath, &m_pTheme);
2310 BalExitOnFailure(hr, "Failed to load theme from path: %ls", sczThemePath);
2311
2312 hr = ThemeRegisterVariableCallbacks(m_pTheme, EvaluateVariableConditionCallback, FormatVariableStringCallback, GetVariableNumericCallback, SetVariableNumericCallback, GetVariableStringCallback, SetVariableStringCallback, NULL);
2313 BalExitOnFailure(hr, "Failed to register variable theme callbacks.");
2314
2315 hr = ThemeLocalize(m_pTheme, m_pWixLoc);
2316 BalExitOnFailure(hr, "Failed to localize theme: %ls", sczThemePath);
2317
2318 LExit:
2319 ReleaseStr(sczThemePath);
2320
2321 return hr;
2322 }
2323
2324
2325 HRESULT ParseOverridableVariablesFromXml(
2326 __in IXMLDOMDocument* pixdManifest
2327 )
2328 {
2329 HRESULT hr = S_OK;
2330 IXMLDOMNode* pNode = NULL;
2331 IXMLDOMNodeList* pNodes = NULL;
2332 DWORD cNodes = 0;
2333 LPWSTR scz = NULL;
2334
2335 // Get the list of variables users can override on the command line.
2336 hr = XmlSelectNodes(pixdManifest, L"/BootstrapperApplicationData/WixStdbaOverridableVariable", &pNodes);
2337 if (S_FALSE == hr)
2338 {
2339 ExitFunction1(hr = S_OK);
2340 }
2341 ExitOnFailure(hr, "Failed to select overridable variable nodes.");
2342
2343 hr = pNodes->get_length((long*)&cNodes);
2344 ExitOnFailure(hr, "Failed to get overridable variable node count.");
2345
2346 if (cNodes)
2347 {
2348 hr = DictCreateStringList(&m_sdOverridableVariables, 32, DICT_FLAG_NONE);
2349 ExitOnFailure(hr, "Failed to create the string dictionary.");
2350
2351 for (DWORD i = 0; i < cNodes; ++i)
2352 {
2353 hr = XmlNextElement(pNodes, &pNode, NULL);
2354 ExitOnFailure(hr, "Failed to get next node.");
2355
2356 // @Name
2357 hr = XmlGetAttributeEx(pNode, L"Name", &scz);
2358 ExitOnFailure(hr, "Failed to get @Name.");
2359
2360 hr = DictAddKey(m_sdOverridableVariables, scz);
2361 ExitOnFailure(hr, "Failed to add \"%ls\" to the string dictionary.", scz);
2362
2363 // prepare next iteration
2364 ReleaseNullObject(pNode);
2365 }
2366 }
2367
2368 LExit:
2369 ReleaseObject(pNode);
2370 ReleaseObject(pNodes);
2371 ReleaseStr(scz);
2372 return hr;
2373 }
2374
2375
2376 HRESULT InitializePackageInfo()
2377 {
2378 HRESULT hr = S_OK;
2379 BAL_INFO_PACKAGE* pPackage = NULL;
2380
2381 for (DWORD i = 0; i < m_Bundle.packages.cPackages; ++i)
2382 {
2383 pPackage = &m_Bundle.packages.rgPackages[i];
2384
2385 hr = InitializePackageInfoForPackage(pPackage);
2386 BalExitOnFailure(hr, "Failed to initialize wixstdba package info for package: %ls.", pPackage->sczId);
2387 }
2388
2389 LExit:
2390 return hr;
2391 }
2392
2393
2394 HRESULT InitializePackageInfoForPackage(
2395 __in BAL_INFO_PACKAGE* pPackage
2396 )
2397 {
2398 HRESULT hr = S_OK;
2399
2400 pPackage->pvCustomData = MemAlloc(sizeof(WIXSTDBA_PACKAGE_INFO), TRUE);
2401 BalExitOnNull(pPackage->pvCustomData, hr, E_OUTOFMEMORY, "Failed to allocate memory for wixstdba package info.");
2402
2403 LExit:
2404 return hr;
2405 }
2406
2407
2408 HRESULT InitializePrerequisiteInformation()
2409 {
2410 HRESULT hr = S_OK;
2411 BAL_INFO_PACKAGE* pPackage = NULL;
2412
2413 for (DWORD i = 0; i < m_Bundle.packages.cPackages; ++i)
2414 {
2415 pPackage = &m_Bundle.packages.rgPackages[i];
2416 if (!pPackage->fPrereqPackage)
2417 {
2418 continue;
2419 }
2420
2421 if (pPackage->sczPrereqLicenseFile)
2422 {
2423 if (m_sczLicenseFile)
2424 {
2425 hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
2426 BalExitOnFailure(hr, "More than one license file specified in prerequisite info.");
2427 }
2428
2429 hr = StrAllocString(&m_sczLicenseFile, pPackage->sczPrereqLicenseFile, 0);
2430 BalExitOnFailure(hr, "Failed to copy license file location from prereq package.");
2431 }
2432
2433 if (pPackage->sczPrereqLicenseUrl)
2434 {
2435 if (m_sczLicenseUrl)
2436 {
2437 hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
2438 BalExitOnFailure(hr, "More than one license URL specified in prerequisite info.");
2439 }
2440
2441 hr = StrAllocString(&m_sczLicenseUrl, pPackage->sczPrereqLicenseUrl, 0);
2442 BalExitOnFailure(hr, "Failed to copy license URL from prereq package.");
2443 }
2444 }
2445
2446 LExit:
2447 return hr;
2448 }
2449
2450
2451 HRESULT ParseBootstrapperApplicationDataFromXml(
2452 __in IXMLDOMDocument* pixdManifest
2453 )
2454 {
2455 HRESULT hr = S_OK;
2456 IXMLDOMNode* pNode = NULL;
2457 DWORD dwBool = 0;
2458
2459 hr = XmlSelectSingleNode(pixdManifest, L"/BootstrapperApplicationData/WixStdbaInformation", &pNode);
2460 if (S_FALSE == hr)
2461 {
2462 hr = E_INVALIDARG;
2463 }
2464 BalExitOnFailure(hr, "BootstrapperApplication.xml manifest is missing wixstdba information.");
2465
2466 hr = XmlGetAttributeEx(pNode, L"LicenseFile", &m_sczLicenseFile);
2467 if (E_NOTFOUND == hr)
2468 {
2469 hr = S_OK;
2470 }
2471 BalExitOnFailure(hr, "Failed to get license file.");
2472
2473 hr = XmlGetAttributeEx(pNode, L"LicenseUrl", &m_sczLicenseUrl);
2474 if (E_NOTFOUND == hr)
2475 {
2476 hr = S_OK;
2477 }
2478 BalExitOnFailure(hr, "Failed to get license URL.");
2479
2480 ReleaseObject(pNode);
2481
2482 hr = XmlSelectSingleNode(pixdManifest, L"/BootstrapperApplicationData/WixStdbaOptions", &pNode);
2483 if (S_FALSE == hr)
2484 {
2485 ExitFunction1(hr = S_OK);
2486 }
2487 BalExitOnFailure(hr, "Failed to read wixstdba options from BootstrapperApplication.xml manifest.");
2488
2489 hr = XmlGetAttributeNumber(pNode, L"SuppressOptionsUI", &dwBool);
2490 if (S_FALSE == hr)
2491 {
2492 hr = S_OK;
2493 }
2494 else if (SUCCEEDED(hr) && dwBool)
2495 {
2496 hr = BalSetNumericVariable(WIXSTDBA_VARIABLE_SUPPRESS_OPTIONS_UI, 1);
2497 BalExitOnFailure(hr, "Failed to set '%ls' variable.", WIXSTDBA_VARIABLE_SUPPRESS_OPTIONS_UI);
2498 }
2499 BalExitOnFailure(hr, "Failed to get SuppressOptionsUI value.");
2500
2501 dwBool = 0;
2502 hr = XmlGetAttributeNumber(pNode, L"SuppressDowngradeFailure", &dwBool);
2503 if (S_FALSE == hr)
2504 {
2505 hr = S_OK;
2506 }
2507 else if (SUCCEEDED(hr))
2508 {
2509 m_fSuppressDowngradeFailure = 0 < dwBool;
2510 }
2511 BalExitOnFailure(hr, "Failed to get SuppressDowngradeFailure value.");
2512
2513 dwBool = 0;
2514 hr = XmlGetAttributeNumber(pNode, L"SuppressRepair", &dwBool);
2515 if (S_FALSE == hr)
2516 {
2517 hr = S_OK;
2518 }
2519 else if (SUCCEEDED(hr))
2520 {
2521 m_fSuppressRepair = 0 < dwBool;
2522 }
2523 BalExitOnFailure(hr, "Failed to get SuppressRepair value.");
2524
2525 hr = XmlGetAttributeNumber(pNode, L"ShowVersion", &dwBool);
2526 if (S_FALSE == hr)
2527 {
2528 hr = S_OK;
2529 }
2530 else if (SUCCEEDED(hr) && dwBool)
2531 {
2532 hr = BalSetNumericVariable(WIXSTDBA_VARIABLE_SHOW_VERSION, 1);
2533 BalExitOnFailure(hr, "Failed to set '%ls' variable.", WIXSTDBA_VARIABLE_SHOW_VERSION);
2534 }
2535 BalExitOnFailure(hr, "Failed to get ShowVersion value.");
2536
2537 hr = XmlGetAttributeNumber(pNode, L"SupportCacheOnly", &dwBool);
2538 if (S_FALSE == hr)
2539 {
2540 hr = S_OK;
2541 }
2542 else if (SUCCEEDED(hr))
2543 {
2544 m_fSupportCacheOnly = 0 < dwBool;
2545 }
2546 BalExitOnFailure(hr, "Failed to get SupportCacheOnly value.");
2547
2548 LExit:
2549 ReleaseObject(pNode);
2550 return hr;
2551 }
2552
2553 HRESULT GetPackageInfo(
2554 __in_z LPCWSTR wzPackageId,
2555 __out WIXSTDBA_PACKAGE_INFO** ppPackageInfo,
2556 __out BAL_INFO_PACKAGE** ppPackage
2557 )
2558 {
2559 HRESULT hr = E_NOTFOUND;
2560 WIXSTDBA_PACKAGE_INFO* pPackageInfo = NULL;
2561 BAL_INFO_PACKAGE* pPackage = NULL;
2562
2563 Assert(wzPackageId && *wzPackageId);
2564 Assert(ppPackage);
2565 Assert(ppPackageInfo);
2566
2567 hr = BalInfoFindPackageById(&m_Bundle.packages, wzPackageId, &pPackage);
2568 if (E_NOTFOUND != hr)
2569 {
2570 ExitOnFailure(hr, "Failed trying to find the requested package.");
2571
2572 pPackageInfo = reinterpret_cast<WIXSTDBA_PACKAGE_INFO*>(pPackage->pvCustomData);
2573 }
2574
2575 *ppPackageInfo = pPackageInfo;
2576 *ppPackage = pPackage;
2577
2578 LExit:
2579 return hr;
2580 }
2581
2582
2583 //
2584 // Get the file version of the bootstrapper and record in bootstrapper log file
2585 //
2586 HRESULT GetBundleFileVersion()
2587 {
2588 HRESULT hr = S_OK;
2589 ULARGE_INTEGER uliVersion = { };
2590 LPWSTR sczCurrentPath = NULL;
2591 VERUTIL_VERSION* pVersion = NULL;
2592
2593 hr = PathForCurrentProcess(&sczCurrentPath, NULL);
2594 BalExitOnFailure(hr, "Failed to get bundle path.");
2595
2596 hr = FileVersion(sczCurrentPath, &uliVersion.HighPart, &uliVersion.LowPart);
2597 BalExitOnFailure(hr, "Failed to get bundle file version.");
2598
2599 hr = VerVersionFromQword(uliVersion.QuadPart, &pVersion);
2600 BalExitOnFailure(hr, "Failed to create bundle file version.");
2601
2602 hr = m_pEngine->SetVariableVersion(WIXSTDBA_VARIABLE_BUNDLE_FILE_VERSION, pVersion->sczVersion);
2603 BalExitOnFailure(hr, "Failed to set WixBundleFileVersion variable.");
2604
2605 LExit:
2606 ReleaseVerutilVersion(pVersion);
2607 ReleaseStr(sczCurrentPath);
2608
2609 return hr;
2610 }
2611
2612
2613 //
2614 // CreateMainWindow - creates the main install window.
2615 //
2616 HRESULT CreateMainWindow()
2617 {
2618 HRESULT hr = S_OK;
2619 HICON hIcon = reinterpret_cast<HICON>(m_pTheme->hIcon);
2620 WNDCLASSW wc = { };
2621 DWORD dwWindowStyle = 0;
2622 int x = CW_USEDEFAULT;
2623 int y = CW_USEDEFAULT;
2624 POINT ptCursor = { };
2625
2626 // If the theme did not provide an icon, try using the icon from the bundle engine.
2627 if (!hIcon)
2628 {
2629 HMODULE hBootstrapperEngine = ::GetModuleHandleW(NULL);
2630 if (hBootstrapperEngine)
2631 {
2632 hIcon = ::LoadIconW(hBootstrapperEngine, MAKEINTRESOURCEW(1));
2633 }
2634 }
2635
2636 // Register the window class and create the window.
2637 wc.lpfnWndProc = CWixStandardBootstrapperApplication::WndProc;
2638 wc.hInstance = m_hModule;
2639 wc.hIcon = hIcon;
2640 wc.hCursor = ::LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
2641 wc.hbrBackground = m_pTheme->rgFonts[m_pTheme->dwFontId].hBackground;
2642 wc.lpszMenuName = NULL;
2643 wc.lpszClassName = WIXSTDBA_WINDOW_CLASS;
2644 if (!::RegisterClassW(&wc))
2645 {
2646 ExitWithLastError(hr, "Failed to register window.");
2647 }
2648
2649 m_fRegistered = TRUE;
2650
2651 // Calculate the window style based on the theme style and command display value.
2652 dwWindowStyle = m_pTheme->dwStyle;
2653 if (BOOTSTRAPPER_DISPLAY_NONE >= m_command.display)
2654 {
2655 dwWindowStyle &= ~WS_VISIBLE;
2656 }
2657
2658 // Don't show the window if there is a splash screen (it will be made visible when the splash screen is hidden)
2659 if (::IsWindow(m_command.hwndSplashScreen))
2660 {
2661 dwWindowStyle &= ~WS_VISIBLE;
2662 }
2663
2664 // Center the window on the monitor with the mouse.
2665 if (::GetCursorPos(&ptCursor))
2666 {
2667 x = ptCursor.x;
2668 y = ptCursor.y;
2669 }
2670
2671 hr = ThemeCreateParentWindow(m_pTheme, 0, wc.lpszClassName, m_pTheme->sczCaption, dwWindowStyle, x, y, HWND_DESKTOP, m_hModule, this, THEME_WINDOW_INITIAL_POSITION_CENTER_MONITOR_FROM_COORDINATES, &m_hWnd);
2672 ExitOnFailure(hr, "Failed to create window.");
2673
2674 hr = S_OK;
2675
2676 LExit:
2677 return hr;
2678 }
2679
2680
2681 //
2682 // InitializeTaskbarButton - initializes taskbar button for progress.
2683 //
2684 void InitializeTaskbarButton()
2685 {
2686 HRESULT hr = S_OK;
2687
2688 hr = ::CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_ALL, __uuidof(ITaskbarList3), reinterpret_cast<LPVOID*>(&m_pTaskbarList));
2689 if (REGDB_E_CLASSNOTREG == hr) // not supported before Windows 7
2690 {
2691 ExitFunction1(hr = S_OK);
2692 }
2693 BalExitOnFailure(hr, "Failed to create ITaskbarList3. Continuing.");
2694
2695 m_uTaskbarButtonCreatedMessage = ::RegisterWindowMessageW(L"TaskbarButtonCreated");
2696 BalExitOnNullWithLastError(m_uTaskbarButtonCreatedMessage, hr, "Failed to get TaskbarButtonCreated message. Continuing.");
2697
2698 LExit:
2699 return;
2700 }
2701
2702 //
2703 // DestroyMainWindow - clean up all the window registration.
2704 //
2705 void DestroyMainWindow()
2706 {
2707 if (::IsWindow(m_hWnd))
2708 {
2709 ::DestroyWindow(m_hWnd);
2710 m_hWnd = NULL;
2711 m_fTaskbarButtonOK = FALSE;
2712 }
2713
2714 if (m_fRegistered)
2715 {
2716 ::UnregisterClassW(WIXSTDBA_WINDOW_CLASS, m_hModule);
2717 m_fRegistered = FALSE;
2718 }
2719 }
2720
2721
2722 //
2723 // UninitializeTaskbarButton - clean up the taskbar registration.
2724 //
2725 void UninitializeTaskbarButton()
2726 {
2727 m_fTaskbarButtonOK = FALSE;
2728 ReleaseNullObject(m_pTaskbarList);
2729 }
2730
2731
2732 static LRESULT CallDefaultWndProc(
2733 __in CWixStandardBootstrapperApplication* pBA,
2734 __in HWND hWnd,
2735 __in UINT uMsg,
2736 __in WPARAM wParam,
2737 __in LPARAM lParam
2738 )
2739 {
2740 LRESULT lres = NULL;
2741 THEME* pTheme = NULL;
2742 HRESULT hr = S_OK;
2743 BA_FUNCTIONS_WNDPROC_ARGS wndProcArgs = { };
2744 BA_FUNCTIONS_WNDPROC_RESULTS wndProcResults = { };
2745
2746 if (pBA)
2747 {
2748 pTheme = pBA->m_pTheme;
2749
2750 if (pBA->m_pfnBAFunctionsProc)
2751 {
2752 wndProcArgs.cbSize = sizeof(wndProcArgs);
2753 wndProcArgs.pTheme = pTheme;
2754 wndProcArgs.hWnd = hWnd;
2755 wndProcArgs.uMsg = uMsg;
2756 wndProcArgs.wParam = wParam;
2757 wndProcArgs.lParam = lParam;
2758 wndProcResults.cbSize = sizeof(wndProcResults);
2759
2760 hr = pBA->m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_WNDPROC, &wndProcArgs, &wndProcResults, pBA->m_pvBAFunctionsProcContext);
2761 if (E_NOTIMPL != hr)
2762 {
2763 lres = wndProcResults.lres;
2764 ExitFunction();
2765 }
2766 }
2767 }
2768
2769 lres = ThemeDefWindowProc(pTheme, hWnd, uMsg, wParam, lParam);
2770
2771 LExit:
2772 return lres;
2773 }
2774
2775 //
2776 // WndProc - standard windows message handler.
2777 //
2778 static LRESULT CALLBACK WndProc(
2779 __in HWND hWnd,
2780 __in UINT uMsg,
2781 __in WPARAM wParam,
2782 __in LPARAM lParam
2783 )
2784 {
2785#pragma warning(suppress:4312)
2786 CWixStandardBootstrapperApplication* pBA = reinterpret_cast<CWixStandardBootstrapperApplication*>(::GetWindowLongPtrW(hWnd, GWLP_USERDATA));
2787 BOOL fCancel = FALSE;
2788
2789 switch (uMsg)
2790 {
2791 case WM_NCCREATE:
2792 {
2793 LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
2794 pBA = reinterpret_cast<CWixStandardBootstrapperApplication*>(lpcs->lpCreateParams);
2795#pragma warning(suppress:4244)
2796 ::SetWindowLongPtrW(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pBA));
2797 }
2798 break;
2799
2800 case WM_NCDESTROY:
2801 {
2802 LRESULT lres = CallDefaultWndProc(pBA, hWnd, uMsg, wParam, lParam);
2803 ::SetWindowLongPtrW(hWnd, GWLP_USERDATA, 0);
2804 ::PostQuitMessage(0);
2805 return lres;
2806 }
2807
2808 case WM_CREATE:
2809 if (!pBA->OnCreate(hWnd))
2810 {
2811 return -1;
2812 }
2813 break;
2814
2815 case WM_QUERYENDSESSION:
2816 fCancel = true;
2817 pBA->OnSystemShutdown(static_cast<DWORD>(lParam), &fCancel);
2818 return !fCancel;
2819
2820 case WM_CLOSE:
2821 // If the user chose not to close, do *not* let the default window proc handle the message.
2822 if (!pBA->OnClose())
2823 {
2824 return 0;
2825 }
2826 break;
2827
2828 case WM_WIXSTDBA_SHOW_HELP:
2829 pBA->OnShowHelp();
2830 return 0;
2831
2832 case WM_WIXSTDBA_DETECT_PACKAGES:
2833 pBA->OnDetect();
2834 return 0;
2835
2836 case WM_WIXSTDBA_PLAN_PACKAGES:
2837 pBA->OnPlan(static_cast<BOOTSTRAPPER_ACTION>(lParam));
2838 return 0;
2839
2840 case WM_WIXSTDBA_APPLY_PACKAGES:
2841 pBA->OnApply();
2842 return 0;
2843
2844 case WM_WIXSTDBA_CHANGE_STATE:
2845 pBA->OnChangeState(static_cast<WIXSTDBA_STATE>(lParam));
2846 return 0;
2847
2848 case WM_WIXSTDBA_SHOW_FAILURE:
2849 pBA->OnShowFailure();
2850 return 0;
2851
2852 case WM_COMMAND:
2853 switch (HIWORD(wParam))
2854 {
2855 case BN_CLICKED:
2856 switch (LOWORD(wParam))
2857 {
2858 case WIXSTDBA_CONTROL_EULA_ACCEPT_CHECKBOX:
2859 pBA->OnClickAcceptCheckbox();
2860 return 0;
2861
2862 case WIXSTDBA_CONTROL_INSTALL_BUTTON:
2863 pBA->OnClickInstallButton();
2864 return 0;
2865
2866 case WIXSTDBA_CONTROL_REPAIR_BUTTON:
2867 pBA->OnClickRepairButton();
2868 return 0;
2869
2870 case WIXSTDBA_CONTROL_UNINSTALL_BUTTON:
2871 pBA->OnClickUninstallButton();
2872 return 0;
2873
2874 case WIXSTDBA_CONTROL_LAUNCH_BUTTON:
2875 pBA->OnClickLaunchButton();
2876 return 0;
2877
2878 case WIXSTDBA_CONTROL_SUCCESS_RESTART_BUTTON: __fallthrough;
2879 case WIXSTDBA_CONTROL_FAILURE_RESTART_BUTTON:
2880 pBA->OnClickRestartButton();
2881 return 0;
2882
2883 case WIXSTDBA_CONTROL_PROGRESS_CANCEL_BUTTON:
2884 pBA->OnClickCloseButton();
2885 return 0;
2886 }
2887 break;
2888 }
2889 break;
2890
2891 case WM_NOTIFY:
2892 if (lParam)
2893 {
2894 LPNMHDR pnmhdr = reinterpret_cast<LPNMHDR>(lParam);
2895 switch (pnmhdr->code)
2896 {
2897 case NM_CLICK: __fallthrough;
2898 case NM_RETURN:
2899 switch (static_cast<DWORD>(pnmhdr->idFrom))
2900 {
2901 case WIXSTDBA_CONTROL_EULA_LINK:
2902 pBA->OnClickEulaLink();
2903 return 1;
2904 case WIXSTDBA_CONTROL_FAILURE_LOGFILE_LINK:
2905 pBA->OnClickLogFileLink();
2906 return 1;
2907 }
2908 }
2909 }
2910 break;
2911 }
2912
2913 if (pBA && pBA->m_pTaskbarList && uMsg == pBA->m_uTaskbarButtonCreatedMessage)
2914 {
2915 pBA->m_fTaskbarButtonOK = TRUE;
2916 return 0;
2917 }
2918
2919 return CallDefaultWndProc(pBA, hWnd, uMsg, wParam, lParam);
2920 }
2921
2922
2923 //
2924 // OnCreate - finishes loading the theme.
2925 //
2926 BOOL OnCreate(
2927 __in HWND /*hWnd*/
2928 )
2929 {
2930 HRESULT hr = S_OK;
2931 LPWSTR sczLicenseFormatted = NULL;
2932 LPWSTR sczLicensePath = NULL;
2933 LPWSTR sczLicenseDirectory = NULL;
2934 LPWSTR sczLicenseFilename = NULL;
2935 BA_FUNCTIONS_ONTHEMELOADED_ARGS themeLoadedArgs = { };
2936 BA_FUNCTIONS_ONTHEMELOADED_RESULTS themeLoadedResults = { };
2937
2938 hr = ThemeLoadControls(m_pTheme, vrgInitControls, countof(vrgInitControls));
2939 BalExitOnFailure(hr, "Failed to load theme controls.");
2940
2941 C_ASSERT(COUNT_WIXSTDBA_PAGE == countof(vrgwzPageNames));
2942 C_ASSERT(countof(m_rgdwPageIds) == countof(vrgwzPageNames));
2943
2944 ThemeGetPageIds(m_pTheme, vrgwzPageNames, m_rgdwPageIds, countof(m_rgdwPageIds));
2945
2946 // Load the RTF EULA control with text if the control exists.
2947 if (ThemeControlExists(m_pTheme, WIXSTDBA_CONTROL_EULA_RICHEDIT))
2948 {
2949 hr = (m_sczLicenseFile && *m_sczLicenseFile) ? S_OK : E_INVALIDDATA;
2950 if (SUCCEEDED(hr))
2951 {
2952 hr = StrAllocString(&sczLicenseFormatted, m_sczLicenseFile, 0);
2953 if (SUCCEEDED(hr))
2954 {
2955 hr = LocLocalizeString(m_pWixLoc, &sczLicenseFormatted);
2956 if (SUCCEEDED(hr))
2957 {
2958 // Assume there is no hidden variables to be formatted
2959 // so don't worry about securely freeing it.
2960 hr = BalFormatString(sczLicenseFormatted, &sczLicenseFormatted);
2961 if (SUCCEEDED(hr))
2962 {
2963 hr = PathRelativeToModule(&sczLicensePath, sczLicenseFormatted, m_hModule);
2964 if (SUCCEEDED(hr))
2965 {
2966 hr = PathGetDirectory(sczLicensePath, &sczLicenseDirectory);
2967 if (SUCCEEDED(hr))
2968 {
2969 hr = StrAllocString(&sczLicenseFilename, PathFile(sczLicenseFormatted), 0);
2970 if (SUCCEEDED(hr))
2971 {
2972 hr = LocProbeForFile(sczLicenseDirectory, sczLicenseFilename, m_sczLanguage, &sczLicensePath);
2973 if (SUCCEEDED(hr))
2974 {
2975 hr = ThemeLoadRichEditFromFile(m_pTheme, WIXSTDBA_CONTROL_EULA_RICHEDIT, sczLicensePath, m_hModule);
2976 }
2977 }
2978 }
2979 }
2980 }
2981 }
2982 }
2983 }
2984
2985 if (FAILED(hr))
2986 {
2987 BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "Failed to load file into license richedit control from path '%ls' manifest value: %ls", sczLicensePath, m_sczLicenseFile);
2988 hr = S_OK;
2989 }
2990 }
2991
2992 if (m_pfnBAFunctionsProc)
2993 {
2994 themeLoadedArgs.cbSize = sizeof(themeLoadedArgs);
2995 themeLoadedArgs.pTheme = m_pTheme;
2996 themeLoadedArgs.pWixLoc = m_pWixLoc;
2997 themeLoadedResults.cbSize = sizeof(themeLoadedResults);
2998 hr = m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONTHEMELOADED, &themeLoadedArgs, &themeLoadedResults, m_pvBAFunctionsProcContext);
2999 BalExitOnFailure(hr, "BAFunctions OnThemeLoaded failed.");
3000 }
3001
3002 LExit:
3003 ReleaseStr(sczLicenseFilename);
3004 ReleaseStr(sczLicenseDirectory);
3005 ReleaseStr(sczLicensePath);
3006 ReleaseStr(sczLicenseFormatted);
3007
3008 return SUCCEEDED(hr);
3009 }
3010
3011
3012 //
3013 // OnShowFailure - display the failure page.
3014 //
3015 void OnShowFailure()
3016 {
3017 SetState(WIXSTDBA_STATE_FAILED, S_OK);
3018
3019 // If the UI should be visible, display it now and hide the splash screen
3020 if (BOOTSTRAPPER_DISPLAY_NONE < m_command.display)
3021 {
3022 ::ShowWindow(m_pTheme->hwndParent, SW_SHOW);
3023 }
3024
3025 m_pEngine->CloseSplashScreen();
3026
3027 return;
3028 }
3029
3030
3031 //
3032 // OnShowHelp - display the help page.
3033 //
3034 void OnShowHelp()
3035 {
3036 SetState(WIXSTDBA_STATE_HELP, S_OK);
3037
3038 // If the UI should be visible, display it now and hide the splash screen
3039 if (BOOTSTRAPPER_DISPLAY_NONE < m_command.display)
3040 {
3041 ::ShowWindow(m_pTheme->hwndParent, SW_SHOW);
3042 }
3043
3044 m_pEngine->CloseSplashScreen();
3045
3046 return;
3047 }
3048
3049
3050 //
3051 // OnDetect - start the processing of packages.
3052 //
3053 void OnDetect()
3054 {
3055 HRESULT hr = S_OK;
3056
3057 SetState(WIXSTDBA_STATE_DETECTING, hr);
3058
3059 // If the UI should be visible, display it now and hide the splash screen
3060 if (BOOTSTRAPPER_DISPLAY_NONE < m_command.display)
3061 {
3062 ::ShowWindow(m_pTheme->hwndParent, SW_SHOW);
3063 }
3064
3065 m_pEngine->CloseSplashScreen();
3066
3067 // Tell the core we're ready for the packages to be processed now.
3068 hr = m_pEngine->Detect();
3069 BalExitOnFailure(hr, "Failed to start detecting chain.");
3070
3071 LExit:
3072 if (FAILED(hr))
3073 {
3074 SetState(WIXSTDBA_STATE_DETECTING, hr);
3075 }
3076
3077 return;
3078 }
3079
3080
3081 //
3082 // OnPlan - plan the detected changes.
3083 //
3084 void OnPlan(
3085 __in BOOTSTRAPPER_ACTION action
3086 )
3087 {
3088 HRESULT hr = S_OK;
3089
3090 m_plannedAction = action;
3091
3092 // If we are going to apply a downgrade, bail.
3093 if (m_fDowngrading && BOOTSTRAPPER_ACTION_UNINSTALL < action)
3094 {
3095 if (m_fSuppressDowngradeFailure)
3096 {
3097 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "A newer version of this product is installed but downgrade failure has been suppressed; continuing...");
3098 }
3099 else
3100 {
3101 hr = HRESULT_FROM_WIN32(ERROR_PRODUCT_VERSION);
3102 BalExitOnFailure(hr, "Cannot install a product when a newer version is installed.");
3103 }
3104 }
3105
3106 SetState(WIXSTDBA_STATE_PLANNING, hr);
3107
3108 hr = m_pEngine->Plan(action);
3109 BalExitOnFailure(hr, "Failed to start planning packages.");
3110
3111 LExit:
3112 if (FAILED(hr))
3113 {
3114 SetState(WIXSTDBA_STATE_PLANNING, hr);
3115 }
3116
3117 return;
3118 }
3119
3120
3121 //
3122 // OnApply - apply the packages.
3123 //
3124 void OnApply()
3125 {
3126 HRESULT hr = S_OK;
3127
3128 SetState(WIXSTDBA_STATE_APPLYING, hr);
3129 SetProgressState(hr);
3130 SetTaskbarButtonProgress(0);
3131
3132 hr = m_pEngine->Apply(m_hWnd);
3133 BalExitOnFailure(hr, "Failed to start applying packages.");
3134
3135 ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_PROGRESS_CANCEL_BUTTON, TRUE); // ensure the cancel button is enabled before starting.
3136
3137 LExit:
3138 if (FAILED(hr))
3139 {
3140 SetState(WIXSTDBA_STATE_APPLYING, hr);
3141 }
3142
3143 return;
3144 }
3145
3146
3147 //
3148 // OnChangeState - change state.
3149 //
3150 void OnChangeState(
3151 __in WIXSTDBA_STATE state
3152 )
3153 {
3154 WIXSTDBA_STATE stateOld = m_state;
3155 DWORD dwOldPageId = 0;
3156 DWORD dwNewPageId = 0;
3157 LPWSTR sczText = NULL;
3158 LPWSTR sczUnformattedText = NULL;
3159 LPWSTR sczControlState = NULL;
3160 LPWSTR sczControlName = NULL;
3161
3162 m_state = state;
3163
3164 // If our install is at the end (success or failure) and we're not showing full UI or
3165 // we successfully installed the prerequisite then exit (prompt for restart if required).
3166 if ((WIXSTDBA_STATE_APPLIED <= m_state && BOOTSTRAPPER_DISPLAY_FULL > m_command.display) ||
3167 (WIXSTDBA_STATE_APPLIED == m_state && m_fPrereq))
3168 {
3169 // If a restart was required but we were not automatically allowed to
3170 // accept the reboot then do the prompt.
3171 if (m_fRestartRequired && !m_fAllowRestart)
3172 {
3173 StrAllocFromError(&sczUnformattedText, HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED), NULL);
3174
3175 int nResult = ::MessageBoxW(m_hWnd, sczUnformattedText ? sczUnformattedText : L"The requested operation is successful. Changes will not be effective until the system is rebooted.", m_pTheme->sczCaption, MB_ICONEXCLAMATION | MB_OKCANCEL);
3176 m_fAllowRestart = (IDOK == nResult);
3177 }
3178
3179 // Quietly exit.
3180 ::PostMessageW(m_hWnd, WM_CLOSE, 0, 0);
3181 }
3182 else // try to change the pages.
3183 {
3184 DeterminePageId(stateOld, &dwOldPageId);
3185 DeterminePageId(m_state, &dwNewPageId);
3186
3187 if (dwOldPageId != dwNewPageId)
3188 {
3189 // Enable disable controls per-page.
3190 if (m_rgdwPageIds[WIXSTDBA_PAGE_INSTALL] == dwNewPageId) // on the "Install" page, ensure the install button is enabled/disabled correctly.
3191 {
3192 LONGLONG llElevated = 0;
3193 if (m_Bundle.fPerMachine)
3194 {
3195 BalGetNumericVariable(WIXBUNDLE_VARIABLE_ELEVATED, &llElevated);
3196 }
3197 ThemeControlElevates(m_pTheme, WIXSTDBA_CONTROL_INSTALL_BUTTON, (m_Bundle.fPerMachine && !llElevated));
3198
3199 // If the EULA control exists, show it only if a license URL is provided as well.
3200 if (ThemeControlExists(m_pTheme, WIXSTDBA_CONTROL_EULA_LINK))
3201 {
3202 BOOL fEulaLink = (m_sczLicenseUrl && *m_sczLicenseUrl);
3203 ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_EULA_LINK, fEulaLink);
3204 ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_EULA_ACCEPT_CHECKBOX, fEulaLink);
3205 }
3206
3207 BOOL fAcceptedLicense = !ThemeControlExists(m_pTheme, WIXSTDBA_CONTROL_EULA_ACCEPT_CHECKBOX) || !ThemeControlEnabled(m_pTheme, WIXSTDBA_CONTROL_EULA_ACCEPT_CHECKBOX) || ThemeIsControlChecked(m_pTheme, WIXSTDBA_CONTROL_EULA_ACCEPT_CHECKBOX);
3208 ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_INSTALL_BUTTON, fAcceptedLicense);
3209 }
3210 else if (m_rgdwPageIds[WIXSTDBA_PAGE_MODIFY] == dwNewPageId)
3211 {
3212 ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_REPAIR_BUTTON, !m_fSuppressRepair);
3213 }
3214 else if (m_rgdwPageIds[WIXSTDBA_PAGE_SUCCESS] == dwNewPageId) // on the "Success" page, check if the restart or launch button should be enabled.
3215 {
3216 BOOL fShowRestartButton = FALSE;
3217 BOOL fLaunchTargetExists = FALSE;
3218 if (m_fRestartRequired)
3219 {
3220 if (BOOTSTRAPPER_RESTART_PROMPT == m_command.restart)
3221 {
3222 fShowRestartButton = TRUE;
3223 }
3224 }
3225 else if (ThemeControlExists(m_pTheme, WIXSTDBA_CONTROL_LAUNCH_BUTTON))
3226 {
3227 fLaunchTargetExists = BalVariableExists(WIXSTDBA_VARIABLE_LAUNCH_TARGET_PATH);
3228 }
3229
3230 ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_LAUNCH_BUTTON, fLaunchTargetExists && BOOTSTRAPPER_ACTION_UNINSTALL < m_plannedAction);
3231 ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_SUCCESS_RESTART_BUTTON, fShowRestartButton);
3232 }
3233 else if (m_rgdwPageIds[WIXSTDBA_PAGE_FAILURE] == dwNewPageId) // on the "Failure" page, show error message and check if the restart button should be enabled.
3234 {
3235 BOOL fShowLogLink = (m_Bundle.sczLogVariable && *m_Bundle.sczLogVariable); // if there is a log file variable then we'll assume the log file exists.
3236 BOOL fShowErrorMessage = FALSE;
3237 BOOL fShowRestartButton = FALSE;
3238
3239 if (FAILED(m_hrFinal))
3240 {
3241 // If we know the failure message, use that.
3242 if (m_sczFailedMessage && *m_sczFailedMessage)
3243 {
3244 StrAllocString(&sczUnformattedText, m_sczFailedMessage, 0);
3245 }
3246 else if (E_MBAHOST_NET452_ON_WIN7RTM == m_hrFinal)
3247 {
3248 HRESULT hr = StrAllocString(&sczUnformattedText, L"#(loc.NET452WIN7RTMErrorMessage)", 0);
3249 if (FAILED(hr))
3250 {
3251 BalLogError(hr, "Failed to initialize NET452WIN7RTMErrorMessage loc identifier.");
3252 }
3253 else
3254 {
3255 hr = LocLocalizeString(m_pWixLoc, &sczUnformattedText);
3256 if (FAILED(hr))
3257 {
3258 BalLogError(hr, "Failed to localize NET452WIN7RTMErrorMessage: %ls", sczUnformattedText);
3259 ReleaseNullStr(sczUnformattedText);
3260 }
3261 }
3262 }
3263 else if (E_DNCHOST_SCD_RUNTIME_FAILURE == m_hrFinal)
3264 {
3265 HRESULT hr = StrAllocString(&sczUnformattedText, L"#(loc.SCDRUNTIMEFAILUREErrorMessage)", 0);
3266 if (FAILED(hr))
3267 {
3268 BalLogError(hr, "Failed to initialize SCDRUNTIMEFAILUREErrorMessage loc identifier.");
3269 }
3270 else
3271 {
3272 hr = LocLocalizeString(m_pWixLoc, &sczUnformattedText);
3273 if (FAILED(hr))
3274 {
3275 BalLogError(hr, "Failed to localize SCDRUNTIMEFAILUREErrorMessage: %ls", sczUnformattedText);
3276 ReleaseNullStr(sczUnformattedText);
3277 }
3278 }
3279 }
3280 else // try to get the error message from the error code.
3281 {
3282 StrAllocFromError(&sczUnformattedText, m_hrFinal, NULL);
3283 if (!sczUnformattedText || !*sczUnformattedText)
3284 {
3285 StrAllocFromError(&sczUnformattedText, E_FAIL, NULL);
3286 }
3287 }
3288
3289 if (E_WIXSTDBA_CONDITION_FAILED == m_hrFinal)
3290 {
3291 if (sczUnformattedText)
3292 {
3293 StrAllocString(&sczText, sczUnformattedText, 0);
3294 }
3295 }
3296 else if (E_MBAHOST_NET452_ON_WIN7RTM == m_hrFinal)
3297 {
3298 if (sczUnformattedText)
3299 {
3300 BalFormatString(sczUnformattedText, &sczText);
3301 }
3302 }
3303 else if (E_DNCHOST_SCD_RUNTIME_FAILURE == m_hrFinal)
3304 {
3305 if (sczUnformattedText)
3306 {
3307 BalFormatString(sczUnformattedText, &sczText);
3308 }
3309 }
3310 else
3311 {
3312 StrAllocFormatted(&sczText, L"0x%08x - %ls", m_hrFinal, sczUnformattedText);
3313 }
3314
3315 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_FAILURE_MESSAGE_TEXT, sczText);
3316 fShowErrorMessage = TRUE;
3317 }
3318
3319 if (m_fRestartRequired)
3320 {
3321 if (BOOTSTRAPPER_RESTART_PROMPT == m_command.restart)
3322 {
3323 fShowRestartButton = TRUE;
3324 }
3325 }
3326
3327 ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_FAILURE_LOGFILE_LINK, fShowLogLink);
3328 ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_FAILURE_MESSAGE_TEXT, fShowErrorMessage);
3329 ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_FAILURE_RESTART_BUTTON, fShowRestartButton);
3330 }
3331
3332 HRESULT hr = ThemeShowPage(m_pTheme, dwOldPageId, SW_HIDE);
3333 if (FAILED(hr))
3334 {
3335 BalLogError(hr, "Failed to hide page: %u", dwOldPageId);
3336 }
3337
3338 hr = ThemeShowPage(m_pTheme, dwNewPageId, SW_SHOW);
3339 if (FAILED(hr))
3340 {
3341 BalLogError(hr, "Failed to show page: %u", dwOldPageId);
3342 }
3343
3344 // On the install page set the focus to the install button or the next enabled control if install is disabled.
3345 if (m_rgdwPageIds[WIXSTDBA_PAGE_INSTALL] == dwNewPageId)
3346 {
3347 ThemeSetFocus(m_pTheme, WIXSTDBA_CONTROL_INSTALL_BUTTON);
3348 }
3349 }
3350 }
3351
3352 ReleaseStr(sczText);
3353 ReleaseStr(sczUnformattedText);
3354 ReleaseStr(sczControlState);
3355 ReleaseStr(sczControlName);
3356 }
3357
3358
3359 //
3360 // OnClose - called when the window is trying to be closed.
3361 //
3362 BOOL OnClose()
3363 {
3364 BOOL fClose = FALSE;
3365 BOOL fCancel = FALSE;
3366
3367 // If we've already succeeded or failed or showing the help page, just close (prompts are annoying if the bootstrapper is done).
3368 if (WIXSTDBA_STATE_APPLIED <= m_state || WIXSTDBA_STATE_HELP == m_state)
3369 {
3370 fClose = TRUE;
3371 }
3372 else // prompt the user or force the cancel if there is no UI.
3373 {
3374 ::EnterCriticalSection(&m_csShowingInternalUiThisPackage);
3375 fClose = PromptCancel(
3376 m_hWnd,
3377 BOOTSTRAPPER_DISPLAY_FULL != m_command.display || m_fShowingInternalUiThisPackage,
3378 m_sczConfirmCloseMessage ? m_sczConfirmCloseMessage : L"Are you sure you want to cancel?",
3379 m_pTheme->sczCaption);
3380 ::LeaveCriticalSection(&m_csShowingInternalUiThisPackage);
3381
3382 fCancel = fClose;
3383 }
3384
3385 // If we're doing progress then we never close, we just cancel to let rollback occur.
3386 if (WIXSTDBA_STATE_APPLYING <= m_state && WIXSTDBA_STATE_APPLIED > m_state)
3387 {
3388 // If we canceled, disable cancel button since clicking it again is silly.
3389 if (fClose)
3390 {
3391 ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_PROGRESS_CANCEL_BUTTON, FALSE);
3392 }
3393
3394 fClose = FALSE;
3395 }
3396
3397 if (fClose)
3398 {
3399 DWORD dwCurrentPageId = 0;
3400 DeterminePageId(m_state, &dwCurrentPageId);
3401
3402 // Hide the current page to let thmutil do its thing with variables.
3403 ThemeShowPageEx(m_pTheme, dwCurrentPageId, SW_HIDE, fCancel ? THEME_SHOW_PAGE_REASON_CANCEL : THEME_SHOW_PAGE_REASON_DEFAULT);
3404 }
3405
3406 return fClose;
3407 }
3408
3409
3410 //
3411 // OnClickAcceptCheckbox - allow the install to continue.
3412 //
3413 void OnClickAcceptCheckbox()
3414 {
3415 BOOL fAcceptedLicense = ThemeIsControlChecked(m_pTheme, WIXSTDBA_CONTROL_EULA_ACCEPT_CHECKBOX);
3416 ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_INSTALL_BUTTON, fAcceptedLicense);
3417 }
3418
3419
3420 //
3421 // OnClickInstallButton - start the install by planning the packages.
3422 //
3423 void OnClickInstallButton()
3424 {
3425 this->OnPlan(BOOTSTRAPPER_ACTION_INSTALL);
3426 }
3427
3428
3429 //
3430 // OnClickRepairButton - start the repair.
3431 //
3432 void OnClickRepairButton()
3433 {
3434 this->OnPlan(BOOTSTRAPPER_ACTION_REPAIR);
3435 }
3436
3437
3438 //
3439 // OnClickUninstallButton - start the uninstall.
3440 //
3441 void OnClickUninstallButton()
3442 {
3443 this->OnPlan(BOOTSTRAPPER_ACTION_UNINSTALL);
3444 }
3445
3446
3447 //
3448 // OnClickCloseButton - close the application.
3449 //
3450 void OnClickCloseButton()
3451 {
3452 ::SendMessageW(m_hWnd, WM_CLOSE, 0, 0);
3453 }
3454
3455
3456 //
3457 // OnClickEulaLink - show the end user license agreement.
3458 //
3459 void OnClickEulaLink()
3460 {
3461 HRESULT hr = S_OK;
3462 LPWSTR sczLicenseUrl = NULL;
3463 LPWSTR sczLicensePath = NULL;
3464 LPWSTR sczLicenseDirectory = NULL;
3465 LPWSTR sczLicenseFilename = NULL;
3466 URI_PROTOCOL protocol = URI_PROTOCOL_UNKNOWN;
3467
3468 hr = StrAllocString(&sczLicenseUrl, m_sczLicenseUrl, 0);
3469 BalExitOnFailure(hr, "Failed to copy license URL: %ls", m_sczLicenseUrl);
3470
3471 hr = LocLocalizeString(m_pWixLoc, &sczLicenseUrl);
3472 BalExitOnFailure(hr, "Failed to localize license URL: %ls", m_sczLicenseUrl);
3473
3474 // Assume there is no hidden variables to be formatted
3475 // so don't worry about securely freeing it.
3476 hr = BalFormatString(sczLicenseUrl, &sczLicenseUrl);
3477 BalExitOnFailure(hr, "Failed to get formatted license URL: %ls", m_sczLicenseUrl);
3478
3479 hr = UriProtocol(sczLicenseUrl, &protocol);
3480 if (FAILED(hr) || URI_PROTOCOL_UNKNOWN == protocol)
3481 {
3482 // Probe for localized license file
3483 hr = PathRelativeToModule(&sczLicensePath, sczLicenseUrl, m_hModule);
3484 if (SUCCEEDED(hr))
3485 {
3486 hr = PathGetDirectory(sczLicensePath, &sczLicenseDirectory);
3487 if (SUCCEEDED(hr))
3488 {
3489 hr = LocProbeForFile(sczLicenseDirectory, PathFile(sczLicenseUrl), m_sczLanguage, &sczLicensePath);
3490 }
3491 }
3492 }
3493
3494 hr = ShelExecUnelevated(sczLicensePath ? sczLicensePath : sczLicenseUrl, NULL, L"open", NULL, SW_SHOWDEFAULT);
3495 BalExitOnFailure(hr, "Failed to launch URL to EULA.");
3496
3497 LExit:
3498 ReleaseStr(sczLicensePath);
3499 ReleaseStr(sczLicenseUrl);
3500 ReleaseStr(sczLicenseDirectory);
3501 ReleaseStr(sczLicenseFilename);
3502
3503 return;
3504 }
3505
3506
3507 //
3508 // OnClickLaunchButton - launch the app from the success page.
3509 //
3510 void OnClickLaunchButton()
3511 {
3512 HRESULT hr = S_OK;
3513 LPWSTR sczUnformattedLaunchTarget = NULL;
3514 LPWSTR sczLaunchTarget = NULL;
3515 LPWSTR sczLaunchTargetElevatedId = NULL;
3516 LPWSTR sczUnformattedArguments = NULL;
3517 LPWSTR sczArguments = NULL;
3518 LPWSTR sczUnformattedLaunchFolder = NULL;
3519 LPWSTR sczLaunchFolder = NULL;
3520 int nCmdShow = SW_SHOWNORMAL;
3521
3522 hr = BalGetStringVariable(WIXSTDBA_VARIABLE_LAUNCH_TARGET_PATH, &sczUnformattedLaunchTarget);
3523 BalExitOnFailure(hr, "Failed to get launch target variable '%ls'.", WIXSTDBA_VARIABLE_LAUNCH_TARGET_PATH);
3524
3525 hr = BalFormatString(sczUnformattedLaunchTarget, &sczLaunchTarget);
3526 BalExitOnFailure(hr, "Failed to format launch target variable: %ls", sczUnformattedLaunchTarget);
3527
3528 if (BalVariableExists(WIXSTDBA_VARIABLE_LAUNCH_TARGET_ELEVATED_ID))
3529 {
3530 hr = BalGetStringVariable(WIXSTDBA_VARIABLE_LAUNCH_TARGET_ELEVATED_ID, &sczLaunchTargetElevatedId);
3531 BalExitOnFailure(hr, "Failed to get launch target elevated id '%ls'.", WIXSTDBA_VARIABLE_LAUNCH_TARGET_ELEVATED_ID);
3532 }
3533
3534 if (BalVariableExists(WIXSTDBA_VARIABLE_LAUNCH_ARGUMENTS))
3535 {
3536 hr = BalGetStringVariable(WIXSTDBA_VARIABLE_LAUNCH_ARGUMENTS, &sczUnformattedArguments);
3537 BalExitOnFailure(hr, "Failed to get launch arguments '%ls'.", WIXSTDBA_VARIABLE_LAUNCH_ARGUMENTS);
3538 }
3539
3540 if (BalVariableExists(WIXSTDBA_VARIABLE_LAUNCH_HIDDEN))
3541 {
3542 nCmdShow = SW_HIDE;
3543 }
3544
3545 if (BalVariableExists(WIXSTDBA_VARIABLE_LAUNCH_WORK_FOLDER))
3546 {
3547 hr = BalGetStringVariable(WIXSTDBA_VARIABLE_LAUNCH_WORK_FOLDER, &sczUnformattedLaunchFolder);
3548 BalExitOnFailure(hr, "Failed to get launch working directory variable '%ls'.", WIXSTDBA_VARIABLE_LAUNCH_WORK_FOLDER);
3549 }
3550
3551 if (sczLaunchTargetElevatedId && !m_fTriedToLaunchElevated)
3552 {
3553 m_fTriedToLaunchElevated = TRUE;
3554 hr = m_pEngine->LaunchApprovedExe(m_hWnd, sczLaunchTargetElevatedId, sczUnformattedArguments, 0);
3555 if (FAILED(hr))
3556 {
3557 BalLogError(hr, "Failed to launch elevated target: %ls", sczLaunchTargetElevatedId);
3558
3559 //try with ShelExec next time
3560 OnClickLaunchButton();
3561 }
3562 }
3563 else
3564 {
3565 if (sczUnformattedArguments)
3566 {
3567 hr = BalFormatString(sczUnformattedArguments, &sczArguments);
3568 BalExitOnFailure(hr, "Failed to format launch arguments variable: %ls", sczUnformattedArguments);
3569 }
3570
3571 if (sczUnformattedLaunchFolder)
3572 {
3573 hr = BalFormatString(sczUnformattedLaunchFolder, &sczLaunchFolder);
3574 BalExitOnFailure(hr, "Failed to format launch working directory variable: %ls", sczUnformattedLaunchFolder);
3575 }
3576
3577 hr = ShelExec(sczLaunchTarget, sczArguments, L"open", sczLaunchFolder, nCmdShow, m_hWnd, NULL);
3578 BalExitOnFailure(hr, "Failed to launch target: %ls", sczLaunchTarget);
3579
3580 ::PostMessageW(m_hWnd, WM_CLOSE, 0, 0);
3581 }
3582
3583 LExit:
3584 StrSecureZeroFreeString(sczLaunchFolder);
3585 ReleaseStr(sczUnformattedLaunchFolder);
3586 StrSecureZeroFreeString(sczArguments);
3587 ReleaseStr(sczUnformattedArguments);
3588 ReleaseStr(sczLaunchTargetElevatedId);
3589 StrSecureZeroFreeString(sczLaunchTarget);
3590 ReleaseStr(sczUnformattedLaunchTarget);
3591
3592 return;
3593 }
3594
3595
3596 //
3597 // OnClickRestartButton - allows the restart and closes the app.
3598 //
3599 void OnClickRestartButton()
3600 {
3601 AssertSz(m_fRestartRequired, "Restart must be requested to be able to click on the restart button.");
3602
3603 m_fAllowRestart = TRUE;
3604 ::SendMessageW(m_hWnd, WM_CLOSE, 0, 0);
3605
3606 return;
3607 }
3608
3609
3610 //
3611 // OnClickLogFileLink - show the log file.
3612 //
3613 void OnClickLogFileLink()
3614 {
3615 HRESULT hr = S_OK;
3616 LPWSTR sczLogFile = NULL;
3617
3618 hr = BalGetStringVariable(m_Bundle.sczLogVariable, &sczLogFile);
3619 BalExitOnFailure(hr, "Failed to get log file variable '%ls'.", m_Bundle.sczLogVariable);
3620
3621 hr = ShelExecUnelevated(L"notepad.exe", sczLogFile, L"open", NULL, SW_SHOWDEFAULT);
3622 BalExitOnFailure(hr, "Failed to open log file target: %ls", sczLogFile);
3623
3624 LExit:
3625 ReleaseStr(sczLogFile);
3626
3627 return;
3628 }
3629
3630
3631 //
3632 // SetState
3633 //
3634 void SetState(
3635 __in WIXSTDBA_STATE state,
3636 __in HRESULT hrStatus
3637 )
3638 {
3639 if (FAILED(hrStatus))
3640 {
3641 m_hrFinal = hrStatus;
3642 }
3643
3644 if (FAILED(m_hrFinal))
3645 {
3646 state = WIXSTDBA_STATE_FAILED;
3647 }
3648
3649 if (m_state < state)
3650 {
3651 ::PostMessageW(m_hWnd, WM_WIXSTDBA_CHANGE_STATE, 0, state);
3652 }
3653 }
3654
3655
3656 void DeterminePageId(
3657 __in WIXSTDBA_STATE state,
3658 __out DWORD* pdwPageId
3659 )
3660 {
3661 if (BOOTSTRAPPER_DISPLAY_PASSIVE == m_command.display)
3662 {
3663 switch (state)
3664 {
3665 case WIXSTDBA_STATE_INITIALIZED:
3666 *pdwPageId = BOOTSTRAPPER_ACTION_HELP == m_command.action ? m_rgdwPageIds[WIXSTDBA_PAGE_HELP] : m_rgdwPageIds[WIXSTDBA_PAGE_LOADING];
3667 break;
3668
3669 case WIXSTDBA_STATE_HELP:
3670 *pdwPageId = m_rgdwPageIds[WIXSTDBA_PAGE_HELP];
3671 break;
3672
3673 case WIXSTDBA_STATE_DETECTING:
3674 *pdwPageId = m_rgdwPageIds[WIXSTDBA_PAGE_LOADING] ? m_rgdwPageIds[WIXSTDBA_PAGE_LOADING] : m_rgdwPageIds[WIXSTDBA_PAGE_PROGRESS_PASSIVE] ? m_rgdwPageIds[WIXSTDBA_PAGE_PROGRESS_PASSIVE] : m_rgdwPageIds[WIXSTDBA_PAGE_PROGRESS];
3675 break;
3676
3677 case WIXSTDBA_STATE_DETECTED: __fallthrough;
3678 case WIXSTDBA_STATE_PLANNING: __fallthrough;
3679 case WIXSTDBA_STATE_PLANNED: __fallthrough;
3680 case WIXSTDBA_STATE_APPLYING: __fallthrough;
3681 case WIXSTDBA_STATE_CACHING: __fallthrough;
3682 case WIXSTDBA_STATE_CACHED: __fallthrough;
3683 case WIXSTDBA_STATE_EXECUTING: __fallthrough;
3684 case WIXSTDBA_STATE_EXECUTED:
3685 *pdwPageId = m_rgdwPageIds[WIXSTDBA_PAGE_PROGRESS_PASSIVE] ? m_rgdwPageIds[WIXSTDBA_PAGE_PROGRESS_PASSIVE] : m_rgdwPageIds[WIXSTDBA_PAGE_PROGRESS];
3686 break;
3687
3688 default:
3689 *pdwPageId = 0;
3690 break;
3691 }
3692 }
3693 else if (BOOTSTRAPPER_DISPLAY_FULL == m_command.display)
3694 {
3695 switch (state)
3696 {
3697 case WIXSTDBA_STATE_INITIALIZING:
3698 *pdwPageId = 0;
3699 break;
3700
3701 case WIXSTDBA_STATE_INITIALIZED:
3702 *pdwPageId = BOOTSTRAPPER_ACTION_HELP == m_command.action ? m_rgdwPageIds[WIXSTDBA_PAGE_HELP] : m_rgdwPageIds[WIXSTDBA_PAGE_LOADING];
3703 break;
3704
3705 case WIXSTDBA_STATE_HELP:
3706 *pdwPageId = m_rgdwPageIds[WIXSTDBA_PAGE_HELP];
3707 break;
3708
3709 case WIXSTDBA_STATE_DETECTING:
3710 *pdwPageId = m_rgdwPageIds[WIXSTDBA_PAGE_LOADING];
3711 break;
3712
3713 case WIXSTDBA_STATE_DETECTED:
3714 switch (m_command.action)
3715 {
3716 case BOOTSTRAPPER_ACTION_INSTALL:
3717 *pdwPageId = m_rgdwPageIds[WIXSTDBA_PAGE_INSTALL];
3718 break;
3719
3720 case BOOTSTRAPPER_ACTION_MODIFY: __fallthrough;
3721 case BOOTSTRAPPER_ACTION_REPAIR: __fallthrough;
3722 case BOOTSTRAPPER_ACTION_UNINSTALL:
3723 *pdwPageId = m_rgdwPageIds[WIXSTDBA_PAGE_MODIFY];
3724 break;
3725 }
3726 break;
3727
3728 case WIXSTDBA_STATE_PLANNING: __fallthrough;
3729 case WIXSTDBA_STATE_PLANNED: __fallthrough;
3730 case WIXSTDBA_STATE_APPLYING: __fallthrough;
3731 case WIXSTDBA_STATE_CACHING: __fallthrough;
3732 case WIXSTDBA_STATE_CACHED: __fallthrough;
3733 case WIXSTDBA_STATE_EXECUTING: __fallthrough;
3734 case WIXSTDBA_STATE_EXECUTED:
3735 *pdwPageId = m_rgdwPageIds[WIXSTDBA_PAGE_PROGRESS];
3736 break;
3737
3738 case WIXSTDBA_STATE_APPLIED:
3739 *pdwPageId = m_rgdwPageIds[WIXSTDBA_PAGE_SUCCESS];
3740 break;
3741
3742 case WIXSTDBA_STATE_FAILED:
3743 *pdwPageId = m_rgdwPageIds[WIXSTDBA_PAGE_FAILURE];
3744 break;
3745 }
3746 }
3747 }
3748
3749
3750 HRESULT EvaluateConditions()
3751 {
3752 HRESULT hr = S_OK;
3753 BOOL fResult = FALSE;
3754
3755 for (DWORD i = 0; i < m_Conditions.cConditions; ++i)
3756 {
3757 BAL_CONDITION* pCondition = m_Conditions.rgConditions + i;
3758
3759 hr = BalConditionEvaluate(pCondition, m_pEngine, &fResult, &m_sczFailedMessage);
3760 BalExitOnFailure(hr, "Failed to evaluate condition.");
3761
3762 if (!fResult)
3763 {
3764 hr = E_WIXSTDBA_CONDITION_FAILED;
3765 BalExitOnFailure(hr, "%ls", m_sczFailedMessage);
3766 }
3767 }
3768
3769 ReleaseNullStrSecure(m_sczFailedMessage);
3770
3771 LExit:
3772 return hr;
3773 }
3774
3775 void UpdateCacheProgress(
3776 __in DWORD dwOverallPercentage
3777 )
3778 {
3779 WCHAR wzProgress[5] = { };
3780
3781 ::StringCchPrintfW(wzProgress, countof(wzProgress), L"%u%%", dwOverallPercentage);
3782 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_CACHE_PROGRESS_TEXT, wzProgress);
3783
3784 ThemeSetProgressControl(m_pTheme, WIXSTDBA_CONTROL_CACHE_PROGRESS_BAR, dwOverallPercentage);
3785
3786 m_dwCalculatedCacheProgress = dwOverallPercentage * WIXSTDBA_ACQUIRE_PERCENTAGE / 100;
3787 ThemeSetProgressControl(m_pTheme, WIXSTDBA_CONTROL_OVERALL_CALCULATED_PROGRESS_BAR, m_dwCalculatedCacheProgress + m_dwCalculatedExecuteProgress);
3788
3789 SetTaskbarButtonProgress(m_dwCalculatedCacheProgress + m_dwCalculatedExecuteProgress);
3790 }
3791
3792
3793 void SetTaskbarButtonProgress(
3794 __in DWORD dwOverallPercentage
3795 )
3796 {
3797 HRESULT hr = S_OK;
3798
3799 if (m_fTaskbarButtonOK)
3800 {
3801 hr = m_pTaskbarList->SetProgressValue(m_hWnd, dwOverallPercentage, 100UL);
3802 BalExitOnFailure(hr, "Failed to set taskbar button progress to: %d%%.", dwOverallPercentage);
3803 }
3804
3805 LExit:
3806 return;
3807 }
3808
3809
3810 void SetTaskbarButtonState(
3811 __in TBPFLAG tbpFlags
3812 )
3813 {
3814 HRESULT hr = S_OK;
3815
3816 if (m_fTaskbarButtonOK)
3817 {
3818 hr = m_pTaskbarList->SetProgressState(m_hWnd, tbpFlags);
3819 BalExitOnFailure(hr, "Failed to set taskbar button state.", tbpFlags);
3820 }
3821
3822 LExit:
3823 return;
3824 }
3825
3826
3827 void SetProgressState(
3828 __in HRESULT hrStatus
3829 )
3830 {
3831 TBPFLAG flag = TBPF_NORMAL;
3832
3833 if (IsCanceled() || HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT) == hrStatus)
3834 {
3835 flag = TBPF_PAUSED;
3836 }
3837 else if (IsRollingBack() || FAILED(hrStatus))
3838 {
3839 flag = TBPF_ERROR;
3840 }
3841
3842 SetTaskbarButtonState(flag);
3843 }
3844
3845
3846 HRESULT LoadBAFunctions(
3847 __in IXMLDOMDocument* pixdManifest
3848 )
3849 {
3850 HRESULT hr = S_OK;
3851 IXMLDOMNode* pBAFunctionsNode = NULL;
3852 IXMLDOMNode* pPayloadNode = NULL;
3853 LPWSTR sczPayloadId = NULL;
3854 LPWSTR sczPayloadXPath = NULL;
3855 LPWSTR sczBafName = NULL;
3856 LPWSTR sczBafPath = NULL;
3857 BA_FUNCTIONS_CREATE_ARGS bafCreateArgs = { };
3858 BA_FUNCTIONS_CREATE_RESULTS bafCreateResults = { };
3859
3860 hr = XmlSelectSingleNode(pixdManifest, L"/BootstrapperApplicationData/WixBalBAFunctions", &pBAFunctionsNode);
3861 BalExitOnFailure(hr, "Failed to read WixBalBAFunctions node from BootstrapperApplicationData.xml.");
3862
3863 if (S_FALSE == hr)
3864 {
3865 ExitFunction();
3866 }
3867
3868 hr = XmlGetAttributeEx(pBAFunctionsNode, L"PayloadId", &sczPayloadId);
3869 BalExitOnFailure(hr, "Failed to get BAFunctions PayloadId.");
3870
3871 hr = StrAllocFormatted(&sczPayloadXPath, L"/BootstrapperApplicationData/WixPayloadProperties[@Payload='%ls']", sczPayloadId);
3872 BalExitOnFailure(hr, "Failed to format BAFunctions payload XPath.");
3873
3874 hr = XmlSelectSingleNode(pixdManifest, sczPayloadXPath, &pPayloadNode);
3875 if (S_FALSE == hr)
3876 {
3877 hr = E_NOTFOUND;
3878 }
3879 BalExitOnFailure(hr, "Failed to find WixPayloadProperties node for BAFunctions PayloadId: %ls.", sczPayloadId);
3880
3881 hr = XmlGetAttributeEx(pPayloadNode, L"Name", &sczBafName);
3882 BalExitOnFailure(hr, "Failed to get BAFunctions Name.");
3883
3884 hr = PathRelativeToModule(&sczBafPath, sczBafName, m_hModule);
3885 BalExitOnFailure(hr, "Failed to get path to BAFunctions DLL.");
3886
3887 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "WIXSTDBA: LoadBAFunctions() - BAFunctions DLL %ls", sczBafPath);
3888
3889 m_hBAFModule = ::LoadLibraryExW(sczBafPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
3890 BalExitOnNullWithLastError(m_hBAFModule, hr, "WIXSTDBA: LoadBAFunctions() - Failed to load DLL %ls", sczBafPath);
3891
3892 PFN_BA_FUNCTIONS_CREATE pfnBAFunctionsCreate = reinterpret_cast<PFN_BA_FUNCTIONS_CREATE>(::GetProcAddress(m_hBAFModule, "BAFunctionsCreate"));
3893 BalExitOnNullWithLastError(pfnBAFunctionsCreate, hr, "Failed to get BAFunctionsCreate entry-point from: %ls", sczBafPath);
3894
3895 bafCreateArgs.cbSize = sizeof(bafCreateArgs);
3896 bafCreateArgs.qwBAFunctionsAPIVersion = MAKEQWORDVERSION(0, 0, 0, 2); // TODO: need to decide whether to keep this, and if so when to update it.
3897 bafCreateArgs.pBootstrapperCreateArgs = &m_createArgs;
3898
3899 bafCreateResults.cbSize = sizeof(bafCreateResults);
3900
3901 hr = pfnBAFunctionsCreate(&bafCreateArgs, &bafCreateResults);
3902 BalExitOnFailure(hr, "Failed to create BAFunctions.");
3903
3904 m_pfnBAFunctionsProc = bafCreateResults.pfnBAFunctionsProc;
3905 m_pvBAFunctionsProcContext = bafCreateResults.pvBAFunctionsProcContext;
3906
3907 LExit:
3908 if (m_hBAFModule && !m_pfnBAFunctionsProc)
3909 {
3910 ::FreeLibrary(m_hBAFModule);
3911 m_hBAFModule = NULL;
3912 }
3913 ReleaseStr(sczBafPath);
3914 ReleaseStr(sczBafName);
3915 ReleaseStr(sczPayloadXPath);
3916 ReleaseStr(sczPayloadId);
3917 ReleaseObject(pBAFunctionsNode);
3918 ReleaseObject(pPayloadNode);
3919
3920 return hr;
3921 }
3922
3923
3924public:
3925 //
3926 // Constructor - initialize member variables.
3927 //
3928 CWixStandardBootstrapperApplication(
3929 __in HMODULE hModule,
3930 __in BOOL fPrereq,
3931 __in HRESULT hrHostInitialization,
3932 __in IBootstrapperEngine* pEngine,
3933 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs
3934 ) : CBalBaseBootstrapperApplication(pEngine, pArgs, 3, 3000)
3935 {
3936 m_hModule = hModule;
3937 memcpy_s(&m_command, sizeof(m_command), pArgs->pCommand, sizeof(BOOTSTRAPPER_COMMAND));
3938 memcpy_s(&m_createArgs, sizeof(m_createArgs), pArgs, sizeof(BOOTSTRAPPER_CREATE_ARGS));
3939 m_createArgs.pCommand = &m_command;
3940
3941 if (fPrereq)
3942 {
3943 // Pre-req BA should only show help or do an install (to launch the Managed BA which can then do the right action).
3944 if (BOOTSTRAPPER_ACTION_HELP != m_command.action)
3945 {
3946 m_command.action = BOOTSTRAPPER_ACTION_INSTALL;
3947 }
3948 }
3949 else // maybe modify the action state if the bundle is or is not already installed.
3950 {
3951 LONGLONG llInstalled = 0;
3952 HRESULT hr = BalGetNumericVariable(L"WixBundleInstalled", &llInstalled);
3953 if (SUCCEEDED(hr) && BOOTSTRAPPER_RESUME_TYPE_REBOOT != m_command.resumeType && 0 < llInstalled && BOOTSTRAPPER_ACTION_INSTALL == m_command.action)
3954 {
3955 m_command.action = BOOTSTRAPPER_ACTION_MODIFY;
3956 }
3957 else if (0 == llInstalled && (BOOTSTRAPPER_ACTION_MODIFY == m_command.action || BOOTSTRAPPER_ACTION_REPAIR == m_command.action))
3958 {
3959 m_command.action = BOOTSTRAPPER_ACTION_INSTALL;
3960 }
3961 }
3962
3963 m_plannedAction = BOOTSTRAPPER_ACTION_UNKNOWN;
3964
3965 // When resuming from restart doing some install-like operation, try to find the package that forced the
3966 // restart. We'll use this information during planning.
3967 m_sczAfterForcedRestartPackage = NULL;
3968
3969 if (BOOTSTRAPPER_RESUME_TYPE_REBOOT == m_command.resumeType && BOOTSTRAPPER_ACTION_UNINSTALL < m_command.action)
3970 {
3971 // Ensure the forced restart package variable is null when it is an empty string.
3972 HRESULT hr = BalGetStringVariable(L"WixBundleForcedRestartPackage", &m_sczAfterForcedRestartPackage);
3973 if (FAILED(hr) || !m_sczAfterForcedRestartPackage || !*m_sczAfterForcedRestartPackage)
3974 {
3975 ReleaseNullStr(m_sczAfterForcedRestartPackage);
3976 }
3977 }
3978
3979 m_pWixLoc = NULL;
3980 memset(&m_Bundle, 0, sizeof(m_Bundle));
3981 memset(&m_Conditions, 0, sizeof(m_Conditions));
3982 m_sczConfirmCloseMessage = NULL;
3983 m_sczFailedMessage = NULL;
3984
3985 m_sczLanguage = NULL;
3986 m_pTheme = NULL;
3987 memset(m_rgdwPageIds, 0, sizeof(m_rgdwPageIds));
3988 m_hUiThread = NULL;
3989 m_fRegistered = FALSE;
3990 m_hWnd = NULL;
3991
3992 m_state = WIXSTDBA_STATE_INITIALIZING;
3993 m_hrFinal = hrHostInitialization;
3994
3995 m_fDowngrading = FALSE;
3996 m_restartResult = BOOTSTRAPPER_APPLY_RESTART_NONE;
3997 m_fRestartRequired = FALSE;
3998 m_fAllowRestart = FALSE;
3999
4000 m_sczLicenseFile = NULL;
4001 m_sczLicenseUrl = NULL;
4002 m_fSuppressDowngradeFailure = FALSE;
4003 m_fSuppressRepair = FALSE;
4004 m_fSupportCacheOnly = FALSE;
4005
4006 m_sdOverridableVariables = NULL;
4007 m_pTaskbarList = NULL;
4008 m_uTaskbarButtonCreatedMessage = UINT_MAX;
4009 m_fTaskbarButtonOK = FALSE;
4010 ::InitializeCriticalSection(&m_csShowingInternalUiThisPackage);
4011 m_fShowingInternalUiThisPackage = FALSE;
4012 m_fTriedToLaunchElevated = FALSE;
4013
4014 m_fPrereq = fPrereq;
4015 m_fPrereqInstalled = FALSE;
4016 m_fPrereqAlreadyInstalled = FALSE;
4017
4018 pEngine->AddRef();
4019 m_pEngine = pEngine;
4020
4021 m_hBAFModule = NULL;
4022 m_pfnBAFunctionsProc = NULL;
4023 m_pvBAFunctionsProcContext = NULL;
4024 }
4025
4026
4027 //
4028 // Destructor - release member variables.
4029 //
4030 ~CWixStandardBootstrapperApplication()
4031 {
4032 AssertSz(!::IsWindow(m_hWnd), "Window should have been destroyed before destructor.");
4033 AssertSz(!m_pTaskbarList, "Taskbar should have been released before destructor.");
4034 AssertSz(!m_pTheme, "Theme should have been released before destructor.");
4035
4036 for (DWORD i = 0; i < m_Bundle.packages.cPackages; ++i)
4037 {
4038 ReleaseMem(m_Bundle.packages.rgPackages[i].pvCustomData);
4039 }
4040
4041 ::DeleteCriticalSection(&m_csShowingInternalUiThisPackage);
4042 ReleaseDict(m_sdOverridableVariables);
4043 ReleaseStr(m_sczFailedMessage);
4044 ReleaseStr(m_sczConfirmCloseMessage);
4045 BalConditionsUninitialize(&m_Conditions);
4046 BalInfoUninitialize(&m_Bundle);
4047 LocFree(m_pWixLoc);
4048
4049 ReleaseStr(m_sczLanguage);
4050 ReleaseStr(m_sczLicenseFile);
4051 ReleaseStr(m_sczLicenseUrl);
4052 ReleaseStr(m_sczAfterForcedRestartPackage);
4053 ReleaseNullObject(m_pEngine);
4054
4055 if (m_hBAFModule)
4056 {
4057 PFN_BA_FUNCTIONS_DESTROY pfnBAFunctionsDestroy = reinterpret_cast<PFN_BA_FUNCTIONS_DESTROY>(::GetProcAddress(m_hBAFModule, "BAFunctionsDestroy"));
4058 if (pfnBAFunctionsDestroy)
4059 {
4060 pfnBAFunctionsDestroy();
4061 }
4062
4063 ::FreeLibrary(m_hBAFModule);
4064 m_hBAFModule = NULL;
4065 }
4066 }
4067
4068private:
4069 HMODULE m_hModule;
4070 BOOTSTRAPPER_CREATE_ARGS m_createArgs;
4071 BOOTSTRAPPER_COMMAND m_command;
4072 IBootstrapperEngine* m_pEngine;
4073 BOOTSTRAPPER_ACTION m_plannedAction;
4074
4075 LPWSTR m_sczAfterForcedRestartPackage;
4076
4077 WIX_LOCALIZATION* m_pWixLoc;
4078 BAL_INFO_BUNDLE m_Bundle;
4079 BAL_CONDITIONS m_Conditions;
4080 LPWSTR m_sczFailedMessage;
4081 LPWSTR m_sczConfirmCloseMessage;
4082
4083 LPWSTR m_sczLanguage;
4084 THEME* m_pTheme;
4085 DWORD m_rgdwPageIds[countof(vrgwzPageNames)];
4086 HANDLE m_hUiThread;
4087 BOOL m_fRegistered;
4088 HWND m_hWnd;
4089
4090 WIXSTDBA_STATE m_state;
4091 HRESULT m_hrFinal;
4092
4093 BOOL m_fStartedExecution;
4094 DWORD m_dwCalculatedCacheProgress;
4095 DWORD m_dwCalculatedExecuteProgress;
4096
4097 BOOL m_fDowngrading;
4098 BOOTSTRAPPER_APPLY_RESTART m_restartResult;
4099 BOOL m_fRestartRequired;
4100 BOOL m_fAllowRestart;
4101
4102 LPWSTR m_sczLicenseFile;
4103 LPWSTR m_sczLicenseUrl;
4104 BOOL m_fSuppressDowngradeFailure;
4105 BOOL m_fSuppressRepair;
4106 BOOL m_fSupportCacheOnly;
4107
4108 STRINGDICT_HANDLE m_sdOverridableVariables;
4109
4110 BOOL m_fPrereq;
4111 BOOL m_fPrereqInstalled;
4112 BOOL m_fPrereqAlreadyInstalled;
4113
4114 ITaskbarList3* m_pTaskbarList;
4115 UINT m_uTaskbarButtonCreatedMessage;
4116 BOOL m_fTaskbarButtonOK;
4117 CRITICAL_SECTION m_csShowingInternalUiThisPackage;
4118 BOOL m_fShowingInternalUiThisPackage;
4119 BOOL m_fTriedToLaunchElevated;
4120
4121 HMODULE m_hBAFModule;
4122 PFN_BA_FUNCTIONS_PROC m_pfnBAFunctionsProc;
4123 LPVOID m_pvBAFunctionsProcContext;
4124};
4125
4126
4127//
4128// CreateBootstrapperApplication - creates a new IBootstrapperApplication object.
4129//
4130HRESULT CreateBootstrapperApplication(
4131 __in HMODULE hModule,
4132 __in BOOL fPrereq,
4133 __in HRESULT hrHostInitialization,
4134 __in IBootstrapperEngine* pEngine,
4135 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
4136 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults,
4137 __out IBootstrapperApplication** ppApplication
4138 )
4139{
4140 HRESULT hr = S_OK;
4141 CWixStandardBootstrapperApplication* pApplication = NULL;
4142
4143 if (BOOTSTRAPPER_DISPLAY_UNKNOWN == pArgs->pCommand->display)
4144 {
4145 BalExitOnFailure(hr = E_INVALIDARG, "Engine requested Unknown display type.");
4146 }
4147
4148 pApplication = new CWixStandardBootstrapperApplication(hModule, fPrereq, hrHostInitialization, pEngine, pArgs);
4149 ExitOnNull(pApplication, hr, E_OUTOFMEMORY, "Failed to create new standard bootstrapper application object.");
4150
4151 pResults->pfnBootstrapperApplicationProc = BalBaseBootstrapperApplicationProc;
4152 pResults->pvBootstrapperApplicationProcContext = pApplication;
4153 *ppApplication = pApplication;
4154 pApplication = NULL;
4155
4156LExit:
4157 ReleaseObject(pApplication);
4158 return hr;
4159}
4160
4161
4162static HRESULT DAPI EvaluateVariableConditionCallback(
4163 __in_z LPCWSTR wzCondition,
4164 __out BOOL* pf,
4165 __in_opt LPVOID /*pvContext*/
4166 )
4167{
4168 return BalEvaluateCondition(wzCondition, pf);
4169}
4170
4171
4172static HRESULT DAPI FormatVariableStringCallback(
4173 __in_z LPCWSTR wzFormat,
4174 __inout LPWSTR* psczOut,
4175 __in_opt LPVOID /*pvContext*/
4176 )
4177{
4178 return BalFormatString(wzFormat, psczOut);
4179}
4180
4181
4182static HRESULT DAPI GetVariableNumericCallback(
4183 __in_z LPCWSTR wzVariable,
4184 __out LONGLONG* pllValue,
4185 __in_opt LPVOID /*pvContext*/
4186 )
4187{
4188 return BalGetNumericVariable(wzVariable, pllValue);
4189}
4190
4191
4192static HRESULT DAPI SetVariableNumericCallback(
4193 __in_z LPCWSTR wzVariable,
4194 __in LONGLONG llValue,
4195 __in_opt LPVOID /*pvContext*/
4196 )
4197{
4198 return BalSetNumericVariable(wzVariable, llValue);
4199}
4200
4201
4202static HRESULT DAPI GetVariableStringCallback(
4203 __in_z LPCWSTR wzVariable,
4204 __inout LPWSTR* psczValue,
4205 __in_opt LPVOID /*pvContext*/
4206 )
4207{
4208 return BalGetStringVariable(wzVariable, psczValue);
4209}
4210
4211
4212static HRESULT DAPI SetVariableStringCallback(
4213 __in_z LPCWSTR wzVariable,
4214 __in_z_opt LPCWSTR wzValue,
4215 __in BOOL fFormatted,
4216 __in_opt LPVOID /*pvContext*/
4217 )
4218{
4219 return BalSetStringVariable(wzVariable, wzValue, fFormatted);
4220}
4221
4222static LPCSTR LoggingRequestStateToString(
4223 __in BOOTSTRAPPER_REQUEST_STATE requestState
4224 )
4225{
4226 switch (requestState)
4227 {
4228 case BOOTSTRAPPER_REQUEST_STATE_NONE:
4229 return "None";
4230 case BOOTSTRAPPER_REQUEST_STATE_FORCE_ABSENT:
4231 return "ForceAbsent";
4232 case BOOTSTRAPPER_REQUEST_STATE_ABSENT:
4233 return "Absent";
4234 case BOOTSTRAPPER_REQUEST_STATE_CACHE:
4235 return "Cache";
4236 case BOOTSTRAPPER_REQUEST_STATE_PRESENT:
4237 return "Present";
4238 case BOOTSTRAPPER_REQUEST_STATE_REPAIR:
4239 return "Repair";
4240 default:
4241 return "Invalid";
4242 }
4243}
4244
4245static LPCSTR LoggingMsiFeatureStateToString(
4246 __in BOOTSTRAPPER_FEATURE_STATE featureState
4247 )
4248{
4249 switch (featureState)
4250 {
4251 case BOOTSTRAPPER_FEATURE_STATE_UNKNOWN:
4252 return "Unknown";
4253 case BOOTSTRAPPER_FEATURE_STATE_ABSENT:
4254 return "Absent";
4255 case BOOTSTRAPPER_FEATURE_STATE_ADVERTISED:
4256 return "Advertised";
4257 case BOOTSTRAPPER_FEATURE_STATE_LOCAL:
4258 return "Local";
4259 case BOOTSTRAPPER_FEATURE_STATE_SOURCE:
4260 return "Source";
4261 default:
4262 return "Invalid";
4263 }
4264}
diff --git a/src/ext/Bal/wixstdba/packages.config b/src/ext/Bal/wixstdba/packages.config
new file mode 100644
index 00000000..071284ac
--- /dev/null
+++ b/src/ext/Bal/wixstdba/packages.config
@@ -0,0 +1,10 @@
1<?xml version="1.0" encoding="utf-8"?>
2<packages>
3 <package id="Microsoft.Build.Tasks.Git" 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" />
6 <package id="Nerdbank.GitVersioning" version="3.3.37" targetFramework="native" developmentDependency="true" />
7 <package id="WixToolset.BalUtil" version="4.0.58" targetFramework="native" />
8 <package id="WixToolset.BootstrapperCore.Native" version="4.0.141" targetFramework="native" />
9 <package id="WixToolset.DUtil" version="4.0.72" targetFramework="native" />
10</packages> \ No newline at end of file
diff --git a/src/ext/Bal/wixstdba/precomp.cpp b/src/ext/Bal/wixstdba/precomp.cpp
new file mode 100644
index 00000000..37664a1c
--- /dev/null
+++ b/src/ext/Bal/wixstdba/precomp.cpp
@@ -0,0 +1,3 @@
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"
diff --git a/src/ext/Bal/wixstdba/precomp.h b/src/ext/Bal/wixstdba/precomp.h
new file mode 100644
index 00000000..547183bd
--- /dev/null
+++ b/src/ext/Bal/wixstdba/precomp.h
@@ -0,0 +1,58 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5#include <windows.h>
6
7#pragma warning(push)
8#pragma warning(disable:4458) // declaration of 'xxx' hides class member
9#include <gdiplus.h>
10#pragma warning(pop)
11
12#include <msiquery.h>
13#include <objbase.h>
14#include <shlobj.h>
15#include <shlwapi.h>
16#include <stdlib.h>
17#include <strsafe.h>
18#include <stddef.h>
19
20#include "dutil.h"
21#include "apputil.h"
22#include "memutil.h"
23#include "dictutil.h"
24#include "dirutil.h"
25#include "fileutil.h"
26#include "locutil.h"
27#include "logutil.h"
28#include "pathutil.h"
29#include "resrutil.h"
30#include "shelutil.h"
31#include "strutil.h"
32#include "thmutil.h"
33#include "verutil.h"
34#include "uriutil.h"
35#include "xmlutil.h"
36
37#include "BootstrapperEngine.h"
38#include "BootstrapperApplication.h"
39#include "IBootstrapperEngine.h"
40#include "IBootstrapperApplication.h"
41
42#include "balutil.h"
43#include "balinfo.h"
44#include "balcondition.h"
45
46#include "BAFunctions.h"
47
48#include "wixstdba.messages.h"
49
50HRESULT CreateBootstrapperApplication(
51 __in HMODULE hModule,
52 __in BOOL fPrereq,
53 __in HRESULT hrHostInitialization,
54 __in IBootstrapperEngine* pEngine,
55 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
56 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults,
57 __out IBootstrapperApplication** ppApplication
58 );
diff --git a/src/ext/Bal/wixstdba/resource.h b/src/ext/Bal/wixstdba/resource.h
new file mode 100644
index 00000000..149a8ff4
--- /dev/null
+++ b/src/ext/Bal/wixstdba/resource.h
@@ -0,0 +1,15 @@
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#define IDC_STATIC -1
4
5
6// Next default values for new objects
7//
8#ifdef APSTUDIO_INVOKED
9#ifndef APSTUDIO_READONLY_SYMBOLS
10#define _APS_NEXT_RESOURCE_VALUE 102
11#define _APS_NEXT_COMMAND_VALUE 40001
12#define _APS_NEXT_CONTROL_VALUE 1003
13#define _APS_NEXT_SYMED_VALUE 101
14#endif
15#endif
diff --git a/src/ext/Bal/wixstdba/wixstdba.cpp b/src/ext/Bal/wixstdba/wixstdba.cpp
new file mode 100644
index 00000000..a96f1738
--- /dev/null
+++ b/src/ext/Bal/wixstdba/wixstdba.cpp
@@ -0,0 +1,144 @@
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
5static HINSTANCE vhInstance = NULL;
6static IBootstrapperApplication* vpApplication = NULL;
7
8static void CALLBACK WixstdbaTraceError(
9 __in_z LPCSTR szFile,
10 __in int iLine,
11 __in REPORT_LEVEL rl,
12 __in UINT source,
13 __in HRESULT hrError,
14 __in_z __format_string LPCSTR szFormat,
15 __in va_list args
16 );
17
18extern "C" BOOL WINAPI DllMain(
19 IN HINSTANCE hInstance,
20 IN DWORD dwReason,
21 IN LPVOID /* pvReserved */
22 )
23{
24 switch(dwReason)
25 {
26 case DLL_PROCESS_ATTACH:
27 ::DisableThreadLibraryCalls(hInstance);
28 vhInstance = hInstance;
29 break;
30
31 case DLL_PROCESS_DETACH:
32 vhInstance = NULL;
33 break;
34 }
35
36 return TRUE;
37}
38
39
40extern "C" HRESULT WINAPI BootstrapperApplicationCreate(
41 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
42 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults
43 )
44{
45 HRESULT hr = S_OK;
46 IBootstrapperEngine* pEngine = NULL;
47
48 DutilInitialize(&WixstdbaTraceError);
49
50 hr = BalInitializeFromCreateArgs(pArgs, &pEngine);
51 ExitOnFailure(hr, "Failed to initialize Bal.");
52
53 hr = CreateBootstrapperApplication(vhInstance, FALSE, S_OK, pEngine, pArgs, pResults, &vpApplication);
54 BalExitOnFailure(hr, "Failed to create bootstrapper application interface.");
55
56LExit:
57 ReleaseObject(pEngine);
58
59 return hr;
60}
61
62
63extern "C" void WINAPI BootstrapperApplicationDestroy()
64{
65 ReleaseNullObject(vpApplication);
66 BalUninitialize();
67 DutilUninitialize();
68}
69
70
71extern "C" HRESULT WINAPI DncPrereqBootstrapperApplicationCreate(
72 __in HRESULT hrHostInitialization,
73 __in IBootstrapperEngine* pEngine,
74 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
75 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults
76 )
77{
78 HRESULT hr = S_OK;
79
80 DutilInitialize(&WixstdbaTraceError);
81
82 BalInitialize(pEngine);
83
84 hr = CreateBootstrapperApplication(vhInstance, TRUE, hrHostInitialization, pEngine, pArgs, pResults, &vpApplication);
85 BalExitOnFailure(hr, "Failed to create .NET Core prerequisite bootstrapper application interface.");
86
87LExit:
88 return hr;
89}
90
91
92extern "C" void WINAPI DncPrereqBootstrapperApplicationDestroy()
93{
94 ReleaseNullObject(vpApplication);
95 BalUninitialize();
96 DutilUninitialize();
97}
98
99
100extern "C" HRESULT WINAPI MbaPrereqBootstrapperApplicationCreate(
101 __in HRESULT hrHostInitialization,
102 __in IBootstrapperEngine* pEngine,
103 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
104 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults
105 )
106{
107 HRESULT hr = S_OK;
108
109 DutilInitialize(&WixstdbaTraceError);
110
111 BalInitialize(pEngine);
112
113 hr = CreateBootstrapperApplication(vhInstance, TRUE, hrHostInitialization, pEngine, pArgs, pResults, &vpApplication);
114 BalExitOnFailure(hr, "Failed to create managed prerequisite bootstrapper application interface.");
115
116LExit:
117 return hr;
118}
119
120
121extern "C" void WINAPI MbaPrereqBootstrapperApplicationDestroy()
122{
123 ReleaseNullObject(vpApplication);
124 BalUninitialize();
125 DutilUninitialize();
126}
127
128static void CALLBACK WixstdbaTraceError(
129 __in_z LPCSTR /*szFile*/,
130 __in int /*iLine*/,
131 __in REPORT_LEVEL /*rl*/,
132 __in UINT source,
133 __in HRESULT hrError,
134 __in_z __format_string LPCSTR szFormat,
135 __in va_list args
136 )
137{
138 // BalLogError currently uses the Exit... macros,
139 // so if expanding the scope need to ensure this doesn't get called recursively.
140 if (DUTIL_SOURCE_THMUTIL == source)
141 {
142 BalLogErrorArgs(hrError, szFormat, args);
143 }
144}
diff --git a/src/ext/Bal/wixstdba/wixstdba.def b/src/ext/Bal/wixstdba/wixstdba.def
new file mode 100644
index 00000000..ba9980d3
--- /dev/null
+++ b/src/ext/Bal/wixstdba/wixstdba.def
@@ -0,0 +1,10 @@
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
4EXPORTS
5 BootstrapperApplicationCreate
6 BootstrapperApplicationDestroy
7 DncPrereqBootstrapperApplicationCreate
8 DncPrereqBootstrapperApplicationDestroy
9 MbaPrereqBootstrapperApplicationCreate
10 MbaPrereqBootstrapperApplicationDestroy
diff --git a/src/ext/Bal/wixstdba/wixstdba.mc b/src/ext/Bal/wixstdba/wixstdba.mc
new file mode 100644
index 00000000..688b1da1
--- /dev/null
+++ b/src/ext/Bal/wixstdba/wixstdba.mc
@@ -0,0 +1,73 @@
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
4MessageIdTypedef=DWORD
5
6LanguageNames=(English=0x409:MSG00409)
7
8
9; // message definitions
10
11; // MessageId=#
12; // Severity=Success
13; // SymbolicName=MSG_SUCCESS
14; // Language=English
15; // Success %1.
16; // .
17;
18; // MessageId=#
19; // Severity=Warning
20; // SymbolicName=MSG_WARNING
21; // Language=English
22; // Warning %1.
23; // .
24;
25; // MessageId=#
26; // Severity=Error
27; // SymbolicName=MSG_ERROR
28; // Language=English
29; // Error %1.
30; // .
31
32MessageId=1
33Severity=Success
34SymbolicName=MSG_WIXSTDBA_PLANNED_FORWARD_COMPATIBLE_BUNDLE
35Language=English
36WIXSTDBA: Planned forward compatible bundle: %1!ls!, wixstdba requested: %2!hs!, bafunctions requested: %3!hs!
37.
38
39MessageId=2
40Severity=Success
41SymbolicName=MSG_WIXSTDBA_PLANNED_PACKAGE
42Language=English
43WIXSTDBA: Planned package: %1!ls!, wixstdba requested: %2!hs!, bafunctions requested: %3!hs!
44.
45
46MessageId=3
47Severity=Success
48SymbolicName=MSG_WIXSTDBA_PLANNED_RELATED_BUNDLE
49Language=English
50WIXSTDBA: Planned related bundle: %1!ls!, wixstdba requested: %2!hs!, bafunctions requested: %3!hs!
51.
52
53MessageId=5
54Severity=Success
55SymbolicName=MSG_WIXSTDBA_PLANNED_TARGET_MSI_PACKAGE
56Language=English
57WIXSTDBA: Planned target MSI package: %1!ls!, productCode: %2!ls!, wixstdba requested: %3!hs!, bafunctions requested: %4!hs!
58.
59
60MessageId=6
61Severity=Success
62SymbolicName=MSG_WIXSTDBA_PLANNED_MSI_FEATURE
63Language=English
64WIXSTDBA: Planned MSI feature: %2!ls! for %1!ls!, wixstdba requested: %3!hs!, bafunctions requested: %4!hs!
65.
66
67MessageId=7
68Severity=Success
69SymbolicName=MSG_WIXSTDBA_PLANNED_MSI_PACKAGE
70Language=English
71WIXSTDBA: Planned MSI package: %1!ls!, wixstdba requested: actionMsiProperty=%2!d!;uiLevel=%3!d!;disableExternalUiHandler=%4!hs!, bafunctions requested: actionMsiProperty=%5!d!;uiLevel=%6!d!;disableExternalUiHandler=%7!hs!
72.
73
diff --git a/src/ext/Bal/wixstdba/wixstdba.vcxproj b/src/ext/Bal/wixstdba/wixstdba.vcxproj
new file mode 100644
index 00000000..06b1c8d8
--- /dev/null
+++ b/src/ext/Bal/wixstdba/wixstdba.vcxproj
@@ -0,0 +1,101 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
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')" />
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.BalUtil.4.0.58\build\WixToolset.BalUtil.props" Condition="Exists('..\..\packages\WixToolset.BalUtil.4.0.58\build\WixToolset.BalUtil.props')" />
9 <Import Project="..\..\packages\WixToolset.BootstrapperCore.Native.4.0.141\build\WixToolset.BootstrapperCore.Native.props" Condition="Exists('..\..\packages\WixToolset.BootstrapperCore.Native.4.0.141\build\WixToolset.BootstrapperCore.Native.props')" />
10 <Import Project="..\..\packages\WixToolset.DUtil.4.0.72\build\WixToolset.DUtil.props" Condition="Exists('..\..\packages\WixToolset.DUtil.4.0.72\build\WixToolset.DUtil.props')" />
11
12 <ItemGroup Label="ProjectConfigurations">
13 <ProjectConfiguration Include="Debug|ARM64">
14 <Configuration>Debug</Configuration>
15 <Platform>ARM64</Platform>
16 </ProjectConfiguration>
17 <ProjectConfiguration Include="Release|ARM64">
18 <Configuration>Release</Configuration>
19 <Platform>ARM64</Platform>
20 </ProjectConfiguration>
21 <ProjectConfiguration Include="Debug|Win32">
22 <Configuration>Debug</Configuration>
23 <Platform>Win32</Platform>
24 </ProjectConfiguration>
25 <ProjectConfiguration Include="Release|Win32">
26 <Configuration>Release</Configuration>
27 <Platform>Win32</Platform>
28 </ProjectConfiguration>
29 <ProjectConfiguration Include="Debug|x64">
30 <Configuration>Debug</Configuration>
31 <Platform>x64</Platform>
32 </ProjectConfiguration>
33 <ProjectConfiguration Include="Release|x64">
34 <Configuration>Release</Configuration>
35 <Platform>x64</Platform>
36 </ProjectConfiguration>
37 </ItemGroup>
38
39 <PropertyGroup Label="Globals">
40 <ProjectGuid>{41085A22-E6AA-4E8B-AB1B-DDEE0DC89DFA}</ProjectGuid>
41 <ConfigurationType>DynamicLibrary</ConfigurationType>
42 <PlatformToolset>v142</PlatformToolset>
43 <CharacterSet>Unicode</CharacterSet>
44 <TargetName>WixStdBA</TargetName>
45 <ProjectModuleDefinitionFile>wixstdba.def</ProjectModuleDefinitionFile>
46 </PropertyGroup>
47
48 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
49 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
50
51 <PropertyGroup>
52 <ProjectAdditionalLinkLibraries>comctl32.lib;gdiplus.lib;msimg32.lib;shlwapi.lib;wininet.lib;wixstdba.res</ProjectAdditionalLinkLibraries>
53 </PropertyGroup>
54
55 <ItemGroup>
56 <ClCompile Include="precomp.cpp">
57 <PrecompiledHeader>Create</PrecompiledHeader>
58 </ClCompile>
59 <ClCompile Include="WixStandardBootstrapperApplication.cpp" />
60 <ClCompile Include="wixstdba.cpp" />
61 </ItemGroup>
62 <ItemGroup>
63 <ClInclude Include="precomp.h" />
64 <ClInclude Include="resource.h" />
65 </ItemGroup>
66 <ItemGroup>
67 <None Include="wixstdba.def" />
68 </ItemGroup>
69 <ItemGroup>
70 <None Include="packages.config" />
71 </ItemGroup>
72 <ItemGroup>
73 <CustomBuild Include="wixstdba.mc">
74 <Message>Compiling message file...</Message>
75 <Command>mc.exe -h "$(IntDir)." -r "$(IntDir)." -A -c -z wixstdba.messages "$(InputDir)wixstdba.mc"
76rc.exe -fo "$(OutDir)wixstdba.res" "$(IntDir)wixstdba.messages.rc"</Command>
77 <Outputs>$(IntDir)wixstdba.messages.h;$(IntDir)wixstdba.messages.rc</Outputs>
78 </CustomBuild>
79 </ItemGroup>
80
81 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
82 <Import Project="..\..\packages\Microsoft.Build.Tasks.Git.1.0.0\build\Microsoft.Build.Tasks.Git.targets" Condition="Exists('..\..\packages\Microsoft.Build.Tasks.Git.1.0.0\build\Microsoft.Build.Tasks.Git.targets')" />
83 <Import Project="..\..\packages\Microsoft.SourceLink.Common.1.0.0\build\Microsoft.SourceLink.Common.targets" Condition="Exists('..\..\packages\Microsoft.SourceLink.Common.1.0.0\build\Microsoft.SourceLink.Common.targets')" />
84 <Import Project="..\..\packages\Microsoft.SourceLink.GitHub.1.0.0\build\Microsoft.SourceLink.GitHub.targets" Condition="Exists('..\..\packages\Microsoft.SourceLink.GitHub.1.0.0\build\Microsoft.SourceLink.GitHub.targets')" />
85 <Import Project="..\..\packages\Nerdbank.GitVersioning.3.3.37\build\Nerdbank.GitVersioning.targets" Condition="Exists('..\..\packages\Nerdbank.GitVersioning.3.3.37\build\Nerdbank.GitVersioning.targets')" />
86 <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
87 <PropertyGroup>
88 <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>
89 </PropertyGroup>
90 <Error Condition="!Exists('..\..\packages\Microsoft.Build.Tasks.Git.1.0.0\build\Microsoft.Build.Tasks.Git.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Build.Tasks.Git.1.0.0\build\Microsoft.Build.Tasks.Git.props'))" />
91 <Error Condition="!Exists('..\..\packages\Microsoft.Build.Tasks.Git.1.0.0\build\Microsoft.Build.Tasks.Git.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Build.Tasks.Git.1.0.0\build\Microsoft.Build.Tasks.Git.targets'))" />
92 <Error Condition="!Exists('..\..\packages\Microsoft.SourceLink.Common.1.0.0\build\Microsoft.SourceLink.Common.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.SourceLink.Common.1.0.0\build\Microsoft.SourceLink.Common.props'))" />
93 <Error Condition="!Exists('..\..\packages\Microsoft.SourceLink.Common.1.0.0\build\Microsoft.SourceLink.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.SourceLink.Common.1.0.0\build\Microsoft.SourceLink.Common.targets'))" />
94 <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'))" />
95 <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'))" />
96 <Error Condition="!Exists('..\..\packages\Nerdbank.GitVersioning.3.3.37\build\Nerdbank.GitVersioning.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Nerdbank.GitVersioning.3.3.37\build\Nerdbank.GitVersioning.targets'))" />
97 <Error Condition="!Exists('..\..\packages\WixToolset.BalUtil.4.0.58\build\WixToolset.BalUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.BalUtil.4.0.58\build\WixToolset.BalUtil.props'))" />
98 <Error Condition="!Exists('..\..\packages\WixToolset.BootstrapperCore.Native.4.0.141\build\WixToolset.BootstrapperCore.Native.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.BootstrapperCore.Native.4.0.141\build\WixToolset.BootstrapperCore.Native.props'))" />
99 <Error Condition="!Exists('..\..\packages\WixToolset.DUtil.4.0.72\build\WixToolset.DUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.DUtil.4.0.72\build\WixToolset.DUtil.props'))" />
100 </Target>
101</Project> \ No newline at end of file
diff --git a/src/ext/Util/CustomizedNativeRecommendedRules.ruleset b/src/ext/Util/CustomizedNativeRecommendedRules.ruleset
new file mode 100644
index 00000000..142b141c
--- /dev/null
+++ b/src/ext/Util/CustomizedNativeRecommendedRules.ruleset
@@ -0,0 +1,8 @@
1<?xml version="1.0" encoding="utf-8"?>
2<RuleSet Name="Customized Microsoft Native Recommended Rules" Description="Microsoft Native Recommended Rules, -C26812" ToolsVersion="16.0">
3 <Include Path="nativerecommendedrules.ruleset" Action="Default" />
4 <Rules AnalyzerId="Microsoft.Analyzers.NativeCodeAnalysis" RuleNamespace="Microsoft.Rules.Native">
5 <!-- We need C style enums since we support BAs written in C -->
6 <Rule Id="C26812" Action="None" />
7 </Rules>
8</RuleSet> \ No newline at end of file
diff --git a/src/ext/Util/Directory.Build.props b/src/ext/Util/Directory.Build.props
new file mode 100644
index 00000000..b3c6287c
--- /dev/null
+++ b/src/ext/Util/Directory.Build.props
@@ -0,0 +1,27 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3<!--
4 Do NOT modify this file. Update the canonical version in Home\repo-template\src\Directory.Build.props
5 then update all of the repos.
6-->
7<Project>
8 <PropertyGroup>
9 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
10 <EnableSourceLink Condition=" '$(NCrunch)' == '1' ">false</EnableSourceLink>
11 <MSBuildWarningsAsMessages>MSB3246</MSBuildWarningsAsMessages>
12
13 <ProjectName Condition=" '$(ProjectName)' == '' ">$(MSBuildProjectName)</ProjectName>
14 <BaseOutputPath>$([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)..\build\))</BaseOutputPath>
15 <BaseIntermediateOutputPath>$(BaseOutputPath)obj\$(ProjectName)\</BaseIntermediateOutputPath>
16 <OutputPath>$(BaseOutputPath)$(Configuration)\</OutputPath>
17
18 <Authors>WiX Toolset Team</Authors>
19 <Company>WiX Toolset</Company>
20 <Copyright>Copyright (c) .NET Foundation and contributors. All rights reserved.</Copyright>
21 <PackageLicenseExpression>MS-RL</PackageLicenseExpression>
22 <Product>WiX Toolset</Product>
23 </PropertyGroup>
24
25 <Import Project="Directory$(MSBuildProjectExtension).props" Condition=" Exists('Directory$(MSBuildProjectExtension).props') " />
26 <Import Project="Custom.Build.props" Condition=" Exists('Custom.Build.props') " />
27</Project>
diff --git a/src/ext/Util/Directory.Build.targets b/src/ext/Util/Directory.Build.targets
new file mode 100644
index 00000000..2fcc765a
--- /dev/null
+++ b/src/ext/Util/Directory.Build.targets
@@ -0,0 +1,51 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3<!--
4 Do NOT modify this file. Update the canonical version in Home\repo-template\src\Directory.Build.targets
5 then update all of the repos.
6-->
7<!--
8 Replace PackageReferences with ProjectReferences when the projects can be found in .sln.
9 See the original here: https://github.com/dotnet/sdk/issues/1151#issuecomment-385133284
10-->
11<Project>
12 <PropertyGroup>
13 <ReplacePackageReferences>true</ReplacePackageReferences>
14 <TheSolutionPath Condition=" '$(NCrunch)'=='' ">$(SolutionPath)</TheSolutionPath>
15 <TheSolutionPath Condition=" '$(NCrunch)'=='1' ">$(NCrunchOriginalSolutionPath)</TheSolutionPath>
16 </PropertyGroup>
17
18 <Choose>
19 <When Condition="$(ReplacePackageReferences) AND '$(TheSolutionPath)' != '' AND '$(TheSolutionPath)' != '*undefined*' AND Exists('$(TheSolutionPath)')">
20
21 <PropertyGroup>
22 <SolutionFileContent>$([System.IO.File]::ReadAllText($(TheSolutionPath)))</SolutionFileContent>
23 <SmartSolutionDir>$([System.IO.Path]::GetDirectoryName( $(TheSolutionPath) ))</SmartSolutionDir>
24 <RegexPattern>(?&lt;="[PackageName]", ")(.*)(?=", ")</RegexPattern>
25 </PropertyGroup>
26
27 <ItemGroup>
28 <!-- Keep the identity of the PackageReference -->
29 <SmartPackageReference Include="@(PackageReference)">
30 <PackageName>%(Identity)</PackageName>
31 <InSolution>$(SolutionFileContent.Contains('\%(Identity).csproj'))</InSolution>
32 </SmartPackageReference>
33
34 <!-- Filter them by mapping them to another ItemGroup using the WithMetadataValue item function -->
35 <PackageInSolution Include="@(SmartPackageReference->WithMetadataValue('InSolution', True))">
36 <Pattern>$(RegexPattern.Replace('[PackageName]','%(PackageName)') )</Pattern>
37 <SmartPath>$([System.Text.RegularExpressions.Regex]::Match('$(SolutionFileContent)', '%(Pattern)'))</SmartPath>
38 </PackageInSolution>
39
40 <ProjectReference Include="@(PackageInSolution->'$(SmartSolutionDir)\%(SmartPath)' )"/>
41
42 <!-- Remove the package references that are now referenced as projects -->
43 <PackageReference Remove="@(PackageInSolution->'%(PackageName)')"/>
44 </ItemGroup>
45
46 </When>
47 </Choose>
48
49 <Import Project="Directory$(MSBuildProjectExtension).targets" Condition=" Exists('Directory$(MSBuildProjectExtension).targets') " />
50 <Import Project="Custom.Build.targets" Condition=" Exists('Custom.Build.targets') " />
51</Project>
diff --git a/src/ext/Util/Directory.csproj.props b/src/ext/Util/Directory.csproj.props
new file mode 100644
index 00000000..81d24ad1
--- /dev/null
+++ b/src/ext/Util/Directory.csproj.props
@@ -0,0 +1,13 @@
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 Do NOT modify this file. Update the canonical version in Home\repo-template\src\CSharp.Build.props
4 then update all of the repos.
5-->
6<Project>
7 <PropertyGroup>
8 <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
9 <SignAssembly>true</SignAssembly>
10 <AssemblyOriginatorKeyFile>$([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)wix.snk))</AssemblyOriginatorKeyFile>
11 <NBGV_EmitThisAssemblyClass>false</NBGV_EmitThisAssemblyClass>
12 </PropertyGroup>
13</Project>
diff --git a/src/ext/Util/Directory.csproj.targets b/src/ext/Util/Directory.csproj.targets
new file mode 100644
index 00000000..c3270426
--- /dev/null
+++ b/src/ext/Util/Directory.csproj.targets
@@ -0,0 +1,26 @@
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 Do NOT modify this file. Update the canonical version in Home\repo-template\src\Directory.csproj.targets
4 then update all of the repos.
5-->
6<Project>
7 <PropertyGroup>
8 <CreateDocumentation Condition=" '$(CreateDocumentationFile)'!='true' ">false</CreateDocumentation>
9 <DocumentationFile Condition=" '$(CreateDocumentationFile)'=='true' ">$(OutputPath)\$(AssemblyName).xml</DocumentationFile>
10 </PropertyGroup>
11
12 <Target Name="SetNuspecProperties" DependsOnTargets="InitializeSourceControlInformation" AfterTargets="GetBuildVersion"
13 Condition=" Exists('$(MSBuildProjectName).nuspec') ">
14 <PropertyGroup>
15 <ProjectUrl Condition=" '$(ProjectUrl)'=='' and '$(PrivateRepositoryUrl)'!='' ">$(PrivateRepositoryUrl.Replace('.git',''))</ProjectUrl>
16
17 <NuspecFile>$(MSBuildProjectName).nuspec</NuspecFile>
18 <NuspecBasePath Condition=" '$(NuspecBasePath)'=='' ">$(OutputPath)..\</NuspecBasePath>
19 <NuspecProperties>$(NuspecProperties);Id=$(PackageId);Authors=$(Authors);Copyright=$(Copyright);Description=$(Description);Title=$(Title)</NuspecProperties>
20 <NuspecProperties>$(NuspecProperties);Version=$(PackageVersion);RepositoryCommit=$(SourceRevisionId);RepositoryType=$(RepositoryType);RepositoryUrl=$(PrivateRepositoryUrl);ProjectFolder=$(MSBuildProjectDirectory)\;ProjectUrl=$(ProjectUrl)</NuspecProperties>
21 <PublishRepositoryUrl>true</PublishRepositoryUrl>
22 <SymbolPackageFormat>snupkg</SymbolPackageFormat>
23 </PropertyGroup>
24 </Target>
25
26</Project>
diff --git a/src/ext/Util/Directory.vcxproj.props b/src/ext/Util/Directory.vcxproj.props
new file mode 100644
index 00000000..11778f41
--- /dev/null
+++ b/src/ext/Util/Directory.vcxproj.props
@@ -0,0 +1,97 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4<Project>
5 <PropertyGroup>
6 <Platform Condition=" '$(Platform)' == '' OR '$(Platform)' == 'AnyCPU' ">Win32</Platform>
7 <IntDir>$(BaseIntermediateOutputPath)$(Configuration)\$(Platform)\</IntDir>
8 <OutDir>$(OutputPath)$(Platform)\</OutDir>
9
10 <!-- NBGV properties -->
11 <AssemblyCompany>$(Company)</AssemblyCompany>
12 <AssemblyCopyright>$(Copyright)</AssemblyCopyright>
13
14 <RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>
15 <NuGetTargetMoniker>native,Version=v0.0</NuGetTargetMoniker>
16 </PropertyGroup>
17
18 <PropertyGroup Condition="'$(WindowsTargetPlatformVersion)'=='' AND '$(VisualStudioVersion)'>='15.0'">
19 <WindowsTargetPlatformVersion>$([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0'))</WindowsTargetPlatformVersion>
20 </PropertyGroup>
21
22 <PropertyGroup>
23 <CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)CustomizedNativeRecommendedRules.ruleset</CodeAnalysisRuleSet>
24 </PropertyGroup>
25
26 <ItemDefinitionGroup>
27 <ClCompile>
28 <DisableSpecificWarnings>$(DisableSpecificCompilerWarnings)</DisableSpecificWarnings>
29 <WarningLevel>Level4</WarningLevel>
30 <AdditionalIncludeDirectories>$(ProjectDir)inc;$(MSBuildProjectDirectory);$(IntDir);$(SqlCESdkIncludePath);$(ProjectAdditionalIncludeDirectories);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
31 <PreprocessorDefinitions>WIN32;_WINDOWS;_WIN32_MSI=500;_WIN32_WINNT=0x0501;$(ArmPreprocessorDefinitions);$(UnicodePreprocessorDefinitions);_CRT_STDIO_LEGACY_WIDE_SPECIFIERS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
32 <PrecompiledHeader>Use</PrecompiledHeader>
33 <PrecompiledHeaderFile>precomp.h</PrecompiledHeaderFile>
34 <CallingConvention Condition="'$(Platform)'=='Win32'">StdCall</CallingConvention>
35 <TreatWarningAsError>true</TreatWarningAsError>
36 <ExceptionHandling>false</ExceptionHandling>
37 <AdditionalOptions>-YlprecompDefine</AdditionalOptions>
38 <AdditionalOptions Condition=" $(PlatformToolset.StartsWith('v14')) ">/Zc:threadSafeInit- %(AdditionalOptions)</AdditionalOptions>
39 <MultiProcessorCompilation Condition=" $(NUMBER_OF_PROCESSORS) &gt; 4 ">true</MultiProcessorCompilation>
40 </ClCompile>
41 <ResourceCompile>
42 <PreprocessorDefinitions>$(ArmPreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
43 <AdditionalIncludeDirectories>$(ProjectAdditionalResourceIncludeDirectories);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
44 </ResourceCompile>
45 <Lib>
46 <AdditionalLibraryDirectories>$(OutDir);$(AdditionalMultiTargetLibraryPath);$(ProjectAdditionalLibraryDirectories);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
47 </Lib>
48 <Link>
49 <SubSystem>$(ProjectSubSystem)</SubSystem>
50 <ModuleDefinitionFile>$(ProjectModuleDefinitionFile)</ModuleDefinitionFile>
51 <NoEntryPoint>$(ResourceOnlyDll)</NoEntryPoint>
52 <GenerateDebugInformation>true</GenerateDebugInformation>
53 <AdditionalDependencies>$(ProjectAdditionalLinkLibraries);advapi32.lib;comdlg32.lib;user32.lib;oleaut32.lib;gdi32.lib;shell32.lib;ole32.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
54 <AdditionalLibraryDirectories>$(OutDir);$(AdditionalMultiTargetLibraryPath);$(ArmLibraryDirectories);$(ProjectAdditionalLinkLibraryDirectories);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
55 <AdditionalOptions Condition=" $(PlatformToolset.StartsWith('v14')) ">/IGNORE:4099 %(AdditionalOptions)</AdditionalOptions>
56 </Link>
57 </ItemDefinitionGroup>
58
59 <ItemDefinitionGroup Condition=" '$(Platform)'=='Win32' and '$(PlatformToolset)'!='v100'">
60 <ClCompile>
61 <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
62 </ClCompile>
63 </ItemDefinitionGroup>
64 <ItemDefinitionGroup Condition=" '$(Platform)'=='arm' ">
65 <ClCompile>
66 <CallingConvention>CDecl</CallingConvention>
67 </ClCompile>
68 </ItemDefinitionGroup>
69 <ItemDefinitionGroup Condition=" '$(ConfigurationType)'=='StaticLibrary' ">
70 <ClCompile>
71 <DebugInformationFormat>OldStyle</DebugInformationFormat>
72 <OmitDefaultLibName>true</OmitDefaultLibName>
73 <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
74 </ClCompile>
75 </ItemDefinitionGroup>
76 <ItemDefinitionGroup Condition=" '$(Configuration)'=='Debug' ">
77 <ClCompile>
78 <Optimization>Disabled</Optimization>
79 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
80 <PreprocessorDefinitions>_DEBUG;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
81 <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
82 </ClCompile>
83 </ItemDefinitionGroup>
84 <ItemDefinitionGroup Condition=" '$(Configuration)'=='Release' ">
85 <ClCompile>
86 <Optimization>MinSpace</Optimization>
87 <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
88 <FunctionLevelLinking>true</FunctionLevelLinking>
89 <IntrinsicFunctions>true</IntrinsicFunctions>
90 <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
91 </ClCompile>
92 <Link>
93 <EnableCOMDATFolding>true</EnableCOMDATFolding>
94 <OptimizeReferences>true</OptimizeReferences>
95 </Link>
96 </ItemDefinitionGroup>
97</Project>
diff --git a/src/ext/Util/README.md b/src/ext/Util/README.md
new file mode 100644
index 00000000..540c539c
--- /dev/null
+++ b/src/ext/Util/README.md
@@ -0,0 +1,3 @@
1# Util.wixext
2WixToolset.Util.wixext - Utility WiX Toolset Extension
3
diff --git a/src/ext/Util/Util.wixext.sln b/src/ext/Util/Util.wixext.sln
new file mode 100644
index 00000000..050fd8b3
--- /dev/null
+++ b/src/ext/Util/Util.wixext.sln
@@ -0,0 +1,87 @@
1
2Microsoft Visual Studio Solution File, Format Version 12.00
3# Visual Studio Version 16
4VisualStudioVersion = 16.0.30204.135
5MinimumVisualStudioVersion = 15.0.26124.0
6Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "utilbe", "src\be\utilbe.vcxproj", "{630C1EE7-2517-4A8C-83E3-DA1150308B58}"
7EndProject
8Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "utilca", "src\ca\utilca.vcxproj", "{076018F7-19BD-423A-ABBF-229273DA08D8}"
9EndProject
10Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "util", "src\wixlib\util.wixproj", "{1ACFFEFD-505A-41A5-ACBF-A02B7B473AA2}"
11EndProject
12Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolset.Util.wixext", "src\wixext\WixToolset.Util.wixext.csproj", "{6CF033EB-0A39-4AC6-9D41-9BD506352045}"
13EndProject
14Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolsetTest.Util", "src\test\WixToolsetTest.Util\WixToolsetTest.Util.csproj", "{D5D34EC4-AF91-4B11-AC0A-FA5242AE924B}"
15EndProject
16Global
17 GlobalSection(SolutionConfigurationPlatforms) = preSolution
18 Debug|Any CPU = Debug|Any CPU
19 Debug|x64 = Debug|x64
20 Debug|x86 = Debug|x86
21 Release|Any CPU = Release|Any CPU
22 Release|x64 = Release|x64
23 Release|x86 = Release|x86
24 EndGlobalSection
25 GlobalSection(ProjectConfigurationPlatforms) = postSolution
26 {630C1EE7-2517-4A8C-83E3-DA1150308B58}.Debug|Any CPU.ActiveCfg = Debug|Win32
27 {630C1EE7-2517-4A8C-83E3-DA1150308B58}.Debug|Any CPU.Build.0 = Debug|Win32
28 {630C1EE7-2517-4A8C-83E3-DA1150308B58}.Debug|x64.ActiveCfg = Debug|Win32
29 {630C1EE7-2517-4A8C-83E3-DA1150308B58}.Debug|x86.ActiveCfg = Debug|Win32
30 {630C1EE7-2517-4A8C-83E3-DA1150308B58}.Debug|x86.Build.0 = Debug|Win32
31 {630C1EE7-2517-4A8C-83E3-DA1150308B58}.Release|Any CPU.ActiveCfg = Release|Win32
32 {630C1EE7-2517-4A8C-83E3-DA1150308B58}.Release|Any CPU.Build.0 = Release|Win32
33 {630C1EE7-2517-4A8C-83E3-DA1150308B58}.Release|x64.ActiveCfg = Release|Win32
34 {630C1EE7-2517-4A8C-83E3-DA1150308B58}.Release|x86.ActiveCfg = Release|Win32
35 {630C1EE7-2517-4A8C-83E3-DA1150308B58}.Release|x86.Build.0 = Release|Win32
36 {076018F7-19BD-423A-ABBF-229273DA08D8}.Debug|Any CPU.ActiveCfg = Debug|Win32
37 {076018F7-19BD-423A-ABBF-229273DA08D8}.Debug|Any CPU.Build.0 = Debug|Win32
38 {076018F7-19BD-423A-ABBF-229273DA08D8}.Debug|x64.ActiveCfg = Debug|Win32
39 {076018F7-19BD-423A-ABBF-229273DA08D8}.Debug|x86.ActiveCfg = Debug|Win32
40 {076018F7-19BD-423A-ABBF-229273DA08D8}.Debug|x86.Build.0 = Debug|Win32
41 {076018F7-19BD-423A-ABBF-229273DA08D8}.Release|Any CPU.ActiveCfg = Release|Win32
42 {076018F7-19BD-423A-ABBF-229273DA08D8}.Release|Any CPU.Build.0 = Release|Win32
43 {076018F7-19BD-423A-ABBF-229273DA08D8}.Release|x64.ActiveCfg = Release|Win32
44 {076018F7-19BD-423A-ABBF-229273DA08D8}.Release|x86.ActiveCfg = Release|Win32
45 {076018F7-19BD-423A-ABBF-229273DA08D8}.Release|x86.Build.0 = Release|Win32
46 {1ACFFEFD-505A-41A5-ACBF-A02B7B473AA2}.Debug|Any CPU.ActiveCfg = Debug|x86
47 {1ACFFEFD-505A-41A5-ACBF-A02B7B473AA2}.Debug|Any CPU.Build.0 = Debug|x86
48 {1ACFFEFD-505A-41A5-ACBF-A02B7B473AA2}.Debug|x64.ActiveCfg = Debug|x86
49 {1ACFFEFD-505A-41A5-ACBF-A02B7B473AA2}.Debug|x86.ActiveCfg = Debug|x86
50 {1ACFFEFD-505A-41A5-ACBF-A02B7B473AA2}.Debug|x86.Build.0 = Debug|x86
51 {1ACFFEFD-505A-41A5-ACBF-A02B7B473AA2}.Release|Any CPU.ActiveCfg = Release|x86
52 {1ACFFEFD-505A-41A5-ACBF-A02B7B473AA2}.Release|Any CPU.Build.0 = Release|x86
53 {1ACFFEFD-505A-41A5-ACBF-A02B7B473AA2}.Release|x64.ActiveCfg = Release|x86
54 {1ACFFEFD-505A-41A5-ACBF-A02B7B473AA2}.Release|x86.ActiveCfg = Release|x86
55 {1ACFFEFD-505A-41A5-ACBF-A02B7B473AA2}.Release|x86.Build.0 = Release|x86
56 {6CF033EB-0A39-4AC6-9D41-9BD506352045}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
57 {6CF033EB-0A39-4AC6-9D41-9BD506352045}.Debug|Any CPU.Build.0 = Debug|Any CPU
58 {6CF033EB-0A39-4AC6-9D41-9BD506352045}.Debug|x64.ActiveCfg = Debug|Any CPU
59 {6CF033EB-0A39-4AC6-9D41-9BD506352045}.Debug|x64.Build.0 = Debug|Any CPU
60 {6CF033EB-0A39-4AC6-9D41-9BD506352045}.Debug|x86.ActiveCfg = Debug|Any CPU
61 {6CF033EB-0A39-4AC6-9D41-9BD506352045}.Debug|x86.Build.0 = Debug|Any CPU
62 {6CF033EB-0A39-4AC6-9D41-9BD506352045}.Release|Any CPU.ActiveCfg = Release|Any CPU
63 {6CF033EB-0A39-4AC6-9D41-9BD506352045}.Release|Any CPU.Build.0 = Release|Any CPU
64 {6CF033EB-0A39-4AC6-9D41-9BD506352045}.Release|x64.ActiveCfg = Release|Any CPU
65 {6CF033EB-0A39-4AC6-9D41-9BD506352045}.Release|x64.Build.0 = Release|Any CPU
66 {6CF033EB-0A39-4AC6-9D41-9BD506352045}.Release|x86.ActiveCfg = Release|Any CPU
67 {6CF033EB-0A39-4AC6-9D41-9BD506352045}.Release|x86.Build.0 = Release|Any CPU
68 {D5D34EC4-AF91-4B11-AC0A-FA5242AE924B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
69 {D5D34EC4-AF91-4B11-AC0A-FA5242AE924B}.Debug|Any CPU.Build.0 = Debug|Any CPU
70 {D5D34EC4-AF91-4B11-AC0A-FA5242AE924B}.Debug|x64.ActiveCfg = Debug|Any CPU
71 {D5D34EC4-AF91-4B11-AC0A-FA5242AE924B}.Debug|x64.Build.0 = Debug|Any CPU
72 {D5D34EC4-AF91-4B11-AC0A-FA5242AE924B}.Debug|x86.ActiveCfg = Debug|Any CPU
73 {D5D34EC4-AF91-4B11-AC0A-FA5242AE924B}.Debug|x86.Build.0 = Debug|Any CPU
74 {D5D34EC4-AF91-4B11-AC0A-FA5242AE924B}.Release|Any CPU.ActiveCfg = Release|Any CPU
75 {D5D34EC4-AF91-4B11-AC0A-FA5242AE924B}.Release|Any CPU.Build.0 = Release|Any CPU
76 {D5D34EC4-AF91-4B11-AC0A-FA5242AE924B}.Release|x64.ActiveCfg = Release|Any CPU
77 {D5D34EC4-AF91-4B11-AC0A-FA5242AE924B}.Release|x64.Build.0 = Release|Any CPU
78 {D5D34EC4-AF91-4B11-AC0A-FA5242AE924B}.Release|x86.ActiveCfg = Release|Any CPU
79 {D5D34EC4-AF91-4B11-AC0A-FA5242AE924B}.Release|x86.Build.0 = Release|Any CPU
80 EndGlobalSection
81 GlobalSection(SolutionProperties) = preSolution
82 HideSolutionNode = FALSE
83 EndGlobalSection
84 GlobalSection(ExtensibilityGlobals) = postSolution
85 SolutionGuid = {E4566A6B-47D0-4EA0-989A-D763AC39105D}
86 EndGlobalSection
87EndGlobal
diff --git a/src/ext/Util/Util.wixext.v3.ncrunchsolution b/src/ext/Util/Util.wixext.v3.ncrunchsolution
new file mode 100644
index 00000000..10420ac9
--- /dev/null
+++ b/src/ext/Util/Util.wixext.v3.ncrunchsolution
@@ -0,0 +1,6 @@
1<SolutionConfiguration>
2 <Settings>
3 <AllowParallelTestExecution>True</AllowParallelTestExecution>
4 <SolutionConfigured>True</SolutionConfigured>
5 </Settings>
6</SolutionConfiguration> \ No newline at end of file
diff --git a/src/ext/Util/appveyor.cmd b/src/ext/Util/appveyor.cmd
new file mode 100644
index 00000000..8322ffae
--- /dev/null
+++ b/src/ext/Util/appveyor.cmd
@@ -0,0 +1,19 @@
1@setlocal
2@pushd %~dp0
3@set _C=Release
4@if /i "%1"=="debug" set _C=Debug
5
6:: Restore
7msbuild -p:Configuration=%_C% -t:Restore || exit /b
8
9:: Build
10msbuild -p:Configuration=%_C% src\test\WixToolsetTest.Util\WixToolsetTest.Util.csproj || exit /b
11
12:: Test
13dotnet test -c %_C% --no-build src\test\WixToolsetTest.Util || exit /b
14
15:: Pack
16msbuild -p:Configuration=%_C% -p:NoBuild=true -t:Pack src\wixext\WixToolset.Util.wixext.csproj || exit /b
17
18@popd
19@endlocal
diff --git a/src/ext/Util/appveyor.yml b/src/ext/Util/appveyor.yml
new file mode 100644
index 00000000..7c686b04
--- /dev/null
+++ b/src/ext/Util/appveyor.yml
@@ -0,0 +1,40 @@
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# Do NOT modify this file. Update the canonical version in Home\repo-template\src\appveyor.yml
4# then update all of the repos.
5
6branches:
7 only:
8 - master
9 - develop
10
11image: Visual Studio 2019
12
13version: 0.0.0.{build}
14configuration: Release
15
16environment:
17 DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
18 DOTNET_CLI_TELEMETRY_OPTOUT: 1
19 NUGET_XMLDOC_MODE: skip
20
21build_script:
22 - appveyor.cmd
23
24pull_requests:
25 do_not_increment_build_number: true
26
27nuget:
28 disable_publish_on_pr: true
29
30skip_branch_with_pr: true
31skip_tags: true
32
33artifacts:
34- path: build\Release\**\*.nupkg
35 name: nuget
36
37notifications:
38- provider: Slack
39 incoming_webhook:
40 secure: p5xuu+4x2JHfwGDMDe5KcG1k7gZxqYc4jWVwvyNZv5cvkubPD2waJs5yXMAXZNN7Z63/3PWHb7q4KoY/99AjauYa1nZ4c5qYqRPFRBKTHfA=
diff --git a/src/ext/Util/be/UtilBundleExtension.cpp b/src/ext/Util/be/UtilBundleExtension.cpp
new file mode 100644
index 00000000..2ac842a5
--- /dev/null
+++ b/src/ext/Util/be/UtilBundleExtension.cpp
@@ -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
6class CWixUtilBundleExtension : public CBextBaseBundleExtension
7{
8public: // 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
21public: //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
49public:
50 CWixUtilBundleExtension(
51 __in IBundleExtensionEngine* pEngine
52 ) : CBextBaseBundleExtension(pEngine)
53 {
54 m_searches = { };
55 }
56
57 ~CWixUtilBundleExtension()
58 {
59 UtilSearchUninitialize(&m_searches);
60 }
61
62private:
63 UTIL_SEARCHES m_searches;
64};
65
66HRESULT 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
84LExit:
85 ReleaseObject(pExtension);
86 return hr;
87}
diff --git a/src/ext/Util/be/UtilBundleExtension.h b/src/ext/Util/be/UtilBundleExtension.h
new file mode 100644
index 00000000..c55d6b85
--- /dev/null
+++ b/src/ext/Util/be/UtilBundleExtension.h
@@ -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 BUNDLE_EXTENSION_DECORATION(L"UtilBundleExtension")
8
9
10// function declarations
11
12HRESULT UtilBundleExtensionCreate(
13 __in IBundleExtensionEngine* pEngine,
14 __in const BUNDLE_EXTENSION_CREATE_ARGS* pArgs,
15 __out IBundleExtension** ppBundleExtension
16 );
diff --git a/src/ext/Util/be/beDecor.h b/src/ext/Util/be/beDecor.h
new file mode 100644
index 00000000..2c6a8818
--- /dev/null
+++ b/src/ext/Util/be/beDecor.h
@@ -0,0 +1,13 @@
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#if defined(_M_ARM64)
6#define BUNDLE_EXTENSION_DECORATION(f) L"Wix4" f L"_A64"
7#elif defined(_M_AMD64)
8#define BUNDLE_EXTENSION_DECORATION(f) L"Wix4" f L"_X64"
9#elif defined(_M_ARM)
10#define BUNDLE_EXTENSION_DECORATION(f) L"Wix4" f L"_ARM"
11#else
12#define BUNDLE_EXTENSION_DECORATION(f) L"Wix4" f L"_X86"
13#endif
diff --git a/src/ext/Util/be/detectsha2support.cpp b/src/ext/Util/be/detectsha2support.cpp
new file mode 100644
index 00000000..90e349cd
--- /dev/null
+++ b/src/ext/Util/be/detectsha2support.cpp
@@ -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
6HRESULT DetectSHA2CodeSigning(
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
35LExit:
36 ::FreeLibrary(hModule);
37
38 return hr;
39}
40
41HRESULT UtilPerformDetectSHA2CodeSigning(
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 = DetectSHA2CodeSigning(&fSupported);
51 ExitOnFailure(hr, "DetectSHA2CodeSigning failed.");
52
53 hr = pEngine->SetVariableNumeric(wzVariable, fSupported ? 1 : 0);
54 ExitOnFailure(hr, "Failed to set variable '%ls'", wzVariable);
55
56LExit:
57 return hr;
58}
diff --git a/src/ext/Util/be/detectsha2support.h b/src/ext/Util/be/detectsha2support.h
new file mode 100644
index 00000000..c38a3d59
--- /dev/null
+++ b/src/ext/Util/be/detectsha2support.h
@@ -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
4HRESULT UtilPerformDetectSHA2CodeSigning(
5 __in LPCWSTR wzVariable,
6 __in UTIL_SEARCH* pSearch,
7 __in IBundleExtensionEngine* pEngine
8 ); \ No newline at end of file
diff --git a/src/ext/Util/be/precomp.cpp b/src/ext/Util/be/precomp.cpp
new file mode 100644
index 00000000..37664a1c
--- /dev/null
+++ b/src/ext/Util/be/precomp.cpp
@@ -0,0 +1,3 @@
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"
diff --git a/src/ext/Util/be/precomp.h b/src/ext/Util/be/precomp.h
new file mode 100644
index 00000000..76d24c7b
--- /dev/null
+++ b/src/ext/Util/be/precomp.h
@@ -0,0 +1,37 @@
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#if _WIN32_MSI < 150
6#define _WIN32_MSI 150
7#endif
8
9#include <windows.h>
10#include <msiquery.h>
11#include <msidefs.h>
12#include <stierr.h>
13
14#include <strsafe.h>
15
16#include <msxml2.h>
17
18#define MAXUINT USHRT_MAX
19
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 "beDecor.h"
35#include "utilsearch.h"
36#include "detectsha2support.h"
37#include "UtilBundleExtension.h"
diff --git a/src/ext/Util/be/utilbe.cpp b/src/ext/Util/be/utilbe.cpp
new file mode 100644
index 00000000..d9816dc7
--- /dev/null
+++ b/src/ext/Util/be/utilbe.cpp
@@ -0,0 +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
6static IBundleExtension* vpBundleExtension = NULL;
7
8// function definitions
9
10extern "C" HRESULT WINAPI BundleExtensionCreate(
11 __in const BUNDLE_EXTENSION_CREATE_ARGS* pArgs,
12 __inout BUNDLE_EXTENSION_CREATE_RESULTS* pResults
13 )
14{
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
30LExit:
31 ReleaseObject(pEngine);
32
33 return hr;
34}
35
36extern "C" void WINAPI BundleExtensionDestroy()
37{
38 BextUninitialize();
39 ReleaseNullObject(vpBundleExtension);
40 XmlUninitialize();
41} \ No newline at end of file
diff --git a/src/ext/Util/be/utilbe.def b/src/ext/Util/be/utilbe.def
new file mode 100644
index 00000000..711b1a5c
--- /dev/null
+++ b/src/ext/Util/be/utilbe.def
@@ -0,0 +1,8 @@
1; Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3
4LIBRARY "utilbe"
5
6EXPORTS
7 BundleExtensionCreate
8 BundleExtensionDestroy
diff --git a/src/ext/Util/be/utilbe.vcxproj b/src/ext/Util/be/utilbe.vcxproj
new file mode 100644
index 00000000..683b376a
--- /dev/null
+++ b/src/ext/Util/be/utilbe.vcxproj
@@ -0,0 +1,80 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4<Project DefaultTargets="Build" ToolsVersion="16.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
5 <ItemGroup Label="ProjectConfigurations">
6 <ProjectConfiguration Include="Debug|ARM64">
7 <Configuration>Debug</Configuration>
8 <Platform>ARM64</Platform>
9 </ProjectConfiguration>
10 <ProjectConfiguration Include="Release|ARM64">
11 <Configuration>Release</Configuration>
12 <Platform>ARM64</Platform>
13 </ProjectConfiguration>
14 <ProjectConfiguration Include="Debug|X64">
15 <Configuration>Debug</Configuration>
16 <Platform>X64</Platform>
17 </ProjectConfiguration>
18 <ProjectConfiguration Include="Release|X64">
19 <Configuration>Release</Configuration>
20 <Platform>X64</Platform>
21 </ProjectConfiguration>
22 <ProjectConfiguration Include="Debug|Win32">
23 <Configuration>Debug</Configuration>
24 <Platform>Win32</Platform>
25 </ProjectConfiguration>
26 <ProjectConfiguration Include="Release|Win32">
27 <Configuration>Release</Configuration>
28 <Platform>Win32</Platform>
29 </ProjectConfiguration>
30 </ItemGroup>
31
32 <PropertyGroup Label="Globals">
33 <ProjectGuid>{630C1EE7-2517-4A8C-83E3-DA1150308B58}</ProjectGuid>
34 <ConfigurationType>DynamicLibrary</ConfigurationType>
35 <TargetName>utilbe</TargetName>
36 <PlatformToolset>v142</PlatformToolset>
37 <CharacterSet>Unicode</CharacterSet>
38 <ProjectModuleDefinitionFile>utilbe.def</ProjectModuleDefinitionFile>
39 <Description>WiX Toolset Util BundleExtension</Description>
40 </PropertyGroup>
41
42 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
43 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
44
45 <PropertyGroup>
46 <ProjectAdditionalLinkLibraries>msi.lib</ProjectAdditionalLinkLibraries>
47 </PropertyGroup>
48
49 <ItemGroup>
50 <ClCompile Include="detectsha2support.cpp" />
51 <ClCompile Include="precomp.cpp">
52 <PrecompiledHeader>Create</PrecompiledHeader>
53 </ClCompile>
54 <ClCompile Include="utilbe.cpp" />
55 <ClCompile Include="UtilBundleExtension.cpp" />
56 <ClCompile Include="utilsearch.cpp" />
57 </ItemGroup>
58
59 <ItemGroup>
60 <ClInclude Include="beDecor.h" />
61 <ClInclude Include="detectsha2support.h" />
62 <ClInclude Include="precomp.h" />
63 <ClInclude Include="UtilBundleExtension.h" />
64 <ClInclude Include="utilsearch.h" />
65 </ItemGroup>
66
67 <ItemGroup>
68 <None Include="utilbe.def" />
69 </ItemGroup>
70
71 <ItemGroup>
72 <PackageReference Include="WixToolset.BextUtil" Version="4.0.58" />
73 <PackageReference Include="WixToolset.BootstrapperCore.Native" Version="4.0.141" />
74 <PackageReference Include="WixToolset.DUtil" Version="4.0.72" />
75 <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" />
76 <PackageReference Include="Nerdbank.GitVersioning" Version="3.3.37" />
77 </ItemGroup>
78
79 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
80</Project>
diff --git a/src/ext/Util/be/utilsearch.cpp b/src/ext/Util/be/utilsearch.cpp
new file mode 100644
index 00000000..7cd2ea09
--- /dev/null
+++ b/src/ext/Util/be/utilsearch.cpp
@@ -0,0 +1,160 @@
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
6STDMETHODIMP 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 LPWSTR scz = NULL;
17
18 // Select Util search nodes.
19 hr = XmlSelectNodes(pixnBundleExtension, L"WixWindowsFeatureSearch", &pixnNodes);
20 ExitOnFailure(hr, "Failed to select Util search nodes.");
21
22 // Get Util search node count.
23 hr = pixnNodes->get_length((long*)&cNodes);
24 ExitOnFailure(hr, "Failed to get Util search node count.");
25
26 if (!cNodes)
27 {
28 ExitFunction();
29 }
30
31 // Allocate memory for searches.
32 pSearches->rgSearches = (UTIL_SEARCH*)MemAlloc(sizeof(UTIL_SEARCH) * cNodes, TRUE);
33 ExitOnNull(pSearches->rgSearches, hr, E_OUTOFMEMORY, "Failed to allocate memory for search structs.");
34
35 pSearches->cSearches = cNodes;
36
37 // Parse search elements.
38 for (DWORD i = 0; i < cNodes; ++i)
39 {
40 UTIL_SEARCH* pSearch = &pSearches->rgSearches[i];
41
42 hr = XmlNextElement(pixnNodes, &pixnNode, &bstrNodeName);
43 ExitOnFailure(hr, "Failed to get next node.");
44
45 // @Id
46 hr = XmlGetAttributeEx(pixnNode, L"Id", &pSearch->sczId);
47 ExitOnFailure(hr, "Failed to get @Id.");
48
49 // Read type specific attributes.
50 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrNodeName, -1, L"WixWindowsFeatureSearch", -1))
51 {
52 pSearch->Type = UTIL_SEARCH_TYPE_WINDOWS_FEATURE_SEARCH;
53
54 // @Type
55 hr = XmlGetAttributeEx(pixnNode, L"Type", &scz);
56 ExitOnFailure(hr, "Failed to get @Type.");
57
58 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"sha2CodeSigning", -1))
59 {
60 pSearch->WindowsFeatureSearch.type = UTIL_WINDOWS_FEATURE_SEARCH_TYPE_SHA2_CODE_SIGNING;
61 }
62 else
63 {
64 hr = E_INVALIDARG;
65 ExitOnFailure(hr, "Invalid value for @Type: %ls", scz);
66 }
67 }
68 else
69 {
70 hr = E_UNEXPECTED;
71 ExitOnFailure(hr, "Unexpected element name: %ls", bstrNodeName);
72 }
73
74 // prepare next iteration
75 ReleaseNullObject(pixnNode);
76 ReleaseNullBSTR(bstrNodeName);
77 }
78
79LExit:
80 ReleaseStr(scz);
81 ReleaseBSTR(bstrNodeName);
82 ReleaseObject(pixnNode);
83 ReleaseObject(pixnNodes);
84
85 return hr;
86}
87
88void UtilSearchUninitialize(
89 __in UTIL_SEARCHES* pSearches
90 )
91{
92 if (pSearches->rgSearches)
93 {
94 for (DWORD i = 0; i < pSearches->cSearches; ++i)
95 {
96 UTIL_SEARCH* pSearch = &pSearches->rgSearches[i];
97
98 ReleaseStr(pSearch->sczId);
99 }
100 MemFree(pSearches->rgSearches);
101 }
102}
103
104STDMETHODIMP UtilSearchExecute(
105 __in UTIL_SEARCHES* pSearches,
106 __in LPCWSTR wzSearchId,
107 __in LPCWSTR wzVariable,
108 __in IBundleExtensionEngine* pEngine
109 )
110{
111 HRESULT hr = S_OK;
112 UTIL_SEARCH* pSearch = NULL;
113
114 hr = UtilSearchFindById(pSearches, wzSearchId, &pSearch);
115 ExitOnFailure(hr, "Search id '%ls' is unknown to the util extension.");
116
117 switch (pSearch->Type)
118 {
119 case UTIL_SEARCH_TYPE_WINDOWS_FEATURE_SEARCH:
120 switch (pSearch->WindowsFeatureSearch.type)
121 {
122 case UTIL_WINDOWS_FEATURE_SEARCH_TYPE_SHA2_CODE_SIGNING:
123 hr = UtilPerformDetectSHA2CodeSigning(wzVariable, pSearch, pEngine);
124 break;
125 default:
126 hr = E_UNEXPECTED;
127 }
128 break;
129 default:
130 hr = E_UNEXPECTED;
131 }
132
133LExit:
134 return hr;
135}
136
137STDMETHODIMP UtilSearchFindById(
138 __in UTIL_SEARCHES* pSearches,
139 __in LPCWSTR wzId,
140 __out UTIL_SEARCH** ppSearch
141 )
142{
143 HRESULT hr = S_OK;
144
145 for (DWORD i = 0; i < pSearches->cSearches; ++i)
146 {
147 UTIL_SEARCH* pSearch = &pSearches->rgSearches[i];
148
149 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pSearch->sczId, -1, wzId, -1))
150 {
151 *ppSearch = pSearch;
152 ExitFunction1(hr = S_OK);
153 }
154 }
155
156 hr = E_NOTFOUND;
157
158LExit:
159 return hr;
160}
diff --git a/src/ext/Util/be/utilsearch.h b/src/ext/Util/be/utilsearch.h
new file mode 100644
index 00000000..deeab1f7
--- /dev/null
+++ b/src/ext/Util/be/utilsearch.h
@@ -0,0 +1,65 @@
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
7enum UTIL_SEARCH_TYPE
8{
9 UTIL_SEARCH_TYPE_NONE,
10 UTIL_SEARCH_TYPE_WINDOWS_FEATURE_SEARCH,
11};
12
13enum UTIL_WINDOWS_FEATURE_SEARCH_TYPE
14{
15 UTIL_WINDOWS_FEATURE_SEARCH_TYPE_NONE,
16 UTIL_WINDOWS_FEATURE_SEARCH_TYPE_SHA2_CODE_SIGNING,
17};
18
19
20// structs
21
22typedef struct _UTIL_SEARCH
23{
24 LPWSTR sczId;
25
26 UTIL_SEARCH_TYPE Type;
27 union
28 {
29 struct
30 {
31 UTIL_WINDOWS_FEATURE_SEARCH_TYPE type;
32 } WindowsFeatureSearch;
33 };
34} UTIL_SEARCH;
35
36typedef struct _UTIL_SEARCHES
37{
38 UTIL_SEARCH* rgSearches;
39 DWORD cSearches;
40} UTIL_SEARCHES;
41
42
43// function declarations
44
45STDMETHODIMP UtilSearchParseFromXml(
46 __in UTIL_SEARCHES* pSearches,
47 __in IXMLDOMNode* pixnBundleExtension
48 );
49
50void UtilSearchUninitialize(
51 __in UTIL_SEARCHES* pSearches
52 );
53
54STDMETHODIMP UtilSearchExecute(
55 __in UTIL_SEARCHES* pSearches,
56 __in LPCWSTR wzSearchId,
57 __in LPCWSTR wzVariable,
58 __in IBundleExtensionEngine* pEngine
59 );
60
61STDMETHODIMP UtilSearchFindById(
62 __in UTIL_SEARCHES* pSearches,
63 __in LPCWSTR wzId,
64 __out UTIL_SEARCH** ppSearch
65 );
diff --git a/src/ext/Util/ca/BroadcastSettingChange.cpp b/src/ext/Util/ca/BroadcastSettingChange.cpp
new file mode 100644
index 00000000..2e153ad3
--- /dev/null
+++ b/src/ext/Util/ca/BroadcastSettingChange.cpp
@@ -0,0 +1,45 @@
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/********************************************************************
7WixBroadcastSettingChange
8
9 Send WM_SETTINGCHANGE message to all top-level windows indicating
10 that unspecified settings have changed.
11********************************************************************/
12extern "C" UINT __stdcall WixBroadcastSettingChange(
13 __in MSIHANDLE hInstall
14 )
15{
16 HRESULT hr = WcaInitialize(hInstall, "WixBroadcastSettingChange");
17 ExitOnFailure(hr, "failed to initialize WixBroadcastSettingChange");
18
19 // best effort; ignore failures
20 ::SendMessageTimeoutW(HWND_BROADCAST, WM_SETTINGCHANGE, NULL, NULL, SMTO_ABORTIFHUNG, 1000, NULL);
21
22LExit:
23 return WcaFinalize(ERROR_SUCCESS);
24}
25
26
27/********************************************************************
28WixBroadcastEnvironmentChange
29
30 Send WM_SETTINGCHANGE message to all top-level windows indicating
31 that environment variables have changed.
32********************************************************************/
33extern "C" UINT __stdcall WixBroadcastEnvironmentChange(
34 __in MSIHANDLE hInstall
35 )
36{
37 HRESULT hr = WcaInitialize(hInstall, "WixBroadcastEnvironmentChange");
38 ExitOnFailure(hr, "failed to initialize WixBroadcastEnvironmentChange");
39
40 // best effort; ignore failures
41 ::SendMessageTimeoutW(HWND_BROADCAST, WM_SETTINGCHANGE, NULL, reinterpret_cast<LPARAM>(L"Environment"), SMTO_ABORTIFHUNG, 1000, NULL);
42
43LExit:
44 return WcaFinalize(ERROR_SUCCESS);
45}
diff --git a/src/ext/Util/ca/CheckReboot.cpp b/src/ext/Util/ca/CheckReboot.cpp
new file mode 100644
index 00000000..ce056411
--- /dev/null
+++ b/src/ext/Util/ca/CheckReboot.cpp
@@ -0,0 +1,36 @@
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/********************************************************************
7WixCheckRebootRequired - entry point for WixCheckRebootRequired Custom Action
8
9 called as Type 1 CustomAction (binary DLL) from Windows Installer
10 in InstallExecuteSequence after InstallFinalize
11********************************************************************/
12extern "C" UINT __stdcall WixCheckRebootRequired(
13 __in MSIHANDLE hInstall
14 )
15{
16 HRESULT hr = S_OK;
17 DWORD er = ERROR_SUCCESS;
18
19 hr = WcaInitialize(hInstall, "WixCheckRebootRequired");
20 ExitOnFailure(hr, "failed to initialize");
21
22 if (WcaDidDeferredActionRequireReboot())
23 {
24 WcaLog(LOGMSG_STANDARD, "Reboot required by deferred CustomAction.");
25
26 er = ::MsiSetMode(hInstall, MSIRUNMODE_REBOOTATEND, TRUE);
27 hr = HRESULT_FROM_WIN32(er);
28 ExitOnFailure(hr, "Failed to schedule reboot.");
29 }
30
31LExit:
32
33 if (FAILED(hr))
34 er = ERROR_INSTALL_FAILURE;
35 return WcaFinalize(er);
36}
diff --git a/src/ext/Util/ca/CloseApps.cpp b/src/ext/Util/ca/CloseApps.cpp
new file mode 100644
index 00000000..d4256c43
--- /dev/null
+++ b/src/ext/Util/ca/CloseApps.cpp
@@ -0,0 +1,568 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5#define DEFAULT_PROCESS_EXIT_WAIT_TIME 5000
6
7// structs
8LPCWSTR wzQUERY_CLOSEAPPS = L"SELECT `Wix4CloseApplication`, `Target`, `Description`, `Condition`, `Attributes`, `Property`, `TerminateExitCode`, `Timeout` FROM `Wix4CloseApplication` ORDER BY `Sequence`";
9enum eQUERY_CLOSEAPPS { QCA_ID = 1, QCA_TARGET, QCA_DESCRIPTION, QCA_CONDITION, QCA_ATTRIBUTES, QCA_PROPERTY, QCA_TERMINATEEXITCODE, QCA_TIMEOUT };
10
11// CloseApplication.Attributes
12enum CLOSEAPP_ATTRIBUTES
13{
14 CLOSEAPP_ATTRIBUTE_NONE = 0x0,
15 CLOSEAPP_ATTRIBUTE_CLOSEMESSAGE = 0x1,
16 CLOSEAPP_ATTRIBUTE_REBOOTPROMPT = 0x2,
17 CLOSEAPP_ATTRIBUTE_ELEVATEDCLOSEMESSAGE = 0x4,
18 CLOSEAPP_ATTRIBUTE_ENDSESSIONMESSAGE = 0x8,
19 CLOSEAPP_ATTRIBUTE_ELEVATEDENDSESSIONMESSAGE = 0x10,
20 CLOSEAPP_ATTRIBUTE_TERMINATEPROCESS = 0x20,
21 CLOSEAPP_ATTRIBUTE_PROMPTTOCONTINUE = 0x40,
22};
23
24struct PROCESS_AND_MESSAGE
25{
26 DWORD dwProcessId;
27 DWORD dwMessageId;
28 DWORD dwTimeout;
29};
30
31
32/******************************************************************
33 EnumWindowsProc - callback function which sends message if the
34 current window matches the passed in process ID
35
36******************************************************************/
37BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
38{
39 PROCESS_AND_MESSAGE* pPM = reinterpret_cast<PROCESS_AND_MESSAGE*>(lParam);
40 DWORD dwProcessId = 0;
41 DWORD_PTR dwResult = 0;
42 BOOL fQueryEndSession = WM_QUERYENDSESSION == pPM->dwMessageId;
43 BOOL fContinueWindowsInProcess = TRUE; // assume we will send message to all top-level windows in a process.
44
45 ::GetWindowThreadProcessId(hwnd, &dwProcessId);
46
47 // check if the process Id is the one we're looking for
48 if (dwProcessId != pPM->dwProcessId)
49 {
50 return TRUE;
51 }
52
53 WcaLog(LOGMSG_VERBOSE, "Sending message to process id 0x%x", dwProcessId);
54
55 if (::SendMessageTimeoutW(hwnd, pPM->dwMessageId, 0, fQueryEndSession ? ENDSESSION_CLOSEAPP : 0, SMTO_BLOCK, pPM->dwTimeout, &dwResult))
56 {
57 WcaLog(LOGMSG_VERBOSE, "Result 0x%x", dwResult);
58
59 if (fQueryEndSession)
60 {
61 // If application said it was okay to close, do that.
62 if (dwResult)
63 {
64 ::SendMessageTimeoutW(hwnd, WM_ENDSESSION, TRUE, ENDSESSION_CLOSEAPP, SMTO_BLOCK, pPM->dwTimeout, &dwResult);
65 }
66 else // application said don't try to close it, so don't bother sending messages to any other top-level windows.
67 {
68 fContinueWindowsInProcess = FALSE;
69 }
70 }
71 }
72 else // log result message.
73 {
74 WcaLog(LOGMSG_VERBOSE, "Failed to send message id: %u, error: 0x%x", pPM->dwMessageId, ::GetLastError());
75 }
76
77 // so we know we succeeded
78 ::SetLastError(ERROR_SUCCESS);
79
80 return fContinueWindowsInProcess;
81}
82
83/******************************************************************
84 PromptToContinue - displays the prompt if the application is still
85 running.
86
87******************************************************************/
88static HRESULT PromptToContinue(
89 __in_z LPCWSTR wzApplication,
90 __in_z LPCWSTR wzPrompt
91 )
92{
93 HRESULT hr = S_OK;
94 UINT er = ERROR_SUCCESS;
95 PMSIHANDLE hRecMessage = NULL;
96 DWORD *prgProcessIds = NULL;
97 DWORD cProcessIds = 0;
98
99 hRecMessage = ::MsiCreateRecord(1);
100 ExitOnNull(hRecMessage, hr, E_OUTOFMEMORY, "Failed to create record for prompt.");
101
102 er = ::MsiRecordSetStringW(hRecMessage, 0, wzPrompt);
103 ExitOnWin32Error(er, hr, "Failed to set prompt record field string");
104
105 do
106 {
107 hr = ProcFindAllIdsFromExeName(wzApplication, &prgProcessIds, &cProcessIds);
108 if (SUCCEEDED(hr) && 0 < cProcessIds)
109 {
110 er = WcaProcessMessage(static_cast<INSTALLMESSAGE>(INSTALLMESSAGE_WARNING | MB_ABORTRETRYIGNORE | MB_DEFBUTTON3 | MB_ICONWARNING), hRecMessage);
111 if (IDABORT == er)
112 {
113 hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT);
114 }
115 else if (IDRETRY == er)
116 {
117 hr = S_FALSE;
118 }
119 else if (IDIGNORE == er)
120 {
121 hr = S_OK;
122 }
123 else
124 {
125 ExitOnWin32Error(er, hr, "Unexpected return value from prompt to continue.");
126 }
127 }
128
129 ReleaseNullMem(prgProcessIds);
130 cProcessIds = 0;
131 } while (S_FALSE == hr);
132
133LExit:
134 ReleaseMem(prgProcessIds);
135 return hr;
136}
137
138/******************************************************************
139 SendProcessMessage - helper function to enumerate the top-level
140 windows and send to all matching a process ID.
141
142******************************************************************/
143void SendProcessMessage(
144 __in DWORD dwProcessId,
145 __in DWORD dwMessageId,
146 __in DWORD dwTimeout
147 )
148{
149 WcaLog(LOGMSG_VERBOSE, "Attempting to send process id 0x%x message id: %u", dwProcessId, dwMessageId);
150
151 PROCESS_AND_MESSAGE pm = { };
152 pm.dwProcessId = dwProcessId;
153 pm.dwMessageId = dwMessageId;
154 pm.dwTimeout = dwTimeout;
155
156 if (!::EnumWindows(EnumWindowsProc, reinterpret_cast<LPARAM>(&pm)))
157 {
158 DWORD dwLastError = ::GetLastError();
159 if (ERROR_SUCCESS != dwLastError)
160 {
161 WcaLog(LOGMSG_VERBOSE, "CloseApp enumeration error: 0x%x", dwLastError);
162 }
163 }
164}
165
166/******************************************************************
167 SendApplicationMessage - helper function to iterate through the
168 processes for the specified application and send all
169 applicable process Ids a message and give them time to process
170 the message.
171
172******************************************************************/
173void SendApplicationMessage(
174 __in LPCWSTR wzApplication,
175 __in DWORD dwMessageId,
176 __in DWORD dwTimeout
177 )
178{
179 DWORD *prgProcessIds = NULL;
180 DWORD cProcessIds = 0, iProcessId;
181 HRESULT hr = S_OK;
182
183 WcaLog(LOGMSG_VERBOSE, "Checking App: %ls ", wzApplication);
184
185 hr = ProcFindAllIdsFromExeName(wzApplication, &prgProcessIds, &cProcessIds);
186
187 if (SUCCEEDED(hr) && 0 < cProcessIds)
188 {
189 WcaLog(LOGMSG_VERBOSE, "App: %ls found running, %d processes, attempting to send message.", wzApplication, cProcessIds);
190
191 for (iProcessId = 0; iProcessId < cProcessIds; ++iProcessId)
192 {
193 SendProcessMessage(prgProcessIds[iProcessId], dwMessageId, dwTimeout);
194 }
195
196 ProcWaitForIds(prgProcessIds, cProcessIds, dwTimeout);
197 }
198
199 ReleaseMem(prgProcessIds);
200}
201
202/******************************************************************
203 SetRunningProcessProperty - helper function that sets the specified
204 property if there are any instances of the specified executable
205 running. Useful to show custom UI to ask for shutdown.
206******************************************************************/
207void SetRunningProcessProperty(
208 __in LPCWSTR wzApplication,
209 __in LPCWSTR wzProperty
210 )
211{
212 DWORD *prgProcessIds = NULL;
213 DWORD cProcessIds = 0;
214 HRESULT hr = S_OK;
215
216 WcaLog(LOGMSG_VERBOSE, "Checking App: %ls ", wzApplication);
217
218 hr = ProcFindAllIdsFromExeName(wzApplication, &prgProcessIds, &cProcessIds);
219
220 if (SUCCEEDED(hr) && 0 < cProcessIds)
221 {
222 WcaLog(LOGMSG_VERBOSE, "App: %ls found running, %d processes, setting '%ls' property.", wzApplication, cProcessIds, wzProperty);
223 WcaSetIntProperty(wzProperty, cProcessIds);
224 }
225
226 ReleaseMem(prgProcessIds);
227}
228
229/******************************************************************
230 TerminateProcesses - helper function that kills the provided set of
231 process ids such that they return a particular exit code.
232******************************************************************/
233void TerminateProcesses(
234 __in_ecount(cProcessIds) DWORD rgdwProcessIds[],
235 __in DWORD cProcessIds,
236 __in DWORD dwExitCode
237 )
238{
239 for (DWORD i = 0; i < cProcessIds; ++i)
240 {
241 HANDLE hProcess = ::OpenProcess(PROCESS_TERMINATE, FALSE, rgdwProcessIds[i]);
242 if (hProcess)
243 {
244 ::TerminateProcess(hProcess, dwExitCode);
245 ::CloseHandle(hProcess);
246 }
247 }
248}
249
250/******************************************************************
251 WixCloseApplications - entry point for WixCloseApplications Custom Action
252
253 called as Type 1 CustomAction (binary DLL) from Windows Installer
254 in InstallExecuteSequence before InstallFiles
255******************************************************************/
256extern "C" UINT __stdcall WixCloseApplications(
257 __in MSIHANDLE hInstall
258 )
259{
260 //AssertSz(FALSE, "debug WixCloseApplications");
261 HRESULT hr = S_OK;
262 UINT er = ERROR_SUCCESS;
263
264 LPWSTR pwzData = NULL;
265 LPWSTR pwzId = NULL;
266 LPWSTR pwzTarget = NULL;
267 LPWSTR pwzDescription = NULL;
268 LPWSTR pwzCondition = NULL;
269 LPWSTR pwzProperty = NULL;
270 DWORD dwAttributes = 0;
271 DWORD dwTimeout = 0;
272 DWORD dwTerminateExitCode = 0;
273 MSICONDITION condition = MSICONDITION_NONE;
274
275 DWORD cCloseApps = 0;
276
277 PMSIHANDLE hView = NULL;
278 PMSIHANDLE hRec = NULL;
279 MSIHANDLE hListboxTable = NULL;
280 MSIHANDLE hListboxColumns = NULL;
281
282 LPWSTR pwzCustomActionData = NULL;
283 //DWORD cchCustomActionData = 0;
284
285 //
286 // initialize
287 //
288 hr = WcaInitialize(hInstall, "WixCloseApplications");
289 ExitOnFailure(hr, "failed to initialize");
290
291 //
292 // loop through all the objects to be secured
293 //
294 hr = WcaOpenExecuteView(wzQUERY_CLOSEAPPS, &hView);
295 ExitOnFailure(hr, "failed to open view on Wix4CloseApplication table");
296 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
297 {
298 hr = WcaGetRecordString(hRec, QCA_ID, &pwzId);
299 ExitOnFailure(hr, "failed to get id from Wix4CloseApplication table");
300
301 hr = WcaGetRecordString(hRec, QCA_CONDITION, &pwzCondition);
302 ExitOnFailure(hr, "failed to get condition from Wix4CloseApplication table");
303
304 if (pwzCondition && *pwzCondition)
305 {
306 condition = ::MsiEvaluateConditionW(hInstall, pwzCondition);
307 if (MSICONDITION_ERROR == condition)
308 {
309 hr = E_INVALIDARG;
310 ExitOnFailure(hr, "failed to process condition for Wix4CloseApplication '%ls'", pwzId);
311 }
312 else if (MSICONDITION_FALSE == condition)
313 {
314 continue; // skip processing this target
315 }
316 }
317
318 hr = WcaGetRecordFormattedString(hRec, QCA_TARGET, &pwzTarget);
319 ExitOnFailure(hr, "failed to get target from Wix4CloseApplication table");
320
321 hr = WcaGetRecordFormattedString(hRec, QCA_DESCRIPTION, &pwzDescription);
322 ExitOnFailure(hr, "failed to get description from Wix4CloseApplication table");
323
324 hr = WcaGetRecordInteger(hRec, QCA_ATTRIBUTES, reinterpret_cast<int*>(&dwAttributes));
325 ExitOnFailure(hr, "failed to get attributes from Wix4CloseApplication table");
326
327 hr = WcaGetRecordFormattedString(hRec, QCA_PROPERTY, &pwzProperty);
328 ExitOnFailure(hr, "failed to get property from Wix4CloseApplication table");
329
330 hr = WcaGetRecordInteger(hRec, QCA_TERMINATEEXITCODE, reinterpret_cast<int*>(&dwTerminateExitCode));
331 if (S_FALSE == hr)
332 {
333 dwTerminateExitCode = 0;
334 hr = S_OK;
335 }
336 ExitOnFailure(hr, "failed to get terminate exit-code from Wix4CloseApplication table");
337
338 hr = WcaGetRecordInteger(hRec, QCA_TIMEOUT, reinterpret_cast<int*>(&dwTimeout));
339 if (S_FALSE == hr)
340 {
341 dwTimeout = DEFAULT_PROCESS_EXIT_WAIT_TIME;
342 hr = S_OK;
343 }
344 ExitOnFailure(hr, "failed to get timeout from Wix4CloseApplication table");
345
346 // Before trying any changes to the machine, prompt if requested.
347 if (dwAttributes & CLOSEAPP_ATTRIBUTE_PROMPTTOCONTINUE)
348 {
349 hr = PromptToContinue(pwzTarget, pwzDescription ? pwzDescription : L"");
350 if (HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT) == hr)
351 {
352 // Skip error message if user canceled.
353 ExitFunction();
354 }
355 ExitOnFailure(hr, "Failure while prompting user to continue to close application.");
356 }
357
358 //
359 // send WM_CLOSE or WM_QUERYENDSESSION to currently running applications
360 //
361 if (dwAttributes & CLOSEAPP_ATTRIBUTE_CLOSEMESSAGE)
362 {
363 SendApplicationMessage(pwzTarget, WM_CLOSE, dwTimeout);
364 }
365
366 if (dwAttributes & CLOSEAPP_ATTRIBUTE_ENDSESSIONMESSAGE)
367 {
368 SendApplicationMessage(pwzTarget, WM_QUERYENDSESSION, dwTimeout);
369 }
370
371 //
372 // Pass the targets to the deferred action in case the app comes back
373 // even if we close it now.
374 //
375 if (dwAttributes & (CLOSEAPP_ATTRIBUTE_ELEVATEDCLOSEMESSAGE | CLOSEAPP_ATTRIBUTE_ELEVATEDENDSESSIONMESSAGE | CLOSEAPP_ATTRIBUTE_REBOOTPROMPT | CLOSEAPP_ATTRIBUTE_TERMINATEPROCESS))
376 {
377 hr = WcaWriteStringToCaData(pwzTarget, &pwzCustomActionData);
378 ExitOnFailure(hr, "failed to add target data to CustomActionData");
379
380 hr = WcaWriteIntegerToCaData(dwAttributes, &pwzCustomActionData);
381 ExitOnFailure(hr, "failed to add attribute data to CustomActionData");
382
383 hr = WcaWriteIntegerToCaData(dwTimeout, &pwzCustomActionData);
384 ExitOnFailure(hr, "failed to add timeout data to CustomActionData");
385
386 hr = WcaWriteIntegerToCaData(dwTerminateExitCode, &pwzCustomActionData);
387 ExitOnFailure(hr, "failed to add timeout data to CustomActionData");
388 }
389
390 if (pwzProperty && *pwzProperty)
391 {
392 SetRunningProcessProperty(pwzTarget, pwzProperty);
393 }
394
395 ++cCloseApps;
396 }
397
398 // if we looped through all records all is well
399 if (E_NOMOREITEMS == hr)
400 {
401 hr = S_OK;
402 }
403 ExitOnFailure(hr, "failed while looping through all apps to close");
404
405 //
406 // Do the UI dance now.
407 //
408 /*
409
410 TODO: Do this eventually
411
412 if (cCloseApps)
413 {
414 while (TRUE)
415 {
416 for (DWORD i = 0; i < cCloseApps; ++i)
417 {
418 hr = WcaAddTempRecord(&hListboxTable, &hListboxColumns, L"ListBox", NULL, 0, 4, L"FileInUseProcess", i, target, description);
419 if (FAILED(hr))
420 {
421 }
422 }
423 }
424 }
425 */
426
427 //
428 // schedule the custom action and add to progress bar
429 //
430 if (pwzCustomActionData && *pwzCustomActionData)
431 {
432 Assert(0 < cCloseApps);
433
434 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"CloseApplicationsDeferred"), pwzCustomActionData, cCloseApps * COST_CLOSEAPP);
435 ExitOnFailure(hr, "failed to schedule CloseApplicationsDeferred action");
436 }
437
438LExit:
439 if (hListboxColumns)
440 {
441 ::MsiCloseHandle(hListboxColumns);
442 }
443 if (hListboxTable)
444 {
445 ::MsiCloseHandle(hListboxTable);
446 }
447
448 ReleaseStr(pwzCustomActionData);
449 ReleaseStr(pwzData);
450 ReleaseStr(pwzProperty);
451 ReleaseStr(pwzCondition);
452 ReleaseStr(pwzDescription);
453 ReleaseStr(pwzTarget);
454 ReleaseStr(pwzId);
455
456 if (FAILED(hr))
457 {
458 er = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT) == hr ? ERROR_INSTALL_USEREXIT : ERROR_INSTALL_FAILURE;
459 }
460 return WcaFinalize(er);
461}
462
463
464/******************************************************************
465 WixCloseApplicationsDeferred - entry point for
466 WixCloseApplicationsDeferred Custom Action
467 called as Type 1025 CustomAction
468 (deferred binary DLL)
469
470 NOTE: deferred CustomAction since it modifies the machine
471 NOTE: CustomActionData == wzTarget\tdwAttributes\tdwTimeout\tdwTerminateExitCode\t...
472******************************************************************/
473extern "C" UINT __stdcall WixCloseApplicationsDeferred(
474 __in MSIHANDLE hInstall
475 )
476{
477 //AssertSz(FALSE, "debug WixCloseApplicationsDeferred");
478 HRESULT hr = S_OK;
479 DWORD er = ERROR_SUCCESS;
480
481 LPWSTR pwz = NULL;
482 LPWSTR pwzData = NULL;
483 LPWSTR pwzTarget = NULL;
484 DWORD dwAttributes = 0;
485 DWORD dwTimeout = 0;
486 DWORD dwTerminateExitCode = 0;
487
488 DWORD *prgProcessIds = NULL;
489 DWORD cProcessIds = 0;
490
491 //
492 // initialize
493 //
494 hr = WcaInitialize(hInstall, "WixCloseApplicationsDeferred");
495 ExitOnFailure(hr, "failed to initialize");
496
497 hr = WcaGetProperty(L"CustomActionData", &pwzData);
498 ExitOnFailure(hr, "failed to get CustomActionData");
499
500 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData);
501
502 pwz = pwzData;
503
504 //
505 // loop through all the passed in data
506 //
507 while (pwz && *pwz)
508 {
509 hr = WcaReadStringFromCaData(&pwz, &pwzTarget);
510 ExitOnFailure(hr, "failed to process target from CustomActionData");
511
512 hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&dwAttributes));
513 ExitOnFailure(hr, "failed to process attributes from CustomActionData");
514
515 hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&dwTimeout));
516 ExitOnFailure(hr, "failed to process timeout from CustomActionData");
517
518 hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&dwTerminateExitCode));
519 ExitOnFailure(hr, "failed to process terminate exit code from CustomActionData");
520
521 WcaLog(LOGMSG_VERBOSE, "Checking for App: %ls Attributes: %d", pwzTarget, dwAttributes);
522
523 //
524 // send WM_CLOSE or WM_QUERYENDSESSION to currently running applications
525 //
526 if (dwAttributes & CLOSEAPP_ATTRIBUTE_ELEVATEDCLOSEMESSAGE)
527 {
528 SendApplicationMessage(pwzTarget, WM_CLOSE, dwTimeout);
529 }
530
531 if (dwAttributes & CLOSEAPP_ATTRIBUTE_ELEVATEDENDSESSIONMESSAGE)
532 {
533 SendApplicationMessage(pwzTarget, WM_QUERYENDSESSION, dwTimeout);
534 }
535
536 // If we find that an app that we need closed is still runing, require a
537 // restart or kill the process as directed.
538 ProcFindAllIdsFromExeName(pwzTarget, &prgProcessIds, &cProcessIds);
539 if (0 < cProcessIds)
540 {
541 if (dwAttributes & CLOSEAPP_ATTRIBUTE_REBOOTPROMPT)
542 {
543 WcaLog(LOGMSG_VERBOSE, "App: %ls found running, requiring a reboot.", pwzTarget);
544
545 WcaDeferredActionRequiresReboot();
546 }
547 else if (dwAttributes & CLOSEAPP_ATTRIBUTE_TERMINATEPROCESS)
548 {
549 TerminateProcesses(prgProcessIds, cProcessIds, dwTerminateExitCode);
550 }
551 }
552
553 hr = WcaProgressMessage(COST_CLOSEAPP, FALSE);
554 ExitOnFailure(hr, "failed to send progress message");
555 }
556
557LExit:
558 ReleaseMem(prgProcessIds);
559
560 ReleaseStr(pwzTarget);
561 ReleaseStr(pwzData);
562
563 if (FAILED(hr))
564 {
565 er = ERROR_INSTALL_FAILURE;
566 }
567 return WcaFinalize(er);
568}
diff --git a/src/ext/Util/ca/CustomMsiErrors.h b/src/ext/Util/ca/CustomMsiErrors.h
new file mode 100644
index 00000000..3218b61b
--- /dev/null
+++ b/src/ext/Util/ca/CustomMsiErrors.h
@@ -0,0 +1,32 @@
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#define msierrSecureObjectsFailedCreateSD 25520
6#define msierrSecureObjectsFailedSet 25521
7#define msierrSecureObjectsUnknownType 25522
8
9#define msierrXmlFileFailedRead 25530
10#define msierrXmlFileFailedOpen 25531
11#define msierrXmlFileFailedSelect 25532
12#define msierrXmlFileFailedSave 25533
13
14#define msierrXmlConfigFailedRead 25540
15#define msierrXmlConfigFailedOpen 25541
16#define msierrXmlConfigFailedSelect 25542
17#define msierrXmlConfigFailedSave 25543
18
19#define msierrPERFMONFailedRegisterDLL 26251
20#define msierrPERFMONFailedUnregisterDLL 26252
21#define msierrInstallPerfCounterData 26253
22#define msierrUninstallPerfCounterData 26254
23
24#define msierrSMBFailedCreate 26301
25#define msierrSMBFailedDrop 26302
26#define msierrUSRFailedUserCreate 26401
27#define msierrUSRFailedUserCreatePswd 26402
28#define msierrUSRFailedUserGroupAdd 26403
29#define msierrUSRFailedUserCreateExists 26404
30#define msierrUSRFailedGrantLogonAsService 26405
31
32//Last available is 26450 \ No newline at end of file
diff --git a/src/ext/Util/ca/FormatFiles.cpp b/src/ext/Util/ca/FormatFiles.cpp
new file mode 100644
index 00000000..d1533999
--- /dev/null
+++ b/src/ext/Util/ca/FormatFiles.cpp
@@ -0,0 +1,221 @@
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
5const UINT COST_FILEFORMATTING = 2000;
6
7
8//
9// WixSchedFormatFiles - immediate CA to schedule format files CAs
10//
11extern "C" UINT __stdcall WixSchedFormatFiles(
12 __in MSIHANDLE hInstall
13 )
14{
15 HRESULT hr = S_OK;
16 UINT er = ERROR_SUCCESS;
17 PSCZ sczBinaryKey;
18 PSCZ sczFileKey;
19 PSCZ sczComponentKey;
20 PSCZ sczFormattedFile;
21 PSCZ sczFilePath;
22 PMSIHANDLE hView;
23 PMSIHANDLE hRec;
24 PSCZ sczFileContent;
25 PSCZ sczFormattedContent;
26 PSCZ sczExecCustomActionData;
27 PSCZ sczRollbackCustomActionData;
28
29 LPCWSTR wzQuery =
30 L"SELECT `Wix4FormatFile`.`Binary_`, `Wix4FormatFile`.`File_`, `File`.`Component_` "
31 L"FROM `Wix4FormatFile`, `File` "
32 L"WHERE `Wix4FormatFile`.`File_` = `File`.`File`";
33 enum eQuery { eqBinaryKey = 1, eqFileKey, eqComponentKey };
34
35 // initialize
36 hr = WcaInitialize(hInstall, "WixSchedFormatFiles");
37 ExitOnFailure(hr, "Failed to initialize for WixSchedFormatFiles.");
38
39 // query and loop through all the files
40 hr = WcaOpenExecuteView(wzQuery, &hView);
41 ExitOnFailure(hr, "Failed to open view on Wix4FormatFile table");
42
43 DWORD cFiles = 0;
44 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
45 {
46 ++cFiles;
47
48 hr = WcaGetRecordString(hRec, eqBinaryKey, &sczBinaryKey);
49 ExitOnFailure(hr, "Failed to get Binary table key.");
50
51 hr = WcaGetRecordString(hRec, eqFileKey, &sczFileKey);
52 ExitOnFailure(hr, "Failed to get File table key.");
53
54 hr = WcaGetRecordString(hRec, eqComponentKey, &sczComponentKey);
55 ExitOnFailure(hr, "Failed to get Component table key.");
56
57 // we need to know if the component's being installed, uninstalled, or reinstalled
58 WCA_TODO todo = WcaGetComponentToDo(sczComponentKey);
59 if (WCA_TODO_INSTALL == todo || WCA_TODO_REINSTALL == todo)
60 {
61 // turn the file key into the path to the target file
62 hr = StrAllocFormatted(&sczFormattedFile, L"[#%ls]", sczFileKey);
63 ExitOnFailure(hr, "Failed to format file string for file: %ls", sczFileKey);
64 hr = WcaGetFormattedString(sczFormattedFile, &sczFilePath);
65 ExitOnFailure(hr, "Failed to get path for file: %ls", sczFileKey);
66
67 // extract binary to string
68 WCA_ENCODING encoding = WCA_ENCODING_UNKNOWN;
69 hr = WcaExtractBinaryToString(sczBinaryKey, &sczFileContent, &encoding);
70 ExitOnFailure(hr, "Failed to extract binary: %ls", sczBinaryKey);
71
72 // format string
73 hr = WcaGetFormattedString(sczFileContent, &sczFormattedContent);
74 ExitOnFailure(hr, "Failed to format file content: %ls", sczFileContent);
75
76 // write to deferred custom action data
77 hr = WcaWriteStringToCaData(sczFilePath, &sczExecCustomActionData);
78 ExitOnFailure(hr, "Failed to write deferred custom action data for file: %ls", sczFilePath);
79
80 hr = WcaWriteIntegerToCaData(encoding, &sczExecCustomActionData);
81 ExitOnFailure(hr, "Failed to write deferred custom action data for encoding: %d", encoding);
82
83 hr = WcaWriteStringToCaData(sczFormattedContent, &sczExecCustomActionData);
84 ExitOnFailure(hr, "Failed to write deferred custom action data for file content: %ls", sczFilePath);
85
86 // write to rollback custom action data
87 hr = WcaWriteStringToCaData(sczFilePath, &sczRollbackCustomActionData);
88 ExitOnFailure(hr, "Failed to write rollback custom action data for file: %ls", sczFilePath);
89
90 hr = WcaWriteIntegerToCaData(encoding, &sczRollbackCustomActionData);
91 ExitOnFailure(hr, "Failed to write deferred custom action data for encoding: %d", encoding);
92
93 hr = WcaWriteStringToCaData(sczFileContent, &sczRollbackCustomActionData);
94 ExitOnFailure(hr, "Failed to write rollback custom action data for file content: %ls", sczFilePath);
95 }
96 }
97
98 // reaching the end of the list is actually a good thing, not an error
99 if (E_NOMOREITEMS == hr)
100 {
101 hr = S_OK;
102 }
103 ExitOnFailure(hr, "Failure occurred while processing Wix4FormatFile table");
104
105 // schedule deferred CAs if there's anything to do
106 if (sczRollbackCustomActionData && *sczRollbackCustomActionData)
107 {
108 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackFormatFiles"), sczRollbackCustomActionData, cFiles * COST_FILEFORMATTING);
109 ExitOnFailure(hr, "Failed to schedule RollbackFormatFiles");
110 }
111
112 if (sczExecCustomActionData && *sczExecCustomActionData)
113 {
114 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecFormatFiles"), sczExecCustomActionData, cFiles * COST_FILEFORMATTING);
115 ExitOnFailure(hr, "Failed to schedule ExecFormatFiles");
116 }
117
118LExit:
119 return WcaFinalize(er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er);
120}
121
122
123//
124// WixExecFormatFiles - deferred and rollback CAs to write formatted files
125//
126extern "C" UINT __stdcall WixExecFormatFiles(
127 __in MSIHANDLE hInstall
128 )
129{
130 HRESULT hr = S_OK;
131 UINT er = ERROR_SUCCESS;
132 PSCZ sczCustomActionData;
133 LPWSTR pwz = NULL;
134 PSCZ sczFilePath;
135 PSCZ sczFileContent;
136 LPSTR psz = NULL;
137
138 // initialize
139 hr = WcaInitialize(hInstall, "WixExecFormatFiles");
140 ExitOnFailure(hr, "Failed to initialize for WixExecFormatFiles.");
141
142 hr = WcaGetProperty(L"CustomActionData", &sczCustomActionData);
143 ExitOnFailure(hr, "Failed to get CustomActionData.");
144#ifdef _DEBUG
145 WcaLog(LOGMSG_STANDARD, "CustomActionData: %ls", sczCustomActionData);
146#endif
147
148 // loop through all the passed in data
149 pwz = sczCustomActionData;
150 while (pwz && *pwz)
151 {
152 // extract the custom action data
153 hr = WcaReadStringFromCaData(&pwz, &sczFilePath);
154 ExitOnFailure(hr, "Failed to read file path from custom action data");
155
156 WCA_ENCODING encoding = WCA_ENCODING_UNKNOWN;
157 hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&encoding));
158 ExitOnFailure(hr, "Failed to read encoding from custom action data");
159
160 hr = WcaReadStringFromCaData(&pwz, &sczFileContent);
161 ExitOnFailure(hr, "Failed to read file content from custom action data");
162
163 // re-encode content
164 LPCBYTE pbData = NULL;
165 size_t cbData = 0;
166 switch (encoding)
167 {
168 case WCA_ENCODING_UTF_16:
169 pbData = reinterpret_cast<LPCBYTE>(LPCWSTR(sczFileContent));
170 cbData = lstrlenW(sczFileContent) * sizeof(WCHAR);
171 break;
172
173 case WCA_ENCODING_UTF_8:
174 hr = StrAnsiAllocString(&psz, sczFileContent, 0, CP_UTF8);
175 ExitOnFailure(hr, "Failed to convert Unicode to UTF-8.");
176 pbData = reinterpret_cast<LPCBYTE>(psz);
177
178 hr = ::StringCbLengthA(psz, STRSAFE_MAX_CCH, &cbData);
179 ExitOnFailure(hr, "Failed to count UTF-8 bytes.");
180 break;
181
182 case WCA_ENCODING_ANSI:
183 hr = StrAnsiAllocString(&psz, sczFileContent, 0, CP_ACP);
184 ExitOnFailure(hr, "Failed to convert Unicode to ANSI.");
185 pbData = reinterpret_cast<LPCBYTE>(psz);
186
187 hr = ::StringCbLengthA(psz, STRSAFE_MAX_CCH, &cbData);
188 ExitOnFailure(hr, "Failed to count UTF-8 bytes.");
189 break;
190
191 default:
192 break;
193 }
194
195#ifdef _DEBUG
196 WcaLog(LOGMSG_STANDARD, "File: %ls", sczCustomActionData);
197 WcaLog(LOGMSG_STANDARD, "Content: %ls", sczFileContent);
198#endif
199
200 // write file and preserve modified time
201 FILETIME filetime;
202
203 hr = FileGetTime(sczFilePath, NULL, NULL, &filetime);
204 ExitOnFailure(hr, "Failed to get modified time of file : %ls", sczFilePath);
205
206 hr = FileWrite(sczFilePath, FILE_ATTRIBUTE_NORMAL, pbData, cbData, NULL);
207 ExitOnFailure(hr, "Failed to write file content: %ls", sczFilePath);
208
209 hr = FileSetTime(sczFilePath, NULL, NULL, &filetime);
210 ExitOnFailure(hr, "Failed to set modified time of file : %ls", sczFilePath);
211
212 // Tick the progress bar
213 hr = WcaProgressMessage(COST_FILEFORMATTING, FALSE);
214 ExitOnFailure(hr, "Failed to tick progress bar for file: %ls", sczFilePath);
215 }
216
217LExit:
218 ReleaseStr(psz);
219
220 return WcaFinalize(er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er);
221}
diff --git a/src/ext/Util/ca/OsInfo.cpp b/src/ext/Util/ca/OsInfo.cpp
new file mode 100644
index 00000000..4783673e
--- /dev/null
+++ b/src/ext/Util/ca/OsInfo.cpp
@@ -0,0 +1,487 @@
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// constants we'll pick up from later SDKs
6#define SM_TABLETPC 86
7#define SM_MEDIACENTER 87
8#define SM_STARTER 88
9#define SM_SERVERR2 89
10#define VER_SUITE_WH_SERVER 0x00008000
11
12/********************************************************************
13WixQueryOsInfo - entry point for WixQueryOsInfo custom action
14
15 Called as Type 1 custom action (DLL from the Binary table) from
16 Windows Installer to set properties that identify OS information
17 and predefined directories
18********************************************************************/
19extern "C" UINT __stdcall WixQueryOsInfo(
20 __in MSIHANDLE hInstall
21 )
22{
23 HRESULT hr = S_OK;
24 DWORD er = ERROR_SUCCESS;
25 OSVERSIONINFOEXW ovix = {0};
26
27 hr = WcaInitialize(hInstall, "WixQueryOsInfo");
28 ExitOnFailure(hr, "WixQueryOsInfo failed to initialize");
29
30 // identify product suites
31 ovix.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
32 #pragma warning(suppress: 4996) //TODO: use osutil
33 ::GetVersionExW(reinterpret_cast<LPOSVERSIONINFOW>(&ovix));
34
35 if (VER_SUITE_SMALLBUSINESS == (ovix.wSuiteMask & VER_SUITE_SMALLBUSINESS))
36 {
37 WcaSetIntProperty(L"WIX_SUITE_SMALLBUSINESS", 1);
38 }
39
40 if (VER_SUITE_ENTERPRISE == (ovix.wSuiteMask & VER_SUITE_ENTERPRISE))
41 {
42 WcaSetIntProperty(L"WIX_SUITE_ENTERPRISE", 1);
43 }
44
45 if (VER_SUITE_BACKOFFICE == (ovix.wSuiteMask & VER_SUITE_BACKOFFICE))
46 {
47 WcaSetIntProperty(L"WIX_SUITE_BACKOFFICE", 1);
48 }
49
50 if (VER_SUITE_COMMUNICATIONS == (ovix.wSuiteMask & VER_SUITE_COMMUNICATIONS))
51 {
52 WcaSetIntProperty(L"WIX_SUITE_COMMUNICATIONS", 1);
53 }
54
55 if (VER_SUITE_TERMINAL == (ovix.wSuiteMask & VER_SUITE_TERMINAL))
56 {
57 WcaSetIntProperty(L"WIX_SUITE_TERMINAL", 1);
58 }
59
60 if (VER_SUITE_SMALLBUSINESS_RESTRICTED == (ovix.wSuiteMask & VER_SUITE_SMALLBUSINESS_RESTRICTED))
61 {
62 WcaSetIntProperty(L"WIX_SUITE_SMALLBUSINESS_RESTRICTED", 1);
63 }
64
65 if (VER_SUITE_EMBEDDEDNT == (ovix.wSuiteMask & VER_SUITE_EMBEDDEDNT))
66 {
67 WcaSetIntProperty(L"WIX_SUITE_EMBEDDEDNT", 1);
68 }
69
70 if (VER_SUITE_DATACENTER == (ovix.wSuiteMask & VER_SUITE_DATACENTER))
71 {
72 WcaSetIntProperty(L"WIX_SUITE_DATACENTER", 1);
73 }
74
75 if (VER_SUITE_SINGLEUSERTS == (ovix.wSuiteMask & VER_SUITE_SINGLEUSERTS))
76 {
77 WcaSetIntProperty(L"WIX_SUITE_SINGLEUSERTS", 1);
78 }
79
80 if (VER_SUITE_PERSONAL == (ovix.wSuiteMask & VER_SUITE_PERSONAL))
81 {
82 WcaSetIntProperty(L"WIX_SUITE_PERSONAL", 1);
83 }
84
85 if (VER_SUITE_BLADE == (ovix.wSuiteMask & VER_SUITE_BLADE))
86 {
87 WcaSetIntProperty(L"WIX_SUITE_BLADE", 1);
88 }
89
90 if (VER_SUITE_EMBEDDED_RESTRICTED == (ovix.wSuiteMask & VER_SUITE_EMBEDDED_RESTRICTED))
91 {
92 WcaSetIntProperty(L"WIX_SUITE_EMBEDDED_RESTRICTED", 1);
93 }
94
95 if (VER_SUITE_SECURITY_APPLIANCE == (ovix.wSuiteMask & VER_SUITE_SECURITY_APPLIANCE))
96 {
97 WcaSetIntProperty(L"WIX_SUITE_SECURITY_APPLIANCE", 1);
98 }
99
100 if (VER_SUITE_STORAGE_SERVER == (ovix.wSuiteMask & VER_SUITE_STORAGE_SERVER))
101 {
102 WcaSetIntProperty(L"WIX_SUITE_STORAGE_SERVER", 1);
103 }
104
105 if (VER_SUITE_COMPUTE_SERVER == (ovix.wSuiteMask & VER_SUITE_COMPUTE_SERVER))
106 {
107 WcaSetIntProperty(L"WIX_SUITE_COMPUTE_SERVER", 1);
108 }
109
110 if (VER_SUITE_WH_SERVER == (ovix.wSuiteMask & VER_SUITE_WH_SERVER))
111 {
112 WcaSetIntProperty(L"WIX_SUITE_WH_SERVER", 1);
113 }
114
115 // only for XP and later
116 if (5 < ovix.dwMajorVersion || (5 == ovix.dwMajorVersion && 0 < ovix.dwMinorVersion))
117 {
118 if (::GetSystemMetrics(SM_SERVERR2))
119 {
120 WcaSetIntProperty(L"WIX_SUITE_SERVERR2", 1);
121 }
122
123 if (::GetSystemMetrics(SM_MEDIACENTER))
124 {
125 WcaSetIntProperty(L"WIX_SUITE_MEDIACENTER", 1);
126 }
127
128 if (::GetSystemMetrics(SM_STARTER))
129 {
130 WcaSetIntProperty(L"WIX_SUITE_STARTER", 1);
131 }
132
133 if (::GetSystemMetrics(SM_TABLETPC))
134 {
135 WcaSetIntProperty(L"WIX_SUITE_TABLETPC", 1);
136 }
137 }
138
139LExit:
140 if (FAILED(hr))
141 er = ERROR_INSTALL_FAILURE;
142 return WcaFinalize(er);
143}
144
145/********************************************************************
146WixQueryOsDirs - entry point for WixQueryOsDirs custom action
147
148 Called as Type 1 custom action (DLL from the Binary table) from
149 Windows Installer to set properties that identify predefined directories
150********************************************************************/
151extern "C" UINT __stdcall WixQueryOsDirs(
152 __in MSIHANDLE hInstall
153 )
154{
155 HRESULT hr = S_OK;
156 DWORD er = ERROR_SUCCESS;
157
158 hr = WcaInitialize(hInstall, "WixQueryOsDirs");
159 ExitOnFailure(hr, "WixQueryOsDirs failed to initialize");
160
161 // get the paths of the CSIDLs that represent real paths and for which MSI
162 // doesn't yet have standard folder properties
163 WCHAR path[MAX_PATH];
164 if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_ADMINTOOLS, NULL, SHGFP_TYPE_CURRENT, path))
165 {
166 WcaSetProperty(L"WIX_DIR_ADMINTOOLS", path);
167 }
168
169 if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_ALTSTARTUP, NULL, SHGFP_TYPE_CURRENT, path))
170 {
171 WcaSetProperty(L"WIX_DIR_ALTSTARTUP", path);
172 }
173
174 if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_CDBURN_AREA, NULL, SHGFP_TYPE_CURRENT, path))
175 {
176 WcaSetProperty(L"WIX_DIR_CDBURN_AREA", path);
177 }
178
179 if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_ADMINTOOLS, NULL, SHGFP_TYPE_CURRENT, path))
180 {
181 WcaSetProperty(L"WIX_DIR_COMMON_ADMINTOOLS", path);
182 }
183
184 if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_ALTSTARTUP, NULL, SHGFP_TYPE_CURRENT, path))
185 {
186 WcaSetProperty(L"WIX_DIR_COMMON_ALTSTARTUP", path);
187 }
188
189 if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_DOCUMENTS, NULL, SHGFP_TYPE_CURRENT, path))
190 {
191 WcaSetProperty(L"WIX_DIR_COMMON_DOCUMENTS", path);
192 }
193
194 if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_FAVORITES, NULL, SHGFP_TYPE_CURRENT, path))
195 {
196 WcaSetProperty(L"WIX_DIR_COMMON_FAVORITES", path);
197 }
198
199 if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_MUSIC, NULL, SHGFP_TYPE_CURRENT, path))
200 {
201 WcaSetProperty(L"WIX_DIR_COMMON_MUSIC", path);
202 }
203
204 if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_PICTURES, NULL, SHGFP_TYPE_CURRENT, path))
205 {
206 WcaSetProperty(L"WIX_DIR_COMMON_PICTURES", path);
207 }
208
209 if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_VIDEO, NULL, SHGFP_TYPE_CURRENT, path))
210 {
211 WcaSetProperty(L"WIX_DIR_COMMON_VIDEO", path);
212 }
213
214 if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COOKIES, NULL, SHGFP_TYPE_CURRENT, path))
215 {
216 WcaSetProperty(L"WIX_DIR_COOKIES", path);
217 }
218
219 if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_DESKTOP, NULL, SHGFP_TYPE_CURRENT, path))
220 {
221 WcaSetProperty(L"WIX_DIR_DESKTOP", path);
222 }
223
224 if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_HISTORY, NULL, SHGFP_TYPE_CURRENT, path))
225 {
226 WcaSetProperty(L"WIX_DIR_HISTORY", path);
227 }
228
229 if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_INTERNET_CACHE, NULL, SHGFP_TYPE_CURRENT, path))
230 {
231 WcaSetProperty(L"WIX_DIR_INTERNET_CACHE", path);
232 }
233
234 if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_MYMUSIC, NULL, SHGFP_TYPE_CURRENT, path))
235 {
236 WcaSetProperty(L"WIX_DIR_MYMUSIC", path);
237 }
238
239 if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_MYPICTURES, NULL, SHGFP_TYPE_CURRENT, path))
240 {
241 WcaSetProperty(L"WIX_DIR_MYPICTURES", path);
242 }
243
244 if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_MYVIDEO, NULL, SHGFP_TYPE_CURRENT, path))
245 {
246 WcaSetProperty(L"WIX_DIR_MYVIDEO", path);
247 }
248
249 if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_NETHOOD, NULL, SHGFP_TYPE_CURRENT, path))
250 {
251 WcaSetProperty(L"WIX_DIR_NETHOOD", path);
252 }
253
254 if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, path))
255 {
256 WcaSetProperty(L"WIX_DIR_PERSONAL", path);
257 }
258
259 if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_PRINTHOOD, NULL, SHGFP_TYPE_CURRENT, path))
260 {
261 WcaSetProperty(L"WIX_DIR_PRINTHOOD", path);
262 }
263
264 if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, path))
265 {
266 WcaSetProperty(L"WIX_DIR_PROFILE", path);
267 }
268
269 if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_RECENT, NULL, SHGFP_TYPE_CURRENT, path))
270 {
271 WcaSetProperty(L"WIX_DIR_RECENT", path);
272 }
273
274 if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_RESOURCES, NULL, SHGFP_TYPE_CURRENT, path))
275 {
276 WcaSetProperty(L"WIX_DIR_RESOURCES", path);
277 }
278
279LExit:
280 if (FAILED(hr))
281 er = ERROR_INSTALL_FAILURE;
282 return WcaFinalize(er);
283}
284
285
286/********************************************************************
287SetPropertyWellKnownSID
288
289 Set a property with the localized name of a well known windows SID
290********************************************************************/
291static HRESULT SetPropertyWellKnownSID(
292 __in WELL_KNOWN_SID_TYPE sidType,
293 __in LPCWSTR wzPropertyName,
294 __in BOOL fIncludeDomainName
295 )
296{
297 HRESULT hr = S_OK;
298 PSID psid = NULL;
299 WCHAR wzRefDomain[MAX_PATH] = {0};
300 SID_NAME_USE nameUse;
301 DWORD refSize = MAX_PATH;
302 WCHAR wzName[MAX_PATH] = {0};
303 LPWSTR pwzPropertyValue = NULL;
304 DWORD size = MAX_PATH;
305
306 hr = AclGetWellKnownSid(sidType, &psid);
307 ExitOnFailure(hr, "Failed to get SID; skipping account %ls", wzPropertyName);
308
309 if (!::LookupAccountSidW(NULL, psid, wzName, &size, wzRefDomain, &refSize, &nameUse))
310 {
311 ExitWithLastError(hr, "Failed to look up account for SID; skipping account %ls.", wzPropertyName);
312 }
313
314 if (fIncludeDomainName)
315 {
316 hr = StrAllocFormatted(&pwzPropertyValue, L"%s\\%s", wzRefDomain, wzName);
317 ExitOnFailure(hr, "Failed to format property value");
318
319 hr = WcaSetProperty(wzPropertyName, pwzPropertyValue);
320 ExitOnFailure(hr, "Failed write domain\\name property");
321 }
322 else
323 {
324 hr = WcaSetProperty(wzPropertyName, wzName);
325 ExitOnFailure(hr, "Failed write to name-only property");
326 }
327
328LExit:
329 if (NULL != psid)
330 {
331 ::LocalFree(psid);
332 }
333 ReleaseStr(pwzPropertyValue);
334 return hr;
335}
336
337/********************************************************************
338WixQueryOsWellKnownSID - entry point for WixQueryOsWellKnownSID custom action
339
340 Called as Type 1 custom action (DLL from the Binary table) from
341 Windows Installer to set properties with the localized names of built-in
342 Windows Security IDs
343********************************************************************/
344extern "C" UINT __stdcall WixQueryOsWellKnownSID(
345 __in MSIHANDLE hInstall
346 )
347{
348 HRESULT hr = S_OK;
349 DWORD er = ERROR_SUCCESS;
350
351 hr = WcaInitialize(hInstall, "WixQueryOsWellKnownSID");
352 ExitOnFailure(hr, "WixQueryOsWellKnownSID failed to initialize");
353
354 SetPropertyWellKnownSID(WinLocalSystemSid, L"WIX_ACCOUNT_LOCALSYSTEM", TRUE);
355 SetPropertyWellKnownSID(WinLocalServiceSid, L"WIX_ACCOUNT_LOCALSERVICE", TRUE);
356 SetPropertyWellKnownSID(WinNetworkServiceSid, L"WIX_ACCOUNT_NETWORKSERVICE", TRUE);
357 SetPropertyWellKnownSID(WinBuiltinAdministratorsSid, L"WIX_ACCOUNT_ADMINISTRATORS", TRUE);
358 SetPropertyWellKnownSID(WinBuiltinUsersSid, L"WIX_ACCOUNT_USERS", TRUE);
359 SetPropertyWellKnownSID(WinBuiltinGuestsSid, L"WIX_ACCOUNT_GUESTS", TRUE);
360 SetPropertyWellKnownSID(WinBuiltinPerfLoggingUsersSid, L"WIX_ACCOUNT_PERFLOGUSERS", TRUE);
361 SetPropertyWellKnownSID(WinBuiltinPerfLoggingUsersSid, L"WIX_ACCOUNT_PERFLOGUSERS_NODOMAIN", FALSE);
362
363LExit:
364 if (FAILED(hr))
365 {
366 er = ERROR_INSTALL_FAILURE;
367 }
368 return WcaFinalize(er);
369}
370
371
372/********************************************************************
373DetectWDDMDriver
374
375 Set a property if the driver on the machine is a WDDM driver. One
376 reliable way to detect the presence of a WDDM driver is to try and
377 use the Direct3DCreate9Ex() function. This method attempts that
378 then sets the property appropriately.
379********************************************************************/
380static HRESULT DetectWDDMDriver()
381{
382 HRESULT hr = S_OK;
383 HMODULE hModule = NULL;
384
385 // Manually load the d3d9.dll library. If the library couldn't be loaded then we obviously won't be able
386 // to try calling the function so just return.
387 hr = LoadSystemLibrary(L"d3d9.dll", &hModule);
388 if (E_MODNOTFOUND == hr)
389 {
390 TraceError(hr, "Unable to load DirectX APIs, skipping WDDM driver check.");
391 ExitFunction1(hr = S_OK);
392 }
393 ExitOnFailure(hr, "Failed to the load the existing DirectX APIs.");
394
395 // Obtain the address of the Direct3DCreate9Ex function. If this fails we know it isn't a WDDM
396 // driver so just exit.
397 const void* Direct3DCreate9ExPtr = ::GetProcAddress(hModule, "Direct3DCreate9Ex");
398 ExitOnNull(Direct3DCreate9ExPtr, hr, S_OK, "Unable to load Direct3DCreateEx function, so the driver is not a WDDM driver.");
399
400 // At this point we know it's a WDDM driver so set the property.
401 hr = WcaSetIntProperty(L"WIX_WDDM_DRIVER_PRESENT", 1);
402 ExitOnFailure(hr, "Failed write property");
403
404LExit:
405 if (NULL != hModule)
406 {
407 FreeLibrary(hModule);
408 }
409
410 return hr;
411}
412
413/********************************************************************
414DetectIsCompositionEnabled
415
416 Set a property based on the return value of DwmIsCompositionEnabled().
417********************************************************************/
418static HRESULT DetectIsCompositionEnabled()
419{
420 HRESULT hr = S_OK;
421 HMODULE hModule = NULL;
422 BOOL compositionState = false;
423
424 // Manually load the d3d9.dll library. If the library can't load it's likely because we are not on a Vista
425 // OS. Just return ok, and the property won't get set.
426 hr = LoadSystemLibrary(L"dwmapi.dll", &hModule);
427 if (E_MODNOTFOUND == hr)
428 {
429 TraceError(hr, "Unable to load Vista desktop window manager APIs, skipping Composition Enabled check.");
430 ExitFunction1(hr = S_OK);
431 }
432 ExitOnFailure(hr, "Failed to load the existing window manager APIs.");
433
434 // If for some reason we can't get the function pointer that's ok, just return.
435 typedef HRESULT (WINAPI *DWMISCOMPOSITIONENABLEDPTR)(BOOL*);
436 DWMISCOMPOSITIONENABLEDPTR DwmIsCompositionEnabledPtr = (DWMISCOMPOSITIONENABLEDPTR)::GetProcAddress(hModule, "DwmIsCompositionEnabled");
437 ExitOnNull(hModule, hr, S_OK, "Unable to obtain function information, skipping Composition Enabled check.");
438
439 hr = DwmIsCompositionEnabledPtr(&compositionState);
440 ExitOnFailure(hr, "Failed to retrieve Composition state");
441
442 if (compositionState)
443 {
444 hr = WcaSetIntProperty(L"WIX_DWM_COMPOSITION_ENABLED", 1);
445 ExitOnFailure(hr, "Failed write property");
446 }
447
448LExit:
449 if (NULL != hModule)
450 {
451 FreeLibrary(hModule);
452 }
453 return hr;
454}
455
456/********************************************************************
457WixQueryOsDriverInfo - entry point for WixQueryOsDriverInfo custom action
458
459 Called as Type 1 custom action (DLL from the Binary table) from
460 Windows Installer to set properties about drivers installed on
461 the target machine
462********************************************************************/
463extern "C" UINT __stdcall WixQueryOsDriverInfo(
464 __in MSIHANDLE hInstall
465 )
466{
467 HRESULT hr = S_OK;
468 DWORD er = ERROR_SUCCESS;
469
470 hr = WcaInitialize(hInstall, "WixQueryOsDriverInfo");
471 ExitOnFailure(hr, "WixQueryOsDriverInfo failed to initialize");
472
473 // Detect the WDDM driver status
474 hr = DetectWDDMDriver();
475 ExitOnFailure(hr, "Failed to detect WIX_WDDM_DRIVER_PRESENT");
476
477 // Detect whether composition is enabled
478 hr = DetectIsCompositionEnabled();
479 ExitOnFailure(hr, "Failed to detect WIX_DWM_COMPOSITION_ENABLED");
480
481LExit:
482 if (FAILED(hr))
483 {
484 er = ERROR_INSTALL_FAILURE;
485 }
486 return WcaFinalize(er);
487}
diff --git a/src/ext/Util/ca/RemoveFoldersEx.cpp b/src/ext/Util/ca/RemoveFoldersEx.cpp
new file mode 100644
index 00000000..cbc7f4bb
--- /dev/null
+++ b/src/ext/Util/ca/RemoveFoldersEx.cpp
@@ -0,0 +1,243 @@
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
5LPCWSTR vcsRemoveFolderExQuery =
6 L"SELECT `Wix4RemoveFolderEx`, `Component_`, `Property`, `InstallMode`, `WixRemoveFolderEx`.`Condition`, `Component`.`Attributes`"
7 L"FROM `Wix4RemoveFolderEx``,`Component` "
8 L"WHERE `Wix4RemoveFolderEx`.`Component_`=`Component`.`Component`";
9enum eRemoveFolderExQuery { rfqId = 1, rfqComponent, rfqProperty, rfqMode, rfqCondition, rfqComponentAttributes };
10
11static HRESULT RecursePath(
12 __in_z LPCWSTR wzPath,
13 __in_z LPCWSTR wzId,
14 __in_z LPCWSTR wzComponent,
15 __in_z LPCWSTR wzProperty,
16 __in int iMode,
17 __in BOOL fDisableWow64Redirection,
18 __inout DWORD* pdwCounter,
19 __inout MSIHANDLE* phTable,
20 __inout MSIHANDLE* phColumns
21 )
22{
23 HRESULT hr = S_OK;
24 DWORD er;
25 LPWSTR sczSearch = NULL;
26 LPWSTR sczProperty = NULL;
27 HANDLE hFind = INVALID_HANDLE_VALUE;
28 WIN32_FIND_DATAW wfd;
29 LPWSTR sczNext = NULL;
30
31 if (fDisableWow64Redirection)
32 {
33 hr = WcaDisableWow64FSRedirection();
34 ExitOnFailure(hr, "Custom action was told to act on a 64-bit component, but was unable to disable filesystem redirection through the Wow64 API.");
35 }
36
37 // First recurse down to all the child directories.
38 hr = StrAllocFormatted(&sczSearch, L"%s*", wzPath);
39 ExitOnFailure(hr, "Failed to allocate file search string in path: %S", wzPath);
40
41 hFind = ::FindFirstFileW(sczSearch, &wfd);
42 if (INVALID_HANDLE_VALUE == hFind)
43 {
44 er = ::GetLastError();
45 if (ERROR_PATH_NOT_FOUND == er)
46 {
47 WcaLog(LOGMSG_STANDARD, "Search path not found: %ls; skipping", sczSearch);
48 ExitFunction1(hr = S_FALSE);
49 }
50 else
51 {
52 hr = HRESULT_FROM_WIN32(er);
53 }
54 ExitOnFailure(hr, "Failed to find all files in path: %S", wzPath);
55 }
56
57 do
58 {
59 // Skip files and the dot directories.
60 if (FILE_ATTRIBUTE_DIRECTORY != (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) || L'.' == wfd.cFileName[0] && (L'\0' == wfd.cFileName[1] || (L'.' == wfd.cFileName[1] && L'\0' == wfd.cFileName[2])))
61 {
62 continue;
63 }
64
65 hr = StrAllocFormatted(&sczNext, L"%s%s\\", wzPath, wfd.cFileName);
66 ExitOnFailure(hr, "Failed to concat filename '%S' to string: %S", wfd.cFileName, wzPath);
67
68 // Don't re-disable redirection; if it was necessary, we've already done it.
69 hr = RecursePath(sczNext, wzId, wzComponent, wzProperty, iMode, FALSE, pdwCounter, phTable, phColumns);
70 ExitOnFailure(hr, "Failed to recurse path: %S", sczNext);
71 } while (::FindNextFileW(hFind, &wfd));
72
73 er = ::GetLastError();
74 if (ERROR_NO_MORE_FILES == er)
75 {
76 hr = S_OK;
77 }
78 else
79 {
80 hr = HRESULT_FROM_WIN32(er);
81 ExitOnFailure(hr, "Failed while looping through files in directory: %S", wzPath);
82 }
83
84 // Finally, set a property that points at our path.
85 hr = StrAllocFormatted(&sczProperty, L"_%s_%u", wzProperty, *pdwCounter);
86 ExitOnFailure(hr, "Failed to allocate Property for RemoveFile table with property: %S.", wzProperty);
87
88 ++(*pdwCounter);
89
90 hr = WcaSetProperty(sczProperty, wzPath);
91 ExitOnFailure(hr, "Failed to set Property: %S with path: %S", sczProperty, wzPath);
92
93 // Add the row to remove any files and another row to remove the folder.
94 hr = WcaAddTempRecord(phTable, phColumns, L"RemoveFile", NULL, 1, 5, L"RfxFiles", wzComponent, L"*.*", sczProperty, iMode);
95 ExitOnFailure(hr, "Failed to add row to remove all files for Wix4RemoveFolderEx row: %ls under path: %ls", wzId, wzPath);
96
97 hr = WcaAddTempRecord(phTable, phColumns, L"RemoveFile", NULL, 1, 5, L"RfxFolder", wzComponent, NULL, sczProperty, iMode);
98 ExitOnFailure(hr, "Failed to add row to remove folder for Wix4RemoveFolderEx row: %ls under path: %ls", wzId, wzPath);
99
100LExit:
101 if (INVALID_HANDLE_VALUE != hFind)
102 {
103 ::FindClose(hFind);
104 }
105
106 if (fDisableWow64Redirection)
107 {
108 WcaRevertWow64FSRedirection();
109 }
110
111 ReleaseStr(sczNext);
112 ReleaseStr(sczProperty);
113 ReleaseStr(sczSearch);
114 return hr;
115}
116
117extern "C" UINT WINAPI WixRemoveFoldersEx(
118 __in MSIHANDLE hInstall
119 )
120{
121 //AssertSz(FALSE, "debug WixRemoveFoldersEx");
122
123 HRESULT hr = S_OK;
124 PMSIHANDLE hView;
125 PMSIHANDLE hRec;
126 LPWSTR sczId = NULL;
127 LPWSTR sczComponent = NULL;
128 LPWSTR sczProperty = NULL;
129 LPWSTR sczCondition = NULL;
130 LPWSTR sczPath = NULL;
131 LPWSTR sczExpandedPath = NULL;
132 int iMode = 0;
133 int iComponentAttributes;
134 BOOL f64BitComponent = FALSE;
135 DWORD dwCounter = 0;
136 DWORD_PTR cchLen = 0;
137 MSIHANDLE hTable = NULL;
138 MSIHANDLE hColumns = NULL;
139
140 hr = WcaInitialize(hInstall, "WixRemoveFoldersEx");
141 ExitOnFailure(hr, "Failed to initialize WixRemoveFoldersEx.");
142
143 WcaInitializeWow64();
144
145 // anything to do?
146 if (S_OK != WcaTableExists(L"Wix4RemoveFolderEx"))
147 {
148 WcaLog(LOGMSG_STANDARD, "Wix4RemoveFolderEx table doesn't exist, so there are no folders to remove.");
149 ExitFunction();
150 }
151
152 // query and loop through all the remove folders exceptions
153 hr = WcaOpenExecuteView(vcsRemoveFolderExQuery, &hView);
154 ExitOnFailure(hr, "Failed to open view on Wix4RemoveFolderEx table");
155
156 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
157 {
158 hr = WcaGetRecordString(hRec, rfqId, &sczId);
159 ExitOnFailure(hr, "Failed to get remove folder identity.");
160
161 hr = WcaGetRecordString(hRec, rfqCondition, &sczCondition);
162 ExitOnFailure(hr, "Failed to get remove folder condition.");
163
164 if (sczCondition && *sczCondition)
165 {
166 MSICONDITION condition = ::MsiEvaluateConditionW(hInstall, sczCondition);
167 if (MSICONDITION_TRUE == condition)
168 {
169 WcaLog(LOGMSG_STANDARD, "True condition for row %S: %S; processing.", sczId, sczCondition);
170 }
171 else
172 {
173 WcaLog(LOGMSG_STANDARD, "False or invalid condition for row %S: %S; skipping.", sczId, sczCondition);
174 continue;
175 }
176 }
177
178 hr = WcaGetRecordString(hRec, rfqComponent, &sczComponent);
179 ExitOnFailure(hr, "Failed to get remove folder component.");
180
181 hr = WcaGetRecordString(hRec, rfqProperty, &sczProperty);
182 ExitOnFailure(hr, "Failed to get remove folder property.");
183
184 hr = WcaGetRecordInteger(hRec, rfqMode, &iMode);
185 ExitOnFailure(hr, "Failed to get remove folder mode");
186
187 hr = WcaGetProperty(sczProperty, &sczPath);
188 ExitOnFailure(hr, "Failed to resolve remove folder property: %S for row: %S", sczProperty, sczId);
189
190 hr = WcaGetRecordInteger(hRec, rfqComponentAttributes, &iComponentAttributes);
191 ExitOnFailure(hr, "failed to get component attributes for row: %ls", sczId);
192
193 f64BitComponent = iComponentAttributes & msidbComponentAttributes64bit;
194
195 // fail early if the property isn't set as you probably don't want your installers trying to delete SystemFolder
196 // StringCchLengthW succeeds only if the string is zero characters plus 1 for the terminating null
197 hr = ::StringCchLengthW(sczPath, 1, reinterpret_cast<UINT_PTR*>(&cchLen));
198 if (SUCCEEDED(hr))
199 {
200 ExitOnFailure(hr = E_INVALIDARG, "Missing folder property: %S for row: %S", sczProperty, sczId);
201 }
202
203 hr = PathExpand(&sczExpandedPath, sczPath, PATH_EXPAND_ENVIRONMENT);
204 ExitOnFailure(hr, "Failed to expand path: %S for row: %S", sczPath, sczId);
205
206 hr = PathBackslashTerminate(&sczExpandedPath);
207 ExitOnFailure(hr, "Failed to backslash-terminate path: %S", sczExpandedPath);
208
209 WcaLog(LOGMSG_STANDARD, "Recursing path: %S for row: %S.", sczExpandedPath, sczId);
210 hr = RecursePath(sczExpandedPath, sczId, sczComponent, sczProperty, iMode, f64BitComponent, &dwCounter, &hTable, &hColumns);
211 ExitOnFailure(hr, "Failed while navigating path: %S for row: %S", sczPath, sczId);
212 }
213
214 // reaching the end of the list is actually a good thing, not an error
215 if (E_NOMOREITEMS == hr)
216 {
217 hr = S_OK;
218 }
219 ExitOnFailure(hr, "Failure occured while processing Wix4RemoveFolderEx table");
220
221LExit:
222 WcaFinalizeWow64();
223
224 if (hColumns)
225 {
226 ::MsiCloseHandle(hColumns);
227 }
228
229 if (hTable)
230 {
231 ::MsiCloseHandle(hTable);
232 }
233
234 ReleaseStr(sczExpandedPath);
235 ReleaseStr(sczPath);
236 ReleaseStr(sczProperty);
237 ReleaseStr(sczComponent);
238 ReleaseStr(sczCondition);
239 ReleaseStr(sczId);
240
241 DWORD er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
242 return WcaFinalize(er);
243}
diff --git a/src/ext/Util/ca/RemoveRegistryKeysEx.cpp b/src/ext/Util/ca/RemoveRegistryKeysEx.cpp
new file mode 100644
index 00000000..478c0779
--- /dev/null
+++ b/src/ext/Util/ca/RemoveRegistryKeysEx.cpp
@@ -0,0 +1,114 @@
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
5LPCWSTR vcsRemoveRegistryKeyExQuery =
6 L"SELECT `Wix4RemoveRegistryKeyEx`, `Component_`, `Root`, `Key`, `InstallMode`, `Condition` FROM `Wix4RemoveRegistryKeyEx`";
7enum eRemoveRegistryKeyExQuery { rrxqId = 1, rrxqComponent, rrxqRoot, rrxqKey, rrxqMode, rrxqCondition };
8
9extern "C" UINT WINAPI WixRemoveRegistryKeysEx(
10 __in MSIHANDLE hInstall
11)
12{
13 //AssertSz(FALSE, "debug WixRemoveRegistryKeyEx");
14
15 HRESULT hr = S_OK;
16 PMSIHANDLE hView;
17 PMSIHANDLE hRec;
18 LPWSTR sczId = NULL;
19 LPWSTR sczComponent = NULL;
20 LPWSTR sczCondition = NULL;
21 LPWSTR sczKey = NULL;
22 int iRoot = 0;
23 int iMode = 0;
24 MSIHANDLE hTable = NULL;
25 MSIHANDLE hColumns = NULL;
26
27 hr = WcaInitialize(hInstall, __FUNCTION__);
28 ExitOnFailure(hr, "Failed to initialize " __FUNCTION__);
29
30 // anything to do?
31 if (S_OK != WcaTableExists(L"Wix4RemoveRegistryKeyEx"))
32 {
33 WcaLog(LOGMSG_STANDARD, "Wix4RemoveRegistryKeyEx table doesn't exist, so there are no registry keys to remove.");
34 ExitFunction();
35 }
36
37 hr = WcaOpenExecuteView(vcsRemoveRegistryKeyExQuery, &hView);
38 ExitOnFailure(hr, "Failed to open view on Wix4RemoveRegistryKeyEx table");
39
40 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
41 {
42 hr = WcaGetRecordString(hRec, rrxqId, &sczId);
43 ExitOnFailure(hr, "Failed to get Wix4RemoveRegistryKeyEx identity.");
44
45 hr = WcaGetRecordString(hRec, rrxqCondition, &sczCondition);
46 ExitOnFailure(hr, "Failed to get Wix4RemoveRegistryKeyEx condition.");
47
48 if (sczCondition && *sczCondition)
49 {
50 MSICONDITION condition = ::MsiEvaluateConditionW(hInstall, sczCondition);
51 if (MSICONDITION_TRUE == condition)
52 {
53 WcaLog(LOGMSG_STANDARD, "True condition for row %S: %S; processing.", sczId, sczCondition);
54 }
55 else
56 {
57 WcaLog(LOGMSG_STANDARD, "False or invalid condition for row %S: %S; skipping.", sczId, sczCondition);
58 continue;
59 }
60 }
61
62 hr = WcaGetRecordString(hRec, rrxqComponent, &sczComponent);
63 ExitOnFailure(hr, "Failed to get Wix4RemoveRegistryKeyEx component.");
64
65 hr = WcaGetRecordInteger(hRec, rrxqRoot, &iRoot);
66 ExitOnFailure(hr, "Failed to get Wix4RemoveRegistryKeyEx root.");
67
68 hr = WcaGetRecordString(hRec, rrxqKey, &sczKey);
69 ExitOnFailure(hr, "Failed to get Wix4RemoveRegistryKeyEx key.");
70
71 hr = WcaGetRecordInteger(hRec, rrxqMode, &iMode);
72 ExitOnFailure(hr, "Failed to get Wix4RemoveRegistryKeyEx mode.");
73
74 switch (iMode)
75 {
76 case 1: // remove on install
77 WcaLog(LOGMSG_STANDARD, "Adding RemoveRegistry row: %ls/%d/%ls/-/%ls", sczId, iRoot, sczKey, sczComponent);
78 hr = WcaAddTempRecord(&hTable, &hColumns, L"RemoveRegistry", NULL, 0, 5, sczId, iRoot, sczKey, L"-", sczComponent);
79 ExitOnFailure(hr, "Failed to add RemoveRegistry row for remove-on-install Wix4RemoveRegistryKeyEx row: %ls:", sczId);
80 break;
81 case 2: // remove on uninstall
82 WcaLog(LOGMSG_STANDARD, "Adding Registry row: %ls/%d/%ls/-/null/%ls", sczId, iRoot, sczKey, sczComponent);
83 hr = WcaAddTempRecord(&hTable, &hColumns, L"Registry", NULL, 0, 6, sczId, iRoot, sczKey, L"-", NULL, sczComponent);
84 ExitOnFailure(hr, "Failed to add Registry row for remove-on-uninstall Wix4RemoveRegistryKeyEx row: %ls:", sczId);
85 break;
86 }
87 }
88
89 // reaching the end of the list is actually a good thing, not an error
90 if (E_NOMOREITEMS == hr)
91 {
92 hr = S_OK;
93 }
94 ExitOnFailure(hr, "Failure occured while processing Wix4RemoveRegistryKeyEx table.");
95
96LExit:
97 if (hColumns)
98 {
99 ::MsiCloseHandle(hColumns);
100 }
101
102 if (hTable)
103 {
104 ::MsiCloseHandle(hTable);
105 }
106
107 ReleaseStr(sczKey);
108 ReleaseStr(sczComponent);
109 ReleaseStr(sczCondition);
110 ReleaseStr(sczId);
111
112 DWORD er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
113 return WcaFinalize(er);
114}
diff --git a/src/ext/Util/ca/RestartManager.cpp b/src/ext/Util/ca/RestartManager.cpp
new file mode 100644
index 00000000..c31819c1
--- /dev/null
+++ b/src/ext/Util/ca/RestartManager.cpp
@@ -0,0 +1,185 @@
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 <restartmanager.h>
5
6// Include space for the terminating null.
7#define CCH_SESSION_KEY CCH_RM_SESSION_KEY + 1
8
9enum eRmuResourceType
10{
11 etInvalid,
12 etFilename,
13 etApplication,
14 etServiceName,
15
16 // Mask types from Attributes.
17 etTypeMask = 0xf,
18};
19
20LPCWSTR vcsRestartResourceQuery =
21 L"SELECT `Wix4RestartResource`.`Wix4RestartResource`, `Wix4RestartResource`.`Component_`, `Wix4RestartResource`.`Resource`, `Wix4RestartResource`.`Attributes` "
22 L"FROM `Wix4RestartResource`";
23enum eRestartResourceQuery { rrqRestartResource = 1, rrqComponent, rrqResource, rrqAttributes };
24
25/********************************************************************
26WixRegisterRestartResources - Immediate CA to register resources with RM.
27
28Enumerates components before InstallValidate and registers resources
29to be restarted by Restart Manager if the component action
30is anything other than None.
31
32Do not disable file system redirection.
33
34********************************************************************/
35extern "C" UINT __stdcall WixRegisterRestartResources(
36 __in MSIHANDLE hInstall
37 )
38{
39 HRESULT hr = S_OK;
40 UINT er = ERROR_SUCCESS;
41
42 PMSIHANDLE hView = NULL;
43 PMSIHANDLE hRec = NULL;
44
45 LPWSTR wzSessionKey = NULL;
46 size_t cchSessionKey = 0;
47 PRMU_SESSION pSession = NULL;
48
49 LPWSTR wzRestartResource = NULL;
50 LPWSTR wzComponent = NULL;
51 LPWSTR wzResource = NULL;
52 int iAttributes = NULL;
53 BOOL fIsComponentNull = FALSE;
54 WCA_TODO todo = WCA_TODO_UNKNOWN;
55 int iType = etInvalid;
56
57 hr = WcaInitialize(hInstall, "WixRegisterRestartResources");
58 ExitOnFailure(hr, "Failed to initialize.");
59
60 // Skip if the table doesn't exist.
61 if (S_OK != WcaTableExists(L"Wix4RestartResource"))
62 {
63 WcaLog(LOGMSG_STANDARD, "The Wix4RestartResource table does not exist; there are no resources to register with Restart Manager.");
64 ExitFunction();
65 }
66
67 // Get the existing Restart Manager session if available.
68 hr = WcaGetProperty(L"MsiRestartManagerSessionKey", &wzSessionKey);
69 ExitOnFailure(hr, "Failed to get the MsiRestartManagerSessionKey property.");
70
71 hr = ::StringCchLengthW(wzSessionKey, CCH_SESSION_KEY, &cchSessionKey);
72 ExitOnFailure(hr, "Failed to get the MsiRestartManagerSessionKey string length.");
73
74 // Skip if the property doesn't exist.
75 if (0 == cchSessionKey)
76 {
77 WcaLog(LOGMSG_STANDARD, "The MsiRestartManagerSessionKey property is not available to join.");
78 ExitFunction();
79 }
80
81 // Join the existing Restart Manager session if supported.
82 hr = RmuJoinSession(&pSession, wzSessionKey);
83 if (E_MODNOTFOUND == hr)
84 {
85 WcaLog(LOGMSG_STANDARD, "The Restart Manager is not supported on this platform. Skipping.");
86 ExitFunction1(hr = S_OK);
87 }
88 else if (FAILED(hr))
89 {
90 WcaLog(LOGMSG_STANDARD, "Failed to join the existing Restart Manager session %ls.", wzSessionKey);
91 ExitFunction1(hr = S_OK);
92 }
93
94 // Loop through each record in the table.
95 hr = WcaOpenExecuteView(vcsRestartResourceQuery, &hView);
96 ExitOnFailure(hr, "Failed to open a view on the RestartResource table.");
97
98 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
99 {
100 hr = WcaGetRecordString(hRec, rrqRestartResource, &wzRestartResource);
101 ExitOnFailure(hr, "Failed to get the RestartResource field value.");
102
103 hr = WcaGetRecordString(hRec, rrqComponent, &wzComponent);
104 ExitOnFailure(hr, "Failed to get the Component_ field value.");
105
106 hr = WcaGetRecordFormattedString(hRec, rrqResource, &wzResource);
107 ExitOnFailure(hr, "Failed to get the Resource formatted field value.");
108
109 hr = WcaGetRecordInteger(hRec, rrqAttributes, &iAttributes);
110 ExitOnFailure(hr, "Failed to get the Attributes field value.");
111
112 fIsComponentNull = ::MsiRecordIsNull(hRec, rrqComponent);
113 todo = WcaGetComponentToDo(wzComponent);
114
115 // Only register resources for components that are null, or being installed, reinstalled, or uninstalled.
116 if (!fIsComponentNull && WCA_TODO_UNKNOWN == todo)
117 {
118 WcaLog(LOGMSG_VERBOSE, "Skipping resource %ls.", wzRestartResource);
119 continue;
120 }
121
122 // Get the type from Attributes and add to the Restart Manager.
123 iType = iAttributes & etTypeMask;
124 switch (iType)
125 {
126 case etFilename:
127 WcaLog(LOGMSG_VERBOSE, "Registering file name %ls with the Restart Manager.", wzResource);
128 hr = RmuAddFile(pSession, wzResource);
129 ExitOnFailure(hr, "Failed to register the file name with the Restart Manager session.");
130 break;
131
132 case etApplication:
133 WcaLog(LOGMSG_VERBOSE, "Registering process name %ls with the Restart Manager.", wzResource);
134 hr = RmuAddProcessesByName(pSession, wzResource);
135 if (E_NOTFOUND == hr)
136 {
137 // ERROR_ACCESS_DENIED was returned when trying to register this process.
138 // Since other instances may have been registered, log a message and continue the setup rather than failing.
139 WcaLog(LOGMSG_STANDARD, "The process, %ls, could not be registered with the Restart Manager (probably because the setup is not elevated and the process is in another user context). A reboot may be requested later.", wzResource);
140 hr = S_OK;
141 }
142 else
143 {
144 ExitOnFailure(hr, "Failed to register the process name with the Restart Manager session.");
145 }
146 break;
147
148 case etServiceName:
149 WcaLog(LOGMSG_VERBOSE, "Registering service name %ls with the Restart Manager.", wzResource);
150 hr = RmuAddService(pSession, wzResource);
151 ExitOnFailure(hr, "Failed to register the service name with the Restart Manager session.");
152 break;
153
154 default:
155 WcaLog(LOGMSG_VERBOSE, "The resource type %d for %ls is not supported and will not be registered.", iType, wzRestartResource);
156 break;
157 }
158 }
159
160 if (E_NOMOREITEMS == hr)
161 {
162 hr = S_OK;
163 }
164 ExitOnFailure(hr, "Failed while looping through all rows to register resources.");
165
166 // Register the resources and unjoin the session.
167 hr = RmuEndSession(pSession);
168 if (FAILED(hr))
169 {
170 WcaLog(LOGMSG_VERBOSE, "Failed to register the resources with the Restart Manager.");
171 ExitFunction1(hr = S_OK);
172 }
173
174LExit:
175 ReleaseStr(wzRestartResource);
176 ReleaseStr(wzComponent);
177 ReleaseStr(wzResource);
178
179 if (FAILED(hr))
180 {
181 er = ERROR_INSTALL_FAILURE;
182 }
183
184 return WcaFinalize(er);
185}
diff --git a/src/ext/Util/ca/TouchFile.cpp b/src/ext/Util/ca/TouchFile.cpp
new file mode 100644
index 00000000..e704f922
--- /dev/null
+++ b/src/ext/Util/ca/TouchFile.cpp
@@ -0,0 +1,308 @@
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
5LPCWSTR vcsTouchFileQuery = L"SELECT `Wix4TouchFile`, `Component_`, `Path`, `Attributes` FROM `Wix4TouchFile`";
6enum TOUCH_FILE_QUERY { tfqId = 1, tfqComponent, tfqPath, tfqTouchFileAttributes };
7
8enum TOUCH_FILE_ATTRIBUTE
9{
10 TOUCH_FILE_ATTRIBUTE_ON_INSTALL = 0x01,
11 TOUCH_FILE_ATTRIBUTE_ON_REINSTALL = 0x02,
12 TOUCH_FILE_ATTRIBUTE_ON_UNINSTALL = 0x04,
13 TOUCH_FILE_ATTRIBUTE_64BIT = 0x10,
14 TOUCH_FILE_ATTRIBUTE_VITAL = 0x20
15};
16
17
18static BOOL SetExistingFileModifiedTime(
19 __in_z LPCWSTR wzId,
20 __in_z LPCWSTR wzPath,
21 __in BOOL f64Bit,
22 __in FILETIME* pftModified
23 )
24{
25 HRESULT hr = S_OK;
26 BOOL fReenableFileSystemRedirection = FALSE;
27
28 if (f64Bit)
29 {
30 hr = WcaDisableWow64FSRedirection();
31 ExitOnFailure(hr, "Failed to disable 64-bit file system redirection to path: '%ls' for: %ls", wzPath, wzId);
32
33 fReenableFileSystemRedirection = TRUE;
34 }
35
36 hr = FileSetTime(wzPath, NULL, NULL, pftModified);
37
38LExit:
39 if (fReenableFileSystemRedirection)
40 {
41 WcaRevertWow64FSRedirection();
42 }
43
44 return SUCCEEDED(hr);
45}
46
47
48static HRESULT AddDataToCustomActionData(
49 __deref_inout_z LPWSTR* psczCustomActionData,
50 __in_z LPCWSTR wzId,
51 __in_z LPCWSTR wzPath,
52 __in int iTouchFileAttributes,
53 __in FILETIME ftModified
54 )
55{
56 HRESULT hr = S_OK;
57
58 hr = WcaWriteStringToCaData(wzId, psczCustomActionData);
59 ExitOnFailure(hr, "Failed to add touch file identity to custom action data.");
60
61 hr = WcaWriteStringToCaData(wzPath, psczCustomActionData);
62 ExitOnFailure(hr, "Failed to add touch file path to custom action data.");
63
64 hr = WcaWriteIntegerToCaData(iTouchFileAttributes, psczCustomActionData);
65 ExitOnFailure(hr, "Failed to add touch file attributes to custom action data.");
66
67 hr = WcaWriteIntegerToCaData(ftModified.dwHighDateTime, psczCustomActionData);
68 ExitOnFailure(hr, "Failed to add touch file high date/time to custom action data.");
69
70 hr = WcaWriteIntegerToCaData(ftModified.dwLowDateTime, psczCustomActionData);
71 ExitOnFailure(hr, "Failed to add touch file low date/time to custom action data.");
72
73LExit:
74 return hr;
75}
76
77
78static BOOL TryGetExistingFileModifiedTime(
79 __in_z LPCWSTR wzId,
80 __in_z LPCWSTR wzPath,
81 __in BOOL f64Bit,
82 __inout FILETIME* pftModified
83 )
84{
85 HRESULT hr = S_OK;
86 BOOL fReenableFileSystemRedirection = FALSE;
87
88 if (f64Bit)
89 {
90 hr = WcaDisableWow64FSRedirection();
91 ExitOnFailure(hr, "Failed to disable 64-bit file system redirection to path: '%ls' for: %ls", wzPath, wzId);
92
93 fReenableFileSystemRedirection = TRUE;
94 }
95
96 hr = FileGetTime(wzPath, NULL, NULL, pftModified);
97 if (E_PATHNOTFOUND == hr || E_FILENOTFOUND == hr)
98 {
99 // If the file doesn't exist yet there is nothing to rollback (i.e. file will probably be removed during rollback), so
100 // keep the error code but don't log anything.
101 }
102 else if (FAILED(hr))
103 {
104 WcaLog(LOGMSG_STANDARD, "Cannot access modified timestamp for file: '%ls' due to error: 0x%x. Continuing with out rollback for: %ls", wzPath, hr, wzId);
105 }
106
107LExit:
108 if (fReenableFileSystemRedirection)
109 {
110 WcaRevertWow64FSRedirection();
111 }
112
113 return SUCCEEDED(hr);
114}
115
116
117static HRESULT ProcessTouchFileTable(
118 __in BOOL fInstalling
119 )
120{
121 HRESULT hr = S_OK;
122
123 FILETIME ftModified = {};
124
125 PMSIHANDLE hView;
126 PMSIHANDLE hRec;
127
128 LPWSTR sczId = NULL;
129 LPWSTR sczComponent = NULL;
130 int iTouchFileAttributes = 0;
131 LPWSTR sczPath = NULL;
132
133 FILETIME ftRollbackModified = {};
134 LPWSTR sczRollbackData = NULL;
135 LPWSTR sczExecuteData = NULL;
136
137 if (S_OK != WcaTableExists(L"Wix4TouchFile"))
138 {
139 ExitFunction();
140 }
141
142 ::GetSystemTimeAsFileTime(&ftModified);
143
144 hr = WcaOpenExecuteView(vcsTouchFileQuery, &hView);
145 ExitOnFailure(hr, "Failed to open view on Wix4TouchFile table");
146
147 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
148 {
149 hr = WcaGetRecordString(hRec, tfqId, &sczId);
150 ExitOnFailure(hr, "Failed to get touch file identity.");
151
152 hr = WcaGetRecordString(hRec, tfqComponent, &sczComponent);
153 ExitOnFailure(hr, "Failed to get touch file component for: %ls", sczId);
154
155 hr = WcaGetRecordInteger(hRec, tfqTouchFileAttributes, &iTouchFileAttributes);
156 ExitOnFailure(hr, "Failed to get touch file attributes for: %ls", sczId);
157
158 WCA_TODO todo = WcaGetComponentToDo(sczComponent);
159
160 BOOL fOnInstall = fInstalling && WCA_TODO_INSTALL == todo && (iTouchFileAttributes & TOUCH_FILE_ATTRIBUTE_ON_INSTALL);
161 BOOL fOnReinstall = fInstalling && WCA_TODO_REINSTALL == todo && (iTouchFileAttributes & TOUCH_FILE_ATTRIBUTE_ON_REINSTALL);
162 BOOL fOnUninstall = !fInstalling && WCA_TODO_UNINSTALL == todo && (iTouchFileAttributes & TOUCH_FILE_ATTRIBUTE_ON_UNINSTALL);
163
164 if (fOnInstall || fOnReinstall || fOnUninstall)
165 {
166 hr = WcaGetRecordFormattedString(hRec, tfqPath, &sczPath);
167 ExitOnFailure(hr, "Failed to get touch file path for: %ls", sczId);
168
169 if (TryGetExistingFileModifiedTime(sczId, sczPath, (iTouchFileAttributes & TOUCH_FILE_ATTRIBUTE_64BIT), &ftRollbackModified))
170 {
171 hr = AddDataToCustomActionData(&sczRollbackData, sczId, sczPath, iTouchFileAttributes, ftRollbackModified);
172 ExitOnFailure(hr, "Failed to add to rollback custom action data for: %ls", sczId);
173 }
174
175 hr = AddDataToCustomActionData(&sczExecuteData, sczId, sczPath, iTouchFileAttributes, ftModified);
176 ExitOnFailure(hr, "Failed to add to execute custom action data for: %ls", sczId);
177 }
178 }
179
180 if (E_NOMOREITEMS == hr)
181 {
182 hr = S_OK;
183 }
184 ExitOnFailure(hr, "Failure occured while processing Wix4TouchFile table");
185
186 if (sczRollbackData)
187 {
188 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackTouchFile"), sczRollbackData, 0);
189 ExitOnFailure(hr, "Failed to schedule RollbackTouchFile");
190 }
191
192 if (sczExecuteData)
193 {
194 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecuteTouchFile"), sczExecuteData, 0);
195 ExitOnFailure(hr, "Failed to schedule ExecuteTouchFile");
196 }
197
198LExit:
199 ReleaseStr(sczExecuteData);
200 ReleaseStr(sczRollbackData);
201 ReleaseStr(sczPath);
202 ReleaseStr(sczComponent);
203 ReleaseStr(sczId);
204
205 return hr;
206}
207
208
209extern "C" UINT WINAPI WixTouchFileDuringInstall(
210 __in MSIHANDLE hInstall
211 )
212{
213 //AssertSz(FALSE, "debug WixTouchFileDuringInstall");
214
215 HRESULT hr = S_OK;
216
217 hr = WcaInitialize(hInstall, "WixTouchFileDuringInstall");
218 ExitOnFailure(hr, "Failed to initialize WixTouchFileDuringInstall.");
219
220 hr = ProcessTouchFileTable(TRUE);
221
222LExit:
223 DWORD er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
224 return WcaFinalize(er);
225}
226
227
228extern "C" UINT WINAPI WixTouchFileDuringUninstall(
229 __in MSIHANDLE hInstall
230 )
231{
232 //AssertSz(FALSE, "debug WixTouchFileDuringUninstall");
233
234 HRESULT hr = S_OK;
235
236 hr = WcaInitialize(hInstall, "WixTouchFileDuringUninstall");
237 ExitOnFailure(hr, "Failed to initialize WixTouchFileDuringUninstall.");
238
239 hr = ProcessTouchFileTable(FALSE);
240
241LExit:
242 DWORD er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
243 return WcaFinalize(er);
244}
245
246
247extern "C" UINT WINAPI WixExecuteTouchFile(
248 __in MSIHANDLE hInstall
249 )
250{
251 HRESULT hr = S_OK;
252
253 LPWSTR sczData = NULL;
254 LPWSTR pwz = NULL;
255
256 LPWSTR sczId = NULL;
257 LPWSTR sczPath = NULL;
258 int iTouchFileAttributes = 0;
259 FILETIME ftModified = {};
260
261 hr = WcaInitialize(hInstall, "WixExecuteTouchFile");
262 ExitOnFailure(hr, "Failed to initialize WixExecuteTouchFile.");
263
264 hr = WcaGetProperty(L"CustomActionData", &sczData);
265 ExitOnFailure(hr, "Failed to get custom action data for WixExecuteTouchFile.");
266
267 pwz = sczData;
268
269 while (pwz && *pwz)
270 {
271 hr = WcaReadStringFromCaData(&pwz, &sczId);
272 ExitOnFailure(hr, "Failed to get touch file identity from custom action data.");
273
274 hr = WcaReadStringFromCaData(&pwz, &sczPath);
275 ExitOnFailure(hr, "Failed to get touch file path from custom action data for: %ls", sczId);
276
277 hr = WcaReadIntegerFromCaData(&pwz, &iTouchFileAttributes);
278 ExitOnFailure(hr, "Failed to get touch file attributes from custom action data for: %ls", sczId);
279
280 hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&ftModified.dwHighDateTime));
281 ExitOnFailure(hr, "Failed to get touch file high date/time from custom action data for: %ls", sczId);
282
283 hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&ftModified.dwLowDateTime));
284 ExitOnFailure(hr, "Failed to get touch file low date/time from custom action data for: %ls", sczId);
285
286 hr = SetExistingFileModifiedTime(sczId, sczPath, (iTouchFileAttributes & TOUCH_FILE_ATTRIBUTE_64BIT), &ftModified);
287 if (FAILED(hr))
288 {
289 if (iTouchFileAttributes & TOUCH_FILE_ATTRIBUTE_VITAL)
290 {
291 ExitOnFailure(hr, "Failed to touch file: '%ls' for: %ls", &sczPath, sczId);
292 }
293 else
294 {
295 WcaLog(LOGMSG_STANDARD, "Could not touch non-vital file: '%ls' for: %ls with error: 0x%x. Continuing...", sczPath, sczId, hr);
296 hr = S_OK;
297 }
298 }
299 }
300
301LExit:
302 ReleaseStr(sczPath);
303 ReleaseStr(sczId);
304 ReleaseStr(sczData);
305
306 DWORD er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
307 return WcaFinalize(er);
308}
diff --git a/src/ext/Util/ca/XmlConfig.cpp b/src/ext/Util/ca/XmlConfig.cpp
new file mode 100644
index 00000000..a1ec9d6f
--- /dev/null
+++ b/src/ext/Util/ca/XmlConfig.cpp
@@ -0,0 +1,1130 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5#define XMLCONFIG_ELEMENT 0x00000001
6#define XMLCONFIG_VALUE 0x00000002
7#define XMLCONFIG_DOCUMENT 0x00000004
8#define XMLCONFIG_CREATE 0x00000010
9#define XMLCONFIG_DELETE 0x00000020
10#define XMLCONFIG_INSTALL 0x00000100
11#define XMLCONFIG_UNINSTALL 0x00000200
12#define XMLCONFIG_PRESERVE_MODIFIED 0x00001000
13
14enum eXmlAction
15{
16 xaUnknown = 0,
17 xaOpenFile,
18 xaOpenFilex64,
19 xaWriteValue,
20 xaWriteDocument,
21 xaDeleteValue,
22 xaCreateElement,
23 xaDeleteElement,
24};
25
26enum eXmlPreserveDate
27{
28 xdDontPreserve = 0,
29 xdPreserve
30};
31
32LPCWSTR vcsXmlConfigQuery =
33 L"SELECT `Wix4XmlConfig`.`Wix4XmlConfig`, `Wix4XmlConfig`.`File`, `Wix4XmlConfig`.`ElementId`, `Wix4XmlConfig`.`ElementPath`, `Wix4XmlConfig`.`VerifyPath`, `Wix4XmlConfig`.`Name`, "
34 L"`Wix4XmlConfig`.`Value`, `Wix4XmlConfig`.`Flags`, `Wix4XmlConfig`.`Component_`, `Component`.`Attributes` "
35 L"FROM `Wix4XmlConfig`,`Component` WHERE `Wix4XmlConfig`.`Component_`=`Component`.`Component` ORDER BY `File`, `Sequence`";
36enum eXmlConfigQuery { xfqXmlConfig = 1, xfqFile, xfqElementId, xfqElementPath, xfqVerifyPath, xfqName, xfqValue, xfqXmlFlags, xfqComponent, xfqCompAttributes };
37
38struct XML_CONFIG_CHANGE
39{
40 WCHAR wzId[MAX_DARWIN_KEY + 1];
41
42 WCHAR wzComponent[MAX_DARWIN_KEY + 1];
43 INSTALLSTATE isInstalled;
44 INSTALLSTATE isAction;
45
46 WCHAR wzFile[MAX_PATH];
47 LPWSTR pwzElementId;
48 LPWSTR pwzElementPath;
49 LPWSTR pwzVerifyPath;
50 WCHAR wzName[MAX_DARWIN_COLUMN];
51 LPWSTR pwzValue;
52 BOOL fInstalledFile;
53
54 int iXmlFlags;
55 int iCompAttributes;
56
57 XML_CONFIG_CHANGE* pxfcAdditionalChanges;
58 int cAdditionalChanges;
59
60 XML_CONFIG_CHANGE* pxfcPrev;
61 XML_CONFIG_CHANGE* pxfcNext;
62};
63
64static HRESULT FreeXmlConfigChangeList(
65 __in_opt XML_CONFIG_CHANGE* pxfcList
66 )
67{
68 HRESULT hr = S_OK;
69
70 XML_CONFIG_CHANGE* pxfcDelete;
71 while(pxfcList)
72 {
73 pxfcDelete = pxfcList;
74 pxfcList = pxfcList->pxfcNext;
75
76 if (pxfcDelete->pwzElementId)
77 {
78 hr = MemFree(pxfcDelete->pwzElementId);
79 ExitOnFailure(hr, "failed to free xml config element id in change list item");
80 }
81
82 if (pxfcDelete->pwzElementPath)
83 {
84 hr = MemFree(pxfcDelete->pwzElementPath);
85 ExitOnFailure(hr, "failed to free xml config element path in change list item");
86 }
87
88 if (pxfcDelete->pwzVerifyPath)
89 {
90 hr = MemFree(pxfcDelete->pwzVerifyPath);
91 ExitOnFailure(hr, "failed to free xml config verify path in change list item");
92 }
93
94 if (pxfcDelete->pwzValue)
95 {
96 hr = MemFree(pxfcDelete->pwzValue);
97 ExitOnFailure(hr, "failed to free xml config value in change list item");
98 }
99
100 hr = MemFree(pxfcDelete);
101 ExitOnFailure(hr, "failed to free xml config change list item");
102 }
103
104LExit:
105 return hr;
106}
107
108static HRESULT AddXmlConfigChangeToList(
109 __inout XML_CONFIG_CHANGE** ppxfcHead,
110 __inout XML_CONFIG_CHANGE** ppxfcTail
111 )
112{
113 Assert(ppxfcHead && ppxfcTail);
114
115 HRESULT hr = S_OK;
116
117 XML_CONFIG_CHANGE* pxfc = static_cast<XML_CONFIG_CHANGE*>(MemAlloc(sizeof(XML_CONFIG_CHANGE), TRUE));
118 ExitOnNull(pxfc, hr, E_OUTOFMEMORY, "failed to allocate memory for new xml file change list element");
119
120 // Add it to the end of the list
121 if (NULL == *ppxfcHead)
122 {
123 *ppxfcHead = pxfc;
124 *ppxfcTail = pxfc;
125 }
126 else
127 {
128 Assert(*ppxfcTail && (*ppxfcTail)->pxfcNext == NULL);
129 (*ppxfcTail)->pxfcNext = pxfc;
130 pxfc->pxfcPrev = *ppxfcTail;
131 *ppxfcTail = pxfc;
132 }
133
134LExit:
135 return hr;
136}
137
138
139static HRESULT ReadXmlConfigTable(
140 __inout XML_CONFIG_CHANGE** ppxfcHead,
141 __inout XML_CONFIG_CHANGE** ppxfcTail
142 )
143{
144 Assert(ppxfcHead && ppxfcTail);
145
146 HRESULT hr = S_OK;
147 UINT er = ERROR_SUCCESS;
148
149 PMSIHANDLE hView = NULL;
150 PMSIHANDLE hRec = NULL;
151
152 LPWSTR pwzData = NULL;
153
154 // loop through all the xml configurations
155 hr = WcaOpenExecuteView(vcsXmlConfigQuery, &hView);
156 ExitOnFailure(hr, "failed to open view on Wix4XmlConfig table");
157
158 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
159 {
160 hr = AddXmlConfigChangeToList(ppxfcHead, ppxfcTail);
161 ExitOnFailure(hr, "failed to add xml file change to list");
162
163 // Get record Id
164 hr = WcaGetRecordString(hRec, xfqXmlConfig, &pwzData);
165 ExitOnFailure(hr, "failed to get Wix4XmlConfig record Id");
166 hr = StringCchCopyW((*ppxfcTail)->wzId, countof((*ppxfcTail)->wzId), pwzData);
167 ExitOnFailure(hr, "failed to copy Wix4XmlConfig record Id");
168
169 // Get component name
170 hr = WcaGetRecordString(hRec, xfqComponent, &pwzData);
171 ExitOnFailure(hr, "failed to get component name for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId);
172
173 // Get the component's state
174 if (pwzData && *pwzData)
175 {
176 hr = StringCchCopyW((*ppxfcTail)->wzComponent, countof((*ppxfcTail)->wzComponent), pwzData);
177 ExitOnFailure(hr, "failed to copy component id");
178
179 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), (*ppxfcTail)->wzComponent, &(*ppxfcTail)->isInstalled, &(*ppxfcTail)->isAction);
180 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "failed to get install state for component id");
181 }
182
183 // Get the xml file
184 hr = WcaGetRecordFormattedString(hRec, xfqFile, &pwzData);
185 ExitOnFailure(hr, "failed to get xml file for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId);
186 hr = StringCchCopyW((*ppxfcTail)->wzFile, countof((*ppxfcTail)->wzFile), pwzData);
187 ExitOnFailure(hr, "failed to copy xml file path");
188
189 // Figure out if the file is already on the machine or if it's being installed
190 hr = WcaGetRecordString(hRec, xfqFile, &pwzData);
191 ExitOnFailure(hr, "failed to get xml file for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId);
192 if (NULL != wcsstr(pwzData, L"[!") || NULL != wcsstr(pwzData, L"[#"))
193 {
194 (*ppxfcTail)->fInstalledFile = TRUE;
195 }
196
197 // Get the Wix4XmlConfig table flags
198 hr = WcaGetRecordInteger(hRec, xfqXmlFlags, &(*ppxfcTail)->iXmlFlags);
199 ExitOnFailure(hr, "failed to get Wix4XmlConfig flags for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId);
200
201 // Get the Element Id
202 hr = WcaGetRecordFormattedString(hRec, xfqElementId, &(*ppxfcTail)->pwzElementId);
203 ExitOnFailure(hr, "failed to get Element Id for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId);
204
205 // Get the Element Path
206 hr = WcaGetRecordFormattedString(hRec, xfqElementPath, &(*ppxfcTail)->pwzElementPath);
207 ExitOnFailure(hr, "failed to get Element Path for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId);
208
209 // Get the Verify Path
210 hr = WcaGetRecordFormattedString(hRec, xfqVerifyPath, &(*ppxfcTail)->pwzVerifyPath);
211 ExitOnFailure(hr, "failed to get Verify Path for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId);
212
213 // Get the name
214 hr = WcaGetRecordFormattedString(hRec, xfqName, &pwzData);
215 ExitOnFailure(hr, "failed to get Name for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId);
216 hr = StringCchCopyW((*ppxfcTail)->wzName, countof((*ppxfcTail)->wzName), pwzData);
217 ExitOnFailure(hr, "failed to copy name of element");
218
219 // Get the value
220 hr = WcaGetRecordFormattedString(hRec, xfqValue, &pwzData);
221 ExitOnFailure(hr, "failed to get Value for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId);
222 hr = StrAllocString(&(*ppxfcTail)->pwzValue, pwzData, 0);
223 ExitOnFailure(hr, "failed to allocate buffer for value");
224
225 // Get the component attributes
226 hr = WcaGetRecordInteger(hRec, xfqCompAttributes, &(*ppxfcTail)->iCompAttributes);
227 ExitOnFailure(hr, "failed to get component attributes for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId);
228 }
229
230 // if we looped through all records all is well
231 if (E_NOMOREITEMS == hr)
232 {
233 hr = S_OK;
234 }
235 ExitOnFailure(hr, "failed while looping through all objects to secure");
236
237LExit:
238 ReleaseStr(pwzData);
239
240 return hr;
241}
242
243static HRESULT ProcessChanges(
244 __inout XML_CONFIG_CHANGE** ppxfcHead
245 )
246{
247 Assert(ppxfcHead && *ppxfcHead);
248 HRESULT hr = S_OK;
249
250 XML_CONFIG_CHANGE* pxfc = NULL;
251 XML_CONFIG_CHANGE* pxfcNext = NULL;
252 XML_CONFIG_CHANGE* pxfcCheck = NULL;
253 int cAdditionalChanges = 0;
254 XML_CONFIG_CHANGE* pxfcLast = NULL;
255
256 // If there's only one item in the list, none of this matters
257 if (pxfc && !pxfc->pxfcNext)
258 {
259 ExitFunction();
260 }
261
262 // Loop through the list
263 pxfc = *ppxfcHead;
264 while (pxfc)
265 {
266 // Keep track of where our next spot will be since our current node may be moved
267 pxfcNext = pxfc->pxfcNext;
268
269 // With each node, check to see if it's element path matches the Id of some other node in the list
270 pxfcCheck = *ppxfcHead;
271 while (pxfcCheck)
272 {
273 if (pxfc->pwzElementId)
274 {
275 if (0 == lstrcmpW(pxfc->pwzElementId, pxfcCheck->wzId)
276 && 0 == pxfc->iXmlFlags
277 && XMLCONFIG_CREATE & pxfcCheck->iXmlFlags
278 && XMLCONFIG_ELEMENT & pxfcCheck->iXmlFlags)
279 {
280 // We found a match. First, take it out of the current list
281 if (pxfc->pxfcPrev)
282 {
283 pxfc->pxfcPrev->pxfcNext = pxfc->pxfcNext;
284 }
285 else // it was the head. Update the head
286 {
287 *ppxfcHead = pxfc->pxfcNext;
288 }
289
290 if (pxfc->pxfcNext)
291 {
292 pxfc->pxfcNext->pxfcPrev = pxfc->pxfcPrev;
293 }
294
295 pxfc->pxfcNext = NULL;
296 pxfc->pxfcPrev = NULL;
297
298 // Now, add this node to the end of the matched node's additional changes list
299 if (!pxfcCheck->pxfcAdditionalChanges)
300 {
301 pxfcCheck->pxfcAdditionalChanges = pxfc;
302 pxfcCheck->cAdditionalChanges = 1;
303 }
304 else
305 {
306 pxfcLast = pxfcCheck->pxfcAdditionalChanges;
307 cAdditionalChanges = 1;
308 while (pxfcLast->pxfcNext)
309 {
310 pxfcLast = pxfcLast->pxfcNext;
311 ++cAdditionalChanges;
312 }
313 pxfcLast->pxfcNext = pxfc;
314 pxfc->pxfcPrev = pxfcLast;
315 pxfcCheck->cAdditionalChanges = ++cAdditionalChanges;
316 }
317 }
318 else
319 {
320 hr = E_NOTFOUND;
321 ExitOnRootFailure(hr, "failed to find matching ElementId: %ls", pxfc->pwzElementId);
322 }
323 }
324
325 pxfcCheck = pxfcCheck->pxfcNext;
326 }
327
328 pxfc = pxfcNext;
329 }
330
331LExit:
332
333 return hr;
334}
335
336
337static HRESULT BeginChangeFile(
338 __in LPCWSTR pwzFile,
339 __in int iCompAttributes,
340 __inout LPWSTR* ppwzCustomActionData
341 )
342{
343 Assert(pwzFile && *pwzFile && ppwzCustomActionData);
344
345 HRESULT hr = S_OK;
346 BOOL fIs64Bit = iCompAttributes & msidbComponentAttributes64bit;
347
348 LPBYTE pbData = NULL;
349 SIZE_T cbData = 0;
350
351 LPWSTR pwzRollbackCustomActionData = NULL;
352
353 if (fIs64Bit)
354 {
355 hr = WcaWriteIntegerToCaData((int)xaOpenFilex64, ppwzCustomActionData);
356 ExitOnFailure(hr, "failed to write 64-bit file indicator to custom action data");
357 }
358 else
359 {
360 hr = WcaWriteIntegerToCaData((int)xaOpenFile, ppwzCustomActionData);
361 ExitOnFailure(hr, "failed to write file indicator to custom action data");
362 }
363
364 hr = WcaWriteStringToCaData(pwzFile, ppwzCustomActionData);
365 ExitOnFailure(hr, "failed to write file to custom action data: %ls", pwzFile);
366
367 // If the file already exits, then we have to put it back the way it was on failure
368 if (FileExistsEx(pwzFile, NULL))
369 {
370 hr = FileRead(&pbData, &cbData, pwzFile);
371 ExitOnFailure(hr, "failed to read file: %ls", pwzFile);
372
373 // Set up the rollback for this file
374 hr = WcaWriteIntegerToCaData((int)fIs64Bit, &pwzRollbackCustomActionData);
375 ExitOnFailure(hr, "failed to write component bitness to rollback custom action data");
376
377 hr = WcaWriteStringToCaData(pwzFile, &pwzRollbackCustomActionData);
378 ExitOnFailure(hr, "failed to write file name to rollback custom action data: %ls", pwzFile);
379
380 hr = WcaWriteStreamToCaData(pbData, cbData, &pwzRollbackCustomActionData);
381 ExitOnFailure(hr, "failed to write file contents to rollback custom action data.");
382
383 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecXmlConfigRollback"), pwzRollbackCustomActionData, COST_XMLFILE);
384 ExitOnFailure(hr, "failed to schedule ExecXmlConfigRollback for file: %ls", pwzFile);
385
386 ReleaseStr(pwzRollbackCustomActionData);
387 }
388LExit:
389 ReleaseMem(pbData);
390
391 return hr;
392}
393
394
395static HRESULT WriteChangeData(
396 __in XML_CONFIG_CHANGE* pxfc,
397 __in eXmlAction action,
398 __inout LPWSTR* ppwzCustomActionData
399 )
400{
401 Assert(pxfc && ppwzCustomActionData);
402
403 HRESULT hr = S_OK;
404 XML_CONFIG_CHANGE* pxfcAdditionalChanges = NULL;
405 LPCWSTR wzElementPath = pxfc->pwzElementId ? pxfc->pwzElementId : pxfc->pwzElementPath;
406
407 hr = WcaWriteStringToCaData(wzElementPath, ppwzCustomActionData);
408 ExitOnFailure(hr, "failed to write ElementPath to custom action data: %ls", wzElementPath);
409
410 hr = WcaWriteStringToCaData(pxfc->pwzVerifyPath, ppwzCustomActionData);
411 ExitOnFailure(hr, "failed to write VerifyPath to custom action data: %ls", pxfc->pwzVerifyPath);
412
413 hr = WcaWriteStringToCaData(pxfc->wzName, ppwzCustomActionData);
414 ExitOnFailure(hr, "failed to write Name to custom action data: %ls", pxfc->wzName);
415
416 hr = WcaWriteStringToCaData(pxfc->pwzValue, ppwzCustomActionData);
417 ExitOnFailure(hr, "failed to write Value to custom action data: %ls", pxfc->pwzValue);
418
419 if (pxfc->iXmlFlags & XMLCONFIG_CREATE && pxfc->iXmlFlags & XMLCONFIG_ELEMENT && xaCreateElement == action && pxfc->pxfcAdditionalChanges)
420 {
421 hr = WcaWriteIntegerToCaData(pxfc->cAdditionalChanges, ppwzCustomActionData);
422 ExitOnFailure(hr, "failed to write additional changes value to custom action data");
423
424 pxfcAdditionalChanges = pxfc->pxfcAdditionalChanges;
425 while (pxfcAdditionalChanges)
426 {
427 Assert((0 == lstrcmpW(pxfcAdditionalChanges->wzComponent, pxfc->wzComponent)) && 0 == pxfcAdditionalChanges->iXmlFlags && (0 == lstrcmpW(pxfcAdditionalChanges->wzFile, pxfc->wzFile)));
428
429 hr = WcaWriteStringToCaData(pxfcAdditionalChanges->wzName, ppwzCustomActionData);
430 ExitOnFailure(hr, "failed to write Name to custom action data: %ls", pxfc->wzName);
431
432 hr = WcaWriteStringToCaData(pxfcAdditionalChanges->pwzValue, ppwzCustomActionData);
433 ExitOnFailure(hr, "failed to write Value to custom action data: %ls", pxfc->pwzValue);
434
435 pxfcAdditionalChanges = pxfcAdditionalChanges->pxfcNext;
436 }
437 }
438 else
439 {
440 hr = WcaWriteIntegerToCaData(0, ppwzCustomActionData);
441 ExitOnFailure(hr, "failed to write additional changes value to custom action data");
442 }
443
444LExit:
445 return hr;
446}
447
448
449/******************************************************************
450 SchedXmlConfig - entry point for XmlConfig Custom Action
451
452********************************************************************/
453extern "C" UINT __stdcall SchedXmlConfig(
454 __in MSIHANDLE hInstall
455 )
456{
457// AssertSz(FALSE, "debug SchedXmlConfig");
458
459 HRESULT hr = S_OK;
460 UINT er = ERROR_SUCCESS;
461
462 LPWSTR pwzCurrentFile = NULL;
463 BOOL fCurrentFileChanged = FALSE;
464
465 PMSIHANDLE hView = NULL;
466 PMSIHANDLE hRec = NULL;
467
468 XML_CONFIG_CHANGE* pxfcHead = NULL;
469 XML_CONFIG_CHANGE* pxfcTail = NULL; // TODO: do we need this any more?
470 XML_CONFIG_CHANGE* pxfc = NULL;
471
472 eXmlAction xa = xaUnknown;
473 eXmlPreserveDate xd;
474
475 LPWSTR pwzCustomActionData = NULL;
476
477 DWORD cFiles = 0;
478
479 // initialize
480 hr = WcaInitialize(hInstall, "SchedXmlConfig");
481 ExitOnFailure(hr, "failed to initialize");
482
483 hr = ReadXmlConfigTable(&pxfcHead, &pxfcTail);
484 MessageExitOnFailure(hr, msierrXmlConfigFailedRead, "failed to read Wix4XmlConfig table");
485
486 hr = ProcessChanges(&pxfcHead);
487 ExitOnFailure(hr, "failed to process Wix4XmlConfig changes");
488
489 // loop through all the xml configurations
490 for (pxfc = pxfcHead; pxfc; pxfc = pxfc->pxfcNext)
491 {
492 // If this is a different file, or the first file...
493 if (NULL == pwzCurrentFile || 0 != lstrcmpW(pwzCurrentFile, pxfc->wzFile))
494 {
495 // Remember the file we're currently working on
496 hr = StrAllocString(&pwzCurrentFile, pxfc->wzFile, 0);
497 ExitOnFailure(hr, "failed to copy file name");
498
499 fCurrentFileChanged = TRUE;
500 }
501
502 //
503 // Figure out what action to take
504 //
505 xa = xaUnknown;
506
507 // If it's being installed or reinstalled or uninstalled and that matches
508 // what we are doing then calculate the right action.
509 if ((XMLCONFIG_INSTALL & pxfc->iXmlFlags && (WcaIsInstalling(pxfc->isInstalled, pxfc->isAction) || WcaIsReInstalling(pxfc->isInstalled, pxfc->isAction))) ||
510 (XMLCONFIG_UNINSTALL & pxfc->iXmlFlags && WcaIsUninstalling(pxfc->isInstalled, pxfc->isAction)))
511 {
512 if (XMLCONFIG_CREATE & pxfc->iXmlFlags && XMLCONFIG_ELEMENT & pxfc->iXmlFlags)
513 {
514 xa = xaCreateElement;
515 }
516 else if (XMLCONFIG_DELETE & pxfc->iXmlFlags && XMLCONFIG_ELEMENT & pxfc->iXmlFlags)
517 {
518 xa = xaDeleteElement;
519 }
520 else if (XMLCONFIG_DELETE & pxfc->iXmlFlags && XMLCONFIG_VALUE & pxfc->iXmlFlags)
521 {
522 xa = xaDeleteValue;
523 }
524 else if (XMLCONFIG_CREATE & pxfc->iXmlFlags && XMLCONFIG_VALUE & pxfc->iXmlFlags)
525 {
526 xa = xaWriteValue;
527 }
528 else if (XMLCONFIG_CREATE & pxfc->iXmlFlags && XMLCONFIG_DOCUMENT & pxfc->iXmlFlags)
529 {
530 xa = xaWriteDocument;
531 }
532 else if (XMLCONFIG_DELETE & pxfc->iXmlFlags && XMLCONFIG_DOCUMENT & pxfc->iXmlFlags)
533 {
534 hr = E_INVALIDARG;
535 ExitOnFailure(hr, "Invalid flag configuration. Cannot delete a fragment node.");
536 }
537 }
538
539 if (XMLCONFIG_PRESERVE_MODIFIED & pxfc->iXmlFlags)
540 {
541 xd = xdPreserve;
542 }
543 else
544 {
545 xd= xdDontPreserve;
546 }
547
548 if (xaUnknown != xa)
549 {
550 if (fCurrentFileChanged)
551 {
552 hr = BeginChangeFile(pwzCurrentFile, pxfc->iCompAttributes, &pwzCustomActionData);
553 ExitOnFailure(hr, "failed to begin file change for file: %ls", pwzCurrentFile);
554
555 fCurrentFileChanged = FALSE;
556 ++cFiles;
557 }
558
559 hr = WcaWriteIntegerToCaData((int)xa, &pwzCustomActionData);
560 ExitOnFailure(hr, "failed to write action indicator custom action data");
561
562 hr = WcaWriteIntegerToCaData((int)xd, &pwzCustomActionData);
563 ExitOnFailure(hr, "failed to write Preserve Date indicator to custom action data");
564
565 hr = WriteChangeData(pxfc, xa, &pwzCustomActionData);
566 ExitOnFailure(hr, "failed to write change data");
567 }
568 }
569
570 // If we looped through all records all is well
571 if (E_NOMOREITEMS == hr)
572 {
573 hr = S_OK;
574 }
575 ExitOnFailure(hr, "failed while looping through all objects to secure");
576
577 // Schedule the custom action and add to progress bar
578 if (pwzCustomActionData && *pwzCustomActionData)
579 {
580 Assert(0 < cFiles);
581
582 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecXmlConfig"), pwzCustomActionData, cFiles * COST_XMLFILE);
583 ExitOnFailure(hr, "failed to schedule ExecXmlConfig action");
584 }
585
586LExit:
587 ReleaseStr(pwzCurrentFile);
588 ReleaseStr(pwzCustomActionData);
589
590 FreeXmlConfigChangeList(pxfcHead);
591
592 if (FAILED(hr))
593 {
594 er = ERROR_INSTALL_FAILURE;
595 }
596 return WcaFinalize(er);
597}
598
599
600/******************************************************************
601 ExecXmlConfig - entry point for XmlConfig Custom Action
602
603*******************************************************************/
604extern "C" UINT __stdcall ExecXmlConfig(
605 __in MSIHANDLE hInstall
606 )
607{
608 //AssertSz(FALSE, "debug ExecXmlConfig");
609 HRESULT hr = S_OK;
610 HRESULT hrOpenFailure = S_OK;
611 UINT er = ERROR_SUCCESS;
612
613#ifndef _WIN64
614 BOOL fIsFSRedirectDisabled = FALSE;
615#endif
616 BOOL fPreserveDate = FALSE;
617
618 LPWSTR pwzCustomActionData = NULL;
619 LPWSTR pwzData = NULL;
620 LPWSTR pwzFile = NULL;
621 LPWSTR pwzElementPath = NULL;
622 LPWSTR pwzVerifyPath = NULL;
623 LPWSTR pwzName = NULL;
624 LPWSTR pwzValue = NULL;
625 LPWSTR pwz = NULL;
626 int cAdditionalChanges = 0;
627
628 IXMLDOMDocument* pixd = NULL;
629 IXMLDOMNode* pixn = NULL;
630 IXMLDOMNode* pixnVerify = NULL;
631 IXMLDOMNode* pixnNewNode = NULL;
632 IXMLDOMNode* pixnRemovedChild = NULL;
633
634 IXMLDOMDocument* pixdNew = NULL;
635 IXMLDOMElement* pixeNew = NULL;
636
637 FILETIME ft;
638
639 int id = IDRETRY;
640
641 eXmlAction xa;
642 eXmlPreserveDate xd;
643
644 // initialize
645 hr = WcaInitialize(hInstall, "ExecXmlConfig");
646 ExitOnFailure(hr, "failed to initialize");
647
648 hr = XmlInitialize();
649 ExitOnFailure(hr, "failed to initialize xml utilities");
650
651 hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData);
652 ExitOnFailure(hr, "failed to get CustomActionData");
653
654 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData);
655
656 pwz = pwzCustomActionData;
657
658 hr = WcaReadIntegerFromCaData(&pwz, (int*) &xa);
659 ExitOnFailure(hr, "failed to process CustomActionData");
660
661#ifndef _WIN64
662 // Initialize the Wow64 API - store the result in fWow64APIPresent
663 // If it fails, this doesn't warrant an error yet, because we only need the Wow64 API in some cases
664 WcaInitializeWow64();
665 BOOL fIsWow64Process = WcaIsWow64Process();
666#endif
667
668 if (xaOpenFile != xa && xaOpenFilex64 != xa)
669 {
670 ExitOnFailure(hr = E_INVALIDARG, "invalid custom action data");
671 }
672
673 // loop through all the passed in data
674 while (pwz && *pwz)
675 {
676 hr = WcaReadStringFromCaData(&pwz, &pwzFile);
677 ExitOnFailure(hr, "failed to read file name from custom action data");
678
679 // Default to not preserve date, preserve it if any modifications require us to
680 fPreserveDate = FALSE;
681
682 // Open the file
683 ReleaseNullObject(pixd);
684
685#ifndef _WIN64
686 if (xaOpenFilex64 == xa)
687 {
688 if (!fIsWow64Process)
689 {
690 hr = E_NOTIMPL;
691 ExitOnFailure(hr, "Custom action was told to act on a 64-bit component, but the custom action process is not running in WOW.");
692 }
693
694 hr = WcaDisableWow64FSRedirection();
695 ExitOnFailure(hr, "Custom action was told to act on a 64-bit component, but was unable to disable filesystem redirection through the Wow64 API.");
696
697 fIsFSRedirectDisabled = TRUE;
698 }
699#endif
700
701 hr = XmlLoadDocumentFromFileEx(pwzFile, XML_LOAD_PRESERVE_WHITESPACE, &pixd);
702 if (FAILED(hr))
703 {
704 // Ignore the return code for now. If they try to add something, we'll fail the install. If all they do is remove stuff then it doesn't matter.
705 hrOpenFailure = hr;
706 hr = S_OK;
707 }
708 else
709 {
710 hrOpenFailure = S_OK;
711 }
712
713 WcaLog(LOGMSG_VERBOSE, "Configuring Xml File: %ls", pwzFile);
714
715 while (pwz && *pwz)
716 {
717 // If we skip past an element that has additional changes we need to strip them off the stream before
718 // moving on to the next element. Do that now and then restart the outer loop.
719 if (cAdditionalChanges > 0)
720 {
721 while (cAdditionalChanges > 0)
722 {
723 hr = WcaReadStringFromCaData(&pwz, &pwzName);
724 ExitOnFailure(hr, "failed to process CustomActionData");
725 hr = WcaReadStringFromCaData(&pwz, &pwzValue);
726 ExitOnFailure(hr, "failed to process CustomActionData");
727
728 cAdditionalChanges--;
729 }
730 continue;
731 }
732
733 hr = WcaReadIntegerFromCaData(&pwz, (int*) &xa);
734 ExitOnFailure(hr, "failed to process CustomActionData");
735
736 // Break if we need to move on to a different file
737 if (xaOpenFile == xa || xaOpenFilex64 == xa)
738 {
739 break;
740 }
741
742 hr = WcaReadIntegerFromCaData(&pwz, (int*) &xd);
743 ExitOnFailure(hr, "failed to process CustomActionData");
744
745 if (xdPreserve == xd)
746 {
747 fPreserveDate = TRUE;
748 }
749
750 // Get path, name, and value to be written
751 hr = WcaReadStringFromCaData(&pwz, &pwzElementPath);
752 ExitOnFailure(hr, "failed to process CustomActionData");
753 hr = WcaReadStringFromCaData(&pwz, &pwzVerifyPath);
754 ExitOnFailure(hr, "failed to process CustomActionData");
755 hr = WcaReadStringFromCaData(&pwz, &pwzName);
756 ExitOnFailure(hr, "failed to process CustomActionData");
757 hr = WcaReadStringFromCaData(&pwz, &pwzValue);
758 ExitOnFailure(hr, "failed to process CustomActionData");
759 hr = WcaReadIntegerFromCaData(&pwz, &cAdditionalChanges);
760 ExitOnFailure(hr, "failed to process CustomActionData");
761
762 // If we failed to open the file and we're adding something to the file, we've got a problem. Otherwise, just continue on since the file's already gone.
763 if (FAILED(hrOpenFailure))
764 {
765 if (xaCreateElement == xa || xaWriteValue == xa || xaWriteDocument == xa)
766 {
767 MessageExitOnFailure(hr = hrOpenFailure, msierrXmlConfigFailedOpen, "failed to load XML file: %ls", pwzFile);
768 }
769 else
770 {
771 continue;
772 }
773 }
774
775 // Select the node we're about to modify
776 ReleaseNullObject(pixn);
777
778 hr = XmlSelectSingleNode(pixd, pwzElementPath, &pixn);
779
780 // If we failed to find the node that we are going to add to, we've got a problem. Otherwise, just continue since the node's already gone.
781 if (S_FALSE == hr)
782 {
783 if (xaCreateElement == xa || xaWriteValue == xa || xaWriteDocument == xa)
784 {
785 hr = HRESULT_FROM_WIN32(ERROR_OBJECT_NOT_FOUND);
786 }
787 else
788 {
789 hr = S_OK;
790 continue;
791 }
792 }
793
794 MessageExitOnFailure(hr, msierrXmlConfigFailedSelect, "failed to find node: %ls in XML file: %ls", pwzElementPath, pwzFile);
795
796 // Make the modification
797 switch (xa)
798 {
799 case xaWriteValue:
800 if (pwzName && *pwzName)
801 {
802 // We're setting an attribute
803 hr = XmlSetAttribute(pixn, pwzName, pwzValue);
804 ExitOnFailure(hr, "failed to set attribute: %ls to value %ls", pwzName, pwzValue);
805 }
806 else
807 {
808 // We're setting the text of the node
809 hr = XmlSetText(pixn, pwzValue);
810 ExitOnFailure(hr, "failed to set text to: %ls for element %ls. Make sure that XPath points to an element.", pwzValue, pwzElementPath);
811 }
812 break;
813 case xaWriteDocument:
814 if (NULL != pwzVerifyPath && 0 != pwzVerifyPath[0])
815 {
816 hr = XmlSelectSingleNode(pixn, pwzVerifyPath, &pixnVerify);
817 if (S_OK == hr)
818 {
819 // We found the verify path which means we have no further work to do
820 continue;
821 }
822 ExitOnFailure(hr, "failed to query verify path: %ls", pwzVerifyPath);
823 }
824
825 hr = XmlLoadDocumentEx(pwzValue, XML_LOAD_PRESERVE_WHITESPACE, &pixdNew);
826 ExitOnFailure(hr, "Failed to load value as document.");
827
828 hr = pixdNew->get_documentElement(&pixeNew);
829 ExitOnFailure(hr, "Failed to get document element.");
830
831 hr = pixn->appendChild(pixeNew, NULL);
832 ExitOnFailure(hr, "Failed to append document element on to parent element.");
833
834 ReleaseNullObject(pixeNew);
835 ReleaseNullObject(pixdNew);
836 break;
837
838 case xaCreateElement:
839 if (NULL != pwzVerifyPath && 0 != pwzVerifyPath[0])
840 {
841 hr = XmlSelectSingleNode(pixn, pwzVerifyPath, &pixnVerify);
842 if (S_OK == hr)
843 {
844 // We found the verify path which means we have no further work to do
845 continue;
846 }
847 ExitOnFailure(hr, "failed to query verify path: %ls", pwzVerifyPath);
848 }
849
850 hr = XmlCreateChild(pixn, pwzName, &pixnNewNode);
851 ExitOnFailure(hr, "failed to create child element: %ls", pwzName);
852
853 if (pwzValue && *pwzValue)
854 {
855 hr = XmlSetText(pixnNewNode, pwzValue);
856 ExitOnFailure(hr, "failed to set text to: %ls for node: %ls", pwzValue, pwzName);
857 }
858
859 while (cAdditionalChanges > 0)
860 {
861 hr = WcaReadStringFromCaData(&pwz, &pwzName);
862 ExitOnFailure(hr, "failed to process CustomActionData");
863 hr = WcaReadStringFromCaData(&pwz, &pwzValue);
864 ExitOnFailure(hr, "failed to process CustomActionData");
865
866 // Set the additional attribute
867 hr = XmlSetAttribute(pixnNewNode, pwzName, pwzValue);
868 ExitOnFailure(hr, "failed to set attribute: %ls to value %ls", pwzName, pwzValue);
869
870 cAdditionalChanges--;
871 }
872
873 ReleaseNullObject(pixnNewNode);
874 break;
875 case xaDeleteValue:
876 if (pwzName && *pwzName)
877 {
878 // Delete the attribute
879 hr = XmlRemoveAttribute(pixn, pwzName);
880 ExitOnFailure(hr, "failed to remove attribute: %ls", pwzName);
881 }
882 else
883 {
884 // Clear the text value for the node
885 hr = XmlSetText(pixn, L"");
886 ExitOnFailure(hr, "failed to clear text value");
887 }
888 break;
889 case xaDeleteElement:
890 if (NULL != pwzVerifyPath && 0 != pwzVerifyPath[0])
891 {
892 hr = XmlSelectSingleNode(pixn, pwzVerifyPath, &pixnVerify);
893 if (S_OK == hr)
894 {
895 hr = pixn->removeChild(pixnVerify, &pixnRemovedChild);
896 ExitOnFailure(hr, "failed to remove created child element");
897
898 ReleaseNullObject(pixnRemovedChild);
899 }
900 else
901 {
902 WcaLog(LOGMSG_VERBOSE, "Failed to select path %ls for deleting. Skipping...", pwzVerifyPath);
903 hr = S_OK;
904 }
905 }
906 else
907 {
908 // TODO: This requires a VerifyPath to delete an element. Should we support not having one?
909 WcaLog(LOGMSG_VERBOSE, "No VerifyPath specified for delete element of ID: %ls", pwzElementPath);
910 }
911 break;
912 default:
913 ExitOnFailure(hr = E_UNEXPECTED, "Invalid modification specified in custom action data");
914 break;
915 }
916 }
917
918
919 // Now that we've made all of the changes to this file, save it and move on to the next
920 if (S_OK == hrOpenFailure)
921 {
922 if (fPreserveDate)
923 {
924 hr = FileGetTime(pwzFile, NULL, NULL, &ft);
925 ExitOnFailure(hr, "failed to get modified time of file : %ls", pwzFile);
926 }
927
928 int iSaveAttempt = 0;
929
930 do
931 {
932 hr = XmlSaveDocument(pixd, pwzFile);
933 if (FAILED(hr))
934 {
935 id = WcaErrorMessage(msierrXmlConfigFailedSave, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 1, pwzFile);
936 switch (id)
937 {
938 case IDABORT:
939 ExitOnFailure(hr, "Failed to save changes to XML file: %ls", pwzFile);
940 case IDRETRY:
941 hr = S_FALSE; // hit me, baby, one more time
942 break;
943 case IDIGNORE:
944 hr = S_OK; // pretend everything is okay and bail
945 break;
946 case 0: // No UI case, MsiProcessMessage returns 0
947 if (STIERR_SHARING_VIOLATION == hr)
948 {
949 // Only in case of sharing violation do we retry 30 times, once a second.
950 if (iSaveAttempt < 30)
951 {
952 hr = S_FALSE;
953 ++iSaveAttempt;
954 WcaLog(LOGMSG_VERBOSE, "Unable to save changes to XML file: %ls, retry attempt: %x", pwzFile, iSaveAttempt);
955 Sleep(1000);
956 }
957 else
958 {
959 ExitOnFailure(hr, "Failed to save changes to XML file: %ls", pwzFile);
960 }
961 }
962 break;
963 default: // Unknown error
964 ExitOnFailure(hr, "Failed to save changes to XML file: %ls", pwzFile);
965 }
966 }
967 } while (S_FALSE == hr);
968
969 if (fPreserveDate)
970 {
971 hr = FileSetTime(pwzFile, NULL, NULL, &ft);
972 ExitOnFailure(hr, "failed to set modified time of file : %ls", pwzFile);
973 }
974
975#ifndef _WIN64
976 if (fIsFSRedirectDisabled)
977 {
978 fIsFSRedirectDisabled = FALSE;
979 WcaRevertWow64FSRedirection();
980 }
981#endif
982 }
983 }
984
985LExit:
986#ifndef _WIN64
987 // Make sure we revert FS Redirection if necessary before exiting
988 if (fIsFSRedirectDisabled)
989 {
990 fIsFSRedirectDisabled = FALSE;
991 WcaRevertWow64FSRedirection();
992 }
993 WcaFinalizeWow64();
994#endif
995
996 ReleaseStr(pwzCustomActionData);
997 ReleaseStr(pwzData);
998 ReleaseStr(pwzFile);
999 ReleaseStr(pwzElementPath);
1000 ReleaseStr(pwzVerifyPath);
1001 ReleaseStr(pwzName);
1002 ReleaseStr(pwzValue);
1003
1004 ReleaseObject(pixeNew);
1005 ReleaseObject(pixdNew);
1006
1007 ReleaseObject(pixn);
1008 ReleaseObject(pixd);
1009 ReleaseObject(pixnNewNode);
1010 ReleaseObject(pixnRemovedChild);
1011
1012 XmlUninitialize();
1013
1014 if (FAILED(hr))
1015 {
1016 er = ERROR_INSTALL_FAILURE;
1017 }
1018 return WcaFinalize(er);
1019}
1020
1021
1022/******************************************************************
1023 ExecXmlConfigRollback - entry point for XmlConfig rollback Custom Action
1024
1025*******************************************************************/
1026extern "C" UINT __stdcall ExecXmlConfigRollback(
1027 __in MSIHANDLE hInstall
1028 )
1029{
1030// AssertSz(FALSE, "debug ExecXmlConfigRollback");
1031 HRESULT hr = S_OK;
1032 UINT er = ERROR_SUCCESS;
1033
1034 int iIs64Bit;
1035#ifndef _WIN64
1036 BOOL fIs64Bit = FALSE;
1037#endif
1038
1039 LPWSTR pwzCustomActionData = NULL;
1040 LPWSTR pwz = NULL;
1041 LPWSTR pwzFileName = NULL;
1042 LPBYTE pbData = NULL;
1043 DWORD_PTR cbData = 0;
1044
1045 FILETIME ft;
1046
1047 HANDLE hFile = INVALID_HANDLE_VALUE;
1048
1049 // initialize
1050 hr = WcaInitialize(hInstall, "ExecXmlConfigRollback");
1051 ExitOnFailure(hr, "failed to initialize");
1052
1053
1054 hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData);
1055 ExitOnFailure(hr, "failed to get CustomActionData");
1056
1057 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData);
1058
1059 pwz = pwzCustomActionData;
1060
1061 hr = WcaReadIntegerFromCaData(&pwz, &iIs64Bit);
1062 ExitOnFailure(hr, "failed to read component bitness from custom action data");
1063
1064 hr = WcaReadStringFromCaData(&pwz, &pwzFileName);
1065 ExitOnFailure(hr, "failed to read file name from custom action data");
1066
1067 hr = WcaReadStreamFromCaData(&pwz, &pbData, &cbData);
1068 ExitOnFailure(hr, "failed to read file contents from custom action data");
1069
1070#ifndef _WIN64
1071 fIs64Bit = (BOOL)iIs64Bit;
1072
1073 if (fIs64Bit)
1074 {
1075 hr = WcaInitializeWow64();
1076 if (S_FALSE == hr)
1077 {
1078 hr = TYPE_E_DLLFUNCTIONNOTFOUND;
1079 }
1080 ExitOnFailure(hr, "failed to initialize Wow64 API");
1081
1082 if (!WcaIsWow64Process())
1083 {
1084 hr = E_NOTIMPL;
1085 ExitOnFailure(hr, "Custom action was told to rollback a 64-bit component, but the Wow64 API is unavailable.");
1086 }
1087
1088 hr = WcaDisableWow64FSRedirection();
1089 ExitOnFailure(hr, "Custom action was told to rollback a 64-bit component, but was unable to Disable Filesystem Redirection through the Wow64 API.");
1090 }
1091#endif
1092
1093 hr = FileGetTime(pwzFileName, NULL, NULL, &ft);
1094 ExitOnFailure(hr, "Failed to get modified date of file %ls.", pwzFileName);
1095
1096 // Open the file
1097 hFile = ::CreateFileW(pwzFileName, GENERIC_WRITE, NULL, NULL, TRUNCATE_EXISTING, NULL, NULL);
1098 ExitOnInvalidHandleWithLastError(hFile, hr, "failed to open file: %ls", pwzFileName);
1099
1100 // Write out the old data
1101 hr = FileWriteHandle(hFile, pbData, cbData);
1102 ExitOnFailure(hr, "failed to write to file: %ls", pwzFileName);
1103
1104 ReleaseFile(hFile);
1105
1106 hr = FileSetTime(pwzFileName, NULL, NULL, &ft);
1107 ExitOnFailure(hr, "Failed to set modified date of file %ls.", pwzFileName);
1108
1109LExit:
1110 ReleaseStr(pwzCustomActionData);
1111 ReleaseStr(pwzFileName);
1112
1113 ReleaseFile(hFile);
1114
1115#ifndef _WIN64
1116 if (fIs64Bit)
1117 {
1118 WcaRevertWow64FSRedirection();
1119 WcaFinalizeWow64();
1120 }
1121#endif
1122
1123 ReleaseMem(pbData);
1124
1125 if (FAILED(hr))
1126 {
1127 er = ERROR_INSTALL_FAILURE;
1128 }
1129 return WcaFinalize(er);
1130}
diff --git a/src/ext/Util/ca/XmlFile.cpp b/src/ext/Util/ca/XmlFile.cpp
new file mode 100644
index 00000000..04a4ae98
--- /dev/null
+++ b/src/ext/Util/ca/XmlFile.cpp
@@ -0,0 +1,940 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5#define XMLFILE_CREATE_ELEMENT 0x00000001
6#define XMLFILE_DELETE_VALUE 0x00000002
7#define XMLFILE_BULKWRITE_VALUE 0x00000004
8
9#define XMLFILE_DONT_UNINSTALL 0x00010000
10#define XMLFILE_PRESERVE_MODIFIED 0x00001000
11#define XMLFILE_USE_XPATH 0x00000100
12
13extern BOOL vfMsxml30;
14
15enum eXmlAction
16{
17 xaOpenFile = 1,
18 xaOpenFilex64,
19 xaWriteValue,
20 xaDeleteValue,
21 xaCreateElement,
22 xaDeleteElement,
23 xaBulkWriteValue,
24};
25
26enum eXmlPreserveDate
27{
28 xdDontPreserve = 0,
29 xdPreserve
30};
31
32enum eXmlSelectionLanguage
33{
34 xsXSLPattern = 0,
35 xsXPath = 1,
36};
37
38LPCWSTR vcsXmlFileQuery =
39 L"SELECT `Wix4XmlFile`.`Wix4XmlFile`, `Wix4XmlFile`.`File`, `Wix4XmlFile`.`ElementPath`, `Wix4XmlFile`.`Name`, `Wix4XmlFile`.`Value`, "
40 L"`Wix4XmlFile`.`Flags`, `Wix4XmlFile`.`Component_`, `Component`.`Attributes` "
41 L"FROM `Wix4XmlFile`,`Component` WHERE `Wix4XmlFile`.`Component_`=`Component`.`Component` ORDER BY `File`, `Sequence`";
42enum eXmlFileQuery { xfqXmlFile = 1, xfqFile, xfqXPath, xfqName, xfqValue, xfqXmlFlags, xfqComponent, xfqCompAttributes };
43
44struct XML_FILE_CHANGE
45{
46 WCHAR wzId[MAX_DARWIN_KEY];
47
48 INSTALLSTATE isInstalled;
49 INSTALLSTATE isAction;
50
51 WCHAR wzFile[MAX_PATH];
52 LPWSTR pwzElementPath;
53 WCHAR wzName[MAX_DARWIN_COLUMN];
54 LPWSTR pwzValue;
55
56 int iXmlFlags;
57 int iCompAttributes;
58
59 XML_FILE_CHANGE* pxfcPrev;
60 XML_FILE_CHANGE* pxfcNext;
61};
62
63//static HRESULT FreeXmlFileChangeList(
64// __in XML_FILE_CHANGE* pxfcList
65// )
66//{
67// HRESULT hr = S_OK;
68//
69// XML_FILE_CHANGE* pxfcDelete;
70// while(pxfcList)
71// {
72// pxfcDelete = pxfcList;
73// pxfcList = pxfcList->pxfcNext;
74//
75// ReleaseStr(pxfcDelete->pwzElementPath);
76// ReleaseStr(pxfcDelete->pwzValue);
77//
78// hr = MemFree(pxfcDelete);
79// ExitOnFailure(hr, "failed to free xml file change list item");
80// }
81//
82//LExit:
83// return hr;
84//}
85
86static HRESULT AddXmlFileChangeToList(
87 __inout XML_FILE_CHANGE** ppxfcHead,
88 __inout XML_FILE_CHANGE** ppxfcTail
89 )
90{
91 Assert(ppxfcHead && ppxfcTail);
92
93 HRESULT hr = S_OK;
94
95 XML_FILE_CHANGE* pxfc = static_cast<XML_FILE_CHANGE*>(MemAlloc(sizeof(XML_FILE_CHANGE), TRUE));
96 ExitOnNull(pxfc, hr, E_OUTOFMEMORY, "failed to allocate memory for new xml file change list element");
97
98 // Add it to the end of the list
99 if (NULL == *ppxfcHead)
100 {
101 *ppxfcHead = pxfc;
102 *ppxfcTail = pxfc;
103 }
104 else
105 {
106 Assert(*ppxfcTail && (*ppxfcTail)->pxfcNext == NULL);
107 (*ppxfcTail)->pxfcNext = pxfc;
108 pxfc->pxfcPrev = *ppxfcTail;
109 *ppxfcTail = pxfc;
110 }
111
112LExit:
113 return hr;
114}
115
116
117static HRESULT ReadXmlFileTable(
118 __inout XML_FILE_CHANGE** ppxfcHead,
119 __inout XML_FILE_CHANGE** ppxfcTail
120 )
121{
122 Assert(ppxfcHead && ppxfcTail);
123
124 HRESULT hr = S_OK;
125 UINT er = ERROR_SUCCESS;
126
127 PMSIHANDLE hView = NULL;
128 PMSIHANDLE hRec = NULL;
129
130 LPWSTR pwzData = NULL;
131
132 // check to see if necessary tables are specified
133 if (S_FALSE == WcaTableExists(L"Wix4XmlFile"))
134 {
135 ExitFunction1(hr = S_FALSE);
136 }
137
138 // loop through all the xml configurations
139 hr = WcaOpenExecuteView(vcsXmlFileQuery, &hView);
140 ExitOnFailure(hr, "failed to open view on Wix4XmlFile table");
141
142 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
143 {
144 hr = AddXmlFileChangeToList(ppxfcHead, ppxfcTail);
145 ExitOnFailure(hr, "failed to add xml file change to list");
146
147 // Get record Id
148 hr = WcaGetRecordString(hRec, xfqXmlFile, &pwzData);
149 ExitOnFailure(hr, "failed to get Wix4XmlFile record Id");
150 hr = StringCchCopyW((*ppxfcTail)->wzId, countof((*ppxfcTail)->wzId), pwzData);
151 ExitOnFailure(hr, "failed to copy Wix4XmlFile record Id");
152
153 // Get component name
154 hr = WcaGetRecordString(hRec, xfqComponent, &pwzData);
155 ExitOnFailure(hr, "failed to get component name for Wix4XmlFile: %ls", (*ppxfcTail)->wzId);
156
157 // Get the component's state
158 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &(*ppxfcTail)->isInstalled, &(*ppxfcTail)->isAction);
159 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "failed to get install state for Component: %ls", pwzData);
160
161 // Get the xml file
162 hr = WcaGetRecordFormattedString(hRec, xfqFile, &pwzData);
163 ExitOnFailure(hr, "failed to get xml file for Wix4XmlFile: %ls", (*ppxfcTail)->wzId);
164 hr = StringCchCopyW((*ppxfcTail)->wzFile, countof((*ppxfcTail)->wzFile), pwzData);
165 ExitOnFailure(hr, "failed to copy xml file path");
166
167 // Get the Wix4XmlFile table flags
168 hr = WcaGetRecordInteger(hRec, xfqXmlFlags, &(*ppxfcTail)->iXmlFlags);
169 ExitOnFailure(hr, "failed to get Wix4XmlFile flags for Wix4XmlFile: %ls", (*ppxfcTail)->wzId);
170
171 // Get the XPath
172 hr = WcaGetRecordFormattedString(hRec, xfqXPath, &(*ppxfcTail)->pwzElementPath);
173 ExitOnFailure(hr, "failed to get XPath for Wix4XmlFile: %ls", (*ppxfcTail)->wzId);
174
175 // Get the name
176 hr = WcaGetRecordFormattedString(hRec, xfqName, &pwzData);
177 ExitOnFailure(hr, "failed to get Name for Wix4XmlFile: %ls", (*ppxfcTail)->wzId);
178 hr = StringCchCopyW((*ppxfcTail)->wzName, countof((*ppxfcTail)->wzName), pwzData);
179 ExitOnFailure(hr, "failed to copy name of element");
180
181 // Get the value
182 hr = WcaGetRecordFormattedString(hRec, xfqValue, &pwzData);
183 ExitOnFailure(hr, "failed to get Value for Wix4XmlFile: %ls", (*ppxfcTail)->wzId);
184 hr = StrAllocString(&(*ppxfcTail)->pwzValue, pwzData, 0);
185 ExitOnFailure(hr, "failed to allocate buffer for value");
186
187 // Get the component attributes
188 hr = WcaGetRecordInteger(hRec, xfqCompAttributes, &(*ppxfcTail)->iCompAttributes);
189 ExitOnFailure(hr, "failed to get component attributes for Wix4XmlFile: %ls", (*ppxfcTail)->wzId);
190 }
191
192 // if we looped through all records all is well
193 if (E_NOMOREITEMS == hr)
194 hr = S_OK;
195 ExitOnFailure(hr, "failed while looping through all objects to secure");
196
197LExit:
198 ReleaseStr(pwzData);
199
200 return hr;
201}
202
203
204static HRESULT BeginChangeFile(
205 __in LPCWSTR pwzFile,
206 __in XML_FILE_CHANGE* pxfc,
207 __inout LPWSTR* ppwzCustomActionData
208 )
209{
210 Assert(pwzFile && *pwzFile && ppwzCustomActionData);
211
212 HRESULT hr = S_OK;
213 BOOL fIs64Bit = pxfc->iCompAttributes & msidbComponentAttributes64bit;
214 BOOL fUseXPath = pxfc->iXmlFlags & XMLFILE_USE_XPATH;
215 LPBYTE pbData = NULL;
216 SIZE_T cbData = 0;
217
218 LPWSTR pwzRollbackCustomActionData = NULL;
219
220 if (fIs64Bit)
221 {
222 hr = WcaWriteIntegerToCaData((int)xaOpenFilex64, ppwzCustomActionData);
223 ExitOnFailure(hr, "failed to write 64-bit file indicator to custom action data");
224 }
225 else
226 {
227 hr = WcaWriteIntegerToCaData((int)xaOpenFile, ppwzCustomActionData);
228 ExitOnFailure(hr, "failed to write file indicator to custom action data");
229 }
230 if (fUseXPath)
231 {
232 hr = WcaWriteIntegerToCaData((int)xsXPath, ppwzCustomActionData);
233 ExitOnFailure(hr, "failed to write XPath selectionlanguage indicator to custom action data");
234 }
235 else
236 {
237 hr = WcaWriteIntegerToCaData((int)xsXSLPattern, ppwzCustomActionData);
238 ExitOnFailure(hr, "failed to write XSLPattern selectionlanguage indicator to custom action data");
239 }
240 hr = WcaWriteStringToCaData(pwzFile, ppwzCustomActionData);
241 ExitOnFailure(hr, "failed to write file to custom action data: %ls", pwzFile);
242
243 // If the file already exits, then we have to put it back the way it was on failure
244 if (FileExistsEx(pwzFile, NULL))
245 {
246 hr = FileRead(&pbData, &cbData, pwzFile);
247 ExitOnFailure(hr, "failed to read file: %ls", pwzFile);
248
249 // Set up the rollback for this file
250 hr = WcaWriteIntegerToCaData((int)fIs64Bit, &pwzRollbackCustomActionData);
251 ExitOnFailure(hr, "failed to write component bitness to rollback custom action data");
252
253 hr = WcaWriteStringToCaData(pwzFile, &pwzRollbackCustomActionData);
254 ExitOnFailure(hr, "failed to write file name to rollback custom action data: %ls", pwzFile);
255
256 hr = WcaWriteStreamToCaData(pbData, cbData, &pwzRollbackCustomActionData);
257 ExitOnFailure(hr, "failed to write file contents to rollback custom action data.");
258
259 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecXmlFileRollback"), pwzRollbackCustomActionData, COST_XMLFILE);
260 ExitOnFailure(hr, "failed to schedule ExecXmlFileRollback for file: %ls", pwzFile);
261
262 ReleaseStr(pwzRollbackCustomActionData);
263 }
264LExit:
265 ReleaseMem(pbData);
266
267 return hr;
268}
269
270
271static HRESULT WriteChangeData(
272 __in XML_FILE_CHANGE* pxfc,
273 __inout LPWSTR* ppwzCustomActionData
274 )
275{
276 Assert(pxfc && ppwzCustomActionData);
277
278 HRESULT hr = S_OK;
279
280 hr = WcaWriteStringToCaData(pxfc->pwzElementPath, ppwzCustomActionData);
281 ExitOnFailure(hr, "failed to write ElementPath to custom action data: %ls", pxfc->pwzElementPath);
282
283 hr = WcaWriteStringToCaData(pxfc->wzName, ppwzCustomActionData);
284 ExitOnFailure(hr, "failed to write Name to custom action data: %ls", pxfc->wzName);
285
286 hr = WcaWriteStringToCaData(pxfc->pwzValue, ppwzCustomActionData);
287 ExitOnFailure(hr, "failed to write Value to custom action data: %ls", pxfc->pwzValue);
288
289LExit:
290 return hr;
291}
292
293
294/******************************************************************
295 SchedXmlFile - entry point for XmlFile Custom Action
296
297********************************************************************/
298extern "C" UINT __stdcall SchedXmlFile(
299 __in MSIHANDLE hInstall
300 )
301{
302// AssertSz(FALSE, "debug SchedXmlFile");
303
304 HRESULT hr = S_OK;
305 UINT er = ERROR_SUCCESS;
306
307 LPWSTR pwzCurrentFile = NULL;
308 BOOL fCurrentFileChanged = FALSE;
309 BOOL fCurrentUseXPath = FALSE;
310
311 PMSIHANDLE hView = NULL;
312 PMSIHANDLE hRec = NULL;
313
314 XML_FILE_CHANGE* pxfcHead = NULL;
315 XML_FILE_CHANGE* pxfcTail = NULL;
316 XML_FILE_CHANGE* pxfc = NULL;
317 XML_FILE_CHANGE* pxfcUninstall = NULL;
318
319 LPWSTR pwzCustomActionData = NULL;
320
321 DWORD cFiles = 0;
322
323 // initialize
324 hr = WcaInitialize(hInstall, "SchedXmlFile");
325 ExitOnFailure(hr, "failed to initialize");
326
327 hr = ReadXmlFileTable(&pxfcHead, &pxfcTail);
328 if (S_FALSE == hr)
329 {
330 WcaLog(LOGMSG_VERBOSE, "Skipping SchedXmlFile because Wix4XmlFile table not present");
331 ExitFunction1(hr = S_OK);
332 }
333
334 MessageExitOnFailure(hr, msierrXmlFileFailedRead, "failed to read Wix4XmlFile table");
335
336 // loop through all the xml configurations
337 for (pxfc = pxfcHead; pxfc; pxfc = pxfc->pxfcNext)
338 {
339 // If this is the first file, a different file, the last file, or the SelectionLanguage property changes...
340 if (NULL == pwzCurrentFile || 0 != lstrcmpW(pwzCurrentFile, pxfc->wzFile) || NULL == pxfc->pxfcNext || fCurrentUseXPath != ((XMLFILE_USE_XPATH & pxfc->iXmlFlags)))
341 {
342 // If this isn't the first file
343 if (NULL != pwzCurrentFile)
344 {
345 // Do the uninstall work for the current file by walking backwards through the list (so the sequence is reversed)
346 for (pxfcUninstall = ((NULL != pxfc->pxfcNext) ? pxfc->pxfcPrev : pxfc); pxfcUninstall && 0 == lstrcmpW(pwzCurrentFile, pxfcUninstall->wzFile) && fCurrentUseXPath == ((XMLFILE_USE_XPATH & pxfcUninstall->iXmlFlags)); pxfcUninstall = pxfcUninstall->pxfcPrev)
347 {
348 // If it's being uninstalled
349 if (WcaIsUninstalling(pxfcUninstall->isInstalled, pxfcUninstall->isAction))
350 {
351 // Uninstall the change
352 if (!(XMLFILE_DONT_UNINSTALL & pxfcUninstall->iXmlFlags))
353 {
354 if (!fCurrentFileChanged)
355 {
356 hr = BeginChangeFile(pwzCurrentFile, pxfcUninstall, &pwzCustomActionData);
357 ExitOnFailure(hr, "failed to begin file change for file: %ls", pwzCurrentFile);
358
359 fCurrentFileChanged = TRUE;
360 ++cFiles;
361 }
362 if (XMLFILE_CREATE_ELEMENT & pxfcUninstall->iXmlFlags)
363 {
364 hr = WcaWriteIntegerToCaData((int)xaDeleteElement, &pwzCustomActionData);
365 ExitOnFailure(hr, "failed to write delete element action indicator to custom action data");
366 }
367 else
368 {
369 hr = WcaWriteIntegerToCaData((int)xaDeleteValue, &pwzCustomActionData);
370 ExitOnFailure(hr, "failed to write delete value action indicator to custom action data");
371 }
372
373 if (XMLFILE_PRESERVE_MODIFIED & pxfc->iXmlFlags)
374 {
375 hr = WcaWriteIntegerToCaData((int)xdPreserve, &pwzCustomActionData);
376 ExitOnFailure(hr, "failed to write Preserve Date indicator to custom action data");
377 }
378 else
379 {
380 hr = WcaWriteIntegerToCaData((int)xdDontPreserve, &pwzCustomActionData);
381 ExitOnFailure(hr, "failed to write Don't Preserve Date indicator to custom action data");
382 }
383
384 hr = WriteChangeData(pxfcUninstall, &pwzCustomActionData);
385 ExitOnFailure(hr, "failed to write uninstall change data");
386 }
387 }
388 }
389 }
390
391 // Remember the file we're currently working on
392 hr = StrAllocString(&pwzCurrentFile, pxfc->wzFile, 0);
393 ExitOnFailure(hr, "failed to copy file name");
394 fCurrentUseXPath = (XMLFILE_USE_XPATH & pxfc->iXmlFlags);
395
396 // We haven't changed the current file yet
397 fCurrentFileChanged = FALSE;
398 }
399
400 // If it's being installed
401 if (WcaIsInstalling(pxfc->isInstalled, pxfc->isAction))
402 {
403 if (!fCurrentFileChanged)
404 {
405 hr = BeginChangeFile(pwzCurrentFile, pxfc, &pwzCustomActionData);
406 ExitOnFailure(hr, "failed to begin file change for file: %ls", pwzCurrentFile);
407 fCurrentFileChanged = TRUE;
408 ++cFiles;
409 }
410
411 // Install the change
412 if (XMLFILE_CREATE_ELEMENT & pxfc->iXmlFlags)
413 {
414 hr = WcaWriteIntegerToCaData((int)xaCreateElement, &pwzCustomActionData);
415 ExitOnFailure(hr, "failed to write create element action indicator to custom action data");
416 }
417 else if (XMLFILE_DELETE_VALUE & pxfc->iXmlFlags)
418 {
419 hr = WcaWriteIntegerToCaData((int)xaDeleteValue, &pwzCustomActionData);
420 ExitOnFailure(hr, "failed to write delete value action indicator to custom action data");
421 }
422 else if (XMLFILE_BULKWRITE_VALUE & pxfc->iXmlFlags)
423 {
424 hr = WcaWriteIntegerToCaData((int)xaBulkWriteValue, &pwzCustomActionData);
425 ExitOnFailure(hr, "failed to write builkwrite value action indicator to custom action data");
426 }
427 else
428 {
429 hr = WcaWriteIntegerToCaData((int)xaWriteValue, &pwzCustomActionData);
430 ExitOnFailure(hr, "failed to write file indicator to custom action data");
431 }
432
433 if (XMLFILE_PRESERVE_MODIFIED & pxfc->iXmlFlags)
434 {
435 hr = WcaWriteIntegerToCaData((int)xdPreserve, &pwzCustomActionData);
436 ExitOnFailure(hr, "failed to write Preserve Date indicator to custom action data");
437 }
438 else
439 {
440 hr = WcaWriteIntegerToCaData((int)xdDontPreserve, &pwzCustomActionData);
441 ExitOnFailure(hr, "failed to write Don't Preserve Date indicator to custom action data");
442 }
443
444 hr = WriteChangeData(pxfc, &pwzCustomActionData);
445 ExitOnFailure(hr, "failed to write change data");
446 }
447 }
448
449 // If we looped through all records all is well
450 if (E_NOMOREITEMS == hr)
451 hr = S_OK;
452 ExitOnFailure(hr, "failed while looping through all objects to secure");
453
454 // Schedule the custom action and add to progress bar
455 if (pwzCustomActionData && *pwzCustomActionData)
456 {
457 Assert(0 < cFiles);
458
459 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecXmlFile"), pwzCustomActionData, cFiles * COST_XMLFILE);
460 ExitOnFailure(hr, "failed to schedule ExecXmlFile action");
461 }
462
463LExit:
464 ReleaseStr(pwzCurrentFile);
465 ReleaseStr(pwzCustomActionData);
466
467 return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILURE : er);
468}
469
470
471/******************************************************************
472 ExecXmlFile - entry point for XmlFile Custom Action
473
474*******************************************************************/
475extern "C" UINT __stdcall ExecXmlFile(
476 __in MSIHANDLE hInstall
477 )
478{
479// AssertSz(FALSE, "debug ExecXmlFile");
480 HRESULT hr = S_OK;
481 HRESULT hrOpenFailure = S_OK;
482 UINT er = ERROR_SUCCESS;
483
484 BOOL fIsFSRedirectDisabled = FALSE;
485 BOOL fPreserveDate = FALSE;
486
487 int id = IDRETRY;
488
489 LPWSTR pwzCustomActionData = NULL;
490 LPWSTR pwzData = NULL;
491 LPWSTR pwzFile = NULL;
492 LPWSTR pwzXPath = NULL;
493 LPWSTR pwzName = NULL;
494 LPWSTR pwzValue = NULL;
495 LPWSTR pwz = NULL;
496
497 IXMLDOMDocument* pixd = NULL;
498 IXMLDOMNode* pixn = NULL;
499 IXMLDOMNode* pixnNewNode = NULL;
500 IXMLDOMNodeList* pixNodes = NULL;
501 IXMLDOMDocument2 *pixdDocument2 = NULL;
502
503 FILETIME ft;
504
505 BSTR bstrProperty = ::SysAllocString(L"SelectionLanguage");
506 ExitOnNull(bstrProperty, hr, E_OUTOFMEMORY, "failed SysAllocString");
507 VARIANT varValue;
508 ::VariantInit(&varValue);
509 varValue.vt = VT_BSTR;
510 varValue.bstrVal = ::SysAllocString(L"XPath");
511 ExitOnNull(varValue.bstrVal, hr, E_OUTOFMEMORY, "failed SysAllocString");
512 eXmlAction xa;
513 eXmlPreserveDate xd;
514 eXmlSelectionLanguage xl;
515
516 // initialize
517 hr = WcaInitialize(hInstall, "ExecXmlFile");
518 ExitOnFailure(hr, "failed to initialize");
519
520 hr = XmlInitialize();
521 ExitOnFailure(hr, "failed to initialize xml utilities");
522
523 hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData);
524 ExitOnFailure(hr, "failed to get CustomActionData");
525
526 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData);
527
528 pwz = pwzCustomActionData;
529
530 hr = WcaReadIntegerFromCaData(&pwz, (int*) &xa);
531 ExitOnFailure(hr, "failed to process CustomActionData");
532
533#ifndef _WIN64
534 // Initialize the Wow64 API - store the result in fWow64APIPresent
535 // If it fails, this doesn't warrant an error yet, because we only need the Wow64 API in some cases
536 WcaInitializeWow64();
537 BOOL fIsWow64Process = WcaIsWow64Process();
538#endif
539
540 if (xaOpenFile != xa && xaOpenFilex64 != xa)
541 ExitOnFailure(hr = E_INVALIDARG, "invalid custom action data");
542
543 // loop through all the passed in data
544 while (pwz && *pwz)
545 {
546 hr = WcaReadIntegerFromCaData(&pwz, (int*) &xl);
547 ExitOnFailure(hr, "failed to process CustomActionData");
548
549 hr = WcaReadStringFromCaData(&pwz, &pwzFile);
550 ExitOnFailure(hr, "failed to read file name from custom action data");
551
552 // Default to not preserve the modified date
553 fPreserveDate = FALSE;
554
555 // Open the file
556 ReleaseNullObject(pixd);
557
558 if (xaOpenFilex64 == xa)
559 {
560#ifndef _WIN64
561 if (!fIsWow64Process)
562 {
563 hr = E_NOTIMPL;
564 ExitOnFailure(hr, "Custom action was told to act on a 64-bit component, but the custom action process is not running in WOW.");
565 }
566
567 hr = WcaDisableWow64FSRedirection();
568 ExitOnFailure(hr, "Custom action was told to act on a 64-bit component, but was unable to disable filesystem redirection through the Wow64 API.");
569
570 fIsFSRedirectDisabled = TRUE;
571#endif
572 }
573
574 hr = XmlLoadDocumentFromFileEx(pwzFile, XML_LOAD_PRESERVE_WHITESPACE, &pixd);
575 if (FAILED(hr))
576 {
577 // Ignore the return code for now. If they try to add something, we'll fail the install. If all they do is remove stuff then it doesn't matter.
578 hrOpenFailure = hr;
579 hr = S_OK;
580 }
581 else
582 {
583 hrOpenFailure = S_OK;
584 }
585 WcaLog(LOGMSG_VERBOSE, "Configuring Xml File: %ls", pwzFile);
586
587 if (xsXPath == xl)
588 {
589 if (vfMsxml30)
590 {
591 // If we failed to open the file, don't fail immediately; just skip setting the selection language, and we'll fail later if appropriate
592 if (SUCCEEDED(hrOpenFailure))
593 {
594 hr = pixd->QueryInterface(XmlUtil_IID_IXMLDOMDocument2, (void**)&pixdDocument2);
595 ExitOnFailure(hr, "failed in querying IXMLDOMDocument2 interface");
596 hr = pixdDocument2->setProperty(bstrProperty, varValue);
597 ExitOnFailure(hr, "failed in setting SelectionLanguage");
598 }
599 }
600 else
601 {
602 ExitOnFailure(hr = E_NOTIMPL, "Error: current MSXML version does not support xpath query.");
603 }
604 }
605
606 while (pwz && *pwz)
607 {
608 hr = WcaReadIntegerFromCaData(&pwz, (int*) &xa);
609 ExitOnFailure(hr, "failed to process CustomActionData");
610
611 // Break if we need to move on to a different file
612 if (xaOpenFile == xa || xaOpenFilex64 == xa)
613 break;
614
615 hr = WcaReadIntegerFromCaData(&pwz, (int*) &xd);
616 ExitOnFailure(hr, "failed to process CustomActionData");
617
618 if (xdPreserve == xd)
619 {
620 fPreserveDate = TRUE;
621 }
622
623 // Get path, name, and value to be written
624 hr = WcaReadStringFromCaData(&pwz, &pwzXPath);
625 ExitOnFailure(hr, "failed to process CustomActionData");
626 hr = WcaReadStringFromCaData(&pwz, &pwzName);
627 ExitOnFailure(hr, "failed to process CustomActionData");
628 hr = WcaReadStringFromCaData(&pwz, &pwzValue);
629 ExitOnFailure(hr, "failed to process CustomActionData");
630
631 // If we failed to open the file and we're adding something to the file, we've got a problem. Otherwise, just continue on since the file's already gone.
632 if (FAILED(hrOpenFailure))
633 {
634 if (xaCreateElement == xa || xaWriteValue == xa || xaBulkWriteValue == xa)
635 {
636 MessageExitOnFailure(hr = hrOpenFailure, msierrXmlFileFailedOpen, "failed to load XML file: %ls", pwzFile);
637 }
638 else
639 {
640 continue;
641 }
642 }
643
644 // Select the node we're about to modify
645 ReleaseNullObject(pixn);
646
647 if (xaBulkWriteValue == xa)
648 {
649 hr = XmlSelectNodes(pixd, pwzXPath, &pixNodes);
650 if (S_FALSE == hr)
651 {
652 hr = HRESULT_FROM_WIN32(ERROR_OBJECT_NOT_FOUND);
653 }
654
655 MessageExitOnFailure(hr, msierrXmlFileFailedSelect, "failed to find any nodes: %ls in XML file: %ls", pwzXPath, pwzFile);
656 for (;;)
657 {
658 pixNodes->nextNode(&pixn);
659 if (NULL == pixn)
660 break;
661
662 if (pwzName && *pwzName)
663 {
664 // We're setting an attribute
665 hr = XmlSetAttribute(pixn, pwzName, pwzValue);
666 ExitOnFailure(hr, "failed to set attribute: %ls to value %ls", pwzName, pwzValue);
667 }
668 else
669 {
670 // We're setting the text of the node
671 hr = XmlSetText(pixn, pwzValue);
672 ExitOnFailure(hr, "failed to set text to: %ls for element %ls. Make sure that XPath points to an element.", pwzValue, pwzXPath);
673 }
674 ReleaseNullObject(pixn);
675 }
676 }
677 else
678 {
679 hr = XmlSelectSingleNode(pixd, pwzXPath, &pixn);
680 if (S_FALSE == hr)
681 hr = HRESULT_FROM_WIN32(ERROR_OBJECT_NOT_FOUND);
682 MessageExitOnFailure(hr, msierrXmlFileFailedSelect, "failed to find node: %ls in XML file: %ls", pwzXPath, pwzFile);
683
684 // Make the modification
685 if (xaWriteValue == xa)
686 {
687 if (pwzName && *pwzName)
688 {
689 // We're setting an attribute
690 hr = XmlSetAttribute(pixn, pwzName, pwzValue);
691 ExitOnFailure(hr, "failed to set attribute: %ls to value %ls", pwzName, pwzValue);
692 }
693 else
694 {
695 // We're setting the text of the node
696 hr = XmlSetText(pixn, pwzValue);
697 ExitOnFailure(hr, "failed to set text to: %ls for element %ls. Make sure that XPath points to an element.", pwzValue, pwzXPath);
698 }
699 }
700 else if (xaCreateElement == xa)
701 {
702 hr = XmlCreateChild(pixn, pwzName, &pixnNewNode);
703 ExitOnFailure(hr, "failed to create child element: %ls", pwzName);
704
705 if (pwzValue && *pwzValue)
706 {
707 hr = XmlSetText(pixnNewNode, pwzValue);
708 ExitOnFailure(hr, "failed to set text to: %ls for node: %ls", pwzValue, pwzName);
709 }
710
711 ReleaseNullObject(pixnNewNode);
712 }
713 else if (xaDeleteValue == xa)
714 {
715 if (pwzName && *pwzName)
716 {
717 // Delete the attribute
718 hr = XmlRemoveAttribute(pixn, pwzName);
719 ExitOnFailure(hr, "failed to remove attribute: %ls", pwzName);
720 }
721 else
722 {
723 // Clear the text value for the node
724 hr = XmlSetText(pixn, L"");
725 ExitOnFailure(hr, "failed to clear text value");
726 }
727 }
728 else if (xaDeleteElement == xa)
729 {
730 // TODO: This may be a little heavy handed
731 hr = XmlRemoveChildren(pixn, pwzName);
732 ExitOnFailure(hr, "failed to delete child node: %ls", pwzName);
733 }
734 else
735 {
736 ExitOnFailure(hr = E_UNEXPECTED, "Invalid modification specified in custom action data");
737 }
738 }
739 }
740
741 // Now that we've made all of the changes to this file, save it and move on to the next
742 if (S_OK == hrOpenFailure)
743 {
744 if (fPreserveDate)
745 {
746 hr = FileGetTime(pwzFile, NULL, NULL, &ft);
747 ExitOnFailure(hr, "failed to get modified time of file : %ls", pwzFile);
748 }
749
750 int iSaveAttempt = 0;
751
752 do
753 {
754 hr = XmlSaveDocument(pixd, pwzFile);
755 if (FAILED(hr))
756 {
757 id = WcaErrorMessage(msierrXmlConfigFailedSave, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 1, pwzFile);
758 switch (id)
759 {
760 case IDABORT:
761 ExitOnFailure(hr, "Failed to save changes to XML file: %ls", pwzFile);
762 case IDRETRY:
763 hr = S_FALSE; // hit me, baby, one more time
764 break;
765 case IDIGNORE:
766 hr = S_OK; // pretend everything is okay and bail
767 break;
768 case 0: // No UI case, MsiProcessMessage returns 0
769 if (STIERR_SHARING_VIOLATION == hr)
770 {
771 // Only in case of sharing violation do we retry 30 times, once a second.
772 if (iSaveAttempt < 30)
773 {
774 hr = S_FALSE;
775 ++iSaveAttempt;
776 WcaLog(LOGMSG_VERBOSE, "Unable to save changes to XML file: %ls, retry attempt: %x", pwzFile, iSaveAttempt);
777 Sleep(1000);
778 }
779 else
780 {
781 ExitOnFailure(hr, "Failed to save changes to XML file: %ls", pwzFile);
782 }
783 }
784 break;
785 default: // Unknown error
786 ExitOnFailure(hr, "Failed to save changes to XML file: %ls", pwzFile);
787 }
788 }
789 } while (S_FALSE == hr);
790
791 if (fPreserveDate)
792 {
793 hr = FileSetTime(pwzFile, NULL, NULL, &ft);
794 ExitOnFailure(hr, "failed to set modified time of file : %ls", pwzFile);
795 }
796
797 if (fIsFSRedirectDisabled)
798 {
799 fIsFSRedirectDisabled = FALSE;
800 WcaRevertWow64FSRedirection();
801 }
802 }
803 }
804
805LExit:
806 // Make sure we revert FS Redirection if necessary before exiting
807 if (fIsFSRedirectDisabled)
808 {
809 fIsFSRedirectDisabled = FALSE;
810 WcaRevertWow64FSRedirection();
811 }
812#ifndef _WIN64
813 WcaFinalizeWow64();
814#endif
815
816 ReleaseStr(pwzCustomActionData);
817 ReleaseStr(pwzData);
818 ReleaseStr(pwzFile);
819 ReleaseStr(pwzXPath);
820 ReleaseStr(pwzName);
821 ReleaseStr(pwzValue);
822 ReleaseBSTR(bstrProperty);
823 ReleaseVariant(varValue);
824
825 ReleaseObject(pixdDocument2);
826 ReleaseObject(pixn);
827 ReleaseObject(pixd);
828 ReleaseObject(pixnNewNode);
829 ReleaseObject(pixNodes);
830
831 XmlUninitialize();
832
833 return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILURE : er);
834}
835
836
837/******************************************************************
838 ExecXmlFileRollback - entry point for XmlFile rollback Custom Action
839
840*******************************************************************/
841extern "C" UINT __stdcall ExecXmlFileRollback(
842 __in MSIHANDLE hInstall
843 )
844{
845// AssertSz(FALSE, "debug ExecXmlFileRollback");
846 HRESULT hr = S_OK;
847 UINT er = ERROR_SUCCESS;
848
849 int iIs64Bit;
850 BOOL fIs64Bit = FALSE;
851
852 LPWSTR pwzCustomActionData = NULL;
853 LPWSTR pwz = NULL;
854 LPWSTR pwzFileName = NULL;
855 LPBYTE pbData = NULL;
856 DWORD_PTR cbData = 0;
857
858 FILETIME ft;
859
860 HANDLE hFile = INVALID_HANDLE_VALUE;
861
862 // initialize
863 hr = WcaInitialize(hInstall, "ExecXmlFileRollback");
864 ExitOnFailure(hr, "failed to initialize");
865
866
867 hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData);
868 ExitOnFailure(hr, "failed to get CustomActionData");
869
870 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData);
871
872 pwz = pwzCustomActionData;
873
874 hr = WcaReadIntegerFromCaData(&pwz, &iIs64Bit);
875 ExitOnFailure(hr, "failed to read component bitness from custom action data");
876
877 hr = WcaReadStringFromCaData(&pwz, &pwzFileName);
878 ExitOnFailure(hr, "failed to read file name from custom action data");
879
880 hr = WcaReadStreamFromCaData(&pwz, &pbData, &cbData);
881 ExitOnFailure(hr, "failed to read file contents from custom action data");
882
883#ifndef _WIN64
884 fIs64Bit = (BOOL)iIs64Bit;
885
886 if (fIs64Bit)
887 {
888 hr = WcaInitializeWow64();
889 if (S_FALSE == hr)
890 {
891 hr = TYPE_E_DLLFUNCTIONNOTFOUND;
892 }
893 ExitOnFailure(hr, "failed to initialize Wow64 API");
894
895 if (!WcaIsWow64Process())
896 {
897 hr = E_NOTIMPL;
898 ExitOnFailure(hr, "Custom action was told to rollback a 64-bit component, but the custom action process is not running in WOW.");
899 }
900
901 hr = WcaDisableWow64FSRedirection();
902 ExitOnFailure(hr, "Custom action was told to rollback a 64-bit component, but was unable to Disable Filesystem Redirection through the Wow64 API.");
903 }
904#endif
905
906 // Always preserve the modified date on rollback
907 hr = FileGetTime(pwzFileName, NULL, NULL, &ft);
908 ExitOnFailure(hr, "Failed to get modified date of file %ls.", pwzFileName);
909
910 // Open the file
911 hFile = ::CreateFileW(pwzFileName, GENERIC_WRITE, NULL, NULL, TRUNCATE_EXISTING, NULL, NULL);
912 ExitOnInvalidHandleWithLastError(hFile, hr, "failed to open file: %ls", pwzFileName);
913
914 // Write out the old data
915 hr = FileWriteHandle(hFile, pbData, cbData);
916 ExitOnFailure(hr, "failed to write to file: %ls", pwzFileName);
917
918 ReleaseFile(hFile);
919
920 // Always preserve the modified date on rollback
921 hr = FileSetTime(pwzFileName, NULL, NULL, &ft);
922 ExitOnFailure(hr, "Failed to set modified date of file %ls.", pwzFileName);
923
924LExit:
925 ReleaseStr(pwzCustomActionData);
926 ReleaseStr(pwzFileName);
927
928 ReleaseFile(hFile);
929
930 if (fIs64Bit)
931 {
932 WcaRevertWow64FSRedirection();
933 WcaFinalizeWow64();
934 }
935
936 ReleaseMem(pbData);
937
938 return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILURE : er);
939}
940
diff --git a/src/ext/Util/ca/caDecor.h b/src/ext/Util/ca/caDecor.h
new file mode 100644
index 00000000..da274650
--- /dev/null
+++ b/src/ext/Util/ca/caDecor.h
@@ -0,0 +1,13 @@
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#if defined(_M_ARM64)
6#define CUSTOM_ACTION_DECORATION(f) L"Wix4" f L"_A64"
7#elif defined(_M_AMD64)
8#define CUSTOM_ACTION_DECORATION(f) L"Wix4" f L"_X64"
9#elif defined(_M_ARM)
10#define CUSTOM_ACTION_DECORATION(f) L"Wix4" f L"_ARM"
11#else
12#define CUSTOM_ACTION_DECORATION(f) L"Wix4" f L"_X86"
13#endif
diff --git a/src/ext/Util/ca/cost.h b/src/ext/Util/ca/cost.h
new file mode 100644
index 00000000..6507e85d
--- /dev/null
+++ b/src/ext/Util/ca/cost.h
@@ -0,0 +1,9 @@
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
5const UINT COST_SECUREOBJECT = 1000;
6const UINT COST_SERVICECONFIG = 1000;
7const UINT COST_XMLFILE = 1000;
8const UINT COST_CLOSEAPP = 500;
9const UINT COST_INTERNETSHORTCUT = 2000;
diff --git a/src/ext/Util/ca/dllmain.cpp b/src/ext/Util/ca/dllmain.cpp
new file mode 100644
index 00000000..35ae6d1c
--- /dev/null
+++ b/src/ext/Util/ca/dllmain.cpp
@@ -0,0 +1,26 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5/********************************************************************
6DllMain - standard entry point for all WiX custom actions
7
8********************************************************************/
9extern "C" BOOL WINAPI DllMain(
10 IN HINSTANCE hInst,
11 IN ULONG ulReason,
12 IN LPVOID)
13{
14 switch(ulReason)
15 {
16 case DLL_PROCESS_ATTACH:
17 WcaGlobalInitialize(hInst);
18 break;
19
20 case DLL_PROCESS_DETACH:
21 WcaGlobalFinalize();
22 break;
23 }
24
25 return TRUE;
26}
diff --git a/src/ext/Util/ca/exitearlywithsuccess.cpp b/src/ext/Util/ca/exitearlywithsuccess.cpp
new file mode 100644
index 00000000..00828329
--- /dev/null
+++ b/src/ext/Util/ca/exitearlywithsuccess.cpp
@@ -0,0 +1,27 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6/******************************************************************
7WixExitEarlyWithSuccess - entry point for WixExitEarlyWithSuccess
8 custom action which does nothing except return exit code
9 ERROR_NO_MORE_ITEMS. The Windows Installer documentation at
10 http://msdn.microsoft.com/library/aa368072.aspx indicates that
11 this exit code is not treated as an error. This will cause a
12 calling application to receive a successful return code if
13 this custom action executes. This can be useful for backwards
14 compatibility when an application redistributes an MSI and
15 a future major upgrade is released for that MSI. It should be
16 conditioned on a property set by an entry in the Upgrade table
17 of the MSI that detects newer major upgrades of the same MSI
18 already installed on the system. It should be scheduled after
19 the FindRelatedProducts action so that the property will be
20 set if appropriate.
21********************************************************************/
22extern "C" UINT __stdcall WixExitEarlyWithSuccess(
23 __in MSIHANDLE /*hInstall*/
24 )
25{
26 return ERROR_NO_MORE_ITEMS;
27}
diff --git a/src/ext/Util/ca/netshortcuts.cpp b/src/ext/Util/ca/netshortcuts.cpp
new file mode 100644
index 00000000..06826264
--- /dev/null
+++ b/src/ext/Util/ca/netshortcuts.cpp
@@ -0,0 +1,437 @@
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
5LPCWSTR vcsShortcutsQuery =
6 L"SELECT `Component_`, `Directory_`, `Name`, `Target`, `Attributes`, `IconFile`, `IconIndex` "
7 L"FROM `Wix4InternetShortcut`";
8enum eShortcutsQuery { esqComponent = 1, esqDirectory, esqFilename, esqTarget, esqAttributes, esqIconFile, esqIconIndex };
9enum eShortcutsAttributes { esaLink = 0, esaURL = 1 };
10
11/******************************************************************
12 WixSchedInternetShortcuts - entry point
13
14********************************************************************/
15extern "C" UINT __stdcall WixSchedInternetShortcuts(
16 __in MSIHANDLE hInstall
17 )
18{
19 HRESULT hr = S_OK;
20 UINT er = ERROR_SUCCESS;
21
22 UINT uiCost = 0;
23
24 PMSIHANDLE hView = NULL;
25 PMSIHANDLE hRec = NULL;
26
27 MSIHANDLE hCreateFolderTable = NULL;
28 MSIHANDLE hCreateFolderColumns = NULL;
29
30 LPWSTR pwzCustomActionData = NULL;
31 LPWSTR pwzComponent = NULL;
32 LPWSTR pwzDirectory = NULL;
33 LPWSTR pwzFilename = NULL;
34 LPWSTR pwzTarget = NULL;
35 LPWSTR pwzShortcutPath = NULL;
36 int iAttr = 0;
37 LPWSTR pwzIconFile = NULL;
38 int iIconIndex = 0;
39 IUniformResourceLocatorW* piURL = NULL;
40 IShellLinkW* piShellLink = NULL;
41 BOOL fInitializedCom = FALSE;
42
43 hr = WcaInitialize(hInstall, "WixSchedInternetShortcuts");
44 ExitOnFailure(hr, "failed to initialize WixSchedInternetShortcuts.");
45
46 // anything to do?
47 if (S_OK != WcaTableExists(L"Wix4InternetShortcut"))
48 {
49 WcaLog(LOGMSG_STANDARD, "Wix4InternetShortcut table doesn't exist, so there are no Internet shortcuts to process");
50 goto LExit;
51 }
52
53 // check to see if we can create a shortcut - Server Core and others may not have a shell registered.
54 hr = ::CoInitialize(NULL);
55 ExitOnFailure(hr, "failed to initialize COM");
56 fInitializedCom = TRUE;
57
58 hr = ::CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_ALL, IID_IUniformResourceLocatorW, (void**)&piURL);
59 if (S_OK != hr)
60 {
61 WcaLog(LOGMSG_STANDARD, "failed to create an instance of IUniformResourceLocatorW, skipping shortcut creation");
62 ExitFunction1(hr = S_OK);
63 }
64
65 hr = ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_ALL, IID_IShellLinkW, (void**)&piShellLink);
66 if (S_OK != hr)
67 {
68 WcaLog(LOGMSG_STANDARD, "failed to create an instance of IShellLinkW, skipping shortcut creation");
69 ExitFunction1(hr = S_OK);
70 }
71
72 // query and loop through all the shortcuts
73 hr = WcaOpenExecuteView(vcsShortcutsQuery, &hView);
74 ExitOnFailure(hr, "failed to open view on Wix4InternetShortcut table");
75
76 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
77 {
78 // read column values
79 hr = WcaGetRecordString(hRec, esqComponent, &pwzComponent);
80 ExitOnFailure(hr, "failed to get shortcut component");
81 hr = WcaGetRecordString(hRec, esqDirectory, &pwzDirectory);
82 ExitOnFailure(hr, "failed to get shortcut directory");
83 hr = WcaGetRecordString(hRec, esqFilename, &pwzFilename);
84 ExitOnFailure(hr, "failed to get shortcut filename");
85 hr = WcaGetRecordFormattedString(hRec, esqTarget, &pwzTarget);
86 ExitOnFailure(hr, "failed to get shortcut target");
87 hr = WcaGetRecordInteger(hRec, esqAttributes, &iAttr);
88 ExitOnFailure(hr, "failed to get shortcut attributes");
89 hr = WcaGetRecordFormattedString(hRec, esqIconFile, &pwzIconFile);
90 ExitOnFailure(hr, "failed to get shortcut icon file");
91 hr = WcaGetRecordInteger(hRec, esqIconIndex, &iIconIndex);
92 ExitOnFailure(hr, "failed to get shortcut icon index");
93
94 // skip processing this Wix4InternetShortcut row if the component isn't being configured
95 WCA_TODO todo = WcaGetComponentToDo(pwzComponent);
96 if (WCA_TODO_UNKNOWN == todo)
97 {
98 WcaLog(LOGMSG_VERBOSE, "Skipping shortcut for null-action component '%ls'", pwzComponent);
99 continue;
100 }
101
102 // we need to create the directory where the shortcut is supposed to live; rather
103 // than doing so in our deferred custom action, use the CreateFolder table to have MSI
104 // make (and remove) them on our behalf (including the correct cleanup of parent directories).
105 MSIDBERROR dbError = MSIDBERROR_NOERROR;
106 WcaLog(LOGMSG_STANDARD, "Adding folder '%ls', component '%ls' to the CreateFolder table", pwzDirectory, pwzComponent);
107 hr = WcaAddTempRecord(&hCreateFolderTable, &hCreateFolderColumns, L"CreateFolder", &dbError, 0, 2, pwzDirectory, pwzComponent);
108 if (MSIDBERROR_DUPLICATEKEY == dbError)
109 {
110 WcaLog(LOGMSG_STANDARD, "Folder '%ls' already exists in the CreateFolder table; the above error is harmless", pwzDirectory);
111 hr = S_OK;
112 }
113 ExitOnFailure(hr, "Couldn't add temporary CreateFolder row");
114
115 // only if we're installing/reinstalling do we need to schedule the deferred CA
116 // (uninstallation is handled via permanent RemoveFile rows and temporary CreateFolder rows)
117 if (WCA_TODO_INSTALL == todo || WCA_TODO_REINSTALL == todo)
118 {
119 // turn the Directory_ id into a path
120 hr = WcaGetTargetPath(pwzDirectory, &pwzShortcutPath);
121 ExitOnFailure(hr, "failed to allocate string for shortcut directory");
122
123 // append the shortcut filename
124 hr = StrAllocConcat(&pwzShortcutPath, pwzFilename, 0);
125 ExitOnFailure(hr, "failed to allocate string for shortcut filename");
126
127 // write the shortcut path and target to custom action data for deferred CAs
128 hr = WcaWriteStringToCaData(pwzShortcutPath, &pwzCustomActionData);
129 ExitOnFailure(hr, "failed to write shortcut path to custom action data");
130 hr = WcaWriteStringToCaData(pwzTarget, &pwzCustomActionData);
131 ExitOnFailure(hr, "failed to write shortcut target to custom action data");
132 hr = WcaWriteIntegerToCaData(iAttr, &pwzCustomActionData);
133 ExitOnFailure(hr, "failed to write shortcut attributes to custom action data");
134 hr = WcaWriteStringToCaData(pwzIconFile, &pwzCustomActionData);
135 ExitOnFailure(hr, "failed to write icon file to custom action data");
136 hr = WcaWriteIntegerToCaData(iIconIndex, &pwzCustomActionData);
137 ExitOnFailure(hr, "failed to write icon index to custom action data");
138
139 uiCost += COST_INTERNETSHORTCUT;
140 }
141 }
142
143 if (E_NOMOREITEMS == hr)
144 {
145 hr = S_OK;
146 }
147 ExitOnFailure(hr, "Failure occured while processing Wix4InternetShortcut table");
148
149 // if we have any shortcuts to install
150 if (pwzCustomActionData && *pwzCustomActionData)
151 {
152 // add cost to progress bar
153 hr = WcaProgressMessage(uiCost, TRUE);
154 ExitOnFailure(hr, "failed to extend progress bar for InternetShortcuts");
155
156 // provide custom action data to deferred and rollback CAs
157 hr = WcaSetProperty(CUSTOM_ACTION_DECORATION(L"RollbackInternetShortcuts"), pwzCustomActionData);
158 ExitOnFailure(hr, "failed to set WixRollbackInternetShortcuts rollback custom action data");
159 hr = WcaSetProperty(CUSTOM_ACTION_DECORATION(L"CreateInternetShortcuts"), pwzCustomActionData);
160 ExitOnFailure(hr, "failed to set WixCreateInternetShortcuts custom action data");
161 }
162
163LExit:
164 if (hCreateFolderTable)
165 {
166 ::MsiCloseHandle(hCreateFolderTable);
167 }
168
169 if (hCreateFolderColumns)
170 {
171 ::MsiCloseHandle(hCreateFolderColumns);
172 }
173
174 ReleaseStr(pwzCustomActionData);
175 ReleaseStr(pwzComponent);
176 ReleaseStr(pwzDirectory);
177 ReleaseStr(pwzFilename);
178 ReleaseStr(pwzTarget);
179 ReleaseStr(pwzShortcutPath);
180 ReleaseObject(piShellLink);
181 ReleaseObject(piURL);
182
183 if (fInitializedCom)
184 {
185 ::CoUninitialize();
186 }
187
188 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
189 return WcaFinalize(er);
190}
191
192
193
194/******************************************************************
195 CreateUrl - Creates a shortcut via IUniformResourceLocatorW
196
197*******************************************************************/
198static HRESULT CreateUrl(
199 __in_z LPCWSTR wzTarget,
200 __in_z LPCWSTR wzShortcutPath,
201 __in_z_opt LPCWSTR wzIconPath,
202 __in int iconIndex
203)
204{
205 HRESULT hr = S_OK;
206 IUniformResourceLocatorW* piURL = NULL;
207 IPersistFile* piPersistFile = NULL;
208 IPropertySetStorage* piProperties = NULL;
209 IPropertyStorage* piStorage = NULL;
210
211 // create an internet shortcut object
212 WcaLog(LOGMSG_STANDARD, "Creating IUniformResourceLocatorW shortcut '%ls' target '%ls'", wzShortcutPath, wzTarget);
213 hr = ::CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_ALL, IID_IUniformResourceLocatorW, (void**)&piURL);
214 ExitOnFailure(hr, "failed to create an instance of IUniformResourceLocatorW");
215
216 // set shortcut target
217 hr = piURL->SetURL(wzTarget, 0);
218 ExitOnFailure(hr, "failed to set shortcut '%ls' target '%ls'", wzShortcutPath, wzTarget);
219
220 if (wzIconPath)
221 {
222 WcaLog(LOGMSG_STANDARD, "Adding icon '%ls' index '%d'", wzIconPath, iconIndex);
223
224 hr = piURL->QueryInterface(IID_IPropertySetStorage, (void **)&piProperties);
225 ExitOnFailure(hr, "failed to get IPropertySetStorage for shortcut '%ls'", wzShortcutPath);
226
227 hr = piProperties->Open(FMTID_Intshcut, STGM_WRITE, &piStorage);
228 ExitOnFailure(hr, "failed to open storage for shortcut '%ls'", wzShortcutPath);
229
230 PROPSPEC ppids[2] = { {PRSPEC_PROPID, PID_IS_ICONINDEX}, {PRSPEC_PROPID, PID_IS_ICONFILE} };
231 PROPVARIANT ppvar[2];
232
233 PropVariantInit(ppvar);
234 PropVariantInit(ppvar + 1);
235
236 ppvar[0].vt = VT_I4;
237 ppvar[0].lVal = iconIndex;
238 ppvar[1].vt = VT_LPWSTR;
239 ppvar[1].pwszVal = const_cast<LPWSTR>(wzIconPath);
240
241 hr = piStorage->WriteMultiple(2, ppids, ppvar, 0);
242 ExitOnFailure(hr, "failed to write icon storage for shortcut '%ls'", wzShortcutPath);
243
244 hr = piStorage->Commit(STGC_DEFAULT);
245 ExitOnFailure(hr, "failed to commit icon storage for shortcut '%ls'", wzShortcutPath);
246 }
247
248 // get an IPersistFile and save the shortcut
249 hr = piURL->QueryInterface(IID_IPersistFile, (void**)&piPersistFile);
250 ExitOnFailure(hr, "failed to get IPersistFile for shortcut '%ls'", wzShortcutPath);
251
252 hr = piPersistFile->Save(wzShortcutPath, TRUE);
253 ExitOnFailure(hr, "failed to save shortcut '%ls'", wzShortcutPath);
254
255LExit:
256 ReleaseObject(piPersistFile);
257 ReleaseObject(piURL);
258 ReleaseObject(piStorage);
259 ReleaseObject(piProperties);
260
261 return hr;
262}
263
264/******************************************************************
265 CreateLink - Creates a shortcut via IShellLinkW
266
267*******************************************************************/
268static HRESULT CreateLink(
269 __in_z LPCWSTR wzTarget,
270 __in_z LPCWSTR wzShortcutPath,
271 __in_z_opt LPCWSTR wzIconPath,
272 __in int iconIndex
273)
274{
275 HRESULT hr = S_OK;
276 IShellLinkW* piShellLink = NULL;
277 IPersistFile* piPersistFile = NULL;
278
279 // create an internet shortcut object
280 WcaLog(LOGMSG_STANDARD, "Creating IShellLinkW shortcut '%ls' target '%ls'", wzShortcutPath, wzTarget);
281 hr = ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_ALL, IID_IShellLinkW, (void**)&piShellLink);
282 ExitOnFailure(hr, "failed to create an instance of IShellLinkW");
283
284 // set shortcut target
285 hr = piShellLink->SetPath(wzTarget);
286 ExitOnFailure(hr, "failed to set shortcut '%ls' target '%ls'", wzShortcutPath, wzTarget);
287
288 if (wzIconPath)
289 {
290 WcaLog(LOGMSG_STANDARD, "Adding icon '%ls' index '%d'", wzIconPath, iconIndex);
291 hr = piShellLink->SetIconLocation(wzIconPath, iconIndex);
292 ExitOnFailure(hr, "failed to set icon for shortcut '%ls'", wzShortcutPath);
293 }
294
295 // get an IPersistFile and save the shortcut
296 hr = piShellLink->QueryInterface(IID_IPersistFile, (void**)&piPersistFile);
297 ExitOnFailure(hr, "failed to get IPersistFile for shortcut '%ls'", wzShortcutPath);
298
299 hr = piPersistFile->Save(wzShortcutPath, TRUE);
300 ExitOnFailure(hr, "failed to save shortcut '%ls'", wzShortcutPath);
301
302LExit:
303 ReleaseObject(piPersistFile);
304 ReleaseObject(piShellLink);
305
306 return hr;
307}
308
309
310
311/******************************************************************
312 WixCreateInternetShortcuts - entry point for Internet shortcuts
313 custom action
314*******************************************************************/
315extern "C" UINT __stdcall WixCreateInternetShortcuts(
316 __in MSIHANDLE hInstall
317 )
318{
319 HRESULT hr = S_OK;
320 UINT er = ERROR_SUCCESS;
321
322 LPWSTR pwz = NULL;
323 LPWSTR pwzCustomActionData = NULL;
324 LPWSTR pwzTarget = NULL;
325 LPWSTR pwzShortcutPath = NULL;
326 LPWSTR pwzIconPath = NULL;
327 BOOL fInitializedCom = FALSE;
328 int iAttr = 0;
329 int iIconIndex = 0;
330
331 // initialize
332 hr = WcaInitialize(hInstall, "WixCreateInternetShortcuts");
333 ExitOnFailure(hr, "failed to initialize WixCreateInternetShortcuts");
334
335 hr = ::CoInitialize(NULL);
336 ExitOnFailure(hr, "failed to initialize COM");
337 fInitializedCom = TRUE;
338
339 // extract the custom action data
340 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
341 ExitOnFailure(hr, "failed to get CustomActionData");
342
343 // loop through all the custom action data
344 pwz = pwzCustomActionData;
345 while (pwz && *pwz)
346 {
347 hr = WcaReadStringFromCaData(&pwz, &pwzShortcutPath);
348 ExitOnFailure(hr, "failed to read shortcut path from custom action data");
349 hr = WcaReadStringFromCaData(&pwz, &pwzTarget);
350 ExitOnFailure(hr, "failed to read shortcut target from custom action data");
351 hr = WcaReadIntegerFromCaData(&pwz, &iAttr);
352 ExitOnFailure(hr, "failed to read shortcut attributes from custom action data");
353 hr = WcaReadStringFromCaData(&pwz, &pwzIconPath);
354 ExitOnFailure(hr, "failed to read shortcut icon path from custom action data");
355 hr = WcaReadIntegerFromCaData(&pwz, &iIconIndex);
356 ExitOnFailure(hr, "failed to read shortcut icon index from custom action data");
357
358 if ((iAttr & esaURL) == esaURL)
359 {
360 hr = CreateUrl(pwzTarget, pwzShortcutPath, pwzIconPath, iIconIndex);
361 }
362 else
363 {
364 hr = CreateLink(pwzTarget, pwzShortcutPath, pwzIconPath, iIconIndex);
365 }
366 ExitOnFailure(hr, "failed to create Internet shortcut");
367
368 // tick the progress bar
369 hr = WcaProgressMessage(COST_INTERNETSHORTCUT, FALSE);
370 ExitOnFailure(hr, "failed to tick progress bar for shortcut: %ls", pwzShortcutPath);
371 }
372
373LExit:
374 ReleaseStr(pwzCustomActionData);
375 ReleaseStr(pwzTarget);
376 ReleaseStr(pwzShortcutPath);
377
378 if (fInitializedCom)
379 {
380 ::CoUninitialize();
381 }
382
383 er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er;
384 return WcaFinalize(er);
385}
386
387
388
389/******************************************************************
390 WixRollbackInternetShortcuts - entry point for Internet shortcuts
391 custom action (rollback)
392*******************************************************************/
393extern "C" UINT __stdcall WixRollbackInternetShortcuts(
394 __in MSIHANDLE hInstall
395 )
396{
397 HRESULT hr = S_OK;
398 UINT er = ERROR_SUCCESS;
399
400 LPWSTR pwz = NULL;
401 LPWSTR pwzCustomActionData = NULL;
402 LPWSTR pwzShortcutPath = NULL;
403 int iAttr = 0;
404
405 // initialize
406 hr = WcaInitialize(hInstall, "WixRemoveInternetShortcuts");
407 ExitOnFailure(hr, "failed to initialize WixRemoveInternetShortcuts");
408
409 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
410 ExitOnFailure(hr, "failed to get CustomActionData");
411
412 // loop through all the custom action data
413 pwz = pwzCustomActionData;
414 while (pwz && *pwz)
415 {
416 // extract the custom action data we're interested in
417 hr = WcaReadStringFromCaData(&pwz, &pwzShortcutPath);
418 ExitOnFailure(hr, "failed to read shortcut path from custom action data for rollback");
419
420 // delete file
421 hr = FileEnsureDelete(pwzShortcutPath);
422 ExitOnFailure(hr, "failed to delete file '%ls'", pwzShortcutPath);
423
424 // skip over the shortcut target and attributes
425 hr = WcaReadStringFromCaData(&pwz, &pwzShortcutPath);
426 ExitOnFailure(hr, "failed to skip shortcut target from custom action data for rollback");
427 hr = WcaReadIntegerFromCaData(&pwz, &iAttr);
428 ExitOnFailure(hr, "failed to read shortcut attributes from custom action data");
429 }
430
431LExit:
432 ReleaseStr(pwzCustomActionData);
433 ReleaseStr(pwzShortcutPath);
434
435 er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er;
436 return WcaFinalize(er);
437}
diff --git a/src/ext/Util/ca/precomp.h b/src/ext/Util/ca/precomp.h
new file mode 100644
index 00000000..c5d6afe5
--- /dev/null
+++ b/src/ext/Util/ca/precomp.h
@@ -0,0 +1,54 @@
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#if _WIN32_MSI < 150
6#define _WIN32_MSI 150
7#endif
8
9#include <windows.h>
10#include <msiquery.h>
11#include <msidefs.h>
12#include <stierr.h>
13
14#include <strsafe.h>
15
16#include <msxml2.h>
17#include <Iads.h>
18#include <activeds.h>
19#include <lm.h> // NetApi32.lib
20#include <Ntsecapi.h>
21#include <Dsgetdc.h>
22#include <shlobj.h>
23#include <intshcut.h>
24
25#define MAXUINT USHRT_MAX
26
27#include "wcautil.h"
28#include "wcawow64.h"
29#include "wcawrapquery.h"
30#include "aclutil.h"
31#include "dirutil.h"
32#include "fileutil.h"
33#include "memutil.h"
34#include "osutil.h"
35#include "pathutil.h"
36#include "procutil.h"
37#include "shelutil.h"
38#include "strutil.h"
39#include "sczutil.h"
40#include "rmutil.h"
41#include "userutil.h"
42#include "xmlutil.h"
43#include "wiutil.h"
44
45#include "CustomMsiErrors.h"
46
47#include "sca.h"
48#include "scacost.h"
49#include "cost.h"
50#include "scauser.h"
51#include "scasmb.h"
52#include "scasmbexec.h"
53
54#include "caDecor.h"
diff --git a/src/ext/Util/ca/qtexecca.cpp b/src/ext/Util/ca/qtexecca.cpp
new file mode 100644
index 00000000..ddcc812f
--- /dev/null
+++ b/src/ext/Util/ca/qtexecca.cpp
@@ -0,0 +1,316 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5#define OUTPUT_BUFFER 1024
6
7// These old "CA" prefix names are deprecated, and intended to go away in wix 4.0, only staying now for compatibility reasons
8const LPCWSTR CAQUIET_TIMEOUT_PROPERTY = L"QtExecCmdTimeout";
9const LPCWSTR CAQUIET_ARGUMENTS_PROPERTY = L"QtExecCmdLine";
10const LPCWSTR CAQUIET64_ARGUMENTS_PROPERTY = L"QtExec64CmdLine";
11// end deprecated section
12
13// WixCA name quiet commandline argument properties
14const LPCWSTR WIX_QUIET_ARGUMENTS_PROPERTY = L"WixQuietExecCmdLine";
15const LPCWSTR WIX_QUIET64_ARGUMENTS_PROPERTY = L"WixQuietExec64CmdLine";
16
17// WixCA quiet timeout properties
18const LPCWSTR WIX_QUIET_TIMEOUT_PROPERTY = L"WixQuietExecCmdTimeout";
19const LPCWSTR WIX_QUIET64_TIMEOUT_PROPERTY = L"WixQuietExec64CmdTimeout";
20
21// WixCA silent commandline argument properties
22const LPCWSTR WIX_SILENT_ARGUMENTS_PROPERTY = L"WixSilentExecCmdLine";
23const LPCWSTR WIX_SILENT64_ARGUMENTS_PROPERTY = L"WixSilentExec64CmdLine";
24
25// WixCA silent timeout properties
26const LPCWSTR WIX_SILENT_TIMEOUT_PROPERTY = L"WixSilentExecCmdTimeout";
27const LPCWSTR WIX_SILENT64_TIMEOUT_PROPERTY = L"WixSilentExec64CmdTimeout";
28
29HRESULT BuildCommandLine(
30 __in LPCWSTR wzProperty,
31 __out LPWSTR *ppwzCommand
32 )
33{
34 Assert(ppwzCommand);
35
36 HRESULT hr = S_OK;
37 BOOL fScheduled = ::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_SCHEDULED);
38 BOOL fRollback = ::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK);
39 BOOL fCommit = ::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_COMMIT);
40
41 if (fScheduled || fRollback || fCommit)
42 {
43 if (WcaIsPropertySet("CustomActionData"))
44 {
45 hr = WcaGetProperty( L"CustomActionData", ppwzCommand);
46 ExitOnFailure(hr, "Failed to get CustomActionData");
47 }
48 }
49 else if (WcaIsUnicodePropertySet(wzProperty))
50 {
51 hr = WcaGetFormattedProperty(wzProperty, ppwzCommand);
52 ExitOnFailure(hr, "Failed to get %ls", wzProperty);
53 hr = WcaSetProperty(wzProperty, L""); // clear out the property now that we've read it
54 ExitOnFailure(hr, "Failed to set %ls", wzProperty);
55 }
56
57 if (!*ppwzCommand)
58 {
59 ExitOnFailure(hr = E_INVALIDARG, "Failed to get command line data");
60 }
61
62 if (L'"' != **ppwzCommand)
63 {
64 WcaLog(LOGMSG_STANDARD, "Command string must begin with quoted application name.");
65 ExitOnFailure(hr = E_INVALIDARG, "invalid command line property value");
66 }
67
68LExit:
69 return hr;
70}
71
72#define ONEMINUTE 60000
73
74DWORD GetTimeout(LPCWSTR wzPropertyName)
75{
76 DWORD dwTimeout = ONEMINUTE;
77 HRESULT hr = S_OK;
78
79 LPWSTR pwzData = NULL;
80
81 if (WcaIsUnicodePropertySet(wzPropertyName))
82 {
83 hr = WcaGetProperty(wzPropertyName, &pwzData);
84 ExitOnFailure(hr, "Failed to get %ls", wzPropertyName);
85
86 if ((dwTimeout = (DWORD)_wtoi(pwzData)) == 0)
87 {
88 dwTimeout = ONEMINUTE;
89 }
90 }
91
92LExit:
93 ReleaseStr(pwzData);
94
95 return dwTimeout;
96
97}
98
99HRESULT ExecCommon(
100 __in LPCWSTR wzArgumentsProperty,
101 __in LPCWSTR wzTimeoutProperty,
102 __in BOOL fLogCommand,
103 __in BOOL fLogOutput
104 )
105{
106 HRESULT hr = S_OK;
107 LPWSTR pwzCommand = NULL;
108 DWORD dwTimeout = 0;
109
110 hr = BuildCommandLine(wzArgumentsProperty, &pwzCommand);
111 ExitOnFailure(hr, "Failed to get Command Line");
112
113 dwTimeout = GetTimeout(wzTimeoutProperty);
114
115 hr = QuietExec(pwzCommand, dwTimeout, fLogCommand, fLogOutput);
116 ExitOnFailure(hr, "QuietExec Failed");
117
118LExit:
119 ReleaseStr(pwzCommand);
120
121 return hr;
122}
123
124HRESULT ExecCommon64(
125 __in LPCWSTR wzArgumentsProperty,
126 __in LPCWSTR wzTimeoutProperty,
127 __in BOOL fLogCommand,
128 __in BOOL fLogOutput
129 )
130{
131 HRESULT hr = S_OK;
132 LPWSTR pwzCommand = NULL;
133 DWORD dwTimeout = 0;
134#ifndef _WIN64
135 BOOL fIsWow64Initialized = FALSE;
136 BOOL fRedirected = FALSE;
137
138 hr = WcaInitializeWow64();
139 if (S_FALSE == hr)
140 {
141 hr = TYPE_E_DLLFUNCTIONNOTFOUND;
142 }
143 ExitOnFailure(hr, "Failed to intialize WOW64.");
144 fIsWow64Initialized = TRUE;
145
146 hr = WcaDisableWow64FSRedirection();
147 ExitOnFailure(hr, "Failed to enable filesystem redirection.");
148 fRedirected = TRUE;
149#endif
150
151 hr = BuildCommandLine(wzArgumentsProperty, &pwzCommand);
152 ExitOnFailure(hr, "Failed to get Command Line");
153
154 dwTimeout = GetTimeout(wzTimeoutProperty);
155
156 hr = QuietExec(pwzCommand, dwTimeout, fLogCommand, fLogOutput);
157 ExitOnFailure(hr, "QuietExec64 Failed");
158
159LExit:
160 ReleaseStr(pwzCommand);
161
162#ifndef _WIN64
163 if (fRedirected)
164 {
165 WcaRevertWow64FSRedirection();
166 }
167
168 if (fIsWow64Initialized)
169 {
170 WcaFinalizeWow64();
171 }
172#endif
173
174 return hr;
175}
176
177// These two custom actions are deprecated, and should go away in wix v4.0. WixQuietExec replaces this one,
178// and is not intended to have any difference in behavior apart from CA name and property names.
179extern "C" UINT __stdcall CAQuietExec(
180 __in MSIHANDLE hInstall
181 )
182{
183 Assert(hInstall);
184 HRESULT hr = S_OK;
185 UINT er = ERROR_SUCCESS;
186
187 hr = WcaInitialize(hInstall, "CAQuietExec");
188 ExitOnFailure(hr, "Failed to initialize");
189
190 hr = ExecCommon(CAQUIET_ARGUMENTS_PROPERTY, CAQUIET_TIMEOUT_PROPERTY, TRUE, TRUE);
191 ExitOnFailure(hr, "Failed in ExecCommon method");
192
193LExit:
194 if (FAILED(hr))
195 {
196 er = ERROR_INSTALL_FAILURE;
197 }
198
199 return WcaFinalize(er);
200}
201
202// 2nd deprecated custom action name, superseded by WixQuietExec64
203extern "C" UINT __stdcall CAQuietExec64(
204 __in MSIHANDLE hInstall
205 )
206{
207 Assert(hInstall);
208 HRESULT hr = S_OK;
209 UINT er = ERROR_SUCCESS;
210
211 hr = WcaInitialize(hInstall, "CAQuietExec64");
212 ExitOnFailure(hr, "Failed to initialize");
213
214 hr = ExecCommon64(CAQUIET64_ARGUMENTS_PROPERTY, CAQUIET_TIMEOUT_PROPERTY, TRUE, TRUE);
215 ExitOnFailure(hr, "Failed in ExecCommon64 method");
216
217LExit:
218 if (FAILED(hr))
219 {
220 er = ERROR_INSTALL_FAILURE;
221 }
222
223 return WcaFinalize(er);
224}
225
226extern "C" UINT __stdcall WixQuietExec(
227 __in MSIHANDLE hInstall
228 )
229{
230 Assert(hInstall);
231 HRESULT hr = S_OK;
232 UINT er = ERROR_SUCCESS;
233
234 hr = WcaInitialize(hInstall, "WixQuietExec");
235 ExitOnFailure(hr, "Failed to initialize");
236
237 hr = ExecCommon(WIX_QUIET_ARGUMENTS_PROPERTY, WIX_QUIET_TIMEOUT_PROPERTY, TRUE, TRUE);
238 ExitOnFailure(hr, "Failed in ExecCommon method");
239
240LExit:
241 if (FAILED(hr))
242 {
243 er = ERROR_INSTALL_FAILURE;
244 }
245
246 return WcaFinalize(er);
247}
248
249extern "C" UINT __stdcall WixQuietExec64(
250 __in MSIHANDLE hInstall
251 )
252{
253 Assert(hInstall);
254 HRESULT hr = S_OK;
255 UINT er = ERROR_SUCCESS;
256
257 hr = WcaInitialize(hInstall, "WixQuietExec64");
258 ExitOnFailure(hr, "Failed to initialize");
259
260 hr = ExecCommon64(WIX_QUIET64_ARGUMENTS_PROPERTY, WIX_QUIET64_TIMEOUT_PROPERTY, TRUE, TRUE);
261 ExitOnFailure(hr, "Failed in ExecCommon method");
262
263LExit:
264 if (FAILED(hr))
265 {
266 er = ERROR_INSTALL_FAILURE;
267 }
268
269 return WcaFinalize(er);
270}
271
272extern "C" UINT __stdcall WixSilentExec(
273 __in MSIHANDLE hInstall
274 )
275{
276 Assert(hInstall);
277 HRESULT hr = S_OK;
278 UINT er = ERROR_SUCCESS;
279
280 hr = WcaInitialize(hInstall, "WixSilentExec");
281 ExitOnFailure(hr, "Failed to initialize");
282
283 hr = ExecCommon(WIX_SILENT_ARGUMENTS_PROPERTY, WIX_SILENT_TIMEOUT_PROPERTY, FALSE, FALSE);
284 ExitOnFailure(hr, "Failed in ExecCommon method");
285
286LExit:
287 if (FAILED(hr))
288 {
289 er = ERROR_INSTALL_FAILURE;
290 }
291
292 return WcaFinalize(er);
293}
294
295extern "C" UINT __stdcall WixSilentExec64(
296 __in MSIHANDLE hInstall
297 )
298{
299 Assert(hInstall);
300 HRESULT hr = S_OK;
301 UINT er = ERROR_SUCCESS;
302
303 hr = WcaInitialize(hInstall, "WixSilentExec64");
304 ExitOnFailure(hr, "Failed to initialize");
305
306 hr = ExecCommon64(WIX_SILENT64_ARGUMENTS_PROPERTY, WIX_SILENT64_TIMEOUT_PROPERTY, FALSE, FALSE);
307 ExitOnFailure(hr, "Failed in ExecCommon method");
308
309LExit:
310 if (FAILED(hr))
311 {
312 er = ERROR_INSTALL_FAILURE;
313 }
314
315 return WcaFinalize(er);
316}
diff --git a/src/ext/Util/ca/sca.h b/src/ext/Util/ca/sca.h
new file mode 100644
index 00000000..599122ff
--- /dev/null
+++ b/src/ext/Util/ca/sca.h
@@ -0,0 +1,19 @@
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// user creation attributes definitions
5enum SCAU_ATTRIBUTES
6{
7 SCAU_DONT_EXPIRE_PASSWRD = 0x00000001,
8 SCAU_PASSWD_CANT_CHANGE = 0x00000002,
9 SCAU_PASSWD_CHANGE_REQD_ON_LOGIN = 0x00000004,
10 SCAU_DISABLE_ACCOUNT = 0x00000008,
11 SCAU_FAIL_IF_EXISTS = 0x00000010,
12 SCAU_UPDATE_IF_EXISTS = 0x00000020,
13 SCAU_ALLOW_LOGON_AS_SERVICE = 0x00000040,
14 SCAU_ALLOW_LOGON_AS_BATCH = 0x00000080,
15
16 SCAU_DONT_REMOVE_ON_UNINSTALL = 0x00000100,
17 SCAU_DONT_CREATE_USER = 0x00000200,
18 SCAU_NON_VITAL = 0x00000400,
19}; \ No newline at end of file
diff --git a/src/ext/Util/ca/scacost.h b/src/ext/Util/ca/scacost.h
new file mode 100644
index 00000000..5b215035
--- /dev/null
+++ b/src/ext/Util/ca/scacost.h
@@ -0,0 +1,18 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5const UINT COST_PERFMON_REGISTER = 1000;
6const UINT COST_PERFMON_UNREGISTER = 1000;
7
8const UINT COST_SMB_CREATESMB = 10000;
9const UINT COST_SMB_DROPSMB = 5000;
10const UINT COST_USER_ADD = 10000;
11const UINT COST_USER_DELETE = 10000;
12
13const UINT COST_PERFMONMANIFEST_REGISTER = 1000;
14const UINT COST_PERFMONMANIFEST_UNREGISTER = 1000;
15
16const UINT COST_EVENTMANIFEST_REGISTER = 1000;
17const UINT COST_EVENTMANIFEST_UNREGISTER = 1000;
18
diff --git a/src/ext/Util/ca/scaexec.cpp b/src/ext/Util/ca/scaexec.cpp
new file mode 100644
index 00000000..5845c1b4
--- /dev/null
+++ b/src/ext/Util/ca/scaexec.cpp
@@ -0,0 +1,1082 @@
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/********************************************************************
7 * CreateSmb - CUSTOM ACTION ENTRY POINT for creating fileshares
8 *
9 * Input: deferred CustomActionData -
10 * wzFsKey\twzShareDesc\twzFullPath\tfIntegratedAuth\twzUserName\tnPermissions\twzUserName\tnPermissions...
11 *
12 * ****************************************************************/
13extern "C" UINT __stdcall CreateSmb(MSIHANDLE hInstall)
14{
15//AssertSz(0, "debug CreateSmb");
16 UINT er = ERROR_SUCCESS;
17 HRESULT hr = S_OK;
18
19 LPWSTR pwzData = NULL;
20 LPWSTR pwz = NULL;
21 LPWSTR pwzFsKey = NULL;
22 LPWSTR pwzShareDesc = NULL;
23 LPWSTR pwzDirectory = NULL;
24 int iAccessMode = 0;
25 DWORD nExPermissions = 0;
26 BOOL fIntegratedAuth;
27 LPWSTR pwzExUser = NULL;
28 SCA_SMBP ssp = {0};
29 DWORD dwExUserPerms = 0;
30 DWORD dwCounter = 0;
31 SCA_SMBP_USER_PERMS* pUserPermsList = NULL;
32
33 hr = WcaInitialize(hInstall, "CreateSmb");
34 ExitOnFailure(hr, "failed to initialize");
35
36 hr = WcaGetProperty( L"CustomActionData", &pwzData);
37 ExitOnFailure(hr, "failed to get CustomActionData");
38
39 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData);
40
41 pwz = pwzData;
42 hr = WcaReadStringFromCaData(&pwz, &pwzFsKey); // share name
43 ExitOnFailure(hr, "failed to read share name");
44 hr = WcaReadStringFromCaData(&pwz, &pwzShareDesc); // share description
45 ExitOnFailure(hr, "failed to read share name");
46 hr = WcaReadStringFromCaData(&pwz, &pwzDirectory); // full path to share
47 ExitOnFailure(hr, "failed to read share name");
48 hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int *>(&fIntegratedAuth));
49 ExitOnFailure(hr, "failed to read integrated authentication");
50
51 hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int *>(&dwExUserPerms));
52 ExitOnFailure(hr, "failed to read count of permissions to set");
53 if(dwExUserPerms > 0)
54 {
55 pUserPermsList = static_cast<SCA_SMBP_USER_PERMS*>(MemAlloc(sizeof(SCA_SMBP_USER_PERMS)*dwExUserPerms, TRUE));
56 ExitOnNull(pUserPermsList, hr, E_OUTOFMEMORY, "failed to allocate memory for permissions structure");
57
58 //Pull out all of the ExUserPerm strings
59 for (dwCounter = 0; dwCounter < dwExUserPerms; ++dwCounter)
60 {
61 hr = WcaReadStringFromCaData(&pwz, &pwzExUser); // user account
62 ExitOnFailure(hr, "failed to read user account");
63 pUserPermsList[dwCounter].wzUser = pwzExUser;
64 pwzExUser = NULL;
65
66 hr = WcaReadIntegerFromCaData(&pwz, &iAccessMode);
67 ExitOnFailure(hr, "failed to read access mode");
68 pUserPermsList[dwCounter].accessMode = (ACCESS_MODE)iAccessMode;
69 iAccessMode = 0;
70
71 hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int *>(&nExPermissions));
72 ExitOnFailure(hr, "failed to read count of permissions");
73 pUserPermsList[dwCounter].nPermissions = nExPermissions;
74 nExPermissions = 0;
75 }
76 }
77
78 ssp.wzKey = pwzFsKey;
79 ssp.wzDescription = pwzShareDesc;
80 ssp.wzDirectory = pwzDirectory;
81 ssp.fUseIntegratedAuth = fIntegratedAuth;
82 ssp.dwUserPermissionCount = dwExUserPerms;
83 ssp.pUserPerms = pUserPermsList;
84
85 hr = ScaEnsureSmbExists(&ssp);
86 MessageExitOnFailure(hr, msierrSMBFailedCreate, "failed to create share: '%ls'", pwzFsKey);
87
88 hr = WcaProgressMessage(COST_SMB_CREATESMB, FALSE);
89
90LExit:
91 ReleaseStr(pwzFsKey);
92 ReleaseStr(pwzShareDesc);
93 ReleaseStr(pwzDirectory);
94 ReleaseStr(pwzData);
95
96 if (pUserPermsList)
97 {
98 MemFree(pUserPermsList);
99 }
100
101 if (FAILED(hr))
102 {
103 er = ERROR_INSTALL_FAILURE;
104 }
105 return WcaFinalize(er);
106}
107
108
109
110/********************************************************************
111 DropSmb - CUSTOM ACTION ENTRY POINT for creating fileshares
112
113 Input: deferred CustomActionData - wzFsKey\twzShareDesc\twzFullPath\tnPermissions\tfIntegratedAuth\twzUserName\twzPassword
114
115 * ****************************************************************/
116extern "C" UINT __stdcall DropSmb(MSIHANDLE hInstall)
117{
118 //AssertSz(0, "debug DropSmb");
119 UINT er = ERROR_SUCCESS;
120 HRESULT hr = S_OK;
121
122 LPWSTR pwzData = NULL;
123 LPWSTR pwz = NULL;
124 LPWSTR pwzFsKey = NULL;
125 SCA_SMBP ssp = {0};
126
127 hr = WcaInitialize(hInstall, "DropSmb");
128 ExitOnFailure(hr, "failed to initialize");
129
130 hr = WcaGetProperty( L"CustomActionData", &pwzData);
131 ExitOnFailure(hr, "failed to get CustomActionData");
132
133 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData);
134
135 pwz = pwzData;
136 hr = WcaReadStringFromCaData(&pwz, &pwzFsKey); // share name
137 ExitOnFailure(hr, "failed to read share name");
138
139 ssp.wzKey = pwzFsKey;
140
141 hr = ScaDropSmb(&ssp);
142 MessageExitOnFailure(hr, msierrSMBFailedDrop, "failed to delete share: '%ls'", pwzFsKey);
143
144 hr = WcaProgressMessage(COST_SMB_DROPSMB, FALSE);
145
146LExit:
147 ReleaseStr(pwzFsKey);
148 ReleaseStr(pwzData);
149
150 if (FAILED(hr))
151 {
152 er = ERROR_INSTALL_FAILURE;
153 }
154 return WcaFinalize(er);
155}
156
157
158static HRESULT AddUserToGroup(
159 __in LPWSTR wzUser,
160 __in LPCWSTR wzUserDomain,
161 __in LPCWSTR wzGroup,
162 __in LPCWSTR wzGroupDomain
163 )
164{
165 Assert(wzUser && *wzUser && wzUserDomain && wzGroup && *wzGroup && wzGroupDomain);
166
167 HRESULT hr = S_OK;
168 IADsGroup *pGroup = NULL;
169 BSTR bstrUser = NULL;
170 BSTR bstrGroup = NULL;
171 LPCWSTR wz = NULL;
172 LPWSTR pwzUser = NULL;
173 LOCALGROUP_MEMBERS_INFO_3 lgmi;
174
175 if (*wzGroupDomain)
176 {
177 wz = wzGroupDomain;
178 }
179
180 // Try adding it to the global group first
181 UINT ui = ::NetGroupAddUser(wz, wzGroup, wzUser);
182 if (NERR_GroupNotFound == ui)
183 {
184 // Try adding it to the local group
185 if (wzUserDomain)
186 {
187 hr = StrAllocFormatted(&pwzUser, L"%s\\%s", wzUserDomain, wzUser);
188 ExitOnFailure(hr, "failed to allocate user domain string");
189 }
190
191 lgmi.lgrmi3_domainandname = (NULL == pwzUser ? wzUser : pwzUser);
192 ui = ::NetLocalGroupAddMembers(wz, wzGroup, 3 , reinterpret_cast<LPBYTE>(&lgmi), 1);
193 }
194 hr = HRESULT_FROM_WIN32(ui);
195 if (HRESULT_FROM_WIN32(ERROR_MEMBER_IN_ALIAS) == hr) // if they're already a member of the group don't report an error
196 hr = S_OK;
197
198 //
199 // If we failed, try active directory
200 //
201 if (FAILED(hr))
202 {
203 WcaLog(LOGMSG_VERBOSE, "Failed to add user: %ls, domain %ls to group: %ls, domain: %ls with error 0x%x. Attempting to use Active Directory", wzUser, wzUserDomain, wzGroup, wzGroupDomain, hr);
204
205 hr = UserCreateADsPath(wzUserDomain, wzUser, &bstrUser);
206 ExitOnFailure(hr, "failed to create user ADsPath for user: %ls domain: %ls", wzUser, wzUserDomain);
207
208 hr = UserCreateADsPath(wzGroupDomain, wzGroup, &bstrGroup);
209 ExitOnFailure(hr, "failed to create group ADsPath for group: %ls domain: %ls", wzGroup, wzGroupDomain);
210
211 hr = ::ADsGetObject(bstrGroup,IID_IADsGroup, reinterpret_cast<void**>(&pGroup));
212 ExitOnFailure(hr, "Failed to get group '%ls'.", reinterpret_cast<WCHAR*>(bstrGroup) );
213
214 hr = pGroup->Add(bstrUser);
215 if ((HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS) == hr) || (HRESULT_FROM_WIN32(ERROR_MEMBER_IN_ALIAS) == hr))
216 hr = S_OK;
217
218 ExitOnFailure(hr, "Failed to add user %ls to group '%ls'.", reinterpret_cast<WCHAR*>(bstrUser), reinterpret_cast<WCHAR*>(bstrGroup) );
219 }
220
221LExit:
222 ReleaseObject(pGroup);
223 ReleaseBSTR(bstrUser);
224 ReleaseBSTR(bstrGroup);
225
226 return hr;
227}
228
229static HRESULT RemoveUserFromGroup(
230 __in LPWSTR wzUser,
231 __in LPCWSTR wzUserDomain,
232 __in LPCWSTR wzGroup,
233 __in LPCWSTR wzGroupDomain
234 )
235{
236 Assert(wzUser && *wzUser && wzUserDomain && wzGroup && *wzGroup && wzGroupDomain);
237
238 HRESULT hr = S_OK;
239 IADsGroup *pGroup = NULL;
240 BSTR bstrUser = NULL;
241 BSTR bstrGroup = NULL;
242 LPCWSTR wz = NULL;
243 LPWSTR pwzUser = NULL;
244 LOCALGROUP_MEMBERS_INFO_3 lgmi;
245
246 if (*wzGroupDomain)
247 {
248 wz = wzGroupDomain;
249 }
250
251 // Try removing it from the global group first
252 UINT ui = ::NetGroupDelUser(wz, wzGroup, wzUser);
253 if (NERR_GroupNotFound == ui)
254 {
255 // Try removing it from the local group
256 if (wzUserDomain)
257 {
258 hr = StrAllocFormatted(&pwzUser, L"%s\\%s", wzUserDomain, wzUser);
259 ExitOnFailure(hr, "failed to allocate user domain string");
260 }
261
262 lgmi.lgrmi3_domainandname = (NULL == pwzUser ? wzUser : pwzUser);
263 ui = ::NetLocalGroupDelMembers(wz, wzGroup, 3 , reinterpret_cast<LPBYTE>(&lgmi), 1);
264 }
265 hr = HRESULT_FROM_WIN32(ui);
266
267 //
268 // If we failed, try active directory
269 //
270 if (FAILED(hr))
271 {
272 WcaLog(LOGMSG_VERBOSE, "Failed to remove user: %ls, domain %ls from group: %ls, domain: %ls with error 0x%x. Attempting to use Active Directory", wzUser, wzUserDomain, wzGroup, wzGroupDomain, hr);
273
274 hr = UserCreateADsPath(wzUserDomain, wzUser, &bstrUser);
275 ExitOnFailure(hr, "failed to create user ADsPath in order to remove user: %ls domain: %ls from a group", wzUser, wzUserDomain);
276
277 hr = UserCreateADsPath(wzGroupDomain, wzGroup, &bstrGroup);
278 ExitOnFailure(hr, "failed to create group ADsPath in order to remove user from group: %ls domain: %ls", wzGroup, wzGroupDomain);
279
280 hr = ::ADsGetObject(bstrGroup,IID_IADsGroup, reinterpret_cast<void**>(&pGroup));
281 ExitOnFailure(hr, "Failed to get group '%ls'.", reinterpret_cast<WCHAR*>(bstrGroup) );
282
283 hr = pGroup->Remove(bstrUser);
284 ExitOnFailure(hr, "Failed to remove user %ls from group '%ls'.", reinterpret_cast<WCHAR*>(bstrUser), reinterpret_cast<WCHAR*>(bstrGroup) );
285 }
286
287LExit:
288 ReleaseObject(pGroup);
289 ReleaseBSTR(bstrUser);
290 ReleaseBSTR(bstrGroup);
291
292 return hr;
293}
294
295
296static HRESULT GetUserHasRight(
297 __in LSA_HANDLE hPolicy,
298 __in PSID pUserSid,
299 __in LPWSTR wzRight,
300 __out BOOL* fHasRight
301)
302{
303 HRESULT hr = S_OK;
304 NTSTATUS nt = 0;
305 LSA_UNICODE_STRING lucPrivilege = { 0 };
306 PLSA_ENUMERATION_INFORMATION rgSids = NULL;
307 ULONG cSids = 0;
308 *fHasRight = FALSE;
309
310 lucPrivilege.Buffer = wzRight;
311 lucPrivilege.Length = static_cast<USHORT>(lstrlenW(lucPrivilege.Buffer) * sizeof(WCHAR));
312 lucPrivilege.MaximumLength = (lucPrivilege.Length + 1) * sizeof(WCHAR);
313
314 nt = ::LsaEnumerateAccountsWithUserRight(hPolicy, &lucPrivilege, reinterpret_cast<PVOID*>(&rgSids), &cSids);
315 hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt));
316 ExitOnFailure(hr, "Failed to enumerate users for right: %ls", lucPrivilege.Buffer);
317
318 for (DWORD i = 0; i < cSids; ++i)
319 {
320 PLSA_ENUMERATION_INFORMATION pInfo = rgSids + i;
321 if (::EqualSid(pUserSid, pInfo->Sid))
322 {
323 *fHasRight = TRUE;
324 break;
325 }
326 }
327
328LExit:
329 if (rgSids)
330 {
331 ::LsaFreeMemory(rgSids);
332 }
333
334 return hr;
335}
336
337
338static HRESULT GetExistingUserRightsAssignments(
339 __in_opt LPCWSTR wzDomain,
340 __in LPCWSTR wzName,
341 __inout int* iAttributes
342)
343{
344 HRESULT hr = S_OK;
345 NTSTATUS nt = 0;
346 BOOL fHasRight = FALSE;
347
348 LSA_HANDLE hPolicy = NULL;
349 LSA_OBJECT_ATTRIBUTES objectAttributes = { 0 };
350
351 LPWSTR pwzUser = NULL;
352 PSID psid = NULL;
353
354 if (wzDomain && *wzDomain)
355 {
356 hr = StrAllocFormatted(&pwzUser, L"%s\\%s", wzDomain, wzName);
357 ExitOnFailure(hr, "Failed to allocate user with domain string");
358 }
359 else
360 {
361 hr = StrAllocString(&pwzUser, wzName, 0);
362 ExitOnFailure(hr, "Failed to allocate string from user name.");
363 }
364
365 hr = AclGetAccountSid(NULL, pwzUser, &psid);
366 ExitOnFailure(hr, "Failed to get SID for user: %ls", pwzUser);
367
368 nt = ::LsaOpenPolicy(NULL, &objectAttributes, POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION, &hPolicy);
369 hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt));
370 ExitOnFailure(hr, "Failed to open LSA policy store");
371
372 hr = GetUserHasRight(hPolicy, psid, L"SeServiceLogonRight", &fHasRight);
373 ExitOnFailure(hr, "Failed to check LogonAsService right");
374
375 if (fHasRight)
376 {
377 *iAttributes |= SCAU_ALLOW_LOGON_AS_SERVICE;
378 }
379
380 hr = GetUserHasRight(hPolicy, psid, L"SeBatchLogonRight", &fHasRight);
381 ExitOnFailure(hr, "Failed to check LogonAsBatchJob right");
382
383 if (fHasRight)
384 {
385 *iAttributes |= SCAU_ALLOW_LOGON_AS_BATCH;
386 }
387
388LExit:
389 if (hPolicy)
390 {
391 ::LsaClose(hPolicy);
392 }
393
394 ReleaseSid(psid);
395 ReleaseStr(pwzUser);
396 return hr;
397}
398
399
400static HRESULT ModifyUserLocalServiceRight(
401 __in_opt LPCWSTR wzDomain,
402 __in LPCWSTR wzName,
403 __in BOOL fAdd
404 )
405{
406 HRESULT hr = S_OK;
407 NTSTATUS nt = 0;
408
409 LPWSTR pwzUser = NULL;
410 PSID psid = NULL;
411 LSA_HANDLE hPolicy = NULL;
412 LSA_OBJECT_ATTRIBUTES ObjectAttributes = { 0 };
413 LSA_UNICODE_STRING lucPrivilege = { 0 };
414
415 if (wzDomain && *wzDomain)
416 {
417 hr = StrAllocFormatted(&pwzUser, L"%s\\%s", wzDomain, wzName);
418 ExitOnFailure(hr, "Failed to allocate user with domain string");
419 }
420 else
421 {
422 hr = StrAllocString(&pwzUser, wzName, 0);
423 ExitOnFailure(hr, "Failed to allocate string from user name.");
424 }
425
426 hr = AclGetAccountSid(NULL, pwzUser, &psid);
427 ExitOnFailure(hr, "Failed to get SID for user: %ls", pwzUser);
428
429 nt = ::LsaOpenPolicy(NULL, &ObjectAttributes, POLICY_ALL_ACCESS, &hPolicy);
430 hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt));
431 ExitOnFailure(hr, "Failed to open LSA policy store.");
432
433 lucPrivilege.Buffer = L"SeServiceLogonRight";
434 lucPrivilege.Length = static_cast<USHORT>(lstrlenW(lucPrivilege.Buffer) * sizeof(WCHAR));
435 lucPrivilege.MaximumLength = (lucPrivilege.Length + 1) * sizeof(WCHAR);
436
437 if (fAdd)
438 {
439 nt = ::LsaAddAccountRights(hPolicy, psid, &lucPrivilege, 1);
440 hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt));
441 ExitOnFailure(hr, "Failed to add 'logon as service' bit to user: %ls", pwzUser);
442 }
443 else
444 {
445 nt = ::LsaRemoveAccountRights(hPolicy, psid, FALSE, &lucPrivilege, 1);
446 hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt));
447 ExitOnFailure(hr, "Failed to remove 'logon as service' bit from user: %ls", pwzUser);
448 }
449
450LExit:
451 if (hPolicy)
452 {
453 ::LsaClose(hPolicy);
454 }
455
456 ReleaseSid(psid);
457 ReleaseStr(pwzUser);
458 return hr;
459}
460
461
462static HRESULT ModifyUserLocalBatchRight(
463 __in_opt LPCWSTR wzDomain,
464 __in LPCWSTR wzName,
465 __in BOOL fAdd
466 )
467{
468 HRESULT hr = S_OK;
469 NTSTATUS nt = 0;
470
471 LPWSTR pwzUser = NULL;
472 PSID psid = NULL;
473 LSA_HANDLE hPolicy = NULL;
474 LSA_OBJECT_ATTRIBUTES ObjectAttributes = { 0 };
475 LSA_UNICODE_STRING lucPrivilege = { 0 };
476
477 if (wzDomain && *wzDomain)
478 {
479 hr = StrAllocFormatted(&pwzUser, L"%s\\%s", wzDomain, wzName);
480 ExitOnFailure(hr, "Failed to allocate user with domain string");
481 }
482 else
483 {
484 hr = StrAllocString(&pwzUser, wzName, 0);
485 ExitOnFailure(hr, "Failed to allocate string from user name.");
486 }
487
488 hr = AclGetAccountSid(NULL, pwzUser, &psid);
489 ExitOnFailure(hr, "Failed to get SID for user: %ls", pwzUser);
490
491 nt = ::LsaOpenPolicy(NULL, &ObjectAttributes, POLICY_ALL_ACCESS, &hPolicy);
492 hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt));
493 ExitOnFailure(hr, "Failed to open LSA policy store.");
494
495 lucPrivilege.Buffer = L"SeBatchLogonRight";
496 lucPrivilege.Length = static_cast<USHORT>(lstrlenW(lucPrivilege.Buffer) * sizeof(WCHAR));
497 lucPrivilege.MaximumLength = (lucPrivilege.Length + 1) * sizeof(WCHAR);
498
499 if (fAdd)
500 {
501 nt = ::LsaAddAccountRights(hPolicy, psid, &lucPrivilege, 1);
502 hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt));
503 ExitOnFailure(hr, "Failed to add 'logon as batch job' bit to user: %ls", pwzUser);
504 }
505 else
506 {
507 nt = ::LsaRemoveAccountRights(hPolicy, psid, FALSE, &lucPrivilege, 1);
508 hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt));
509 ExitOnFailure(hr, "Failed to remove 'logon as batch job' bit from user: %ls", pwzUser);
510 }
511
512 LExit:
513 if (hPolicy)
514 {
515 ::LsaClose(hPolicy);
516 }
517
518 ReleaseSid(psid);
519 ReleaseStr(pwzUser);
520 return hr;
521}
522
523static void SetUserPasswordAndAttributes(
524 __in USER_INFO_1* puserInfo,
525 __in LPWSTR wzPassword,
526 __in int iAttributes
527 )
528{
529 Assert(puserInfo);
530
531 // Set the User's password
532 puserInfo->usri1_password = wzPassword;
533
534 // Apply the Attributes
535 if (SCAU_DONT_EXPIRE_PASSWRD & iAttributes)
536 {
537 puserInfo->usri1_flags |= UF_DONT_EXPIRE_PASSWD;
538 }
539 else
540 {
541 puserInfo->usri1_flags &= ~UF_DONT_EXPIRE_PASSWD;
542 }
543
544 if (SCAU_PASSWD_CANT_CHANGE & iAttributes)
545 {
546 puserInfo->usri1_flags |= UF_PASSWD_CANT_CHANGE;
547 }
548 else
549 {
550 puserInfo->usri1_flags &= ~UF_PASSWD_CANT_CHANGE;
551 }
552
553 if (SCAU_DISABLE_ACCOUNT & iAttributes)
554 {
555 puserInfo->usri1_flags |= UF_ACCOUNTDISABLE;
556 }
557 else
558 {
559 puserInfo->usri1_flags &= ~UF_ACCOUNTDISABLE;
560 }
561
562 if (SCAU_PASSWD_CHANGE_REQD_ON_LOGIN & iAttributes) // TODO: for some reason this doesn't work
563 {
564 puserInfo->usri1_flags |= UF_PASSWORD_EXPIRED;
565 }
566 else
567 {
568 puserInfo->usri1_flags &= ~UF_PASSWORD_EXPIRED;
569 }
570}
571
572
573static HRESULT RemoveUserInternal(
574 LPWSTR wzGroupCaData,
575 LPWSTR wzDomain,
576 LPWSTR wzName,
577 int iAttributes
578)
579{
580 HRESULT hr = S_OK;
581 UINT er = ERROR_SUCCESS;
582
583 LPWSTR pwz = NULL;
584 LPWSTR pwzGroup = NULL;
585 LPWSTR pwzGroupDomain = NULL;
586 LPCWSTR wz = NULL;
587 PDOMAIN_CONTROLLER_INFOW pDomainControllerInfo = NULL;
588
589 //
590 // Remove the logon as service privilege.
591 //
592 if (SCAU_ALLOW_LOGON_AS_SERVICE & iAttributes)
593 {
594 hr = ModifyUserLocalServiceRight(wzDomain, wzName, FALSE);
595 if (FAILED(hr))
596 {
597 WcaLogError(hr, "Failed to remove logon as service right from user, continuing...");
598 hr = S_OK;
599 }
600 }
601
602 if (SCAU_ALLOW_LOGON_AS_BATCH & iAttributes)
603 {
604 hr = ModifyUserLocalBatchRight(wzDomain, wzName, FALSE);
605 if (FAILED(hr))
606 {
607 WcaLogError(hr, "Failed to remove logon as batch job right from user, continuing...");
608 hr = S_OK;
609 }
610 }
611
612 //
613 // Remove the User Account if the user was created by us.
614 //
615 if (!(SCAU_DONT_CREATE_USER & iAttributes))
616 {
617 if (wzDomain && *wzDomain)
618 {
619 er = ::DsGetDcNameW(NULL, (LPCWSTR)wzDomain, NULL, NULL, NULL, &pDomainControllerInfo);
620 if (RPC_S_SERVER_UNAVAILABLE == er)
621 {
622 // MSDN says, if we get the above error code, try again with the "DS_FORCE_REDISCOVERY" flag
623 er = ::DsGetDcNameW(NULL, (LPCWSTR)wzDomain, NULL, NULL, DS_FORCE_REDISCOVERY, &pDomainControllerInfo);
624 }
625 if (ERROR_SUCCESS == er)
626 {
627 wz = pDomainControllerInfo->DomainControllerName + 2; //Add 2 so that we don't get the \\ prefix
628 }
629 else
630 {
631 wz = wzDomain;
632 }
633 }
634
635 er = ::NetUserDel(wz, wzName);
636 if (NERR_UserNotFound == er)
637 {
638 er = NERR_Success;
639 }
640 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "failed to delete user account: %ls", wzName);
641 }
642 else
643 {
644 //
645 // Remove the user from the groups
646 //
647 pwz = wzGroupCaData;
648 while (S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzGroup)))
649 {
650 hr = WcaReadStringFromCaData(&pwz, &pwzGroupDomain);
651
652 if (FAILED(hr))
653 {
654 WcaLogError(hr, "failed to get domain for group: %ls, continuing anyway.", pwzGroup);
655 }
656 else
657 {
658 hr = RemoveUserFromGroup(wzName, wzDomain, pwzGroup, pwzGroupDomain);
659 if (FAILED(hr))
660 {
661 WcaLogError(hr, "failed to remove user: %ls from group %ls, continuing anyway.", wzName, pwzGroup);
662 }
663 }
664 }
665
666 if (E_NOMOREITEMS == hr) // if there are no more items, all is well
667 {
668 hr = S_OK;
669 }
670
671 ExitOnFailure(hr, "failed to get next group from which to remove user:%ls", wzName);
672 }
673
674LExit:
675 if (pDomainControllerInfo)
676 {
677 ::NetApiBufferFree(static_cast<LPVOID>(pDomainControllerInfo));
678 }
679
680 return hr;
681}
682
683
684/********************************************************************
685 CreateUser - CUSTOM ACTION ENTRY POINT for creating users
686
687 Input: deferred CustomActionData - UserName\tDomain\tPassword\tAttributes\tGroupName\tDomain\tGroupName\tDomain...
688 * *****************************************************************/
689extern "C" UINT __stdcall CreateUser(
690 __in MSIHANDLE hInstall
691 )
692{
693 //AssertSz(0, "Debug CreateUser");
694
695 HRESULT hr = S_OK;
696 UINT er = ERROR_SUCCESS;
697
698 LPWSTR pwzData = NULL;
699 LPWSTR pwz = NULL;
700 LPWSTR pwzName = NULL;
701 LPWSTR pwzDomain = NULL;
702 LPWSTR pwzScriptKey = NULL;
703 LPWSTR pwzPassword = NULL;
704 LPWSTR pwzGroup = NULL;
705 LPWSTR pwzGroupDomain = NULL;
706 PDOMAIN_CONTROLLER_INFOW pDomainControllerInfo = NULL;
707 int iAttributes = 0;
708 BOOL fInitializedCom = FALSE;
709
710 WCA_CASCRIPT_HANDLE hRollbackScript = NULL;
711 int iOriginalAttributes = 0;
712 int iRollbackAttributes = 0;
713
714 USER_INFO_1 userInfo;
715 USER_INFO_1* puserInfo = NULL;
716 DWORD dw;
717 LPCWSTR wz = NULL;
718
719 hr = WcaInitialize(hInstall, "CreateUser");
720 ExitOnFailure(hr, "failed to initialize");
721
722 hr = ::CoInitialize(NULL);
723 ExitOnFailure(hr, "failed to initialize COM");
724 fInitializedCom = TRUE;
725
726 hr = WcaGetProperty( L"CustomActionData", &pwzData);
727 ExitOnFailure(hr, "failed to get CustomActionData");
728
729 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData);
730
731 //
732 // Read in the CustomActionData
733 //
734 pwz = pwzData;
735 hr = WcaReadStringFromCaData(&pwz, &pwzName);
736 ExitOnFailure(hr, "failed to read user name from custom action data");
737
738 hr = WcaReadStringFromCaData(&pwz, &pwzDomain);
739 ExitOnFailure(hr, "failed to read domain from custom action data");
740
741 hr = WcaReadIntegerFromCaData(&pwz, &iAttributes);
742 ExitOnFailure(hr, "failed to read attributes from custom action data");
743
744 hr = WcaReadStringFromCaData(&pwz, &pwzScriptKey);
745 ExitOnFailure(hr, "failed to read encoding key from custom action data");
746
747 hr = WcaReadStringFromCaData(&pwz, &pwzPassword);
748 ExitOnFailure(hr, "failed to read password from custom action data");
749
750 // There is no rollback scheduled if the key is empty.
751 // Best effort to get original configuration and save it in the script so rollback can restore it.
752 if (*pwzScriptKey)
753 {
754 hr = WcaCaScriptCreate(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, FALSE, &hRollbackScript);
755 ExitOnFailure(hr, "Failed to open rollback CustomAction script.");
756
757 iRollbackAttributes = 0;
758 hr = GetExistingUserRightsAssignments(pwzDomain, pwzName, &iOriginalAttributes);
759 if (FAILED(hr))
760 {
761 WcaLogError(hr, "failed to get existing user rights: %ls, continuing anyway.", pwzName);
762 }
763 else
764 {
765 if (!(SCAU_ALLOW_LOGON_AS_SERVICE & iOriginalAttributes) && (SCAU_ALLOW_LOGON_AS_SERVICE & iAttributes))
766 {
767 iRollbackAttributes |= SCAU_ALLOW_LOGON_AS_SERVICE;
768 }
769 if (!(SCAU_ALLOW_LOGON_AS_BATCH & iOriginalAttributes) && (SCAU_ALLOW_LOGON_AS_BATCH & iAttributes))
770 {
771 iRollbackAttributes |= SCAU_ALLOW_LOGON_AS_BATCH;
772 }
773 }
774
775 hr = WcaCaScriptWriteNumber(hRollbackScript, iRollbackAttributes);
776 ExitOnFailure(hr, "Failed to add data to rollback script.");
777
778 // Nudge the system to get all our rollback data written to disk.
779 WcaCaScriptFlush(hRollbackScript);
780 }
781
782 if (!(SCAU_DONT_CREATE_USER & iAttributes))
783 {
784 ::ZeroMemory(&userInfo, sizeof(USER_INFO_1));
785 userInfo.usri1_name = pwzName;
786 userInfo.usri1_priv = USER_PRIV_USER;
787 userInfo.usri1_flags = UF_SCRIPT;
788 userInfo.usri1_home_dir = NULL;
789 userInfo.usri1_comment = NULL;
790 userInfo.usri1_script_path = NULL;
791
792 SetUserPasswordAndAttributes(&userInfo, pwzPassword, iAttributes);
793
794 //
795 // Create the User
796 //
797 if (pwzDomain && *pwzDomain)
798 {
799 er = ::DsGetDcNameW( NULL, (LPCWSTR)pwzDomain, NULL, NULL, NULL, &pDomainControllerInfo );
800 if (RPC_S_SERVER_UNAVAILABLE == er)
801 {
802 // MSDN says, if we get the above error code, try again with the "DS_FORCE_REDISCOVERY" flag
803 er = ::DsGetDcNameW( NULL, (LPCWSTR)pwzDomain, NULL, NULL, DS_FORCE_REDISCOVERY, &pDomainControllerInfo );
804 }
805 if (ERROR_SUCCESS == er)
806 {
807 wz = pDomainControllerInfo->DomainControllerName + 2; //Add 2 so that we don't get the \\ prefix
808 }
809 else
810 {
811 wz = pwzDomain;
812 }
813 }
814
815 er = ::NetUserAdd(wz, 1, reinterpret_cast<LPBYTE>(&userInfo), &dw);
816 if (NERR_UserExists == er)
817 {
818 if (SCAU_UPDATE_IF_EXISTS & iAttributes)
819 {
820 er = ::NetUserGetInfo(wz, pwzName, 1, reinterpret_cast<LPBYTE*>(&puserInfo));
821 if (NERR_Success == er)
822 {
823 // Change the existing user's password and attributes again then try
824 // to update user with this new data
825 SetUserPasswordAndAttributes(puserInfo, pwzPassword, iAttributes);
826
827 er = ::NetUserSetInfo(wz, pwzName, 1, reinterpret_cast<LPBYTE>(puserInfo), &dw);
828 }
829 }
830 else if (!(SCAU_FAIL_IF_EXISTS & iAttributes))
831 {
832 er = NERR_Success;
833 }
834 }
835 else if (NERR_PasswordTooShort == er || NERR_PasswordTooLong == er)
836 {
837 MessageExitOnFailure(hr = HRESULT_FROM_WIN32(er), msierrUSRFailedUserCreatePswd, "failed to create user: %ls due to invalid password.", pwzName);
838 }
839 MessageExitOnFailure(hr = HRESULT_FROM_WIN32(er), msierrUSRFailedUserCreate, "failed to create user: %ls", pwzName);
840 }
841
842 if (SCAU_ALLOW_LOGON_AS_SERVICE & iAttributes)
843 {
844 hr = ModifyUserLocalServiceRight(pwzDomain, pwzName, TRUE);
845 MessageExitOnFailure(hr, msierrUSRFailedGrantLogonAsService, "Failed to grant logon as service rights to user: %ls", pwzName);
846 }
847
848 if (SCAU_ALLOW_LOGON_AS_BATCH & iAttributes)
849 {
850 hr = ModifyUserLocalBatchRight(pwzDomain, pwzName, TRUE);
851 MessageExitOnFailure(hr, msierrUSRFailedGrantLogonAsService, "Failed to grant logon as batch job rights to user: %ls", pwzName);
852 }
853
854 //
855 // Add the users to groups
856 //
857 while (S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzGroup)))
858 {
859 hr = WcaReadStringFromCaData(&pwz, &pwzGroupDomain);
860 ExitOnFailure(hr, "failed to get domain for group: %ls", pwzGroup);
861
862 hr = AddUserToGroup(pwzName, pwzDomain, pwzGroup, pwzGroupDomain);
863 MessageExitOnFailure(hr, msierrUSRFailedUserGroupAdd, "failed to add user: %ls to group %ls", pwzName, pwzGroup);
864 }
865 if (E_NOMOREITEMS == hr) // if there are no more items, all is well
866 {
867 hr = S_OK;
868 }
869 ExitOnFailure(hr, "failed to get next group in which to include user:%ls", pwzName);
870
871LExit:
872 WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_PRESERVE);
873
874 if (puserInfo)
875 {
876 ::NetApiBufferFree((LPVOID)puserInfo);
877 }
878
879 if (pDomainControllerInfo)
880 {
881 ::NetApiBufferFree((LPVOID)pDomainControllerInfo);
882 }
883
884 ReleaseStr(pwzData);
885 ReleaseStr(pwzName);
886 ReleaseStr(pwzDomain);
887 ReleaseStr(pwzScriptKey);
888 ReleaseStr(pwzPassword);
889 ReleaseStr(pwzGroup);
890 ReleaseStr(pwzGroupDomain);
891
892 if (fInitializedCom)
893 {
894 ::CoUninitialize();
895 }
896
897 if (SCAU_NON_VITAL & iAttributes)
898 {
899 er = ERROR_SUCCESS;
900 }
901 else if (FAILED(hr))
902 {
903 er = ERROR_INSTALL_FAILURE;
904 }
905
906 return WcaFinalize(er);
907}
908
909
910/********************************************************************
911 CreateUserRollback - CUSTOM ACTION ENTRY POINT for CreateUser rollback
912
913 * *****************************************************************/
914extern "C" UINT __stdcall CreateUserRollback(
915 MSIHANDLE hInstall
916)
917{
918 //AssertSz(0, "Debug CreateUserRollback");
919
920 HRESULT hr = S_OK;
921 UINT er = ERROR_SUCCESS;
922
923 LPWSTR pwzData = NULL;
924 LPWSTR pwz = NULL;
925 LPWSTR pwzName = NULL;
926 LPWSTR pwzDomain = NULL;
927 LPWSTR pwzScriptKey = NULL;
928 int iAttributes = 0;
929 BOOL fInitializedCom = FALSE;
930
931 WCA_CASCRIPT_HANDLE hRollbackScript = NULL;
932 LPWSTR pwzRollbackData = NULL;
933 int iOriginalAttributes = 0;
934
935 hr = WcaInitialize(hInstall, "CreateUserRollback");
936 ExitOnFailure(hr, "failed to initialize");
937
938 hr = ::CoInitialize(NULL);
939 ExitOnFailure(hr, "failed to initialize COM");
940 fInitializedCom = TRUE;
941
942 hr = WcaGetProperty(L"CustomActionData", &pwzData);
943 ExitOnFailure(hr, "failed to get CustomActionData");
944
945 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData);
946
947 //
948 // Read in the CustomActionData
949 //
950 pwz = pwzData;
951 hr = WcaReadStringFromCaData(&pwz, &pwzScriptKey);
952 ExitOnFailure(hr, "failed to read encoding key from custom action data");
953
954 hr = WcaReadStringFromCaData(&pwz, &pwzName);
955 ExitOnFailure(hr, "failed to read name from custom action data");
956
957 hr = WcaReadStringFromCaData(&pwz, &pwzDomain);
958 ExitOnFailure(hr, "failed to read domain from custom action data");
959
960 hr = WcaReadIntegerFromCaData(&pwz, &iAttributes);
961 ExitOnFailure(hr, "failed to read attributes from custom action data");
962
963 // Best effort to read original configuration from CreateUser.
964 hr = WcaCaScriptOpen(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, &hRollbackScript);
965 if (FAILED(hr))
966 {
967 WcaLogError(hr, "Failed to open rollback CustomAction script, continuing anyway.");
968 }
969 else
970 {
971 hr = WcaCaScriptReadAsCustomActionData(hRollbackScript, &pwzRollbackData);
972 if (FAILED(hr))
973 {
974 WcaLogError(hr, "Failed to read rollback script into CustomAction data, continuing anyway.");
975 }
976 else
977 {
978 WcaLog(LOGMSG_TRACEONLY, "Rollback Data: %ls", pwzRollbackData);
979
980 pwz = pwzRollbackData;
981 hr = WcaReadIntegerFromCaData(&pwz, &iOriginalAttributes);
982 if (FAILED(hr))
983 {
984 WcaLogError(hr, "failed to read attributes from rollback data, continuing anyway");
985 }
986 else
987 {
988 iAttributes |= iOriginalAttributes;
989 }
990 }
991 }
992
993 hr = RemoveUserInternal(pwz, pwzDomain, pwzName, iAttributes);
994
995LExit:
996 WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_DELETE);
997
998 ReleaseStr(pwzData);
999 ReleaseStr(pwzName);
1000 ReleaseStr(pwzDomain);
1001 ReleaseStr(pwzScriptKey);
1002 ReleaseStr(pwzRollbackData);
1003
1004 if (fInitializedCom)
1005 {
1006 ::CoUninitialize();
1007 }
1008
1009 if (FAILED(hr))
1010 {
1011 er = ERROR_INSTALL_FAILURE;
1012 }
1013
1014 return WcaFinalize(er);
1015}
1016
1017
1018/********************************************************************
1019 RemoveUser - CUSTOM ACTION ENTRY POINT for removing users
1020
1021 Input: deferred CustomActionData - Name\tDomain
1022 * *****************************************************************/
1023extern "C" UINT __stdcall RemoveUser(
1024 MSIHANDLE hInstall
1025)
1026{
1027 //AssertSz(0, "Debug RemoveUser");
1028
1029 HRESULT hr = S_OK;
1030 UINT er = ERROR_SUCCESS;
1031
1032 LPWSTR pwzData = NULL;
1033 LPWSTR pwz = NULL;
1034 LPWSTR pwzName = NULL;
1035 LPWSTR pwzDomain = NULL;
1036 int iAttributes = 0;
1037 BOOL fInitializedCom = FALSE;
1038
1039 hr = WcaInitialize(hInstall, "RemoveUser");
1040 ExitOnFailure(hr, "failed to initialize");
1041
1042 hr = ::CoInitialize(NULL);
1043 ExitOnFailure(hr, "failed to initialize COM");
1044 fInitializedCom = TRUE;
1045
1046 hr = WcaGetProperty(L"CustomActionData", &pwzData);
1047 ExitOnFailure(hr, "failed to get CustomActionData");
1048
1049 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData);
1050
1051 //
1052 // Read in the CustomActionData
1053 //
1054 pwz = pwzData;
1055 hr = WcaReadStringFromCaData(&pwz, &pwzName);
1056 ExitOnFailure(hr, "failed to read name from custom action data");
1057
1058 hr = WcaReadStringFromCaData(&pwz, &pwzDomain);
1059 ExitOnFailure(hr, "failed to read domain from custom action data");
1060
1061 hr = WcaReadIntegerFromCaData(&pwz, &iAttributes);
1062 ExitOnFailure(hr, "failed to read attributes from custom action data");
1063
1064 hr = RemoveUserInternal(pwz, pwzDomain, pwzName, iAttributes);
1065
1066LExit:
1067 ReleaseStr(pwzData);
1068 ReleaseStr(pwzName);
1069 ReleaseStr(pwzDomain);
1070
1071 if (fInitializedCom)
1072 {
1073 ::CoUninitialize();
1074 }
1075
1076 if (FAILED(hr))
1077 {
1078 er = ERROR_INSTALL_FAILURE;
1079 }
1080
1081 return WcaFinalize(er);
1082}
diff --git a/src/ext/Util/ca/scamanifest.cpp b/src/ext/Util/ca/scamanifest.cpp
new file mode 100644
index 00000000..adb8d3d3
--- /dev/null
+++ b/src/ext/Util/ca/scamanifest.cpp
@@ -0,0 +1,377 @@
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
5LPCWSTR vcsPerfmonManifestQuery = L"SELECT `Component_`, `File`, `ResourceFileDirectory` FROM `Wix4PerfmonManifest`";
6LPCWSTR vcsEventManifestQuery = L"SELECT `Component_`, `File` FROM `Wix4EventManifest`";
7enum ePerfMonManifestQuery { pfmComponent = 1, pfmFile, pfmResourceFileDir };
8enum eEventManifestQuery { emComponent = 1, emFile};
9
10BOOL IsVistaOrAbove()
11{
12 OSVERSIONINFO osvi;
13 ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
14 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
15 #pragma warning(suppress: 4996) //TODO: use non-deprecated function to check OS version
16 if (!::GetVersionEx(&osvi))
17 {
18 return false;
19 }
20 return osvi.dwMajorVersion >= 6;
21}
22
23
24/********************************************************************
25 ConfigurePerfmonManifestRegister - CUSTOM ACTION ENTRY POINT for scheduling
26 Perfmon counter manifest registering
27
28********************************************************************/
29extern "C" UINT __stdcall ConfigurePerfmonManifestRegister(
30 __in MSIHANDLE hInstall
31 )
32{
33 HRESULT hr;
34 UINT er = ERROR_SUCCESS;
35
36 PMSIHANDLE hView, hRec;
37 LPWSTR pwzData = NULL, pwzResourceFilePath = NULL, pwzFile = NULL, pwzCommand = NULL;
38 INSTALLSTATE isInstalled, isAction;
39
40 hr = WcaInitialize(hInstall, "ConfigurePerfmonManifestReg");
41 ExitOnFailure(hr, "Failed to initialize");
42
43 if (!IsVistaOrAbove())
44 {
45 WcaLog(LOGMSG_VERBOSE, "Skipping ConfigurePerfmonManifestRegister() because the target system does not support perfmon manifest");
46 ExitFunction1(hr = S_FALSE);
47 }
48 // check to see if necessary tables are specified
49 if (S_OK != WcaTableExists(L"Wix4PerfmonManifest"))
50 {
51 WcaLog(LOGMSG_VERBOSE, "Skipping ConfigurePerfmonManifestRegister() because Wix4PerfmonManifest table not present");
52 ExitFunction1(hr = S_FALSE);
53 }
54
55 hr = WcaOpenExecuteView(vcsPerfmonManifestQuery, &hView);
56 ExitOnFailure(hr, "failed to open view on PerfMonManifest table");
57 while ((hr = WcaFetchRecord(hView, &hRec)) == S_OK)
58 {
59 // get component install state
60 hr = WcaGetRecordString(hRec, pfmComponent, &pwzData);
61 ExitOnFailure(hr, "failed to get Component for PerfMonManifest");
62 er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction);
63 hr = HRESULT_FROM_WIN32(er);
64 ExitOnFailure(hr, "failed to get Component state for PerfMonManifest");
65 if (!WcaIsInstalling(isInstalled, isAction))
66 {
67 continue;
68 }
69
70 hr = WcaGetRecordFormattedString(hRec, pfmFile, &pwzFile);
71 ExitOnFailure(hr, "failed to get File for PerfMonManifest");
72
73 hr = WcaGetRecordFormattedString(hRec, pfmResourceFileDir, &pwzResourceFilePath);
74 ExitOnFailure(hr, "failed to get ApplicationIdentity for PerfMonManifest");
75 size_t iResourcePath = lstrlenW(pwzResourceFilePath);
76 if ( iResourcePath > 0 && *(pwzResourceFilePath + iResourcePath -1) == L'\\')
77 *(pwzResourceFilePath + iResourcePath -1) = 0; //remove the trailing '\'
78
79 hr = StrAllocFormatted(&pwzCommand, L"\"unlodctr.exe\" /m:\"%s\"", pwzFile);
80 ExitOnFailure(hr, "failed to copy string in PerfMonManifest");
81
82 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackRegisterPerfmonManifest"), pwzCommand, COST_PERFMONMANIFEST_UNREGISTER);
83 ExitOnFailure(hr, "failed to schedule RollbackRegisterPerfmonManifest action");
84
85 if ( *pwzResourceFilePath )
86 {
87 hr = StrAllocFormatted(&pwzCommand, L"\"lodctr.exe\" /m:\"%s\" \"%s\"", pwzFile, pwzResourceFilePath);
88 ExitOnFailure(hr, "failed to copy string in PerfMonManifest");
89 }
90 else
91 {
92 hr = StrAllocFormatted(&pwzCommand, L"\"lodctr.exe\" /m:\"%s\"", pwzFile);
93 ExitOnFailure(hr, "failed to copy string in PerfMonManifest");
94 }
95
96 WcaLog(LOGMSG_VERBOSE, "RegisterPerfmonManifest's CustomActionData: '%ls'", pwzCommand);
97
98 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RegisterPerfmonManifest"), pwzCommand, COST_PERFMONMANIFEST_REGISTER);
99 ExitOnFailure(hr, "failed to schedule RegisterPerfmonManifest action");
100 }
101
102 if (hr == E_NOMOREITEMS)
103 {
104 hr = S_OK;
105 }
106 ExitOnFailure(hr, "Failure while processing PerfMonManifest");
107
108 hr = S_OK;
109
110LExit:
111 ReleaseStr(pwzData);
112 ReleaseStr(pwzResourceFilePath);
113 ReleaseStr(pwzFile);
114 ReleaseStr(pwzCommand);
115
116 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
117 return WcaFinalize(er);
118}
119
120
121/********************************************************************
122 ConfigurePerfmonUninstall - CUSTOM ACTION ENTRY POINT for uninstalling
123 Perfmon counters
124
125********************************************************************/
126extern "C" UINT __stdcall ConfigurePerfmonManifestUnregister(
127 __in MSIHANDLE hInstall
128 )
129{
130 HRESULT hr;
131 UINT er = ERROR_SUCCESS;
132
133 PMSIHANDLE hView, hRec;
134 LPWSTR pwzData = NULL, pwzResourceFilePath = NULL, pwzFile = NULL, pwzCommand = NULL;
135 INSTALLSTATE isInstalled, isAction;
136
137 hr = WcaInitialize(hInstall, "ConfigurePerfmonManifestUnreg");
138 ExitOnFailure(hr, "Failed to initialize");
139
140 if (!IsVistaOrAbove())
141 {
142 WcaLog(LOGMSG_VERBOSE, "Skipping ConfigurePerfmonManifestUnregister() because the target system does not support perfmon manifest");
143 ExitFunction1(hr = S_FALSE);
144 }
145 // check to see if necessary tables are specified
146 if (WcaTableExists(L"Wix4PerfmonManifest") != S_OK)
147 {
148 WcaLog(LOGMSG_VERBOSE, "Skipping ConfigurePerfmonManifestUnregister() because Wix4PerfmonManifest table not present");
149 ExitFunction1(hr = S_FALSE);
150 }
151
152 hr = WcaOpenExecuteView(vcsPerfmonManifestQuery, &hView);
153 ExitOnFailure(hr, "failed to open view on Wix4PerfmonManifest table");
154 while ((hr = WcaFetchRecord(hView, &hRec)) == S_OK)
155 {
156 // get component install state
157 hr = WcaGetRecordString(hRec, pfmComponent, &pwzData);
158 ExitOnFailure(hr, "failed to get Component for Wix4PerfmonManifest");
159 er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction);
160 hr = HRESULT_FROM_WIN32(er);
161 ExitOnFailure(hr, "failed to get Component state for Wix4PerfmonManifest");
162 if (!WcaIsUninstalling(isInstalled, isAction))
163 {
164 continue;
165 }
166
167 hr = WcaGetRecordFormattedString(hRec, pfmFile, &pwzFile);
168 ExitOnFailure(hr, "failed to get File for Wix4PerfmonManifest");
169
170 hr = WcaGetRecordFormattedString(hRec, pfmResourceFileDir, &pwzResourceFilePath);
171 ExitOnFailure(hr, "failed to get ApplicationIdentity for Wix4PerfmonManifest");
172 size_t iResourcePath = lstrlenW(pwzResourceFilePath);
173 if ( iResourcePath > 0 && *(pwzResourceFilePath + iResourcePath -1) == L'\\')
174 *(pwzResourceFilePath + iResourcePath -1) = 0; //remove the trailing '\'
175
176 hr = StrAllocFormatted(&pwzCommand, L"\"lodctr.exe\" /m:\"%s\" \"%s\"", pwzFile, pwzResourceFilePath);
177 ExitOnFailure(hr, "failed to copy string in Wix4PerfmonManifest");
178
179 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackUnregisterPerfmonManifest"), pwzCommand, COST_PERFMONMANIFEST_REGISTER);
180 ExitOnFailure(hr, "failed to schedule RollbackUnregisterPerfmonManifest action");
181
182 hr = StrAllocFormatted(&pwzCommand, L"\"unlodctr.exe\" /m:\"%s\"", pwzFile);
183 ExitOnFailure(hr, "failed to copy string in PerfMonManifest");
184
185 WcaLog(LOGMSG_VERBOSE, "UnRegisterPerfmonManifest's CustomActionData: '%ls'", pwzCommand);
186
187 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"UnregisterPerfmonManifest"), pwzCommand, COST_PERFMONMANIFEST_UNREGISTER);
188 ExitOnFailure(hr, "failed to schedule UnregisterPerfmonManifest action");
189 }
190
191 if (hr == E_NOMOREITEMS)
192 {
193 hr = S_OK;
194 }
195 ExitOnFailure(hr, "Failure while processing PerfMonManifest");
196
197 hr = S_OK;
198
199LExit:
200 ReleaseStr(pwzData);
201 ReleaseStr(pwzResourceFilePath);
202 ReleaseStr(pwzFile);
203 ReleaseStr(pwzCommand);
204
205 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
206 return WcaFinalize(er);
207}
208
209/********************************************************************
210 ConfigureEventManifestRegister - CUSTOM ACTION ENTRY POINT for scheduling
211 Event manifest registering
212
213********************************************************************/
214extern "C" UINT __stdcall ConfigureEventManifestRegister(
215 __in MSIHANDLE hInstall
216 )
217{
218 HRESULT hr;
219 UINT er = ERROR_SUCCESS;
220
221 PMSIHANDLE hView, hRec;
222 LPWSTR pwzData = NULL, pwzFile = NULL, pwzCommand = NULL;
223 INSTALLSTATE isInstalled, isAction;
224
225 hr = WcaInitialize(hInstall, "ConfigureEventManifestReg");
226 ExitOnFailure(hr, "Failed to initialize");
227
228 if (!IsVistaOrAbove())
229 {
230 WcaLog(LOGMSG_VERBOSE, "Skipping ConfigureEventManifestRegister() because the target system does not support event manifest");
231 ExitFunction1(hr = S_FALSE);
232 }
233 // check to see if necessary tables are specified
234 if (S_OK != WcaTableExists(L"Wix4EventManifest"))
235 {
236 WcaLog(LOGMSG_VERBOSE, "Skipping ConfigureEventManifestRegister() because Wix4EventManifest table not present");
237 ExitFunction1(hr = S_FALSE);
238 }
239
240 hr = WcaOpenExecuteView(vcsEventManifestQuery, &hView);
241 ExitOnFailure(hr, "failed to open view on Wix4EventManifest table");
242 while ((hr = WcaFetchRecord(hView, &hRec)) == S_OK)
243 {
244 // get component install state
245 hr = WcaGetRecordString(hRec, emComponent, &pwzData);
246 ExitOnFailure(hr, "failed to get Component for Wix4EventManifest");
247 er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction);
248 hr = HRESULT_FROM_WIN32(er);
249 ExitOnFailure(hr, "failed to get Component state for Wix4EventManifest");
250 if (!WcaIsInstalling(isInstalled, isAction))
251 {
252 continue;
253 }
254
255 hr = WcaGetRecordFormattedString(hRec, emFile, &pwzFile);
256 ExitOnFailure(hr, "failed to get File for Wix4EventManifest");
257
258 hr = StrAllocFormatted(&pwzCommand, L"\"wevtutil.exe\" um \"%s\"", pwzFile);
259 ExitOnFailure(hr, "failed to copy string in Wix4EventManifest");
260
261 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackRegisterEventManifest"), pwzCommand, COST_PERFMONMANIFEST_UNREGISTER);
262 ExitOnFailure(hr, "failed to schedule RollbackRegisterEventManifest action");
263
264 hr = StrAllocFormatted(&pwzCommand, L"\"wevtutil.exe\" im \"%s\"", pwzFile);
265 ExitOnFailure(hr, "failed to copy string in Wix4EventManifest");
266 WcaLog(LOGMSG_VERBOSE, "RegisterEventManifest's CustomActionData: '%ls'", pwzCommand);
267
268 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RegisterEventManifest"), pwzCommand, COST_EVENTMANIFEST_REGISTER);
269 ExitOnFailure(hr, "failed to schedule RegisterEventManifest action");
270 }
271
272 if (hr == E_NOMOREITEMS)
273 {
274 hr = S_OK;
275 }
276 ExitOnFailure(hr, "Failure while processing Wix4EventManifest");
277
278 hr = S_OK;
279
280LExit:
281 ReleaseStr(pwzData);
282 ReleaseStr(pwzFile);
283 ReleaseStr(pwzCommand);
284
285 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
286 return WcaFinalize(er);
287}
288
289
290
291/********************************************************************
292 ConfigureEventManifestRegister - CUSTOM ACTION ENTRY POINT for scheduling
293 Event manifest registering
294
295********************************************************************/
296extern "C" UINT __stdcall ConfigureEventManifestUnregister(
297 __in MSIHANDLE hInstall
298 )
299{
300 HRESULT hr;
301 UINT er = ERROR_SUCCESS;
302
303 PMSIHANDLE hView, hRec;
304 LPWSTR pwzData = NULL, pwzFile = NULL, pwzCommand = NULL;
305 INSTALLSTATE isInstalled, isAction;
306
307 hr = WcaInitialize(hInstall, "ConfigureEventManifestUnreg");
308 ExitOnFailure(hr, "Failed to initialize");
309
310 if (!IsVistaOrAbove())
311 {
312 WcaLog(LOGMSG_VERBOSE, "Skipping ConfigureEventManifestUnregister() because the target system does not support event manifest");
313 ExitFunction1(hr = S_FALSE);
314 }
315 // check to see if necessary tables are specified
316 if (S_OK != WcaTableExists(L"Wix4EventManifest"))
317 {
318 WcaLog(LOGMSG_VERBOSE, "Skipping ConfigureEventManifestUnregister() because Wix4EventManifest table not present");
319 ExitFunction1(hr = S_FALSE);
320 }
321
322 hr = WcaOpenExecuteView(vcsEventManifestQuery, &hView);
323 ExitOnFailure(hr, "failed to open view on Wix4EventManifest table");
324 while ((hr = WcaFetchRecord(hView, &hRec)) == S_OK)
325 {
326 // get component install state
327 hr = WcaGetRecordString(hRec, emComponent, &pwzData);
328 ExitOnFailure(hr, "failed to get Component for Wix4EventManifest");
329 er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction);
330 hr = HRESULT_FROM_WIN32(er);
331 ExitOnFailure(hr, "failed to get Component state for Wix4EventManifest");
332
333 // nothing to do on an install
334 // schedule the rollback action when reinstalling to re-register pre-patch manifest
335 if (!WcaIsUninstalling(isInstalled, isAction) && !WcaIsReInstalling(isInstalled, isAction))
336 {
337 continue;
338 }
339
340 hr = WcaGetRecordFormattedString(hRec, emFile, &pwzFile);
341 ExitOnFailure(hr, "failed to get File for Wix4EventManifest");
342
343 hr = StrAllocFormatted(&pwzCommand, L"\"wevtutil.exe\" im \"%s\"", pwzFile);
344 ExitOnFailure(hr, "failed to copy string in Wix4EventManifest");
345
346 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackUnregisterEventManifest"), pwzCommand, COST_PERFMONMANIFEST_REGISTER);
347 ExitOnFailure(hr, "failed to schedule RollbackUnregisterEventManifest action");
348
349 // no need to uninstall on a repair/patch. Register action will re-register and update the manifest.
350 if (!WcaIsReInstalling(isInstalled, isAction))
351 {
352 hr = StrAllocFormatted(&pwzCommand, L"\"wevtutil.exe\" um \"%s\"", pwzFile);
353 ExitOnFailure(hr, "failed to copy string in Wix4EventManifest");
354 WcaLog(LOGMSG_VERBOSE, "UnregisterEventManifest's CustomActionData: '%ls'", pwzCommand);
355
356 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"UnregisterEventManifest"), pwzCommand, COST_PERFMONMANIFEST_UNREGISTER);
357 ExitOnFailure(hr, "failed to schedule UnregisterEventManifest action");
358 }
359 }
360
361 if (hr == E_NOMOREITEMS)
362 {
363 hr = S_OK;
364 }
365 ExitOnFailure(hr, "Failure while processing Wix4EventManifest");
366
367 hr = S_OK;
368
369LExit:
370 ReleaseStr(pwzData);
371 ReleaseStr(pwzFile);
372 ReleaseStr(pwzCommand);
373
374 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
375 return WcaFinalize(er);
376}
377
diff --git a/src/ext/Util/ca/scaperf.cpp b/src/ext/Util/ca/scaperf.cpp
new file mode 100644
index 00000000..fd301278
--- /dev/null
+++ b/src/ext/Util/ca/scaperf.cpp
@@ -0,0 +1,310 @@
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
5LPCWSTR vcsPerfCounterDataQuery = L"SELECT `Wix4PerformanceCategory`, `Component_`, `Name`, `IniData`, `ConstantData` FROM `Wix4PerformanceCategory`";
6enum ePerfCounterDataQuery { pcdqId = 1, pcdqComponent, pcdqName, pcdqIniData, pcdqConstantData };
7
8LPCWSTR vcsPerfMonQuery = L"SELECT `Component_`, `File`, `Name` FROM `Wix4Perfmon`";
9enum ePerfMonQuery { pmqComponent = 1, pmqFile, pmqName };
10
11
12static HRESULT ProcessPerformanceCategory(
13 __in MSIHANDLE hInstall,
14 __in BOOL fInstall
15 );
16
17
18/********************************************************************
19 InstallPerfCounterData - CUSTOM ACTION ENTRY POINT for installing
20 Performance Counters.
21
22********************************************************************/
23extern "C" UINT __stdcall InstallPerfCounterData(
24 __in MSIHANDLE hInstall
25 )
26{
27 // AssertSz(FALSE, "debug InstallPerfCounterData{}");
28 HRESULT hr;
29 UINT er = ERROR_SUCCESS;
30
31 hr = WcaInitialize(hInstall, "InstallPerfCounterData");
32 ExitOnFailure(hr, "Failed to initialize InstallPerfCounterData.");
33
34 hr = ProcessPerformanceCategory(hInstall, TRUE);
35 MessageExitOnFailure(hr, msierrInstallPerfCounterData, "Failed to process Wix4PerformanceCategory table.");
36
37LExit:
38 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
39 return WcaFinalize(er);
40}
41
42
43/********************************************************************
44 UninstallPerfCounterData - CUSTOM ACTION ENTRY POINT for installing
45 Performance Counters.
46
47********************************************************************/
48extern "C" UINT __stdcall UninstallPerfCounterData(
49 __in MSIHANDLE hInstall
50 )
51{
52 // AssertSz(FALSE, "debug UninstallPerfCounterData{}");
53 HRESULT hr;
54 UINT er = ERROR_SUCCESS;
55
56 hr = WcaInitialize(hInstall, "UninstallPerfCounterData");
57 ExitOnFailure(hr, "Failed to initialize UninstallPerfCounterData.");
58
59 hr = ProcessPerformanceCategory(hInstall, FALSE);
60 MessageExitOnFailure(hr, msierrUninstallPerfCounterData, "Failed to process Wix4PerformanceCategory table.");
61
62LExit:
63 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
64 return WcaFinalize(er);
65}
66
67
68/********************************************************************
69 RegisterPerfmon - CUSTOM ACTION ENTRY POINT for installing Perfmon counters
70
71********************************************************************/
72extern "C" UINT __stdcall ConfigurePerfmonInstall(
73 __in MSIHANDLE hInstall
74 )
75{
76// Assert(FALSE);
77 HRESULT hr;
78 UINT er = ERROR_SUCCESS;
79
80 PMSIHANDLE hView, hRec;
81 LPWSTR pwzData = NULL, pwzName = NULL, pwzFile = NULL;
82 INSTALLSTATE isInstalled, isAction;
83
84 hr = WcaInitialize(hInstall, "ConfigurePerfmonInstall");
85 ExitOnFailure(hr, "Failed to initialize");
86
87 // check to see if necessary tables are specified
88 if (S_OK != WcaTableExists(L"Wix4Perfmon"))
89 {
90 WcaLog(LOGMSG_VERBOSE, "Skipping RegisterPerfmon() because Wix4Perfmon table not present");
91 ExitFunction1(hr = S_FALSE);
92 }
93
94 hr = WcaOpenExecuteView(vcsPerfMonQuery, &hView);
95 ExitOnFailure(hr, "failed to open view on PerfMon table");
96 while ((hr = WcaFetchRecord(hView, &hRec)) == S_OK)
97 {
98 // get component install state
99 hr = WcaGetRecordString(hRec, pmqComponent, &pwzData);
100 ExitOnFailure(hr, "failed to get Component for PerfMon");
101 er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction);
102 hr = HRESULT_FROM_WIN32(er);
103 ExitOnFailure(hr, "failed to get Component state for PerfMon");
104 if (!WcaIsInstalling(isInstalled, isAction))
105 {
106 continue;
107 }
108
109 hr = WcaGetRecordString(hRec, pmqName, &pwzName);
110 ExitOnFailure(hr, "failed to get Name for PerfMon");
111
112 hr = WcaGetRecordFormattedString(hRec, pmqFile, &pwzFile);
113 ExitOnFailure(hr, "failed to get File for PerfMon");
114
115 WcaLog(LOGMSG_VERBOSE, "ConfigurePerfmonInstall's CustomActionData: '%ls', '%ls'", pwzName, pwzFile);
116 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RegisterPerfmon"), pwzFile, COST_PERFMON_REGISTER);
117 ExitOnFailure(hr, "failed to schedule RegisterPerfmon action");
118 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackRegisterPerfmon"), pwzName, COST_PERFMON_UNREGISTER);
119 ExitOnFailure(hr, "failed to schedule RollbackRegisterPerfmon action");
120 }
121
122 if (hr == E_NOMOREITEMS)
123 {
124 hr = S_OK;
125 }
126 ExitOnFailure(hr, "Failure while processing PerfMon");
127
128 hr = S_OK;
129
130LExit:
131 ReleaseStr(pwzData);
132 ReleaseStr(pwzName);
133 ReleaseStr(pwzFile);
134
135 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
136 return WcaFinalize(er);
137}
138
139
140/********************************************************************
141 ConfigurePerfmonUninstall - CUSTOM ACTION ENTRY POINT for uninstalling
142 Perfmon counters
143
144********************************************************************/
145extern "C" UINT __stdcall ConfigurePerfmonUninstall(
146 __in MSIHANDLE hInstall
147 )
148{
149// Assert(FALSE);
150 HRESULT hr;
151 UINT er = ERROR_SUCCESS;
152
153 PMSIHANDLE hView, hRec;
154 LPWSTR pwzData = NULL, pwzName = NULL, pwzFile = NULL;
155 INSTALLSTATE isInstalled, isAction;
156
157 hr = WcaInitialize(hInstall, "ConfigurePerfmonUninstall");
158 ExitOnFailure(hr, "Failed to initialize");
159
160 // check to see if necessary tables are specified
161 if (WcaTableExists(L"Wix4Perfmon") != S_OK)
162 {
163 WcaLog(LOGMSG_VERBOSE, "Skipping UnregisterPerfmon() because Wix4Perfmon table not present");
164 ExitFunction1(hr = S_FALSE);
165 }
166
167 hr = WcaOpenExecuteView(vcsPerfMonQuery, &hView);
168 ExitOnFailure(hr, "failed to open view on PerfMon table");
169 while ((hr = WcaFetchRecord(hView, &hRec)) == S_OK)
170 {
171 // get component install state
172 hr = WcaGetRecordString(hRec, pmqComponent, &pwzData);
173 ExitOnFailure(hr, "failed to get Component for PerfMon");
174 er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction);
175 hr = HRESULT_FROM_WIN32(er);
176 ExitOnFailure(hr, "failed to get Component state for PerfMon");
177 if (!WcaIsUninstalling(isInstalled, isAction))
178 {
179 continue;
180 }
181
182 hr = WcaGetRecordString(hRec, pmqName, &pwzName);
183 ExitOnFailure(hr, "failed to get Name for PerfMon");
184
185 hr = WcaGetRecordFormattedString(hRec, pmqFile, &pwzFile);
186 ExitOnFailure(hr, "failed to get File for PerfMon");
187
188 WcaLog(LOGMSG_VERBOSE, "ConfigurePerfmonUninstall's CustomActionData: '%ls', '%ls'", pwzName, pwzFile);
189 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"UnregisterPerfmon"), pwzName, COST_PERFMON_UNREGISTER);
190 ExitOnFailure(hr, "failed to schedule UnregisterPerfmon action");
191 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackUnregisterPerfmon"), pwzFile, COST_PERFMON_REGISTER);
192 ExitOnFailure(hr, "failed to schedule RollbackUnregisterPerfmon action");
193 }
194
195 if (hr == E_NOMOREITEMS)
196 {
197 hr = S_OK;
198 }
199 ExitOnFailure(hr, "Failure while processing PerfMon");
200
201 hr = S_OK;
202
203LExit:
204 ReleaseStr(pwzData);
205 ReleaseStr(pwzName);
206 ReleaseStr(pwzFile);
207
208 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
209 return WcaFinalize(er);
210}
211
212
213
214static HRESULT ProcessPerformanceCategory(
215 __in MSIHANDLE hInstall,
216 __in BOOL fInstall
217 )
218{
219 HRESULT hr = S_OK;
220 DWORD er = ERROR_SUCCESS;
221
222 PMSIHANDLE hView, hRec;
223 LPWSTR pwzId = NULL;
224 LPWSTR pwzComponent = NULL;
225 LPWSTR pwzName = NULL;
226 LPWSTR pwzData = NULL;
227 INSTALLSTATE isInstalled, isAction;
228
229 LPWSTR pwzCustomActionData = NULL;
230
231 // check to see if necessary tables are specified
232 if (S_OK != WcaTableExists(L"Wix4PerformanceCategory"))
233 {
234 ExitFunction1(hr = S_FALSE);
235 }
236
237 hr = WcaOpenExecuteView(vcsPerfCounterDataQuery, &hView);
238 ExitOnFailure(hr, "failed to open view on Wix4PerformanceCategory table");
239 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
240 {
241 hr = WcaGetRecordString(hRec, pcdqId, &pwzId);
242 ExitOnFailure(hr, "Failed to get id for Wix4PerformanceCategory.");
243
244 // Check to see if the Component is being installed or uninstalled
245 // when we are processing the same.
246 hr = WcaGetRecordString(hRec, pcdqComponent, &pwzComponent);
247 ExitOnFailure(hr, "Failed to get Component for Wix4PerformanceCategory: %ls", pwzId);
248
249 er = ::MsiGetComponentStateW(hInstall, pwzComponent, &isInstalled, &isAction);
250 hr = HRESULT_FROM_WIN32(er);
251 ExitOnFailure(hr, "Failed to get Component state for Wix4PerformanceCategory: %ls", pwzId);
252
253 if ((fInstall && !WcaIsInstalling(isInstalled, isAction)) ||
254 (!fInstall && !WcaIsUninstalling(isInstalled, isAction)))
255 {
256 continue;
257 }
258
259 hr = WcaGetRecordString(hRec, pcdqName, &pwzName);
260 ExitOnFailure(hr, "Failed to get Name for Wix4PerformanceCategory: %ls", pwzId);
261 hr = WcaWriteStringToCaData(pwzName, &pwzCustomActionData);
262 ExitOnFailure(hr, "Failed to add Name to CustomActionData for Wix4PerformanceCategory: %ls", pwzId);
263
264 hr = WcaGetRecordString(hRec, pcdqIniData, &pwzData);
265 ExitOnFailure(hr, "Failed to get IniData for Wix4PerformanceCategory: %ls", pwzId);
266 hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
267 ExitOnFailure(hr, "Failed to add IniData to CustomActionData for Wix4PerformanceCategory: %ls", pwzId);
268
269 hr = WcaGetRecordString(hRec, pcdqConstantData, &pwzData);
270 ExitOnFailure(hr, "Failed to get ConstantData for Wix4PerformanceCategory: %ls", pwzId);
271 hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
272 ExitOnFailure(hr, "Failed to add ConstantData to CustomActionData for Wix4PerformanceCategory: %ls", pwzId);
273 }
274
275 if (hr == E_NOMOREITEMS)
276 {
277 hr = S_OK;
278 }
279 ExitOnFailure(hr, "Failure while processing Wix4PerformanceCategory table.");
280
281 // If there was any data built up, schedule it for execution.
282 if (pwzCustomActionData)
283 {
284 if (fInstall)
285 {
286 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackRegisterPerfCounterData"), pwzCustomActionData, COST_PERFMON_UNREGISTER);
287 ExitOnFailure(hr, "Failed to schedule RollbackRegisterPerfCounterData action for Wix4PerformanceCategory: %ls", pwzId);
288
289 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RegisterPerfCounterData"), pwzCustomActionData, COST_PERFMON_REGISTER);
290 ExitOnFailure(hr, "Failed to schedule RegisterPerfCounterData action for Wix4PerformanceCategory: %ls", pwzId);
291 }
292 else
293 {
294 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackUnregisterPerfCounterData"), pwzCustomActionData, COST_PERFMON_REGISTER);
295 ExitOnFailure(hr, "Failed to schedule RollbackUnregisterPerfCounterData action for Wix4PerformanceCategory: %ls", pwzId);
296
297 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"UnregisterPerfCounterData"), pwzCustomActionData, COST_PERFMON_UNREGISTER);
298 ExitOnFailure(hr, "Failed to schedule UnregisterPerfCounterData action for Wix4PerformanceCategory: %ls", pwzId);
299 }
300 }
301
302LExit:
303 ReleaseStr(pwzCustomActionData);
304 ReleaseStr(pwzData);
305 ReleaseStr(pwzName);
306 ReleaseStr(pwzComponent);
307 ReleaseStr(pwzId);
308
309 return hr;
310}
diff --git a/src/ext/Util/ca/scaperfexec.cpp b/src/ext/Util/ca/scaperfexec.cpp
new file mode 100644
index 00000000..c5425754
--- /dev/null
+++ b/src/ext/Util/ca/scaperfexec.cpp
@@ -0,0 +1,423 @@
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
5typedef DWORD (STDAPICALLTYPE *PFNPERFCOUNTERTEXTSTRINGS)(LPWSTR lpCommandLine, BOOL bQuietModeArg);
6
7static HRESULT ExecutePerfCounterData(
8 __in MSIHANDLE hInstall,
9 __in BOOL fInstall
10 );
11static HRESULT CreateDataFile(
12 __in LPCWSTR wzTempFolder,
13 __in LPCWSTR wzData,
14 __in BOOL fIniData,
15 __out HANDLE *phFile,
16 __out_opt LPWSTR *ppwzFile
17 );
18
19
20/********************************************************************
21 RegisterPerfCounterData - CUSTOM ACTION ENTRY POINT for registering
22 performance counters
23
24 Input: deferred CustomActionData: wzName\twzIniData\twzConstantData\twzName\twzIniData\twzConstantData\t...
25*******************************************************************/
26extern "C" UINT __stdcall RegisterPerfCounterData(
27 __in MSIHANDLE hInstall
28 )
29{
30 // AssertSz(FALSE, "debug RegisterPerfCounterData()");
31 HRESULT hr = S_OK;
32 DWORD er = ERROR_SUCCESS;
33
34 hr = WcaInitialize(hInstall, "RegisterPerfCounterData");
35 ExitOnFailure(hr, "Failed to initialize RegisterPerfCounterData.");
36
37 hr = ExecutePerfCounterData(hInstall, TRUE);
38 MessageExitOnFailure(hr, msierrInstallPerfCounterData, "Failed to execute Wix4PerformanceCategory table.");
39
40LExit:
41 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
42 return WcaFinalize(er);
43}
44
45
46/********************************************************************
47 UnregisterPerfCounterData - CUSTOM ACTION ENTRY POINT for registering
48 performance counters
49
50 Input: deferred CustomActionData: wzName\twzIniData\twzConstantData\twzName\twzIniData\twzConstantData\t...
51*******************************************************************/
52extern "C" UINT __stdcall UnregisterPerfCounterData(
53 __in MSIHANDLE hInstall
54 )
55{
56 // AssertSz(FALSE, "debug UnregisterPerfCounterData()");
57 HRESULT hr = S_OK;
58 DWORD er = ERROR_SUCCESS;
59
60 hr = WcaInitialize(hInstall, "UnregisterPerfCounterData");
61 ExitOnFailure(hr, "Failed to initialize UnregisterPerfCounterData.");
62
63 hr = ExecutePerfCounterData(hInstall, FALSE);
64 MessageExitOnFailure(hr, msierrUninstallPerfCounterData, "Failed to execute Wix4PerformanceCategory table.");
65
66LExit:
67 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
68 return WcaFinalize(er);
69}
70
71
72/********************************************************************
73 RegisterPerfmon - CUSTOM ACTION ENTRY POINT for registering
74 counters
75
76 Input: deferred CustomActionData -
77 wzFile or wzName
78*******************************************************************/
79extern "C" UINT __stdcall RegisterPerfmon(
80 __in MSIHANDLE hInstall
81 )
82{
83// Assert(FALSE);
84 UINT er = ERROR_SUCCESS;
85 HRESULT hr = S_OK;
86 LPWSTR pwzData = NULL;
87
88 HMODULE hMod = NULL;
89 PFNPERFCOUNTERTEXTSTRINGS pfnPerfCounterTextString;
90 DWORD dwRet;
91 LPWSTR pwzShortPath = NULL;
92 DWORD cchShortPath = MAX_PATH;
93 DWORD cchShortPathLength = 0;
94
95 LPWSTR pwzCommand = NULL;
96
97 hr = WcaInitialize(hInstall, "RegisterPerfmon");
98 ExitOnFailure(hr, "failed to initialize");
99
100 hr = WcaGetProperty(L"CustomActionData", &pwzData);
101 ExitOnFailure(hr, "failed to get CustomActionData");
102
103 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData);
104
105 // do the perfmon registration
106 if (NULL == hMod)
107 {
108 hr = LoadSystemLibrary(L"loadperf.dll", &hMod);
109 }
110 ExitOnFailure(hr, "failed to load DLL for PerfMon");
111
112 pfnPerfCounterTextString = (PFNPERFCOUNTERTEXTSTRINGS)::GetProcAddress(hMod, "LoadPerfCounterTextStringsW");
113 ExitOnNullWithLastError(pfnPerfCounterTextString, hr, "failed to get DLL function for PerfMon");
114
115 hr = StrAlloc(&pwzShortPath, cchShortPath);
116 ExitOnFailure(hr, "failed to allocate string");
117
118 WcaLog(LOGMSG_VERBOSE, "Converting DLL path to short format: %ls", pwzData);
119 cchShortPathLength = ::GetShortPathNameW(pwzData, pwzShortPath, cchShortPath);
120 if (cchShortPathLength > cchShortPath)
121 {
122 cchShortPath = cchShortPathLength + 1;
123 hr = StrAlloc(&pwzShortPath, cchShortPath);
124 ExitOnFailure(hr, "failed to allocate string");
125
126 cchShortPathLength = ::GetShortPathNameW(pwzData, pwzShortPath, cchShortPath);
127 }
128
129 if (0 == cchShortPathLength)
130 {
131 ExitOnLastError(hr, "failed to get short path format of path: %ls", pwzData);
132 }
133
134 hr = StrAllocFormatted(&pwzCommand, L"lodctr \"%s\"", pwzShortPath);
135 ExitOnFailure(hr, "failed to format lodctr string");
136
137 WcaLog(LOGMSG_VERBOSE, "RegisterPerfmon running command: '%ls'", pwzCommand);
138 dwRet = (*pfnPerfCounterTextString)(pwzCommand, TRUE);
139 if (dwRet != ERROR_SUCCESS && dwRet != ERROR_ALREADY_EXISTS)
140 {
141 hr = HRESULT_FROM_WIN32(dwRet);
142 MessageExitOnFailure(hr, msierrPERFMONFailedRegisterDLL, "failed to register with PerfMon, DLL: %ls", pwzData);
143 }
144
145 hr = S_OK;
146LExit:
147 ReleaseStr(pwzData);
148
149 if (FAILED(hr))
150 er = ERROR_INSTALL_FAILURE;
151 return WcaFinalize(er);
152}
153
154
155extern "C" UINT __stdcall UnregisterPerfmon(
156 __in MSIHANDLE hInstall
157 )
158{
159// Assert(FALSE);
160 UINT er = ERROR_SUCCESS;
161 HRESULT hr = S_OK;
162 LPWSTR pwzData = NULL;
163
164 HMODULE hMod = NULL;
165 PFNPERFCOUNTERTEXTSTRINGS pfnPerfCounterTextString;
166 DWORD dwRet;
167 WCHAR wz[255];
168
169 hr = WcaInitialize(hInstall, "UnregisterPerfmon");
170 ExitOnFailure(hr, "failed to initialize");
171
172 hr = WcaGetProperty(L"CustomActionData", &pwzData);
173 ExitOnFailure(hr, "failed to get CustomActionData");
174
175 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData);
176
177 // do the perfmon unregistration
178 hr = E_FAIL;
179 if (hMod == NULL)
180 {
181 hr = LoadSystemLibrary(L"loadperf.dll", &hMod);
182 }
183 ExitOnFailure(hr, "failed to load DLL for PerfMon");
184
185 pfnPerfCounterTextString = (PFNPERFCOUNTERTEXTSTRINGS)::GetProcAddress(hMod, "UnloadPerfCounterTextStringsW");
186 ExitOnNullWithLastError(pfnPerfCounterTextString, hr, "failed to get DLL function for PerfMon");
187
188 hr = ::StringCchPrintfW(wz, countof(wz), L"unlodctr \"%s\"", pwzData);
189 ExitOnFailure(hr, "Failed to format unlodctr string with: %ls", pwzData);
190 WcaLog(LOGMSG_VERBOSE, "UnregisterPerfmon running command: '%ls'", wz);
191 dwRet = (*pfnPerfCounterTextString)(wz, TRUE);
192 // if the counters aren't registered, then OK to continue
193 if (dwRet != ERROR_SUCCESS && dwRet != ERROR_FILE_NOT_FOUND && dwRet != ERROR_BADKEY)
194 {
195 hr = HRESULT_FROM_WIN32(dwRet);
196 MessageExitOnFailure(hr, msierrPERFMONFailedUnregisterDLL, "failed to unregsister with PerfMon, DLL: %ls", pwzData);
197 }
198
199 hr = S_OK;
200LExit:
201 ReleaseStr(pwzData);
202
203 if (FAILED(hr))
204 er = ERROR_INSTALL_FAILURE;
205 return WcaFinalize(er);
206}
207
208
209static HRESULT ExecutePerfCounterData(
210 __in MSIHANDLE /*hInstall*/,
211 __in BOOL fInstall
212 )
213{
214 HRESULT hr = S_OK;
215 DWORD er = ERROR_SUCCESS;
216
217 HMODULE hModule = NULL;
218 PFNPERFCOUNTERTEXTSTRINGS pfnPerfCounterTextString = NULL;
219 LPCWSTR wzPrefix = NULL;
220
221 LPWSTR pwzCustomActionData = NULL;
222 LPWSTR pwz = NULL;
223
224 LPWSTR pwzName = NULL;
225 LPWSTR pwzIniData = NULL;
226 LPWSTR pwzConstantData = NULL;
227 LPWSTR pwzTempFolder = NULL;
228 LPWSTR pwzIniFile = NULL;
229 LPWSTR pwzExecute = NULL;
230
231 HANDLE hIniData = INVALID_HANDLE_VALUE;
232 HANDLE hConstantData = INVALID_HANDLE_VALUE;
233
234 // Load the system performance counter helper DLL then get the appropriate
235 // entrypoint out of it. Fortunately, they have the same signature so we
236 // can use one function pointer to point to both.
237 hr = LoadSystemLibrary(L"loadperf.dll", &hModule);
238 ExitOnFailure(hr, "failed to load DLL for PerfMon");
239
240 if (fInstall)
241 {
242 wzPrefix = L"lodctr";
243 pfnPerfCounterTextString = (PFNPERFCOUNTERTEXTSTRINGS)::GetProcAddress(hModule, "LoadPerfCounterTextStringsW");
244 }
245 else
246 {
247 wzPrefix = L"unlodctr";
248 pfnPerfCounterTextString = (PFNPERFCOUNTERTEXTSTRINGS)::GetProcAddress(hModule, "UnloadPerfCounterTextStringsW");
249 }
250 ExitOnNullWithLastError(pfnPerfCounterTextString, hr, "Failed to get DLL function for PerfMon");
251
252 // Now get the CustomActionData and execute it.
253 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
254 ExitOnFailure(hr, "Failed to get CustomActionData.");
255
256 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData);
257
258 pwz = pwzCustomActionData;
259
260 while (S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzName)))
261 {
262 hr = WcaReadStringFromCaData(&pwz, &pwzIniData);
263 ExitOnFailure(hr, "Failed to read IniData from custom action data.");
264
265 hr = WcaReadStringFromCaData(&pwz, &pwzConstantData);
266 ExitOnFailure(hr, "Failed to read ConstantData from custom action data.");
267
268 if (fInstall)
269 {
270 hr = PathCreateTempDirectory(NULL, L"WIXPF%03x", 999, &pwzTempFolder);
271 ExitOnFailure(hr, "Failed to create temp directory.");
272
273 hr = CreateDataFile(pwzTempFolder, pwzIniData, TRUE, &hIniData, &pwzIniFile);
274 ExitOnFailure(hr, "Failed to create .ini file for performance counter category: %ls", pwzName);
275
276 hr = CreateDataFile(pwzTempFolder, pwzConstantData, FALSE, &hConstantData, NULL);
277 ExitOnFailure(hr, "Failed to create .h file for performance counter category: %ls", pwzName);
278
279 hr = StrAllocFormatted(&pwzExecute, L"%s \"%s\"", wzPrefix, pwzIniFile);
280 ExitOnFailure(hr, "Failed to allocate string to execute.");
281
282 // Execute the install.
283 er = (*pfnPerfCounterTextString)(pwzExecute, TRUE);
284 hr = HRESULT_FROM_WIN32(er);
285 ExitOnFailure(hr, "Failed to execute install of performance counter category: %ls", pwzName);
286
287 if (INVALID_HANDLE_VALUE != hIniData)
288 {
289 ::CloseHandle(hIniData);
290 hIniData = INVALID_HANDLE_VALUE;
291 }
292
293 if (INVALID_HANDLE_VALUE != hConstantData)
294 {
295 ::CloseHandle(hConstantData);
296 hConstantData = INVALID_HANDLE_VALUE;
297 }
298
299 DirEnsureDelete(pwzTempFolder, TRUE, TRUE);
300 }
301 else
302 {
303 hr = StrAllocFormatted(&pwzExecute, L"%s \"%s\"", wzPrefix, pwzName);
304 ExitOnFailure(hr, "Failed to allocate string to execute.");
305
306 // Execute the uninstall and if the counter isn't registered then ignore
307 // the error since it won't hurt anything.
308 er = (*pfnPerfCounterTextString)(pwzExecute, TRUE);
309 if (ERROR_FILE_NOT_FOUND == er || ERROR_BADKEY == er)
310 {
311 er = ERROR_SUCCESS;
312 }
313 hr = HRESULT_FROM_WIN32(er);
314 ExitOnFailure(hr, "Failed to execute uninstall of performance counter category: %ls", pwzName);
315 }
316 }
317
318 if (E_NOMOREITEMS == hr) // If there are no more items, all is well
319 {
320 hr = S_OK;
321 }
322 ExitOnFailure(hr, "Failed to execute all perf counter data.");
323
324 hr = S_OK;
325
326LExit:
327 if (INVALID_HANDLE_VALUE != hIniData)
328 {
329 ::CloseHandle(hIniData);
330 }
331
332 if (INVALID_HANDLE_VALUE != hConstantData)
333 {
334 ::CloseHandle(hConstantData);
335 }
336
337 ReleaseStr(pwzExecute);
338 ReleaseStr(pwzIniFile);
339 ReleaseStr(pwzTempFolder);
340 ReleaseStr(pwzConstantData);
341 ReleaseStr(pwzIniData);
342 ReleaseStr(pwzName);
343 ReleaseStr(pwzCustomActionData);
344
345 if (hModule)
346 {
347 ::FreeLibrary(hModule);
348 }
349
350 return hr;
351}
352
353
354static HRESULT CreateDataFile(
355 __in LPCWSTR wzTempFolder,
356 __in LPCWSTR wzData,
357 __in BOOL fIniData,
358 __out HANDLE *phFile,
359 __out_opt LPWSTR *ppwzFile
360 )
361{
362 HRESULT hr = S_OK;
363 HANDLE hFile = INVALID_HANDLE_VALUE;
364 LPWSTR pwzFile = NULL;
365 LPSTR pszData = NULL;
366 DWORD cbData = 0;
367 DWORD cbWritten = 0;
368
369 // Convert the data to UTF-8 because lodctr/unloctr
370 // doesn't like unicode.
371 hr = StrAnsiAllocString(&pszData, wzData, 0, CP_UTF8);
372 ExitOnFailure(hr, "Failed to covert data to ANSI.");
373
374 cbData = lstrlenA(pszData);
375
376 // Concatenate the paths together, open the file data file
377 // and dump the data in there.
378 hr = StrAllocString(&pwzFile, wzTempFolder, 0);
379 ExitOnFailure(hr, "Failed to copy temp directory name.");
380
381 hr = StrAllocConcat(&pwzFile, L"wixperf", 0);
382 ExitOnFailure(hr, "Failed to add name of file.");
383
384 hr = StrAllocConcat(&pwzFile, fIniData ? L".ini" : L".h", 0);
385 ExitOnFailure(hr, "Failed to add extension of file.");
386
387 hFile = ::CreateFileW(pwzFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
388 if (INVALID_HANDLE_VALUE == hFile)
389 {
390 ExitWithLastError(hr, "Failed to open new temp file: %ls", pwzFile);
391 }
392
393 if (!::WriteFile(hFile, pszData, cbData, &cbWritten, NULL))
394 {
395 ExitWithLastError(hr, "Failed to write data to new temp file: %ls", pwzFile);
396 }
397
398 if (INVALID_HANDLE_VALUE != hFile)
399 {
400 ::CloseHandle(hFile);
401 hFile = INVALID_HANDLE_VALUE;
402 }
403
404 // Return the requested values.
405 *phFile = hFile;
406 hFile = INVALID_HANDLE_VALUE;
407
408 if (ppwzFile)
409 {
410 *ppwzFile = pwzFile;
411 pwzFile = NULL;
412 }
413
414LExit:
415 if (INVALID_HANDLE_VALUE != hFile)
416 {
417 ::CloseHandle(hFile);
418 }
419 ReleaseStr(pszData);
420 ReleaseStr(pwzFile);
421
422 return hr;
423}
diff --git a/src/ext/Util/ca/scasched.cpp b/src/ext/Util/ca/scasched.cpp
new file mode 100644
index 00000000..d81b1f14
--- /dev/null
+++ b/src/ext/Util/ca/scasched.cpp
@@ -0,0 +1,127 @@
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/********************************************************************
7ConfigureSmb - CUSTOM ACTION ENTRY POINT for installing fileshare settings
8
9********************************************************************/
10extern "C" UINT __stdcall ConfigureSmbInstall(
11 __in MSIHANDLE hInstall
12 )
13{
14 HRESULT hr = S_OK;
15 UINT er = ERROR_SUCCESS;
16
17 SCA_SMB* pssList = NULL;
18
19 // initialize
20 hr = WcaInitialize(hInstall, "ConfigureSmbInstall");
21 ExitOnFailure(hr, "Failed to initialize");
22
23 // check to see if necessary tables are specified
24 if (WcaTableExists(L"Wix4FileShare") != S_OK)
25 {
26 WcaLog(LOGMSG_VERBOSE, "Skipping SMB CustomAction, no Wix4FileShare table");
27 ExitFunction1(hr = S_FALSE);
28 }
29
30 hr = ScaSmbRead(&pssList);
31 ExitOnFailure(hr, "failed to read Wix4FileShare table");
32
33 hr = ScaSmbInstall(pssList);
34 ExitOnFailure(hr, "failed to install FileShares");
35
36LExit:
37 if (pssList)
38 ScaSmbFreeList(pssList);
39
40 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
41 return WcaFinalize(er);
42}
43
44
45/********************************************************************
46ConfigureSmb - CUSTOM ACTION ENTRY POINT for uninstalling fileshare settings
47
48********************************************************************/
49extern "C" UINT __stdcall ConfigureSmbUninstall(
50 __in MSIHANDLE hInstall
51 )
52{
53 HRESULT hr = S_OK;
54 UINT er = ERROR_SUCCESS;
55
56 SCA_SMB* pssList = NULL;
57
58 // initialize
59 hr = WcaInitialize(hInstall, "ConfigureSmbUninstall");
60 ExitOnFailure(hr, "Failed to initialize");
61
62 // check to see if necessary tables are specified
63 if (WcaTableExists(L"Wix4FileShare") != S_OK)
64 {
65 WcaLog(LOGMSG_VERBOSE, "Skipping SMB CustomAction, no Wix4FileShare table");
66 ExitFunction1(hr = S_FALSE);
67 }
68
69 hr = ScaSmbRead(&pssList);
70 ExitOnFailure(hr, "failed to read Wix4FileShare table");
71
72 hr = ScaSmbUninstall(pssList);
73 ExitOnFailure(hr, "failed to uninstall FileShares");
74
75LExit:
76 if (pssList)
77 ScaSmbFreeList(pssList);
78
79 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
80 return WcaFinalize(er);
81}
82
83
84/********************************************************************
85ConfigureUsers - CUSTOM ACTION ENTRY POINT for installing users
86
87********************************************************************/
88extern "C" UINT __stdcall ConfigureUsers(
89 __in MSIHANDLE hInstall
90 )
91{
92 //AssertSz(0, "Debug ConfigureUsers");
93
94 HRESULT hr = S_OK;
95 UINT er = ERROR_SUCCESS;
96
97 BOOL fInitializedCom = FALSE;
98 SCA_USER* psuList = NULL;
99
100 // initialize
101 hr = WcaInitialize(hInstall, "ConfigureUsers");
102 ExitOnFailure(hr, "Failed to initialize");
103
104 hr = ::CoInitialize(NULL);
105 ExitOnFailure(hr, "failed to initialize COM");
106 fInitializedCom = TRUE;
107
108 hr = ScaUserRead(&psuList);
109 ExitOnFailure(hr, "failed to read Wix4User table");
110
111 hr = ScaUserExecute(psuList);
112 ExitOnFailure(hr, "failed to add/remove User actions");
113
114LExit:
115 if (psuList)
116 {
117 ScaUserFreeList(psuList);
118 }
119
120 if (fInitializedCom)
121 {
122 ::CoUninitialize();
123 }
124
125 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
126 return WcaFinalize(er);
127} \ No newline at end of file
diff --git a/src/ext/Util/ca/scasmb.h b/src/ext/Util/ca/scasmb.h
new file mode 100644
index 00000000..f2a4b53c
--- /dev/null
+++ b/src/ext/Util/ca/scasmb.h
@@ -0,0 +1,46 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5#include "scauser.h"
6
7// structs
8// Structure used to hold and extra user/permission pairs from the Wix4FileSharePermissions Table
9struct SCA_SMB_EX_USER_PERMS
10{
11 int nPermissions;
12 ACCESS_MODE accessMode;
13 SCA_USER scau;
14 SCA_SMB_EX_USER_PERMS* pExUserPermsNext;
15};
16
17struct SCA_SMB // hungarian ss
18{
19 WCHAR wzId[MAX_DARWIN_KEY + 1];
20 WCHAR wzShareName[MAX_DARWIN_KEY + 1];
21 WCHAR wzDescription[MAX_DARWIN_COLUMN + 1];
22 WCHAR wzComponent[MAX_DARWIN_KEY + 1];
23 WCHAR wzDirectory[MAX_PATH + 1];
24
25 int nUserPermissionCount;
26 int nPermissions;
27 SCA_SMB_EX_USER_PERMS* pExUserPerms;
28
29 INSTALLSTATE isInstalled, isAction;
30
31 BOOL fUseIntegratedAuth;
32 BOOL fLegacyUserProvided;
33 struct SCA_USER scau;
34
35 struct SCA_SMB* pssNext;
36};
37
38
39#define RESERVED 0
40
41// schedule prototypes
42HRESULT ScaSmbRead(SCA_SMB** ppssList);
43HRESULT ScaSmbExPermsRead(SCA_SMB* pss);
44HRESULT ScaSmbUninstall(SCA_SMB* pssList);
45HRESULT ScaSmbInstall(SCA_SMB* pssList);
46void ScaSmbFreeList(SCA_SMB* pssList);
diff --git a/src/ext/Util/ca/scasmbexec.cpp b/src/ext/Util/ca/scasmbexec.cpp
new file mode 100644
index 00000000..ced3aa78
--- /dev/null
+++ b/src/ext/Util/ca/scasmbexec.cpp
@@ -0,0 +1,316 @@
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/********************************************************************
7 AllocateAcl - allocate an acl and populate it with this user and
8 permission information user could be user or domain\user
9
10********************************************************************/
11HRESULT AllocateAcl(SCA_SMBP* pssp, PACL* ppACL)
12{
13 HRESULT hr = S_OK;
14 EXPLICIT_ACCESSW* pEA = NULL;
15 DWORD cEA = 0;
16 DWORD dwCounter = 0;
17
18 PSID psid = NULL;
19 LPCWSTR wzUser = NULL;
20 DWORD nPermissions = 0;
21 DWORD nErrorReturn = 0;
22 ACCESS_MODE accessMode = NOT_USED_ACCESS;
23
24 cEA = pssp->dwUserPermissionCount + 1;
25 if (cEA >= MAXSIZE_T / sizeof(EXPLICIT_ACCESSW))
26 {
27 ExitOnFailure(hr = E_OUTOFMEMORY, "Too many user permissions to allocate: %u", cEA);
28 }
29
30 pEA = static_cast<EXPLICIT_ACCESSW*>(MemAlloc(cEA * sizeof(EXPLICIT_ACCESSW), TRUE));
31 ExitOnNull(pEA, hr, E_OUTOFMEMORY, "failed to allocate memory for explicit access structure");
32
33 // figure out how big the psid is
34 for (dwCounter = 0; dwCounter < pssp->dwUserPermissionCount; ++dwCounter)
35 {
36 wzUser = pssp->pUserPerms[dwCounter].wzUser;
37 nPermissions = pssp->pUserPerms[dwCounter].nPermissions;
38 accessMode = pssp->pUserPerms[dwCounter].accessMode;
39 //
40 // create the appropriate SID
41 //
42
43 // figure out the right user to put into the access block
44 if (0 == lstrcmpW(wzUser, L"Everyone"))
45 {
46 hr = AclGetWellKnownSid(WinWorldSid, &psid);
47 }
48 else if (0 == lstrcmpW(wzUser, L"Administrators"))
49 {
50 hr = AclGetWellKnownSid(WinBuiltinAdministratorsSid, &psid);
51 }
52 else if (0 == lstrcmpW(wzUser, L"LocalSystem"))
53 {
54 hr = AclGetWellKnownSid(WinLocalSystemSid, &psid);
55 }
56 else if (0 == lstrcmpW(wzUser, L"LocalService"))
57 {
58 hr = AclGetWellKnownSid(WinLocalServiceSid, &psid);
59 }
60 else if (0 == lstrcmpW(wzUser, L"NetworkService"))
61 {
62 hr = AclGetWellKnownSid(WinNetworkServiceSid, &psid);
63 }
64 else if (0 == lstrcmpW(wzUser, L"AuthenticatedUser"))
65 {
66 hr = AclGetWellKnownSid(WinAuthenticatedUserSid, &psid);
67 }
68 else if (0 == lstrcmpW(wzUser, L"Guests"))
69 {
70 hr = AclGetWellKnownSid(WinBuiltinGuestsSid, &psid);
71 }
72 else if(0 == lstrcmpW(wzUser, L"CREATOR OWNER"))
73 {
74 hr = AclGetWellKnownSid(WinCreatorOwnerSid, &psid);
75 }
76 else
77 {
78 hr = AclGetAccountSid(NULL, wzUser, &psid);
79 }
80 ExitOnFailure(hr, "failed to get sid for account: %ls", wzUser);
81
82 // we now have a valid pSid, fill in the EXPLICIT_ACCESS
83
84 /* Permissions options: (see sca.sdh for defined sdl options)
85 #define GENERIC_READ (0x80000000L) 2147483648
86 #define GENERIC_WRITE (0x40000000L) 1073741824
87 #define GENERIC_EXECUTE (0x20000000L) 536870912
88 #define GENERIC_ALL (0x10000000L) 268435456
89 */
90 pEA[dwCounter].grfAccessPermissions = nPermissions;
91 pEA[dwCounter].grfAccessMode = accessMode;
92 pEA[dwCounter].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
93#pragma prefast(push)
94#pragma prefast(disable:25029)
95 ::BuildTrusteeWithSidW(&(pEA[dwCounter].Trustee), psid);
96#pragma prefast(pop)
97 }
98
99 // create a new ACL that contains the ACE
100 *ppACL = NULL;
101#pragma prefast(push)
102#pragma prefast(disable:25029)
103 nErrorReturn = ::SetEntriesInAclW(dwCounter, pEA, NULL, ppACL);
104#pragma prefast(pop)
105 ExitOnFailure(hr = HRESULT_FROM_WIN32(nErrorReturn), "failed to allocate ACL");
106
107LExit:
108 if (psid)
109 {
110 AclFreeSid(psid);
111 }
112
113 ReleaseMem(pEA);
114
115 return hr;
116}
117
118
119
120/********************************************************************
121 FillShareInfo - fill the NetShareAdd data structure
122
123********************************************************************/
124void FillShareInfo(SHARE_INFO_502* psi, SCA_SMBP* pssp, PSECURITY_DESCRIPTOR pSD)
125{
126 psi->shi502_netname = pssp->wzKey;
127 psi->shi502_type = STYPE_DISKTREE;
128 psi->shi502_remark = pssp->wzDescription;
129 psi->shi502_permissions = 0; // not used
130 psi->shi502_max_uses = 0xFFFFFFFF;
131 psi->shi502_current_uses = 0;
132 psi->shi502_path = pssp->wzDirectory;
133 psi->shi502_passwd = NULL; // not file share perms
134 psi->shi502_reserved = 0;
135 psi->shi502_security_descriptor = pSD;
136}
137
138
139
140/* NET_API_STATUS return codes
141NERR_Success = 0
142NERR_DuplicateShare = 2118
143NERR_BufTooSmall = 2123
144NERR_NetNameNotFound = 2310
145NERR_RedirectedPath = 2117
146NERR_UnknownDevDir = 2116
147*/
148
149/********************************************************************
150 DoesShareExists - Does a share of this name exist on this computer?
151
152********************************************************************/
153HRESULT DoesShareExist(__in LPWSTR wzShareName)
154{
155 HRESULT hr = S_OK;
156 NET_API_STATUS s;
157 SHARE_INFO_502* psi = NULL;
158 s = ::NetShareGetInfo(NULL, wzShareName, 502, (BYTE**) &psi);
159
160 switch (s)
161 {
162 case NERR_Success:
163 hr = S_OK;
164 break;
165 case NERR_NetNameNotFound:
166 hr = E_FILENOTFOUND;
167 break;
168 default:
169 WcaLogError(s, "NetShareGetInfo returned an unexpected value.", NULL);
170 hr = HRESULT_FROM_WIN32(s);
171 break;
172 }
173
174 ::NetApiBufferFree(psi);
175
176 return hr;
177}
178
179
180
181/********************************************************************
182 CreateShare - create the file share on this computer
183
184********************************************************************/
185HRESULT CreateShare(SCA_SMBP* pssp)
186{
187 if (!pssp || !(pssp->wzKey))
188 return E_INVALIDARG;
189
190 HRESULT hr = S_OK;
191 PACL pACL = NULL;
192 SHARE_INFO_502 si;
193 NET_API_STATUS s;
194 DWORD dwParamErr = 0;
195
196 BOOL fShareExists = SUCCEEDED(DoesShareExist(pssp->wzKey));
197
198 PSECURITY_DESCRIPTOR pSD = static_cast<PSECURITY_DESCRIPTOR>(MemAlloc(SECURITY_DESCRIPTOR_MIN_LENGTH, TRUE));
199 ExitOnNull(pSD, hr, E_OUTOFMEMORY, "Failed to allocate memory for security descriptor");
200
201#pragma prefast(push)
202#pragma prefast(disable:25029)
203 if (!::InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
204#pragma prefast(pop)
205 {
206 ExitOnLastError(hr, "failed to initialize security descriptor");
207 }
208
209 hr = AllocateAcl(pssp, &pACL);
210 ExitOnFailure(hr, "Failed to allocate ACL for fileshare");
211
212 if (NULL == pACL)
213 {
214 WcaLog(LOGMSG_VERBOSE, "Ignoring NULL DACL.");
215 }
216#pragma prefast(push)
217#pragma prefast(disable:25028) // We only call this when pACL isn't NULL, so this call is safe according to the docs
218 // add the ACL to the security descriptor.
219 else if (!::SetSecurityDescriptorDacl(pSD, TRUE, pACL, FALSE))
220 {
221 ExitOnLastError(hr, "Failed to set security descriptor");
222 }
223#pragma prefast(pop)
224
225 // all that is left is to create the share
226 FillShareInfo(&si, pssp, pSD);
227
228 // Fail if the directory doesn't exist
229 if (!DirExists(pssp->wzDirectory, NULL))
230 ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_OBJECT_NOT_FOUND), "Can't create a file share on directory that doesn't exist: %ls.", pssp->wzDirectory);
231
232 WcaLog(LOGMSG_VERBOSE, "Creating file share on directory \'%ls\' named \'%ls\'.", pssp->wzDirectory, pssp->wzKey);
233
234 if (!fShareExists)
235 {
236 s = ::NetShareAdd(NULL, 502, (BYTE*) &si, &dwParamErr);
237 WcaLog(LOGMSG_VERBOSE, "Adding a new file share.");
238 }
239 else
240 {
241 // The share exists. Write our new permissions over the top.
242 s = ::NetShareSetInfo(NULL, pssp->wzKey, 502, (BYTE*) &si, &dwParamErr);
243 WcaLog(LOGMSG_VERBOSE, "Setting permissions on existing share.");
244 }
245
246 if (NERR_Success != s)
247 {
248 hr = E_FAIL;
249 if (!fShareExists && NERR_DuplicateShare == s)
250 WcaLog(LOGMSG_VERBOSE, "Duplicate error when existence check failed.");
251
252 // error codes listed above.
253 ExitOnFailure(hr, "Failed to create/modify file share: Err: %d", s);
254 }
255
256LExit:
257 if (pACL)
258 {
259 ::LocalFree(pACL);
260 }
261
262 ReleaseMem(pSD);
263
264 return hr;
265}
266
267
268/********************************************************************
269 ScaEnsureSmbExists
270
271********************************************************************/
272HRESULT ScaEnsureSmbExists(SCA_SMBP* pssp)
273{
274 HRESULT hr = S_OK;
275
276 // create the share
277 hr = CreateShare(pssp);
278
279 return hr;
280}
281
282
283//
284// Delete File Shares - real work
285//
286
287/********************************************************************
288 ScaDropSmb - delete this file share from this computer
289
290********************************************************************/
291HRESULT ScaDropSmb(SCA_SMBP* pssp)
292{
293 HRESULT hr = S_OK;
294 NET_API_STATUS s;
295
296 hr = DoesShareExist(pssp->wzKey);
297
298 if (E_FILENOTFOUND == hr)
299 {
300 WcaLog(LOGMSG_VERBOSE, "Share doesn't exist, share removal skipped. (%ls)", pssp->wzKey);
301 ExitFunction1(hr = S_OK);
302
303 }
304
305 ExitOnFailure(hr, "Unable to detect share. (%ls)", pssp->wzKey);
306
307 s = ::NetShareDel(NULL, pssp->wzKey, 0);
308 if (NERR_Success != s)
309 {
310 hr = E_FAIL;
311 ExitOnFailure(hr, "Failed to remove file share: Err: %d", s);
312 }
313
314LExit:
315 return hr;
316}
diff --git a/src/ext/Util/ca/scasmbexec.h b/src/ext/Util/ca/scasmbexec.h
new file mode 100644
index 00000000..e3c8f8bb
--- /dev/null
+++ b/src/ext/Util/ca/scasmbexec.h
@@ -0,0 +1,27 @@
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
5struct SCA_SMBP_USER_PERMS
6{
7 DWORD nPermissions;
8 ACCESS_MODE accessMode;
9 WCHAR* wzUser;
10 //Not adding Password because I can't find anywhere that it is used
11};
12
13struct SCA_SMBP // hungarian ssp
14{
15 WCHAR* wzKey;
16 WCHAR* wzDescription;
17 WCHAR* wzComponent;
18 WCHAR* wzDirectory; // full path of the dir to share to
19
20 DWORD dwUserPermissionCount; //Count of SCA_SMBP_EX_USER_PERMS structures
21 SCA_SMBP_USER_PERMS* pUserPerms;
22 BOOL fUseIntegratedAuth;
23};
24
25
26HRESULT ScaEnsureSmbExists(SCA_SMBP* pssp);
27HRESULT ScaDropSmb(SCA_SMBP* pssp);
diff --git a/src/ext/Util/ca/scasmbsched.cpp b/src/ext/Util/ca/scasmbsched.cpp
new file mode 100644
index 00000000..e29f7f51
--- /dev/null
+++ b/src/ext/Util/ca/scasmbsched.cpp
@@ -0,0 +1,639 @@
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/********************************************************************
7 Helper functions to maintain a list of file shares to create / remove
8
9********************************************************************/
10SCA_SMB* NewSmb()
11{
12 SCA_SMB* pss = (SCA_SMB*)MemAlloc(sizeof(SCA_SMB), TRUE);
13 Assert(pss);
14 return pss;
15}
16
17
18SCA_SMB_EX_USER_PERMS* NewExUserPermsSmb()
19{
20 SCA_SMB_EX_USER_PERMS* pExUserPerms = (SCA_SMB_EX_USER_PERMS*)MemAlloc(sizeof(SCA_SMB_EX_USER_PERMS), TRUE);
21 Assert(pExUserPerms);
22 return pExUserPerms;
23}
24
25
26SCA_SMB* AddSmbToList(SCA_SMB* pssList, SCA_SMB* pss)
27{
28 if (pssList)
29 {
30 SCA_SMB* pssT = pssList;
31 while (pssT->pssNext)
32 {
33 pssT = pssT->pssNext;
34 }
35
36 pssT->pssNext = pss;
37 }
38 else
39 {
40 pssList = pss;
41 }
42
43 return pssList;
44}
45
46
47SCA_SMB_EX_USER_PERMS* AddExUserPermsSmbToList(
48 SCA_SMB_EX_USER_PERMS* pExUserPermsList,
49 SCA_SMB_EX_USER_PERMS* pExUserPerms
50 )
51{
52 SCA_SMB_EX_USER_PERMS* pExUserPermsTemp = pExUserPermsList;
53 if (pExUserPermsList)
54 {
55 while (pExUserPermsTemp->pExUserPermsNext)
56 {
57 pExUserPermsTemp = pExUserPermsTemp->pExUserPermsNext;
58 }
59
60 pExUserPermsTemp->pExUserPermsNext = pExUserPerms;
61 }
62 else
63 {
64 pExUserPermsList = pExUserPerms;
65 }
66
67 return pExUserPermsList;
68}
69
70void ScaSmbFreeList(SCA_SMB* pssList)
71{
72 SCA_SMB* pssDelete = pssList;
73 while (pssList)
74 {
75 pssDelete = pssList;
76 pssList = pssList->pssNext;
77
78 MemFree(pssDelete);
79 }
80}
81
82void ScaExUserPermsSmbFreeList(SCA_SMB_EX_USER_PERMS* pExUserPermsList)
83{
84 SCA_SMB_EX_USER_PERMS* pExUserPermsDelete = pExUserPermsList;
85 while (pExUserPermsList)
86 {
87 pExUserPermsDelete = pExUserPermsList;
88 pExUserPermsList = pExUserPermsList->pExUserPermsNext;
89
90 MemFree(pExUserPermsDelete);
91 }
92}
93
94// sql query constants
95LPCWSTR vcsSmbQuery = L"SELECT `Wix4FileShare`, `ShareName`, `Description`, `Directory_`, "
96 L"`Component_`, `User_`, `Permissions` FROM `Wix4FileShare`";
97
98enum eSmbQuery {
99 ssqFileShare = 1,
100 ssqShareName,
101 ssqDescription,
102 ssqDirectory,
103 ssqComponent,
104 ssqUser,
105 ssqPermissions
106 };
107
108
109/********************************************************************
110 ScaSmbRead - read all of the information from the msi tables and
111 return a list of file share jobs to be done.
112
113********************************************************************/
114HRESULT ScaSmbRead(SCA_SMB** ppssList)
115{
116 HRESULT hr = S_OK;
117 UINT er = ERROR_SUCCESS;
118 PMSIHANDLE hView, hRec;
119
120 LPWSTR pwzData = NULL;
121
122 SCA_SMB* pss = NULL;
123 BOOL bUserPermissionsTableExists = FALSE;
124
125 if (S_OK != WcaTableExists(L"Wix4FileShare"))
126 {
127 WcaLog(LOGMSG_VERBOSE, "Skipping ScaSmbCreateShare() - Wix4FileShare table not present");
128 ExitFunction1(hr = S_FALSE);
129 }
130
131 if (S_OK == WcaTableExists(L"Wix4FileSharePermissions"))
132 {
133 bUserPermissionsTableExists = TRUE;
134 }
135 else
136 {
137 WcaLog(LOGMSG_VERBOSE, "No Additional Permissions - Wix4FileSharePermissions table not present");
138 }
139
140 WcaLog(LOGMSG_VERBOSE, "Reading File Share Tables");
141
142 // loop through all the fileshares
143 hr = WcaOpenExecuteView(vcsSmbQuery, &hView);
144 ExitOnFailure(hr, "Failed to open view on Wix4FileShare table");
145 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
146 {
147 pss = NewSmb();
148 if (!pss)
149 {
150 hr = E_OUTOFMEMORY;
151 break;
152 }
153 Assert(pss);
154 ::ZeroMemory(pss, sizeof(*pss));
155
156 hr = WcaGetRecordString(hRec, ssqFileShare, &pwzData);
157 ExitOnFailure(hr, "Failed to get Wix4FileShare.Wix4FileShare");
158 hr = ::StringCchCopyW(pss->wzId, countof(pss->wzId), pwzData);
159 ExitOnFailure(hr, "Failed to copy ID string to smb object");
160
161 hr = WcaGetRecordFormattedString(hRec, ssqShareName, &pwzData);
162 ExitOnFailure(hr, "Failed to get Wix4FileShare.ShareName");
163 hr = ::StringCchCopyW(pss->wzShareName, countof(pss->wzShareName), pwzData);
164 ExitOnFailure(hr, "Failed to copy share name string to smb object");
165
166 hr = WcaGetRecordString(hRec, ssqComponent, &pwzData);
167 ExitOnFailure(hr, "Failed to get Component for Wix4FileShare: '%ls'", pss->wzShareName);
168 hr = ::StringCchCopyW(pss->wzComponent, countof(pss->wzComponent), pwzData);
169 ExitOnFailure(hr, "Failed to copy component string to smb object");
170
171 hr = WcaGetRecordFormattedString(hRec, ssqDescription, &pwzData);
172 ExitOnFailure(hr, "Failed to get Share Description for Wix4FileShare: '%ls'", pss->wzShareName);
173 hr = ::StringCchCopyW(pss->wzDescription, countof(pss->wzDescription), pwzData);
174 ExitOnFailure(hr, "Failed to copy description string to smb object");
175
176 // get user info from the user table
177 hr = WcaGetRecordFormattedString(hRec, ssqUser, &pwzData);
178 ExitOnFailure(hr, "Failed to get Wix4User record for Wix4FileShare: '%ls'", pss->wzShareName);
179
180 // get component install state
181 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pss->wzComponent, &pss->isInstalled, &pss->isAction);
182 hr = HRESULT_FROM_WIN32(er);
183 ExitOnFailure(hr, "Failed to get Component state for Wix4FileShare");
184
185 // if a user was specified
186 if (*pwzData)
187 {
188 pss->fUseIntegratedAuth = FALSE;
189 pss->fLegacyUserProvided = TRUE;
190 hr = ScaGetUser(pwzData, &pss->scau);
191 ExitOnFailure(hr, "Failed to get user information for fileshare: '%ls'", pss->wzShareName);
192 }
193 else
194 {
195 pss->fLegacyUserProvided = FALSE;
196 // TODO: figure out whether this is useful still
197 //pss->fUseIntegratedAuth = TRUE;
198 // integrated authorization doesn't have a User record
199 }
200
201 // get the share's directory
202 hr = WcaGetRecordString(hRec, ssqDirectory, &pwzData);
203 ExitOnFailure(hr, "Failed to get directory for Wix4FileShare: '%ls'", pss->wzShareName);
204
205 WCHAR wzPath[MAX_PATH];
206 DWORD dwLen;
207 dwLen = countof(wzPath);
208 // review: relevant for file shares?
209 if (INSTALLSTATE_SOURCE == pss->isAction)
210 {
211 er = ::MsiGetSourcePathW(WcaGetInstallHandle(), pwzData, wzPath, &dwLen);
212 }
213 else
214 {
215 er = ::MsiGetTargetPathW(WcaGetInstallHandle(), pwzData, wzPath, &dwLen);
216 }
217 hr = HRESULT_FROM_WIN32(er);
218 ExitOnFailure(hr, "Failed to get Source/TargetPath for Directory");
219
220 // If the path is to the root of a drive, then it needs a trailing backslash.
221 // Otherwise, it can't have a trailing backslash.
222 if (3 < dwLen)
223 {
224 if (wzPath[dwLen - 1] == L'\\')
225 {
226 wzPath[dwLen - 1] = 0;
227 }
228 }
229 else if (2 == dwLen && wzPath[1] == L':')
230 {
231 wzPath[2] = L'\\';
232 wzPath[3] = 0;
233 }
234
235 hr = ::StringCchCopyW(pss->wzDirectory, countof(pss->wzDirectory), wzPath);
236 ExitOnFailure(hr, "Failed to copy directory string to smb object");
237
238 hr = WcaGetRecordInteger(hRec, ssqPermissions, &pss->nPermissions);
239 ExitOnFailure(hr, "Failed to get Wix4FileShare.Permissions");
240
241 // Check to see if additional user & permissions are specified for this share
242 if (bUserPermissionsTableExists)
243 {
244 hr = ScaSmbExPermsRead(pss);
245 ExitOnFailure(hr, "Failed to get Additional File Share Permissions");
246 }
247
248 *ppssList = AddSmbToList(*ppssList, pss);
249 pss = NULL; // set the smb NULL so it doesn't accidentally get freed below
250 }
251
252 if (E_NOMOREITEMS == hr)
253 {
254 hr = S_OK;
255 }
256 ExitOnFailure(hr, "Failure occured while processing Wix4FileShare table");
257
258LExit:
259 // if anything was left over after an error clean it all up
260 if (pss)
261 {
262 ScaSmbFreeList(pss);
263 }
264
265 ReleaseStr(pwzData);
266
267 return hr;
268}
269
270
271/********************************************************************
272 RetrieveSMBShareUserPermList - retrieve SMB Share's user permission list
273
274********************************************************************/
275HRESULT RetrieveFileShareUserPerm(SCA_SMB* pss, SCA_SMB_EX_USER_PERMS** ppExUserPermsList, DWORD *pUserPermsCount)
276{
277 HRESULT hr = S_OK;
278 SHARE_INFO_502* psi = NULL;
279 NET_API_STATUS s;
280 BOOL bValid, bDaclDefaulted;
281 PACL acl = NULL;
282 PEXPLICIT_ACCESSW pEA = NULL;
283 ULONG nCount = 0;
284 DWORD er = ERROR_SUCCESS;
285 PSID pSID = NULL;
286 DWORD nUserNameSize = MAX_DARWIN_COLUMN;
287 DWORD nDomainNameSize = MAX_DARWIN_COLUMN;
288 SID_NAME_USE peUse;
289 DWORD dwCounter = 0;
290 SCA_SMB_EX_USER_PERMS* pExUserPermsList = NULL;
291 DWORD dwUserPermsCount = 0;
292
293 *pUserPermsCount = 0;
294 s = ::NetShareGetInfo(NULL, pss->wzShareName, 502, (LPBYTE*)&psi);
295 WcaLog(LOGMSG_VERBOSE, "retrieving permissions on existing file share.");
296 if (NERR_NetNameNotFound == s)
297 {
298 WcaLog(LOGMSG_VERBOSE, "File share has already been removed.");
299 ExitFunction1(hr = S_OK);
300 }
301 else if (NERR_Success != s || psi == NULL)
302 {
303 hr = E_FAIL;
304 ExitOnFailure(hr, "Failed to get share information with return code: %d", s);
305 }
306 if (!::GetSecurityDescriptorDacl(psi->shi502_security_descriptor, &bValid, &acl, &bDaclDefaulted) || !bValid)
307 {
308 ExitOnLastError(hr, "Failed to get acl from security descriptor");
309 }
310
311 er = ::GetExplicitEntriesFromAclW(acl, &nCount, &pEA);
312 hr = HRESULT_FROM_WIN32(er);
313 ExitOnFailure(hr, "Failed to get access entries from acl for file share %ls", pss->wzShareName);
314 for (dwCounter = 0; dwCounter < nCount; ++dwCounter)
315 {
316 if (TRUSTEE_IS_SID == pEA[dwCounter].Trustee.TrusteeForm)
317 {
318 SCA_SMB_EX_USER_PERMS* pExUserPerms = NewExUserPermsSmb();
319 ::ZeroMemory(pExUserPerms, sizeof(*pExUserPerms));
320 pExUserPermsList = AddExUserPermsSmbToList(pExUserPermsList, pExUserPerms);
321 pSID = (PSID)(pEA[dwCounter].Trustee.ptstrName);
322 if (!::LookupAccountSidW(NULL, pSID, pExUserPerms->scau.wzName, &nUserNameSize, pExUserPerms->scau.wzDomain, &nDomainNameSize, &peUse))
323 {
324 hr = E_FAIL;
325 ExitOnFailure(hr, "Failed to get account name from SID");
326 }
327 pExUserPerms->nPermissions = pEA[dwCounter].grfAccessPermissions;
328 pExUserPerms->accessMode = pEA[dwCounter].grfAccessMode;
329 ++dwUserPermsCount;
330 nUserNameSize = MAX_DARWIN_COLUMN;
331 nDomainNameSize = MAX_DARWIN_COLUMN;
332 }
333 }
334 *ppExUserPermsList = pExUserPermsList;
335 *pUserPermsCount = dwUserPermsCount;
336
337LExit:
338 if (psi)
339 {
340 ::NetApiBufferFree(psi);
341 }
342
343 if (pEA)
344 {
345 ::LocalFree(pEA);
346 }
347
348 return hr;
349}
350
351
352/********************************************************************
353 SchedCreateSmb - schedule one instance of a file share creation
354
355********************************************************************/
356HRESULT SchedCreateSmb(SCA_SMB* pss)
357{
358 HRESULT hr = S_OK;
359
360 WCHAR wzDomainUser[255]; // "domain\user"
361 SCA_SMB_EX_USER_PERMS* pExUserPermsList = NULL;
362 int nCounter = 0;
363 WCHAR* pwzRollbackCustomActionData = NULL;
364 WCHAR* pwzCustomActionData = NULL;
365
366 hr = WcaWriteStringToCaData(pss->wzShareName, &pwzRollbackCustomActionData);
367 ExitOnFailure(hr, "failed to add ShareName to CustomActionData");
368
369 hr = WcaWriteStringToCaData(pss->wzShareName, &pwzCustomActionData);
370 ExitOnFailure(hr, "failed to add ShareName to CustomActionData");
371
372 hr = WcaWriteStringToCaData(pss->wzDescription, &pwzCustomActionData);
373 ExitOnFailure(hr, "Failed to add server name to CustomActionData");
374
375 hr = WcaWriteStringToCaData(pss->wzDirectory, &pwzCustomActionData);
376 ExitOnFailure(hr, "Failed to add full path instance to CustomActionData");
377
378 hr = WcaWriteStringToCaData(pss->fUseIntegratedAuth ? L"1" : L"0", &pwzCustomActionData);
379 ExitOnFailure(hr, "Failed to add server name to CustomActionData");
380
381 if (pss->fLegacyUserProvided)
382 {
383 hr = WcaWriteIntegerToCaData(pss->nUserPermissionCount + 1, &pwzCustomActionData);
384 ExitOnFailure(hr, "Failed to add additional user permission count to CustomActionData");
385
386 hr = UserBuildDomainUserName(wzDomainUser, countof(wzDomainUser), pss->scau.wzName, pss->scau.wzDomain);
387 ExitOnFailure(hr, "Failed to build user and domain name for CustomActionData");
388 hr = WcaWriteStringToCaData(wzDomainUser, &pwzCustomActionData);
389 ExitOnFailure(hr, "Failed to add server Domain\\UserName to CustomActionData");
390
391 hr = WcaWriteIntegerToCaData(pss->nPermissions, &pwzCustomActionData);
392 ExitOnFailure(hr, "Failed to add permissions to CustomActionData");
393 }
394 else
395 {
396 hr = WcaWriteIntegerToCaData(pss->nUserPermissionCount, &pwzCustomActionData);
397 ExitOnFailure(hr, "Failed to add additional user permission count to CustomActionData");
398 }
399
400 if (pss->nUserPermissionCount > 0)
401 {
402 nCounter = 0;
403 for (pExUserPermsList = pss->pExUserPerms; pExUserPermsList; pExUserPermsList = pExUserPermsList->pExUserPermsNext)
404 {
405 Assert(nCounter < pss->nUserPermissionCount);
406
407 hr = UserBuildDomainUserName(wzDomainUser, countof(wzDomainUser), pExUserPermsList->scau.wzName, pExUserPermsList->scau.wzDomain);
408 ExitOnFailure(hr, "Failed to build user and domain name for CustomActionData");
409 hr = WcaWriteStringToCaData(wzDomainUser, &pwzCustomActionData);
410 ExitOnFailure(hr, "Failed to add server Domain\\UserName to CustomActionData");
411
412 hr = WcaWriteIntegerToCaData((int)pExUserPermsList->accessMode, &pwzCustomActionData);
413 ExitOnFailure(hr, "Failed to add access mode to CustomActionData");
414
415 hr = WcaWriteIntegerToCaData(pExUserPermsList->nPermissions, &pwzCustomActionData);
416 ExitOnFailure(hr, "Failed to add permissions to CustomActionData");
417 ++nCounter;
418 }
419 Assert(nCounter == pss->nUserPermissionCount);
420 }
421
422 // Schedule the rollback first
423 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"CreateSmbRollback"), pwzRollbackCustomActionData, COST_SMB_DROPSMB);
424 ExitOnFailure(hr, "Failed to schedule DropSmb action");
425
426 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"CreateSmb"), pwzCustomActionData, COST_SMB_CREATESMB);
427 ExitOnFailure(hr, "Failed to schedule CreateSmb action");
428
429LExit:
430 ReleaseStr(pwzRollbackCustomActionData);
431 ReleaseStr(pwzCustomActionData);
432
433 if (pExUserPermsList)
434 {
435 ScaExUserPermsSmbFreeList(pExUserPermsList);
436 }
437
438 return hr;
439}
440
441
442/********************************************************************
443 ScaSmbInstall - for every file share, schedule the create custom action
444
445********************************************************************/
446HRESULT ScaSmbInstall(SCA_SMB* pssList)
447{
448 HRESULT hr = S_FALSE; // assume nothing will be done
449 SCA_SMB* pss = NULL;
450
451 for (pss = pssList; pss; pss = pss->pssNext)
452 {
453 // if installing this component
454 if (WcaIsInstalling(pss->isInstalled, pss->isAction) )
455 {
456 hr = SchedCreateSmb(pss);
457 ExitOnFailure(hr, "Failed to schedule the creation of the fileshare: %ls", pss->wzShareName);
458 }
459 }
460
461LExit:
462 return hr;
463}
464
465
466/********************************************************************
467 SchedDropSmb - schedule one instance of a file share removal
468
469********************************************************************/
470HRESULT SchedDropSmb(SCA_SMB* pss)
471{
472 HRESULT hr = S_OK;
473
474 WCHAR* pwzCustomActionData = NULL;
475 WCHAR* pwzRollbackCustomActionData = NULL;
476 SCA_SMB_EX_USER_PERMS *pExUserPermsList = NULL;
477 SCA_SMB_EX_USER_PERMS *pExUserPerm = NULL;
478 WCHAR wzDomainUser[255]; // "domain\user"
479 DWORD dwUserPermsCount = 0;
480
481 // roll back DropSmb
482 hr = WcaWriteStringToCaData(pss->wzShareName, &pwzRollbackCustomActionData);
483 ExitOnFailure(hr, "failed to add ShareName to CustomActionData");
484
485 hr = WcaWriteStringToCaData(pss->wzDescription, &pwzRollbackCustomActionData);
486 ExitOnFailure(hr, "Failed to add server name to CustomActionData");
487
488 hr = WcaWriteStringToCaData(pss->wzDirectory, &pwzRollbackCustomActionData);
489 ExitOnFailure(hr, "Failed to add full path instance to CustomActionData");
490
491 hr = WcaWriteStringToCaData(L"1", &pwzRollbackCustomActionData);
492 ExitOnFailure(hr, "Failed to add useintegrated flag to CustomActionData");
493
494 hr = RetrieveFileShareUserPerm(pss, &pExUserPermsList, &dwUserPermsCount);
495 ExitOnFailure(hr, "Failed to retrieve SMBShare's user permissions");
496
497 hr = WcaWriteIntegerToCaData((int)dwUserPermsCount, &pwzRollbackCustomActionData);
498 ExitOnFailure(hr, "Failed to add additional user permission count to CustomActionData");
499
500 for (pExUserPerm = pExUserPermsList; pExUserPerm; pExUserPerm = pExUserPerm->pExUserPermsNext)
501 {
502 hr = UserBuildDomainUserName(wzDomainUser, countof(wzDomainUser), pExUserPerm->scau.wzName, pExUserPerm->scau.wzDomain);
503 ExitOnFailure(hr, "Failed to build user and domain name for CustomActionData");
504 hr = WcaWriteStringToCaData(wzDomainUser, &pwzRollbackCustomActionData);
505 ExitOnFailure(hr, "Failed to add server Domain\\UserName to CustomActionData");
506
507 hr = WcaWriteIntegerToCaData((int)pExUserPerm->accessMode, &pwzRollbackCustomActionData);
508 ExitOnFailure(hr, "Failed to add access mode to CustomActionData");
509
510 hr = WcaWriteIntegerToCaData(pExUserPerm->nPermissions, &pwzRollbackCustomActionData);
511 ExitOnFailure(hr, "Failed to add permissions to CustomActionData");
512 }
513
514 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"DropSmbRollback"), pwzRollbackCustomActionData, COST_SMB_CREATESMB);
515 ExitOnFailure(hr, "Failed to schedule DropSmbRollback action");
516
517 // DropSMB
518 hr = WcaWriteStringToCaData(pss->wzShareName, &pwzCustomActionData);
519 ExitOnFailure(hr, "failed to add ShareName to CustomActionData");
520
521 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"DropSmb"), pwzCustomActionData, COST_SMB_DROPSMB);
522 ExitOnFailure(hr, "Failed to schedule DropSmb action");
523
524LExit:
525 ReleaseStr(pwzCustomActionData);
526
527 if (pExUserPermsList)
528 {
529 ScaExUserPermsSmbFreeList(pExUserPermsList);
530 }
531
532 return hr;
533
534}
535
536
537/********************************************************************
538 ScaSmbUninstall - for every file share, schedule the drop custom action
539
540********************************************************************/
541HRESULT ScaSmbUninstall(SCA_SMB* pssList)
542{
543 HRESULT hr = S_FALSE; // assume nothing will be done
544 SCA_SMB* pss = NULL;
545
546 for (pss = pssList; pss; pss = pss->pssNext)
547 {
548 // if uninstalling this component
549 if (WcaIsUninstalling(pss->isInstalled, pss->isAction) )
550 {
551 hr = SchedDropSmb(pss);
552 ExitOnFailure(hr, "Failed to remove file share %ls", pss->wzShareName);
553 }
554 }
555
556LExit:
557 return hr;
558}
559
560LPCWSTR vcsSmbExUserPermsQuery = L"SELECT `FileShare_`,`User_`,`Permissions` "
561 L"FROM `Wix4FileSharePermissions` WHERE `FileShare_`=?";
562
563enum eSmbUserPermsQuery {
564 ssupqFileShare = 1,
565 ssupqUser,
566 ssupqPermissions
567
568};
569
570
571/********************************************************************
572 ScaSmbExPermsRead - for Every entry in File Permissions table add a
573 User Name & Permissions structure to the List
574
575********************************************************************/
576HRESULT ScaSmbExPermsRead(SCA_SMB* pss)
577{
578 HRESULT hr = S_OK;
579 PMSIHANDLE hView, hRec;
580
581 LPWSTR pwzData = NULL;
582 SCA_SMB_EX_USER_PERMS* pExUserPermsList = pss->pExUserPerms;
583 SCA_SMB_EX_USER_PERMS* pExUserPerms = NULL;
584 int nCounter = 0;
585
586 hRec = ::MsiCreateRecord(1);
587 hr = WcaSetRecordString(hRec, 1, pss->wzId);
588 ExitOnFailure(hr, "Failed to look up FileShare");
589
590 hr = WcaOpenView(vcsSmbExUserPermsQuery, &hView);
591 ExitOnFailure(hr, "Failed to open view on Wix4FileSharePermissions table");
592 hr = WcaExecuteView(hView, hRec);
593 ExitOnFailure(hr, "Failed to execute view on Wix4FileSharePermissions table");
594
595 // loop through all User/Permissions paris returned
596 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
597 {
598 pExUserPerms = NewExUserPermsSmb();
599 if (!pExUserPerms)
600 {
601 hr = E_OUTOFMEMORY;
602 break;
603 }
604 Assert(pExUserPerms);
605 ::ZeroMemory(pExUserPerms, sizeof(*pExUserPerms));
606
607 hr = WcaGetRecordString(hRec, ssupqUser, &pwzData);
608 ExitOnFailure(hr, "Failed to get Wix4FileSharePermissions.User");
609 hr = ScaGetUser(pwzData, &pExUserPerms->scau);
610 ExitOnFailure(hr, "Failed to get user information for fileshare: '%ls'", pss->wzShareName);
611
612 hr = WcaGetRecordInteger(hRec, ssupqPermissions, &pExUserPerms->nPermissions);
613 ExitOnFailure(hr, "Failed to get Wix4FileSharePermissions.Permissions");
614 pExUserPerms->accessMode = SET_ACCESS; // we only support SET_ACCESS here
615
616 pExUserPermsList = AddExUserPermsSmbToList(pExUserPermsList, pExUserPerms);
617 ++nCounter;
618 pExUserPerms = NULL; // set the smb NULL so it doesn't accidentally get freed below
619 }
620
621 if (E_NOMOREITEMS == hr)
622 {
623 hr = S_OK;
624 pss->pExUserPerms = pExUserPermsList;
625 pss->nUserPermissionCount = nCounter;
626 }
627 ExitOnFailure(hr, "Failure occured while processing FileShare table");
628
629LExit:
630 // if anything was left over after an error clean it all up
631 if (pExUserPerms)
632 {
633 ScaExUserPermsSmbFreeList(pExUserPerms);
634 }
635
636 ReleaseStr(pwzData);
637
638 return hr;
639}
diff --git a/src/ext/Util/ca/scauser.cpp b/src/ext/Util/ca/scauser.cpp
new file mode 100644
index 00000000..b25e9daf
--- /dev/null
+++ b/src/ext/Util/ca/scauser.cpp
@@ -0,0 +1,709 @@
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
5LPCWSTR vcsUserQuery = L"SELECT `Wix4User`, `Component_`, `Name`, `Domain`, `Password` FROM `Wix4User` WHERE `Wix4User`=?";
6enum eUserQuery { vuqUser = 1, vuqComponent, vuqName, vuqDomain, vuqPassword };
7
8LPCWSTR vcsGroupQuery = L"SELECT `Wix4Group`, `Component_`, `Name`, `Domain` FROM `Wix4Group` WHERE `Wix4Group`=?";
9enum eGroupQuery { vgqGroup = 1, vgqComponent, vgqName, vgqDomain };
10
11LPCWSTR vcsUserGroupQuery = L"SELECT `Wix4User_`, `Wix4Group_` FROM `Wix4UserGroup` WHERE `Wix4User_`=?";
12enum eUserGroupQuery { vugqUser = 1, vugqGroup };
13
14LPCWSTR vActionableQuery = L"SELECT `Wix4User`,`Component_`,`Name`,`Domain`,`Password`,`Attributes` FROM `Wix4User` WHERE `Component_` IS NOT NULL";
15enum eActionableQuery { vaqUser = 1, vaqComponent, vaqName, vaqDomain, vaqPassword, vaqAttributes };
16
17
18static HRESULT AddUserToList(
19 __inout SCA_USER** ppsuList
20 );
21
22static HRESULT AddGroupToList(
23 __inout SCA_GROUP** ppsgList
24 );
25
26
27HRESULT __stdcall ScaGetUser(
28 __in LPCWSTR wzUser,
29 __out SCA_USER* pscau
30 )
31{
32 if (!wzUser || !pscau)
33 {
34 return E_INVALIDARG;
35 }
36
37 HRESULT hr = S_OK;
38 PMSIHANDLE hView, hRec;
39
40 LPWSTR pwzData = NULL;
41
42 // clear struct and bail right away if no user key was passed to search for
43 ::ZeroMemory(pscau, sizeof(*pscau));
44 if (!*wzUser)
45 {
46 ExitFunction1(hr = S_OK);
47 }
48
49 hRec = ::MsiCreateRecord(1);
50 hr = WcaSetRecordString(hRec, 1, wzUser);
51 ExitOnFailure(hr, "Failed to look up User");
52
53 hr = WcaOpenView(vcsUserQuery, &hView);
54 ExitOnFailure(hr, "Failed to open view on Wix4User table");
55 hr = WcaExecuteView(hView, hRec);
56 ExitOnFailure(hr, "Failed to execute view on Wix4User table");
57
58 hr = WcaFetchSingleRecord(hView, &hRec);
59 if (S_OK == hr)
60 {
61 hr = WcaGetRecordString(hRec, vuqUser, &pwzData);
62 ExitOnFailure(hr, "Failed to get Wix4User.User");
63 hr = ::StringCchCopyW(pscau->wzKey, countof(pscau->wzKey), pwzData);
64 ExitOnFailure(hr, "Failed to copy key string to user object");
65
66 hr = WcaGetRecordString(hRec, vuqComponent, &pwzData);
67 ExitOnFailure(hr, "Failed to get Wix4User.Component_");
68 hr = ::StringCchCopyW(pscau->wzComponent, countof(pscau->wzComponent), pwzData);
69 ExitOnFailure(hr, "Failed to copy component string to user object");
70
71 hr = WcaGetRecordFormattedString(hRec, vuqName, &pwzData);
72 ExitOnFailure(hr, "Failed to get Wix4User.Name");
73 hr = ::StringCchCopyW(pscau->wzName, countof(pscau->wzName), pwzData);
74 ExitOnFailure(hr, "Failed to copy name string to user object");
75
76 hr = WcaGetRecordFormattedString(hRec, vuqDomain, &pwzData);
77 ExitOnFailure(hr, "Failed to get Wix4User.Domain");
78 hr = ::StringCchCopyW(pscau->wzDomain, countof(pscau->wzDomain), pwzData);
79 ExitOnFailure(hr, "Failed to copy domain string to user object");
80
81 hr = WcaGetRecordFormattedString(hRec, vuqPassword, &pwzData);
82 ExitOnFailure(hr, "Failed to get Wix4User.Password");
83 hr = ::StringCchCopyW(pscau->wzPassword, countof(pscau->wzPassword), pwzData);
84 ExitOnFailure(hr, "Failed to copy password string to user object");
85 }
86 else if (E_NOMOREITEMS == hr)
87 {
88 WcaLog(LOGMSG_STANDARD, "Error: Cannot locate Wix4User.User='%ls'", wzUser);
89 hr = E_FAIL;
90 }
91 else
92 {
93 ExitOnFailure(hr, "Error or found multiple matching Wix4User rows");
94 }
95
96LExit:
97 ReleaseStr(pwzData);
98
99 return hr;
100}
101
102HRESULT __stdcall ScaGetUserDeferred(
103 __in LPCWSTR wzUser,
104 __in WCA_WRAPQUERY_HANDLE hUserQuery,
105 __out SCA_USER* pscau
106 )
107{
108 if (!wzUser || !pscau)
109 {
110 return E_INVALIDARG;
111 }
112
113 HRESULT hr = S_OK;
114 MSIHANDLE hRec, hRecTest;
115
116 LPWSTR pwzData = NULL;
117
118 // clear struct and bail right away if no user key was passed to search for
119 ::ZeroMemory(pscau, sizeof(*pscau));
120 if (!*wzUser)
121 {
122 ExitFunction1(hr = S_OK);
123 }
124
125 // Reset back to the first record
126 WcaFetchWrappedReset(hUserQuery);
127
128 hr = WcaFetchWrappedRecordWhereString(hUserQuery, vuqUser, wzUser, &hRec);
129 if (S_OK == hr)
130 {
131 hr = WcaFetchWrappedRecordWhereString(hUserQuery, vuqUser, wzUser, &hRecTest);
132 if (S_OK == hr)
133 {
134 AssertSz(FALSE, "Found multiple matching Wix4User rows");
135 }
136
137 hr = WcaGetRecordString(hRec, vuqUser, &pwzData);
138 ExitOnFailure(hr, "Failed to get Wix4User.User");
139 hr = ::StringCchCopyW(pscau->wzKey, countof(pscau->wzKey), pwzData);
140 ExitOnFailure(hr, "Failed to copy key string to user object (in deferred CA)");
141
142 hr = WcaGetRecordString(hRec, vuqComponent, &pwzData);
143 ExitOnFailure(hr, "Failed to get Wix4User.Component_");
144 hr = ::StringCchCopyW(pscau->wzComponent, countof(pscau->wzComponent), pwzData);
145 ExitOnFailure(hr, "Failed to copy component string to user object (in deferred CA)");
146
147 hr = WcaGetRecordString(hRec, vuqName, &pwzData);
148 ExitOnFailure(hr, "Failed to get Wix4User.Name");
149 hr = ::StringCchCopyW(pscau->wzName, countof(pscau->wzName), pwzData);
150 ExitOnFailure(hr, "Failed to copy name string to user object (in deferred CA)");
151
152 hr = WcaGetRecordString(hRec, vuqDomain, &pwzData);
153 ExitOnFailure(hr, "Failed to get Wix4User.Domain");
154 hr = ::StringCchCopyW(pscau->wzDomain, countof(pscau->wzDomain), pwzData);
155 ExitOnFailure(hr, "Failed to copy domain string to user object (in deferred CA)");
156
157 hr = WcaGetRecordString(hRec, vuqPassword, &pwzData);
158 ExitOnFailure(hr, "Failed to get Wix4User.Password");
159 hr = ::StringCchCopyW(pscau->wzPassword, countof(pscau->wzPassword), pwzData);
160 ExitOnFailure(hr, "Failed to copy password string to user object (in deferred CA)");
161 }
162 else if (E_NOMOREITEMS == hr)
163 {
164 WcaLog(LOGMSG_STANDARD, "Error: Cannot locate Wix4User.User='%ls'", wzUser);
165 hr = E_FAIL;
166 }
167 else
168 {
169 ExitOnFailure(hr, "Error fetching single Wix4User row");
170 }
171
172LExit:
173 ReleaseStr(pwzData);
174
175 return hr;
176}
177
178
179HRESULT __stdcall ScaGetGroup(
180 __in LPCWSTR wzGroup,
181 __out SCA_GROUP* pscag
182 )
183{
184 if (!wzGroup || !pscag)
185 {
186 return E_INVALIDARG;
187 }
188
189 HRESULT hr = S_OK;
190 PMSIHANDLE hView, hRec;
191
192 LPWSTR pwzData = NULL;
193
194 hRec = ::MsiCreateRecord(1);
195 hr = WcaSetRecordString(hRec, 1, wzGroup);
196 ExitOnFailure(hr, "Failed to look up Group");
197
198 hr = WcaOpenView(vcsGroupQuery, &hView);
199 ExitOnFailure(hr, "Failed to open view on Wix4Group table");
200 hr = WcaExecuteView(hView, hRec);
201 ExitOnFailure(hr, "Failed to execute view on Wix4Group table");
202
203 hr = WcaFetchSingleRecord(hView, &hRec);
204 if (S_OK == hr)
205 {
206 hr = WcaGetRecordString(hRec, vgqGroup, &pwzData);
207 ExitOnFailure(hr, "Failed to get Wix4Group.Wix4Group.");
208 hr = ::StringCchCopyW(pscag->wzKey, countof(pscag->wzKey), pwzData);
209 ExitOnFailure(hr, "Failed to copy Wix4Group.Wix4Group.");
210
211 hr = WcaGetRecordString(hRec, vgqComponent, &pwzData);
212 ExitOnFailure(hr, "Failed to get Wix4Group.Component_");
213 hr = ::StringCchCopyW(pscag->wzComponent, countof(pscag->wzComponent), pwzData);
214 ExitOnFailure(hr, "Failed to copy Wix4Group.Component_.");
215
216 hr = WcaGetRecordFormattedString(hRec, vgqName, &pwzData);
217 ExitOnFailure(hr, "Failed to get Wix4Group.Name");
218 hr = ::StringCchCopyW(pscag->wzName, countof(pscag->wzName), pwzData);
219 ExitOnFailure(hr, "Failed to copy Wix4Group.Name.");
220
221 hr = WcaGetRecordFormattedString(hRec, vgqDomain, &pwzData);
222 ExitOnFailure(hr, "Failed to get Wix4Group.Domain");
223 hr = ::StringCchCopyW(pscag->wzDomain, countof(pscag->wzDomain), pwzData);
224 ExitOnFailure(hr, "Failed to copy Wix4Group.Domain.");
225 }
226 else if (E_NOMOREITEMS == hr)
227 {
228 WcaLog(LOGMSG_STANDARD, "Error: Cannot locate Wix4Group.Wix4Group='%ls'", wzGroup);
229 hr = E_FAIL;
230 }
231 else
232 {
233 ExitOnFailure(hr, "Error or found multiple matching Wix4Group rows");
234 }
235
236LExit:
237 ReleaseStr(pwzData);
238
239 return hr;
240}
241
242
243void ScaUserFreeList(
244 __in SCA_USER* psuList
245 )
246{
247 SCA_USER* psuDelete = psuList;
248 while (psuList)
249 {
250 psuDelete = psuList;
251 psuList = psuList->psuNext;
252
253 ScaGroupFreeList(psuDelete->psgGroups);
254 MemFree(psuDelete);
255 }
256}
257
258
259void ScaGroupFreeList(
260 __in SCA_GROUP* psgList
261 )
262{
263 SCA_GROUP* psgDelete = psgList;
264 while (psgList)
265 {
266 psgDelete = psgList;
267 psgList = psgList->psgNext;
268
269 MemFree(psgDelete);
270 }
271}
272
273
274HRESULT ScaUserRead(
275 __out SCA_USER** ppsuList
276 )
277{
278 //Assert(FALSE);
279 Assert(ppsuList);
280
281 HRESULT hr = S_OK;
282 UINT er = ERROR_SUCCESS;
283 PMSIHANDLE hView, hRec, hUserRec, hUserGroupView;
284
285 LPWSTR pwzData = NULL;
286
287 BOOL fUserGroupExists = FALSE;
288
289 SCA_USER *psu = NULL;
290
291 INSTALLSTATE isInstalled, isAction;
292
293 if (S_OK != WcaTableExists(L"Wix4User"))
294 {
295 WcaLog(LOGMSG_VERBOSE, "Wix4User Table does not exist, exiting");
296 ExitFunction1(hr = S_FALSE);
297 }
298
299 if (S_OK == WcaTableExists(L"Wix4UserGroup"))
300 {
301 fUserGroupExists = TRUE;
302 }
303
304 //
305 // loop through all the users
306 //
307 hr = WcaOpenExecuteView(vActionableQuery, &hView);
308 ExitOnFailure(hr, "failed to open view on Wix4User table");
309 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
310 {
311 hr = WcaGetRecordString(hRec, vaqComponent, &pwzData);
312 ExitOnFailure(hr, "failed to get Wix4User.Component");
313
314 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &isInstalled, &isAction);
315 hr = HRESULT_FROM_WIN32(er);
316 ExitOnFailure(hr, "failed to get Component state for Wix4User");
317
318 // don't bother if we aren't installing or uninstalling this component
319 if (WcaIsInstalling(isInstalled, isAction) || WcaIsUninstalling(isInstalled, isAction))
320 {
321 //
322 // Add the user to the list and populate it's values
323 //
324 hr = AddUserToList(ppsuList);
325 ExitOnFailure(hr, "failed to add user to list");
326
327 psu = *ppsuList;
328
329 psu->isInstalled = isInstalled;
330 psu->isAction = isAction;
331 hr = ::StringCchCopyW(psu->wzComponent, countof(psu->wzComponent), pwzData);
332 ExitOnFailure(hr, "failed to copy component name: %ls", pwzData);
333
334 hr = WcaGetRecordString(hRec, vaqUser, &pwzData);
335 ExitOnFailure(hr, "failed to get Wix4User.User");
336 hr = ::StringCchCopyW(psu->wzKey, countof(psu->wzKey), pwzData);
337 ExitOnFailure(hr, "failed to copy user key: %ls", pwzData);
338
339 hr = WcaGetRecordFormattedString(hRec, vaqName, &pwzData);
340 ExitOnFailure(hr, "failed to get Wix4User.Name");
341 hr = ::StringCchCopyW(psu->wzName, countof(psu->wzName), pwzData);
342 ExitOnFailure(hr, "failed to copy user name: %ls", pwzData);
343
344 hr = WcaGetRecordFormattedString(hRec, vaqDomain, &pwzData);
345 ExitOnFailure(hr, "failed to get Wix4User.Domain");
346 hr = ::StringCchCopyW(psu->wzDomain, countof(psu->wzDomain), pwzData);
347 ExitOnFailure(hr, "failed to copy user domain: %ls", pwzData);
348
349 hr = WcaGetRecordFormattedString(hRec, vaqPassword, &pwzData);
350 ExitOnFailure(hr, "failed to get Wix4User.Password");
351 hr = ::StringCchCopyW(psu->wzPassword, countof(psu->wzPassword), pwzData);
352 ExitOnFailure(hr, "failed to copy user password");
353
354 hr = WcaGetRecordInteger(hRec, vaqAttributes, &psu->iAttributes);
355 ExitOnFailure(hr, "failed to get Wix4User.Attributes");
356
357 // Check if this user is to be added to any groups
358 if (fUserGroupExists)
359 {
360 hUserRec = ::MsiCreateRecord(1);
361 hr = WcaSetRecordString(hUserRec, 1, psu->wzKey);
362 ExitOnFailure(hr, "Failed to create user record for querying Wix4UserGroup table");
363
364 hr = WcaOpenView(vcsUserGroupQuery, &hUserGroupView);
365 ExitOnFailure(hr, "Failed to open view on Wix4UserGroup table for user %ls", psu->wzKey);
366 hr = WcaExecuteView(hUserGroupView, hUserRec);
367 ExitOnFailure(hr, "Failed to execute view on Wix4UserGroup table for user: %ls", psu->wzKey);
368
369 while (S_OK == (hr = WcaFetchRecord(hUserGroupView, &hRec)))
370 {
371 hr = WcaGetRecordString(hRec, vugqGroup, &pwzData);
372 ExitOnFailure(hr, "failed to get Wix4UserGroup.Group");
373
374 hr = AddGroupToList(&(psu->psgGroups));
375 ExitOnFailure(hr, "failed to add group to list");
376
377 hr = ScaGetGroup(pwzData, psu->psgGroups);
378 ExitOnFailure(hr, "failed to get information for group: %ls", pwzData);
379 }
380
381 if (E_NOMOREITEMS == hr)
382 {
383 hr = S_OK;
384 }
385 ExitOnFailure(hr, "failed to enumerate selected rows from Wix4UserGroup table");
386 }
387 }
388 }
389
390 if (E_NOMOREITEMS == hr)
391 {
392 hr = S_OK;
393 }
394 ExitOnFailure(hr, "failed to enumerate selected rows from Wix4User table");
395
396LExit:
397 ReleaseStr(pwzData);
398
399 return hr;
400}
401
402
403static HRESULT WriteGroupInfo(
404 __in SCA_GROUP* psgList,
405 __in LPWSTR *ppwzActionData
406 )
407{
408 HRESULT hr = S_OK;
409
410 for (SCA_GROUP* psg = psgList; psg; psg = psg->psgNext)
411 {
412 hr = WcaWriteStringToCaData(psg->wzName, ppwzActionData);
413 ExitOnFailure(hr, "failed to add group name to custom action data: %ls", psg->wzName);
414
415 hr = WcaWriteStringToCaData(psg->wzDomain, ppwzActionData);
416 ExitOnFailure(hr, "failed to add group domain to custom action data: %ls", psg->wzDomain);
417 }
418
419LExit:
420 return hr;
421}
422
423
424// Behaves like WriteGroupInfo, but it filters out groups the user is currently a member of,
425// because we don't want to rollback those
426static HRESULT WriteGroupRollbackInfo(
427 __in LPCWSTR pwzName,
428 __in LPCWSTR pwzDomain,
429 __in SCA_GROUP* psgList,
430 __in LPWSTR *ppwzActionData
431 )
432{
433 HRESULT hr = S_OK;
434 BOOL fIsMember = FALSE;
435
436 for (SCA_GROUP* psg = psgList; psg; psg = psg->psgNext)
437 {
438 hr = UserCheckIsMember(pwzName, pwzDomain, psg->wzName, psg->wzDomain, &fIsMember);
439 if (FAILED(hr))
440 {
441 WcaLog(LOGMSG_VERBOSE, "Failed to check if user: %ls (domain: %ls) is member of a group while collecting rollback information (error code 0x%x) - continuing", pwzName, pwzDomain, hr);
442 hr = S_OK;
443 continue;
444 }
445
446 // If the user is currently a member, we don't want to undo that on rollback, so skip adding
447 // this group record to the list of groups to rollback
448 if (fIsMember)
449 {
450 continue;
451 }
452
453 hr = WcaWriteStringToCaData(psg->wzName, ppwzActionData);
454 ExitOnFailure(hr, "failed to add group name to custom action data: %ls", psg->wzName);
455
456 hr = WcaWriteStringToCaData(psg->wzDomain, ppwzActionData);
457 ExitOnFailure(hr, "failed to add group domain to custom action data: %ls", psg->wzDomain);
458 }
459
460LExit:
461 return hr;
462}
463
464
465/* ****************************************************************
466ScaUserExecute - Schedules user account creation or removal based on
467component state.
468
469******************************************************************/
470HRESULT ScaUserExecute(
471 __in SCA_USER *psuList
472 )
473{
474 HRESULT hr = S_OK;
475 DWORD er = 0;
476 PDOMAIN_CONTROLLER_INFOW pDomainControllerInfo = NULL;
477
478 LPWSTR pwzBaseScriptKey = NULL;
479 DWORD cScriptKey = 0;
480
481 USER_INFO_0 *pUserInfo = NULL;
482 LPWSTR pwzScriptKey = NULL;
483 LPWSTR pwzActionData = NULL;
484 LPWSTR pwzRollbackData = NULL;
485
486 // Get the base script key for this CustomAction.
487 hr = WcaCaScriptCreateKey(&pwzBaseScriptKey);
488 ExitOnFailure(hr, "Failed to get encoding key.");
489
490 // Loop through all the users to be configured.
491 for (SCA_USER *psu = psuList; psu; psu = psu->psuNext)
492 {
493 USER_EXISTS ueUserExists = USER_EXISTS_INDETERMINATE;
494
495 // Always put the User Name and Domain plus Attributes on the front of the CustomAction
496 // data. Sometimes we'll add more data.
497 Assert(psu->wzName);
498 hr = WcaWriteStringToCaData(psu->wzName, &pwzActionData);
499 ExitOnFailure(hr, "Failed to add user name to custom action data: %ls", psu->wzName);
500 hr = WcaWriteStringToCaData(psu->wzDomain, &pwzActionData);
501 ExitOnFailure(hr, "Failed to add user domain to custom action data: %ls", psu->wzDomain);
502 hr = WcaWriteIntegerToCaData(psu->iAttributes, &pwzActionData);
503 ExitOnFailure(hr, "failed to add user attributes to custom action data for user: %ls", psu->wzKey);
504
505 // Check to see if the user already exists since we have to be very careful when adding
506 // and removing users. Note: MSDN says that it is safe to call these APIs from any
507 // user, so we should be safe calling it during immediate mode.
508 er = ::NetApiBufferAllocate(sizeof(USER_INFO_0), reinterpret_cast<LPVOID*>(&pUserInfo));
509 hr = HRESULT_FROM_WIN32(er);
510 ExitOnFailure(hr, "Failed to allocate memory to check existence of user: %ls", psu->wzName);
511
512 LPCWSTR wzDomain = psu->wzDomain;
513 if (wzDomain && *wzDomain)
514 {
515 er = ::DsGetDcNameW(NULL, wzDomain, NULL, NULL, NULL, &pDomainControllerInfo);
516 if (RPC_S_SERVER_UNAVAILABLE == er)
517 {
518 // MSDN says, if we get the above error code, try again with the "DS_FORCE_REDISCOVERY" flag
519 er = ::DsGetDcNameW(NULL, wzDomain, NULL, NULL, DS_FORCE_REDISCOVERY, &pDomainControllerInfo);
520 }
521 if (ERROR_SUCCESS == er)
522 {
523 wzDomain = pDomainControllerInfo->DomainControllerName + 2; //Add 2 so that we don't get the \\ prefix
524 }
525 }
526
527 er = ::NetUserGetInfo(wzDomain, psu->wzName, 0, reinterpret_cast<LPBYTE*>(pUserInfo));
528 if (NERR_Success == er)
529 {
530 ueUserExists = USER_EXISTS_YES;
531 }
532 else if (NERR_UserNotFound == er)
533 {
534 ueUserExists = USER_EXISTS_NO;
535 }
536 else
537 {
538 ueUserExists = USER_EXISTS_INDETERMINATE;
539 hr = HRESULT_FROM_WIN32(er);
540 WcaLog(LOGMSG_VERBOSE, "Failed to check existence of domain: %ls, user: %ls (error code 0x%x) - continuing", wzDomain, psu->wzName, hr);
541 hr = S_OK;
542 er = ERROR_SUCCESS;
543 }
544
545 if (WcaIsInstalling(psu->isInstalled, psu->isAction))
546 {
547 // If the user exists, check to see if we are supposed to fail if user the exists before
548 // the install.
549 if (USER_EXISTS_YES == ueUserExists)
550 {
551 // Reinstalls will always fail if we don't remove the check for "fail if exists".
552 if (WcaIsReInstalling(psu->isInstalled, psu->isAction))
553 {
554 psu->iAttributes &= ~SCAU_FAIL_IF_EXISTS;
555 }
556
557 if ((SCAU_FAIL_IF_EXISTS & (psu->iAttributes)) && !(SCAU_UPDATE_IF_EXISTS & (psu->iAttributes)))
558 {
559 hr = HRESULT_FROM_WIN32(NERR_UserExists);
560 MessageExitOnFailure(hr, msierrUSRFailedUserCreateExists, "Failed to create user: %ls because user already exists.", psu->wzName);
561 }
562 }
563
564 // Rollback only if the user already exists, we couldn't determine if the user exists, or we are going to create the user
565 if ((USER_EXISTS_YES == ueUserExists) || (USER_EXISTS_INDETERMINATE == ueUserExists) || !(psu->iAttributes & SCAU_DONT_CREATE_USER))
566 {
567 ++cScriptKey;
568 hr = StrAllocFormatted(&pwzScriptKey, L"%ls%u", pwzBaseScriptKey, cScriptKey);
569 ExitOnFailure(hr, "Failed to create encoding key.");
570
571 // Write the script key to CustomActionData for install and rollback so information can be passed to rollback.
572 hr = WcaWriteStringToCaData(pwzScriptKey, &pwzActionData);
573 ExitOnFailure(hr, "Failed to add encoding key to custom action data.");
574
575 hr = WcaWriteStringToCaData(pwzScriptKey, &pwzRollbackData);
576 ExitOnFailure(hr, "Failed to add encoding key to rollback custom action data.");
577
578 INT iRollbackUserAttributes = psu->iAttributes;
579
580 // If the user already exists, ensure this is accounted for in rollback
581 if (USER_EXISTS_YES == ueUserExists)
582 {
583 iRollbackUserAttributes |= SCAU_DONT_CREATE_USER;
584 }
585 else
586 {
587 iRollbackUserAttributes &= ~SCAU_DONT_CREATE_USER;
588 }
589
590 // The deferred CA determines when to rollback User Rights Assignments so these should never be set.
591 iRollbackUserAttributes &= ~SCAU_ALLOW_LOGON_AS_SERVICE;
592 iRollbackUserAttributes &= ~SCAU_ALLOW_LOGON_AS_BATCH;
593
594 hr = WcaWriteStringToCaData(psu->wzName, &pwzRollbackData);
595 ExitOnFailure(hr, "Failed to add user name to rollback custom action data: %ls", psu->wzName);
596 hr = WcaWriteStringToCaData(psu->wzDomain, &pwzRollbackData);
597 ExitOnFailure(hr, "Failed to add user domain to rollback custom action data: %ls", psu->wzDomain);
598 hr = WcaWriteIntegerToCaData(iRollbackUserAttributes, &pwzRollbackData);
599 ExitOnFailure(hr, "failed to add user attributes to rollback custom action data for user: %ls", psu->wzKey);
600
601 // If the user already exists, add relevant group information to rollback data
602 if (USER_EXISTS_YES == ueUserExists || USER_EXISTS_INDETERMINATE == ueUserExists)
603 {
604 hr = WriteGroupRollbackInfo(psu->wzName, psu->wzDomain, psu->psgGroups, &pwzRollbackData);
605 ExitOnFailure(hr, "failed to add group information to rollback custom action data");
606 }
607
608 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"CreateUserRollback"), pwzRollbackData, COST_USER_DELETE);
609 ExitOnFailure(hr, "failed to schedule CreateUserRollback");
610 }
611 else
612 {
613 // Write empty script key to CustomActionData since there is no rollback.
614 hr = WcaWriteStringToCaData(L"", &pwzActionData);
615 ExitOnFailure(hr, "Failed to add empty encoding key to custom action data.");
616 }
617
618 //
619 // Schedule the creation now.
620 //
621 hr = WcaWriteStringToCaData(psu->wzPassword, &pwzActionData);
622 ExitOnFailure(hr, "failed to add user password to custom action data for user: %ls", psu->wzKey);
623
624 // Add user's group information to custom action data
625 hr = WriteGroupInfo(psu->psgGroups, &pwzActionData);
626 ExitOnFailure(hr, "failed to add group information to custom action data");
627
628 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"CreateUser"), pwzActionData, COST_USER_ADD);
629 ExitOnFailure(hr, "failed to schedule CreateUser");
630 }
631 else if (((USER_EXISTS_YES == ueUserExists) || (USER_EXISTS_INDETERMINATE == ueUserExists)) && WcaIsUninstalling(psu->isInstalled, psu->isAction) && !(psu->iAttributes & SCAU_DONT_REMOVE_ON_UNINSTALL))
632 {
633 // Add user's group information - this will ensure the user can be removed from any groups they were added to, if the user isn't be deleted
634 hr = WriteGroupInfo(psu->psgGroups, &pwzActionData);
635 ExitOnFailure(hr, "failed to add group information to custom action data");
636
637 //
638 // Schedule the removal because the user exists and we don't have any flags set
639 // that say, don't remove the user on uninstall.
640 //
641 // Note: We can't rollback the removal of a user which is why RemoveUser is a commit
642 // CustomAction.
643 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RemoveUser"), pwzActionData, COST_USER_DELETE);
644 ExitOnFailure(hr, "failed to schedule RemoveUser");
645 }
646
647 ReleaseNullStr(pwzScriptKey);
648 ReleaseNullStr(pwzActionData);
649 ReleaseNullStr(pwzRollbackData);
650 if (pUserInfo)
651 {
652 ::NetApiBufferFree(static_cast<LPVOID>(pUserInfo));
653 pUserInfo = NULL;
654 }
655 if (pDomainControllerInfo)
656 {
657 ::NetApiBufferFree(static_cast<LPVOID>(pDomainControllerInfo));
658 pDomainControllerInfo = NULL;
659 }
660 }
661
662LExit:
663 ReleaseStr(pwzBaseScriptKey);
664 ReleaseStr(pwzScriptKey);
665 ReleaseStr(pwzActionData);
666 ReleaseStr(pwzRollbackData);
667 if (pUserInfo)
668 {
669 ::NetApiBufferFree(static_cast<LPVOID>(pUserInfo));
670 }
671 if (pDomainControllerInfo)
672 {
673 ::NetApiBufferFree(static_cast<LPVOID>(pDomainControllerInfo));
674 }
675
676 return hr;
677}
678
679
680static HRESULT AddUserToList(
681 __inout SCA_USER** ppsuList
682 )
683{
684 HRESULT hr = S_OK;
685 SCA_USER* psu = static_cast<SCA_USER*>(MemAlloc(sizeof(SCA_USER), TRUE));
686 ExitOnNull(psu, hr, E_OUTOFMEMORY, "failed to allocate memory for new user list element");
687
688 psu->psuNext = *ppsuList;
689 *ppsuList = psu;
690
691LExit:
692 return hr;
693}
694
695
696static HRESULT AddGroupToList(
697 __inout SCA_GROUP** ppsgList
698 )
699{
700 HRESULT hr = S_OK;
701 SCA_GROUP* psg = static_cast<SCA_GROUP*>(MemAlloc(sizeof(SCA_GROUP), TRUE));
702 ExitOnNull(psg, hr, E_OUTOFMEMORY, "failed to allocate memory for new group list element");
703
704 psg->psgNext = *ppsgList;
705 *ppsgList = psg;
706
707LExit:
708 return hr;
709}
diff --git a/src/ext/Util/ca/scauser.h b/src/ext/Util/ca/scauser.h
new file mode 100644
index 00000000..a5fd5ea8
--- /dev/null
+++ b/src/ext/Util/ca/scauser.h
@@ -0,0 +1,67 @@
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
5enum USER_EXISTS
6{
7 USER_EXISTS_YES,
8 USER_EXISTS_NO,
9 USER_EXISTS_INDETERMINATE
10};
11
12// structs
13struct SCA_GROUP
14{
15 WCHAR wzKey[MAX_DARWIN_KEY + 1];
16 WCHAR wzComponent[MAX_DARWIN_KEY + 1];
17
18 WCHAR wzDomain[MAX_DARWIN_COLUMN + 1];
19 WCHAR wzName[MAX_DARWIN_COLUMN + 1];
20
21 SCA_GROUP *psgNext;
22};
23
24struct SCA_USER
25{
26 WCHAR wzKey[MAX_DARWIN_KEY + 1];
27 WCHAR wzComponent[MAX_DARWIN_KEY + 1];
28 INSTALLSTATE isInstalled;
29 INSTALLSTATE isAction;
30
31 WCHAR wzDomain[MAX_DARWIN_COLUMN + 1];
32 WCHAR wzName[MAX_DARWIN_COLUMN + 1];
33 WCHAR wzPassword[MAX_DARWIN_COLUMN + 1];
34 INT iAttributes;
35
36 SCA_GROUP *psgGroups;
37
38 SCA_USER *psuNext;
39};
40
41
42// prototypes
43HRESULT __stdcall ScaGetUser(
44 __in LPCWSTR wzUser,
45 __out SCA_USER* pscau
46 );
47HRESULT __stdcall ScaGetUserDeferred(
48 __in LPCWSTR wzUser,
49 __in WCA_WRAPQUERY_HANDLE hUserQuery,
50 __out SCA_USER* pscau
51 );
52HRESULT __stdcall ScaGetGroup(
53 __in LPCWSTR wzGroup,
54 __out SCA_GROUP* pscag
55 );
56void ScaUserFreeList(
57 __in SCA_USER* psuList
58 );
59void ScaGroupFreeList(
60 __in SCA_GROUP* psgList
61 );
62HRESULT ScaUserRead(
63 __inout SCA_USER** ppsuList
64 );
65HRESULT ScaUserExecute(
66 __in SCA_USER *psuList
67 );
diff --git a/src/ext/Util/ca/secureobj.cpp b/src/ext/Util/ca/secureobj.cpp
new file mode 100644
index 00000000..72842eb5
--- /dev/null
+++ b/src/ext/Util/ca/secureobj.cpp
@@ -0,0 +1,915 @@
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// structs
6LPCWSTR wzQUERY_SECUREOBJECTS = L"SELECT `Wix4SecureObject`.`Wix4SecureObject`, `Wix4SecureObject`.`Table`, `Wix4SecureObject`.`Domain`, `Wix4SecureObject`.`User`, `Wix4SecureObject`.`Attributes`, "
7 L"`Wix4SecureObject`.`Permission`, `Wix4SecureObject`.`Component_`, `Component`.`Attributes` FROM `Wix4SecureObject`,`Component` WHERE "
8 L"`Wix4SecureObject`.`Component_`=`Component`.`Component`";
9enum eQUERY_SECUREOBJECTS { QSO_SECUREOBJECT = 1, QSO_TABLE, QSO_DOMAIN, QSO_USER, QSO_ATTRIBUTES, QSO_PERMISSION, QSO_COMPONENT, QSO_COMPATTRIBUTES };
10
11LPCWSTR wzQUERY_REGISTRY = L"SELECT `Registry`.`Registry`, `Registry`.`Root`, `Registry`.`Key` FROM `Registry` WHERE `Registry`.`Registry`=?";
12enum eQUERY_OBJECTCOMPONENT { QSOC_REGISTRY = 1, QSOC_REGROOT, QSOC_REGKEY };
13
14LPCWSTR wzQUERY_SERVICEINSTALL = L"SELECT `ServiceInstall`.`Name` FROM `ServiceInstall` WHERE `ServiceInstall`.`ServiceInstall`=?";
15enum eQUERY_SECURESERVICEINSTALL { QSSI_NAME = 1 };
16
17enum eOBJECTTYPE { OT_UNKNOWN, OT_SERVICE, OT_FOLDER, OT_FILE, OT_REGISTRY };
18
19enum eSECURE_OBJECT_ATTRIBUTE
20{
21 SECURE_OBJECT_ATTRIBUTE_INHERITABLE = 0x1,
22};
23
24static eOBJECTTYPE EObjectTypeFromString(
25 __in LPCWSTR pwzTable
26 )
27{
28 if (NULL == pwzTable)
29 {
30 return OT_UNKNOWN;
31 }
32
33 eOBJECTTYPE eType = OT_UNKNOWN;
34
35 // ensure we're looking at a known table
36 if (0 == lstrcmpW(L"ServiceInstall", pwzTable))
37 {
38 eType = OT_SERVICE;
39 }
40 else if (0 == lstrcmpW(L"CreateFolder", pwzTable))
41 {
42 eType = OT_FOLDER;
43 }
44 else if (0 == lstrcmpW(L"File", pwzTable))
45 {
46 eType = OT_FILE;
47 }
48 else if (0 == lstrcmpW(L"Registry", pwzTable))
49 {
50 eType = OT_REGISTRY;
51 }
52
53 return eType;
54}
55
56static SE_OBJECT_TYPE SEObjectTypeFromString(
57 __in LPCWSTR pwzTable
58 )
59{
60 if (NULL == pwzTable)
61 {
62 return SE_UNKNOWN_OBJECT_TYPE;
63 }
64
65 SE_OBJECT_TYPE objectType = SE_UNKNOWN_OBJECT_TYPE;
66
67 if (0 == lstrcmpW(L"ServiceInstall", pwzTable))
68 {
69 objectType = SE_SERVICE;
70 }
71 else if (0 == lstrcmpW(L"CreateFolder", pwzTable) || 0 == lstrcmpW(L"File", pwzTable))
72 {
73 objectType = SE_FILE_OBJECT;
74 }
75 else if (0 == lstrcmpW(L"Registry", pwzTable))
76 {
77 objectType = SE_REGISTRY_KEY;
78 }
79 else
80 {
81 // Do nothing; we'll return SE_UNKNOWN_OBJECT_TYPE, and the caller should handle the situation
82 }
83
84 return objectType;
85}
86
87static HRESULT StoreACLRollbackInfo(
88 __in LPWSTR pwzObject,
89 __in LPCWSTR pwzTable
90 )
91{
92 HRESULT hr = S_OK;
93 DWORD er = ERROR_SUCCESS;
94 PSECURITY_DESCRIPTOR psd = NULL;
95 SECURITY_DESCRIPTOR_CONTROL sdc = {0};
96 DWORD dwRevision = 0;
97 LPWSTR pwzCustomActionData = NULL;
98 LPWSTR pwzSecurityInfo = NULL;
99
100 Assert(pwzObject && pwzTable);
101
102 SE_OBJECT_TYPE objectType = SEObjectTypeFromString(const_cast<LPCWSTR> (pwzTable));
103
104 if (SE_UNKNOWN_OBJECT_TYPE != objectType)
105 {
106 er = ::GetNamedSecurityInfoW(pwzObject, objectType, DACL_SECURITY_INFORMATION, NULL, NULL, NULL, NULL, &psd);
107 if (ERROR_FILE_NOT_FOUND == er || ERROR_PATH_NOT_FOUND == er || ERROR_SERVICE_DOES_NOT_EXIST == HRESULT_CODE(er))
108 {
109 // If the file, path or service doesn't exist yet, skip rollback without a message
110 hr = HRESULT_FROM_WIN32(er);
111 ExitFunction();
112 }
113
114 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Unable to schedule rollback for object: %ls", pwzObject);
115
116 //Need to see if DACL is protected so getting Descriptor information
117 if (!::GetSecurityDescriptorControl(psd, &sdc, &dwRevision))
118 {
119 ExitOnLastError(hr, "Unable to schedule rollback for object (failed to get security descriptor control): %ls", pwzObject);
120 }
121
122 // Convert the security information to a string, and write this to the custom action data
123 if (!::ConvertSecurityDescriptorToStringSecurityDescriptorW(psd,SDDL_REVISION_1,DACL_SECURITY_INFORMATION,&pwzSecurityInfo,NULL))
124 {
125 hr = E_UNEXPECTED;
126 ExitOnFailure(hr, "Unable to schedule rollback for object (failed to convert security descriptor to a valid security descriptor string): %ls", pwzObject);
127 }
128
129 hr = WcaWriteStringToCaData(pwzObject, &pwzCustomActionData);
130 ExitOnFailure(hr, "failed to add object data to rollback CustomActionData");
131
132 hr = WcaWriteStringToCaData(pwzTable, &pwzCustomActionData);
133 ExitOnFailure(hr, "failed to add table name to rollback CustomActionData");
134
135 hr = WcaWriteStringToCaData(pwzSecurityInfo, &pwzCustomActionData);
136 ExitOnFailure(hr, "failed to add security info data to rollback CustomActionData");
137
138 // Write a 1 if DACL is protected, 0 otherwise
139 if (sdc & SE_DACL_PROTECTED)
140 {
141 hr = WcaWriteIntegerToCaData(1,&pwzCustomActionData);
142 ExitOnFailure(hr, "failed to add data to rollbackCustomActionData");
143 }
144 else
145 {
146 hr = WcaWriteIntegerToCaData(0,&pwzCustomActionData);
147 ExitOnFailure(hr, "failed to add data to rollback CustomActionData");
148 }
149
150 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecSecureObjectsRollback"), pwzCustomActionData, COST_SECUREOBJECT);
151 ExitOnFailure(hr, "failed to schedule ExecSecureObjectsRollback for item: %ls of type: %ls", pwzObject, pwzTable);
152
153 ReleaseStr(pwzCustomActionData);
154 pwzCustomActionData = NULL;
155
156 }
157 else
158 {
159 MessageExitOnFailure(hr = E_UNEXPECTED, msierrSecureObjectsUnknownType, "unknown object type: %ls", pwzTable);
160 }
161LExit:
162 ReleaseStr(pwzCustomActionData);
163
164 if (psd)
165 {
166 ::LocalFree(psd);
167 }
168
169 return hr;
170}
171
172static HRESULT GetTargetPath(
173 __in eOBJECTTYPE eType,
174 __in LPCWSTR pwzSecureObject,
175 __out LPWSTR* ppwzTargetPath
176 )
177{
178 HRESULT hr = S_OK;
179
180 PMSIHANDLE hView = NULL;
181 PMSIHANDLE hRecObject = NULL;
182 PMSIHANDLE hRec = NULL;
183
184 int iRoot = 0;
185 int iAllUsers = 0;
186 LPWSTR pwzKey = NULL;
187 LPWSTR pwzFormattedString = NULL;
188
189 if (OT_SERVICE == eType)
190 {
191 hr = WcaTableExists(L"ServiceInstall");
192 if (S_FALSE == hr)
193 {
194 hr = E_UNEXPECTED;
195 }
196 ExitOnFailure(hr, "failed to open ServiceInstall table to secure object");
197
198 hr = WcaOpenView(wzQUERY_SERVICEINSTALL, &hView);
199 ExitOnFailure(hr, "failed to open view on ServiceInstall table");
200
201 // create a record that stores the object to secure
202 hRec = MsiCreateRecord(1);
203 MsiRecordSetStringW(hRec, 1, pwzSecureObject);
204
205 // execute a view looking for the object's ServiceInstall.ServiceInstall row.
206 hr = WcaExecuteView(hView, hRec);
207 ExitOnFailure(hr, "failed to execute view on ServiceInstall table");
208 hr = WcaFetchSingleRecord(hView, &hRecObject);
209 ExitOnFailure(hr, "failed to fetch ServiceInstall row for secure object");
210
211 hr = WcaGetRecordFormattedString(hRecObject, QSSI_NAME, ppwzTargetPath);
212 ExitOnFailure(hr, "failed to get service name for secure object: %ls", pwzSecureObject);
213 }
214 else if (OT_FOLDER == eType)
215 {
216 hr = WcaGetTargetPath(pwzSecureObject, ppwzTargetPath);
217 ExitOnFailure(hr, "failed to get target path for directory id: %ls", pwzSecureObject);
218 }
219 else if (OT_FILE == eType)
220 {
221 hr = StrAllocFormatted(&pwzFormattedString, L"[#%s]", pwzSecureObject);
222 ExitOnFailure(hr, "failed to create formatted string for securing file object: %ls", pwzSecureObject);
223
224 hr = WcaGetFormattedString(pwzFormattedString, ppwzTargetPath);
225 ExitOnFailure(hr, "failed to get file path from formatted string: %ls for secure object: %ls", pwzFormattedString, pwzSecureObject);
226 }
227 else if (OT_REGISTRY == eType)
228 {
229 hr = WcaTableExists(L"Registry");
230 if (S_FALSE == hr)
231 {
232 hr = E_UNEXPECTED;
233 }
234 ExitOnFailure(hr, "failed to open Registry table to secure object");
235
236 hr = WcaOpenView(wzQUERY_REGISTRY, &hView);
237 ExitOnFailure(hr, "failed to open view on Registry table");
238
239 // create a record that stores the object to secure
240 hRec = MsiCreateRecord(1);
241 MsiRecordSetStringW(hRec, 1, pwzSecureObject);
242
243 // execute a view looking for the object's Registry row
244 hr = WcaExecuteView(hView, hRec);
245 ExitOnFailure(hr, "failed to execute view on Registry table");
246 hr = WcaFetchSingleRecord(hView, &hRecObject);
247 ExitOnFailure(hr, "failed to fetch Registry row for secure object");
248
249 hr = WcaGetRecordInteger(hRecObject, QSOC_REGROOT, &iRoot);
250 ExitOnFailure(hr, "Failed to get reg key root for secure object: %ls", pwzSecureObject);
251
252 hr = WcaGetRecordFormattedString(hRecObject, QSOC_REGKEY, &pwzKey);
253 ExitOnFailure(hr, "Failed to get reg key for secure object: %ls", pwzSecureObject);
254
255 // Decode the root value
256 if (-1 == iRoot)
257 {
258 // They didn't specify a root so that means it's either HKCU or HKLM depending on ALLUSERS property
259 hr = WcaGetIntProperty(L"ALLUSERS", &iAllUsers);
260 ExitOnFailure(hr, "failed to get value of ALLUSERS property");
261
262 if (1 == iAllUsers)
263 {
264 hr = StrAllocString(ppwzTargetPath, L"MACHINE\\", 0);
265 ExitOnFailure(hr, "failed to allocate target registry string with HKLM root");
266 }
267 else
268 {
269 hr = StrAllocString(ppwzTargetPath, L"CURRENT_USER\\", 0);
270 ExitOnFailure(hr, "failed to allocate target registry string with HKCU root");
271 }
272 }
273 else if (msidbRegistryRootClassesRoot == iRoot)
274 {
275 hr = StrAllocString(ppwzTargetPath, L"CLASSES_ROOT\\", 0);
276 ExitOnFailure(hr, "failed to allocate target registry string with HKCR root");
277 }
278 else if (msidbRegistryRootCurrentUser == iRoot)
279 {
280 hr = StrAllocString(ppwzTargetPath, L"CURRENT_USER\\", 0);
281 ExitOnFailure(hr, "failed to allocate target registry string with HKCU root");
282 }
283 else if (msidbRegistryRootLocalMachine == iRoot)
284 {
285 hr = StrAllocString(ppwzTargetPath, L"MACHINE\\", 0);
286 ExitOnFailure(hr, "failed to allocate target registry string with HKLM root");
287 }
288 else if (msidbRegistryRootUsers == iRoot)
289 {
290 hr = StrAllocString(ppwzTargetPath, L"USERS\\", 0);
291 ExitOnFailure(hr, "failed to allocate target registry string with HKU root");
292 }
293 else
294 {
295 ExitOnFailure(hr = E_UNEXPECTED, "Unknown registry key root specified for secure object: '%ls' root: %d", pwzSecureObject, iRoot);
296 }
297
298 hr = StrAllocConcat(ppwzTargetPath, pwzKey, 0);
299 ExitOnFailure(hr, "Failed to concat key: %ls for secure object: %ls", pwzKey, pwzSecureObject);
300 }
301 else
302 {
303 AssertSz(FALSE, "How did you get here?");
304 ExitOnFailure(hr = E_UNEXPECTED, "Unknown secure object type: %d", eType);
305 }
306
307LExit:
308 ReleaseStr(pwzFormattedString);
309 ReleaseStr(pwzKey);
310
311 return hr;
312}
313
314/******************************************************************
315 SchedSecureObjects - entry point for SchedSecureObjects Custom Action
316
317 called as Type 1 CustomAction (binary DLL) from Windows Installer
318 in InstallExecuteSequence, to schedule ExecSecureObjects
319******************************************************************/
320extern "C" UINT __stdcall SchedSecureObjects(
321 __in MSIHANDLE hInstall
322 )
323{
324// AssertSz(FALSE, "debug SchedSecureObjects");
325 HRESULT hr = S_OK;
326 UINT er = ERROR_SUCCESS;
327
328 LPWSTR pwzSecureObject = NULL;
329 LPWSTR pwzData = NULL;
330 LPWSTR pwzTable = NULL;
331 LPWSTR pwzTargetPath = NULL;
332
333 PMSIHANDLE hView = NULL;
334 PMSIHANDLE hRec = NULL;
335
336 INSTALLSTATE isInstalled;
337 INSTALLSTATE isAction;
338
339 LPWSTR pwzCustomActionData = NULL;
340
341 DWORD cObjects = 0;
342 eOBJECTTYPE eType = OT_UNKNOWN;
343 DWORD dwAttributes = 0;
344
345 //
346 // initialize
347 //
348 hr = WcaInitialize(hInstall, "SchedSecureObjects");
349 ExitOnFailure(hr, "failed to initialize");
350
351 // anything to do?
352 if (S_OK != WcaTableExists(L"Wix4SecureObject"))
353 {
354 WcaLog(LOGMSG_STANDARD, "Wix4SecureObject table doesn't exist, so there are no objects to secure.");
355 ExitFunction();
356 }
357
358 //
359 // loop through all the objects to be secured
360 //
361 hr = WcaOpenExecuteView(wzQUERY_SECUREOBJECTS, &hView);
362 ExitOnFailure(hr, "failed to open view on Wix4SecureObject table");
363 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
364 {
365 hr = WcaGetRecordString(hRec, QSO_TABLE, &pwzTable);
366 ExitOnFailure(hr, "failed to get object table");
367
368 eType = EObjectTypeFromString(pwzTable);
369
370 if (OT_UNKNOWN == eType)
371 {
372 ExitOnFailure(hr = E_INVALIDARG, "unknown SecureObject.Table: %ls", pwzTable);
373 }
374
375 int iCompAttributes = 0;
376 hr = WcaGetRecordInteger(hRec, QSO_COMPATTRIBUTES, &iCompAttributes);
377 ExitOnFailure(hr, "failed to get Component attributes for secure object");
378
379 BOOL fIs64Bit = iCompAttributes & msidbComponentAttributes64bit;
380
381 // Only process entries in the Wix4SecureObject table whose components match the bitness of this CA
382#ifdef _WIN64
383 if (!fIs64Bit)
384 {
385 continue;
386 }
387#else
388 if (fIs64Bit)
389 {
390 continue;
391 }
392#endif
393
394 // Get the object to secure
395 hr = WcaGetRecordString(hRec, QSO_SECUREOBJECT, &pwzSecureObject);
396 ExitOnFailure(hr, "failed to get name of object");
397
398 hr = GetTargetPath(eType, pwzSecureObject, &pwzTargetPath);
399 ExitOnFailure(hr, "failed to get target path of object '%ls'", pwzSecureObject);
400
401 hr = WcaGetRecordString(hRec, QSO_COMPONENT, &pwzData);
402 ExitOnFailure(hr, "failed to get Component name for secure object");
403
404 //
405 // if we are installing this Component
406 //
407 er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction);
408 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "failed to get install state for Component: %ls", pwzData);
409
410 if (WcaIsInstalling(isInstalled, isAction))
411 {
412 hr = WcaWriteStringToCaData(pwzTargetPath, &pwzCustomActionData);
413 ExitOnFailure(hr, "failed to add data to CustomActionData");
414
415 // add the data to the CustomActionData
416 hr = WcaGetRecordString(hRec, QSO_SECUREOBJECT, &pwzData);
417 ExitOnFailure(hr, "failed to get name of object");
418 hr = WcaWriteStringToCaData(pwzTable, &pwzCustomActionData);
419 ExitOnFailure(hr, "failed to add data to CustomActionData");
420
421 hr = WcaGetRecordFormattedString(hRec, QSO_DOMAIN, &pwzData);
422 ExitOnFailure(hr, "failed to get domain for user to configure object");
423 hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
424 ExitOnFailure(hr, "failed to add data to CustomActionData");
425
426 hr = WcaGetRecordFormattedString(hRec, QSO_USER, &pwzData);
427 ExitOnFailure(hr, "failed to get user to configure object");
428 hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
429 ExitOnFailure(hr, "failed to add data to CustomActionData");
430
431 hr = WcaGetRecordInteger(hRec, QSO_ATTRIBUTES, reinterpret_cast<int*>(&dwAttributes));
432 ExitOnFailure(hr, "failed to get attributes to configure object");
433 hr = WcaWriteIntegerToCaData(dwAttributes, &pwzCustomActionData);
434 ExitOnFailure(hr, "failed to add data to CustomActionData");
435
436 hr = WcaGetRecordString(hRec, QSO_PERMISSION, &pwzData);
437 ExitOnFailure(hr, "failed to get permission to configure object");
438 hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
439 ExitOnFailure(hr, "failed to add data to CustomActionData");
440
441 ++cObjects;
442 }
443 }
444
445 // if we looped through all records all is well
446 if (E_NOMOREITEMS == hr)
447 hr = S_OK;
448 ExitOnFailure(hr, "failed while looping through all objects to secure");
449
450 //
451 // schedule the custom action and add to progress bar
452 //
453 if (pwzCustomActionData && *pwzCustomActionData)
454 {
455 Assert(0 < cObjects);
456
457 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecSecureObjects"), pwzCustomActionData, cObjects * COST_SECUREOBJECT);
458 ExitOnFailure(hr, "failed to schedule ExecSecureObjects action");
459 }
460
461LExit:
462 ReleaseStr(pwzSecureObject);
463 ReleaseStr(pwzCustomActionData);
464 ReleaseStr(pwzData);
465 ReleaseStr(pwzTable);
466 ReleaseStr(pwzTargetPath);
467
468 if (FAILED(hr))
469 {
470 er = ERROR_INSTALL_FAILURE;
471 }
472 return WcaFinalize(er);
473}
474
475/******************************************************************
476 SchedSecureObjectsRollback - entry point for SchedSecureObjectsRollback Custom Action
477
478 called as Type 1 CustomAction (binary DLL) from Windows Installer
479 in InstallExecuteSequence before SchedSecureObjects
480******************************************************************/
481extern "C" UINT __stdcall SchedSecureObjectsRollback(
482 __in MSIHANDLE hInstall
483 )
484{
485// AssertSz(FALSE, "debug SchedSecureObjectsRollback");
486 HRESULT hr = S_OK;
487 UINT er = ERROR_SUCCESS;
488
489 LPWSTR pwzSecureObject = NULL;
490 LPWSTR pwzTable = NULL;
491 LPWSTR pwzTargetPath = NULL;
492
493 PMSIHANDLE hView = NULL;
494 PMSIHANDLE hRec = NULL;
495
496 LPWSTR pwzCustomActionData = NULL;
497
498 eOBJECTTYPE eType = OT_UNKNOWN;
499
500 //
501 // initialize
502 //
503 hr = WcaInitialize(hInstall, "SchedSecureObjectsRollback");
504 ExitOnFailure(hr, "failed to initialize");
505
506 //
507 // loop through all the objects to be secured
508 //
509 hr = WcaOpenExecuteView(wzQUERY_SECUREOBJECTS, &hView);
510 ExitOnFailure(hr, "failed to open view on Wix4SecureObject table");
511 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
512 {
513 hr = WcaGetRecordString(hRec, QSO_TABLE, &pwzTable);
514 ExitOnFailure(hr, "failed to get object table");
515
516 eType = EObjectTypeFromString(pwzTable);
517
518 if (OT_UNKNOWN == eType)
519 {
520 ExitOnFailure(hr = E_INVALIDARG, "unknown SecureObject.Table: %ls", pwzTable);
521 }
522
523 int iCompAttributes = 0;
524 hr = WcaGetRecordInteger(hRec, QSO_COMPATTRIBUTES, &iCompAttributes);
525 ExitOnFailure(hr, "failed to get Component attributes for secure object");
526
527 BOOL fIs64Bit = iCompAttributes & msidbComponentAttributes64bit;
528
529 // Only process entries in the Wix4SecureObject table whose components match the bitness of this CA
530#ifdef _WIN64
531 if (!fIs64Bit)
532 {
533 continue;
534 }
535#else
536 if (fIs64Bit)
537 {
538 continue;
539 }
540#endif
541
542 // get the object being secured that we are planning to schedule rollback for
543 hr = WcaGetRecordString(hRec, QSO_SECUREOBJECT, &pwzSecureObject);
544 ExitOnFailure(hr, "failed to get name of object");
545
546 hr = GetTargetPath(eType, pwzSecureObject, &pwzTargetPath);
547 ExitOnFailure(hr, "failed to get target path of object '%ls' in order to schedule rollback", pwzSecureObject);
548
549 hr = StoreACLRollbackInfo(pwzTargetPath, pwzTable);
550 if (FAILED(hr))
551 {
552 WcaLog(LOGMSG_STANDARD, "Failed to store ACL rollback information with error 0x%x - continuing", hr);
553 }
554 }
555
556 // if we looped through all records all is well
557 if (E_NOMOREITEMS == hr)
558 {
559 hr = S_OK;
560 }
561 ExitOnFailure(hr, "failed while looping through all objects to schedule rollback for");
562
563LExit:
564 ReleaseStr(pwzCustomActionData);
565 ReleaseStr(pwzSecureObject);
566 ReleaseStr(pwzTable);
567 ReleaseStr(pwzTargetPath);
568
569 if (FAILED(hr))
570 {
571 er = ERROR_INSTALL_FAILURE;
572 }
573 return WcaFinalize(er);
574}
575
576/******************************************************************
577 CaExecSecureObjects - entry point for SecureObjects Custom Action
578 called as Type 1025 CustomAction (deferred binary DLL)
579
580 NOTE: deferred CustomAction since it modifies the machine
581 NOTE: CustomActionData == wzObject\twzTable\twzDomain\twzUser\tdwAttributes\tdwPermissions\t...
582******************************************************************/
583extern "C" UINT __stdcall ExecSecureObjects(
584 __in MSIHANDLE hInstall
585 )
586{
587// AssertSz(FALSE, "debug ExecSecureObjects");
588 HRESULT hr = S_OK;
589 DWORD er = ERROR_SUCCESS;
590
591 LPWSTR pwz = NULL;
592 LPWSTR pwzData = NULL;
593 LPWSTR pwzObject = NULL;
594 LPWSTR pwzTable = NULL;
595 LPWSTR pwzDomain = NULL;
596 DWORD dwRevision = 0;
597 LPWSTR pwzUser = NULL;
598 DWORD dwPermissions = 0;
599 DWORD dwAttributes = 0;
600 LPWSTR pwzAccount = NULL;
601 PSID psid = NULL;
602
603 EXPLICIT_ACCESSW ea = {0};
604 SE_OBJECT_TYPE objectType = SE_UNKNOWN_OBJECT_TYPE;
605 PSECURITY_DESCRIPTOR psd = NULL;
606 SECURITY_DESCRIPTOR_CONTROL sdc = {0};
607 SECURITY_INFORMATION si = {0};
608 PACL pAclExisting = NULL; // doesn't get freed
609 PACL pAclNew = NULL;
610
611 PMSIHANDLE hActionRec = ::MsiCreateRecord(1);
612
613 //
614 // initialize
615 //
616 hr = WcaInitialize(hInstall, "ExecSecureObjects");
617 ExitOnFailure(hr, "failed to initialize");
618
619 hr = WcaGetProperty(L"CustomActionData", &pwzData);
620 ExitOnFailure(hr, "failed to get CustomActionData");
621
622 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData);
623
624 pwz = pwzData;
625
626 //
627 // loop through all the passed in data
628 //
629 while (pwz && *pwz)
630 {
631 hr = WcaReadStringFromCaData(&pwz, &pwzObject);
632 ExitOnFailure(hr, "failed to process CustomActionData");
633
634 hr = WcaReadStringFromCaData(&pwz, &pwzTable);
635 ExitOnFailure(hr, "failed to process CustomActionData");
636 hr = WcaReadStringFromCaData(&pwz, &pwzDomain);
637 ExitOnFailure(hr, "failed to process CustomActionData");
638 hr = WcaReadStringFromCaData(&pwz, &pwzUser);
639 ExitOnFailure(hr, "failed to process CustomActionData");
640 hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&dwAttributes));
641 ExitOnFailure(hr, "failed to process CustomActionData");
642 hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&dwPermissions));
643 ExitOnFailure(hr, "failed to process CustomActionData");
644
645 WcaLog(LOGMSG_VERBOSE, "Securing Object: %ls Type: %ls User: %ls", pwzObject, pwzTable, pwzUser);
646
647 //
648 // create the appropriate SID
649 //
650
651 // figure out the right user to put into the access block
652 if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"Everyone"))
653 {
654 hr = AclGetWellKnownSid(WinWorldSid, &psid);
655 }
656 else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"Administrators"))
657 {
658 hr = AclGetWellKnownSid(WinBuiltinAdministratorsSid, &psid);
659 }
660 else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"LocalSystem"))
661 {
662 hr = AclGetWellKnownSid(WinLocalSystemSid, &psid);
663 }
664 else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"LocalService"))
665 {
666 hr = AclGetWellKnownSid(WinLocalServiceSid, &psid);
667 }
668 else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"NetworkService"))
669 {
670 hr = AclGetWellKnownSid(WinNetworkServiceSid, &psid);
671 }
672 else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"AuthenticatedUser"))
673 {
674 hr = AclGetWellKnownSid(WinAuthenticatedUserSid, &psid);
675 }
676 else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"Guests"))
677 {
678 hr = AclGetWellKnownSid(WinBuiltinGuestsSid, &psid);
679 }
680 else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"CREATOR OWNER"))
681 {
682 hr = AclGetWellKnownSid(WinCreatorOwnerSid, &psid);
683 }
684 else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"INTERACTIVE"))
685 {
686 hr = AclGetWellKnownSid(WinInteractiveSid, &psid);
687 }
688 else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"Users"))
689 {
690 hr = AclGetWellKnownSid(WinBuiltinUsersSid, &psid);
691 }
692 else
693 {
694 hr = StrAllocFormatted(&pwzAccount, L"%s%s%s", pwzDomain, *pwzDomain ? L"\\" : L"", pwzUser);
695 ExitOnFailure(hr, "failed to build domain user name");
696
697 hr = AclGetAccountSid(NULL, pwzAccount, &psid);
698 }
699 ExitOnFailure(hr, "failed to get sid for account: %ls%ls%ls", pwzDomain, *pwzDomain ? L"\\" : L"", pwzUser);
700
701 //
702 // build up the explicit access
703 //
704 ea.grfAccessMode = SET_ACCESS;
705
706 if (dwAttributes & SECURE_OBJECT_ATTRIBUTE_INHERITABLE)
707 {
708 ea.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
709 }
710 else
711 {
712 ea.grfInheritance = NO_INHERITANCE;
713 }
714
715#pragma prefast(push)
716#pragma prefast(disable:25029)
717 ::BuildTrusteeWithSidW(&ea.Trustee, psid);
718#pragma prefast(pop)
719
720 objectType = SEObjectTypeFromString(const_cast<LPCWSTR> (pwzTable));
721
722 // always add these permissions for services
723 // these are basic permissions that are often forgotten
724 if (0 == lstrcmpW(L"ServiceInstall", pwzTable))
725 {
726 dwPermissions |= SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_INTERROGATE;
727 }
728
729 ea.grfAccessPermissions = dwPermissions;
730
731 if (SE_UNKNOWN_OBJECT_TYPE != objectType)
732 {
733 er = ::GetNamedSecurityInfoW(pwzObject, objectType, DACL_SECURITY_INFORMATION, NULL, NULL, &pAclExisting, NULL, &psd);
734 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "failed to get security info for object: %ls", pwzObject);
735
736 //Need to see if DACL is protected so getting Descriptor information
737 if (!::GetSecurityDescriptorControl(psd, &sdc, &dwRevision))
738 {
739 ExitOnLastError(hr, "failed to get security descriptor control for object: %ls", pwzObject);
740 }
741
742#pragma prefast(push)
743#pragma prefast(disable:25029)
744 er = ::SetEntriesInAclW(1, &ea, pAclExisting, &pAclNew);
745#pragma prefast(pop)
746 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "failed to add ACLs for object: %ls", pwzObject);
747
748 if (sdc & SE_DACL_PROTECTED)
749 {
750 si = DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION;
751 }
752 else
753 {
754 si = DACL_SECURITY_INFORMATION;
755 }
756 er = ::SetNamedSecurityInfoW(pwzObject, objectType, si, NULL, NULL, pAclNew, NULL);
757 MessageExitOnFailure(hr = HRESULT_FROM_WIN32(er), msierrSecureObjectsFailedSet, "failed to set security info for object: %ls", pwzObject);
758 }
759 else
760 {
761 MessageExitOnFailure(hr = E_UNEXPECTED, msierrSecureObjectsUnknownType, "unknown object type: %ls", pwzTable);
762 }
763
764 hr = WcaProgressMessage(COST_SECUREOBJECT, FALSE);
765 ExitOnFailure(hr, "failed to send progress message");
766
767 objectType = SE_UNKNOWN_OBJECT_TYPE;
768 }
769
770LExit:
771 ReleaseStr(pwzUser);
772 ReleaseStr(pwzDomain);
773 ReleaseStr(pwzTable);
774 ReleaseStr(pwzObject);
775 ReleaseStr(pwzData);
776 ReleaseStr(pwzAccount);
777
778 if (pAclNew)
779 {
780 ::LocalFree(pAclNew);
781 }
782 if (psd)
783 {
784 ::LocalFree(psd);
785 }
786 if (psid)
787 {
788 AclFreeSid(psid);
789 }
790
791 if (FAILED(hr))
792 {
793 er = ERROR_INSTALL_FAILURE;
794 }
795 return WcaFinalize(er);
796}
797
798extern "C" UINT __stdcall ExecSecureObjectsRollback(
799 __in MSIHANDLE hInstall
800 )
801{
802// AssertSz(FALSE, "debug ExecSecureObjectsRollback");
803 HRESULT hr = S_OK;
804 DWORD er = ERROR_SUCCESS;
805
806 LPWSTR pwz = NULL;
807 LPWSTR pwzData = NULL;
808 LPWSTR pwzObject = NULL;
809 LPWSTR pwzTable = NULL;
810 LPWSTR pwzSecurityInfo = NULL;
811
812 SE_OBJECT_TYPE objectType = SE_UNKNOWN_OBJECT_TYPE;
813 PSECURITY_DESCRIPTOR psd = NULL;
814 ULONG psdSize;
815 SECURITY_DESCRIPTOR_CONTROL sdc = {0};
816 SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
817 PACL pDacl = NULL;
818 BOOL bDaclPresent = false;
819 BOOL bDaclDefaulted = false;
820 DWORD dwRevision = 0;
821 int iProtected;
822
823 // initialize
824 hr = WcaInitialize(hInstall, "ExecSecureObjectsRollback");
825 ExitOnFailure(hr, "failed to initialize");
826
827 hr = WcaGetProperty(L"CustomActionData", &pwzData);
828 ExitOnFailure(hr, "failed to get CustomActionData");
829
830 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData);
831
832 pwz = pwzData;
833
834 hr = WcaReadStringFromCaData(&pwz, &pwzObject);
835 ExitOnFailure(hr, "failed to process CustomActionData");
836
837 hr = WcaReadStringFromCaData(&pwz, &pwzTable);
838 ExitOnFailure(hr, "failed to process CustomActionData");
839
840 objectType = SEObjectTypeFromString(const_cast<LPCWSTR> (pwzTable));
841
842 if (SE_UNKNOWN_OBJECT_TYPE != objectType)
843 {
844 hr = WcaReadStringFromCaData(&pwz, &pwzSecurityInfo);
845 ExitOnFailure(hr, "failed to process CustomActionData");
846
847 hr = WcaReadIntegerFromCaData(&pwz, &iProtected);
848 ExitOnFailure(hr, "failed to process CustomActionData");
849
850 if (!::ConvertStringSecurityDescriptorToSecurityDescriptorW(pwzSecurityInfo,SDDL_REVISION_1,&psd,&psdSize))
851 {
852 ExitOnLastError(hr, "failed to convert security descriptor string to a valid security descriptor");
853 }
854
855 if (!::GetSecurityDescriptorDacl(psd,&bDaclPresent,&pDacl,&bDaclDefaulted))
856 {
857 hr = E_UNEXPECTED;
858 ExitOnFailure(hr, "failed to get security descriptor's DACL - error code: %d",pwzSecurityInfo,GetLastError());
859 }
860
861 // The below situation may always be caught by the above if block - the documentation isn't very clear. To be safe, we're going to test for it.
862 if (!bDaclPresent)
863 {
864 hr = E_UNEXPECTED;
865 ExitOnFailure(hr, "security descriptor does not contain a DACL");
866 }
867
868 //Need to see if DACL is protected so getting Descriptor information
869 if (!::GetSecurityDescriptorControl(psd, &sdc, &dwRevision))
870 {
871 ExitOnLastError(hr, "failed to get security descriptor control for object: %ls", pwzObject);
872 }
873
874 // Write a 1 if DACL is protected, 0 otherwise
875 switch (iProtected)
876 {
877 case 0:
878 // Unnecessary to do anything - leave si to the default flags
879 break;
880
881 case 1:
882 si = si | PROTECTED_DACL_SECURITY_INFORMATION;
883 break;
884
885 default:
886 hr = E_UNEXPECTED;
887 ExitOnFailure(hr, "unrecognized value in CustomActionData");
888 break;
889 }
890
891 er = ::SetNamedSecurityInfoW(pwzObject, objectType, si, NULL, NULL, pDacl, NULL);
892 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "failed to set security info for object: %ls error code: %d", pwzObject, GetLastError());
893 }
894 else
895 {
896 MessageExitOnFailure(hr = E_UNEXPECTED, msierrSecureObjectsUnknownType, "unknown object type: %ls", pwzTable);
897 }
898
899LExit:
900 ReleaseStr(pwzData);
901 ReleaseStr(pwzObject);
902 ReleaseStr(pwzTable);
903 ReleaseStr(pwzSecurityInfo);
904
905 if (psd)
906 {
907 ::LocalFree(psd);
908 }
909
910 if (FAILED(hr))
911 {
912 er = ERROR_INSTALL_FAILURE;
913 }
914 return WcaFinalize(er);
915}
diff --git a/src/ext/Util/ca/serviceconfig.cpp b/src/ext/Util/ca/serviceconfig.cpp
new file mode 100644
index 00000000..04b25ffa
--- /dev/null
+++ b/src/ext/Util/ca/serviceconfig.cpp
@@ -0,0 +1,821 @@
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// structs
6LPCWSTR wzQUERY_SERVICECONFIG = L"SELECT `ServiceName`, `Component_`, `NewService`, `FirstFailureActionType`, `SecondFailureActionType`, `ThirdFailureActionType`, `ResetPeriodInDays`, `RestartServiceDelayInSeconds`, `ProgramCommandLine`, `RebootMessage` FROM `Wix4ServiceConfig`";
7enum eQUERY_SERVICECONFIG { QSC_SERVICENAME = 1, QSC_COMPONENT, QSC_NEWSERVICE, QSC_FIRSTFAILUREACTIONTYPE, QSC_SECONDFAILUREACTIONTYPE, QSC_THIRDFAILUREACTIONTYPE, QSC_RESETPERIODINDAYS, QSC_RESTARTSERVICEDELAYINSECONDS, QSC_PROGRAMCOMMANDLINE, QSC_REBOOTMESSAGE };
8
9// consts
10LPCWSTR c_wzActionTypeNone = L"none";
11LPCWSTR c_wzActionTypeReboot = L"reboot";
12LPCWSTR c_wzActionTypeRestart = L"restart";
13LPCWSTR c_wzActionTypeRunCommand = L"runCommand";
14
15// prototypes
16static SC_ACTION_TYPE GetSCActionType(
17 __in LPCWSTR pwzActionTypeName
18 );
19
20static HRESULT GetSCActionTypeString(
21 __in SC_ACTION_TYPE type,
22 __out_ecount(cchActionTypeString) LPWSTR wzActionTypeString,
23 __in DWORD cchActionTypeString
24 );
25
26static HRESULT GetService(
27 __in SC_HANDLE hSCM,
28 __in LPCWSTR wzService,
29 __in DWORD dwOpenServiceAccess,
30 __out SC_HANDLE* phService
31 );
32
33static HRESULT ConfigureService(
34 __in SC_HANDLE hSCM,
35 __in SC_HANDLE hService,
36 __in LPCWSTR wzServiceName,
37 __in DWORD dwRestartServiceDelayInSeconds,
38 __in LPCWSTR wzFirstFailureActionType,
39 __in LPCWSTR wzSecondFailureActionType,
40 __in LPCWSTR wzThirdFailureActionType,
41 __in DWORD dwResetPeriodInDays,
42 __in LPWSTR wzRebootMessage,
43 __in LPWSTR wzProgramCommandLine
44 );
45
46
47/******************************************************************
48SchedServiceConfig - entry point for SchedServiceConfig Custom Action
49
50called as Type 1 CustomAction (binary DLL) from Windows Installer
51in InstallExecuteSequence before CaExecServiceConfig
52********************************************************************/
53extern "C" UINT __stdcall SchedServiceConfig(
54 __in MSIHANDLE hInstall
55 )
56{
57 //AssertSz(FALSE, "debug SchedServiceConfig");
58 HRESULT hr = S_OK;
59 UINT er = ERROR_SUCCESS;
60
61 LPWSTR pwzScriptKey = NULL;
62 LPWSTR pwzCustomActionData = NULL;
63
64 PMSIHANDLE hView = NULL;
65 PMSIHANDLE hRec = NULL;
66 LPWSTR pwzData = NULL;
67 int iData = 0;
68 DWORD cServices = 0;
69
70 // initialize
71 hr = WcaInitialize(hInstall, "SchedServiceConfig");
72 ExitOnFailure(hr, "Failed to initialize.");
73
74 // Get the script key for this CustomAction and put it on the front of the
75 // CustomActionData of the install action.
76 hr = WcaCaScriptCreateKey(&pwzScriptKey);
77 ExitOnFailure(hr, "Failed to get encoding key.");
78
79 hr = WcaWriteStringToCaData(pwzScriptKey, &pwzCustomActionData);
80 ExitOnFailure(hr, "Failed to add encoding key to CustomActionData.");
81
82 // Loop through all the services to be configured.
83 hr = WcaOpenExecuteView(wzQUERY_SERVICECONFIG, &hView);
84 ExitOnFailure(hr, "Failed to open view on Wix4ServiceConfig table.");
85
86 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
87 {
88 INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN;
89 INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN;
90
91 // Get component name to check if we are installing it. If so
92 // then add the table data to the CustomActionData, otherwise
93 // skip it.
94 hr = WcaGetRecordString(hRec, QSC_COMPONENT, &pwzData);
95 ExitOnFailure(hr, "Failed to get component name");
96
97 hr = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction);
98 ExitOnFailure(hr = HRESULT_FROM_WIN32(hr), "Failed to get install state for Component: %ls", pwzData);
99
100 if (WcaIsInstalling(isInstalled, isAction))
101 {
102 // Add the data to the CustomActionData (for install).
103 hr = WcaGetRecordFormattedString(hRec, QSC_SERVICENAME, &pwzData);
104 ExitOnFailure(hr, "Failed to get name of service.");
105 hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
106 ExitOnFailure(hr, "Failed to add name to CustomActionData.");
107
108 hr = WcaGetRecordInteger(hRec, QSC_NEWSERVICE, &iData);
109 ExitOnFailure(hr, "Failed to get Wix4ServiceConfig.NewService.");
110 hr = WcaWriteIntegerToCaData(0 != iData, &pwzCustomActionData);
111 ExitOnFailure(hr, "Failed to add NewService data to CustomActionData");
112
113 hr = WcaGetRecordString(hRec, QSC_FIRSTFAILUREACTIONTYPE, &pwzData);
114 ExitOnFailure(hr, "failed to get first failure action type");
115 hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
116 ExitOnFailure(hr, "failed to add data to CustomActionData");
117
118 hr = WcaGetRecordString(hRec, QSC_SECONDFAILUREACTIONTYPE, &pwzData);
119 ExitOnFailure(hr, "failed to get second failure action type");
120 hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
121 ExitOnFailure(hr, "failed to add data to CustomActionData");
122
123 hr = WcaGetRecordString(hRec, QSC_THIRDFAILUREACTIONTYPE, &pwzData);
124 ExitOnFailure(hr, "failed to get third failure action type");
125 hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
126 ExitOnFailure(hr, "failed to add data to CustomActionData");
127
128 hr = WcaGetRecordInteger(hRec, QSC_RESETPERIODINDAYS, &iData);
129 if (S_FALSE == hr) // deal w/ possible null value
130 {
131 iData = 0;
132 }
133 ExitOnFailure(hr, "failed to get reset period in days between service restart attempts.");
134 hr = WcaWriteIntegerToCaData(iData, &pwzCustomActionData);
135 ExitOnFailure(hr, "failed to add data to CustomActionData");
136
137 hr = WcaGetRecordInteger(hRec, QSC_RESTARTSERVICEDELAYINSECONDS, &iData);
138 if (S_FALSE == hr) // deal w/ possible null value
139 {
140 iData = 0;
141 }
142 ExitOnFailure(hr, "failed to get server restart delay value.");
143 hr = WcaWriteIntegerToCaData(iData, &pwzCustomActionData);
144 ExitOnFailure(hr, "failed to add data to CustomActionData");
145
146 hr = WcaGetRecordFormattedString(hRec, QSC_PROGRAMCOMMANDLINE, &pwzData); // null value already dealt w/ properly
147 ExitOnFailure(hr, "failed to get command line to run on service failure.");
148 hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
149 ExitOnFailure(hr, "failed to add data to CustomActionData");
150
151 hr = WcaGetRecordString(hRec, QSC_REBOOTMESSAGE, &pwzData); // null value already dealt w/ properly
152 ExitOnFailure(hr, "failed to get message to send to users when server reboots due to service failure.");
153 hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
154 ExitOnFailure(hr, "failed to add data to CustomActionData");
155
156 ++cServices;
157 }
158 }
159
160 // if we looped through all records all is well
161 if (E_NOMOREITEMS == hr)
162 {
163 hr = S_OK;
164 }
165 ExitOnFailure(hr, "failed while looping through all objects to secure");
166
167 // setup CustomActionData and add to progress bar for download
168 if (0 < cServices)
169 {
170 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackServiceConfig"), pwzScriptKey, cServices * COST_SERVICECONFIG);
171 ExitOnFailure(hr, "failed to schedule RollbackServiceConfig action");
172
173 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecServiceConfig"), pwzCustomActionData, cServices * COST_SERVICECONFIG);
174 ExitOnFailure(hr, "failed to schedule ExecServiceConfig action");
175 }
176
177LExit:
178 ReleaseStr(pwzData);
179 ReleaseStr(pwzCustomActionData);
180 ReleaseStr(pwzScriptKey);
181
182 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
183 return WcaFinalize(er);
184}
185
186
187/******************************************************************
188CaExecServiceConfig - entry point for ServiceConfig Custom Action.
189
190NOTE: deferred CustomAction since it modifies the machine
191NOTE: CustomActionData == wzServiceName\tfNewService\twzFirstFailureActionType\twzSecondFailureActionType\twzThirdFailureActionType\tdwResetPeriodInDays\tdwRestartServiceDelayInSeconds\twzProgramCommandLine\twzRebootMessage\twzServiceName\tfNewService\t...
192*******************************************************************/
193extern "C" UINT __stdcall ExecServiceConfig(
194 __in MSIHANDLE hInstall
195 )
196{
197 //AssertSz(FALSE, "debug ExecServiceConfig");
198 HRESULT hr = S_OK;
199 DWORD er = 0;
200
201 LPWSTR pwzCustomActionData = NULL;
202 LPWSTR pwz = NULL;
203
204 LPWSTR pwzScriptKey = NULL;
205 WCA_CASCRIPT_HANDLE hRollbackScript = NULL;
206
207 LPWSTR pwzServiceName = NULL;
208 BOOL fNewService = FALSE;
209 LPWSTR pwzFirstFailureActionType = NULL;
210 LPWSTR pwzSecondFailureActionType = NULL;
211 LPWSTR pwzThirdFailureActionType = NULL;
212 LPWSTR pwzProgramCommandLine = NULL;
213 LPWSTR pwzRebootMessage = NULL;
214 DWORD dwResetPeriodInDays = 0;
215 DWORD dwRestartServiceDelayInSeconds = 0;
216
217 LPVOID lpMsgBuf = NULL;
218 SC_HANDLE hSCM = NULL;
219 SC_HANDLE hService = NULL;
220
221 DWORD dwRestartDelay = 0;
222 WCHAR wzActionName[32] = { 0 };
223
224 DWORD cbExistingServiceConfig = 0;
225
226 SERVICE_FAILURE_ACTIONSW* psfa = NULL;
227
228 // initialize
229 hr = WcaInitialize(hInstall, "ExecServiceConfig");
230 ExitOnFailure(hr, "failed to initialize");
231
232 // Open the Services Control Manager up front.
233 hSCM = ::OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
234 if (NULL == hSCM)
235 {
236 er = ::GetLastError();
237 hr = HRESULT_FROM_WIN32(er);
238
239#pragma prefast(push)
240#pragma prefast(disable:25028)
241 ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, er, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpMsgBuf, 0, NULL);
242#pragma prefast(pop)
243
244 ExitOnFailure(hr, "Failed to get handle to SCM. Error: %ls", (LPWSTR)lpMsgBuf);
245 }
246
247 // First, get the script key out of the CustomActionData and
248 // use that to create the rollback script for this action.
249 hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData);
250 ExitOnFailure(hr, "failed to get CustomActionData");
251
252 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData);
253
254 pwz = pwzCustomActionData;
255
256 hr = WcaReadStringFromCaData(&pwz, &pwzScriptKey);
257 if (!pwzScriptKey)
258 {
259 hr = E_UNEXPECTED;
260 ExitOnFailure(hr, "Failed due to unexpected CustomActionData passed.");
261 }
262 ExitOnFailure(hr, "Failed to read encoding key from CustomActionData.");
263
264 hr = WcaCaScriptCreate(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, FALSE, &hRollbackScript);
265 ExitOnFailure(hr, "Failed to open rollback CustomAction script.");
266
267 // Next, loop through the rest of the CustomActionData, processing
268 // each service config row in turn.
269 while (pwz && *pwz)
270 {
271 hr = WcaReadStringFromCaData(&pwz, &pwzServiceName);
272 ExitOnFailure(hr, "failed to process CustomActionData");
273 hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&fNewService));
274 ExitOnFailure(hr, "failed to process CustomActionData");
275 hr = WcaReadStringFromCaData(&pwz, &pwzFirstFailureActionType);
276 ExitOnFailure(hr, "failed to process CustomActionData");
277 hr = WcaReadStringFromCaData(&pwz, &pwzSecondFailureActionType);
278 ExitOnFailure(hr, "failed to process CustomActionData");
279 hr = WcaReadStringFromCaData(&pwz, &pwzThirdFailureActionType);
280 ExitOnFailure(hr, "failed to process CustomActionData");
281 hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&dwResetPeriodInDays));
282 ExitOnFailure(hr, "failed to process CustomActionData");
283 hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&dwRestartServiceDelayInSeconds));
284 ExitOnFailure(hr, "failed to process CustomActionData");
285 hr = WcaReadStringFromCaData(&pwz, &pwzProgramCommandLine);
286 ExitOnFailure(hr, "failed to process CustomActionData");
287 hr = WcaReadStringFromCaData(&pwz, &pwzRebootMessage);
288 ExitOnFailure(hr, "failed to process CustomActionData");
289
290 WcaLog(LOGMSG_VERBOSE, "Configuring Service: %ls", pwzServiceName);
291
292 // Open the handle with all the permissions we might need:
293 // SERVICE_QUERY_CONFIG is needed for QueryServiceConfig2().
294 // SERVICE_CHANGE_CONFIG is needed for ChangeServiceConfig2().
295 // SERVICE_START is required in order to handle SC_ACTION_RESTART action.
296 hr = GetService(hSCM, pwzServiceName, SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | SERVICE_START, &hService);
297 ExitOnFailure(hr, "Failed to get service: %ls", pwzServiceName);
298
299 // If we are configuring a service that existed on the machine, we need to
300 // read the existing service configuration and write it out to the rollback
301 // log so rollback can put it back if anything goes wrong.
302 if (!fNewService)
303 {
304 // First, read the existing service config.
305 if (!::QueryServiceConfig2W(hService, SERVICE_CONFIG_FAILURE_ACTIONS, NULL, 0, &cbExistingServiceConfig) && ERROR_INSUFFICIENT_BUFFER != ::GetLastError())
306 {
307 ExitWithLastError(hr, "Failed to get current service config info.");
308 }
309
310 psfa = static_cast<LPSERVICE_FAILURE_ACTIONSW>(MemAlloc(cbExistingServiceConfig, TRUE));
311 ExitOnNull(psfa, hr, E_OUTOFMEMORY, "failed to allocate memory for service failure actions.");
312
313 if (!::QueryServiceConfig2W(hService, SERVICE_CONFIG_FAILURE_ACTIONS, (LPBYTE)psfa, cbExistingServiceConfig, &cbExistingServiceConfig))
314 {
315 ExitOnLastError(hr, "failed to Query Service.");
316 }
317
318 // Build up rollback log so we can restore service state if necessary
319 hr = WcaCaScriptWriteString(hRollbackScript, pwzServiceName);
320 ExitOnFailure(hr, "Failed to add service name to Rollback Log");
321
322 // If this service struct is empty, fill in default values
323 if (3 > psfa->cActions)
324 {
325 hr = WcaCaScriptWriteString(hRollbackScript, c_wzActionTypeNone);
326 ExitOnFailure(hr, "failed to add data to Rollback CustomActionData");
327
328 hr = WcaCaScriptWriteString(hRollbackScript, c_wzActionTypeNone);
329 ExitOnFailure(hr, "failed to add data to Rollback CustomActionData");
330
331 hr = WcaCaScriptWriteString(hRollbackScript, c_wzActionTypeNone);
332 ExitOnFailure(hr, "failed to add data to Rollback CustomActionData");
333 }
334 else
335 {
336 // psfa actually had actions defined, so use the first three.
337 for (int i = 0; i < 3; ++i)
338 {
339 hr = GetSCActionTypeString(psfa->lpsaActions[i].Type, wzActionName, countof(wzActionName));
340 ExitOnFailure(hr, "failed to query SFA object");
341
342 if (SC_ACTION_RESTART == psfa->lpsaActions[i].Type)
343 {
344 dwRestartDelay = psfa->lpsaActions[i].Delay / 1000;
345 }
346
347 hr = WcaCaScriptWriteString(hRollbackScript, wzActionName);
348 ExitOnFailure(hr, "failed to add data to Rollback CustomActionData");
349 }
350 }
351
352 hr = WcaCaScriptWriteNumber(hRollbackScript, psfa->dwResetPeriod / (24 * 60 * 60));
353 ExitOnFailure(hr, "failed to add data to CustomActionData");
354
355 hr = WcaCaScriptWriteNumber(hRollbackScript, dwRestartDelay);
356 ExitOnFailure(hr, "failed to add data to CustomActionData");
357
358 // Handle the null cases.
359 if (!psfa->lpCommand)
360 {
361 psfa->lpCommand = L"";
362 }
363 hr = WcaCaScriptWriteString(hRollbackScript, psfa->lpCommand);
364 ExitOnFailure(hr, "failed to add data to Rollback CustomActionData");
365
366 // Handle the null cases.
367 if (!psfa->lpRebootMsg)
368 {
369 psfa->lpRebootMsg = L"";
370 }
371 hr = WcaCaScriptWriteString(hRollbackScript, psfa->lpRebootMsg);
372 ExitOnFailure(hr, "failed to add data to Rollback CustomActionData");
373
374 // Nudge the system to get all our rollback data written to disk.
375 WcaCaScriptFlush(hRollbackScript);
376
377 ReleaseNullMem(psfa);
378 }
379
380 hr = ConfigureService(hSCM, hService, pwzServiceName, dwRestartServiceDelayInSeconds, pwzFirstFailureActionType,
381 pwzSecondFailureActionType, pwzThirdFailureActionType, dwResetPeriodInDays, pwzRebootMessage, pwzProgramCommandLine);
382 ExitOnFailure(hr, "Failed to configure service: %ls", pwzServiceName);
383
384 hr = WcaProgressMessage(COST_SERVICECONFIG, FALSE);
385 ExitOnFailure(hr, "failed to send progress message");
386
387 // Per-service cleanup
388 ::CloseServiceHandle(hService);
389 hService = NULL;
390 dwResetPeriodInDays = 0;
391 dwRestartServiceDelayInSeconds = 0;
392 }
393
394LExit:
395 WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_PRESERVE);
396
397 if (lpMsgBuf)
398 {
399 ::LocalFree(lpMsgBuf);
400 }
401
402 if (hService)
403 {
404 ::CloseServiceHandle(hService);
405 }
406
407 if (hSCM)
408 {
409 ::CloseServiceHandle(hSCM);
410 }
411
412 ReleaseMem(psfa);
413
414 ReleaseStr(pwzRebootMessage);
415 ReleaseStr(pwzProgramCommandLine);
416 ReleaseStr(pwzThirdFailureActionType);
417 ReleaseStr(pwzSecondFailureActionType);
418 ReleaseStr(pwzFirstFailureActionType);
419 ReleaseStr(pwzServiceName);
420 ReleaseStr(pwzScriptKey);
421 ReleaseStr(pwzCustomActionData);
422
423 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
424 return WcaFinalize(er);
425}
426
427
428/******************************************************************
429RollbackServiceConfig - entry point for ServiceConfig rollback
430 Custom Action.
431
432NOTE: CustomActionScript Data == wzServiceName\twzFirstFailureActionType\twzSecondFailureActionType\twzThirdFailureActionType\tdwResetPeriodInDays\tdwRestartServiceDelayInSeconds\twzProgramCommandLine\twzRebootMessage\twzServiceName\t...
433*******************************************************************/
434extern "C" UINT __stdcall RollbackServiceConfig(
435 __in MSIHANDLE hInstall
436 )
437{
438 //AssertSz(FALSE, "debug RollbackServiceConfig");
439 HRESULT hr = S_OK;
440 DWORD er = 0;
441
442 LPWSTR pwzCustomActionData = NULL;
443 LPWSTR pwz = NULL;
444
445 LPWSTR pwzScriptKey = NULL;
446 WCA_CASCRIPT_HANDLE hRollbackScript = NULL;
447
448 LPWSTR pwzServiceName = NULL;
449 LPWSTR pwzFirstFailureActionType = NULL;
450 LPWSTR pwzSecondFailureActionType = NULL;
451 LPWSTR pwzThirdFailureActionType = NULL;
452 LPWSTR pwzProgramCommandLine = NULL;
453 LPWSTR pwzRebootMessage = NULL;
454 DWORD dwResetPeriodInDays = 0;
455 DWORD dwRestartServiceDelayInSeconds = 0;
456
457 LPVOID lpMsgBuf = NULL;
458 SC_HANDLE hSCM = NULL;
459 SC_HANDLE hService = NULL;
460
461 // initialize
462 hr = WcaInitialize(hInstall, "RollbackServiceConfig");
463 ExitOnFailure(hr, "Failed to initialize 'RollbackServiceConfig'.");
464
465 // Open the Services Control Manager up front.
466 hSCM = ::OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
467 if (NULL == hSCM)
468 {
469 er = ::GetLastError();
470 hr = HRESULT_FROM_WIN32(er);
471
472#pragma prefast(push)
473#pragma prefast(disable:25028)
474 ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, er, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpMsgBuf, 0, NULL);
475#pragma prefast(pop)
476
477 ExitOnFailure(hr, "Failed to get handle to SCM. Error: %ls", (LPWSTR)lpMsgBuf);
478
479 // Make sure we still abort, in case hSCM was NULL but no error was returned from GetLastError
480 ExitOnNull(hSCM, hr, E_POINTER, "Getting handle to SCM reported success, but no handle was returned.");
481 }
482
483 // Get the script key from the CustomAction data and use it to open
484 // the rollback log and read the data over the CustomActionData
485 // because all of the information is in the script data not the
486 // CustomActionData.
487 hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData);
488 ExitOnFailure(hr, "failed to get CustomActionData");
489
490 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData);
491
492 pwz = pwzCustomActionData;
493
494 hr = WcaReadStringFromCaData(&pwz, &pwzScriptKey);
495 if (!pwzScriptKey)
496 {
497 hr = E_UNEXPECTED;
498 ExitOnFailure(hr, "Failed due to unexpected CustomActionData passed.");
499 }
500 ExitOnFailure(hr, "Failed to read encoding key from CustomActionData.");
501
502 hr = WcaCaScriptOpen(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, &hRollbackScript);
503 ExitOnFailure(hr, "Failed to open rollback CustomAction script.");
504
505 hr = WcaCaScriptReadAsCustomActionData(hRollbackScript, &pwzCustomActionData);
506 ExitOnFailure(hr, "Failed to read rollback script into CustomAction data.");
507
508 // Loop through the script's CustomActionData, processing each
509 // service config in turn.
510 pwz = pwzCustomActionData;
511 while (pwz && *pwz)
512 {
513 hr = WcaReadStringFromCaData(&pwz, &pwzServiceName);
514 ExitOnFailure(hr, "failed to process CustomActionData");
515 hr = WcaReadStringFromCaData(&pwz, &pwzFirstFailureActionType);
516 ExitOnFailure(hr, "failed to process CustomActionData");
517 hr = WcaReadStringFromCaData(&pwz, &pwzSecondFailureActionType);
518 ExitOnFailure(hr, "failed to process CustomActionData");
519 hr = WcaReadStringFromCaData(&pwz, &pwzThirdFailureActionType);
520 ExitOnFailure(hr, "failed to process CustomActionData");
521 hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&dwResetPeriodInDays));
522 ExitOnFailure(hr, "failed to process CustomActionData");
523 hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&dwRestartServiceDelayInSeconds));
524 ExitOnFailure(hr, "failed to process CustomActionData");
525 hr = WcaReadStringFromCaData(&pwz, &pwzProgramCommandLine);
526 ExitOnFailure(hr, "failed to process CustomActionData");
527 hr = WcaReadStringFromCaData(&pwz, &pwzRebootMessage);
528 ExitOnFailure(hr, "failed to process CustomActionData");
529
530 WcaLog(LOGMSG_VERBOSE, "Reconfiguring Service: %ls", pwzServiceName);
531
532 // Open the handle with all the permissions we might need.
533 // SERVICE_CHANGE_CONFIG is needed for ChangeServiceConfig2().
534 // SERVICE_START is required in order to handle SC_ACTION_RESTART action.
535 hr = GetService(hSCM, pwzServiceName, SERVICE_CHANGE_CONFIG | SERVICE_START, &hService);
536 ExitOnFailure(hr, "Failed to get service: %ls", pwzServiceName);
537
538 hr = ConfigureService(hSCM, hService, pwzServiceName, dwRestartServiceDelayInSeconds, pwzFirstFailureActionType,
539 pwzSecondFailureActionType, pwzThirdFailureActionType, dwResetPeriodInDays, pwzRebootMessage, pwzProgramCommandLine);
540 ExitOnFailure(hr, "Failed to configure service: %ls", pwzServiceName);
541
542 hr = WcaProgressMessage(COST_SERVICECONFIG, FALSE);
543 ExitOnFailure(hr, "failed to send progress message");
544
545 // Per-service cleanup
546 ::CloseServiceHandle(hService);
547 hService = NULL;
548 dwResetPeriodInDays = 0;
549 dwRestartServiceDelayInSeconds = 0;
550 }
551
552LExit:
553 if (lpMsgBuf) // Allocated with FormatString.
554 {
555 ::LocalFree(lpMsgBuf);
556 }
557
558 if (hService)
559 {
560 ::CloseServiceHandle(hService);
561 }
562
563 if (hSCM)
564 {
565 ::CloseServiceHandle(hSCM);
566 }
567
568 WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_DELETE);
569
570 ReleaseStr(pwzRebootMessage);
571 ReleaseStr(pwzProgramCommandLine);
572 ReleaseStr(pwzThirdFailureActionType);
573 ReleaseStr(pwzSecondFailureActionType);
574 ReleaseStr(pwzFirstFailureActionType);
575 ReleaseStr(pwzServiceName);
576 ReleaseStr(pwzScriptKey);
577 ReleaseStr(pwzCustomActionData);
578
579 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
580 return WcaFinalize(er);
581}
582
583
584/**********************************************************
585GetSCActionType - helper function to return the SC_ACTION_TYPE
586for a given string matching the allowed set.
587REBOOT, RESTART, RUN_COMMAND and NONE
588**********************************************************/
589static SC_ACTION_TYPE GetSCActionType(
590 __in LPCWSTR pwzActionTypeName
591 )
592{
593 SC_ACTION_TYPE actionType;
594
595 // verify that action types are valid. if not, just default to NONE
596 if (0 == lstrcmpiW(c_wzActionTypeReboot, pwzActionTypeName))
597 {
598 actionType = SC_ACTION_REBOOT;
599 }
600 else if (0 == lstrcmpiW(c_wzActionTypeRestart, pwzActionTypeName))
601 {
602 actionType = SC_ACTION_RESTART;
603 }
604 else if (0 == lstrcmpiW(c_wzActionTypeRunCommand, pwzActionTypeName))
605 {
606 actionType = SC_ACTION_RUN_COMMAND;
607 }
608 else
609 {
610 // default to none
611 actionType = SC_ACTION_NONE;
612 }
613
614 return actionType;
615}
616
617
618static HRESULT GetSCActionTypeString(
619 __in SC_ACTION_TYPE type,
620 __out_ecount(cchActionTypeString) LPWSTR wzActionTypeString,
621 __in DWORD cchActionTypeString
622 )
623{
624 HRESULT hr = S_OK;
625
626 switch (type)
627 {
628 case SC_ACTION_REBOOT:
629 hr = StringCchCopyW(wzActionTypeString, cchActionTypeString, c_wzActionTypeReboot);
630 ExitOnFailure(hr, "Failed to copy 'reboot' into action type.");
631 break;
632 case SC_ACTION_RESTART:
633 hr = StringCchCopyW(wzActionTypeString, cchActionTypeString, c_wzActionTypeRestart);
634 ExitOnFailure(hr, "Failed to copy 'restart' into action type.");
635 break;
636 case SC_ACTION_RUN_COMMAND:
637 hr = StringCchCopyW(wzActionTypeString, cchActionTypeString, c_wzActionTypeRunCommand);
638 ExitOnFailure(hr, "Failed to copy 'runCommand' into action type.");
639 break;
640 case SC_ACTION_NONE:
641 hr = StringCchCopyW(wzActionTypeString, cchActionTypeString, c_wzActionTypeNone);
642 ExitOnFailure(hr, "Failed to copy 'none' into action type.");
643 break;
644 default:
645 break;
646 }
647
648LExit:
649 return hr;
650}
651
652
653static HRESULT GetService(
654 __in SC_HANDLE hSCM,
655 __in LPCWSTR wzService,
656 __in DWORD dwOpenServiceAccess,
657 __out SC_HANDLE* phService
658 )
659{
660 HRESULT hr = S_OK;
661 DWORD er = ERROR_SUCCESS;
662 LPVOID lpMsgBuf = NULL;
663
664 *phService = ::OpenServiceW(hSCM, wzService, dwOpenServiceAccess);
665 if (NULL == *phService)
666 {
667 er = ::GetLastError();
668 hr = HRESULT_FROM_WIN32(er);
669 if (ERROR_SERVICE_DOES_NOT_EXIST == er)
670 {
671 ExitOnFailure(hr, "Service '%ls' does not exist on this system.", wzService);
672 }
673 else
674 {
675#pragma prefast(push)
676#pragma prefast(disable:25028)
677 ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, er, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpMsgBuf, 0, NULL);
678#pragma prefast(pop)
679
680 ExitOnFailure(hr, "Failed to get handle to the service '%ls'. Error: %ls", wzService, (LPWSTR)lpMsgBuf);
681 }
682 }
683
684LExit:
685 if (lpMsgBuf) // Allocated with FormatString.
686 {
687 ::LocalFree(lpMsgBuf);
688 }
689
690 return hr;
691}
692
693
694static HRESULT ConfigureService(
695 __in SC_HANDLE /*hSCM*/,
696 __in SC_HANDLE hService,
697 __in LPCWSTR wzServiceName,
698 __in DWORD dwRestartServiceDelayInSeconds,
699 __in LPCWSTR wzFirstFailureActionType,
700 __in LPCWSTR wzSecondFailureActionType,
701 __in LPCWSTR wzThirdFailureActionType,
702 __in DWORD dwResetPeriodInDays,
703 __in LPWSTR wzRebootMessage,
704 __in LPWSTR wzProgramCommandLine
705 )
706{
707 HRESULT hr = S_OK;
708 DWORD er = ERROR_SUCCESS;
709
710 HANDLE hToken = NULL;
711 TOKEN_PRIVILEGES priv = { 0 };
712 TOKEN_PRIVILEGES* pPrevPriv = NULL;
713 DWORD cbPrevPriv = 0;
714 BOOL fAdjustedPrivileges = FALSE;
715
716 SC_ACTION actions[3]; // the UI always shows 3 actions, so we'll always do 3
717 SERVICE_FAILURE_ACTIONSW sfa;
718 LPVOID lpMsgBuf = NULL;
719
720 // Always get the shutdown privilege in case we need to configure service to reboot.
721 if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken))
722 {
723 ExitWithLastError(hr, "Failed to get process token.");
724 }
725
726 priv.PrivilegeCount = 1;
727 priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
728 if (!::LookupPrivilegeValueW(NULL, L"SeShutdownPrivilege", &priv.Privileges[0].Luid))
729 {
730 ExitWithLastError(hr, "Failed to get shutdown privilege LUID.");
731 }
732
733 cbPrevPriv = sizeof(TOKEN_PRIVILEGES);
734 pPrevPriv = static_cast<TOKEN_PRIVILEGES*>(MemAlloc(cbPrevPriv, TRUE));
735 ExitOnNull(pPrevPriv, hr, E_OUTOFMEMORY, "Failed to allocate memory for empty previous privileges.");
736
737 if (!::AdjustTokenPrivileges(hToken, FALSE, &priv, cbPrevPriv, pPrevPriv, &cbPrevPriv))
738 {
739 LPVOID pv = MemReAlloc(pPrevPriv, cbPrevPriv, TRUE);
740 ExitOnNull(pv, hr, E_OUTOFMEMORY, "Failed to allocate memory for previous privileges.");
741 pPrevPriv = static_cast<TOKEN_PRIVILEGES*>(pv);
742
743 if (!::AdjustTokenPrivileges(hToken, FALSE, &priv, cbPrevPriv, pPrevPriv, &cbPrevPriv))
744 {
745 ExitWithLastError(hr, "Failed to get shutdown privilege LUID.");
746 }
747 }
748
749 fAdjustedPrivileges = TRUE;
750
751 // build up SC_ACTION array
752 // TODO: why is delay only respected when SC_ACTION_RESTART is requested?
753 actions[0].Type = GetSCActionType(wzFirstFailureActionType);
754 actions[0].Delay = 0;
755 if (SC_ACTION_RESTART == actions[0].Type)
756 {
757 actions[0].Delay = dwRestartServiceDelayInSeconds * 1000; // seconds to milliseconds
758 }
759
760 actions[1].Type = GetSCActionType(wzSecondFailureActionType);
761 actions[1].Delay = 0;
762 if (SC_ACTION_RESTART == actions[1].Type)
763 {
764 actions[1].Delay = dwRestartServiceDelayInSeconds * 1000; // seconds to milliseconds
765 }
766
767 actions[2].Type = GetSCActionType(wzThirdFailureActionType);
768 actions[2].Delay = 0;
769 if (SC_ACTION_RESTART == actions[2].Type)
770 {
771 actions[2].Delay = dwRestartServiceDelayInSeconds * 1000; // seconds to milliseconds
772 }
773
774 // build up the SERVICE_FAILURE_ACTIONSW struct
775 sfa.dwResetPeriod = dwResetPeriodInDays * (24 * 60 * 60); // days to seconds
776 sfa.lpRebootMsg = wzRebootMessage;
777 sfa.lpCommand = wzProgramCommandLine;
778 sfa.cActions = countof(actions);
779 sfa.lpsaActions = actions;
780
781 // Call ChangeServiceConfig2 to actually set up the failure actions
782 if (!::ChangeServiceConfig2W(hService, SERVICE_CONFIG_FAILURE_ACTIONS, (LPVOID)&sfa))
783 {
784 er = ::GetLastError();
785 hr = HRESULT_FROM_WIN32(er);
786
787#pragma prefast(push)
788#pragma prefast(disable:25028)
789 ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, er, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpMsgBuf, 0, NULL);
790#pragma prefast(pop)
791
792 // Check if this is a service that can't be modified.
793 if (ERROR_CANNOT_DETECT_PROCESS_ABORT == er)
794 {
795 WcaLog(LOGMSG_STANDARD, "WARNING: Service \"%ls\" is not configurable on this server and will not be set.", wzServiceName);
796 }
797 ExitOnFailure(hr, "Cannot change service configuration. Error: %ls", (LPWSTR)lpMsgBuf);
798
799 if (lpMsgBuf)
800 {
801 ::LocalFree(lpMsgBuf);
802 lpMsgBuf = NULL;
803 }
804 }
805
806LExit:
807 if (lpMsgBuf)
808 {
809 ::LocalFree(lpMsgBuf);
810 }
811
812 if (fAdjustedPrivileges)
813 {
814 ::AdjustTokenPrivileges(hToken, FALSE, pPrevPriv, 0, NULL, NULL);
815 }
816
817 ReleaseMem(pPrevPriv);
818 ReleaseHandle(hToken);
819
820 return hr;
821}
diff --git a/src/ext/Util/ca/shellexecca.cpp b/src/ext/Util/ca/shellexecca.cpp
new file mode 100644
index 00000000..ea21d3bd
--- /dev/null
+++ b/src/ext/Util/ca/shellexecca.cpp
@@ -0,0 +1,271 @@
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
5HRESULT ShellExec(
6 __in LPCWSTR wzTarget,
7 __in BOOL fUnelevated
8 )
9{
10 HRESULT hr = S_OK;
11 LPWSTR sczWorkingDirectory = NULL;
12
13 // a reasonable working directory (not the system32 default from MSI) is the directory where the target lives
14 hr = PathGetDirectory(wzTarget, &sczWorkingDirectory);
15 ExitOnFailure(hr, "failed to get directory for target: %ls", wzTarget);
16
17 if (!DirExists(sczWorkingDirectory, NULL))
18 {
19 ReleaseNullStr(sczWorkingDirectory);
20 }
21
22 if (fUnelevated)
23 {
24 hr = ShelExecUnelevated(wzTarget, NULL, NULL, sczWorkingDirectory, SW_SHOWDEFAULT);
25 ExitOnFailure(hr, "ShelExecUnelevated failed with target %ls", wzTarget);
26 }
27 else
28 {
29 HINSTANCE hinst = ::ShellExecuteW(NULL, NULL, wzTarget, NULL, sczWorkingDirectory, SW_SHOWDEFAULT);
30 if (hinst <= HINSTANCE(32))
31 {
32 LONG64 code = reinterpret_cast<LONG64>(hinst);
33 switch (code)
34 {
35 case ERROR_FILE_NOT_FOUND:
36 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
37 break;
38 case ERROR_PATH_NOT_FOUND:
39 hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
40 break;
41 case ERROR_BAD_FORMAT:
42 hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT);
43 break;
44 case SE_ERR_ASSOCINCOMPLETE:
45 case SE_ERR_NOASSOC:
46 hr = HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION);
47 break;
48 case SE_ERR_DDEBUSY:
49 case SE_ERR_DDEFAIL:
50 case SE_ERR_DDETIMEOUT:
51 hr = HRESULT_FROM_WIN32(ERROR_DDE_FAIL);
52 break;
53 case SE_ERR_DLLNOTFOUND:
54 hr = HRESULT_FROM_WIN32(ERROR_DLL_NOT_FOUND);
55 break;
56 case SE_ERR_OOM:
57 hr = E_OUTOFMEMORY;
58 break;
59 case SE_ERR_ACCESSDENIED:
60 hr = E_ACCESSDENIED;
61 break;
62 default:
63 hr = E_FAIL;
64 }
65
66 ExitOnFailure(hr, "ShellExec failed with return code %llu.", code);
67 }
68 }
69
70
71LExit:
72 ReleaseStr(sczWorkingDirectory);
73 return hr;
74}
75
76extern "C" UINT __stdcall WixShellExec(
77 __in MSIHANDLE hInstall
78 )
79{
80 Assert(hInstall);
81 HRESULT hr = S_OK;
82 UINT er = ERROR_SUCCESS;
83 LPWSTR pwzTarget = NULL;
84
85 hr = WcaInitialize(hInstall, "WixShellExec");
86 ExitOnFailure(hr, "failed to initialize");
87
88 hr = WcaGetFormattedProperty(L"WixShellExecTarget", &pwzTarget);
89 ExitOnFailure(hr, "failed to get WixShellExecTarget");
90
91 WcaLog(LOGMSG_VERBOSE, "WixShellExecTarget is %ls", pwzTarget);
92
93 if (!pwzTarget || !*pwzTarget)
94 {
95 hr = E_INVALIDARG;
96 ExitOnFailure(hr, "failed to get WixShellExecTarget");
97 }
98
99 hr = ShellExec(pwzTarget, FALSE);
100 ExitOnFailure(hr, "failed to launch target");
101
102LExit:
103 ReleaseStr(pwzTarget);
104
105 if (FAILED(hr))
106 {
107 er = ERROR_INSTALL_FAILURE;
108 }
109 return WcaFinalize(er);
110}
111
112extern "C" UINT __stdcall WixUnelevatedShellExec(
113 __in MSIHANDLE hInstall
114 )
115{
116 Assert(hInstall);
117 HRESULT hr = S_OK;
118 UINT er = ERROR_SUCCESS;
119 LPWSTR pwzTarget = NULL;
120
121 hr = WcaInitialize(hInstall, "WixUnelevatedShellExec");
122 ExitOnFailure(hr, "failed to initialize");
123
124 hr = WcaGetFormattedProperty(L"WixUnelevatedShellExecTarget", &pwzTarget);
125 ExitOnFailure(hr, "failed to get WixUnelevatedShellExecTarget");
126
127 WcaLog(LOGMSG_VERBOSE, "WixUnelevatedShellExecTarget is %ls", pwzTarget);
128
129 if (!pwzTarget || !*pwzTarget)
130 {
131 hr = E_INVALIDARG;
132 ExitOnFailure(hr, "failed to get WixShellExecTarget");
133 }
134
135 hr = ShellExec(pwzTarget, TRUE);
136 ExitOnFailure(hr, "failed to launch target");
137
138LExit:
139 ReleaseStr(pwzTarget);
140
141 if (FAILED(hr))
142 {
143 er = ERROR_INSTALL_FAILURE;
144 }
145 return WcaFinalize(er);
146}
147
148//
149// ExtractBinary extracts the data from the Binary table row with the given ID into a file.
150//
151HRESULT ExtractBinary(
152 __in LPCWSTR wzBinaryId,
153 __out BYTE** pbData,
154 __out DWORD* pcbData
155 )
156{
157 HRESULT hr = S_OK;
158 LPWSTR pwzSql = NULL;
159 PMSIHANDLE hView;
160 PMSIHANDLE hRec;
161
162 // make sure we're not horked from the get-go
163 hr = WcaTableExists(L"Binary");
164 if (S_OK != hr)
165 {
166 if (SUCCEEDED(hr))
167 {
168 hr = E_UNEXPECTED;
169 }
170 ExitOnFailure(hr, "There is no Binary table.");
171 }
172
173 ExitOnNull(wzBinaryId, hr, E_INVALIDARG, "Binary ID cannot be null");
174 ExitOnNull(*wzBinaryId, hr, E_INVALIDARG, "Binary ID cannot be empty string");
175
176 hr = StrAllocFormatted(&pwzSql, L"SELECT `Data` FROM `Binary` WHERE `Name`=\'%s\'", wzBinaryId);
177 ExitOnFailure(hr, "Failed to allocate Binary table query.");
178
179 hr = WcaOpenExecuteView(pwzSql, &hView);
180 ExitOnFailure(hr, "Failed to open view on Binary table");
181
182 hr = WcaFetchSingleRecord(hView, &hRec);
183 ExitOnFailure(hr, "Failed to retrieve request from Binary table");
184
185 hr = WcaGetRecordStream(hRec, 1, pbData, pcbData);
186 ExitOnFailure(hr, "Failed to read Binary.Data.");
187
188LExit:
189 ReleaseStr(pwzSql);
190
191 return hr;
192}
193
194extern "C" UINT __stdcall WixShellExecBinary(
195 __in MSIHANDLE hInstall
196 )
197{
198 Assert(hInstall);
199 HRESULT hr = S_OK;
200 UINT er = ERROR_SUCCESS;
201 LPWSTR pwzBinary = NULL;
202 LPWSTR pwzFilename = NULL;
203 BYTE* pbData = NULL;
204 DWORD cbData = 0;
205 HANDLE hFile = INVALID_HANDLE_VALUE;
206
207#if 0
208 ::MessageBoxA(0, "WixShellExecBinary", "-->> ATTACH HERE", MB_OK);
209#endif
210
211 hr = WcaInitialize(hInstall, "WixShellExecBinary");
212 ExitOnFailure(hr, "failed to initialize");
213
214 hr = WcaGetFormattedProperty(L"WixShellExecBinaryId", &pwzBinary);
215 ExitOnFailure(hr, "failed to get WixShellExecBinaryId");
216
217 WcaLog(LOGMSG_VERBOSE, "WixShellExecBinaryId is %ls", pwzBinary);
218
219 if (!pwzBinary || !*pwzBinary)
220 {
221 hr = E_INVALIDARG;
222 ExitOnFailure(hr, "failed to get WixShellExecBinaryId");
223 }
224
225 // get temporary path for extracted file
226 StrAlloc(&pwzFilename, MAX_PATH);
227 ExitOnFailure(hr, "Failed to allocate temporary path");
228 ::GetTempPathW(MAX_PATH, pwzFilename);
229 hr = ::StringCchCatW(pwzFilename, MAX_PATH, pwzBinary);
230 ExitOnFailure(hr, "Failed to append filename.");
231
232 // grab the bits
233 hr = ExtractBinary(pwzBinary, &pbData, &cbData);
234 ExitOnFailure(hr, "failed to extract binary data");
235
236 // write 'em to the temp file
237 hFile = ::CreateFileW(pwzFilename, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
238 if (INVALID_HANDLE_VALUE == hFile)
239 {
240 ExitWithLastError(hr, "Failed to open new temp file: %ls", pwzFilename);
241 }
242
243 DWORD cbWritten = 0;
244 if (!::WriteFile(hFile, pbData, cbData, &cbWritten, NULL))
245 {
246 ExitWithLastError(hr, "Failed to write data to new temp file: %ls", pwzFilename);
247 }
248
249 // close it
250 ::CloseHandle(hFile);
251 hFile = INVALID_HANDLE_VALUE;
252
253 // and run it
254 hr = ShellExec(pwzFilename, FALSE);
255 ExitOnFailure(hr, "failed to launch target: %ls", pwzFilename);
256
257LExit:
258 ReleaseStr(pwzBinary);
259 ReleaseStr(pwzFilename);
260 ReleaseMem(pbData);
261 if (INVALID_HANDLE_VALUE != hFile)
262 {
263 ::CloseHandle(hFile);
264 }
265
266 if (FAILED(hr))
267 {
268 er = ERROR_INSTALL_FAILURE;
269 }
270 return WcaFinalize(er);
271}
diff --git a/src/ext/Util/ca/test.cpp b/src/ext/Util/ca/test.cpp
new file mode 100644
index 00000000..c4d215f0
--- /dev/null
+++ b/src/ext/Util/ca/test.cpp
@@ -0,0 +1,269 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5#define WIXCA_UITHREAD_CLASS_WINDOW L"WixCaMessageWindow"
6
7extern HMODULE g_hInstCADLL;
8
9
10// structs
11
12struct UITHREAD_CONTEXT
13{
14 HANDLE hInitializedEvent;
15 HINSTANCE hInstance;
16 HWND hWnd;
17};
18
19
20// internal function declarations
21
22static HRESULT CreateMessageWindow(
23 __out HWND* phWnd
24 );
25
26static void CloseMessageWindow(
27 __in HWND hWnd
28 );
29
30static DWORD WINAPI ThreadProc(
31 __in LPVOID pvContext
32 );
33
34static LRESULT CALLBACK WndProc(
35 __in HWND hWnd,
36 __in UINT uMsg,
37 __in WPARAM wParam,
38 __in LPARAM lParam
39 );
40
41
42/******************************************************************
43WixFailWhenDeferred - entry point for WixFailWhenDeferred
44 custom action which always fails when running as a deferred
45 custom action (otherwise it blindly succeeds). It's useful when
46 testing the rollback of deferred custom actions: Schedule it
47 immediately after the rollback/deferred CA pair you're testing
48 and it will fail, causing your rollback CA to get invoked.
49********************************************************************/
50extern "C" UINT __stdcall WixFailWhenDeferred(
51 __in MSIHANDLE hInstall
52 )
53{
54 return ::MsiGetMode(hInstall, MSIRUNMODE_SCHEDULED) ? ERROR_INSTALL_FAILURE : ERROR_SUCCESS;
55}
56
57/******************************************************************
58WixWaitForEvent - entry point for WixWaitForEvent custom action
59 which waits for either the WixWaitForEventFail or
60 WixWaitForEventSucceed named auto reset events. Signaling the
61 WixWaitForEventFail event will return ERROR_INSTALL_FAILURE or
62 signaling the WixWaitForEventSucceed event will return
63 ERROR_SUCCESS. Both events are declared in the Global\ namespace.
64********************************************************************/
65extern "C" UINT __stdcall WixWaitForEvent(
66 __in MSIHANDLE hInstall
67 )
68{
69 HRESULT hr = S_OK;
70 UINT er = ERROR_SUCCESS;
71 HWND hMessageWindow = NULL;
72 LPCWSTR wzSDDL = L"D:(A;;GA;;;WD)";
73 OS_VERSION version = OS_VERSION_UNKNOWN;
74 DWORD dwServicePack = 0;
75 PSECURITY_DESCRIPTOR pSD = NULL;
76 SECURITY_ATTRIBUTES sa = { };
77 HANDLE rghEvents[2];
78
79 hr = WcaInitialize(hInstall, "WixWaitForEvent");
80 ExitOnFailure(hr, "Failed to initialize.");
81
82 // Create a window to prevent shutdown requests.
83 hr = CreateMessageWindow(&hMessageWindow);
84 ExitOnFailure(hr, "Failed to create message window.");
85
86 // If running on Vista/2008 or newer use integrity enhancements.
87 OsGetVersion(&version, &dwServicePack);
88 if (OS_VERSION_VISTA <= version)
89 {
90 // Add SACL to allow Everyone to signal from a medium integrity level.
91 wzSDDL = L"D:(A;;GA;;;WD)S:(ML;;NW;;;ME)";
92 }
93
94 // Create the security descriptor and attributes for the events.
95 if (!::ConvertStringSecurityDescriptorToSecurityDescriptorW(wzSDDL, SDDL_REVISION_1, &pSD, NULL))
96 {
97 ExitWithLastError(hr, "Failed to create the security descriptor for the events.");
98 }
99
100 sa.nLength = sizeof(sa);
101 sa.lpSecurityDescriptor = pSD;
102 sa.bInheritHandle = FALSE;
103
104 rghEvents[0] = ::CreateEventW(&sa, FALSE, FALSE, L"Global\\WixWaitForEventFail");
105 ExitOnNullWithLastError(rghEvents[0], hr, "Failed to create the Global\\WixWaitForEventFail event.");
106
107 rghEvents[1] = ::CreateEventW(&sa, FALSE, FALSE, L"Global\\WixWaitForEventSucceed");
108 ExitOnNullWithLastError(rghEvents[1], hr, "Failed to create the Global\\WixWaitForEventSucceed event.");
109
110 // Wait for either of the events to be signaled and handle accordingly.
111 er = ::WaitForMultipleObjects(countof(rghEvents), rghEvents, FALSE, INFINITE);
112 switch (er)
113 {
114 case WAIT_OBJECT_0 + 0:
115 er = ERROR_INSTALL_FAILURE;
116 break;
117 case WAIT_OBJECT_0 + 1:
118 er = ERROR_SUCCESS;
119 break;
120 default:
121 ExitOnWin32Error(er, hr, "Unexpected failure.");
122 }
123
124LExit:
125 ReleaseHandle(rghEvents[1]);
126 ReleaseHandle(rghEvents[0]);
127
128 if (pSD)
129 {
130 ::LocalFree(pSD);
131 }
132
133 if (hMessageWindow)
134 {
135 CloseMessageWindow(hMessageWindow);
136 }
137
138 if (FAILED(hr))
139 {
140 er = ERROR_INSTALL_FAILURE;
141 }
142
143 return WcaFinalize(er);
144}
145
146
147// internal function definitions
148
149static HRESULT CreateMessageWindow(
150 __out HWND* phWnd
151 )
152{
153 HRESULT hr = S_OK;
154 HANDLE rgWaitHandles[2] = { };
155 UITHREAD_CONTEXT context = { };
156
157 // Create event to signal after the UI thread / window is initialized.
158 rgWaitHandles[0] = ::CreateEventW(NULL, TRUE, FALSE, NULL);
159 ExitOnNullWithLastError(rgWaitHandles[0], hr, "Failed to create initialization event.");
160
161 // Pass necessary information to create the window.
162 context.hInitializedEvent = rgWaitHandles[0];
163 context.hInstance = (HINSTANCE)g_hInstCADLL;
164
165 // Create our separate UI thread.
166 rgWaitHandles[1] = ::CreateThread(NULL, 0, ThreadProc, &context, 0, NULL);
167 ExitOnNullWithLastError(rgWaitHandles[1], hr, "Failed to create the UI thread.");
168
169 // Wait for either the thread to be initialized or the window to exit / fail prematurely.
170 ::WaitForMultipleObjects(countof(rgWaitHandles), rgWaitHandles, FALSE, INFINITE);
171
172 // Pass the window back to the caller.
173 *phWnd = context.hWnd;
174
175LExit:
176 ReleaseHandle(rgWaitHandles[1]);
177 ReleaseHandle(rgWaitHandles[0]);
178
179 return hr;
180}
181
182static void CloseMessageWindow(
183 __in HWND hWnd
184 )
185{
186 if (::IsWindow(hWnd))
187 {
188 ::PostMessageW(hWnd, WM_CLOSE, 0, 0);
189 }
190}
191
192static DWORD WINAPI ThreadProc(
193 __in LPVOID pvContext
194 )
195{
196 HRESULT hr = S_OK;
197 UITHREAD_CONTEXT* pContext = static_cast<UITHREAD_CONTEXT*>(pvContext);
198
199 WNDCLASSW wc = { };
200 BOOL fRegistered = TRUE;
201 HWND hWnd = NULL;
202
203 BOOL fRet = FALSE;
204 MSG msg = { };
205
206 wc.lpfnWndProc = WndProc;
207 wc.hInstance = pContext->hInstance;
208 wc.lpszClassName = WIXCA_UITHREAD_CLASS_WINDOW;
209
210 if (!::RegisterClassW(&wc))
211 {
212 ExitWithLastError(hr, "Failed to register window.");
213 }
214
215 fRegistered = TRUE;
216
217 // Create the window to handle reboots without activating it.
218 hWnd = ::CreateWindowExW(WS_EX_TOOLWINDOW, wc.lpszClassName, NULL, WS_POPUP | WS_VISIBLE, CW_USEDEFAULT, SW_SHOWNA, 0, 0, HWND_DESKTOP, NULL, pContext->hInstance, NULL);
219 ExitOnNullWithLastError(hWnd, hr, "Failed to create window.");
220
221 // Persist the window handle and let the caller know we've initialized.
222 pContext->hWnd = hWnd;
223 ::SetEvent(pContext->hInitializedEvent);
224
225 // Pump messages until the window is closed.
226 while (0 != (fRet = ::GetMessageW(&msg, NULL, 0, 0)))
227 {
228 if (-1 == fRet)
229 {
230 hr = E_UNEXPECTED;
231 ExitOnFailure(hr, "Unexpected return value from message pump.");
232 }
233 else if (!::IsDialogMessageW(msg.hwnd, &msg))
234 {
235 ::TranslateMessage(&msg);
236 ::DispatchMessageW(&msg);
237 }
238 }
239
240LExit:
241 if (fRegistered)
242 {
243 ::UnregisterClassW(WIXCA_UITHREAD_CLASS_WINDOW, pContext->hInstance);
244 }
245
246 return hr;
247}
248
249static LRESULT CALLBACK WndProc(
250 __in HWND hWnd,
251 __in UINT uMsg,
252 __in WPARAM wParam,
253 __in LPARAM lParam
254 )
255{
256 switch (uMsg)
257 {
258 case WM_QUERYENDSESSION:
259 // Prevent the process from being shut down.
260 WcaLog(LOGMSG_VERBOSE, "Disallowed system request to shut down the custom action server.");
261 return FALSE;
262
263 case WM_DESTROY:
264 ::PostQuitMessage(0);
265 return 0;
266 }
267
268 return ::DefWindowProcW(hWnd, uMsg, wParam, lParam);
269}
diff --git a/src/ext/Util/ca/utilca.cpp b/src/ext/Util/ca/utilca.cpp
new file mode 100644
index 00000000..37664a1c
--- /dev/null
+++ b/src/ext/Util/ca/utilca.cpp
@@ -0,0 +1,3 @@
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"
diff --git a/src/ext/Util/ca/utilca.def b/src/ext/Util/ca/utilca.def
new file mode 100644
index 00000000..412d86a3
--- /dev/null
+++ b/src/ext/Util/ca/utilca.def
@@ -0,0 +1,91 @@
1; Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3
4LIBRARY "utilca"
5
6EXPORTS
7; BroadcastSettingChange.cpp
8 WixBroadcastSettingChange
9 WixBroadcastEnvironmentChange
10; checkreboot.cpp
11 WixCheckRebootRequired
12; closeapps.cpp
13 WixCloseApplications
14 WixCloseApplicationsDeferred
15; exitearlywithsuccess.cpp
16 WixExitEarlyWithSuccess
17; FormatFiles.cpp
18 WixSchedFormatFiles
19 WixExecFormatFiles
20; osinfo.cpp
21 WixQueryOsInfo
22 WixQueryOsDirs
23 WixQueryOsWellKnownSID
24 WixQueryOsDriverInfo
25; netshortcuts.cpp
26 WixSchedInternetShortcuts
27 WixCreateInternetShortcuts
28 WixRollbackInternetShortcuts
29; qtexecca.cpp
30 CAQuietExec
31 CAQuietExec64
32 WixQuietExec
33 WixQuietExec64
34 WixSilentExec
35 WixSilentExec64
36; RemoveFoldersEx.cpp
37 WixRemoveFoldersEx
38; RemoveRegistryKeysEx.cpp
39 WixRemoveRegistryKeysEx
40;scaexec.cpp
41 RegisterPerfCounterData
42 UnregisterPerfCounterData
43 RegisterPerfmon
44 UnregisterPerfmon
45 CreateSmb
46 DropSmb
47 CreateUser
48 CreateUserRollback
49 RemoveUser
50;scasched.cpp
51 ConfigurePerfmonInstall
52 ConfigurePerfmonUninstall
53 ConfigureSmbInstall
54 ConfigureSmbUninstall
55 ConfigureUsers
56 InstallPerfCounterData
57 UninstallPerfCounterData
58 ConfigurePerfmonManifestRegister
59 ConfigurePerfmonManifestUnregister
60 ConfigureEventManifestRegister
61 ConfigureEventManifestUnregister
62; RestartManager.cpp
63 WixRegisterRestartResources
64; secureobj.cpp
65 SchedSecureObjects
66 SchedSecureObjectsRollback
67 ExecSecureObjects
68 ExecSecureObjectsRollback
69; serviceconfig.cpp
70 SchedServiceConfig
71 ExecServiceConfig
72 RollbackServiceConfig
73; shellexecca.cpp
74 WixShellExec
75 WixShellExecBinary
76 WixUnelevatedShellExec
77; test.cpp
78 WixFailWhenDeferred
79 WixWaitForEvent
80; TouchFile.cpp
81 WixTouchFileDuringInstall
82 WixTouchFileDuringUninstall
83 WixExecuteTouchFile
84; xmlfile.cpp
85 SchedXmlFile
86 ExecXmlFile
87 ExecXmlFileRollback
88; xmlconfig.cpp
89 SchedXmlConfig
90 ExecXmlConfig
91 ExecXmlConfigRollback
diff --git a/src/ext/Util/ca/utilca.vcxproj b/src/ext/Util/ca/utilca.vcxproj
new file mode 100644
index 00000000..7b64db95
--- /dev/null
+++ b/src/ext/Util/ca/utilca.vcxproj
@@ -0,0 +1,106 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4<Project DefaultTargets="Build" ToolsVersion="16.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
5 <ItemGroup Label="ProjectConfigurations">
6 <ProjectConfiguration Include="Debug|ARM64">
7 <Configuration>Debug</Configuration>
8 <Platform>ARM64</Platform>
9 </ProjectConfiguration>
10 <ProjectConfiguration Include="Release|ARM64">
11 <Configuration>Release</Configuration>
12 <Platform>ARM64</Platform>
13 </ProjectConfiguration>
14 <ProjectConfiguration Include="Debug|X64">
15 <Configuration>Debug</Configuration>
16 <Platform>X64</Platform>
17 </ProjectConfiguration>
18 <ProjectConfiguration Include="Release|X64">
19 <Configuration>Release</Configuration>
20 <Platform>X64</Platform>
21 </ProjectConfiguration>
22 <ProjectConfiguration Include="Debug|Win32">
23 <Configuration>Debug</Configuration>
24 <Platform>Win32</Platform>
25 </ProjectConfiguration>
26 <ProjectConfiguration Include="Release|Win32">
27 <Configuration>Release</Configuration>
28 <Platform>Win32</Platform>
29 </ProjectConfiguration>
30 </ItemGroup>
31
32 <PropertyGroup Label="Globals">
33 <ProjectGuid>{076018F7-19BD-423A-ABBF-229273DA08D8}</ProjectGuid>
34 <ConfigurationType>DynamicLibrary</ConfigurationType>
35 <TargetName>utilca</TargetName>
36 <PlatformToolset>v142</PlatformToolset>
37 <CharacterSet>Unicode</CharacterSet>
38 <ProjectModuleDefinitionFile>utilca.def</ProjectModuleDefinitionFile>
39 <Description>WiX Toolset Util CustomAction</Description>
40 </PropertyGroup>
41
42 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
43 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
44
45 <PropertyGroup>
46 <ProjectAdditionalLinkLibraries>activeds.lib;adsiid.lib;msi.lib;netapi32.lib;shlwapi.lib</ProjectAdditionalLinkLibraries>
47 </PropertyGroup>
48
49 <ItemGroup>
50 <ClCompile Include="BroadcastSettingChange.cpp" />
51 <ClCompile Include="CheckReboot.cpp" />
52 <ClCompile Include="CloseApps.cpp" />
53 <ClCompile Include="dllmain.cpp">
54 <PrecompiledHeader>Create</PrecompiledHeader>
55 </ClCompile>
56 <ClCompile Include="exitearlywithsuccess.cpp" />
57 <ClCompile Include="FormatFiles.cpp" />
58 <ClCompile Include="netshortcuts.cpp" />
59 <ClCompile Include="OsInfo.cpp" />
60 <ClCompile Include="qtexecca.cpp" />
61 <ClCompile Include="RemoveFoldersEx.cpp" />
62 <ClCompile Include="RemoveRegistryKeysEx.cpp" />
63 <ClCompile Include="RestartManager.cpp" />
64 <ClCompile Include="scaexec.cpp" />
65 <ClCompile Include="scamanifest.cpp" />
66 <ClCompile Include="scaperf.cpp" />
67 <ClCompile Include="scaperfexec.cpp" />
68 <ClCompile Include="scasched.cpp" />
69 <ClCompile Include="scasmbexec.cpp" />
70 <ClCompile Include="scasmbsched.cpp" />
71 <ClCompile Include="scauser.cpp" />
72 <ClCompile Include="secureobj.cpp" />
73 <ClCompile Include="serviceconfig.cpp" />
74 <ClCompile Include="shellexecca.cpp" />
75 <ClCompile Include="test.cpp" />
76 <ClCompile Include="TouchFile.cpp" />
77 <ClCompile Include="utilca.cpp" />
78 <ClCompile Include="XmlConfig.cpp" />
79 <ClCompile Include="XmlFile.cpp" />
80 </ItemGroup>
81
82 <ItemGroup>
83 <ClInclude Include="caDecor.h" />
84 <ClInclude Include="cost.h" />
85 <ClInclude Include="CustomMsiErrors.h" />
86 <ClInclude Include="precomp.h" />
87 <ClInclude Include="sca.h" />
88 <ClInclude Include="scacost.h" />
89 <ClInclude Include="scasmb.h" />
90 <ClInclude Include="scasmbexec.h" />
91 <ClInclude Include="scauser.h" />
92 </ItemGroup>
93
94 <ItemGroup>
95 <None Include="utilca.def" />
96 </ItemGroup>
97
98 <ItemGroup>
99 <PackageReference Include="WixToolset.Dutil" Version="4.0.72" />
100 <PackageReference Include="WixToolset.WcaUtil" Version="4.0.19" />
101 <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" />
102 <PackageReference Include="Nerdbank.GitVersioning" Version="3.3.37" />
103 </ItemGroup>
104
105 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
106</Project>
diff --git a/src/ext/Util/nuget.config b/src/ext/Util/nuget.config
new file mode 100644
index 00000000..8d711148
--- /dev/null
+++ b/src/ext/Util/nuget.config
@@ -0,0 +1,18 @@
1<?xml version="1.0" encoding="utf-8"?>
2<configuration>
3 <packageSources>
4 <clear />
5 <add key="wixtoolset-balutil" value="https://ci.appveyor.com/nuget/wixtoolset-balutil" />
6 <add key="wixtoolset-burn" value="https://ci.appveyor.com/nuget/wixtoolset-burn" />
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" />
10 <add key="wixtoolset-core-native" value="https://ci.appveyor.com/nuget/wixtoolset-core-native" />
11 <add key="wixtoolset-dtf" value="https://ci.appveyor.com/nuget/wixtoolset-dtf" />
12 <add key="wixtoolset-dutil" value="https://ci.appveyor.com/nuget/wixtoolset-dutil" />
13 <add key="wixtoolset-wcautil" value="https://ci.appveyor.com/nuget/wixtoolset-wcautil" />
14 <add key="wixtoolset-tools" value="https://ci.appveyor.com/nuget/wixtoolset-tools" />
15 <add key="wixbuildtools" value="https://ci.appveyor.com/nuget/wixbuildtools" />
16 <add key="api.nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
17 </packageSources>
18</configuration> \ No newline at end of file
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/.Data/burn.exe b/src/ext/Util/test/WixToolsetTest.Util/TestData/.Data/burn.exe
new file mode 100644
index 00000000..2a4f423f
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/.Data/burn.exe
Binary files differ
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/Bundle.en-us.wxl b/src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/Bundle.en-us.wxl
new file mode 100644
index 00000000..f50a5386
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/Bundle.en-us.wxl
@@ -0,0 +1,8 @@
1<!--
2This file contains the declaration of all the localizable strings.
3-->
4<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US">
5
6 <String Id="BundleName">~TestBundle</String>
7
8</WixLocalization>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/Bundle.wxs b/src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/Bundle.wxs
new file mode 100644
index 00000000..7fef0725
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/Bundle.wxs
@@ -0,0 +1,52 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
2 <Bundle Name="!(loc.BundleName)" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
3 <BootstrapperApplication>
4 <BootstrapperApplicationDll SourceFile="fakeba.dll" />
5 </BootstrapperApplication>
6
7 <util:RegistrySearchRef Id="RegistrySearchId" />
8 <util:RegistrySearchRef Id="RegistrySearchId64" />
9 <util:ProductSearchRef Id="ProductSearchId" />
10 <util:FileSearchRef Id="FileSearchId" />
11 <util:WindowsFeatureSearchRef Id="DetectSHA2SupportId" />
12
13 <Chain>
14 <MsiPackage SourceFile="test.msi">
15 <MsiProperty Name="TEST" Value="1" />
16 </MsiPackage>
17 </Chain>
18 </Bundle>
19
20 <Fragment>
21 <util:RegistrySearch
22 Id="RegistrySearchId"
23 Variable="RegistrySearchVariable"
24 Root="HKLM"
25 Key="SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full"
26 Value="Release"
27 Result="value" />
28 </Fragment>
29
30 <Fragment>
31 <util:RegistrySearch
32 Id="RegistrySearchId64"
33 Variable="RegistrySearchVariable64"
34 Root="HKLM"
35 Key="SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full"
36 Value="Release"
37 Result="value"
38 Bitness="always64" />
39 </Fragment>
40
41 <Fragment>
42 <util:ProductSearch Id="ProductSearchId" Variable="ProductSearchVariable" UpgradeCode="738D02BF-E231-4370-8209-E9FD4E1BE2A1" Condition="1 &amp; 2 &lt; 3" Result="version" />
43 </Fragment>
44
45 <Fragment>
46 <util:FileSearch Id="FileSearchId" Variable="FileSearchVariable" Path="%windir%\System32\mscoree.dll" Result="exists" />
47 </Fragment>
48
49 <Fragment>
50 <util:WindowsFeatureSearch Id="DetectSHA2SupportId" Variable="IsSHA2Supported" Feature="sha2CodeSigning" />
51 </Fragment>
52</Wix>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/MsiPackage/Shared.dll b/src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/MsiPackage/Shared.dll
new file mode 100644
index 00000000..0e461ba8
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/MsiPackage/Shared.dll
@@ -0,0 +1 @@
This is Shared.dll. \ No newline at end of file
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/MsiPackage/test.txt b/src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/MsiPackage/test.txt
new file mode 100644
index 00000000..8b986220
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/MsiPackage/test.txt
@@ -0,0 +1 @@
This is test.txt \ No newline at end of file
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/fakeba.dll b/src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/fakeba.dll
new file mode 100644
index 00000000..970efdf0
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/fakeba.dll
@@ -0,0 +1 @@
This is a fakeba.dll \ No newline at end of file
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/test.msi b/src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/test.msi
new file mode 100644
index 00000000..0722d60e
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/test.msi
Binary files differ
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/CloseApplication/Package.en-us.wxl b/src/ext/Util/test/WixToolsetTest.Util/TestData/CloseApplication/Package.en-us.wxl
new file mode 100644
index 00000000..5301bb1a
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/CloseApplication/Package.en-us.wxl
@@ -0,0 +1,9 @@
1<!--
2This file contains the declaration of all the localizable strings.
3-->
4<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US">
5
6 <String Id="DowngradeError">A newer version of [ProductName] is already installed.</String>
7 <String Id="FeatureTitle">MsiPackage</String>
8
9</WixLocalization>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/CloseApplication/Package.wxs b/src/ext/Util/test/WixToolsetTest.Util/TestData/CloseApplication/Package.wxs
new file mode 100644
index 00000000..8e054256
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/CloseApplication/Package.wxs
@@ -0,0 +1,17 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
2 <Package Name="MsiPackage" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
3 <MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeError)" />
4
5 <Feature Id="ProductFeature" Title="!(loc.FeatureTitle)">
6 <ComponentGroupRef Id="ProductComponents" />
7 </Feature>
8
9 <util:CloseApplication Id="CloseMyApp" CloseMessage="yes" Property="MYAPPISRUNNING" Target="explorer.exe" />
10 </Package>
11
12 <Fragment>
13 <StandardDirectory Id="ProgramFilesFolder">
14 <Directory Id="INSTALLFOLDER" Name="MsiPackage" />
15 </StandardDirectory>
16 </Fragment>
17</Wix>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/CloseApplication/PackageComponents.wxs b/src/ext/Util/test/WixToolsetTest.Util/TestData/CloseApplication/PackageComponents.wxs
new file mode 100644
index 00000000..e27b3c43
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/CloseApplication/PackageComponents.wxs
@@ -0,0 +1,9 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2 <Fragment>
3 <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
4 <Component>
5 <File Source="example.txt" />
6 </Component>
7 </ComponentGroup>
8 </Fragment>
9</Wix>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/CloseApplication/example.txt b/src/ext/Util/test/WixToolsetTest.Util/TestData/CloseApplication/example.txt
new file mode 100644
index 00000000..1b4ffe8a
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/CloseApplication/example.txt
@@ -0,0 +1 @@
This is example.txt. \ No newline at end of file
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/EventManifest/Package.en-us.wxl b/src/ext/Util/test/WixToolsetTest.Util/TestData/EventManifest/Package.en-us.wxl
new file mode 100644
index 00000000..5301bb1a
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/EventManifest/Package.en-us.wxl
@@ -0,0 +1,9 @@
1<!--
2This file contains the declaration of all the localizable strings.
3-->
4<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US">
5
6 <String Id="DowngradeError">A newer version of [ProductName] is already installed.</String>
7 <String Id="FeatureTitle">MsiPackage</String>
8
9</WixLocalization>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/EventManifest/Package.wxs b/src/ext/Util/test/WixToolsetTest.Util/TestData/EventManifest/Package.wxs
new file mode 100644
index 00000000..daae573a
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/EventManifest/Package.wxs
@@ -0,0 +1,15 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2 <Package Name="MsiPackage" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
3 <MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeError)" />
4
5 <Feature Id="ProductFeature" Title="!(loc.FeatureTitle)">
6 <ComponentGroupRef Id="ProductComponents" />
7 </Feature>
8 </Package>
9
10 <Fragment>
11 <StandardDirectory Id="ProgramFilesFolder">
12 <Directory Id="INSTALLFOLDER" Name="MsiPackage" />
13 </StandardDirectory>
14 </Fragment>
15</Wix>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/EventManifest/PackageComponents.wxs b/src/ext/Util/test/WixToolsetTest.Util/TestData/EventManifest/PackageComponents.wxs
new file mode 100644
index 00000000..2ec8ce82
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/EventManifest/PackageComponents.wxs
@@ -0,0 +1,11 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
2 <Fragment>
3 <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
4 <Component>
5 <File Id="Manifest.dll" Source="example.txt">
6 <util:EventManifest MessageFile="[Manifest.dll]" ResourceFile="[Manifest.dll]" />
7 </File>
8 </Component>
9 </ComponentGroup>
10 </Fragment>
11</Wix>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/EventManifest/example.txt b/src/ext/Util/test/WixToolsetTest.Util/TestData/EventManifest/example.txt
new file mode 100644
index 00000000..1b4ffe8a
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/EventManifest/example.txt
@@ -0,0 +1 @@
This is example.txt. \ No newline at end of file
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcut/Package.en-us.wxl b/src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcut/Package.en-us.wxl
new file mode 100644
index 00000000..5301bb1a
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcut/Package.en-us.wxl
@@ -0,0 +1,9 @@
1<!--
2This file contains the declaration of all the localizable strings.
3-->
4<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US">
5
6 <String Id="DowngradeError">A newer version of [ProductName] is already installed.</String>
7 <String Id="FeatureTitle">MsiPackage</String>
8
9</WixLocalization>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcut/Package.ico b/src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcut/Package.ico
new file mode 100644
index 00000000..53134de7
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcut/Package.ico
Binary files differ
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcut/Package.wxs b/src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcut/Package.wxs
new file mode 100644
index 00000000..daae573a
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcut/Package.wxs
@@ -0,0 +1,15 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2 <Package Name="MsiPackage" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
3 <MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeError)" />
4
5 <Feature Id="ProductFeature" Title="!(loc.FeatureTitle)">
6 <ComponentGroupRef Id="ProductComponents" />
7 </Feature>
8 </Package>
9
10 <Fragment>
11 <StandardDirectory Id="ProgramFilesFolder">
12 <Directory Id="INSTALLFOLDER" Name="MsiPackage" />
13 </StandardDirectory>
14 </Fragment>
15</Wix>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcut/PackageComponents.wxs b/src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcut/PackageComponents.wxs
new file mode 100644
index 00000000..2a1b4347
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcut/PackageComponents.wxs
@@ -0,0 +1,11 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
2 <Fragment>
3 <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
4 <Component>
5 <File Id="Package.ico" Source="Package.ico" />
6 <util:InternetShortcut Type="link" Name="WiX Toolset (link)" Target="https://wixtoolset.org" IconFile="[#Package.ico]" />
7 <util:InternetShortcut Type="url" Name="WiX Toolset (url)" Target="https://wixtoolset.org" IconFile="[#Package.ico]" />
8 </Component>
9 </ComponentGroup>
10 </Fragment>
11</Wix>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcut/example.txt b/src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcut/example.txt
new file mode 100644
index 00000000..1b4ffe8a
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcut/example.txt
@@ -0,0 +1 @@
This is example.txt. \ No newline at end of file
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcutModule/Module.wxs b/src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcutModule/Module.wxs
new file mode 100644
index 00000000..1355d42e
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcutModule/Module.wxs
@@ -0,0 +1,13 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2 <Module Language="1033" Version="1.0.0.0" Id="InternetShortcutModule" Guid="047730a5-30fe-4a62-a520-da9381b8226a">
3 <SummaryInformation Manufacturer="Example Corporation" />
4
5 <ComponentGroupRef Id="ProductComponents" />
6 </Module>
7
8 <Fragment>
9 <StandardDirectory Id="ProgramFilesFolder">
10 <Directory Id="INSTALLFOLDER" Name="MergeModule" />
11 </StandardDirectory>
12 </Fragment>
13</Wix>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcutModule/ModuleComponents.wxs b/src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcutModule/ModuleComponents.wxs
new file mode 100644
index 00000000..2a1b4347
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcutModule/ModuleComponents.wxs
@@ -0,0 +1,11 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
2 <Fragment>
3 <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
4 <Component>
5 <File Id="Package.ico" Source="Package.ico" />
6 <util:InternetShortcut Type="link" Name="WiX Toolset (link)" Target="https://wixtoolset.org" IconFile="[#Package.ico]" />
7 <util:InternetShortcut Type="url" Name="WiX Toolset (url)" Target="https://wixtoolset.org" IconFile="[#Package.ico]" />
8 </Component>
9 </ComponentGroup>
10 </Fragment>
11</Wix>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcutModule/Package.ico b/src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcutModule/Package.ico
new file mode 100644
index 00000000..53134de7
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcutModule/Package.ico
Binary files differ
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/PermissionEx/Package.en-us.wxl b/src/ext/Util/test/WixToolsetTest.Util/TestData/PermissionEx/Package.en-us.wxl
new file mode 100644
index 00000000..5301bb1a
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/PermissionEx/Package.en-us.wxl
@@ -0,0 +1,9 @@
1<!--
2This file contains the declaration of all the localizable strings.
3-->
4<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US">
5
6 <String Id="DowngradeError">A newer version of [ProductName] is already installed.</String>
7 <String Id="FeatureTitle">MsiPackage</String>
8
9</WixLocalization>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/PermissionEx/Package.wxs b/src/ext/Util/test/WixToolsetTest.Util/TestData/PermissionEx/Package.wxs
new file mode 100644
index 00000000..daae573a
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/PermissionEx/Package.wxs
@@ -0,0 +1,15 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2 <Package Name="MsiPackage" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
3 <MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeError)" />
4
5 <Feature Id="ProductFeature" Title="!(loc.FeatureTitle)">
6 <ComponentGroupRef Id="ProductComponents" />
7 </Feature>
8 </Package>
9
10 <Fragment>
11 <StandardDirectory Id="ProgramFilesFolder">
12 <Directory Id="INSTALLFOLDER" Name="MsiPackage" />
13 </StandardDirectory>
14 </Fragment>
15</Wix>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/PermissionEx/PackageComponents.wxs b/src/ext/Util/test/WixToolsetTest.Util/TestData/PermissionEx/PackageComponents.wxs
new file mode 100644
index 00000000..0634d7d4
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/PermissionEx/PackageComponents.wxs
@@ -0,0 +1,23 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
2 <Fragment>
3 <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
4 <Component>
5 <File Source="example.txt">
6 <util:PermissionEx User="Everyone" GenericAll="yes" />
7 </File>
8 <CreateFolder>
9 <util:PermissionEx User="Everyone" GenericAll="yes" />
10 </CreateFolder>
11 <ServiceInstall Name="testsvc" Type="ownProcess" Start="disabled" ErrorControl="normal">
12 <util:PermissionEx User="Everyone" GenericAll="yes" />
13 </ServiceInstall>
14 <RegistryKey Id="ExampleRegistryKey" ForceCreateOnInstall="yes" Root="HKLM" Key="TestRegistryKey">
15 <util:PermissionEx User="Everyone" GenericAll="yes" />
16 </RegistryKey>
17 <RegistryValue Root="HKLM" Key="TestRegistryValueKey" Value="abc">
18 <util:PermissionEx User="Everyone" GenericAll="yes" />
19 </RegistryValue>
20 </Component>
21 </ComponentGroup>
22 </Fragment>
23</Wix>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/PermissionEx/example.txt b/src/ext/Util/test/WixToolsetTest.Util/TestData/PermissionEx/example.txt
new file mode 100644
index 00000000..1b4ffe8a
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/PermissionEx/example.txt
@@ -0,0 +1 @@
This is example.txt. \ No newline at end of file
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/Queries/Package.en-us.wxl b/src/ext/Util/test/WixToolsetTest.Util/TestData/Queries/Package.en-us.wxl
new file mode 100644
index 00000000..5301bb1a
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/Queries/Package.en-us.wxl
@@ -0,0 +1,9 @@
1<!--
2This file contains the declaration of all the localizable strings.
3-->
4<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US">
5
6 <String Id="DowngradeError">A newer version of [ProductName] is already installed.</String>
7 <String Id="FeatureTitle">MsiPackage</String>
8
9</WixLocalization>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/Queries/Package.wxs b/src/ext/Util/test/WixToolsetTest.Util/TestData/Queries/Package.wxs
new file mode 100644
index 00000000..abf0dbb4
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/Queries/Package.wxs
@@ -0,0 +1,23 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
2 <Package Name="MsiPackage" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
3 <MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeError)" />
4
5 <util:BroadcastEnvironmentChange />
6 <util:CheckRebootRequired />
7 <util:QueryWindowsDriverInfo />
8 <util:QueryWindowsSuiteInfo />
9
10 <Feature Id="ProductFeature" Title="!(loc.FeatureTitle)">
11 <ComponentGroupRef Id="ProductComponents" />
12 </Feature>
13 </Package>
14
15 <Fragment><util:BroadcastSettingChange />
16
17
18
19 <StandardDirectory Id="ProgramFilesFolder">
20 <Directory Id="INSTALLFOLDER" Name="MsiPackage" />
21 </StandardDirectory>
22 </Fragment>
23</Wix>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/Queries/PackageComponents.wxs b/src/ext/Util/test/WixToolsetTest.Util/TestData/Queries/PackageComponents.wxs
new file mode 100644
index 00000000..e27b3c43
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/Queries/PackageComponents.wxs
@@ -0,0 +1,9 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2 <Fragment>
3 <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
4 <Component>
5 <File Source="example.txt" />
6 </Component>
7 </ComponentGroup>
8 </Fragment>
9</Wix>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/Queries/example.txt b/src/ext/Util/test/WixToolsetTest.Util/TestData/Queries/example.txt
new file mode 100644
index 00000000..1b4ffe8a
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/Queries/example.txt
@@ -0,0 +1 @@
This is example.txt. \ No newline at end of file
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/RemoveFolderEx/Module.wxs b/src/ext/Util/test/WixToolsetTest.Util/TestData/RemoveFolderEx/Module.wxs
new file mode 100644
index 00000000..2c2be584
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/RemoveFolderEx/Module.wxs
@@ -0,0 +1,13 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2 <Module Language="1033" Version="1.0.0.0" Id="InternetShortcutModule" Guid="047730a5-30fe-4a62-a520-da9381b8226a">
3 <SummaryInformation Manufacturer="Example Corporation" />
4
5 <ComponentGroupRef Id="ModuleComponents" />
6 </Module>
7
8 <Fragment>
9 <StandardDirectory Id="ProgramFilesFolder">
10 <Directory Id="INSTALLFOLDER" Name="MergeModule" />
11 </StandardDirectory>
12 </Fragment>
13</Wix>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/RemoveFolderEx/ModuleComponents.wxs b/src/ext/Util/test/WixToolsetTest.Util/TestData/RemoveFolderEx/ModuleComponents.wxs
new file mode 100644
index 00000000..236d9df0
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/RemoveFolderEx/ModuleComponents.wxs
@@ -0,0 +1,10 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
2 <Fragment>
3 <ComponentGroup Id="ModuleComponents" Directory="INSTALLFOLDER">
4 <Component>
5 <File Source="ModuleComponents.wxs" />
6 <util:RemoveFolderEx On="both" Property="RemoveProp" />
7 </Component>
8 </ComponentGroup>
9 </Fragment>
10</Wix>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/RemoveRegistryKeyEx/Module.wxs b/src/ext/Util/test/WixToolsetTest.Util/TestData/RemoveRegistryKeyEx/Module.wxs
new file mode 100644
index 00000000..32b246f4
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/RemoveRegistryKeyEx/Module.wxs
@@ -0,0 +1,13 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2 <Module Language="1033" Version="1.0.0.0" Id="InternetShortcutModule" Guid="047730a5-30fe-4a62-a520-da9381b8226a">
3 <SummaryInformation Manufacturer="Example Corporation" />
4
5 <ComponentGroupRef Id="ModuleComponents" />
6 </Module>
7
8 <Fragment>
9 <StandardDirectory Id="ProgramFilesFolder">
10 <Directory Id="INSTALLFOLDER" Name="MergeModule" />
11 </StandardDirectory>
12 </Fragment>
13</Wix>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/RemoveRegistryKeyEx/ModuleComponents.wxs b/src/ext/Util/test/WixToolsetTest.Util/TestData/RemoveRegistryKeyEx/ModuleComponents.wxs
new file mode 100644
index 00000000..0a0c8cb6
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/RemoveRegistryKeyEx/ModuleComponents.wxs
@@ -0,0 +1,10 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
2 <Fragment>
3 <ComponentGroup Id="ModuleComponents" Directory="INSTALLFOLDER">
4 <Component>
5 <File Source="ModuleComponents.wxs" />
6 <util:RemoveRegistryKey Root="HKLM" Key="SOFTWARE\Example" On="install" />
7 </Component>
8 </ComponentGroup>
9 </Fragment>
10</Wix>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/UsingFileShare/Package.en-us.wxl b/src/ext/Util/test/WixToolsetTest.Util/TestData/UsingFileShare/Package.en-us.wxl
new file mode 100644
index 00000000..5301bb1a
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/UsingFileShare/Package.en-us.wxl
@@ -0,0 +1,9 @@
1<!--
2This file contains the declaration of all the localizable strings.
3-->
4<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US">
5
6 <String Id="DowngradeError">A newer version of [ProductName] is already installed.</String>
7 <String Id="FeatureTitle">MsiPackage</String>
8
9</WixLocalization>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/UsingFileShare/Package.wxs b/src/ext/Util/test/WixToolsetTest.Util/TestData/UsingFileShare/Package.wxs
new file mode 100644
index 00000000..daae573a
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/UsingFileShare/Package.wxs
@@ -0,0 +1,15 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2 <Package Name="MsiPackage" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
3 <MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeError)" />
4
5 <Feature Id="ProductFeature" Title="!(loc.FeatureTitle)">
6 <ComponentGroupRef Id="ProductComponents" />
7 </Feature>
8 </Package>
9
10 <Fragment>
11 <StandardDirectory Id="ProgramFilesFolder">
12 <Directory Id="INSTALLFOLDER" Name="MsiPackage" />
13 </StandardDirectory>
14 </Fragment>
15</Wix>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/UsingFileShare/PackageComponents.wxs b/src/ext/Util/test/WixToolsetTest.Util/TestData/UsingFileShare/PackageComponents.wxs
new file mode 100644
index 00000000..7cedbb30
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/UsingFileShare/PackageComponents.wxs
@@ -0,0 +1,14 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
2 <Fragment>
3 <util:User Id="Everyone" Name="Everyone" />
4
5 <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
6 <Component>
7 <File Source="example.txt" />
8 <util:FileShare Id="ExampleFileShare" Description="An example file share" Name="example">
9 <util:FileSharePermission User="Everyone" Read="yes" />
10 </util:FileShare>
11 </Component>
12 </ComponentGroup>
13 </Fragment>
14</Wix>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/UsingFileShare/example.txt b/src/ext/Util/test/WixToolsetTest.Util/TestData/UsingFileShare/example.txt
new file mode 100644
index 00000000..1b4ffe8a
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/UsingFileShare/example.txt
@@ -0,0 +1 @@
This is example.txt. \ No newline at end of file
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/XmlConfig/Package.en-us.wxl b/src/ext/Util/test/WixToolsetTest.Util/TestData/XmlConfig/Package.en-us.wxl
new file mode 100644
index 00000000..5301bb1a
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/XmlConfig/Package.en-us.wxl
@@ -0,0 +1,9 @@
1<!--
2This file contains the declaration of all the localizable strings.
3-->
4<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US">
5
6 <String Id="DowngradeError">A newer version of [ProductName] is already installed.</String>
7 <String Id="FeatureTitle">MsiPackage</String>
8
9</WixLocalization>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/XmlConfig/Package.wxs b/src/ext/Util/test/WixToolsetTest.Util/TestData/XmlConfig/Package.wxs
new file mode 100644
index 00000000..a2002634
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/XmlConfig/Package.wxs
@@ -0,0 +1,17 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
2 <Package Name="MsiPackage" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
3 <MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeError)" />
4
5 <Feature Id="ProductFeature" Title="!(loc.FeatureTitle)">
6 <Component Id="Del" Directory="INSTALLFOLDER" Guid="3613414c-11f5-40fa-a1f1-a0ba722a6895">
7 <util:XmlConfig Id="DelElement" File="[INSTALLFOLDER]my.xml" Action="delete" Node="element" VerifyPath="xxx" ElementPath="//root/sub" On="install" Sequence="1" />
8 </Component>
9 </Feature>
10 </Package>
11
12 <Fragment>
13 <StandardDirectory Id="ProgramFilesFolder">
14 <Directory Id="INSTALLFOLDER" Name="MsiPackage" />
15 </StandardDirectory>
16 </Fragment>
17</Wix>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/XmlConfigModule/Module.wxs b/src/ext/Util/test/WixToolsetTest.Util/TestData/XmlConfigModule/Module.wxs
new file mode 100644
index 00000000..29e8555b
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/XmlConfigModule/Module.wxs
@@ -0,0 +1,19 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
2 <Module Id="XmlConfigModule" Language="1033" Version="1.0.0.0" Guid="047730a5-30fe-4a62-a520-da9381b8226a">
3
4 <Component Id="Parent" Directory="INSTALLFOLDER">
5 <File Id="my.xml" Source="my.xml" />
6 <util:XmlConfig Id="AddElement" File="[my.xml]" Action="create" Node="element" VerifyPath="xxx" ElementPath="//root/sub" On="install" Sequence="1" />
7 </Component>
8
9 <Component Id="Child" Directory="INSTALLFOLDER" Guid="4613414c-11f5-40fa-a1f1-a0ba722a6895">
10 <util:XmlConfig Id="ChildElement" File="[my.xml]" VerifyPath="xxx" ElementId="AddElement" Sequence="1" />
11 </Component>
12 </Module>
13
14 <Fragment>
15 <StandardDirectory Id="ProgramFilesFolder">
16 <Directory Id="INSTALLFOLDER" Name="MsiPackage" />
17 </StandardDirectory>
18 </Fragment>
19</Wix>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/XmlConfigModule/my.xml b/src/ext/Util/test/WixToolsetTest.Util/TestData/XmlConfigModule/my.xml
new file mode 100644
index 00000000..bad25217
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/XmlConfigModule/my.xml
@@ -0,0 +1 @@
This is my.xml file.
diff --git a/src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs b/src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs
new file mode 100644
index 00000000..883f9794
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs
@@ -0,0 +1,317 @@
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
3namespace WixToolsetTest.Util
4{
5 using System.IO;
6 using System.Linq;
7 using WixBuildTools.TestSupport;
8 using WixToolset.Core.TestPackage;
9 using WixToolset.Data;
10 using WixToolset.Data.Symbols;
11 using WixToolset.Util;
12 using Xunit;
13
14 public class UtilExtensionFixture
15 {
16 [Fact]
17 public void CanBuildUsingFileShare()
18 {
19 var folder = TestData.Get(@"TestData\UsingFileShare");
20 var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder });
21
22 var results = build.BuildAndQuery(Build, "Binary", "CustomAction", "Wix4FileShare", "Wix4FileSharePermissions");
23 WixAssert.CompareLineByLine(new[]
24 {
25 "Binary:Wix4UtilCA_X86\t[Binary data]",
26 "CustomAction:Wix4ConfigureSmbInstall_X86\t1\tWix4UtilCA_X86\tConfigureSmbInstall\t",
27 "CustomAction:Wix4ConfigureSmbUninstall_X86\t1\tWix4UtilCA_X86\tConfigureSmbUninstall\t",
28 "CustomAction:Wix4CreateSmb_X86\t11265\tWix4UtilCA_X86\tCreateSmb\t",
29 "CustomAction:Wix4CreateSmbRollback_X86\t11585\tWix4UtilCA_X86\tDropSmb\t",
30 "CustomAction:Wix4DropSmb_X86\t11265\tWix4UtilCA_X86\tDropSmb\t",
31 "CustomAction:Wix4DropSmbRollback_X86\t11585\tWix4UtilCA_X86\tCreateSmb\t",
32 "Wix4FileShare:ExampleFileShare\texample\tfilF5_pLhBuF5b4N9XEo52g_hUM5Lo\tAn example file share\tINSTALLFOLDER",
33 "Wix4FileSharePermissions:ExampleFileShare\tEveryone\t1",
34 }, results.OrderBy(s => s).ToArray());
35 }
36
37 [Fact]
38 public void CanBuildUsingFileShareX64()
39 {
40 var folder = TestData.Get(@"TestData\UsingFileShare");
41 var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder });
42
43 var results = build.BuildAndQuery(BuildX64, "Binary", "CustomAction", "Wix4FileShare", "Wix4FileSharePermissions");
44 WixAssert.CompareLineByLine(new[]
45 {
46 "Binary:Wix4UtilCA_X64\t[Binary data]",
47 "CustomAction:Wix4ConfigureSmbInstall_X64\t1\tWix4UtilCA_X64\tConfigureSmbInstall\t",
48 "CustomAction:Wix4ConfigureSmbUninstall_X64\t1\tWix4UtilCA_X64\tConfigureSmbUninstall\t",
49 "CustomAction:Wix4CreateSmb_X64\t11265\tWix4UtilCA_X64\tCreateSmb\t",
50 "CustomAction:Wix4CreateSmbRollback_X64\t11585\tWix4UtilCA_X64\tDropSmb\t",
51 "CustomAction:Wix4DropSmb_X64\t11265\tWix4UtilCA_X64\tDropSmb\t",
52 "CustomAction:Wix4DropSmbRollback_X64\t11585\tWix4UtilCA_X64\tCreateSmb\t",
53 "Wix4FileShare:ExampleFileShare\texample\tfilF5_pLhBuF5b4N9XEo52g_hUM5Lo\tAn example file share\tINSTALLFOLDER",
54 "Wix4FileSharePermissions:ExampleFileShare\tEveryone\t1",
55 }, results.OrderBy(s => s).ToArray());
56 }
57
58 [Fact]
59 public void CanBuildCloseApplication()
60 {
61 var folder = TestData.Get(@"TestData\CloseApplication");
62 var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder });
63
64 var results = build.BuildAndQuery(BuildARM64, "Binary", "CustomAction", "Wix4CloseApplication");
65 WixAssert.CompareLineByLine(new[]
66 {
67 "Binary:Wix4UtilCA_A64\t[Binary data]",
68 "CustomAction:Wix4CheckRebootRequired_A64\t65\tWix4UtilCA_A64\tWixCheckRebootRequired\t",
69 "CustomAction:Wix4CloseApplications_A64\t1\tWix4UtilCA_A64\tWixCloseApplications\t",
70 "CustomAction:Wix4CloseApplicationsDeferred_A64\t3073\tWix4UtilCA_A64\tWixCloseApplicationsDeferred\t",
71 "Wix4CloseApplication:CloseMyApp\texplorer.exe\t\t\t3\t\tMYAPPISRUNNING\t\t",
72 }, results.OrderBy(s => s).ToArray());
73 }
74
75 [Fact]
76 public void CanBuildInternetShortcutInProduct()
77 {
78 var folder = TestData.Get(@"TestData\InternetShortcut");
79 var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder });
80
81 var results = build.BuildAndQuery(BuildX64, "Binary", "CustomAction", "RemoveFile", "Wix4InternetShortcut");
82 WixAssert.CompareLineByLine(new[]
83 {
84 "Binary:Wix4UtilCA_X64\t[Binary data]",
85 "CustomAction:Wix4CreateInternetShortcuts_X64\t3073\tWix4UtilCA_X64\tWixCreateInternetShortcuts\t",
86 "CustomAction:Wix4RollbackInternetShortcuts_X64\t3329\tWix4UtilCA_X64\tWixRollbackInternetShortcuts\t",
87 "CustomAction:Wix4SchedInternetShortcuts_X64\t1\tWix4UtilCA_X64\tWixSchedInternetShortcuts\t",
88 "RemoveFile:uisdCsU32.1i4Hebrg1N7E194zJQ8Y\tPackage.ico\thoiptxrr.url|WiX Toolset (url).url\tINSTALLFOLDER\t2",
89 "RemoveFile:uisjV.q0ROZZYR3h_lkpbkZtLtPH0A\tPackage.ico\tjcxd1dwf.lnk|WiX Toolset (link).lnk\tINSTALLFOLDER\t2",
90 "Wix4InternetShortcut:uisdCsU32.1i4Hebrg1N7E194zJQ8Y\tPackage.ico\tINSTALLFOLDER\tWiX Toolset (url).url\thttps://wixtoolset.org\t1\t[#Package.ico]\t0",
91 "Wix4InternetShortcut:uisjV.q0ROZZYR3h_lkpbkZtLtPH0A\tPackage.ico\tINSTALLFOLDER\tWiX Toolset (link).lnk\thttps://wixtoolset.org\t0\t[#Package.ico]\t0",
92 }, results.OrderBy(s => s).ToArray());
93 }
94
95 [Fact]
96 public void CanBuildInternetShortcutInMergeModule()
97 {
98 var folder = TestData.Get(@"TestData\InternetShortcutModule");
99 var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }, "test.msm");
100
101 var results = build.BuildAndQuery(BuildX64, "Binary", "CustomAction", "RemoveFile", "Wix4InternetShortcut");
102 WixAssert.CompareLineByLine(new[]
103 {
104 "Binary:Wix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A\t[Binary data]",
105 "CustomAction:Wix4CreateInternetShortcuts_X64\t3073\tWix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A\tWixCreateInternetShortcuts\t",
106 "CustomAction:Wix4RollbackInternetShortcuts_X64\t3329\tWix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A\tWixRollbackInternetShortcuts\t",
107 "CustomAction:Wix4SchedInternetShortcuts_X64\t1\tWix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A\tWixSchedInternetShortcuts\t",
108 "RemoveFile:uisdCsU32.1i4Hebrg1N7E194zJQ8Y.047730A5_30FE_4A62_A520_DA9381B8226A\tPackage.ico.047730A5_30FE_4A62_A520_DA9381B8226A\thoiptxrr.url|WiX Toolset (url).url\tINSTALLFOLDER.047730A5_30FE_4A62_A520_DA9381B8226A\t2",
109 "RemoveFile:uisjV.q0ROZZYR3h_lkpbkZtLtPH0A.047730A5_30FE_4A62_A520_DA9381B8226A\tPackage.ico.047730A5_30FE_4A62_A520_DA9381B8226A\tjcxd1dwf.lnk|WiX Toolset (link).lnk\tINSTALLFOLDER.047730A5_30FE_4A62_A520_DA9381B8226A\t2",
110 "Wix4InternetShortcut:uisdCsU32.1i4Hebrg1N7E194zJQ8Y.047730A5_30FE_4A62_A520_DA9381B8226A\tPackage.ico.047730A5_30FE_4A62_A520_DA9381B8226A\tINSTALLFOLDER.047730A5_30FE_4A62_A520_DA9381B8226A\tWiX Toolset (url).url\thttps://wixtoolset.org\t1\t[#Package.ico.047730A5_30FE_4A62_A520_DA9381B8226A]\t0",
111 "Wix4InternetShortcut:uisjV.q0ROZZYR3h_lkpbkZtLtPH0A.047730A5_30FE_4A62_A520_DA9381B8226A\tPackage.ico.047730A5_30FE_4A62_A520_DA9381B8226A\tINSTALLFOLDER.047730A5_30FE_4A62_A520_DA9381B8226A\tWiX Toolset (link).lnk\thttps://wixtoolset.org\t0\t[#Package.ico.047730A5_30FE_4A62_A520_DA9381B8226A]\t0",
112 }, results.OrderBy(s => s).ToArray());
113 }
114
115 [Fact]
116 public void CanBuildWithPermissionEx()
117 {
118 var folder = TestData.Get(@"TestData\PermissionEx");
119 var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder });
120
121 var results = build.BuildAndQuery(BuildX64, "Wix4SecureObject");
122 WixAssert.CompareLineByLine(new[]
123 {
124 "Wix4SecureObject:ExampleRegistryKey\tRegistry\t\tEveryone\t1\t268435456\tfilF5_pLhBuF5b4N9XEo52g_hUM5Lo",
125 "Wix4SecureObject:filF5_pLhBuF5b4N9XEo52g_hUM5Lo\tFile\t\tEveryone\t1\t268435456\tfilF5_pLhBuF5b4N9XEo52g_hUM5Lo",
126 "Wix4SecureObject:INSTALLFOLDER\tCreateFolder\t\tEveryone\t1\t268435456\tfilF5_pLhBuF5b4N9XEo52g_hUM5Lo",
127 "Wix4SecureObject:regL6DnQ9yJpDJH5OdcVji4YXsdX2c\tRegistry\t\tEveryone\t1\t268435456\tfilF5_pLhBuF5b4N9XEo52g_hUM5Lo",
128 "Wix4SecureObject:testsvc\tServiceInstall\t\tEveryone\t1\t268435456\tfilF5_pLhBuF5b4N9XEo52g_hUM5Lo",
129 }, results.OrderBy(s => s).ToArray());
130 }
131
132 [Fact]
133 public void CanBuildRemoveRegistryKeyExInMergeModule()
134 {
135 var folder = TestData.Get(@"TestData", "RemoveRegistryKeyEx");
136 var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }, "test.msm");
137
138 var results = build.BuildAndQuery(BuildX64, "Binary", "CustomAction", "RemoveRegistry", "Wix4RemoveRegistryKeyEx");
139 WixAssert.CompareLineByLine(new[]
140 {
141 "Binary:Wix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A\t[Binary data]",
142 "CustomAction:Wix4RemoveRegistryKeysEx_X64.047730A5_30FE_4A62_A520_DA9381B8226A\t65\tWix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A\tWixRemoveRegistryKeysEx\t",
143 "Wix4RemoveRegistryKeyEx:rrxfcDhR4HhE3v3rYiQcNtQjyahQNg.047730A5_30FE_4A62_A520_DA9381B8226A\tfilh4juyUVjoUcWWtcQmd5L07FoON4.047730A5_30FE_4A62_A520_DA9381B8226A\t2\tSOFTWARE\\Example\t1\t",
144 }, results.OrderBy(s => s).ToArray());
145 }
146
147 [Fact]
148 public void CanBuildRemoveFolderExInMergeModule()
149 {
150 var folder = TestData.Get(@"TestData\RemoveFolderEx");
151 var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }, "test.msm");
152
153 var results = build.BuildAndQuery(BuildX64, "Binary", "CustomAction", "RemoveFile", "Wix4RemoveFolderEx");
154 WixAssert.CompareLineByLine(new[]
155 {
156 "Binary:Wix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A\t[Binary data]",
157 "CustomAction:Wix4RemoveFoldersEx_X64.047730A5_30FE_4A62_A520_DA9381B8226A\t65\tWix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A\tWixRemoveFoldersEx\t",
158 "Wix4RemoveFolderEx:wrf5qCm1SE.zp8djrlk78l1IYFXsEw.047730A5_30FE_4A62_A520_DA9381B8226A\tfilh4juyUVjoUcWWtcQmd5L07FoON4.047730A5_30FE_4A62_A520_DA9381B8226A\tRemoveProp.047730A5_30FE_4A62_A520_DA9381B8226A\t3\t",
159 }, results.OrderBy(s => s).ToArray());
160 }
161
162 [Fact]
163 public void CanBuildWithEventManifest()
164 {
165 var folder = TestData.Get(@"TestData\EventManifest");
166 var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder });
167
168 var results = build.BuildAndQuery(BuildARM64, "Binary", "CustomAction", "Wix4EventManifest", "Wix4XmlFile");
169 WixAssert.CompareLineByLine(new[]
170 {
171 "Binary:Wix4UtilCA_A64\t[Binary data]",
172 "CustomAction:Wix4ConfigureEventManifestRegister_A64\t1\tWix4UtilCA_A64\tConfigureEventManifestRegister\t",
173 "CustomAction:Wix4ConfigureEventManifestUnregister_A64\t1\tWix4UtilCA_A64\tConfigureEventManifestUnregister\t",
174 "CustomAction:Wix4ExecXmlFile_A64\t11265\tWix4UtilCA_A64\tExecXmlFile\t",
175 "CustomAction:Wix4ExecXmlFileRollback_A64\t11521\tWix4UtilCA_A64\tExecXmlFileRollback\t",
176 "CustomAction:Wix4RegisterEventManifest_A64\t3073\tWix4UtilCA_A64\tWixQuietExec\t",
177 "CustomAction:Wix4RollbackRegisterEventManifest_A64\t3393\tWix4UtilCA_A64\tWixQuietExec\t",
178 "CustomAction:Wix4RollbackUnregisterEventManifest_A64\t3329\tWix4UtilCA_A64\tWixQuietExec\t",
179 "CustomAction:Wix4SchedXmlFile_A64\t1\tWix4UtilCA_A64\tSchedXmlFile\t",
180 "CustomAction:Wix4UnregisterEventManifest_A64\t3137\tWix4UtilCA_A64\tWixQuietExec\t",
181 "Wix4EventManifest:Manifest.dll\t[#Manifest.dll]",
182 "Wix4XmlFile:Config_Manifest.dllMessageFile\t[#Manifest.dll]\t/*/*/*/*[\\[]@messageFileName[\\]]\tmessageFileName\t[Manifest.dll]\t4100\tManifest.dll\t",
183 "Wix4XmlFile:Config_Manifest.dllResourceFile\t[#Manifest.dll]\t/*/*/*/*[\\[]@resourceFileName[\\]]\tresourceFileName\t[Manifest.dll]\t4100\tManifest.dll\t",
184 }, results.OrderBy(s => s).ToArray());
185 }
186
187 [Fact]
188 public void CanBuildWithQueries()
189 {
190 var folder = TestData.Get(@"TestData\Queries");
191 var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder });
192
193 var results = build.BuildAndQuery(BuildARM64, "Binary", "CustomAction");
194 WixAssert.CompareLineByLine(new[]
195 {
196 "Binary:Wix4UtilCA_A64\t[Binary data]",
197 "CustomAction:Wix4BroadcastEnvironmentChange_A64\t65\tWix4UtilCA_A64\tWixBroadcastEnvironmentChange\t",
198 "CustomAction:Wix4BroadcastSettingChange_A64\t65\tWix4UtilCA_A64\tWixBroadcastSettingChange\t",
199 "CustomAction:Wix4CheckRebootRequired_A64\t65\tWix4UtilCA_A64\tWixCheckRebootRequired\t",
200 "CustomAction:Wix4QueryOsDriverInfo_A64\t257\tWix4UtilCA_A64\tWixQueryOsDriverInfo\t",
201 "CustomAction:Wix4QueryOsInfo_A64\t257\tWix4UtilCA_A64\tWixQueryOsInfo\t",
202 }, results.OrderBy(s => s).ToArray());
203 }
204
205 [Fact]
206 public void CanBuildWithXmlConfig()
207 {
208 var folder = TestData.Get(@"TestData", "XmlConfig");
209 var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder });
210
211 var results = build.BuildAndQuery(BuildX64, "Wix4XmlConfig");
212 WixAssert.CompareLineByLine(new[]
213 {
214 "Wix4XmlConfig:DelElement\t[INSTALLFOLDER]my.xml\t\t//root/sub\txxx\t\t\t289\tDel\t1",
215 }, results.OrderBy(s => s).ToArray());
216 }
217
218 [Fact]
219 public void CanBuildModuleWithXmlConfig()
220 {
221 var folder = TestData.Get(@"TestData", "XmlConfigModule");
222 var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder });
223
224 var results = build.BuildAndQuery(BuildX64, "Wix4XmlConfig");
225 WixAssert.CompareLineByLine(new[]
226 {
227 "Wix4XmlConfig:AddElement.047730A5_30FE_4A62_A520_DA9381B8226A\t[my.xml.047730A5_30FE_4A62_A520_DA9381B8226A]\t\t//root/sub\txxx\t\t\t273\tParent.047730A5_30FE_4A62_A520_DA9381B8226A\t1",
228 "Wix4XmlConfig:ChildElement.047730A5_30FE_4A62_A520_DA9381B8226A\t[my.xml.047730A5_30FE_4A62_A520_DA9381B8226A]\tAddElement.047730A5_30FE_4A62_A520_DA9381B8226A\t\txxx\t\t\t0\tChild.047730A5_30FE_4A62_A520_DA9381B8226A\t1",
229 }, results.OrderBy(s => s).ToArray());
230 }
231
232 [Fact]
233 public void CanBuildBundleWithSearches()
234 {
235 var burnStubPath = TestData.Get(@"TestData\.Data\burn.exe");
236 var folder = TestData.Get(@"TestData\BundleWithSearches");
237 var rootFolder = TestData.Get();
238 var wixext = Path.Combine(rootFolder, "WixToolset.Util.wixext.dll");
239
240 using (var fs = new DisposableFileSystem())
241 {
242 var baseFolder = fs.GetFolder();
243 var intermediateFolder = Path.Combine(baseFolder, "obj");
244 var bundlePath = Path.Combine(baseFolder, @"bin\test.exe");
245 var baFolderPath = Path.Combine(baseFolder, "ba");
246 var extractFolderPath = Path.Combine(baseFolder, "extract");
247
248 var result = WixRunner.Execute(new[]
249 {
250 "build",
251 Path.Combine(folder, "Bundle.wxs"),
252 "-ext", wixext,
253 "-loc", Path.Combine(folder, "Bundle.en-us.wxl"),
254 "-bindpath", Path.Combine(folder, "data"),
255 "-intermediateFolder", intermediateFolder,
256 "-o", bundlePath
257 });
258
259 result.AssertSuccess();
260
261 Assert.True(File.Exists(bundlePath));
262#if TODO
263 Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb")));
264#endif
265
266 var extractResult = BundleExtractor.ExtractBAContainer(null, bundlePath, baFolderPath, extractFolderPath);
267 extractResult.AssertSuccess();
268
269 var bundleExtensionDatas = extractResult.SelectBundleExtensionDataNodes("/be:BundleExtensionData/be:BundleExtension[@Id='Wix4UtilBundleExtension_X86']");
270 Assert.Equal(1, bundleExtensionDatas.Count);
271 Assert.Equal("<BundleExtension Id='Wix4UtilBundleExtension_X86'>" +
272 "<WixWindowsFeatureSearch Id='DetectSHA2SupportId' Type='sha2CodeSigning' />" +
273 "</BundleExtension>", bundleExtensionDatas[0].GetTestXml());
274
275 var utilSearches = extractResult.SelectManifestNodes("/burn:BurnManifest/*[self::burn:ExtensionSearch or self::burn:FileSearch or self::burn:MsiProductSearch or self::burn:RegistrySearch]");
276 Assert.Equal(5, utilSearches.Count);
277 Assert.Equal("<ExtensionSearch Id='DetectSHA2SupportId' Variable='IsSHA2Supported' " +
278 "ExtensionId='Wix4UtilBundleExtension_X86' />", utilSearches[0].GetTestXml());
279 Assert.Equal("<FileSearch Id='FileSearchId' Variable='FileSearchVariable' " +
280 $@"Path='%windir%\System32\mscoree.dll' Type='exists' />", utilSearches[1].GetTestXml());
281 Assert.Equal("<MsiProductSearch Id='ProductSearchId' Variable='ProductSearchVariable' Condition='1 &amp; 2 &lt; 3' " +
282 "UpgradeCode='{738D02BF-E231-4370-8209-E9FD4E1BE2A1}' Type='version' />", utilSearches[2].GetTestXml());
283 Assert.Equal("<RegistrySearch Id='RegistrySearchId' Variable='RegistrySearchVariable' " +
284 @"Root='HKLM' Key='SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full' Value='Release' Type='value' VariableType='string' />", utilSearches[3].GetTestXml());
285 Assert.Equal("<RegistrySearch Id='RegistrySearchId64' Variable='RegistrySearchVariable64' " +
286 @"Root='HKLM' Key='SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full' Value='Release' Type='value' Win64='yes' VariableType='string' />", utilSearches[4].GetTestXml());
287 }
288 }
289
290 private static void Build(string[] args)
291 {
292 var result = WixRunner.Execute(args);
293 result.AssertSuccess();
294 }
295
296 private static void BuildX64(string[] args)
297 {
298 var newArgs = args.ToList();
299 newArgs.Add("-platform");
300 newArgs.Add("x64");
301 newArgs.Add("-sw1072");
302
303 var result = WixRunner.Execute(newArgs.ToArray());
304 result.AssertSuccess();
305 }
306
307 private static void BuildARM64(string[] args)
308 {
309 var newArgs = args.ToList();
310 newArgs.Add("-platform");
311 newArgs.Add("arm64");
312
313 var result = WixRunner.Execute(newArgs.ToArray());
314 result.AssertSuccess();
315 }
316 }
317}
diff --git a/src/ext/Util/test/WixToolsetTest.Util/WixToolsetTest.Util.csproj b/src/ext/Util/test/WixToolsetTest.Util/WixToolsetTest.Util.csproj
new file mode 100644
index 00000000..e77ecbed
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/WixToolsetTest.Util.csproj
@@ -0,0 +1,38 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4<Project Sdk="Microsoft.NET.Sdk">
5 <PropertyGroup>
6 <TargetFramework>netcoreapp3.1</TargetFramework>
7 <IsPackable>false</IsPackable>
8 </PropertyGroup>
9
10 <PropertyGroup>
11 <NoWarn>NU1701</NoWarn>
12 </PropertyGroup>
13
14 <ItemGroup>
15 <Content Include="TestData\**" CopyToOutputDirectory="PreserveNewest" />
16 </ItemGroup>
17
18 <ItemGroup>
19 <ProjectReference Include="..\..\wixext\WixToolset.Util.wixext.csproj" />
20 </ItemGroup>
21
22 <ItemGroup>
23 <PackageReference Include="WixToolset.Core" Version="4.0.*" />
24 <PackageReference Include="WixToolset.Core.Burn" Version="4.0.*" />
25 <PackageReference Include="WixToolset.Core.WindowsInstaller" Version="4.0.*" />
26 <PackageReference Include="WixToolset.Core.TestPackage" Version="4.0.*" />
27 </ItemGroup>
28
29 <ItemGroup>
30 <PackageReference Include="WixBuildTools.TestSupport" Version="4.0.*" />
31 </ItemGroup>
32
33 <ItemGroup>
34 <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
35 <PackageReference Include="xunit" Version="2.4.1" />
36 <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" PrivateAssets="All" />
37 </ItemGroup>
38</Project>
diff --git a/src/ext/Util/test/WixToolsetTest.Util/WixToolsetTest.Util.v3.ncrunchproject b/src/ext/Util/test/WixToolsetTest.Util/WixToolsetTest.Util.v3.ncrunchproject
new file mode 100644
index 00000000..7b5b2139
--- /dev/null
+++ b/src/ext/Util/test/WixToolsetTest.Util/WixToolsetTest.Util.v3.ncrunchproject
@@ -0,0 +1,5 @@
1<ProjectConfiguration>
2 <Settings>
3 <CopyReferencedAssembliesToWorkspace>True</CopyReferencedAssembliesToWorkspace>
4 </Settings>
5</ProjectConfiguration> \ No newline at end of file
diff --git a/src/ext/Util/wix.snk b/src/ext/Util/wix.snk
new file mode 100644
index 00000000..3908a66a
--- /dev/null
+++ b/src/ext/Util/wix.snk
Binary files differ
diff --git a/src/ext/Util/wixext/PerformanceCounterType.cs b/src/ext/Util/wixext/PerformanceCounterType.cs
new file mode 100644
index 00000000..1e06efd3
--- /dev/null
+++ b/src/ext/Util/wixext/PerformanceCounterType.cs
@@ -0,0 +1,192 @@
1// Captured from: C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.dll
2
3namespace System.Diagnostics
4{
5 public enum PerformanceCounterType
6 {
7 //
8 // Summary:
9 // An instantaneous counter that shows the most recently observed value in hexadecimal
10 // format. Used, for example, to maintain a simple count of items or operations.
11 NumberOfItemsHEX32 = 0,
12 //
13 // Summary:
14 // An instantaneous counter that shows the most recently observed value. Used, for
15 // example, to maintain a simple count of a very large number of items or operations.
16 // It is the same as NumberOfItemsHEX32 except that it uses larger fields to accommodate
17 // larger values.
18 NumberOfItemsHEX64 = 256,
19 //
20 // Summary:
21 // An instantaneous counter that shows the most recently observed value. Used, for
22 // example, to maintain a simple count of items or operations.
23 NumberOfItems32 = 65536,
24 //
25 // Summary:
26 // An instantaneous counter that shows the most recently observed value. Used, for
27 // example, to maintain a simple count of a very large number of items or operations.
28 // It is the same as NumberOfItems32 except that it uses larger fields to accommodate
29 // larger values.
30 NumberOfItems64 = 65792,
31 //
32 // Summary:
33 // A difference counter that shows the change in the measured attribute between
34 // the two most recent sample intervals.
35 CounterDelta32 = 4195328,
36 //
37 // Summary:
38 // A difference counter that shows the change in the measured attribute between
39 // the two most recent sample intervals. It is the same as the CounterDelta32 counter
40 // type except that is uses larger fields to accomodate larger values.
41 CounterDelta64 = 4195584,
42 //
43 // Summary:
44 // An average counter that shows the average number of operations completed in one
45 // second. When a counter of this type samples the data, each sampling interrupt
46 // returns one or zero. The counter data is the number of ones that were sampled.
47 // It measures time in units of ticks of the system performance timer.
48 SampleCounter = 4260864,
49 //
50 // Summary:
51 // An average counter designed to monitor the average length of a queue to a resource
52 // over time. It shows the difference between the queue lengths observed during
53 // the last two sample intervals divided by the duration of the interval. This type
54 // of counter is typically used to track the number of items that are queued or
55 // waiting.
56 CountPerTimeInterval32 = 4523008,
57 //
58 // Summary:
59 // An average counter that monitors the average length of a queue to a resource
60 // over time. Counters of this type display the difference between the queue lengths
61 // observed during the last two sample intervals, divided by the duration of the
62 // interval. This counter type is the same as CountPerTimeInterval32 except that
63 // it uses larger fields to accommodate larger values. This type of counter is typically
64 // used to track a high-volume or very large number of items that are queued or
65 // waiting.
66 CountPerTimeInterval64 = 4523264,
67 //
68 // Summary:
69 // A difference counter that shows the average number of operations completed during
70 // each second of the sample interval. Counters of this type measure time in ticks
71 // of the system clock.
72 RateOfCountsPerSecond32 = 272696320,
73 //
74 // Summary:
75 // A difference counter that shows the average number of operations completed during
76 // each second of the sample interval. Counters of this type measure time in ticks
77 // of the system clock. This counter type is the same as the RateOfCountsPerSecond32
78 // type, but it uses larger fields to accommodate larger values to track a high-volume
79 // number of items or operations per second, such as a byte-transmission rate.
80 RateOfCountsPerSecond64 = 272696576,
81 //
82 // Summary:
83 // An instantaneous percentage counter that shows the ratio of a subset to its set
84 // as a percentage. For example, it compares the number of bytes in use on a disk
85 // to the total number of bytes on the disk. Counters of this type display the current
86 // percentage only, not an average over time.
87 RawFraction = 537003008,
88 //
89 // Summary:
90 // A percentage counter that shows the average time that a component is active as
91 // a percentage of the total sample time.
92 CounterTimer = 541132032,
93 //
94 // Summary:
95 // A percentage counter that shows the active time of a component as a percentage
96 // of the total elapsed time of the sample interval. It measures time in units of
97 // 100 nanoseconds (ns). Counters of this type are designed to measure the activity
98 // of one component at a time.
99 Timer100Ns = 542180608,
100 //
101 // Summary:
102 // A percentage counter that shows the average ratio of hits to all operations during
103 // the last two sample intervals.
104 SampleFraction = 549585920,
105 //
106 // Summary:
107 // A percentage counter that displays the average percentage of active time observed
108 // during sample interval. The value of these counters is calculated by monitoring
109 // the percentage of time that the service was inactive and then subtracting that
110 // value from 100 percent.
111 CounterTimerInverse = 557909248,
112 //
113 // Summary:
114 // A percentage counter that shows the average percentage of active time observed
115 // during the sample interval.
116 Timer100NsInverse = 558957824,
117 //
118 // Summary:
119 // A percentage counter that displays the active time of one or more components
120 // as a percentage of the total time of the sample interval. Because the numerator
121 // records the active time of components operating simultaneously, the resulting
122 // percentage can exceed 100 percent.
123 CounterMultiTimer = 574686464,
124 //
125 // Summary:
126 // A percentage counter that shows the active time of one or more components as
127 // a percentage of the total time of the sample interval. It measures time in 100
128 // nanosecond (ns) units.
129 CounterMultiTimer100Ns = 575735040,
130 //
131 // Summary:
132 // A percentage counter that shows the active time of one or more components as
133 // a percentage of the total time of the sample interval. It derives the active
134 // time by measuring the time that the components were not active and subtracting
135 // the result from 100 percent by the number of objects monitored.
136 CounterMultiTimerInverse = 591463680,
137 //
138 // Summary:
139 // A percentage counter that shows the active time of one or more components as
140 // a percentage of the total time of the sample interval. Counters of this type
141 // measure time in 100 nanosecond (ns) units. They derive the active time by measuring
142 // the time that the components were not active and subtracting the result from
143 // multiplying 100 percent by the number of objects monitored.
144 CounterMultiTimer100NsInverse = 592512256,
145 //
146 // Summary:
147 // An average counter that measures the time it takes, on average, to complete a
148 // process or operation. Counters of this type display a ratio of the total elapsed
149 // time of the sample interval to the number of processes or operations completed
150 // during that time. This counter type measures time in ticks of the system clock.
151 AverageTimer32 = 805438464,
152 //
153 // Summary:
154 // A difference timer that shows the total time between when the component or process
155 // started and the time when this value is calculated.
156 ElapsedTime = 807666944,
157 //
158 // Summary:
159 // An average counter that shows how many items are processed, on average, during
160 // an operation. Counters of this type display a ratio of the items processed to
161 // the number of operations completed. The ratio is calculated by comparing the
162 // number of items processed during the last interval to the number of operations
163 // completed during the last interval.
164 AverageCount64 = 1073874176,
165 //
166 // Summary:
167 // A base counter that stores the number of sampling interrupts taken and is used
168 // as a denominator in the sampling fraction. The sampling fraction is the number
169 // of samples that were 1 (or true) for a sample interrupt. Check that this value
170 // is greater than zero before using it as the denominator in a calculation of SampleFraction.
171 SampleBase = 1073939457,
172 //
173 // Summary:
174 // A base counter that is used in the calculation of time or count averages, such
175 // as AverageTimer32 and AverageCount64. Stores the denominator for calculating
176 // a counter to present "time per operation" or "count per operation".
177 AverageBase = 1073939458,
178 //
179 // Summary:
180 // A base counter that stores the denominator of a counter that presents a general
181 // arithmetic fraction. Check that this value is greater than zero before using
182 // it as the denominator in a RawFraction value calculation.
183 RawBase = 1073939459,
184 //
185 // Summary:
186 // A base counter that indicates the number of items sampled. It is used as the
187 // denominator in the calculations to get an average among the items sampled when
188 // taking timings of multiple, but similar items. Used with CounterMultiTimer, CounterMultiTimerInverse,
189 // CounterMultiTimer100Ns, and CounterMultiTimer100NsInverse.
190 CounterMultiBase = 1107494144
191 }
192}
diff --git a/src/ext/Util/wixext/Symbols/EventManifestSymbol.cs b/src/ext/Util/wixext/Symbols/EventManifestSymbol.cs
new file mode 100644
index 00000000..ccd3c899
--- /dev/null
+++ b/src/ext/Util/wixext/Symbols/EventManifestSymbol.cs
@@ -0,0 +1,55 @@
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
3namespace WixToolset.Util
4{
5 using WixToolset.Data;
6 using WixToolset.Util.Symbols;
7
8 public static partial class UtilSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition EventManifest = new IntermediateSymbolDefinition(
11 UtilSymbolDefinitionType.EventManifest.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(EventManifestSymbolFields.ComponentRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(EventManifestSymbolFields.File), IntermediateFieldType.String),
16 },
17 typeof(EventManifestSymbol));
18 }
19}
20
21namespace WixToolset.Util.Symbols
22{
23 using WixToolset.Data;
24
25 public enum EventManifestSymbolFields
26 {
27 ComponentRef,
28 File,
29 }
30
31 public class EventManifestSymbol : IntermediateSymbol
32 {
33 public EventManifestSymbol() : base(UtilSymbolDefinitions.EventManifest, null, null)
34 {
35 }
36
37 public EventManifestSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.EventManifest, sourceLineNumber, id)
38 {
39 }
40
41 public IntermediateField this[EventManifestSymbolFields index] => this.Fields[(int)index];
42
43 public string ComponentRef
44 {
45 get => this.Fields[(int)EventManifestSymbolFields.ComponentRef].AsString();
46 set => this.Set((int)EventManifestSymbolFields.ComponentRef, value);
47 }
48
49 public string File
50 {
51 get => this.Fields[(int)EventManifestSymbolFields.File].AsString();
52 set => this.Set((int)EventManifestSymbolFields.File, value);
53 }
54 }
55} \ No newline at end of file
diff --git a/src/ext/Util/wixext/Symbols/FileSharePermissionsSymbol.cs b/src/ext/Util/wixext/Symbols/FileSharePermissionsSymbol.cs
new file mode 100644
index 00000000..3db92f22
--- /dev/null
+++ b/src/ext/Util/wixext/Symbols/FileSharePermissionsSymbol.cs
@@ -0,0 +1,63 @@
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
3namespace WixToolset.Util
4{
5 using WixToolset.Data;
6 using WixToolset.Util.Symbols;
7
8 public static partial class UtilSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition FileSharePermissions = new IntermediateSymbolDefinition(
11 UtilSymbolDefinitionType.FileSharePermissions.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(FileSharePermissionsSymbolFields.FileShareRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(FileSharePermissionsSymbolFields.UserRef), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(FileSharePermissionsSymbolFields.Permissions), IntermediateFieldType.Number),
17 },
18 typeof(FileSharePermissionsSymbol));
19 }
20}
21
22namespace WixToolset.Util.Symbols
23{
24 using WixToolset.Data;
25
26 public enum FileSharePermissionsSymbolFields
27 {
28 FileShareRef,
29 UserRef,
30 Permissions,
31 }
32
33 public class FileSharePermissionsSymbol : IntermediateSymbol
34 {
35 public FileSharePermissionsSymbol() : base(UtilSymbolDefinitions.FileSharePermissions, null, null)
36 {
37 }
38
39 public FileSharePermissionsSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.FileSharePermissions, sourceLineNumber, id)
40 {
41 }
42
43 public IntermediateField this[FileSharePermissionsSymbolFields index] => this.Fields[(int)index];
44
45 public string FileShareRef
46 {
47 get => this.Fields[(int)FileSharePermissionsSymbolFields.FileShareRef].AsString();
48 set => this.Set((int)FileSharePermissionsSymbolFields.FileShareRef, value);
49 }
50
51 public string UserRef
52 {
53 get => this.Fields[(int)FileSharePermissionsSymbolFields.UserRef].AsString();
54 set => this.Set((int)FileSharePermissionsSymbolFields.UserRef, value);
55 }
56
57 public int Permissions
58 {
59 get => this.Fields[(int)FileSharePermissionsSymbolFields.Permissions].AsNumber();
60 set => this.Set((int)FileSharePermissionsSymbolFields.Permissions, value);
61 }
62 }
63} \ No newline at end of file
diff --git a/src/ext/Util/wixext/Symbols/FileShareSymbol.cs b/src/ext/Util/wixext/Symbols/FileShareSymbol.cs
new file mode 100644
index 00000000..c956ff42
--- /dev/null
+++ b/src/ext/Util/wixext/Symbols/FileShareSymbol.cs
@@ -0,0 +1,71 @@
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
3namespace WixToolset.Util
4{
5 using WixToolset.Data;
6 using WixToolset.Util.Symbols;
7
8 public static partial class UtilSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition FileShare = new IntermediateSymbolDefinition(
11 UtilSymbolDefinitionType.FileShare.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(FileShareSymbolFields.ShareName), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(FileShareSymbolFields.ComponentRef), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(FileShareSymbolFields.Description), IntermediateFieldType.String),
17 new IntermediateFieldDefinition(nameof(FileShareSymbolFields.DirectoryRef), IntermediateFieldType.String),
18 },
19 typeof(FileShareSymbol));
20 }
21}
22
23namespace WixToolset.Util.Symbols
24{
25 using WixToolset.Data;
26
27 public enum FileShareSymbolFields
28 {
29 ShareName,
30 ComponentRef,
31 Description,
32 DirectoryRef,
33 }
34
35 public class FileShareSymbol : IntermediateSymbol
36 {
37 public FileShareSymbol() : base(UtilSymbolDefinitions.FileShare, null, null)
38 {
39 }
40
41 public FileShareSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.FileShare, sourceLineNumber, id)
42 {
43 }
44
45 public IntermediateField this[FileShareSymbolFields index] => this.Fields[(int)index];
46
47 public string ShareName
48 {
49 get => this.Fields[(int)FileShareSymbolFields.ShareName].AsString();
50 set => this.Set((int)FileShareSymbolFields.ShareName, value);
51 }
52
53 public string ComponentRef
54 {
55 get => this.Fields[(int)FileShareSymbolFields.ComponentRef].AsString();
56 set => this.Set((int)FileShareSymbolFields.ComponentRef, value);
57 }
58
59 public string Description
60 {
61 get => this.Fields[(int)FileShareSymbolFields.Description].AsString();
62 set => this.Set((int)FileShareSymbolFields.Description, value);
63 }
64
65 public string DirectoryRef
66 {
67 get => this.Fields[(int)FileShareSymbolFields.DirectoryRef].AsString();
68 set => this.Set((int)FileShareSymbolFields.DirectoryRef, value);
69 }
70 }
71} \ No newline at end of file
diff --git a/src/ext/Util/wixext/Symbols/GroupSymbol.cs b/src/ext/Util/wixext/Symbols/GroupSymbol.cs
new file mode 100644
index 00000000..b378db44
--- /dev/null
+++ b/src/ext/Util/wixext/Symbols/GroupSymbol.cs
@@ -0,0 +1,63 @@
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
3namespace WixToolset.Util
4{
5 using WixToolset.Data;
6 using WixToolset.Util.Symbols;
7
8 public static partial class UtilSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition Group = new IntermediateSymbolDefinition(
11 UtilSymbolDefinitionType.Group.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(GroupSymbolFields.ComponentRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(GroupSymbolFields.Name), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(GroupSymbolFields.Domain), IntermediateFieldType.String),
17 },
18 typeof(GroupSymbol));
19 }
20}
21
22namespace WixToolset.Util.Symbols
23{
24 using WixToolset.Data;
25
26 public enum GroupSymbolFields
27 {
28 ComponentRef,
29 Name,
30 Domain,
31 }
32
33 public class GroupSymbol : IntermediateSymbol
34 {
35 public GroupSymbol() : base(UtilSymbolDefinitions.Group, null, null)
36 {
37 }
38
39 public GroupSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.Group, sourceLineNumber, id)
40 {
41 }
42
43 public IntermediateField this[GroupSymbolFields index] => this.Fields[(int)index];
44
45 public string ComponentRef
46 {
47 get => this.Fields[(int)GroupSymbolFields.ComponentRef].AsString();
48 set => this.Set((int)GroupSymbolFields.ComponentRef, value);
49 }
50
51 public string Name
52 {
53 get => this.Fields[(int)GroupSymbolFields.Name].AsString();
54 set => this.Set((int)GroupSymbolFields.Name, value);
55 }
56
57 public string Domain
58 {
59 get => this.Fields[(int)GroupSymbolFields.Domain].AsString();
60 set => this.Set((int)GroupSymbolFields.Domain, value);
61 }
62 }
63} \ No newline at end of file
diff --git a/src/ext/Util/wixext/Symbols/PerfmonManifestSymbol.cs b/src/ext/Util/wixext/Symbols/PerfmonManifestSymbol.cs
new file mode 100644
index 00000000..03fef14e
--- /dev/null
+++ b/src/ext/Util/wixext/Symbols/PerfmonManifestSymbol.cs
@@ -0,0 +1,63 @@
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
3namespace WixToolset.Util
4{
5 using WixToolset.Data;
6 using WixToolset.Util.Symbols;
7
8 public static partial class UtilSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition PerfmonManifest = new IntermediateSymbolDefinition(
11 UtilSymbolDefinitionType.PerfmonManifest.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(PerfmonManifestSymbolFields.ComponentRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(PerfmonManifestSymbolFields.File), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(PerfmonManifestSymbolFields.ResourceFileDirectory), IntermediateFieldType.String),
17 },
18 typeof(PerfmonManifestSymbol));
19 }
20}
21
22namespace WixToolset.Util.Symbols
23{
24 using WixToolset.Data;
25
26 public enum PerfmonManifestSymbolFields
27 {
28 ComponentRef,
29 File,
30 ResourceFileDirectory,
31 }
32
33 public class PerfmonManifestSymbol : IntermediateSymbol
34 {
35 public PerfmonManifestSymbol() : base(UtilSymbolDefinitions.PerfmonManifest, null, null)
36 {
37 }
38
39 public PerfmonManifestSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.PerfmonManifest, sourceLineNumber, id)
40 {
41 }
42
43 public IntermediateField this[PerfmonManifestSymbolFields index] => this.Fields[(int)index];
44
45 public string ComponentRef
46 {
47 get => this.Fields[(int)PerfmonManifestSymbolFields.ComponentRef].AsString();
48 set => this.Set((int)PerfmonManifestSymbolFields.ComponentRef, value);
49 }
50
51 public string File
52 {
53 get => this.Fields[(int)PerfmonManifestSymbolFields.File].AsString();
54 set => this.Set((int)PerfmonManifestSymbolFields.File, value);
55 }
56
57 public string ResourceFileDirectory
58 {
59 get => this.Fields[(int)PerfmonManifestSymbolFields.ResourceFileDirectory].AsString();
60 set => this.Set((int)PerfmonManifestSymbolFields.ResourceFileDirectory, value);
61 }
62 }
63} \ No newline at end of file
diff --git a/src/ext/Util/wixext/Symbols/PerfmonSymbol.cs b/src/ext/Util/wixext/Symbols/PerfmonSymbol.cs
new file mode 100644
index 00000000..6784ebd1
--- /dev/null
+++ b/src/ext/Util/wixext/Symbols/PerfmonSymbol.cs
@@ -0,0 +1,63 @@
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
3namespace WixToolset.Util
4{
5 using WixToolset.Data;
6 using WixToolset.Util.Symbols;
7
8 public static partial class UtilSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition Perfmon = new IntermediateSymbolDefinition(
11 UtilSymbolDefinitionType.Perfmon.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(PerfmonSymbolFields.ComponentRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(PerfmonSymbolFields.File), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(PerfmonSymbolFields.Name), IntermediateFieldType.String),
17 },
18 typeof(PerfmonSymbol));
19 }
20}
21
22namespace WixToolset.Util.Symbols
23{
24 using WixToolset.Data;
25
26 public enum PerfmonSymbolFields
27 {
28 ComponentRef,
29 File,
30 Name,
31 }
32
33 public class PerfmonSymbol : IntermediateSymbol
34 {
35 public PerfmonSymbol() : base(UtilSymbolDefinitions.Perfmon, null, null)
36 {
37 }
38
39 public PerfmonSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.Perfmon, sourceLineNumber, id)
40 {
41 }
42
43 public IntermediateField this[PerfmonSymbolFields index] => this.Fields[(int)index];
44
45 public string ComponentRef
46 {
47 get => this.Fields[(int)PerfmonSymbolFields.ComponentRef].AsString();
48 set => this.Set((int)PerfmonSymbolFields.ComponentRef, value);
49 }
50
51 public string File
52 {
53 get => this.Fields[(int)PerfmonSymbolFields.File].AsString();
54 set => this.Set((int)PerfmonSymbolFields.File, value);
55 }
56
57 public string Name
58 {
59 get => this.Fields[(int)PerfmonSymbolFields.Name].AsString();
60 set => this.Set((int)PerfmonSymbolFields.Name, value);
61 }
62 }
63} \ No newline at end of file
diff --git a/src/ext/Util/wixext/Symbols/PerformanceCategorySymbol.cs b/src/ext/Util/wixext/Symbols/PerformanceCategorySymbol.cs
new file mode 100644
index 00000000..5ecf388c
--- /dev/null
+++ b/src/ext/Util/wixext/Symbols/PerformanceCategorySymbol.cs
@@ -0,0 +1,71 @@
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
3namespace WixToolset.Util
4{
5 using WixToolset.Data;
6 using WixToolset.Util.Symbols;
7
8 public static partial class UtilSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition PerformanceCategory = new IntermediateSymbolDefinition(
11 UtilSymbolDefinitionType.PerformanceCategory.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(PerformanceCategorySymbolFields.ComponentRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(PerformanceCategorySymbolFields.Name), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(PerformanceCategorySymbolFields.IniData), IntermediateFieldType.String),
17 new IntermediateFieldDefinition(nameof(PerformanceCategorySymbolFields.ConstantData), IntermediateFieldType.String),
18 },
19 typeof(PerformanceCategorySymbol));
20 }
21}
22
23namespace WixToolset.Util.Symbols
24{
25 using WixToolset.Data;
26
27 public enum PerformanceCategorySymbolFields
28 {
29 ComponentRef,
30 Name,
31 IniData,
32 ConstantData,
33 }
34
35 public class PerformanceCategorySymbol : IntermediateSymbol
36 {
37 public PerformanceCategorySymbol() : base(UtilSymbolDefinitions.PerformanceCategory, null, null)
38 {
39 }
40
41 public PerformanceCategorySymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.PerformanceCategory, sourceLineNumber, id)
42 {
43 }
44
45 public IntermediateField this[PerformanceCategorySymbolFields index] => this.Fields[(int)index];
46
47 public string ComponentRef
48 {
49 get => this.Fields[(int)PerformanceCategorySymbolFields.ComponentRef].AsString();
50 set => this.Set((int)PerformanceCategorySymbolFields.ComponentRef, value);
51 }
52
53 public string Name
54 {
55 get => this.Fields[(int)PerformanceCategorySymbolFields.Name].AsString();
56 set => this.Set((int)PerformanceCategorySymbolFields.Name, value);
57 }
58
59 public string IniData
60 {
61 get => this.Fields[(int)PerformanceCategorySymbolFields.IniData].AsString();
62 set => this.Set((int)PerformanceCategorySymbolFields.IniData, value);
63 }
64
65 public string ConstantData
66 {
67 get => this.Fields[(int)PerformanceCategorySymbolFields.ConstantData].AsString();
68 set => this.Set((int)PerformanceCategorySymbolFields.ConstantData, value);
69 }
70 }
71} \ No newline at end of file
diff --git a/src/ext/Util/wixext/Symbols/SecureObjectsSymbol.cs b/src/ext/Util/wixext/Symbols/SecureObjectsSymbol.cs
new file mode 100644
index 00000000..25fc6dca
--- /dev/null
+++ b/src/ext/Util/wixext/Symbols/SecureObjectsSymbol.cs
@@ -0,0 +1,103 @@
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
3namespace WixToolset.Util
4{
5 using WixToolset.Data;
6 using WixToolset.Util.Symbols;
7
8 public static partial class UtilSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition SecureObjects = new IntermediateSymbolDefinition(
11 UtilSymbolDefinitionType.SecureObjects.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(SecureObjectsSymbolFields.SecureObject), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(SecureObjectsSymbolFields.Table), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(SecureObjectsSymbolFields.Domain), IntermediateFieldType.String),
17 new IntermediateFieldDefinition(nameof(SecureObjectsSymbolFields.User), IntermediateFieldType.String),
18 new IntermediateFieldDefinition(nameof(SecureObjectsSymbolFields.Attributes), IntermediateFieldType.Number),
19 new IntermediateFieldDefinition(nameof(SecureObjectsSymbolFields.Permission), IntermediateFieldType.Number),
20 new IntermediateFieldDefinition(nameof(SecureObjectsSymbolFields.ComponentRef), IntermediateFieldType.String),
21 },
22 typeof(SecureObjectsSymbol));
23 }
24}
25
26namespace WixToolset.Util.Symbols
27{
28 using System;
29 using WixToolset.Data;
30
31 public enum SecureObjectsSymbolFields
32 {
33 SecureObject,
34 Table,
35 Domain,
36 User,
37 Attributes,
38 Permission,
39 ComponentRef,
40 }
41
42 [Flags]
43 public enum WixPermissionExAttributes
44 {
45 None = 0x0,
46 Inheritable = 0x01
47 }
48
49 public class SecureObjectsSymbol : IntermediateSymbol
50 {
51 public SecureObjectsSymbol() : base(UtilSymbolDefinitions.SecureObjects, null, null)
52 {
53 }
54
55 public SecureObjectsSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.SecureObjects, sourceLineNumber, id)
56 {
57 }
58
59 public IntermediateField this[SecureObjectsSymbolFields index] => this.Fields[(int)index];
60
61 public string SecureObject
62 {
63 get => this.Fields[(int)SecureObjectsSymbolFields.SecureObject].AsString();
64 set => this.Set((int)SecureObjectsSymbolFields.SecureObject, value);
65 }
66
67 public string Table
68 {
69 get => this.Fields[(int)SecureObjectsSymbolFields.Table].AsString();
70 set => this.Set((int)SecureObjectsSymbolFields.Table, value);
71 }
72
73 public string Domain
74 {
75 get => this.Fields[(int)SecureObjectsSymbolFields.Domain].AsString();
76 set => this.Set((int)SecureObjectsSymbolFields.Domain, value);
77 }
78
79 public string User
80 {
81 get => this.Fields[(int)SecureObjectsSymbolFields.User].AsString();
82 set => this.Set((int)SecureObjectsSymbolFields.User, value);
83 }
84
85 public WixPermissionExAttributes Attributes
86 {
87 get => (WixPermissionExAttributes)this.Fields[(int)SecureObjectsSymbolFields.Attributes].AsNumber();
88 set => this.Set((int)SecureObjectsSymbolFields.Attributes, (int)value);
89 }
90
91 public int? Permission
92 {
93 get => this.Fields[(int)SecureObjectsSymbolFields.Permission].AsNullableNumber();
94 set => this.Set((int)SecureObjectsSymbolFields.Permission, value);
95 }
96
97 public string ComponentRef
98 {
99 get => this.Fields[(int)SecureObjectsSymbolFields.ComponentRef].AsString();
100 set => this.Set((int)SecureObjectsSymbolFields.ComponentRef, value);
101 }
102 }
103} \ No newline at end of file
diff --git a/src/ext/Util/wixext/Symbols/ServiceConfigSymbol.cs b/src/ext/Util/wixext/Symbols/ServiceConfigSymbol.cs
new file mode 100644
index 00000000..3a877f9b
--- /dev/null
+++ b/src/ext/Util/wixext/Symbols/ServiceConfigSymbol.cs
@@ -0,0 +1,119 @@
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
3namespace WixToolset.Util
4{
5 using WixToolset.Data;
6 using WixToolset.Util.Symbols;
7
8 public static partial class UtilSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition ServiceConfig = new IntermediateSymbolDefinition(
11 UtilSymbolDefinitionType.ServiceConfig.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.ServiceName), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.ComponentRef), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.NewService), IntermediateFieldType.Number),
17 new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.FirstFailureActionType), IntermediateFieldType.String),
18 new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.SecondFailureActionType), IntermediateFieldType.String),
19 new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.ThirdFailureActionType), IntermediateFieldType.String),
20 new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.ResetPeriodInDays), IntermediateFieldType.Number),
21 new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.RestartServiceDelayInSeconds), IntermediateFieldType.Number),
22 new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.ProgramCommandLine), IntermediateFieldType.String),
23 new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.RebootMessage), IntermediateFieldType.String),
24 },
25 typeof(ServiceConfigSymbol));
26 }
27}
28
29namespace WixToolset.Util.Symbols
30{
31 using WixToolset.Data;
32
33 public enum ServiceConfigSymbolFields
34 {
35 ServiceName,
36 ComponentRef,
37 NewService,
38 FirstFailureActionType,
39 SecondFailureActionType,
40 ThirdFailureActionType,
41 ResetPeriodInDays,
42 RestartServiceDelayInSeconds,
43 ProgramCommandLine,
44 RebootMessage,
45 }
46
47 public class ServiceConfigSymbol : IntermediateSymbol
48 {
49 public ServiceConfigSymbol() : base(UtilSymbolDefinitions.ServiceConfig, null, null)
50 {
51 }
52
53 public ServiceConfigSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.ServiceConfig, sourceLineNumber, id)
54 {
55 }
56
57 public IntermediateField this[ServiceConfigSymbolFields index] => this.Fields[(int)index];
58
59 public string ServiceName
60 {
61 get => this.Fields[(int)ServiceConfigSymbolFields.ServiceName].AsString();
62 set => this.Set((int)ServiceConfigSymbolFields.ServiceName, value);
63 }
64
65 public string ComponentRef
66 {
67 get => this.Fields[(int)ServiceConfigSymbolFields.ComponentRef].AsString();
68 set => this.Set((int)ServiceConfigSymbolFields.ComponentRef, value);
69 }
70
71 public int NewService
72 {
73 get => this.Fields[(int)ServiceConfigSymbolFields.NewService].AsNumber();
74 set => this.Set((int)ServiceConfigSymbolFields.NewService, value);
75 }
76
77 public string FirstFailureActionType
78 {
79 get => this.Fields[(int)ServiceConfigSymbolFields.FirstFailureActionType].AsString();
80 set => this.Set((int)ServiceConfigSymbolFields.FirstFailureActionType, value);
81 }
82
83 public string SecondFailureActionType
84 {
85 get => this.Fields[(int)ServiceConfigSymbolFields.SecondFailureActionType].AsString();
86 set => this.Set((int)ServiceConfigSymbolFields.SecondFailureActionType, value);
87 }
88
89 public string ThirdFailureActionType
90 {
91 get => this.Fields[(int)ServiceConfigSymbolFields.ThirdFailureActionType].AsString();
92 set => this.Set((int)ServiceConfigSymbolFields.ThirdFailureActionType, value);
93 }
94
95 public int? ResetPeriodInDays
96 {
97 get => this.Fields[(int)ServiceConfigSymbolFields.ResetPeriodInDays].AsNullableNumber();
98 set => this.Set((int)ServiceConfigSymbolFields.ResetPeriodInDays, value);
99 }
100
101 public int? RestartServiceDelayInSeconds
102 {
103 get => this.Fields[(int)ServiceConfigSymbolFields.RestartServiceDelayInSeconds].AsNullableNumber();
104 set => this.Set((int)ServiceConfigSymbolFields.RestartServiceDelayInSeconds, value);
105 }
106
107 public string ProgramCommandLine
108 {
109 get => this.Fields[(int)ServiceConfigSymbolFields.ProgramCommandLine].AsString();
110 set => this.Set((int)ServiceConfigSymbolFields.ProgramCommandLine, value);
111 }
112
113 public string RebootMessage
114 {
115 get => this.Fields[(int)ServiceConfigSymbolFields.RebootMessage].AsString();
116 set => this.Set((int)ServiceConfigSymbolFields.RebootMessage, value);
117 }
118 }
119} \ No newline at end of file
diff --git a/src/ext/Util/wixext/Symbols/UserGroupSymbol.cs b/src/ext/Util/wixext/Symbols/UserGroupSymbol.cs
new file mode 100644
index 00000000..c8f3998e
--- /dev/null
+++ b/src/ext/Util/wixext/Symbols/UserGroupSymbol.cs
@@ -0,0 +1,55 @@
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
3namespace WixToolset.Util
4{
5 using WixToolset.Data;
6 using WixToolset.Util.Symbols;
7
8 public static partial class UtilSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition UserGroup = new IntermediateSymbolDefinition(
11 UtilSymbolDefinitionType.UserGroup.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(UserGroupSymbolFields.UserRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(UserGroupSymbolFields.GroupRef), IntermediateFieldType.String),
16 },
17 typeof(UserGroupSymbol));
18 }
19}
20
21namespace WixToolset.Util.Symbols
22{
23 using WixToolset.Data;
24
25 public enum UserGroupSymbolFields
26 {
27 UserRef,
28 GroupRef,
29 }
30
31 public class UserGroupSymbol : IntermediateSymbol
32 {
33 public UserGroupSymbol() : base(UtilSymbolDefinitions.UserGroup, null, null)
34 {
35 }
36
37 public UserGroupSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.UserGroup, sourceLineNumber, id)
38 {
39 }
40
41 public IntermediateField this[UserGroupSymbolFields index] => this.Fields[(int)index];
42
43 public string UserRef
44 {
45 get => this.Fields[(int)UserGroupSymbolFields.UserRef].AsString();
46 set => this.Set((int)UserGroupSymbolFields.UserRef, value);
47 }
48
49 public string GroupRef
50 {
51 get => this.Fields[(int)UserGroupSymbolFields.GroupRef].AsString();
52 set => this.Set((int)UserGroupSymbolFields.GroupRef, value);
53 }
54 }
55} \ No newline at end of file
diff --git a/src/ext/Util/wixext/Symbols/UserSymbol.cs b/src/ext/Util/wixext/Symbols/UserSymbol.cs
new file mode 100644
index 00000000..5f00064b
--- /dev/null
+++ b/src/ext/Util/wixext/Symbols/UserSymbol.cs
@@ -0,0 +1,79 @@
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
3namespace WixToolset.Util
4{
5 using WixToolset.Data;
6 using WixToolset.Util.Symbols;
7
8 public static partial class UtilSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition User = new IntermediateSymbolDefinition(
11 UtilSymbolDefinitionType.User.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(UserSymbolFields.ComponentRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(UserSymbolFields.Name), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(UserSymbolFields.Domain), IntermediateFieldType.String),
17 new IntermediateFieldDefinition(nameof(UserSymbolFields.Password), IntermediateFieldType.String),
18 new IntermediateFieldDefinition(nameof(UserSymbolFields.Attributes), IntermediateFieldType.Number),
19 },
20 typeof(UserSymbol));
21 }
22}
23
24namespace WixToolset.Util.Symbols
25{
26 using WixToolset.Data;
27
28 public enum UserSymbolFields
29 {
30 ComponentRef,
31 Name,
32 Domain,
33 Password,
34 Attributes,
35 }
36
37 public class UserSymbol : IntermediateSymbol
38 {
39 public UserSymbol() : base(UtilSymbolDefinitions.User, null, null)
40 {
41 }
42
43 public UserSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.User, sourceLineNumber, id)
44 {
45 }
46
47 public IntermediateField this[UserSymbolFields index] => this.Fields[(int)index];
48
49 public string ComponentRef
50 {
51 get => this.Fields[(int)UserSymbolFields.ComponentRef].AsString();
52 set => this.Set((int)UserSymbolFields.ComponentRef, value);
53 }
54
55 public string Name
56 {
57 get => this.Fields[(int)UserSymbolFields.Name].AsString();
58 set => this.Set((int)UserSymbolFields.Name, value);
59 }
60
61 public string Domain
62 {
63 get => this.Fields[(int)UserSymbolFields.Domain].AsString();
64 set => this.Set((int)UserSymbolFields.Domain, value);
65 }
66
67 public string Password
68 {
69 get => this.Fields[(int)UserSymbolFields.Password].AsString();
70 set => this.Set((int)UserSymbolFields.Password, value);
71 }
72
73 public int Attributes
74 {
75 get => this.Fields[(int)UserSymbolFields.Attributes].AsNumber();
76 set => this.Set((int)UserSymbolFields.Attributes, value);
77 }
78 }
79} \ No newline at end of file
diff --git a/src/ext/Util/wixext/Symbols/UtilSymbolDefinitions.cs b/src/ext/Util/wixext/Symbols/UtilSymbolDefinitions.cs
new file mode 100644
index 00000000..72091c3b
--- /dev/null
+++ b/src/ext/Util/wixext/Symbols/UtilSymbolDefinitions.cs
@@ -0,0 +1,125 @@
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
3namespace WixToolset.Util
4{
5 using System;
6 using WixToolset.Data;
7 using WixToolset.Data.Burn;
8
9 public enum UtilSymbolDefinitionType
10 {
11 EventManifest,
12 FileShare,
13 FileSharePermissions,
14 Group,
15 Perfmon,
16 PerfmonManifest,
17 PerformanceCategory,
18 SecureObjects,
19 ServiceConfig,
20 User,
21 UserGroup,
22 WixCloseApplication,
23 WixFormatFiles,
24 WixInternetShortcut,
25 WixRemoveFolderEx,
26 WixRemoveRegistryKeyEx,
27 WixRestartResource,
28 WixTouchFile,
29 WixWindowsFeatureSearch,
30 XmlConfig,
31 XmlFile,
32 }
33
34 public static partial class UtilSymbolDefinitions
35 {
36 public static readonly Version Version = new Version("4.0.0");
37
38 public static IntermediateSymbolDefinition ByName(string name)
39 {
40 if (!Enum.TryParse(name, out UtilSymbolDefinitionType type))
41 {
42 return null;
43 }
44
45 return ByType(type);
46 }
47
48 public static IntermediateSymbolDefinition ByType(UtilSymbolDefinitionType type)
49 {
50 switch (type)
51 {
52 case UtilSymbolDefinitionType.EventManifest:
53 return UtilSymbolDefinitions.EventManifest;
54
55 case UtilSymbolDefinitionType.FileShare:
56 return UtilSymbolDefinitions.FileShare;
57
58 case UtilSymbolDefinitionType.FileSharePermissions:
59 return UtilSymbolDefinitions.FileSharePermissions;
60
61 case UtilSymbolDefinitionType.Group:
62 return UtilSymbolDefinitions.Group;
63
64 case UtilSymbolDefinitionType.Perfmon:
65 return UtilSymbolDefinitions.Perfmon;
66
67 case UtilSymbolDefinitionType.PerfmonManifest:
68 return UtilSymbolDefinitions.PerfmonManifest;
69
70 case UtilSymbolDefinitionType.PerformanceCategory:
71 return UtilSymbolDefinitions.PerformanceCategory;
72
73 case UtilSymbolDefinitionType.SecureObjects:
74 return UtilSymbolDefinitions.SecureObjects;
75
76 case UtilSymbolDefinitionType.ServiceConfig:
77 return UtilSymbolDefinitions.ServiceConfig;
78
79 case UtilSymbolDefinitionType.User:
80 return UtilSymbolDefinitions.User;
81
82 case UtilSymbolDefinitionType.UserGroup:
83 return UtilSymbolDefinitions.UserGroup;
84
85 case UtilSymbolDefinitionType.WixCloseApplication:
86 return UtilSymbolDefinitions.WixCloseApplication;
87
88 case UtilSymbolDefinitionType.WixFormatFiles:
89 return UtilSymbolDefinitions.WixFormatFiles;
90
91 case UtilSymbolDefinitionType.WixInternetShortcut:
92 return UtilSymbolDefinitions.WixInternetShortcut;
93
94 case UtilSymbolDefinitionType.WixRemoveFolderEx:
95 return UtilSymbolDefinitions.WixRemoveFolderEx;
96
97 case UtilSymbolDefinitionType.WixRemoveRegistryKeyEx:
98 return UtilSymbolDefinitions.WixRemoveRegistryKeyEx;
99
100 case UtilSymbolDefinitionType.WixRestartResource:
101 return UtilSymbolDefinitions.WixRestartResource;
102
103 case UtilSymbolDefinitionType.WixTouchFile:
104 return UtilSymbolDefinitions.WixTouchFile;
105
106 case UtilSymbolDefinitionType.WixWindowsFeatureSearch:
107 return UtilSymbolDefinitions.WixWindowsFeatureSearch;
108
109 case UtilSymbolDefinitionType.XmlConfig:
110 return UtilSymbolDefinitions.XmlConfig;
111
112 case UtilSymbolDefinitionType.XmlFile:
113 return UtilSymbolDefinitions.XmlFile;
114
115 default:
116 throw new ArgumentOutOfRangeException(nameof(type));
117 }
118 }
119
120 static UtilSymbolDefinitions()
121 {
122 WixWindowsFeatureSearch.AddTag(BurnConstants.BundleExtensionSearchSymbolDefinitionTag);
123 }
124 }
125}
diff --git a/src/ext/Util/wixext/Symbols/WixCloseApplicationSymbol.cs b/src/ext/Util/wixext/Symbols/WixCloseApplicationSymbol.cs
new file mode 100644
index 00000000..0738e3e4
--- /dev/null
+++ b/src/ext/Util/wixext/Symbols/WixCloseApplicationSymbol.cs
@@ -0,0 +1,103 @@
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
3namespace WixToolset.Util
4{
5 using WixToolset.Data;
6 using WixToolset.Util.Symbols;
7
8 public static partial class UtilSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition WixCloseApplication = new IntermediateSymbolDefinition(
11 UtilSymbolDefinitionType.WixCloseApplication.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(WixCloseApplicationSymbolFields.Target), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(WixCloseApplicationSymbolFields.Description), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(WixCloseApplicationSymbolFields.Condition), IntermediateFieldType.String),
17 new IntermediateFieldDefinition(nameof(WixCloseApplicationSymbolFields.Attributes), IntermediateFieldType.Number),
18 new IntermediateFieldDefinition(nameof(WixCloseApplicationSymbolFields.Sequence), IntermediateFieldType.Number),
19 new IntermediateFieldDefinition(nameof(WixCloseApplicationSymbolFields.Property), IntermediateFieldType.String),
20 new IntermediateFieldDefinition(nameof(WixCloseApplicationSymbolFields.TerminateExitCode), IntermediateFieldType.Number),
21 new IntermediateFieldDefinition(nameof(WixCloseApplicationSymbolFields.Timeout), IntermediateFieldType.Number),
22 },
23 typeof(WixCloseApplicationSymbol));
24 }
25}
26
27namespace WixToolset.Util.Symbols
28{
29 using WixToolset.Data;
30
31 public enum WixCloseApplicationSymbolFields
32 {
33 Target,
34 Description,
35 Condition,
36 Attributes,
37 Sequence,
38 Property,
39 TerminateExitCode,
40 Timeout,
41 }
42
43 public class WixCloseApplicationSymbol : IntermediateSymbol
44 {
45 public WixCloseApplicationSymbol() : base(UtilSymbolDefinitions.WixCloseApplication, null, null)
46 {
47 }
48
49 public WixCloseApplicationSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.WixCloseApplication, sourceLineNumber, id)
50 {
51 }
52
53 public IntermediateField this[WixCloseApplicationSymbolFields index] => this.Fields[(int)index];
54
55 public string Target
56 {
57 get => this.Fields[(int)WixCloseApplicationSymbolFields.Target].AsString();
58 set => this.Set((int)WixCloseApplicationSymbolFields.Target, value);
59 }
60
61 public string Description
62 {
63 get => this.Fields[(int)WixCloseApplicationSymbolFields.Description].AsString();
64 set => this.Set((int)WixCloseApplicationSymbolFields.Description, value);
65 }
66
67 public string Condition
68 {
69 get => this.Fields[(int)WixCloseApplicationSymbolFields.Condition].AsString();
70 set => this.Set((int)WixCloseApplicationSymbolFields.Condition, value);
71 }
72
73 public int Attributes
74 {
75 get => this.Fields[(int)WixCloseApplicationSymbolFields.Attributes].AsNumber();
76 set => this.Set((int)WixCloseApplicationSymbolFields.Attributes, value);
77 }
78
79 public int? Sequence
80 {
81 get => this.Fields[(int)WixCloseApplicationSymbolFields.Sequence].AsNullableNumber();
82 set => this.Set((int)WixCloseApplicationSymbolFields.Sequence, value);
83 }
84
85 public string Property
86 {
87 get => this.Fields[(int)WixCloseApplicationSymbolFields.Property].AsString();
88 set => this.Set((int)WixCloseApplicationSymbolFields.Property, value);
89 }
90
91 public int? TerminateExitCode
92 {
93 get => this.Fields[(int)WixCloseApplicationSymbolFields.TerminateExitCode].AsNullableNumber();
94 set => this.Set((int)WixCloseApplicationSymbolFields.TerminateExitCode, value);
95 }
96
97 public int? Timeout
98 {
99 get => this.Fields[(int)WixCloseApplicationSymbolFields.Timeout].AsNullableNumber();
100 set => this.Set((int)WixCloseApplicationSymbolFields.Timeout, value);
101 }
102 }
103} \ No newline at end of file
diff --git a/src/ext/Util/wixext/Symbols/WixFormatFilesSymbol.cs b/src/ext/Util/wixext/Symbols/WixFormatFilesSymbol.cs
new file mode 100644
index 00000000..38a9b8ff
--- /dev/null
+++ b/src/ext/Util/wixext/Symbols/WixFormatFilesSymbol.cs
@@ -0,0 +1,55 @@
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
3namespace WixToolset.Util
4{
5 using WixToolset.Data;
6 using WixToolset.Util.Symbols;
7
8 public static partial class UtilSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition WixFormatFiles = new IntermediateSymbolDefinition(
11 UtilSymbolDefinitionType.WixFormatFiles.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(WixFormatFilesSymbolFields.BinaryRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(WixFormatFilesSymbolFields.FileRef), IntermediateFieldType.String),
16 },
17 typeof(WixFormatFilesSymbol));
18 }
19}
20
21namespace WixToolset.Util.Symbols
22{
23 using WixToolset.Data;
24
25 public enum WixFormatFilesSymbolFields
26 {
27 BinaryRef,
28 FileRef,
29 }
30
31 public class WixFormatFilesSymbol : IntermediateSymbol
32 {
33 public WixFormatFilesSymbol() : base(UtilSymbolDefinitions.WixFormatFiles, null, null)
34 {
35 }
36
37 public WixFormatFilesSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.WixFormatFiles, sourceLineNumber, id)
38 {
39 }
40
41 public IntermediateField this[WixFormatFilesSymbolFields index] => this.Fields[(int)index];
42
43 public string BinaryRef
44 {
45 get => this.Fields[(int)WixFormatFilesSymbolFields.BinaryRef].AsString();
46 set => this.Set((int)WixFormatFilesSymbolFields.BinaryRef, value);
47 }
48
49 public string FileRef
50 {
51 get => this.Fields[(int)WixFormatFilesSymbolFields.FileRef].AsString();
52 set => this.Set((int)WixFormatFilesSymbolFields.FileRef, value);
53 }
54 }
55} \ No newline at end of file
diff --git a/src/ext/Util/wixext/Symbols/WixInternetShortcutSymbol.cs b/src/ext/Util/wixext/Symbols/WixInternetShortcutSymbol.cs
new file mode 100644
index 00000000..e8265e02
--- /dev/null
+++ b/src/ext/Util/wixext/Symbols/WixInternetShortcutSymbol.cs
@@ -0,0 +1,95 @@
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
3namespace WixToolset.Util
4{
5 using WixToolset.Data;
6 using WixToolset.Util.Symbols;
7
8 public static partial class UtilSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition WixInternetShortcut = new IntermediateSymbolDefinition(
11 UtilSymbolDefinitionType.WixInternetShortcut.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(WixInternetShortcutSymbolFields.ComponentRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(WixInternetShortcutSymbolFields.DirectoryRef), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(WixInternetShortcutSymbolFields.Name), IntermediateFieldType.String),
17 new IntermediateFieldDefinition(nameof(WixInternetShortcutSymbolFields.Target), IntermediateFieldType.String),
18 new IntermediateFieldDefinition(nameof(WixInternetShortcutSymbolFields.Attributes), IntermediateFieldType.Number),
19 new IntermediateFieldDefinition(nameof(WixInternetShortcutSymbolFields.IconFile), IntermediateFieldType.String),
20 new IntermediateFieldDefinition(nameof(WixInternetShortcutSymbolFields.IconIndex), IntermediateFieldType.Number),
21 },
22 typeof(WixInternetShortcutSymbol));
23 }
24}
25
26namespace WixToolset.Util.Symbols
27{
28 using WixToolset.Data;
29
30 public enum WixInternetShortcutSymbolFields
31 {
32 ComponentRef,
33 DirectoryRef,
34 Name,
35 Target,
36 Attributes,
37 IconFile,
38 IconIndex,
39 }
40
41 public class WixInternetShortcutSymbol : IntermediateSymbol
42 {
43 public WixInternetShortcutSymbol() : base(UtilSymbolDefinitions.WixInternetShortcut, null, null)
44 {
45 }
46
47 public WixInternetShortcutSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.WixInternetShortcut, sourceLineNumber, id)
48 {
49 }
50
51 public IntermediateField this[WixInternetShortcutSymbolFields index] => this.Fields[(int)index];
52
53 public string ComponentRef
54 {
55 get => this.Fields[(int)WixInternetShortcutSymbolFields.ComponentRef].AsString();
56 set => this.Set((int)WixInternetShortcutSymbolFields.ComponentRef, value);
57 }
58
59 public string DirectoryRef
60 {
61 get => this.Fields[(int)WixInternetShortcutSymbolFields.DirectoryRef].AsString();
62 set => this.Set((int)WixInternetShortcutSymbolFields.DirectoryRef, value);
63 }
64
65 public string Name
66 {
67 get => this.Fields[(int)WixInternetShortcutSymbolFields.Name].AsString();
68 set => this.Set((int)WixInternetShortcutSymbolFields.Name, value);
69 }
70
71 public string Target
72 {
73 get => this.Fields[(int)WixInternetShortcutSymbolFields.Target].AsString();
74 set => this.Set((int)WixInternetShortcutSymbolFields.Target, value);
75 }
76
77 public int Attributes
78 {
79 get => this.Fields[(int)WixInternetShortcutSymbolFields.Attributes].AsNumber();
80 set => this.Set((int)WixInternetShortcutSymbolFields.Attributes, value);
81 }
82
83 public string IconFile
84 {
85 get => this.Fields[(int)WixInternetShortcutSymbolFields.IconFile].AsString();
86 set => this.Set((int)WixInternetShortcutSymbolFields.IconFile, value);
87 }
88
89 public int? IconIndex
90 {
91 get => this.Fields[(int)WixInternetShortcutSymbolFields.IconIndex].AsNullableNumber();
92 set => this.Set((int)WixInternetShortcutSymbolFields.IconIndex, value);
93 }
94 }
95} \ No newline at end of file
diff --git a/src/ext/Util/wixext/Symbols/WixRemoveFolderExSymbol.cs b/src/ext/Util/wixext/Symbols/WixRemoveFolderExSymbol.cs
new file mode 100644
index 00000000..86352b6c
--- /dev/null
+++ b/src/ext/Util/wixext/Symbols/WixRemoveFolderExSymbol.cs
@@ -0,0 +1,78 @@
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
3namespace WixToolset.Util
4{
5 using WixToolset.Data;
6 using WixToolset.Util.Symbols;
7
8 public static partial class UtilSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition WixRemoveFolderEx = new IntermediateSymbolDefinition(
11 UtilSymbolDefinitionType.WixRemoveFolderEx.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(WixRemoveFolderExSymbolFields.ComponentRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(WixRemoveFolderExSymbolFields.Property), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(WixRemoveFolderExSymbolFields.InstallMode), IntermediateFieldType.Number),
17 new IntermediateFieldDefinition(nameof(WixRemoveFolderExSymbolFields.Condition), IntermediateFieldType.String),
18 },
19 typeof(WixRemoveFolderExSymbol));
20 }
21}
22
23namespace WixToolset.Util.Symbols
24{
25 using WixToolset.Data;
26
27 public enum WixRemoveFolderExSymbolFields
28 {
29 ComponentRef,
30 Property,
31 InstallMode,
32 Condition,
33 }
34
35 public enum WixRemoveFolderExInstallMode
36 {
37 Install = 1,
38 Uninstall = 2,
39 Both = 3,
40 }
41
42 public class WixRemoveFolderExSymbol : IntermediateSymbol
43 {
44 public WixRemoveFolderExSymbol() : base(UtilSymbolDefinitions.WixRemoveFolderEx, null, null)
45 {
46 }
47
48 public WixRemoveFolderExSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.WixRemoveFolderEx, sourceLineNumber, id)
49 {
50 }
51
52 public IntermediateField this[WixRemoveFolderExSymbolFields index] => this.Fields[(int)index];
53
54 public string ComponentRef
55 {
56 get => this.Fields[(int)WixRemoveFolderExSymbolFields.ComponentRef].AsString();
57 set => this.Set((int)WixRemoveFolderExSymbolFields.ComponentRef, value);
58 }
59
60 public string Property
61 {
62 get => this.Fields[(int)WixRemoveFolderExSymbolFields.Property].AsString();
63 set => this.Set((int)WixRemoveFolderExSymbolFields.Property, value);
64 }
65
66 public WixRemoveFolderExInstallMode InstallMode
67 {
68 get => (WixRemoveFolderExInstallMode)this.Fields[(int)WixRemoveFolderExSymbolFields.InstallMode].AsNumber();
69 set => this.Set((int)WixRemoveFolderExSymbolFields.InstallMode, (int)value);
70 }
71
72 public string Condition
73 {
74 get => this.Fields[(int)WixRemoveFolderExSymbolFields.Condition].AsString();
75 set => this.Set((int)WixRemoveFolderExSymbolFields.Condition, value);
76 }
77 }
78} \ No newline at end of file
diff --git a/src/ext/Util/wixext/Symbols/WixRemoveRegistryKeyExSymbol.cs b/src/ext/Util/wixext/Symbols/WixRemoveRegistryKeyExSymbol.cs
new file mode 100644
index 00000000..8e4bd212
--- /dev/null
+++ b/src/ext/Util/wixext/Symbols/WixRemoveRegistryKeyExSymbol.cs
@@ -0,0 +1,86 @@
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
3namespace WixToolset.Util
4{
5 using WixToolset.Data;
6 using WixToolset.Util.Symbols;
7
8 public static partial class UtilSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition WixRemoveRegistryKeyEx = new IntermediateSymbolDefinition(
11 UtilSymbolDefinitionType.WixRemoveRegistryKeyEx.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(WixRemoveRegistryKeyExSymbolFields.ComponentRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(WixRemoveRegistryKeyExSymbolFields.Root), IntermediateFieldType.Number),
16 new IntermediateFieldDefinition(nameof(WixRemoveRegistryKeyExSymbolFields.Key), IntermediateFieldType.String),
17 new IntermediateFieldDefinition(nameof(WixRemoveRegistryKeyExSymbolFields.InstallMode), IntermediateFieldType.Number),
18 new IntermediateFieldDefinition(nameof(WixRemoveRegistryKeyExSymbolFields.Condition), IntermediateFieldType.String),
19 },
20 typeof(WixRemoveRegistryKeyExSymbol));
21 }
22}
23
24namespace WixToolset.Util.Symbols
25{
26 using WixToolset.Data;
27 using WixToolset.Data.Symbols;
28
29 public enum WixRemoveRegistryKeyExSymbolFields
30 {
31 ComponentRef,
32 Root,
33 Key,
34 InstallMode,
35 Condition,
36 }
37
38 public enum WixRemoveRegistryKeyExInstallMode
39 {
40 Install = 1,
41 Uninstall = 2,
42 }
43
44 public class WixRemoveRegistryKeyExSymbol : IntermediateSymbol
45 {
46 public WixRemoveRegistryKeyExSymbol() : base(UtilSymbolDefinitions.WixRemoveRegistryKeyEx, null, null)
47 {
48 }
49
50 public WixRemoveRegistryKeyExSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.WixRemoveRegistryKeyEx, sourceLineNumber, id)
51 {
52 }
53
54 public IntermediateField this[WixRemoveRegistryKeyExSymbolFields index] => this.Fields[(int)index];
55
56 public string ComponentRef
57 {
58 get => this.Fields[(int)WixRemoveRegistryKeyExSymbolFields.ComponentRef].AsString();
59 set => this.Set((int)WixRemoveRegistryKeyExSymbolFields.ComponentRef, value);
60 }
61
62 public RegistryRootType Root
63 {
64 get => (RegistryRootType)this.Fields[(int)WixRemoveRegistryKeyExSymbolFields.Root].AsNumber();
65 set => this.Set((int)WixRemoveRegistryKeyExSymbolFields.Root, (int)value);
66 }
67
68 public string Key
69 {
70 get => (string)this.Fields[(int)WixRemoveRegistryKeyExSymbolFields.Key];
71 set => this.Set((int)WixRemoveRegistryKeyExSymbolFields.Key, value);
72 }
73
74 public WixRemoveRegistryKeyExInstallMode InstallMode
75 {
76 get => (WixRemoveRegistryKeyExInstallMode)this.Fields[(int)WixRemoveRegistryKeyExSymbolFields.InstallMode].AsNumber();
77 set => this.Set((int)WixRemoveRegistryKeyExSymbolFields.InstallMode, (int)value);
78 }
79
80 public string Condition
81 {
82 get => this.Fields[(int)WixRemoveRegistryKeyExSymbolFields.Condition].AsString();
83 set => this.Set((int)WixRemoveRegistryKeyExSymbolFields.Condition, value);
84 }
85 }
86}
diff --git a/src/ext/Util/wixext/Symbols/WixRestartResourceSymbol.cs b/src/ext/Util/wixext/Symbols/WixRestartResourceSymbol.cs
new file mode 100644
index 00000000..01b92b63
--- /dev/null
+++ b/src/ext/Util/wixext/Symbols/WixRestartResourceSymbol.cs
@@ -0,0 +1,71 @@
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
3namespace WixToolset.Util
4{
5 using WixToolset.Data;
6 using WixToolset.Util.Symbols;
7
8 public static partial class UtilSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition WixRestartResource = new IntermediateSymbolDefinition(
11 UtilSymbolDefinitionType.WixRestartResource.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(WixRestartResourceSymbolFields.ComponentRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(WixRestartResourceSymbolFields.Resource), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(WixRestartResourceSymbolFields.Attributes), IntermediateFieldType.Number),
17 },
18 typeof(WixRestartResourceSymbol));
19 }
20}
21
22namespace WixToolset.Util.Symbols
23{
24 using WixToolset.Data;
25
26 public enum WixRestartResourceSymbolFields
27 {
28 ComponentRef,
29 Resource,
30 Attributes,
31 }
32
33 public enum WixRestartResourceAttributes
34 {
35 Filename = 1,
36 ProcessName,
37 ServiceName,
38 TypeMask = 0xf,
39 }
40
41 public class WixRestartResourceSymbol : IntermediateSymbol
42 {
43 public WixRestartResourceSymbol() : base(UtilSymbolDefinitions.WixRestartResource, null, null)
44 {
45 }
46
47 public WixRestartResourceSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.WixRestartResource, sourceLineNumber, id)
48 {
49 }
50
51 public IntermediateField this[WixRestartResourceSymbolFields index] => this.Fields[(int)index];
52
53 public string ComponentRef
54 {
55 get => this.Fields[(int)WixRestartResourceSymbolFields.ComponentRef].AsString();
56 set => this.Set((int)WixRestartResourceSymbolFields.ComponentRef, value);
57 }
58
59 public string Resource
60 {
61 get => this.Fields[(int)WixRestartResourceSymbolFields.Resource].AsString();
62 set => this.Set((int)WixRestartResourceSymbolFields.Resource, value);
63 }
64
65 public WixRestartResourceAttributes? Attributes
66 {
67 get => (WixRestartResourceAttributes?)this.Fields[(int)WixRestartResourceSymbolFields.Attributes].AsNullableNumber();
68 set => this.Set((int)WixRestartResourceSymbolFields.Attributes, (int?)value);
69 }
70 }
71} \ No newline at end of file
diff --git a/src/ext/Util/wixext/Symbols/WixTouchFileSymbol.cs b/src/ext/Util/wixext/Symbols/WixTouchFileSymbol.cs
new file mode 100644
index 00000000..447c21ba
--- /dev/null
+++ b/src/ext/Util/wixext/Symbols/WixTouchFileSymbol.cs
@@ -0,0 +1,63 @@
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
3namespace WixToolset.Util
4{
5 using WixToolset.Data;
6 using WixToolset.Util.Symbols;
7
8 public static partial class UtilSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition WixTouchFile = new IntermediateSymbolDefinition(
11 UtilSymbolDefinitionType.WixTouchFile.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(WixTouchFileSymbolFields.ComponentRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(WixTouchFileSymbolFields.Path), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(WixTouchFileSymbolFields.Attributes), IntermediateFieldType.Number),
17 },
18 typeof(WixTouchFileSymbol));
19 }
20}
21
22namespace WixToolset.Util.Symbols
23{
24 using WixToolset.Data;
25
26 public enum WixTouchFileSymbolFields
27 {
28 ComponentRef,
29 Path,
30 Attributes,
31 }
32
33 public class WixTouchFileSymbol : IntermediateSymbol
34 {
35 public WixTouchFileSymbol() : base(UtilSymbolDefinitions.WixTouchFile, null, null)
36 {
37 }
38
39 public WixTouchFileSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.WixTouchFile, sourceLineNumber, id)
40 {
41 }
42
43 public IntermediateField this[WixTouchFileSymbolFields index] => this.Fields[(int)index];
44
45 public string ComponentRef
46 {
47 get => this.Fields[(int)WixTouchFileSymbolFields.ComponentRef].AsString();
48 set => this.Set((int)WixTouchFileSymbolFields.ComponentRef, value);
49 }
50
51 public string Path
52 {
53 get => this.Fields[(int)WixTouchFileSymbolFields.Path].AsString();
54 set => this.Set((int)WixTouchFileSymbolFields.Path, value);
55 }
56
57 public int Attributes
58 {
59 get => this.Fields[(int)WixTouchFileSymbolFields.Attributes].AsNumber();
60 set => this.Set((int)WixTouchFileSymbolFields.Attributes, value);
61 }
62 }
63} \ No newline at end of file
diff --git a/src/ext/Util/wixext/Symbols/WixWindowsFeatureSearchSymbol.cs b/src/ext/Util/wixext/Symbols/WixWindowsFeatureSearchSymbol.cs
new file mode 100644
index 00000000..9a43692c
--- /dev/null
+++ b/src/ext/Util/wixext/Symbols/WixWindowsFeatureSearchSymbol.cs
@@ -0,0 +1,47 @@
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
3namespace WixToolset.Util
4{
5 using WixToolset.Data;
6 using WixToolset.Util.Symbols;
7
8 public static partial class UtilSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition WixWindowsFeatureSearch = new IntermediateSymbolDefinition(
11 UtilSymbolDefinitionType.WixWindowsFeatureSearch.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(WixWindowsFeatureSearchSymbolFields.Type), IntermediateFieldType.String),
15 },
16 typeof(WixWindowsFeatureSearchSymbol));
17 }
18}
19
20namespace WixToolset.Util.Symbols
21{
22 using WixToolset.Data;
23
24 public enum WixWindowsFeatureSearchSymbolFields
25 {
26 Type,
27 }
28
29 public class WixWindowsFeatureSearchSymbol : IntermediateSymbol
30 {
31 public WixWindowsFeatureSearchSymbol() : base(UtilSymbolDefinitions.WixWindowsFeatureSearch, null, null)
32 {
33 }
34
35 public WixWindowsFeatureSearchSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.WixWindowsFeatureSearch, sourceLineNumber, id)
36 {
37 }
38
39 public IntermediateField this[WixWindowsFeatureSearchSymbolFields index] => this.Fields[(int)index];
40
41 public string Type
42 {
43 get => this.Fields[(int)WixWindowsFeatureSearchSymbolFields.Type].AsString();
44 set => this.Set((int)WixWindowsFeatureSearchSymbolFields.Type, value);
45 }
46 }
47}
diff --git a/src/ext/Util/wixext/Symbols/XmlConfigSymbol.cs b/src/ext/Util/wixext/Symbols/XmlConfigSymbol.cs
new file mode 100644
index 00000000..6503a586
--- /dev/null
+++ b/src/ext/Util/wixext/Symbols/XmlConfigSymbol.cs
@@ -0,0 +1,111 @@
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
3namespace WixToolset.Util
4{
5 using WixToolset.Data;
6 using WixToolset.Util.Symbols;
7
8 public static partial class UtilSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition XmlConfig = new IntermediateSymbolDefinition(
11 UtilSymbolDefinitionType.XmlConfig.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.File), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.ElementId), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.ElementPath), IntermediateFieldType.String),
17 new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.VerifyPath), IntermediateFieldType.String),
18 new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.Name), IntermediateFieldType.String),
19 new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.Value), IntermediateFieldType.String),
20 new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.Flags), IntermediateFieldType.Number),
21 new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.ComponentRef), IntermediateFieldType.String),
22 new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.Sequence), IntermediateFieldType.Number),
23 },
24 typeof(XmlConfigSymbol));
25 }
26}
27
28namespace WixToolset.Util.Symbols
29{
30 using WixToolset.Data;
31
32 public enum XmlConfigSymbolFields
33 {
34 File,
35 ElementId,
36 ElementPath,
37 VerifyPath,
38 Name,
39 Value,
40 Flags,
41 ComponentRef,
42 Sequence,
43 }
44
45 public class XmlConfigSymbol : IntermediateSymbol
46 {
47 public XmlConfigSymbol() : base(UtilSymbolDefinitions.XmlConfig, null, null)
48 {
49 }
50
51 public XmlConfigSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.XmlConfig, sourceLineNumber, id)
52 {
53 }
54
55 public IntermediateField this[XmlConfigSymbolFields index] => this.Fields[(int)index];
56
57 public string File
58 {
59 get => this.Fields[(int)XmlConfigSymbolFields.File].AsString();
60 set => this.Set((int)XmlConfigSymbolFields.File, value);
61 }
62
63 public string ElementId
64 {
65 get => this.Fields[(int)XmlConfigSymbolFields.ElementId].AsString();
66 set => this.Set((int)XmlConfigSymbolFields.ElementId, value);
67 }
68
69 public string ElementPath
70 {
71 get => this.Fields[(int)XmlConfigSymbolFields.ElementPath].AsString();
72 set => this.Set((int)XmlConfigSymbolFields.ElementPath, value);
73 }
74
75 public string VerifyPath
76 {
77 get => this.Fields[(int)XmlConfigSymbolFields.VerifyPath].AsString();
78 set => this.Set((int)XmlConfigSymbolFields.VerifyPath, value);
79 }
80
81 public string Name
82 {
83 get => this.Fields[(int)XmlConfigSymbolFields.Name].AsString();
84 set => this.Set((int)XmlConfigSymbolFields.Name, value);
85 }
86
87 public string Value
88 {
89 get => this.Fields[(int)XmlConfigSymbolFields.Value].AsString();
90 set => this.Set((int)XmlConfigSymbolFields.Value, value);
91 }
92
93 public int Flags
94 {
95 get => this.Fields[(int)XmlConfigSymbolFields.Flags].AsNumber();
96 set => this.Set((int)XmlConfigSymbolFields.Flags, value);
97 }
98
99 public string ComponentRef
100 {
101 get => this.Fields[(int)XmlConfigSymbolFields.ComponentRef].AsString();
102 set => this.Set((int)XmlConfigSymbolFields.ComponentRef, value);
103 }
104
105 public int? Sequence
106 {
107 get => this.Fields[(int)XmlConfigSymbolFields.Sequence].AsNullableNumber();
108 set => this.Set((int)XmlConfigSymbolFields.Sequence, value);
109 }
110 }
111} \ No newline at end of file
diff --git a/src/ext/Util/wixext/Symbols/XmlFileSymbol.cs b/src/ext/Util/wixext/Symbols/XmlFileSymbol.cs
new file mode 100644
index 00000000..7d5d991b
--- /dev/null
+++ b/src/ext/Util/wixext/Symbols/XmlFileSymbol.cs
@@ -0,0 +1,95 @@
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
3namespace WixToolset.Util
4{
5 using WixToolset.Data;
6 using WixToolset.Util.Symbols;
7
8 public static partial class UtilSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition XmlFile = new IntermediateSymbolDefinition(
11 UtilSymbolDefinitionType.XmlFile.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(XmlFileSymbolFields.File), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(XmlFileSymbolFields.ElementPath), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(XmlFileSymbolFields.Name), IntermediateFieldType.String),
17 new IntermediateFieldDefinition(nameof(XmlFileSymbolFields.Value), IntermediateFieldType.String),
18 new IntermediateFieldDefinition(nameof(XmlFileSymbolFields.Flags), IntermediateFieldType.Number),
19 new IntermediateFieldDefinition(nameof(XmlFileSymbolFields.ComponentRef), IntermediateFieldType.String),
20 new IntermediateFieldDefinition(nameof(XmlFileSymbolFields.Sequence), IntermediateFieldType.Number),
21 },
22 typeof(XmlFileSymbol));
23 }
24}
25
26namespace WixToolset.Util.Symbols
27{
28 using WixToolset.Data;
29
30 public enum XmlFileSymbolFields
31 {
32 File,
33 ElementPath,
34 Name,
35 Value,
36 Flags,
37 ComponentRef,
38 Sequence,
39 }
40
41 public class XmlFileSymbol : IntermediateSymbol
42 {
43 public XmlFileSymbol() : base(UtilSymbolDefinitions.XmlFile, null, null)
44 {
45 }
46
47 public XmlFileSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.XmlFile, sourceLineNumber, id)
48 {
49 }
50
51 public IntermediateField this[XmlFileSymbolFields index] => this.Fields[(int)index];
52
53 public string File
54 {
55 get => this.Fields[(int)XmlFileSymbolFields.File].AsString();
56 set => this.Set((int)XmlFileSymbolFields.File, value);
57 }
58
59 public string ElementPath
60 {
61 get => this.Fields[(int)XmlFileSymbolFields.ElementPath].AsString();
62 set => this.Set((int)XmlFileSymbolFields.ElementPath, value);
63 }
64
65 public string Name
66 {
67 get => this.Fields[(int)XmlFileSymbolFields.Name].AsString();
68 set => this.Set((int)XmlFileSymbolFields.Name, value);
69 }
70
71 public string Value
72 {
73 get => this.Fields[(int)XmlFileSymbolFields.Value].AsString();
74 set => this.Set((int)XmlFileSymbolFields.Value, value);
75 }
76
77 public int Flags
78 {
79 get => this.Fields[(int)XmlFileSymbolFields.Flags].AsNumber();
80 set => this.Set((int)XmlFileSymbolFields.Flags, value);
81 }
82
83 public string ComponentRef
84 {
85 get => this.Fields[(int)XmlFileSymbolFields.ComponentRef].AsString();
86 set => this.Set((int)XmlFileSymbolFields.ComponentRef, value);
87 }
88
89 public int? Sequence
90 {
91 get => this.Fields[(int)XmlFileSymbolFields.Sequence].AsNullableNumber();
92 set => this.Set((int)XmlFileSymbolFields.Sequence, value);
93 }
94 }
95} \ No newline at end of file
diff --git a/src/ext/Util/wixext/UtilCompiler.cs b/src/ext/Util/wixext/UtilCompiler.cs
new file mode 100644
index 00000000..45079150
--- /dev/null
+++ b/src/ext/Util/wixext/UtilCompiler.cs
@@ -0,0 +1,3889 @@
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
3namespace WixToolset.Util
4{
5 using System;
6 using System.Collections;
7 using System.Collections.Generic;
8 using System.Globalization;
9 using System.Linq;
10 using System.Text;
11 using System.Text.RegularExpressions;
12 using System.Xml.Linq;
13 using WixToolset.Data;
14 using WixToolset.Data.Symbols;
15 using WixToolset.Extensibility;
16 using WixToolset.Extensibility.Data;
17 using WixToolset.Util.Symbols;
18
19 /// <summary>
20 /// The compiler for the WiX Toolset Utility Extension.
21 /// </summary>
22 public sealed class UtilCompiler : BaseCompilerExtension
23 {
24 // user creation attributes definitions (from sca.h)
25 internal const int UserDontExpirePasswrd = 0x00000001;
26 internal const int UserPasswdCantChange = 0x00000002;
27 internal const int UserPasswdChangeReqdOnLogin = 0x00000004;
28 internal const int UserDisableAccount = 0x00000008;
29 internal const int UserFailIfExists = 0x00000010;
30 internal const int UserUpdateIfExists = 0x00000020;
31 internal const int UserLogonAsService = 0x00000040;
32 internal const int UserLogonAsBatchJob = 0x00000080;
33
34 internal const int UserDontRemoveOnUninstall = 0x00000100;
35 internal const int UserDontCreateUser = 0x00000200;
36 internal const int UserNonVital = 0x00000400;
37
38 private static readonly Regex FindPropertyBrackets = new Regex(@"\[(?!\\|\])|(?<!\[\\\]|\[\\|\\\[)\]", RegexOptions.ExplicitCapture | RegexOptions.Compiled);
39
40 public override XNamespace Namespace => "http://wixtoolset.org/schemas/v4/wxs/util";
41
42 /// <summary>
43 /// Types of Internet shortcuts.
44 /// </summary>
45 public enum InternetShortcutType
46 {
47 /// <summary>Create a .lnk file.</summary>
48 Link = 0,
49
50 /// <summary>Create a .url file.</summary>
51 Url,
52 }
53
54 /// <summary>
55 /// Types of permission setting methods.
56 /// </summary>
57 private enum PermissionType
58 {
59 /// <summary>LockPermissions (normal) type permission setting.</summary>
60 LockPermissions,
61
62 /// <summary>FileSharePermissions type permission setting.</summary>
63 FileSharePermissions,
64
65 /// <summary>SecureObjects type permission setting.</summary>
66 SecureObjects,
67 }
68
69 /// <summary>
70 /// Processes an element for the Compiler.
71 /// </summary>
72 /// <param name="parentElement">Parent element of element to process.</param>
73 /// <param name="element">Element to process.</param>
74 /// <param name="context">Extra information about the context in which this element is being parsed.</param>
75 public override void ParseElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, IDictionary<string, string> context)
76 {
77 this.ParsePossibleKeyPathElement(intermediate, section, parentElement, element, context);
78 }
79
80 /// <summary>
81 /// Processes an element for the Compiler.
82 /// </summary>
83 /// <param name="sourceLineNumbers">Source line number for the parent element.</param>
84 /// <param name="parentElement">Parent element of element to process.</param>
85 /// <param name="element">Element to process.</param>
86 /// <param name="contextValues">Extra information about the context in which this element is being parsed.</param>
87 public override IComponentKeyPath ParsePossibleKeyPathElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, IDictionary<string, string> context)
88 {
89 IComponentKeyPath possibleKeyPath = null;
90
91 switch (parentElement.Name.LocalName)
92 {
93 case "CreateFolder":
94 var createFolderId = context["DirectoryId"];
95 var createFolderComponentId = context["ComponentId"];
96
97 // If this doesn't parse successfully, something really odd is going on, so let the exception get thrown
98 var createFolderWin64 = Boolean.Parse(context["Win64"]);
99
100 switch (element.Name.LocalName)
101 {
102 case "PermissionEx":
103 this.ParsePermissionExElement(intermediate, section, element, createFolderId, createFolderComponentId, createFolderWin64, "CreateFolder");
104 break;
105 default:
106 this.ParseHelper.UnexpectedElement(parentElement, element);
107 break;
108 }
109 break;
110 case "Component":
111 var componentId = context["ComponentId"];
112 var directoryId = context["DirectoryId"];
113 var componentWin64 = Boolean.Parse(context["Win64"]);
114
115 switch (element.Name.LocalName)
116 {
117 case "EventSource":
118 possibleKeyPath = this.ParseEventSourceElement(intermediate, section, element, componentId);
119 break;
120 case "FileShare":
121 this.ParseFileShareElement(intermediate, section, element, componentId, directoryId);
122 break;
123 case "InternetShortcut":
124 this.ParseInternetShortcutElement(intermediate, section, element, componentId, directoryId);
125 break;
126 case "PerformanceCategory":
127 this.ParsePerformanceCategoryElement(intermediate, section, element, componentId);
128 break;
129 case "RemoveFolderEx":
130 this.ParseRemoveFolderExElement(intermediate, section, element, componentId);
131 break;
132 case "RemoveRegistryKey":
133 this.ParseRemoveRegistryKeyExElement(intermediate, section, element, componentId);
134 break;
135 case "RestartResource":
136 this.ParseRestartResourceElement(intermediate, section, element, componentId);
137 break;
138 case "ServiceConfig":
139 this.ParseServiceConfigElement(intermediate, section, element, componentId, "Component", null);
140 break;
141 case "TouchFile":
142 this.ParseTouchFileElement(intermediate, section, element, componentId, componentWin64);
143 break;
144 case "User":
145 this.ParseUserElement(intermediate, section, element, componentId);
146 break;
147 case "XmlFile":
148 this.ParseXmlFileElement(intermediate, section, element, componentId);
149 break;
150 case "XmlConfig":
151 this.ParseXmlConfigElement(intermediate, section, element, componentId, false);
152 break;
153 default:
154 this.ParseHelper.UnexpectedElement(parentElement, element);
155 break;
156 }
157 break;
158 case "File":
159 var fileId = context["FileId"];
160 var fileComponentId = context["ComponentId"];
161
162 // If this doesn't parse successfully, something really odd is going on, so let the exception get thrown
163 var fileWin64 = Boolean.Parse(context["Win64"]);
164
165 switch (element.Name.LocalName)
166 {
167 case "PerfCounter":
168 this.ParsePerfCounterElement(intermediate, section, element, fileComponentId, fileId);
169 break;
170 case "PermissionEx":
171 this.ParsePermissionExElement(intermediate, section, element, fileId, fileComponentId, fileWin64, "File");
172 break;
173 case "PerfCounterManifest":
174 this.ParsePerfCounterManifestElement(intermediate, section, element, fileComponentId, fileId);
175 break;
176 case "EventManifest":
177 this.ParseEventManifestElement(intermediate, section, element, fileComponentId, fileId);
178 break;
179 case "FormatFile":
180 this.ParseFormatFileElement(intermediate, section, element, fileId, fileWin64);
181 break;
182 default:
183 this.ParseHelper.UnexpectedElement(parentElement, element);
184 break;
185 }
186 break;
187 case "Bundle":
188 case "Fragment":
189 case "Module":
190 case "Package":
191 switch (element.Name.LocalName)
192 {
193 case "CloseApplication":
194 this.ParseCloseApplicationElement(intermediate, section, element);
195 break;
196 case "Group":
197 this.ParseGroupElement(intermediate, section, element, null);
198 break;
199 case "RestartResource":
200 // Currently not supported for Bundles.
201 if (parentElement.Name.LocalName != "Bundle")
202 {
203 this.ParseRestartResourceElement(intermediate, section, element, null);
204 }
205 else
206 {
207 this.ParseHelper.UnexpectedElement(parentElement, element);
208 }
209 break;
210 case "User":
211 this.ParseUserElement(intermediate, section, element, null);
212 break;
213 case "BroadcastEnvironmentChange":
214 case "BroadcastSettingChange":
215 case "CheckRebootRequired":
216 case "ExitEarlyWithSuccess":
217 case "FailWhenDeferred":
218 case "QueryWindowsDirectories":
219 case "QueryWindowsDriverInfo":
220 case "QueryWindowsSuiteInfo":
221 case "QueryWindowsWellKnownSIDs":
222 case "WaitForEvent":
223 case "WaitForEventDeferred":
224 this.AddCustomActionReference(intermediate, section, element, parentElement);
225 break;
226 case "ComponentSearch":
227 case "ComponentSearchRef":
228 case "DirectorySearch":
229 case "DirectorySearchRef":
230 case "FileSearch":
231 case "FileSearchRef":
232 case "ProductSearch":
233 case "ProductSearchRef":
234 case "RegistrySearch":
235 case "RegistrySearchRef":
236 case "WindowsFeatureSearch":
237 case "WindowsFeatureSearchRef":
238 // These will eventually be supported under Module/Product, but are not yet.
239 if (parentElement.Name.LocalName == "Bundle" || parentElement.Name.LocalName == "Fragment")
240 {
241 // TODO: When these are supported by all section types, move
242 // these out of the nested switch and back into the surrounding one.
243 switch (element.Name.LocalName)
244 {
245 case "ComponentSearch":
246 this.ParseComponentSearchElement(intermediate, section, element);
247 break;
248 case "ComponentSearchRef":
249 this.ParseComponentSearchRefElement(intermediate, section, element);
250 break;
251 case "DirectorySearch":
252 this.ParseDirectorySearchElement(intermediate, section, element);
253 break;
254 case "DirectorySearchRef":
255 this.ParseWixSearchRefElement(intermediate, section, element);
256 break;
257 case "FileSearch":
258 this.ParseFileSearchElement(intermediate, section, element);
259 break;
260 case "FileSearchRef":
261 this.ParseWixSearchRefElement(intermediate, section, element);
262 break;
263 case "ProductSearch":
264 this.ParseProductSearchElement(intermediate, section, element);
265 break;
266 case "ProductSearchRef":
267 this.ParseWixSearchRefElement(intermediate, section, element);
268 break;
269 case "RegistrySearch":
270 this.ParseRegistrySearchElement(intermediate, section, element);
271 break;
272 case "RegistrySearchRef":
273 this.ParseWixSearchRefElement(intermediate, section, element);
274 break;
275 case "WindowsFeatureSearch":
276 this.ParseWindowsFeatureSearchElement(intermediate, section, element);
277 break;
278 case "WindowsFeatureSearchRef":
279 this.ParseWindowsFeatureSearchRefElement(intermediate, section, element);
280 break;
281 }
282 }
283 else
284 {
285 this.ParseHelper.UnexpectedElement(parentElement, element);
286 }
287 break;
288 default:
289 this.ParseHelper.UnexpectedElement(parentElement, element);
290 break;
291 }
292 break;
293 case "Registry":
294 case "RegistryKey":
295 case "RegistryValue":
296 var registryId = context["RegistryId"];
297 var registryComponentId = context["ComponentId"];
298
299 // If this doesn't parse successfully, something really odd is going on, so let the exception get thrown
300 var registryWin64 = Boolean.Parse(context["Win64"]);
301
302 switch (element.Name.LocalName)
303 {
304 case "PermissionEx":
305 this.ParsePermissionExElement(intermediate, section, element, registryId, registryComponentId, registryWin64, "Registry");
306 break;
307 default:
308 this.ParseHelper.UnexpectedElement(parentElement, element);
309 break;
310 }
311 break;
312 case "ServiceInstall":
313 var serviceInstallId = context["ServiceInstallId"];
314 var serviceInstallName = context["ServiceInstallName"];
315 var serviceInstallComponentId = context["ServiceInstallComponentId"];
316
317 // If this doesn't parse successfully, something really odd is going on, so let the exception get thrown
318 var serviceInstallWin64 = Boolean.Parse(context["Win64"]);
319
320 switch (element.Name.LocalName)
321 {
322 case "PermissionEx":
323 this.ParsePermissionExElement(intermediate, section, element, serviceInstallId, serviceInstallComponentId, serviceInstallWin64, "ServiceInstall");
324 break;
325 case "ServiceConfig":
326 this.ParseServiceConfigElement(intermediate, section, element, serviceInstallComponentId, "ServiceInstall", serviceInstallName);
327 break;
328 default:
329 this.ParseHelper.UnexpectedElement(parentElement, element);
330 break;
331 }
332 break;
333 case "UI":
334 switch (element.Name.LocalName)
335 {
336 case "BroadcastEnvironmentChange":
337 case "BroadcastSettingChange":
338 case "CheckRebootRequired":
339 case "ExitEarlyWithSuccess":
340 case "FailWhenDeferred":
341 case "QueryWindowsDirectories":
342 case "QueryWindowsDriverInfo":
343 case "QueryWindowsSuiteInfo":
344 case "QueryWindowsWellKnownSIDs":
345 case "WaitForEvent":
346 case "WaitForEventDeferred":
347 this.AddCustomActionReference(intermediate, section, element, parentElement);
348 break;
349 }
350 break;
351 default:
352 this.ParseHelper.UnexpectedElement(parentElement, element);
353 break;
354 }
355
356 return possibleKeyPath;
357 }
358
359 private void AddCustomActionReference(Intermediate intermediate, IntermediateSection section, XElement element, XElement parentElement)
360 {
361 // These elements are not supported for bundles.
362 if (parentElement.Name.LocalName == "Bundle")
363 {
364 this.ParseHelper.UnexpectedElement(parentElement, element);
365 return;
366 }
367
368 var customAction = element.Name.LocalName;
369 switch (element.Name.LocalName)
370 {
371 case "BroadcastEnvironmentChange":
372 case "BroadcastSettingChange":
373 case "CheckRebootRequired":
374 case "ExitEarlyWithSuccess":
375 case "FailWhenDeferred":
376 case "WaitForEvent":
377 case "WaitForEventDeferred":
378 //default: customAction = element.Name.LocalName;
379 break;
380 case "QueryWindowsDirectories":
381 customAction = "QueryOsDirs";
382 break;
383 case "QueryWindowsDriverInfo":
384 customAction = "QueryOsDriverInfo";
385 break;
386 case "QueryWindowsSuiteInfo":
387 customAction = "QueryOsInfo";
388 break;
389 case "QueryWindowsWellKnownSIDs":
390 customAction = "QueryOsWellKnownSID";
391 break;
392 }
393
394 foreach (var attrib in element.Attributes())
395 {
396 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
397 {
398 // no attributes today
399 }
400 else
401 {
402 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
403 }
404 }
405
406 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
407
408 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
409
410 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4" + customAction, this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
411 }
412
413 /// <summary>
414 /// Parses the common search attributes shared across all searches.
415 /// </summary>
416 /// <param name="sourceLineNumbers">Source line number for the parent element.</param>
417 /// <param name="attrib">Attribute to parse.</param>
418 /// <param name="id">Value of the Id attribute.</param>
419 /// <param name="variable">Value of the Variable attribute.</param>
420 /// <param name="condition">Value of the Condition attribute.</param>
421 /// <param name="after">Value of the After attribute.</param>
422 private void ParseCommonSearchAttributes(SourceLineNumber sourceLineNumbers, XAttribute attrib, ref Identifier id, ref string variable, ref string condition, ref string after)
423 {
424 switch (attrib.Name.LocalName)
425 {
426 case "Id":
427 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
428 break;
429 case "Variable":
430 variable = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
431 // TODO: handle standard bundle variables
432 break;
433 case "Condition":
434 condition = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
435 break;
436 case "After":
437 after = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
438 break;
439 default:
440 System.Diagnostics.Debug.Assert(false);
441 break;
442 }
443 }
444
445 /// <summary>
446 /// Parses a ComponentSearch element.
447 /// </summary>
448 /// <param name="element">Element to parse.</param>
449 private void ParseComponentSearchElement(Intermediate intermediate, IntermediateSection section, XElement element)
450 {
451 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
452 Identifier id = null;
453 string variable = null;
454 string condition = null;
455 string after = null;
456 string guid = null;
457 string productCode = null;
458 var attributes = WixComponentSearchAttributes.KeyPath;
459
460 foreach (var attrib in element.Attributes())
461 {
462 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
463 {
464 switch (attrib.Name.LocalName)
465 {
466 case "Id":
467 case "Variable":
468 case "Condition":
469 case "After":
470 this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after);
471 break;
472 case "Guid":
473 guid = this.ParseHelper.GetAttributeGuidValue(sourceLineNumbers, attrib);
474 break;
475 case "ProductCode":
476 productCode = this.ParseHelper.GetAttributeGuidValue(sourceLineNumbers, attrib);
477 break;
478 case "Result":
479 var result = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
480 switch (result)
481 {
482 case "directory":
483 attributes = WixComponentSearchAttributes.WantDirectory;
484 break;
485 case "keyPath":
486 attributes = WixComponentSearchAttributes.KeyPath;
487 break;
488 case "state":
489 attributes = WixComponentSearchAttributes.State;
490 break;
491 default:
492 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, result, "directory", "keyPath", "state"));
493 break;
494 }
495 break;
496 default:
497 this.ParseHelper.UnexpectedAttribute(element, attrib);
498 break;
499 }
500 }
501 else
502 {
503 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
504 }
505 }
506
507 if (null == guid)
508 {
509 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Guid"));
510 }
511
512 if (null == id)
513 {
514 id = this.ParseHelper.CreateIdentifier("wcs", variable, condition, after, guid, productCode, attributes.ToString());
515 }
516
517 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
518
519 this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, null);
520
521 if (!this.Messaging.EncounteredError)
522 {
523 section.AddSymbol(new WixComponentSearchSymbol(sourceLineNumbers, id)
524 {
525 Guid = guid,
526 ProductCode = productCode,
527 Attributes = attributes,
528 });
529 }
530 }
531
532 /// <summary>
533 /// Parses a ComponentSearchRef element
534 /// </summary>
535 /// <param name="element">Element to parse.</param>
536 private void ParseComponentSearchRefElement(Intermediate intermediate, IntermediateSection section, XElement element)
537 {
538 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
539 string refId = null;
540
541 foreach (var attrib in element.Attributes())
542 {
543 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
544 {
545 switch (attrib.Name.LocalName)
546 {
547 case "Id":
548 refId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
549 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.WixComponentSearch, refId);
550 break;
551 default:
552 this.ParseHelper.UnexpectedAttribute(element, attrib);
553 break;
554 }
555 }
556 else
557 {
558 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
559 }
560 }
561
562 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
563 }
564
565 /// <summary>
566 /// Parses a WindowsFeatureSearch element.
567 /// </summary>
568 /// <param name="element">Element to parse.</param>
569 private void ParseWindowsFeatureSearchElement(Intermediate intermediate, IntermediateSection section, XElement element)
570 {
571 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
572 Identifier id = null;
573 string variable = null;
574 string condition = null;
575 string after = null;
576 string feature = null;
577
578 foreach (var attrib in element.Attributes())
579 {
580 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
581 {
582 switch (attrib.Name.LocalName)
583 {
584 case "Id":
585 case "Variable":
586 case "Condition":
587 case "After":
588 this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after);
589 break;
590 case "Feature":
591 feature = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
592 switch (feature)
593 {
594 case "sha2CodeSigning":
595 break;
596 default:
597 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Feature", feature, "sha2CodeSigning"));
598 break;
599 }
600 break;
601 default:
602 this.ParseHelper.UnexpectedAttribute(element, attrib);
603 break;
604 }
605 }
606 else
607 {
608 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
609 }
610 }
611
612 if (id == null)
613 {
614 id = this.ParseHelper.CreateIdentifier("wwfs", variable, condition, after);
615 }
616
617 if (feature == null)
618 {
619 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Feature"));
620 }
621
622 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
623
624 var bundleExtensionId = this.ParseHelper.CreateIdentifierValueFromPlatform("Wix4UtilBundleExtension", this.Context.Platform, BurnPlatforms.X86 | BurnPlatforms.X64 | BurnPlatforms.ARM64);
625 if (bundleExtensionId == null)
626 {
627 this.Messaging.Write(ErrorMessages.UnsupportedPlatformForElement(sourceLineNumbers, this.Context.Platform.ToString(), element.Name.LocalName));
628 }
629
630 this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, bundleExtensionId);
631
632 if (!this.Messaging.EncounteredError)
633 {
634 section.AddSymbol(new WixWindowsFeatureSearchSymbol(sourceLineNumbers, id)
635 {
636 Type = feature,
637 });
638 }
639 }
640
641 /// <summary>
642 /// Parses a WindowsFeatureSearchRef element
643 /// </summary>
644 /// <param name="element">Element to parse.</param>
645 private void ParseWindowsFeatureSearchRefElement(Intermediate intermediate, IntermediateSection section, XElement element)
646 {
647 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
648
649 foreach (var attrib in element.Attributes())
650 {
651 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
652 {
653 switch (attrib.Name.LocalName)
654 {
655 case "Id":
656 var refId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
657 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, UtilSymbolDefinitions.WixWindowsFeatureSearch, refId);
658 break;
659 default:
660 this.ParseHelper.UnexpectedAttribute(element, attrib);
661 break;
662 }
663 }
664 else
665 {
666 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
667 }
668 }
669
670 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
671 }
672
673 /// <summary>
674 /// Parses an event source element.
675 /// </summary>
676 /// <param name="element">Element to parse.</param>
677 /// <param name="componentId">Identifier of parent component.</param>
678 private IComponentKeyPath ParseEventSourceElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
679 {
680 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
681 string sourceName = null;
682 string logName = null;
683 string categoryMessageFile = null;
684 var categoryCount = CompilerConstants.IntegerNotSet;
685 string eventMessageFile = null;
686 string parameterMessageFile = null;
687 int typesSupported = 0;
688 var isKeyPath = false;
689
690 foreach (var attrib in element.Attributes())
691 {
692 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
693 {
694 switch (attrib.Name.LocalName)
695 {
696 case "CategoryCount":
697 categoryCount = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
698 break;
699 case "CategoryMessageFile":
700 categoryMessageFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
701 break;
702 case "EventMessageFile":
703 eventMessageFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
704 break;
705 case "KeyPath":
706 isKeyPath = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
707 break;
708 case "Log":
709 logName = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
710 if ("Security" == logName)
711 {
712 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, logName, "Application", "System", "<customEventLog>"));
713 }
714 break;
715 case "Name":
716 sourceName = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
717 break;
718 case "ParameterMessageFile":
719 parameterMessageFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
720 break;
721 case "SupportsErrors":
722 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
723 {
724 typesSupported |= 0x01; // EVENTLOG_ERROR_TYPE
725 }
726 break;
727 case "SupportsFailureAudits":
728 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
729 {
730 typesSupported |= 0x10; // EVENTLOG_AUDIT_FAILURE
731 }
732 break;
733 case "SupportsInformationals":
734 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
735 {
736 typesSupported |= 0x04; // EVENTLOG_INFORMATION_TYPE
737 }
738 break;
739 case "SupportsSuccessAudits":
740 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
741 {
742 typesSupported |= 0x08; // EVENTLOG_AUDIT_SUCCESS
743 }
744 break;
745 case "SupportsWarnings":
746 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
747 {
748 typesSupported |= 0x02; // EVENTLOG_WARNING_TYPE
749 }
750 break;
751 default:
752 this.ParseHelper.UnexpectedAttribute(element, attrib);
753 break;
754 }
755 }
756 else
757 {
758 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
759 }
760 }
761
762 if (null == sourceName)
763 {
764 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
765 }
766
767 if (null == logName)
768 {
769 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "EventLog"));
770 }
771
772 if (null == eventMessageFile)
773 {
774 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "EventMessageFile"));
775 }
776
777 if (null == categoryMessageFile && 0 < categoryCount)
778 {
779 this.Messaging.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, element.Name.LocalName, "CategoryCount", "CategoryMessageFile"));
780 }
781
782 if (null != categoryMessageFile && CompilerConstants.IntegerNotSet == categoryCount)
783 {
784 this.Messaging.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, element.Name.LocalName, "CategoryMessageFile", "CategoryCount"));
785 }
786
787 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
788
789 string eventSourceKey = $@"SYSTEM\CurrentControlSet\Services\EventLog\{logName}\{sourceName}";
790 var id = this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, eventSourceKey, "EventMessageFile", String.Concat("#%", eventMessageFile), componentId, false);
791
792 if (null != categoryMessageFile)
793 {
794 this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, eventSourceKey, "CategoryMessageFile", String.Concat("#%", categoryMessageFile), componentId, false);
795 }
796
797 if (CompilerConstants.IntegerNotSet != categoryCount)
798 {
799 this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, eventSourceKey, "CategoryCount", String.Concat("#", categoryCount), componentId, false);
800 }
801
802 if (null != parameterMessageFile)
803 {
804 this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, eventSourceKey, "ParameterMessageFile", String.Concat("#%", parameterMessageFile), componentId, false);
805 }
806
807 if (0 != typesSupported)
808 {
809 this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, eventSourceKey, "TypesSupported", String.Concat("#", typesSupported), componentId, false);
810 }
811
812 var componentKeyPath = this.CreateComponentKeyPath();
813 componentKeyPath.Id = id.Id;
814 componentKeyPath.Explicit = isKeyPath;
815 componentKeyPath.Type = PossibleKeyPathType.Registry;
816 return componentKeyPath;
817 }
818
819 /// <summary>
820 /// Parses a close application element.
821 /// </summary>
822 /// <param name="element">Element to parse.</param>
823 private void ParseCloseApplicationElement(Intermediate intermediate, IntermediateSection section, XElement element)
824 {
825 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
826 string condition = null;
827 string description = null;
828 string target = null;
829 string property = null;
830 Identifier id = null;
831 int attributes = 2; // default to CLOSEAPP_ATTRIBUTE_REBOOTPROMPT enabled
832 var sequence = CompilerConstants.IntegerNotSet;
833 var terminateExitCode = CompilerConstants.IntegerNotSet;
834 var timeout = CompilerConstants.IntegerNotSet;
835
836 foreach (var attrib in element.Attributes())
837 {
838 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
839 {
840 switch (attrib.Name.LocalName)
841 {
842 case "Id":
843 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
844 break;
845 case "Condition":
846 condition = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
847 break;
848 case "Description":
849 description = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
850 break;
851 case "Property":
852 property = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
853 break;
854 case "Sequence":
855 sequence = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
856 break;
857 case "Timeout":
858 timeout = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
859 break;
860 case "Target":
861 target = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
862 break;
863 case "CloseMessage":
864 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
865 {
866 attributes |= 1; // CLOSEAPP_ATTRIBUTE_CLOSEMESSAGE
867 }
868 else
869 {
870 attributes &= ~1; // CLOSEAPP_ATTRIBUTE_CLOSEMESSAGE
871 }
872 break;
873 case "EndSessionMessage":
874 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
875 {
876 attributes |= 8; // CLOSEAPP_ATTRIBUTE_ENDSESSIONMESSAGE
877 }
878 else
879 {
880 attributes &= ~8; // CLOSEAPP_ATTRIBUTE_ENDSESSIONMESSAGE
881 }
882 break;
883 case "PromptToContinue":
884 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
885 {
886 attributes |= 0x40; // CLOSEAPP_ATTRIBUTE_PROMPTTOCONTINUE
887 }
888 else
889 {
890 attributes &= ~0x40; // CLOSEAPP_ATTRIBUTE_PROMPTTOCONTINUE
891 }
892 break;
893 case "RebootPrompt":
894 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
895 {
896 attributes |= 2; // CLOSEAPP_ATTRIBUTE_REBOOTPROMPT
897 }
898 else
899 {
900 attributes &= ~2; // CLOSEAPP_ATTRIBUTE_REBOOTPROMPT
901 }
902 break;
903 case "ElevatedCloseMessage":
904 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
905 {
906 attributes |= 4; // CLOSEAPP_ATTRIBUTE_ELEVATEDCLOSEMESSAGE
907 }
908 else
909 {
910 attributes &= ~4; // CLOSEAPP_ATTRIBUTE_ELEVATEDCLOSEMESSAGE
911 }
912 break;
913 case "ElevatedEndSessionMessage":
914 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
915 {
916 attributes |= 0x10; // CLOSEAPP_ATTRIBUTE_ELEVATEDENDSESSIONMESSAGE
917 }
918 else
919 {
920 attributes &= ~0x10; // CLOSEAPP_ATTRIBUTE_ELEVATEDENDSESSIONMESSAGE
921 }
922 break;
923 case "TerminateProcess":
924 terminateExitCode = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
925 attributes |= 0x20; // CLOSEAPP_ATTRIBUTE_TERMINATEPROCESS
926 break;
927 default:
928 this.ParseHelper.UnexpectedAttribute(element, attrib);
929 break;
930 }
931 }
932 else
933 {
934 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
935 }
936 }
937
938 if (null == target)
939 {
940 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Target"));
941 }
942 else if (null == id)
943 {
944 id = this.ParseHelper.CreateIdentifier("ca", target);
945 }
946
947 if (String.IsNullOrEmpty(description) && 0x40 == (attributes & 0x40))
948 {
949 this.Messaging.Write(ErrorMessages.IllegalAttributeValueWithoutOtherAttribute(sourceLineNumbers, element.Name.LocalName, "PromptToContinue", "yes", "Description"));
950 }
951
952 if (0x22 == (attributes & 0x22))
953 {
954 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "TerminateProcess", "RebootPrompt", "yes"));
955 }
956
957 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
958
959 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4CloseApplications", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
960
961 if (!this.Messaging.EncounteredError)
962 {
963 var symbol = section.AddSymbol(new WixCloseApplicationSymbol(sourceLineNumbers, id)
964 {
965 Target = target,
966 Description = description,
967 Condition = condition,
968 Attributes = attributes,
969 Property = property,
970 });
971 if (CompilerConstants.IntegerNotSet != sequence)
972 {
973 symbol.Sequence = sequence;
974 }
975 if (CompilerConstants.IntegerNotSet != terminateExitCode)
976 {
977 symbol.TerminateExitCode = terminateExitCode;
978 }
979 if (CompilerConstants.IntegerNotSet != timeout)
980 {
981 symbol.Timeout = timeout * 1000; // make the timeout milliseconds in the table.
982 }
983 }
984 }
985
986 /// <summary>
987 /// Parses a DirectorySearch element.
988 /// </summary>
989 /// <param name="element">Element to parse.</param>
990 private void ParseDirectorySearchElement(Intermediate intermediate, IntermediateSection section, XElement element)
991 {
992 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
993 Identifier id = null;
994 string variable = null;
995 string condition = null;
996 string after = null;
997 string path = null;
998 var attributes = WixFileSearchAttributes.IsDirectory;
999
1000 foreach (var attrib in element.Attributes())
1001 {
1002 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1003 {
1004 switch (attrib.Name.LocalName)
1005 {
1006 case "Id":
1007 case "Variable":
1008 case "Condition":
1009 case "After":
1010 this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after);
1011 break;
1012 case "Path":
1013 path = this.ParseHelper.GetAttributeLongFilename(sourceLineNumbers, attrib, false, true);
1014 break;
1015 case "Result":
1016 var result = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1017 switch (result)
1018 {
1019 case "exists":
1020 attributes |= WixFileSearchAttributes.WantExists;
1021 break;
1022 default:
1023 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, result, "exists"));
1024 break;
1025 }
1026 break;
1027 default:
1028 this.ParseHelper.UnexpectedAttribute(element, attrib);
1029 break;
1030 }
1031 }
1032 else
1033 {
1034 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
1035 }
1036 }
1037
1038 if (null == path)
1039 {
1040 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Path"));
1041 }
1042
1043 if (null == id)
1044 {
1045 id = this.ParseHelper.CreateIdentifier("wds", variable, condition, after, path, attributes.ToString());
1046 }
1047
1048 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
1049
1050 this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, null);
1051
1052 if (!this.Messaging.EncounteredError)
1053 {
1054 this.CreateWixFileSearchRow(section, sourceLineNumbers, id, path, attributes);
1055 }
1056 }
1057
1058 /// <summary>
1059 /// Parses a DirectorySearchRef, FileSearchRef, ProductSearchRef, and RegistrySearchRef elements
1060 /// </summary>
1061 /// <param name="node">Element to parse.</param>
1062 private void ParseWixSearchRefElement(Intermediate intermediate, IntermediateSection section, XElement node)
1063 {
1064 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node);
1065
1066 foreach (XAttribute attrib in node.Attributes())
1067 {
1068 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1069 {
1070 switch (attrib.Name.LocalName)
1071 {
1072 case "Id":
1073 var refId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
1074 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.WixSearch, refId);
1075 break;
1076 default:
1077 this.ParseHelper.UnexpectedAttribute(node, attrib);
1078 break;
1079 }
1080 }
1081 else
1082 {
1083 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib);
1084 }
1085 }
1086
1087 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, node);
1088 }
1089
1090 /// <summary>
1091 /// Parses a FileSearch element.
1092 /// </summary>
1093 /// <param name="node">Element to parse.</param>
1094 private void ParseFileSearchElement(Intermediate intermediate, IntermediateSection section, XElement node)
1095 {
1096 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node);
1097 Identifier id = null;
1098 string variable = null;
1099 string condition = null;
1100 string after = null;
1101 string path = null;
1102 var attributes = WixFileSearchAttributes.Default;
1103
1104 foreach (var attrib in node.Attributes())
1105 {
1106 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1107 {
1108 switch (attrib.Name.LocalName)
1109 {
1110 case "Id":
1111 case "Variable":
1112 case "Condition":
1113 case "After":
1114 this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after);
1115 break;
1116 case "Path":
1117 path = this.ParseHelper.GetAttributeLongFilename(sourceLineNumbers, attrib, false, true);
1118 break;
1119 case "Result":
1120 string result = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1121 switch (result)
1122 {
1123 case "exists":
1124 attributes |= WixFileSearchAttributes.WantExists;
1125 break;
1126 case "version":
1127 attributes |= WixFileSearchAttributes.WantVersion;
1128 break;
1129 default:
1130 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, result, "exists", "version"));
1131 break;
1132 }
1133 break;
1134 default:
1135 this.ParseHelper.UnexpectedAttribute(node, attrib);
1136 break;
1137 }
1138 }
1139 else
1140 {
1141 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib);
1142 }
1143 }
1144
1145 if (null == path)
1146 {
1147 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Path"));
1148 }
1149
1150 if (null == id)
1151 {
1152 id = this.ParseHelper.CreateIdentifier("wfs", variable, condition, after, path, attributes.ToString());
1153 }
1154
1155 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, node);
1156
1157 this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, node.Name.LocalName, id, variable, condition, after, null);
1158
1159 if (!this.Messaging.EncounteredError)
1160 {
1161 this.CreateWixFileSearchRow(section, sourceLineNumbers, id, path, attributes);
1162 }
1163 }
1164
1165 /// <summary>
1166 /// Creates a row in the WixFileSearch table.
1167 /// </summary>
1168 /// <param name="sourceLineNumbers">Source line number for the parent element.</param>
1169 /// <param name="id">Identifier of the search (key into the WixSearch table)</param>
1170 /// <param name="path">File/directory path to search for.</param>
1171 /// <param name="attributes"></param>
1172 private void CreateWixFileSearchRow(IntermediateSection section, SourceLineNumber sourceLineNumbers, Identifier id, string path, WixFileSearchAttributes attributes)
1173 {
1174 section.AddSymbol(new WixFileSearchSymbol(sourceLineNumbers, id)
1175 {
1176 Path = path,
1177 Attributes = attributes,
1178 });
1179 }
1180
1181 /// <summary>
1182 /// Parses a file share element.
1183 /// </summary>
1184 /// <param name="element">Element to parse.</param>
1185 /// <param name="componentId">Identifier of parent component.</param>
1186 /// <param name="directoryId">Identifier of referred to directory.</param>
1187 private void ParseFileShareElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string directoryId)
1188 {
1189 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
1190 string description = null;
1191 string name = null;
1192 Identifier id = null;
1193
1194 foreach (var attrib in element.Attributes())
1195 {
1196 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1197 {
1198 switch (attrib.Name.LocalName)
1199 {
1200 case "Id":
1201 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
1202 break;
1203 case "Name":
1204 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1205 break;
1206 case "Description":
1207 description = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1208 break;
1209 default:
1210 this.ParseHelper.UnexpectedAttribute(element, attrib);
1211 break;
1212 }
1213 }
1214 else
1215 {
1216 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
1217 }
1218 }
1219
1220 if (null == id)
1221 {
1222 id = this.ParseHelper.CreateIdentifier("ufs", componentId, name);
1223 }
1224
1225 if (null == name)
1226 {
1227 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
1228 }
1229
1230 if (!element.Elements().Any())
1231 {
1232 this.Messaging.Write(ErrorMessages.ExpectedElement(sourceLineNumbers, element.Name.LocalName, "FileSharePermission"));
1233 }
1234
1235 foreach (var child in element.Elements())
1236 {
1237 if (this.Namespace == child.Name.Namespace)
1238 {
1239 switch (child.Name.LocalName)
1240 {
1241 case "FileSharePermission":
1242 this.ParseFileSharePermissionElement(intermediate, section, child, id);
1243 break;
1244 default:
1245 this.ParseHelper.UnexpectedElement(element, child);
1246 break;
1247 }
1248 }
1249 else
1250 {
1251 this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
1252 }
1253 }
1254
1255 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureSmbInstall", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
1256 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureSmbUninstall", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
1257
1258 if (!this.Messaging.EncounteredError)
1259 {
1260 section.AddSymbol(new FileShareSymbol(sourceLineNumbers, id)
1261 {
1262 ShareName = name,
1263 ComponentRef = componentId,
1264 Description = description,
1265 DirectoryRef = directoryId,
1266 });
1267 }
1268 }
1269
1270 /// <summary>
1271 /// Parses a FileSharePermission element.
1272 /// </summary>
1273 /// <param name="element">Element to parse.</param>
1274 /// <param name="fileShareId">The identifier of the parent FileShare element.</param>
1275 private void ParseFileSharePermissionElement(Intermediate intermediate, IntermediateSection section, XElement element, Identifier fileShareId)
1276 {
1277 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
1278 var bits = new BitArray(32);
1279 string user = null;
1280
1281 foreach (var attrib in element.Attributes())
1282 {
1283 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1284 {
1285 switch (attrib.Name.LocalName)
1286 {
1287 case "User":
1288 user = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
1289 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, UtilSymbolDefinitions.User, user);
1290 break;
1291 default:
1292 var attribValue = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1293 if (!this.TrySetBitFromName(UtilConstants.StandardPermissions, attrib.Name.LocalName, attribValue, bits, 16))
1294 {
1295 if (!this.TrySetBitFromName(UtilConstants.GenericPermissions, attrib.Name.LocalName, attribValue, bits, 28))
1296 {
1297 if (!this.TrySetBitFromName(UtilConstants.FolderPermissions, attrib.Name.LocalName, attribValue, bits, 0))
1298 {
1299 this.ParseHelper.UnexpectedAttribute(element, attrib);
1300 break;
1301 }
1302 }
1303 }
1304 break;
1305 }
1306 }
1307 else
1308 {
1309 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
1310 }
1311 }
1312
1313 var permission = this.CreateIntegerFromBitArray(bits);
1314
1315 if (null == user)
1316 {
1317 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "User"));
1318 }
1319
1320 if (Int32.MinValue == permission) // just GENERIC_READ, which is MSI_NULL
1321 {
1322 this.Messaging.Write(ErrorMessages.GenericReadNotAllowed(sourceLineNumbers));
1323 }
1324
1325 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
1326
1327 if (!this.Messaging.EncounteredError)
1328 {
1329 section.AddSymbol(new FileSharePermissionsSymbol(sourceLineNumbers)
1330 {
1331 FileShareRef = fileShareId.Id,
1332 UserRef = user,
1333 Permissions = permission,
1334 });
1335 }
1336 }
1337
1338 /// <summary>
1339 /// Parses a group element.
1340 /// </summary>
1341 /// <param name="element">Node to be parsed.</param>
1342 /// <param name="componentId">Component Id of the parent component of this element.</param>
1343 private void ParseGroupElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
1344 {
1345 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
1346 Identifier id = null;
1347 string domain = null;
1348 string name = null;
1349
1350 foreach (var attrib in element.Attributes())
1351 {
1352 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1353 {
1354 switch (attrib.Name.LocalName)
1355 {
1356 case "Id":
1357 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
1358 break;
1359 case "Name":
1360 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1361 break;
1362 case "Domain":
1363 domain = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1364 break;
1365 default:
1366 this.ParseHelper.UnexpectedAttribute(element, attrib);
1367 break;
1368 }
1369 }
1370 else
1371 {
1372 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
1373 }
1374 }
1375
1376 if (null == id)
1377 {
1378 id = this.ParseHelper.CreateIdentifier("ugr", componentId, domain, name);
1379 }
1380
1381 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
1382
1383 if (!this.Messaging.EncounteredError)
1384 {
1385 section.AddSymbol(new GroupSymbol(sourceLineNumbers, id)
1386 {
1387 ComponentRef = componentId,
1388 Name = name,
1389 Domain = domain,
1390 });
1391 }
1392 }
1393
1394 /// <summary>
1395 /// Parses a GroupRef element
1396 /// </summary>
1397 /// <param name="element">Element to parse.</param>
1398 /// <param name="userId">Required user id to be joined to the group.</param>
1399 private void ParseGroupRefElement(Intermediate intermediate, IntermediateSection section, XElement element, string userId)
1400 {
1401 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
1402 string groupId = null;
1403
1404 foreach (var attrib in element.Attributes())
1405 {
1406 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1407 {
1408 switch (attrib.Name.LocalName)
1409 {
1410 case "Id":
1411 groupId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
1412 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, UtilSymbolDefinitions.Group, groupId);
1413 break;
1414 default:
1415 this.ParseHelper.UnexpectedAttribute(element, attrib);
1416 break;
1417 }
1418 }
1419 else
1420 {
1421 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
1422 }
1423 }
1424
1425 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
1426
1427 if (!this.Messaging.EncounteredError)
1428 {
1429 section.AddSymbol(new UserGroupSymbol(sourceLineNumbers)
1430 {
1431 UserRef = userId,
1432 GroupRef = groupId,
1433 });
1434 }
1435 }
1436
1437 /// <summary>
1438 /// Parses an InternetShortcut element.
1439 /// </summary>
1440 /// <param name="element">Element to parse.</param>
1441 /// <param name="componentId">Identifier of parent component.</param>
1442 /// <param name="defaultTarget">Default directory if none is specified on the InternetShortcut element.</param>
1443 private void ParseInternetShortcutElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string defaultTarget)
1444 {
1445 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
1446 Identifier id = null;
1447 string name = null;
1448 string target = null;
1449 string directoryId = null;
1450 string type = null;
1451 string iconFile = null;
1452 int iconIndex = 0;
1453
1454 foreach (var attrib in element.Attributes())
1455 {
1456 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1457 {
1458 switch (attrib.Name.LocalName)
1459 {
1460 case "Directory":
1461 directoryId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
1462 break;
1463 case "Id":
1464 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
1465 break;
1466 case "Name":
1467 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1468 break;
1469 case "Target":
1470 target = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1471 break;
1472 case "Type":
1473 type = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1474 break;
1475 case "IconFile":
1476 iconFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1477 break;
1478 case "IconIndex":
1479 iconIndex = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
1480 break;
1481 default:
1482 this.ParseHelper.UnexpectedAttribute(element, attrib);
1483 break;
1484 }
1485 }
1486 else
1487 {
1488 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
1489 }
1490 }
1491
1492 // If there was no directoryId specified on the InternetShortcut element, default to the one on
1493 // the parent component.
1494 if (null == directoryId)
1495 {
1496 directoryId = defaultTarget;
1497 }
1498
1499 if (null == id)
1500 {
1501 id = this.ParseHelper.CreateIdentifier("uis", componentId, directoryId, name, target);
1502 }
1503
1504 // In theory this can never be the case, since InternetShortcut can only be under
1505 // a component element, and if the Directory wasn't specified the default will come
1506 // from the component. However, better safe than sorry, so here's a check to make sure
1507 // it didn't wind up being null after setting it to the defaultTarget.
1508 if (null == directoryId)
1509 {
1510 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Directory"));
1511 }
1512
1513 if (null == name)
1514 {
1515 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
1516 }
1517
1518 if (null == target)
1519 {
1520 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Target"));
1521 }
1522
1523 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
1524
1525 var shortcutType = InternetShortcutType.Link;
1526 if (String.Equals(type, "url", StringComparison.OrdinalIgnoreCase))
1527 {
1528 shortcutType = InternetShortcutType.Url;
1529 }
1530
1531 if (!this.Messaging.EncounteredError)
1532 {
1533 this.CreateWixInternetShortcut(section, sourceLineNumbers, componentId, directoryId, id, name, target, shortcutType, iconFile, iconIndex);
1534 }
1535 }
1536
1537 /// <summary>
1538 /// Creates the rows needed for WixInternetShortcut to work.
1539 /// </summary>
1540 /// <param name="core">The CompilerCore object used to create rows.</param>
1541 /// <param name="sourceLineNumbers">Source line information about the owner element.</param>
1542 /// <param name="componentId">Identifier of parent component.</param>
1543 /// <param name="directoryId">Identifier of directory containing shortcut.</param>
1544 /// <param name="id">Identifier of shortcut.</param>
1545 /// <param name="name">Name of shortcut without extension.</param>
1546 /// <param name="target">Target URL of shortcut.</param>
1547 private void CreateWixInternetShortcut(IntermediateSection section, SourceLineNumber sourceLineNumbers, string componentId, string directoryId, Identifier shortcutId, string name, string target, InternetShortcutType type, string iconFile, int iconIndex)
1548 {
1549 // add the appropriate extension based on type of shortcut
1550 name = String.Concat(name, InternetShortcutType.Url == type ? ".url" : ".lnk");
1551
1552 section.AddSymbol(new WixInternetShortcutSymbol(sourceLineNumbers, shortcutId)
1553 {
1554 ComponentRef = componentId,
1555 DirectoryRef = directoryId,
1556 Name = name,
1557 Target = target,
1558 Attributes = (int)type,
1559 IconFile = iconFile,
1560 IconIndex = iconIndex,
1561 });
1562
1563 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedInternetShortcuts", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
1564
1565 // make sure we have a CreateFolder table so that the immediate CA can add temporary rows to handle installation and uninstallation
1566 this.ParseHelper.EnsureTable(section, sourceLineNumbers, "CreateFolder");
1567
1568 // use built-in MSI functionality to remove the shortcuts rather than doing so via CA
1569 section.AddSymbol(new RemoveFileSymbol(sourceLineNumbers, shortcutId)
1570 {
1571 ComponentRef = componentId,
1572 DirPropertyRef = directoryId,
1573 OnUninstall = true,
1574 FileName = name,
1575 });
1576 }
1577
1578 /// <summary>
1579 /// Parses a performance category element.
1580 /// </summary>
1581 /// <param name="element">Element to parse.</param>
1582 /// <param name="componentId">Identifier of parent component.</param>
1583 private void ParsePerformanceCategoryElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
1584 {
1585 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
1586 Identifier id = null;
1587 string name = null;
1588 string help = null;
1589 var multiInstance = YesNoType.No;
1590 int defaultLanguage = 0x09; // default to "english"
1591
1592 var parsedPerformanceCounters = new List<ParsedPerformanceCounter>();
1593
1594 // default to managed performance counter
1595 var library = "netfxperf.dll";
1596 var openEntryPoint = "OpenPerformanceData";
1597 var collectEntryPoint = "CollectPerformanceData";
1598 var closeEntryPoint = "ClosePerformanceData";
1599
1600 foreach (var attrib in element.Attributes())
1601 {
1602 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1603 {
1604 switch (attrib.Name.LocalName)
1605 {
1606 case "Close":
1607 closeEntryPoint = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1608 break;
1609 case "Collect":
1610 collectEntryPoint = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1611 break;
1612 case "DefaultLanguage":
1613 defaultLanguage = this.GetPerformanceCounterLanguage(sourceLineNumbers, attrib);
1614 break;
1615 case "Help":
1616 help = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1617 break;
1618 case "Id":
1619 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
1620 break;
1621 case "Library":
1622 library = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1623 break;
1624 case "MultiInstance":
1625 multiInstance = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1626 break;
1627 case "Name":
1628 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1629 break;
1630 case "Open":
1631 openEntryPoint = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1632 break;
1633 default:
1634 this.ParseHelper.UnexpectedAttribute(element, attrib);
1635 break;
1636 }
1637 }
1638 else
1639 {
1640 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
1641 }
1642 }
1643
1644 if (null == id && null == name)
1645 {
1646 this.Messaging.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, element.Name.LocalName, "Id", "Name"));
1647 }
1648 else if (null == id)
1649 {
1650 id = this.ParseHelper.CreateIdentifier("upc", componentId, name);
1651 }
1652 else if (null == name)
1653 {
1654 name = id.Id;
1655 }
1656
1657 // Process the child counter elements.
1658 foreach (var child in element.Elements())
1659 {
1660 if (this.Namespace == child.Name.Namespace)
1661 {
1662 switch (child.Name.LocalName)
1663 {
1664 case "PerformanceCounter":
1665 var counter = this.ParsePerformanceCounterElement(intermediate, section, child, defaultLanguage);
1666 if (null != counter)
1667 {
1668 parsedPerformanceCounters.Add(counter);
1669 }
1670 break;
1671 default:
1672 this.ParseHelper.UnexpectedElement(element, child);
1673 break;
1674 }
1675 }
1676 else
1677 {
1678 this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
1679 }
1680 }
1681
1682
1683 if (!this.Messaging.EncounteredError)
1684 {
1685 // Calculate the ini and h file content.
1686 var objectName = "OBJECT_1";
1687 var objectLanguage = defaultLanguage.ToString("D3", CultureInfo.InvariantCulture);
1688
1689 var sbIniData = new StringBuilder();
1690 sbIniData.AppendFormat("[info]\r\ndrivername={0}\r\nsymbolfile=wixperf.h\r\n\r\n[objects]\r\n{1}_{2}_NAME=\r\n\r\n[languages]\r\n{2}=LANG{2}\r\n\r\n", name, objectName, objectLanguage);
1691 sbIniData.AppendFormat("[text]\r\n{0}_{1}_NAME={2}\r\n", objectName, objectLanguage, name);
1692 if (null != help)
1693 {
1694 sbIniData.AppendFormat("{0}_{1}_HELP={2}\r\n", objectName, objectLanguage, help);
1695 }
1696
1697 int symbolConstantsCounter = 0;
1698 var sbSymbolicConstants = new StringBuilder();
1699 sbSymbolicConstants.AppendFormat("#define {0} {1}\r\n", objectName, symbolConstantsCounter);
1700
1701 var sbCounterNames = new StringBuilder("[~]");
1702 var sbCounterTypes = new StringBuilder("[~]");
1703 for (int i = 0; i < parsedPerformanceCounters.Count; ++i)
1704 {
1705 var counter = parsedPerformanceCounters[i];
1706 var counterName = String.Concat("DEVICE_COUNTER_", i + 1);
1707
1708 sbIniData.AppendFormat("{0}_{1}_NAME={2}\r\n", counterName, counter.Language, counter.Name);
1709 if (null != counter.Help)
1710 {
1711 sbIniData.AppendFormat("{0}_{1}_HELP={2}\r\n", counterName, counter.Language, counter.Help);
1712 }
1713
1714 symbolConstantsCounter += 2;
1715 sbSymbolicConstants.AppendFormat("#define {0} {1}\r\n", counterName, symbolConstantsCounter);
1716
1717 sbCounterNames.Append(UtilCompiler.FindPropertyBrackets.Replace(counter.Name, this.EscapeProperties));
1718 sbCounterNames.Append("[~]");
1719 sbCounterTypes.Append(counter.Type);
1720 sbCounterTypes.Append("[~]");
1721 }
1722
1723 sbSymbolicConstants.AppendFormat("#define LAST_{0}_COUNTER_OFFSET {1}\r\n", objectName, symbolConstantsCounter);
1724
1725 // Add the calculated INI and H strings to the PerformanceCategory table.
1726 section.AddSymbol(new PerformanceCategorySymbol(sourceLineNumbers, id)
1727 {
1728 ComponentRef = componentId,
1729 Name = name,
1730 IniData = sbIniData.ToString(),
1731 ConstantData = sbSymbolicConstants.ToString(),
1732 });
1733
1734 // Set up the application's performance key.
1735 var escapedName = UtilCompiler.FindPropertyBrackets.Replace(name, this.EscapeProperties);
1736 var linkageKey = String.Format(@"SYSTEM\CurrentControlSet\Services\{0}\Linkage", escapedName);
1737 var performanceKey = String.Format(@"SYSTEM\CurrentControlSet\Services\{0}\Performance", escapedName);
1738
1739 this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, linkageKey, "Export", escapedName, componentId, false);
1740 this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "-", null, componentId, false);
1741 this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Library", library, componentId, false);
1742 this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Open", openEntryPoint, componentId, false);
1743 this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Collect", collectEntryPoint, componentId, false);
1744 this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Close", closeEntryPoint, componentId, false);
1745 this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "IsMultiInstance", YesNoType.Yes == multiInstance ? "#1" : "#0", componentId, false);
1746 this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Counter Names", sbCounterNames.ToString(), componentId, false);
1747 this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Counter Types", sbCounterTypes.ToString(), componentId, false);
1748 }
1749
1750 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4InstallPerfCounterData", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
1751 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4UninstallPerfCounterData", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
1752 }
1753
1754 /// <summary>
1755 /// Gets the performance counter language as a decimal number.
1756 /// </summary>
1757 /// <param name="sourceLineNumbers">Source line information about the owner element.</param>
1758 /// <param name="attribute">The attribute containing the value to get.</param>
1759 /// <returns>Numeric representation of the language as per WinNT.h.</returns>
1760 private int GetPerformanceCounterLanguage(SourceLineNumber sourceLineNumbers, XAttribute attribute)
1761 {
1762 int language = 0;
1763 if (String.Empty == attribute.Value)
1764 {
1765 this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName));
1766 }
1767 else
1768 {
1769 switch (attribute.Value)
1770 {
1771 case "afrikaans":
1772 language = 0x36;
1773 break;
1774 case "albanian":
1775 language = 0x1c;
1776 break;
1777 case "arabic":
1778 language = 0x01;
1779 break;
1780 case "armenian":
1781 language = 0x2b;
1782 break;
1783 case "assamese":
1784 language = 0x4d;
1785 break;
1786 case "azeri":
1787 language = 0x2c;
1788 break;
1789 case "basque":
1790 language = 0x2d;
1791 break;
1792 case "belarusian":
1793 language = 0x23;
1794 break;
1795 case "bengali":
1796 language = 0x45;
1797 break;
1798 case "bulgarian":
1799 language = 0x02;
1800 break;
1801 case "catalan":
1802 language = 0x03;
1803 break;
1804 case "chinese":
1805 language = 0x04;
1806 break;
1807 case "croatian":
1808 language = 0x1a;
1809 break;
1810 case "czech":
1811 language = 0x05;
1812 break;
1813 case "danish":
1814 language = 0x06;
1815 break;
1816 case "divehi":
1817 language = 0x65;
1818 break;
1819 case "dutch":
1820 language = 0x13;
1821 break;
1822 case "piglatin":
1823 case "english":
1824 language = 0x09;
1825 break;
1826 case "estonian":
1827 language = 0x25;
1828 break;
1829 case "faeroese":
1830 language = 0x38;
1831 break;
1832 case "farsi":
1833 language = 0x29;
1834 break;
1835 case "finnish":
1836 language = 0x0b;
1837 break;
1838 case "french":
1839 language = 0x0c;
1840 break;
1841 case "galician":
1842 language = 0x56;
1843 break;
1844 case "georgian":
1845 language = 0x37;
1846 break;
1847 case "german":
1848 language = 0x07;
1849 break;
1850 case "greek":
1851 language = 0x08;
1852 break;
1853 case "gujarati":
1854 language = 0x47;
1855 break;
1856 case "hebrew":
1857 language = 0x0d;
1858 break;
1859 case "hindi":
1860 language = 0x39;
1861 break;
1862 case "hungarian":
1863 language = 0x0e;
1864 break;
1865 case "icelandic":
1866 language = 0x0f;
1867 break;
1868 case "indonesian":
1869 language = 0x21;
1870 break;
1871 case "italian":
1872 language = 0x10;
1873 break;
1874 case "japanese":
1875 language = 0x11;
1876 break;
1877 case "kannada":
1878 language = 0x4b;
1879 break;
1880 case "kashmiri":
1881 language = 0x60;
1882 break;
1883 case "kazak":
1884 language = 0x3f;
1885 break;
1886 case "konkani":
1887 language = 0x57;
1888 break;
1889 case "korean":
1890 language = 0x12;
1891 break;
1892 case "kyrgyz":
1893 language = 0x40;
1894 break;
1895 case "latvian":
1896 language = 0x26;
1897 break;
1898 case "lithuanian":
1899 language = 0x27;
1900 break;
1901 case "macedonian":
1902 language = 0x2f;
1903 break;
1904 case "malay":
1905 language = 0x3e;
1906 break;
1907 case "malayalam":
1908 language = 0x4c;
1909 break;
1910 case "manipuri":
1911 language = 0x58;
1912 break;
1913 case "marathi":
1914 language = 0x4e;
1915 break;
1916 case "mongolian":
1917 language = 0x50;
1918 break;
1919 case "nepali":
1920 language = 0x61;
1921 break;
1922 case "norwegian":
1923 language = 0x14;
1924 break;
1925 case "oriya":
1926 language = 0x48;
1927 break;
1928 case "polish":
1929 language = 0x15;
1930 break;
1931 case "portuguese":
1932 language = 0x16;
1933 break;
1934 case "punjabi":
1935 language = 0x46;
1936 break;
1937 case "romanian":
1938 language = 0x18;
1939 break;
1940 case "russian":
1941 language = 0x19;
1942 break;
1943 case "sanskrit":
1944 language = 0x4f;
1945 break;
1946 case "serbian":
1947 language = 0x1a;
1948 break;
1949 case "sindhi":
1950 language = 0x59;
1951 break;
1952 case "slovak":
1953 language = 0x1b;
1954 break;
1955 case "slovenian":
1956 language = 0x24;
1957 break;
1958 case "spanish":
1959 language = 0x0a;
1960 break;
1961 case "swahili":
1962 language = 0x41;
1963 break;
1964 case "swedish":
1965 language = 0x1d;
1966 break;
1967 case "syriac":
1968 language = 0x5a;
1969 break;
1970 case "tamil":
1971 language = 0x49;
1972 break;
1973 case "tatar":
1974 language = 0x44;
1975 break;
1976 case "telugu":
1977 language = 0x4a;
1978 break;
1979 case "thai":
1980 language = 0x1e;
1981 break;
1982 case "turkish":
1983 language = 0x1f;
1984 break;
1985 case "ukrainian":
1986 language = 0x22;
1987 break;
1988 case "urdu":
1989 language = 0x20;
1990 break;
1991 case "uzbek":
1992 language = 0x43;
1993 break;
1994 case "vietnamese":
1995 language = 0x2a;
1996 break;
1997 default:
1998 this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName));
1999 break;
2000 }
2001 }
2002
2003 return language;
2004 }
2005
2006 /// <summary>
2007 /// Parses a performance counter element.
2008 /// </summary>
2009 /// <param name="element">Element to parse.</param>
2010 /// <param name="defaultLanguage">Default language for the performance counter.</param>
2011 private ParsedPerformanceCounter ParsePerformanceCounterElement(Intermediate intermediate, IntermediateSection section, XElement element, int defaultLanguage)
2012 {
2013 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2014 ParsedPerformanceCounter parsedPerformanceCounter = null;
2015 string name = null;
2016 string help = null;
2017 var type = System.Diagnostics.PerformanceCounterType.NumberOfItems32;
2018 int language = defaultLanguage;
2019
2020 foreach (var attrib in element.Attributes())
2021 {
2022 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2023 {
2024 switch (attrib.Name.LocalName)
2025 {
2026 case "Help":
2027 help = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2028 break;
2029 case "Name":
2030 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2031 break;
2032 case "Type":
2033 type = this.GetPerformanceCounterType(sourceLineNumbers, attrib);
2034 break;
2035 case "Language":
2036 language = this.GetPerformanceCounterLanguage(sourceLineNumbers, attrib);
2037 break;
2038 default:
2039 this.ParseHelper.UnexpectedAttribute(element, attrib);
2040 break;
2041 }
2042 }
2043 else
2044 {
2045 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2046 }
2047 }
2048
2049 if (null == name)
2050 {
2051 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
2052 }
2053
2054 if (null == help)
2055 {
2056 this.Messaging.Write(UtilWarnings.RequiredAttributeForWindowsXP(sourceLineNumbers, element.Name.LocalName, "Help"));
2057 }
2058
2059 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2060
2061 if (!this.Messaging.EncounteredError)
2062 {
2063 parsedPerformanceCounter = new ParsedPerformanceCounter(name, help, type, language);
2064 }
2065
2066 return parsedPerformanceCounter;
2067 }
2068
2069 /// <summary>
2070 /// Gets the performance counter type.
2071 /// </summary>
2072 /// <param name="sourceLineNumbers">Source line information about the owner element.</param>
2073 /// <param name="attribute">The attribute containing the value to get.</param>
2074 /// <returns>Numeric representation of the language as per WinNT.h.</returns>
2075 private System.Diagnostics.PerformanceCounterType GetPerformanceCounterType(SourceLineNumber sourceLineNumbers, XAttribute attribute)
2076 {
2077 var type = System.Diagnostics.PerformanceCounterType.NumberOfItems32;
2078 if (String.Empty == attribute.Value)
2079 {
2080 this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName));
2081 }
2082 else
2083 {
2084 switch (attribute.Value)
2085 {
2086 case "averageBase":
2087 type = System.Diagnostics.PerformanceCounterType.AverageBase;
2088 break;
2089 case "averageCount64":
2090 type = System.Diagnostics.PerformanceCounterType.AverageCount64;
2091 break;
2092 case "averageTimer32":
2093 type = System.Diagnostics.PerformanceCounterType.AverageTimer32;
2094 break;
2095 case "counterDelta32":
2096 type = System.Diagnostics.PerformanceCounterType.CounterDelta32;
2097 break;
2098 case "counterTimerInverse":
2099 type = System.Diagnostics.PerformanceCounterType.CounterTimerInverse;
2100 break;
2101 case "sampleFraction":
2102 type = System.Diagnostics.PerformanceCounterType.SampleFraction;
2103 break;
2104 case "timer100Ns":
2105 type = System.Diagnostics.PerformanceCounterType.Timer100Ns;
2106 break;
2107 case "counterTimer":
2108 type = System.Diagnostics.PerformanceCounterType.CounterTimer;
2109 break;
2110 case "rawFraction":
2111 type = System.Diagnostics.PerformanceCounterType.RawFraction;
2112 break;
2113 case "timer100NsInverse":
2114 type = System.Diagnostics.PerformanceCounterType.Timer100NsInverse;
2115 break;
2116 case "counterMultiTimer":
2117 type = System.Diagnostics.PerformanceCounterType.CounterMultiTimer;
2118 break;
2119 case "counterMultiTimer100Ns":
2120 type = System.Diagnostics.PerformanceCounterType.CounterMultiTimer100Ns;
2121 break;
2122 case "counterMultiTimerInverse":
2123 type = System.Diagnostics.PerformanceCounterType.CounterMultiTimerInverse;
2124 break;
2125 case "counterMultiTimer100NsInverse":
2126 type = System.Diagnostics.PerformanceCounterType.CounterMultiTimer100NsInverse;
2127 break;
2128 case "elapsedTime":
2129 type = System.Diagnostics.PerformanceCounterType.ElapsedTime;
2130 break;
2131 case "sampleBase":
2132 type = System.Diagnostics.PerformanceCounterType.SampleBase;
2133 break;
2134 case "rawBase":
2135 type = System.Diagnostics.PerformanceCounterType.RawBase;
2136 break;
2137 case "counterMultiBase":
2138 type = System.Diagnostics.PerformanceCounterType.CounterMultiBase;
2139 break;
2140 case "rateOfCountsPerSecond64":
2141 type = System.Diagnostics.PerformanceCounterType.RateOfCountsPerSecond64;
2142 break;
2143 case "rateOfCountsPerSecond32":
2144 type = System.Diagnostics.PerformanceCounterType.RateOfCountsPerSecond32;
2145 break;
2146 case "countPerTimeInterval64":
2147 type = System.Diagnostics.PerformanceCounterType.CountPerTimeInterval64;
2148 break;
2149 case "countPerTimeInterval32":
2150 type = System.Diagnostics.PerformanceCounterType.CountPerTimeInterval32;
2151 break;
2152 case "sampleCounter":
2153 type = System.Diagnostics.PerformanceCounterType.SampleCounter;
2154 break;
2155 case "counterDelta64":
2156 type = System.Diagnostics.PerformanceCounterType.CounterDelta64;
2157 break;
2158 case "numberOfItems64":
2159 type = System.Diagnostics.PerformanceCounterType.NumberOfItems64;
2160 break;
2161 case "numberOfItems32":
2162 type = System.Diagnostics.PerformanceCounterType.NumberOfItems32;
2163 break;
2164 case "numberOfItemsHEX64":
2165 type = System.Diagnostics.PerformanceCounterType.NumberOfItemsHEX64;
2166 break;
2167 case "numberOfItemsHEX32":
2168 type = System.Diagnostics.PerformanceCounterType.NumberOfItemsHEX32;
2169 break;
2170 default:
2171 this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName));
2172 break;
2173 }
2174 }
2175
2176 return type;
2177 }
2178
2179 /// <summary>
2180 /// Parses a perf counter element.
2181 /// </summary>
2182 /// <param name="element">Element to parse.</param>
2183 /// <param name="componentId">Identifier of parent component.</param>
2184 /// <param name="fileId">Identifier of referenced file.</param>
2185 private void ParsePerfCounterElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string fileId)
2186 {
2187 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2188 string name = null;
2189
2190 this.Messaging.Write(UtilWarnings.DeprecatedPerfCounterElement(sourceLineNumbers));
2191
2192 foreach (var attrib in element.Attributes())
2193 {
2194 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2195 {
2196 switch (attrib.Name.LocalName)
2197 {
2198 case "Name":
2199 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2200 break;
2201 default:
2202 this.ParseHelper.UnexpectedAttribute(element, attrib);
2203 break;
2204 }
2205 }
2206 else
2207 {
2208 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2209 }
2210 }
2211
2212 if (null == name)
2213 {
2214 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
2215 }
2216
2217 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2218
2219 if (!this.Messaging.EncounteredError)
2220 {
2221 section.AddSymbol(new PerfmonSymbol(sourceLineNumbers)
2222 {
2223 ComponentRef = componentId,
2224 File = $"[#{fileId}]",
2225 Name = name,
2226 });
2227 }
2228
2229 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigurePerfmonInstall", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
2230 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigurePerfmonUninstall", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
2231 }
2232
2233
2234 /// <summary>
2235 /// Parses a perf manifest element.
2236 /// </summary>
2237 /// <param name="element">Element to parse.</param>
2238 /// <param name="componentId">Identifier of parent component.</param>
2239 /// <param name="fileId">Identifier of referenced file.</param>
2240 private void ParsePerfCounterManifestElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string fileId)
2241 {
2242 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2243 string resourceFileDirectory = null;
2244
2245 foreach (var attrib in element.Attributes())
2246 {
2247 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2248 {
2249 switch (attrib.Name.LocalName)
2250 {
2251 case "ResourceFileDirectory":
2252 resourceFileDirectory = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2253 break;
2254 default:
2255 this.ParseHelper.UnexpectedAttribute(element, attrib);
2256 break;
2257 }
2258 }
2259 else
2260 {
2261 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2262 }
2263 }
2264
2265 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2266
2267 if (!this.Messaging.EncounteredError)
2268 {
2269 section.AddSymbol(new PerfmonManifestSymbol(sourceLineNumbers)
2270 {
2271 ComponentRef = componentId,
2272 File = $"[#{fileId}]",
2273 ResourceFileDirectory = resourceFileDirectory,
2274 });
2275 }
2276
2277 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigurePerfmonManifestRegister", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
2278 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigurePerfmonManifestUnregister", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
2279 }
2280
2281 /// <summary>
2282 /// Parses a format files element.
2283 /// </summary>
2284 /// <param name="element">Element to parse.</param>
2285 /// <param name="fileId">Identifier of referenced file.</param>
2286 /// <param name="win64">Flag to determine whether the component is 64-bit.</param>
2287 private void ParseFormatFileElement(Intermediate intermediate, IntermediateSection section, XElement element, string fileId, bool win64)
2288 {
2289 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2290 string binaryId = null;
2291
2292 foreach (var attrib in element.Attributes())
2293 {
2294 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2295 {
2296 switch (attrib.Name.LocalName)
2297 {
2298 case "BinaryRef":
2299 binaryId = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2300 break;
2301 default:
2302 this.ParseHelper.UnexpectedAttribute(element, attrib);
2303 break;
2304 }
2305 }
2306 else
2307 {
2308 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2309 }
2310 }
2311
2312 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2313
2314 if (null == binaryId)
2315 {
2316 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "BinaryRef"));
2317 }
2318
2319 if (!this.Messaging.EncounteredError)
2320 {
2321 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedFormatFiles", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
2322
2323 section.AddSymbol(new WixFormatFilesSymbol(sourceLineNumbers)
2324 {
2325 BinaryRef = binaryId,
2326 FileRef = fileId,
2327 });
2328
2329 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.Binary, binaryId);
2330 }
2331 }
2332
2333 /// <summary>
2334 /// Parses a event manifest element.
2335 /// </summary>
2336 /// <param name="element">Element to parse.</param>
2337 /// <param name="componentId">Identifier of parent component.</param>
2338 /// <param name="fileId">Identifier of referenced file.</param>
2339 private void ParseEventManifestElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string fileId)
2340 {
2341 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2342 string messageFile = null;
2343 string resourceFile = null;
2344 string parameterFile = null;
2345
2346 foreach (var attrib in element.Attributes())
2347 {
2348 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2349 {
2350 switch (attrib.Name.LocalName)
2351 {
2352 case "MessageFile":
2353 messageFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2354 break;
2355 case "ResourceFile":
2356 resourceFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2357 break;
2358 case "ParameterFile":
2359 parameterFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2360 break;
2361 default:
2362 this.ParseHelper.UnexpectedAttribute(element, attrib);
2363 break;
2364 }
2365 }
2366 else
2367 {
2368 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2369 }
2370 }
2371
2372 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2373
2374 if (!this.Messaging.EncounteredError)
2375 {
2376 section.AddSymbol(new EventManifestSymbol(sourceLineNumbers)
2377 {
2378 ComponentRef = componentId,
2379 File = $"[#{fileId}]",
2380 });
2381
2382 if (null != messageFile)
2383 {
2384 section.AddSymbol(new XmlFileSymbol(sourceLineNumbers, new Identifier(AccessModifier.Section, $"Config_{fileId}MessageFile"))
2385 {
2386 File = $"[#{fileId}]",
2387 ElementPath = "/*/*/*/*[\\[]@messageFileName[\\]]",
2388 Name = "messageFileName",
2389 Value = messageFile,
2390 Flags = 4 | 0x00001000, //bulk write | preserve modified date
2391 ComponentRef = componentId,
2392 });
2393 }
2394 if (null != parameterFile)
2395 {
2396 section.AddSymbol(new XmlFileSymbol(sourceLineNumbers, new Identifier(AccessModifier.Section, $"Config_{fileId}ParameterFile"))
2397 {
2398 File = $"[#{fileId}]",
2399 ElementPath = "/*/*/*/*[\\[]@parameterFileName[\\]]",
2400 Name = "parameterFileName",
2401 Value = parameterFile,
2402 Flags = 4 | 0x00001000, //bulk write | preserve modified date
2403 ComponentRef = componentId,
2404 });
2405 }
2406 if (null != resourceFile)
2407 {
2408 section.AddSymbol(new XmlFileSymbol(sourceLineNumbers, new Identifier(AccessModifier.Section, $"Config_{fileId}ResourceFile"))
2409 {
2410 File = $"[#{fileId}]",
2411 ElementPath = "/*/*/*/*[\\[]@resourceFileName[\\]]",
2412 Name = "resourceFileName",
2413 Value = resourceFile,
2414 Flags = 4 | 0x00001000, //bulk write | preserve modified date
2415 ComponentRef = componentId,
2416 });
2417 }
2418
2419 }
2420
2421 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureEventManifestRegister", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
2422 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureEventManifestUnregister", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
2423
2424 if (null != messageFile || null != parameterFile || null != resourceFile)
2425 {
2426 this.AddReferenceToSchedXmlFile(sourceLineNumbers, section);
2427 }
2428 }
2429
2430 /// <summary>
2431 /// Parses a PermissionEx element.
2432 /// </summary>
2433 /// <param name="element">Element to parse.</param>
2434 /// <param name="objectId">Identifier of object to be secured.</param>
2435 /// <param name="componentId">Identifier of component, used to determine install state.</param>
2436 /// <param name="win64">Flag to determine whether the component is 64-bit.</param>
2437 /// <param name="tableName">Name of table that contains objectId.</param>
2438 private void ParsePermissionExElement(Intermediate intermediate, IntermediateSection section, XElement element, string objectId, string componentId, bool win64, string tableName)
2439 {
2440 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2441 var bits = new BitArray(32);
2442 string domain = null;
2443 string[] specialPermissions = null;
2444 string user = null;
2445 var attributes = WixPermissionExAttributes.Inheritable; // default to inheritable.
2446
2447 var permissionType = PermissionType.SecureObjects;
2448
2449 switch (tableName)
2450 {
2451 case "CreateFolder":
2452 specialPermissions = UtilConstants.FolderPermissions;
2453 break;
2454 case "File":
2455 specialPermissions = UtilConstants.FilePermissions;
2456 break;
2457 case "Registry":
2458 specialPermissions = UtilConstants.RegistryPermissions;
2459 if (String.IsNullOrEmpty(objectId))
2460 {
2461 this.Messaging.Write(UtilErrors.InvalidRegistryObject(sourceLineNumbers, element.Parent.Name.LocalName));
2462 }
2463 break;
2464 case "ServiceInstall":
2465 specialPermissions = UtilConstants.ServicePermissions;
2466 permissionType = PermissionType.SecureObjects;
2467 break;
2468 default:
2469 this.ParseHelper.UnexpectedElement(element.Parent, element);
2470 break;
2471 }
2472
2473 foreach (var attrib in element.Attributes())
2474 {
2475 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2476 {
2477 switch (attrib.Name.LocalName)
2478 {
2479 case "Domain":
2480 if (PermissionType.FileSharePermissions == permissionType)
2481 {
2482 this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, element.Parent.Name.LocalName));
2483 }
2484 domain = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2485 break;
2486 case "Inheritable":
2487 if (this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) == YesNoType.No)
2488 {
2489 attributes &= ~WixPermissionExAttributes.Inheritable;
2490 }
2491 break;
2492 case "User":
2493 user = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2494 break;
2495 default:
2496 var attribValue = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
2497 if (!this.TrySetBitFromName(UtilConstants.StandardPermissions, attrib.Name.LocalName, attribValue, bits, 16))
2498 {
2499 if (!this.TrySetBitFromName(UtilConstants.GenericPermissions, attrib.Name.LocalName, attribValue, bits, 28))
2500 {
2501 if (!this.TrySetBitFromName(specialPermissions, attrib.Name.LocalName, attribValue, bits, 0))
2502 {
2503 this.ParseHelper.UnexpectedAttribute(element, attrib);
2504 break;
2505 }
2506 }
2507 }
2508 break;
2509 }
2510 }
2511 else
2512 {
2513 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2514 }
2515 }
2516
2517 var permission = this.CreateIntegerFromBitArray(bits);
2518
2519 if (null == user)
2520 {
2521 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "User"));
2522 }
2523
2524 if (Int32.MinValue == permission) // just GENERIC_READ, which is MSI_NULL
2525 {
2526 this.Messaging.Write(ErrorMessages.GenericReadNotAllowed(sourceLineNumbers));
2527 }
2528
2529 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2530
2531 if (!this.Messaging.EncounteredError)
2532 {
2533 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedSecureObjects", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
2534
2535 var id = this.ParseHelper.CreateIdentifier("sec", objectId, tableName, domain, user);
2536 section.AddSymbol(new SecureObjectsSymbol(sourceLineNumbers, id)
2537 {
2538 SecureObject = objectId,
2539 Table = tableName,
2540 Domain = domain,
2541 User = user,
2542 Attributes = attributes,
2543 Permission = permission,
2544 ComponentRef = componentId,
2545 });
2546 }
2547 }
2548
2549 /// <summary>
2550 /// Parses a ProductSearch element.
2551 /// </summary>
2552 /// <param name="element">Element to parse.</param>
2553 private void ParseProductSearchElement(Intermediate intermediate, IntermediateSection section, XElement element)
2554 {
2555 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2556 Identifier id = null;
2557 string variable = null;
2558 string condition = null;
2559 string after = null;
2560 string productCode = null;
2561 string upgradeCode = null;
2562 var attributes = WixProductSearchAttributes.Version;
2563
2564 foreach (var attrib in element.Attributes())
2565 {
2566 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2567 {
2568 switch (attrib.Name.LocalName)
2569 {
2570 case "Id":
2571 case "Variable":
2572 case "Condition":
2573 case "After":
2574 this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after);
2575 break;
2576 case "ProductCode":
2577 productCode = this.ParseHelper.GetAttributeGuidValue(sourceLineNumbers, attrib, false);
2578 break;
2579 case "UpgradeCode":
2580 upgradeCode = this.ParseHelper.GetAttributeGuidValue(sourceLineNumbers, attrib, false);
2581 break;
2582 case "Result":
2583 var result = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2584 switch (result)
2585 {
2586 case "version":
2587 attributes = WixProductSearchAttributes.Version;
2588 break;
2589 case "language":
2590 attributes = WixProductSearchAttributes.Language;
2591 break;
2592 case "state":
2593 attributes = WixProductSearchAttributes.State;
2594 break;
2595 case "assignment":
2596 attributes = WixProductSearchAttributes.Assignment;
2597 break;
2598 default:
2599 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, result, "version", "language", "state", "assignment"));
2600 break;
2601 }
2602 break;
2603 default:
2604 this.ParseHelper.UnexpectedAttribute(element, attrib);
2605 break;
2606 }
2607 }
2608 else
2609 {
2610 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2611 }
2612 }
2613
2614 if (null == upgradeCode && null == productCode)
2615 {
2616 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "ProductCode", "UpgradeCode", true));
2617 }
2618
2619 if (null != upgradeCode && null != productCode)
2620 {
2621 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "UpgradeCode", "ProductCode"));
2622 }
2623
2624 if (null == id)
2625 {
2626 id = this.ParseHelper.CreateIdentifier("wps", variable, condition, after, (productCode == null ? upgradeCode : productCode), attributes.ToString());
2627 }
2628
2629 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2630
2631 this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, null);
2632
2633 if (!this.Messaging.EncounteredError)
2634 {
2635 // set an additional flag if this is an upgrade code
2636 if (null != upgradeCode)
2637 {
2638 attributes |= WixProductSearchAttributes.UpgradeCode;
2639 }
2640
2641 section.AddSymbol(new WixProductSearchSymbol(sourceLineNumbers, id)
2642 {
2643 Guid = productCode ?? upgradeCode,
2644 Attributes = attributes,
2645 });
2646 }
2647 }
2648
2649 /// <summary>
2650 /// Parses a RegistrySearch element.
2651 /// </summary>
2652 /// <param name="element">Element to parse.</param>
2653 private void ParseRegistrySearchElement(Intermediate intermediate, IntermediateSection section, XElement element)
2654 {
2655 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2656 Identifier id = null;
2657 string variable = null;
2658 string condition = null;
2659 string after = null;
2660 RegistryRootType? root = null;
2661 string key = null;
2662 string value = null;
2663 var expand = YesNoType.NotSet;
2664 var win64 = this.Context.IsCurrentPlatform64Bit;
2665 var attributes = WixRegistrySearchAttributes.Raw | WixRegistrySearchAttributes.WantValue;
2666
2667 foreach (var attrib in element.Attributes())
2668 {
2669 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2670 {
2671 switch (attrib.Name.LocalName)
2672 {
2673 case "Id":
2674 case "Variable":
2675 case "Condition":
2676 case "After":
2677 this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after);
2678 break;
2679 case "Bitness":
2680 var bitnessValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2681 switch (bitnessValue)
2682 {
2683 case "always32":
2684 win64 = false;
2685 break;
2686 case "always64":
2687 win64 = true;
2688 break;
2689 case "default":
2690 case "":
2691 break;
2692 default:
2693 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Name.LocalName, attrib.Name.LocalName, bitnessValue, "default", "always32", "always64"));
2694 break;
2695 }
2696 break;
2697 case "Root":
2698 root = this.ParseHelper.GetAttributeRegistryRootValue(sourceLineNumbers, attrib, false);
2699 break;
2700 case "Key":
2701 key = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2702 break;
2703 case "Value":
2704 value = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2705 break;
2706 case "ExpandEnvironmentVariables":
2707 expand = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
2708 break;
2709 case "Format":
2710 string format = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2711 switch (format)
2712 {
2713 case "raw":
2714 attributes |= WixRegistrySearchAttributes.Raw;
2715 break;
2716 case "compatible":
2717 attributes |= WixRegistrySearchAttributes.Compatible;
2718 break;
2719 default:
2720 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, format, "raw", "compatible"));
2721 break;
2722 }
2723 break;
2724 case "Result":
2725 var result = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2726 switch (result)
2727 {
2728 case "exists":
2729 attributes |= WixRegistrySearchAttributes.WantExists;
2730 break;
2731 case "value":
2732 attributes |= WixRegistrySearchAttributes.WantValue;
2733 break;
2734 default:
2735 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, result, "exists", "value"));
2736 break;
2737 }
2738 break;
2739 default:
2740 this.ParseHelper.UnexpectedAttribute(element, attrib);
2741 break;
2742 }
2743 }
2744 else
2745 {
2746 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2747 }
2748 }
2749
2750 if (!root.HasValue)
2751 {
2752 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Root"));
2753 }
2754
2755 if (null == key)
2756 {
2757 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Key"));
2758 }
2759
2760 if (null == id)
2761 {
2762 id = this.ParseHelper.CreateIdentifier("wrs", variable, condition, after, root.ToString(), key, value, attributes.ToString());
2763 }
2764
2765 if (expand == YesNoType.Yes)
2766 {
2767 if (0 != (attributes & WixRegistrySearchAttributes.WantExists))
2768 {
2769 this.Messaging.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "ExpandEnvironmentVariables", expand.ToString(), "Result", "exists"));
2770 }
2771
2772 attributes |= WixRegistrySearchAttributes.ExpandEnvironmentVariables;
2773 }
2774
2775 if (win64)
2776 {
2777 attributes |= WixRegistrySearchAttributes.Win64;
2778 }
2779
2780 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2781
2782 this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, null);
2783
2784 if (!this.Messaging.EncounteredError)
2785 {
2786 section.AddSymbol(new WixRegistrySearchSymbol(sourceLineNumbers, id)
2787 {
2788 Root = root.Value,
2789 Key = key,
2790 Value = value,
2791 Attributes = attributes,
2792 });
2793 }
2794 }
2795
2796 /// <summary>
2797 /// Parses a RemoveFolderEx element.
2798 /// </summary>
2799 /// <param name="element">Element to parse.</param>
2800 /// <param name="componentId">Identifier of parent component.</param>
2801 private void ParseRemoveFolderExElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
2802 {
2803 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2804 Identifier id = null;
2805 var mode = WixRemoveFolderExInstallMode.Uninstall;
2806 string property = null;
2807 string condition = null;
2808
2809 foreach (var attrib in element.Attributes())
2810 {
2811 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2812 {
2813 switch (attrib.Name.LocalName)
2814 {
2815 case "Condition":
2816 condition = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2817 break;
2818 case "Id":
2819 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
2820 break;
2821 case "On":
2822 var onValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2823 if (onValue.Length == 0)
2824 {
2825 }
2826 else
2827 {
2828 switch (onValue)
2829 {
2830 case "install":
2831 mode = WixRemoveFolderExInstallMode.Install;
2832 break;
2833 case "uninstall":
2834 mode = WixRemoveFolderExInstallMode.Uninstall;
2835 break;
2836 case "both":
2837 mode = WixRemoveFolderExInstallMode.Both;
2838 break;
2839 default:
2840 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "On", onValue, "install", "uninstall", "both"));
2841 break;
2842 }
2843 }
2844 break;
2845 case "Property":
2846 property = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2847 break;
2848 default:
2849 this.ParseHelper.UnexpectedAttribute(element, attrib);
2850 break;
2851 }
2852 }
2853 else
2854 {
2855 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2856 }
2857 }
2858
2859 if (String.IsNullOrEmpty(property))
2860 {
2861 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Property"));
2862 }
2863
2864 if (id == null)
2865 {
2866 id = this.ParseHelper.CreateIdentifier("wrf", componentId, property, mode.ToString());
2867 }
2868
2869 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2870
2871 if (!this.Messaging.EncounteredError)
2872 {
2873 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4RemoveFoldersEx", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
2874
2875 section.AddSymbol(new WixRemoveFolderExSymbol(sourceLineNumbers, id)
2876 {
2877 ComponentRef = componentId,
2878 Property = property,
2879 InstallMode = mode,
2880 Condition = condition
2881 });
2882
2883 this.ParseHelper.EnsureTable(section, sourceLineNumbers, "RemoveFile");
2884 }
2885 }
2886
2887 /// <summary>
2888 /// Parses a RemoveRegistryKeyEx element.
2889 /// </summary>
2890 /// <param name="node">Element to parse.</param>
2891 /// <param name="componentId">Identifier of parent component.</param>
2892 private void ParseRemoveRegistryKeyExElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
2893 {
2894 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2895 Identifier id = null;
2896 var mode = WixRemoveRegistryKeyExInstallMode.Uninstall;
2897 string condition = null;
2898 RegistryRootType? root = null;
2899 string key = null;
2900
2901 foreach (var attrib in element.Attributes())
2902 {
2903 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2904 {
2905 switch (attrib.Name.LocalName)
2906 {
2907 case "Condition":
2908 condition = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2909 break;
2910 case "Id":
2911 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
2912 break;
2913 case "On":
2914 var actionValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2915 switch (actionValue)
2916 {
2917 case "":
2918 break;
2919 case "install":
2920 mode = WixRemoveRegistryKeyExInstallMode.Install;
2921 break;
2922 case "uninstall":
2923 mode = WixRemoveRegistryKeyExInstallMode.Uninstall;
2924 break;
2925 default:
2926 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "On", actionValue, "install", "uninstall"));
2927 break;
2928 }
2929 break;
2930 case "Root":
2931 root = this.ParseHelper.GetAttributeRegistryRootValue(sourceLineNumbers, attrib, false);
2932 break;
2933 case "Key":
2934 key = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2935 break;
2936 default:
2937 this.ParseHelper.UnexpectedAttribute(element, attrib);
2938 break;
2939 }
2940 }
2941 else
2942 {
2943 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2944 }
2945 }
2946
2947 if (!root.HasValue)
2948 {
2949 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Root"));
2950 }
2951
2952 if (key == null)
2953 {
2954 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Key"));
2955 }
2956
2957 if (id == null)
2958 {
2959 id = this.ParseHelper.CreateIdentifier("rrx", componentId, condition, root.ToString(), key, mode.ToString());
2960 }
2961
2962 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2963
2964 if (!this.Messaging.EncounteredError)
2965 {
2966 this.ParseHelper.EnsureTable(section, sourceLineNumbers, "Registry");
2967 this.ParseHelper.EnsureTable(section, sourceLineNumbers, "RemoveRegistry");
2968 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4RemoveRegistryKeysEx", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
2969
2970 section.AddSymbol(new WixRemoveRegistryKeyExSymbol(sourceLineNumbers, id)
2971 {
2972 ComponentRef = componentId,
2973 Root = root.Value,
2974 Key = key,
2975 InstallMode = mode,
2976 Condition = condition
2977 });
2978 }
2979 }
2980
2981 /// <summary>
2982 /// Parses a RestartResource element.
2983 /// </summary>
2984 /// <param name="element">The element to parse.</param>
2985 /// <param name="componentId">The identity of the parent component.</param>
2986 private void ParseRestartResourceElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
2987 {
2988 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2989 Identifier id = null;
2990 string resource = null;
2991 WixRestartResourceAttributes? attributes = null;
2992
2993 foreach (var attrib in element.Attributes())
2994 {
2995 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2996 {
2997 switch (attrib.Name.LocalName)
2998 {
2999 case "Id":
3000 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
3001 break;
3002
3003 case "Path":
3004 resource = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3005 attributes = WixRestartResourceAttributes.Filename;
3006 break;
3007
3008 case "ProcessName":
3009 resource = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3010 attributes = WixRestartResourceAttributes.ProcessName;
3011 break;
3012
3013 case "ServiceName":
3014 resource = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3015 attributes = WixRestartResourceAttributes.ServiceName;
3016 break;
3017
3018 default:
3019 this.ParseHelper.UnexpectedAttribute(element, attrib);
3020 break;
3021 }
3022 }
3023 else
3024 {
3025 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
3026 }
3027 }
3028
3029 // Validate the attribute.
3030 if (id == null)
3031 {
3032 id = this.ParseHelper.CreateIdentifier("wrr", componentId, resource, attributes.ToString());
3033 }
3034
3035 if (!attributes.HasValue)
3036 {
3037 this.Messaging.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, element.Name.LocalName, "Path", "ProcessName", "ServiceName"));
3038 }
3039
3040 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
3041
3042 if (!this.Messaging.EncounteredError)
3043 {
3044 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4RegisterRestartResources", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
3045
3046 section.AddSymbol(new WixRestartResourceSymbol(sourceLineNumbers, id)
3047 {
3048 ComponentRef = componentId,
3049 Resource = resource,
3050 Attributes = attributes,
3051 });
3052 }
3053 }
3054
3055 /// <summary>
3056 /// Parses a service configuration element.
3057 /// </summary>
3058 /// <param name="element">Element to parse.</param>
3059 /// <param name="componentId">Identifier of parent component.</param>
3060 /// <param name="parentTableName">Name of parent element.</param>
3061 /// <param name="parentTableServiceName">Optional name of service </param>
3062 private void ParseServiceConfigElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string parentTableName, string parentTableServiceName)
3063 {
3064 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
3065 string firstFailureActionType = null;
3066 var newService = false;
3067 string programCommandLine = null;
3068 string rebootMessage = null;
3069 var resetPeriod = CompilerConstants.IntegerNotSet;
3070 var restartServiceDelay = CompilerConstants.IntegerNotSet;
3071 string secondFailureActionType = null;
3072 string serviceName = null;
3073 string thirdFailureActionType = null;
3074
3075 foreach (var attrib in element.Attributes())
3076 {
3077 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
3078 {
3079 switch (attrib.Name.LocalName)
3080 {
3081 case "FirstFailureActionType":
3082 firstFailureActionType = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3083 break;
3084 case "ProgramCommandLine":
3085 programCommandLine = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3086 break;
3087 case "RebootMessage":
3088 rebootMessage = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3089 break;
3090 case "ResetPeriodInDays":
3091 resetPeriod = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
3092 break;
3093 case "RestartServiceDelayInSeconds":
3094 restartServiceDelay = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
3095 break;
3096 case "SecondFailureActionType":
3097 secondFailureActionType = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3098 break;
3099 case "ServiceName":
3100 serviceName = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3101 break;
3102 case "ThirdFailureActionType":
3103 thirdFailureActionType = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3104 break;
3105 default:
3106 this.ParseHelper.UnexpectedAttribute(element, attrib);
3107 break;
3108 }
3109 }
3110 else
3111 {
3112 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
3113 }
3114 }
3115
3116 // if this element is a child of ServiceInstall then ignore the service name provided.
3117 if ("ServiceInstall" == parentTableName)
3118 {
3119 // TODO: the ServiceName attribute should not be allowed in this case (the overwriting behavior may confuse users)
3120 serviceName = parentTableServiceName;
3121 newService = true;
3122 }
3123 else
3124 {
3125 // not a child of ServiceInstall, so ServiceName must have been provided
3126 if (null == serviceName)
3127 {
3128 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "ServiceName"));
3129 }
3130 }
3131
3132 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
3133
3134 if (!this.Messaging.EncounteredError)
3135 {
3136 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedServiceConfig", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
3137
3138 section.AddSymbol(new ServiceConfigSymbol(sourceLineNumbers)
3139 {
3140 ServiceName = serviceName,
3141 ComponentRef = componentId,
3142 NewService = newService ? 1 : 0,
3143 FirstFailureActionType = firstFailureActionType,
3144 SecondFailureActionType = secondFailureActionType,
3145 ThirdFailureActionType = thirdFailureActionType,
3146 ResetPeriodInDays = resetPeriod,
3147 RestartServiceDelayInSeconds = restartServiceDelay,
3148 ProgramCommandLine = programCommandLine,
3149 RebootMessage = rebootMessage,
3150 });
3151 }
3152 }
3153
3154 /// <summary>
3155 /// Parses a touch file element.
3156 /// </summary>
3157 /// <param name="element">Element to parse.</param>
3158 /// <param name="componentId">Identifier of parent component.</param>
3159 /// <param name="win64">Indicates whether the path is a 64-bit path.</param>
3160 private void ParseTouchFileElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, bool win64)
3161 {
3162 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
3163 Identifier id = null;
3164 string path = null;
3165 var onInstall = YesNoType.NotSet;
3166 var onReinstall = YesNoType.NotSet;
3167 var onUninstall = YesNoType.NotSet;
3168 var nonvital = YesNoType.NotSet;
3169 int attributes = 0;
3170
3171 foreach (var attrib in element.Attributes())
3172 {
3173 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
3174 {
3175 switch (attrib.Name.LocalName)
3176 {
3177 case "Id":
3178 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
3179 break;
3180 case "Path":
3181 path = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3182 break;
3183 case "OnInstall":
3184 onInstall = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
3185 break;
3186 case "OnReinstall":
3187 onReinstall = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
3188 break;
3189 case "OnUninstall":
3190 onUninstall = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
3191 break;
3192 case "Nonvital":
3193 nonvital = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
3194 break;
3195 default:
3196 this.ParseHelper.UnexpectedAttribute(element, attrib);
3197 break;
3198 }
3199 }
3200 else
3201 {
3202 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
3203 }
3204 }
3205
3206 if (null == path)
3207 {
3208 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Path"));
3209 }
3210
3211 // If none of the scheduling actions are set, default to touching on install and reinstall.
3212 if (YesNoType.NotSet == onInstall && YesNoType.NotSet == onReinstall && YesNoType.NotSet == onUninstall)
3213 {
3214 onInstall = YesNoType.Yes;
3215 onReinstall = YesNoType.Yes;
3216 }
3217
3218 attributes |= YesNoType.Yes == onInstall ? 0x1 : 0;
3219 attributes |= YesNoType.Yes == onReinstall ? 0x2 : 0;
3220 attributes |= YesNoType.Yes == onUninstall ? 0x4 : 0;
3221 attributes |= win64 ? 0x10 : 0;
3222 attributes |= YesNoType.Yes == nonvital ? 0 : 0x20;
3223
3224 if (null == id)
3225 {
3226 id = this.ParseHelper.CreateIdentifier("tf", path, attributes.ToString());
3227 }
3228
3229 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
3230
3231 if (!this.Messaging.EncounteredError)
3232 {
3233 section.AddSymbol(new WixTouchFileSymbol(sourceLineNumbers, id)
3234 {
3235 ComponentRef = componentId,
3236 Path = path,
3237 Attributes = attributes,
3238 });
3239
3240 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4TouchFileDuringInstall", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
3241 }
3242 }
3243
3244 /// <summary>
3245 /// Parses an user element.
3246 /// </summary>
3247 /// <param name="element">Element to parse.</param>
3248 /// <param name="componentId">Optional identifier of parent component.</param>
3249 private void ParseUserElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
3250 {
3251 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
3252 Identifier id = null;
3253 int attributes = 0;
3254 string domain = null;
3255 string name = null;
3256 string password = null;
3257
3258 foreach (var attrib in element.Attributes())
3259 {
3260 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
3261 {
3262 switch (attrib.Name.LocalName)
3263 {
3264 case "Id":
3265 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
3266 break;
3267 case "CanNotChangePassword":
3268 if (null == componentId)
3269 {
3270 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3271 }
3272
3273 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3274 {
3275 attributes |= UserPasswdCantChange;
3276 }
3277 break;
3278 case "CreateUser":
3279 if (null == componentId)
3280 {
3281 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3282 }
3283
3284 if (YesNoType.No == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3285 {
3286 attributes |= UserDontCreateUser;
3287 }
3288 break;
3289 case "Disabled":
3290 if (null == componentId)
3291 {
3292 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3293 }
3294
3295 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3296 {
3297 attributes |= UserDisableAccount;
3298 }
3299 break;
3300 case "Domain":
3301 domain = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3302 break;
3303 case "FailIfExists":
3304 if (null == componentId)
3305 {
3306 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3307 }
3308
3309 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3310 {
3311 attributes |= UserFailIfExists;
3312 }
3313 break;
3314 case "LogonAsService":
3315 if (null == componentId)
3316 {
3317 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3318 }
3319 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3320 {
3321 attributes |= UserLogonAsService;
3322 }
3323 break;
3324 case "LogonAsBatchJob":
3325 if (null == componentId)
3326 {
3327 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3328 }
3329 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3330 {
3331 attributes |= UserLogonAsBatchJob;
3332 }
3333 break;
3334 case "Name":
3335 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3336 break;
3337 case "Password":
3338 password = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3339 break;
3340 case "PasswordExpired":
3341 if (null == componentId)
3342 {
3343 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3344 }
3345
3346 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3347 {
3348 attributes |= UserPasswdChangeReqdOnLogin;
3349 }
3350 break;
3351 case "PasswordNeverExpires":
3352 if (null == componentId)
3353 {
3354 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3355 }
3356
3357 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3358 {
3359 attributes |= UserDontExpirePasswrd;
3360 }
3361 break;
3362 case "RemoveOnUninstall":
3363 if (null == componentId)
3364 {
3365 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3366 }
3367
3368 if (YesNoType.No == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3369 {
3370 attributes |= UserDontRemoveOnUninstall;
3371 }
3372 break;
3373 case "UpdateIfExists":
3374 if (null == componentId)
3375 {
3376 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3377 }
3378
3379 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3380 {
3381 attributes |= UserUpdateIfExists;
3382 }
3383 break;
3384 case "Vital":
3385 if (null == componentId)
3386 {
3387 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3388 }
3389
3390 if (YesNoType.No == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3391 {
3392 attributes |= UserNonVital;
3393 }
3394 break;
3395 default:
3396 this.ParseHelper.UnexpectedAttribute(element, attrib);
3397 break;
3398 }
3399 }
3400 else
3401 {
3402 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
3403 }
3404 }
3405
3406 if (null == id)
3407 {
3408 id = this.ParseHelper.CreateIdentifier("usr", componentId, name);
3409 }
3410
3411 if (null == name)
3412 {
3413 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
3414 }
3415
3416 foreach (var child in element.Elements())
3417 {
3418 if (this.Namespace == child.Name.Namespace)
3419 {
3420 switch (child.Name.LocalName)
3421 {
3422 case "GroupRef":
3423 if (null == componentId)
3424 {
3425 var childSourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(child);
3426 this.Messaging.Write(UtilErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName));
3427 }
3428
3429 this.ParseGroupRefElement(intermediate, section, child, id.Id);
3430 break;
3431 default:
3432 this.ParseHelper.UnexpectedElement(element, child);
3433 break;
3434 }
3435 }
3436 else
3437 {
3438 this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
3439 }
3440 }
3441
3442 if (null != componentId)
3443 {
3444 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureUsers", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
3445 }
3446
3447 if (!this.Messaging.EncounteredError)
3448 {
3449 section.AddSymbol(new UserSymbol(sourceLineNumbers, id)
3450 {
3451 ComponentRef = componentId,
3452 Name = name,
3453 Domain = domain,
3454 Password = password,
3455 Attributes = attributes,
3456 });
3457 }
3458 }
3459
3460 /// <summary>
3461 /// Parses a XmlFile element.
3462 /// </summary>
3463 /// <param name="element">Element to parse.</param>
3464 /// <param name="componentId">Identifier of parent component.</param>
3465 private void ParseXmlFileElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
3466 {
3467 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
3468 Identifier id = null;
3469 string file = null;
3470 string elementPath = null;
3471 string name = null;
3472 string value = null;
3473 int sequence = -1;
3474 int flags = 0;
3475
3476 foreach (var attrib in element.Attributes())
3477 {
3478 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
3479 {
3480 switch (attrib.Name.LocalName)
3481 {
3482 case "Action":
3483 var actionValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3484 switch (actionValue)
3485 {
3486 case "createElement":
3487 flags |= 0x00000001; // XMLFILE_CREATE_ELEMENT
3488 break;
3489 case "deleteValue":
3490 flags |= 0x00000002; // XMLFILE_DELETE_VALUE
3491 break;
3492 case "bulkSetValue":
3493 flags |= 0x00000004; // XMLFILE_BULKWRITE_VALUE
3494 break;
3495 case "setValue":
3496 // no flag for set value since it's the default
3497 break;
3498 default:
3499 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Action", actionValue, "createElement", "deleteValue", "setValue", "bulkSetValue"));
3500 break;
3501 }
3502 break;
3503 case "SelectionLanguage":
3504 string selectionLanguage = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3505 switch (selectionLanguage)
3506 {
3507 case "XPath":
3508 flags |= 0x00000100; // XMLFILE_USE_XPATH
3509 break;
3510 case "XSLPattern":
3511 // no flag for since it's the default
3512 break;
3513 default:
3514 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "SelectionLanguage", selectionLanguage, "XPath", "XSLPattern"));
3515 break;
3516 }
3517 break;
3518 case "Id":
3519 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
3520 break;
3521 case "File":
3522 file = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3523 break;
3524 case "ElementPath":
3525 elementPath = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3526 break;
3527 case "Name":
3528 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3529 break;
3530 case "Permanent":
3531 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3532 {
3533 flags |= 0x00010000; // XMLFILE_DONT_UNINSTALL
3534 }
3535 break;
3536 case "Sequence":
3537 sequence = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, Int16.MaxValue);
3538 break;
3539 case "Value":
3540 value = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3541 break;
3542 case "PreserveModifiedDate":
3543 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3544 {
3545 flags |= 0x00001000; // XMLFILE_PRESERVE_MODIFIED
3546 }
3547 break;
3548 default:
3549 this.ParseHelper.UnexpectedAttribute(element, attrib);
3550 break;
3551 }
3552 }
3553 else
3554 {
3555 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
3556 }
3557 }
3558
3559 if (null == id)
3560 {
3561 id = this.ParseHelper.CreateIdentifier("uxf", componentId, file, elementPath, name);
3562 }
3563
3564 if (null == file)
3565 {
3566 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "File"));
3567 }
3568
3569 if (null == elementPath)
3570 {
3571 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "ElementPath"));
3572 }
3573
3574 if ((0x00000001 /*XMLFILE_CREATE_ELEMENT*/ & flags) != 0 && null == name)
3575 {
3576 this.Messaging.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, element.Name.LocalName, "Action", "Name"));
3577 }
3578
3579 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
3580
3581 if (!this.Messaging.EncounteredError)
3582 {
3583 var symbol = section.AddSymbol(new XmlFileSymbol(sourceLineNumbers, id)
3584 {
3585 File = file,
3586 ElementPath = elementPath,
3587 Name = name,
3588 Value = value,
3589 Flags = flags,
3590 ComponentRef = componentId,
3591 });
3592 if (-1 != sequence)
3593 {
3594 symbol.Sequence = sequence;
3595 }
3596 }
3597
3598 this.AddReferenceToSchedXmlFile(sourceLineNumbers, section);
3599 }
3600
3601 /// <summary>
3602 /// Parses a XmlConfig element.
3603 /// </summary>
3604 /// <param name="element">Element to parse.</param>
3605 /// <param name="componentId">Identifier of parent component.</param>
3606 /// <param name="nested">Whether or not the element is nested.</param>
3607 private void ParseXmlConfigElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, bool nested)
3608 {
3609 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
3610 Identifier id = null;
3611 string elementId = null;
3612 string elementPath = null;
3613 int flags = 0;
3614 string file = null;
3615 string name = null;
3616 var sequence = CompilerConstants.IntegerNotSet;
3617 string value = null;
3618 string verifyPath = null;
3619
3620 foreach (var attrib in element.Attributes())
3621 {
3622 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
3623 {
3624 switch (attrib.Name.LocalName)
3625 {
3626 case "Id":
3627 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
3628 break;
3629 case "Action":
3630 if (nested)
3631 {
3632 this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, element.Parent.Name.LocalName));
3633 }
3634 else
3635 {
3636 string actionValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3637 switch (actionValue)
3638 {
3639 case "create":
3640 flags |= 0x10; // XMLCONFIG_CREATE
3641 break;
3642 case "delete":
3643 flags |= 0x20; // XMLCONFIG_DELETE
3644 break;
3645 default:
3646 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, actionValue, "create", "delete"));
3647 break;
3648 }
3649 }
3650 break;
3651 case "ElementId":
3652 elementId = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3653 break;
3654 case "ElementPath":
3655 elementPath = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3656 break;
3657 case "File":
3658 file = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3659 break;
3660 case "Name":
3661 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3662 break;
3663 case "Node":
3664 if (nested)
3665 {
3666 this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, element.Parent.Name.LocalName));
3667 }
3668 else
3669 {
3670 var nodeValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3671 switch (nodeValue)
3672 {
3673 case "element":
3674 flags |= 0x1; // XMLCONFIG_ELEMENT
3675 break;
3676 case "value":
3677 flags |= 0x2; // XMLCONFIG_VALUE
3678 break;
3679 case "document":
3680 flags |= 0x4; // XMLCONFIG_DOCUMENT
3681 break;
3682 default:
3683 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, nodeValue, "element", "value", "document"));
3684 break;
3685 }
3686 }
3687 break;
3688 case "On":
3689 if (nested)
3690 {
3691 this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, element.Parent.Name.LocalName));
3692 }
3693 else
3694 {
3695 var onValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3696 switch (onValue)
3697 {
3698 case "install":
3699 flags |= 0x100; // XMLCONFIG_INSTALL
3700 break;
3701 case "uninstall":
3702 flags |= 0x200; // XMLCONFIG_UNINSTALL
3703 break;
3704 default:
3705 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, onValue, "install", "uninstall"));
3706 break;
3707 }
3708 }
3709 break;
3710 case "PreserveModifiedDate":
3711 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3712 {
3713 flags |= 0x00001000; // XMLCONFIG_PRESERVE_MODIFIED
3714 }
3715 break;
3716 case "Sequence":
3717 sequence = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, Int16.MaxValue);
3718 break;
3719 case "Value":
3720 value = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3721 break;
3722 case "VerifyPath":
3723 verifyPath = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3724 break;
3725 default:
3726 this.ParseHelper.UnexpectedAttribute(element, attrib);
3727 break;
3728 }
3729 }
3730 else
3731 {
3732 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
3733 }
3734 }
3735
3736 if (null == id)
3737 {
3738 id = this.ParseHelper.CreateIdentifier("uxc", componentId, file, elementId, elementPath);
3739 }
3740
3741 if (null == file)
3742 {
3743 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "File"));
3744 }
3745
3746 if (null == elementId && null == elementPath)
3747 {
3748 this.Messaging.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, element.Name.LocalName, "ElementId", "ElementPath"));
3749 }
3750 else if (null != elementId)
3751 {
3752 if (null != elementPath)
3753 {
3754 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "ElementId", "ElementPath"));
3755 }
3756
3757 if (0 != flags)
3758 {
3759 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, "ElementId", "Action", "Node", "On"));
3760 }
3761
3762 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, UtilSymbolDefinitions.XmlConfig, elementId);
3763 }
3764
3765 // find unexpected child elements
3766 foreach (var child in element.Elements())
3767 {
3768 if (this.Namespace == child.Name.Namespace)
3769 {
3770 switch (child.Name.LocalName)
3771 {
3772 case "XmlConfig":
3773 if (nested)
3774 {
3775 this.Messaging.Write(ErrorMessages.UnexpectedElement(sourceLineNumbers, element.Name.LocalName, child.Name.LocalName));
3776 }
3777 else
3778 {
3779 this.ParseXmlConfigElement(intermediate, section, child, componentId, true);
3780 }
3781 break;
3782 default:
3783 this.ParseHelper.UnexpectedElement(element, child);
3784 break;
3785 }
3786 }
3787 else
3788 {
3789 this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
3790 }
3791 }
3792
3793 if (!this.Messaging.EncounteredError)
3794 {
3795 var symbol = section.AddSymbol(new XmlConfigSymbol(sourceLineNumbers, id)
3796 {
3797 File = file,
3798 ElementId = elementId,
3799 ElementPath = elementPath,
3800 VerifyPath = verifyPath,
3801 Name = name,
3802 Value = value,
3803 Flags = flags,
3804 ComponentRef = componentId,
3805 });
3806
3807 if (CompilerConstants.IntegerNotSet != sequence)
3808 {
3809 symbol.Sequence = sequence;
3810 }
3811 }
3812
3813 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedXmlConfig", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
3814 }
3815
3816 /// <summary>
3817 /// Match evaluator to escape properties in a string.
3818 /// </summary>
3819 private string EscapeProperties(Match match)
3820 {
3821 string escape = null;
3822 switch (match.Value)
3823 {
3824 case "[":
3825 escape = @"[\[]";
3826 break;
3827 case "]":
3828 escape = @"[\]]";
3829 break;
3830 }
3831
3832 return escape;
3833 }
3834
3835 private int CreateIntegerFromBitArray(BitArray bits)
3836 {
3837 if (32 != bits.Length)
3838 {
3839 throw new ArgumentException(String.Format("Can only convert a bit array with 32-bits to integer. Actual number of bits in array: {0}", bits.Length), "bits");
3840 }
3841
3842 var intArray = new int[1];
3843 bits.CopyTo(intArray, 0);
3844
3845 return intArray[0];
3846 }
3847
3848 private bool TrySetBitFromName(string[] attributeNames, string attributeName, YesNoType attributeValue, BitArray bits, int offset)
3849 {
3850 for (var i = 0; i < attributeNames.Length; i++)
3851 {
3852 if (attributeName.Equals(attributeNames[i], StringComparison.Ordinal))
3853 {
3854 bits.Set(i + offset, YesNoType.Yes == attributeValue);
3855 return true;
3856 }
3857 }
3858
3859 return false;
3860 }
3861
3862 private void AddReferenceToSchedXmlFile(SourceLineNumber sourceLineNumbers, IntermediateSection section)
3863 {
3864 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedXmlFile", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
3865 }
3866
3867 /// <summary>
3868 /// Private class that stores the data from a parsed PerformanceCounter element.
3869 /// </summary>
3870 private class ParsedPerformanceCounter
3871 {
3872 internal ParsedPerformanceCounter(string name, string help, System.Diagnostics.PerformanceCounterType type, int language)
3873 {
3874 this.Name = name;
3875 this.Help = help;
3876 this.Type = (int)type;
3877 this.Language = language.ToString("D3", CultureInfo.InvariantCulture);
3878 }
3879
3880 internal string Name { get; }
3881
3882 internal string Help { get; }
3883
3884 internal int Type { get; }
3885
3886 internal string Language { get; }
3887 }
3888 }
3889}
diff --git a/src/ext/Util/wixext/UtilConstants.cs b/src/ext/Util/wixext/UtilConstants.cs
new file mode 100644
index 00000000..28ff368f
--- /dev/null
+++ b/src/ext/Util/wixext/UtilConstants.cs
@@ -0,0 +1,17 @@
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
3namespace WixToolset.Util
4{
5 /// <summary>
6 /// Constants used by Utility Extension.
7 /// </summary>
8 internal static class UtilConstants
9 {
10 internal static readonly string[] FilePermissions = { "Read", "Write", "Append", "ReadExtendedAttributes", "WriteExtendedAttributes", "Execute", null, "ReadAttributes", "WriteAttributes" };
11 internal static readonly string[] FolderPermissions = { "Read", "CreateFile", "CreateChild", "ReadExtendedAttributes", "WriteExtendedAttributes", "Traverse", "DeleteChild", "ReadAttributes", "WriteAttributes" };
12 internal static readonly string[] GenericPermissions = { "GenericAll", "GenericExecute", "GenericWrite", "GenericRead" };
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}
diff --git a/src/ext/Util/wixext/UtilDecompiler.cs b/src/ext/Util/wixext/UtilDecompiler.cs
new file mode 100644
index 00000000..9ef3390f
--- /dev/null
+++ b/src/ext/Util/wixext/UtilDecompiler.cs
@@ -0,0 +1,1543 @@
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
3namespace WixToolset.Extensions
4{
5#if TODO_CONSIDER_DECOMPILER
6 using System;
7 using System.IO;
8 using System.Text;
9 using System.Collections;
10 using System.Diagnostics;
11 using System.Globalization;
12
13 using Util = WixToolset.Extensions.Serialize.Util;
14 using WixToolset.Data;
15 using WixToolset.Extensibility;
16 using Wix = WixToolset.Data.Serialize;
17
18 /// <summary>
19 /// The decompiler for the WiX Toolset Utility Extension.
20 /// </summary>
21 public sealed class UtilDecompiler : DecompilerExtension
22 {
23 /// <summary>
24 /// Creates a decompiler for Utility Extension.
25 /// </summary>
26 public UtilDecompiler()
27 {
28 this.TableDefinitions = UtilExtensionData.GetExtensionTableDefinitions();
29 }
30
31 /// <summary>
32 /// Get the extensions library to be removed.
33 /// </summary>
34 /// <param name="tableDefinitions">Table definitions for library.</param>
35 /// <returns>Library to remove from decompiled output.</returns>
36 public override Library GetLibraryToRemove(TableDefinitionCollection tableDefinitions)
37 {
38 return UtilExtensionData.GetExtensionLibrary(tableDefinitions);
39 }
40
41 /// <summary>
42 /// Called at the beginning of the decompilation of a database.
43 /// </summary>
44 /// <param name="tables">The collection of all tables.</param>
45 public override void Initialize(TableIndexedCollection tables)
46 {
47 this.CleanupSecureCustomProperties(tables);
48 this.CleanupInternetShortcutRemoveFileTables(tables);
49 }
50
51 /// <summary>
52 /// Decompile the SecureCustomProperties field to PropertyRefs for known extension properties.
53 /// </summary>
54 /// <remarks>
55 /// If we've referenced any of the suite or directory properties, add
56 /// a PropertyRef to refer to the Property (and associated custom action)
57 /// from the extension's library. Then remove the property from
58 /// SecureCustomExtensions property so later decompilation won't create
59 /// new Property elements.
60 /// </remarks>
61 /// <param name="tables">The collection of all tables.</param>
62 private void CleanupSecureCustomProperties(TableIndexedCollection tables)
63 {
64 Table propertyTable = tables["Property"];
65
66 if (null != propertyTable)
67 {
68 foreach (Row row in propertyTable.Rows)
69 {
70 if ("SecureCustomProperties" == row[0].ToString())
71 {
72 StringBuilder remainingProperties = new StringBuilder();
73 string[] secureCustomProperties = row[1].ToString().Split(';');
74 foreach (string property in secureCustomProperties)
75 {
76 if (property.StartsWith("WIX_SUITE_", StringComparison.Ordinal) || property.StartsWith("WIX_DIR_", StringComparison.Ordinal)
77 || property.StartsWith("WIX_ACCOUNT_", StringComparison.Ordinal))
78 {
79 Wix.PropertyRef propertyRef = new Wix.PropertyRef();
80 propertyRef.Id = property;
81 this.Core.RootElement.AddChild(propertyRef);
82 }
83 else
84 {
85 if (0 < remainingProperties.Length)
86 {
87 remainingProperties.Append(";");
88 }
89 remainingProperties.Append(property);
90 }
91 }
92
93 row[1] = remainingProperties.ToString();
94 break;
95 }
96 }
97 }
98 }
99
100 /// <summary>
101 /// Remove RemoveFile rows that the InternetShortcut compiler extension adds for us.
102 /// </summary>
103 /// <param name="tables">The collection of all tables.</param>
104 private void CleanupInternetShortcutRemoveFileTables(TableIndexedCollection tables)
105 {
106 // index the WixInternetShortcut table
107 Table wixInternetShortcutTable = tables["WixInternetShortcut"];
108 Hashtable wixInternetShortcuts = new Hashtable();
109 if (null != wixInternetShortcutTable)
110 {
111 foreach (Row row in wixInternetShortcutTable.Rows)
112 {
113 wixInternetShortcuts.Add(row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), row);
114 }
115 }
116
117 // remove the RemoveFile rows with primary keys that match the WixInternetShortcut table's
118 Table removeFileTable = tables["RemoveFile"];
119 if (null != removeFileTable)
120 {
121 for (int i = removeFileTable.Rows.Count - 1; 0 <= i; i--)
122 {
123 if (null != wixInternetShortcuts[removeFileTable.Rows[i][0]])
124 {
125 removeFileTable.Rows.RemoveAt(i);
126 }
127 }
128 }
129 }
130
131 /// <summary>
132 /// Decompiles an extension table.
133 /// </summary>
134 /// <param name="table">The table to decompile.</param>
135 public override void DecompileTable(Table table)
136 {
137 switch (table.Name)
138 {
139 case "WixCloseApplication":
140 this.DecompileWixCloseApplicationTable(table);
141 break;
142 case "WixRemoveFolderEx":
143 this.DecompileWixRemoveFolderExTable(table);
144 break;
145 case "WixRestartResource":
146 this.DecompileWixRestartResourceTable(table);
147 break;
148 case "FileShare":
149 this.DecompileFileShareTable(table);
150 break;
151 case "FileSharePermissions":
152 this.DecompileFileSharePermissionsTable(table);
153 break;
154 case "WixInternetShortcut":
155 this.DecompileWixInternetShortcutTable(table);
156 break;
157 case "Group":
158 this.DecompileGroupTable(table);
159 break;
160 case "Perfmon":
161 this.DecompilePerfmonTable(table);
162 break;
163 case "PerfmonManifest":
164 this.DecompilePerfmonManifestTable(table);
165 break;
166 case "EventManifest":
167 this.DecompileEventManifestTable(table);
168 break;
169 case "SecureObjects":
170 this.DecompileSecureObjectsTable(table);
171 break;
172 case "ServiceConfig":
173 this.DecompileServiceConfigTable(table);
174 break;
175 case "User":
176 this.DecompileUserTable(table);
177 break;
178 case "UserGroup":
179 this.DecompileUserGroupTable(table);
180 break;
181 case "XmlConfig":
182 this.DecompileXmlConfigTable(table);
183 break;
184 case "XmlFile":
185 // XmlFile decompilation has been moved to FinalizeXmlFileTable function
186 break;
187 default:
188 base.DecompileTable(table);
189 break;
190 }
191 }
192
193 /// <summary>
194 /// Finalize decompilation.
195 /// </summary>
196 /// <param name="tables">The collection of all tables.</param>
197 public override void Finish(TableIndexedCollection tables)
198 {
199 this.FinalizePerfmonTable(tables);
200 this.FinalizePerfmonManifestTable(tables);
201 this.FinalizeSecureObjectsTable(tables);
202 this.FinalizeServiceConfigTable(tables);
203 this.FinalizeXmlConfigTable(tables);
204 this.FinalizeXmlFileTable(tables);
205 this.FinalizeEventManifestTable(tables);
206 }
207
208 /// <summary>
209 /// Decompile the WixCloseApplication table.
210 /// </summary>
211 /// <param name="table">The table to decompile.</param>
212 private void DecompileWixCloseApplicationTable(Table table)
213 {
214 foreach (Row row in table.Rows)
215 {
216 Util.CloseApplication closeApplication = new Util.CloseApplication();
217
218 closeApplication.Id = (string)row[0];
219
220 closeApplication.Target = (string)row[1];
221
222 if (null != row[2])
223 {
224 closeApplication.Description = (string)row[2];
225 }
226
227 if (null != row[3])
228 {
229 closeApplication.Content = (string)row[3];
230 }
231
232 // set defaults
233 closeApplication.CloseMessage = Util.YesNoType.no;
234 closeApplication.RebootPrompt = Util.YesNoType.yes;
235 closeApplication.ElevatedCloseMessage = Util.YesNoType.no;
236
237 if (null != row[4])
238 {
239 int attribute = (int)row[4];
240
241 closeApplication.CloseMessage = (0x1 == (attribute & 0x1)) ? Util.YesNoType.yes : Util.YesNoType.no;
242 closeApplication.RebootPrompt = (0x2 == (attribute & 0x2)) ? Util.YesNoType.yes : Util.YesNoType.no;
243 closeApplication.ElevatedCloseMessage = (0x4 == (attribute & 0x4)) ? Util.YesNoType.yes : Util.YesNoType.no;
244 }
245
246 if (null != row[5])
247 {
248 closeApplication.Sequence = (int)row[5];
249 }
250
251 if (null != row[6])
252 {
253 closeApplication.Property = (string)row[6];
254 }
255
256 this.Core.RootElement.AddChild(closeApplication);
257 }
258 }
259
260 /// <summary>
261 /// Decompile the WixRemoveFolderEx table.
262 /// </summary>
263 /// <param name="table">The table to decompile.</param>
264 private void DecompileWixRemoveFolderExTable(Table table)
265 {
266 foreach (Row row in table.Rows)
267 {
268 // Set the Id even if auto-generated previously.
269 Util.RemoveFolderEx removeFolder = new Util.RemoveFolderEx();
270 removeFolder.Id = (string)row[0];
271 removeFolder.Property = (string)row[2];
272
273 int installMode = (int)row[3];
274 switch ((UtilCompiler.WixRemoveFolderExOn)installMode)
275 {
276 case UtilCompiler.WixRemoveFolderExOn.Install:
277 removeFolder.On = Util.RemoveFolderEx.OnType.install;
278 break;
279
280 case UtilCompiler.WixRemoveFolderExOn.Uninstall:
281 removeFolder.On = Util.RemoveFolderEx.OnType.uninstall;
282 break;
283
284 case UtilCompiler.WixRemoveFolderExOn.Both:
285 removeFolder.On = Util.RemoveFolderEx.OnType.both;
286 break;
287
288 default:
289 this.Core.OnMessage(WixWarnings.UnrepresentableColumnValue(row.SourceLineNumbers, table.Name, "InstallMode", installMode));
290 break;
291 }
292
293 // Add to the appropriate Component or section element.
294 string componentId = (string)row[1];
295 Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", componentId);
296 if (null != component)
297 {
298 component.AddChild(removeFolder);
299 }
300 else
301 {
302 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", componentId, "Component"));
303 }
304 }
305 }
306
307 /// <summary>
308 /// Decompile the WixRestartResource table.
309 /// </summary>
310 /// <param name="table">The table to decompile.</param>
311 private void DecompileWixRestartResourceTable(Table table)
312 {
313 foreach (Row row in table.Rows)
314 {
315 // Set the Id even if auto-generated previously.
316 Util.RestartResource restartResource = new Util.RestartResource();
317 restartResource.Id = (string)row[0];
318
319 // Determine the resource type and set accordingly.
320 string resource = (string)row[2];
321 int attributes = (int)row[3];
322 UtilCompiler.WixRestartResourceAttributes type = (UtilCompiler.WixRestartResourceAttributes)(attributes & (int)UtilCompiler.WixRestartResourceAttributes.TypeMask);
323
324 switch (type)
325 {
326 case UtilCompiler.WixRestartResourceAttributes.Filename:
327 restartResource.Path = resource;
328 break;
329
330 case UtilCompiler.WixRestartResourceAttributes.ProcessName:
331 restartResource.ProcessName = resource;
332 break;
333
334 case UtilCompiler.WixRestartResourceAttributes.ServiceName:
335 restartResource.ServiceName = resource;
336 break;
337
338 default:
339 this.Core.OnMessage(WixWarnings.UnrepresentableColumnValue(row.SourceLineNumbers, table.Name, "Attributes", attributes));
340 break;
341 }
342
343 // Add to the appropriate Component or section element.
344 string componentId = (string)row[1];
345 if (!String.IsNullOrEmpty(componentId))
346 {
347 Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", componentId);
348 if (null != component)
349 {
350 component.AddChild(restartResource);
351 }
352 else
353 {
354 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", componentId, "Component"));
355 }
356 }
357 else
358 {
359 this.Core.RootElement.AddChild(restartResource);
360 }
361 }
362 }
363
364 /// <summary>
365 /// Decompile the FileShare table.
366 /// </summary>
367 /// <param name="table">The table to decompile.</param>
368 private void DecompileFileShareTable(Table table)
369 {
370 foreach (Row row in table.Rows)
371 {
372 Util.FileShare fileShare = new Util.FileShare();
373
374 fileShare.Id = (string)row[0];
375
376 fileShare.Name = (string)row[1];
377
378 if (null != row[3])
379 {
380 fileShare.Description = (string)row[3];
381 }
382
383 // the Directory_ column is set by the parent Component
384
385 // the User_ and Permissions columns are deprecated
386
387 Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[2]);
388 if (null != component)
389 {
390 component.AddChild(fileShare);
391 }
392 else
393 {
394 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[2], "Component"));
395 }
396 this.Core.IndexElement(row, fileShare);
397 }
398 }
399
400 /// <summary>
401 /// Decompile the FileSharePermissions table.
402 /// </summary>
403 /// <param name="table">The table to decompile.</param>
404 private void DecompileFileSharePermissionsTable(Table table)
405 {
406 foreach (Row row in table.Rows)
407 {
408 Util.FileSharePermission fileSharePermission = new Util.FileSharePermission();
409
410 fileSharePermission.User = (string)row[1];
411
412 string[] specialPermissions = UtilConstants.FolderPermissions;
413 int permissions = (int)row[2];
414 for (int i = 0; i < 32; i++)
415 {
416 if (0 != ((permissions >> i) & 1))
417 {
418 string name = null;
419
420 if (16 > i && specialPermissions.Length > i)
421 {
422 name = specialPermissions[i];
423 }
424 else if (28 > i && UtilConstants.StandardPermissions.Length > (i - 16))
425 {
426 name = UtilConstants.StandardPermissions[i - 16];
427 }
428 else if (0 <= (i - 28) && UtilConstants.GenericPermissions.Length > (i - 28))
429 {
430 name = UtilConstants.GenericPermissions[i - 28];
431 }
432
433 if (null == name)
434 {
435 this.Core.OnMessage(WixWarnings.UnknownPermission(row.SourceLineNumbers, row.Table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), i));
436 }
437 else
438 {
439 switch (name)
440 {
441 case "ChangePermission":
442 fileSharePermission.ChangePermission = Util.YesNoType.yes;
443 break;
444 case "CreateChild":
445 fileSharePermission.CreateChild = Util.YesNoType.yes;
446 break;
447 case "CreateFile":
448 fileSharePermission.CreateFile = Util.YesNoType.yes;
449 break;
450 case "Delete":
451 fileSharePermission.Delete = Util.YesNoType.yes;
452 break;
453 case "DeleteChild":
454 fileSharePermission.DeleteChild = Util.YesNoType.yes;
455 break;
456 case "GenericAll":
457 fileSharePermission.GenericAll = Util.YesNoType.yes;
458 break;
459 case "GenericExecute":
460 fileSharePermission.GenericExecute = Util.YesNoType.yes;
461 break;
462 case "GenericRead":
463 fileSharePermission.GenericRead = Util.YesNoType.yes;
464 break;
465 case "GenericWrite":
466 fileSharePermission.GenericWrite = Util.YesNoType.yes;
467 break;
468 case "Read":
469 fileSharePermission.Read = Util.YesNoType.yes;
470 break;
471 case "ReadAttributes":
472 fileSharePermission.ReadAttributes = Util.YesNoType.yes;
473 break;
474 case "ReadExtendedAttributes":
475 fileSharePermission.ReadExtendedAttributes = Util.YesNoType.yes;
476 break;
477 case "ReadPermission":
478 fileSharePermission.ReadPermission = Util.YesNoType.yes;
479 break;
480 case "Synchronize":
481 fileSharePermission.Synchronize = Util.YesNoType.yes;
482 break;
483 case "TakeOwnership":
484 fileSharePermission.TakeOwnership = Util.YesNoType.yes;
485 break;
486 case "Traverse":
487 fileSharePermission.Traverse = Util.YesNoType.yes;
488 break;
489 case "WriteAttributes":
490 fileSharePermission.WriteAttributes = Util.YesNoType.yes;
491 break;
492 case "WriteExtendedAttributes":
493 fileSharePermission.WriteExtendedAttributes = Util.YesNoType.yes;
494 break;
495 default:
496 Debug.Fail(String.Format("Unknown permission '{0}'.", name));
497 break;
498 }
499 }
500 }
501 }
502
503 Util.FileShare fileShare = (Util.FileShare)this.Core.GetIndexedElement("FileShare", (string)row[0]);
504 if (null != fileShare)
505 {
506 fileShare.AddChild(fileSharePermission);
507 }
508 else
509 {
510 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "FileShare_", (string)row[0], "FileShare"));
511 }
512 }
513 }
514
515 /// <summary>
516 /// Decompile the Group table.
517 /// </summary>
518 /// <param name="table">The table to decompile.</param>
519 private void DecompileGroupTable(Table table)
520 {
521 foreach (Row row in table.Rows)
522 {
523 Util.Group group = new Util.Group();
524
525 group.Id = (string)row[0];
526
527 if (null != row[1])
528 {
529 this.Core.OnMessage(WixWarnings.UnrepresentableColumnValue(row.SourceLineNumbers, table.Name, "Component_", (string)row[1]));
530 }
531
532 group.Name = (string)row[2];
533
534 if (null != row[3])
535 {
536 group.Domain = (string)row[3];
537 }
538
539 this.Core.RootElement.AddChild(group);
540 }
541 }
542
543 /// <summary>
544 /// Decompile the WixInternetShortcut table.
545 /// </summary>
546 /// <param name="table">The table to decompile.</param>
547 private void DecompileWixInternetShortcutTable(Table table)
548 {
549 foreach (Row row in table.Rows)
550 {
551 Util.InternetShortcut internetShortcut = new Util.InternetShortcut();
552 internetShortcut.Id = (string)row[0];
553 internetShortcut.Directory = (string)row[2];
554 // remove .lnk/.url extension because compiler extension adds it back for us
555 internetShortcut.Name = Path.ChangeExtension((string)row[3], null);
556 internetShortcut.Target = (string)row[4];
557 internetShortcut.IconFile = (string)row[6];
558 internetShortcut.IconIndex = (int)row[7];
559
560 UtilCompiler.InternetShortcutType shortcutType = (UtilCompiler.InternetShortcutType)row[5];
561 switch (shortcutType)
562 {
563 case UtilCompiler.InternetShortcutType.Link:
564 internetShortcut.Type = Util.InternetShortcut.TypeType.link;
565 break;
566 case UtilCompiler.InternetShortcutType.Url:
567 internetShortcut.Type = Util.InternetShortcut.TypeType.url;
568 break;
569 }
570
571 Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[1]);
572 if (null != component)
573 {
574 component.AddChild(internetShortcut);
575 }
576 else
577 {
578 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[1], "Component"));
579 }
580
581 this.Core.IndexElement(row, internetShortcut);
582 }
583 }
584
585 /// <summary>
586 /// Decompile the Perfmon table.
587 /// </summary>
588 /// <param name="table">The table to decompile.</param>
589 private void DecompilePerfmonTable(Table table)
590 {
591 foreach (Row row in table.Rows)
592 {
593 Util.PerfCounter perfCounter = new Util.PerfCounter();
594
595 perfCounter.Name = (string)row[2];
596
597 this.Core.IndexElement(row, perfCounter);
598 }
599 }
600
601 /// <summary>
602 /// Decompile the PerfmonManifest table.
603 /// </summary>
604 /// <param name="table">The table to decompile.</param>
605 private void DecompilePerfmonManifestTable(Table table)
606 {
607 foreach (Row row in table.Rows)
608 {
609 Util.PerfCounterManifest perfCounterManifest = new Util.PerfCounterManifest();
610
611 perfCounterManifest.ResourceFileDirectory = (string)row[2];
612
613 this.Core.IndexElement(row, perfCounterManifest);
614 }
615 }
616
617 /// <summary>
618 /// Decompile the EventManifest table.
619 /// </summary>
620 /// <param name="table">The table to decompile.</param>
621 private void DecompileEventManifestTable(Table table)
622 {
623 foreach (Row row in table.Rows)
624 {
625 Util.EventManifest eventManifest = new Util.EventManifest();
626 this.Core.IndexElement(row, eventManifest);
627 }
628 }
629
630 /// <summary>
631 /// Decompile the SecureObjects table.
632 /// </summary>
633 /// <param name="table">The table to decompile.</param>
634 private void DecompileSecureObjectsTable(Table table)
635 {
636 foreach (Row row in table.Rows)
637 {
638 Util.PermissionEx permissionEx = new Util.PermissionEx();
639
640 string[] specialPermissions;
641 switch ((string)row[1])
642 {
643 case "CreateFolder":
644 specialPermissions = UtilConstants.FolderPermissions;
645 break;
646 case "File":
647 specialPermissions = UtilConstants.FilePermissions;
648 break;
649 case "Registry":
650 specialPermissions = UtilConstants.RegistryPermissions;
651 break;
652 case "ServiceInstall":
653 specialPermissions = UtilConstants.ServicePermissions;
654 break;
655 default:
656 this.Core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, row.Table.Name, row.Fields[1].Column.Name, row[1]));
657 return;
658 }
659
660 int permissionBits = (int)row[4];
661 for (int i = 0; i < 32; i++)
662 {
663 if (0 != ((permissionBits >> i) & 1))
664 {
665 string name = null;
666
667 if (16 > i && specialPermissions.Length > i)
668 {
669 name = specialPermissions[i];
670 }
671 else if (28 > i && UtilConstants.StandardPermissions.Length > (i - 16))
672 {
673 name = UtilConstants.StandardPermissions[i - 16];
674 }
675 else if (0 <= (i - 28) && UtilConstants.GenericPermissions.Length > (i - 28))
676 {
677 name = UtilConstants.GenericPermissions[i - 28];
678 }
679
680 if (null == name)
681 {
682 this.Core.OnMessage(WixWarnings.UnknownPermission(row.SourceLineNumbers, row.Table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), i));
683 }
684 else
685 {
686 switch (name)
687 {
688 case "Append":
689 permissionEx.Append = Util.YesNoType.yes;
690 break;
691 case "ChangePermission":
692 permissionEx.ChangePermission = Util.YesNoType.yes;
693 break;
694 case "CreateChild":
695 permissionEx.CreateChild = Util.YesNoType.yes;
696 break;
697 case "CreateFile":
698 permissionEx.CreateFile = Util.YesNoType.yes;
699 break;
700 case "CreateLink":
701 permissionEx.CreateLink = Util.YesNoType.yes;
702 break;
703 case "CreateSubkeys":
704 permissionEx.CreateSubkeys = Util.YesNoType.yes;
705 break;
706 case "Delete":
707 permissionEx.Delete = Util.YesNoType.yes;
708 break;
709 case "DeleteChild":
710 permissionEx.DeleteChild = Util.YesNoType.yes;
711 break;
712 case "EnumerateSubkeys":
713 permissionEx.EnumerateSubkeys = Util.YesNoType.yes;
714 break;
715 case "Execute":
716 permissionEx.Execute = Util.YesNoType.yes;
717 break;
718 case "GenericAll":
719 permissionEx.GenericAll = Util.YesNoType.yes;
720 break;
721 case "GenericExecute":
722 permissionEx.GenericExecute = Util.YesNoType.yes;
723 break;
724 case "GenericRead":
725 permissionEx.GenericRead = Util.YesNoType.yes;
726 break;
727 case "GenericWrite":
728 permissionEx.GenericWrite = Util.YesNoType.yes;
729 break;
730 case "Notify":
731 permissionEx.Notify = Util.YesNoType.yes;
732 break;
733 case "Read":
734 permissionEx.Read = Util.YesNoType.yes;
735 break;
736 case "ReadAttributes":
737 permissionEx.ReadAttributes = Util.YesNoType.yes;
738 break;
739 case "ReadExtendedAttributes":
740 permissionEx.ReadExtendedAttributes = Util.YesNoType.yes;
741 break;
742 case "ReadPermission":
743 permissionEx.ReadPermission = Util.YesNoType.yes;
744 break;
745 case "ServiceChangeConfig":
746 permissionEx.ServiceChangeConfig = Util.YesNoType.yes;
747 break;
748 case "ServiceEnumerateDependents":
749 permissionEx.ServiceEnumerateDependents = Util.YesNoType.yes;
750 break;
751 case "ServiceInterrogate":
752 permissionEx.ServiceInterrogate = Util.YesNoType.yes;
753 break;
754 case "ServicePauseContinue":
755 permissionEx.ServicePauseContinue = Util.YesNoType.yes;
756 break;
757 case "ServiceQueryConfig":
758 permissionEx.ServiceQueryConfig = Util.YesNoType.yes;
759 break;
760 case "ServiceQueryStatus":
761 permissionEx.ServiceQueryStatus = Util.YesNoType.yes;
762 break;
763 case "ServiceStart":
764 permissionEx.ServiceStart = Util.YesNoType.yes;
765 break;
766 case "ServiceStop":
767 permissionEx.ServiceStop = Util.YesNoType.yes;
768 break;
769 case "ServiceUserDefinedControl":
770 permissionEx.ServiceUserDefinedControl = Util.YesNoType.yes;
771 break;
772 case "Synchronize":
773 permissionEx.Synchronize = Util.YesNoType.yes;
774 break;
775 case "TakeOwnership":
776 permissionEx.TakeOwnership = Util.YesNoType.yes;
777 break;
778 case "Traverse":
779 permissionEx.Traverse = Util.YesNoType.yes;
780 break;
781 case "Write":
782 permissionEx.Write = Util.YesNoType.yes;
783 break;
784 case "WriteAttributes":
785 permissionEx.WriteAttributes = Util.YesNoType.yes;
786 break;
787 case "WriteExtendedAttributes":
788 permissionEx.WriteExtendedAttributes = Util.YesNoType.yes;
789 break;
790 default:
791 throw new InvalidOperationException(String.Format("Unknown permission attribute '{0}'.", name));
792 }
793 }
794 }
795 }
796
797 if (null != row[2])
798 {
799 permissionEx.Domain = (string)row[2];
800 }
801
802 permissionEx.User = (string)row[3];
803
804 this.Core.IndexElement(row, permissionEx);
805 }
806 }
807
808 /// <summary>
809 /// Decompile the ServiceConfig table.
810 /// </summary>
811 /// <param name="table">The table to decompile.</param>
812 private void DecompileServiceConfigTable(Table table)
813 {
814 foreach (Row row in table.Rows)
815 {
816 Util.ServiceConfig serviceConfig = new Util.ServiceConfig();
817
818 serviceConfig.ServiceName = (string)row[0];
819
820 switch ((string)row[3])
821 {
822 case "none":
823 serviceConfig.FirstFailureActionType = Util.ServiceConfig.FirstFailureActionTypeType.none;
824 break;
825 case "reboot":
826 serviceConfig.FirstFailureActionType = Util.ServiceConfig.FirstFailureActionTypeType.reboot;
827 break;
828 case "restart":
829 serviceConfig.FirstFailureActionType = Util.ServiceConfig.FirstFailureActionTypeType.restart;
830 break;
831 case "runCommand":
832 serviceConfig.FirstFailureActionType = Util.ServiceConfig.FirstFailureActionTypeType.runCommand;
833 break;
834 default:
835 this.Core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[3].Column.Name, row[3]));
836 break;
837 }
838
839 switch ((string)row[4])
840 {
841 case "none":
842 serviceConfig.SecondFailureActionType = Util.ServiceConfig.SecondFailureActionTypeType.none;
843 break;
844 case "reboot":
845 serviceConfig.SecondFailureActionType = Util.ServiceConfig.SecondFailureActionTypeType.reboot;
846 break;
847 case "restart":
848 serviceConfig.SecondFailureActionType = Util.ServiceConfig.SecondFailureActionTypeType.restart;
849 break;
850 case "runCommand":
851 serviceConfig.SecondFailureActionType = Util.ServiceConfig.SecondFailureActionTypeType.runCommand;
852 break;
853 default:
854 this.Core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4]));
855 break;
856 }
857
858 switch ((string)row[5])
859 {
860 case "none":
861 serviceConfig.ThirdFailureActionType = Util.ServiceConfig.ThirdFailureActionTypeType.none;
862 break;
863 case "reboot":
864 serviceConfig.ThirdFailureActionType = Util.ServiceConfig.ThirdFailureActionTypeType.reboot;
865 break;
866 case "restart":
867 serviceConfig.ThirdFailureActionType = Util.ServiceConfig.ThirdFailureActionTypeType.restart;
868 break;
869 case "runCommand":
870 serviceConfig.ThirdFailureActionType = Util.ServiceConfig.ThirdFailureActionTypeType.runCommand;
871 break;
872 default:
873 this.Core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[5].Column.Name, row[5]));
874 break;
875 }
876
877 if (null != row[6])
878 {
879 serviceConfig.ResetPeriodInDays = (int)row[6];
880 }
881
882 if (null != row[7])
883 {
884 serviceConfig.RestartServiceDelayInSeconds = (int)row[7];
885 }
886
887 if (null != row[8])
888 {
889 serviceConfig.ProgramCommandLine = (string)row[8];
890 }
891
892 if (null != row[9])
893 {
894 serviceConfig.RebootMessage = (string)row[9];
895 }
896
897 this.Core.IndexElement(row, serviceConfig);
898 }
899 }
900
901 /// <summary>
902 /// Decompile the User table.
903 /// </summary>
904 /// <param name="table">The table to decompile.</param>
905 private void DecompileUserTable(Table table)
906 {
907 foreach (Row row in table.Rows)
908 {
909 Util.User user = new Util.User();
910
911 user.Id = (string)row[0];
912
913 user.Name = (string)row[2];
914
915 if (null != row[3])
916 {
917 user.Domain = (string)row[3];
918 }
919
920 if (null != row[4])
921 {
922 user.Password = (string)row[4];
923 }
924
925 if (null != row[5])
926 {
927 int attributes = (int)row[5];
928
929 if (UtilCompiler.UserDontExpirePasswrd == (attributes & UtilCompiler.UserDontExpirePasswrd))
930 {
931 user.PasswordNeverExpires = Util.YesNoType.yes;
932 }
933
934 if (UtilCompiler.UserPasswdCantChange == (attributes & UtilCompiler.UserPasswdCantChange))
935 {
936 user.CanNotChangePassword = Util.YesNoType.yes;
937 }
938
939 if (UtilCompiler.UserPasswdChangeReqdOnLogin == (attributes & UtilCompiler.UserPasswdChangeReqdOnLogin))
940 {
941 user.PasswordExpired = Util.YesNoType.yes;
942 }
943
944 if (UtilCompiler.UserDisableAccount == (attributes & UtilCompiler.UserDisableAccount))
945 {
946 user.Disabled = Util.YesNoType.yes;
947 }
948
949 if (UtilCompiler.UserFailIfExists == (attributes & UtilCompiler.UserFailIfExists))
950 {
951 user.FailIfExists = Util.YesNoType.yes;
952 }
953
954 if (UtilCompiler.UserUpdateIfExists == (attributes & UtilCompiler.UserUpdateIfExists))
955 {
956 user.UpdateIfExists = Util.YesNoType.yes;
957 }
958
959 if (UtilCompiler.UserLogonAsService == (attributes & UtilCompiler.UserLogonAsService))
960 {
961 user.LogonAsService = Util.YesNoType.yes;
962 }
963
964 if (UtilCompiler.UserDontRemoveOnUninstall == (attributes & UtilCompiler.UserDontRemoveOnUninstall))
965 {
966 user.RemoveOnUninstall = Util.YesNoType.no;
967 }
968
969 if (UtilCompiler.UserDontCreateUser == (attributes & UtilCompiler.UserDontCreateUser))
970 {
971 user.CreateUser = Util.YesNoType.no;
972 }
973
974 if (UtilCompiler.UserNonVital == (attributes & UtilCompiler.UserNonVital))
975 {
976 user.Vital = Util.YesNoType.no;
977 }
978 }
979
980 if (null != row[1])
981 {
982 Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[1]);
983
984 if (null != component)
985 {
986 component.AddChild(user);
987 }
988 else
989 {
990 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[1], "Component"));
991 }
992 }
993 else
994 {
995 this.Core.RootElement.AddChild(user);
996 }
997 this.Core.IndexElement(row, user);
998 }
999 }
1000
1001 /// <summary>
1002 /// Decompile the UserGroup table.
1003 /// </summary>
1004 /// <param name="table">The table to decompile.</param>
1005 private void DecompileUserGroupTable(Table table)
1006 {
1007 foreach (Row row in table.Rows)
1008 {
1009 Util.User user = (Util.User)this.Core.GetIndexedElement("User", (string)row[0]);
1010
1011 if (null != user)
1012 {
1013 Util.GroupRef groupRef = new Util.GroupRef();
1014
1015 groupRef.Id = (string)row[1];
1016
1017 user.AddChild(groupRef);
1018 }
1019 else
1020 {
1021 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Group_", (string)row[0], "Group"));
1022 }
1023 }
1024 }
1025
1026 /// <summary>
1027 /// Decompile the XmlConfig table.
1028 /// </summary>
1029 /// <param name="table">The table to decompile.</param>
1030 private void DecompileXmlConfigTable(Table table)
1031 {
1032 foreach (Row row in table.Rows)
1033 {
1034 Util.XmlConfig xmlConfig = new Util.XmlConfig();
1035
1036 xmlConfig.Id = (string)row[0];
1037
1038 xmlConfig.File = (string)row[1];
1039
1040 xmlConfig.ElementPath = (string)row[2];
1041
1042 if (null != row[3])
1043 {
1044 xmlConfig.VerifyPath = (string)row[3];
1045 }
1046
1047 if (null != row[4])
1048 {
1049 xmlConfig.Name = (string)row[4];
1050 }
1051
1052 if (null != row[5])
1053 {
1054 xmlConfig.Value = (string)row[5];
1055 }
1056
1057 int flags = (int)row[6];
1058
1059 if (0x1 == (flags & 0x1))
1060 {
1061 xmlConfig.Node = Util.XmlConfig.NodeType.element;
1062 }
1063 else if (0x2 == (flags & 0x2))
1064 {
1065 xmlConfig.Node = Util.XmlConfig.NodeType.value;
1066 }
1067 else if (0x4 == (flags & 0x4))
1068 {
1069 xmlConfig.Node = Util.XmlConfig.NodeType.document;
1070 }
1071
1072 if (0x10 == (flags & 0x10))
1073 {
1074 xmlConfig.Action = Util.XmlConfig.ActionType.create;
1075 }
1076 else if (0x20 == (flags & 0x20))
1077 {
1078 xmlConfig.Action = Util.XmlConfig.ActionType.delete;
1079 }
1080
1081 if (0x100 == (flags & 0x100))
1082 {
1083 xmlConfig.On = Util.XmlConfig.OnType.install;
1084 }
1085 else if (0x200 == (flags & 0x200))
1086 {
1087 xmlConfig.On = Util.XmlConfig.OnType.uninstall;
1088 }
1089
1090 if (0x00001000 == (flags & 0x00001000))
1091 {
1092 xmlConfig.PreserveModifiedDate = Util.YesNoType.yes;
1093 }
1094
1095 if (null != row[8])
1096 {
1097 xmlConfig.Sequence = (int)row[8];
1098 }
1099
1100 this.Core.IndexElement(row, xmlConfig);
1101 }
1102 }
1103
1104 /// <summary>
1105 /// Finalize the Perfmon table.
1106 /// </summary>
1107 /// <param name="tables">The collection of all tables.</param>
1108 /// <remarks>
1109 /// Since the PerfCounter element nests under a File element, but
1110 /// the Perfmon table does not have a foreign key relationship with
1111 /// the File table (instead it has a formatted string that usually
1112 /// refers to a file row - but doesn't have to), the nesting must
1113 /// be inferred during finalization.
1114 /// </remarks>
1115 private void FinalizePerfmonTable(TableIndexedCollection tables)
1116 {
1117 Table perfmonTable = tables["Perfmon"];
1118
1119 if (null != perfmonTable)
1120 {
1121 foreach (Row row in perfmonTable.Rows)
1122 {
1123 string formattedFile = (string)row[1];
1124 Util.PerfCounter perfCounter = (Util.PerfCounter)this.Core.GetIndexedElement(row);
1125
1126 // try to "de-format" the File column's value to determine the proper parent File element
1127 if ((formattedFile.StartsWith("[#", StringComparison.Ordinal) || formattedFile.StartsWith("[!", StringComparison.Ordinal))
1128 && formattedFile.EndsWith("]", StringComparison.Ordinal))
1129 {
1130 string fileId = formattedFile.Substring(2, formattedFile.Length - 3);
1131
1132 Wix.File file = (Wix.File)this.Core.GetIndexedElement("File", fileId);
1133 if (null != file)
1134 {
1135 file.AddChild(perfCounter);
1136 }
1137 else
1138 {
1139 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, perfmonTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "File", formattedFile, "File"));
1140 }
1141 }
1142 else
1143 {
1144 this.Core.OnMessage(UtilErrors.IllegalFileValueInPerfmonOrManifest(formattedFile, "Perfmon"));
1145 }
1146 }
1147 }
1148 }
1149
1150 /// <summary>
1151 /// Finalize the PerfmonManifest table.
1152 /// </summary>
1153 /// <param name="tables">The collection of all tables.</param>
1154 private void FinalizePerfmonManifestTable(TableIndexedCollection tables)
1155 {
1156 Table perfmonManifestTable = tables["PerfmonManifest"];
1157
1158 if (null != perfmonManifestTable)
1159 {
1160 foreach (Row row in perfmonManifestTable.Rows)
1161 {
1162 string formattedFile = (string)row[1];
1163 Util.PerfCounterManifest perfCounterManifest = (Util.PerfCounterManifest)this.Core.GetIndexedElement(row);
1164
1165 // try to "de-format" the File column's value to determine the proper parent File element
1166 if ((formattedFile.StartsWith("[#", StringComparison.Ordinal) || formattedFile.StartsWith("[!", StringComparison.Ordinal))
1167 && formattedFile.EndsWith("]", StringComparison.Ordinal))
1168 {
1169 string fileId = formattedFile.Substring(2, formattedFile.Length - 3);
1170
1171 Wix.File file = (Wix.File)this.Core.GetIndexedElement("File", fileId);
1172 if (null != file)
1173 {
1174 file.AddChild(perfCounterManifest);
1175 }
1176 else
1177 {
1178 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, perfCounterManifest.ResourceFileDirectory, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "File", formattedFile, "File"));
1179 }
1180 }
1181 else
1182 {
1183 this.Core.OnMessage(UtilErrors.IllegalFileValueInPerfmonOrManifest(formattedFile, "PerfmonManifest"));
1184 }
1185 }
1186 }
1187 }
1188
1189 /// <summary>
1190 /// Finalize the SecureObjects table.
1191 /// </summary>
1192 /// <param name="tables">The collection of all tables.</param>
1193 /// <remarks>
1194 /// Nests the PermissionEx elements below their parent elements. There are no declared foreign
1195 /// keys for the parents of the SecureObjects table.
1196 /// </remarks>
1197 private void FinalizeSecureObjectsTable(TableIndexedCollection tables)
1198 {
1199 Table createFolderTable = tables["CreateFolder"];
1200 Table secureObjectsTable = tables["SecureObjects"];
1201
1202 Hashtable createFolders = new Hashtable();
1203
1204 // index the CreateFolder table because the foreign key to this table from the
1205 // LockPermissions table is only part of the primary key of this table
1206 if (null != createFolderTable)
1207 {
1208 foreach (Row row in createFolderTable.Rows)
1209 {
1210 Wix.CreateFolder createFolder = (Wix.CreateFolder)this.Core.GetIndexedElement(row);
1211 string directoryId = (string)row[0];
1212
1213 if (!createFolders.Contains(directoryId))
1214 {
1215 createFolders.Add(directoryId, new ArrayList());
1216 }
1217 ((ArrayList)createFolders[directoryId]).Add(createFolder);
1218 }
1219 }
1220
1221 if (null != secureObjectsTable)
1222 {
1223 foreach (Row row in secureObjectsTable.Rows)
1224 {
1225 string id = (string)row[0];
1226 string table = (string)row[1];
1227
1228 Util.PermissionEx permissionEx = (Util.PermissionEx)this.Core.GetIndexedElement(row);
1229
1230 if ("CreateFolder" == table)
1231 {
1232 ArrayList createFolderElements = (ArrayList)createFolders[id];
1233
1234 if (null != createFolderElements)
1235 {
1236 foreach (Wix.CreateFolder createFolder in createFolderElements)
1237 {
1238 createFolder.AddChild(permissionEx);
1239 }
1240 }
1241 else
1242 {
1243 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "SecureObjects", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "LockObject", id, table));
1244 }
1245 }
1246 else
1247 {
1248 Wix.IParentElement parentElement = (Wix.IParentElement)this.Core.GetIndexedElement(table, id);
1249
1250 if (null != parentElement)
1251 {
1252 parentElement.AddChild(permissionEx);
1253 }
1254 else
1255 {
1256 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "SecureObjects", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "LockObject", id, table));
1257 }
1258 }
1259 }
1260 }
1261 }
1262
1263 /// <summary>
1264 /// Finalize the ServiceConfig table.
1265 /// </summary>
1266 /// <param name="tables">The collection of all tables.</param>
1267 /// <remarks>
1268 /// Since there is no foreign key from the ServiceName column to the
1269 /// ServiceInstall table, this relationship must be handled late.
1270 /// </remarks>
1271 private void FinalizeServiceConfigTable(TableIndexedCollection tables)
1272 {
1273 Table serviceConfigTable = tables["ServiceConfig"];
1274 Table serviceInstallTable = tables["ServiceInstall"];
1275
1276 Hashtable serviceInstalls = new Hashtable();
1277
1278 // index the ServiceInstall table because the foreign key used by the ServiceConfig
1279 // table is actually the ServiceInstall.Name, not the ServiceInstall.ServiceInstall
1280 // this is unfortunate because the service Name is not guaranteed to be unique, so
1281 // decompiler must assume there could be multiple matches and add the ServiceConfig to each
1282 // TODO: the Component column information should be taken into acount to accurately identify
1283 // the correct column to use
1284 if (null != serviceInstallTable)
1285 {
1286 foreach (Row row in serviceInstallTable.Rows)
1287 {
1288 string name = (string)row[1];
1289 Wix.ServiceInstall serviceInstall = (Wix.ServiceInstall)this.Core.GetIndexedElement(row);
1290
1291 if (!serviceInstalls.Contains(name))
1292 {
1293 serviceInstalls.Add(name, new ArrayList());
1294 }
1295
1296 ((ArrayList)serviceInstalls[name]).Add(serviceInstall);
1297 }
1298 }
1299
1300 if (null != serviceConfigTable)
1301 {
1302 foreach (Row row in serviceConfigTable.Rows)
1303 {
1304 Util.ServiceConfig serviceConfig = (Util.ServiceConfig)this.Core.GetIndexedElement(row);
1305
1306 if (0 == (int)row[2])
1307 {
1308 Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[1]);
1309
1310 if (null != component)
1311 {
1312 component.AddChild(serviceConfig);
1313 }
1314 else
1315 {
1316 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, serviceConfigTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[1], "Component"));
1317 }
1318 }
1319 else
1320 {
1321 ArrayList serviceInstallElements = (ArrayList)serviceInstalls[row[0]];
1322
1323 if (null != serviceInstallElements)
1324 {
1325 foreach (Wix.ServiceInstall serviceInstall in serviceInstallElements)
1326 {
1327 serviceInstall.AddChild(serviceConfig);
1328 }
1329 }
1330 else
1331 {
1332 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, serviceConfigTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "ServiceName", (string)row[0], "ServiceInstall"));
1333 }
1334 }
1335 }
1336 }
1337 }
1338
1339 /// <summary>
1340 /// Finalize the XmlConfig table.
1341 /// </summary>
1342 /// <param name="tables">Collection of all tables.</param>
1343 private void FinalizeXmlConfigTable(TableIndexedCollection tables)
1344 {
1345 Table xmlConfigTable = tables["XmlConfig"];
1346
1347 if (null != xmlConfigTable)
1348 {
1349 foreach (Row row in xmlConfigTable.Rows)
1350 {
1351 Util.XmlConfig xmlConfig = (Util.XmlConfig)this.Core.GetIndexedElement(row);
1352
1353 if (null == row[6] || 0 == (int)row[6])
1354 {
1355 Util.XmlConfig parentXmlConfig = (Util.XmlConfig)this.Core.GetIndexedElement("XmlConfig", (string)row[2]);
1356
1357 if (null != parentXmlConfig)
1358 {
1359 parentXmlConfig.AddChild(xmlConfig);
1360 }
1361 else
1362 {
1363 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, xmlConfigTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "ElementPath", (string)row[2], "XmlConfig"));
1364 }
1365 }
1366 else
1367 {
1368 Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[7]);
1369
1370 if (null != component)
1371 {
1372 component.AddChild(xmlConfig);
1373 }
1374 else
1375 {
1376 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, xmlConfigTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[7], "Component"));
1377 }
1378 }
1379 }
1380 }
1381 }
1382
1383
1384 /// <summary>
1385 /// Finalize the XmlFile table.
1386 /// </summary>
1387 /// <param name="tables">The collection of all tables.</param>
1388 /// <remarks>
1389 /// Some of the XmlFile table rows are compiler generated from util:EventManifest node
1390 /// These rows should not be appended to component.
1391 /// </remarks>
1392 private void FinalizeXmlFileTable(TableIndexedCollection tables)
1393 {
1394 Table xmlFileTable = tables["XmlFile"];
1395 Table eventManifestTable = tables["EventManifest"];
1396
1397 if (null != xmlFileTable)
1398 {
1399 foreach (Row row in xmlFileTable.Rows)
1400 {
1401 bool bManifestGenerated = false;
1402 string xmlFileConfigId = (string)row[0];
1403 if (null != eventManifestTable)
1404 {
1405 foreach (Row emrow in eventManifestTable.Rows)
1406 {
1407 string formattedFile = (string)emrow[1];
1408 if ((formattedFile.StartsWith("[#", StringComparison.Ordinal) || formattedFile.StartsWith("[!", StringComparison.Ordinal))
1409 && formattedFile.EndsWith("]", StringComparison.Ordinal))
1410 {
1411 string fileId = formattedFile.Substring(2, formattedFile.Length - 3);
1412 if (String.Equals(String.Concat("Config_", fileId, "ResourceFile"), xmlFileConfigId))
1413 {
1414 Util.EventManifest eventManifest = (Util.EventManifest)this.Core.GetIndexedElement(emrow);
1415 if (null != eventManifest)
1416 {
1417 eventManifest.ResourceFile = (string)row[4];
1418 }
1419 bManifestGenerated = true;
1420 }
1421
1422 else if (String.Equals(String.Concat("Config_", fileId, "MessageFile"), xmlFileConfigId))
1423 {
1424 Util.EventManifest eventManifest = (Util.EventManifest)this.Core.GetIndexedElement(emrow);
1425 if (null != eventManifest)
1426 {
1427 eventManifest.MessageFile = (string)row[4];
1428 }
1429 bManifestGenerated = true;
1430 }
1431 }
1432 }
1433 }
1434
1435 if (true == bManifestGenerated)
1436 continue;
1437
1438 Util.XmlFile xmlFile = new Util.XmlFile();
1439
1440 xmlFile.Id = (string)row[0];
1441 xmlFile.File = (string)row[1];
1442 xmlFile.ElementPath = (string)row[2];
1443
1444 if (null != row[3])
1445 {
1446 xmlFile.Name = (string)row[3];
1447 }
1448
1449 if (null != row[4])
1450 {
1451 xmlFile.Value = (string)row[4];
1452 }
1453
1454 int flags = (int)row[5];
1455 if (0x1 == (flags & 0x1) && 0x2 == (flags & 0x2))
1456 {
1457 this.Core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, xmlFileTable.Name, row.Fields[5].Column.Name, row[5]));
1458 }
1459 else if (0x1 == (flags & 0x1))
1460 {
1461 xmlFile.Action = Util.XmlFile.ActionType.createElement;
1462 }
1463 else if (0x2 == (flags & 0x2))
1464 {
1465 xmlFile.Action = Util.XmlFile.ActionType.deleteValue;
1466 }
1467 else
1468 {
1469 xmlFile.Action = Util.XmlFile.ActionType.setValue;
1470 }
1471
1472 if (0x100 == (flags & 0x100))
1473 {
1474 xmlFile.SelectionLanguage = Util.XmlFile.SelectionLanguageType.XPath;
1475 }
1476
1477 if (0x00001000 == (flags & 0x00001000))
1478 {
1479 xmlFile.PreserveModifiedDate = Util.YesNoType.yes;
1480 }
1481
1482 if (0x00010000 == (flags & 0x00010000))
1483 {
1484 xmlFile.Permanent = Util.YesNoType.yes;
1485 }
1486
1487 if (null != row[7])
1488 {
1489 xmlFile.Sequence = (int)row[7];
1490 }
1491
1492 Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[6]);
1493
1494 if (null != component)
1495 {
1496 component.AddChild(xmlFile);
1497 }
1498 else
1499 {
1500 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, xmlFileTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[6], "Component"));
1501 }
1502 }
1503 }
1504 }
1505
1506 /// <summary>
1507 /// Finalize the eventManifest table.
1508 /// This function must be called after FinalizeXmlFileTable
1509 /// </summary>
1510 /// <param name="tables">The collection of all tables.</param>
1511 private void FinalizeEventManifestTable(TableIndexedCollection tables)
1512 {
1513 Table eventManifestTable = tables["EventManifest"];
1514
1515 if (null != eventManifestTable)
1516 {
1517 foreach (Row row in eventManifestTable.Rows)
1518 {
1519 string formattedFile = (string)row[1];
1520 Util.EventManifest eventManifest = (Util.EventManifest)this.Core.GetIndexedElement(row);
1521
1522 // try to "de-format" the File column's value to determine the proper parent File element
1523 if ((formattedFile.StartsWith("[#", StringComparison.Ordinal) || formattedFile.StartsWith("[!", StringComparison.Ordinal))
1524 && formattedFile.EndsWith("]", StringComparison.Ordinal))
1525 {
1526 string fileId = formattedFile.Substring(2, formattedFile.Length - 3);
1527
1528 Wix.File file = (Wix.File)this.Core.GetIndexedElement("File", fileId);
1529 if (null != file)
1530 {
1531 file.AddChild(eventManifest);
1532 }
1533 }
1534 else
1535 {
1536 this.Core.OnMessage(UtilErrors.IllegalFileValueInPerfmonOrManifest(formattedFile, "EventManifest"));
1537 }
1538 }
1539 }
1540 }
1541 }
1542#endif
1543}
diff --git a/src/ext/Util/wixext/UtilErrors.cs b/src/ext/Util/wixext/UtilErrors.cs
new file mode 100644
index 00000000..b9ce1688
--- /dev/null
+++ b/src/ext/Util/wixext/UtilErrors.cs
@@ -0,0 +1,49 @@
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
3namespace WixToolset.Util
4{
5 using System;
6 using System.Resources;
7 using WixToolset.Data;
8
9 public static class UtilErrors
10 {
11 public static Message IllegalAttributeWithoutComponent(SourceLineNumber sourceLineNumbers, string elementName, string attributeName)
12 {
13 return Message(sourceLineNumbers, Ids.IllegalAttributeWithoutComponent, "The {0}/@{1} attribute cannot be specified unless the element has a Component as an ancestor. A {0} that does not have a Component ancestor is not installed.", elementName, attributeName);
14 }
15
16 public static Message IllegalElementWithoutComponent(SourceLineNumber sourceLineNumbers, string elementName)
17 {
18 return Message(sourceLineNumbers, Ids.IllegalElementWithoutComponent, "The {0} element cannot be specified unless the element has a Component as an ancestor. A {0} that does not have a Component ancestor is not installed.", elementName);
19 }
20
21 public static Message IllegalFileValueInPerfmonOrManifest(string file, string table)
22 {
23 return Message(null, Ids.IllegalFileValueInPerfmonOrManifest, "The value '{0}' in the File column, {1} table is invalid. It should be in the form of '[#file]' or '[!file]'.", file, table);
24 }
25
26 public static Message InvalidRegistryObject(SourceLineNumber sourceLineNumbers, string registryElementName)
27 {
28 return Message(sourceLineNumbers, Ids.InvalidRegistryObject, "The {0} element has no id and cannot have its permissions set. If you want to set permissions on a 'placeholder' registry key, force its creation by setting the ForceCreateOnInstall attribute to yes.", registryElementName);
29 }
30
31 private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args)
32 {
33 return new Message(sourceLineNumber, MessageLevel.Error, (int)id, format, args);
34 }
35
36 private static Message Message(SourceLineNumber sourceLineNumber, Ids id, ResourceManager resourceManager, string resourceName, params object[] args)
37 {
38 return new Message(sourceLineNumber, MessageLevel.Error, (int)id, resourceManager, resourceName, args);
39 }
40
41 public enum Ids
42 {
43 IllegalAttributeWithoutComponent = 5050,
44 IllegalElementWithoutComponent = 5051,
45 IllegalFileValueInPerfmonOrManifest = 5054,
46 InvalidRegistryObject = 5063,
47 }
48 }
49}
diff --git a/src/ext/Util/wixext/UtilExtensionData.cs b/src/ext/Util/wixext/UtilExtensionData.cs
new file mode 100644
index 00000000..d3ca3358
--- /dev/null
+++ b/src/ext/Util/wixext/UtilExtensionData.cs
@@ -0,0 +1,23 @@
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
3namespace WixToolset.Util
4{
5 using WixToolset.Data;
6 using WixToolset.Extensibility;
7
8 public sealed class UtilExtensionData : BaseExtensionData
9 {
10 public override string DefaultCulture => "en-US";
11
12 public override bool TryGetSymbolDefinitionByName(string name, out IntermediateSymbolDefinition symbolDefinition)
13 {
14 symbolDefinition = UtilSymbolDefinitions.ByName(name);
15 return symbolDefinition != null;
16 }
17
18 public override Intermediate GetLibrary(ISymbolDefinitionCreator symbolDefinitions)
19 {
20 return Intermediate.Load(typeof(UtilExtensionData).Assembly, "WixToolset.Util.util.wixlib", symbolDefinitions);
21 }
22 }
23}
diff --git a/src/ext/Util/wixext/UtilExtensionFactory.cs b/src/ext/Util/wixext/UtilExtensionFactory.cs
new file mode 100644
index 00000000..08352813
--- /dev/null
+++ b/src/ext/Util/wixext/UtilExtensionFactory.cs
@@ -0,0 +1,18 @@
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
3namespace WixToolset.Util
4{
5 using System;
6 using System.Collections.Generic;
7 using WixToolset.Extensibility;
8
9 public class UtilExtensionFactory : BaseExtensionFactory
10 {
11 protected override IReadOnlyCollection<Type> ExtensionTypes => new[]
12 {
13 typeof(UtilCompiler),
14 typeof(UtilExtensionData),
15 typeof(UtilWindowsInstallerBackendBinderExtension),
16 };
17 }
18}
diff --git a/src/ext/Util/wixext/UtilTableDefinitions.cs b/src/ext/Util/wixext/UtilTableDefinitions.cs
new file mode 100644
index 00000000..12f423cc
--- /dev/null
+++ b/src/ext/Util/wixext/UtilTableDefinitions.cs
@@ -0,0 +1,319 @@
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
3namespace WixToolset.Util
4{
5 using WixToolset.Data.WindowsInstaller;
6
7 public static class UtilTableDefinitions
8 {
9 public static readonly TableDefinition Wix4CloseApplication = new TableDefinition(
10 "Wix4CloseApplication",
11 UtilSymbolDefinitions.WixCloseApplication,
12 new[]
13 {
14 new ColumnDefinition("Wix4CloseApplication", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token in table.", modularizeType: ColumnModularizeType.Column),
15 new ColumnDefinition("Target", ColumnType.Localized, 0, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "Name of executable to ensure is closed.", modularizeType: ColumnModularizeType.Property),
16 new ColumnDefinition("Description", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Description string displayed to user when executable is in use.", modularizeType: ColumnModularizeType.Property, forceLocalizable: true),
17 new ColumnDefinition("Condition", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Condition, description: "Optional expression which skips the closing.", modularizeType: ColumnModularizeType.Condition, forceLocalizable: true),
18 new ColumnDefinition("Attributes", ColumnType.Number, 4, primaryKey: false, nullable: false, ColumnCategory.Unknown, minValue: 0, maxValue: 2147483647, description: "A 32-bit word that specifies the attribute flags to be applied."),
19 new ColumnDefinition("Sequence", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Unknown, minValue: 1, maxValue: 2147483647, description: "Sequence to order the closings by."),
20 new ColumnDefinition("Property", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Identifier, description: "Optional property that is set to the number of running instances of the app.", modularizeType: ColumnModularizeType.Property, forceLocalizable: true),
21 new ColumnDefinition("TerminateExitCode", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Unknown, minValue: 0, maxValue: 2147483647, description: "Exit code to return from a terminated application."),
22 new ColumnDefinition("Timeout", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Unknown, minValue: 1, maxValue: 2147483647, description: "Timeout in milliseconds before scheduling restart or terminating application."),
23 },
24 symbolIdIsPrimaryKey: true
25 );
26
27 public static readonly TableDefinition Wix4RemoveFolderEx = new TableDefinition(
28 "Wix4RemoveFolderEx",
29 UtilSymbolDefinitions.WixRemoveFolderEx,
30 new[]
31 {
32 new ColumnDefinition("Wix4RemoveFolderEx", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Identifier for the WixRemoveFolderEx row in the package.", modularizeType: ColumnModularizeType.Column),
33 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, description: "Foreign key into the Component table used to determine install state", modularizeType: ColumnModularizeType.Column),
34 new ColumnDefinition("Property", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, description: "Name of Property that contains the root of the directory tree to remove.", modularizeType: ColumnModularizeType.Column),
35 new ColumnDefinition("InstallMode", ColumnType.Number, 2, primaryKey: false, nullable: false, ColumnCategory.Unknown, minValue: 1, maxValue: 3, description: "1 == Remove only when the associated component is being installed (msiInstallStateLocal or msiInstallStateSource), 2 == Remove only when the associated component is being removed (msiInstallStateAbsent), 3 = Remove in either of the above cases."),
36 new ColumnDefinition("Condition", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Condition, description: "Optional expression which skips the removing of folders.", modularizeType: ColumnModularizeType.Condition, forceLocalizable: true),
37 },
38 symbolIdIsPrimaryKey: true
39 );
40
41 public static readonly TableDefinition Wix4RemoveRegistryKeyEx = new TableDefinition(
42 "Wix4RemoveRegistryKeyEx",
43 UtilSymbolDefinitions.WixRemoveRegistryKeyEx,
44 new[]
45 {
46 new ColumnDefinition("Wix4RemoveRegistryKeyEx", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Identifier for the Wix4RemoveRegistryKeyEx row in the package.", modularizeType: ColumnModularizeType.Column),
47 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, description: "Foreign key into the Component table used to determine install state", modularizeType: ColumnModularizeType.Column),
48 new ColumnDefinition("Root", ColumnType.Number, 2, primaryKey: false, nullable: false, ColumnCategory.Unknown, minValue: -1, maxValue: 3, description: "The predefined root key for the registry value, one of rrkEnum."),
49 new ColumnDefinition("Key", ColumnType.Localized, 255, primaryKey: false, nullable: false, ColumnCategory.RegPath, description: "The key for the registry value.", modularizeType: ColumnModularizeType.Property),
50 new ColumnDefinition("InstallMode", ColumnType.Number, 2, primaryKey: false, nullable: false, ColumnCategory.Unknown, minValue: 1, maxValue: 3, description: "1 == Remove only when the associated component is being installed (msiInstallStateLocal or msiInstallStateSource), 2 == Remove only when the associated component is being removed (msiInstallStateAbsent), 3 = Remove in either of the above cases."),
51 new ColumnDefinition("Condition", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Condition, description: "Optional expression to control whether the registry key is removed.", modularizeType: ColumnModularizeType.Condition, forceLocalizable: true),
52 },
53 symbolIdIsPrimaryKey: true
54 );
55
56 public static readonly TableDefinition Wix4RestartResource = new TableDefinition(
57 "Wix4RestartResource",
58 UtilSymbolDefinitions.WixRestartResource,
59 new[]
60 {
61 new ColumnDefinition("Wix4RestartResource", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized identifier.", modularizeType: ColumnModularizeType.Column),
62 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, description: "Foreign key into the Component table used to determine install state.", modularizeType: ColumnModularizeType.Column),
63 new ColumnDefinition("Resource", ColumnType.String, 0, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "The resource to be registered with the Restart Manager.", modularizeType: ColumnModularizeType.Property),
64 new ColumnDefinition("Attributes", ColumnType.Number, 4, primaryKey: false, nullable: false, ColumnCategory.Unknown, minValue: 0, maxValue: 2147483647, description: "A 32-bit word that specifies the type of resource and flags used for processing."),
65 },
66 symbolIdIsPrimaryKey: true
67 );
68
69 public static readonly TableDefinition Wix4FileShare = new TableDefinition(
70 "Wix4FileShare",
71 UtilSymbolDefinitions.FileShare,
72 new[]
73 {
74 new ColumnDefinition("Wix4FileShare", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized identifier", modularizeType: ColumnModularizeType.Column),
75 new ColumnDefinition("ShareName", ColumnType.String, 255, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "The actual share name used"),
76 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, description: "Foreign key into the Component table used to determine install state", modularizeType: ColumnModularizeType.Column),
77 new ColumnDefinition("Description", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Text, description: "Description string displayed for the file share"),
78 new ColumnDefinition("Directory_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "Directory", keyColumn: 1, description: "Foreign key referencing directory that the share is created on", modularizeType: ColumnModularizeType.Column),
79 },
80 symbolIdIsPrimaryKey: true
81 );
82
83 public static readonly TableDefinition Wix4FileSharePermissions = new TableDefinition(
84 "Wix4FileSharePermissions",
85 UtilSymbolDefinitions.FileSharePermissions,
86 new[]
87 {
88 new ColumnDefinition("Wix4FileShare_", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, keyTable: "FileShare", keyColumn: 1, description: "FileShare that these premissions are to be applied to.", modularizeType: ColumnModularizeType.Column),
89 new ColumnDefinition("Wix4User_", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, keyTable: "Wix4User", description: "User that these premissions are to apply to.", modularizeType: ColumnModularizeType.Column),
90 new ColumnDefinition("Permissions", ColumnType.Number, 4, primaryKey: false, nullable: false, ColumnCategory.Unknown, description: "Permissions int, as in EXPLICIT_ACCESS.grfAccessPermissions in MSDN"),
91 },
92 symbolIdIsPrimaryKey: false
93 );
94
95 public static readonly TableDefinition Wix4Group = new TableDefinition(
96 "Wix4Group",
97 UtilSymbolDefinitions.Group,
98 new[]
99 {
100 new ColumnDefinition("Wix4Group", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token", modularizeType: ColumnModularizeType.Column),
101 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Text, keyTable: "Component", keyColumn: 1, description: "Foreign key, Component used to determine install state", modularizeType: ColumnModularizeType.Column),
102 new ColumnDefinition("Name", ColumnType.String, 255, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "Group name", modularizeType: ColumnModularizeType.Property),
103 new ColumnDefinition("Domain", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Group domain", modularizeType: ColumnModularizeType.Property),
104 },
105 symbolIdIsPrimaryKey: true
106 );
107
108 public static readonly TableDefinition Wix4InternetShortcut = new TableDefinition(
109 "Wix4InternetShortcut",
110 UtilSymbolDefinitions.WixInternetShortcut,
111 new[]
112 {
113 new ColumnDefinition("Wix4InternetShortcut", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token in table.", modularizeType: ColumnModularizeType.Column),
114 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Text, keyTable: "Component", keyColumn: 1, description: "Foreign key, Component used to determine install state", modularizeType: ColumnModularizeType.Column),
115 new ColumnDefinition("Directory_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "Directory", keyColumn: 1, description: "Foreign key referencing directory that the shortcut is created in", modularizeType: ColumnModularizeType.Column),
116 new ColumnDefinition("Name", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Text, description: "Name used for shortcut.", modularizeType: ColumnModularizeType.Property),
117 new ColumnDefinition("Target", ColumnType.Localized, 0, primaryKey: false, nullable: false, ColumnCategory.Text, description: "URL target."),
118 new ColumnDefinition("Attributes", ColumnType.Number, 2, primaryKey: false, nullable: false, ColumnCategory.Unknown, description: "Attribute flags that control how the shortcut is created."),
119 new ColumnDefinition("IconFile", ColumnType.Localized, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Icon file for shortcut", modularizeType: ColumnModularizeType.Property),
120 new ColumnDefinition("IconIndex", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Index of the icon being referenced."),
121 },
122 symbolIdIsPrimaryKey: true
123 );
124
125 public static readonly TableDefinition Wix4PerformanceCategory = new TableDefinition(
126 "Wix4PerformanceCategory",
127 UtilSymbolDefinitions.PerformanceCategory,
128 new[]
129 {
130 new ColumnDefinition("Wix4PerformanceCategory", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token in table.", modularizeType: ColumnModularizeType.Column),
131 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, description: "Component used to determine install state", modularizeType: ColumnModularizeType.Column),
132 new ColumnDefinition("Name", ColumnType.String, 80, primaryKey: false, nullable: false, ColumnCategory.Text, description: "Name of the performance counter category."),
133 new ColumnDefinition("IniData", ColumnType.Localized, 0, primaryKey: false, nullable: false, ColumnCategory.Text, description: "Data that goes into the performance counter .ini file."),
134 new ColumnDefinition("ConstantData", ColumnType.Localized, 0, primaryKey: false, nullable: false, ColumnCategory.Text, description: "Data that goes into the performance counter .h file."),
135 },
136 symbolIdIsPrimaryKey: true
137 );
138
139 public static readonly TableDefinition Wix4Perfmon = new TableDefinition(
140 "Wix4Perfmon",
141 UtilSymbolDefinitions.Perfmon,
142 new[]
143 {
144 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, description: "Component used to determine install state", modularizeType: ColumnModularizeType.Column),
145 new ColumnDefinition("File", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Formatted, description: "Name of .INI file", modularizeType: ColumnModularizeType.Property),
146 new ColumnDefinition("Name", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Text, description: "Service name in registry"),
147 },
148 symbolIdIsPrimaryKey: false
149 );
150
151 public static readonly TableDefinition Wix4PerfmonManifest = new TableDefinition(
152 "Wix4PerfmonManifest",
153 UtilSymbolDefinitions.PerfmonManifest,
154 new[]
155 {
156 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, description: "Component used to determine install state", modularizeType: ColumnModularizeType.Column),
157 new ColumnDefinition("File", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Formatted, description: "Name of perfmon manifest file", modularizeType: ColumnModularizeType.Property),
158 new ColumnDefinition("ResourceFileDirectory", ColumnType.String, 255, primaryKey: true, nullable: false, ColumnCategory.Formatted, description: "The path of the Resource File Directory"),
159 },
160 symbolIdIsPrimaryKey: false
161 );
162
163 public static readonly TableDefinition Wix4EventManifest = new TableDefinition(
164 "Wix4EventManifest",
165 UtilSymbolDefinitions.EventManifest,
166 new[]
167 {
168 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, description: "Component used to determine install state", modularizeType: ColumnModularizeType.Column),
169 new ColumnDefinition("File", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Formatted, description: "Name of event manifest file", modularizeType: ColumnModularizeType.Property),
170 },
171 symbolIdIsPrimaryKey: false
172 );
173
174 public static readonly TableDefinition Wix4SecureObject = new TableDefinition(
175 "Wix4SecureObject",
176 UtilSymbolDefinitions.SecureObjects,
177 new[]
178 {
179 new ColumnDefinition("Wix4SecureObject", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token in Table", modularizeType: ColumnModularizeType.Column),
180 new ColumnDefinition("Table", ColumnType.String, 32, primaryKey: true, nullable: false, ColumnCategory.Text, description: "Table SecureObject should be securing"),
181 new ColumnDefinition("Domain", ColumnType.String, 255, primaryKey: true, nullable: true, ColumnCategory.Text, description: "Domain half of user account to secure", modularizeType: ColumnModularizeType.Property),
182 new ColumnDefinition("User", ColumnType.String, 255, primaryKey: true, nullable: false, ColumnCategory.Text, description: "User name half of user account to secure", modularizeType: ColumnModularizeType.Property),
183 new ColumnDefinition("Attributes", ColumnType.Number, 4, primaryKey: false, nullable: false, ColumnCategory.Integer, minValue: 0, maxValue: 2147483647, description: "A 32-bit word that specifies the attribute flags to be applied."),
184 new ColumnDefinition("Permission", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Unknown, minValue: -2147483647, maxValue: 2147483647, description: "Permissions to grant to User"),
185 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, description: "Foreign key into the Component table used to determine install state", modularizeType: ColumnModularizeType.Column),
186 },
187 symbolIdIsPrimaryKey: false
188 );
189
190 public static readonly TableDefinition Wix4ServiceConfig = new TableDefinition(
191 "Wix4ServiceConfig",
192 UtilSymbolDefinitions.ServiceConfig,
193 new[]
194 {
195 new ColumnDefinition("ServiceName", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Formatted, description: "Primary key, non-localized token"),
196 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, description: "Foreign key, Component used to determine install state ", modularizeType: ColumnModularizeType.Column),
197 new ColumnDefinition("NewService", ColumnType.Number, 1, primaryKey: false, nullable: false, ColumnCategory.Unknown, minValue: 0, maxValue: 1, description: "Whether the affected service is being installed or already exists."),
198 new ColumnDefinition("FirstFailureActionType", ColumnType.String, 32, primaryKey: false, nullable: false, ColumnCategory.Text, description: "First failure action type for configured service to take."),
199 new ColumnDefinition("SecondFailureActionType", ColumnType.String, 32, primaryKey: false, nullable: false, ColumnCategory.Text, description: "Second failure action type for configured service to take."),
200 new ColumnDefinition("ThirdFailureActionType", ColumnType.String, 32, primaryKey: false, nullable: false, ColumnCategory.Text, description: "Third failure action type for configured service to take."),
201 new ColumnDefinition("ResetPeriodInDays", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Integer, minValue: 0, description: "Period after which to reset the failure count for the service."),
202 new ColumnDefinition("RestartServiceDelayInSeconds", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Integer, minValue: 0, description: "Period after which to restart the service after a given failure."),
203 new ColumnDefinition("ProgramCommandLine", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Command line for program to run if failure action is RUN_COMMAND."),
204 new ColumnDefinition("RebootMessage", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Text, description: "Message to show to users when rebooting if failure action is REBOOT."),
205 },
206 symbolIdIsPrimaryKey: false
207 );
208
209 public static readonly TableDefinition Wix4TouchFile = new TableDefinition(
210 "Wix4TouchFile",
211 UtilSymbolDefinitions.WixTouchFile,
212 new[]
213 {
214 new ColumnDefinition("Wix4TouchFile", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Identifier for the Wix4TouchFile row in the package.", modularizeType: ColumnModularizeType.Column),
215 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, description: "Foreign key into the Component table used to determine install state", modularizeType: ColumnModularizeType.Column),
216 new ColumnDefinition("Path", ColumnType.String, 255, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "Formatted column that resolves to the path to touch.", modularizeType: ColumnModularizeType.Property),
217 new ColumnDefinition("Attributes", ColumnType.Number, 2, primaryKey: false, nullable: false, ColumnCategory.Unknown, minValue: 1, maxValue: 63, description: "1 == Touch only when the associated component is being installed, 2 == Touch only when the associated component is being repaired , 4 == Touch only when the associated component is being removed, 16 = path is in 64-bit location, 32 = touching the file is vital."),
218 },
219 symbolIdIsPrimaryKey: true
220 );
221
222 public static readonly TableDefinition Wix4User = new TableDefinition(
223 "Wix4User",
224 UtilSymbolDefinitions.User,
225 new[]
226 {
227 new ColumnDefinition("Wix4User", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token", modularizeType: ColumnModularizeType.Column),
228 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Text, keyTable: "Component", keyColumn: 1, description: "Foreign key, Component used to determine install state", modularizeType: ColumnModularizeType.Column),
229 new ColumnDefinition("Name", ColumnType.String, 255, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "User name", modularizeType: ColumnModularizeType.Property),
230 new ColumnDefinition("Domain", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "User domain", modularizeType: ColumnModularizeType.Property),
231 new ColumnDefinition("Password", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "User password", modularizeType: ColumnModularizeType.Property),
232 new ColumnDefinition("Attributes", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Unknown, minValue: 0, maxValue: 65535, description: "Attributes describing how to create the user"),
233 },
234 symbolIdIsPrimaryKey: true
235 );
236
237 public static readonly TableDefinition Wix4UserGroup = new TableDefinition(
238 "Wix4UserGroup",
239 UtilSymbolDefinitions.UserGroup,
240 new[]
241 {
242 new ColumnDefinition("Wix4User_", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, keyTable: "Wix4User", keyColumn: 1, description: "User to be joined to a Group.", modularizeType: ColumnModularizeType.Column),
243 new ColumnDefinition("Wix4Group_", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, keyTable: "Wix4Group", keyColumn: 1, description: "Group to join User to.", modularizeType: ColumnModularizeType.Column),
244 },
245 symbolIdIsPrimaryKey: false
246 );
247
248 public static readonly TableDefinition Wix4XmlFile = new TableDefinition(
249 "Wix4XmlFile",
250 UtilSymbolDefinitions.XmlFile,
251 new[]
252 {
253 new ColumnDefinition("Wix4XmlFile", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token.", modularizeType: ColumnModularizeType.Column),
254 new ColumnDefinition("File", ColumnType.Localized, 255, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "The .XML file in which to write the information", modularizeType: ColumnModularizeType.Property),
255 new ColumnDefinition("ElementPath", ColumnType.Localized, 0, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "The .XML file element to modify.", modularizeType: ColumnModularizeType.Property),
256 new ColumnDefinition("Name", ColumnType.Localized, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "The .XML file node to set/add in the element.", modularizeType: ColumnModularizeType.Property),
257 new ColumnDefinition("Value", ColumnType.Localized, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "The value to be written.", modularizeType: ColumnModularizeType.Property),
258 new ColumnDefinition("Flags", ColumnType.Number, 4, primaryKey: false, nullable: false, ColumnCategory.Unknown, minValue: 0, maxValue: 70143, description: "Flags"),
259 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, description: "Foreign key into the Component table referencing component that controls the installing of the .XML value.", modularizeType: ColumnModularizeType.Column),
260 new ColumnDefinition("Sequence", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Order to execute the XML modifications."),
261 },
262 symbolIdIsPrimaryKey: true
263 );
264
265 public static readonly TableDefinition Wix4XmlConfig = new TableDefinition(
266 "Wix4XmlConfig",
267 UtilSymbolDefinitions.XmlConfig,
268 new[]
269 {
270 new ColumnDefinition("Wix4XmlConfig", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token.", modularizeType: ColumnModularizeType.Column),
271 new ColumnDefinition("File", ColumnType.Localized, 255, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "The .XML file in which to write the information", modularizeType: ColumnModularizeType.Property),
272 new ColumnDefinition("ElementId", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Identifier, keyTable: "Wix4XmlConfig", keyColumn: 1, description: "A foreign key reference to another Wix4XmlConfig row if no attributes are set and the row referenced is a create element row.", modularizeType: ColumnModularizeType.Column),
273 new ColumnDefinition("ElementPath", ColumnType.Localized, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "The XPATH query for an element to modify or add children to. Must be null if ElementId is provided", modularizeType: ColumnModularizeType.Property),
274 new ColumnDefinition("VerifyPath", ColumnType.Localized, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "The XPATH query run from ElementPath to verify whether a repair is necessary. Also used to uninstall.", modularizeType: ColumnModularizeType.Property),
275 new ColumnDefinition("Name", ColumnType.Localized, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "The .XML file node to set/add in the element.", modularizeType: ColumnModularizeType.Property),
276 new ColumnDefinition("Value", ColumnType.Localized, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "The value to be written.", modularizeType: ColumnModularizeType.Property),
277 new ColumnDefinition("Flags", ColumnType.Number, 4, primaryKey: false, nullable: false, ColumnCategory.Unknown, minValue: 0, maxValue: 65536, description: "Element=1,Value=2,Document=4,Create=16,Delete=32,Install=256,Uninstall=512"),
278 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, description: "Foreign key into the Component table referencing component that controls the installing of the .XML value.", modularizeType: ColumnModularizeType.Column),
279 new ColumnDefinition("Sequence", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Order to execute the XML modifications."),
280 },
281 symbolIdIsPrimaryKey: true
282 );
283
284 public static readonly TableDefinition Wix4FormatFile = new TableDefinition(
285 "Wix4FormatFile",
286 UtilSymbolDefinitions.WixFormatFiles,
287 new[]
288 {
289 new ColumnDefinition("Binary_", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, keyTable: "Binary", keyColumn: 1, description: "Binary data to be formatted.", modularizeType: ColumnModularizeType.Column),
290 new ColumnDefinition("File_", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, keyTable: "File", keyColumn: 1, description: "File whose component controls the custom action and where the formatted data is written.", modularizeType: ColumnModularizeType.Column),
291 },
292 symbolIdIsPrimaryKey: false
293 );
294
295 public static readonly TableDefinition[] All = new[]
296 {
297 Wix4CloseApplication,
298 Wix4RemoveFolderEx,
299 Wix4RemoveRegistryKeyEx,
300 Wix4RestartResource,
301 Wix4FileShare,
302 Wix4FileSharePermissions,
303 Wix4Group,
304 Wix4InternetShortcut,
305 Wix4PerformanceCategory,
306 Wix4Perfmon,
307 Wix4PerfmonManifest,
308 Wix4EventManifest,
309 Wix4SecureObject,
310 Wix4ServiceConfig,
311 Wix4TouchFile,
312 Wix4User,
313 Wix4UserGroup,
314 Wix4XmlFile,
315 Wix4XmlConfig,
316 Wix4FormatFile,
317 };
318 }
319}
diff --git a/src/ext/Util/wixext/UtilWarnings.cs b/src/ext/Util/wixext/UtilWarnings.cs
new file mode 100644
index 00000000..b65abe45
--- /dev/null
+++ b/src/ext/Util/wixext/UtilWarnings.cs
@@ -0,0 +1,37 @@
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
3namespace WixToolset.Util
4{
5 using System;
6 using System.Resources;
7 using WixToolset.Data;
8
9 public static class UtilWarnings
10 {
11 public static Message DeprecatedPerfCounterElement(SourceLineNumber sourceLineNumbers)
12 {
13 return Message(sourceLineNumbers, Ids.DeprecatedPerfCounterElement, "The PerfCounter element has been deprecated. Please use the PerformanceCounter element instead.");
14 }
15
16 public static Message RequiredAttributeForWindowsXP(SourceLineNumber sourceLineNumbers, string elementName, string attributeName)
17 {
18 return Message(sourceLineNumbers, Ids.RequiredAttributeForWindowsXP, "The {0}/@{1} attribute must be specified to successfully install on Windows XP. You can ignore this warning if this installation does not install on Windows XP.", elementName, attributeName);
19 }
20
21 private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args)
22 {
23 return new Message(sourceLineNumber, MessageLevel.Warning, (int)id, format, args);
24 }
25
26 private static Message Message(SourceLineNumber sourceLineNumber, Ids id, ResourceManager resourceManager, string resourceName, params object[] args)
27 {
28 return new Message(sourceLineNumber, MessageLevel.Warning, (int)id, resourceManager, resourceName, args);
29 }
30
31 public enum Ids
32 {
33 DeprecatedPerfCounterElement = 5153,
34 RequiredAttributeForWindowsXP = 5154,
35 }
36 }
37}
diff --git a/src/ext/Util/wixext/UtilWindowsInstallerBackendExtension.cs b/src/ext/Util/wixext/UtilWindowsInstallerBackendExtension.cs
new file mode 100644
index 00000000..bca7c700
--- /dev/null
+++ b/src/ext/Util/wixext/UtilWindowsInstallerBackendExtension.cs
@@ -0,0 +1,13 @@
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
3namespace WixToolset.Util
4{
5 using System.Collections.Generic;
6 using WixToolset.Data.WindowsInstaller;
7 using WixToolset.Extensibility;
8
9 public class UtilWindowsInstallerBackendBinderExtension : BaseWindowsInstallerBackendBinderExtension
10 {
11 public override IReadOnlyCollection<TableDefinition> TableDefinitions => UtilTableDefinitions.All;
12 }
13}
diff --git a/src/ext/Util/wixext/WixToolset.Util.wixext.csproj b/src/ext/Util/wixext/WixToolset.Util.wixext.csproj
new file mode 100644
index 00000000..10fc569e
--- /dev/null
+++ b/src/ext/Util/wixext/WixToolset.Util.wixext.csproj
@@ -0,0 +1,31 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4<Project Sdk="Microsoft.NET.Sdk">
5 <PropertyGroup>
6 <TargetFramework>netstandard2.0</TargetFramework>
7 <RootNamespace>WixToolset.Util</RootNamespace>
8 <Description>WiX Toolset Utility Extension</Description>
9 <Title>WiX Toolset Util Extension</Title>
10 <DebugType>embedded</DebugType>
11 <IncludeSymbols>true</IncludeSymbols>
12 </PropertyGroup>
13
14 <ItemGroup>
15 <EmbeddedResource Include="$(OutputPath)..\util.wixlib" />
16 </ItemGroup>
17
18 <ItemGroup>
19 <ProjectReference Include="..\wixlib\util.wixproj" ReferenceOutputAssembly="false" Condition=" '$(NCrunch)'=='' " />
20 </ItemGroup>
21
22 <ItemGroup>
23 <PackageReference Include="WixToolset.Data" Version="4.0.*" />
24 <PackageReference Include="WixToolset.Extensibility" Version="4.0.*" />
25 </ItemGroup>
26
27 <ItemGroup>
28 <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="all" />
29 <PackageReference Include="Nerdbank.GitVersioning" Version="3.3.37" PrivateAssets="All" />
30 </ItemGroup>
31</Project>
diff --git a/src/ext/Util/wixext/WixToolset.Util.wixext.nuspec b/src/ext/Util/wixext/WixToolset.Util.wixext.nuspec
new file mode 100644
index 00000000..ba3eaade
--- /dev/null
+++ b/src/ext/Util/wixext/WixToolset.Util.wixext.nuspec
@@ -0,0 +1,25 @@
1<?xml version="1.0"?>
2<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
3 <metadata minClientVersion="4.0">
4 <id>$id$</id>
5 <version>$version$</version>
6 <title>$title$</title>
7 <description>$description$</description>
8 <authors>$authors$</authors>
9 <license type="expression">MS-RL</license>
10 <requireLicenseAcceptance>false</requireLicenseAcceptance>
11 <copyright>$copyright$</copyright>
12 <projectUrl>$projectUrl$</projectUrl>
13 <repository type="$repositorytype$" url="$repositoryurl$" commit="$repositorycommit$" />
14 </metadata>
15
16 <files>
17 <file src="$projectFolder$$id$.targets" target="build" />
18
19 <file src="netstandard2.0\$id$.dll" target="tools" />
20
21 <file src="ARM64\*.pdb" target="pdbs\ARM64" />
22 <file src="x86\*.pdb" target="pdbs\x86" />
23 <file src="x64\*.pdb" target="pdbs\x64" />
24 </files>
25</package>
diff --git a/src/ext/Util/wixext/WixToolset.Util.wixext.targets b/src/ext/Util/wixext/WixToolset.Util.wixext.targets
new file mode 100644
index 00000000..64dff429
--- /dev/null
+++ b/src/ext/Util/wixext/WixToolset.Util.wixext.targets
@@ -0,0 +1,11 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
5 <PropertyGroup>
6 <WixToolsetUtilWixextPath Condition=" '$(WixToolsetUtilWixextPath)' == '' ">$(MSBuildThisFileDirectory)..\tools\WixToolset.Util.wixext.dll</WixToolsetUtilWixextPath>
7 </PropertyGroup>
8 <ItemGroup>
9 <WixExtension Include="$(WixToolsetUtilWixextPath)" />
10 </ItemGroup>
11</Project>
diff --git a/src/ext/Util/wixext/WixToolset.Util.wixext.v3.ncrunchproject b/src/ext/Util/wixext/WixToolset.Util.wixext.v3.ncrunchproject
new file mode 100644
index 00000000..d75e7ab3
--- /dev/null
+++ b/src/ext/Util/wixext/WixToolset.Util.wixext.v3.ncrunchproject
@@ -0,0 +1,7 @@
1<ProjectConfiguration>
2 <Settings>
3 <AdditionalFilesToIncludeForProject>
4 <Value>..\..\build\Debug\util.wixlib</Value>
5 </AdditionalFilesToIncludeForProject>
6 </Settings>
7</ProjectConfiguration> \ No newline at end of file
diff --git a/src/ext/Util/wixlib/UtilBundleExtension_Platform.wxi b/src/ext/Util/wixlib/UtilBundleExtension_Platform.wxi
new file mode 100644
index 00000000..379c8f57
--- /dev/null
+++ b/src/ext/Util/wixlib/UtilBundleExtension_Platform.wxi
@@ -0,0 +1,10 @@
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
4<Include xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <?include caDecor.wxi ?>
6
7 <Fragment>
8 <BundleExtension Id="$(var.Prefix)UtilBundleExtension$(var.Suffix)" SourceFile="!(bindpath.$(var.platform))utilbe.dll" Name="$(var.Prefix)UtilBundleExtension$(var.Suffix)\utilbe.dll" />
9 </Fragment>
10</Include>
diff --git a/src/ext/Util/wixlib/UtilBundleExtension_arm64.wxs b/src/ext/Util/wixlib/UtilBundleExtension_arm64.wxs
new file mode 100644
index 00000000..b17be031
--- /dev/null
+++ b/src/ext/Util/wixlib/UtilBundleExtension_arm64.wxs
@@ -0,0 +1,7 @@
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
4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <?define platform=arm64 ?>
6 <?include UtilBundleExtension_Platform.wxi ?>
7</Wix>
diff --git a/src/ext/Util/wixlib/UtilBundleExtension_x64.wxs b/src/ext/Util/wixlib/UtilBundleExtension_x64.wxs
new file mode 100644
index 00000000..96c85a5b
--- /dev/null
+++ b/src/ext/Util/wixlib/UtilBundleExtension_x64.wxs
@@ -0,0 +1,7 @@
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
4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <?define platform=x64 ?>
6 <?include UtilBundleExtension_Platform.wxi ?>
7</Wix>
diff --git a/src/ext/Util/wixlib/UtilBundleExtension_x86.wxs b/src/ext/Util/wixlib/UtilBundleExtension_x86.wxs
new file mode 100644
index 00000000..3b458687
--- /dev/null
+++ b/src/ext/Util/wixlib/UtilBundleExtension_x86.wxs
@@ -0,0 +1,7 @@
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
4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <?define platform=x86 ?>
6 <?include UtilBundleExtension_Platform.wxi ?>
7</Wix>
diff --git a/src/ext/Util/wixlib/UtilExtension.wxs b/src/ext/Util/wixlib/UtilExtension.wxs
new file mode 100644
index 00000000..0f445ab4
--- /dev/null
+++ b/src/ext/Util/wixlib/UtilExtension.wxs
@@ -0,0 +1,64 @@
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
4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <?include caDecor.wxi ?>
6 <?include caerr.wxi ?>
7
8 <Fragment>
9 <UI Id="ConfigureUsersErrorText">
10 <Error Id="$(var.msierrUSRFailedUserCreate)" Message="!(loc.msierrUSRFailedUserCreate)" />
11 <Error Id="$(var.msierrUSRFailedUserCreatePswd)" Message="!(loc.msierrUSRFailedUserCreatePswd)" />
12 <Error Id="$(var.msierrUSRFailedUserGroupAdd)" Message="!(loc.msierrUSRFailedUserGroupAdd)" />
13 <Error Id="$(var.msierrUSRFailedGrantLogonAsService)" Message="Failed to grant 'logon as service' rights to user. ([2] [3] [4] [5])" />
14 <Error Id="$(var.msierrUSRFailedUserCreateExists)" Message="!(loc.msierrUSRFailedUserCreateExists)" />
15 </UI>
16 </Fragment>
17
18 <Fragment>
19 <UI Id="ConfigureSmbErrorsText">
20 <Error Id="$(var.msierrSMBFailedCreate)" Message="!(loc.msierrSMBFailedCreate)" />
21 <Error Id="$(var.msierrSMBFailedDrop)" Message="!(loc.msierrSMBFailedDrop)" />
22 </UI>
23 </Fragment>
24
25 <Fragment>
26 <UI Id="PerCounterDataErrorsText">
27 <Error Id="$(var.msierrInstallPerfCounterData)" Message="!(loc.msierrInstallPerfCounterData)" />
28 <Error Id="$(var.msierrUninstallPerfCounterData)" Message="!(loc.msierrUninstallPerfCounterData)" />
29 </UI>
30 </Fragment>
31
32 <Fragment>
33 <UI Id="ConfigurePerfmonErrorsText">
34 <Error Id="$(var.msierrPERFMONFailedRegisterDLL)" Message="!(loc.msierrPERFMONFailedRegisterDLL)" />
35 <Error Id="$(var.msierrPERFMONFailedUnregisterDLL)" Message="!(loc.msierrPERFMONFailedUnregisterDLL)" />
36 </UI>
37 </Fragment>
38
39 <Fragment>
40 <UI Id="SecureObjectsErrors">
41 <Error Id="$(var.msierrSecureObjectsFailedCreateSD)" Message="!(loc.msierrSecureObjectsFailedCreateSD)" />
42 <Error Id="$(var.msierrSecureObjectsFailedSet)" Message="!(loc.msierrSecureObjectsFailedSet)" />
43 <Error Id="$(var.msierrSecureObjectsUnknownType)" Message="!(loc.msierrSecureObjectsUnknownType)" />
44 </UI>
45 </Fragment>
46
47 <Fragment>
48 <UI Id="XmlFileErrorsText">
49 <Error Id="$(var.msierrXmlFileFailedRead)" Message="!(loc.msierrXmlFileFailedRead)" />
50 <Error Id="$(var.msierrXmlFileFailedOpen)" Message="!(loc.msierrXmlFileFailedOpen)" />
51 <Error Id="$(var.msierrXmlFileFailedSelect)" Message="!(loc.msierrXmlFileFailedSelect)" />
52 <Error Id="$(var.msierrXmlFileFailedSave)" Message="!(loc.msierrXmlFileFailedSave)" />
53 </UI>
54 </Fragment>
55
56 <Fragment>
57 <UI Id="XmlConfigErrorsText">
58 <Error Id="$(var.msierrXmlConfigFailedRead)" Message="!(loc.msierrXmlConfigFailedRead)" />
59 <Error Id="$(var.msierrXmlConfigFailedOpen)" Message="!(loc.msierrXmlConfigFailedOpen)" />
60 <Error Id="$(var.msierrXmlConfigFailedSelect)" Message="!(loc.msierrXmlConfigFailedSelect)" />
61 <Error Id="$(var.msierrXmlConfigFailedSave)" Message="!(loc.msierrXmlConfigFailedSave)" />
62 </UI>
63 </Fragment>
64</Wix>
diff --git a/src/ext/Util/wixlib/UtilExtension_Platform.wxi b/src/ext/Util/wixlib/UtilExtension_Platform.wxi
new file mode 100644
index 00000000..913c01b9
--- /dev/null
+++ b/src/ext/Util/wixlib/UtilExtension_Platform.wxi
@@ -0,0 +1,360 @@
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
4<Include xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <?include caDecor.wxi ?>
6
7 <Fragment>
8 <CustomAction Id="$(var.Prefix)FailWhenDeferred$(var.Suffix)" DllEntry="WixFailWhenDeferred" Execute="deferred" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
9
10 <InstallExecuteSequence>
11 <Custom Action="$(var.Prefix)FailWhenDeferred$(var.Suffix)" Before="InstallFinalize" Overridable="yes" Condition="WIXFAILWHENDEFERRED=1 AND VersionNT &gt; 400" />
12 </InstallExecuteSequence>
13 </Fragment>
14
15 <Fragment>
16 <CustomAction Id="$(var.Prefix)WaitForEvent$(var.Suffix)" DllEntry="WixWaitForEvent" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
17
18 <InstallExecuteSequence>
19 <Custom Action="$(var.Prefix)WaitForEvent$(var.Suffix)" Before="InstallFinalize" Overridable="yes" />
20 </InstallExecuteSequence>
21 </Fragment>
22
23 <Fragment>
24 <CustomAction Id="$(var.Prefix)WaitForEventDeferred$(var.Suffix)" DllEntry="WixWaitForEvent" Execute="deferred" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
25
26 <InstallExecuteSequence>
27 <Custom Action="$(var.Prefix)WaitForEventDeferred$(var.Suffix)" After="InstallInitialize" Overridable="yes" />
28 </InstallExecuteSequence>
29 </Fragment>
30
31 <Fragment>
32 <CustomAction Id="$(var.Prefix)ExitEarlyWithSuccess$(var.Suffix)" DllEntry="WixExitEarlyWithSuccess" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
33
34 <InstallExecuteSequence>
35 <Custom Action="$(var.Prefix)ExitEarlyWithSuccess$(var.Suffix)" After="FindRelatedProducts" Overridable="yes" Condition="NEWERVERSIONDETECTED AND VersionNT &gt; 400" />
36 </InstallExecuteSequence>
37 </Fragment>
38
39 <Fragment>
40 <CustomAction Id="$(var.Prefix)RemoveFoldersEx$(var.Suffix)" DllEntry="WixRemoveFoldersEx" Execute="immediate" Return="ignore" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
41
42 <InstallExecuteSequence>
43 <Custom Action="$(var.Prefix)RemoveFoldersEx$(var.Suffix)" Before="CostInitialize" />
44 </InstallExecuteSequence>
45 </Fragment>
46
47 <Fragment>
48 <CustomAction Id="$(var.Prefix)RemoveRegistryKeysEx$(var.Suffix)" DllEntry="WixRemoveRegistryKeysEx" Execute="immediate" Return="ignore" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
49
50 <InstallExecuteSequence>
51 <Custom Action="$(var.Prefix)RemoveRegistryKeysEx$(var.Suffix)" Before="RemoveRegistryValues" />
52 </InstallExecuteSequence>
53 </Fragment>
54
55 <Fragment>
56 <CustomAction Id="$(var.Prefix)BroadcastSettingChange$(var.Suffix)" DllEntry="WixBroadcastSettingChange" Execute="immediate" Return="ignore" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
57
58 <InstallExecuteSequence>
59 <Custom Action="$(var.Prefix)BroadcastSettingChange$(var.Suffix)" After="InstallFinalize" Overridable="yes" />
60 </InstallExecuteSequence>
61 </Fragment>
62
63 <Fragment>
64 <CustomAction Id="$(var.Prefix)BroadcastEnvironmentChange$(var.Suffix)" DllEntry="WixBroadcastEnvironmentChange" Execute="immediate" Return="ignore" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
65
66 <InstallExecuteSequence>
67 <Custom Action="$(var.Prefix)BroadcastEnvironmentChange$(var.Suffix)" After="InstallFinalize" Overridable="yes" />
68 </InstallExecuteSequence>
69 </Fragment>
70
71 <!-- ShellExec custom actions (for when only one is needed; multiple executions need their own IDs) -->
72 <Fragment>
73 <PropertyRef Id="WixShellExecBinaryId" />
74 <CustomAction Id="$(var.Prefix)ShellExecBinary$(var.Suffix)" DllEntry="WixShellExecBinary" Execute="immediate" Return="check" Impersonate="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
75 </Fragment>
76
77 <Fragment>
78 <PropertyRef Id="WixShellExecTarget" />
79 <CustomAction Id="$(var.Prefix)ShellExec$(var.Suffix)" DllEntry="WixShellExec" Execute="immediate" Return="check" Impersonate="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
80 </Fragment>
81
82 <Fragment>
83 <PropertyRef Id="WixUnelevatedShellExecTarget" />
84 <CustomAction Id="$(var.Prefix)UnelevatedShellExec$(var.Suffix)" DllEntry="WixUnelevatedShellExec" Execute="immediate" Return="check" Impersonate="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
85 </Fragment>
86
87 <Fragment>
88 <PropertyRef Id="WixQuietExecCmdLine" />
89 <CustomAction Id="$(var.Prefix)QuietExec$(var.Suffix)" DllEntry="WixQuietExec" Execute="immediate" Return="check" Impersonate="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
90 </Fragment>
91
92 <Fragment>
93 <PropertyRef Id="WixQuietExec64CmdLine" />
94 <CustomAction Id="$(var.Prefix)QuietExec64$(var.Suffix)" DllEntry="WixQuietExec64" Execute="immediate" Return="check" Impersonate="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
95 </Fragment>
96
97 <!-- SilentExec custom actions differ from QtExec in that they do not log the commandline or output of the exe -->
98 <Fragment>
99 <PropertyRef Id="WixSilentExecCmdLine" />
100 <CustomAction Id="$(var.Prefix)SilentExec$(var.Suffix)" DllEntry="WixSilentExec" Execute="immediate" Return="check" Impersonate="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
101 </Fragment>
102
103 <Fragment>
104 <PropertyRef Id="WixSilentExec64CmdLine" />
105 <CustomAction Id="$(var.Prefix)SilentExec64$(var.Suffix)" DllEntry="WixSilentExec64" Execute="immediate" Return="check" Impersonate="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
106 </Fragment>
107
108 <Fragment>
109 <CustomAction Id="$(var.Prefix)CheckRebootRequired$(var.Suffix)" DllEntry="WixCheckRebootRequired" Execute="immediate" Return="ignore" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
110
111 <InstallExecuteSequence>
112 <!-- Condition this so it runs on install and MMode, but not uninstall -->
113 <Custom Action="$(var.Prefix)CheckRebootRequired$(var.Suffix)" After="InstallFinalize" Overridable="yes" Condition="NOT REMOVE~=&quot;ALL&quot; AND VersionNT &gt; 400" />
114 </InstallExecuteSequence>
115 </Fragment>
116
117 <Fragment>
118 <CustomAction Id="$(var.Prefix)CloseApplications$(var.Suffix)" DllEntry="WixCloseApplications" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
119 <CustomAction Id="$(var.Prefix)CloseApplicationsDeferred$(var.Suffix)" DllEntry="WixCloseApplicationsDeferred" Impersonate="no" Execute="deferred" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
120 <CustomActionRef Id="$(var.Prefix)CheckRebootRequired$(var.Suffix)" />
121
122 <InstallExecuteSequence>
123 <Custom Action="$(var.Prefix)CloseApplications$(var.Suffix)" Before="InstallFiles" Overridable="yes" Condition="VersionNT &gt; 400" />
124 </InstallExecuteSequence>
125 </Fragment>
126
127 <Fragment>
128 <CustomAction Id="$(var.Prefix)RegisterRestartResources$(var.Suffix)" DllEntry="WixRegisterRestartResources$(var.Suffix)" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
129
130 <InstallExecuteSequence>
131 <Custom Action="$(var.Prefix)RegisterRestartResources$(var.Suffix)" Before="InstallValidate" Overridable="yes" />
132 </InstallExecuteSequence>
133 </Fragment>
134
135 <Fragment>
136 <UIRef Id="ConfigureUsersErrorText" />
137
138 <CustomAction Id="$(var.Prefix)ConfigureUsers$(var.Suffix)" DllEntry="ConfigureUsers" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
139 <CustomAction Id="$(var.Prefix)CreateUser$(var.Suffix)" DllEntry="CreateUser" Impersonate="no" Execute="deferred" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
140 <CustomAction Id="$(var.Prefix)CreateUserRollback$(var.Suffix)" DllEntry="CreateUserRollback" Impersonate="no" Execute="rollback" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
141 <!-- RemoveUser is a type commit action because it is not possible to rollback the removal of a user -->
142 <CustomAction Id="$(var.Prefix)RemoveUser$(var.Suffix)" DllEntry="RemoveUser" Impersonate="no" Execute="commit" Return="ignore" HideTarget="yes" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
143
144 <InstallExecuteSequence>
145 <Custom Action="$(var.Prefix)ConfigureUsers$(var.Suffix)" Before="InstallFiles" Overridable="yes" Condition="VersionNT &gt; 400" />
146 </InstallExecuteSequence>
147 </Fragment>
148
149 <Fragment>
150 <UIRef Id="ConfigureSmbErrorsText" />
151
152 <CustomAction Id="$(var.Prefix)ConfigureSmbInstall$(var.Suffix)" DllEntry="ConfigureSmbInstall" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
153 <CustomAction Id="$(var.Prefix)ConfigureSmbUninstall$(var.Suffix)" DllEntry="ConfigureSmbUninstall" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
154 <CustomAction Id="$(var.Prefix)CreateSmb$(var.Suffix)" DllEntry="CreateSmb" Impersonate="no" Execute="deferred" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
155 <CustomAction Id="$(var.Prefix)CreateSmbRollback$(var.Suffix)" DllEntry="DropSmb" Impersonate="no" Execute="rollback" Return="ignore" HideTarget="yes" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
156 <CustomAction Id="$(var.Prefix)DropSmb$(var.Suffix)" DllEntry="DropSmb" Impersonate="no" Execute="deferred" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
157 <CustomAction Id="$(var.Prefix)DropSmbRollback$(var.Suffix)" DllEntry="CreateSmb" Impersonate="no" Execute="rollback" Return="ignore" HideTarget="yes" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
158
159 <InstallExecuteSequence>
160 <Custom Action="$(var.Prefix)ConfigureSmbInstall$(var.Suffix)" After="InstallFiles" Overridable="yes" Condition="VersionNT &gt; 400" />
161 <Custom Action="$(var.Prefix)ConfigureSmbUninstall$(var.Suffix)" After="RemoveFiles" Overridable="yes" Condition="VersionNT &gt; 400" />
162 </InstallExecuteSequence>
163 </Fragment>
164
165 <Fragment>
166 <UIRef Id="PerCounterDataErrorsText" />
167
168 <CustomAction Id="$(var.Prefix)InstallPerfCounterData$(var.Suffix)" DllEntry="InstallPerfCounterData" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
169 <CustomAction Id="$(var.Prefix)UninstallPerfCounterData$(var.Suffix)" DllEntry="UninstallPerfCounterData" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
170 <CustomAction Id="$(var.Prefix)RegisterPerfCounterData$(var.Suffix)" DllEntry="RegisterPerfCounterData" Impersonate="no" Execute="deferred" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
171 <CustomAction Id="$(var.Prefix)UnregisterPerfCounterData$(var.Suffix)" DllEntry="UnregisterPerfCounterData" Impersonate="no" Execute="deferred" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
172 <CustomAction Id="$(var.Prefix)RollbackRegisterPerfCounterData$(var.Suffix)" DllEntry="UnregisterPerfCounterData" Impersonate="no" Execute="rollback" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
173 <CustomAction Id="$(var.Prefix)RollbackUnregisterPerfCounterData$(var.Suffix)" DllEntry="RegisterPerfCounterData" Impersonate="no" Execute="rollback" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
174
175 <InstallExecuteSequence>
176 <Custom Action="$(var.Prefix)InstallPerfCounterData$(var.Suffix)" After="WriteRegistryValues" Overridable="yes" Condition="VersionNT &gt; 400" />
177 <Custom Action="$(var.Prefix)UninstallPerfCounterData$(var.Suffix)" Before="RemoveRegistryValues" Overridable="yes" Condition="VersionNT &gt; 400" />
178 </InstallExecuteSequence>
179 </Fragment>
180
181 <Fragment>
182 <UIRef Id="ConfigurePerfmonErrorsText" />
183
184 <CustomAction Id="$(var.Prefix)ConfigurePerfmonInstall$(var.Suffix)" DllEntry="ConfigurePerfmonInstall" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
185 <CustomAction Id="$(var.Prefix)ConfigurePerfmonUninstall$(var.Suffix)" DllEntry="ConfigurePerfmonUninstall" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
186 <CustomAction Id="$(var.Prefix)RegisterPerfmon$(var.Suffix)" DllEntry="RegisterPerfmon" Impersonate="no" Execute="deferred" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
187 <CustomAction Id="$(var.Prefix)UnregisterPerfmon$(var.Suffix)" DllEntry="UnregisterPerfmon" Impersonate="no" Execute="deferred" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
188 <CustomAction Id="$(var.Prefix)RollbackRegisterPerfmon$(var.Suffix)" DllEntry="UnregisterPerfmon" Impersonate="no" Execute="rollback" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
189 <CustomAction Id="$(var.Prefix)RollbackUnregisterPerfmon$(var.Suffix)" DllEntry="RegisterPerfmon" Impersonate="no" Execute="rollback" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
190
191 <InstallExecuteSequence>
192 <Custom Action="$(var.Prefix)ConfigurePerfmonInstall$(var.Suffix)" After="WriteRegistryValues" Overridable="yes" Condition="VersionNT &gt; 400" />
193 <Custom Action="$(var.Prefix)ConfigurePerfmonUninstall$(var.Suffix)" Before="RemoveRegistryValues" Overridable="yes" Condition="VersionNT &gt; 400" />
194 </InstallExecuteSequence>
195 </Fragment>
196
197 <Fragment>
198 <CustomAction Id="$(var.Prefix)ConfigurePerfmonManifestRegister$(var.Suffix)" DllEntry="ConfigurePerfmonManifestRegister" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
199 <CustomAction Id="$(var.Prefix)ConfigurePerfmonManifestUnregister$(var.Suffix)" DllEntry="ConfigurePerfmonManifestUnregister" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
200 <CustomAction Id="$(var.Prefix)RegisterPerfmonManifest$(var.Suffix)" DllEntry="WixQuietExec" Impersonate="no" Execute="deferred" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
201 <CustomAction Id="$(var.Prefix)UnregisterPerfmonManifest$(var.Suffix)" DllEntry="WixQuietExec" Impersonate="no" Execute="deferred" Return="ignore" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
202 <CustomAction Id="$(var.Prefix)RollbackRegisterPerfmonManifest$(var.Suffix)" DllEntry="WixQuietExec" Impersonate="no" Execute="rollback" Return="ignore" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
203 <CustomAction Id="$(var.Prefix)RollbackUnregisterPerfmonManifest$(var.Suffix)" DllEntry="WixQuietExec" Impersonate="no" Execute="rollback" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
204
205 <InstallExecuteSequence>
206 <Custom Action="$(var.Prefix)ConfigurePerfmonManifestRegister$(var.Suffix)" After="InstallFiles" Overridable="yes" Condition="VersionNT &gt; 400" />
207 <Custom Action="$(var.Prefix)ConfigurePerfmonManifestUnregister$(var.Suffix)" After="RemoveRegistryValues" Overridable="yes" Condition="VersionNT &gt; 400" />
208 </InstallExecuteSequence>
209 </Fragment>
210
211 <Fragment>
212 <CustomAction Id="$(var.Prefix)ConfigureEventManifestRegister$(var.Suffix)" DllEntry="ConfigureEventManifestRegister" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
213 <CustomAction Id="$(var.Prefix)ConfigureEventManifestUnregister$(var.Suffix)" DllEntry="ConfigureEventManifestUnregister" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
214 <CustomAction Id="$(var.Prefix)RegisterEventManifest$(var.Suffix)" DllEntry="WixQuietExec" Impersonate="no" Execute="deferred" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
215 <CustomAction Id="$(var.Prefix)UnregisterEventManifest$(var.Suffix)" DllEntry="WixQuietExec" Impersonate="no" Execute="deferred" Return="ignore" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
216 <CustomAction Id="$(var.Prefix)RollbackRegisterEventManifest$(var.Suffix)" DllEntry="WixQuietExec" Impersonate="no" Execute="rollback" Return="ignore" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
217 <CustomAction Id="$(var.Prefix)RollbackUnregisterEventManifest$(var.Suffix)" DllEntry="WixQuietExec" Impersonate="no" Execute="rollback" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
218
219 <InstallExecuteSequence>
220 <Custom Action="$(var.Prefix)ConfigureEventManifestRegister$(var.Suffix)" After="$(var.Prefix)SchedXmlFile$(var.Suffix)" Overridable="yes" Condition="VersionNT &gt; 400" />
221 <Custom Action="$(var.Prefix)ConfigureEventManifestUnregister$(var.Suffix)" After="RemoveRegistryValues" Overridable="yes" Condition="VersionNT &gt; 400" />
222 </InstallExecuteSequence>
223 </Fragment>
224
225 <Fragment>
226 <CustomAction Id="$(var.Prefix)SchedServiceConfig$(var.Suffix)" DllEntry="SchedServiceConfig" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
227 <CustomAction Id="$(var.Prefix)ExecServiceConfig$(var.Suffix)" DllEntry="ExecServiceConfig" Execute="deferred" Impersonate="no" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
228 <CustomAction Id="$(var.Prefix)RollbackServiceConfig$(var.Suffix)" DllEntry="RollbackServiceConfig" Execute="rollback" Impersonate="no" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
229
230 <InstallExecuteSequence>
231 <!-- Condition this so it runs on install and MMode, but not uninstall -->
232 <Custom Action="$(var.Prefix)SchedServiceConfig$(var.Suffix)" After="InstallServices" Overridable="yes" Condition="NOT REMOVE~=&quot;ALL&quot; AND VersionNT &gt; 400" />
233 </InstallExecuteSequence>
234 </Fragment>
235
236 <Fragment>
237 <CustomAction Id="$(var.Prefix)TouchFileDuringInstall$(var.Suffix)" DllEntry="WixTouchFileDuringInstall" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
238 <CustomAction Id="$(var.Prefix)TouchFileDuringUninstall$(var.Suffix)" DllEntry="WixTouchFileDuringUninstall" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
239 <CustomAction Id="$(var.Prefix)ExecuteTouchFile$(var.Suffix)" DllEntry="WixExecuteTouchFile" Execute="deferred" Impersonate="no" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
240 <CustomAction Id="$(var.Prefix)RollbackTouchFile$(var.Suffix)" DllEntry="WixExecuteTouchFile" Execute="rollback" Impersonate="no" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
241
242 <InstallExecuteSequence>
243 <Custom Action="$(var.Prefix)TouchFileDuringUninstall" Before="RemoveFiles" Overridable="yes" />
244 <Custom Action="$(var.Prefix)TouchFileDuringInstall" After="InstallFiles" Overridable="yes" />
245 </InstallExecuteSequence>
246 </Fragment>
247
248 <Fragment>
249 <UIRef Id="XmlFileErrorsText" />
250
251 <CustomAction Id="$(var.Prefix)SchedXmlFile$(var.Suffix)" DllEntry="SchedXmlFile" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
252 <CustomAction Id="$(var.Prefix)ExecXmlFile$(var.Suffix)" DllEntry="ExecXmlFile" Execute="deferred" Impersonate="no" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
253 <CustomAction Id="$(var.Prefix)ExecXmlFileRollback$(var.Suffix)" DllEntry="ExecXmlFileRollback" Execute="rollback" Impersonate="no" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
254
255 <InstallExecuteSequence>
256 <Custom Action="$(var.Prefix)SchedXmlFile$(var.Suffix)" After="DuplicateFiles" Overridable="yes" Condition="VersionNT &gt; 400" />
257 </InstallExecuteSequence>
258 </Fragment>
259
260 <Fragment>
261 <UIRef Id="XmlConfigErrorsText" />
262
263 <CustomAction Id="$(var.Prefix)SchedXmlConfig$(var.Suffix)" DllEntry="SchedXmlConfig" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
264 <CustomAction Id="$(var.Prefix)ExecXmlConfig$(var.Suffix)" DllEntry="ExecXmlConfig" Execute="deferred" Impersonate="no" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
265 <CustomAction Id="$(var.Prefix)ExecXmlConfigRollback$(var.Suffix)" DllEntry="ExecXmlConfigRollback" Execute="rollback" Impersonate="no" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
266
267 <InstallExecuteSequence>
268 <Custom Action="$(var.Prefix)SchedXmlConfig$(var.Suffix)" After="DuplicateFiles" Overridable="yes" Condition="VersionNT &gt; 400" />
269 </InstallExecuteSequence>
270 </Fragment>
271
272 <Fragment>
273 <CustomAction Id="$(var.Prefix)SchedInternetShortcuts$(var.Suffix)" DllEntry="WixSchedInternetShortcuts" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
274 <CustomAction Id="$(var.Prefix)RollbackInternetShortcuts$(var.Suffix)" DllEntry="WixRollbackInternetShortcuts" Impersonate="no" Execute="rollback" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
275 <CustomAction Id="$(var.Prefix)CreateInternetShortcuts$(var.Suffix)" DllEntry="WixCreateInternetShortcuts" Impersonate="no" Execute="deferred" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
276
277 <InstallExecuteSequence>
278 <Custom Action="$(var.Prefix)SchedInternetShortcuts$(var.Suffix)" Before="RemoveFolders" Overridable="yes" Condition="VersionNT &gt; 400" />
279 <Custom Action="$(var.Prefix)RollbackInternetShortcuts$(var.Suffix)" Before="$(var.Prefix)CreateInternetShortcuts$(var.Suffix)" Overridable="yes" Condition="VersionNT &gt; 400" />
280 <Custom Action="$(var.Prefix)CreateInternetShortcuts$(var.Suffix)" After="CreateShortcuts" Overridable="yes" Condition="VersionNT &gt; 400" />
281 </InstallExecuteSequence>
282 </Fragment>
283
284 <Fragment>
285 <UIRef Id="SecureObjectsErrors" />
286
287 <CustomAction Id="$(var.Prefix)SchedSecureObjects$(var.Suffix)" DllEntry="SchedSecureObjects" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
288 <CustomAction Id="$(var.Prefix)SchedSecureObjectsRollback$(var.Suffix)" DllEntry="SchedSecureObjectsRollback" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
289 <CustomAction Id="$(var.Prefix)ExecSecureObjects$(var.Suffix)" DllEntry="ExecSecureObjects" Execute="deferred" Impersonate="no" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
290 <CustomAction Id="$(var.Prefix)ExecSecureObjectsRollback$(var.Suffix)" DllEntry="ExecSecureObjectsRollback" Execute="rollback" Impersonate="no" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
291
292 <InstallExecuteSequence>
293 <!-- Condition this so it runs on install and MMode, but not uninstall -->
294 <Custom Action="$(var.Prefix)SchedSecureObjects$(var.Suffix)" After="InstallServices" Overridable="yes" Condition="NOT REMOVE~=&quot;ALL&quot; AND VersionNT &gt; 400" />
295 <Custom Action="$(var.Prefix)SchedSecureObjectsRollback$(var.Suffix)" After="UnpublishFeatures" Overridable="yes" Condition="VersionNT &gt; 400" />
296 </InstallExecuteSequence>
297 </Fragment>
298
299 <Fragment>
300 <CustomAction Id="$(var.Prefix)SchedFormatFiles$(var.Suffix)" DllEntry="WixSchedFormatFiles" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
301 <CustomAction Id="$(var.Prefix)ExecFormatFiles$(var.Suffix)" DllEntry="WixExecFormatFiles" Execute="deferred" Impersonate="no" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
302 <CustomAction Id="$(var.Prefix)RollbackFormatFiles$(var.Suffix)" DllEntry="WixExecFormatFiles" Execute="rollback" Impersonate="no" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
303
304 <InstallExecuteSequence>
305 <Custom Action="$(var.Prefix)SchedFormatFiles$(var.Suffix)" After="InstallFiles" />
306 </InstallExecuteSequence>
307 </Fragment>
308
309 <Fragment>
310 <CustomAction Id="$(var.Prefix)QueryOsInfo$(var.Suffix)" DllEntry="WixQueryOsInfo" Execute="firstSequence" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
311
312 <InstallExecuteSequence>
313 <Custom Action="$(var.Prefix)QueryOsInfo$(var.Suffix)" After="AppSearch" Overridable="yes" Condition="VersionNT &gt; 400 OR (VersionNT = 400 AND ServicePackLevel &gt; 3)" />
314 </InstallExecuteSequence>
315
316 <InstallUISequence>
317 <Custom Action="$(var.Prefix)QueryOsInfo$(var.Suffix)" After="AppSearch" Overridable="yes" Condition="VersionNT &gt; 400 OR (VersionNT = 400 AND ServicePackLevel &gt; 3)" />
318 </InstallUISequence>
319 </Fragment>
320
321 <Fragment>
322 <CustomAction Id="$(var.Prefix)QueryOsDirs$(var.Suffix)" DllEntry="WixQueryOsDirs" Execute="firstSequence" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
323
324 <InstallExecuteSequence>
325 <Custom Action="$(var.Prefix)QueryOsDirs$(var.Suffix)" After="AppSearch" Overridable="yes" Condition="VersionNT &gt; 400 OR (VersionNT = 400 AND ServicePackLevel &gt; 3)" />
326 </InstallExecuteSequence>
327
328 <InstallUISequence>
329 <Custom Action="$(var.Prefix)QueryOsDirs$(var.Suffix)" After="AppSearch" Overridable="yes" Condition="VersionNT &gt; 400 OR (VersionNT = 400 AND ServicePackLevel &gt; 3)" />
330 </InstallUISequence>
331 </Fragment>
332
333 <Fragment>
334 <CustomAction Id="$(var.Prefix)QueryOsWellKnownSID$(var.Suffix)" DllEntry="WixQueryOsWellKnownSID" Execute="firstSequence" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
335
336 <InstallExecuteSequence>
337 <Custom Action="$(var.Prefix)QueryOsWellKnownSID$(var.Suffix)" After="AppSearch" Overridable="yes" Condition="VersionNT &gt; 400 OR (VersionNT = 400 AND ServicePackLevel &gt; 3)" />
338 </InstallExecuteSequence>
339
340 <InstallUISequence>
341 <Custom Action="$(var.Prefix)QueryOsWellKnownSID$(var.Suffix)" After="AppSearch" Overridable="yes" Condition="VersionNT &gt; 400 OR (VersionNT = 400 AND ServicePackLevel &gt; 3)" />
342 </InstallUISequence>
343 </Fragment>
344
345 <Fragment>
346 <CustomAction Id="$(var.Prefix)QueryOsDriverInfo$(var.Suffix)" DllEntry="WixQueryOsDriverInfo" Execute="firstSequence" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
347
348 <InstallExecuteSequence>
349 <Custom Action="$(var.Prefix)QueryOsDriverInfo$(var.Suffix)" After="AppSearch" Overridable="yes" Condition="VersionNT &gt; 400 OR (VersionNT = 400 AND ServicePackLevel &gt; 3)" />
350 </InstallExecuteSequence>
351
352 <InstallUISequence>
353 <Custom Action="$(var.Prefix)QueryOsDriverInfo$(var.Suffix)" After="AppSearch" Overridable="yes" Condition="VersionNT &gt; 400 OR (VersionNT = 400 AND ServicePackLevel &gt; 3)" />
354 </InstallUISequence>
355 </Fragment>
356
357 <Fragment>
358 <Binary Id="$(var.Prefix)UtilCA$(var.Suffix)" SourceFile="!(bindpath.$(var.platform))utilca.dll" />
359 </Fragment>
360</Include>
diff --git a/src/ext/Util/wixlib/UtilExtension_arm64.wxs b/src/ext/Util/wixlib/UtilExtension_arm64.wxs
new file mode 100644
index 00000000..b9dc73b8
--- /dev/null
+++ b/src/ext/Util/wixlib/UtilExtension_arm64.wxs
@@ -0,0 +1,7 @@
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
4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <?define platform=arm64 ?>
6 <?include UtilExtension_Platform.wxi ?>
7</Wix>
diff --git a/src/ext/Util/wixlib/UtilExtension_x64.wxs b/src/ext/Util/wixlib/UtilExtension_x64.wxs
new file mode 100644
index 00000000..40cdf306
--- /dev/null
+++ b/src/ext/Util/wixlib/UtilExtension_x64.wxs
@@ -0,0 +1,7 @@
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
4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <?define platform=x64 ?>
6 <?include UtilExtension_Platform.wxi ?>
7</Wix>
diff --git a/src/ext/Util/wixlib/UtilExtension_x86.wxs b/src/ext/Util/wixlib/UtilExtension_x86.wxs
new file mode 100644
index 00000000..bd0fa562
--- /dev/null
+++ b/src/ext/Util/wixlib/UtilExtension_x86.wxs
@@ -0,0 +1,7 @@
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
4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <?define platform=x86 ?>
6 <?include UtilExtension_Platform.wxi ?>
7</Wix>
diff --git a/src/ext/Util/wixlib/caDecor.wxi b/src/ext/Util/wixlib/caDecor.wxi
new file mode 100644
index 00000000..b1711518
--- /dev/null
+++ b/src/ext/Util/wixlib/caDecor.wxi
@@ -0,0 +1,39 @@
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
4<Include xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <?ifdef Prefix ?>
6 <?undef Prefix ?>
7 <?endif?>
8
9 <?define Prefix="Wix4" ?>
10
11 <?ifndef platform ?>
12 <?define platform="x86" ?>
13 <?endif?>
14
15 <?if $(var.platform)="" ?>
16 <?undef platform ?>
17 <?define platform="x86" ?>
18 <?endif?>
19
20 <?ifdef Suffix ?>
21 <?undef Suffix ?>
22 <?endif?>
23
24 <?if $(var.platform)~="x86" ?>
25 <?define Suffix="_X86" ?>
26 <?endif?>
27
28 <?if $(var.platform)~="x64" ?>
29 <?define Suffix="_X64" ?>
30 <?endif?>
31
32 <?if $(var.platform)~="arm" ?>
33 <?define Suffix="_A32" ?>
34 <?endif?>
35
36 <?if $(var.platform)~="arm64" ?>
37 <?define Suffix="_A64" ?>
38 <?endif?>
39</Include>
diff --git a/src/ext/Util/wixlib/caerr.wxi b/src/ext/Util/wixlib/caerr.wxi
new file mode 100644
index 00000000..ff7ec121
--- /dev/null
+++ b/src/ext/Util/wixlib/caerr.wxi
@@ -0,0 +1,96 @@
1<Include xmlns="http://wixtoolset.org/schemas/v4/wxs">
2 <?define msierrSecureObjectsFailedCreateSD = 25520?>
3 <?define msierrSecureObjectsFailedSet = 25521?>
4 <?define msierrSecureObjectsUnknownType = 25522?>
5 <?define msierrXmlFileFailedRead = 25530?>
6 <?define msierrXmlFileFailedOpen = 25531?>
7 <?define msierrXmlFileFailedSelect = 25532?>
8 <?define msierrXmlFileFailedSave = 25533?>
9 <?define msierrXmlConfigFailedRead = 25540?>
10 <?define msierrXmlConfigFailedOpen = 25541?>
11 <?define msierrXmlConfigFailedSelect = 25542?>
12 <?define msierrXmlConfigFailedSave = 25543?>
13 <?define msierrFirewallCannotConnect = 25580?>
14 <?define msierrIISCannotConnect = 26001?>
15 <?define msierrIISFailedReadWebSite = 26002?>
16 <?define msierrIISFailedReadWebDirs = 26003?>
17 <?define msierrIISFailedReadVDirs = 26004?>
18 <?define msierrIISFailedReadFilters = 26005?>
19 <?define msierrIISFailedReadAppPool = 26006?>
20 <?define msierrIISFailedReadMimeMap = 26007?>
21 <?define msierrIISFailedReadProp = 26008?>
22 <?define msierrIISFailedReadWebSvcExt = 26009?>
23 <?define msierrIISFailedReadWebError = 26010?>
24 <?define msierrIISFailedReadHttpHeader = 26011?>
25 <?define msierrIISFailedSchedTransaction = 26031?>
26 <?define msierrIISFailedSchedInstallWebs = 26032?>
27 <?define msierrIISFailedSchedInstallWebDirs = 26033?>
28 <?define msierrIISFailedSchedInstallVDirs = 26034?>
29 <?define msierrIISFailedSchedInstallFilters = 26035?>
30 <?define msierrIISFailedSchedInstallAppPool = 26036?>
31 <?define msierrIISFailedSchedInstallProp = 26037?>
32 <?define msierrIISFailedSchedInstallWebSvcExt = 26038?>
33 <?define msierrIISFailedSchedUninstallWebs = 26051?>
34 <?define msierrIISFailedSchedUninstallWebDirs = 26052?>
35 <?define msierrIISFailedSchedUninstallVDirs = 26053?>
36 <?define msierrIISFailedSchedUninstallFilters = 26054?>
37 <?define msierrIISFailedSchedUninstallAppPool = 26055?>
38 <?define msierrIISFailedSchedUninstallProp = 26056?>
39 <?define msierrIISFailedSchedUninstallWebSvcExt = 26057?>
40 <?define msierrIISFailedStartTransaction = 26101?>
41 <?define msierrIISFailedOpenKey = 26102?>
42 <?define msierrIISFailedCreateKey = 26103?>
43 <?define msierrIISFailedWriteData = 26104?>
44 <?define msierrIISFailedCreateApp = 26105?>
45 <?define msierrIISFailedDeleteKey = 26106?>
46 <?define msierrIISFailedDeleteApp = 26107?>
47 <?define msierrIISFailedDeleteValue = 26108?>
48 <?define msierrIISFailedCommitInUse = 26109?>
49 <?define msierrSQLFailedCreateDatabase = 26201?>
50 <?define msierrSQLFailedDropDatabase = 26202?>
51 <?define msierrSQLFailedConnectDatabase = 26203?>
52 <?define msierrSQLFailedExecString = 26204?>
53 <?define msierrSQLDatabaseAlreadyExists = 26205?>
54 <?define msierrPERFMONFailedRegisterDLL = 26251?>
55 <?define msierrPERFMONFailedUnregisterDLL = 26252?>
56 <?define msierrInstallPerfCounterData = 26253?>
57 <?define msierrUninstallPerfCounterData = 26254?>
58 <?define msierrSMBFailedCreate = 26301?>
59 <?define msierrSMBFailedDrop = 26302?>
60 <?define msierrCERTFailedOpen = 26351?>
61 <?define msierrCERTFailedAdd = 26352?>
62 <?define msierrUSRFailedUserCreate = 26401?>
63 <?define msierrUSRFailedUserCreatePswd = 26402?>
64 <?define msierrUSRFailedUserGroupAdd = 26403?>
65 <?define msierrUSRFailedUserCreateExists = 26404?>
66 <?define msierrUSRFailedGrantLogonAsService = 26405?>
67 <?define msierrDependencyMissingDependencies = 26451?>
68 <?define msierrDependencyHasDependents = 26452?>
69 <?define msierrDotNetRuntimeRequired = 27000?>
70 <?define msierrComPlusCannotConnect = 28001?>
71 <?define msierrComPlusPartitionReadFailed = 28002?>
72 <?define msierrComPlusPartitionRoleReadFailed = 28003?>
73 <?define msierrComPlusUserInPartitionRoleReadFailed = 28004?>
74 <?define msierrComPlusPartitionUserReadFailed = 28005?>
75 <?define msierrComPlusApplicationReadFailed = 28006?>
76 <?define msierrComPlusApplicationRoleReadFailed = 28007?>
77 <?define msierrComPlusUserInApplicationRoleReadFailed = 28008?>
78 <?define msierrComPlusAssembliesReadFailed = 28009?>
79 <?define msierrComPlusSubscriptionReadFailed = 28010?>
80 <?define msierrComPlusPartitionDependency = 28011?>
81 <?define msierrComPlusPartitionNotFound = 28012?>
82 <?define msierrComPlusPartitionIdConflict = 28013?>
83 <?define msierrComPlusPartitionNameConflict = 28014?>
84 <?define msierrComPlusApplicationDependency = 28015?>
85 <?define msierrComPlusApplicationNotFound = 28016?>
86 <?define msierrComPlusApplicationIdConflict = 28017?>
87 <?define msierrComPlusApplicationNameConflict = 28018?>
88 <?define msierrComPlusApplicationRoleDependency = 28019?>
89 <?define msierrComPlusApplicationRoleNotFound = 28020?>
90 <?define msierrComPlusApplicationRoleConflict = 28021?>
91 <?define msierrComPlusAssemblyDependency = 28022?>
92 <?define msierrComPlusSubscriptionIdConflict = 28023?>
93 <?define msierrComPlusSubscriptionNameConflict = 28024?>
94 <?define msierrComPlusFailedLookupNames = 28025?>
95 <?define msierrMsmqCannotConnect = 28101?>
96</Include> \ No newline at end of file
diff --git a/src/ext/Util/wixlib/de-de.wxl b/src/ext/Util/wixlib/de-de.wxl
new file mode 100644
index 00000000..65785a3b
--- /dev/null
+++ b/src/ext/Util/wixlib/de-de.wxl
@@ -0,0 +1,32 @@
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
4<WixLocalization Culture="de-de" xmlns="http://wixtoolset.org/schemas/v4/wxl">
5 <String Id="msierrUSRFailedUserCreate" Overridable="yes">Konnte den Benutzer nicht anlegen. ([2] [3] [4] [5])</String>
6 <String Id="msierrUSRFailedUserCreatePswd" Overridable="yes">Konnte den Benutzer auf Grund eines falschen Passwortes nicht anlegen. ([2] [3] [4] [5])</String>
7 <String Id="msierrUSRFailedUserGroupAdd" Overridable="yes">Konnte Benutzer nicht zur Gruppe hinzufügen. ([2] [3] [4] [5])</String>
8 <String Id="msierrUSRFailedUserCreateExists" Overridable="yes">Konnte den Benutzer nicht anlegen, da er bereits existierte. ([2] [3] [4] [5])</String>
9
10 <String Id="msierrSMBFailedCreate" Overridable="yes">Konnte Netzwerkfreigabe nicht anlegen. ([2] [3] [4] [5])</String>
11 <String Id="msierrSMBFailedDrop" Overridable="yes">Konnte Netzwerkfreigabe nicht entfernen. ([2] [3] [4] [5])</String>
12
13 <String Id="msierrPERFMONFailedRegisterDLL" Overridable="yes">Konnte die DLL nicht für PerfMon registrieren. ([2] [3] [4] [5])</String>
14 <String Id="msierrPERFMONFailedUnregisterDLL" Overridable="yes">Konnte die DLL nicht für PerfMon deregistrieren. ([2] [3] [4] [5])</String>
15
16 <String Id="msierrInstallPerfCounterData" Overridable="yes">Konnte die Daten der Leistungsüberwachung (performance counters) nicht installieren. ([2] [3] [4] [5])</String>
17 <String Id="msierrUninstallPerfCounterData" Overridable="yes">Konnte die Daten der Leistungsüberwachung (performance counters) nicht deinstallieren. ([2] [3] [4] [5])</String>
18
19 <String Id="msierrSecureObjectsFailedCreateSD" Overridable="yes">Konnte keinen Security Descriptor für [3]\[4] erstellen, System Fehler: [2]</String>
20 <String Id="msierrSecureObjectsFailedSet" Overridable="yes">Konnte keinen Security Descriptor für das Objekt [3] erstellen, System Fehler: [2]</String>
21 <String Id="msierrSecureObjectsUnknownType" Overridable="yes">Unbekannter Objekt Typ [3], System Fehler: [2]</String>
22
23 <String Id="msierrXmlFileFailedRead" Overridable="yes">Beim Lesen der XML Dateien trat ein Fehler auf.</String>
24 <String Id="msierrXmlFileFailedOpen" Overridable="yes">Konnte XML Datei [3] nicht öffnen, System Fehler: [2]</String>
25 <String Id="msierrXmlFileFailedSelect" Overridable="yes">Konnte Knoten [3] in der XML Datei [4] nicht finden, System Fehler: [2]</String>
26 <String Id="msierrXmlFileFailedSave" Overridable="yes">Beim Speichern der Änderungen an der XML Datei [3] trat ein Fehler auf, System Fehler: [2]</String>
27
28 <String Id="msierrXmlConfigFailedRead" Overridable="yes">Bei der Konfiguration der XML Dateien trat ein Fehler auf.</String>
29 <String Id="msierrXmlConfigFailedOpen" Overridable="yes">Konnte XML Datei [3] nicht öffnen, System Fehler: [2]</String>
30 <String Id="msierrXmlConfigFailedSelect" Overridable="yes">Konnte Knoten [3] in der XML Datei [4] nicht finden, System Fehler: [2]</String>
31 <String Id="msierrXmlConfigFailedSave" Overridable="yes">Beim Speichern der Änderungen an der XML Datei [3] trat ein Fehler auf, System Fehler: [2]</String>
32</WixLocalization>
diff --git a/src/ext/Util/wixlib/en-us.wxl b/src/ext/Util/wixlib/en-us.wxl
new file mode 100644
index 00000000..e8b146a4
--- /dev/null
+++ b/src/ext/Util/wixlib/en-us.wxl
@@ -0,0 +1,32 @@
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
4<WixLocalization Culture="en-us" xmlns="http://wixtoolset.org/schemas/v4/wxl">
5 <String Id="msierrUSRFailedUserCreate" Overridable="yes">Failed to create user. ([2] [3] [4] [5])</String>
6 <String Id="msierrUSRFailedUserCreatePswd" Overridable="yes">Failed to create user due to invalid password. ([2] [3] [4] [5])</String>
7 <String Id="msierrUSRFailedUserGroupAdd" Overridable="yes">Failed to add user to group. ([2] [3] [4] [5])</String>
8 <String Id="msierrUSRFailedUserCreateExists" Overridable="yes">Failed to create user because it already exists. ([2] [3] [4] [5])</String>
9
10 <String Id="msierrSMBFailedCreate" Overridable="yes">Failed to create network share. ([2] [3] [4] [5])</String>
11 <String Id="msierrSMBFailedDrop" Overridable="yes">Failed to drop network share. ([2] [3] [4] [5])</String>
12
13 <String Id="msierrPERFMONFailedRegisterDLL" Overridable="yes">Failed to register DLL with PerfMon. ([2] [3] [4] [5])</String>
14 <String Id="msierrPERFMONFailedUnregisterDLL" Overridable="yes">Failed to unregister DLL with PerfMon. ([2] [3] [4] [5])</String>
15
16 <String Id="msierrInstallPerfCounterData" Overridable="yes">Failed to install performance counters. ([2] [3] [4] [5])</String>
17 <String Id="msierrUninstallPerfCounterData" Overridable="yes">Failed to uninstall performance counters. ([2] [3] [4] [5])</String>
18
19 <String Id="msierrSecureObjectsFailedCreateSD" Overridable="yes">Failed to create security descriptor for [3]\[4], system error: [2]</String>
20 <String Id="msierrSecureObjectsFailedSet" Overridable="yes">Failed to set security descriptor on object [3], system error: [2]</String>
21 <String Id="msierrSecureObjectsUnknownType" Overridable="yes">Unknown Object Type [3], system error: [2]</String>
22
23 <String Id="msierrXmlFileFailedRead" Overridable="yes">There was a failure while configuring XML files.</String>
24 <String Id="msierrXmlFileFailedOpen" Overridable="yes">Failed to open XML file [3], system error: [2]</String>
25 <String Id="msierrXmlFileFailedSelect" Overridable="yes">Failed to find node: [3] in XML file: [4], system error: [2]</String>
26 <String Id="msierrXmlFileFailedSave" Overridable="yes">Failed to save changes to XML file [3], system error: [2]</String>
27
28 <String Id="msierrXmlConfigFailedRead" Overridable="yes">There was a failure while configuring XML files.</String>
29 <String Id="msierrXmlConfigFailedOpen" Overridable="yes">Failed to open XML file [3], system error: [2]</String>
30 <String Id="msierrXmlConfigFailedSelect" Overridable="yes">Failed to find node: [3] in XML file: [4], system error: [2]</String>
31 <String Id="msierrXmlConfigFailedSave" Overridable="yes">Failed to save changes to XML file [3], system error: [2]</String>
32</WixLocalization>
diff --git a/src/ext/Util/wixlib/es-es.wxl b/src/ext/Util/wixlib/es-es.wxl
new file mode 100644
index 00000000..ca5ab8bb
--- /dev/null
+++ b/src/ext/Util/wixlib/es-es.wxl
@@ -0,0 +1,31 @@
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<WixLocalization Culture="es-es" xmlns="http://wixtoolset.org/schemas/v4/wxl">
4 <String Id="msierrUSRFailedUserCreate" Overridable="yes">La creación del usuario ha fracasado. ([2] [3] [4] [5])</String>
5 <String Id="msierrUSRFailedUserCreatePswd" Overridable="yes">La creación del usuario ha fracasado porque la contraseña es incorrecta. ([2] [3] [4] [5])</String>
6 <String Id="msierrUSRFailedUserGroupAdd" Overridable="yes">El aditamento del usuario al grupo ha fracasado. ([2] [3] [4] [5])</String>
7 <String Id="msierrUSRFailedUserCreateExists" Overridable="yes">La creación del usuario ha fracasado porque ya existe. ([2] [3] [4] [5])</String>
8
9 <String Id="msierrSMBFailedCreate" Overridable="yes">La creación de la red compartida ha fracasado. ([2] [3] [4] [5])</String>
10 <String Id="msierrSMBFailedDrop" Overridable="yes">La eliminación de la red compartida ha fracasado. ([2] [3] [4] [5])</String>
11
12 <String Id="msierrPERFMONFailedRegisterDLL" Overridable="yes">La inscripción al registro de la DLL con PerfMon ha fracasado. ([2] [3] [4] [5])</String>
13 <String Id="msierrPERFMONFailedUnregisterDLL" Overridable="yes">La cancelación de la inscripción al registro de la DLL con PerfMon ha fracasado. ([2] [3] [4] [5])</String>
14
15 <String Id="msierrInstallPerfCounterData" Overridable="yes">La instalación de los contadores de rendimiento ha fracasado. ([2] [3] [4] [5])</String>
16 <String Id="msierrUninstallPerfCounterData" Overridable="yes">La desinstalación de los contadores de rendimiento ha fracasado. ([2] [3] [4] [5])</String>
17
18 <String Id="msierrSecureObjectsFailedCreateSD" Overridable="yes">La creación de los ACLs ha fracasado por [3]\[4], error del sistema : [2]</String>
19 <String Id="msierrSecureObjectsFailedSet" Overridable="yes">El posicionamiento de los ACLs por el objecto [3] ha fracasado, error del sistema: [2]</String>
20 <String Id="msierrSecureObjectsUnknownType" Overridable="yes">Tipo de objecto no conocido [3], error del sistema: [2]</String>
21
22 <String Id="msierrXmlFileFailedRead" Overridable="yes">Un problema ha aparecido durante la configuración de los ficheros XML.</String>
23 <String Id="msierrXmlFileFailedOpen" Overridable="yes">Fracaso de la apertura de los ficheros XML [3], error del sistema: [2]</String>
24 <String Id="msierrXmlFileFailedSelect" Overridable="yes">Fracaso de la búsqueda del nodo: [3] en el fichero XML: [4], error del sistema: [2]</String>
25 <String Id="msierrXmlFileFailedSave" Overridable="yes">Fracaso durante la salvaguardia de las modificaciones en el fichero XML [3], error del sistema: [2]</String>
26
27 <String Id="msierrXmlConfigFailedRead" Overridable="yes">Un problema ha aparecido durante la configuración de los ficheros XML.</String>
28 <String Id="msierrXmlConfigFailedOpen" Overridable="yes">Fracaso de la apertura de los ficheros XML [3], error del sistema: [2]</String>
29 <String Id="msierrXmlConfigFailedSelect" Overridable="yes">Fracaso de la búsqueda del nodo: [3] en el fichero XML: [4], error del sistema: [2]</String>
30 <String Id="msierrXmlConfigFailedSave" Overridable="yes">Fracaso durante la salvaguardia de las modificaciones en el fichero XML [3], error del sistema: [2]</String>
31</WixLocalization> \ No newline at end of file
diff --git a/src/ext/Util/wixlib/fr-fr.wxl b/src/ext/Util/wixlib/fr-fr.wxl
new file mode 100644
index 00000000..ad34b56a
--- /dev/null
+++ b/src/ext/Util/wixlib/fr-fr.wxl
@@ -0,0 +1,31 @@
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<WixLocalization Culture="fr-fr" xmlns="http://wixtoolset.org/schemas/v4/wxl">
4 <String Id="msierrUSRFailedUserCreate" Overridable="yes">La création de l'utilisateur a échoué. ([2] [3] [4] [5])</String>
5 <String Id="msierrUSRFailedUserCreatePswd" Overridable="yes">La création de l'utilisateur a échoué car le mot de passe est invalide. ([2] [3] [4] [5])</String>
6 <String Id="msierrUSRFailedUserGroupAdd" Overridable="yes">L'ajout de l'utilisateur au groupe a échoué. ([2] [3] [4] [5])</String>
7 <String Id="msierrUSRFailedUserCreateExists" Overridable="yes">La création de l'utilisateur a échoué car il existe dejà. ([2] [3] [4] [5])</String>
8
9 <String Id="msierrSMBFailedCreate" Overridable="yes">La création du partage reseau a échoué. ([2] [3] [4] [5])</String>
10 <String Id="msierrSMBFailedDrop" Overridable="yes">La suppression du partage reseau a échoué. ([2] [3] [4] [5])</String>
11
12 <String Id="msierrPERFMONFailedRegisterDLL" Overridable="yes">L'inscription au registre de la DLL avec PerfMon a échoué. ([2] [3] [4] [5])</String>
13 <String Id="msierrPERFMONFailedUnregisterDLL" Overridable="yes">La desinscription au registre de la DLL avec PerfMon a échoué. ([2] [3] [4] [5])</String>
14
15 <String Id="msierrInstallPerfCounterData" Overridable="yes">L'installation des compteurs de performance a échoué. ([2] [3] [4] [5])</String>
16 <String Id="msierrUninstallPerfCounterData" Overridable="yes">La desinstallation des compteurs de performance a échoué. ([2] [3] [4] [5])</String>
17
18 <String Id="msierrSecureObjectsFailedCreateSD" Overridable="yes">La création des ACLs a échoué pour [3]\[4], erreur systeme: [2]</String>
19 <String Id="msierrSecureObjectsFailedSet" Overridable="yes">Le positionnement des ACLs pour l'objet [3] a échoué, erreur systeme: [2]</String>
20 <String Id="msierrSecureObjectsUnknownType" Overridable="yes">Type d'objet inconnu [3], erreur systeme: [2]</String>
21
22 <String Id="msierrXmlFileFailedRead" Overridable="yes">Un problème est survenu lors de la configuration des fichiers XML.</String>
23 <String Id="msierrXmlFileFailedOpen" Overridable="yes">Echec de l'ouverture des fichiers XML [3], erreur systeme: [2]</String>
24 <String Id="msierrXmlFileFailedSelect" Overridable="yes">Echec de la recherche du noeud: [3] dans le fichier XML: [4], erreur systeme: [2]</String>
25 <String Id="msierrXmlFileFailedSave" Overridable="yes">Echec lors de la sauvegarde des modifications dans le fichier XML [3], erreur systeme: [2]</String>
26
27 <String Id="msierrXmlConfigFailedRead" Overridable="yes">Un problème est survenu lors de la configuration des fichiers XML.</String>
28 <String Id="msierrXmlConfigFailedOpen" Overridable="yes">Echec de l'ouverture des fichiers XML [3], erreur systeme: [2]</String>
29 <String Id="msierrXmlConfigFailedSelect" Overridable="yes">Echec de la recherche du noeud: [3] dans le fichier XML: [4], erreur systeme: [2]</String>
30 <String Id="msierrXmlConfigFailedSave" Overridable="yes">Echec lors de la sauvegarde des modifications dans le fichier XML [3], erreur systeme: [2]</String>
31</WixLocalization> \ No newline at end of file
diff --git a/src/ext/Util/wixlib/it-it.wxl b/src/ext/Util/wixlib/it-it.wxl
new file mode 100644
index 00000000..8cea0a14
--- /dev/null
+++ b/src/ext/Util/wixlib/it-it.wxl
@@ -0,0 +1,32 @@
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
4<WixLocalization Culture="it-it" xmlns="http://wixtoolset.org/schemas/v4/wxl">
5 <String Id="msierrUSRFailedUserCreate" Overridable="yes">Impossibile creare l'utente. ([2] [3] [4] [5])</String>
6 <String Id="msierrUSRFailedUserCreatePswd" Overridable="yes">Impossibile creare l'utente perchè la password è errata. ([2] [3] [4] [5])</String>
7 <String Id="msierrUSRFailedUserGroupAdd" Overridable="yes">Impossibile aggiungere l'utente al gruppo. ([2] [3] [4] [5])</String>
8 <String Id="msierrUSRFailedUserCreateExists" Overridable="yes">Impossibile creare l'utente perchè già esistente. ([2] [3] [4] [5])</String>
9
10 <String Id="msierrSMBFailedCreate" Overridable="yes">Impossibile creare la risorsa di rete. ([2] [3] [4] [5])</String>
11 <String Id="msierrSMBFailedDrop" Overridable="yes">Impossibile eliminare la risorsa di rete. ([2] [3] [4] [5])</String>
12
13 <String Id="msierrPERFMONFailedRegisterDLL" Overridable="yes">Impossibile registrare la DLL con PerfMon. ([2] [3] [4] [5])</String>
14 <String Id="msierrPERFMONFailedUnregisterDLL" Overridable="yes">Impossibile rimuovere la registrazione della DLL con PerfMon. ([2] [3] [4] [5])</String>
15
16 <String Id="msierrInstallPerfCounterData" Overridable="yes">Impossibile installare i contatori delle prestazioni. ([2] [3] [4] [5])</String>
17 <String Id="msierrUninstallPerfCounterData" Overridable="yes">Impossibile rimuovere i contatori delle prestazioni. ([2] [3] [4] [5])</String>
18
19 <String Id="msierrSecureObjectsFailedCreateSD" Overridable="yes">Impossibile creare i descrittori di sicurezza per [3]\[4], errore di sistema: [2]</String>
20 <String Id="msierrSecureObjectsFailedSet" Overridable="yes">Impossibile impostare i descrittori di sicurezza sull'oggetto [3], errore di sistema: [2]</String>
21 <String Id="msierrSecureObjectsUnknownType" Overridable="yes">Tipo di oggetto sconosciuto [3], errore di sistema: [2]</String>
22
23 <String Id="msierrXmlFileFailedRead" Overridable="yes">Si è verificato un errore durante la configurazione dei file XML.</String>
24 <String Id="msierrXmlFileFailedOpen" Overridable="yes">Impossibile aprire il file XML [3], errore di sistema: [2]</String>
25 <String Id="msierrXmlFileFailedSelect" Overridable="yes">Impossibile trovare il nodo: [3] nel file XML: [4], errore di sistema: [2]</String>
26 <String Id="msierrXmlFileFailedSave" Overridable="yes">Impossible salvare le modifiche al file XML [3], errore di sistema: [2]</String>
27
28 <String Id="msierrXmlConfigFailedRead" Overridable="yes">Si è verificato un errore durante la configurazione dei file XML.</String>
29 <String Id="msierrXmlConfigFailedOpen" Overridable="yes">Impossibile aprire il file XML [3], errore di sistema: [2]</String>
30 <String Id="msierrXmlConfigFailedSelect" Overridable="yes">Impossibile trovare il nodo: [3] nel file XML: [4], errore di sistema: [2]</String>
31 <String Id="msierrXmlConfigFailedSave" Overridable="yes">Impossibile salvare le modifiche al file XML [3], errore di sitema: [2]</String>
32</WixLocalization>
diff --git a/src/ext/Util/wixlib/ja-jp.wxl b/src/ext/Util/wixlib/ja-jp.wxl
new file mode 100644
index 00000000..5f5cf40d
--- /dev/null
+++ b/src/ext/Util/wixlib/ja-jp.wxl
@@ -0,0 +1,32 @@
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
4<WixLocalization Culture="ja-jp" xmlns="http://wixtoolset.org/schemas/v4/wxl">
5 <String Id="msierrUSRFailedUserCreate" Overridable="yes">ユーザー作成に失敗しました。 ([2] [3] [4] [5])</String>
6 <String Id="msierrUSRFailedUserCreatePswd" Overridable="yes">パスワードが無効のためユーザー作成に失敗しました。 ([2] [3] [4] [5])</String>
7 <String Id="msierrUSRFailedUserGroupAdd" Overridable="yes">ユーザーをグループに追加でいませんでした。 ([2] [3] [4] [5])</String>
8 <String Id="msierrUSRFailedUserCreateExists" Overridable="yes">ユーザーが既に存在するため作成できませんでした。 ([2] [3] [4] [5])</String>
9
10 <String Id="msierrSMBFailedCreate" Overridable="yes">ネットワーク共有の作成に失敗しました。 ([2] [3] [4] [5])</String>
11 <String Id="msierrSMBFailedDrop" Overridable="yes">ネットワーク共有の削除に失敗しました。 ([2] [3] [4] [5])</String>
12
13 <String Id="msierrPERFMONFailedRegisterDLL" Overridable="yes">DLL を PerfMon に登録でいませんでした。 ([2] [3] [4] [5])</String>
14 <String Id="msierrPERFMONFailedUnregisterDLL" Overridable="yes">DLL を PerfMon より登録解除できませんでした。 ([2] [3] [4] [5])</String>
15
16 <String Id="msierrInstallPerfCounterData" Overridable="yes">パフォーマンス カウンタをインストールできませんでした。 ([2] [3] [4] [5])</String>
17 <String Id="msierrUninstallPerfCounterData" Overridable="yes">パフォーマンス カウンタをアンインストールできませんでした。 ([2] [3] [4] [5])</String>
18
19 <String Id="msierrSecureObjectsFailedCreateSD" Overridable="yes">[3]\[4] 用セキュリティ ディスクリプターを作成できませんでした、システム エラー: [2]</String>
20 <String Id="msierrSecureObjectsFailedSet" Overridable="yes">オブジェクト [3] 上のセキュリティ ディスクリプターを設定できませんでした、システム エラー: [2]</String>
21 <String Id="msierrSecureObjectsUnknownType" Overridable="yes">不明なオブジェクト種別 [3]、システム エラー: [2]</String>
22
23 <String Id="msierrXmlFileFailedRead" Overridable="yes">XML ファイル構成中に失敗しました。</String>
24 <String Id="msierrXmlFileFailedOpen" Overridable="yes">XML ファイル [3] を開けませんでした、システム エラー: [2]</String>
25 <String Id="msierrXmlFileFailedSelect" Overridable="yes">XML ファイル [4] 内にノード [3] が見つかりませんでした、システム エラー: [2]</String>
26 <String Id="msierrXmlFileFailedSave" Overridable="yes">XML ファイル [3] へ変更を保存できませんでした、システム エラー: [2]</String>
27
28 <String Id="msierrXmlConfigFailedRead" Overridable="yes">XML ファイル構成中に失敗しました。</String>
29 <String Id="msierrXmlConfigFailedOpen" Overridable="yes">XML ファイル [3] を開けませんでした、システム エラー: [2]</String>
30 <String Id="msierrXmlConfigFailedSelect" Overridable="yes">XML ファイル [4] 内にノード [3] が見つかりませんでした、システム エラー: [2]</String>
31 <String Id="msierrXmlConfigFailedSave" Overridable="yes">XML ファイル [3] へ変更を保存できませんでした、システム エラー: [2]</String>
32</WixLocalization>
diff --git a/src/ext/Util/wixlib/pt-br.wxl b/src/ext/Util/wixlib/pt-br.wxl
new file mode 100644
index 00000000..3ca27dda
--- /dev/null
+++ b/src/ext/Util/wixlib/pt-br.wxl
@@ -0,0 +1,26 @@
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
4<WixLocalization Culture="pt-br" xmlns="http://wixtoolset.org/schemas/v4/wxl">
5 <String Id="msierrUSRFailedUserCreate" Overridable="yes">Falha ao criar usuário. ([2] [3] [4] [5])</String>
6 <String Id="msierrUSRFailedUserCreatePswd" Overridable="yes">Falha ao criar usuário devido a senha inválida. ([2] [3] [4] [5])</String>
7 <String Id="msierrUSRFailedUserGroupAdd" Overridable="yes">Falha ao adicionar o usuário ao grupo. ([2] [3] [4] [5])</String>
8 <String Id="msierrUSRFailedUserCreateExists" Overridable="yes">Falha ao criar o usuário, porque ele já existe. ([2] [3] [4] [5])</String>
9 <String Id="msierrSMBFailedCreate" Overridable="yes">Falha ao criar o compartilhamento de rede. ([2] [3] [4] [5])</String>
10 <String Id="msierrSMBFailedDrop" Overridable="yes">Falha ao cair compartilhamento de rede. ([2] [3] [4] [5])</String>
11 <String Id="msierrPERFMONFailedRegisterDLL" Overridable="yes">Falha ao registrar DLL com PerfMon. ([2] [3] [4] [5])</String>
12 <String Id="msierrPERFMONFailedUnregisterDLL" Overridable="yes">Falha ao cancelar o registro de DLL com PerfMon. ([2] [3] [4] [5])</String>
13 <String Id="msierrInstallPerfCounterData" Overridable="yes">Falha ao instalar contadores de desempenho. ([2] [3] [4] [5])</String>
14 <String Id="msierrUninstallPerfCounterData" Overridable="yes">Falha ao desinstalar contadores de desempenho. ([2] [3] [4] [5])</String>
15 <String Id="msierrSecureObjectsFailedCreateSD" Overridable="yes">Falha ao criar o descritor de segurança [3] \ [4], erro do sistema: [2]</String>
16 <String Id="msierrSecureObjectsFailedSet" Overridable="yes">Falha ao definir o descritor de segurança sobre o objeto [3], erro do sistema: [2]</String>
17 <String Id="msierrSecureObjectsUnknownType" Overridable="yes">Objeto Desconhecido Tipo [3], erro do sistema: [2]</String>
18 <String Id="msierrXmlFileFailedRead" Overridable="yes">Houve uma falha ao configurar arquivos XML.</String>
19 <String Id="msierrXmlFileFailedOpen" Overridable="yes">Falha ao abrir o arquivo XML [3], erro do sistema: [2]</String>
20 <String Id="msierrXmlFileFailedSelect" Overridable="yes">Falha ao localizar nó: [3] no arquivo XML: [4], erro do sistema: [2]</String>
21 <String Id="msierrXmlFileFailedSave" Overridable="yes">Falha ao salvar as alterações para o arquivo XML [3], erro do sistema: [2]</String>
22 <String Id="msierrXmlConfigFailedRead" Overridable="yes">Houve uma falha ao configurar arquivos XML.</String>
23 <String Id="msierrXmlConfigFailedOpen" Overridable="yes">Falha ao abrir o arquivo XML [3], erro do sistema: [2]</String>
24 <String Id="msierrXmlConfigFailedSelect" Overridable="yes">Falha ao localizar nó: [3] no arquivo XML: [4], erro do sistema: [2]</String>
25 <String Id="msierrXmlConfigFailedSave" Overridable="yes">Falha ao salvar as alterações para o arquivo XML [3], erro do sistema: [2]</String>
26</WixLocalization>
diff --git a/src/ext/Util/wixlib/util.v3.ncrunchproject b/src/ext/Util/wixlib/util.v3.ncrunchproject
new file mode 100644
index 00000000..319cd523
--- /dev/null
+++ b/src/ext/Util/wixlib/util.v3.ncrunchproject
@@ -0,0 +1,5 @@
1<ProjectConfiguration>
2 <Settings>
3 <IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely>
4 </Settings>
5</ProjectConfiguration> \ No newline at end of file
diff --git a/src/ext/Util/wixlib/util.wixproj b/src/ext/Util/wixlib/util.wixproj
new file mode 100644
index 00000000..99dede7d
--- /dev/null
+++ b/src/ext/Util/wixlib/util.wixproj
@@ -0,0 +1,27 @@
1<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
2<Project Sdk="WixToolset.Sdk">
3
4 <PropertyGroup>
5 <OutputType>Library</OutputType>
6 <BindFiles>true</BindFiles>
7 </PropertyGroup>
8
9 <ItemGroup>
10 <BindInputPaths Include="$(OutputPath)x86" BindName='x86' />
11 <BindInputPaths Include="$(OutputPath)x64" BindName='x64' />
12 <BindInputPaths Include="$(OutputPath)arm64" BindName='arm64' />
13 </ItemGroup>
14
15 <ItemGroup>
16 <ProjectReference Include="..\be\utilbe.vcxproj" Properties="Platform=ARM64" ReferenceOutputAssembly="false" />
17 <ProjectReference Include="..\be\utilbe.vcxproj" Properties="Platform=x86" ReferenceOutputAssembly="false" />
18 <ProjectReference Include="..\be\utilbe.vcxproj" Properties="Platform=x64" ReferenceOutputAssembly="false" />
19 <ProjectReference Include="..\ca\utilca.vcxproj" Properties="Platform=ARM64" ReferenceOutputAssembly="false" />
20 <ProjectReference Include="..\ca\utilca.vcxproj" Properties="Platform=x86" ReferenceOutputAssembly="false" />
21 <ProjectReference Include="..\ca\utilca.vcxproj" Properties="Platform=x64" ReferenceOutputAssembly="false" />
22 </ItemGroup>
23
24 <ItemGroup>
25 <PackageReference Include="Nerdbank.GitVersioning" Version="3.3.37" PrivateAssets="All" />
26 </ItemGroup>
27</Project>
diff --git a/src/ext/global.json b/src/ext/global.json
index 23d7a5bd..697f5687 100644
--- a/src/ext/global.json
+++ b/src/ext/global.json
@@ -1,5 +1,8 @@
1{ 1{
2 "msbuild-sdks": { 2 "msbuild-sdks": {
3 "WixToolset.Sdk": "4.0.0-build-0213" 3 "WixToolset.Sdk": "4.0.0-build-0213"
4 },
5 "sdk": {
6 "allowPrerelease": false
4 } 7 }
5} 8}