From ff659159e041bf6c083e6b7fcb9b726065a9dd73 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Mon, 3 May 2021 09:55:22 -0700 Subject: Move Util.wixext into ext --- src/.editorconfig | 37 + src/CustomizedNativeRecommendedRules.ruleset | 8 - src/Directory.Build.props | 27 - src/Directory.Build.targets | 51 - src/Directory.csproj.props | 13 - src/Directory.csproj.targets | 26 - src/Directory.vcxproj.props | 97 - src/be/UtilBundleExtension.cpp | 87 - src/be/UtilBundleExtension.h | 16 - src/be/beDecor.h | 13 - src/be/detectsha2support.cpp | 58 - src/be/detectsha2support.h | 8 - src/be/precomp.cpp | 3 - src/be/precomp.h | 37 - src/be/utilbe.cpp | 41 - src/be/utilbe.def | 8 - src/be/utilbe.vcxproj | 80 - src/be/utilsearch.cpp | 160 - src/be/utilsearch.h | 65 - src/ca/BroadcastSettingChange.cpp | 45 - src/ca/CheckReboot.cpp | 36 - src/ca/CloseApps.cpp | 568 --- src/ca/CustomMsiErrors.h | 32 - src/ca/FormatFiles.cpp | 221 -- src/ca/OsInfo.cpp | 487 --- src/ca/RemoveFoldersEx.cpp | 243 -- src/ca/RemoveRegistryKeysEx.cpp | 114 - src/ca/RestartManager.cpp | 185 - src/ca/TouchFile.cpp | 308 -- src/ca/XmlConfig.cpp | 1130 ------ src/ca/XmlFile.cpp | 940 ----- src/ca/caDecor.h | 13 - src/ca/cost.h | 9 - src/ca/dllmain.cpp | 26 - src/ca/exitearlywithsuccess.cpp | 27 - src/ca/netshortcuts.cpp | 437 --- src/ca/precomp.h | 54 - src/ca/qtexecca.cpp | 316 -- src/ca/sca.h | 19 - src/ca/scacost.h | 18 - src/ca/scaexec.cpp | 1082 ------ src/ca/scamanifest.cpp | 377 -- src/ca/scaperf.cpp | 310 -- src/ca/scaperfexec.cpp | 423 --- src/ca/scasched.cpp | 127 - src/ca/scasmb.h | 46 - src/ca/scasmbexec.cpp | 316 -- src/ca/scasmbexec.h | 27 - src/ca/scasmbsched.cpp | 639 ---- src/ca/scauser.cpp | 709 ---- src/ca/scauser.h | 67 - src/ca/secureobj.cpp | 915 ----- src/ca/serviceconfig.cpp | 821 ----- src/ca/shellexecca.cpp | 271 -- src/ca/test.cpp | 269 -- src/ca/utilca.cpp | 3 - src/ca/utilca.def | 91 - src/ca/utilca.vcxproj | 106 - .../Util/CustomizedNativeRecommendedRules.ruleset | 8 + src/ext/Util/Directory.Build.props | 27 + src/ext/Util/Directory.Build.targets | 51 + src/ext/Util/Directory.csproj.props | 13 + src/ext/Util/Directory.csproj.targets | 26 + src/ext/Util/Directory.vcxproj.props | 97 + src/ext/Util/README.md | 3 + src/ext/Util/Util.wixext.sln | 87 + src/ext/Util/Util.wixext.v3.ncrunchsolution | 6 + src/ext/Util/appveyor.cmd | 19 + src/ext/Util/appveyor.yml | 40 + src/ext/Util/be/UtilBundleExtension.cpp | 87 + src/ext/Util/be/UtilBundleExtension.h | 16 + src/ext/Util/be/beDecor.h | 13 + src/ext/Util/be/detectsha2support.cpp | 58 + src/ext/Util/be/detectsha2support.h | 8 + src/ext/Util/be/precomp.cpp | 3 + src/ext/Util/be/precomp.h | 37 + src/ext/Util/be/utilbe.cpp | 41 + src/ext/Util/be/utilbe.def | 8 + src/ext/Util/be/utilbe.vcxproj | 80 + src/ext/Util/be/utilsearch.cpp | 160 + src/ext/Util/be/utilsearch.h | 65 + src/ext/Util/ca/BroadcastSettingChange.cpp | 45 + src/ext/Util/ca/CheckReboot.cpp | 36 + src/ext/Util/ca/CloseApps.cpp | 568 +++ src/ext/Util/ca/CustomMsiErrors.h | 32 + src/ext/Util/ca/FormatFiles.cpp | 221 ++ src/ext/Util/ca/OsInfo.cpp | 487 +++ src/ext/Util/ca/RemoveFoldersEx.cpp | 243 ++ src/ext/Util/ca/RemoveRegistryKeysEx.cpp | 114 + src/ext/Util/ca/RestartManager.cpp | 185 + src/ext/Util/ca/TouchFile.cpp | 308 ++ src/ext/Util/ca/XmlConfig.cpp | 1130 ++++++ src/ext/Util/ca/XmlFile.cpp | 940 +++++ src/ext/Util/ca/caDecor.h | 13 + src/ext/Util/ca/cost.h | 9 + src/ext/Util/ca/dllmain.cpp | 26 + src/ext/Util/ca/exitearlywithsuccess.cpp | 27 + src/ext/Util/ca/netshortcuts.cpp | 437 +++ src/ext/Util/ca/precomp.h | 54 + src/ext/Util/ca/qtexecca.cpp | 316 ++ src/ext/Util/ca/sca.h | 19 + src/ext/Util/ca/scacost.h | 18 + src/ext/Util/ca/scaexec.cpp | 1082 ++++++ src/ext/Util/ca/scamanifest.cpp | 377 ++ src/ext/Util/ca/scaperf.cpp | 310 ++ src/ext/Util/ca/scaperfexec.cpp | 423 +++ src/ext/Util/ca/scasched.cpp | 127 + src/ext/Util/ca/scasmb.h | 46 + src/ext/Util/ca/scasmbexec.cpp | 316 ++ src/ext/Util/ca/scasmbexec.h | 27 + src/ext/Util/ca/scasmbsched.cpp | 639 ++++ src/ext/Util/ca/scauser.cpp | 709 ++++ src/ext/Util/ca/scauser.h | 67 + src/ext/Util/ca/secureobj.cpp | 915 +++++ src/ext/Util/ca/serviceconfig.cpp | 821 +++++ src/ext/Util/ca/shellexecca.cpp | 271 ++ src/ext/Util/ca/test.cpp | 269 ++ src/ext/Util/ca/utilca.cpp | 3 + src/ext/Util/ca/utilca.def | 91 + src/ext/Util/ca/utilca.vcxproj | 106 + src/ext/Util/nuget.config | 18 + .../WixToolsetTest.Util/TestData/.Data/burn.exe | Bin 0 -> 463360 bytes .../TestData/BundleWithSearches/Bundle.en-us.wxl | 8 + .../TestData/BundleWithSearches/Bundle.wxs | 52 + .../BundleWithSearches/data/MsiPackage/Shared.dll | 1 + .../BundleWithSearches/data/MsiPackage/test.txt | 1 + .../TestData/BundleWithSearches/data/fakeba.dll | 1 + .../TestData/BundleWithSearches/data/test.msi | Bin 0 -> 32768 bytes .../TestData/CloseApplication/Package.en-us.wxl | 9 + .../TestData/CloseApplication/Package.wxs | 17 + .../CloseApplication/PackageComponents.wxs | 9 + .../TestData/CloseApplication/example.txt | 1 + .../TestData/EventManifest/Package.en-us.wxl | 9 + .../TestData/EventManifest/Package.wxs | 15 + .../TestData/EventManifest/PackageComponents.wxs | 11 + .../TestData/EventManifest/example.txt | 1 + .../TestData/InternetShortcut/Package.en-us.wxl | 9 + .../TestData/InternetShortcut/Package.ico | Bin 0 -> 83899 bytes .../TestData/InternetShortcut/Package.wxs | 15 + .../InternetShortcut/PackageComponents.wxs | 11 + .../TestData/InternetShortcut/example.txt | 1 + .../TestData/InternetShortcutModule/Module.wxs | 13 + .../InternetShortcutModule/ModuleComponents.wxs | 11 + .../TestData/InternetShortcutModule/Package.ico | Bin 0 -> 83899 bytes .../TestData/PermissionEx/Package.en-us.wxl | 9 + .../TestData/PermissionEx/Package.wxs | 15 + .../TestData/PermissionEx/PackageComponents.wxs | 23 + .../TestData/PermissionEx/example.txt | 1 + .../TestData/Queries/Package.en-us.wxl | 9 + .../TestData/Queries/Package.wxs | 23 + .../TestData/Queries/PackageComponents.wxs | 9 + .../TestData/Queries/example.txt | 1 + .../TestData/RemoveFolderEx/Module.wxs | 13 + .../TestData/RemoveFolderEx/ModuleComponents.wxs | 10 + .../TestData/RemoveRegistryKeyEx/Module.wxs | 13 + .../RemoveRegistryKeyEx/ModuleComponents.wxs | 10 + .../TestData/UsingFileShare/Package.en-us.wxl | 9 + .../TestData/UsingFileShare/Package.wxs | 15 + .../TestData/UsingFileShare/PackageComponents.wxs | 14 + .../TestData/UsingFileShare/example.txt | 1 + .../TestData/XmlConfig/Package.en-us.wxl | 9 + .../TestData/XmlConfig/Package.wxs | 17 + .../TestData/XmlConfigModule/Module.wxs | 19 + .../TestData/XmlConfigModule/my.xml | 1 + .../WixToolsetTest.Util/UtilExtensionFixture.cs | 317 ++ .../WixToolsetTest.Util/WixToolsetTest.Util.csproj | 38 + .../WixToolsetTest.Util.v3.ncrunchproject | 5 + src/ext/Util/wix.snk | Bin 0 -> 596 bytes src/ext/Util/wixext/PerformanceCounterType.cs | 192 + src/ext/Util/wixext/Symbols/EventManifestSymbol.cs | 55 + .../wixext/Symbols/FileSharePermissionsSymbol.cs | 63 + src/ext/Util/wixext/Symbols/FileShareSymbol.cs | 71 + src/ext/Util/wixext/Symbols/GroupSymbol.cs | 63 + .../Util/wixext/Symbols/PerfmonManifestSymbol.cs | 63 + src/ext/Util/wixext/Symbols/PerfmonSymbol.cs | 63 + .../wixext/Symbols/PerformanceCategorySymbol.cs | 71 + src/ext/Util/wixext/Symbols/SecureObjectsSymbol.cs | 103 + src/ext/Util/wixext/Symbols/ServiceConfigSymbol.cs | 119 + src/ext/Util/wixext/Symbols/UserGroupSymbol.cs | 55 + src/ext/Util/wixext/Symbols/UserSymbol.cs | 79 + .../Util/wixext/Symbols/UtilSymbolDefinitions.cs | 125 + .../wixext/Symbols/WixCloseApplicationSymbol.cs | 103 + .../Util/wixext/Symbols/WixFormatFilesSymbol.cs | 55 + .../wixext/Symbols/WixInternetShortcutSymbol.cs | 95 + .../Util/wixext/Symbols/WixRemoveFolderExSymbol.cs | 78 + .../wixext/Symbols/WixRemoveRegistryKeyExSymbol.cs | 86 + .../wixext/Symbols/WixRestartResourceSymbol.cs | 71 + src/ext/Util/wixext/Symbols/WixTouchFileSymbol.cs | 63 + .../Symbols/WixWindowsFeatureSearchSymbol.cs | 47 + src/ext/Util/wixext/Symbols/XmlConfigSymbol.cs | 111 + src/ext/Util/wixext/Symbols/XmlFileSymbol.cs | 95 + src/ext/Util/wixext/UtilCompiler.cs | 3889 ++++++++++++++++++++ src/ext/Util/wixext/UtilConstants.cs | 17 + src/ext/Util/wixext/UtilDecompiler.cs | 1543 ++++++++ src/ext/Util/wixext/UtilErrors.cs | 49 + src/ext/Util/wixext/UtilExtensionData.cs | 23 + src/ext/Util/wixext/UtilExtensionFactory.cs | 18 + src/ext/Util/wixext/UtilTableDefinitions.cs | 319 ++ src/ext/Util/wixext/UtilWarnings.cs | 37 + .../wixext/UtilWindowsInstallerBackendExtension.cs | 13 + src/ext/Util/wixext/WixToolset.Util.wixext.csproj | 31 + src/ext/Util/wixext/WixToolset.Util.wixext.nuspec | 25 + src/ext/Util/wixext/WixToolset.Util.wixext.targets | 11 + .../WixToolset.Util.wixext.v3.ncrunchproject | 7 + .../Util/wixlib/UtilBundleExtension_Platform.wxi | 10 + src/ext/Util/wixlib/UtilBundleExtension_arm64.wxs | 7 + src/ext/Util/wixlib/UtilBundleExtension_x64.wxs | 7 + src/ext/Util/wixlib/UtilBundleExtension_x86.wxs | 7 + src/ext/Util/wixlib/UtilExtension.wxs | 64 + src/ext/Util/wixlib/UtilExtension_Platform.wxi | 360 ++ src/ext/Util/wixlib/UtilExtension_arm64.wxs | 7 + src/ext/Util/wixlib/UtilExtension_x64.wxs | 7 + src/ext/Util/wixlib/UtilExtension_x86.wxs | 7 + src/ext/Util/wixlib/caDecor.wxi | 39 + src/ext/Util/wixlib/caerr.wxi | 96 + src/ext/Util/wixlib/de-de.wxl | 32 + src/ext/Util/wixlib/en-us.wxl | 32 + src/ext/Util/wixlib/es-es.wxl | 31 + src/ext/Util/wixlib/fr-fr.wxl | 31 + src/ext/Util/wixlib/it-it.wxl | 32 + src/ext/Util/wixlib/ja-jp.wxl | 32 + src/ext/Util/wixlib/pt-br.wxl | 26 + src/ext/Util/wixlib/util.v3.ncrunchproject | 5 + src/ext/Util/wixlib/util.wixproj | 27 + src/ext/global.json | 8 + .../WixToolsetTest.Util/TestData/.Data/burn.exe | Bin 463360 -> 0 bytes .../TestData/BundleWithSearches/Bundle.en-us.wxl | 8 - .../TestData/BundleWithSearches/Bundle.wxs | 52 - .../BundleWithSearches/data/MsiPackage/Shared.dll | 1 - .../BundleWithSearches/data/MsiPackage/test.txt | 1 - .../TestData/BundleWithSearches/data/fakeba.dll | 1 - .../TestData/BundleWithSearches/data/test.msi | Bin 32768 -> 0 bytes .../TestData/CloseApplication/Package.en-us.wxl | 9 - .../TestData/CloseApplication/Package.wxs | 17 - .../CloseApplication/PackageComponents.wxs | 9 - .../TestData/CloseApplication/example.txt | 1 - .../TestData/EventManifest/Package.en-us.wxl | 9 - .../TestData/EventManifest/Package.wxs | 15 - .../TestData/EventManifest/PackageComponents.wxs | 11 - .../TestData/EventManifest/example.txt | 1 - .../TestData/InternetShortcut/Package.en-us.wxl | 9 - .../TestData/InternetShortcut/Package.ico | Bin 83899 -> 0 bytes .../TestData/InternetShortcut/Package.wxs | 15 - .../InternetShortcut/PackageComponents.wxs | 11 - .../TestData/InternetShortcut/example.txt | 1 - .../TestData/InternetShortcutModule/Module.wxs | 13 - .../InternetShortcutModule/ModuleComponents.wxs | 11 - .../TestData/InternetShortcutModule/Package.ico | Bin 83899 -> 0 bytes .../TestData/PermissionEx/Package.en-us.wxl | 9 - .../TestData/PermissionEx/Package.wxs | 15 - .../TestData/PermissionEx/PackageComponents.wxs | 23 - .../TestData/PermissionEx/example.txt | 1 - .../TestData/Queries/Package.en-us.wxl | 9 - .../TestData/Queries/Package.wxs | 23 - .../TestData/Queries/PackageComponents.wxs | 9 - .../TestData/Queries/example.txt | 1 - .../TestData/RemoveFolderEx/Module.wxs | 13 - .../TestData/RemoveFolderEx/ModuleComponents.wxs | 10 - .../TestData/RemoveRegistryKeyEx/Module.wxs | 13 - .../RemoveRegistryKeyEx/ModuleComponents.wxs | 10 - .../TestData/UsingFileShare/Package.en-us.wxl | 9 - .../TestData/UsingFileShare/Package.wxs | 15 - .../TestData/UsingFileShare/PackageComponents.wxs | 14 - .../TestData/UsingFileShare/example.txt | 1 - .../TestData/XmlConfig/Package.en-us.wxl | 9 - .../TestData/XmlConfig/Package.wxs | 17 - .../TestData/XmlConfigModule/Module.wxs | 19 - .../TestData/XmlConfigModule/my.xml | 1 - .../WixToolsetTest.Util/UtilExtensionFixture.cs | 317 -- .../WixToolsetTest.Util/WixToolsetTest.Util.csproj | 38 - .../WixToolsetTest.Util.v3.ncrunchproject | 5 - src/version.json | 11 + src/wix.snk | Bin 596 -> 0 bytes src/wixext/PerformanceCounterType.cs | 192 - src/wixext/Symbols/EventManifestSymbol.cs | 55 - src/wixext/Symbols/FileSharePermissionsSymbol.cs | 63 - src/wixext/Symbols/FileShareSymbol.cs | 71 - src/wixext/Symbols/GroupSymbol.cs | 63 - src/wixext/Symbols/PerfmonManifestSymbol.cs | 63 - src/wixext/Symbols/PerfmonSymbol.cs | 63 - src/wixext/Symbols/PerformanceCategorySymbol.cs | 71 - src/wixext/Symbols/SecureObjectsSymbol.cs | 103 - src/wixext/Symbols/ServiceConfigSymbol.cs | 119 - src/wixext/Symbols/UserGroupSymbol.cs | 55 - src/wixext/Symbols/UserSymbol.cs | 79 - src/wixext/Symbols/UtilSymbolDefinitions.cs | 125 - src/wixext/Symbols/WixCloseApplicationSymbol.cs | 103 - src/wixext/Symbols/WixFormatFilesSymbol.cs | 55 - src/wixext/Symbols/WixInternetShortcutSymbol.cs | 95 - src/wixext/Symbols/WixRemoveFolderExSymbol.cs | 78 - src/wixext/Symbols/WixRemoveRegistryKeyExSymbol.cs | 86 - src/wixext/Symbols/WixRestartResourceSymbol.cs | 71 - src/wixext/Symbols/WixTouchFileSymbol.cs | 63 - .../Symbols/WixWindowsFeatureSearchSymbol.cs | 47 - src/wixext/Symbols/XmlConfigSymbol.cs | 111 - src/wixext/Symbols/XmlFileSymbol.cs | 95 - src/wixext/UtilCompiler.cs | 3889 -------------------- src/wixext/UtilConstants.cs | 17 - src/wixext/UtilDecompiler.cs | 1543 -------- src/wixext/UtilErrors.cs | 49 - src/wixext/UtilExtensionData.cs | 23 - src/wixext/UtilExtensionFactory.cs | 18 - src/wixext/UtilTableDefinitions.cs | 319 -- src/wixext/UtilWarnings.cs | 37 - src/wixext/UtilWindowsInstallerBackendExtension.cs | 13 - src/wixext/WixToolset.Util.wixext.csproj | 31 - src/wixext/WixToolset.Util.wixext.nuspec | 25 - src/wixext/WixToolset.Util.wixext.targets | 11 - .../WixToolset.Util.wixext.v3.ncrunchproject | 7 - src/wixlib/UtilBundleExtension_Platform.wxi | 10 - src/wixlib/UtilBundleExtension_arm64.wxs | 7 - src/wixlib/UtilBundleExtension_x64.wxs | 7 - src/wixlib/UtilBundleExtension_x86.wxs | 7 - src/wixlib/UtilExtension.wxs | 64 - src/wixlib/UtilExtension_Platform.wxi | 360 -- src/wixlib/UtilExtension_arm64.wxs | 7 - src/wixlib/UtilExtension_x64.wxs | 7 - src/wixlib/UtilExtension_x86.wxs | 7 - src/wixlib/caDecor.wxi | 39 - src/wixlib/caerr.wxi | 96 - src/wixlib/de-de.wxl | 32 - src/wixlib/en-us.wxl | 32 - src/wixlib/es-es.wxl | 31 - src/wixlib/fr-fr.wxl | 31 - src/wixlib/it-it.wxl | 32 - src/wixlib/ja-jp.wxl | 32 - src/wixlib/pt-br.wxl | 26 - src/wixlib/util.v3.ncrunchproject | 5 - src/wixlib/util.wixproj | 27 - 329 files changed, 22397 insertions(+), 22168 deletions(-) create mode 100644 src/.editorconfig delete mode 100644 src/CustomizedNativeRecommendedRules.ruleset delete mode 100644 src/Directory.Build.props delete mode 100644 src/Directory.Build.targets delete mode 100644 src/Directory.csproj.props delete mode 100644 src/Directory.csproj.targets delete mode 100644 src/Directory.vcxproj.props delete mode 100644 src/be/UtilBundleExtension.cpp delete mode 100644 src/be/UtilBundleExtension.h delete mode 100644 src/be/beDecor.h delete mode 100644 src/be/detectsha2support.cpp delete mode 100644 src/be/detectsha2support.h delete mode 100644 src/be/precomp.cpp delete mode 100644 src/be/precomp.h delete mode 100644 src/be/utilbe.cpp delete mode 100644 src/be/utilbe.def delete mode 100644 src/be/utilbe.vcxproj delete mode 100644 src/be/utilsearch.cpp delete mode 100644 src/be/utilsearch.h delete mode 100644 src/ca/BroadcastSettingChange.cpp delete mode 100644 src/ca/CheckReboot.cpp delete mode 100644 src/ca/CloseApps.cpp delete mode 100644 src/ca/CustomMsiErrors.h delete mode 100644 src/ca/FormatFiles.cpp delete mode 100644 src/ca/OsInfo.cpp delete mode 100644 src/ca/RemoveFoldersEx.cpp delete mode 100644 src/ca/RemoveRegistryKeysEx.cpp delete mode 100644 src/ca/RestartManager.cpp delete mode 100644 src/ca/TouchFile.cpp delete mode 100644 src/ca/XmlConfig.cpp delete mode 100644 src/ca/XmlFile.cpp delete mode 100644 src/ca/caDecor.h delete mode 100644 src/ca/cost.h delete mode 100644 src/ca/dllmain.cpp delete mode 100644 src/ca/exitearlywithsuccess.cpp delete mode 100644 src/ca/netshortcuts.cpp delete mode 100644 src/ca/precomp.h delete mode 100644 src/ca/qtexecca.cpp delete mode 100644 src/ca/sca.h delete mode 100644 src/ca/scacost.h delete mode 100644 src/ca/scaexec.cpp delete mode 100644 src/ca/scamanifest.cpp delete mode 100644 src/ca/scaperf.cpp delete mode 100644 src/ca/scaperfexec.cpp delete mode 100644 src/ca/scasched.cpp delete mode 100644 src/ca/scasmb.h delete mode 100644 src/ca/scasmbexec.cpp delete mode 100644 src/ca/scasmbexec.h delete mode 100644 src/ca/scasmbsched.cpp delete mode 100644 src/ca/scauser.cpp delete mode 100644 src/ca/scauser.h delete mode 100644 src/ca/secureobj.cpp delete mode 100644 src/ca/serviceconfig.cpp delete mode 100644 src/ca/shellexecca.cpp delete mode 100644 src/ca/test.cpp delete mode 100644 src/ca/utilca.cpp delete mode 100644 src/ca/utilca.def delete mode 100644 src/ca/utilca.vcxproj create mode 100644 src/ext/Util/CustomizedNativeRecommendedRules.ruleset create mode 100644 src/ext/Util/Directory.Build.props create mode 100644 src/ext/Util/Directory.Build.targets create mode 100644 src/ext/Util/Directory.csproj.props create mode 100644 src/ext/Util/Directory.csproj.targets create mode 100644 src/ext/Util/Directory.vcxproj.props create mode 100644 src/ext/Util/README.md create mode 100644 src/ext/Util/Util.wixext.sln create mode 100644 src/ext/Util/Util.wixext.v3.ncrunchsolution create mode 100644 src/ext/Util/appveyor.cmd create mode 100644 src/ext/Util/appveyor.yml create mode 100644 src/ext/Util/be/UtilBundleExtension.cpp create mode 100644 src/ext/Util/be/UtilBundleExtension.h create mode 100644 src/ext/Util/be/beDecor.h create mode 100644 src/ext/Util/be/detectsha2support.cpp create mode 100644 src/ext/Util/be/detectsha2support.h create mode 100644 src/ext/Util/be/precomp.cpp create mode 100644 src/ext/Util/be/precomp.h create mode 100644 src/ext/Util/be/utilbe.cpp create mode 100644 src/ext/Util/be/utilbe.def create mode 100644 src/ext/Util/be/utilbe.vcxproj create mode 100644 src/ext/Util/be/utilsearch.cpp create mode 100644 src/ext/Util/be/utilsearch.h create mode 100644 src/ext/Util/ca/BroadcastSettingChange.cpp create mode 100644 src/ext/Util/ca/CheckReboot.cpp create mode 100644 src/ext/Util/ca/CloseApps.cpp create mode 100644 src/ext/Util/ca/CustomMsiErrors.h create mode 100644 src/ext/Util/ca/FormatFiles.cpp create mode 100644 src/ext/Util/ca/OsInfo.cpp create mode 100644 src/ext/Util/ca/RemoveFoldersEx.cpp create mode 100644 src/ext/Util/ca/RemoveRegistryKeysEx.cpp create mode 100644 src/ext/Util/ca/RestartManager.cpp create mode 100644 src/ext/Util/ca/TouchFile.cpp create mode 100644 src/ext/Util/ca/XmlConfig.cpp create mode 100644 src/ext/Util/ca/XmlFile.cpp create mode 100644 src/ext/Util/ca/caDecor.h create mode 100644 src/ext/Util/ca/cost.h create mode 100644 src/ext/Util/ca/dllmain.cpp create mode 100644 src/ext/Util/ca/exitearlywithsuccess.cpp create mode 100644 src/ext/Util/ca/netshortcuts.cpp create mode 100644 src/ext/Util/ca/precomp.h create mode 100644 src/ext/Util/ca/qtexecca.cpp create mode 100644 src/ext/Util/ca/sca.h create mode 100644 src/ext/Util/ca/scacost.h create mode 100644 src/ext/Util/ca/scaexec.cpp create mode 100644 src/ext/Util/ca/scamanifest.cpp create mode 100644 src/ext/Util/ca/scaperf.cpp create mode 100644 src/ext/Util/ca/scaperfexec.cpp create mode 100644 src/ext/Util/ca/scasched.cpp create mode 100644 src/ext/Util/ca/scasmb.h create mode 100644 src/ext/Util/ca/scasmbexec.cpp create mode 100644 src/ext/Util/ca/scasmbexec.h create mode 100644 src/ext/Util/ca/scasmbsched.cpp create mode 100644 src/ext/Util/ca/scauser.cpp create mode 100644 src/ext/Util/ca/scauser.h create mode 100644 src/ext/Util/ca/secureobj.cpp create mode 100644 src/ext/Util/ca/serviceconfig.cpp create mode 100644 src/ext/Util/ca/shellexecca.cpp create mode 100644 src/ext/Util/ca/test.cpp create mode 100644 src/ext/Util/ca/utilca.cpp create mode 100644 src/ext/Util/ca/utilca.def create mode 100644 src/ext/Util/ca/utilca.vcxproj create mode 100644 src/ext/Util/nuget.config create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/.Data/burn.exe create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/Bundle.en-us.wxl create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/Bundle.wxs create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/MsiPackage/Shared.dll create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/MsiPackage/test.txt create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/fakeba.dll create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/test.msi create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/CloseApplication/Package.en-us.wxl create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/CloseApplication/Package.wxs create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/CloseApplication/PackageComponents.wxs create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/CloseApplication/example.txt create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/EventManifest/Package.en-us.wxl create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/EventManifest/Package.wxs create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/EventManifest/PackageComponents.wxs create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/EventManifest/example.txt create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcut/Package.en-us.wxl create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcut/Package.ico create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcut/Package.wxs create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcut/PackageComponents.wxs create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcut/example.txt create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcutModule/Module.wxs create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcutModule/ModuleComponents.wxs create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcutModule/Package.ico create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/PermissionEx/Package.en-us.wxl create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/PermissionEx/Package.wxs create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/PermissionEx/PackageComponents.wxs create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/PermissionEx/example.txt create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/Queries/Package.en-us.wxl create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/Queries/Package.wxs create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/Queries/PackageComponents.wxs create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/Queries/example.txt create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/RemoveFolderEx/Module.wxs create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/RemoveFolderEx/ModuleComponents.wxs create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/RemoveRegistryKeyEx/Module.wxs create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/RemoveRegistryKeyEx/ModuleComponents.wxs create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/UsingFileShare/Package.en-us.wxl create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/UsingFileShare/Package.wxs create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/UsingFileShare/PackageComponents.wxs create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/UsingFileShare/example.txt create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/XmlConfig/Package.en-us.wxl create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/XmlConfig/Package.wxs create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/XmlConfigModule/Module.wxs create mode 100644 src/ext/Util/test/WixToolsetTest.Util/TestData/XmlConfigModule/my.xml create mode 100644 src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs create mode 100644 src/ext/Util/test/WixToolsetTest.Util/WixToolsetTest.Util.csproj create mode 100644 src/ext/Util/test/WixToolsetTest.Util/WixToolsetTest.Util.v3.ncrunchproject create mode 100644 src/ext/Util/wix.snk create mode 100644 src/ext/Util/wixext/PerformanceCounterType.cs create mode 100644 src/ext/Util/wixext/Symbols/EventManifestSymbol.cs create mode 100644 src/ext/Util/wixext/Symbols/FileSharePermissionsSymbol.cs create mode 100644 src/ext/Util/wixext/Symbols/FileShareSymbol.cs create mode 100644 src/ext/Util/wixext/Symbols/GroupSymbol.cs create mode 100644 src/ext/Util/wixext/Symbols/PerfmonManifestSymbol.cs create mode 100644 src/ext/Util/wixext/Symbols/PerfmonSymbol.cs create mode 100644 src/ext/Util/wixext/Symbols/PerformanceCategorySymbol.cs create mode 100644 src/ext/Util/wixext/Symbols/SecureObjectsSymbol.cs create mode 100644 src/ext/Util/wixext/Symbols/ServiceConfigSymbol.cs create mode 100644 src/ext/Util/wixext/Symbols/UserGroupSymbol.cs create mode 100644 src/ext/Util/wixext/Symbols/UserSymbol.cs create mode 100644 src/ext/Util/wixext/Symbols/UtilSymbolDefinitions.cs create mode 100644 src/ext/Util/wixext/Symbols/WixCloseApplicationSymbol.cs create mode 100644 src/ext/Util/wixext/Symbols/WixFormatFilesSymbol.cs create mode 100644 src/ext/Util/wixext/Symbols/WixInternetShortcutSymbol.cs create mode 100644 src/ext/Util/wixext/Symbols/WixRemoveFolderExSymbol.cs create mode 100644 src/ext/Util/wixext/Symbols/WixRemoveRegistryKeyExSymbol.cs create mode 100644 src/ext/Util/wixext/Symbols/WixRestartResourceSymbol.cs create mode 100644 src/ext/Util/wixext/Symbols/WixTouchFileSymbol.cs create mode 100644 src/ext/Util/wixext/Symbols/WixWindowsFeatureSearchSymbol.cs create mode 100644 src/ext/Util/wixext/Symbols/XmlConfigSymbol.cs create mode 100644 src/ext/Util/wixext/Symbols/XmlFileSymbol.cs create mode 100644 src/ext/Util/wixext/UtilCompiler.cs create mode 100644 src/ext/Util/wixext/UtilConstants.cs create mode 100644 src/ext/Util/wixext/UtilDecompiler.cs create mode 100644 src/ext/Util/wixext/UtilErrors.cs create mode 100644 src/ext/Util/wixext/UtilExtensionData.cs create mode 100644 src/ext/Util/wixext/UtilExtensionFactory.cs create mode 100644 src/ext/Util/wixext/UtilTableDefinitions.cs create mode 100644 src/ext/Util/wixext/UtilWarnings.cs create mode 100644 src/ext/Util/wixext/UtilWindowsInstallerBackendExtension.cs create mode 100644 src/ext/Util/wixext/WixToolset.Util.wixext.csproj create mode 100644 src/ext/Util/wixext/WixToolset.Util.wixext.nuspec create mode 100644 src/ext/Util/wixext/WixToolset.Util.wixext.targets create mode 100644 src/ext/Util/wixext/WixToolset.Util.wixext.v3.ncrunchproject create mode 100644 src/ext/Util/wixlib/UtilBundleExtension_Platform.wxi create mode 100644 src/ext/Util/wixlib/UtilBundleExtension_arm64.wxs create mode 100644 src/ext/Util/wixlib/UtilBundleExtension_x64.wxs create mode 100644 src/ext/Util/wixlib/UtilBundleExtension_x86.wxs create mode 100644 src/ext/Util/wixlib/UtilExtension.wxs create mode 100644 src/ext/Util/wixlib/UtilExtension_Platform.wxi create mode 100644 src/ext/Util/wixlib/UtilExtension_arm64.wxs create mode 100644 src/ext/Util/wixlib/UtilExtension_x64.wxs create mode 100644 src/ext/Util/wixlib/UtilExtension_x86.wxs create mode 100644 src/ext/Util/wixlib/caDecor.wxi create mode 100644 src/ext/Util/wixlib/caerr.wxi create mode 100644 src/ext/Util/wixlib/de-de.wxl create mode 100644 src/ext/Util/wixlib/en-us.wxl create mode 100644 src/ext/Util/wixlib/es-es.wxl create mode 100644 src/ext/Util/wixlib/fr-fr.wxl create mode 100644 src/ext/Util/wixlib/it-it.wxl create mode 100644 src/ext/Util/wixlib/ja-jp.wxl create mode 100644 src/ext/Util/wixlib/pt-br.wxl create mode 100644 src/ext/Util/wixlib/util.v3.ncrunchproject create mode 100644 src/ext/Util/wixlib/util.wixproj create mode 100644 src/ext/global.json delete mode 100644 src/test/WixToolsetTest.Util/TestData/.Data/burn.exe delete mode 100644 src/test/WixToolsetTest.Util/TestData/BundleWithSearches/Bundle.en-us.wxl delete mode 100644 src/test/WixToolsetTest.Util/TestData/BundleWithSearches/Bundle.wxs delete mode 100644 src/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/MsiPackage/Shared.dll delete mode 100644 src/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/MsiPackage/test.txt delete mode 100644 src/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/fakeba.dll delete mode 100644 src/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/test.msi delete mode 100644 src/test/WixToolsetTest.Util/TestData/CloseApplication/Package.en-us.wxl delete mode 100644 src/test/WixToolsetTest.Util/TestData/CloseApplication/Package.wxs delete mode 100644 src/test/WixToolsetTest.Util/TestData/CloseApplication/PackageComponents.wxs delete mode 100644 src/test/WixToolsetTest.Util/TestData/CloseApplication/example.txt delete mode 100644 src/test/WixToolsetTest.Util/TestData/EventManifest/Package.en-us.wxl delete mode 100644 src/test/WixToolsetTest.Util/TestData/EventManifest/Package.wxs delete mode 100644 src/test/WixToolsetTest.Util/TestData/EventManifest/PackageComponents.wxs delete mode 100644 src/test/WixToolsetTest.Util/TestData/EventManifest/example.txt delete mode 100644 src/test/WixToolsetTest.Util/TestData/InternetShortcut/Package.en-us.wxl delete mode 100644 src/test/WixToolsetTest.Util/TestData/InternetShortcut/Package.ico delete mode 100644 src/test/WixToolsetTest.Util/TestData/InternetShortcut/Package.wxs delete mode 100644 src/test/WixToolsetTest.Util/TestData/InternetShortcut/PackageComponents.wxs delete mode 100644 src/test/WixToolsetTest.Util/TestData/InternetShortcut/example.txt delete mode 100644 src/test/WixToolsetTest.Util/TestData/InternetShortcutModule/Module.wxs delete mode 100644 src/test/WixToolsetTest.Util/TestData/InternetShortcutModule/ModuleComponents.wxs delete mode 100644 src/test/WixToolsetTest.Util/TestData/InternetShortcutModule/Package.ico delete mode 100644 src/test/WixToolsetTest.Util/TestData/PermissionEx/Package.en-us.wxl delete mode 100644 src/test/WixToolsetTest.Util/TestData/PermissionEx/Package.wxs delete mode 100644 src/test/WixToolsetTest.Util/TestData/PermissionEx/PackageComponents.wxs delete mode 100644 src/test/WixToolsetTest.Util/TestData/PermissionEx/example.txt delete mode 100644 src/test/WixToolsetTest.Util/TestData/Queries/Package.en-us.wxl delete mode 100644 src/test/WixToolsetTest.Util/TestData/Queries/Package.wxs delete mode 100644 src/test/WixToolsetTest.Util/TestData/Queries/PackageComponents.wxs delete mode 100644 src/test/WixToolsetTest.Util/TestData/Queries/example.txt delete mode 100644 src/test/WixToolsetTest.Util/TestData/RemoveFolderEx/Module.wxs delete mode 100644 src/test/WixToolsetTest.Util/TestData/RemoveFolderEx/ModuleComponents.wxs delete mode 100644 src/test/WixToolsetTest.Util/TestData/RemoveRegistryKeyEx/Module.wxs delete mode 100644 src/test/WixToolsetTest.Util/TestData/RemoveRegistryKeyEx/ModuleComponents.wxs delete mode 100644 src/test/WixToolsetTest.Util/TestData/UsingFileShare/Package.en-us.wxl delete mode 100644 src/test/WixToolsetTest.Util/TestData/UsingFileShare/Package.wxs delete mode 100644 src/test/WixToolsetTest.Util/TestData/UsingFileShare/PackageComponents.wxs delete mode 100644 src/test/WixToolsetTest.Util/TestData/UsingFileShare/example.txt delete mode 100644 src/test/WixToolsetTest.Util/TestData/XmlConfig/Package.en-us.wxl delete mode 100644 src/test/WixToolsetTest.Util/TestData/XmlConfig/Package.wxs delete mode 100644 src/test/WixToolsetTest.Util/TestData/XmlConfigModule/Module.wxs delete mode 100644 src/test/WixToolsetTest.Util/TestData/XmlConfigModule/my.xml delete mode 100644 src/test/WixToolsetTest.Util/UtilExtensionFixture.cs delete mode 100644 src/test/WixToolsetTest.Util/WixToolsetTest.Util.csproj delete mode 100644 src/test/WixToolsetTest.Util/WixToolsetTest.Util.v3.ncrunchproject create mode 100644 src/version.json delete mode 100644 src/wix.snk delete mode 100644 src/wixext/PerformanceCounterType.cs delete mode 100644 src/wixext/Symbols/EventManifestSymbol.cs delete mode 100644 src/wixext/Symbols/FileSharePermissionsSymbol.cs delete mode 100644 src/wixext/Symbols/FileShareSymbol.cs delete mode 100644 src/wixext/Symbols/GroupSymbol.cs delete mode 100644 src/wixext/Symbols/PerfmonManifestSymbol.cs delete mode 100644 src/wixext/Symbols/PerfmonSymbol.cs delete mode 100644 src/wixext/Symbols/PerformanceCategorySymbol.cs delete mode 100644 src/wixext/Symbols/SecureObjectsSymbol.cs delete mode 100644 src/wixext/Symbols/ServiceConfigSymbol.cs delete mode 100644 src/wixext/Symbols/UserGroupSymbol.cs delete mode 100644 src/wixext/Symbols/UserSymbol.cs delete mode 100644 src/wixext/Symbols/UtilSymbolDefinitions.cs delete mode 100644 src/wixext/Symbols/WixCloseApplicationSymbol.cs delete mode 100644 src/wixext/Symbols/WixFormatFilesSymbol.cs delete mode 100644 src/wixext/Symbols/WixInternetShortcutSymbol.cs delete mode 100644 src/wixext/Symbols/WixRemoveFolderExSymbol.cs delete mode 100644 src/wixext/Symbols/WixRemoveRegistryKeyExSymbol.cs delete mode 100644 src/wixext/Symbols/WixRestartResourceSymbol.cs delete mode 100644 src/wixext/Symbols/WixTouchFileSymbol.cs delete mode 100644 src/wixext/Symbols/WixWindowsFeatureSearchSymbol.cs delete mode 100644 src/wixext/Symbols/XmlConfigSymbol.cs delete mode 100644 src/wixext/Symbols/XmlFileSymbol.cs delete mode 100644 src/wixext/UtilCompiler.cs delete mode 100644 src/wixext/UtilConstants.cs delete mode 100644 src/wixext/UtilDecompiler.cs delete mode 100644 src/wixext/UtilErrors.cs delete mode 100644 src/wixext/UtilExtensionData.cs delete mode 100644 src/wixext/UtilExtensionFactory.cs delete mode 100644 src/wixext/UtilTableDefinitions.cs delete mode 100644 src/wixext/UtilWarnings.cs delete mode 100644 src/wixext/UtilWindowsInstallerBackendExtension.cs delete mode 100644 src/wixext/WixToolset.Util.wixext.csproj delete mode 100644 src/wixext/WixToolset.Util.wixext.nuspec delete mode 100644 src/wixext/WixToolset.Util.wixext.targets delete mode 100644 src/wixext/WixToolset.Util.wixext.v3.ncrunchproject delete mode 100644 src/wixlib/UtilBundleExtension_Platform.wxi delete mode 100644 src/wixlib/UtilBundleExtension_arm64.wxs delete mode 100644 src/wixlib/UtilBundleExtension_x64.wxs delete mode 100644 src/wixlib/UtilBundleExtension_x86.wxs delete mode 100644 src/wixlib/UtilExtension.wxs delete mode 100644 src/wixlib/UtilExtension_Platform.wxi delete mode 100644 src/wixlib/UtilExtension_arm64.wxs delete mode 100644 src/wixlib/UtilExtension_x64.wxs delete mode 100644 src/wixlib/UtilExtension_x86.wxs delete mode 100644 src/wixlib/caDecor.wxi delete mode 100644 src/wixlib/caerr.wxi delete mode 100644 src/wixlib/de-de.wxl delete mode 100644 src/wixlib/en-us.wxl delete mode 100644 src/wixlib/es-es.wxl delete mode 100644 src/wixlib/fr-fr.wxl delete mode 100644 src/wixlib/it-it.wxl delete mode 100644 src/wixlib/ja-jp.wxl delete mode 100644 src/wixlib/pt-br.wxl delete mode 100644 src/wixlib/util.v3.ncrunchproject delete mode 100644 src/wixlib/util.wixproj (limited to 'src') diff --git a/src/.editorconfig b/src/.editorconfig new file mode 100644 index 00000000..1d72e683 --- /dev/null +++ b/src/.editorconfig @@ -0,0 +1,37 @@ +# Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. +# +# Do NOT modify this file. Update the canonical version in Home\repo-template\src\.editorconfig +# then update all of the repos. + +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true + +[*.{cs,vb}] +dotnet_sort_system_directives_first = true + +[*.cs] +csharp_indent_case_contents = true : error +csharp_indent_switch_labels = true : error +csharp_new_line_before_open_brace = all +csharp_prefer_braces = true : error +csharp_style_expression_bodied_methods = when_on_single_line : suggestion +csharp_style_expression_bodied_constructors = when_on_single_line : suggestion +csharp_style_expression_bodied_operators = when_on_single_line : suggestion +csharp_style_expression_bodied_properties = when_on_single_line : suggestion +csharp_style_expression_bodied_indexers = when_on_single_line : suggestion +csharp_style_expression_bodied_accessors = when_on_single_line : suggestion +csharp_style_var_elsewhere = true : suggestion +csharp_style_var_for_built_in_types = true : suggestion +csharp_style_var_when_type_is_apparent = true : suggestion +dotnet_style_qualification_for_event = true : error +dotnet_style_qualification_for_field = true : error +dotnet_style_qualification_for_method = true : error +dotnet_style_qualification_for_property = true : error + +[*.targets] +indent_size = 2 diff --git a/src/CustomizedNativeRecommendedRules.ruleset b/src/CustomizedNativeRecommendedRules.ruleset deleted file mode 100644 index 142b141c..00000000 --- a/src/CustomizedNativeRecommendedRules.ruleset +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/src/Directory.Build.props b/src/Directory.Build.props deleted file mode 100644 index b3c6287c..00000000 --- a/src/Directory.Build.props +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - Debug - false - MSB3246 - - $(MSBuildProjectName) - $([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)..\build\)) - $(BaseOutputPath)obj\$(ProjectName)\ - $(BaseOutputPath)$(Configuration)\ - - WiX Toolset Team - WiX Toolset - Copyright (c) .NET Foundation and contributors. All rights reserved. - MS-RL - WiX Toolset - - - - - diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets deleted file mode 100644 index 2fcc765a..00000000 --- a/src/Directory.Build.targets +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - true - $(SolutionPath) - $(NCrunchOriginalSolutionPath) - - - - - - - $([System.IO.File]::ReadAllText($(TheSolutionPath))) - $([System.IO.Path]::GetDirectoryName( $(TheSolutionPath) )) - (?<="[PackageName]", ")(.*)(?=", ") - - - - - - %(Identity) - $(SolutionFileContent.Contains('\%(Identity).csproj')) - - - - - $(RegexPattern.Replace('[PackageName]','%(PackageName)') ) - $([System.Text.RegularExpressions.Regex]::Match('$(SolutionFileContent)', '%(Pattern)')) - - - - - - - - - - - - - - diff --git a/src/Directory.csproj.props b/src/Directory.csproj.props deleted file mode 100644 index 81d24ad1..00000000 --- a/src/Directory.csproj.props +++ /dev/null @@ -1,13 +0,0 @@ - - - - - true - true - $([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)wix.snk)) - false - - diff --git a/src/Directory.csproj.targets b/src/Directory.csproj.targets deleted file mode 100644 index c3270426..00000000 --- a/src/Directory.csproj.targets +++ /dev/null @@ -1,26 +0,0 @@ - - - - - false - $(OutputPath)\$(AssemblyName).xml - - - - - $(PrivateRepositoryUrl.Replace('.git','')) - - $(MSBuildProjectName).nuspec - $(OutputPath)..\ - $(NuspecProperties);Id=$(PackageId);Authors=$(Authors);Copyright=$(Copyright);Description=$(Description);Title=$(Title) - $(NuspecProperties);Version=$(PackageVersion);RepositoryCommit=$(SourceRevisionId);RepositoryType=$(RepositoryType);RepositoryUrl=$(PrivateRepositoryUrl);ProjectFolder=$(MSBuildProjectDirectory)\;ProjectUrl=$(ProjectUrl) - true - snupkg - - - - diff --git a/src/Directory.vcxproj.props b/src/Directory.vcxproj.props deleted file mode 100644 index 11778f41..00000000 --- a/src/Directory.vcxproj.props +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - Win32 - $(BaseIntermediateOutputPath)$(Configuration)\$(Platform)\ - $(OutputPath)$(Platform)\ - - - $(Company) - $(Copyright) - - win-x86;win-x64;win-arm64 - native,Version=v0.0 - - - - $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) - - - - $(MSBuildThisFileDirectory)CustomizedNativeRecommendedRules.ruleset - - - - - $(DisableSpecificCompilerWarnings) - Level4 - $(ProjectDir)inc;$(MSBuildProjectDirectory);$(IntDir);$(SqlCESdkIncludePath);$(ProjectAdditionalIncludeDirectories);%(AdditionalIncludeDirectories) - WIN32;_WINDOWS;_WIN32_MSI=500;_WIN32_WINNT=0x0501;$(ArmPreprocessorDefinitions);$(UnicodePreprocessorDefinitions);_CRT_STDIO_LEGACY_WIDE_SPECIFIERS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) - Use - precomp.h - StdCall - true - false - -YlprecompDefine - /Zc:threadSafeInit- %(AdditionalOptions) - true - - - $(ArmPreprocessorDefinitions);%(PreprocessorDefinitions) - $(ProjectAdditionalResourceIncludeDirectories);%(AdditionalIncludeDirectories) - - - $(OutDir);$(AdditionalMultiTargetLibraryPath);$(ProjectAdditionalLibraryDirectories);%(AdditionalLibraryDirectories) - - - $(ProjectSubSystem) - $(ProjectModuleDefinitionFile) - $(ResourceOnlyDll) - true - $(ProjectAdditionalLinkLibraries);advapi32.lib;comdlg32.lib;user32.lib;oleaut32.lib;gdi32.lib;shell32.lib;ole32.lib;version.lib;%(AdditionalDependencies) - $(OutDir);$(AdditionalMultiTargetLibraryPath);$(ArmLibraryDirectories);$(ProjectAdditionalLinkLibraryDirectories);%(AdditionalLibraryDirectories) - /IGNORE:4099 %(AdditionalOptions) - - - - - - NoExtensions - - - - - CDecl - - - - - OldStyle - true - true - - - - - Disabled - EnableFastChecks - _DEBUG;DEBUG;%(PreprocessorDefinitions) - MultiThreadedDebug - - - - - MinSpace - NDEBUG;%(PreprocessorDefinitions) - true - true - MultiThreaded - - - true - true - - - diff --git a/src/be/UtilBundleExtension.cpp b/src/be/UtilBundleExtension.cpp deleted file mode 100644 index 2ac842a5..00000000 --- a/src/be/UtilBundleExtension.cpp +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" -#include "BextBaseBundleExtension.h" - -class CWixUtilBundleExtension : public CBextBaseBundleExtension -{ -public: // IBundleExtension - virtual STDMETHODIMP Search( - __in LPCWSTR wzId, - __in LPCWSTR wzVariable - ) - { - HRESULT hr = S_OK; - - hr = UtilSearchExecute(&m_searches, wzId, wzVariable, m_pEngine); - - return hr; - } - -public: //CBextBaseBundleExtension - virtual STDMETHODIMP Initialize( - __in const BUNDLE_EXTENSION_CREATE_ARGS* pCreateArgs - ) - { - HRESULT hr = S_OK; - IXMLDOMDocument* pixdManifest = NULL; - IXMLDOMNode* pixnBundleExtension = NULL; - - hr = CBextBaseBundleExtension::Initialize(pCreateArgs); - ExitOnFailure(hr, "CBextBaseBundleExtension initialization failed."); - - hr = XmlLoadDocumentFromFile(m_sczBundleExtensionDataPath, &pixdManifest); - ExitOnFailure(hr, "Failed to load bundle extension manifest from path: %ls", m_sczBundleExtensionDataPath); - - hr = BextGetBundleExtensionDataNode(pixdManifest, UTIL_BUNDLE_EXTENSION_ID, &pixnBundleExtension); - ExitOnFailure(hr, "Failed to get BundleExtension '%ls'", UTIL_BUNDLE_EXTENSION_ID); - - hr = UtilSearchParseFromXml(&m_searches, pixnBundleExtension); - ExitOnFailure(hr, "Failed to parse searches from bundle extension manifest."); - - LExit: - ReleaseObject(pixnBundleExtension); - ReleaseObject(pixdManifest); - - return hr; - } - -public: - CWixUtilBundleExtension( - __in IBundleExtensionEngine* pEngine - ) : CBextBaseBundleExtension(pEngine) - { - m_searches = { }; - } - - ~CWixUtilBundleExtension() - { - UtilSearchUninitialize(&m_searches); - } - -private: - UTIL_SEARCHES m_searches; -}; - -HRESULT UtilBundleExtensionCreate( - __in IBundleExtensionEngine* pEngine, - __in const BUNDLE_EXTENSION_CREATE_ARGS* pArgs, - __out IBundleExtension** ppBundleExtension - ) -{ - HRESULT hr = S_OK; - CWixUtilBundleExtension* pExtension = NULL; - - pExtension = new CWixUtilBundleExtension(pEngine); - ExitOnNull(pExtension, hr, E_OUTOFMEMORY, "Failed to create new CWixUtilBundleExtension."); - - hr = pExtension->Initialize(pArgs); - ExitOnFailure(hr, "CWixUtilBundleExtension initialization failed"); - - *ppBundleExtension = pExtension; - pExtension = NULL; - -LExit: - ReleaseObject(pExtension); - return hr; -} diff --git a/src/be/UtilBundleExtension.h b/src/be/UtilBundleExtension.h deleted file mode 100644 index c55d6b85..00000000 --- a/src/be/UtilBundleExtension.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - - -// constants - -#define UTIL_BUNDLE_EXTENSION_ID BUNDLE_EXTENSION_DECORATION(L"UtilBundleExtension") - - -// function declarations - -HRESULT UtilBundleExtensionCreate( - __in IBundleExtensionEngine* pEngine, - __in const BUNDLE_EXTENSION_CREATE_ARGS* pArgs, - __out IBundleExtension** ppBundleExtension - ); diff --git a/src/be/beDecor.h b/src/be/beDecor.h deleted file mode 100644 index 2c6a8818..00000000 --- a/src/be/beDecor.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - - -#if defined(_M_ARM64) -#define BUNDLE_EXTENSION_DECORATION(f) L"Wix4" f L"_A64" -#elif defined(_M_AMD64) -#define BUNDLE_EXTENSION_DECORATION(f) L"Wix4" f L"_X64" -#elif defined(_M_ARM) -#define BUNDLE_EXTENSION_DECORATION(f) L"Wix4" f L"_ARM" -#else -#define BUNDLE_EXTENSION_DECORATION(f) L"Wix4" f L"_X86" -#endif diff --git a/src/be/detectsha2support.cpp b/src/be/detectsha2support.cpp deleted file mode 100644 index 90e349cd..00000000 --- a/src/be/detectsha2support.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" - -// https://gist.github.com/navossoc/7572c7d82243e9f818989e2765e7793a -HRESULT DetectSHA2CodeSigning( - __out BOOL* pfSupported - ) -{ - HRESULT hr = S_OK; - HMODULE hModule = NULL; - FARPROC pfn = NULL; - DWORD er = ERROR_SUCCESS; - - hr = LoadSystemLibrary(L"wintrust.dll", &hModule); - ExitOnFailure(hr, "Failed to load wintrust.dll"); - - pfn = ::GetProcAddress(hModule, "CryptCATAdminAcquireContext2"); - if (pfn) - { - *pfSupported = TRUE; - ExitFunction1(hr = S_OK); - } - - er = ::GetLastError(); - if (er == ERROR_PROC_NOT_FOUND) - { - *pfSupported = FALSE; - ExitFunction1(hr = S_OK); - } - - hr = HRESULT_FROM_WIN32(er); - ExitOnFailure(hr, "Failed to probe for CryptCATAdminAcquireContext2 in wintrust.dll"); - -LExit: - ::FreeLibrary(hModule); - - return hr; -} - -HRESULT UtilPerformDetectSHA2CodeSigning( - __in LPCWSTR wzVariable, - __in UTIL_SEARCH* /*pSearch*/, - __in IBundleExtensionEngine* pEngine - ) -{ - HRESULT hr = S_OK; - BOOL fSupported = FALSE; - - hr = DetectSHA2CodeSigning(&fSupported); - ExitOnFailure(hr, "DetectSHA2CodeSigning failed."); - - hr = pEngine->SetVariableNumeric(wzVariable, fSupported ? 1 : 0); - ExitOnFailure(hr, "Failed to set variable '%ls'", wzVariable); - -LExit: - return hr; -} diff --git a/src/be/detectsha2support.h b/src/be/detectsha2support.h deleted file mode 100644 index c38a3d59..00000000 --- a/src/be/detectsha2support.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -HRESULT UtilPerformDetectSHA2CodeSigning( - __in LPCWSTR wzVariable, - __in UTIL_SEARCH* pSearch, - __in IBundleExtensionEngine* pEngine - ); \ No newline at end of file diff --git a/src/be/precomp.cpp b/src/be/precomp.cpp deleted file mode 100644 index 37664a1c..00000000 --- a/src/be/precomp.cpp +++ /dev/null @@ -1,3 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" diff --git a/src/be/precomp.h b/src/be/precomp.h deleted file mode 100644 index 76d24c7b..00000000 --- a/src/be/precomp.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - - -#if _WIN32_MSI < 150 -#define _WIN32_MSI 150 -#endif - -#include -#include -#include -#include - -#include - -#include - -#define MAXUINT USHRT_MAX - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include "beDecor.h" -#include "utilsearch.h" -#include "detectsha2support.h" -#include "UtilBundleExtension.h" diff --git a/src/be/utilbe.cpp b/src/be/utilbe.cpp deleted file mode 100644 index d9816dc7..00000000 --- a/src/be/utilbe.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" -#include "BextBaseBundleExtensionProc.h" - -static IBundleExtension* vpBundleExtension = NULL; - -// function definitions - -extern "C" HRESULT WINAPI BundleExtensionCreate( - __in const BUNDLE_EXTENSION_CREATE_ARGS* pArgs, - __inout BUNDLE_EXTENSION_CREATE_RESULTS* pResults - ) -{ - HRESULT hr = S_OK; - IBundleExtensionEngine* pEngine = NULL; - - hr = XmlInitialize(); - ExitOnFailure(hr, "Failed to initialize XML."); - - hr = BextInitializeFromCreateArgs(pArgs, &pEngine); - ExitOnFailure(hr, "Failed to initialize bext"); - - hr = UtilBundleExtensionCreate(pEngine, pArgs, &vpBundleExtension); - BextExitOnFailure(hr, "Failed to create WixUtilBundleExtension"); - - pResults->pfnBundleExtensionProc = BextBaseBundleExtensionProc; - pResults->pvBundleExtensionProcContext = vpBundleExtension; - -LExit: - ReleaseObject(pEngine); - - return hr; -} - -extern "C" void WINAPI BundleExtensionDestroy() -{ - BextUninitialize(); - ReleaseNullObject(vpBundleExtension); - XmlUninitialize(); -} \ No newline at end of file diff --git a/src/be/utilbe.def b/src/be/utilbe.def deleted file mode 100644 index 711b1a5c..00000000 --- a/src/be/utilbe.def +++ /dev/null @@ -1,8 +0,0 @@ -; Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - - -LIBRARY "utilbe" - -EXPORTS - BundleExtensionCreate - BundleExtensionDestroy diff --git a/src/be/utilbe.vcxproj b/src/be/utilbe.vcxproj deleted file mode 100644 index 683b376a..00000000 --- a/src/be/utilbe.vcxproj +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - Debug - ARM64 - - - Release - ARM64 - - - Debug - X64 - - - Release - X64 - - - Debug - Win32 - - - Release - Win32 - - - - - {630C1EE7-2517-4A8C-83E3-DA1150308B58} - DynamicLibrary - utilbe - v142 - Unicode - utilbe.def - WiX Toolset Util BundleExtension - - - - - - - msi.lib - - - - - - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/be/utilsearch.cpp b/src/be/utilsearch.cpp deleted file mode 100644 index 7cd2ea09..00000000 --- a/src/be/utilsearch.cpp +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" - - -STDMETHODIMP UtilSearchParseFromXml( - __in UTIL_SEARCHES* pSearches, - __in IXMLDOMNode* pixnBundleExtension - ) -{ - HRESULT hr = S_OK; - IXMLDOMNodeList* pixnNodes = NULL; - IXMLDOMNode* pixnNode = NULL; - DWORD cNodes = 0; - BSTR bstrNodeName = NULL; - LPWSTR scz = NULL; - - // Select Util search nodes. - hr = XmlSelectNodes(pixnBundleExtension, L"WixWindowsFeatureSearch", &pixnNodes); - ExitOnFailure(hr, "Failed to select Util search nodes."); - - // Get Util search node count. - hr = pixnNodes->get_length((long*)&cNodes); - ExitOnFailure(hr, "Failed to get Util search node count."); - - if (!cNodes) - { - ExitFunction(); - } - - // Allocate memory for searches. - pSearches->rgSearches = (UTIL_SEARCH*)MemAlloc(sizeof(UTIL_SEARCH) * cNodes, TRUE); - ExitOnNull(pSearches->rgSearches, hr, E_OUTOFMEMORY, "Failed to allocate memory for search structs."); - - pSearches->cSearches = cNodes; - - // Parse search elements. - for (DWORD i = 0; i < cNodes; ++i) - { - UTIL_SEARCH* pSearch = &pSearches->rgSearches[i]; - - hr = XmlNextElement(pixnNodes, &pixnNode, &bstrNodeName); - ExitOnFailure(hr, "Failed to get next node."); - - // @Id - hr = XmlGetAttributeEx(pixnNode, L"Id", &pSearch->sczId); - ExitOnFailure(hr, "Failed to get @Id."); - - // Read type specific attributes. - if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrNodeName, -1, L"WixWindowsFeatureSearch", -1)) - { - pSearch->Type = UTIL_SEARCH_TYPE_WINDOWS_FEATURE_SEARCH; - - // @Type - hr = XmlGetAttributeEx(pixnNode, L"Type", &scz); - ExitOnFailure(hr, "Failed to get @Type."); - - if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"sha2CodeSigning", -1)) - { - pSearch->WindowsFeatureSearch.type = UTIL_WINDOWS_FEATURE_SEARCH_TYPE_SHA2_CODE_SIGNING; - } - else - { - hr = E_INVALIDARG; - ExitOnFailure(hr, "Invalid value for @Type: %ls", scz); - } - } - else - { - hr = E_UNEXPECTED; - ExitOnFailure(hr, "Unexpected element name: %ls", bstrNodeName); - } - - // prepare next iteration - ReleaseNullObject(pixnNode); - ReleaseNullBSTR(bstrNodeName); - } - -LExit: - ReleaseStr(scz); - ReleaseBSTR(bstrNodeName); - ReleaseObject(pixnNode); - ReleaseObject(pixnNodes); - - return hr; -} - -void UtilSearchUninitialize( - __in UTIL_SEARCHES* pSearches - ) -{ - if (pSearches->rgSearches) - { - for (DWORD i = 0; i < pSearches->cSearches; ++i) - { - UTIL_SEARCH* pSearch = &pSearches->rgSearches[i]; - - ReleaseStr(pSearch->sczId); - } - MemFree(pSearches->rgSearches); - } -} - -STDMETHODIMP UtilSearchExecute( - __in UTIL_SEARCHES* pSearches, - __in LPCWSTR wzSearchId, - __in LPCWSTR wzVariable, - __in IBundleExtensionEngine* pEngine - ) -{ - HRESULT hr = S_OK; - UTIL_SEARCH* pSearch = NULL; - - hr = UtilSearchFindById(pSearches, wzSearchId, &pSearch); - ExitOnFailure(hr, "Search id '%ls' is unknown to the util extension."); - - switch (pSearch->Type) - { - case UTIL_SEARCH_TYPE_WINDOWS_FEATURE_SEARCH: - switch (pSearch->WindowsFeatureSearch.type) - { - case UTIL_WINDOWS_FEATURE_SEARCH_TYPE_SHA2_CODE_SIGNING: - hr = UtilPerformDetectSHA2CodeSigning(wzVariable, pSearch, pEngine); - break; - default: - hr = E_UNEXPECTED; - } - break; - default: - hr = E_UNEXPECTED; - } - -LExit: - return hr; -} - -STDMETHODIMP UtilSearchFindById( - __in UTIL_SEARCHES* pSearches, - __in LPCWSTR wzId, - __out UTIL_SEARCH** ppSearch - ) -{ - HRESULT hr = S_OK; - - for (DWORD i = 0; i < pSearches->cSearches; ++i) - { - UTIL_SEARCH* pSearch = &pSearches->rgSearches[i]; - - if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pSearch->sczId, -1, wzId, -1)) - { - *ppSearch = pSearch; - ExitFunction1(hr = S_OK); - } - } - - hr = E_NOTFOUND; - -LExit: - return hr; -} diff --git a/src/be/utilsearch.h b/src/be/utilsearch.h deleted file mode 100644 index deeab1f7..00000000 --- a/src/be/utilsearch.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - - -// constants - -enum UTIL_SEARCH_TYPE -{ - UTIL_SEARCH_TYPE_NONE, - UTIL_SEARCH_TYPE_WINDOWS_FEATURE_SEARCH, -}; - -enum UTIL_WINDOWS_FEATURE_SEARCH_TYPE -{ - UTIL_WINDOWS_FEATURE_SEARCH_TYPE_NONE, - UTIL_WINDOWS_FEATURE_SEARCH_TYPE_SHA2_CODE_SIGNING, -}; - - -// structs - -typedef struct _UTIL_SEARCH -{ - LPWSTR sczId; - - UTIL_SEARCH_TYPE Type; - union - { - struct - { - UTIL_WINDOWS_FEATURE_SEARCH_TYPE type; - } WindowsFeatureSearch; - }; -} UTIL_SEARCH; - -typedef struct _UTIL_SEARCHES -{ - UTIL_SEARCH* rgSearches; - DWORD cSearches; -} UTIL_SEARCHES; - - -// function declarations - -STDMETHODIMP UtilSearchParseFromXml( - __in UTIL_SEARCHES* pSearches, - __in IXMLDOMNode* pixnBundleExtension - ); - -void UtilSearchUninitialize( - __in UTIL_SEARCHES* pSearches - ); - -STDMETHODIMP UtilSearchExecute( - __in UTIL_SEARCHES* pSearches, - __in LPCWSTR wzSearchId, - __in LPCWSTR wzVariable, - __in IBundleExtensionEngine* pEngine - ); - -STDMETHODIMP UtilSearchFindById( - __in UTIL_SEARCHES* pSearches, - __in LPCWSTR wzId, - __out UTIL_SEARCH** ppSearch - ); diff --git a/src/ca/BroadcastSettingChange.cpp b/src/ca/BroadcastSettingChange.cpp deleted file mode 100644 index 2e153ad3..00000000 --- a/src/ca/BroadcastSettingChange.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" - - -/******************************************************************** -WixBroadcastSettingChange - - Send WM_SETTINGCHANGE message to all top-level windows indicating - that unspecified settings have changed. -********************************************************************/ -extern "C" UINT __stdcall WixBroadcastSettingChange( - __in MSIHANDLE hInstall - ) -{ - HRESULT hr = WcaInitialize(hInstall, "WixBroadcastSettingChange"); - ExitOnFailure(hr, "failed to initialize WixBroadcastSettingChange"); - - // best effort; ignore failures - ::SendMessageTimeoutW(HWND_BROADCAST, WM_SETTINGCHANGE, NULL, NULL, SMTO_ABORTIFHUNG, 1000, NULL); - -LExit: - return WcaFinalize(ERROR_SUCCESS); -} - - -/******************************************************************** -WixBroadcastEnvironmentChange - - Send WM_SETTINGCHANGE message to all top-level windows indicating - that environment variables have changed. -********************************************************************/ -extern "C" UINT __stdcall WixBroadcastEnvironmentChange( - __in MSIHANDLE hInstall - ) -{ - HRESULT hr = WcaInitialize(hInstall, "WixBroadcastEnvironmentChange"); - ExitOnFailure(hr, "failed to initialize WixBroadcastEnvironmentChange"); - - // best effort; ignore failures - ::SendMessageTimeoutW(HWND_BROADCAST, WM_SETTINGCHANGE, NULL, reinterpret_cast(L"Environment"), SMTO_ABORTIFHUNG, 1000, NULL); - -LExit: - return WcaFinalize(ERROR_SUCCESS); -} diff --git a/src/ca/CheckReboot.cpp b/src/ca/CheckReboot.cpp deleted file mode 100644 index ce056411..00000000 --- a/src/ca/CheckReboot.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" - - -/******************************************************************** -WixCheckRebootRequired - entry point for WixCheckRebootRequired Custom Action - - called as Type 1 CustomAction (binary DLL) from Windows Installer - in InstallExecuteSequence after InstallFinalize -********************************************************************/ -extern "C" UINT __stdcall WixCheckRebootRequired( - __in MSIHANDLE hInstall - ) -{ - HRESULT hr = S_OK; - DWORD er = ERROR_SUCCESS; - - hr = WcaInitialize(hInstall, "WixCheckRebootRequired"); - ExitOnFailure(hr, "failed to initialize"); - - if (WcaDidDeferredActionRequireReboot()) - { - WcaLog(LOGMSG_STANDARD, "Reboot required by deferred CustomAction."); - - er = ::MsiSetMode(hInstall, MSIRUNMODE_REBOOTATEND, TRUE); - hr = HRESULT_FROM_WIN32(er); - ExitOnFailure(hr, "Failed to schedule reboot."); - } - -LExit: - - if (FAILED(hr)) - er = ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} diff --git a/src/ca/CloseApps.cpp b/src/ca/CloseApps.cpp deleted file mode 100644 index d4256c43..00000000 --- a/src/ca/CloseApps.cpp +++ /dev/null @@ -1,568 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" - -#define DEFAULT_PROCESS_EXIT_WAIT_TIME 5000 - -// structs -LPCWSTR wzQUERY_CLOSEAPPS = L"SELECT `Wix4CloseApplication`, `Target`, `Description`, `Condition`, `Attributes`, `Property`, `TerminateExitCode`, `Timeout` FROM `Wix4CloseApplication` ORDER BY `Sequence`"; -enum eQUERY_CLOSEAPPS { QCA_ID = 1, QCA_TARGET, QCA_DESCRIPTION, QCA_CONDITION, QCA_ATTRIBUTES, QCA_PROPERTY, QCA_TERMINATEEXITCODE, QCA_TIMEOUT }; - -// CloseApplication.Attributes -enum CLOSEAPP_ATTRIBUTES -{ - CLOSEAPP_ATTRIBUTE_NONE = 0x0, - CLOSEAPP_ATTRIBUTE_CLOSEMESSAGE = 0x1, - CLOSEAPP_ATTRIBUTE_REBOOTPROMPT = 0x2, - CLOSEAPP_ATTRIBUTE_ELEVATEDCLOSEMESSAGE = 0x4, - CLOSEAPP_ATTRIBUTE_ENDSESSIONMESSAGE = 0x8, - CLOSEAPP_ATTRIBUTE_ELEVATEDENDSESSIONMESSAGE = 0x10, - CLOSEAPP_ATTRIBUTE_TERMINATEPROCESS = 0x20, - CLOSEAPP_ATTRIBUTE_PROMPTTOCONTINUE = 0x40, -}; - -struct PROCESS_AND_MESSAGE -{ - DWORD dwProcessId; - DWORD dwMessageId; - DWORD dwTimeout; -}; - - -/****************************************************************** - EnumWindowsProc - callback function which sends message if the - current window matches the passed in process ID - -******************************************************************/ -BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) -{ - PROCESS_AND_MESSAGE* pPM = reinterpret_cast(lParam); - DWORD dwProcessId = 0; - DWORD_PTR dwResult = 0; - BOOL fQueryEndSession = WM_QUERYENDSESSION == pPM->dwMessageId; - BOOL fContinueWindowsInProcess = TRUE; // assume we will send message to all top-level windows in a process. - - ::GetWindowThreadProcessId(hwnd, &dwProcessId); - - // check if the process Id is the one we're looking for - if (dwProcessId != pPM->dwProcessId) - { - return TRUE; - } - - WcaLog(LOGMSG_VERBOSE, "Sending message to process id 0x%x", dwProcessId); - - if (::SendMessageTimeoutW(hwnd, pPM->dwMessageId, 0, fQueryEndSession ? ENDSESSION_CLOSEAPP : 0, SMTO_BLOCK, pPM->dwTimeout, &dwResult)) - { - WcaLog(LOGMSG_VERBOSE, "Result 0x%x", dwResult); - - if (fQueryEndSession) - { - // If application said it was okay to close, do that. - if (dwResult) - { - ::SendMessageTimeoutW(hwnd, WM_ENDSESSION, TRUE, ENDSESSION_CLOSEAPP, SMTO_BLOCK, pPM->dwTimeout, &dwResult); - } - else // application said don't try to close it, so don't bother sending messages to any other top-level windows. - { - fContinueWindowsInProcess = FALSE; - } - } - } - else // log result message. - { - WcaLog(LOGMSG_VERBOSE, "Failed to send message id: %u, error: 0x%x", pPM->dwMessageId, ::GetLastError()); - } - - // so we know we succeeded - ::SetLastError(ERROR_SUCCESS); - - return fContinueWindowsInProcess; -} - -/****************************************************************** - PromptToContinue - displays the prompt if the application is still - running. - -******************************************************************/ -static HRESULT PromptToContinue( - __in_z LPCWSTR wzApplication, - __in_z LPCWSTR wzPrompt - ) -{ - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - PMSIHANDLE hRecMessage = NULL; - DWORD *prgProcessIds = NULL; - DWORD cProcessIds = 0; - - hRecMessage = ::MsiCreateRecord(1); - ExitOnNull(hRecMessage, hr, E_OUTOFMEMORY, "Failed to create record for prompt."); - - er = ::MsiRecordSetStringW(hRecMessage, 0, wzPrompt); - ExitOnWin32Error(er, hr, "Failed to set prompt record field string"); - - do - { - hr = ProcFindAllIdsFromExeName(wzApplication, &prgProcessIds, &cProcessIds); - if (SUCCEEDED(hr) && 0 < cProcessIds) - { - er = WcaProcessMessage(static_cast(INSTALLMESSAGE_WARNING | MB_ABORTRETRYIGNORE | MB_DEFBUTTON3 | MB_ICONWARNING), hRecMessage); - if (IDABORT == er) - { - hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT); - } - else if (IDRETRY == er) - { - hr = S_FALSE; - } - else if (IDIGNORE == er) - { - hr = S_OK; - } - else - { - ExitOnWin32Error(er, hr, "Unexpected return value from prompt to continue."); - } - } - - ReleaseNullMem(prgProcessIds); - cProcessIds = 0; - } while (S_FALSE == hr); - -LExit: - ReleaseMem(prgProcessIds); - return hr; -} - -/****************************************************************** - SendProcessMessage - helper function to enumerate the top-level - windows and send to all matching a process ID. - -******************************************************************/ -void SendProcessMessage( - __in DWORD dwProcessId, - __in DWORD dwMessageId, - __in DWORD dwTimeout - ) -{ - WcaLog(LOGMSG_VERBOSE, "Attempting to send process id 0x%x message id: %u", dwProcessId, dwMessageId); - - PROCESS_AND_MESSAGE pm = { }; - pm.dwProcessId = dwProcessId; - pm.dwMessageId = dwMessageId; - pm.dwTimeout = dwTimeout; - - if (!::EnumWindows(EnumWindowsProc, reinterpret_cast(&pm))) - { - DWORD dwLastError = ::GetLastError(); - if (ERROR_SUCCESS != dwLastError) - { - WcaLog(LOGMSG_VERBOSE, "CloseApp enumeration error: 0x%x", dwLastError); - } - } -} - -/****************************************************************** - SendApplicationMessage - helper function to iterate through the - processes for the specified application and send all - applicable process Ids a message and give them time to process - the message. - -******************************************************************/ -void SendApplicationMessage( - __in LPCWSTR wzApplication, - __in DWORD dwMessageId, - __in DWORD dwTimeout - ) -{ - DWORD *prgProcessIds = NULL; - DWORD cProcessIds = 0, iProcessId; - HRESULT hr = S_OK; - - WcaLog(LOGMSG_VERBOSE, "Checking App: %ls ", wzApplication); - - hr = ProcFindAllIdsFromExeName(wzApplication, &prgProcessIds, &cProcessIds); - - if (SUCCEEDED(hr) && 0 < cProcessIds) - { - WcaLog(LOGMSG_VERBOSE, "App: %ls found running, %d processes, attempting to send message.", wzApplication, cProcessIds); - - for (iProcessId = 0; iProcessId < cProcessIds; ++iProcessId) - { - SendProcessMessage(prgProcessIds[iProcessId], dwMessageId, dwTimeout); - } - - ProcWaitForIds(prgProcessIds, cProcessIds, dwTimeout); - } - - ReleaseMem(prgProcessIds); -} - -/****************************************************************** - SetRunningProcessProperty - helper function that sets the specified - property if there are any instances of the specified executable - running. Useful to show custom UI to ask for shutdown. -******************************************************************/ -void SetRunningProcessProperty( - __in LPCWSTR wzApplication, - __in LPCWSTR wzProperty - ) -{ - DWORD *prgProcessIds = NULL; - DWORD cProcessIds = 0; - HRESULT hr = S_OK; - - WcaLog(LOGMSG_VERBOSE, "Checking App: %ls ", wzApplication); - - hr = ProcFindAllIdsFromExeName(wzApplication, &prgProcessIds, &cProcessIds); - - if (SUCCEEDED(hr) && 0 < cProcessIds) - { - WcaLog(LOGMSG_VERBOSE, "App: %ls found running, %d processes, setting '%ls' property.", wzApplication, cProcessIds, wzProperty); - WcaSetIntProperty(wzProperty, cProcessIds); - } - - ReleaseMem(prgProcessIds); -} - -/****************************************************************** - TerminateProcesses - helper function that kills the provided set of - process ids such that they return a particular exit code. -******************************************************************/ -void TerminateProcesses( - __in_ecount(cProcessIds) DWORD rgdwProcessIds[], - __in DWORD cProcessIds, - __in DWORD dwExitCode - ) -{ - for (DWORD i = 0; i < cProcessIds; ++i) - { - HANDLE hProcess = ::OpenProcess(PROCESS_TERMINATE, FALSE, rgdwProcessIds[i]); - if (hProcess) - { - ::TerminateProcess(hProcess, dwExitCode); - ::CloseHandle(hProcess); - } - } -} - -/****************************************************************** - WixCloseApplications - entry point for WixCloseApplications Custom Action - - called as Type 1 CustomAction (binary DLL) from Windows Installer - in InstallExecuteSequence before InstallFiles -******************************************************************/ -extern "C" UINT __stdcall WixCloseApplications( - __in MSIHANDLE hInstall - ) -{ - //AssertSz(FALSE, "debug WixCloseApplications"); - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - - LPWSTR pwzData = NULL; - LPWSTR pwzId = NULL; - LPWSTR pwzTarget = NULL; - LPWSTR pwzDescription = NULL; - LPWSTR pwzCondition = NULL; - LPWSTR pwzProperty = NULL; - DWORD dwAttributes = 0; - DWORD dwTimeout = 0; - DWORD dwTerminateExitCode = 0; - MSICONDITION condition = MSICONDITION_NONE; - - DWORD cCloseApps = 0; - - PMSIHANDLE hView = NULL; - PMSIHANDLE hRec = NULL; - MSIHANDLE hListboxTable = NULL; - MSIHANDLE hListboxColumns = NULL; - - LPWSTR pwzCustomActionData = NULL; - //DWORD cchCustomActionData = 0; - - // - // initialize - // - hr = WcaInitialize(hInstall, "WixCloseApplications"); - ExitOnFailure(hr, "failed to initialize"); - - // - // loop through all the objects to be secured - // - hr = WcaOpenExecuteView(wzQUERY_CLOSEAPPS, &hView); - ExitOnFailure(hr, "failed to open view on Wix4CloseApplication table"); - while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) - { - hr = WcaGetRecordString(hRec, QCA_ID, &pwzId); - ExitOnFailure(hr, "failed to get id from Wix4CloseApplication table"); - - hr = WcaGetRecordString(hRec, QCA_CONDITION, &pwzCondition); - ExitOnFailure(hr, "failed to get condition from Wix4CloseApplication table"); - - if (pwzCondition && *pwzCondition) - { - condition = ::MsiEvaluateConditionW(hInstall, pwzCondition); - if (MSICONDITION_ERROR == condition) - { - hr = E_INVALIDARG; - ExitOnFailure(hr, "failed to process condition for Wix4CloseApplication '%ls'", pwzId); - } - else if (MSICONDITION_FALSE == condition) - { - continue; // skip processing this target - } - } - - hr = WcaGetRecordFormattedString(hRec, QCA_TARGET, &pwzTarget); - ExitOnFailure(hr, "failed to get target from Wix4CloseApplication table"); - - hr = WcaGetRecordFormattedString(hRec, QCA_DESCRIPTION, &pwzDescription); - ExitOnFailure(hr, "failed to get description from Wix4CloseApplication table"); - - hr = WcaGetRecordInteger(hRec, QCA_ATTRIBUTES, reinterpret_cast(&dwAttributes)); - ExitOnFailure(hr, "failed to get attributes from Wix4CloseApplication table"); - - hr = WcaGetRecordFormattedString(hRec, QCA_PROPERTY, &pwzProperty); - ExitOnFailure(hr, "failed to get property from Wix4CloseApplication table"); - - hr = WcaGetRecordInteger(hRec, QCA_TERMINATEEXITCODE, reinterpret_cast(&dwTerminateExitCode)); - if (S_FALSE == hr) - { - dwTerminateExitCode = 0; - hr = S_OK; - } - ExitOnFailure(hr, "failed to get terminate exit-code from Wix4CloseApplication table"); - - hr = WcaGetRecordInteger(hRec, QCA_TIMEOUT, reinterpret_cast(&dwTimeout)); - if (S_FALSE == hr) - { - dwTimeout = DEFAULT_PROCESS_EXIT_WAIT_TIME; - hr = S_OK; - } - ExitOnFailure(hr, "failed to get timeout from Wix4CloseApplication table"); - - // Before trying any changes to the machine, prompt if requested. - if (dwAttributes & CLOSEAPP_ATTRIBUTE_PROMPTTOCONTINUE) - { - hr = PromptToContinue(pwzTarget, pwzDescription ? pwzDescription : L""); - if (HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT) == hr) - { - // Skip error message if user canceled. - ExitFunction(); - } - ExitOnFailure(hr, "Failure while prompting user to continue to close application."); - } - - // - // send WM_CLOSE or WM_QUERYENDSESSION to currently running applications - // - if (dwAttributes & CLOSEAPP_ATTRIBUTE_CLOSEMESSAGE) - { - SendApplicationMessage(pwzTarget, WM_CLOSE, dwTimeout); - } - - if (dwAttributes & CLOSEAPP_ATTRIBUTE_ENDSESSIONMESSAGE) - { - SendApplicationMessage(pwzTarget, WM_QUERYENDSESSION, dwTimeout); - } - - // - // Pass the targets to the deferred action in case the app comes back - // even if we close it now. - // - if (dwAttributes & (CLOSEAPP_ATTRIBUTE_ELEVATEDCLOSEMESSAGE | CLOSEAPP_ATTRIBUTE_ELEVATEDENDSESSIONMESSAGE | CLOSEAPP_ATTRIBUTE_REBOOTPROMPT | CLOSEAPP_ATTRIBUTE_TERMINATEPROCESS)) - { - hr = WcaWriteStringToCaData(pwzTarget, &pwzCustomActionData); - ExitOnFailure(hr, "failed to add target data to CustomActionData"); - - hr = WcaWriteIntegerToCaData(dwAttributes, &pwzCustomActionData); - ExitOnFailure(hr, "failed to add attribute data to CustomActionData"); - - hr = WcaWriteIntegerToCaData(dwTimeout, &pwzCustomActionData); - ExitOnFailure(hr, "failed to add timeout data to CustomActionData"); - - hr = WcaWriteIntegerToCaData(dwTerminateExitCode, &pwzCustomActionData); - ExitOnFailure(hr, "failed to add timeout data to CustomActionData"); - } - - if (pwzProperty && *pwzProperty) - { - SetRunningProcessProperty(pwzTarget, pwzProperty); - } - - ++cCloseApps; - } - - // if we looped through all records all is well - if (E_NOMOREITEMS == hr) - { - hr = S_OK; - } - ExitOnFailure(hr, "failed while looping through all apps to close"); - - // - // Do the UI dance now. - // - /* - - TODO: Do this eventually - - if (cCloseApps) - { - while (TRUE) - { - for (DWORD i = 0; i < cCloseApps; ++i) - { - hr = WcaAddTempRecord(&hListboxTable, &hListboxColumns, L"ListBox", NULL, 0, 4, L"FileInUseProcess", i, target, description); - if (FAILED(hr)) - { - } - } - } - } - */ - - // - // schedule the custom action and add to progress bar - // - if (pwzCustomActionData && *pwzCustomActionData) - { - Assert(0 < cCloseApps); - - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"CloseApplicationsDeferred"), pwzCustomActionData, cCloseApps * COST_CLOSEAPP); - ExitOnFailure(hr, "failed to schedule CloseApplicationsDeferred action"); - } - -LExit: - if (hListboxColumns) - { - ::MsiCloseHandle(hListboxColumns); - } - if (hListboxTable) - { - ::MsiCloseHandle(hListboxTable); - } - - ReleaseStr(pwzCustomActionData); - ReleaseStr(pwzData); - ReleaseStr(pwzProperty); - ReleaseStr(pwzCondition); - ReleaseStr(pwzDescription); - ReleaseStr(pwzTarget); - ReleaseStr(pwzId); - - if (FAILED(hr)) - { - er = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT) == hr ? ERROR_INSTALL_USEREXIT : ERROR_INSTALL_FAILURE; - } - return WcaFinalize(er); -} - - -/****************************************************************** - WixCloseApplicationsDeferred - entry point for - WixCloseApplicationsDeferred Custom Action - called as Type 1025 CustomAction - (deferred binary DLL) - - NOTE: deferred CustomAction since it modifies the machine - NOTE: CustomActionData == wzTarget\tdwAttributes\tdwTimeout\tdwTerminateExitCode\t... -******************************************************************/ -extern "C" UINT __stdcall WixCloseApplicationsDeferred( - __in MSIHANDLE hInstall - ) -{ - //AssertSz(FALSE, "debug WixCloseApplicationsDeferred"); - HRESULT hr = S_OK; - DWORD er = ERROR_SUCCESS; - - LPWSTR pwz = NULL; - LPWSTR pwzData = NULL; - LPWSTR pwzTarget = NULL; - DWORD dwAttributes = 0; - DWORD dwTimeout = 0; - DWORD dwTerminateExitCode = 0; - - DWORD *prgProcessIds = NULL; - DWORD cProcessIds = 0; - - // - // initialize - // - hr = WcaInitialize(hInstall, "WixCloseApplicationsDeferred"); - ExitOnFailure(hr, "failed to initialize"); - - hr = WcaGetProperty(L"CustomActionData", &pwzData); - ExitOnFailure(hr, "failed to get CustomActionData"); - - WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); - - pwz = pwzData; - - // - // loop through all the passed in data - // - while (pwz && *pwz) - { - hr = WcaReadStringFromCaData(&pwz, &pwzTarget); - ExitOnFailure(hr, "failed to process target from CustomActionData"); - - hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&dwAttributes)); - ExitOnFailure(hr, "failed to process attributes from CustomActionData"); - - hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&dwTimeout)); - ExitOnFailure(hr, "failed to process timeout from CustomActionData"); - - hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&dwTerminateExitCode)); - ExitOnFailure(hr, "failed to process terminate exit code from CustomActionData"); - - WcaLog(LOGMSG_VERBOSE, "Checking for App: %ls Attributes: %d", pwzTarget, dwAttributes); - - // - // send WM_CLOSE or WM_QUERYENDSESSION to currently running applications - // - if (dwAttributes & CLOSEAPP_ATTRIBUTE_ELEVATEDCLOSEMESSAGE) - { - SendApplicationMessage(pwzTarget, WM_CLOSE, dwTimeout); - } - - if (dwAttributes & CLOSEAPP_ATTRIBUTE_ELEVATEDENDSESSIONMESSAGE) - { - SendApplicationMessage(pwzTarget, WM_QUERYENDSESSION, dwTimeout); - } - - // If we find that an app that we need closed is still runing, require a - // restart or kill the process as directed. - ProcFindAllIdsFromExeName(pwzTarget, &prgProcessIds, &cProcessIds); - if (0 < cProcessIds) - { - if (dwAttributes & CLOSEAPP_ATTRIBUTE_REBOOTPROMPT) - { - WcaLog(LOGMSG_VERBOSE, "App: %ls found running, requiring a reboot.", pwzTarget); - - WcaDeferredActionRequiresReboot(); - } - else if (dwAttributes & CLOSEAPP_ATTRIBUTE_TERMINATEPROCESS) - { - TerminateProcesses(prgProcessIds, cProcessIds, dwTerminateExitCode); - } - } - - hr = WcaProgressMessage(COST_CLOSEAPP, FALSE); - ExitOnFailure(hr, "failed to send progress message"); - } - -LExit: - ReleaseMem(prgProcessIds); - - ReleaseStr(pwzTarget); - ReleaseStr(pwzData); - - if (FAILED(hr)) - { - er = ERROR_INSTALL_FAILURE; - } - return WcaFinalize(er); -} diff --git a/src/ca/CustomMsiErrors.h b/src/ca/CustomMsiErrors.h deleted file mode 100644 index 3218b61b..00000000 --- a/src/ca/CustomMsiErrors.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - - -#define msierrSecureObjectsFailedCreateSD 25520 -#define msierrSecureObjectsFailedSet 25521 -#define msierrSecureObjectsUnknownType 25522 - -#define msierrXmlFileFailedRead 25530 -#define msierrXmlFileFailedOpen 25531 -#define msierrXmlFileFailedSelect 25532 -#define msierrXmlFileFailedSave 25533 - -#define msierrXmlConfigFailedRead 25540 -#define msierrXmlConfigFailedOpen 25541 -#define msierrXmlConfigFailedSelect 25542 -#define msierrXmlConfigFailedSave 25543 - -#define msierrPERFMONFailedRegisterDLL 26251 -#define msierrPERFMONFailedUnregisterDLL 26252 -#define msierrInstallPerfCounterData 26253 -#define msierrUninstallPerfCounterData 26254 - -#define msierrSMBFailedCreate 26301 -#define msierrSMBFailedDrop 26302 -#define msierrUSRFailedUserCreate 26401 -#define msierrUSRFailedUserCreatePswd 26402 -#define msierrUSRFailedUserGroupAdd 26403 -#define msierrUSRFailedUserCreateExists 26404 -#define msierrUSRFailedGrantLogonAsService 26405 - -//Last available is 26450 \ No newline at end of file diff --git a/src/ca/FormatFiles.cpp b/src/ca/FormatFiles.cpp deleted file mode 100644 index d1533999..00000000 --- a/src/ca/FormatFiles.cpp +++ /dev/null @@ -1,221 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" - -const UINT COST_FILEFORMATTING = 2000; - - -// -// WixSchedFormatFiles - immediate CA to schedule format files CAs -// -extern "C" UINT __stdcall WixSchedFormatFiles( - __in MSIHANDLE hInstall - ) -{ - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - PSCZ sczBinaryKey; - PSCZ sczFileKey; - PSCZ sczComponentKey; - PSCZ sczFormattedFile; - PSCZ sczFilePath; - PMSIHANDLE hView; - PMSIHANDLE hRec; - PSCZ sczFileContent; - PSCZ sczFormattedContent; - PSCZ sczExecCustomActionData; - PSCZ sczRollbackCustomActionData; - - LPCWSTR wzQuery = - L"SELECT `Wix4FormatFile`.`Binary_`, `Wix4FormatFile`.`File_`, `File`.`Component_` " - L"FROM `Wix4FormatFile`, `File` " - L"WHERE `Wix4FormatFile`.`File_` = `File`.`File`"; - enum eQuery { eqBinaryKey = 1, eqFileKey, eqComponentKey }; - - // initialize - hr = WcaInitialize(hInstall, "WixSchedFormatFiles"); - ExitOnFailure(hr, "Failed to initialize for WixSchedFormatFiles."); - - // query and loop through all the files - hr = WcaOpenExecuteView(wzQuery, &hView); - ExitOnFailure(hr, "Failed to open view on Wix4FormatFile table"); - - DWORD cFiles = 0; - while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) - { - ++cFiles; - - hr = WcaGetRecordString(hRec, eqBinaryKey, &sczBinaryKey); - ExitOnFailure(hr, "Failed to get Binary table key."); - - hr = WcaGetRecordString(hRec, eqFileKey, &sczFileKey); - ExitOnFailure(hr, "Failed to get File table key."); - - hr = WcaGetRecordString(hRec, eqComponentKey, &sczComponentKey); - ExitOnFailure(hr, "Failed to get Component table key."); - - // we need to know if the component's being installed, uninstalled, or reinstalled - WCA_TODO todo = WcaGetComponentToDo(sczComponentKey); - if (WCA_TODO_INSTALL == todo || WCA_TODO_REINSTALL == todo) - { - // turn the file key into the path to the target file - hr = StrAllocFormatted(&sczFormattedFile, L"[#%ls]", sczFileKey); - ExitOnFailure(hr, "Failed to format file string for file: %ls", sczFileKey); - hr = WcaGetFormattedString(sczFormattedFile, &sczFilePath); - ExitOnFailure(hr, "Failed to get path for file: %ls", sczFileKey); - - // extract binary to string - WCA_ENCODING encoding = WCA_ENCODING_UNKNOWN; - hr = WcaExtractBinaryToString(sczBinaryKey, &sczFileContent, &encoding); - ExitOnFailure(hr, "Failed to extract binary: %ls", sczBinaryKey); - - // format string - hr = WcaGetFormattedString(sczFileContent, &sczFormattedContent); - ExitOnFailure(hr, "Failed to format file content: %ls", sczFileContent); - - // write to deferred custom action data - hr = WcaWriteStringToCaData(sczFilePath, &sczExecCustomActionData); - ExitOnFailure(hr, "Failed to write deferred custom action data for file: %ls", sczFilePath); - - hr = WcaWriteIntegerToCaData(encoding, &sczExecCustomActionData); - ExitOnFailure(hr, "Failed to write deferred custom action data for encoding: %d", encoding); - - hr = WcaWriteStringToCaData(sczFormattedContent, &sczExecCustomActionData); - ExitOnFailure(hr, "Failed to write deferred custom action data for file content: %ls", sczFilePath); - - // write to rollback custom action data - hr = WcaWriteStringToCaData(sczFilePath, &sczRollbackCustomActionData); - ExitOnFailure(hr, "Failed to write rollback custom action data for file: %ls", sczFilePath); - - hr = WcaWriteIntegerToCaData(encoding, &sczRollbackCustomActionData); - ExitOnFailure(hr, "Failed to write deferred custom action data for encoding: %d", encoding); - - hr = WcaWriteStringToCaData(sczFileContent, &sczRollbackCustomActionData); - ExitOnFailure(hr, "Failed to write rollback custom action data for file content: %ls", sczFilePath); - } - } - - // reaching the end of the list is actually a good thing, not an error - if (E_NOMOREITEMS == hr) - { - hr = S_OK; - } - ExitOnFailure(hr, "Failure occurred while processing Wix4FormatFile table"); - - // schedule deferred CAs if there's anything to do - if (sczRollbackCustomActionData && *sczRollbackCustomActionData) - { - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackFormatFiles"), sczRollbackCustomActionData, cFiles * COST_FILEFORMATTING); - ExitOnFailure(hr, "Failed to schedule RollbackFormatFiles"); - } - - if (sczExecCustomActionData && *sczExecCustomActionData) - { - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecFormatFiles"), sczExecCustomActionData, cFiles * COST_FILEFORMATTING); - ExitOnFailure(hr, "Failed to schedule ExecFormatFiles"); - } - -LExit: - return WcaFinalize(er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er); -} - - -// -// WixExecFormatFiles - deferred and rollback CAs to write formatted files -// -extern "C" UINT __stdcall WixExecFormatFiles( - __in MSIHANDLE hInstall - ) -{ - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - PSCZ sczCustomActionData; - LPWSTR pwz = NULL; - PSCZ sczFilePath; - PSCZ sczFileContent; - LPSTR psz = NULL; - - // initialize - hr = WcaInitialize(hInstall, "WixExecFormatFiles"); - ExitOnFailure(hr, "Failed to initialize for WixExecFormatFiles."); - - hr = WcaGetProperty(L"CustomActionData", &sczCustomActionData); - ExitOnFailure(hr, "Failed to get CustomActionData."); -#ifdef _DEBUG - WcaLog(LOGMSG_STANDARD, "CustomActionData: %ls", sczCustomActionData); -#endif - - // loop through all the passed in data - pwz = sczCustomActionData; - while (pwz && *pwz) - { - // extract the custom action data - hr = WcaReadStringFromCaData(&pwz, &sczFilePath); - ExitOnFailure(hr, "Failed to read file path from custom action data"); - - WCA_ENCODING encoding = WCA_ENCODING_UNKNOWN; - hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&encoding)); - ExitOnFailure(hr, "Failed to read encoding from custom action data"); - - hr = WcaReadStringFromCaData(&pwz, &sczFileContent); - ExitOnFailure(hr, "Failed to read file content from custom action data"); - - // re-encode content - LPCBYTE pbData = NULL; - size_t cbData = 0; - switch (encoding) - { - case WCA_ENCODING_UTF_16: - pbData = reinterpret_cast(LPCWSTR(sczFileContent)); - cbData = lstrlenW(sczFileContent) * sizeof(WCHAR); - break; - - case WCA_ENCODING_UTF_8: - hr = StrAnsiAllocString(&psz, sczFileContent, 0, CP_UTF8); - ExitOnFailure(hr, "Failed to convert Unicode to UTF-8."); - pbData = reinterpret_cast(psz); - - hr = ::StringCbLengthA(psz, STRSAFE_MAX_CCH, &cbData); - ExitOnFailure(hr, "Failed to count UTF-8 bytes."); - break; - - case WCA_ENCODING_ANSI: - hr = StrAnsiAllocString(&psz, sczFileContent, 0, CP_ACP); - ExitOnFailure(hr, "Failed to convert Unicode to ANSI."); - pbData = reinterpret_cast(psz); - - hr = ::StringCbLengthA(psz, STRSAFE_MAX_CCH, &cbData); - ExitOnFailure(hr, "Failed to count UTF-8 bytes."); - break; - - default: - break; - } - -#ifdef _DEBUG - WcaLog(LOGMSG_STANDARD, "File: %ls", sczCustomActionData); - WcaLog(LOGMSG_STANDARD, "Content: %ls", sczFileContent); -#endif - - // write file and preserve modified time - FILETIME filetime; - - hr = FileGetTime(sczFilePath, NULL, NULL, &filetime); - ExitOnFailure(hr, "Failed to get modified time of file : %ls", sczFilePath); - - hr = FileWrite(sczFilePath, FILE_ATTRIBUTE_NORMAL, pbData, cbData, NULL); - ExitOnFailure(hr, "Failed to write file content: %ls", sczFilePath); - - hr = FileSetTime(sczFilePath, NULL, NULL, &filetime); - ExitOnFailure(hr, "Failed to set modified time of file : %ls", sczFilePath); - - // Tick the progress bar - hr = WcaProgressMessage(COST_FILEFORMATTING, FALSE); - ExitOnFailure(hr, "Failed to tick progress bar for file: %ls", sczFilePath); - } - -LExit: - ReleaseStr(psz); - - return WcaFinalize(er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er); -} diff --git a/src/ca/OsInfo.cpp b/src/ca/OsInfo.cpp deleted file mode 100644 index 4783673e..00000000 --- a/src/ca/OsInfo.cpp +++ /dev/null @@ -1,487 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" - -// constants we'll pick up from later SDKs -#define SM_TABLETPC 86 -#define SM_MEDIACENTER 87 -#define SM_STARTER 88 -#define SM_SERVERR2 89 -#define VER_SUITE_WH_SERVER 0x00008000 - -/******************************************************************** -WixQueryOsInfo - entry point for WixQueryOsInfo custom action - - Called as Type 1 custom action (DLL from the Binary table) from - Windows Installer to set properties that identify OS information - and predefined directories -********************************************************************/ -extern "C" UINT __stdcall WixQueryOsInfo( - __in MSIHANDLE hInstall - ) -{ - HRESULT hr = S_OK; - DWORD er = ERROR_SUCCESS; - OSVERSIONINFOEXW ovix = {0}; - - hr = WcaInitialize(hInstall, "WixQueryOsInfo"); - ExitOnFailure(hr, "WixQueryOsInfo failed to initialize"); - - // identify product suites - ovix.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW); - #pragma warning(suppress: 4996) //TODO: use osutil - ::GetVersionExW(reinterpret_cast(&ovix)); - - if (VER_SUITE_SMALLBUSINESS == (ovix.wSuiteMask & VER_SUITE_SMALLBUSINESS)) - { - WcaSetIntProperty(L"WIX_SUITE_SMALLBUSINESS", 1); - } - - if (VER_SUITE_ENTERPRISE == (ovix.wSuiteMask & VER_SUITE_ENTERPRISE)) - { - WcaSetIntProperty(L"WIX_SUITE_ENTERPRISE", 1); - } - - if (VER_SUITE_BACKOFFICE == (ovix.wSuiteMask & VER_SUITE_BACKOFFICE)) - { - WcaSetIntProperty(L"WIX_SUITE_BACKOFFICE", 1); - } - - if (VER_SUITE_COMMUNICATIONS == (ovix.wSuiteMask & VER_SUITE_COMMUNICATIONS)) - { - WcaSetIntProperty(L"WIX_SUITE_COMMUNICATIONS", 1); - } - - if (VER_SUITE_TERMINAL == (ovix.wSuiteMask & VER_SUITE_TERMINAL)) - { - WcaSetIntProperty(L"WIX_SUITE_TERMINAL", 1); - } - - if (VER_SUITE_SMALLBUSINESS_RESTRICTED == (ovix.wSuiteMask & VER_SUITE_SMALLBUSINESS_RESTRICTED)) - { - WcaSetIntProperty(L"WIX_SUITE_SMALLBUSINESS_RESTRICTED", 1); - } - - if (VER_SUITE_EMBEDDEDNT == (ovix.wSuiteMask & VER_SUITE_EMBEDDEDNT)) - { - WcaSetIntProperty(L"WIX_SUITE_EMBEDDEDNT", 1); - } - - if (VER_SUITE_DATACENTER == (ovix.wSuiteMask & VER_SUITE_DATACENTER)) - { - WcaSetIntProperty(L"WIX_SUITE_DATACENTER", 1); - } - - if (VER_SUITE_SINGLEUSERTS == (ovix.wSuiteMask & VER_SUITE_SINGLEUSERTS)) - { - WcaSetIntProperty(L"WIX_SUITE_SINGLEUSERTS", 1); - } - - if (VER_SUITE_PERSONAL == (ovix.wSuiteMask & VER_SUITE_PERSONAL)) - { - WcaSetIntProperty(L"WIX_SUITE_PERSONAL", 1); - } - - if (VER_SUITE_BLADE == (ovix.wSuiteMask & VER_SUITE_BLADE)) - { - WcaSetIntProperty(L"WIX_SUITE_BLADE", 1); - } - - if (VER_SUITE_EMBEDDED_RESTRICTED == (ovix.wSuiteMask & VER_SUITE_EMBEDDED_RESTRICTED)) - { - WcaSetIntProperty(L"WIX_SUITE_EMBEDDED_RESTRICTED", 1); - } - - if (VER_SUITE_SECURITY_APPLIANCE == (ovix.wSuiteMask & VER_SUITE_SECURITY_APPLIANCE)) - { - WcaSetIntProperty(L"WIX_SUITE_SECURITY_APPLIANCE", 1); - } - - if (VER_SUITE_STORAGE_SERVER == (ovix.wSuiteMask & VER_SUITE_STORAGE_SERVER)) - { - WcaSetIntProperty(L"WIX_SUITE_STORAGE_SERVER", 1); - } - - if (VER_SUITE_COMPUTE_SERVER == (ovix.wSuiteMask & VER_SUITE_COMPUTE_SERVER)) - { - WcaSetIntProperty(L"WIX_SUITE_COMPUTE_SERVER", 1); - } - - if (VER_SUITE_WH_SERVER == (ovix.wSuiteMask & VER_SUITE_WH_SERVER)) - { - WcaSetIntProperty(L"WIX_SUITE_WH_SERVER", 1); - } - - // only for XP and later - if (5 < ovix.dwMajorVersion || (5 == ovix.dwMajorVersion && 0 < ovix.dwMinorVersion)) - { - if (::GetSystemMetrics(SM_SERVERR2)) - { - WcaSetIntProperty(L"WIX_SUITE_SERVERR2", 1); - } - - if (::GetSystemMetrics(SM_MEDIACENTER)) - { - WcaSetIntProperty(L"WIX_SUITE_MEDIACENTER", 1); - } - - if (::GetSystemMetrics(SM_STARTER)) - { - WcaSetIntProperty(L"WIX_SUITE_STARTER", 1); - } - - if (::GetSystemMetrics(SM_TABLETPC)) - { - WcaSetIntProperty(L"WIX_SUITE_TABLETPC", 1); - } - } - -LExit: - if (FAILED(hr)) - er = ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} - -/******************************************************************** -WixQueryOsDirs - entry point for WixQueryOsDirs custom action - - Called as Type 1 custom action (DLL from the Binary table) from - Windows Installer to set properties that identify predefined directories -********************************************************************/ -extern "C" UINT __stdcall WixQueryOsDirs( - __in MSIHANDLE hInstall - ) -{ - HRESULT hr = S_OK; - DWORD er = ERROR_SUCCESS; - - hr = WcaInitialize(hInstall, "WixQueryOsDirs"); - ExitOnFailure(hr, "WixQueryOsDirs failed to initialize"); - - // get the paths of the CSIDLs that represent real paths and for which MSI - // doesn't yet have standard folder properties - WCHAR path[MAX_PATH]; - if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_ADMINTOOLS, NULL, SHGFP_TYPE_CURRENT, path)) - { - WcaSetProperty(L"WIX_DIR_ADMINTOOLS", path); - } - - if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_ALTSTARTUP, NULL, SHGFP_TYPE_CURRENT, path)) - { - WcaSetProperty(L"WIX_DIR_ALTSTARTUP", path); - } - - if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_CDBURN_AREA, NULL, SHGFP_TYPE_CURRENT, path)) - { - WcaSetProperty(L"WIX_DIR_CDBURN_AREA", path); - } - - if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_ADMINTOOLS, NULL, SHGFP_TYPE_CURRENT, path)) - { - WcaSetProperty(L"WIX_DIR_COMMON_ADMINTOOLS", path); - } - - if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_ALTSTARTUP, NULL, SHGFP_TYPE_CURRENT, path)) - { - WcaSetProperty(L"WIX_DIR_COMMON_ALTSTARTUP", path); - } - - if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_DOCUMENTS, NULL, SHGFP_TYPE_CURRENT, path)) - { - WcaSetProperty(L"WIX_DIR_COMMON_DOCUMENTS", path); - } - - if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_FAVORITES, NULL, SHGFP_TYPE_CURRENT, path)) - { - WcaSetProperty(L"WIX_DIR_COMMON_FAVORITES", path); - } - - if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_MUSIC, NULL, SHGFP_TYPE_CURRENT, path)) - { - WcaSetProperty(L"WIX_DIR_COMMON_MUSIC", path); - } - - if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_PICTURES, NULL, SHGFP_TYPE_CURRENT, path)) - { - WcaSetProperty(L"WIX_DIR_COMMON_PICTURES", path); - } - - if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_VIDEO, NULL, SHGFP_TYPE_CURRENT, path)) - { - WcaSetProperty(L"WIX_DIR_COMMON_VIDEO", path); - } - - if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COOKIES, NULL, SHGFP_TYPE_CURRENT, path)) - { - WcaSetProperty(L"WIX_DIR_COOKIES", path); - } - - if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_DESKTOP, NULL, SHGFP_TYPE_CURRENT, path)) - { - WcaSetProperty(L"WIX_DIR_DESKTOP", path); - } - - if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_HISTORY, NULL, SHGFP_TYPE_CURRENT, path)) - { - WcaSetProperty(L"WIX_DIR_HISTORY", path); - } - - if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_INTERNET_CACHE, NULL, SHGFP_TYPE_CURRENT, path)) - { - WcaSetProperty(L"WIX_DIR_INTERNET_CACHE", path); - } - - if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_MYMUSIC, NULL, SHGFP_TYPE_CURRENT, path)) - { - WcaSetProperty(L"WIX_DIR_MYMUSIC", path); - } - - if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_MYPICTURES, NULL, SHGFP_TYPE_CURRENT, path)) - { - WcaSetProperty(L"WIX_DIR_MYPICTURES", path); - } - - if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_MYVIDEO, NULL, SHGFP_TYPE_CURRENT, path)) - { - WcaSetProperty(L"WIX_DIR_MYVIDEO", path); - } - - if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_NETHOOD, NULL, SHGFP_TYPE_CURRENT, path)) - { - WcaSetProperty(L"WIX_DIR_NETHOOD", path); - } - - if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, path)) - { - WcaSetProperty(L"WIX_DIR_PERSONAL", path); - } - - if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_PRINTHOOD, NULL, SHGFP_TYPE_CURRENT, path)) - { - WcaSetProperty(L"WIX_DIR_PRINTHOOD", path); - } - - if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, path)) - { - WcaSetProperty(L"WIX_DIR_PROFILE", path); - } - - if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_RECENT, NULL, SHGFP_TYPE_CURRENT, path)) - { - WcaSetProperty(L"WIX_DIR_RECENT", path); - } - - if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_RESOURCES, NULL, SHGFP_TYPE_CURRENT, path)) - { - WcaSetProperty(L"WIX_DIR_RESOURCES", path); - } - -LExit: - if (FAILED(hr)) - er = ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} - - -/******************************************************************** -SetPropertyWellKnownSID - - Set a property with the localized name of a well known windows SID -********************************************************************/ -static HRESULT SetPropertyWellKnownSID( - __in WELL_KNOWN_SID_TYPE sidType, - __in LPCWSTR wzPropertyName, - __in BOOL fIncludeDomainName - ) -{ - HRESULT hr = S_OK; - PSID psid = NULL; - WCHAR wzRefDomain[MAX_PATH] = {0}; - SID_NAME_USE nameUse; - DWORD refSize = MAX_PATH; - WCHAR wzName[MAX_PATH] = {0}; - LPWSTR pwzPropertyValue = NULL; - DWORD size = MAX_PATH; - - hr = AclGetWellKnownSid(sidType, &psid); - ExitOnFailure(hr, "Failed to get SID; skipping account %ls", wzPropertyName); - - if (!::LookupAccountSidW(NULL, psid, wzName, &size, wzRefDomain, &refSize, &nameUse)) - { - ExitWithLastError(hr, "Failed to look up account for SID; skipping account %ls.", wzPropertyName); - } - - if (fIncludeDomainName) - { - hr = StrAllocFormatted(&pwzPropertyValue, L"%s\\%s", wzRefDomain, wzName); - ExitOnFailure(hr, "Failed to format property value"); - - hr = WcaSetProperty(wzPropertyName, pwzPropertyValue); - ExitOnFailure(hr, "Failed write domain\\name property"); - } - else - { - hr = WcaSetProperty(wzPropertyName, wzName); - ExitOnFailure(hr, "Failed write to name-only property"); - } - -LExit: - if (NULL != psid) - { - ::LocalFree(psid); - } - ReleaseStr(pwzPropertyValue); - return hr; -} - -/******************************************************************** -WixQueryOsWellKnownSID - entry point for WixQueryOsWellKnownSID custom action - - Called as Type 1 custom action (DLL from the Binary table) from - Windows Installer to set properties with the localized names of built-in - Windows Security IDs -********************************************************************/ -extern "C" UINT __stdcall WixQueryOsWellKnownSID( - __in MSIHANDLE hInstall - ) -{ - HRESULT hr = S_OK; - DWORD er = ERROR_SUCCESS; - - hr = WcaInitialize(hInstall, "WixQueryOsWellKnownSID"); - ExitOnFailure(hr, "WixQueryOsWellKnownSID failed to initialize"); - - SetPropertyWellKnownSID(WinLocalSystemSid, L"WIX_ACCOUNT_LOCALSYSTEM", TRUE); - SetPropertyWellKnownSID(WinLocalServiceSid, L"WIX_ACCOUNT_LOCALSERVICE", TRUE); - SetPropertyWellKnownSID(WinNetworkServiceSid, L"WIX_ACCOUNT_NETWORKSERVICE", TRUE); - SetPropertyWellKnownSID(WinBuiltinAdministratorsSid, L"WIX_ACCOUNT_ADMINISTRATORS", TRUE); - SetPropertyWellKnownSID(WinBuiltinUsersSid, L"WIX_ACCOUNT_USERS", TRUE); - SetPropertyWellKnownSID(WinBuiltinGuestsSid, L"WIX_ACCOUNT_GUESTS", TRUE); - SetPropertyWellKnownSID(WinBuiltinPerfLoggingUsersSid, L"WIX_ACCOUNT_PERFLOGUSERS", TRUE); - SetPropertyWellKnownSID(WinBuiltinPerfLoggingUsersSid, L"WIX_ACCOUNT_PERFLOGUSERS_NODOMAIN", FALSE); - -LExit: - if (FAILED(hr)) - { - er = ERROR_INSTALL_FAILURE; - } - return WcaFinalize(er); -} - - -/******************************************************************** -DetectWDDMDriver - - Set a property if the driver on the machine is a WDDM driver. One - reliable way to detect the presence of a WDDM driver is to try and - use the Direct3DCreate9Ex() function. This method attempts that - then sets the property appropriately. -********************************************************************/ -static HRESULT DetectWDDMDriver() -{ - HRESULT hr = S_OK; - HMODULE hModule = NULL; - - // Manually load the d3d9.dll library. If the library couldn't be loaded then we obviously won't be able - // to try calling the function so just return. - hr = LoadSystemLibrary(L"d3d9.dll", &hModule); - if (E_MODNOTFOUND == hr) - { - TraceError(hr, "Unable to load DirectX APIs, skipping WDDM driver check."); - ExitFunction1(hr = S_OK); - } - ExitOnFailure(hr, "Failed to the load the existing DirectX APIs."); - - // Obtain the address of the Direct3DCreate9Ex function. If this fails we know it isn't a WDDM - // driver so just exit. - const void* Direct3DCreate9ExPtr = ::GetProcAddress(hModule, "Direct3DCreate9Ex"); - ExitOnNull(Direct3DCreate9ExPtr, hr, S_OK, "Unable to load Direct3DCreateEx function, so the driver is not a WDDM driver."); - - // At this point we know it's a WDDM driver so set the property. - hr = WcaSetIntProperty(L"WIX_WDDM_DRIVER_PRESENT", 1); - ExitOnFailure(hr, "Failed write property"); - -LExit: - if (NULL != hModule) - { - FreeLibrary(hModule); - } - - return hr; -} - -/******************************************************************** -DetectIsCompositionEnabled - - Set a property based on the return value of DwmIsCompositionEnabled(). -********************************************************************/ -static HRESULT DetectIsCompositionEnabled() -{ - HRESULT hr = S_OK; - HMODULE hModule = NULL; - BOOL compositionState = false; - - // Manually load the d3d9.dll library. If the library can't load it's likely because we are not on a Vista - // OS. Just return ok, and the property won't get set. - hr = LoadSystemLibrary(L"dwmapi.dll", &hModule); - if (E_MODNOTFOUND == hr) - { - TraceError(hr, "Unable to load Vista desktop window manager APIs, skipping Composition Enabled check."); - ExitFunction1(hr = S_OK); - } - ExitOnFailure(hr, "Failed to load the existing window manager APIs."); - - // If for some reason we can't get the function pointer that's ok, just return. - typedef HRESULT (WINAPI *DWMISCOMPOSITIONENABLEDPTR)(BOOL*); - DWMISCOMPOSITIONENABLEDPTR DwmIsCompositionEnabledPtr = (DWMISCOMPOSITIONENABLEDPTR)::GetProcAddress(hModule, "DwmIsCompositionEnabled"); - ExitOnNull(hModule, hr, S_OK, "Unable to obtain function information, skipping Composition Enabled check."); - - hr = DwmIsCompositionEnabledPtr(&compositionState); - ExitOnFailure(hr, "Failed to retrieve Composition state"); - - if (compositionState) - { - hr = WcaSetIntProperty(L"WIX_DWM_COMPOSITION_ENABLED", 1); - ExitOnFailure(hr, "Failed write property"); - } - -LExit: - if (NULL != hModule) - { - FreeLibrary(hModule); - } - return hr; -} - -/******************************************************************** -WixQueryOsDriverInfo - entry point for WixQueryOsDriverInfo custom action - - Called as Type 1 custom action (DLL from the Binary table) from - Windows Installer to set properties about drivers installed on - the target machine -********************************************************************/ -extern "C" UINT __stdcall WixQueryOsDriverInfo( - __in MSIHANDLE hInstall - ) -{ - HRESULT hr = S_OK; - DWORD er = ERROR_SUCCESS; - - hr = WcaInitialize(hInstall, "WixQueryOsDriverInfo"); - ExitOnFailure(hr, "WixQueryOsDriverInfo failed to initialize"); - - // Detect the WDDM driver status - hr = DetectWDDMDriver(); - ExitOnFailure(hr, "Failed to detect WIX_WDDM_DRIVER_PRESENT"); - - // Detect whether composition is enabled - hr = DetectIsCompositionEnabled(); - ExitOnFailure(hr, "Failed to detect WIX_DWM_COMPOSITION_ENABLED"); - -LExit: - if (FAILED(hr)) - { - er = ERROR_INSTALL_FAILURE; - } - return WcaFinalize(er); -} diff --git a/src/ca/RemoveFoldersEx.cpp b/src/ca/RemoveFoldersEx.cpp deleted file mode 100644 index cbc7f4bb..00000000 --- a/src/ca/RemoveFoldersEx.cpp +++ /dev/null @@ -1,243 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" - -LPCWSTR vcsRemoveFolderExQuery = - L"SELECT `Wix4RemoveFolderEx`, `Component_`, `Property`, `InstallMode`, `WixRemoveFolderEx`.`Condition`, `Component`.`Attributes`" - L"FROM `Wix4RemoveFolderEx``,`Component` " - L"WHERE `Wix4RemoveFolderEx`.`Component_`=`Component`.`Component`"; -enum eRemoveFolderExQuery { rfqId = 1, rfqComponent, rfqProperty, rfqMode, rfqCondition, rfqComponentAttributes }; - -static HRESULT RecursePath( - __in_z LPCWSTR wzPath, - __in_z LPCWSTR wzId, - __in_z LPCWSTR wzComponent, - __in_z LPCWSTR wzProperty, - __in int iMode, - __in BOOL fDisableWow64Redirection, - __inout DWORD* pdwCounter, - __inout MSIHANDLE* phTable, - __inout MSIHANDLE* phColumns - ) -{ - HRESULT hr = S_OK; - DWORD er; - LPWSTR sczSearch = NULL; - LPWSTR sczProperty = NULL; - HANDLE hFind = INVALID_HANDLE_VALUE; - WIN32_FIND_DATAW wfd; - LPWSTR sczNext = NULL; - - if (fDisableWow64Redirection) - { - hr = WcaDisableWow64FSRedirection(); - ExitOnFailure(hr, "Custom action was told to act on a 64-bit component, but was unable to disable filesystem redirection through the Wow64 API."); - } - - // First recurse down to all the child directories. - hr = StrAllocFormatted(&sczSearch, L"%s*", wzPath); - ExitOnFailure(hr, "Failed to allocate file search string in path: %S", wzPath); - - hFind = ::FindFirstFileW(sczSearch, &wfd); - if (INVALID_HANDLE_VALUE == hFind) - { - er = ::GetLastError(); - if (ERROR_PATH_NOT_FOUND == er) - { - WcaLog(LOGMSG_STANDARD, "Search path not found: %ls; skipping", sczSearch); - ExitFunction1(hr = S_FALSE); - } - else - { - hr = HRESULT_FROM_WIN32(er); - } - ExitOnFailure(hr, "Failed to find all files in path: %S", wzPath); - } - - do - { - // Skip files and the dot directories. - 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]))) - { - continue; - } - - hr = StrAllocFormatted(&sczNext, L"%s%s\\", wzPath, wfd.cFileName); - ExitOnFailure(hr, "Failed to concat filename '%S' to string: %S", wfd.cFileName, wzPath); - - // Don't re-disable redirection; if it was necessary, we've already done it. - hr = RecursePath(sczNext, wzId, wzComponent, wzProperty, iMode, FALSE, pdwCounter, phTable, phColumns); - ExitOnFailure(hr, "Failed to recurse path: %S", sczNext); - } while (::FindNextFileW(hFind, &wfd)); - - er = ::GetLastError(); - if (ERROR_NO_MORE_FILES == er) - { - hr = S_OK; - } - else - { - hr = HRESULT_FROM_WIN32(er); - ExitOnFailure(hr, "Failed while looping through files in directory: %S", wzPath); - } - - // Finally, set a property that points at our path. - hr = StrAllocFormatted(&sczProperty, L"_%s_%u", wzProperty, *pdwCounter); - ExitOnFailure(hr, "Failed to allocate Property for RemoveFile table with property: %S.", wzProperty); - - ++(*pdwCounter); - - hr = WcaSetProperty(sczProperty, wzPath); - ExitOnFailure(hr, "Failed to set Property: %S with path: %S", sczProperty, wzPath); - - // Add the row to remove any files and another row to remove the folder. - hr = WcaAddTempRecord(phTable, phColumns, L"RemoveFile", NULL, 1, 5, L"RfxFiles", wzComponent, L"*.*", sczProperty, iMode); - ExitOnFailure(hr, "Failed to add row to remove all files for Wix4RemoveFolderEx row: %ls under path: %ls", wzId, wzPath); - - hr = WcaAddTempRecord(phTable, phColumns, L"RemoveFile", NULL, 1, 5, L"RfxFolder", wzComponent, NULL, sczProperty, iMode); - ExitOnFailure(hr, "Failed to add row to remove folder for Wix4RemoveFolderEx row: %ls under path: %ls", wzId, wzPath); - -LExit: - if (INVALID_HANDLE_VALUE != hFind) - { - ::FindClose(hFind); - } - - if (fDisableWow64Redirection) - { - WcaRevertWow64FSRedirection(); - } - - ReleaseStr(sczNext); - ReleaseStr(sczProperty); - ReleaseStr(sczSearch); - return hr; -} - -extern "C" UINT WINAPI WixRemoveFoldersEx( - __in MSIHANDLE hInstall - ) -{ - //AssertSz(FALSE, "debug WixRemoveFoldersEx"); - - HRESULT hr = S_OK; - PMSIHANDLE hView; - PMSIHANDLE hRec; - LPWSTR sczId = NULL; - LPWSTR sczComponent = NULL; - LPWSTR sczProperty = NULL; - LPWSTR sczCondition = NULL; - LPWSTR sczPath = NULL; - LPWSTR sczExpandedPath = NULL; - int iMode = 0; - int iComponentAttributes; - BOOL f64BitComponent = FALSE; - DWORD dwCounter = 0; - DWORD_PTR cchLen = 0; - MSIHANDLE hTable = NULL; - MSIHANDLE hColumns = NULL; - - hr = WcaInitialize(hInstall, "WixRemoveFoldersEx"); - ExitOnFailure(hr, "Failed to initialize WixRemoveFoldersEx."); - - WcaInitializeWow64(); - - // anything to do? - if (S_OK != WcaTableExists(L"Wix4RemoveFolderEx")) - { - WcaLog(LOGMSG_STANDARD, "Wix4RemoveFolderEx table doesn't exist, so there are no folders to remove."); - ExitFunction(); - } - - // query and loop through all the remove folders exceptions - hr = WcaOpenExecuteView(vcsRemoveFolderExQuery, &hView); - ExitOnFailure(hr, "Failed to open view on Wix4RemoveFolderEx table"); - - while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) - { - hr = WcaGetRecordString(hRec, rfqId, &sczId); - ExitOnFailure(hr, "Failed to get remove folder identity."); - - hr = WcaGetRecordString(hRec, rfqCondition, &sczCondition); - ExitOnFailure(hr, "Failed to get remove folder condition."); - - if (sczCondition && *sczCondition) - { - MSICONDITION condition = ::MsiEvaluateConditionW(hInstall, sczCondition); - if (MSICONDITION_TRUE == condition) - { - WcaLog(LOGMSG_STANDARD, "True condition for row %S: %S; processing.", sczId, sczCondition); - } - else - { - WcaLog(LOGMSG_STANDARD, "False or invalid condition for row %S: %S; skipping.", sczId, sczCondition); - continue; - } - } - - hr = WcaGetRecordString(hRec, rfqComponent, &sczComponent); - ExitOnFailure(hr, "Failed to get remove folder component."); - - hr = WcaGetRecordString(hRec, rfqProperty, &sczProperty); - ExitOnFailure(hr, "Failed to get remove folder property."); - - hr = WcaGetRecordInteger(hRec, rfqMode, &iMode); - ExitOnFailure(hr, "Failed to get remove folder mode"); - - hr = WcaGetProperty(sczProperty, &sczPath); - ExitOnFailure(hr, "Failed to resolve remove folder property: %S for row: %S", sczProperty, sczId); - - hr = WcaGetRecordInteger(hRec, rfqComponentAttributes, &iComponentAttributes); - ExitOnFailure(hr, "failed to get component attributes for row: %ls", sczId); - - f64BitComponent = iComponentAttributes & msidbComponentAttributes64bit; - - // fail early if the property isn't set as you probably don't want your installers trying to delete SystemFolder - // StringCchLengthW succeeds only if the string is zero characters plus 1 for the terminating null - hr = ::StringCchLengthW(sczPath, 1, reinterpret_cast(&cchLen)); - if (SUCCEEDED(hr)) - { - ExitOnFailure(hr = E_INVALIDARG, "Missing folder property: %S for row: %S", sczProperty, sczId); - } - - hr = PathExpand(&sczExpandedPath, sczPath, PATH_EXPAND_ENVIRONMENT); - ExitOnFailure(hr, "Failed to expand path: %S for row: %S", sczPath, sczId); - - hr = PathBackslashTerminate(&sczExpandedPath); - ExitOnFailure(hr, "Failed to backslash-terminate path: %S", sczExpandedPath); - - WcaLog(LOGMSG_STANDARD, "Recursing path: %S for row: %S.", sczExpandedPath, sczId); - hr = RecursePath(sczExpandedPath, sczId, sczComponent, sczProperty, iMode, f64BitComponent, &dwCounter, &hTable, &hColumns); - ExitOnFailure(hr, "Failed while navigating path: %S for row: %S", sczPath, sczId); - } - - // reaching the end of the list is actually a good thing, not an error - if (E_NOMOREITEMS == hr) - { - hr = S_OK; - } - ExitOnFailure(hr, "Failure occured while processing Wix4RemoveFolderEx table"); - -LExit: - WcaFinalizeWow64(); - - if (hColumns) - { - ::MsiCloseHandle(hColumns); - } - - if (hTable) - { - ::MsiCloseHandle(hTable); - } - - ReleaseStr(sczExpandedPath); - ReleaseStr(sczPath); - ReleaseStr(sczProperty); - ReleaseStr(sczComponent); - ReleaseStr(sczCondition); - ReleaseStr(sczId); - - DWORD er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} diff --git a/src/ca/RemoveRegistryKeysEx.cpp b/src/ca/RemoveRegistryKeysEx.cpp deleted file mode 100644 index 478c0779..00000000 --- a/src/ca/RemoveRegistryKeysEx.cpp +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" - -LPCWSTR vcsRemoveRegistryKeyExQuery = - L"SELECT `Wix4RemoveRegistryKeyEx`, `Component_`, `Root`, `Key`, `InstallMode`, `Condition` FROM `Wix4RemoveRegistryKeyEx`"; -enum eRemoveRegistryKeyExQuery { rrxqId = 1, rrxqComponent, rrxqRoot, rrxqKey, rrxqMode, rrxqCondition }; - -extern "C" UINT WINAPI WixRemoveRegistryKeysEx( - __in MSIHANDLE hInstall -) -{ - //AssertSz(FALSE, "debug WixRemoveRegistryKeyEx"); - - HRESULT hr = S_OK; - PMSIHANDLE hView; - PMSIHANDLE hRec; - LPWSTR sczId = NULL; - LPWSTR sczComponent = NULL; - LPWSTR sczCondition = NULL; - LPWSTR sczKey = NULL; - int iRoot = 0; - int iMode = 0; - MSIHANDLE hTable = NULL; - MSIHANDLE hColumns = NULL; - - hr = WcaInitialize(hInstall, __FUNCTION__); - ExitOnFailure(hr, "Failed to initialize " __FUNCTION__); - - // anything to do? - if (S_OK != WcaTableExists(L"Wix4RemoveRegistryKeyEx")) - { - WcaLog(LOGMSG_STANDARD, "Wix4RemoveRegistryKeyEx table doesn't exist, so there are no registry keys to remove."); - ExitFunction(); - } - - hr = WcaOpenExecuteView(vcsRemoveRegistryKeyExQuery, &hView); - ExitOnFailure(hr, "Failed to open view on Wix4RemoveRegistryKeyEx table"); - - while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) - { - hr = WcaGetRecordString(hRec, rrxqId, &sczId); - ExitOnFailure(hr, "Failed to get Wix4RemoveRegistryKeyEx identity."); - - hr = WcaGetRecordString(hRec, rrxqCondition, &sczCondition); - ExitOnFailure(hr, "Failed to get Wix4RemoveRegistryKeyEx condition."); - - if (sczCondition && *sczCondition) - { - MSICONDITION condition = ::MsiEvaluateConditionW(hInstall, sczCondition); - if (MSICONDITION_TRUE == condition) - { - WcaLog(LOGMSG_STANDARD, "True condition for row %S: %S; processing.", sczId, sczCondition); - } - else - { - WcaLog(LOGMSG_STANDARD, "False or invalid condition for row %S: %S; skipping.", sczId, sczCondition); - continue; - } - } - - hr = WcaGetRecordString(hRec, rrxqComponent, &sczComponent); - ExitOnFailure(hr, "Failed to get Wix4RemoveRegistryKeyEx component."); - - hr = WcaGetRecordInteger(hRec, rrxqRoot, &iRoot); - ExitOnFailure(hr, "Failed to get Wix4RemoveRegistryKeyEx root."); - - hr = WcaGetRecordString(hRec, rrxqKey, &sczKey); - ExitOnFailure(hr, "Failed to get Wix4RemoveRegistryKeyEx key."); - - hr = WcaGetRecordInteger(hRec, rrxqMode, &iMode); - ExitOnFailure(hr, "Failed to get Wix4RemoveRegistryKeyEx mode."); - - switch (iMode) - { - case 1: // remove on install - WcaLog(LOGMSG_STANDARD, "Adding RemoveRegistry row: %ls/%d/%ls/-/%ls", sczId, iRoot, sczKey, sczComponent); - hr = WcaAddTempRecord(&hTable, &hColumns, L"RemoveRegistry", NULL, 0, 5, sczId, iRoot, sczKey, L"-", sczComponent); - ExitOnFailure(hr, "Failed to add RemoveRegistry row for remove-on-install Wix4RemoveRegistryKeyEx row: %ls:", sczId); - break; - case 2: // remove on uninstall - WcaLog(LOGMSG_STANDARD, "Adding Registry row: %ls/%d/%ls/-/null/%ls", sczId, iRoot, sczKey, sczComponent); - hr = WcaAddTempRecord(&hTable, &hColumns, L"Registry", NULL, 0, 6, sczId, iRoot, sczKey, L"-", NULL, sczComponent); - ExitOnFailure(hr, "Failed to add Registry row for remove-on-uninstall Wix4RemoveRegistryKeyEx row: %ls:", sczId); - break; - } - } - - // reaching the end of the list is actually a good thing, not an error - if (E_NOMOREITEMS == hr) - { - hr = S_OK; - } - ExitOnFailure(hr, "Failure occured while processing Wix4RemoveRegistryKeyEx table."); - -LExit: - if (hColumns) - { - ::MsiCloseHandle(hColumns); - } - - if (hTable) - { - ::MsiCloseHandle(hTable); - } - - ReleaseStr(sczKey); - ReleaseStr(sczComponent); - ReleaseStr(sczCondition); - ReleaseStr(sczId); - - DWORD er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} diff --git a/src/ca/RestartManager.cpp b/src/ca/RestartManager.cpp deleted file mode 100644 index c31819c1..00000000 --- a/src/ca/RestartManager.cpp +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" -#include - -// Include space for the terminating null. -#define CCH_SESSION_KEY CCH_RM_SESSION_KEY + 1 - -enum eRmuResourceType -{ - etInvalid, - etFilename, - etApplication, - etServiceName, - - // Mask types from Attributes. - etTypeMask = 0xf, -}; - -LPCWSTR vcsRestartResourceQuery = - L"SELECT `Wix4RestartResource`.`Wix4RestartResource`, `Wix4RestartResource`.`Component_`, `Wix4RestartResource`.`Resource`, `Wix4RestartResource`.`Attributes` " - L"FROM `Wix4RestartResource`"; -enum eRestartResourceQuery { rrqRestartResource = 1, rrqComponent, rrqResource, rrqAttributes }; - -/******************************************************************** -WixRegisterRestartResources - Immediate CA to register resources with RM. - -Enumerates components before InstallValidate and registers resources -to be restarted by Restart Manager if the component action -is anything other than None. - -Do not disable file system redirection. - -********************************************************************/ -extern "C" UINT __stdcall WixRegisterRestartResources( - __in MSIHANDLE hInstall - ) -{ - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - - PMSIHANDLE hView = NULL; - PMSIHANDLE hRec = NULL; - - LPWSTR wzSessionKey = NULL; - size_t cchSessionKey = 0; - PRMU_SESSION pSession = NULL; - - LPWSTR wzRestartResource = NULL; - LPWSTR wzComponent = NULL; - LPWSTR wzResource = NULL; - int iAttributes = NULL; - BOOL fIsComponentNull = FALSE; - WCA_TODO todo = WCA_TODO_UNKNOWN; - int iType = etInvalid; - - hr = WcaInitialize(hInstall, "WixRegisterRestartResources"); - ExitOnFailure(hr, "Failed to initialize."); - - // Skip if the table doesn't exist. - if (S_OK != WcaTableExists(L"Wix4RestartResource")) - { - WcaLog(LOGMSG_STANDARD, "The Wix4RestartResource table does not exist; there are no resources to register with Restart Manager."); - ExitFunction(); - } - - // Get the existing Restart Manager session if available. - hr = WcaGetProperty(L"MsiRestartManagerSessionKey", &wzSessionKey); - ExitOnFailure(hr, "Failed to get the MsiRestartManagerSessionKey property."); - - hr = ::StringCchLengthW(wzSessionKey, CCH_SESSION_KEY, &cchSessionKey); - ExitOnFailure(hr, "Failed to get the MsiRestartManagerSessionKey string length."); - - // Skip if the property doesn't exist. - if (0 == cchSessionKey) - { - WcaLog(LOGMSG_STANDARD, "The MsiRestartManagerSessionKey property is not available to join."); - ExitFunction(); - } - - // Join the existing Restart Manager session if supported. - hr = RmuJoinSession(&pSession, wzSessionKey); - if (E_MODNOTFOUND == hr) - { - WcaLog(LOGMSG_STANDARD, "The Restart Manager is not supported on this platform. Skipping."); - ExitFunction1(hr = S_OK); - } - else if (FAILED(hr)) - { - WcaLog(LOGMSG_STANDARD, "Failed to join the existing Restart Manager session %ls.", wzSessionKey); - ExitFunction1(hr = S_OK); - } - - // Loop through each record in the table. - hr = WcaOpenExecuteView(vcsRestartResourceQuery, &hView); - ExitOnFailure(hr, "Failed to open a view on the RestartResource table."); - - while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) - { - hr = WcaGetRecordString(hRec, rrqRestartResource, &wzRestartResource); - ExitOnFailure(hr, "Failed to get the RestartResource field value."); - - hr = WcaGetRecordString(hRec, rrqComponent, &wzComponent); - ExitOnFailure(hr, "Failed to get the Component_ field value."); - - hr = WcaGetRecordFormattedString(hRec, rrqResource, &wzResource); - ExitOnFailure(hr, "Failed to get the Resource formatted field value."); - - hr = WcaGetRecordInteger(hRec, rrqAttributes, &iAttributes); - ExitOnFailure(hr, "Failed to get the Attributes field value."); - - fIsComponentNull = ::MsiRecordIsNull(hRec, rrqComponent); - todo = WcaGetComponentToDo(wzComponent); - - // Only register resources for components that are null, or being installed, reinstalled, or uninstalled. - if (!fIsComponentNull && WCA_TODO_UNKNOWN == todo) - { - WcaLog(LOGMSG_VERBOSE, "Skipping resource %ls.", wzRestartResource); - continue; - } - - // Get the type from Attributes and add to the Restart Manager. - iType = iAttributes & etTypeMask; - switch (iType) - { - case etFilename: - WcaLog(LOGMSG_VERBOSE, "Registering file name %ls with the Restart Manager.", wzResource); - hr = RmuAddFile(pSession, wzResource); - ExitOnFailure(hr, "Failed to register the file name with the Restart Manager session."); - break; - - case etApplication: - WcaLog(LOGMSG_VERBOSE, "Registering process name %ls with the Restart Manager.", wzResource); - hr = RmuAddProcessesByName(pSession, wzResource); - if (E_NOTFOUND == hr) - { - // ERROR_ACCESS_DENIED was returned when trying to register this process. - // Since other instances may have been registered, log a message and continue the setup rather than failing. - 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); - hr = S_OK; - } - else - { - ExitOnFailure(hr, "Failed to register the process name with the Restart Manager session."); - } - break; - - case etServiceName: - WcaLog(LOGMSG_VERBOSE, "Registering service name %ls with the Restart Manager.", wzResource); - hr = RmuAddService(pSession, wzResource); - ExitOnFailure(hr, "Failed to register the service name with the Restart Manager session."); - break; - - default: - WcaLog(LOGMSG_VERBOSE, "The resource type %d for %ls is not supported and will not be registered.", iType, wzRestartResource); - break; - } - } - - if (E_NOMOREITEMS == hr) - { - hr = S_OK; - } - ExitOnFailure(hr, "Failed while looping through all rows to register resources."); - - // Register the resources and unjoin the session. - hr = RmuEndSession(pSession); - if (FAILED(hr)) - { - WcaLog(LOGMSG_VERBOSE, "Failed to register the resources with the Restart Manager."); - ExitFunction1(hr = S_OK); - } - -LExit: - ReleaseStr(wzRestartResource); - ReleaseStr(wzComponent); - ReleaseStr(wzResource); - - if (FAILED(hr)) - { - er = ERROR_INSTALL_FAILURE; - } - - return WcaFinalize(er); -} diff --git a/src/ca/TouchFile.cpp b/src/ca/TouchFile.cpp deleted file mode 100644 index e704f922..00000000 --- a/src/ca/TouchFile.cpp +++ /dev/null @@ -1,308 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" - -LPCWSTR vcsTouchFileQuery = L"SELECT `Wix4TouchFile`, `Component_`, `Path`, `Attributes` FROM `Wix4TouchFile`"; -enum TOUCH_FILE_QUERY { tfqId = 1, tfqComponent, tfqPath, tfqTouchFileAttributes }; - -enum TOUCH_FILE_ATTRIBUTE -{ - TOUCH_FILE_ATTRIBUTE_ON_INSTALL = 0x01, - TOUCH_FILE_ATTRIBUTE_ON_REINSTALL = 0x02, - TOUCH_FILE_ATTRIBUTE_ON_UNINSTALL = 0x04, - TOUCH_FILE_ATTRIBUTE_64BIT = 0x10, - TOUCH_FILE_ATTRIBUTE_VITAL = 0x20 -}; - - -static BOOL SetExistingFileModifiedTime( - __in_z LPCWSTR wzId, - __in_z LPCWSTR wzPath, - __in BOOL f64Bit, - __in FILETIME* pftModified - ) -{ - HRESULT hr = S_OK; - BOOL fReenableFileSystemRedirection = FALSE; - - if (f64Bit) - { - hr = WcaDisableWow64FSRedirection(); - ExitOnFailure(hr, "Failed to disable 64-bit file system redirection to path: '%ls' for: %ls", wzPath, wzId); - - fReenableFileSystemRedirection = TRUE; - } - - hr = FileSetTime(wzPath, NULL, NULL, pftModified); - -LExit: - if (fReenableFileSystemRedirection) - { - WcaRevertWow64FSRedirection(); - } - - return SUCCEEDED(hr); -} - - -static HRESULT AddDataToCustomActionData( - __deref_inout_z LPWSTR* psczCustomActionData, - __in_z LPCWSTR wzId, - __in_z LPCWSTR wzPath, - __in int iTouchFileAttributes, - __in FILETIME ftModified - ) -{ - HRESULT hr = S_OK; - - hr = WcaWriteStringToCaData(wzId, psczCustomActionData); - ExitOnFailure(hr, "Failed to add touch file identity to custom action data."); - - hr = WcaWriteStringToCaData(wzPath, psczCustomActionData); - ExitOnFailure(hr, "Failed to add touch file path to custom action data."); - - hr = WcaWriteIntegerToCaData(iTouchFileAttributes, psczCustomActionData); - ExitOnFailure(hr, "Failed to add touch file attributes to custom action data."); - - hr = WcaWriteIntegerToCaData(ftModified.dwHighDateTime, psczCustomActionData); - ExitOnFailure(hr, "Failed to add touch file high date/time to custom action data."); - - hr = WcaWriteIntegerToCaData(ftModified.dwLowDateTime, psczCustomActionData); - ExitOnFailure(hr, "Failed to add touch file low date/time to custom action data."); - -LExit: - return hr; -} - - -static BOOL TryGetExistingFileModifiedTime( - __in_z LPCWSTR wzId, - __in_z LPCWSTR wzPath, - __in BOOL f64Bit, - __inout FILETIME* pftModified - ) -{ - HRESULT hr = S_OK; - BOOL fReenableFileSystemRedirection = FALSE; - - if (f64Bit) - { - hr = WcaDisableWow64FSRedirection(); - ExitOnFailure(hr, "Failed to disable 64-bit file system redirection to path: '%ls' for: %ls", wzPath, wzId); - - fReenableFileSystemRedirection = TRUE; - } - - hr = FileGetTime(wzPath, NULL, NULL, pftModified); - if (E_PATHNOTFOUND == hr || E_FILENOTFOUND == hr) - { - // If the file doesn't exist yet there is nothing to rollback (i.e. file will probably be removed during rollback), so - // keep the error code but don't log anything. - } - else if (FAILED(hr)) - { - WcaLog(LOGMSG_STANDARD, "Cannot access modified timestamp for file: '%ls' due to error: 0x%x. Continuing with out rollback for: %ls", wzPath, hr, wzId); - } - -LExit: - if (fReenableFileSystemRedirection) - { - WcaRevertWow64FSRedirection(); - } - - return SUCCEEDED(hr); -} - - -static HRESULT ProcessTouchFileTable( - __in BOOL fInstalling - ) -{ - HRESULT hr = S_OK; - - FILETIME ftModified = {}; - - PMSIHANDLE hView; - PMSIHANDLE hRec; - - LPWSTR sczId = NULL; - LPWSTR sczComponent = NULL; - int iTouchFileAttributes = 0; - LPWSTR sczPath = NULL; - - FILETIME ftRollbackModified = {}; - LPWSTR sczRollbackData = NULL; - LPWSTR sczExecuteData = NULL; - - if (S_OK != WcaTableExists(L"Wix4TouchFile")) - { - ExitFunction(); - } - - ::GetSystemTimeAsFileTime(&ftModified); - - hr = WcaOpenExecuteView(vcsTouchFileQuery, &hView); - ExitOnFailure(hr, "Failed to open view on Wix4TouchFile table"); - - while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) - { - hr = WcaGetRecordString(hRec, tfqId, &sczId); - ExitOnFailure(hr, "Failed to get touch file identity."); - - hr = WcaGetRecordString(hRec, tfqComponent, &sczComponent); - ExitOnFailure(hr, "Failed to get touch file component for: %ls", sczId); - - hr = WcaGetRecordInteger(hRec, tfqTouchFileAttributes, &iTouchFileAttributes); - ExitOnFailure(hr, "Failed to get touch file attributes for: %ls", sczId); - - WCA_TODO todo = WcaGetComponentToDo(sczComponent); - - BOOL fOnInstall = fInstalling && WCA_TODO_INSTALL == todo && (iTouchFileAttributes & TOUCH_FILE_ATTRIBUTE_ON_INSTALL); - BOOL fOnReinstall = fInstalling && WCA_TODO_REINSTALL == todo && (iTouchFileAttributes & TOUCH_FILE_ATTRIBUTE_ON_REINSTALL); - BOOL fOnUninstall = !fInstalling && WCA_TODO_UNINSTALL == todo && (iTouchFileAttributes & TOUCH_FILE_ATTRIBUTE_ON_UNINSTALL); - - if (fOnInstall || fOnReinstall || fOnUninstall) - { - hr = WcaGetRecordFormattedString(hRec, tfqPath, &sczPath); - ExitOnFailure(hr, "Failed to get touch file path for: %ls", sczId); - - if (TryGetExistingFileModifiedTime(sczId, sczPath, (iTouchFileAttributes & TOUCH_FILE_ATTRIBUTE_64BIT), &ftRollbackModified)) - { - hr = AddDataToCustomActionData(&sczRollbackData, sczId, sczPath, iTouchFileAttributes, ftRollbackModified); - ExitOnFailure(hr, "Failed to add to rollback custom action data for: %ls", sczId); - } - - hr = AddDataToCustomActionData(&sczExecuteData, sczId, sczPath, iTouchFileAttributes, ftModified); - ExitOnFailure(hr, "Failed to add to execute custom action data for: %ls", sczId); - } - } - - if (E_NOMOREITEMS == hr) - { - hr = S_OK; - } - ExitOnFailure(hr, "Failure occured while processing Wix4TouchFile table"); - - if (sczRollbackData) - { - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackTouchFile"), sczRollbackData, 0); - ExitOnFailure(hr, "Failed to schedule RollbackTouchFile"); - } - - if (sczExecuteData) - { - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecuteTouchFile"), sczExecuteData, 0); - ExitOnFailure(hr, "Failed to schedule ExecuteTouchFile"); - } - -LExit: - ReleaseStr(sczExecuteData); - ReleaseStr(sczRollbackData); - ReleaseStr(sczPath); - ReleaseStr(sczComponent); - ReleaseStr(sczId); - - return hr; -} - - -extern "C" UINT WINAPI WixTouchFileDuringInstall( - __in MSIHANDLE hInstall - ) -{ - //AssertSz(FALSE, "debug WixTouchFileDuringInstall"); - - HRESULT hr = S_OK; - - hr = WcaInitialize(hInstall, "WixTouchFileDuringInstall"); - ExitOnFailure(hr, "Failed to initialize WixTouchFileDuringInstall."); - - hr = ProcessTouchFileTable(TRUE); - -LExit: - DWORD er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} - - -extern "C" UINT WINAPI WixTouchFileDuringUninstall( - __in MSIHANDLE hInstall - ) -{ - //AssertSz(FALSE, "debug WixTouchFileDuringUninstall"); - - HRESULT hr = S_OK; - - hr = WcaInitialize(hInstall, "WixTouchFileDuringUninstall"); - ExitOnFailure(hr, "Failed to initialize WixTouchFileDuringUninstall."); - - hr = ProcessTouchFileTable(FALSE); - -LExit: - DWORD er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} - - -extern "C" UINT WINAPI WixExecuteTouchFile( - __in MSIHANDLE hInstall - ) -{ - HRESULT hr = S_OK; - - LPWSTR sczData = NULL; - LPWSTR pwz = NULL; - - LPWSTR sczId = NULL; - LPWSTR sczPath = NULL; - int iTouchFileAttributes = 0; - FILETIME ftModified = {}; - - hr = WcaInitialize(hInstall, "WixExecuteTouchFile"); - ExitOnFailure(hr, "Failed to initialize WixExecuteTouchFile."); - - hr = WcaGetProperty(L"CustomActionData", &sczData); - ExitOnFailure(hr, "Failed to get custom action data for WixExecuteTouchFile."); - - pwz = sczData; - - while (pwz && *pwz) - { - hr = WcaReadStringFromCaData(&pwz, &sczId); - ExitOnFailure(hr, "Failed to get touch file identity from custom action data."); - - hr = WcaReadStringFromCaData(&pwz, &sczPath); - ExitOnFailure(hr, "Failed to get touch file path from custom action data for: %ls", sczId); - - hr = WcaReadIntegerFromCaData(&pwz, &iTouchFileAttributes); - ExitOnFailure(hr, "Failed to get touch file attributes from custom action data for: %ls", sczId); - - hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&ftModified.dwHighDateTime)); - ExitOnFailure(hr, "Failed to get touch file high date/time from custom action data for: %ls", sczId); - - hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&ftModified.dwLowDateTime)); - ExitOnFailure(hr, "Failed to get touch file low date/time from custom action data for: %ls", sczId); - - hr = SetExistingFileModifiedTime(sczId, sczPath, (iTouchFileAttributes & TOUCH_FILE_ATTRIBUTE_64BIT), &ftModified); - if (FAILED(hr)) - { - if (iTouchFileAttributes & TOUCH_FILE_ATTRIBUTE_VITAL) - { - ExitOnFailure(hr, "Failed to touch file: '%ls' for: %ls", &sczPath, sczId); - } - else - { - WcaLog(LOGMSG_STANDARD, "Could not touch non-vital file: '%ls' for: %ls with error: 0x%x. Continuing...", sczPath, sczId, hr); - hr = S_OK; - } - } - } - -LExit: - ReleaseStr(sczPath); - ReleaseStr(sczId); - ReleaseStr(sczData); - - DWORD er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} diff --git a/src/ca/XmlConfig.cpp b/src/ca/XmlConfig.cpp deleted file mode 100644 index a1ec9d6f..00000000 --- a/src/ca/XmlConfig.cpp +++ /dev/null @@ -1,1130 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" - -#define XMLCONFIG_ELEMENT 0x00000001 -#define XMLCONFIG_VALUE 0x00000002 -#define XMLCONFIG_DOCUMENT 0x00000004 -#define XMLCONFIG_CREATE 0x00000010 -#define XMLCONFIG_DELETE 0x00000020 -#define XMLCONFIG_INSTALL 0x00000100 -#define XMLCONFIG_UNINSTALL 0x00000200 -#define XMLCONFIG_PRESERVE_MODIFIED 0x00001000 - -enum eXmlAction -{ - xaUnknown = 0, - xaOpenFile, - xaOpenFilex64, - xaWriteValue, - xaWriteDocument, - xaDeleteValue, - xaCreateElement, - xaDeleteElement, -}; - -enum eXmlPreserveDate -{ - xdDontPreserve = 0, - xdPreserve -}; - -LPCWSTR vcsXmlConfigQuery = - L"SELECT `Wix4XmlConfig`.`Wix4XmlConfig`, `Wix4XmlConfig`.`File`, `Wix4XmlConfig`.`ElementId`, `Wix4XmlConfig`.`ElementPath`, `Wix4XmlConfig`.`VerifyPath`, `Wix4XmlConfig`.`Name`, " - L"`Wix4XmlConfig`.`Value`, `Wix4XmlConfig`.`Flags`, `Wix4XmlConfig`.`Component_`, `Component`.`Attributes` " - L"FROM `Wix4XmlConfig`,`Component` WHERE `Wix4XmlConfig`.`Component_`=`Component`.`Component` ORDER BY `File`, `Sequence`"; -enum eXmlConfigQuery { xfqXmlConfig = 1, xfqFile, xfqElementId, xfqElementPath, xfqVerifyPath, xfqName, xfqValue, xfqXmlFlags, xfqComponent, xfqCompAttributes }; - -struct XML_CONFIG_CHANGE -{ - WCHAR wzId[MAX_DARWIN_KEY + 1]; - - WCHAR wzComponent[MAX_DARWIN_KEY + 1]; - INSTALLSTATE isInstalled; - INSTALLSTATE isAction; - - WCHAR wzFile[MAX_PATH]; - LPWSTR pwzElementId; - LPWSTR pwzElementPath; - LPWSTR pwzVerifyPath; - WCHAR wzName[MAX_DARWIN_COLUMN]; - LPWSTR pwzValue; - BOOL fInstalledFile; - - int iXmlFlags; - int iCompAttributes; - - XML_CONFIG_CHANGE* pxfcAdditionalChanges; - int cAdditionalChanges; - - XML_CONFIG_CHANGE* pxfcPrev; - XML_CONFIG_CHANGE* pxfcNext; -}; - -static HRESULT FreeXmlConfigChangeList( - __in_opt XML_CONFIG_CHANGE* pxfcList - ) -{ - HRESULT hr = S_OK; - - XML_CONFIG_CHANGE* pxfcDelete; - while(pxfcList) - { - pxfcDelete = pxfcList; - pxfcList = pxfcList->pxfcNext; - - if (pxfcDelete->pwzElementId) - { - hr = MemFree(pxfcDelete->pwzElementId); - ExitOnFailure(hr, "failed to free xml config element id in change list item"); - } - - if (pxfcDelete->pwzElementPath) - { - hr = MemFree(pxfcDelete->pwzElementPath); - ExitOnFailure(hr, "failed to free xml config element path in change list item"); - } - - if (pxfcDelete->pwzVerifyPath) - { - hr = MemFree(pxfcDelete->pwzVerifyPath); - ExitOnFailure(hr, "failed to free xml config verify path in change list item"); - } - - if (pxfcDelete->pwzValue) - { - hr = MemFree(pxfcDelete->pwzValue); - ExitOnFailure(hr, "failed to free xml config value in change list item"); - } - - hr = MemFree(pxfcDelete); - ExitOnFailure(hr, "failed to free xml config change list item"); - } - -LExit: - return hr; -} - -static HRESULT AddXmlConfigChangeToList( - __inout XML_CONFIG_CHANGE** ppxfcHead, - __inout XML_CONFIG_CHANGE** ppxfcTail - ) -{ - Assert(ppxfcHead && ppxfcTail); - - HRESULT hr = S_OK; - - XML_CONFIG_CHANGE* pxfc = static_cast(MemAlloc(sizeof(XML_CONFIG_CHANGE), TRUE)); - ExitOnNull(pxfc, hr, E_OUTOFMEMORY, "failed to allocate memory for new xml file change list element"); - - // Add it to the end of the list - if (NULL == *ppxfcHead) - { - *ppxfcHead = pxfc; - *ppxfcTail = pxfc; - } - else - { - Assert(*ppxfcTail && (*ppxfcTail)->pxfcNext == NULL); - (*ppxfcTail)->pxfcNext = pxfc; - pxfc->pxfcPrev = *ppxfcTail; - *ppxfcTail = pxfc; - } - -LExit: - return hr; -} - - -static HRESULT ReadXmlConfigTable( - __inout XML_CONFIG_CHANGE** ppxfcHead, - __inout XML_CONFIG_CHANGE** ppxfcTail - ) -{ - Assert(ppxfcHead && ppxfcTail); - - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - - PMSIHANDLE hView = NULL; - PMSIHANDLE hRec = NULL; - - LPWSTR pwzData = NULL; - - // loop through all the xml configurations - hr = WcaOpenExecuteView(vcsXmlConfigQuery, &hView); - ExitOnFailure(hr, "failed to open view on Wix4XmlConfig table"); - - while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) - { - hr = AddXmlConfigChangeToList(ppxfcHead, ppxfcTail); - ExitOnFailure(hr, "failed to add xml file change to list"); - - // Get record Id - hr = WcaGetRecordString(hRec, xfqXmlConfig, &pwzData); - ExitOnFailure(hr, "failed to get Wix4XmlConfig record Id"); - hr = StringCchCopyW((*ppxfcTail)->wzId, countof((*ppxfcTail)->wzId), pwzData); - ExitOnFailure(hr, "failed to copy Wix4XmlConfig record Id"); - - // Get component name - hr = WcaGetRecordString(hRec, xfqComponent, &pwzData); - ExitOnFailure(hr, "failed to get component name for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId); - - // Get the component's state - if (pwzData && *pwzData) - { - hr = StringCchCopyW((*ppxfcTail)->wzComponent, countof((*ppxfcTail)->wzComponent), pwzData); - ExitOnFailure(hr, "failed to copy component id"); - - er = ::MsiGetComponentStateW(WcaGetInstallHandle(), (*ppxfcTail)->wzComponent, &(*ppxfcTail)->isInstalled, &(*ppxfcTail)->isAction); - ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "failed to get install state for component id"); - } - - // Get the xml file - hr = WcaGetRecordFormattedString(hRec, xfqFile, &pwzData); - ExitOnFailure(hr, "failed to get xml file for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId); - hr = StringCchCopyW((*ppxfcTail)->wzFile, countof((*ppxfcTail)->wzFile), pwzData); - ExitOnFailure(hr, "failed to copy xml file path"); - - // Figure out if the file is already on the machine or if it's being installed - hr = WcaGetRecordString(hRec, xfqFile, &pwzData); - ExitOnFailure(hr, "failed to get xml file for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId); - if (NULL != wcsstr(pwzData, L"[!") || NULL != wcsstr(pwzData, L"[#")) - { - (*ppxfcTail)->fInstalledFile = TRUE; - } - - // Get the Wix4XmlConfig table flags - hr = WcaGetRecordInteger(hRec, xfqXmlFlags, &(*ppxfcTail)->iXmlFlags); - ExitOnFailure(hr, "failed to get Wix4XmlConfig flags for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId); - - // Get the Element Id - hr = WcaGetRecordFormattedString(hRec, xfqElementId, &(*ppxfcTail)->pwzElementId); - ExitOnFailure(hr, "failed to get Element Id for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId); - - // Get the Element Path - hr = WcaGetRecordFormattedString(hRec, xfqElementPath, &(*ppxfcTail)->pwzElementPath); - ExitOnFailure(hr, "failed to get Element Path for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId); - - // Get the Verify Path - hr = WcaGetRecordFormattedString(hRec, xfqVerifyPath, &(*ppxfcTail)->pwzVerifyPath); - ExitOnFailure(hr, "failed to get Verify Path for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId); - - // Get the name - hr = WcaGetRecordFormattedString(hRec, xfqName, &pwzData); - ExitOnFailure(hr, "failed to get Name for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId); - hr = StringCchCopyW((*ppxfcTail)->wzName, countof((*ppxfcTail)->wzName), pwzData); - ExitOnFailure(hr, "failed to copy name of element"); - - // Get the value - hr = WcaGetRecordFormattedString(hRec, xfqValue, &pwzData); - ExitOnFailure(hr, "failed to get Value for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId); - hr = StrAllocString(&(*ppxfcTail)->pwzValue, pwzData, 0); - ExitOnFailure(hr, "failed to allocate buffer for value"); - - // Get the component attributes - hr = WcaGetRecordInteger(hRec, xfqCompAttributes, &(*ppxfcTail)->iCompAttributes); - ExitOnFailure(hr, "failed to get component attributes for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId); - } - - // if we looped through all records all is well - if (E_NOMOREITEMS == hr) - { - hr = S_OK; - } - ExitOnFailure(hr, "failed while looping through all objects to secure"); - -LExit: - ReleaseStr(pwzData); - - return hr; -} - -static HRESULT ProcessChanges( - __inout XML_CONFIG_CHANGE** ppxfcHead - ) -{ - Assert(ppxfcHead && *ppxfcHead); - HRESULT hr = S_OK; - - XML_CONFIG_CHANGE* pxfc = NULL; - XML_CONFIG_CHANGE* pxfcNext = NULL; - XML_CONFIG_CHANGE* pxfcCheck = NULL; - int cAdditionalChanges = 0; - XML_CONFIG_CHANGE* pxfcLast = NULL; - - // If there's only one item in the list, none of this matters - if (pxfc && !pxfc->pxfcNext) - { - ExitFunction(); - } - - // Loop through the list - pxfc = *ppxfcHead; - while (pxfc) - { - // Keep track of where our next spot will be since our current node may be moved - pxfcNext = pxfc->pxfcNext; - - // With each node, check to see if it's element path matches the Id of some other node in the list - pxfcCheck = *ppxfcHead; - while (pxfcCheck) - { - if (pxfc->pwzElementId) - { - if (0 == lstrcmpW(pxfc->pwzElementId, pxfcCheck->wzId) - && 0 == pxfc->iXmlFlags - && XMLCONFIG_CREATE & pxfcCheck->iXmlFlags - && XMLCONFIG_ELEMENT & pxfcCheck->iXmlFlags) - { - // We found a match. First, take it out of the current list - if (pxfc->pxfcPrev) - { - pxfc->pxfcPrev->pxfcNext = pxfc->pxfcNext; - } - else // it was the head. Update the head - { - *ppxfcHead = pxfc->pxfcNext; - } - - if (pxfc->pxfcNext) - { - pxfc->pxfcNext->pxfcPrev = pxfc->pxfcPrev; - } - - pxfc->pxfcNext = NULL; - pxfc->pxfcPrev = NULL; - - // Now, add this node to the end of the matched node's additional changes list - if (!pxfcCheck->pxfcAdditionalChanges) - { - pxfcCheck->pxfcAdditionalChanges = pxfc; - pxfcCheck->cAdditionalChanges = 1; - } - else - { - pxfcLast = pxfcCheck->pxfcAdditionalChanges; - cAdditionalChanges = 1; - while (pxfcLast->pxfcNext) - { - pxfcLast = pxfcLast->pxfcNext; - ++cAdditionalChanges; - } - pxfcLast->pxfcNext = pxfc; - pxfc->pxfcPrev = pxfcLast; - pxfcCheck->cAdditionalChanges = ++cAdditionalChanges; - } - } - else - { - hr = E_NOTFOUND; - ExitOnRootFailure(hr, "failed to find matching ElementId: %ls", pxfc->pwzElementId); - } - } - - pxfcCheck = pxfcCheck->pxfcNext; - } - - pxfc = pxfcNext; - } - -LExit: - - return hr; -} - - -static HRESULT BeginChangeFile( - __in LPCWSTR pwzFile, - __in int iCompAttributes, - __inout LPWSTR* ppwzCustomActionData - ) -{ - Assert(pwzFile && *pwzFile && ppwzCustomActionData); - - HRESULT hr = S_OK; - BOOL fIs64Bit = iCompAttributes & msidbComponentAttributes64bit; - - LPBYTE pbData = NULL; - SIZE_T cbData = 0; - - LPWSTR pwzRollbackCustomActionData = NULL; - - if (fIs64Bit) - { - hr = WcaWriteIntegerToCaData((int)xaOpenFilex64, ppwzCustomActionData); - ExitOnFailure(hr, "failed to write 64-bit file indicator to custom action data"); - } - else - { - hr = WcaWriteIntegerToCaData((int)xaOpenFile, ppwzCustomActionData); - ExitOnFailure(hr, "failed to write file indicator to custom action data"); - } - - hr = WcaWriteStringToCaData(pwzFile, ppwzCustomActionData); - ExitOnFailure(hr, "failed to write file to custom action data: %ls", pwzFile); - - // If the file already exits, then we have to put it back the way it was on failure - if (FileExistsEx(pwzFile, NULL)) - { - hr = FileRead(&pbData, &cbData, pwzFile); - ExitOnFailure(hr, "failed to read file: %ls", pwzFile); - - // Set up the rollback for this file - hr = WcaWriteIntegerToCaData((int)fIs64Bit, &pwzRollbackCustomActionData); - ExitOnFailure(hr, "failed to write component bitness to rollback custom action data"); - - hr = WcaWriteStringToCaData(pwzFile, &pwzRollbackCustomActionData); - ExitOnFailure(hr, "failed to write file name to rollback custom action data: %ls", pwzFile); - - hr = WcaWriteStreamToCaData(pbData, cbData, &pwzRollbackCustomActionData); - ExitOnFailure(hr, "failed to write file contents to rollback custom action data."); - - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecXmlConfigRollback"), pwzRollbackCustomActionData, COST_XMLFILE); - ExitOnFailure(hr, "failed to schedule ExecXmlConfigRollback for file: %ls", pwzFile); - - ReleaseStr(pwzRollbackCustomActionData); - } -LExit: - ReleaseMem(pbData); - - return hr; -} - - -static HRESULT WriteChangeData( - __in XML_CONFIG_CHANGE* pxfc, - __in eXmlAction action, - __inout LPWSTR* ppwzCustomActionData - ) -{ - Assert(pxfc && ppwzCustomActionData); - - HRESULT hr = S_OK; - XML_CONFIG_CHANGE* pxfcAdditionalChanges = NULL; - LPCWSTR wzElementPath = pxfc->pwzElementId ? pxfc->pwzElementId : pxfc->pwzElementPath; - - hr = WcaWriteStringToCaData(wzElementPath, ppwzCustomActionData); - ExitOnFailure(hr, "failed to write ElementPath to custom action data: %ls", wzElementPath); - - hr = WcaWriteStringToCaData(pxfc->pwzVerifyPath, ppwzCustomActionData); - ExitOnFailure(hr, "failed to write VerifyPath to custom action data: %ls", pxfc->pwzVerifyPath); - - hr = WcaWriteStringToCaData(pxfc->wzName, ppwzCustomActionData); - ExitOnFailure(hr, "failed to write Name to custom action data: %ls", pxfc->wzName); - - hr = WcaWriteStringToCaData(pxfc->pwzValue, ppwzCustomActionData); - ExitOnFailure(hr, "failed to write Value to custom action data: %ls", pxfc->pwzValue); - - if (pxfc->iXmlFlags & XMLCONFIG_CREATE && pxfc->iXmlFlags & XMLCONFIG_ELEMENT && xaCreateElement == action && pxfc->pxfcAdditionalChanges) - { - hr = WcaWriteIntegerToCaData(pxfc->cAdditionalChanges, ppwzCustomActionData); - ExitOnFailure(hr, "failed to write additional changes value to custom action data"); - - pxfcAdditionalChanges = pxfc->pxfcAdditionalChanges; - while (pxfcAdditionalChanges) - { - Assert((0 == lstrcmpW(pxfcAdditionalChanges->wzComponent, pxfc->wzComponent)) && 0 == pxfcAdditionalChanges->iXmlFlags && (0 == lstrcmpW(pxfcAdditionalChanges->wzFile, pxfc->wzFile))); - - hr = WcaWriteStringToCaData(pxfcAdditionalChanges->wzName, ppwzCustomActionData); - ExitOnFailure(hr, "failed to write Name to custom action data: %ls", pxfc->wzName); - - hr = WcaWriteStringToCaData(pxfcAdditionalChanges->pwzValue, ppwzCustomActionData); - ExitOnFailure(hr, "failed to write Value to custom action data: %ls", pxfc->pwzValue); - - pxfcAdditionalChanges = pxfcAdditionalChanges->pxfcNext; - } - } - else - { - hr = WcaWriteIntegerToCaData(0, ppwzCustomActionData); - ExitOnFailure(hr, "failed to write additional changes value to custom action data"); - } - -LExit: - return hr; -} - - -/****************************************************************** - SchedXmlConfig - entry point for XmlConfig Custom Action - -********************************************************************/ -extern "C" UINT __stdcall SchedXmlConfig( - __in MSIHANDLE hInstall - ) -{ -// AssertSz(FALSE, "debug SchedXmlConfig"); - - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - - LPWSTR pwzCurrentFile = NULL; - BOOL fCurrentFileChanged = FALSE; - - PMSIHANDLE hView = NULL; - PMSIHANDLE hRec = NULL; - - XML_CONFIG_CHANGE* pxfcHead = NULL; - XML_CONFIG_CHANGE* pxfcTail = NULL; // TODO: do we need this any more? - XML_CONFIG_CHANGE* pxfc = NULL; - - eXmlAction xa = xaUnknown; - eXmlPreserveDate xd; - - LPWSTR pwzCustomActionData = NULL; - - DWORD cFiles = 0; - - // initialize - hr = WcaInitialize(hInstall, "SchedXmlConfig"); - ExitOnFailure(hr, "failed to initialize"); - - hr = ReadXmlConfigTable(&pxfcHead, &pxfcTail); - MessageExitOnFailure(hr, msierrXmlConfigFailedRead, "failed to read Wix4XmlConfig table"); - - hr = ProcessChanges(&pxfcHead); - ExitOnFailure(hr, "failed to process Wix4XmlConfig changes"); - - // loop through all the xml configurations - for (pxfc = pxfcHead; pxfc; pxfc = pxfc->pxfcNext) - { - // If this is a different file, or the first file... - if (NULL == pwzCurrentFile || 0 != lstrcmpW(pwzCurrentFile, pxfc->wzFile)) - { - // Remember the file we're currently working on - hr = StrAllocString(&pwzCurrentFile, pxfc->wzFile, 0); - ExitOnFailure(hr, "failed to copy file name"); - - fCurrentFileChanged = TRUE; - } - - // - // Figure out what action to take - // - xa = xaUnknown; - - // If it's being installed or reinstalled or uninstalled and that matches - // what we are doing then calculate the right action. - if ((XMLCONFIG_INSTALL & pxfc->iXmlFlags && (WcaIsInstalling(pxfc->isInstalled, pxfc->isAction) || WcaIsReInstalling(pxfc->isInstalled, pxfc->isAction))) || - (XMLCONFIG_UNINSTALL & pxfc->iXmlFlags && WcaIsUninstalling(pxfc->isInstalled, pxfc->isAction))) - { - if (XMLCONFIG_CREATE & pxfc->iXmlFlags && XMLCONFIG_ELEMENT & pxfc->iXmlFlags) - { - xa = xaCreateElement; - } - else if (XMLCONFIG_DELETE & pxfc->iXmlFlags && XMLCONFIG_ELEMENT & pxfc->iXmlFlags) - { - xa = xaDeleteElement; - } - else if (XMLCONFIG_DELETE & pxfc->iXmlFlags && XMLCONFIG_VALUE & pxfc->iXmlFlags) - { - xa = xaDeleteValue; - } - else if (XMLCONFIG_CREATE & pxfc->iXmlFlags && XMLCONFIG_VALUE & pxfc->iXmlFlags) - { - xa = xaWriteValue; - } - else if (XMLCONFIG_CREATE & pxfc->iXmlFlags && XMLCONFIG_DOCUMENT & pxfc->iXmlFlags) - { - xa = xaWriteDocument; - } - else if (XMLCONFIG_DELETE & pxfc->iXmlFlags && XMLCONFIG_DOCUMENT & pxfc->iXmlFlags) - { - hr = E_INVALIDARG; - ExitOnFailure(hr, "Invalid flag configuration. Cannot delete a fragment node."); - } - } - - if (XMLCONFIG_PRESERVE_MODIFIED & pxfc->iXmlFlags) - { - xd = xdPreserve; - } - else - { - xd= xdDontPreserve; - } - - if (xaUnknown != xa) - { - if (fCurrentFileChanged) - { - hr = BeginChangeFile(pwzCurrentFile, pxfc->iCompAttributes, &pwzCustomActionData); - ExitOnFailure(hr, "failed to begin file change for file: %ls", pwzCurrentFile); - - fCurrentFileChanged = FALSE; - ++cFiles; - } - - hr = WcaWriteIntegerToCaData((int)xa, &pwzCustomActionData); - ExitOnFailure(hr, "failed to write action indicator custom action data"); - - hr = WcaWriteIntegerToCaData((int)xd, &pwzCustomActionData); - ExitOnFailure(hr, "failed to write Preserve Date indicator to custom action data"); - - hr = WriteChangeData(pxfc, xa, &pwzCustomActionData); - ExitOnFailure(hr, "failed to write change data"); - } - } - - // If we looped through all records all is well - if (E_NOMOREITEMS == hr) - { - hr = S_OK; - } - ExitOnFailure(hr, "failed while looping through all objects to secure"); - - // Schedule the custom action and add to progress bar - if (pwzCustomActionData && *pwzCustomActionData) - { - Assert(0 < cFiles); - - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecXmlConfig"), pwzCustomActionData, cFiles * COST_XMLFILE); - ExitOnFailure(hr, "failed to schedule ExecXmlConfig action"); - } - -LExit: - ReleaseStr(pwzCurrentFile); - ReleaseStr(pwzCustomActionData); - - FreeXmlConfigChangeList(pxfcHead); - - if (FAILED(hr)) - { - er = ERROR_INSTALL_FAILURE; - } - return WcaFinalize(er); -} - - -/****************************************************************** - ExecXmlConfig - entry point for XmlConfig Custom Action - -*******************************************************************/ -extern "C" UINT __stdcall ExecXmlConfig( - __in MSIHANDLE hInstall - ) -{ - //AssertSz(FALSE, "debug ExecXmlConfig"); - HRESULT hr = S_OK; - HRESULT hrOpenFailure = S_OK; - UINT er = ERROR_SUCCESS; - -#ifndef _WIN64 - BOOL fIsFSRedirectDisabled = FALSE; -#endif - BOOL fPreserveDate = FALSE; - - LPWSTR pwzCustomActionData = NULL; - LPWSTR pwzData = NULL; - LPWSTR pwzFile = NULL; - LPWSTR pwzElementPath = NULL; - LPWSTR pwzVerifyPath = NULL; - LPWSTR pwzName = NULL; - LPWSTR pwzValue = NULL; - LPWSTR pwz = NULL; - int cAdditionalChanges = 0; - - IXMLDOMDocument* pixd = NULL; - IXMLDOMNode* pixn = NULL; - IXMLDOMNode* pixnVerify = NULL; - IXMLDOMNode* pixnNewNode = NULL; - IXMLDOMNode* pixnRemovedChild = NULL; - - IXMLDOMDocument* pixdNew = NULL; - IXMLDOMElement* pixeNew = NULL; - - FILETIME ft; - - int id = IDRETRY; - - eXmlAction xa; - eXmlPreserveDate xd; - - // initialize - hr = WcaInitialize(hInstall, "ExecXmlConfig"); - ExitOnFailure(hr, "failed to initialize"); - - hr = XmlInitialize(); - ExitOnFailure(hr, "failed to initialize xml utilities"); - - hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData); - ExitOnFailure(hr, "failed to get CustomActionData"); - - WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); - - pwz = pwzCustomActionData; - - hr = WcaReadIntegerFromCaData(&pwz, (int*) &xa); - ExitOnFailure(hr, "failed to process CustomActionData"); - -#ifndef _WIN64 - // Initialize the Wow64 API - store the result in fWow64APIPresent - // If it fails, this doesn't warrant an error yet, because we only need the Wow64 API in some cases - WcaInitializeWow64(); - BOOL fIsWow64Process = WcaIsWow64Process(); -#endif - - if (xaOpenFile != xa && xaOpenFilex64 != xa) - { - ExitOnFailure(hr = E_INVALIDARG, "invalid custom action data"); - } - - // loop through all the passed in data - while (pwz && *pwz) - { - hr = WcaReadStringFromCaData(&pwz, &pwzFile); - ExitOnFailure(hr, "failed to read file name from custom action data"); - - // Default to not preserve date, preserve it if any modifications require us to - fPreserveDate = FALSE; - - // Open the file - ReleaseNullObject(pixd); - -#ifndef _WIN64 - if (xaOpenFilex64 == xa) - { - if (!fIsWow64Process) - { - hr = E_NOTIMPL; - ExitOnFailure(hr, "Custom action was told to act on a 64-bit component, but the custom action process is not running in WOW."); - } - - hr = WcaDisableWow64FSRedirection(); - ExitOnFailure(hr, "Custom action was told to act on a 64-bit component, but was unable to disable filesystem redirection through the Wow64 API."); - - fIsFSRedirectDisabled = TRUE; - } -#endif - - hr = XmlLoadDocumentFromFileEx(pwzFile, XML_LOAD_PRESERVE_WHITESPACE, &pixd); - if (FAILED(hr)) - { - // 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. - hrOpenFailure = hr; - hr = S_OK; - } - else - { - hrOpenFailure = S_OK; - } - - WcaLog(LOGMSG_VERBOSE, "Configuring Xml File: %ls", pwzFile); - - while (pwz && *pwz) - { - // If we skip past an element that has additional changes we need to strip them off the stream before - // moving on to the next element. Do that now and then restart the outer loop. - if (cAdditionalChanges > 0) - { - while (cAdditionalChanges > 0) - { - hr = WcaReadStringFromCaData(&pwz, &pwzName); - ExitOnFailure(hr, "failed to process CustomActionData"); - hr = WcaReadStringFromCaData(&pwz, &pwzValue); - ExitOnFailure(hr, "failed to process CustomActionData"); - - cAdditionalChanges--; - } - continue; - } - - hr = WcaReadIntegerFromCaData(&pwz, (int*) &xa); - ExitOnFailure(hr, "failed to process CustomActionData"); - - // Break if we need to move on to a different file - if (xaOpenFile == xa || xaOpenFilex64 == xa) - { - break; - } - - hr = WcaReadIntegerFromCaData(&pwz, (int*) &xd); - ExitOnFailure(hr, "failed to process CustomActionData"); - - if (xdPreserve == xd) - { - fPreserveDate = TRUE; - } - - // Get path, name, and value to be written - hr = WcaReadStringFromCaData(&pwz, &pwzElementPath); - ExitOnFailure(hr, "failed to process CustomActionData"); - hr = WcaReadStringFromCaData(&pwz, &pwzVerifyPath); - ExitOnFailure(hr, "failed to process CustomActionData"); - hr = WcaReadStringFromCaData(&pwz, &pwzName); - ExitOnFailure(hr, "failed to process CustomActionData"); - hr = WcaReadStringFromCaData(&pwz, &pwzValue); - ExitOnFailure(hr, "failed to process CustomActionData"); - hr = WcaReadIntegerFromCaData(&pwz, &cAdditionalChanges); - ExitOnFailure(hr, "failed to process CustomActionData"); - - // 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. - if (FAILED(hrOpenFailure)) - { - if (xaCreateElement == xa || xaWriteValue == xa || xaWriteDocument == xa) - { - MessageExitOnFailure(hr = hrOpenFailure, msierrXmlConfigFailedOpen, "failed to load XML file: %ls", pwzFile); - } - else - { - continue; - } - } - - // Select the node we're about to modify - ReleaseNullObject(pixn); - - hr = XmlSelectSingleNode(pixd, pwzElementPath, &pixn); - - // 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. - if (S_FALSE == hr) - { - if (xaCreateElement == xa || xaWriteValue == xa || xaWriteDocument == xa) - { - hr = HRESULT_FROM_WIN32(ERROR_OBJECT_NOT_FOUND); - } - else - { - hr = S_OK; - continue; - } - } - - MessageExitOnFailure(hr, msierrXmlConfigFailedSelect, "failed to find node: %ls in XML file: %ls", pwzElementPath, pwzFile); - - // Make the modification - switch (xa) - { - case xaWriteValue: - if (pwzName && *pwzName) - { - // We're setting an attribute - hr = XmlSetAttribute(pixn, pwzName, pwzValue); - ExitOnFailure(hr, "failed to set attribute: %ls to value %ls", pwzName, pwzValue); - } - else - { - // We're setting the text of the node - hr = XmlSetText(pixn, pwzValue); - ExitOnFailure(hr, "failed to set text to: %ls for element %ls. Make sure that XPath points to an element.", pwzValue, pwzElementPath); - } - break; - case xaWriteDocument: - if (NULL != pwzVerifyPath && 0 != pwzVerifyPath[0]) - { - hr = XmlSelectSingleNode(pixn, pwzVerifyPath, &pixnVerify); - if (S_OK == hr) - { - // We found the verify path which means we have no further work to do - continue; - } - ExitOnFailure(hr, "failed to query verify path: %ls", pwzVerifyPath); - } - - hr = XmlLoadDocumentEx(pwzValue, XML_LOAD_PRESERVE_WHITESPACE, &pixdNew); - ExitOnFailure(hr, "Failed to load value as document."); - - hr = pixdNew->get_documentElement(&pixeNew); - ExitOnFailure(hr, "Failed to get document element."); - - hr = pixn->appendChild(pixeNew, NULL); - ExitOnFailure(hr, "Failed to append document element on to parent element."); - - ReleaseNullObject(pixeNew); - ReleaseNullObject(pixdNew); - break; - - case xaCreateElement: - if (NULL != pwzVerifyPath && 0 != pwzVerifyPath[0]) - { - hr = XmlSelectSingleNode(pixn, pwzVerifyPath, &pixnVerify); - if (S_OK == hr) - { - // We found the verify path which means we have no further work to do - continue; - } - ExitOnFailure(hr, "failed to query verify path: %ls", pwzVerifyPath); - } - - hr = XmlCreateChild(pixn, pwzName, &pixnNewNode); - ExitOnFailure(hr, "failed to create child element: %ls", pwzName); - - if (pwzValue && *pwzValue) - { - hr = XmlSetText(pixnNewNode, pwzValue); - ExitOnFailure(hr, "failed to set text to: %ls for node: %ls", pwzValue, pwzName); - } - - while (cAdditionalChanges > 0) - { - hr = WcaReadStringFromCaData(&pwz, &pwzName); - ExitOnFailure(hr, "failed to process CustomActionData"); - hr = WcaReadStringFromCaData(&pwz, &pwzValue); - ExitOnFailure(hr, "failed to process CustomActionData"); - - // Set the additional attribute - hr = XmlSetAttribute(pixnNewNode, pwzName, pwzValue); - ExitOnFailure(hr, "failed to set attribute: %ls to value %ls", pwzName, pwzValue); - - cAdditionalChanges--; - } - - ReleaseNullObject(pixnNewNode); - break; - case xaDeleteValue: - if (pwzName && *pwzName) - { - // Delete the attribute - hr = XmlRemoveAttribute(pixn, pwzName); - ExitOnFailure(hr, "failed to remove attribute: %ls", pwzName); - } - else - { - // Clear the text value for the node - hr = XmlSetText(pixn, L""); - ExitOnFailure(hr, "failed to clear text value"); - } - break; - case xaDeleteElement: - if (NULL != pwzVerifyPath && 0 != pwzVerifyPath[0]) - { - hr = XmlSelectSingleNode(pixn, pwzVerifyPath, &pixnVerify); - if (S_OK == hr) - { - hr = pixn->removeChild(pixnVerify, &pixnRemovedChild); - ExitOnFailure(hr, "failed to remove created child element"); - - ReleaseNullObject(pixnRemovedChild); - } - else - { - WcaLog(LOGMSG_VERBOSE, "Failed to select path %ls for deleting. Skipping...", pwzVerifyPath); - hr = S_OK; - } - } - else - { - // TODO: This requires a VerifyPath to delete an element. Should we support not having one? - WcaLog(LOGMSG_VERBOSE, "No VerifyPath specified for delete element of ID: %ls", pwzElementPath); - } - break; - default: - ExitOnFailure(hr = E_UNEXPECTED, "Invalid modification specified in custom action data"); - break; - } - } - - - // Now that we've made all of the changes to this file, save it and move on to the next - if (S_OK == hrOpenFailure) - { - if (fPreserveDate) - { - hr = FileGetTime(pwzFile, NULL, NULL, &ft); - ExitOnFailure(hr, "failed to get modified time of file : %ls", pwzFile); - } - - int iSaveAttempt = 0; - - do - { - hr = XmlSaveDocument(pixd, pwzFile); - if (FAILED(hr)) - { - id = WcaErrorMessage(msierrXmlConfigFailedSave, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 1, pwzFile); - switch (id) - { - case IDABORT: - ExitOnFailure(hr, "Failed to save changes to XML file: %ls", pwzFile); - case IDRETRY: - hr = S_FALSE; // hit me, baby, one more time - break; - case IDIGNORE: - hr = S_OK; // pretend everything is okay and bail - break; - case 0: // No UI case, MsiProcessMessage returns 0 - if (STIERR_SHARING_VIOLATION == hr) - { - // Only in case of sharing violation do we retry 30 times, once a second. - if (iSaveAttempt < 30) - { - hr = S_FALSE; - ++iSaveAttempt; - WcaLog(LOGMSG_VERBOSE, "Unable to save changes to XML file: %ls, retry attempt: %x", pwzFile, iSaveAttempt); - Sleep(1000); - } - else - { - ExitOnFailure(hr, "Failed to save changes to XML file: %ls", pwzFile); - } - } - break; - default: // Unknown error - ExitOnFailure(hr, "Failed to save changes to XML file: %ls", pwzFile); - } - } - } while (S_FALSE == hr); - - if (fPreserveDate) - { - hr = FileSetTime(pwzFile, NULL, NULL, &ft); - ExitOnFailure(hr, "failed to set modified time of file : %ls", pwzFile); - } - -#ifndef _WIN64 - if (fIsFSRedirectDisabled) - { - fIsFSRedirectDisabled = FALSE; - WcaRevertWow64FSRedirection(); - } -#endif - } - } - -LExit: -#ifndef _WIN64 - // Make sure we revert FS Redirection if necessary before exiting - if (fIsFSRedirectDisabled) - { - fIsFSRedirectDisabled = FALSE; - WcaRevertWow64FSRedirection(); - } - WcaFinalizeWow64(); -#endif - - ReleaseStr(pwzCustomActionData); - ReleaseStr(pwzData); - ReleaseStr(pwzFile); - ReleaseStr(pwzElementPath); - ReleaseStr(pwzVerifyPath); - ReleaseStr(pwzName); - ReleaseStr(pwzValue); - - ReleaseObject(pixeNew); - ReleaseObject(pixdNew); - - ReleaseObject(pixn); - ReleaseObject(pixd); - ReleaseObject(pixnNewNode); - ReleaseObject(pixnRemovedChild); - - XmlUninitialize(); - - if (FAILED(hr)) - { - er = ERROR_INSTALL_FAILURE; - } - return WcaFinalize(er); -} - - -/****************************************************************** - ExecXmlConfigRollback - entry point for XmlConfig rollback Custom Action - -*******************************************************************/ -extern "C" UINT __stdcall ExecXmlConfigRollback( - __in MSIHANDLE hInstall - ) -{ -// AssertSz(FALSE, "debug ExecXmlConfigRollback"); - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - - int iIs64Bit; -#ifndef _WIN64 - BOOL fIs64Bit = FALSE; -#endif - - LPWSTR pwzCustomActionData = NULL; - LPWSTR pwz = NULL; - LPWSTR pwzFileName = NULL; - LPBYTE pbData = NULL; - DWORD_PTR cbData = 0; - - FILETIME ft; - - HANDLE hFile = INVALID_HANDLE_VALUE; - - // initialize - hr = WcaInitialize(hInstall, "ExecXmlConfigRollback"); - ExitOnFailure(hr, "failed to initialize"); - - - hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData); - ExitOnFailure(hr, "failed to get CustomActionData"); - - WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); - - pwz = pwzCustomActionData; - - hr = WcaReadIntegerFromCaData(&pwz, &iIs64Bit); - ExitOnFailure(hr, "failed to read component bitness from custom action data"); - - hr = WcaReadStringFromCaData(&pwz, &pwzFileName); - ExitOnFailure(hr, "failed to read file name from custom action data"); - - hr = WcaReadStreamFromCaData(&pwz, &pbData, &cbData); - ExitOnFailure(hr, "failed to read file contents from custom action data"); - -#ifndef _WIN64 - fIs64Bit = (BOOL)iIs64Bit; - - if (fIs64Bit) - { - hr = WcaInitializeWow64(); - if (S_FALSE == hr) - { - hr = TYPE_E_DLLFUNCTIONNOTFOUND; - } - ExitOnFailure(hr, "failed to initialize Wow64 API"); - - if (!WcaIsWow64Process()) - { - hr = E_NOTIMPL; - ExitOnFailure(hr, "Custom action was told to rollback a 64-bit component, but the Wow64 API is unavailable."); - } - - hr = WcaDisableWow64FSRedirection(); - ExitOnFailure(hr, "Custom action was told to rollback a 64-bit component, but was unable to Disable Filesystem Redirection through the Wow64 API."); - } -#endif - - hr = FileGetTime(pwzFileName, NULL, NULL, &ft); - ExitOnFailure(hr, "Failed to get modified date of file %ls.", pwzFileName); - - // Open the file - hFile = ::CreateFileW(pwzFileName, GENERIC_WRITE, NULL, NULL, TRUNCATE_EXISTING, NULL, NULL); - ExitOnInvalidHandleWithLastError(hFile, hr, "failed to open file: %ls", pwzFileName); - - // Write out the old data - hr = FileWriteHandle(hFile, pbData, cbData); - ExitOnFailure(hr, "failed to write to file: %ls", pwzFileName); - - ReleaseFile(hFile); - - hr = FileSetTime(pwzFileName, NULL, NULL, &ft); - ExitOnFailure(hr, "Failed to set modified date of file %ls.", pwzFileName); - -LExit: - ReleaseStr(pwzCustomActionData); - ReleaseStr(pwzFileName); - - ReleaseFile(hFile); - -#ifndef _WIN64 - if (fIs64Bit) - { - WcaRevertWow64FSRedirection(); - WcaFinalizeWow64(); - } -#endif - - ReleaseMem(pbData); - - if (FAILED(hr)) - { - er = ERROR_INSTALL_FAILURE; - } - return WcaFinalize(er); -} diff --git a/src/ca/XmlFile.cpp b/src/ca/XmlFile.cpp deleted file mode 100644 index 04a4ae98..00000000 --- a/src/ca/XmlFile.cpp +++ /dev/null @@ -1,940 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" - -#define XMLFILE_CREATE_ELEMENT 0x00000001 -#define XMLFILE_DELETE_VALUE 0x00000002 -#define XMLFILE_BULKWRITE_VALUE 0x00000004 - -#define XMLFILE_DONT_UNINSTALL 0x00010000 -#define XMLFILE_PRESERVE_MODIFIED 0x00001000 -#define XMLFILE_USE_XPATH 0x00000100 - -extern BOOL vfMsxml30; - -enum eXmlAction -{ - xaOpenFile = 1, - xaOpenFilex64, - xaWriteValue, - xaDeleteValue, - xaCreateElement, - xaDeleteElement, - xaBulkWriteValue, -}; - -enum eXmlPreserveDate -{ - xdDontPreserve = 0, - xdPreserve -}; - -enum eXmlSelectionLanguage -{ - xsXSLPattern = 0, - xsXPath = 1, -}; - -LPCWSTR vcsXmlFileQuery = - L"SELECT `Wix4XmlFile`.`Wix4XmlFile`, `Wix4XmlFile`.`File`, `Wix4XmlFile`.`ElementPath`, `Wix4XmlFile`.`Name`, `Wix4XmlFile`.`Value`, " - L"`Wix4XmlFile`.`Flags`, `Wix4XmlFile`.`Component_`, `Component`.`Attributes` " - L"FROM `Wix4XmlFile`,`Component` WHERE `Wix4XmlFile`.`Component_`=`Component`.`Component` ORDER BY `File`, `Sequence`"; -enum eXmlFileQuery { xfqXmlFile = 1, xfqFile, xfqXPath, xfqName, xfqValue, xfqXmlFlags, xfqComponent, xfqCompAttributes }; - -struct XML_FILE_CHANGE -{ - WCHAR wzId[MAX_DARWIN_KEY]; - - INSTALLSTATE isInstalled; - INSTALLSTATE isAction; - - WCHAR wzFile[MAX_PATH]; - LPWSTR pwzElementPath; - WCHAR wzName[MAX_DARWIN_COLUMN]; - LPWSTR pwzValue; - - int iXmlFlags; - int iCompAttributes; - - XML_FILE_CHANGE* pxfcPrev; - XML_FILE_CHANGE* pxfcNext; -}; - -//static HRESULT FreeXmlFileChangeList( -// __in XML_FILE_CHANGE* pxfcList -// ) -//{ -// HRESULT hr = S_OK; -// -// XML_FILE_CHANGE* pxfcDelete; -// while(pxfcList) -// { -// pxfcDelete = pxfcList; -// pxfcList = pxfcList->pxfcNext; -// -// ReleaseStr(pxfcDelete->pwzElementPath); -// ReleaseStr(pxfcDelete->pwzValue); -// -// hr = MemFree(pxfcDelete); -// ExitOnFailure(hr, "failed to free xml file change list item"); -// } -// -//LExit: -// return hr; -//} - -static HRESULT AddXmlFileChangeToList( - __inout XML_FILE_CHANGE** ppxfcHead, - __inout XML_FILE_CHANGE** ppxfcTail - ) -{ - Assert(ppxfcHead && ppxfcTail); - - HRESULT hr = S_OK; - - XML_FILE_CHANGE* pxfc = static_cast(MemAlloc(sizeof(XML_FILE_CHANGE), TRUE)); - ExitOnNull(pxfc, hr, E_OUTOFMEMORY, "failed to allocate memory for new xml file change list element"); - - // Add it to the end of the list - if (NULL == *ppxfcHead) - { - *ppxfcHead = pxfc; - *ppxfcTail = pxfc; - } - else - { - Assert(*ppxfcTail && (*ppxfcTail)->pxfcNext == NULL); - (*ppxfcTail)->pxfcNext = pxfc; - pxfc->pxfcPrev = *ppxfcTail; - *ppxfcTail = pxfc; - } - -LExit: - return hr; -} - - -static HRESULT ReadXmlFileTable( - __inout XML_FILE_CHANGE** ppxfcHead, - __inout XML_FILE_CHANGE** ppxfcTail - ) -{ - Assert(ppxfcHead && ppxfcTail); - - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - - PMSIHANDLE hView = NULL; - PMSIHANDLE hRec = NULL; - - LPWSTR pwzData = NULL; - - // check to see if necessary tables are specified - if (S_FALSE == WcaTableExists(L"Wix4XmlFile")) - { - ExitFunction1(hr = S_FALSE); - } - - // loop through all the xml configurations - hr = WcaOpenExecuteView(vcsXmlFileQuery, &hView); - ExitOnFailure(hr, "failed to open view on Wix4XmlFile table"); - - while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) - { - hr = AddXmlFileChangeToList(ppxfcHead, ppxfcTail); - ExitOnFailure(hr, "failed to add xml file change to list"); - - // Get record Id - hr = WcaGetRecordString(hRec, xfqXmlFile, &pwzData); - ExitOnFailure(hr, "failed to get Wix4XmlFile record Id"); - hr = StringCchCopyW((*ppxfcTail)->wzId, countof((*ppxfcTail)->wzId), pwzData); - ExitOnFailure(hr, "failed to copy Wix4XmlFile record Id"); - - // Get component name - hr = WcaGetRecordString(hRec, xfqComponent, &pwzData); - ExitOnFailure(hr, "failed to get component name for Wix4XmlFile: %ls", (*ppxfcTail)->wzId); - - // Get the component's state - er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &(*ppxfcTail)->isInstalled, &(*ppxfcTail)->isAction); - ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "failed to get install state for Component: %ls", pwzData); - - // Get the xml file - hr = WcaGetRecordFormattedString(hRec, xfqFile, &pwzData); - ExitOnFailure(hr, "failed to get xml file for Wix4XmlFile: %ls", (*ppxfcTail)->wzId); - hr = StringCchCopyW((*ppxfcTail)->wzFile, countof((*ppxfcTail)->wzFile), pwzData); - ExitOnFailure(hr, "failed to copy xml file path"); - - // Get the Wix4XmlFile table flags - hr = WcaGetRecordInteger(hRec, xfqXmlFlags, &(*ppxfcTail)->iXmlFlags); - ExitOnFailure(hr, "failed to get Wix4XmlFile flags for Wix4XmlFile: %ls", (*ppxfcTail)->wzId); - - // Get the XPath - hr = WcaGetRecordFormattedString(hRec, xfqXPath, &(*ppxfcTail)->pwzElementPath); - ExitOnFailure(hr, "failed to get XPath for Wix4XmlFile: %ls", (*ppxfcTail)->wzId); - - // Get the name - hr = WcaGetRecordFormattedString(hRec, xfqName, &pwzData); - ExitOnFailure(hr, "failed to get Name for Wix4XmlFile: %ls", (*ppxfcTail)->wzId); - hr = StringCchCopyW((*ppxfcTail)->wzName, countof((*ppxfcTail)->wzName), pwzData); - ExitOnFailure(hr, "failed to copy name of element"); - - // Get the value - hr = WcaGetRecordFormattedString(hRec, xfqValue, &pwzData); - ExitOnFailure(hr, "failed to get Value for Wix4XmlFile: %ls", (*ppxfcTail)->wzId); - hr = StrAllocString(&(*ppxfcTail)->pwzValue, pwzData, 0); - ExitOnFailure(hr, "failed to allocate buffer for value"); - - // Get the component attributes - hr = WcaGetRecordInteger(hRec, xfqCompAttributes, &(*ppxfcTail)->iCompAttributes); - ExitOnFailure(hr, "failed to get component attributes for Wix4XmlFile: %ls", (*ppxfcTail)->wzId); - } - - // if we looped through all records all is well - if (E_NOMOREITEMS == hr) - hr = S_OK; - ExitOnFailure(hr, "failed while looping through all objects to secure"); - -LExit: - ReleaseStr(pwzData); - - return hr; -} - - -static HRESULT BeginChangeFile( - __in LPCWSTR pwzFile, - __in XML_FILE_CHANGE* pxfc, - __inout LPWSTR* ppwzCustomActionData - ) -{ - Assert(pwzFile && *pwzFile && ppwzCustomActionData); - - HRESULT hr = S_OK; - BOOL fIs64Bit = pxfc->iCompAttributes & msidbComponentAttributes64bit; - BOOL fUseXPath = pxfc->iXmlFlags & XMLFILE_USE_XPATH; - LPBYTE pbData = NULL; - SIZE_T cbData = 0; - - LPWSTR pwzRollbackCustomActionData = NULL; - - if (fIs64Bit) - { - hr = WcaWriteIntegerToCaData((int)xaOpenFilex64, ppwzCustomActionData); - ExitOnFailure(hr, "failed to write 64-bit file indicator to custom action data"); - } - else - { - hr = WcaWriteIntegerToCaData((int)xaOpenFile, ppwzCustomActionData); - ExitOnFailure(hr, "failed to write file indicator to custom action data"); - } - if (fUseXPath) - { - hr = WcaWriteIntegerToCaData((int)xsXPath, ppwzCustomActionData); - ExitOnFailure(hr, "failed to write XPath selectionlanguage indicator to custom action data"); - } - else - { - hr = WcaWriteIntegerToCaData((int)xsXSLPattern, ppwzCustomActionData); - ExitOnFailure(hr, "failed to write XSLPattern selectionlanguage indicator to custom action data"); - } - hr = WcaWriteStringToCaData(pwzFile, ppwzCustomActionData); - ExitOnFailure(hr, "failed to write file to custom action data: %ls", pwzFile); - - // If the file already exits, then we have to put it back the way it was on failure - if (FileExistsEx(pwzFile, NULL)) - { - hr = FileRead(&pbData, &cbData, pwzFile); - ExitOnFailure(hr, "failed to read file: %ls", pwzFile); - - // Set up the rollback for this file - hr = WcaWriteIntegerToCaData((int)fIs64Bit, &pwzRollbackCustomActionData); - ExitOnFailure(hr, "failed to write component bitness to rollback custom action data"); - - hr = WcaWriteStringToCaData(pwzFile, &pwzRollbackCustomActionData); - ExitOnFailure(hr, "failed to write file name to rollback custom action data: %ls", pwzFile); - - hr = WcaWriteStreamToCaData(pbData, cbData, &pwzRollbackCustomActionData); - ExitOnFailure(hr, "failed to write file contents to rollback custom action data."); - - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecXmlFileRollback"), pwzRollbackCustomActionData, COST_XMLFILE); - ExitOnFailure(hr, "failed to schedule ExecXmlFileRollback for file: %ls", pwzFile); - - ReleaseStr(pwzRollbackCustomActionData); - } -LExit: - ReleaseMem(pbData); - - return hr; -} - - -static HRESULT WriteChangeData( - __in XML_FILE_CHANGE* pxfc, - __inout LPWSTR* ppwzCustomActionData - ) -{ - Assert(pxfc && ppwzCustomActionData); - - HRESULT hr = S_OK; - - hr = WcaWriteStringToCaData(pxfc->pwzElementPath, ppwzCustomActionData); - ExitOnFailure(hr, "failed to write ElementPath to custom action data: %ls", pxfc->pwzElementPath); - - hr = WcaWriteStringToCaData(pxfc->wzName, ppwzCustomActionData); - ExitOnFailure(hr, "failed to write Name to custom action data: %ls", pxfc->wzName); - - hr = WcaWriteStringToCaData(pxfc->pwzValue, ppwzCustomActionData); - ExitOnFailure(hr, "failed to write Value to custom action data: %ls", pxfc->pwzValue); - -LExit: - return hr; -} - - -/****************************************************************** - SchedXmlFile - entry point for XmlFile Custom Action - -********************************************************************/ -extern "C" UINT __stdcall SchedXmlFile( - __in MSIHANDLE hInstall - ) -{ -// AssertSz(FALSE, "debug SchedXmlFile"); - - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - - LPWSTR pwzCurrentFile = NULL; - BOOL fCurrentFileChanged = FALSE; - BOOL fCurrentUseXPath = FALSE; - - PMSIHANDLE hView = NULL; - PMSIHANDLE hRec = NULL; - - XML_FILE_CHANGE* pxfcHead = NULL; - XML_FILE_CHANGE* pxfcTail = NULL; - XML_FILE_CHANGE* pxfc = NULL; - XML_FILE_CHANGE* pxfcUninstall = NULL; - - LPWSTR pwzCustomActionData = NULL; - - DWORD cFiles = 0; - - // initialize - hr = WcaInitialize(hInstall, "SchedXmlFile"); - ExitOnFailure(hr, "failed to initialize"); - - hr = ReadXmlFileTable(&pxfcHead, &pxfcTail); - if (S_FALSE == hr) - { - WcaLog(LOGMSG_VERBOSE, "Skipping SchedXmlFile because Wix4XmlFile table not present"); - ExitFunction1(hr = S_OK); - } - - MessageExitOnFailure(hr, msierrXmlFileFailedRead, "failed to read Wix4XmlFile table"); - - // loop through all the xml configurations - for (pxfc = pxfcHead; pxfc; pxfc = pxfc->pxfcNext) - { - // If this is the first file, a different file, the last file, or the SelectionLanguage property changes... - if (NULL == pwzCurrentFile || 0 != lstrcmpW(pwzCurrentFile, pxfc->wzFile) || NULL == pxfc->pxfcNext || fCurrentUseXPath != ((XMLFILE_USE_XPATH & pxfc->iXmlFlags))) - { - // If this isn't the first file - if (NULL != pwzCurrentFile) - { - // Do the uninstall work for the current file by walking backwards through the list (so the sequence is reversed) - for (pxfcUninstall = ((NULL != pxfc->pxfcNext) ? pxfc->pxfcPrev : pxfc); pxfcUninstall && 0 == lstrcmpW(pwzCurrentFile, pxfcUninstall->wzFile) && fCurrentUseXPath == ((XMLFILE_USE_XPATH & pxfcUninstall->iXmlFlags)); pxfcUninstall = pxfcUninstall->pxfcPrev) - { - // If it's being uninstalled - if (WcaIsUninstalling(pxfcUninstall->isInstalled, pxfcUninstall->isAction)) - { - // Uninstall the change - if (!(XMLFILE_DONT_UNINSTALL & pxfcUninstall->iXmlFlags)) - { - if (!fCurrentFileChanged) - { - hr = BeginChangeFile(pwzCurrentFile, pxfcUninstall, &pwzCustomActionData); - ExitOnFailure(hr, "failed to begin file change for file: %ls", pwzCurrentFile); - - fCurrentFileChanged = TRUE; - ++cFiles; - } - if (XMLFILE_CREATE_ELEMENT & pxfcUninstall->iXmlFlags) - { - hr = WcaWriteIntegerToCaData((int)xaDeleteElement, &pwzCustomActionData); - ExitOnFailure(hr, "failed to write delete element action indicator to custom action data"); - } - else - { - hr = WcaWriteIntegerToCaData((int)xaDeleteValue, &pwzCustomActionData); - ExitOnFailure(hr, "failed to write delete value action indicator to custom action data"); - } - - if (XMLFILE_PRESERVE_MODIFIED & pxfc->iXmlFlags) - { - hr = WcaWriteIntegerToCaData((int)xdPreserve, &pwzCustomActionData); - ExitOnFailure(hr, "failed to write Preserve Date indicator to custom action data"); - } - else - { - hr = WcaWriteIntegerToCaData((int)xdDontPreserve, &pwzCustomActionData); - ExitOnFailure(hr, "failed to write Don't Preserve Date indicator to custom action data"); - } - - hr = WriteChangeData(pxfcUninstall, &pwzCustomActionData); - ExitOnFailure(hr, "failed to write uninstall change data"); - } - } - } - } - - // Remember the file we're currently working on - hr = StrAllocString(&pwzCurrentFile, pxfc->wzFile, 0); - ExitOnFailure(hr, "failed to copy file name"); - fCurrentUseXPath = (XMLFILE_USE_XPATH & pxfc->iXmlFlags); - - // We haven't changed the current file yet - fCurrentFileChanged = FALSE; - } - - // If it's being installed - if (WcaIsInstalling(pxfc->isInstalled, pxfc->isAction)) - { - if (!fCurrentFileChanged) - { - hr = BeginChangeFile(pwzCurrentFile, pxfc, &pwzCustomActionData); - ExitOnFailure(hr, "failed to begin file change for file: %ls", pwzCurrentFile); - fCurrentFileChanged = TRUE; - ++cFiles; - } - - // Install the change - if (XMLFILE_CREATE_ELEMENT & pxfc->iXmlFlags) - { - hr = WcaWriteIntegerToCaData((int)xaCreateElement, &pwzCustomActionData); - ExitOnFailure(hr, "failed to write create element action indicator to custom action data"); - } - else if (XMLFILE_DELETE_VALUE & pxfc->iXmlFlags) - { - hr = WcaWriteIntegerToCaData((int)xaDeleteValue, &pwzCustomActionData); - ExitOnFailure(hr, "failed to write delete value action indicator to custom action data"); - } - else if (XMLFILE_BULKWRITE_VALUE & pxfc->iXmlFlags) - { - hr = WcaWriteIntegerToCaData((int)xaBulkWriteValue, &pwzCustomActionData); - ExitOnFailure(hr, "failed to write builkwrite value action indicator to custom action data"); - } - else - { - hr = WcaWriteIntegerToCaData((int)xaWriteValue, &pwzCustomActionData); - ExitOnFailure(hr, "failed to write file indicator to custom action data"); - } - - if (XMLFILE_PRESERVE_MODIFIED & pxfc->iXmlFlags) - { - hr = WcaWriteIntegerToCaData((int)xdPreserve, &pwzCustomActionData); - ExitOnFailure(hr, "failed to write Preserve Date indicator to custom action data"); - } - else - { - hr = WcaWriteIntegerToCaData((int)xdDontPreserve, &pwzCustomActionData); - ExitOnFailure(hr, "failed to write Don't Preserve Date indicator to custom action data"); - } - - hr = WriteChangeData(pxfc, &pwzCustomActionData); - ExitOnFailure(hr, "failed to write change data"); - } - } - - // If we looped through all records all is well - if (E_NOMOREITEMS == hr) - hr = S_OK; - ExitOnFailure(hr, "failed while looping through all objects to secure"); - - // Schedule the custom action and add to progress bar - if (pwzCustomActionData && *pwzCustomActionData) - { - Assert(0 < cFiles); - - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecXmlFile"), pwzCustomActionData, cFiles * COST_XMLFILE); - ExitOnFailure(hr, "failed to schedule ExecXmlFile action"); - } - -LExit: - ReleaseStr(pwzCurrentFile); - ReleaseStr(pwzCustomActionData); - - return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILURE : er); -} - - -/****************************************************************** - ExecXmlFile - entry point for XmlFile Custom Action - -*******************************************************************/ -extern "C" UINT __stdcall ExecXmlFile( - __in MSIHANDLE hInstall - ) -{ -// AssertSz(FALSE, "debug ExecXmlFile"); - HRESULT hr = S_OK; - HRESULT hrOpenFailure = S_OK; - UINT er = ERROR_SUCCESS; - - BOOL fIsFSRedirectDisabled = FALSE; - BOOL fPreserveDate = FALSE; - - int id = IDRETRY; - - LPWSTR pwzCustomActionData = NULL; - LPWSTR pwzData = NULL; - LPWSTR pwzFile = NULL; - LPWSTR pwzXPath = NULL; - LPWSTR pwzName = NULL; - LPWSTR pwzValue = NULL; - LPWSTR pwz = NULL; - - IXMLDOMDocument* pixd = NULL; - IXMLDOMNode* pixn = NULL; - IXMLDOMNode* pixnNewNode = NULL; - IXMLDOMNodeList* pixNodes = NULL; - IXMLDOMDocument2 *pixdDocument2 = NULL; - - FILETIME ft; - - BSTR bstrProperty = ::SysAllocString(L"SelectionLanguage"); - ExitOnNull(bstrProperty, hr, E_OUTOFMEMORY, "failed SysAllocString"); - VARIANT varValue; - ::VariantInit(&varValue); - varValue.vt = VT_BSTR; - varValue.bstrVal = ::SysAllocString(L"XPath"); - ExitOnNull(varValue.bstrVal, hr, E_OUTOFMEMORY, "failed SysAllocString"); - eXmlAction xa; - eXmlPreserveDate xd; - eXmlSelectionLanguage xl; - - // initialize - hr = WcaInitialize(hInstall, "ExecXmlFile"); - ExitOnFailure(hr, "failed to initialize"); - - hr = XmlInitialize(); - ExitOnFailure(hr, "failed to initialize xml utilities"); - - hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData); - ExitOnFailure(hr, "failed to get CustomActionData"); - - WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); - - pwz = pwzCustomActionData; - - hr = WcaReadIntegerFromCaData(&pwz, (int*) &xa); - ExitOnFailure(hr, "failed to process CustomActionData"); - -#ifndef _WIN64 - // Initialize the Wow64 API - store the result in fWow64APIPresent - // If it fails, this doesn't warrant an error yet, because we only need the Wow64 API in some cases - WcaInitializeWow64(); - BOOL fIsWow64Process = WcaIsWow64Process(); -#endif - - if (xaOpenFile != xa && xaOpenFilex64 != xa) - ExitOnFailure(hr = E_INVALIDARG, "invalid custom action data"); - - // loop through all the passed in data - while (pwz && *pwz) - { - hr = WcaReadIntegerFromCaData(&pwz, (int*) &xl); - ExitOnFailure(hr, "failed to process CustomActionData"); - - hr = WcaReadStringFromCaData(&pwz, &pwzFile); - ExitOnFailure(hr, "failed to read file name from custom action data"); - - // Default to not preserve the modified date - fPreserveDate = FALSE; - - // Open the file - ReleaseNullObject(pixd); - - if (xaOpenFilex64 == xa) - { -#ifndef _WIN64 - if (!fIsWow64Process) - { - hr = E_NOTIMPL; - ExitOnFailure(hr, "Custom action was told to act on a 64-bit component, but the custom action process is not running in WOW."); - } - - hr = WcaDisableWow64FSRedirection(); - ExitOnFailure(hr, "Custom action was told to act on a 64-bit component, but was unable to disable filesystem redirection through the Wow64 API."); - - fIsFSRedirectDisabled = TRUE; -#endif - } - - hr = XmlLoadDocumentFromFileEx(pwzFile, XML_LOAD_PRESERVE_WHITESPACE, &pixd); - if (FAILED(hr)) - { - // 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. - hrOpenFailure = hr; - hr = S_OK; - } - else - { - hrOpenFailure = S_OK; - } - WcaLog(LOGMSG_VERBOSE, "Configuring Xml File: %ls", pwzFile); - - if (xsXPath == xl) - { - if (vfMsxml30) - { - // If we failed to open the file, don't fail immediately; just skip setting the selection language, and we'll fail later if appropriate - if (SUCCEEDED(hrOpenFailure)) - { - hr = pixd->QueryInterface(XmlUtil_IID_IXMLDOMDocument2, (void**)&pixdDocument2); - ExitOnFailure(hr, "failed in querying IXMLDOMDocument2 interface"); - hr = pixdDocument2->setProperty(bstrProperty, varValue); - ExitOnFailure(hr, "failed in setting SelectionLanguage"); - } - } - else - { - ExitOnFailure(hr = E_NOTIMPL, "Error: current MSXML version does not support xpath query."); - } - } - - while (pwz && *pwz) - { - hr = WcaReadIntegerFromCaData(&pwz, (int*) &xa); - ExitOnFailure(hr, "failed to process CustomActionData"); - - // Break if we need to move on to a different file - if (xaOpenFile == xa || xaOpenFilex64 == xa) - break; - - hr = WcaReadIntegerFromCaData(&pwz, (int*) &xd); - ExitOnFailure(hr, "failed to process CustomActionData"); - - if (xdPreserve == xd) - { - fPreserveDate = TRUE; - } - - // Get path, name, and value to be written - hr = WcaReadStringFromCaData(&pwz, &pwzXPath); - ExitOnFailure(hr, "failed to process CustomActionData"); - hr = WcaReadStringFromCaData(&pwz, &pwzName); - ExitOnFailure(hr, "failed to process CustomActionData"); - hr = WcaReadStringFromCaData(&pwz, &pwzValue); - ExitOnFailure(hr, "failed to process CustomActionData"); - - // 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. - if (FAILED(hrOpenFailure)) - { - if (xaCreateElement == xa || xaWriteValue == xa || xaBulkWriteValue == xa) - { - MessageExitOnFailure(hr = hrOpenFailure, msierrXmlFileFailedOpen, "failed to load XML file: %ls", pwzFile); - } - else - { - continue; - } - } - - // Select the node we're about to modify - ReleaseNullObject(pixn); - - if (xaBulkWriteValue == xa) - { - hr = XmlSelectNodes(pixd, pwzXPath, &pixNodes); - if (S_FALSE == hr) - { - hr = HRESULT_FROM_WIN32(ERROR_OBJECT_NOT_FOUND); - } - - MessageExitOnFailure(hr, msierrXmlFileFailedSelect, "failed to find any nodes: %ls in XML file: %ls", pwzXPath, pwzFile); - for (;;) - { - pixNodes->nextNode(&pixn); - if (NULL == pixn) - break; - - if (pwzName && *pwzName) - { - // We're setting an attribute - hr = XmlSetAttribute(pixn, pwzName, pwzValue); - ExitOnFailure(hr, "failed to set attribute: %ls to value %ls", pwzName, pwzValue); - } - else - { - // We're setting the text of the node - hr = XmlSetText(pixn, pwzValue); - ExitOnFailure(hr, "failed to set text to: %ls for element %ls. Make sure that XPath points to an element.", pwzValue, pwzXPath); - } - ReleaseNullObject(pixn); - } - } - else - { - hr = XmlSelectSingleNode(pixd, pwzXPath, &pixn); - if (S_FALSE == hr) - hr = HRESULT_FROM_WIN32(ERROR_OBJECT_NOT_FOUND); - MessageExitOnFailure(hr, msierrXmlFileFailedSelect, "failed to find node: %ls in XML file: %ls", pwzXPath, pwzFile); - - // Make the modification - if (xaWriteValue == xa) - { - if (pwzName && *pwzName) - { - // We're setting an attribute - hr = XmlSetAttribute(pixn, pwzName, pwzValue); - ExitOnFailure(hr, "failed to set attribute: %ls to value %ls", pwzName, pwzValue); - } - else - { - // We're setting the text of the node - hr = XmlSetText(pixn, pwzValue); - ExitOnFailure(hr, "failed to set text to: %ls for element %ls. Make sure that XPath points to an element.", pwzValue, pwzXPath); - } - } - else if (xaCreateElement == xa) - { - hr = XmlCreateChild(pixn, pwzName, &pixnNewNode); - ExitOnFailure(hr, "failed to create child element: %ls", pwzName); - - if (pwzValue && *pwzValue) - { - hr = XmlSetText(pixnNewNode, pwzValue); - ExitOnFailure(hr, "failed to set text to: %ls for node: %ls", pwzValue, pwzName); - } - - ReleaseNullObject(pixnNewNode); - } - else if (xaDeleteValue == xa) - { - if (pwzName && *pwzName) - { - // Delete the attribute - hr = XmlRemoveAttribute(pixn, pwzName); - ExitOnFailure(hr, "failed to remove attribute: %ls", pwzName); - } - else - { - // Clear the text value for the node - hr = XmlSetText(pixn, L""); - ExitOnFailure(hr, "failed to clear text value"); - } - } - else if (xaDeleteElement == xa) - { - // TODO: This may be a little heavy handed - hr = XmlRemoveChildren(pixn, pwzName); - ExitOnFailure(hr, "failed to delete child node: %ls", pwzName); - } - else - { - ExitOnFailure(hr = E_UNEXPECTED, "Invalid modification specified in custom action data"); - } - } - } - - // Now that we've made all of the changes to this file, save it and move on to the next - if (S_OK == hrOpenFailure) - { - if (fPreserveDate) - { - hr = FileGetTime(pwzFile, NULL, NULL, &ft); - ExitOnFailure(hr, "failed to get modified time of file : %ls", pwzFile); - } - - int iSaveAttempt = 0; - - do - { - hr = XmlSaveDocument(pixd, pwzFile); - if (FAILED(hr)) - { - id = WcaErrorMessage(msierrXmlConfigFailedSave, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 1, pwzFile); - switch (id) - { - case IDABORT: - ExitOnFailure(hr, "Failed to save changes to XML file: %ls", pwzFile); - case IDRETRY: - hr = S_FALSE; // hit me, baby, one more time - break; - case IDIGNORE: - hr = S_OK; // pretend everything is okay and bail - break; - case 0: // No UI case, MsiProcessMessage returns 0 - if (STIERR_SHARING_VIOLATION == hr) - { - // Only in case of sharing violation do we retry 30 times, once a second. - if (iSaveAttempt < 30) - { - hr = S_FALSE; - ++iSaveAttempt; - WcaLog(LOGMSG_VERBOSE, "Unable to save changes to XML file: %ls, retry attempt: %x", pwzFile, iSaveAttempt); - Sleep(1000); - } - else - { - ExitOnFailure(hr, "Failed to save changes to XML file: %ls", pwzFile); - } - } - break; - default: // Unknown error - ExitOnFailure(hr, "Failed to save changes to XML file: %ls", pwzFile); - } - } - } while (S_FALSE == hr); - - if (fPreserveDate) - { - hr = FileSetTime(pwzFile, NULL, NULL, &ft); - ExitOnFailure(hr, "failed to set modified time of file : %ls", pwzFile); - } - - if (fIsFSRedirectDisabled) - { - fIsFSRedirectDisabled = FALSE; - WcaRevertWow64FSRedirection(); - } - } - } - -LExit: - // Make sure we revert FS Redirection if necessary before exiting - if (fIsFSRedirectDisabled) - { - fIsFSRedirectDisabled = FALSE; - WcaRevertWow64FSRedirection(); - } -#ifndef _WIN64 - WcaFinalizeWow64(); -#endif - - ReleaseStr(pwzCustomActionData); - ReleaseStr(pwzData); - ReleaseStr(pwzFile); - ReleaseStr(pwzXPath); - ReleaseStr(pwzName); - ReleaseStr(pwzValue); - ReleaseBSTR(bstrProperty); - ReleaseVariant(varValue); - - ReleaseObject(pixdDocument2); - ReleaseObject(pixn); - ReleaseObject(pixd); - ReleaseObject(pixnNewNode); - ReleaseObject(pixNodes); - - XmlUninitialize(); - - return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILURE : er); -} - - -/****************************************************************** - ExecXmlFileRollback - entry point for XmlFile rollback Custom Action - -*******************************************************************/ -extern "C" UINT __stdcall ExecXmlFileRollback( - __in MSIHANDLE hInstall - ) -{ -// AssertSz(FALSE, "debug ExecXmlFileRollback"); - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - - int iIs64Bit; - BOOL fIs64Bit = FALSE; - - LPWSTR pwzCustomActionData = NULL; - LPWSTR pwz = NULL; - LPWSTR pwzFileName = NULL; - LPBYTE pbData = NULL; - DWORD_PTR cbData = 0; - - FILETIME ft; - - HANDLE hFile = INVALID_HANDLE_VALUE; - - // initialize - hr = WcaInitialize(hInstall, "ExecXmlFileRollback"); - ExitOnFailure(hr, "failed to initialize"); - - - hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData); - ExitOnFailure(hr, "failed to get CustomActionData"); - - WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); - - pwz = pwzCustomActionData; - - hr = WcaReadIntegerFromCaData(&pwz, &iIs64Bit); - ExitOnFailure(hr, "failed to read component bitness from custom action data"); - - hr = WcaReadStringFromCaData(&pwz, &pwzFileName); - ExitOnFailure(hr, "failed to read file name from custom action data"); - - hr = WcaReadStreamFromCaData(&pwz, &pbData, &cbData); - ExitOnFailure(hr, "failed to read file contents from custom action data"); - -#ifndef _WIN64 - fIs64Bit = (BOOL)iIs64Bit; - - if (fIs64Bit) - { - hr = WcaInitializeWow64(); - if (S_FALSE == hr) - { - hr = TYPE_E_DLLFUNCTIONNOTFOUND; - } - ExitOnFailure(hr, "failed to initialize Wow64 API"); - - if (!WcaIsWow64Process()) - { - hr = E_NOTIMPL; - ExitOnFailure(hr, "Custom action was told to rollback a 64-bit component, but the custom action process is not running in WOW."); - } - - hr = WcaDisableWow64FSRedirection(); - ExitOnFailure(hr, "Custom action was told to rollback a 64-bit component, but was unable to Disable Filesystem Redirection through the Wow64 API."); - } -#endif - - // Always preserve the modified date on rollback - hr = FileGetTime(pwzFileName, NULL, NULL, &ft); - ExitOnFailure(hr, "Failed to get modified date of file %ls.", pwzFileName); - - // Open the file - hFile = ::CreateFileW(pwzFileName, GENERIC_WRITE, NULL, NULL, TRUNCATE_EXISTING, NULL, NULL); - ExitOnInvalidHandleWithLastError(hFile, hr, "failed to open file: %ls", pwzFileName); - - // Write out the old data - hr = FileWriteHandle(hFile, pbData, cbData); - ExitOnFailure(hr, "failed to write to file: %ls", pwzFileName); - - ReleaseFile(hFile); - - // Always preserve the modified date on rollback - hr = FileSetTime(pwzFileName, NULL, NULL, &ft); - ExitOnFailure(hr, "Failed to set modified date of file %ls.", pwzFileName); - -LExit: - ReleaseStr(pwzCustomActionData); - ReleaseStr(pwzFileName); - - ReleaseFile(hFile); - - if (fIs64Bit) - { - WcaRevertWow64FSRedirection(); - WcaFinalizeWow64(); - } - - ReleaseMem(pbData); - - return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILURE : er); -} - diff --git a/src/ca/caDecor.h b/src/ca/caDecor.h deleted file mode 100644 index 56cfb201..00000000 --- a/src/ca/caDecor.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - - -#if defined(_M_ARM64) -#define CUSTOM_ACTION_DECORATION(f) L"Wix4" f L"_A64" -#elif defined(_M_AMD64) -#define CUSTOM_ACTION_DECORATION(f) L"Wix4" f L"_X64" -#elif defined(_M_ARM) -#define CUSTOM_ACTION_DECORATION(f) L"Wix4" f L"_ARM" -#else -#define CUSTOM_ACTION_DECORATION(f) L"Wix4" f L"_X86" -#endif diff --git a/src/ca/cost.h b/src/ca/cost.h deleted file mode 100644 index 6507e85d..00000000 --- a/src/ca/cost.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - - -const UINT COST_SECUREOBJECT = 1000; -const UINT COST_SERVICECONFIG = 1000; -const UINT COST_XMLFILE = 1000; -const UINT COST_CLOSEAPP = 500; -const UINT COST_INTERNETSHORTCUT = 2000; diff --git a/src/ca/dllmain.cpp b/src/ca/dllmain.cpp deleted file mode 100644 index 35ae6d1c..00000000 --- a/src/ca/dllmain.cpp +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" - -/******************************************************************** -DllMain - standard entry point for all WiX custom actions - -********************************************************************/ -extern "C" BOOL WINAPI DllMain( - IN HINSTANCE hInst, - IN ULONG ulReason, - IN LPVOID) -{ - switch(ulReason) - { - case DLL_PROCESS_ATTACH: - WcaGlobalInitialize(hInst); - break; - - case DLL_PROCESS_DETACH: - WcaGlobalFinalize(); - break; - } - - return TRUE; -} diff --git a/src/ca/exitearlywithsuccess.cpp b/src/ca/exitearlywithsuccess.cpp deleted file mode 100644 index 00828329..00000000 --- a/src/ca/exitearlywithsuccess.cpp +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" - - -/****************************************************************** -WixExitEarlyWithSuccess - entry point for WixExitEarlyWithSuccess - custom action which does nothing except return exit code - ERROR_NO_MORE_ITEMS. The Windows Installer documentation at - http://msdn.microsoft.com/library/aa368072.aspx indicates that - this exit code is not treated as an error. This will cause a - calling application to receive a successful return code if - this custom action executes. This can be useful for backwards - compatibility when an application redistributes an MSI and - a future major upgrade is released for that MSI. It should be - conditioned on a property set by an entry in the Upgrade table - of the MSI that detects newer major upgrades of the same MSI - already installed on the system. It should be scheduled after - the FindRelatedProducts action so that the property will be - set if appropriate. -********************************************************************/ -extern "C" UINT __stdcall WixExitEarlyWithSuccess( - __in MSIHANDLE /*hInstall*/ - ) -{ - return ERROR_NO_MORE_ITEMS; -} diff --git a/src/ca/netshortcuts.cpp b/src/ca/netshortcuts.cpp deleted file mode 100644 index 06826264..00000000 --- a/src/ca/netshortcuts.cpp +++ /dev/null @@ -1,437 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" - -LPCWSTR vcsShortcutsQuery = - L"SELECT `Component_`, `Directory_`, `Name`, `Target`, `Attributes`, `IconFile`, `IconIndex` " - L"FROM `Wix4InternetShortcut`"; -enum eShortcutsQuery { esqComponent = 1, esqDirectory, esqFilename, esqTarget, esqAttributes, esqIconFile, esqIconIndex }; -enum eShortcutsAttributes { esaLink = 0, esaURL = 1 }; - -/****************************************************************** - WixSchedInternetShortcuts - entry point - -********************************************************************/ -extern "C" UINT __stdcall WixSchedInternetShortcuts( - __in MSIHANDLE hInstall - ) -{ - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - - UINT uiCost = 0; - - PMSIHANDLE hView = NULL; - PMSIHANDLE hRec = NULL; - - MSIHANDLE hCreateFolderTable = NULL; - MSIHANDLE hCreateFolderColumns = NULL; - - LPWSTR pwzCustomActionData = NULL; - LPWSTR pwzComponent = NULL; - LPWSTR pwzDirectory = NULL; - LPWSTR pwzFilename = NULL; - LPWSTR pwzTarget = NULL; - LPWSTR pwzShortcutPath = NULL; - int iAttr = 0; - LPWSTR pwzIconFile = NULL; - int iIconIndex = 0; - IUniformResourceLocatorW* piURL = NULL; - IShellLinkW* piShellLink = NULL; - BOOL fInitializedCom = FALSE; - - hr = WcaInitialize(hInstall, "WixSchedInternetShortcuts"); - ExitOnFailure(hr, "failed to initialize WixSchedInternetShortcuts."); - - // anything to do? - if (S_OK != WcaTableExists(L"Wix4InternetShortcut")) - { - WcaLog(LOGMSG_STANDARD, "Wix4InternetShortcut table doesn't exist, so there are no Internet shortcuts to process"); - goto LExit; - } - - // check to see if we can create a shortcut - Server Core and others may not have a shell registered. - hr = ::CoInitialize(NULL); - ExitOnFailure(hr, "failed to initialize COM"); - fInitializedCom = TRUE; - - hr = ::CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_ALL, IID_IUniformResourceLocatorW, (void**)&piURL); - if (S_OK != hr) - { - WcaLog(LOGMSG_STANDARD, "failed to create an instance of IUniformResourceLocatorW, skipping shortcut creation"); - ExitFunction1(hr = S_OK); - } - - hr = ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_ALL, IID_IShellLinkW, (void**)&piShellLink); - if (S_OK != hr) - { - WcaLog(LOGMSG_STANDARD, "failed to create an instance of IShellLinkW, skipping shortcut creation"); - ExitFunction1(hr = S_OK); - } - - // query and loop through all the shortcuts - hr = WcaOpenExecuteView(vcsShortcutsQuery, &hView); - ExitOnFailure(hr, "failed to open view on Wix4InternetShortcut table"); - - while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) - { - // read column values - hr = WcaGetRecordString(hRec, esqComponent, &pwzComponent); - ExitOnFailure(hr, "failed to get shortcut component"); - hr = WcaGetRecordString(hRec, esqDirectory, &pwzDirectory); - ExitOnFailure(hr, "failed to get shortcut directory"); - hr = WcaGetRecordString(hRec, esqFilename, &pwzFilename); - ExitOnFailure(hr, "failed to get shortcut filename"); - hr = WcaGetRecordFormattedString(hRec, esqTarget, &pwzTarget); - ExitOnFailure(hr, "failed to get shortcut target"); - hr = WcaGetRecordInteger(hRec, esqAttributes, &iAttr); - ExitOnFailure(hr, "failed to get shortcut attributes"); - hr = WcaGetRecordFormattedString(hRec, esqIconFile, &pwzIconFile); - ExitOnFailure(hr, "failed to get shortcut icon file"); - hr = WcaGetRecordInteger(hRec, esqIconIndex, &iIconIndex); - ExitOnFailure(hr, "failed to get shortcut icon index"); - - // skip processing this Wix4InternetShortcut row if the component isn't being configured - WCA_TODO todo = WcaGetComponentToDo(pwzComponent); - if (WCA_TODO_UNKNOWN == todo) - { - WcaLog(LOGMSG_VERBOSE, "Skipping shortcut for null-action component '%ls'", pwzComponent); - continue; - } - - // we need to create the directory where the shortcut is supposed to live; rather - // than doing so in our deferred custom action, use the CreateFolder table to have MSI - // make (and remove) them on our behalf (including the correct cleanup of parent directories). - MSIDBERROR dbError = MSIDBERROR_NOERROR; - WcaLog(LOGMSG_STANDARD, "Adding folder '%ls', component '%ls' to the CreateFolder table", pwzDirectory, pwzComponent); - hr = WcaAddTempRecord(&hCreateFolderTable, &hCreateFolderColumns, L"CreateFolder", &dbError, 0, 2, pwzDirectory, pwzComponent); - if (MSIDBERROR_DUPLICATEKEY == dbError) - { - WcaLog(LOGMSG_STANDARD, "Folder '%ls' already exists in the CreateFolder table; the above error is harmless", pwzDirectory); - hr = S_OK; - } - ExitOnFailure(hr, "Couldn't add temporary CreateFolder row"); - - // only if we're installing/reinstalling do we need to schedule the deferred CA - // (uninstallation is handled via permanent RemoveFile rows and temporary CreateFolder rows) - if (WCA_TODO_INSTALL == todo || WCA_TODO_REINSTALL == todo) - { - // turn the Directory_ id into a path - hr = WcaGetTargetPath(pwzDirectory, &pwzShortcutPath); - ExitOnFailure(hr, "failed to allocate string for shortcut directory"); - - // append the shortcut filename - hr = StrAllocConcat(&pwzShortcutPath, pwzFilename, 0); - ExitOnFailure(hr, "failed to allocate string for shortcut filename"); - - // write the shortcut path and target to custom action data for deferred CAs - hr = WcaWriteStringToCaData(pwzShortcutPath, &pwzCustomActionData); - ExitOnFailure(hr, "failed to write shortcut path to custom action data"); - hr = WcaWriteStringToCaData(pwzTarget, &pwzCustomActionData); - ExitOnFailure(hr, "failed to write shortcut target to custom action data"); - hr = WcaWriteIntegerToCaData(iAttr, &pwzCustomActionData); - ExitOnFailure(hr, "failed to write shortcut attributes to custom action data"); - hr = WcaWriteStringToCaData(pwzIconFile, &pwzCustomActionData); - ExitOnFailure(hr, "failed to write icon file to custom action data"); - hr = WcaWriteIntegerToCaData(iIconIndex, &pwzCustomActionData); - ExitOnFailure(hr, "failed to write icon index to custom action data"); - - uiCost += COST_INTERNETSHORTCUT; - } - } - - if (E_NOMOREITEMS == hr) - { - hr = S_OK; - } - ExitOnFailure(hr, "Failure occured while processing Wix4InternetShortcut table"); - - // if we have any shortcuts to install - if (pwzCustomActionData && *pwzCustomActionData) - { - // add cost to progress bar - hr = WcaProgressMessage(uiCost, TRUE); - ExitOnFailure(hr, "failed to extend progress bar for InternetShortcuts"); - - // provide custom action data to deferred and rollback CAs - hr = WcaSetProperty(CUSTOM_ACTION_DECORATION(L"RollbackInternetShortcuts"), pwzCustomActionData); - ExitOnFailure(hr, "failed to set WixRollbackInternetShortcuts rollback custom action data"); - hr = WcaSetProperty(CUSTOM_ACTION_DECORATION(L"CreateInternetShortcuts"), pwzCustomActionData); - ExitOnFailure(hr, "failed to set WixCreateInternetShortcuts custom action data"); - } - -LExit: - if (hCreateFolderTable) - { - ::MsiCloseHandle(hCreateFolderTable); - } - - if (hCreateFolderColumns) - { - ::MsiCloseHandle(hCreateFolderColumns); - } - - ReleaseStr(pwzCustomActionData); - ReleaseStr(pwzComponent); - ReleaseStr(pwzDirectory); - ReleaseStr(pwzFilename); - ReleaseStr(pwzTarget); - ReleaseStr(pwzShortcutPath); - ReleaseObject(piShellLink); - ReleaseObject(piURL); - - if (fInitializedCom) - { - ::CoUninitialize(); - } - - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} - - - -/****************************************************************** - CreateUrl - Creates a shortcut via IUniformResourceLocatorW - -*******************************************************************/ -static HRESULT CreateUrl( - __in_z LPCWSTR wzTarget, - __in_z LPCWSTR wzShortcutPath, - __in_z_opt LPCWSTR wzIconPath, - __in int iconIndex -) -{ - HRESULT hr = S_OK; - IUniformResourceLocatorW* piURL = NULL; - IPersistFile* piPersistFile = NULL; - IPropertySetStorage* piProperties = NULL; - IPropertyStorage* piStorage = NULL; - - // create an internet shortcut object - WcaLog(LOGMSG_STANDARD, "Creating IUniformResourceLocatorW shortcut '%ls' target '%ls'", wzShortcutPath, wzTarget); - hr = ::CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_ALL, IID_IUniformResourceLocatorW, (void**)&piURL); - ExitOnFailure(hr, "failed to create an instance of IUniformResourceLocatorW"); - - // set shortcut target - hr = piURL->SetURL(wzTarget, 0); - ExitOnFailure(hr, "failed to set shortcut '%ls' target '%ls'", wzShortcutPath, wzTarget); - - if (wzIconPath) - { - WcaLog(LOGMSG_STANDARD, "Adding icon '%ls' index '%d'", wzIconPath, iconIndex); - - hr = piURL->QueryInterface(IID_IPropertySetStorage, (void **)&piProperties); - ExitOnFailure(hr, "failed to get IPropertySetStorage for shortcut '%ls'", wzShortcutPath); - - hr = piProperties->Open(FMTID_Intshcut, STGM_WRITE, &piStorage); - ExitOnFailure(hr, "failed to open storage for shortcut '%ls'", wzShortcutPath); - - PROPSPEC ppids[2] = { {PRSPEC_PROPID, PID_IS_ICONINDEX}, {PRSPEC_PROPID, PID_IS_ICONFILE} }; - PROPVARIANT ppvar[2]; - - PropVariantInit(ppvar); - PropVariantInit(ppvar + 1); - - ppvar[0].vt = VT_I4; - ppvar[0].lVal = iconIndex; - ppvar[1].vt = VT_LPWSTR; - ppvar[1].pwszVal = const_cast(wzIconPath); - - hr = piStorage->WriteMultiple(2, ppids, ppvar, 0); - ExitOnFailure(hr, "failed to write icon storage for shortcut '%ls'", wzShortcutPath); - - hr = piStorage->Commit(STGC_DEFAULT); - ExitOnFailure(hr, "failed to commit icon storage for shortcut '%ls'", wzShortcutPath); - } - - // get an IPersistFile and save the shortcut - hr = piURL->QueryInterface(IID_IPersistFile, (void**)&piPersistFile); - ExitOnFailure(hr, "failed to get IPersistFile for shortcut '%ls'", wzShortcutPath); - - hr = piPersistFile->Save(wzShortcutPath, TRUE); - ExitOnFailure(hr, "failed to save shortcut '%ls'", wzShortcutPath); - -LExit: - ReleaseObject(piPersistFile); - ReleaseObject(piURL); - ReleaseObject(piStorage); - ReleaseObject(piProperties); - - return hr; -} - -/****************************************************************** - CreateLink - Creates a shortcut via IShellLinkW - -*******************************************************************/ -static HRESULT CreateLink( - __in_z LPCWSTR wzTarget, - __in_z LPCWSTR wzShortcutPath, - __in_z_opt LPCWSTR wzIconPath, - __in int iconIndex -) -{ - HRESULT hr = S_OK; - IShellLinkW* piShellLink = NULL; - IPersistFile* piPersistFile = NULL; - - // create an internet shortcut object - WcaLog(LOGMSG_STANDARD, "Creating IShellLinkW shortcut '%ls' target '%ls'", wzShortcutPath, wzTarget); - hr = ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_ALL, IID_IShellLinkW, (void**)&piShellLink); - ExitOnFailure(hr, "failed to create an instance of IShellLinkW"); - - // set shortcut target - hr = piShellLink->SetPath(wzTarget); - ExitOnFailure(hr, "failed to set shortcut '%ls' target '%ls'", wzShortcutPath, wzTarget); - - if (wzIconPath) - { - WcaLog(LOGMSG_STANDARD, "Adding icon '%ls' index '%d'", wzIconPath, iconIndex); - hr = piShellLink->SetIconLocation(wzIconPath, iconIndex); - ExitOnFailure(hr, "failed to set icon for shortcut '%ls'", wzShortcutPath); - } - - // get an IPersistFile and save the shortcut - hr = piShellLink->QueryInterface(IID_IPersistFile, (void**)&piPersistFile); - ExitOnFailure(hr, "failed to get IPersistFile for shortcut '%ls'", wzShortcutPath); - - hr = piPersistFile->Save(wzShortcutPath, TRUE); - ExitOnFailure(hr, "failed to save shortcut '%ls'", wzShortcutPath); - -LExit: - ReleaseObject(piPersistFile); - ReleaseObject(piShellLink); - - return hr; -} - - - -/****************************************************************** - WixCreateInternetShortcuts - entry point for Internet shortcuts - custom action -*******************************************************************/ -extern "C" UINT __stdcall WixCreateInternetShortcuts( - __in MSIHANDLE hInstall - ) -{ - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - - LPWSTR pwz = NULL; - LPWSTR pwzCustomActionData = NULL; - LPWSTR pwzTarget = NULL; - LPWSTR pwzShortcutPath = NULL; - LPWSTR pwzIconPath = NULL; - BOOL fInitializedCom = FALSE; - int iAttr = 0; - int iIconIndex = 0; - - // initialize - hr = WcaInitialize(hInstall, "WixCreateInternetShortcuts"); - ExitOnFailure(hr, "failed to initialize WixCreateInternetShortcuts"); - - hr = ::CoInitialize(NULL); - ExitOnFailure(hr, "failed to initialize COM"); - fInitializedCom = TRUE; - - // extract the custom action data - hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData); - ExitOnFailure(hr, "failed to get CustomActionData"); - - // loop through all the custom action data - pwz = pwzCustomActionData; - while (pwz && *pwz) - { - hr = WcaReadStringFromCaData(&pwz, &pwzShortcutPath); - ExitOnFailure(hr, "failed to read shortcut path from custom action data"); - hr = WcaReadStringFromCaData(&pwz, &pwzTarget); - ExitOnFailure(hr, "failed to read shortcut target from custom action data"); - hr = WcaReadIntegerFromCaData(&pwz, &iAttr); - ExitOnFailure(hr, "failed to read shortcut attributes from custom action data"); - hr = WcaReadStringFromCaData(&pwz, &pwzIconPath); - ExitOnFailure(hr, "failed to read shortcut icon path from custom action data"); - hr = WcaReadIntegerFromCaData(&pwz, &iIconIndex); - ExitOnFailure(hr, "failed to read shortcut icon index from custom action data"); - - if ((iAttr & esaURL) == esaURL) - { - hr = CreateUrl(pwzTarget, pwzShortcutPath, pwzIconPath, iIconIndex); - } - else - { - hr = CreateLink(pwzTarget, pwzShortcutPath, pwzIconPath, iIconIndex); - } - ExitOnFailure(hr, "failed to create Internet shortcut"); - - // tick the progress bar - hr = WcaProgressMessage(COST_INTERNETSHORTCUT, FALSE); - ExitOnFailure(hr, "failed to tick progress bar for shortcut: %ls", pwzShortcutPath); - } - -LExit: - ReleaseStr(pwzCustomActionData); - ReleaseStr(pwzTarget); - ReleaseStr(pwzShortcutPath); - - if (fInitializedCom) - { - ::CoUninitialize(); - } - - er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er; - return WcaFinalize(er); -} - - - -/****************************************************************** - WixRollbackInternetShortcuts - entry point for Internet shortcuts - custom action (rollback) -*******************************************************************/ -extern "C" UINT __stdcall WixRollbackInternetShortcuts( - __in MSIHANDLE hInstall - ) -{ - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - - LPWSTR pwz = NULL; - LPWSTR pwzCustomActionData = NULL; - LPWSTR pwzShortcutPath = NULL; - int iAttr = 0; - - // initialize - hr = WcaInitialize(hInstall, "WixRemoveInternetShortcuts"); - ExitOnFailure(hr, "failed to initialize WixRemoveInternetShortcuts"); - - hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData); - ExitOnFailure(hr, "failed to get CustomActionData"); - - // loop through all the custom action data - pwz = pwzCustomActionData; - while (pwz && *pwz) - { - // extract the custom action data we're interested in - hr = WcaReadStringFromCaData(&pwz, &pwzShortcutPath); - ExitOnFailure(hr, "failed to read shortcut path from custom action data for rollback"); - - // delete file - hr = FileEnsureDelete(pwzShortcutPath); - ExitOnFailure(hr, "failed to delete file '%ls'", pwzShortcutPath); - - // skip over the shortcut target and attributes - hr = WcaReadStringFromCaData(&pwz, &pwzShortcutPath); - ExitOnFailure(hr, "failed to skip shortcut target from custom action data for rollback"); - hr = WcaReadIntegerFromCaData(&pwz, &iAttr); - ExitOnFailure(hr, "failed to read shortcut attributes from custom action data"); - } - -LExit: - ReleaseStr(pwzCustomActionData); - ReleaseStr(pwzShortcutPath); - - er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er; - return WcaFinalize(er); -} diff --git a/src/ca/precomp.h b/src/ca/precomp.h deleted file mode 100644 index c5d6afe5..00000000 --- a/src/ca/precomp.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - - -#if _WIN32_MSI < 150 -#define _WIN32_MSI 150 -#endif - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include // NetApi32.lib -#include -#include -#include -#include - -#define MAXUINT USHRT_MAX - -#include "wcautil.h" -#include "wcawow64.h" -#include "wcawrapquery.h" -#include "aclutil.h" -#include "dirutil.h" -#include "fileutil.h" -#include "memutil.h" -#include "osutil.h" -#include "pathutil.h" -#include "procutil.h" -#include "shelutil.h" -#include "strutil.h" -#include "sczutil.h" -#include "rmutil.h" -#include "userutil.h" -#include "xmlutil.h" -#include "wiutil.h" - -#include "CustomMsiErrors.h" - -#include "sca.h" -#include "scacost.h" -#include "cost.h" -#include "scauser.h" -#include "scasmb.h" -#include "scasmbexec.h" - -#include "caDecor.h" diff --git a/src/ca/qtexecca.cpp b/src/ca/qtexecca.cpp deleted file mode 100644 index ddcc812f..00000000 --- a/src/ca/qtexecca.cpp +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" - -#define OUTPUT_BUFFER 1024 - -// These old "CA" prefix names are deprecated, and intended to go away in wix 4.0, only staying now for compatibility reasons -const LPCWSTR CAQUIET_TIMEOUT_PROPERTY = L"QtExecCmdTimeout"; -const LPCWSTR CAQUIET_ARGUMENTS_PROPERTY = L"QtExecCmdLine"; -const LPCWSTR CAQUIET64_ARGUMENTS_PROPERTY = L"QtExec64CmdLine"; -// end deprecated section - -// WixCA name quiet commandline argument properties -const LPCWSTR WIX_QUIET_ARGUMENTS_PROPERTY = L"WixQuietExecCmdLine"; -const LPCWSTR WIX_QUIET64_ARGUMENTS_PROPERTY = L"WixQuietExec64CmdLine"; - -// WixCA quiet timeout properties -const LPCWSTR WIX_QUIET_TIMEOUT_PROPERTY = L"WixQuietExecCmdTimeout"; -const LPCWSTR WIX_QUIET64_TIMEOUT_PROPERTY = L"WixQuietExec64CmdTimeout"; - -// WixCA silent commandline argument properties -const LPCWSTR WIX_SILENT_ARGUMENTS_PROPERTY = L"WixSilentExecCmdLine"; -const LPCWSTR WIX_SILENT64_ARGUMENTS_PROPERTY = L"WixSilentExec64CmdLine"; - -// WixCA silent timeout properties -const LPCWSTR WIX_SILENT_TIMEOUT_PROPERTY = L"WixSilentExecCmdTimeout"; -const LPCWSTR WIX_SILENT64_TIMEOUT_PROPERTY = L"WixSilentExec64CmdTimeout"; - -HRESULT BuildCommandLine( - __in LPCWSTR wzProperty, - __out LPWSTR *ppwzCommand - ) -{ - Assert(ppwzCommand); - - HRESULT hr = S_OK; - BOOL fScheduled = ::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_SCHEDULED); - BOOL fRollback = ::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK); - BOOL fCommit = ::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_COMMIT); - - if (fScheduled || fRollback || fCommit) - { - if (WcaIsPropertySet("CustomActionData")) - { - hr = WcaGetProperty( L"CustomActionData", ppwzCommand); - ExitOnFailure(hr, "Failed to get CustomActionData"); - } - } - else if (WcaIsUnicodePropertySet(wzProperty)) - { - hr = WcaGetFormattedProperty(wzProperty, ppwzCommand); - ExitOnFailure(hr, "Failed to get %ls", wzProperty); - hr = WcaSetProperty(wzProperty, L""); // clear out the property now that we've read it - ExitOnFailure(hr, "Failed to set %ls", wzProperty); - } - - if (!*ppwzCommand) - { - ExitOnFailure(hr = E_INVALIDARG, "Failed to get command line data"); - } - - if (L'"' != **ppwzCommand) - { - WcaLog(LOGMSG_STANDARD, "Command string must begin with quoted application name."); - ExitOnFailure(hr = E_INVALIDARG, "invalid command line property value"); - } - -LExit: - return hr; -} - -#define ONEMINUTE 60000 - -DWORD GetTimeout(LPCWSTR wzPropertyName) -{ - DWORD dwTimeout = ONEMINUTE; - HRESULT hr = S_OK; - - LPWSTR pwzData = NULL; - - if (WcaIsUnicodePropertySet(wzPropertyName)) - { - hr = WcaGetProperty(wzPropertyName, &pwzData); - ExitOnFailure(hr, "Failed to get %ls", wzPropertyName); - - if ((dwTimeout = (DWORD)_wtoi(pwzData)) == 0) - { - dwTimeout = ONEMINUTE; - } - } - -LExit: - ReleaseStr(pwzData); - - return dwTimeout; - -} - -HRESULT ExecCommon( - __in LPCWSTR wzArgumentsProperty, - __in LPCWSTR wzTimeoutProperty, - __in BOOL fLogCommand, - __in BOOL fLogOutput - ) -{ - HRESULT hr = S_OK; - LPWSTR pwzCommand = NULL; - DWORD dwTimeout = 0; - - hr = BuildCommandLine(wzArgumentsProperty, &pwzCommand); - ExitOnFailure(hr, "Failed to get Command Line"); - - dwTimeout = GetTimeout(wzTimeoutProperty); - - hr = QuietExec(pwzCommand, dwTimeout, fLogCommand, fLogOutput); - ExitOnFailure(hr, "QuietExec Failed"); - -LExit: - ReleaseStr(pwzCommand); - - return hr; -} - -HRESULT ExecCommon64( - __in LPCWSTR wzArgumentsProperty, - __in LPCWSTR wzTimeoutProperty, - __in BOOL fLogCommand, - __in BOOL fLogOutput - ) -{ - HRESULT hr = S_OK; - LPWSTR pwzCommand = NULL; - DWORD dwTimeout = 0; -#ifndef _WIN64 - BOOL fIsWow64Initialized = FALSE; - BOOL fRedirected = FALSE; - - hr = WcaInitializeWow64(); - if (S_FALSE == hr) - { - hr = TYPE_E_DLLFUNCTIONNOTFOUND; - } - ExitOnFailure(hr, "Failed to intialize WOW64."); - fIsWow64Initialized = TRUE; - - hr = WcaDisableWow64FSRedirection(); - ExitOnFailure(hr, "Failed to enable filesystem redirection."); - fRedirected = TRUE; -#endif - - hr = BuildCommandLine(wzArgumentsProperty, &pwzCommand); - ExitOnFailure(hr, "Failed to get Command Line"); - - dwTimeout = GetTimeout(wzTimeoutProperty); - - hr = QuietExec(pwzCommand, dwTimeout, fLogCommand, fLogOutput); - ExitOnFailure(hr, "QuietExec64 Failed"); - -LExit: - ReleaseStr(pwzCommand); - -#ifndef _WIN64 - if (fRedirected) - { - WcaRevertWow64FSRedirection(); - } - - if (fIsWow64Initialized) - { - WcaFinalizeWow64(); - } -#endif - - return hr; -} - -// These two custom actions are deprecated, and should go away in wix v4.0. WixQuietExec replaces this one, -// and is not intended to have any difference in behavior apart from CA name and property names. -extern "C" UINT __stdcall CAQuietExec( - __in MSIHANDLE hInstall - ) -{ - Assert(hInstall); - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - - hr = WcaInitialize(hInstall, "CAQuietExec"); - ExitOnFailure(hr, "Failed to initialize"); - - hr = ExecCommon(CAQUIET_ARGUMENTS_PROPERTY, CAQUIET_TIMEOUT_PROPERTY, TRUE, TRUE); - ExitOnFailure(hr, "Failed in ExecCommon method"); - -LExit: - if (FAILED(hr)) - { - er = ERROR_INSTALL_FAILURE; - } - - return WcaFinalize(er); -} - -// 2nd deprecated custom action name, superseded by WixQuietExec64 -extern "C" UINT __stdcall CAQuietExec64( - __in MSIHANDLE hInstall - ) -{ - Assert(hInstall); - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - - hr = WcaInitialize(hInstall, "CAQuietExec64"); - ExitOnFailure(hr, "Failed to initialize"); - - hr = ExecCommon64(CAQUIET64_ARGUMENTS_PROPERTY, CAQUIET_TIMEOUT_PROPERTY, TRUE, TRUE); - ExitOnFailure(hr, "Failed in ExecCommon64 method"); - -LExit: - if (FAILED(hr)) - { - er = ERROR_INSTALL_FAILURE; - } - - return WcaFinalize(er); -} - -extern "C" UINT __stdcall WixQuietExec( - __in MSIHANDLE hInstall - ) -{ - Assert(hInstall); - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - - hr = WcaInitialize(hInstall, "WixQuietExec"); - ExitOnFailure(hr, "Failed to initialize"); - - hr = ExecCommon(WIX_QUIET_ARGUMENTS_PROPERTY, WIX_QUIET_TIMEOUT_PROPERTY, TRUE, TRUE); - ExitOnFailure(hr, "Failed in ExecCommon method"); - -LExit: - if (FAILED(hr)) - { - er = ERROR_INSTALL_FAILURE; - } - - return WcaFinalize(er); -} - -extern "C" UINT __stdcall WixQuietExec64( - __in MSIHANDLE hInstall - ) -{ - Assert(hInstall); - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - - hr = WcaInitialize(hInstall, "WixQuietExec64"); - ExitOnFailure(hr, "Failed to initialize"); - - hr = ExecCommon64(WIX_QUIET64_ARGUMENTS_PROPERTY, WIX_QUIET64_TIMEOUT_PROPERTY, TRUE, TRUE); - ExitOnFailure(hr, "Failed in ExecCommon method"); - -LExit: - if (FAILED(hr)) - { - er = ERROR_INSTALL_FAILURE; - } - - return WcaFinalize(er); -} - -extern "C" UINT __stdcall WixSilentExec( - __in MSIHANDLE hInstall - ) -{ - Assert(hInstall); - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - - hr = WcaInitialize(hInstall, "WixSilentExec"); - ExitOnFailure(hr, "Failed to initialize"); - - hr = ExecCommon(WIX_SILENT_ARGUMENTS_PROPERTY, WIX_SILENT_TIMEOUT_PROPERTY, FALSE, FALSE); - ExitOnFailure(hr, "Failed in ExecCommon method"); - -LExit: - if (FAILED(hr)) - { - er = ERROR_INSTALL_FAILURE; - } - - return WcaFinalize(er); -} - -extern "C" UINT __stdcall WixSilentExec64( - __in MSIHANDLE hInstall - ) -{ - Assert(hInstall); - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - - hr = WcaInitialize(hInstall, "WixSilentExec64"); - ExitOnFailure(hr, "Failed to initialize"); - - hr = ExecCommon64(WIX_SILENT64_ARGUMENTS_PROPERTY, WIX_SILENT64_TIMEOUT_PROPERTY, FALSE, FALSE); - ExitOnFailure(hr, "Failed in ExecCommon method"); - -LExit: - if (FAILED(hr)) - { - er = ERROR_INSTALL_FAILURE; - } - - return WcaFinalize(er); -} diff --git a/src/ca/sca.h b/src/ca/sca.h deleted file mode 100644 index 599122ff..00000000 --- a/src/ca/sca.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -// user creation attributes definitions -enum SCAU_ATTRIBUTES -{ - SCAU_DONT_EXPIRE_PASSWRD = 0x00000001, - SCAU_PASSWD_CANT_CHANGE = 0x00000002, - SCAU_PASSWD_CHANGE_REQD_ON_LOGIN = 0x00000004, - SCAU_DISABLE_ACCOUNT = 0x00000008, - SCAU_FAIL_IF_EXISTS = 0x00000010, - SCAU_UPDATE_IF_EXISTS = 0x00000020, - SCAU_ALLOW_LOGON_AS_SERVICE = 0x00000040, - SCAU_ALLOW_LOGON_AS_BATCH = 0x00000080, - - SCAU_DONT_REMOVE_ON_UNINSTALL = 0x00000100, - SCAU_DONT_CREATE_USER = 0x00000200, - SCAU_NON_VITAL = 0x00000400, -}; \ No newline at end of file diff --git a/src/ca/scacost.h b/src/ca/scacost.h deleted file mode 100644 index 5b215035..00000000 --- a/src/ca/scacost.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - - -const UINT COST_PERFMON_REGISTER = 1000; -const UINT COST_PERFMON_UNREGISTER = 1000; - -const UINT COST_SMB_CREATESMB = 10000; -const UINT COST_SMB_DROPSMB = 5000; -const UINT COST_USER_ADD = 10000; -const UINT COST_USER_DELETE = 10000; - -const UINT COST_PERFMONMANIFEST_REGISTER = 1000; -const UINT COST_PERFMONMANIFEST_UNREGISTER = 1000; - -const UINT COST_EVENTMANIFEST_REGISTER = 1000; -const UINT COST_EVENTMANIFEST_UNREGISTER = 1000; - diff --git a/src/ca/scaexec.cpp b/src/ca/scaexec.cpp deleted file mode 100644 index 5845c1b4..00000000 --- a/src/ca/scaexec.cpp +++ /dev/null @@ -1,1082 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" - - -/******************************************************************** - * CreateSmb - CUSTOM ACTION ENTRY POINT for creating fileshares - * - * Input: deferred CustomActionData - - * wzFsKey\twzShareDesc\twzFullPath\tfIntegratedAuth\twzUserName\tnPermissions\twzUserName\tnPermissions... - * - * ****************************************************************/ -extern "C" UINT __stdcall CreateSmb(MSIHANDLE hInstall) -{ -//AssertSz(0, "debug CreateSmb"); - UINT er = ERROR_SUCCESS; - HRESULT hr = S_OK; - - LPWSTR pwzData = NULL; - LPWSTR pwz = NULL; - LPWSTR pwzFsKey = NULL; - LPWSTR pwzShareDesc = NULL; - LPWSTR pwzDirectory = NULL; - int iAccessMode = 0; - DWORD nExPermissions = 0; - BOOL fIntegratedAuth; - LPWSTR pwzExUser = NULL; - SCA_SMBP ssp = {0}; - DWORD dwExUserPerms = 0; - DWORD dwCounter = 0; - SCA_SMBP_USER_PERMS* pUserPermsList = NULL; - - hr = WcaInitialize(hInstall, "CreateSmb"); - ExitOnFailure(hr, "failed to initialize"); - - hr = WcaGetProperty( L"CustomActionData", &pwzData); - ExitOnFailure(hr, "failed to get CustomActionData"); - - WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); - - pwz = pwzData; - hr = WcaReadStringFromCaData(&pwz, &pwzFsKey); // share name - ExitOnFailure(hr, "failed to read share name"); - hr = WcaReadStringFromCaData(&pwz, &pwzShareDesc); // share description - ExitOnFailure(hr, "failed to read share name"); - hr = WcaReadStringFromCaData(&pwz, &pwzDirectory); // full path to share - ExitOnFailure(hr, "failed to read share name"); - hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&fIntegratedAuth)); - ExitOnFailure(hr, "failed to read integrated authentication"); - - hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&dwExUserPerms)); - ExitOnFailure(hr, "failed to read count of permissions to set"); - if(dwExUserPerms > 0) - { - pUserPermsList = static_cast(MemAlloc(sizeof(SCA_SMBP_USER_PERMS)*dwExUserPerms, TRUE)); - ExitOnNull(pUserPermsList, hr, E_OUTOFMEMORY, "failed to allocate memory for permissions structure"); - - //Pull out all of the ExUserPerm strings - for (dwCounter = 0; dwCounter < dwExUserPerms; ++dwCounter) - { - hr = WcaReadStringFromCaData(&pwz, &pwzExUser); // user account - ExitOnFailure(hr, "failed to read user account"); - pUserPermsList[dwCounter].wzUser = pwzExUser; - pwzExUser = NULL; - - hr = WcaReadIntegerFromCaData(&pwz, &iAccessMode); - ExitOnFailure(hr, "failed to read access mode"); - pUserPermsList[dwCounter].accessMode = (ACCESS_MODE)iAccessMode; - iAccessMode = 0; - - hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&nExPermissions)); - ExitOnFailure(hr, "failed to read count of permissions"); - pUserPermsList[dwCounter].nPermissions = nExPermissions; - nExPermissions = 0; - } - } - - ssp.wzKey = pwzFsKey; - ssp.wzDescription = pwzShareDesc; - ssp.wzDirectory = pwzDirectory; - ssp.fUseIntegratedAuth = fIntegratedAuth; - ssp.dwUserPermissionCount = dwExUserPerms; - ssp.pUserPerms = pUserPermsList; - - hr = ScaEnsureSmbExists(&ssp); - MessageExitOnFailure(hr, msierrSMBFailedCreate, "failed to create share: '%ls'", pwzFsKey); - - hr = WcaProgressMessage(COST_SMB_CREATESMB, FALSE); - -LExit: - ReleaseStr(pwzFsKey); - ReleaseStr(pwzShareDesc); - ReleaseStr(pwzDirectory); - ReleaseStr(pwzData); - - if (pUserPermsList) - { - MemFree(pUserPermsList); - } - - if (FAILED(hr)) - { - er = ERROR_INSTALL_FAILURE; - } - return WcaFinalize(er); -} - - - -/******************************************************************** - DropSmb - CUSTOM ACTION ENTRY POINT for creating fileshares - - Input: deferred CustomActionData - wzFsKey\twzShareDesc\twzFullPath\tnPermissions\tfIntegratedAuth\twzUserName\twzPassword - - * ****************************************************************/ -extern "C" UINT __stdcall DropSmb(MSIHANDLE hInstall) -{ - //AssertSz(0, "debug DropSmb"); - UINT er = ERROR_SUCCESS; - HRESULT hr = S_OK; - - LPWSTR pwzData = NULL; - LPWSTR pwz = NULL; - LPWSTR pwzFsKey = NULL; - SCA_SMBP ssp = {0}; - - hr = WcaInitialize(hInstall, "DropSmb"); - ExitOnFailure(hr, "failed to initialize"); - - hr = WcaGetProperty( L"CustomActionData", &pwzData); - ExitOnFailure(hr, "failed to get CustomActionData"); - - WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); - - pwz = pwzData; - hr = WcaReadStringFromCaData(&pwz, &pwzFsKey); // share name - ExitOnFailure(hr, "failed to read share name"); - - ssp.wzKey = pwzFsKey; - - hr = ScaDropSmb(&ssp); - MessageExitOnFailure(hr, msierrSMBFailedDrop, "failed to delete share: '%ls'", pwzFsKey); - - hr = WcaProgressMessage(COST_SMB_DROPSMB, FALSE); - -LExit: - ReleaseStr(pwzFsKey); - ReleaseStr(pwzData); - - if (FAILED(hr)) - { - er = ERROR_INSTALL_FAILURE; - } - return WcaFinalize(er); -} - - -static HRESULT AddUserToGroup( - __in LPWSTR wzUser, - __in LPCWSTR wzUserDomain, - __in LPCWSTR wzGroup, - __in LPCWSTR wzGroupDomain - ) -{ - Assert(wzUser && *wzUser && wzUserDomain && wzGroup && *wzGroup && wzGroupDomain); - - HRESULT hr = S_OK; - IADsGroup *pGroup = NULL; - BSTR bstrUser = NULL; - BSTR bstrGroup = NULL; - LPCWSTR wz = NULL; - LPWSTR pwzUser = NULL; - LOCALGROUP_MEMBERS_INFO_3 lgmi; - - if (*wzGroupDomain) - { - wz = wzGroupDomain; - } - - // Try adding it to the global group first - UINT ui = ::NetGroupAddUser(wz, wzGroup, wzUser); - if (NERR_GroupNotFound == ui) - { - // Try adding it to the local group - if (wzUserDomain) - { - hr = StrAllocFormatted(&pwzUser, L"%s\\%s", wzUserDomain, wzUser); - ExitOnFailure(hr, "failed to allocate user domain string"); - } - - lgmi.lgrmi3_domainandname = (NULL == pwzUser ? wzUser : pwzUser); - ui = ::NetLocalGroupAddMembers(wz, wzGroup, 3 , reinterpret_cast(&lgmi), 1); - } - hr = HRESULT_FROM_WIN32(ui); - if (HRESULT_FROM_WIN32(ERROR_MEMBER_IN_ALIAS) == hr) // if they're already a member of the group don't report an error - hr = S_OK; - - // - // If we failed, try active directory - // - if (FAILED(hr)) - { - 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); - - hr = UserCreateADsPath(wzUserDomain, wzUser, &bstrUser); - ExitOnFailure(hr, "failed to create user ADsPath for user: %ls domain: %ls", wzUser, wzUserDomain); - - hr = UserCreateADsPath(wzGroupDomain, wzGroup, &bstrGroup); - ExitOnFailure(hr, "failed to create group ADsPath for group: %ls domain: %ls", wzGroup, wzGroupDomain); - - hr = ::ADsGetObject(bstrGroup,IID_IADsGroup, reinterpret_cast(&pGroup)); - ExitOnFailure(hr, "Failed to get group '%ls'.", reinterpret_cast(bstrGroup) ); - - hr = pGroup->Add(bstrUser); - if ((HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS) == hr) || (HRESULT_FROM_WIN32(ERROR_MEMBER_IN_ALIAS) == hr)) - hr = S_OK; - - ExitOnFailure(hr, "Failed to add user %ls to group '%ls'.", reinterpret_cast(bstrUser), reinterpret_cast(bstrGroup) ); - } - -LExit: - ReleaseObject(pGroup); - ReleaseBSTR(bstrUser); - ReleaseBSTR(bstrGroup); - - return hr; -} - -static HRESULT RemoveUserFromGroup( - __in LPWSTR wzUser, - __in LPCWSTR wzUserDomain, - __in LPCWSTR wzGroup, - __in LPCWSTR wzGroupDomain - ) -{ - Assert(wzUser && *wzUser && wzUserDomain && wzGroup && *wzGroup && wzGroupDomain); - - HRESULT hr = S_OK; - IADsGroup *pGroup = NULL; - BSTR bstrUser = NULL; - BSTR bstrGroup = NULL; - LPCWSTR wz = NULL; - LPWSTR pwzUser = NULL; - LOCALGROUP_MEMBERS_INFO_3 lgmi; - - if (*wzGroupDomain) - { - wz = wzGroupDomain; - } - - // Try removing it from the global group first - UINT ui = ::NetGroupDelUser(wz, wzGroup, wzUser); - if (NERR_GroupNotFound == ui) - { - // Try removing it from the local group - if (wzUserDomain) - { - hr = StrAllocFormatted(&pwzUser, L"%s\\%s", wzUserDomain, wzUser); - ExitOnFailure(hr, "failed to allocate user domain string"); - } - - lgmi.lgrmi3_domainandname = (NULL == pwzUser ? wzUser : pwzUser); - ui = ::NetLocalGroupDelMembers(wz, wzGroup, 3 , reinterpret_cast(&lgmi), 1); - } - hr = HRESULT_FROM_WIN32(ui); - - // - // If we failed, try active directory - // - if (FAILED(hr)) - { - 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); - - hr = UserCreateADsPath(wzUserDomain, wzUser, &bstrUser); - ExitOnFailure(hr, "failed to create user ADsPath in order to remove user: %ls domain: %ls from a group", wzUser, wzUserDomain); - - hr = UserCreateADsPath(wzGroupDomain, wzGroup, &bstrGroup); - ExitOnFailure(hr, "failed to create group ADsPath in order to remove user from group: %ls domain: %ls", wzGroup, wzGroupDomain); - - hr = ::ADsGetObject(bstrGroup,IID_IADsGroup, reinterpret_cast(&pGroup)); - ExitOnFailure(hr, "Failed to get group '%ls'.", reinterpret_cast(bstrGroup) ); - - hr = pGroup->Remove(bstrUser); - ExitOnFailure(hr, "Failed to remove user %ls from group '%ls'.", reinterpret_cast(bstrUser), reinterpret_cast(bstrGroup) ); - } - -LExit: - ReleaseObject(pGroup); - ReleaseBSTR(bstrUser); - ReleaseBSTR(bstrGroup); - - return hr; -} - - -static HRESULT GetUserHasRight( - __in LSA_HANDLE hPolicy, - __in PSID pUserSid, - __in LPWSTR wzRight, - __out BOOL* fHasRight -) -{ - HRESULT hr = S_OK; - NTSTATUS nt = 0; - LSA_UNICODE_STRING lucPrivilege = { 0 }; - PLSA_ENUMERATION_INFORMATION rgSids = NULL; - ULONG cSids = 0; - *fHasRight = FALSE; - - lucPrivilege.Buffer = wzRight; - lucPrivilege.Length = static_cast(lstrlenW(lucPrivilege.Buffer) * sizeof(WCHAR)); - lucPrivilege.MaximumLength = (lucPrivilege.Length + 1) * sizeof(WCHAR); - - nt = ::LsaEnumerateAccountsWithUserRight(hPolicy, &lucPrivilege, reinterpret_cast(&rgSids), &cSids); - hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt)); - ExitOnFailure(hr, "Failed to enumerate users for right: %ls", lucPrivilege.Buffer); - - for (DWORD i = 0; i < cSids; ++i) - { - PLSA_ENUMERATION_INFORMATION pInfo = rgSids + i; - if (::EqualSid(pUserSid, pInfo->Sid)) - { - *fHasRight = TRUE; - break; - } - } - -LExit: - if (rgSids) - { - ::LsaFreeMemory(rgSids); - } - - return hr; -} - - -static HRESULT GetExistingUserRightsAssignments( - __in_opt LPCWSTR wzDomain, - __in LPCWSTR wzName, - __inout int* iAttributes -) -{ - HRESULT hr = S_OK; - NTSTATUS nt = 0; - BOOL fHasRight = FALSE; - - LSA_HANDLE hPolicy = NULL; - LSA_OBJECT_ATTRIBUTES objectAttributes = { 0 }; - - LPWSTR pwzUser = NULL; - PSID psid = NULL; - - if (wzDomain && *wzDomain) - { - hr = StrAllocFormatted(&pwzUser, L"%s\\%s", wzDomain, wzName); - ExitOnFailure(hr, "Failed to allocate user with domain string"); - } - else - { - hr = StrAllocString(&pwzUser, wzName, 0); - ExitOnFailure(hr, "Failed to allocate string from user name."); - } - - hr = AclGetAccountSid(NULL, pwzUser, &psid); - ExitOnFailure(hr, "Failed to get SID for user: %ls", pwzUser); - - nt = ::LsaOpenPolicy(NULL, &objectAttributes, POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION, &hPolicy); - hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt)); - ExitOnFailure(hr, "Failed to open LSA policy store"); - - hr = GetUserHasRight(hPolicy, psid, L"SeServiceLogonRight", &fHasRight); - ExitOnFailure(hr, "Failed to check LogonAsService right"); - - if (fHasRight) - { - *iAttributes |= SCAU_ALLOW_LOGON_AS_SERVICE; - } - - hr = GetUserHasRight(hPolicy, psid, L"SeBatchLogonRight", &fHasRight); - ExitOnFailure(hr, "Failed to check LogonAsBatchJob right"); - - if (fHasRight) - { - *iAttributes |= SCAU_ALLOW_LOGON_AS_BATCH; - } - -LExit: - if (hPolicy) - { - ::LsaClose(hPolicy); - } - - ReleaseSid(psid); - ReleaseStr(pwzUser); - return hr; -} - - -static HRESULT ModifyUserLocalServiceRight( - __in_opt LPCWSTR wzDomain, - __in LPCWSTR wzName, - __in BOOL fAdd - ) -{ - HRESULT hr = S_OK; - NTSTATUS nt = 0; - - LPWSTR pwzUser = NULL; - PSID psid = NULL; - LSA_HANDLE hPolicy = NULL; - LSA_OBJECT_ATTRIBUTES ObjectAttributes = { 0 }; - LSA_UNICODE_STRING lucPrivilege = { 0 }; - - if (wzDomain && *wzDomain) - { - hr = StrAllocFormatted(&pwzUser, L"%s\\%s", wzDomain, wzName); - ExitOnFailure(hr, "Failed to allocate user with domain string"); - } - else - { - hr = StrAllocString(&pwzUser, wzName, 0); - ExitOnFailure(hr, "Failed to allocate string from user name."); - } - - hr = AclGetAccountSid(NULL, pwzUser, &psid); - ExitOnFailure(hr, "Failed to get SID for user: %ls", pwzUser); - - nt = ::LsaOpenPolicy(NULL, &ObjectAttributes, POLICY_ALL_ACCESS, &hPolicy); - hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt)); - ExitOnFailure(hr, "Failed to open LSA policy store."); - - lucPrivilege.Buffer = L"SeServiceLogonRight"; - lucPrivilege.Length = static_cast(lstrlenW(lucPrivilege.Buffer) * sizeof(WCHAR)); - lucPrivilege.MaximumLength = (lucPrivilege.Length + 1) * sizeof(WCHAR); - - if (fAdd) - { - nt = ::LsaAddAccountRights(hPolicy, psid, &lucPrivilege, 1); - hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt)); - ExitOnFailure(hr, "Failed to add 'logon as service' bit to user: %ls", pwzUser); - } - else - { - nt = ::LsaRemoveAccountRights(hPolicy, psid, FALSE, &lucPrivilege, 1); - hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt)); - ExitOnFailure(hr, "Failed to remove 'logon as service' bit from user: %ls", pwzUser); - } - -LExit: - if (hPolicy) - { - ::LsaClose(hPolicy); - } - - ReleaseSid(psid); - ReleaseStr(pwzUser); - return hr; -} - - -static HRESULT ModifyUserLocalBatchRight( - __in_opt LPCWSTR wzDomain, - __in LPCWSTR wzName, - __in BOOL fAdd - ) -{ - HRESULT hr = S_OK; - NTSTATUS nt = 0; - - LPWSTR pwzUser = NULL; - PSID psid = NULL; - LSA_HANDLE hPolicy = NULL; - LSA_OBJECT_ATTRIBUTES ObjectAttributes = { 0 }; - LSA_UNICODE_STRING lucPrivilege = { 0 }; - - if (wzDomain && *wzDomain) - { - hr = StrAllocFormatted(&pwzUser, L"%s\\%s", wzDomain, wzName); - ExitOnFailure(hr, "Failed to allocate user with domain string"); - } - else - { - hr = StrAllocString(&pwzUser, wzName, 0); - ExitOnFailure(hr, "Failed to allocate string from user name."); - } - - hr = AclGetAccountSid(NULL, pwzUser, &psid); - ExitOnFailure(hr, "Failed to get SID for user: %ls", pwzUser); - - nt = ::LsaOpenPolicy(NULL, &ObjectAttributes, POLICY_ALL_ACCESS, &hPolicy); - hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt)); - ExitOnFailure(hr, "Failed to open LSA policy store."); - - lucPrivilege.Buffer = L"SeBatchLogonRight"; - lucPrivilege.Length = static_cast(lstrlenW(lucPrivilege.Buffer) * sizeof(WCHAR)); - lucPrivilege.MaximumLength = (lucPrivilege.Length + 1) * sizeof(WCHAR); - - if (fAdd) - { - nt = ::LsaAddAccountRights(hPolicy, psid, &lucPrivilege, 1); - hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt)); - ExitOnFailure(hr, "Failed to add 'logon as batch job' bit to user: %ls", pwzUser); - } - else - { - nt = ::LsaRemoveAccountRights(hPolicy, psid, FALSE, &lucPrivilege, 1); - hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt)); - ExitOnFailure(hr, "Failed to remove 'logon as batch job' bit from user: %ls", pwzUser); - } - - LExit: - if (hPolicy) - { - ::LsaClose(hPolicy); - } - - ReleaseSid(psid); - ReleaseStr(pwzUser); - return hr; -} - -static void SetUserPasswordAndAttributes( - __in USER_INFO_1* puserInfo, - __in LPWSTR wzPassword, - __in int iAttributes - ) -{ - Assert(puserInfo); - - // Set the User's password - puserInfo->usri1_password = wzPassword; - - // Apply the Attributes - if (SCAU_DONT_EXPIRE_PASSWRD & iAttributes) - { - puserInfo->usri1_flags |= UF_DONT_EXPIRE_PASSWD; - } - else - { - puserInfo->usri1_flags &= ~UF_DONT_EXPIRE_PASSWD; - } - - if (SCAU_PASSWD_CANT_CHANGE & iAttributes) - { - puserInfo->usri1_flags |= UF_PASSWD_CANT_CHANGE; - } - else - { - puserInfo->usri1_flags &= ~UF_PASSWD_CANT_CHANGE; - } - - if (SCAU_DISABLE_ACCOUNT & iAttributes) - { - puserInfo->usri1_flags |= UF_ACCOUNTDISABLE; - } - else - { - puserInfo->usri1_flags &= ~UF_ACCOUNTDISABLE; - } - - if (SCAU_PASSWD_CHANGE_REQD_ON_LOGIN & iAttributes) // TODO: for some reason this doesn't work - { - puserInfo->usri1_flags |= UF_PASSWORD_EXPIRED; - } - else - { - puserInfo->usri1_flags &= ~UF_PASSWORD_EXPIRED; - } -} - - -static HRESULT RemoveUserInternal( - LPWSTR wzGroupCaData, - LPWSTR wzDomain, - LPWSTR wzName, - int iAttributes -) -{ - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - - LPWSTR pwz = NULL; - LPWSTR pwzGroup = NULL; - LPWSTR pwzGroupDomain = NULL; - LPCWSTR wz = NULL; - PDOMAIN_CONTROLLER_INFOW pDomainControllerInfo = NULL; - - // - // Remove the logon as service privilege. - // - if (SCAU_ALLOW_LOGON_AS_SERVICE & iAttributes) - { - hr = ModifyUserLocalServiceRight(wzDomain, wzName, FALSE); - if (FAILED(hr)) - { - WcaLogError(hr, "Failed to remove logon as service right from user, continuing..."); - hr = S_OK; - } - } - - if (SCAU_ALLOW_LOGON_AS_BATCH & iAttributes) - { - hr = ModifyUserLocalBatchRight(wzDomain, wzName, FALSE); - if (FAILED(hr)) - { - WcaLogError(hr, "Failed to remove logon as batch job right from user, continuing..."); - hr = S_OK; - } - } - - // - // Remove the User Account if the user was created by us. - // - if (!(SCAU_DONT_CREATE_USER & iAttributes)) - { - if (wzDomain && *wzDomain) - { - er = ::DsGetDcNameW(NULL, (LPCWSTR)wzDomain, NULL, NULL, NULL, &pDomainControllerInfo); - if (RPC_S_SERVER_UNAVAILABLE == er) - { - // MSDN says, if we get the above error code, try again with the "DS_FORCE_REDISCOVERY" flag - er = ::DsGetDcNameW(NULL, (LPCWSTR)wzDomain, NULL, NULL, DS_FORCE_REDISCOVERY, &pDomainControllerInfo); - } - if (ERROR_SUCCESS == er) - { - wz = pDomainControllerInfo->DomainControllerName + 2; //Add 2 so that we don't get the \\ prefix - } - else - { - wz = wzDomain; - } - } - - er = ::NetUserDel(wz, wzName); - if (NERR_UserNotFound == er) - { - er = NERR_Success; - } - ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "failed to delete user account: %ls", wzName); - } - else - { - // - // Remove the user from the groups - // - pwz = wzGroupCaData; - while (S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzGroup))) - { - hr = WcaReadStringFromCaData(&pwz, &pwzGroupDomain); - - if (FAILED(hr)) - { - WcaLogError(hr, "failed to get domain for group: %ls, continuing anyway.", pwzGroup); - } - else - { - hr = RemoveUserFromGroup(wzName, wzDomain, pwzGroup, pwzGroupDomain); - if (FAILED(hr)) - { - WcaLogError(hr, "failed to remove user: %ls from group %ls, continuing anyway.", wzName, pwzGroup); - } - } - } - - if (E_NOMOREITEMS == hr) // if there are no more items, all is well - { - hr = S_OK; - } - - ExitOnFailure(hr, "failed to get next group from which to remove user:%ls", wzName); - } - -LExit: - if (pDomainControllerInfo) - { - ::NetApiBufferFree(static_cast(pDomainControllerInfo)); - } - - return hr; -} - - -/******************************************************************** - CreateUser - CUSTOM ACTION ENTRY POINT for creating users - - Input: deferred CustomActionData - UserName\tDomain\tPassword\tAttributes\tGroupName\tDomain\tGroupName\tDomain... - * *****************************************************************/ -extern "C" UINT __stdcall CreateUser( - __in MSIHANDLE hInstall - ) -{ - //AssertSz(0, "Debug CreateUser"); - - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - - LPWSTR pwzData = NULL; - LPWSTR pwz = NULL; - LPWSTR pwzName = NULL; - LPWSTR pwzDomain = NULL; - LPWSTR pwzScriptKey = NULL; - LPWSTR pwzPassword = NULL; - LPWSTR pwzGroup = NULL; - LPWSTR pwzGroupDomain = NULL; - PDOMAIN_CONTROLLER_INFOW pDomainControllerInfo = NULL; - int iAttributes = 0; - BOOL fInitializedCom = FALSE; - - WCA_CASCRIPT_HANDLE hRollbackScript = NULL; - int iOriginalAttributes = 0; - int iRollbackAttributes = 0; - - USER_INFO_1 userInfo; - USER_INFO_1* puserInfo = NULL; - DWORD dw; - LPCWSTR wz = NULL; - - hr = WcaInitialize(hInstall, "CreateUser"); - ExitOnFailure(hr, "failed to initialize"); - - hr = ::CoInitialize(NULL); - ExitOnFailure(hr, "failed to initialize COM"); - fInitializedCom = TRUE; - - hr = WcaGetProperty( L"CustomActionData", &pwzData); - ExitOnFailure(hr, "failed to get CustomActionData"); - - WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); - - // - // Read in the CustomActionData - // - pwz = pwzData; - hr = WcaReadStringFromCaData(&pwz, &pwzName); - ExitOnFailure(hr, "failed to read user name from custom action data"); - - hr = WcaReadStringFromCaData(&pwz, &pwzDomain); - ExitOnFailure(hr, "failed to read domain from custom action data"); - - hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); - ExitOnFailure(hr, "failed to read attributes from custom action data"); - - hr = WcaReadStringFromCaData(&pwz, &pwzScriptKey); - ExitOnFailure(hr, "failed to read encoding key from custom action data"); - - hr = WcaReadStringFromCaData(&pwz, &pwzPassword); - ExitOnFailure(hr, "failed to read password from custom action data"); - - // There is no rollback scheduled if the key is empty. - // Best effort to get original configuration and save it in the script so rollback can restore it. - if (*pwzScriptKey) - { - hr = WcaCaScriptCreate(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, FALSE, &hRollbackScript); - ExitOnFailure(hr, "Failed to open rollback CustomAction script."); - - iRollbackAttributes = 0; - hr = GetExistingUserRightsAssignments(pwzDomain, pwzName, &iOriginalAttributes); - if (FAILED(hr)) - { - WcaLogError(hr, "failed to get existing user rights: %ls, continuing anyway.", pwzName); - } - else - { - if (!(SCAU_ALLOW_LOGON_AS_SERVICE & iOriginalAttributes) && (SCAU_ALLOW_LOGON_AS_SERVICE & iAttributes)) - { - iRollbackAttributes |= SCAU_ALLOW_LOGON_AS_SERVICE; - } - if (!(SCAU_ALLOW_LOGON_AS_BATCH & iOriginalAttributes) && (SCAU_ALLOW_LOGON_AS_BATCH & iAttributes)) - { - iRollbackAttributes |= SCAU_ALLOW_LOGON_AS_BATCH; - } - } - - hr = WcaCaScriptWriteNumber(hRollbackScript, iRollbackAttributes); - ExitOnFailure(hr, "Failed to add data to rollback script."); - - // Nudge the system to get all our rollback data written to disk. - WcaCaScriptFlush(hRollbackScript); - } - - if (!(SCAU_DONT_CREATE_USER & iAttributes)) - { - ::ZeroMemory(&userInfo, sizeof(USER_INFO_1)); - userInfo.usri1_name = pwzName; - userInfo.usri1_priv = USER_PRIV_USER; - userInfo.usri1_flags = UF_SCRIPT; - userInfo.usri1_home_dir = NULL; - userInfo.usri1_comment = NULL; - userInfo.usri1_script_path = NULL; - - SetUserPasswordAndAttributes(&userInfo, pwzPassword, iAttributes); - - // - // Create the User - // - if (pwzDomain && *pwzDomain) - { - er = ::DsGetDcNameW( NULL, (LPCWSTR)pwzDomain, NULL, NULL, NULL, &pDomainControllerInfo ); - if (RPC_S_SERVER_UNAVAILABLE == er) - { - // MSDN says, if we get the above error code, try again with the "DS_FORCE_REDISCOVERY" flag - er = ::DsGetDcNameW( NULL, (LPCWSTR)pwzDomain, NULL, NULL, DS_FORCE_REDISCOVERY, &pDomainControllerInfo ); - } - if (ERROR_SUCCESS == er) - { - wz = pDomainControllerInfo->DomainControllerName + 2; //Add 2 so that we don't get the \\ prefix - } - else - { - wz = pwzDomain; - } - } - - er = ::NetUserAdd(wz, 1, reinterpret_cast(&userInfo), &dw); - if (NERR_UserExists == er) - { - if (SCAU_UPDATE_IF_EXISTS & iAttributes) - { - er = ::NetUserGetInfo(wz, pwzName, 1, reinterpret_cast(&puserInfo)); - if (NERR_Success == er) - { - // Change the existing user's password and attributes again then try - // to update user with this new data - SetUserPasswordAndAttributes(puserInfo, pwzPassword, iAttributes); - - er = ::NetUserSetInfo(wz, pwzName, 1, reinterpret_cast(puserInfo), &dw); - } - } - else if (!(SCAU_FAIL_IF_EXISTS & iAttributes)) - { - er = NERR_Success; - } - } - else if (NERR_PasswordTooShort == er || NERR_PasswordTooLong == er) - { - MessageExitOnFailure(hr = HRESULT_FROM_WIN32(er), msierrUSRFailedUserCreatePswd, "failed to create user: %ls due to invalid password.", pwzName); - } - MessageExitOnFailure(hr = HRESULT_FROM_WIN32(er), msierrUSRFailedUserCreate, "failed to create user: %ls", pwzName); - } - - if (SCAU_ALLOW_LOGON_AS_SERVICE & iAttributes) - { - hr = ModifyUserLocalServiceRight(pwzDomain, pwzName, TRUE); - MessageExitOnFailure(hr, msierrUSRFailedGrantLogonAsService, "Failed to grant logon as service rights to user: %ls", pwzName); - } - - if (SCAU_ALLOW_LOGON_AS_BATCH & iAttributes) - { - hr = ModifyUserLocalBatchRight(pwzDomain, pwzName, TRUE); - MessageExitOnFailure(hr, msierrUSRFailedGrantLogonAsService, "Failed to grant logon as batch job rights to user: %ls", pwzName); - } - - // - // Add the users to groups - // - while (S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzGroup))) - { - hr = WcaReadStringFromCaData(&pwz, &pwzGroupDomain); - ExitOnFailure(hr, "failed to get domain for group: %ls", pwzGroup); - - hr = AddUserToGroup(pwzName, pwzDomain, pwzGroup, pwzGroupDomain); - MessageExitOnFailure(hr, msierrUSRFailedUserGroupAdd, "failed to add user: %ls to group %ls", pwzName, pwzGroup); - } - if (E_NOMOREITEMS == hr) // if there are no more items, all is well - { - hr = S_OK; - } - ExitOnFailure(hr, "failed to get next group in which to include user:%ls", pwzName); - -LExit: - WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_PRESERVE); - - if (puserInfo) - { - ::NetApiBufferFree((LPVOID)puserInfo); - } - - if (pDomainControllerInfo) - { - ::NetApiBufferFree((LPVOID)pDomainControllerInfo); - } - - ReleaseStr(pwzData); - ReleaseStr(pwzName); - ReleaseStr(pwzDomain); - ReleaseStr(pwzScriptKey); - ReleaseStr(pwzPassword); - ReleaseStr(pwzGroup); - ReleaseStr(pwzGroupDomain); - - if (fInitializedCom) - { - ::CoUninitialize(); - } - - if (SCAU_NON_VITAL & iAttributes) - { - er = ERROR_SUCCESS; - } - else if (FAILED(hr)) - { - er = ERROR_INSTALL_FAILURE; - } - - return WcaFinalize(er); -} - - -/******************************************************************** - CreateUserRollback - CUSTOM ACTION ENTRY POINT for CreateUser rollback - - * *****************************************************************/ -extern "C" UINT __stdcall CreateUserRollback( - MSIHANDLE hInstall -) -{ - //AssertSz(0, "Debug CreateUserRollback"); - - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - - LPWSTR pwzData = NULL; - LPWSTR pwz = NULL; - LPWSTR pwzName = NULL; - LPWSTR pwzDomain = NULL; - LPWSTR pwzScriptKey = NULL; - int iAttributes = 0; - BOOL fInitializedCom = FALSE; - - WCA_CASCRIPT_HANDLE hRollbackScript = NULL; - LPWSTR pwzRollbackData = NULL; - int iOriginalAttributes = 0; - - hr = WcaInitialize(hInstall, "CreateUserRollback"); - ExitOnFailure(hr, "failed to initialize"); - - hr = ::CoInitialize(NULL); - ExitOnFailure(hr, "failed to initialize COM"); - fInitializedCom = TRUE; - - hr = WcaGetProperty(L"CustomActionData", &pwzData); - ExitOnFailure(hr, "failed to get CustomActionData"); - - WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); - - // - // Read in the CustomActionData - // - pwz = pwzData; - hr = WcaReadStringFromCaData(&pwz, &pwzScriptKey); - ExitOnFailure(hr, "failed to read encoding key from custom action data"); - - hr = WcaReadStringFromCaData(&pwz, &pwzName); - ExitOnFailure(hr, "failed to read name from custom action data"); - - hr = WcaReadStringFromCaData(&pwz, &pwzDomain); - ExitOnFailure(hr, "failed to read domain from custom action data"); - - hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); - ExitOnFailure(hr, "failed to read attributes from custom action data"); - - // Best effort to read original configuration from CreateUser. - hr = WcaCaScriptOpen(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, &hRollbackScript); - if (FAILED(hr)) - { - WcaLogError(hr, "Failed to open rollback CustomAction script, continuing anyway."); - } - else - { - hr = WcaCaScriptReadAsCustomActionData(hRollbackScript, &pwzRollbackData); - if (FAILED(hr)) - { - WcaLogError(hr, "Failed to read rollback script into CustomAction data, continuing anyway."); - } - else - { - WcaLog(LOGMSG_TRACEONLY, "Rollback Data: %ls", pwzRollbackData); - - pwz = pwzRollbackData; - hr = WcaReadIntegerFromCaData(&pwz, &iOriginalAttributes); - if (FAILED(hr)) - { - WcaLogError(hr, "failed to read attributes from rollback data, continuing anyway"); - } - else - { - iAttributes |= iOriginalAttributes; - } - } - } - - hr = RemoveUserInternal(pwz, pwzDomain, pwzName, iAttributes); - -LExit: - WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_DELETE); - - ReleaseStr(pwzData); - ReleaseStr(pwzName); - ReleaseStr(pwzDomain); - ReleaseStr(pwzScriptKey); - ReleaseStr(pwzRollbackData); - - if (fInitializedCom) - { - ::CoUninitialize(); - } - - if (FAILED(hr)) - { - er = ERROR_INSTALL_FAILURE; - } - - return WcaFinalize(er); -} - - -/******************************************************************** - RemoveUser - CUSTOM ACTION ENTRY POINT for removing users - - Input: deferred CustomActionData - Name\tDomain - * *****************************************************************/ -extern "C" UINT __stdcall RemoveUser( - MSIHANDLE hInstall -) -{ - //AssertSz(0, "Debug RemoveUser"); - - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - - LPWSTR pwzData = NULL; - LPWSTR pwz = NULL; - LPWSTR pwzName = NULL; - LPWSTR pwzDomain = NULL; - int iAttributes = 0; - BOOL fInitializedCom = FALSE; - - hr = WcaInitialize(hInstall, "RemoveUser"); - ExitOnFailure(hr, "failed to initialize"); - - hr = ::CoInitialize(NULL); - ExitOnFailure(hr, "failed to initialize COM"); - fInitializedCom = TRUE; - - hr = WcaGetProperty(L"CustomActionData", &pwzData); - ExitOnFailure(hr, "failed to get CustomActionData"); - - WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); - - // - // Read in the CustomActionData - // - pwz = pwzData; - hr = WcaReadStringFromCaData(&pwz, &pwzName); - ExitOnFailure(hr, "failed to read name from custom action data"); - - hr = WcaReadStringFromCaData(&pwz, &pwzDomain); - ExitOnFailure(hr, "failed to read domain from custom action data"); - - hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); - ExitOnFailure(hr, "failed to read attributes from custom action data"); - - hr = RemoveUserInternal(pwz, pwzDomain, pwzName, iAttributes); - -LExit: - ReleaseStr(pwzData); - ReleaseStr(pwzName); - ReleaseStr(pwzDomain); - - if (fInitializedCom) - { - ::CoUninitialize(); - } - - if (FAILED(hr)) - { - er = ERROR_INSTALL_FAILURE; - } - - return WcaFinalize(er); -} diff --git a/src/ca/scamanifest.cpp b/src/ca/scamanifest.cpp deleted file mode 100644 index adb8d3d3..00000000 --- a/src/ca/scamanifest.cpp +++ /dev/null @@ -1,377 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" - -LPCWSTR vcsPerfmonManifestQuery = L"SELECT `Component_`, `File`, `ResourceFileDirectory` FROM `Wix4PerfmonManifest`"; -LPCWSTR vcsEventManifestQuery = L"SELECT `Component_`, `File` FROM `Wix4EventManifest`"; -enum ePerfMonManifestQuery { pfmComponent = 1, pfmFile, pfmResourceFileDir }; -enum eEventManifestQuery { emComponent = 1, emFile}; - -BOOL IsVistaOrAbove() -{ - OSVERSIONINFO osvi; - ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - #pragma warning(suppress: 4996) //TODO: use non-deprecated function to check OS version - if (!::GetVersionEx(&osvi)) - { - return false; - } - return osvi.dwMajorVersion >= 6; -} - - -/******************************************************************** - ConfigurePerfmonManifestRegister - CUSTOM ACTION ENTRY POINT for scheduling - Perfmon counter manifest registering - -********************************************************************/ -extern "C" UINT __stdcall ConfigurePerfmonManifestRegister( - __in MSIHANDLE hInstall - ) -{ - HRESULT hr; - UINT er = ERROR_SUCCESS; - - PMSIHANDLE hView, hRec; - LPWSTR pwzData = NULL, pwzResourceFilePath = NULL, pwzFile = NULL, pwzCommand = NULL; - INSTALLSTATE isInstalled, isAction; - - hr = WcaInitialize(hInstall, "ConfigurePerfmonManifestReg"); - ExitOnFailure(hr, "Failed to initialize"); - - if (!IsVistaOrAbove()) - { - WcaLog(LOGMSG_VERBOSE, "Skipping ConfigurePerfmonManifestRegister() because the target system does not support perfmon manifest"); - ExitFunction1(hr = S_FALSE); - } - // check to see if necessary tables are specified - if (S_OK != WcaTableExists(L"Wix4PerfmonManifest")) - { - WcaLog(LOGMSG_VERBOSE, "Skipping ConfigurePerfmonManifestRegister() because Wix4PerfmonManifest table not present"); - ExitFunction1(hr = S_FALSE); - } - - hr = WcaOpenExecuteView(vcsPerfmonManifestQuery, &hView); - ExitOnFailure(hr, "failed to open view on PerfMonManifest table"); - while ((hr = WcaFetchRecord(hView, &hRec)) == S_OK) - { - // get component install state - hr = WcaGetRecordString(hRec, pfmComponent, &pwzData); - ExitOnFailure(hr, "failed to get Component for PerfMonManifest"); - er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction); - hr = HRESULT_FROM_WIN32(er); - ExitOnFailure(hr, "failed to get Component state for PerfMonManifest"); - if (!WcaIsInstalling(isInstalled, isAction)) - { - continue; - } - - hr = WcaGetRecordFormattedString(hRec, pfmFile, &pwzFile); - ExitOnFailure(hr, "failed to get File for PerfMonManifest"); - - hr = WcaGetRecordFormattedString(hRec, pfmResourceFileDir, &pwzResourceFilePath); - ExitOnFailure(hr, "failed to get ApplicationIdentity for PerfMonManifest"); - size_t iResourcePath = lstrlenW(pwzResourceFilePath); - if ( iResourcePath > 0 && *(pwzResourceFilePath + iResourcePath -1) == L'\\') - *(pwzResourceFilePath + iResourcePath -1) = 0; //remove the trailing '\' - - hr = StrAllocFormatted(&pwzCommand, L"\"unlodctr.exe\" /m:\"%s\"", pwzFile); - ExitOnFailure(hr, "failed to copy string in PerfMonManifest"); - - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackRegisterPerfmonManifest"), pwzCommand, COST_PERFMONMANIFEST_UNREGISTER); - ExitOnFailure(hr, "failed to schedule RollbackRegisterPerfmonManifest action"); - - if ( *pwzResourceFilePath ) - { - hr = StrAllocFormatted(&pwzCommand, L"\"lodctr.exe\" /m:\"%s\" \"%s\"", pwzFile, pwzResourceFilePath); - ExitOnFailure(hr, "failed to copy string in PerfMonManifest"); - } - else - { - hr = StrAllocFormatted(&pwzCommand, L"\"lodctr.exe\" /m:\"%s\"", pwzFile); - ExitOnFailure(hr, "failed to copy string in PerfMonManifest"); - } - - WcaLog(LOGMSG_VERBOSE, "RegisterPerfmonManifest's CustomActionData: '%ls'", pwzCommand); - - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RegisterPerfmonManifest"), pwzCommand, COST_PERFMONMANIFEST_REGISTER); - ExitOnFailure(hr, "failed to schedule RegisterPerfmonManifest action"); - } - - if (hr == E_NOMOREITEMS) - { - hr = S_OK; - } - ExitOnFailure(hr, "Failure while processing PerfMonManifest"); - - hr = S_OK; - -LExit: - ReleaseStr(pwzData); - ReleaseStr(pwzResourceFilePath); - ReleaseStr(pwzFile); - ReleaseStr(pwzCommand); - - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} - - -/******************************************************************** - ConfigurePerfmonUninstall - CUSTOM ACTION ENTRY POINT for uninstalling - Perfmon counters - -********************************************************************/ -extern "C" UINT __stdcall ConfigurePerfmonManifestUnregister( - __in MSIHANDLE hInstall - ) -{ - HRESULT hr; - UINT er = ERROR_SUCCESS; - - PMSIHANDLE hView, hRec; - LPWSTR pwzData = NULL, pwzResourceFilePath = NULL, pwzFile = NULL, pwzCommand = NULL; - INSTALLSTATE isInstalled, isAction; - - hr = WcaInitialize(hInstall, "ConfigurePerfmonManifestUnreg"); - ExitOnFailure(hr, "Failed to initialize"); - - if (!IsVistaOrAbove()) - { - WcaLog(LOGMSG_VERBOSE, "Skipping ConfigurePerfmonManifestUnregister() because the target system does not support perfmon manifest"); - ExitFunction1(hr = S_FALSE); - } - // check to see if necessary tables are specified - if (WcaTableExists(L"Wix4PerfmonManifest") != S_OK) - { - WcaLog(LOGMSG_VERBOSE, "Skipping ConfigurePerfmonManifestUnregister() because Wix4PerfmonManifest table not present"); - ExitFunction1(hr = S_FALSE); - } - - hr = WcaOpenExecuteView(vcsPerfmonManifestQuery, &hView); - ExitOnFailure(hr, "failed to open view on Wix4PerfmonManifest table"); - while ((hr = WcaFetchRecord(hView, &hRec)) == S_OK) - { - // get component install state - hr = WcaGetRecordString(hRec, pfmComponent, &pwzData); - ExitOnFailure(hr, "failed to get Component for Wix4PerfmonManifest"); - er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction); - hr = HRESULT_FROM_WIN32(er); - ExitOnFailure(hr, "failed to get Component state for Wix4PerfmonManifest"); - if (!WcaIsUninstalling(isInstalled, isAction)) - { - continue; - } - - hr = WcaGetRecordFormattedString(hRec, pfmFile, &pwzFile); - ExitOnFailure(hr, "failed to get File for Wix4PerfmonManifest"); - - hr = WcaGetRecordFormattedString(hRec, pfmResourceFileDir, &pwzResourceFilePath); - ExitOnFailure(hr, "failed to get ApplicationIdentity for Wix4PerfmonManifest"); - size_t iResourcePath = lstrlenW(pwzResourceFilePath); - if ( iResourcePath > 0 && *(pwzResourceFilePath + iResourcePath -1) == L'\\') - *(pwzResourceFilePath + iResourcePath -1) = 0; //remove the trailing '\' - - hr = StrAllocFormatted(&pwzCommand, L"\"lodctr.exe\" /m:\"%s\" \"%s\"", pwzFile, pwzResourceFilePath); - ExitOnFailure(hr, "failed to copy string in Wix4PerfmonManifest"); - - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackUnregisterPerfmonManifest"), pwzCommand, COST_PERFMONMANIFEST_REGISTER); - ExitOnFailure(hr, "failed to schedule RollbackUnregisterPerfmonManifest action"); - - hr = StrAllocFormatted(&pwzCommand, L"\"unlodctr.exe\" /m:\"%s\"", pwzFile); - ExitOnFailure(hr, "failed to copy string in PerfMonManifest"); - - WcaLog(LOGMSG_VERBOSE, "UnRegisterPerfmonManifest's CustomActionData: '%ls'", pwzCommand); - - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"UnregisterPerfmonManifest"), pwzCommand, COST_PERFMONMANIFEST_UNREGISTER); - ExitOnFailure(hr, "failed to schedule UnregisterPerfmonManifest action"); - } - - if (hr == E_NOMOREITEMS) - { - hr = S_OK; - } - ExitOnFailure(hr, "Failure while processing PerfMonManifest"); - - hr = S_OK; - -LExit: - ReleaseStr(pwzData); - ReleaseStr(pwzResourceFilePath); - ReleaseStr(pwzFile); - ReleaseStr(pwzCommand); - - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} - -/******************************************************************** - ConfigureEventManifestRegister - CUSTOM ACTION ENTRY POINT for scheduling - Event manifest registering - -********************************************************************/ -extern "C" UINT __stdcall ConfigureEventManifestRegister( - __in MSIHANDLE hInstall - ) -{ - HRESULT hr; - UINT er = ERROR_SUCCESS; - - PMSIHANDLE hView, hRec; - LPWSTR pwzData = NULL, pwzFile = NULL, pwzCommand = NULL; - INSTALLSTATE isInstalled, isAction; - - hr = WcaInitialize(hInstall, "ConfigureEventManifestReg"); - ExitOnFailure(hr, "Failed to initialize"); - - if (!IsVistaOrAbove()) - { - WcaLog(LOGMSG_VERBOSE, "Skipping ConfigureEventManifestRegister() because the target system does not support event manifest"); - ExitFunction1(hr = S_FALSE); - } - // check to see if necessary tables are specified - if (S_OK != WcaTableExists(L"Wix4EventManifest")) - { - WcaLog(LOGMSG_VERBOSE, "Skipping ConfigureEventManifestRegister() because Wix4EventManifest table not present"); - ExitFunction1(hr = S_FALSE); - } - - hr = WcaOpenExecuteView(vcsEventManifestQuery, &hView); - ExitOnFailure(hr, "failed to open view on Wix4EventManifest table"); - while ((hr = WcaFetchRecord(hView, &hRec)) == S_OK) - { - // get component install state - hr = WcaGetRecordString(hRec, emComponent, &pwzData); - ExitOnFailure(hr, "failed to get Component for Wix4EventManifest"); - er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction); - hr = HRESULT_FROM_WIN32(er); - ExitOnFailure(hr, "failed to get Component state for Wix4EventManifest"); - if (!WcaIsInstalling(isInstalled, isAction)) - { - continue; - } - - hr = WcaGetRecordFormattedString(hRec, emFile, &pwzFile); - ExitOnFailure(hr, "failed to get File for Wix4EventManifest"); - - hr = StrAllocFormatted(&pwzCommand, L"\"wevtutil.exe\" um \"%s\"", pwzFile); - ExitOnFailure(hr, "failed to copy string in Wix4EventManifest"); - - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackRegisterEventManifest"), pwzCommand, COST_PERFMONMANIFEST_UNREGISTER); - ExitOnFailure(hr, "failed to schedule RollbackRegisterEventManifest action"); - - hr = StrAllocFormatted(&pwzCommand, L"\"wevtutil.exe\" im \"%s\"", pwzFile); - ExitOnFailure(hr, "failed to copy string in Wix4EventManifest"); - WcaLog(LOGMSG_VERBOSE, "RegisterEventManifest's CustomActionData: '%ls'", pwzCommand); - - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RegisterEventManifest"), pwzCommand, COST_EVENTMANIFEST_REGISTER); - ExitOnFailure(hr, "failed to schedule RegisterEventManifest action"); - } - - if (hr == E_NOMOREITEMS) - { - hr = S_OK; - } - ExitOnFailure(hr, "Failure while processing Wix4EventManifest"); - - hr = S_OK; - -LExit: - ReleaseStr(pwzData); - ReleaseStr(pwzFile); - ReleaseStr(pwzCommand); - - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} - - - -/******************************************************************** - ConfigureEventManifestRegister - CUSTOM ACTION ENTRY POINT for scheduling - Event manifest registering - -********************************************************************/ -extern "C" UINT __stdcall ConfigureEventManifestUnregister( - __in MSIHANDLE hInstall - ) -{ - HRESULT hr; - UINT er = ERROR_SUCCESS; - - PMSIHANDLE hView, hRec; - LPWSTR pwzData = NULL, pwzFile = NULL, pwzCommand = NULL; - INSTALLSTATE isInstalled, isAction; - - hr = WcaInitialize(hInstall, "ConfigureEventManifestUnreg"); - ExitOnFailure(hr, "Failed to initialize"); - - if (!IsVistaOrAbove()) - { - WcaLog(LOGMSG_VERBOSE, "Skipping ConfigureEventManifestUnregister() because the target system does not support event manifest"); - ExitFunction1(hr = S_FALSE); - } - // check to see if necessary tables are specified - if (S_OK != WcaTableExists(L"Wix4EventManifest")) - { - WcaLog(LOGMSG_VERBOSE, "Skipping ConfigureEventManifestUnregister() because Wix4EventManifest table not present"); - ExitFunction1(hr = S_FALSE); - } - - hr = WcaOpenExecuteView(vcsEventManifestQuery, &hView); - ExitOnFailure(hr, "failed to open view on Wix4EventManifest table"); - while ((hr = WcaFetchRecord(hView, &hRec)) == S_OK) - { - // get component install state - hr = WcaGetRecordString(hRec, emComponent, &pwzData); - ExitOnFailure(hr, "failed to get Component for Wix4EventManifest"); - er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction); - hr = HRESULT_FROM_WIN32(er); - ExitOnFailure(hr, "failed to get Component state for Wix4EventManifest"); - - // nothing to do on an install - // schedule the rollback action when reinstalling to re-register pre-patch manifest - if (!WcaIsUninstalling(isInstalled, isAction) && !WcaIsReInstalling(isInstalled, isAction)) - { - continue; - } - - hr = WcaGetRecordFormattedString(hRec, emFile, &pwzFile); - ExitOnFailure(hr, "failed to get File for Wix4EventManifest"); - - hr = StrAllocFormatted(&pwzCommand, L"\"wevtutil.exe\" im \"%s\"", pwzFile); - ExitOnFailure(hr, "failed to copy string in Wix4EventManifest"); - - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackUnregisterEventManifest"), pwzCommand, COST_PERFMONMANIFEST_REGISTER); - ExitOnFailure(hr, "failed to schedule RollbackUnregisterEventManifest action"); - - // no need to uninstall on a repair/patch. Register action will re-register and update the manifest. - if (!WcaIsReInstalling(isInstalled, isAction)) - { - hr = StrAllocFormatted(&pwzCommand, L"\"wevtutil.exe\" um \"%s\"", pwzFile); - ExitOnFailure(hr, "failed to copy string in Wix4EventManifest"); - WcaLog(LOGMSG_VERBOSE, "UnregisterEventManifest's CustomActionData: '%ls'", pwzCommand); - - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"UnregisterEventManifest"), pwzCommand, COST_PERFMONMANIFEST_UNREGISTER); - ExitOnFailure(hr, "failed to schedule UnregisterEventManifest action"); - } - } - - if (hr == E_NOMOREITEMS) - { - hr = S_OK; - } - ExitOnFailure(hr, "Failure while processing Wix4EventManifest"); - - hr = S_OK; - -LExit: - ReleaseStr(pwzData); - ReleaseStr(pwzFile); - ReleaseStr(pwzCommand); - - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} - diff --git a/src/ca/scaperf.cpp b/src/ca/scaperf.cpp deleted file mode 100644 index fd301278..00000000 --- a/src/ca/scaperf.cpp +++ /dev/null @@ -1,310 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" - -LPCWSTR vcsPerfCounterDataQuery = L"SELECT `Wix4PerformanceCategory`, `Component_`, `Name`, `IniData`, `ConstantData` FROM `Wix4PerformanceCategory`"; -enum ePerfCounterDataQuery { pcdqId = 1, pcdqComponent, pcdqName, pcdqIniData, pcdqConstantData }; - -LPCWSTR vcsPerfMonQuery = L"SELECT `Component_`, `File`, `Name` FROM `Wix4Perfmon`"; -enum ePerfMonQuery { pmqComponent = 1, pmqFile, pmqName }; - - -static HRESULT ProcessPerformanceCategory( - __in MSIHANDLE hInstall, - __in BOOL fInstall - ); - - -/******************************************************************** - InstallPerfCounterData - CUSTOM ACTION ENTRY POINT for installing - Performance Counters. - -********************************************************************/ -extern "C" UINT __stdcall InstallPerfCounterData( - __in MSIHANDLE hInstall - ) -{ - // AssertSz(FALSE, "debug InstallPerfCounterData{}"); - HRESULT hr; - UINT er = ERROR_SUCCESS; - - hr = WcaInitialize(hInstall, "InstallPerfCounterData"); - ExitOnFailure(hr, "Failed to initialize InstallPerfCounterData."); - - hr = ProcessPerformanceCategory(hInstall, TRUE); - MessageExitOnFailure(hr, msierrInstallPerfCounterData, "Failed to process Wix4PerformanceCategory table."); - -LExit: - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} - - -/******************************************************************** - UninstallPerfCounterData - CUSTOM ACTION ENTRY POINT for installing - Performance Counters. - -********************************************************************/ -extern "C" UINT __stdcall UninstallPerfCounterData( - __in MSIHANDLE hInstall - ) -{ - // AssertSz(FALSE, "debug UninstallPerfCounterData{}"); - HRESULT hr; - UINT er = ERROR_SUCCESS; - - hr = WcaInitialize(hInstall, "UninstallPerfCounterData"); - ExitOnFailure(hr, "Failed to initialize UninstallPerfCounterData."); - - hr = ProcessPerformanceCategory(hInstall, FALSE); - MessageExitOnFailure(hr, msierrUninstallPerfCounterData, "Failed to process Wix4PerformanceCategory table."); - -LExit: - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} - - -/******************************************************************** - RegisterPerfmon - CUSTOM ACTION ENTRY POINT for installing Perfmon counters - -********************************************************************/ -extern "C" UINT __stdcall ConfigurePerfmonInstall( - __in MSIHANDLE hInstall - ) -{ -// Assert(FALSE); - HRESULT hr; - UINT er = ERROR_SUCCESS; - - PMSIHANDLE hView, hRec; - LPWSTR pwzData = NULL, pwzName = NULL, pwzFile = NULL; - INSTALLSTATE isInstalled, isAction; - - hr = WcaInitialize(hInstall, "ConfigurePerfmonInstall"); - ExitOnFailure(hr, "Failed to initialize"); - - // check to see if necessary tables are specified - if (S_OK != WcaTableExists(L"Wix4Perfmon")) - { - WcaLog(LOGMSG_VERBOSE, "Skipping RegisterPerfmon() because Wix4Perfmon table not present"); - ExitFunction1(hr = S_FALSE); - } - - hr = WcaOpenExecuteView(vcsPerfMonQuery, &hView); - ExitOnFailure(hr, "failed to open view on PerfMon table"); - while ((hr = WcaFetchRecord(hView, &hRec)) == S_OK) - { - // get component install state - hr = WcaGetRecordString(hRec, pmqComponent, &pwzData); - ExitOnFailure(hr, "failed to get Component for PerfMon"); - er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction); - hr = HRESULT_FROM_WIN32(er); - ExitOnFailure(hr, "failed to get Component state for PerfMon"); - if (!WcaIsInstalling(isInstalled, isAction)) - { - continue; - } - - hr = WcaGetRecordString(hRec, pmqName, &pwzName); - ExitOnFailure(hr, "failed to get Name for PerfMon"); - - hr = WcaGetRecordFormattedString(hRec, pmqFile, &pwzFile); - ExitOnFailure(hr, "failed to get File for PerfMon"); - - WcaLog(LOGMSG_VERBOSE, "ConfigurePerfmonInstall's CustomActionData: '%ls', '%ls'", pwzName, pwzFile); - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RegisterPerfmon"), pwzFile, COST_PERFMON_REGISTER); - ExitOnFailure(hr, "failed to schedule RegisterPerfmon action"); - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackRegisterPerfmon"), pwzName, COST_PERFMON_UNREGISTER); - ExitOnFailure(hr, "failed to schedule RollbackRegisterPerfmon action"); - } - - if (hr == E_NOMOREITEMS) - { - hr = S_OK; - } - ExitOnFailure(hr, "Failure while processing PerfMon"); - - hr = S_OK; - -LExit: - ReleaseStr(pwzData); - ReleaseStr(pwzName); - ReleaseStr(pwzFile); - - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} - - -/******************************************************************** - ConfigurePerfmonUninstall - CUSTOM ACTION ENTRY POINT for uninstalling - Perfmon counters - -********************************************************************/ -extern "C" UINT __stdcall ConfigurePerfmonUninstall( - __in MSIHANDLE hInstall - ) -{ -// Assert(FALSE); - HRESULT hr; - UINT er = ERROR_SUCCESS; - - PMSIHANDLE hView, hRec; - LPWSTR pwzData = NULL, pwzName = NULL, pwzFile = NULL; - INSTALLSTATE isInstalled, isAction; - - hr = WcaInitialize(hInstall, "ConfigurePerfmonUninstall"); - ExitOnFailure(hr, "Failed to initialize"); - - // check to see if necessary tables are specified - if (WcaTableExists(L"Wix4Perfmon") != S_OK) - { - WcaLog(LOGMSG_VERBOSE, "Skipping UnregisterPerfmon() because Wix4Perfmon table not present"); - ExitFunction1(hr = S_FALSE); - } - - hr = WcaOpenExecuteView(vcsPerfMonQuery, &hView); - ExitOnFailure(hr, "failed to open view on PerfMon table"); - while ((hr = WcaFetchRecord(hView, &hRec)) == S_OK) - { - // get component install state - hr = WcaGetRecordString(hRec, pmqComponent, &pwzData); - ExitOnFailure(hr, "failed to get Component for PerfMon"); - er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction); - hr = HRESULT_FROM_WIN32(er); - ExitOnFailure(hr, "failed to get Component state for PerfMon"); - if (!WcaIsUninstalling(isInstalled, isAction)) - { - continue; - } - - hr = WcaGetRecordString(hRec, pmqName, &pwzName); - ExitOnFailure(hr, "failed to get Name for PerfMon"); - - hr = WcaGetRecordFormattedString(hRec, pmqFile, &pwzFile); - ExitOnFailure(hr, "failed to get File for PerfMon"); - - WcaLog(LOGMSG_VERBOSE, "ConfigurePerfmonUninstall's CustomActionData: '%ls', '%ls'", pwzName, pwzFile); - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"UnregisterPerfmon"), pwzName, COST_PERFMON_UNREGISTER); - ExitOnFailure(hr, "failed to schedule UnregisterPerfmon action"); - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackUnregisterPerfmon"), pwzFile, COST_PERFMON_REGISTER); - ExitOnFailure(hr, "failed to schedule RollbackUnregisterPerfmon action"); - } - - if (hr == E_NOMOREITEMS) - { - hr = S_OK; - } - ExitOnFailure(hr, "Failure while processing PerfMon"); - - hr = S_OK; - -LExit: - ReleaseStr(pwzData); - ReleaseStr(pwzName); - ReleaseStr(pwzFile); - - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} - - - -static HRESULT ProcessPerformanceCategory( - __in MSIHANDLE hInstall, - __in BOOL fInstall - ) -{ - HRESULT hr = S_OK; - DWORD er = ERROR_SUCCESS; - - PMSIHANDLE hView, hRec; - LPWSTR pwzId = NULL; - LPWSTR pwzComponent = NULL; - LPWSTR pwzName = NULL; - LPWSTR pwzData = NULL; - INSTALLSTATE isInstalled, isAction; - - LPWSTR pwzCustomActionData = NULL; - - // check to see if necessary tables are specified - if (S_OK != WcaTableExists(L"Wix4PerformanceCategory")) - { - ExitFunction1(hr = S_FALSE); - } - - hr = WcaOpenExecuteView(vcsPerfCounterDataQuery, &hView); - ExitOnFailure(hr, "failed to open view on Wix4PerformanceCategory table"); - while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) - { - hr = WcaGetRecordString(hRec, pcdqId, &pwzId); - ExitOnFailure(hr, "Failed to get id for Wix4PerformanceCategory."); - - // Check to see if the Component is being installed or uninstalled - // when we are processing the same. - hr = WcaGetRecordString(hRec, pcdqComponent, &pwzComponent); - ExitOnFailure(hr, "Failed to get Component for Wix4PerformanceCategory: %ls", pwzId); - - er = ::MsiGetComponentStateW(hInstall, pwzComponent, &isInstalled, &isAction); - hr = HRESULT_FROM_WIN32(er); - ExitOnFailure(hr, "Failed to get Component state for Wix4PerformanceCategory: %ls", pwzId); - - if ((fInstall && !WcaIsInstalling(isInstalled, isAction)) || - (!fInstall && !WcaIsUninstalling(isInstalled, isAction))) - { - continue; - } - - hr = WcaGetRecordString(hRec, pcdqName, &pwzName); - ExitOnFailure(hr, "Failed to get Name for Wix4PerformanceCategory: %ls", pwzId); - hr = WcaWriteStringToCaData(pwzName, &pwzCustomActionData); - ExitOnFailure(hr, "Failed to add Name to CustomActionData for Wix4PerformanceCategory: %ls", pwzId); - - hr = WcaGetRecordString(hRec, pcdqIniData, &pwzData); - ExitOnFailure(hr, "Failed to get IniData for Wix4PerformanceCategory: %ls", pwzId); - hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); - ExitOnFailure(hr, "Failed to add IniData to CustomActionData for Wix4PerformanceCategory: %ls", pwzId); - - hr = WcaGetRecordString(hRec, pcdqConstantData, &pwzData); - ExitOnFailure(hr, "Failed to get ConstantData for Wix4PerformanceCategory: %ls", pwzId); - hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); - ExitOnFailure(hr, "Failed to add ConstantData to CustomActionData for Wix4PerformanceCategory: %ls", pwzId); - } - - if (hr == E_NOMOREITEMS) - { - hr = S_OK; - } - ExitOnFailure(hr, "Failure while processing Wix4PerformanceCategory table."); - - // If there was any data built up, schedule it for execution. - if (pwzCustomActionData) - { - if (fInstall) - { - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackRegisterPerfCounterData"), pwzCustomActionData, COST_PERFMON_UNREGISTER); - ExitOnFailure(hr, "Failed to schedule RollbackRegisterPerfCounterData action for Wix4PerformanceCategory: %ls", pwzId); - - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RegisterPerfCounterData"), pwzCustomActionData, COST_PERFMON_REGISTER); - ExitOnFailure(hr, "Failed to schedule RegisterPerfCounterData action for Wix4PerformanceCategory: %ls", pwzId); - } - else - { - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackUnregisterPerfCounterData"), pwzCustomActionData, COST_PERFMON_REGISTER); - ExitOnFailure(hr, "Failed to schedule RollbackUnregisterPerfCounterData action for Wix4PerformanceCategory: %ls", pwzId); - - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"UnregisterPerfCounterData"), pwzCustomActionData, COST_PERFMON_UNREGISTER); - ExitOnFailure(hr, "Failed to schedule UnregisterPerfCounterData action for Wix4PerformanceCategory: %ls", pwzId); - } - } - -LExit: - ReleaseStr(pwzCustomActionData); - ReleaseStr(pwzData); - ReleaseStr(pwzName); - ReleaseStr(pwzComponent); - ReleaseStr(pwzId); - - return hr; -} diff --git a/src/ca/scaperfexec.cpp b/src/ca/scaperfexec.cpp deleted file mode 100644 index c5425754..00000000 --- a/src/ca/scaperfexec.cpp +++ /dev/null @@ -1,423 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" - -typedef DWORD (STDAPICALLTYPE *PFNPERFCOUNTERTEXTSTRINGS)(LPWSTR lpCommandLine, BOOL bQuietModeArg); - -static HRESULT ExecutePerfCounterData( - __in MSIHANDLE hInstall, - __in BOOL fInstall - ); -static HRESULT CreateDataFile( - __in LPCWSTR wzTempFolder, - __in LPCWSTR wzData, - __in BOOL fIniData, - __out HANDLE *phFile, - __out_opt LPWSTR *ppwzFile - ); - - -/******************************************************************** - RegisterPerfCounterData - CUSTOM ACTION ENTRY POINT for registering - performance counters - - Input: deferred CustomActionData: wzName\twzIniData\twzConstantData\twzName\twzIniData\twzConstantData\t... -*******************************************************************/ -extern "C" UINT __stdcall RegisterPerfCounterData( - __in MSIHANDLE hInstall - ) -{ - // AssertSz(FALSE, "debug RegisterPerfCounterData()"); - HRESULT hr = S_OK; - DWORD er = ERROR_SUCCESS; - - hr = WcaInitialize(hInstall, "RegisterPerfCounterData"); - ExitOnFailure(hr, "Failed to initialize RegisterPerfCounterData."); - - hr = ExecutePerfCounterData(hInstall, TRUE); - MessageExitOnFailure(hr, msierrInstallPerfCounterData, "Failed to execute Wix4PerformanceCategory table."); - -LExit: - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} - - -/******************************************************************** - UnregisterPerfCounterData - CUSTOM ACTION ENTRY POINT for registering - performance counters - - Input: deferred CustomActionData: wzName\twzIniData\twzConstantData\twzName\twzIniData\twzConstantData\t... -*******************************************************************/ -extern "C" UINT __stdcall UnregisterPerfCounterData( - __in MSIHANDLE hInstall - ) -{ - // AssertSz(FALSE, "debug UnregisterPerfCounterData()"); - HRESULT hr = S_OK; - DWORD er = ERROR_SUCCESS; - - hr = WcaInitialize(hInstall, "UnregisterPerfCounterData"); - ExitOnFailure(hr, "Failed to initialize UnregisterPerfCounterData."); - - hr = ExecutePerfCounterData(hInstall, FALSE); - MessageExitOnFailure(hr, msierrUninstallPerfCounterData, "Failed to execute Wix4PerformanceCategory table."); - -LExit: - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} - - -/******************************************************************** - RegisterPerfmon - CUSTOM ACTION ENTRY POINT for registering - counters - - Input: deferred CustomActionData - - wzFile or wzName -*******************************************************************/ -extern "C" UINT __stdcall RegisterPerfmon( - __in MSIHANDLE hInstall - ) -{ -// Assert(FALSE); - UINT er = ERROR_SUCCESS; - HRESULT hr = S_OK; - LPWSTR pwzData = NULL; - - HMODULE hMod = NULL; - PFNPERFCOUNTERTEXTSTRINGS pfnPerfCounterTextString; - DWORD dwRet; - LPWSTR pwzShortPath = NULL; - DWORD cchShortPath = MAX_PATH; - DWORD cchShortPathLength = 0; - - LPWSTR pwzCommand = NULL; - - hr = WcaInitialize(hInstall, "RegisterPerfmon"); - ExitOnFailure(hr, "failed to initialize"); - - hr = WcaGetProperty(L"CustomActionData", &pwzData); - ExitOnFailure(hr, "failed to get CustomActionData"); - - WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); - - // do the perfmon registration - if (NULL == hMod) - { - hr = LoadSystemLibrary(L"loadperf.dll", &hMod); - } - ExitOnFailure(hr, "failed to load DLL for PerfMon"); - - pfnPerfCounterTextString = (PFNPERFCOUNTERTEXTSTRINGS)::GetProcAddress(hMod, "LoadPerfCounterTextStringsW"); - ExitOnNullWithLastError(pfnPerfCounterTextString, hr, "failed to get DLL function for PerfMon"); - - hr = StrAlloc(&pwzShortPath, cchShortPath); - ExitOnFailure(hr, "failed to allocate string"); - - WcaLog(LOGMSG_VERBOSE, "Converting DLL path to short format: %ls", pwzData); - cchShortPathLength = ::GetShortPathNameW(pwzData, pwzShortPath, cchShortPath); - if (cchShortPathLength > cchShortPath) - { - cchShortPath = cchShortPathLength + 1; - hr = StrAlloc(&pwzShortPath, cchShortPath); - ExitOnFailure(hr, "failed to allocate string"); - - cchShortPathLength = ::GetShortPathNameW(pwzData, pwzShortPath, cchShortPath); - } - - if (0 == cchShortPathLength) - { - ExitOnLastError(hr, "failed to get short path format of path: %ls", pwzData); - } - - hr = StrAllocFormatted(&pwzCommand, L"lodctr \"%s\"", pwzShortPath); - ExitOnFailure(hr, "failed to format lodctr string"); - - WcaLog(LOGMSG_VERBOSE, "RegisterPerfmon running command: '%ls'", pwzCommand); - dwRet = (*pfnPerfCounterTextString)(pwzCommand, TRUE); - if (dwRet != ERROR_SUCCESS && dwRet != ERROR_ALREADY_EXISTS) - { - hr = HRESULT_FROM_WIN32(dwRet); - MessageExitOnFailure(hr, msierrPERFMONFailedRegisterDLL, "failed to register with PerfMon, DLL: %ls", pwzData); - } - - hr = S_OK; -LExit: - ReleaseStr(pwzData); - - if (FAILED(hr)) - er = ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} - - -extern "C" UINT __stdcall UnregisterPerfmon( - __in MSIHANDLE hInstall - ) -{ -// Assert(FALSE); - UINT er = ERROR_SUCCESS; - HRESULT hr = S_OK; - LPWSTR pwzData = NULL; - - HMODULE hMod = NULL; - PFNPERFCOUNTERTEXTSTRINGS pfnPerfCounterTextString; - DWORD dwRet; - WCHAR wz[255]; - - hr = WcaInitialize(hInstall, "UnregisterPerfmon"); - ExitOnFailure(hr, "failed to initialize"); - - hr = WcaGetProperty(L"CustomActionData", &pwzData); - ExitOnFailure(hr, "failed to get CustomActionData"); - - WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); - - // do the perfmon unregistration - hr = E_FAIL; - if (hMod == NULL) - { - hr = LoadSystemLibrary(L"loadperf.dll", &hMod); - } - ExitOnFailure(hr, "failed to load DLL for PerfMon"); - - pfnPerfCounterTextString = (PFNPERFCOUNTERTEXTSTRINGS)::GetProcAddress(hMod, "UnloadPerfCounterTextStringsW"); - ExitOnNullWithLastError(pfnPerfCounterTextString, hr, "failed to get DLL function for PerfMon"); - - hr = ::StringCchPrintfW(wz, countof(wz), L"unlodctr \"%s\"", pwzData); - ExitOnFailure(hr, "Failed to format unlodctr string with: %ls", pwzData); - WcaLog(LOGMSG_VERBOSE, "UnregisterPerfmon running command: '%ls'", wz); - dwRet = (*pfnPerfCounterTextString)(wz, TRUE); - // if the counters aren't registered, then OK to continue - if (dwRet != ERROR_SUCCESS && dwRet != ERROR_FILE_NOT_FOUND && dwRet != ERROR_BADKEY) - { - hr = HRESULT_FROM_WIN32(dwRet); - MessageExitOnFailure(hr, msierrPERFMONFailedUnregisterDLL, "failed to unregsister with PerfMon, DLL: %ls", pwzData); - } - - hr = S_OK; -LExit: - ReleaseStr(pwzData); - - if (FAILED(hr)) - er = ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} - - -static HRESULT ExecutePerfCounterData( - __in MSIHANDLE /*hInstall*/, - __in BOOL fInstall - ) -{ - HRESULT hr = S_OK; - DWORD er = ERROR_SUCCESS; - - HMODULE hModule = NULL; - PFNPERFCOUNTERTEXTSTRINGS pfnPerfCounterTextString = NULL; - LPCWSTR wzPrefix = NULL; - - LPWSTR pwzCustomActionData = NULL; - LPWSTR pwz = NULL; - - LPWSTR pwzName = NULL; - LPWSTR pwzIniData = NULL; - LPWSTR pwzConstantData = NULL; - LPWSTR pwzTempFolder = NULL; - LPWSTR pwzIniFile = NULL; - LPWSTR pwzExecute = NULL; - - HANDLE hIniData = INVALID_HANDLE_VALUE; - HANDLE hConstantData = INVALID_HANDLE_VALUE; - - // Load the system performance counter helper DLL then get the appropriate - // entrypoint out of it. Fortunately, they have the same signature so we - // can use one function pointer to point to both. - hr = LoadSystemLibrary(L"loadperf.dll", &hModule); - ExitOnFailure(hr, "failed to load DLL for PerfMon"); - - if (fInstall) - { - wzPrefix = L"lodctr"; - pfnPerfCounterTextString = (PFNPERFCOUNTERTEXTSTRINGS)::GetProcAddress(hModule, "LoadPerfCounterTextStringsW"); - } - else - { - wzPrefix = L"unlodctr"; - pfnPerfCounterTextString = (PFNPERFCOUNTERTEXTSTRINGS)::GetProcAddress(hModule, "UnloadPerfCounterTextStringsW"); - } - ExitOnNullWithLastError(pfnPerfCounterTextString, hr, "Failed to get DLL function for PerfMon"); - - // Now get the CustomActionData and execute it. - hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData); - ExitOnFailure(hr, "Failed to get CustomActionData."); - - WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); - - pwz = pwzCustomActionData; - - while (S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzName))) - { - hr = WcaReadStringFromCaData(&pwz, &pwzIniData); - ExitOnFailure(hr, "Failed to read IniData from custom action data."); - - hr = WcaReadStringFromCaData(&pwz, &pwzConstantData); - ExitOnFailure(hr, "Failed to read ConstantData from custom action data."); - - if (fInstall) - { - hr = PathCreateTempDirectory(NULL, L"WIXPF%03x", 999, &pwzTempFolder); - ExitOnFailure(hr, "Failed to create temp directory."); - - hr = CreateDataFile(pwzTempFolder, pwzIniData, TRUE, &hIniData, &pwzIniFile); - ExitOnFailure(hr, "Failed to create .ini file for performance counter category: %ls", pwzName); - - hr = CreateDataFile(pwzTempFolder, pwzConstantData, FALSE, &hConstantData, NULL); - ExitOnFailure(hr, "Failed to create .h file for performance counter category: %ls", pwzName); - - hr = StrAllocFormatted(&pwzExecute, L"%s \"%s\"", wzPrefix, pwzIniFile); - ExitOnFailure(hr, "Failed to allocate string to execute."); - - // Execute the install. - er = (*pfnPerfCounterTextString)(pwzExecute, TRUE); - hr = HRESULT_FROM_WIN32(er); - ExitOnFailure(hr, "Failed to execute install of performance counter category: %ls", pwzName); - - if (INVALID_HANDLE_VALUE != hIniData) - { - ::CloseHandle(hIniData); - hIniData = INVALID_HANDLE_VALUE; - } - - if (INVALID_HANDLE_VALUE != hConstantData) - { - ::CloseHandle(hConstantData); - hConstantData = INVALID_HANDLE_VALUE; - } - - DirEnsureDelete(pwzTempFolder, TRUE, TRUE); - } - else - { - hr = StrAllocFormatted(&pwzExecute, L"%s \"%s\"", wzPrefix, pwzName); - ExitOnFailure(hr, "Failed to allocate string to execute."); - - // Execute the uninstall and if the counter isn't registered then ignore - // the error since it won't hurt anything. - er = (*pfnPerfCounterTextString)(pwzExecute, TRUE); - if (ERROR_FILE_NOT_FOUND == er || ERROR_BADKEY == er) - { - er = ERROR_SUCCESS; - } - hr = HRESULT_FROM_WIN32(er); - ExitOnFailure(hr, "Failed to execute uninstall of performance counter category: %ls", pwzName); - } - } - - if (E_NOMOREITEMS == hr) // If there are no more items, all is well - { - hr = S_OK; - } - ExitOnFailure(hr, "Failed to execute all perf counter data."); - - hr = S_OK; - -LExit: - if (INVALID_HANDLE_VALUE != hIniData) - { - ::CloseHandle(hIniData); - } - - if (INVALID_HANDLE_VALUE != hConstantData) - { - ::CloseHandle(hConstantData); - } - - ReleaseStr(pwzExecute); - ReleaseStr(pwzIniFile); - ReleaseStr(pwzTempFolder); - ReleaseStr(pwzConstantData); - ReleaseStr(pwzIniData); - ReleaseStr(pwzName); - ReleaseStr(pwzCustomActionData); - - if (hModule) - { - ::FreeLibrary(hModule); - } - - return hr; -} - - -static HRESULT CreateDataFile( - __in LPCWSTR wzTempFolder, - __in LPCWSTR wzData, - __in BOOL fIniData, - __out HANDLE *phFile, - __out_opt LPWSTR *ppwzFile - ) -{ - HRESULT hr = S_OK; - HANDLE hFile = INVALID_HANDLE_VALUE; - LPWSTR pwzFile = NULL; - LPSTR pszData = NULL; - DWORD cbData = 0; - DWORD cbWritten = 0; - - // Convert the data to UTF-8 because lodctr/unloctr - // doesn't like unicode. - hr = StrAnsiAllocString(&pszData, wzData, 0, CP_UTF8); - ExitOnFailure(hr, "Failed to covert data to ANSI."); - - cbData = lstrlenA(pszData); - - // Concatenate the paths together, open the file data file - // and dump the data in there. - hr = StrAllocString(&pwzFile, wzTempFolder, 0); - ExitOnFailure(hr, "Failed to copy temp directory name."); - - hr = StrAllocConcat(&pwzFile, L"wixperf", 0); - ExitOnFailure(hr, "Failed to add name of file."); - - hr = StrAllocConcat(&pwzFile, fIniData ? L".ini" : L".h", 0); - ExitOnFailure(hr, "Failed to add extension of file."); - - hFile = ::CreateFileW(pwzFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (INVALID_HANDLE_VALUE == hFile) - { - ExitWithLastError(hr, "Failed to open new temp file: %ls", pwzFile); - } - - if (!::WriteFile(hFile, pszData, cbData, &cbWritten, NULL)) - { - ExitWithLastError(hr, "Failed to write data to new temp file: %ls", pwzFile); - } - - if (INVALID_HANDLE_VALUE != hFile) - { - ::CloseHandle(hFile); - hFile = INVALID_HANDLE_VALUE; - } - - // Return the requested values. - *phFile = hFile; - hFile = INVALID_HANDLE_VALUE; - - if (ppwzFile) - { - *ppwzFile = pwzFile; - pwzFile = NULL; - } - -LExit: - if (INVALID_HANDLE_VALUE != hFile) - { - ::CloseHandle(hFile); - } - ReleaseStr(pszData); - ReleaseStr(pwzFile); - - return hr; -} diff --git a/src/ca/scasched.cpp b/src/ca/scasched.cpp deleted file mode 100644 index d81b1f14..00000000 --- a/src/ca/scasched.cpp +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" - - -/******************************************************************** -ConfigureSmb - CUSTOM ACTION ENTRY POINT for installing fileshare settings - -********************************************************************/ -extern "C" UINT __stdcall ConfigureSmbInstall( - __in MSIHANDLE hInstall - ) -{ - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - - SCA_SMB* pssList = NULL; - - // initialize - hr = WcaInitialize(hInstall, "ConfigureSmbInstall"); - ExitOnFailure(hr, "Failed to initialize"); - - // check to see if necessary tables are specified - if (WcaTableExists(L"Wix4FileShare") != S_OK) - { - WcaLog(LOGMSG_VERBOSE, "Skipping SMB CustomAction, no Wix4FileShare table"); - ExitFunction1(hr = S_FALSE); - } - - hr = ScaSmbRead(&pssList); - ExitOnFailure(hr, "failed to read Wix4FileShare table"); - - hr = ScaSmbInstall(pssList); - ExitOnFailure(hr, "failed to install FileShares"); - -LExit: - if (pssList) - ScaSmbFreeList(pssList); - - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} - - -/******************************************************************** -ConfigureSmb - CUSTOM ACTION ENTRY POINT for uninstalling fileshare settings - -********************************************************************/ -extern "C" UINT __stdcall ConfigureSmbUninstall( - __in MSIHANDLE hInstall - ) -{ - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - - SCA_SMB* pssList = NULL; - - // initialize - hr = WcaInitialize(hInstall, "ConfigureSmbUninstall"); - ExitOnFailure(hr, "Failed to initialize"); - - // check to see if necessary tables are specified - if (WcaTableExists(L"Wix4FileShare") != S_OK) - { - WcaLog(LOGMSG_VERBOSE, "Skipping SMB CustomAction, no Wix4FileShare table"); - ExitFunction1(hr = S_FALSE); - } - - hr = ScaSmbRead(&pssList); - ExitOnFailure(hr, "failed to read Wix4FileShare table"); - - hr = ScaSmbUninstall(pssList); - ExitOnFailure(hr, "failed to uninstall FileShares"); - -LExit: - if (pssList) - ScaSmbFreeList(pssList); - - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} - - -/******************************************************************** -ConfigureUsers - CUSTOM ACTION ENTRY POINT for installing users - -********************************************************************/ -extern "C" UINT __stdcall ConfigureUsers( - __in MSIHANDLE hInstall - ) -{ - //AssertSz(0, "Debug ConfigureUsers"); - - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - - BOOL fInitializedCom = FALSE; - SCA_USER* psuList = NULL; - - // initialize - hr = WcaInitialize(hInstall, "ConfigureUsers"); - ExitOnFailure(hr, "Failed to initialize"); - - hr = ::CoInitialize(NULL); - ExitOnFailure(hr, "failed to initialize COM"); - fInitializedCom = TRUE; - - hr = ScaUserRead(&psuList); - ExitOnFailure(hr, "failed to read Wix4User table"); - - hr = ScaUserExecute(psuList); - ExitOnFailure(hr, "failed to add/remove User actions"); - -LExit: - if (psuList) - { - ScaUserFreeList(psuList); - } - - if (fInitializedCom) - { - ::CoUninitialize(); - } - - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} \ No newline at end of file diff --git a/src/ca/scasmb.h b/src/ca/scasmb.h deleted file mode 100644 index f2a4b53c..00000000 --- a/src/ca/scasmb.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - - -#include "scauser.h" - -// structs -// Structure used to hold and extra user/permission pairs from the Wix4FileSharePermissions Table -struct SCA_SMB_EX_USER_PERMS -{ - int nPermissions; - ACCESS_MODE accessMode; - SCA_USER scau; - SCA_SMB_EX_USER_PERMS* pExUserPermsNext; -}; - -struct SCA_SMB // hungarian ss -{ - WCHAR wzId[MAX_DARWIN_KEY + 1]; - WCHAR wzShareName[MAX_DARWIN_KEY + 1]; - WCHAR wzDescription[MAX_DARWIN_COLUMN + 1]; - WCHAR wzComponent[MAX_DARWIN_KEY + 1]; - WCHAR wzDirectory[MAX_PATH + 1]; - - int nUserPermissionCount; - int nPermissions; - SCA_SMB_EX_USER_PERMS* pExUserPerms; - - INSTALLSTATE isInstalled, isAction; - - BOOL fUseIntegratedAuth; - BOOL fLegacyUserProvided; - struct SCA_USER scau; - - struct SCA_SMB* pssNext; -}; - - -#define RESERVED 0 - -// schedule prototypes -HRESULT ScaSmbRead(SCA_SMB** ppssList); -HRESULT ScaSmbExPermsRead(SCA_SMB* pss); -HRESULT ScaSmbUninstall(SCA_SMB* pssList); -HRESULT ScaSmbInstall(SCA_SMB* pssList); -void ScaSmbFreeList(SCA_SMB* pssList); diff --git a/src/ca/scasmbexec.cpp b/src/ca/scasmbexec.cpp deleted file mode 100644 index ced3aa78..00000000 --- a/src/ca/scasmbexec.cpp +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" - - -/******************************************************************** - AllocateAcl - allocate an acl and populate it with this user and - permission information user could be user or domain\user - -********************************************************************/ -HRESULT AllocateAcl(SCA_SMBP* pssp, PACL* ppACL) -{ - HRESULT hr = S_OK; - EXPLICIT_ACCESSW* pEA = NULL; - DWORD cEA = 0; - DWORD dwCounter = 0; - - PSID psid = NULL; - LPCWSTR wzUser = NULL; - DWORD nPermissions = 0; - DWORD nErrorReturn = 0; - ACCESS_MODE accessMode = NOT_USED_ACCESS; - - cEA = pssp->dwUserPermissionCount + 1; - if (cEA >= MAXSIZE_T / sizeof(EXPLICIT_ACCESSW)) - { - ExitOnFailure(hr = E_OUTOFMEMORY, "Too many user permissions to allocate: %u", cEA); - } - - pEA = static_cast(MemAlloc(cEA * sizeof(EXPLICIT_ACCESSW), TRUE)); - ExitOnNull(pEA, hr, E_OUTOFMEMORY, "failed to allocate memory for explicit access structure"); - - // figure out how big the psid is - for (dwCounter = 0; dwCounter < pssp->dwUserPermissionCount; ++dwCounter) - { - wzUser = pssp->pUserPerms[dwCounter].wzUser; - nPermissions = pssp->pUserPerms[dwCounter].nPermissions; - accessMode = pssp->pUserPerms[dwCounter].accessMode; - // - // create the appropriate SID - // - - // figure out the right user to put into the access block - if (0 == lstrcmpW(wzUser, L"Everyone")) - { - hr = AclGetWellKnownSid(WinWorldSid, &psid); - } - else if (0 == lstrcmpW(wzUser, L"Administrators")) - { - hr = AclGetWellKnownSid(WinBuiltinAdministratorsSid, &psid); - } - else if (0 == lstrcmpW(wzUser, L"LocalSystem")) - { - hr = AclGetWellKnownSid(WinLocalSystemSid, &psid); - } - else if (0 == lstrcmpW(wzUser, L"LocalService")) - { - hr = AclGetWellKnownSid(WinLocalServiceSid, &psid); - } - else if (0 == lstrcmpW(wzUser, L"NetworkService")) - { - hr = AclGetWellKnownSid(WinNetworkServiceSid, &psid); - } - else if (0 == lstrcmpW(wzUser, L"AuthenticatedUser")) - { - hr = AclGetWellKnownSid(WinAuthenticatedUserSid, &psid); - } - else if (0 == lstrcmpW(wzUser, L"Guests")) - { - hr = AclGetWellKnownSid(WinBuiltinGuestsSid, &psid); - } - else if(0 == lstrcmpW(wzUser, L"CREATOR OWNER")) - { - hr = AclGetWellKnownSid(WinCreatorOwnerSid, &psid); - } - else - { - hr = AclGetAccountSid(NULL, wzUser, &psid); - } - ExitOnFailure(hr, "failed to get sid for account: %ls", wzUser); - - // we now have a valid pSid, fill in the EXPLICIT_ACCESS - - /* Permissions options: (see sca.sdh for defined sdl options) - #define GENERIC_READ (0x80000000L) 2147483648 - #define GENERIC_WRITE (0x40000000L) 1073741824 - #define GENERIC_EXECUTE (0x20000000L) 536870912 - #define GENERIC_ALL (0x10000000L) 268435456 - */ - pEA[dwCounter].grfAccessPermissions = nPermissions; - pEA[dwCounter].grfAccessMode = accessMode; - pEA[dwCounter].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT; -#pragma prefast(push) -#pragma prefast(disable:25029) - ::BuildTrusteeWithSidW(&(pEA[dwCounter].Trustee), psid); -#pragma prefast(pop) - } - - // create a new ACL that contains the ACE - *ppACL = NULL; -#pragma prefast(push) -#pragma prefast(disable:25029) - nErrorReturn = ::SetEntriesInAclW(dwCounter, pEA, NULL, ppACL); -#pragma prefast(pop) - ExitOnFailure(hr = HRESULT_FROM_WIN32(nErrorReturn), "failed to allocate ACL"); - -LExit: - if (psid) - { - AclFreeSid(psid); - } - - ReleaseMem(pEA); - - return hr; -} - - - -/******************************************************************** - FillShareInfo - fill the NetShareAdd data structure - -********************************************************************/ -void FillShareInfo(SHARE_INFO_502* psi, SCA_SMBP* pssp, PSECURITY_DESCRIPTOR pSD) -{ - psi->shi502_netname = pssp->wzKey; - psi->shi502_type = STYPE_DISKTREE; - psi->shi502_remark = pssp->wzDescription; - psi->shi502_permissions = 0; // not used - psi->shi502_max_uses = 0xFFFFFFFF; - psi->shi502_current_uses = 0; - psi->shi502_path = pssp->wzDirectory; - psi->shi502_passwd = NULL; // not file share perms - psi->shi502_reserved = 0; - psi->shi502_security_descriptor = pSD; -} - - - -/* NET_API_STATUS return codes -NERR_Success = 0 -NERR_DuplicateShare = 2118 -NERR_BufTooSmall = 2123 -NERR_NetNameNotFound = 2310 -NERR_RedirectedPath = 2117 -NERR_UnknownDevDir = 2116 -*/ - -/******************************************************************** - DoesShareExists - Does a share of this name exist on this computer? - -********************************************************************/ -HRESULT DoesShareExist(__in LPWSTR wzShareName) -{ - HRESULT hr = S_OK; - NET_API_STATUS s; - SHARE_INFO_502* psi = NULL; - s = ::NetShareGetInfo(NULL, wzShareName, 502, (BYTE**) &psi); - - switch (s) - { - case NERR_Success: - hr = S_OK; - break; - case NERR_NetNameNotFound: - hr = E_FILENOTFOUND; - break; - default: - WcaLogError(s, "NetShareGetInfo returned an unexpected value.", NULL); - hr = HRESULT_FROM_WIN32(s); - break; - } - - ::NetApiBufferFree(psi); - - return hr; -} - - - -/******************************************************************** - CreateShare - create the file share on this computer - -********************************************************************/ -HRESULT CreateShare(SCA_SMBP* pssp) -{ - if (!pssp || !(pssp->wzKey)) - return E_INVALIDARG; - - HRESULT hr = S_OK; - PACL pACL = NULL; - SHARE_INFO_502 si; - NET_API_STATUS s; - DWORD dwParamErr = 0; - - BOOL fShareExists = SUCCEEDED(DoesShareExist(pssp->wzKey)); - - PSECURITY_DESCRIPTOR pSD = static_cast(MemAlloc(SECURITY_DESCRIPTOR_MIN_LENGTH, TRUE)); - ExitOnNull(pSD, hr, E_OUTOFMEMORY, "Failed to allocate memory for security descriptor"); - -#pragma prefast(push) -#pragma prefast(disable:25029) - if (!::InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) -#pragma prefast(pop) - { - ExitOnLastError(hr, "failed to initialize security descriptor"); - } - - hr = AllocateAcl(pssp, &pACL); - ExitOnFailure(hr, "Failed to allocate ACL for fileshare"); - - if (NULL == pACL) - { - WcaLog(LOGMSG_VERBOSE, "Ignoring NULL DACL."); - } -#pragma prefast(push) -#pragma prefast(disable:25028) // We only call this when pACL isn't NULL, so this call is safe according to the docs - // add the ACL to the security descriptor. - else if (!::SetSecurityDescriptorDacl(pSD, TRUE, pACL, FALSE)) - { - ExitOnLastError(hr, "Failed to set security descriptor"); - } -#pragma prefast(pop) - - // all that is left is to create the share - FillShareInfo(&si, pssp, pSD); - - // Fail if the directory doesn't exist - if (!DirExists(pssp->wzDirectory, NULL)) - ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_OBJECT_NOT_FOUND), "Can't create a file share on directory that doesn't exist: %ls.", pssp->wzDirectory); - - WcaLog(LOGMSG_VERBOSE, "Creating file share on directory \'%ls\' named \'%ls\'.", pssp->wzDirectory, pssp->wzKey); - - if (!fShareExists) - { - s = ::NetShareAdd(NULL, 502, (BYTE*) &si, &dwParamErr); - WcaLog(LOGMSG_VERBOSE, "Adding a new file share."); - } - else - { - // The share exists. Write our new permissions over the top. - s = ::NetShareSetInfo(NULL, pssp->wzKey, 502, (BYTE*) &si, &dwParamErr); - WcaLog(LOGMSG_VERBOSE, "Setting permissions on existing share."); - } - - if (NERR_Success != s) - { - hr = E_FAIL; - if (!fShareExists && NERR_DuplicateShare == s) - WcaLog(LOGMSG_VERBOSE, "Duplicate error when existence check failed."); - - // error codes listed above. - ExitOnFailure(hr, "Failed to create/modify file share: Err: %d", s); - } - -LExit: - if (pACL) - { - ::LocalFree(pACL); - } - - ReleaseMem(pSD); - - return hr; -} - - -/******************************************************************** - ScaEnsureSmbExists - -********************************************************************/ -HRESULT ScaEnsureSmbExists(SCA_SMBP* pssp) -{ - HRESULT hr = S_OK; - - // create the share - hr = CreateShare(pssp); - - return hr; -} - - -// -// Delete File Shares - real work -// - -/******************************************************************** - ScaDropSmb - delete this file share from this computer - -********************************************************************/ -HRESULT ScaDropSmb(SCA_SMBP* pssp) -{ - HRESULT hr = S_OK; - NET_API_STATUS s; - - hr = DoesShareExist(pssp->wzKey); - - if (E_FILENOTFOUND == hr) - { - WcaLog(LOGMSG_VERBOSE, "Share doesn't exist, share removal skipped. (%ls)", pssp->wzKey); - ExitFunction1(hr = S_OK); - - } - - ExitOnFailure(hr, "Unable to detect share. (%ls)", pssp->wzKey); - - s = ::NetShareDel(NULL, pssp->wzKey, 0); - if (NERR_Success != s) - { - hr = E_FAIL; - ExitOnFailure(hr, "Failed to remove file share: Err: %d", s); - } - -LExit: - return hr; -} diff --git a/src/ca/scasmbexec.h b/src/ca/scasmbexec.h deleted file mode 100644 index e3c8f8bb..00000000 --- a/src/ca/scasmbexec.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - - -struct SCA_SMBP_USER_PERMS -{ - DWORD nPermissions; - ACCESS_MODE accessMode; - WCHAR* wzUser; - //Not adding Password because I can't find anywhere that it is used -}; - -struct SCA_SMBP // hungarian ssp -{ - WCHAR* wzKey; - WCHAR* wzDescription; - WCHAR* wzComponent; - WCHAR* wzDirectory; // full path of the dir to share to - - DWORD dwUserPermissionCount; //Count of SCA_SMBP_EX_USER_PERMS structures - SCA_SMBP_USER_PERMS* pUserPerms; - BOOL fUseIntegratedAuth; -}; - - -HRESULT ScaEnsureSmbExists(SCA_SMBP* pssp); -HRESULT ScaDropSmb(SCA_SMBP* pssp); diff --git a/src/ca/scasmbsched.cpp b/src/ca/scasmbsched.cpp deleted file mode 100644 index e29f7f51..00000000 --- a/src/ca/scasmbsched.cpp +++ /dev/null @@ -1,639 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" - - -/******************************************************************** - Helper functions to maintain a list of file shares to create / remove - -********************************************************************/ -SCA_SMB* NewSmb() -{ - SCA_SMB* pss = (SCA_SMB*)MemAlloc(sizeof(SCA_SMB), TRUE); - Assert(pss); - return pss; -} - - -SCA_SMB_EX_USER_PERMS* NewExUserPermsSmb() -{ - SCA_SMB_EX_USER_PERMS* pExUserPerms = (SCA_SMB_EX_USER_PERMS*)MemAlloc(sizeof(SCA_SMB_EX_USER_PERMS), TRUE); - Assert(pExUserPerms); - return pExUserPerms; -} - - -SCA_SMB* AddSmbToList(SCA_SMB* pssList, SCA_SMB* pss) -{ - if (pssList) - { - SCA_SMB* pssT = pssList; - while (pssT->pssNext) - { - pssT = pssT->pssNext; - } - - pssT->pssNext = pss; - } - else - { - pssList = pss; - } - - return pssList; -} - - -SCA_SMB_EX_USER_PERMS* AddExUserPermsSmbToList( - SCA_SMB_EX_USER_PERMS* pExUserPermsList, - SCA_SMB_EX_USER_PERMS* pExUserPerms - ) -{ - SCA_SMB_EX_USER_PERMS* pExUserPermsTemp = pExUserPermsList; - if (pExUserPermsList) - { - while (pExUserPermsTemp->pExUserPermsNext) - { - pExUserPermsTemp = pExUserPermsTemp->pExUserPermsNext; - } - - pExUserPermsTemp->pExUserPermsNext = pExUserPerms; - } - else - { - pExUserPermsList = pExUserPerms; - } - - return pExUserPermsList; -} - -void ScaSmbFreeList(SCA_SMB* pssList) -{ - SCA_SMB* pssDelete = pssList; - while (pssList) - { - pssDelete = pssList; - pssList = pssList->pssNext; - - MemFree(pssDelete); - } -} - -void ScaExUserPermsSmbFreeList(SCA_SMB_EX_USER_PERMS* pExUserPermsList) -{ - SCA_SMB_EX_USER_PERMS* pExUserPermsDelete = pExUserPermsList; - while (pExUserPermsList) - { - pExUserPermsDelete = pExUserPermsList; - pExUserPermsList = pExUserPermsList->pExUserPermsNext; - - MemFree(pExUserPermsDelete); - } -} - -// sql query constants -LPCWSTR vcsSmbQuery = L"SELECT `Wix4FileShare`, `ShareName`, `Description`, `Directory_`, " - L"`Component_`, `User_`, `Permissions` FROM `Wix4FileShare`"; - -enum eSmbQuery { - ssqFileShare = 1, - ssqShareName, - ssqDescription, - ssqDirectory, - ssqComponent, - ssqUser, - ssqPermissions - }; - - -/******************************************************************** - ScaSmbRead - read all of the information from the msi tables and - return a list of file share jobs to be done. - -********************************************************************/ -HRESULT ScaSmbRead(SCA_SMB** ppssList) -{ - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - PMSIHANDLE hView, hRec; - - LPWSTR pwzData = NULL; - - SCA_SMB* pss = NULL; - BOOL bUserPermissionsTableExists = FALSE; - - if (S_OK != WcaTableExists(L"Wix4FileShare")) - { - WcaLog(LOGMSG_VERBOSE, "Skipping ScaSmbCreateShare() - Wix4FileShare table not present"); - ExitFunction1(hr = S_FALSE); - } - - if (S_OK == WcaTableExists(L"Wix4FileSharePermissions")) - { - bUserPermissionsTableExists = TRUE; - } - else - { - WcaLog(LOGMSG_VERBOSE, "No Additional Permissions - Wix4FileSharePermissions table not present"); - } - - WcaLog(LOGMSG_VERBOSE, "Reading File Share Tables"); - - // loop through all the fileshares - hr = WcaOpenExecuteView(vcsSmbQuery, &hView); - ExitOnFailure(hr, "Failed to open view on Wix4FileShare table"); - while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) - { - pss = NewSmb(); - if (!pss) - { - hr = E_OUTOFMEMORY; - break; - } - Assert(pss); - ::ZeroMemory(pss, sizeof(*pss)); - - hr = WcaGetRecordString(hRec, ssqFileShare, &pwzData); - ExitOnFailure(hr, "Failed to get Wix4FileShare.Wix4FileShare"); - hr = ::StringCchCopyW(pss->wzId, countof(pss->wzId), pwzData); - ExitOnFailure(hr, "Failed to copy ID string to smb object"); - - hr = WcaGetRecordFormattedString(hRec, ssqShareName, &pwzData); - ExitOnFailure(hr, "Failed to get Wix4FileShare.ShareName"); - hr = ::StringCchCopyW(pss->wzShareName, countof(pss->wzShareName), pwzData); - ExitOnFailure(hr, "Failed to copy share name string to smb object"); - - hr = WcaGetRecordString(hRec, ssqComponent, &pwzData); - ExitOnFailure(hr, "Failed to get Component for Wix4FileShare: '%ls'", pss->wzShareName); - hr = ::StringCchCopyW(pss->wzComponent, countof(pss->wzComponent), pwzData); - ExitOnFailure(hr, "Failed to copy component string to smb object"); - - hr = WcaGetRecordFormattedString(hRec, ssqDescription, &pwzData); - ExitOnFailure(hr, "Failed to get Share Description for Wix4FileShare: '%ls'", pss->wzShareName); - hr = ::StringCchCopyW(pss->wzDescription, countof(pss->wzDescription), pwzData); - ExitOnFailure(hr, "Failed to copy description string to smb object"); - - // get user info from the user table - hr = WcaGetRecordFormattedString(hRec, ssqUser, &pwzData); - ExitOnFailure(hr, "Failed to get Wix4User record for Wix4FileShare: '%ls'", pss->wzShareName); - - // get component install state - er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pss->wzComponent, &pss->isInstalled, &pss->isAction); - hr = HRESULT_FROM_WIN32(er); - ExitOnFailure(hr, "Failed to get Component state for Wix4FileShare"); - - // if a user was specified - if (*pwzData) - { - pss->fUseIntegratedAuth = FALSE; - pss->fLegacyUserProvided = TRUE; - hr = ScaGetUser(pwzData, &pss->scau); - ExitOnFailure(hr, "Failed to get user information for fileshare: '%ls'", pss->wzShareName); - } - else - { - pss->fLegacyUserProvided = FALSE; - // TODO: figure out whether this is useful still - //pss->fUseIntegratedAuth = TRUE; - // integrated authorization doesn't have a User record - } - - // get the share's directory - hr = WcaGetRecordString(hRec, ssqDirectory, &pwzData); - ExitOnFailure(hr, "Failed to get directory for Wix4FileShare: '%ls'", pss->wzShareName); - - WCHAR wzPath[MAX_PATH]; - DWORD dwLen; - dwLen = countof(wzPath); - // review: relevant for file shares? - if (INSTALLSTATE_SOURCE == pss->isAction) - { - er = ::MsiGetSourcePathW(WcaGetInstallHandle(), pwzData, wzPath, &dwLen); - } - else - { - er = ::MsiGetTargetPathW(WcaGetInstallHandle(), pwzData, wzPath, &dwLen); - } - hr = HRESULT_FROM_WIN32(er); - ExitOnFailure(hr, "Failed to get Source/TargetPath for Directory"); - - // If the path is to the root of a drive, then it needs a trailing backslash. - // Otherwise, it can't have a trailing backslash. - if (3 < dwLen) - { - if (wzPath[dwLen - 1] == L'\\') - { - wzPath[dwLen - 1] = 0; - } - } - else if (2 == dwLen && wzPath[1] == L':') - { - wzPath[2] = L'\\'; - wzPath[3] = 0; - } - - hr = ::StringCchCopyW(pss->wzDirectory, countof(pss->wzDirectory), wzPath); - ExitOnFailure(hr, "Failed to copy directory string to smb object"); - - hr = WcaGetRecordInteger(hRec, ssqPermissions, &pss->nPermissions); - ExitOnFailure(hr, "Failed to get Wix4FileShare.Permissions"); - - // Check to see if additional user & permissions are specified for this share - if (bUserPermissionsTableExists) - { - hr = ScaSmbExPermsRead(pss); - ExitOnFailure(hr, "Failed to get Additional File Share Permissions"); - } - - *ppssList = AddSmbToList(*ppssList, pss); - pss = NULL; // set the smb NULL so it doesn't accidentally get freed below - } - - if (E_NOMOREITEMS == hr) - { - hr = S_OK; - } - ExitOnFailure(hr, "Failure occured while processing Wix4FileShare table"); - -LExit: - // if anything was left over after an error clean it all up - if (pss) - { - ScaSmbFreeList(pss); - } - - ReleaseStr(pwzData); - - return hr; -} - - -/******************************************************************** - RetrieveSMBShareUserPermList - retrieve SMB Share's user permission list - -********************************************************************/ -HRESULT RetrieveFileShareUserPerm(SCA_SMB* pss, SCA_SMB_EX_USER_PERMS** ppExUserPermsList, DWORD *pUserPermsCount) -{ - HRESULT hr = S_OK; - SHARE_INFO_502* psi = NULL; - NET_API_STATUS s; - BOOL bValid, bDaclDefaulted; - PACL acl = NULL; - PEXPLICIT_ACCESSW pEA = NULL; - ULONG nCount = 0; - DWORD er = ERROR_SUCCESS; - PSID pSID = NULL; - DWORD nUserNameSize = MAX_DARWIN_COLUMN; - DWORD nDomainNameSize = MAX_DARWIN_COLUMN; - SID_NAME_USE peUse; - DWORD dwCounter = 0; - SCA_SMB_EX_USER_PERMS* pExUserPermsList = NULL; - DWORD dwUserPermsCount = 0; - - *pUserPermsCount = 0; - s = ::NetShareGetInfo(NULL, pss->wzShareName, 502, (LPBYTE*)&psi); - WcaLog(LOGMSG_VERBOSE, "retrieving permissions on existing file share."); - if (NERR_NetNameNotFound == s) - { - WcaLog(LOGMSG_VERBOSE, "File share has already been removed."); - ExitFunction1(hr = S_OK); - } - else if (NERR_Success != s || psi == NULL) - { - hr = E_FAIL; - ExitOnFailure(hr, "Failed to get share information with return code: %d", s); - } - if (!::GetSecurityDescriptorDacl(psi->shi502_security_descriptor, &bValid, &acl, &bDaclDefaulted) || !bValid) - { - ExitOnLastError(hr, "Failed to get acl from security descriptor"); - } - - er = ::GetExplicitEntriesFromAclW(acl, &nCount, &pEA); - hr = HRESULT_FROM_WIN32(er); - ExitOnFailure(hr, "Failed to get access entries from acl for file share %ls", pss->wzShareName); - for (dwCounter = 0; dwCounter < nCount; ++dwCounter) - { - if (TRUSTEE_IS_SID == pEA[dwCounter].Trustee.TrusteeForm) - { - SCA_SMB_EX_USER_PERMS* pExUserPerms = NewExUserPermsSmb(); - ::ZeroMemory(pExUserPerms, sizeof(*pExUserPerms)); - pExUserPermsList = AddExUserPermsSmbToList(pExUserPermsList, pExUserPerms); - pSID = (PSID)(pEA[dwCounter].Trustee.ptstrName); - if (!::LookupAccountSidW(NULL, pSID, pExUserPerms->scau.wzName, &nUserNameSize, pExUserPerms->scau.wzDomain, &nDomainNameSize, &peUse)) - { - hr = E_FAIL; - ExitOnFailure(hr, "Failed to get account name from SID"); - } - pExUserPerms->nPermissions = pEA[dwCounter].grfAccessPermissions; - pExUserPerms->accessMode = pEA[dwCounter].grfAccessMode; - ++dwUserPermsCount; - nUserNameSize = MAX_DARWIN_COLUMN; - nDomainNameSize = MAX_DARWIN_COLUMN; - } - } - *ppExUserPermsList = pExUserPermsList; - *pUserPermsCount = dwUserPermsCount; - -LExit: - if (psi) - { - ::NetApiBufferFree(psi); - } - - if (pEA) - { - ::LocalFree(pEA); - } - - return hr; -} - - -/******************************************************************** - SchedCreateSmb - schedule one instance of a file share creation - -********************************************************************/ -HRESULT SchedCreateSmb(SCA_SMB* pss) -{ - HRESULT hr = S_OK; - - WCHAR wzDomainUser[255]; // "domain\user" - SCA_SMB_EX_USER_PERMS* pExUserPermsList = NULL; - int nCounter = 0; - WCHAR* pwzRollbackCustomActionData = NULL; - WCHAR* pwzCustomActionData = NULL; - - hr = WcaWriteStringToCaData(pss->wzShareName, &pwzRollbackCustomActionData); - ExitOnFailure(hr, "failed to add ShareName to CustomActionData"); - - hr = WcaWriteStringToCaData(pss->wzShareName, &pwzCustomActionData); - ExitOnFailure(hr, "failed to add ShareName to CustomActionData"); - - hr = WcaWriteStringToCaData(pss->wzDescription, &pwzCustomActionData); - ExitOnFailure(hr, "Failed to add server name to CustomActionData"); - - hr = WcaWriteStringToCaData(pss->wzDirectory, &pwzCustomActionData); - ExitOnFailure(hr, "Failed to add full path instance to CustomActionData"); - - hr = WcaWriteStringToCaData(pss->fUseIntegratedAuth ? L"1" : L"0", &pwzCustomActionData); - ExitOnFailure(hr, "Failed to add server name to CustomActionData"); - - if (pss->fLegacyUserProvided) - { - hr = WcaWriteIntegerToCaData(pss->nUserPermissionCount + 1, &pwzCustomActionData); - ExitOnFailure(hr, "Failed to add additional user permission count to CustomActionData"); - - hr = UserBuildDomainUserName(wzDomainUser, countof(wzDomainUser), pss->scau.wzName, pss->scau.wzDomain); - ExitOnFailure(hr, "Failed to build user and domain name for CustomActionData"); - hr = WcaWriteStringToCaData(wzDomainUser, &pwzCustomActionData); - ExitOnFailure(hr, "Failed to add server Domain\\UserName to CustomActionData"); - - hr = WcaWriteIntegerToCaData(pss->nPermissions, &pwzCustomActionData); - ExitOnFailure(hr, "Failed to add permissions to CustomActionData"); - } - else - { - hr = WcaWriteIntegerToCaData(pss->nUserPermissionCount, &pwzCustomActionData); - ExitOnFailure(hr, "Failed to add additional user permission count to CustomActionData"); - } - - if (pss->nUserPermissionCount > 0) - { - nCounter = 0; - for (pExUserPermsList = pss->pExUserPerms; pExUserPermsList; pExUserPermsList = pExUserPermsList->pExUserPermsNext) - { - Assert(nCounter < pss->nUserPermissionCount); - - hr = UserBuildDomainUserName(wzDomainUser, countof(wzDomainUser), pExUserPermsList->scau.wzName, pExUserPermsList->scau.wzDomain); - ExitOnFailure(hr, "Failed to build user and domain name for CustomActionData"); - hr = WcaWriteStringToCaData(wzDomainUser, &pwzCustomActionData); - ExitOnFailure(hr, "Failed to add server Domain\\UserName to CustomActionData"); - - hr = WcaWriteIntegerToCaData((int)pExUserPermsList->accessMode, &pwzCustomActionData); - ExitOnFailure(hr, "Failed to add access mode to CustomActionData"); - - hr = WcaWriteIntegerToCaData(pExUserPermsList->nPermissions, &pwzCustomActionData); - ExitOnFailure(hr, "Failed to add permissions to CustomActionData"); - ++nCounter; - } - Assert(nCounter == pss->nUserPermissionCount); - } - - // Schedule the rollback first - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"CreateSmbRollback"), pwzRollbackCustomActionData, COST_SMB_DROPSMB); - ExitOnFailure(hr, "Failed to schedule DropSmb action"); - - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"CreateSmb"), pwzCustomActionData, COST_SMB_CREATESMB); - ExitOnFailure(hr, "Failed to schedule CreateSmb action"); - -LExit: - ReleaseStr(pwzRollbackCustomActionData); - ReleaseStr(pwzCustomActionData); - - if (pExUserPermsList) - { - ScaExUserPermsSmbFreeList(pExUserPermsList); - } - - return hr; -} - - -/******************************************************************** - ScaSmbInstall - for every file share, schedule the create custom action - -********************************************************************/ -HRESULT ScaSmbInstall(SCA_SMB* pssList) -{ - HRESULT hr = S_FALSE; // assume nothing will be done - SCA_SMB* pss = NULL; - - for (pss = pssList; pss; pss = pss->pssNext) - { - // if installing this component - if (WcaIsInstalling(pss->isInstalled, pss->isAction) ) - { - hr = SchedCreateSmb(pss); - ExitOnFailure(hr, "Failed to schedule the creation of the fileshare: %ls", pss->wzShareName); - } - } - -LExit: - return hr; -} - - -/******************************************************************** - SchedDropSmb - schedule one instance of a file share removal - -********************************************************************/ -HRESULT SchedDropSmb(SCA_SMB* pss) -{ - HRESULT hr = S_OK; - - WCHAR* pwzCustomActionData = NULL; - WCHAR* pwzRollbackCustomActionData = NULL; - SCA_SMB_EX_USER_PERMS *pExUserPermsList = NULL; - SCA_SMB_EX_USER_PERMS *pExUserPerm = NULL; - WCHAR wzDomainUser[255]; // "domain\user" - DWORD dwUserPermsCount = 0; - - // roll back DropSmb - hr = WcaWriteStringToCaData(pss->wzShareName, &pwzRollbackCustomActionData); - ExitOnFailure(hr, "failed to add ShareName to CustomActionData"); - - hr = WcaWriteStringToCaData(pss->wzDescription, &pwzRollbackCustomActionData); - ExitOnFailure(hr, "Failed to add server name to CustomActionData"); - - hr = WcaWriteStringToCaData(pss->wzDirectory, &pwzRollbackCustomActionData); - ExitOnFailure(hr, "Failed to add full path instance to CustomActionData"); - - hr = WcaWriteStringToCaData(L"1", &pwzRollbackCustomActionData); - ExitOnFailure(hr, "Failed to add useintegrated flag to CustomActionData"); - - hr = RetrieveFileShareUserPerm(pss, &pExUserPermsList, &dwUserPermsCount); - ExitOnFailure(hr, "Failed to retrieve SMBShare's user permissions"); - - hr = WcaWriteIntegerToCaData((int)dwUserPermsCount, &pwzRollbackCustomActionData); - ExitOnFailure(hr, "Failed to add additional user permission count to CustomActionData"); - - for (pExUserPerm = pExUserPermsList; pExUserPerm; pExUserPerm = pExUserPerm->pExUserPermsNext) - { - hr = UserBuildDomainUserName(wzDomainUser, countof(wzDomainUser), pExUserPerm->scau.wzName, pExUserPerm->scau.wzDomain); - ExitOnFailure(hr, "Failed to build user and domain name for CustomActionData"); - hr = WcaWriteStringToCaData(wzDomainUser, &pwzRollbackCustomActionData); - ExitOnFailure(hr, "Failed to add server Domain\\UserName to CustomActionData"); - - hr = WcaWriteIntegerToCaData((int)pExUserPerm->accessMode, &pwzRollbackCustomActionData); - ExitOnFailure(hr, "Failed to add access mode to CustomActionData"); - - hr = WcaWriteIntegerToCaData(pExUserPerm->nPermissions, &pwzRollbackCustomActionData); - ExitOnFailure(hr, "Failed to add permissions to CustomActionData"); - } - - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"DropSmbRollback"), pwzRollbackCustomActionData, COST_SMB_CREATESMB); - ExitOnFailure(hr, "Failed to schedule DropSmbRollback action"); - - // DropSMB - hr = WcaWriteStringToCaData(pss->wzShareName, &pwzCustomActionData); - ExitOnFailure(hr, "failed to add ShareName to CustomActionData"); - - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"DropSmb"), pwzCustomActionData, COST_SMB_DROPSMB); - ExitOnFailure(hr, "Failed to schedule DropSmb action"); - -LExit: - ReleaseStr(pwzCustomActionData); - - if (pExUserPermsList) - { - ScaExUserPermsSmbFreeList(pExUserPermsList); - } - - return hr; - -} - - -/******************************************************************** - ScaSmbUninstall - for every file share, schedule the drop custom action - -********************************************************************/ -HRESULT ScaSmbUninstall(SCA_SMB* pssList) -{ - HRESULT hr = S_FALSE; // assume nothing will be done - SCA_SMB* pss = NULL; - - for (pss = pssList; pss; pss = pss->pssNext) - { - // if uninstalling this component - if (WcaIsUninstalling(pss->isInstalled, pss->isAction) ) - { - hr = SchedDropSmb(pss); - ExitOnFailure(hr, "Failed to remove file share %ls", pss->wzShareName); - } - } - -LExit: - return hr; -} - -LPCWSTR vcsSmbExUserPermsQuery = L"SELECT `FileShare_`,`User_`,`Permissions` " - L"FROM `Wix4FileSharePermissions` WHERE `FileShare_`=?"; - -enum eSmbUserPermsQuery { - ssupqFileShare = 1, - ssupqUser, - ssupqPermissions - -}; - - -/******************************************************************** - ScaSmbExPermsRead - for Every entry in File Permissions table add a - User Name & Permissions structure to the List - -********************************************************************/ -HRESULT ScaSmbExPermsRead(SCA_SMB* pss) -{ - HRESULT hr = S_OK; - PMSIHANDLE hView, hRec; - - LPWSTR pwzData = NULL; - SCA_SMB_EX_USER_PERMS* pExUserPermsList = pss->pExUserPerms; - SCA_SMB_EX_USER_PERMS* pExUserPerms = NULL; - int nCounter = 0; - - hRec = ::MsiCreateRecord(1); - hr = WcaSetRecordString(hRec, 1, pss->wzId); - ExitOnFailure(hr, "Failed to look up FileShare"); - - hr = WcaOpenView(vcsSmbExUserPermsQuery, &hView); - ExitOnFailure(hr, "Failed to open view on Wix4FileSharePermissions table"); - hr = WcaExecuteView(hView, hRec); - ExitOnFailure(hr, "Failed to execute view on Wix4FileSharePermissions table"); - - // loop through all User/Permissions paris returned - while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) - { - pExUserPerms = NewExUserPermsSmb(); - if (!pExUserPerms) - { - hr = E_OUTOFMEMORY; - break; - } - Assert(pExUserPerms); - ::ZeroMemory(pExUserPerms, sizeof(*pExUserPerms)); - - hr = WcaGetRecordString(hRec, ssupqUser, &pwzData); - ExitOnFailure(hr, "Failed to get Wix4FileSharePermissions.User"); - hr = ScaGetUser(pwzData, &pExUserPerms->scau); - ExitOnFailure(hr, "Failed to get user information for fileshare: '%ls'", pss->wzShareName); - - hr = WcaGetRecordInteger(hRec, ssupqPermissions, &pExUserPerms->nPermissions); - ExitOnFailure(hr, "Failed to get Wix4FileSharePermissions.Permissions"); - pExUserPerms->accessMode = SET_ACCESS; // we only support SET_ACCESS here - - pExUserPermsList = AddExUserPermsSmbToList(pExUserPermsList, pExUserPerms); - ++nCounter; - pExUserPerms = NULL; // set the smb NULL so it doesn't accidentally get freed below - } - - if (E_NOMOREITEMS == hr) - { - hr = S_OK; - pss->pExUserPerms = pExUserPermsList; - pss->nUserPermissionCount = nCounter; - } - ExitOnFailure(hr, "Failure occured while processing FileShare table"); - -LExit: - // if anything was left over after an error clean it all up - if (pExUserPerms) - { - ScaExUserPermsSmbFreeList(pExUserPerms); - } - - ReleaseStr(pwzData); - - return hr; -} diff --git a/src/ca/scauser.cpp b/src/ca/scauser.cpp deleted file mode 100644 index b25e9daf..00000000 --- a/src/ca/scauser.cpp +++ /dev/null @@ -1,709 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" - -LPCWSTR vcsUserQuery = L"SELECT `Wix4User`, `Component_`, `Name`, `Domain`, `Password` FROM `Wix4User` WHERE `Wix4User`=?"; -enum eUserQuery { vuqUser = 1, vuqComponent, vuqName, vuqDomain, vuqPassword }; - -LPCWSTR vcsGroupQuery = L"SELECT `Wix4Group`, `Component_`, `Name`, `Domain` FROM `Wix4Group` WHERE `Wix4Group`=?"; -enum eGroupQuery { vgqGroup = 1, vgqComponent, vgqName, vgqDomain }; - -LPCWSTR vcsUserGroupQuery = L"SELECT `Wix4User_`, `Wix4Group_` FROM `Wix4UserGroup` WHERE `Wix4User_`=?"; -enum eUserGroupQuery { vugqUser = 1, vugqGroup }; - -LPCWSTR vActionableQuery = L"SELECT `Wix4User`,`Component_`,`Name`,`Domain`,`Password`,`Attributes` FROM `Wix4User` WHERE `Component_` IS NOT NULL"; -enum eActionableQuery { vaqUser = 1, vaqComponent, vaqName, vaqDomain, vaqPassword, vaqAttributes }; - - -static HRESULT AddUserToList( - __inout SCA_USER** ppsuList - ); - -static HRESULT AddGroupToList( - __inout SCA_GROUP** ppsgList - ); - - -HRESULT __stdcall ScaGetUser( - __in LPCWSTR wzUser, - __out SCA_USER* pscau - ) -{ - if (!wzUser || !pscau) - { - return E_INVALIDARG; - } - - HRESULT hr = S_OK; - PMSIHANDLE hView, hRec; - - LPWSTR pwzData = NULL; - - // clear struct and bail right away if no user key was passed to search for - ::ZeroMemory(pscau, sizeof(*pscau)); - if (!*wzUser) - { - ExitFunction1(hr = S_OK); - } - - hRec = ::MsiCreateRecord(1); - hr = WcaSetRecordString(hRec, 1, wzUser); - ExitOnFailure(hr, "Failed to look up User"); - - hr = WcaOpenView(vcsUserQuery, &hView); - ExitOnFailure(hr, "Failed to open view on Wix4User table"); - hr = WcaExecuteView(hView, hRec); - ExitOnFailure(hr, "Failed to execute view on Wix4User table"); - - hr = WcaFetchSingleRecord(hView, &hRec); - if (S_OK == hr) - { - hr = WcaGetRecordString(hRec, vuqUser, &pwzData); - ExitOnFailure(hr, "Failed to get Wix4User.User"); - hr = ::StringCchCopyW(pscau->wzKey, countof(pscau->wzKey), pwzData); - ExitOnFailure(hr, "Failed to copy key string to user object"); - - hr = WcaGetRecordString(hRec, vuqComponent, &pwzData); - ExitOnFailure(hr, "Failed to get Wix4User.Component_"); - hr = ::StringCchCopyW(pscau->wzComponent, countof(pscau->wzComponent), pwzData); - ExitOnFailure(hr, "Failed to copy component string to user object"); - - hr = WcaGetRecordFormattedString(hRec, vuqName, &pwzData); - ExitOnFailure(hr, "Failed to get Wix4User.Name"); - hr = ::StringCchCopyW(pscau->wzName, countof(pscau->wzName), pwzData); - ExitOnFailure(hr, "Failed to copy name string to user object"); - - hr = WcaGetRecordFormattedString(hRec, vuqDomain, &pwzData); - ExitOnFailure(hr, "Failed to get Wix4User.Domain"); - hr = ::StringCchCopyW(pscau->wzDomain, countof(pscau->wzDomain), pwzData); - ExitOnFailure(hr, "Failed to copy domain string to user object"); - - hr = WcaGetRecordFormattedString(hRec, vuqPassword, &pwzData); - ExitOnFailure(hr, "Failed to get Wix4User.Password"); - hr = ::StringCchCopyW(pscau->wzPassword, countof(pscau->wzPassword), pwzData); - ExitOnFailure(hr, "Failed to copy password string to user object"); - } - else if (E_NOMOREITEMS == hr) - { - WcaLog(LOGMSG_STANDARD, "Error: Cannot locate Wix4User.User='%ls'", wzUser); - hr = E_FAIL; - } - else - { - ExitOnFailure(hr, "Error or found multiple matching Wix4User rows"); - } - -LExit: - ReleaseStr(pwzData); - - return hr; -} - -HRESULT __stdcall ScaGetUserDeferred( - __in LPCWSTR wzUser, - __in WCA_WRAPQUERY_HANDLE hUserQuery, - __out SCA_USER* pscau - ) -{ - if (!wzUser || !pscau) - { - return E_INVALIDARG; - } - - HRESULT hr = S_OK; - MSIHANDLE hRec, hRecTest; - - LPWSTR pwzData = NULL; - - // clear struct and bail right away if no user key was passed to search for - ::ZeroMemory(pscau, sizeof(*pscau)); - if (!*wzUser) - { - ExitFunction1(hr = S_OK); - } - - // Reset back to the first record - WcaFetchWrappedReset(hUserQuery); - - hr = WcaFetchWrappedRecordWhereString(hUserQuery, vuqUser, wzUser, &hRec); - if (S_OK == hr) - { - hr = WcaFetchWrappedRecordWhereString(hUserQuery, vuqUser, wzUser, &hRecTest); - if (S_OK == hr) - { - AssertSz(FALSE, "Found multiple matching Wix4User rows"); - } - - hr = WcaGetRecordString(hRec, vuqUser, &pwzData); - ExitOnFailure(hr, "Failed to get Wix4User.User"); - hr = ::StringCchCopyW(pscau->wzKey, countof(pscau->wzKey), pwzData); - ExitOnFailure(hr, "Failed to copy key string to user object (in deferred CA)"); - - hr = WcaGetRecordString(hRec, vuqComponent, &pwzData); - ExitOnFailure(hr, "Failed to get Wix4User.Component_"); - hr = ::StringCchCopyW(pscau->wzComponent, countof(pscau->wzComponent), pwzData); - ExitOnFailure(hr, "Failed to copy component string to user object (in deferred CA)"); - - hr = WcaGetRecordString(hRec, vuqName, &pwzData); - ExitOnFailure(hr, "Failed to get Wix4User.Name"); - hr = ::StringCchCopyW(pscau->wzName, countof(pscau->wzName), pwzData); - ExitOnFailure(hr, "Failed to copy name string to user object (in deferred CA)"); - - hr = WcaGetRecordString(hRec, vuqDomain, &pwzData); - ExitOnFailure(hr, "Failed to get Wix4User.Domain"); - hr = ::StringCchCopyW(pscau->wzDomain, countof(pscau->wzDomain), pwzData); - ExitOnFailure(hr, "Failed to copy domain string to user object (in deferred CA)"); - - hr = WcaGetRecordString(hRec, vuqPassword, &pwzData); - ExitOnFailure(hr, "Failed to get Wix4User.Password"); - hr = ::StringCchCopyW(pscau->wzPassword, countof(pscau->wzPassword), pwzData); - ExitOnFailure(hr, "Failed to copy password string to user object (in deferred CA)"); - } - else if (E_NOMOREITEMS == hr) - { - WcaLog(LOGMSG_STANDARD, "Error: Cannot locate Wix4User.User='%ls'", wzUser); - hr = E_FAIL; - } - else - { - ExitOnFailure(hr, "Error fetching single Wix4User row"); - } - -LExit: - ReleaseStr(pwzData); - - return hr; -} - - -HRESULT __stdcall ScaGetGroup( - __in LPCWSTR wzGroup, - __out SCA_GROUP* pscag - ) -{ - if (!wzGroup || !pscag) - { - return E_INVALIDARG; - } - - HRESULT hr = S_OK; - PMSIHANDLE hView, hRec; - - LPWSTR pwzData = NULL; - - hRec = ::MsiCreateRecord(1); - hr = WcaSetRecordString(hRec, 1, wzGroup); - ExitOnFailure(hr, "Failed to look up Group"); - - hr = WcaOpenView(vcsGroupQuery, &hView); - ExitOnFailure(hr, "Failed to open view on Wix4Group table"); - hr = WcaExecuteView(hView, hRec); - ExitOnFailure(hr, "Failed to execute view on Wix4Group table"); - - hr = WcaFetchSingleRecord(hView, &hRec); - if (S_OK == hr) - { - hr = WcaGetRecordString(hRec, vgqGroup, &pwzData); - ExitOnFailure(hr, "Failed to get Wix4Group.Wix4Group."); - hr = ::StringCchCopyW(pscag->wzKey, countof(pscag->wzKey), pwzData); - ExitOnFailure(hr, "Failed to copy Wix4Group.Wix4Group."); - - hr = WcaGetRecordString(hRec, vgqComponent, &pwzData); - ExitOnFailure(hr, "Failed to get Wix4Group.Component_"); - hr = ::StringCchCopyW(pscag->wzComponent, countof(pscag->wzComponent), pwzData); - ExitOnFailure(hr, "Failed to copy Wix4Group.Component_."); - - hr = WcaGetRecordFormattedString(hRec, vgqName, &pwzData); - ExitOnFailure(hr, "Failed to get Wix4Group.Name"); - hr = ::StringCchCopyW(pscag->wzName, countof(pscag->wzName), pwzData); - ExitOnFailure(hr, "Failed to copy Wix4Group.Name."); - - hr = WcaGetRecordFormattedString(hRec, vgqDomain, &pwzData); - ExitOnFailure(hr, "Failed to get Wix4Group.Domain"); - hr = ::StringCchCopyW(pscag->wzDomain, countof(pscag->wzDomain), pwzData); - ExitOnFailure(hr, "Failed to copy Wix4Group.Domain."); - } - else if (E_NOMOREITEMS == hr) - { - WcaLog(LOGMSG_STANDARD, "Error: Cannot locate Wix4Group.Wix4Group='%ls'", wzGroup); - hr = E_FAIL; - } - else - { - ExitOnFailure(hr, "Error or found multiple matching Wix4Group rows"); - } - -LExit: - ReleaseStr(pwzData); - - return hr; -} - - -void ScaUserFreeList( - __in SCA_USER* psuList - ) -{ - SCA_USER* psuDelete = psuList; - while (psuList) - { - psuDelete = psuList; - psuList = psuList->psuNext; - - ScaGroupFreeList(psuDelete->psgGroups); - MemFree(psuDelete); - } -} - - -void ScaGroupFreeList( - __in SCA_GROUP* psgList - ) -{ - SCA_GROUP* psgDelete = psgList; - while (psgList) - { - psgDelete = psgList; - psgList = psgList->psgNext; - - MemFree(psgDelete); - } -} - - -HRESULT ScaUserRead( - __out SCA_USER** ppsuList - ) -{ - //Assert(FALSE); - Assert(ppsuList); - - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - PMSIHANDLE hView, hRec, hUserRec, hUserGroupView; - - LPWSTR pwzData = NULL; - - BOOL fUserGroupExists = FALSE; - - SCA_USER *psu = NULL; - - INSTALLSTATE isInstalled, isAction; - - if (S_OK != WcaTableExists(L"Wix4User")) - { - WcaLog(LOGMSG_VERBOSE, "Wix4User Table does not exist, exiting"); - ExitFunction1(hr = S_FALSE); - } - - if (S_OK == WcaTableExists(L"Wix4UserGroup")) - { - fUserGroupExists = TRUE; - } - - // - // loop through all the users - // - hr = WcaOpenExecuteView(vActionableQuery, &hView); - ExitOnFailure(hr, "failed to open view on Wix4User table"); - while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) - { - hr = WcaGetRecordString(hRec, vaqComponent, &pwzData); - ExitOnFailure(hr, "failed to get Wix4User.Component"); - - er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &isInstalled, &isAction); - hr = HRESULT_FROM_WIN32(er); - ExitOnFailure(hr, "failed to get Component state for Wix4User"); - - // don't bother if we aren't installing or uninstalling this component - if (WcaIsInstalling(isInstalled, isAction) || WcaIsUninstalling(isInstalled, isAction)) - { - // - // Add the user to the list and populate it's values - // - hr = AddUserToList(ppsuList); - ExitOnFailure(hr, "failed to add user to list"); - - psu = *ppsuList; - - psu->isInstalled = isInstalled; - psu->isAction = isAction; - hr = ::StringCchCopyW(psu->wzComponent, countof(psu->wzComponent), pwzData); - ExitOnFailure(hr, "failed to copy component name: %ls", pwzData); - - hr = WcaGetRecordString(hRec, vaqUser, &pwzData); - ExitOnFailure(hr, "failed to get Wix4User.User"); - hr = ::StringCchCopyW(psu->wzKey, countof(psu->wzKey), pwzData); - ExitOnFailure(hr, "failed to copy user key: %ls", pwzData); - - hr = WcaGetRecordFormattedString(hRec, vaqName, &pwzData); - ExitOnFailure(hr, "failed to get Wix4User.Name"); - hr = ::StringCchCopyW(psu->wzName, countof(psu->wzName), pwzData); - ExitOnFailure(hr, "failed to copy user name: %ls", pwzData); - - hr = WcaGetRecordFormattedString(hRec, vaqDomain, &pwzData); - ExitOnFailure(hr, "failed to get Wix4User.Domain"); - hr = ::StringCchCopyW(psu->wzDomain, countof(psu->wzDomain), pwzData); - ExitOnFailure(hr, "failed to copy user domain: %ls", pwzData); - - hr = WcaGetRecordFormattedString(hRec, vaqPassword, &pwzData); - ExitOnFailure(hr, "failed to get Wix4User.Password"); - hr = ::StringCchCopyW(psu->wzPassword, countof(psu->wzPassword), pwzData); - ExitOnFailure(hr, "failed to copy user password"); - - hr = WcaGetRecordInteger(hRec, vaqAttributes, &psu->iAttributes); - ExitOnFailure(hr, "failed to get Wix4User.Attributes"); - - // Check if this user is to be added to any groups - if (fUserGroupExists) - { - hUserRec = ::MsiCreateRecord(1); - hr = WcaSetRecordString(hUserRec, 1, psu->wzKey); - ExitOnFailure(hr, "Failed to create user record for querying Wix4UserGroup table"); - - hr = WcaOpenView(vcsUserGroupQuery, &hUserGroupView); - ExitOnFailure(hr, "Failed to open view on Wix4UserGroup table for user %ls", psu->wzKey); - hr = WcaExecuteView(hUserGroupView, hUserRec); - ExitOnFailure(hr, "Failed to execute view on Wix4UserGroup table for user: %ls", psu->wzKey); - - while (S_OK == (hr = WcaFetchRecord(hUserGroupView, &hRec))) - { - hr = WcaGetRecordString(hRec, vugqGroup, &pwzData); - ExitOnFailure(hr, "failed to get Wix4UserGroup.Group"); - - hr = AddGroupToList(&(psu->psgGroups)); - ExitOnFailure(hr, "failed to add group to list"); - - hr = ScaGetGroup(pwzData, psu->psgGroups); - ExitOnFailure(hr, "failed to get information for group: %ls", pwzData); - } - - if (E_NOMOREITEMS == hr) - { - hr = S_OK; - } - ExitOnFailure(hr, "failed to enumerate selected rows from Wix4UserGroup table"); - } - } - } - - if (E_NOMOREITEMS == hr) - { - hr = S_OK; - } - ExitOnFailure(hr, "failed to enumerate selected rows from Wix4User table"); - -LExit: - ReleaseStr(pwzData); - - return hr; -} - - -static HRESULT WriteGroupInfo( - __in SCA_GROUP* psgList, - __in LPWSTR *ppwzActionData - ) -{ - HRESULT hr = S_OK; - - for (SCA_GROUP* psg = psgList; psg; psg = psg->psgNext) - { - hr = WcaWriteStringToCaData(psg->wzName, ppwzActionData); - ExitOnFailure(hr, "failed to add group name to custom action data: %ls", psg->wzName); - - hr = WcaWriteStringToCaData(psg->wzDomain, ppwzActionData); - ExitOnFailure(hr, "failed to add group domain to custom action data: %ls", psg->wzDomain); - } - -LExit: - return hr; -} - - -// Behaves like WriteGroupInfo, but it filters out groups the user is currently a member of, -// because we don't want to rollback those -static HRESULT WriteGroupRollbackInfo( - __in LPCWSTR pwzName, - __in LPCWSTR pwzDomain, - __in SCA_GROUP* psgList, - __in LPWSTR *ppwzActionData - ) -{ - HRESULT hr = S_OK; - BOOL fIsMember = FALSE; - - for (SCA_GROUP* psg = psgList; psg; psg = psg->psgNext) - { - hr = UserCheckIsMember(pwzName, pwzDomain, psg->wzName, psg->wzDomain, &fIsMember); - if (FAILED(hr)) - { - 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); - hr = S_OK; - continue; - } - - // If the user is currently a member, we don't want to undo that on rollback, so skip adding - // this group record to the list of groups to rollback - if (fIsMember) - { - continue; - } - - hr = WcaWriteStringToCaData(psg->wzName, ppwzActionData); - ExitOnFailure(hr, "failed to add group name to custom action data: %ls", psg->wzName); - - hr = WcaWriteStringToCaData(psg->wzDomain, ppwzActionData); - ExitOnFailure(hr, "failed to add group domain to custom action data: %ls", psg->wzDomain); - } - -LExit: - return hr; -} - - -/* **************************************************************** -ScaUserExecute - Schedules user account creation or removal based on -component state. - -******************************************************************/ -HRESULT ScaUserExecute( - __in SCA_USER *psuList - ) -{ - HRESULT hr = S_OK; - DWORD er = 0; - PDOMAIN_CONTROLLER_INFOW pDomainControllerInfo = NULL; - - LPWSTR pwzBaseScriptKey = NULL; - DWORD cScriptKey = 0; - - USER_INFO_0 *pUserInfo = NULL; - LPWSTR pwzScriptKey = NULL; - LPWSTR pwzActionData = NULL; - LPWSTR pwzRollbackData = NULL; - - // Get the base script key for this CustomAction. - hr = WcaCaScriptCreateKey(&pwzBaseScriptKey); - ExitOnFailure(hr, "Failed to get encoding key."); - - // Loop through all the users to be configured. - for (SCA_USER *psu = psuList; psu; psu = psu->psuNext) - { - USER_EXISTS ueUserExists = USER_EXISTS_INDETERMINATE; - - // Always put the User Name and Domain plus Attributes on the front of the CustomAction - // data. Sometimes we'll add more data. - Assert(psu->wzName); - hr = WcaWriteStringToCaData(psu->wzName, &pwzActionData); - ExitOnFailure(hr, "Failed to add user name to custom action data: %ls", psu->wzName); - hr = WcaWriteStringToCaData(psu->wzDomain, &pwzActionData); - ExitOnFailure(hr, "Failed to add user domain to custom action data: %ls", psu->wzDomain); - hr = WcaWriteIntegerToCaData(psu->iAttributes, &pwzActionData); - ExitOnFailure(hr, "failed to add user attributes to custom action data for user: %ls", psu->wzKey); - - // Check to see if the user already exists since we have to be very careful when adding - // and removing users. Note: MSDN says that it is safe to call these APIs from any - // user, so we should be safe calling it during immediate mode. - er = ::NetApiBufferAllocate(sizeof(USER_INFO_0), reinterpret_cast(&pUserInfo)); - hr = HRESULT_FROM_WIN32(er); - ExitOnFailure(hr, "Failed to allocate memory to check existence of user: %ls", psu->wzName); - - LPCWSTR wzDomain = psu->wzDomain; - if (wzDomain && *wzDomain) - { - er = ::DsGetDcNameW(NULL, wzDomain, NULL, NULL, NULL, &pDomainControllerInfo); - if (RPC_S_SERVER_UNAVAILABLE == er) - { - // MSDN says, if we get the above error code, try again with the "DS_FORCE_REDISCOVERY" flag - er = ::DsGetDcNameW(NULL, wzDomain, NULL, NULL, DS_FORCE_REDISCOVERY, &pDomainControllerInfo); - } - if (ERROR_SUCCESS == er) - { - wzDomain = pDomainControllerInfo->DomainControllerName + 2; //Add 2 so that we don't get the \\ prefix - } - } - - er = ::NetUserGetInfo(wzDomain, psu->wzName, 0, reinterpret_cast(pUserInfo)); - if (NERR_Success == er) - { - ueUserExists = USER_EXISTS_YES; - } - else if (NERR_UserNotFound == er) - { - ueUserExists = USER_EXISTS_NO; - } - else - { - ueUserExists = USER_EXISTS_INDETERMINATE; - hr = HRESULT_FROM_WIN32(er); - WcaLog(LOGMSG_VERBOSE, "Failed to check existence of domain: %ls, user: %ls (error code 0x%x) - continuing", wzDomain, psu->wzName, hr); - hr = S_OK; - er = ERROR_SUCCESS; - } - - if (WcaIsInstalling(psu->isInstalled, psu->isAction)) - { - // If the user exists, check to see if we are supposed to fail if user the exists before - // the install. - if (USER_EXISTS_YES == ueUserExists) - { - // Reinstalls will always fail if we don't remove the check for "fail if exists". - if (WcaIsReInstalling(psu->isInstalled, psu->isAction)) - { - psu->iAttributes &= ~SCAU_FAIL_IF_EXISTS; - } - - if ((SCAU_FAIL_IF_EXISTS & (psu->iAttributes)) && !(SCAU_UPDATE_IF_EXISTS & (psu->iAttributes))) - { - hr = HRESULT_FROM_WIN32(NERR_UserExists); - MessageExitOnFailure(hr, msierrUSRFailedUserCreateExists, "Failed to create user: %ls because user already exists.", psu->wzName); - } - } - - // Rollback only if the user already exists, we couldn't determine if the user exists, or we are going to create the user - if ((USER_EXISTS_YES == ueUserExists) || (USER_EXISTS_INDETERMINATE == ueUserExists) || !(psu->iAttributes & SCAU_DONT_CREATE_USER)) - { - ++cScriptKey; - hr = StrAllocFormatted(&pwzScriptKey, L"%ls%u", pwzBaseScriptKey, cScriptKey); - ExitOnFailure(hr, "Failed to create encoding key."); - - // Write the script key to CustomActionData for install and rollback so information can be passed to rollback. - hr = WcaWriteStringToCaData(pwzScriptKey, &pwzActionData); - ExitOnFailure(hr, "Failed to add encoding key to custom action data."); - - hr = WcaWriteStringToCaData(pwzScriptKey, &pwzRollbackData); - ExitOnFailure(hr, "Failed to add encoding key to rollback custom action data."); - - INT iRollbackUserAttributes = psu->iAttributes; - - // If the user already exists, ensure this is accounted for in rollback - if (USER_EXISTS_YES == ueUserExists) - { - iRollbackUserAttributes |= SCAU_DONT_CREATE_USER; - } - else - { - iRollbackUserAttributes &= ~SCAU_DONT_CREATE_USER; - } - - // The deferred CA determines when to rollback User Rights Assignments so these should never be set. - iRollbackUserAttributes &= ~SCAU_ALLOW_LOGON_AS_SERVICE; - iRollbackUserAttributes &= ~SCAU_ALLOW_LOGON_AS_BATCH; - - hr = WcaWriteStringToCaData(psu->wzName, &pwzRollbackData); - ExitOnFailure(hr, "Failed to add user name to rollback custom action data: %ls", psu->wzName); - hr = WcaWriteStringToCaData(psu->wzDomain, &pwzRollbackData); - ExitOnFailure(hr, "Failed to add user domain to rollback custom action data: %ls", psu->wzDomain); - hr = WcaWriteIntegerToCaData(iRollbackUserAttributes, &pwzRollbackData); - ExitOnFailure(hr, "failed to add user attributes to rollback custom action data for user: %ls", psu->wzKey); - - // If the user already exists, add relevant group information to rollback data - if (USER_EXISTS_YES == ueUserExists || USER_EXISTS_INDETERMINATE == ueUserExists) - { - hr = WriteGroupRollbackInfo(psu->wzName, psu->wzDomain, psu->psgGroups, &pwzRollbackData); - ExitOnFailure(hr, "failed to add group information to rollback custom action data"); - } - - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"CreateUserRollback"), pwzRollbackData, COST_USER_DELETE); - ExitOnFailure(hr, "failed to schedule CreateUserRollback"); - } - else - { - // Write empty script key to CustomActionData since there is no rollback. - hr = WcaWriteStringToCaData(L"", &pwzActionData); - ExitOnFailure(hr, "Failed to add empty encoding key to custom action data."); - } - - // - // Schedule the creation now. - // - hr = WcaWriteStringToCaData(psu->wzPassword, &pwzActionData); - ExitOnFailure(hr, "failed to add user password to custom action data for user: %ls", psu->wzKey); - - // Add user's group information to custom action data - hr = WriteGroupInfo(psu->psgGroups, &pwzActionData); - ExitOnFailure(hr, "failed to add group information to custom action data"); - - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"CreateUser"), pwzActionData, COST_USER_ADD); - ExitOnFailure(hr, "failed to schedule CreateUser"); - } - else if (((USER_EXISTS_YES == ueUserExists) || (USER_EXISTS_INDETERMINATE == ueUserExists)) && WcaIsUninstalling(psu->isInstalled, psu->isAction) && !(psu->iAttributes & SCAU_DONT_REMOVE_ON_UNINSTALL)) - { - // 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 - hr = WriteGroupInfo(psu->psgGroups, &pwzActionData); - ExitOnFailure(hr, "failed to add group information to custom action data"); - - // - // Schedule the removal because the user exists and we don't have any flags set - // that say, don't remove the user on uninstall. - // - // Note: We can't rollback the removal of a user which is why RemoveUser is a commit - // CustomAction. - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RemoveUser"), pwzActionData, COST_USER_DELETE); - ExitOnFailure(hr, "failed to schedule RemoveUser"); - } - - ReleaseNullStr(pwzScriptKey); - ReleaseNullStr(pwzActionData); - ReleaseNullStr(pwzRollbackData); - if (pUserInfo) - { - ::NetApiBufferFree(static_cast(pUserInfo)); - pUserInfo = NULL; - } - if (pDomainControllerInfo) - { - ::NetApiBufferFree(static_cast(pDomainControllerInfo)); - pDomainControllerInfo = NULL; - } - } - -LExit: - ReleaseStr(pwzBaseScriptKey); - ReleaseStr(pwzScriptKey); - ReleaseStr(pwzActionData); - ReleaseStr(pwzRollbackData); - if (pUserInfo) - { - ::NetApiBufferFree(static_cast(pUserInfo)); - } - if (pDomainControllerInfo) - { - ::NetApiBufferFree(static_cast(pDomainControllerInfo)); - } - - return hr; -} - - -static HRESULT AddUserToList( - __inout SCA_USER** ppsuList - ) -{ - HRESULT hr = S_OK; - SCA_USER* psu = static_cast(MemAlloc(sizeof(SCA_USER), TRUE)); - ExitOnNull(psu, hr, E_OUTOFMEMORY, "failed to allocate memory for new user list element"); - - psu->psuNext = *ppsuList; - *ppsuList = psu; - -LExit: - return hr; -} - - -static HRESULT AddGroupToList( - __inout SCA_GROUP** ppsgList - ) -{ - HRESULT hr = S_OK; - SCA_GROUP* psg = static_cast(MemAlloc(sizeof(SCA_GROUP), TRUE)); - ExitOnNull(psg, hr, E_OUTOFMEMORY, "failed to allocate memory for new group list element"); - - psg->psgNext = *ppsgList; - *ppsgList = psg; - -LExit: - return hr; -} diff --git a/src/ca/scauser.h b/src/ca/scauser.h deleted file mode 100644 index a5fd5ea8..00000000 --- a/src/ca/scauser.h +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - - -enum USER_EXISTS -{ - USER_EXISTS_YES, - USER_EXISTS_NO, - USER_EXISTS_INDETERMINATE -}; - -// structs -struct SCA_GROUP -{ - WCHAR wzKey[MAX_DARWIN_KEY + 1]; - WCHAR wzComponent[MAX_DARWIN_KEY + 1]; - - WCHAR wzDomain[MAX_DARWIN_COLUMN + 1]; - WCHAR wzName[MAX_DARWIN_COLUMN + 1]; - - SCA_GROUP *psgNext; -}; - -struct SCA_USER -{ - WCHAR wzKey[MAX_DARWIN_KEY + 1]; - WCHAR wzComponent[MAX_DARWIN_KEY + 1]; - INSTALLSTATE isInstalled; - INSTALLSTATE isAction; - - WCHAR wzDomain[MAX_DARWIN_COLUMN + 1]; - WCHAR wzName[MAX_DARWIN_COLUMN + 1]; - WCHAR wzPassword[MAX_DARWIN_COLUMN + 1]; - INT iAttributes; - - SCA_GROUP *psgGroups; - - SCA_USER *psuNext; -}; - - -// prototypes -HRESULT __stdcall ScaGetUser( - __in LPCWSTR wzUser, - __out SCA_USER* pscau - ); -HRESULT __stdcall ScaGetUserDeferred( - __in LPCWSTR wzUser, - __in WCA_WRAPQUERY_HANDLE hUserQuery, - __out SCA_USER* pscau - ); -HRESULT __stdcall ScaGetGroup( - __in LPCWSTR wzGroup, - __out SCA_GROUP* pscag - ); -void ScaUserFreeList( - __in SCA_USER* psuList - ); -void ScaGroupFreeList( - __in SCA_GROUP* psgList - ); -HRESULT ScaUserRead( - __inout SCA_USER** ppsuList - ); -HRESULT ScaUserExecute( - __in SCA_USER *psuList - ); diff --git a/src/ca/secureobj.cpp b/src/ca/secureobj.cpp deleted file mode 100644 index 72842eb5..00000000 --- a/src/ca/secureobj.cpp +++ /dev/null @@ -1,915 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" - -// structs -LPCWSTR wzQUERY_SECUREOBJECTS = L"SELECT `Wix4SecureObject`.`Wix4SecureObject`, `Wix4SecureObject`.`Table`, `Wix4SecureObject`.`Domain`, `Wix4SecureObject`.`User`, `Wix4SecureObject`.`Attributes`, " - L"`Wix4SecureObject`.`Permission`, `Wix4SecureObject`.`Component_`, `Component`.`Attributes` FROM `Wix4SecureObject`,`Component` WHERE " - L"`Wix4SecureObject`.`Component_`=`Component`.`Component`"; -enum eQUERY_SECUREOBJECTS { QSO_SECUREOBJECT = 1, QSO_TABLE, QSO_DOMAIN, QSO_USER, QSO_ATTRIBUTES, QSO_PERMISSION, QSO_COMPONENT, QSO_COMPATTRIBUTES }; - -LPCWSTR wzQUERY_REGISTRY = L"SELECT `Registry`.`Registry`, `Registry`.`Root`, `Registry`.`Key` FROM `Registry` WHERE `Registry`.`Registry`=?"; -enum eQUERY_OBJECTCOMPONENT { QSOC_REGISTRY = 1, QSOC_REGROOT, QSOC_REGKEY }; - -LPCWSTR wzQUERY_SERVICEINSTALL = L"SELECT `ServiceInstall`.`Name` FROM `ServiceInstall` WHERE `ServiceInstall`.`ServiceInstall`=?"; -enum eQUERY_SECURESERVICEINSTALL { QSSI_NAME = 1 }; - -enum eOBJECTTYPE { OT_UNKNOWN, OT_SERVICE, OT_FOLDER, OT_FILE, OT_REGISTRY }; - -enum eSECURE_OBJECT_ATTRIBUTE -{ - SECURE_OBJECT_ATTRIBUTE_INHERITABLE = 0x1, -}; - -static eOBJECTTYPE EObjectTypeFromString( - __in LPCWSTR pwzTable - ) -{ - if (NULL == pwzTable) - { - return OT_UNKNOWN; - } - - eOBJECTTYPE eType = OT_UNKNOWN; - - // ensure we're looking at a known table - if (0 == lstrcmpW(L"ServiceInstall", pwzTable)) - { - eType = OT_SERVICE; - } - else if (0 == lstrcmpW(L"CreateFolder", pwzTable)) - { - eType = OT_FOLDER; - } - else if (0 == lstrcmpW(L"File", pwzTable)) - { - eType = OT_FILE; - } - else if (0 == lstrcmpW(L"Registry", pwzTable)) - { - eType = OT_REGISTRY; - } - - return eType; -} - -static SE_OBJECT_TYPE SEObjectTypeFromString( - __in LPCWSTR pwzTable - ) -{ - if (NULL == pwzTable) - { - return SE_UNKNOWN_OBJECT_TYPE; - } - - SE_OBJECT_TYPE objectType = SE_UNKNOWN_OBJECT_TYPE; - - if (0 == lstrcmpW(L"ServiceInstall", pwzTable)) - { - objectType = SE_SERVICE; - } - else if (0 == lstrcmpW(L"CreateFolder", pwzTable) || 0 == lstrcmpW(L"File", pwzTable)) - { - objectType = SE_FILE_OBJECT; - } - else if (0 == lstrcmpW(L"Registry", pwzTable)) - { - objectType = SE_REGISTRY_KEY; - } - else - { - // Do nothing; we'll return SE_UNKNOWN_OBJECT_TYPE, and the caller should handle the situation - } - - return objectType; -} - -static HRESULT StoreACLRollbackInfo( - __in LPWSTR pwzObject, - __in LPCWSTR pwzTable - ) -{ - HRESULT hr = S_OK; - DWORD er = ERROR_SUCCESS; - PSECURITY_DESCRIPTOR psd = NULL; - SECURITY_DESCRIPTOR_CONTROL sdc = {0}; - DWORD dwRevision = 0; - LPWSTR pwzCustomActionData = NULL; - LPWSTR pwzSecurityInfo = NULL; - - Assert(pwzObject && pwzTable); - - SE_OBJECT_TYPE objectType = SEObjectTypeFromString(const_cast (pwzTable)); - - if (SE_UNKNOWN_OBJECT_TYPE != objectType) - { - er = ::GetNamedSecurityInfoW(pwzObject, objectType, DACL_SECURITY_INFORMATION, NULL, NULL, NULL, NULL, &psd); - if (ERROR_FILE_NOT_FOUND == er || ERROR_PATH_NOT_FOUND == er || ERROR_SERVICE_DOES_NOT_EXIST == HRESULT_CODE(er)) - { - // If the file, path or service doesn't exist yet, skip rollback without a message - hr = HRESULT_FROM_WIN32(er); - ExitFunction(); - } - - ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Unable to schedule rollback for object: %ls", pwzObject); - - //Need to see if DACL is protected so getting Descriptor information - if (!::GetSecurityDescriptorControl(psd, &sdc, &dwRevision)) - { - ExitOnLastError(hr, "Unable to schedule rollback for object (failed to get security descriptor control): %ls", pwzObject); - } - - // Convert the security information to a string, and write this to the custom action data - if (!::ConvertSecurityDescriptorToStringSecurityDescriptorW(psd,SDDL_REVISION_1,DACL_SECURITY_INFORMATION,&pwzSecurityInfo,NULL)) - { - hr = E_UNEXPECTED; - ExitOnFailure(hr, "Unable to schedule rollback for object (failed to convert security descriptor to a valid security descriptor string): %ls", pwzObject); - } - - hr = WcaWriteStringToCaData(pwzObject, &pwzCustomActionData); - ExitOnFailure(hr, "failed to add object data to rollback CustomActionData"); - - hr = WcaWriteStringToCaData(pwzTable, &pwzCustomActionData); - ExitOnFailure(hr, "failed to add table name to rollback CustomActionData"); - - hr = WcaWriteStringToCaData(pwzSecurityInfo, &pwzCustomActionData); - ExitOnFailure(hr, "failed to add security info data to rollback CustomActionData"); - - // Write a 1 if DACL is protected, 0 otherwise - if (sdc & SE_DACL_PROTECTED) - { - hr = WcaWriteIntegerToCaData(1,&pwzCustomActionData); - ExitOnFailure(hr, "failed to add data to rollbackCustomActionData"); - } - else - { - hr = WcaWriteIntegerToCaData(0,&pwzCustomActionData); - ExitOnFailure(hr, "failed to add data to rollback CustomActionData"); - } - - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecSecureObjectsRollback"), pwzCustomActionData, COST_SECUREOBJECT); - ExitOnFailure(hr, "failed to schedule ExecSecureObjectsRollback for item: %ls of type: %ls", pwzObject, pwzTable); - - ReleaseStr(pwzCustomActionData); - pwzCustomActionData = NULL; - - } - else - { - MessageExitOnFailure(hr = E_UNEXPECTED, msierrSecureObjectsUnknownType, "unknown object type: %ls", pwzTable); - } -LExit: - ReleaseStr(pwzCustomActionData); - - if (psd) - { - ::LocalFree(psd); - } - - return hr; -} - -static HRESULT GetTargetPath( - __in eOBJECTTYPE eType, - __in LPCWSTR pwzSecureObject, - __out LPWSTR* ppwzTargetPath - ) -{ - HRESULT hr = S_OK; - - PMSIHANDLE hView = NULL; - PMSIHANDLE hRecObject = NULL; - PMSIHANDLE hRec = NULL; - - int iRoot = 0; - int iAllUsers = 0; - LPWSTR pwzKey = NULL; - LPWSTR pwzFormattedString = NULL; - - if (OT_SERVICE == eType) - { - hr = WcaTableExists(L"ServiceInstall"); - if (S_FALSE == hr) - { - hr = E_UNEXPECTED; - } - ExitOnFailure(hr, "failed to open ServiceInstall table to secure object"); - - hr = WcaOpenView(wzQUERY_SERVICEINSTALL, &hView); - ExitOnFailure(hr, "failed to open view on ServiceInstall table"); - - // create a record that stores the object to secure - hRec = MsiCreateRecord(1); - MsiRecordSetStringW(hRec, 1, pwzSecureObject); - - // execute a view looking for the object's ServiceInstall.ServiceInstall row. - hr = WcaExecuteView(hView, hRec); - ExitOnFailure(hr, "failed to execute view on ServiceInstall table"); - hr = WcaFetchSingleRecord(hView, &hRecObject); - ExitOnFailure(hr, "failed to fetch ServiceInstall row for secure object"); - - hr = WcaGetRecordFormattedString(hRecObject, QSSI_NAME, ppwzTargetPath); - ExitOnFailure(hr, "failed to get service name for secure object: %ls", pwzSecureObject); - } - else if (OT_FOLDER == eType) - { - hr = WcaGetTargetPath(pwzSecureObject, ppwzTargetPath); - ExitOnFailure(hr, "failed to get target path for directory id: %ls", pwzSecureObject); - } - else if (OT_FILE == eType) - { - hr = StrAllocFormatted(&pwzFormattedString, L"[#%s]", pwzSecureObject); - ExitOnFailure(hr, "failed to create formatted string for securing file object: %ls", pwzSecureObject); - - hr = WcaGetFormattedString(pwzFormattedString, ppwzTargetPath); - ExitOnFailure(hr, "failed to get file path from formatted string: %ls for secure object: %ls", pwzFormattedString, pwzSecureObject); - } - else if (OT_REGISTRY == eType) - { - hr = WcaTableExists(L"Registry"); - if (S_FALSE == hr) - { - hr = E_UNEXPECTED; - } - ExitOnFailure(hr, "failed to open Registry table to secure object"); - - hr = WcaOpenView(wzQUERY_REGISTRY, &hView); - ExitOnFailure(hr, "failed to open view on Registry table"); - - // create a record that stores the object to secure - hRec = MsiCreateRecord(1); - MsiRecordSetStringW(hRec, 1, pwzSecureObject); - - // execute a view looking for the object's Registry row - hr = WcaExecuteView(hView, hRec); - ExitOnFailure(hr, "failed to execute view on Registry table"); - hr = WcaFetchSingleRecord(hView, &hRecObject); - ExitOnFailure(hr, "failed to fetch Registry row for secure object"); - - hr = WcaGetRecordInteger(hRecObject, QSOC_REGROOT, &iRoot); - ExitOnFailure(hr, "Failed to get reg key root for secure object: %ls", pwzSecureObject); - - hr = WcaGetRecordFormattedString(hRecObject, QSOC_REGKEY, &pwzKey); - ExitOnFailure(hr, "Failed to get reg key for secure object: %ls", pwzSecureObject); - - // Decode the root value - if (-1 == iRoot) - { - // They didn't specify a root so that means it's either HKCU or HKLM depending on ALLUSERS property - hr = WcaGetIntProperty(L"ALLUSERS", &iAllUsers); - ExitOnFailure(hr, "failed to get value of ALLUSERS property"); - - if (1 == iAllUsers) - { - hr = StrAllocString(ppwzTargetPath, L"MACHINE\\", 0); - ExitOnFailure(hr, "failed to allocate target registry string with HKLM root"); - } - else - { - hr = StrAllocString(ppwzTargetPath, L"CURRENT_USER\\", 0); - ExitOnFailure(hr, "failed to allocate target registry string with HKCU root"); - } - } - else if (msidbRegistryRootClassesRoot == iRoot) - { - hr = StrAllocString(ppwzTargetPath, L"CLASSES_ROOT\\", 0); - ExitOnFailure(hr, "failed to allocate target registry string with HKCR root"); - } - else if (msidbRegistryRootCurrentUser == iRoot) - { - hr = StrAllocString(ppwzTargetPath, L"CURRENT_USER\\", 0); - ExitOnFailure(hr, "failed to allocate target registry string with HKCU root"); - } - else if (msidbRegistryRootLocalMachine == iRoot) - { - hr = StrAllocString(ppwzTargetPath, L"MACHINE\\", 0); - ExitOnFailure(hr, "failed to allocate target registry string with HKLM root"); - } - else if (msidbRegistryRootUsers == iRoot) - { - hr = StrAllocString(ppwzTargetPath, L"USERS\\", 0); - ExitOnFailure(hr, "failed to allocate target registry string with HKU root"); - } - else - { - ExitOnFailure(hr = E_UNEXPECTED, "Unknown registry key root specified for secure object: '%ls' root: %d", pwzSecureObject, iRoot); - } - - hr = StrAllocConcat(ppwzTargetPath, pwzKey, 0); - ExitOnFailure(hr, "Failed to concat key: %ls for secure object: %ls", pwzKey, pwzSecureObject); - } - else - { - AssertSz(FALSE, "How did you get here?"); - ExitOnFailure(hr = E_UNEXPECTED, "Unknown secure object type: %d", eType); - } - -LExit: - ReleaseStr(pwzFormattedString); - ReleaseStr(pwzKey); - - return hr; -} - -/****************************************************************** - SchedSecureObjects - entry point for SchedSecureObjects Custom Action - - called as Type 1 CustomAction (binary DLL) from Windows Installer - in InstallExecuteSequence, to schedule ExecSecureObjects -******************************************************************/ -extern "C" UINT __stdcall SchedSecureObjects( - __in MSIHANDLE hInstall - ) -{ -// AssertSz(FALSE, "debug SchedSecureObjects"); - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - - LPWSTR pwzSecureObject = NULL; - LPWSTR pwzData = NULL; - LPWSTR pwzTable = NULL; - LPWSTR pwzTargetPath = NULL; - - PMSIHANDLE hView = NULL; - PMSIHANDLE hRec = NULL; - - INSTALLSTATE isInstalled; - INSTALLSTATE isAction; - - LPWSTR pwzCustomActionData = NULL; - - DWORD cObjects = 0; - eOBJECTTYPE eType = OT_UNKNOWN; - DWORD dwAttributes = 0; - - // - // initialize - // - hr = WcaInitialize(hInstall, "SchedSecureObjects"); - ExitOnFailure(hr, "failed to initialize"); - - // anything to do? - if (S_OK != WcaTableExists(L"Wix4SecureObject")) - { - WcaLog(LOGMSG_STANDARD, "Wix4SecureObject table doesn't exist, so there are no objects to secure."); - ExitFunction(); - } - - // - // loop through all the objects to be secured - // - hr = WcaOpenExecuteView(wzQUERY_SECUREOBJECTS, &hView); - ExitOnFailure(hr, "failed to open view on Wix4SecureObject table"); - while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) - { - hr = WcaGetRecordString(hRec, QSO_TABLE, &pwzTable); - ExitOnFailure(hr, "failed to get object table"); - - eType = EObjectTypeFromString(pwzTable); - - if (OT_UNKNOWN == eType) - { - ExitOnFailure(hr = E_INVALIDARG, "unknown SecureObject.Table: %ls", pwzTable); - } - - int iCompAttributes = 0; - hr = WcaGetRecordInteger(hRec, QSO_COMPATTRIBUTES, &iCompAttributes); - ExitOnFailure(hr, "failed to get Component attributes for secure object"); - - BOOL fIs64Bit = iCompAttributes & msidbComponentAttributes64bit; - - // Only process entries in the Wix4SecureObject table whose components match the bitness of this CA -#ifdef _WIN64 - if (!fIs64Bit) - { - continue; - } -#else - if (fIs64Bit) - { - continue; - } -#endif - - // Get the object to secure - hr = WcaGetRecordString(hRec, QSO_SECUREOBJECT, &pwzSecureObject); - ExitOnFailure(hr, "failed to get name of object"); - - hr = GetTargetPath(eType, pwzSecureObject, &pwzTargetPath); - ExitOnFailure(hr, "failed to get target path of object '%ls'", pwzSecureObject); - - hr = WcaGetRecordString(hRec, QSO_COMPONENT, &pwzData); - ExitOnFailure(hr, "failed to get Component name for secure object"); - - // - // if we are installing this Component - // - er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction); - ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "failed to get install state for Component: %ls", pwzData); - - if (WcaIsInstalling(isInstalled, isAction)) - { - hr = WcaWriteStringToCaData(pwzTargetPath, &pwzCustomActionData); - ExitOnFailure(hr, "failed to add data to CustomActionData"); - - // add the data to the CustomActionData - hr = WcaGetRecordString(hRec, QSO_SECUREOBJECT, &pwzData); - ExitOnFailure(hr, "failed to get name of object"); - hr = WcaWriteStringToCaData(pwzTable, &pwzCustomActionData); - ExitOnFailure(hr, "failed to add data to CustomActionData"); - - hr = WcaGetRecordFormattedString(hRec, QSO_DOMAIN, &pwzData); - ExitOnFailure(hr, "failed to get domain for user to configure object"); - hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); - ExitOnFailure(hr, "failed to add data to CustomActionData"); - - hr = WcaGetRecordFormattedString(hRec, QSO_USER, &pwzData); - ExitOnFailure(hr, "failed to get user to configure object"); - hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); - ExitOnFailure(hr, "failed to add data to CustomActionData"); - - hr = WcaGetRecordInteger(hRec, QSO_ATTRIBUTES, reinterpret_cast(&dwAttributes)); - ExitOnFailure(hr, "failed to get attributes to configure object"); - hr = WcaWriteIntegerToCaData(dwAttributes, &pwzCustomActionData); - ExitOnFailure(hr, "failed to add data to CustomActionData"); - - hr = WcaGetRecordString(hRec, QSO_PERMISSION, &pwzData); - ExitOnFailure(hr, "failed to get permission to configure object"); - hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); - ExitOnFailure(hr, "failed to add data to CustomActionData"); - - ++cObjects; - } - } - - // if we looped through all records all is well - if (E_NOMOREITEMS == hr) - hr = S_OK; - ExitOnFailure(hr, "failed while looping through all objects to secure"); - - // - // schedule the custom action and add to progress bar - // - if (pwzCustomActionData && *pwzCustomActionData) - { - Assert(0 < cObjects); - - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecSecureObjects"), pwzCustomActionData, cObjects * COST_SECUREOBJECT); - ExitOnFailure(hr, "failed to schedule ExecSecureObjects action"); - } - -LExit: - ReleaseStr(pwzSecureObject); - ReleaseStr(pwzCustomActionData); - ReleaseStr(pwzData); - ReleaseStr(pwzTable); - ReleaseStr(pwzTargetPath); - - if (FAILED(hr)) - { - er = ERROR_INSTALL_FAILURE; - } - return WcaFinalize(er); -} - -/****************************************************************** - SchedSecureObjectsRollback - entry point for SchedSecureObjectsRollback Custom Action - - called as Type 1 CustomAction (binary DLL) from Windows Installer - in InstallExecuteSequence before SchedSecureObjects -******************************************************************/ -extern "C" UINT __stdcall SchedSecureObjectsRollback( - __in MSIHANDLE hInstall - ) -{ -// AssertSz(FALSE, "debug SchedSecureObjectsRollback"); - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - - LPWSTR pwzSecureObject = NULL; - LPWSTR pwzTable = NULL; - LPWSTR pwzTargetPath = NULL; - - PMSIHANDLE hView = NULL; - PMSIHANDLE hRec = NULL; - - LPWSTR pwzCustomActionData = NULL; - - eOBJECTTYPE eType = OT_UNKNOWN; - - // - // initialize - // - hr = WcaInitialize(hInstall, "SchedSecureObjectsRollback"); - ExitOnFailure(hr, "failed to initialize"); - - // - // loop through all the objects to be secured - // - hr = WcaOpenExecuteView(wzQUERY_SECUREOBJECTS, &hView); - ExitOnFailure(hr, "failed to open view on Wix4SecureObject table"); - while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) - { - hr = WcaGetRecordString(hRec, QSO_TABLE, &pwzTable); - ExitOnFailure(hr, "failed to get object table"); - - eType = EObjectTypeFromString(pwzTable); - - if (OT_UNKNOWN == eType) - { - ExitOnFailure(hr = E_INVALIDARG, "unknown SecureObject.Table: %ls", pwzTable); - } - - int iCompAttributes = 0; - hr = WcaGetRecordInteger(hRec, QSO_COMPATTRIBUTES, &iCompAttributes); - ExitOnFailure(hr, "failed to get Component attributes for secure object"); - - BOOL fIs64Bit = iCompAttributes & msidbComponentAttributes64bit; - - // Only process entries in the Wix4SecureObject table whose components match the bitness of this CA -#ifdef _WIN64 - if (!fIs64Bit) - { - continue; - } -#else - if (fIs64Bit) - { - continue; - } -#endif - - // get the object being secured that we are planning to schedule rollback for - hr = WcaGetRecordString(hRec, QSO_SECUREOBJECT, &pwzSecureObject); - ExitOnFailure(hr, "failed to get name of object"); - - hr = GetTargetPath(eType, pwzSecureObject, &pwzTargetPath); - ExitOnFailure(hr, "failed to get target path of object '%ls' in order to schedule rollback", pwzSecureObject); - - hr = StoreACLRollbackInfo(pwzTargetPath, pwzTable); - if (FAILED(hr)) - { - WcaLog(LOGMSG_STANDARD, "Failed to store ACL rollback information with error 0x%x - continuing", hr); - } - } - - // if we looped through all records all is well - if (E_NOMOREITEMS == hr) - { - hr = S_OK; - } - ExitOnFailure(hr, "failed while looping through all objects to schedule rollback for"); - -LExit: - ReleaseStr(pwzCustomActionData); - ReleaseStr(pwzSecureObject); - ReleaseStr(pwzTable); - ReleaseStr(pwzTargetPath); - - if (FAILED(hr)) - { - er = ERROR_INSTALL_FAILURE; - } - return WcaFinalize(er); -} - -/****************************************************************** - CaExecSecureObjects - entry point for SecureObjects Custom Action - called as Type 1025 CustomAction (deferred binary DLL) - - NOTE: deferred CustomAction since it modifies the machine - NOTE: CustomActionData == wzObject\twzTable\twzDomain\twzUser\tdwAttributes\tdwPermissions\t... -******************************************************************/ -extern "C" UINT __stdcall ExecSecureObjects( - __in MSIHANDLE hInstall - ) -{ -// AssertSz(FALSE, "debug ExecSecureObjects"); - HRESULT hr = S_OK; - DWORD er = ERROR_SUCCESS; - - LPWSTR pwz = NULL; - LPWSTR pwzData = NULL; - LPWSTR pwzObject = NULL; - LPWSTR pwzTable = NULL; - LPWSTR pwzDomain = NULL; - DWORD dwRevision = 0; - LPWSTR pwzUser = NULL; - DWORD dwPermissions = 0; - DWORD dwAttributes = 0; - LPWSTR pwzAccount = NULL; - PSID psid = NULL; - - EXPLICIT_ACCESSW ea = {0}; - SE_OBJECT_TYPE objectType = SE_UNKNOWN_OBJECT_TYPE; - PSECURITY_DESCRIPTOR psd = NULL; - SECURITY_DESCRIPTOR_CONTROL sdc = {0}; - SECURITY_INFORMATION si = {0}; - PACL pAclExisting = NULL; // doesn't get freed - PACL pAclNew = NULL; - - PMSIHANDLE hActionRec = ::MsiCreateRecord(1); - - // - // initialize - // - hr = WcaInitialize(hInstall, "ExecSecureObjects"); - ExitOnFailure(hr, "failed to initialize"); - - hr = WcaGetProperty(L"CustomActionData", &pwzData); - ExitOnFailure(hr, "failed to get CustomActionData"); - - WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); - - pwz = pwzData; - - // - // loop through all the passed in data - // - while (pwz && *pwz) - { - hr = WcaReadStringFromCaData(&pwz, &pwzObject); - ExitOnFailure(hr, "failed to process CustomActionData"); - - hr = WcaReadStringFromCaData(&pwz, &pwzTable); - ExitOnFailure(hr, "failed to process CustomActionData"); - hr = WcaReadStringFromCaData(&pwz, &pwzDomain); - ExitOnFailure(hr, "failed to process CustomActionData"); - hr = WcaReadStringFromCaData(&pwz, &pwzUser); - ExitOnFailure(hr, "failed to process CustomActionData"); - hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&dwAttributes)); - ExitOnFailure(hr, "failed to process CustomActionData"); - hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&dwPermissions)); - ExitOnFailure(hr, "failed to process CustomActionData"); - - WcaLog(LOGMSG_VERBOSE, "Securing Object: %ls Type: %ls User: %ls", pwzObject, pwzTable, pwzUser); - - // - // create the appropriate SID - // - - // figure out the right user to put into the access block - if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"Everyone")) - { - hr = AclGetWellKnownSid(WinWorldSid, &psid); - } - else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"Administrators")) - { - hr = AclGetWellKnownSid(WinBuiltinAdministratorsSid, &psid); - } - else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"LocalSystem")) - { - hr = AclGetWellKnownSid(WinLocalSystemSid, &psid); - } - else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"LocalService")) - { - hr = AclGetWellKnownSid(WinLocalServiceSid, &psid); - } - else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"NetworkService")) - { - hr = AclGetWellKnownSid(WinNetworkServiceSid, &psid); - } - else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"AuthenticatedUser")) - { - hr = AclGetWellKnownSid(WinAuthenticatedUserSid, &psid); - } - else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"Guests")) - { - hr = AclGetWellKnownSid(WinBuiltinGuestsSid, &psid); - } - else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"CREATOR OWNER")) - { - hr = AclGetWellKnownSid(WinCreatorOwnerSid, &psid); - } - else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"INTERACTIVE")) - { - hr = AclGetWellKnownSid(WinInteractiveSid, &psid); - } - else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"Users")) - { - hr = AclGetWellKnownSid(WinBuiltinUsersSid, &psid); - } - else - { - hr = StrAllocFormatted(&pwzAccount, L"%s%s%s", pwzDomain, *pwzDomain ? L"\\" : L"", pwzUser); - ExitOnFailure(hr, "failed to build domain user name"); - - hr = AclGetAccountSid(NULL, pwzAccount, &psid); - } - ExitOnFailure(hr, "failed to get sid for account: %ls%ls%ls", pwzDomain, *pwzDomain ? L"\\" : L"", pwzUser); - - // - // build up the explicit access - // - ea.grfAccessMode = SET_ACCESS; - - if (dwAttributes & SECURE_OBJECT_ATTRIBUTE_INHERITABLE) - { - ea.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT; - } - else - { - ea.grfInheritance = NO_INHERITANCE; - } - -#pragma prefast(push) -#pragma prefast(disable:25029) - ::BuildTrusteeWithSidW(&ea.Trustee, psid); -#pragma prefast(pop) - - objectType = SEObjectTypeFromString(const_cast (pwzTable)); - - // always add these permissions for services - // these are basic permissions that are often forgotten - if (0 == lstrcmpW(L"ServiceInstall", pwzTable)) - { - dwPermissions |= SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_INTERROGATE; - } - - ea.grfAccessPermissions = dwPermissions; - - if (SE_UNKNOWN_OBJECT_TYPE != objectType) - { - er = ::GetNamedSecurityInfoW(pwzObject, objectType, DACL_SECURITY_INFORMATION, NULL, NULL, &pAclExisting, NULL, &psd); - ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "failed to get security info for object: %ls", pwzObject); - - //Need to see if DACL is protected so getting Descriptor information - if (!::GetSecurityDescriptorControl(psd, &sdc, &dwRevision)) - { - ExitOnLastError(hr, "failed to get security descriptor control for object: %ls", pwzObject); - } - -#pragma prefast(push) -#pragma prefast(disable:25029) - er = ::SetEntriesInAclW(1, &ea, pAclExisting, &pAclNew); -#pragma prefast(pop) - ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "failed to add ACLs for object: %ls", pwzObject); - - if (sdc & SE_DACL_PROTECTED) - { - si = DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION; - } - else - { - si = DACL_SECURITY_INFORMATION; - } - er = ::SetNamedSecurityInfoW(pwzObject, objectType, si, NULL, NULL, pAclNew, NULL); - MessageExitOnFailure(hr = HRESULT_FROM_WIN32(er), msierrSecureObjectsFailedSet, "failed to set security info for object: %ls", pwzObject); - } - else - { - MessageExitOnFailure(hr = E_UNEXPECTED, msierrSecureObjectsUnknownType, "unknown object type: %ls", pwzTable); - } - - hr = WcaProgressMessage(COST_SECUREOBJECT, FALSE); - ExitOnFailure(hr, "failed to send progress message"); - - objectType = SE_UNKNOWN_OBJECT_TYPE; - } - -LExit: - ReleaseStr(pwzUser); - ReleaseStr(pwzDomain); - ReleaseStr(pwzTable); - ReleaseStr(pwzObject); - ReleaseStr(pwzData); - ReleaseStr(pwzAccount); - - if (pAclNew) - { - ::LocalFree(pAclNew); - } - if (psd) - { - ::LocalFree(psd); - } - if (psid) - { - AclFreeSid(psid); - } - - if (FAILED(hr)) - { - er = ERROR_INSTALL_FAILURE; - } - return WcaFinalize(er); -} - -extern "C" UINT __stdcall ExecSecureObjectsRollback( - __in MSIHANDLE hInstall - ) -{ -// AssertSz(FALSE, "debug ExecSecureObjectsRollback"); - HRESULT hr = S_OK; - DWORD er = ERROR_SUCCESS; - - LPWSTR pwz = NULL; - LPWSTR pwzData = NULL; - LPWSTR pwzObject = NULL; - LPWSTR pwzTable = NULL; - LPWSTR pwzSecurityInfo = NULL; - - SE_OBJECT_TYPE objectType = SE_UNKNOWN_OBJECT_TYPE; - PSECURITY_DESCRIPTOR psd = NULL; - ULONG psdSize; - SECURITY_DESCRIPTOR_CONTROL sdc = {0}; - SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION; - PACL pDacl = NULL; - BOOL bDaclPresent = false; - BOOL bDaclDefaulted = false; - DWORD dwRevision = 0; - int iProtected; - - // initialize - hr = WcaInitialize(hInstall, "ExecSecureObjectsRollback"); - ExitOnFailure(hr, "failed to initialize"); - - hr = WcaGetProperty(L"CustomActionData", &pwzData); - ExitOnFailure(hr, "failed to get CustomActionData"); - - WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); - - pwz = pwzData; - - hr = WcaReadStringFromCaData(&pwz, &pwzObject); - ExitOnFailure(hr, "failed to process CustomActionData"); - - hr = WcaReadStringFromCaData(&pwz, &pwzTable); - ExitOnFailure(hr, "failed to process CustomActionData"); - - objectType = SEObjectTypeFromString(const_cast (pwzTable)); - - if (SE_UNKNOWN_OBJECT_TYPE != objectType) - { - hr = WcaReadStringFromCaData(&pwz, &pwzSecurityInfo); - ExitOnFailure(hr, "failed to process CustomActionData"); - - hr = WcaReadIntegerFromCaData(&pwz, &iProtected); - ExitOnFailure(hr, "failed to process CustomActionData"); - - if (!::ConvertStringSecurityDescriptorToSecurityDescriptorW(pwzSecurityInfo,SDDL_REVISION_1,&psd,&psdSize)) - { - ExitOnLastError(hr, "failed to convert security descriptor string to a valid security descriptor"); - } - - if (!::GetSecurityDescriptorDacl(psd,&bDaclPresent,&pDacl,&bDaclDefaulted)) - { - hr = E_UNEXPECTED; - ExitOnFailure(hr, "failed to get security descriptor's DACL - error code: %d",pwzSecurityInfo,GetLastError()); - } - - // 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. - if (!bDaclPresent) - { - hr = E_UNEXPECTED; - ExitOnFailure(hr, "security descriptor does not contain a DACL"); - } - - //Need to see if DACL is protected so getting Descriptor information - if (!::GetSecurityDescriptorControl(psd, &sdc, &dwRevision)) - { - ExitOnLastError(hr, "failed to get security descriptor control for object: %ls", pwzObject); - } - - // Write a 1 if DACL is protected, 0 otherwise - switch (iProtected) - { - case 0: - // Unnecessary to do anything - leave si to the default flags - break; - - case 1: - si = si | PROTECTED_DACL_SECURITY_INFORMATION; - break; - - default: - hr = E_UNEXPECTED; - ExitOnFailure(hr, "unrecognized value in CustomActionData"); - break; - } - - er = ::SetNamedSecurityInfoW(pwzObject, objectType, si, NULL, NULL, pDacl, NULL); - ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "failed to set security info for object: %ls error code: %d", pwzObject, GetLastError()); - } - else - { - MessageExitOnFailure(hr = E_UNEXPECTED, msierrSecureObjectsUnknownType, "unknown object type: %ls", pwzTable); - } - -LExit: - ReleaseStr(pwzData); - ReleaseStr(pwzObject); - ReleaseStr(pwzTable); - ReleaseStr(pwzSecurityInfo); - - if (psd) - { - ::LocalFree(psd); - } - - if (FAILED(hr)) - { - er = ERROR_INSTALL_FAILURE; - } - return WcaFinalize(er); -} diff --git a/src/ca/serviceconfig.cpp b/src/ca/serviceconfig.cpp deleted file mode 100644 index 04b25ffa..00000000 --- a/src/ca/serviceconfig.cpp +++ /dev/null @@ -1,821 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" - -// structs -LPCWSTR wzQUERY_SERVICECONFIG = L"SELECT `ServiceName`, `Component_`, `NewService`, `FirstFailureActionType`, `SecondFailureActionType`, `ThirdFailureActionType`, `ResetPeriodInDays`, `RestartServiceDelayInSeconds`, `ProgramCommandLine`, `RebootMessage` FROM `Wix4ServiceConfig`"; -enum eQUERY_SERVICECONFIG { QSC_SERVICENAME = 1, QSC_COMPONENT, QSC_NEWSERVICE, QSC_FIRSTFAILUREACTIONTYPE, QSC_SECONDFAILUREACTIONTYPE, QSC_THIRDFAILUREACTIONTYPE, QSC_RESETPERIODINDAYS, QSC_RESTARTSERVICEDELAYINSECONDS, QSC_PROGRAMCOMMANDLINE, QSC_REBOOTMESSAGE }; - -// consts -LPCWSTR c_wzActionTypeNone = L"none"; -LPCWSTR c_wzActionTypeReboot = L"reboot"; -LPCWSTR c_wzActionTypeRestart = L"restart"; -LPCWSTR c_wzActionTypeRunCommand = L"runCommand"; - -// prototypes -static SC_ACTION_TYPE GetSCActionType( - __in LPCWSTR pwzActionTypeName - ); - -static HRESULT GetSCActionTypeString( - __in SC_ACTION_TYPE type, - __out_ecount(cchActionTypeString) LPWSTR wzActionTypeString, - __in DWORD cchActionTypeString - ); - -static HRESULT GetService( - __in SC_HANDLE hSCM, - __in LPCWSTR wzService, - __in DWORD dwOpenServiceAccess, - __out SC_HANDLE* phService - ); - -static HRESULT ConfigureService( - __in SC_HANDLE hSCM, - __in SC_HANDLE hService, - __in LPCWSTR wzServiceName, - __in DWORD dwRestartServiceDelayInSeconds, - __in LPCWSTR wzFirstFailureActionType, - __in LPCWSTR wzSecondFailureActionType, - __in LPCWSTR wzThirdFailureActionType, - __in DWORD dwResetPeriodInDays, - __in LPWSTR wzRebootMessage, - __in LPWSTR wzProgramCommandLine - ); - - -/****************************************************************** -SchedServiceConfig - entry point for SchedServiceConfig Custom Action - -called as Type 1 CustomAction (binary DLL) from Windows Installer -in InstallExecuteSequence before CaExecServiceConfig -********************************************************************/ -extern "C" UINT __stdcall SchedServiceConfig( - __in MSIHANDLE hInstall - ) -{ - //AssertSz(FALSE, "debug SchedServiceConfig"); - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - - LPWSTR pwzScriptKey = NULL; - LPWSTR pwzCustomActionData = NULL; - - PMSIHANDLE hView = NULL; - PMSIHANDLE hRec = NULL; - LPWSTR pwzData = NULL; - int iData = 0; - DWORD cServices = 0; - - // initialize - hr = WcaInitialize(hInstall, "SchedServiceConfig"); - ExitOnFailure(hr, "Failed to initialize."); - - // Get the script key for this CustomAction and put it on the front of the - // CustomActionData of the install action. - hr = WcaCaScriptCreateKey(&pwzScriptKey); - ExitOnFailure(hr, "Failed to get encoding key."); - - hr = WcaWriteStringToCaData(pwzScriptKey, &pwzCustomActionData); - ExitOnFailure(hr, "Failed to add encoding key to CustomActionData."); - - // Loop through all the services to be configured. - hr = WcaOpenExecuteView(wzQUERY_SERVICECONFIG, &hView); - ExitOnFailure(hr, "Failed to open view on Wix4ServiceConfig table."); - - while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) - { - INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN; - INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN; - - // Get component name to check if we are installing it. If so - // then add the table data to the CustomActionData, otherwise - // skip it. - hr = WcaGetRecordString(hRec, QSC_COMPONENT, &pwzData); - ExitOnFailure(hr, "Failed to get component name"); - - hr = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction); - ExitOnFailure(hr = HRESULT_FROM_WIN32(hr), "Failed to get install state for Component: %ls", pwzData); - - if (WcaIsInstalling(isInstalled, isAction)) - { - // Add the data to the CustomActionData (for install). - hr = WcaGetRecordFormattedString(hRec, QSC_SERVICENAME, &pwzData); - ExitOnFailure(hr, "Failed to get name of service."); - hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); - ExitOnFailure(hr, "Failed to add name to CustomActionData."); - - hr = WcaGetRecordInteger(hRec, QSC_NEWSERVICE, &iData); - ExitOnFailure(hr, "Failed to get Wix4ServiceConfig.NewService."); - hr = WcaWriteIntegerToCaData(0 != iData, &pwzCustomActionData); - ExitOnFailure(hr, "Failed to add NewService data to CustomActionData"); - - hr = WcaGetRecordString(hRec, QSC_FIRSTFAILUREACTIONTYPE, &pwzData); - ExitOnFailure(hr, "failed to get first failure action type"); - hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); - ExitOnFailure(hr, "failed to add data to CustomActionData"); - - hr = WcaGetRecordString(hRec, QSC_SECONDFAILUREACTIONTYPE, &pwzData); - ExitOnFailure(hr, "failed to get second failure action type"); - hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); - ExitOnFailure(hr, "failed to add data to CustomActionData"); - - hr = WcaGetRecordString(hRec, QSC_THIRDFAILUREACTIONTYPE, &pwzData); - ExitOnFailure(hr, "failed to get third failure action type"); - hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); - ExitOnFailure(hr, "failed to add data to CustomActionData"); - - hr = WcaGetRecordInteger(hRec, QSC_RESETPERIODINDAYS, &iData); - if (S_FALSE == hr) // deal w/ possible null value - { - iData = 0; - } - ExitOnFailure(hr, "failed to get reset period in days between service restart attempts."); - hr = WcaWriteIntegerToCaData(iData, &pwzCustomActionData); - ExitOnFailure(hr, "failed to add data to CustomActionData"); - - hr = WcaGetRecordInteger(hRec, QSC_RESTARTSERVICEDELAYINSECONDS, &iData); - if (S_FALSE == hr) // deal w/ possible null value - { - iData = 0; - } - ExitOnFailure(hr, "failed to get server restart delay value."); - hr = WcaWriteIntegerToCaData(iData, &pwzCustomActionData); - ExitOnFailure(hr, "failed to add data to CustomActionData"); - - hr = WcaGetRecordFormattedString(hRec, QSC_PROGRAMCOMMANDLINE, &pwzData); // null value already dealt w/ properly - ExitOnFailure(hr, "failed to get command line to run on service failure."); - hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); - ExitOnFailure(hr, "failed to add data to CustomActionData"); - - hr = WcaGetRecordString(hRec, QSC_REBOOTMESSAGE, &pwzData); // null value already dealt w/ properly - ExitOnFailure(hr, "failed to get message to send to users when server reboots due to service failure."); - hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); - ExitOnFailure(hr, "failed to add data to CustomActionData"); - - ++cServices; - } - } - - // if we looped through all records all is well - if (E_NOMOREITEMS == hr) - { - hr = S_OK; - } - ExitOnFailure(hr, "failed while looping through all objects to secure"); - - // setup CustomActionData and add to progress bar for download - if (0 < cServices) - { - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackServiceConfig"), pwzScriptKey, cServices * COST_SERVICECONFIG); - ExitOnFailure(hr, "failed to schedule RollbackServiceConfig action"); - - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecServiceConfig"), pwzCustomActionData, cServices * COST_SERVICECONFIG); - ExitOnFailure(hr, "failed to schedule ExecServiceConfig action"); - } - -LExit: - ReleaseStr(pwzData); - ReleaseStr(pwzCustomActionData); - ReleaseStr(pwzScriptKey); - - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} - - -/****************************************************************** -CaExecServiceConfig - entry point for ServiceConfig Custom Action. - -NOTE: deferred CustomAction since it modifies the machine -NOTE: CustomActionData == wzServiceName\tfNewService\twzFirstFailureActionType\twzSecondFailureActionType\twzThirdFailureActionType\tdwResetPeriodInDays\tdwRestartServiceDelayInSeconds\twzProgramCommandLine\twzRebootMessage\twzServiceName\tfNewService\t... -*******************************************************************/ -extern "C" UINT __stdcall ExecServiceConfig( - __in MSIHANDLE hInstall - ) -{ - //AssertSz(FALSE, "debug ExecServiceConfig"); - HRESULT hr = S_OK; - DWORD er = 0; - - LPWSTR pwzCustomActionData = NULL; - LPWSTR pwz = NULL; - - LPWSTR pwzScriptKey = NULL; - WCA_CASCRIPT_HANDLE hRollbackScript = NULL; - - LPWSTR pwzServiceName = NULL; - BOOL fNewService = FALSE; - LPWSTR pwzFirstFailureActionType = NULL; - LPWSTR pwzSecondFailureActionType = NULL; - LPWSTR pwzThirdFailureActionType = NULL; - LPWSTR pwzProgramCommandLine = NULL; - LPWSTR pwzRebootMessage = NULL; - DWORD dwResetPeriodInDays = 0; - DWORD dwRestartServiceDelayInSeconds = 0; - - LPVOID lpMsgBuf = NULL; - SC_HANDLE hSCM = NULL; - SC_HANDLE hService = NULL; - - DWORD dwRestartDelay = 0; - WCHAR wzActionName[32] = { 0 }; - - DWORD cbExistingServiceConfig = 0; - - SERVICE_FAILURE_ACTIONSW* psfa = NULL; - - // initialize - hr = WcaInitialize(hInstall, "ExecServiceConfig"); - ExitOnFailure(hr, "failed to initialize"); - - // Open the Services Control Manager up front. - hSCM = ::OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); - if (NULL == hSCM) - { - er = ::GetLastError(); - hr = HRESULT_FROM_WIN32(er); - -#pragma prefast(push) -#pragma prefast(disable:25028) - ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, er, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpMsgBuf, 0, NULL); -#pragma prefast(pop) - - ExitOnFailure(hr, "Failed to get handle to SCM. Error: %ls", (LPWSTR)lpMsgBuf); - } - - // First, get the script key out of the CustomActionData and - // use that to create the rollback script for this action. - hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData); - ExitOnFailure(hr, "failed to get CustomActionData"); - - WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); - - pwz = pwzCustomActionData; - - hr = WcaReadStringFromCaData(&pwz, &pwzScriptKey); - if (!pwzScriptKey) - { - hr = E_UNEXPECTED; - ExitOnFailure(hr, "Failed due to unexpected CustomActionData passed."); - } - ExitOnFailure(hr, "Failed to read encoding key from CustomActionData."); - - hr = WcaCaScriptCreate(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, FALSE, &hRollbackScript); - ExitOnFailure(hr, "Failed to open rollback CustomAction script."); - - // Next, loop through the rest of the CustomActionData, processing - // each service config row in turn. - while (pwz && *pwz) - { - hr = WcaReadStringFromCaData(&pwz, &pwzServiceName); - ExitOnFailure(hr, "failed to process CustomActionData"); - hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&fNewService)); - ExitOnFailure(hr, "failed to process CustomActionData"); - hr = WcaReadStringFromCaData(&pwz, &pwzFirstFailureActionType); - ExitOnFailure(hr, "failed to process CustomActionData"); - hr = WcaReadStringFromCaData(&pwz, &pwzSecondFailureActionType); - ExitOnFailure(hr, "failed to process CustomActionData"); - hr = WcaReadStringFromCaData(&pwz, &pwzThirdFailureActionType); - ExitOnFailure(hr, "failed to process CustomActionData"); - hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&dwResetPeriodInDays)); - ExitOnFailure(hr, "failed to process CustomActionData"); - hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&dwRestartServiceDelayInSeconds)); - ExitOnFailure(hr, "failed to process CustomActionData"); - hr = WcaReadStringFromCaData(&pwz, &pwzProgramCommandLine); - ExitOnFailure(hr, "failed to process CustomActionData"); - hr = WcaReadStringFromCaData(&pwz, &pwzRebootMessage); - ExitOnFailure(hr, "failed to process CustomActionData"); - - WcaLog(LOGMSG_VERBOSE, "Configuring Service: %ls", pwzServiceName); - - // Open the handle with all the permissions we might need: - // SERVICE_QUERY_CONFIG is needed for QueryServiceConfig2(). - // SERVICE_CHANGE_CONFIG is needed for ChangeServiceConfig2(). - // SERVICE_START is required in order to handle SC_ACTION_RESTART action. - hr = GetService(hSCM, pwzServiceName, SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | SERVICE_START, &hService); - ExitOnFailure(hr, "Failed to get service: %ls", pwzServiceName); - - // If we are configuring a service that existed on the machine, we need to - // read the existing service configuration and write it out to the rollback - // log so rollback can put it back if anything goes wrong. - if (!fNewService) - { - // First, read the existing service config. - if (!::QueryServiceConfig2W(hService, SERVICE_CONFIG_FAILURE_ACTIONS, NULL, 0, &cbExistingServiceConfig) && ERROR_INSUFFICIENT_BUFFER != ::GetLastError()) - { - ExitWithLastError(hr, "Failed to get current service config info."); - } - - psfa = static_cast(MemAlloc(cbExistingServiceConfig, TRUE)); - ExitOnNull(psfa, hr, E_OUTOFMEMORY, "failed to allocate memory for service failure actions."); - - if (!::QueryServiceConfig2W(hService, SERVICE_CONFIG_FAILURE_ACTIONS, (LPBYTE)psfa, cbExistingServiceConfig, &cbExistingServiceConfig)) - { - ExitOnLastError(hr, "failed to Query Service."); - } - - // Build up rollback log so we can restore service state if necessary - hr = WcaCaScriptWriteString(hRollbackScript, pwzServiceName); - ExitOnFailure(hr, "Failed to add service name to Rollback Log"); - - // If this service struct is empty, fill in default values - if (3 > psfa->cActions) - { - hr = WcaCaScriptWriteString(hRollbackScript, c_wzActionTypeNone); - ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); - - hr = WcaCaScriptWriteString(hRollbackScript, c_wzActionTypeNone); - ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); - - hr = WcaCaScriptWriteString(hRollbackScript, c_wzActionTypeNone); - ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); - } - else - { - // psfa actually had actions defined, so use the first three. - for (int i = 0; i < 3; ++i) - { - hr = GetSCActionTypeString(psfa->lpsaActions[i].Type, wzActionName, countof(wzActionName)); - ExitOnFailure(hr, "failed to query SFA object"); - - if (SC_ACTION_RESTART == psfa->lpsaActions[i].Type) - { - dwRestartDelay = psfa->lpsaActions[i].Delay / 1000; - } - - hr = WcaCaScriptWriteString(hRollbackScript, wzActionName); - ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); - } - } - - hr = WcaCaScriptWriteNumber(hRollbackScript, psfa->dwResetPeriod / (24 * 60 * 60)); - ExitOnFailure(hr, "failed to add data to CustomActionData"); - - hr = WcaCaScriptWriteNumber(hRollbackScript, dwRestartDelay); - ExitOnFailure(hr, "failed to add data to CustomActionData"); - - // Handle the null cases. - if (!psfa->lpCommand) - { - psfa->lpCommand = L""; - } - hr = WcaCaScriptWriteString(hRollbackScript, psfa->lpCommand); - ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); - - // Handle the null cases. - if (!psfa->lpRebootMsg) - { - psfa->lpRebootMsg = L""; - } - hr = WcaCaScriptWriteString(hRollbackScript, psfa->lpRebootMsg); - ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); - - // Nudge the system to get all our rollback data written to disk. - WcaCaScriptFlush(hRollbackScript); - - ReleaseNullMem(psfa); - } - - hr = ConfigureService(hSCM, hService, pwzServiceName, dwRestartServiceDelayInSeconds, pwzFirstFailureActionType, - pwzSecondFailureActionType, pwzThirdFailureActionType, dwResetPeriodInDays, pwzRebootMessage, pwzProgramCommandLine); - ExitOnFailure(hr, "Failed to configure service: %ls", pwzServiceName); - - hr = WcaProgressMessage(COST_SERVICECONFIG, FALSE); - ExitOnFailure(hr, "failed to send progress message"); - - // Per-service cleanup - ::CloseServiceHandle(hService); - hService = NULL; - dwResetPeriodInDays = 0; - dwRestartServiceDelayInSeconds = 0; - } - -LExit: - WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_PRESERVE); - - if (lpMsgBuf) - { - ::LocalFree(lpMsgBuf); - } - - if (hService) - { - ::CloseServiceHandle(hService); - } - - if (hSCM) - { - ::CloseServiceHandle(hSCM); - } - - ReleaseMem(psfa); - - ReleaseStr(pwzRebootMessage); - ReleaseStr(pwzProgramCommandLine); - ReleaseStr(pwzThirdFailureActionType); - ReleaseStr(pwzSecondFailureActionType); - ReleaseStr(pwzFirstFailureActionType); - ReleaseStr(pwzServiceName); - ReleaseStr(pwzScriptKey); - ReleaseStr(pwzCustomActionData); - - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} - - -/****************************************************************** -RollbackServiceConfig - entry point for ServiceConfig rollback - Custom Action. - -NOTE: CustomActionScript Data == wzServiceName\twzFirstFailureActionType\twzSecondFailureActionType\twzThirdFailureActionType\tdwResetPeriodInDays\tdwRestartServiceDelayInSeconds\twzProgramCommandLine\twzRebootMessage\twzServiceName\t... -*******************************************************************/ -extern "C" UINT __stdcall RollbackServiceConfig( - __in MSIHANDLE hInstall - ) -{ - //AssertSz(FALSE, "debug RollbackServiceConfig"); - HRESULT hr = S_OK; - DWORD er = 0; - - LPWSTR pwzCustomActionData = NULL; - LPWSTR pwz = NULL; - - LPWSTR pwzScriptKey = NULL; - WCA_CASCRIPT_HANDLE hRollbackScript = NULL; - - LPWSTR pwzServiceName = NULL; - LPWSTR pwzFirstFailureActionType = NULL; - LPWSTR pwzSecondFailureActionType = NULL; - LPWSTR pwzThirdFailureActionType = NULL; - LPWSTR pwzProgramCommandLine = NULL; - LPWSTR pwzRebootMessage = NULL; - DWORD dwResetPeriodInDays = 0; - DWORD dwRestartServiceDelayInSeconds = 0; - - LPVOID lpMsgBuf = NULL; - SC_HANDLE hSCM = NULL; - SC_HANDLE hService = NULL; - - // initialize - hr = WcaInitialize(hInstall, "RollbackServiceConfig"); - ExitOnFailure(hr, "Failed to initialize 'RollbackServiceConfig'."); - - // Open the Services Control Manager up front. - hSCM = ::OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); - if (NULL == hSCM) - { - er = ::GetLastError(); - hr = HRESULT_FROM_WIN32(er); - -#pragma prefast(push) -#pragma prefast(disable:25028) - ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, er, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpMsgBuf, 0, NULL); -#pragma prefast(pop) - - ExitOnFailure(hr, "Failed to get handle to SCM. Error: %ls", (LPWSTR)lpMsgBuf); - - // Make sure we still abort, in case hSCM was NULL but no error was returned from GetLastError - ExitOnNull(hSCM, hr, E_POINTER, "Getting handle to SCM reported success, but no handle was returned."); - } - - // Get the script key from the CustomAction data and use it to open - // the rollback log and read the data over the CustomActionData - // because all of the information is in the script data not the - // CustomActionData. - hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData); - ExitOnFailure(hr, "failed to get CustomActionData"); - - WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); - - pwz = pwzCustomActionData; - - hr = WcaReadStringFromCaData(&pwz, &pwzScriptKey); - if (!pwzScriptKey) - { - hr = E_UNEXPECTED; - ExitOnFailure(hr, "Failed due to unexpected CustomActionData passed."); - } - ExitOnFailure(hr, "Failed to read encoding key from CustomActionData."); - - hr = WcaCaScriptOpen(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, &hRollbackScript); - ExitOnFailure(hr, "Failed to open rollback CustomAction script."); - - hr = WcaCaScriptReadAsCustomActionData(hRollbackScript, &pwzCustomActionData); - ExitOnFailure(hr, "Failed to read rollback script into CustomAction data."); - - // Loop through the script's CustomActionData, processing each - // service config in turn. - pwz = pwzCustomActionData; - while (pwz && *pwz) - { - hr = WcaReadStringFromCaData(&pwz, &pwzServiceName); - ExitOnFailure(hr, "failed to process CustomActionData"); - hr = WcaReadStringFromCaData(&pwz, &pwzFirstFailureActionType); - ExitOnFailure(hr, "failed to process CustomActionData"); - hr = WcaReadStringFromCaData(&pwz, &pwzSecondFailureActionType); - ExitOnFailure(hr, "failed to process CustomActionData"); - hr = WcaReadStringFromCaData(&pwz, &pwzThirdFailureActionType); - ExitOnFailure(hr, "failed to process CustomActionData"); - hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&dwResetPeriodInDays)); - ExitOnFailure(hr, "failed to process CustomActionData"); - hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&dwRestartServiceDelayInSeconds)); - ExitOnFailure(hr, "failed to process CustomActionData"); - hr = WcaReadStringFromCaData(&pwz, &pwzProgramCommandLine); - ExitOnFailure(hr, "failed to process CustomActionData"); - hr = WcaReadStringFromCaData(&pwz, &pwzRebootMessage); - ExitOnFailure(hr, "failed to process CustomActionData"); - - WcaLog(LOGMSG_VERBOSE, "Reconfiguring Service: %ls", pwzServiceName); - - // Open the handle with all the permissions we might need. - // SERVICE_CHANGE_CONFIG is needed for ChangeServiceConfig2(). - // SERVICE_START is required in order to handle SC_ACTION_RESTART action. - hr = GetService(hSCM, pwzServiceName, SERVICE_CHANGE_CONFIG | SERVICE_START, &hService); - ExitOnFailure(hr, "Failed to get service: %ls", pwzServiceName); - - hr = ConfigureService(hSCM, hService, pwzServiceName, dwRestartServiceDelayInSeconds, pwzFirstFailureActionType, - pwzSecondFailureActionType, pwzThirdFailureActionType, dwResetPeriodInDays, pwzRebootMessage, pwzProgramCommandLine); - ExitOnFailure(hr, "Failed to configure service: %ls", pwzServiceName); - - hr = WcaProgressMessage(COST_SERVICECONFIG, FALSE); - ExitOnFailure(hr, "failed to send progress message"); - - // Per-service cleanup - ::CloseServiceHandle(hService); - hService = NULL; - dwResetPeriodInDays = 0; - dwRestartServiceDelayInSeconds = 0; - } - -LExit: - if (lpMsgBuf) // Allocated with FormatString. - { - ::LocalFree(lpMsgBuf); - } - - if (hService) - { - ::CloseServiceHandle(hService); - } - - if (hSCM) - { - ::CloseServiceHandle(hSCM); - } - - WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_DELETE); - - ReleaseStr(pwzRebootMessage); - ReleaseStr(pwzProgramCommandLine); - ReleaseStr(pwzThirdFailureActionType); - ReleaseStr(pwzSecondFailureActionType); - ReleaseStr(pwzFirstFailureActionType); - ReleaseStr(pwzServiceName); - ReleaseStr(pwzScriptKey); - ReleaseStr(pwzCustomActionData); - - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} - - -/********************************************************** -GetSCActionType - helper function to return the SC_ACTION_TYPE -for a given string matching the allowed set. -REBOOT, RESTART, RUN_COMMAND and NONE -**********************************************************/ -static SC_ACTION_TYPE GetSCActionType( - __in LPCWSTR pwzActionTypeName - ) -{ - SC_ACTION_TYPE actionType; - - // verify that action types are valid. if not, just default to NONE - if (0 == lstrcmpiW(c_wzActionTypeReboot, pwzActionTypeName)) - { - actionType = SC_ACTION_REBOOT; - } - else if (0 == lstrcmpiW(c_wzActionTypeRestart, pwzActionTypeName)) - { - actionType = SC_ACTION_RESTART; - } - else if (0 == lstrcmpiW(c_wzActionTypeRunCommand, pwzActionTypeName)) - { - actionType = SC_ACTION_RUN_COMMAND; - } - else - { - // default to none - actionType = SC_ACTION_NONE; - } - - return actionType; -} - - -static HRESULT GetSCActionTypeString( - __in SC_ACTION_TYPE type, - __out_ecount(cchActionTypeString) LPWSTR wzActionTypeString, - __in DWORD cchActionTypeString - ) -{ - HRESULT hr = S_OK; - - switch (type) - { - case SC_ACTION_REBOOT: - hr = StringCchCopyW(wzActionTypeString, cchActionTypeString, c_wzActionTypeReboot); - ExitOnFailure(hr, "Failed to copy 'reboot' into action type."); - break; - case SC_ACTION_RESTART: - hr = StringCchCopyW(wzActionTypeString, cchActionTypeString, c_wzActionTypeRestart); - ExitOnFailure(hr, "Failed to copy 'restart' into action type."); - break; - case SC_ACTION_RUN_COMMAND: - hr = StringCchCopyW(wzActionTypeString, cchActionTypeString, c_wzActionTypeRunCommand); - ExitOnFailure(hr, "Failed to copy 'runCommand' into action type."); - break; - case SC_ACTION_NONE: - hr = StringCchCopyW(wzActionTypeString, cchActionTypeString, c_wzActionTypeNone); - ExitOnFailure(hr, "Failed to copy 'none' into action type."); - break; - default: - break; - } - -LExit: - return hr; -} - - -static HRESULT GetService( - __in SC_HANDLE hSCM, - __in LPCWSTR wzService, - __in DWORD dwOpenServiceAccess, - __out SC_HANDLE* phService - ) -{ - HRESULT hr = S_OK; - DWORD er = ERROR_SUCCESS; - LPVOID lpMsgBuf = NULL; - - *phService = ::OpenServiceW(hSCM, wzService, dwOpenServiceAccess); - if (NULL == *phService) - { - er = ::GetLastError(); - hr = HRESULT_FROM_WIN32(er); - if (ERROR_SERVICE_DOES_NOT_EXIST == er) - { - ExitOnFailure(hr, "Service '%ls' does not exist on this system.", wzService); - } - else - { -#pragma prefast(push) -#pragma prefast(disable:25028) - ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, er, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpMsgBuf, 0, NULL); -#pragma prefast(pop) - - ExitOnFailure(hr, "Failed to get handle to the service '%ls'. Error: %ls", wzService, (LPWSTR)lpMsgBuf); - } - } - -LExit: - if (lpMsgBuf) // Allocated with FormatString. - { - ::LocalFree(lpMsgBuf); - } - - return hr; -} - - -static HRESULT ConfigureService( - __in SC_HANDLE /*hSCM*/, - __in SC_HANDLE hService, - __in LPCWSTR wzServiceName, - __in DWORD dwRestartServiceDelayInSeconds, - __in LPCWSTR wzFirstFailureActionType, - __in LPCWSTR wzSecondFailureActionType, - __in LPCWSTR wzThirdFailureActionType, - __in DWORD dwResetPeriodInDays, - __in LPWSTR wzRebootMessage, - __in LPWSTR wzProgramCommandLine - ) -{ - HRESULT hr = S_OK; - DWORD er = ERROR_SUCCESS; - - HANDLE hToken = NULL; - TOKEN_PRIVILEGES priv = { 0 }; - TOKEN_PRIVILEGES* pPrevPriv = NULL; - DWORD cbPrevPriv = 0; - BOOL fAdjustedPrivileges = FALSE; - - SC_ACTION actions[3]; // the UI always shows 3 actions, so we'll always do 3 - SERVICE_FAILURE_ACTIONSW sfa; - LPVOID lpMsgBuf = NULL; - - // Always get the shutdown privilege in case we need to configure service to reboot. - if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken)) - { - ExitWithLastError(hr, "Failed to get process token."); - } - - priv.PrivilegeCount = 1; - priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - if (!::LookupPrivilegeValueW(NULL, L"SeShutdownPrivilege", &priv.Privileges[0].Luid)) - { - ExitWithLastError(hr, "Failed to get shutdown privilege LUID."); - } - - cbPrevPriv = sizeof(TOKEN_PRIVILEGES); - pPrevPriv = static_cast(MemAlloc(cbPrevPriv, TRUE)); - ExitOnNull(pPrevPriv, hr, E_OUTOFMEMORY, "Failed to allocate memory for empty previous privileges."); - - if (!::AdjustTokenPrivileges(hToken, FALSE, &priv, cbPrevPriv, pPrevPriv, &cbPrevPriv)) - { - LPVOID pv = MemReAlloc(pPrevPriv, cbPrevPriv, TRUE); - ExitOnNull(pv, hr, E_OUTOFMEMORY, "Failed to allocate memory for previous privileges."); - pPrevPriv = static_cast(pv); - - if (!::AdjustTokenPrivileges(hToken, FALSE, &priv, cbPrevPriv, pPrevPriv, &cbPrevPriv)) - { - ExitWithLastError(hr, "Failed to get shutdown privilege LUID."); - } - } - - fAdjustedPrivileges = TRUE; - - // build up SC_ACTION array - // TODO: why is delay only respected when SC_ACTION_RESTART is requested? - actions[0].Type = GetSCActionType(wzFirstFailureActionType); - actions[0].Delay = 0; - if (SC_ACTION_RESTART == actions[0].Type) - { - actions[0].Delay = dwRestartServiceDelayInSeconds * 1000; // seconds to milliseconds - } - - actions[1].Type = GetSCActionType(wzSecondFailureActionType); - actions[1].Delay = 0; - if (SC_ACTION_RESTART == actions[1].Type) - { - actions[1].Delay = dwRestartServiceDelayInSeconds * 1000; // seconds to milliseconds - } - - actions[2].Type = GetSCActionType(wzThirdFailureActionType); - actions[2].Delay = 0; - if (SC_ACTION_RESTART == actions[2].Type) - { - actions[2].Delay = dwRestartServiceDelayInSeconds * 1000; // seconds to milliseconds - } - - // build up the SERVICE_FAILURE_ACTIONSW struct - sfa.dwResetPeriod = dwResetPeriodInDays * (24 * 60 * 60); // days to seconds - sfa.lpRebootMsg = wzRebootMessage; - sfa.lpCommand = wzProgramCommandLine; - sfa.cActions = countof(actions); - sfa.lpsaActions = actions; - - // Call ChangeServiceConfig2 to actually set up the failure actions - if (!::ChangeServiceConfig2W(hService, SERVICE_CONFIG_FAILURE_ACTIONS, (LPVOID)&sfa)) - { - er = ::GetLastError(); - hr = HRESULT_FROM_WIN32(er); - -#pragma prefast(push) -#pragma prefast(disable:25028) - ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, er, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpMsgBuf, 0, NULL); -#pragma prefast(pop) - - // Check if this is a service that can't be modified. - if (ERROR_CANNOT_DETECT_PROCESS_ABORT == er) - { - WcaLog(LOGMSG_STANDARD, "WARNING: Service \"%ls\" is not configurable on this server and will not be set.", wzServiceName); - } - ExitOnFailure(hr, "Cannot change service configuration. Error: %ls", (LPWSTR)lpMsgBuf); - - if (lpMsgBuf) - { - ::LocalFree(lpMsgBuf); - lpMsgBuf = NULL; - } - } - -LExit: - if (lpMsgBuf) - { - ::LocalFree(lpMsgBuf); - } - - if (fAdjustedPrivileges) - { - ::AdjustTokenPrivileges(hToken, FALSE, pPrevPriv, 0, NULL, NULL); - } - - ReleaseMem(pPrevPriv); - ReleaseHandle(hToken); - - return hr; -} diff --git a/src/ca/shellexecca.cpp b/src/ca/shellexecca.cpp deleted file mode 100644 index ea21d3bd..00000000 --- a/src/ca/shellexecca.cpp +++ /dev/null @@ -1,271 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" - -HRESULT ShellExec( - __in LPCWSTR wzTarget, - __in BOOL fUnelevated - ) -{ - HRESULT hr = S_OK; - LPWSTR sczWorkingDirectory = NULL; - - // a reasonable working directory (not the system32 default from MSI) is the directory where the target lives - hr = PathGetDirectory(wzTarget, &sczWorkingDirectory); - ExitOnFailure(hr, "failed to get directory for target: %ls", wzTarget); - - if (!DirExists(sczWorkingDirectory, NULL)) - { - ReleaseNullStr(sczWorkingDirectory); - } - - if (fUnelevated) - { - hr = ShelExecUnelevated(wzTarget, NULL, NULL, sczWorkingDirectory, SW_SHOWDEFAULT); - ExitOnFailure(hr, "ShelExecUnelevated failed with target %ls", wzTarget); - } - else - { - HINSTANCE hinst = ::ShellExecuteW(NULL, NULL, wzTarget, NULL, sczWorkingDirectory, SW_SHOWDEFAULT); - if (hinst <= HINSTANCE(32)) - { - LONG64 code = reinterpret_cast(hinst); - switch (code) - { - case ERROR_FILE_NOT_FOUND: - hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); - break; - case ERROR_PATH_NOT_FOUND: - hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); - break; - case ERROR_BAD_FORMAT: - hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT); - break; - case SE_ERR_ASSOCINCOMPLETE: - case SE_ERR_NOASSOC: - hr = HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION); - break; - case SE_ERR_DDEBUSY: - case SE_ERR_DDEFAIL: - case SE_ERR_DDETIMEOUT: - hr = HRESULT_FROM_WIN32(ERROR_DDE_FAIL); - break; - case SE_ERR_DLLNOTFOUND: - hr = HRESULT_FROM_WIN32(ERROR_DLL_NOT_FOUND); - break; - case SE_ERR_OOM: - hr = E_OUTOFMEMORY; - break; - case SE_ERR_ACCESSDENIED: - hr = E_ACCESSDENIED; - break; - default: - hr = E_FAIL; - } - - ExitOnFailure(hr, "ShellExec failed with return code %llu.", code); - } - } - - -LExit: - ReleaseStr(sczWorkingDirectory); - return hr; -} - -extern "C" UINT __stdcall WixShellExec( - __in MSIHANDLE hInstall - ) -{ - Assert(hInstall); - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - LPWSTR pwzTarget = NULL; - - hr = WcaInitialize(hInstall, "WixShellExec"); - ExitOnFailure(hr, "failed to initialize"); - - hr = WcaGetFormattedProperty(L"WixShellExecTarget", &pwzTarget); - ExitOnFailure(hr, "failed to get WixShellExecTarget"); - - WcaLog(LOGMSG_VERBOSE, "WixShellExecTarget is %ls", pwzTarget); - - if (!pwzTarget || !*pwzTarget) - { - hr = E_INVALIDARG; - ExitOnFailure(hr, "failed to get WixShellExecTarget"); - } - - hr = ShellExec(pwzTarget, FALSE); - ExitOnFailure(hr, "failed to launch target"); - -LExit: - ReleaseStr(pwzTarget); - - if (FAILED(hr)) - { - er = ERROR_INSTALL_FAILURE; - } - return WcaFinalize(er); -} - -extern "C" UINT __stdcall WixUnelevatedShellExec( - __in MSIHANDLE hInstall - ) -{ - Assert(hInstall); - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - LPWSTR pwzTarget = NULL; - - hr = WcaInitialize(hInstall, "WixUnelevatedShellExec"); - ExitOnFailure(hr, "failed to initialize"); - - hr = WcaGetFormattedProperty(L"WixUnelevatedShellExecTarget", &pwzTarget); - ExitOnFailure(hr, "failed to get WixUnelevatedShellExecTarget"); - - WcaLog(LOGMSG_VERBOSE, "WixUnelevatedShellExecTarget is %ls", pwzTarget); - - if (!pwzTarget || !*pwzTarget) - { - hr = E_INVALIDARG; - ExitOnFailure(hr, "failed to get WixShellExecTarget"); - } - - hr = ShellExec(pwzTarget, TRUE); - ExitOnFailure(hr, "failed to launch target"); - -LExit: - ReleaseStr(pwzTarget); - - if (FAILED(hr)) - { - er = ERROR_INSTALL_FAILURE; - } - return WcaFinalize(er); -} - -// -// ExtractBinary extracts the data from the Binary table row with the given ID into a file. -// -HRESULT ExtractBinary( - __in LPCWSTR wzBinaryId, - __out BYTE** pbData, - __out DWORD* pcbData - ) -{ - HRESULT hr = S_OK; - LPWSTR pwzSql = NULL; - PMSIHANDLE hView; - PMSIHANDLE hRec; - - // make sure we're not horked from the get-go - hr = WcaTableExists(L"Binary"); - if (S_OK != hr) - { - if (SUCCEEDED(hr)) - { - hr = E_UNEXPECTED; - } - ExitOnFailure(hr, "There is no Binary table."); - } - - ExitOnNull(wzBinaryId, hr, E_INVALIDARG, "Binary ID cannot be null"); - ExitOnNull(*wzBinaryId, hr, E_INVALIDARG, "Binary ID cannot be empty string"); - - hr = StrAllocFormatted(&pwzSql, L"SELECT `Data` FROM `Binary` WHERE `Name`=\'%s\'", wzBinaryId); - ExitOnFailure(hr, "Failed to allocate Binary table query."); - - hr = WcaOpenExecuteView(pwzSql, &hView); - ExitOnFailure(hr, "Failed to open view on Binary table"); - - hr = WcaFetchSingleRecord(hView, &hRec); - ExitOnFailure(hr, "Failed to retrieve request from Binary table"); - - hr = WcaGetRecordStream(hRec, 1, pbData, pcbData); - ExitOnFailure(hr, "Failed to read Binary.Data."); - -LExit: - ReleaseStr(pwzSql); - - return hr; -} - -extern "C" UINT __stdcall WixShellExecBinary( - __in MSIHANDLE hInstall - ) -{ - Assert(hInstall); - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - LPWSTR pwzBinary = NULL; - LPWSTR pwzFilename = NULL; - BYTE* pbData = NULL; - DWORD cbData = 0; - HANDLE hFile = INVALID_HANDLE_VALUE; - -#if 0 - ::MessageBoxA(0, "WixShellExecBinary", "-->> ATTACH HERE", MB_OK); -#endif - - hr = WcaInitialize(hInstall, "WixShellExecBinary"); - ExitOnFailure(hr, "failed to initialize"); - - hr = WcaGetFormattedProperty(L"WixShellExecBinaryId", &pwzBinary); - ExitOnFailure(hr, "failed to get WixShellExecBinaryId"); - - WcaLog(LOGMSG_VERBOSE, "WixShellExecBinaryId is %ls", pwzBinary); - - if (!pwzBinary || !*pwzBinary) - { - hr = E_INVALIDARG; - ExitOnFailure(hr, "failed to get WixShellExecBinaryId"); - } - - // get temporary path for extracted file - StrAlloc(&pwzFilename, MAX_PATH); - ExitOnFailure(hr, "Failed to allocate temporary path"); - ::GetTempPathW(MAX_PATH, pwzFilename); - hr = ::StringCchCatW(pwzFilename, MAX_PATH, pwzBinary); - ExitOnFailure(hr, "Failed to append filename."); - - // grab the bits - hr = ExtractBinary(pwzBinary, &pbData, &cbData); - ExitOnFailure(hr, "failed to extract binary data"); - - // write 'em to the temp file - hFile = ::CreateFileW(pwzFilename, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (INVALID_HANDLE_VALUE == hFile) - { - ExitWithLastError(hr, "Failed to open new temp file: %ls", pwzFilename); - } - - DWORD cbWritten = 0; - if (!::WriteFile(hFile, pbData, cbData, &cbWritten, NULL)) - { - ExitWithLastError(hr, "Failed to write data to new temp file: %ls", pwzFilename); - } - - // close it - ::CloseHandle(hFile); - hFile = INVALID_HANDLE_VALUE; - - // and run it - hr = ShellExec(pwzFilename, FALSE); - ExitOnFailure(hr, "failed to launch target: %ls", pwzFilename); - -LExit: - ReleaseStr(pwzBinary); - ReleaseStr(pwzFilename); - ReleaseMem(pbData); - if (INVALID_HANDLE_VALUE != hFile) - { - ::CloseHandle(hFile); - } - - if (FAILED(hr)) - { - er = ERROR_INSTALL_FAILURE; - } - return WcaFinalize(er); -} diff --git a/src/ca/test.cpp b/src/ca/test.cpp deleted file mode 100644 index c4d215f0..00000000 --- a/src/ca/test.cpp +++ /dev/null @@ -1,269 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" - -#define WIXCA_UITHREAD_CLASS_WINDOW L"WixCaMessageWindow" - -extern HMODULE g_hInstCADLL; - - -// structs - -struct UITHREAD_CONTEXT -{ - HANDLE hInitializedEvent; - HINSTANCE hInstance; - HWND hWnd; -}; - - -// internal function declarations - -static HRESULT CreateMessageWindow( - __out HWND* phWnd - ); - -static void CloseMessageWindow( - __in HWND hWnd - ); - -static DWORD WINAPI ThreadProc( - __in LPVOID pvContext - ); - -static LRESULT CALLBACK WndProc( - __in HWND hWnd, - __in UINT uMsg, - __in WPARAM wParam, - __in LPARAM lParam - ); - - -/****************************************************************** -WixFailWhenDeferred - entry point for WixFailWhenDeferred - custom action which always fails when running as a deferred - custom action (otherwise it blindly succeeds). It's useful when - testing the rollback of deferred custom actions: Schedule it - immediately after the rollback/deferred CA pair you're testing - and it will fail, causing your rollback CA to get invoked. -********************************************************************/ -extern "C" UINT __stdcall WixFailWhenDeferred( - __in MSIHANDLE hInstall - ) -{ - return ::MsiGetMode(hInstall, MSIRUNMODE_SCHEDULED) ? ERROR_INSTALL_FAILURE : ERROR_SUCCESS; -} - -/****************************************************************** -WixWaitForEvent - entry point for WixWaitForEvent custom action - which waits for either the WixWaitForEventFail or - WixWaitForEventSucceed named auto reset events. Signaling the - WixWaitForEventFail event will return ERROR_INSTALL_FAILURE or - signaling the WixWaitForEventSucceed event will return - ERROR_SUCCESS. Both events are declared in the Global\ namespace. -********************************************************************/ -extern "C" UINT __stdcall WixWaitForEvent( - __in MSIHANDLE hInstall - ) -{ - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - HWND hMessageWindow = NULL; - LPCWSTR wzSDDL = L"D:(A;;GA;;;WD)"; - OS_VERSION version = OS_VERSION_UNKNOWN; - DWORD dwServicePack = 0; - PSECURITY_DESCRIPTOR pSD = NULL; - SECURITY_ATTRIBUTES sa = { }; - HANDLE rghEvents[2]; - - hr = WcaInitialize(hInstall, "WixWaitForEvent"); - ExitOnFailure(hr, "Failed to initialize."); - - // Create a window to prevent shutdown requests. - hr = CreateMessageWindow(&hMessageWindow); - ExitOnFailure(hr, "Failed to create message window."); - - // If running on Vista/2008 or newer use integrity enhancements. - OsGetVersion(&version, &dwServicePack); - if (OS_VERSION_VISTA <= version) - { - // Add SACL to allow Everyone to signal from a medium integrity level. - wzSDDL = L"D:(A;;GA;;;WD)S:(ML;;NW;;;ME)"; - } - - // Create the security descriptor and attributes for the events. - if (!::ConvertStringSecurityDescriptorToSecurityDescriptorW(wzSDDL, SDDL_REVISION_1, &pSD, NULL)) - { - ExitWithLastError(hr, "Failed to create the security descriptor for the events."); - } - - sa.nLength = sizeof(sa); - sa.lpSecurityDescriptor = pSD; - sa.bInheritHandle = FALSE; - - rghEvents[0] = ::CreateEventW(&sa, FALSE, FALSE, L"Global\\WixWaitForEventFail"); - ExitOnNullWithLastError(rghEvents[0], hr, "Failed to create the Global\\WixWaitForEventFail event."); - - rghEvents[1] = ::CreateEventW(&sa, FALSE, FALSE, L"Global\\WixWaitForEventSucceed"); - ExitOnNullWithLastError(rghEvents[1], hr, "Failed to create the Global\\WixWaitForEventSucceed event."); - - // Wait for either of the events to be signaled and handle accordingly. - er = ::WaitForMultipleObjects(countof(rghEvents), rghEvents, FALSE, INFINITE); - switch (er) - { - case WAIT_OBJECT_0 + 0: - er = ERROR_INSTALL_FAILURE; - break; - case WAIT_OBJECT_0 + 1: - er = ERROR_SUCCESS; - break; - default: - ExitOnWin32Error(er, hr, "Unexpected failure."); - } - -LExit: - ReleaseHandle(rghEvents[1]); - ReleaseHandle(rghEvents[0]); - - if (pSD) - { - ::LocalFree(pSD); - } - - if (hMessageWindow) - { - CloseMessageWindow(hMessageWindow); - } - - if (FAILED(hr)) - { - er = ERROR_INSTALL_FAILURE; - } - - return WcaFinalize(er); -} - - -// internal function definitions - -static HRESULT CreateMessageWindow( - __out HWND* phWnd - ) -{ - HRESULT hr = S_OK; - HANDLE rgWaitHandles[2] = { }; - UITHREAD_CONTEXT context = { }; - - // Create event to signal after the UI thread / window is initialized. - rgWaitHandles[0] = ::CreateEventW(NULL, TRUE, FALSE, NULL); - ExitOnNullWithLastError(rgWaitHandles[0], hr, "Failed to create initialization event."); - - // Pass necessary information to create the window. - context.hInitializedEvent = rgWaitHandles[0]; - context.hInstance = (HINSTANCE)g_hInstCADLL; - - // Create our separate UI thread. - rgWaitHandles[1] = ::CreateThread(NULL, 0, ThreadProc, &context, 0, NULL); - ExitOnNullWithLastError(rgWaitHandles[1], hr, "Failed to create the UI thread."); - - // Wait for either the thread to be initialized or the window to exit / fail prematurely. - ::WaitForMultipleObjects(countof(rgWaitHandles), rgWaitHandles, FALSE, INFINITE); - - // Pass the window back to the caller. - *phWnd = context.hWnd; - -LExit: - ReleaseHandle(rgWaitHandles[1]); - ReleaseHandle(rgWaitHandles[0]); - - return hr; -} - -static void CloseMessageWindow( - __in HWND hWnd - ) -{ - if (::IsWindow(hWnd)) - { - ::PostMessageW(hWnd, WM_CLOSE, 0, 0); - } -} - -static DWORD WINAPI ThreadProc( - __in LPVOID pvContext - ) -{ - HRESULT hr = S_OK; - UITHREAD_CONTEXT* pContext = static_cast(pvContext); - - WNDCLASSW wc = { }; - BOOL fRegistered = TRUE; - HWND hWnd = NULL; - - BOOL fRet = FALSE; - MSG msg = { }; - - wc.lpfnWndProc = WndProc; - wc.hInstance = pContext->hInstance; - wc.lpszClassName = WIXCA_UITHREAD_CLASS_WINDOW; - - if (!::RegisterClassW(&wc)) - { - ExitWithLastError(hr, "Failed to register window."); - } - - fRegistered = TRUE; - - // Create the window to handle reboots without activating it. - hWnd = ::CreateWindowExW(WS_EX_TOOLWINDOW, wc.lpszClassName, NULL, WS_POPUP | WS_VISIBLE, CW_USEDEFAULT, SW_SHOWNA, 0, 0, HWND_DESKTOP, NULL, pContext->hInstance, NULL); - ExitOnNullWithLastError(hWnd, hr, "Failed to create window."); - - // Persist the window handle and let the caller know we've initialized. - pContext->hWnd = hWnd; - ::SetEvent(pContext->hInitializedEvent); - - // Pump messages until the window is closed. - while (0 != (fRet = ::GetMessageW(&msg, NULL, 0, 0))) - { - if (-1 == fRet) - { - hr = E_UNEXPECTED; - ExitOnFailure(hr, "Unexpected return value from message pump."); - } - else if (!::IsDialogMessageW(msg.hwnd, &msg)) - { - ::TranslateMessage(&msg); - ::DispatchMessageW(&msg); - } - } - -LExit: - if (fRegistered) - { - ::UnregisterClassW(WIXCA_UITHREAD_CLASS_WINDOW, pContext->hInstance); - } - - return hr; -} - -static LRESULT CALLBACK WndProc( - __in HWND hWnd, - __in UINT uMsg, - __in WPARAM wParam, - __in LPARAM lParam - ) -{ - switch (uMsg) - { - case WM_QUERYENDSESSION: - // Prevent the process from being shut down. - WcaLog(LOGMSG_VERBOSE, "Disallowed system request to shut down the custom action server."); - return FALSE; - - case WM_DESTROY: - ::PostQuitMessage(0); - return 0; - } - - return ::DefWindowProcW(hWnd, uMsg, wParam, lParam); -} diff --git a/src/ca/utilca.cpp b/src/ca/utilca.cpp deleted file mode 100644 index 37664a1c..00000000 --- a/src/ca/utilca.cpp +++ /dev/null @@ -1,3 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -#include "precomp.h" diff --git a/src/ca/utilca.def b/src/ca/utilca.def deleted file mode 100644 index 412d86a3..00000000 --- a/src/ca/utilca.def +++ /dev/null @@ -1,91 +0,0 @@ -; Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - - -LIBRARY "utilca" - -EXPORTS -; BroadcastSettingChange.cpp - WixBroadcastSettingChange - WixBroadcastEnvironmentChange -; checkreboot.cpp - WixCheckRebootRequired -; closeapps.cpp - WixCloseApplications - WixCloseApplicationsDeferred -; exitearlywithsuccess.cpp - WixExitEarlyWithSuccess -; FormatFiles.cpp - WixSchedFormatFiles - WixExecFormatFiles -; osinfo.cpp - WixQueryOsInfo - WixQueryOsDirs - WixQueryOsWellKnownSID - WixQueryOsDriverInfo -; netshortcuts.cpp - WixSchedInternetShortcuts - WixCreateInternetShortcuts - WixRollbackInternetShortcuts -; qtexecca.cpp - CAQuietExec - CAQuietExec64 - WixQuietExec - WixQuietExec64 - WixSilentExec - WixSilentExec64 -; RemoveFoldersEx.cpp - WixRemoveFoldersEx -; RemoveRegistryKeysEx.cpp - WixRemoveRegistryKeysEx -;scaexec.cpp - RegisterPerfCounterData - UnregisterPerfCounterData - RegisterPerfmon - UnregisterPerfmon - CreateSmb - DropSmb - CreateUser - CreateUserRollback - RemoveUser -;scasched.cpp - ConfigurePerfmonInstall - ConfigurePerfmonUninstall - ConfigureSmbInstall - ConfigureSmbUninstall - ConfigureUsers - InstallPerfCounterData - UninstallPerfCounterData - ConfigurePerfmonManifestRegister - ConfigurePerfmonManifestUnregister - ConfigureEventManifestRegister - ConfigureEventManifestUnregister -; RestartManager.cpp - WixRegisterRestartResources -; secureobj.cpp - SchedSecureObjects - SchedSecureObjectsRollback - ExecSecureObjects - ExecSecureObjectsRollback -; serviceconfig.cpp - SchedServiceConfig - ExecServiceConfig - RollbackServiceConfig -; shellexecca.cpp - WixShellExec - WixShellExecBinary - WixUnelevatedShellExec -; test.cpp - WixFailWhenDeferred - WixWaitForEvent -; TouchFile.cpp - WixTouchFileDuringInstall - WixTouchFileDuringUninstall - WixExecuteTouchFile -; xmlfile.cpp - SchedXmlFile - ExecXmlFile - ExecXmlFileRollback -; xmlconfig.cpp - SchedXmlConfig - ExecXmlConfig - ExecXmlConfigRollback diff --git a/src/ca/utilca.vcxproj b/src/ca/utilca.vcxproj deleted file mode 100644 index 7b64db95..00000000 --- a/src/ca/utilca.vcxproj +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - - Debug - ARM64 - - - Release - ARM64 - - - Debug - X64 - - - Release - X64 - - - Debug - Win32 - - - Release - Win32 - - - - - {076018F7-19BD-423A-ABBF-229273DA08D8} - DynamicLibrary - utilca - v142 - Unicode - utilca.def - WiX Toolset Util CustomAction - - - - - - - activeds.lib;adsiid.lib;msi.lib;netapi32.lib;shlwapi.lib - - - - - - - - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 @@ + + + + + + + + \ 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 @@ + + + + + + Debug + false + MSB3246 + + $(MSBuildProjectName) + $([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)..\build\)) + $(BaseOutputPath)obj\$(ProjectName)\ + $(BaseOutputPath)$(Configuration)\ + + WiX Toolset Team + WiX Toolset + Copyright (c) .NET Foundation and contributors. All rights reserved. + MS-RL + WiX Toolset + + + + + 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 @@ + + + + + + + true + $(SolutionPath) + $(NCrunchOriginalSolutionPath) + + + + + + + $([System.IO.File]::ReadAllText($(TheSolutionPath))) + $([System.IO.Path]::GetDirectoryName( $(TheSolutionPath) )) + (?<="[PackageName]", ")(.*)(?=", ") + + + + + + %(Identity) + $(SolutionFileContent.Contains('\%(Identity).csproj')) + + + + + $(RegexPattern.Replace('[PackageName]','%(PackageName)') ) + $([System.Text.RegularExpressions.Regex]::Match('$(SolutionFileContent)', '%(Pattern)')) + + + + + + + + + + + + + + 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 @@ + + + + + true + true + $([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)wix.snk)) + false + + 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 @@ + + + + + false + $(OutputPath)\$(AssemblyName).xml + + + + + $(PrivateRepositoryUrl.Replace('.git','')) + + $(MSBuildProjectName).nuspec + $(OutputPath)..\ + $(NuspecProperties);Id=$(PackageId);Authors=$(Authors);Copyright=$(Copyright);Description=$(Description);Title=$(Title) + $(NuspecProperties);Version=$(PackageVersion);RepositoryCommit=$(SourceRevisionId);RepositoryType=$(RepositoryType);RepositoryUrl=$(PrivateRepositoryUrl);ProjectFolder=$(MSBuildProjectDirectory)\;ProjectUrl=$(ProjectUrl) + true + snupkg + + + + 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 @@ + + + + + + Win32 + $(BaseIntermediateOutputPath)$(Configuration)\$(Platform)\ + $(OutputPath)$(Platform)\ + + + $(Company) + $(Copyright) + + win-x86;win-x64;win-arm64 + native,Version=v0.0 + + + + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) + + + + $(MSBuildThisFileDirectory)CustomizedNativeRecommendedRules.ruleset + + + + + $(DisableSpecificCompilerWarnings) + Level4 + $(ProjectDir)inc;$(MSBuildProjectDirectory);$(IntDir);$(SqlCESdkIncludePath);$(ProjectAdditionalIncludeDirectories);%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;_WIN32_MSI=500;_WIN32_WINNT=0x0501;$(ArmPreprocessorDefinitions);$(UnicodePreprocessorDefinitions);_CRT_STDIO_LEGACY_WIDE_SPECIFIERS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + Use + precomp.h + StdCall + true + false + -YlprecompDefine + /Zc:threadSafeInit- %(AdditionalOptions) + true + + + $(ArmPreprocessorDefinitions);%(PreprocessorDefinitions) + $(ProjectAdditionalResourceIncludeDirectories);%(AdditionalIncludeDirectories) + + + $(OutDir);$(AdditionalMultiTargetLibraryPath);$(ProjectAdditionalLibraryDirectories);%(AdditionalLibraryDirectories) + + + $(ProjectSubSystem) + $(ProjectModuleDefinitionFile) + $(ResourceOnlyDll) + true + $(ProjectAdditionalLinkLibraries);advapi32.lib;comdlg32.lib;user32.lib;oleaut32.lib;gdi32.lib;shell32.lib;ole32.lib;version.lib;%(AdditionalDependencies) + $(OutDir);$(AdditionalMultiTargetLibraryPath);$(ArmLibraryDirectories);$(ProjectAdditionalLinkLibraryDirectories);%(AdditionalLibraryDirectories) + /IGNORE:4099 %(AdditionalOptions) + + + + + + NoExtensions + + + + + CDecl + + + + + OldStyle + true + true + + + + + Disabled + EnableFastChecks + _DEBUG;DEBUG;%(PreprocessorDefinitions) + MultiThreadedDebug + + + + + MinSpace + NDEBUG;%(PreprocessorDefinitions) + true + true + MultiThreaded + + + true + true + + + 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 @@ +# Util.wixext +WixToolset.Util.wixext - Utility WiX Toolset Extension + 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 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30204.135 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "utilbe", "src\be\utilbe.vcxproj", "{630C1EE7-2517-4A8C-83E3-DA1150308B58}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "utilca", "src\ca\utilca.vcxproj", "{076018F7-19BD-423A-ABBF-229273DA08D8}" +EndProject +Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "util", "src\wixlib\util.wixproj", "{1ACFFEFD-505A-41A5-ACBF-A02B7B473AA2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolset.Util.wixext", "src\wixext\WixToolset.Util.wixext.csproj", "{6CF033EB-0A39-4AC6-9D41-9BD506352045}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolsetTest.Util", "src\test\WixToolsetTest.Util\WixToolsetTest.Util.csproj", "{D5D34EC4-AF91-4B11-AC0A-FA5242AE924B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {630C1EE7-2517-4A8C-83E3-DA1150308B58}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {630C1EE7-2517-4A8C-83E3-DA1150308B58}.Debug|Any CPU.Build.0 = Debug|Win32 + {630C1EE7-2517-4A8C-83E3-DA1150308B58}.Debug|x64.ActiveCfg = Debug|Win32 + {630C1EE7-2517-4A8C-83E3-DA1150308B58}.Debug|x86.ActiveCfg = Debug|Win32 + {630C1EE7-2517-4A8C-83E3-DA1150308B58}.Debug|x86.Build.0 = Debug|Win32 + {630C1EE7-2517-4A8C-83E3-DA1150308B58}.Release|Any CPU.ActiveCfg = Release|Win32 + {630C1EE7-2517-4A8C-83E3-DA1150308B58}.Release|Any CPU.Build.0 = Release|Win32 + {630C1EE7-2517-4A8C-83E3-DA1150308B58}.Release|x64.ActiveCfg = Release|Win32 + {630C1EE7-2517-4A8C-83E3-DA1150308B58}.Release|x86.ActiveCfg = Release|Win32 + {630C1EE7-2517-4A8C-83E3-DA1150308B58}.Release|x86.Build.0 = Release|Win32 + {076018F7-19BD-423A-ABBF-229273DA08D8}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {076018F7-19BD-423A-ABBF-229273DA08D8}.Debug|Any CPU.Build.0 = Debug|Win32 + {076018F7-19BD-423A-ABBF-229273DA08D8}.Debug|x64.ActiveCfg = Debug|Win32 + {076018F7-19BD-423A-ABBF-229273DA08D8}.Debug|x86.ActiveCfg = Debug|Win32 + {076018F7-19BD-423A-ABBF-229273DA08D8}.Debug|x86.Build.0 = Debug|Win32 + {076018F7-19BD-423A-ABBF-229273DA08D8}.Release|Any CPU.ActiveCfg = Release|Win32 + {076018F7-19BD-423A-ABBF-229273DA08D8}.Release|Any CPU.Build.0 = Release|Win32 + {076018F7-19BD-423A-ABBF-229273DA08D8}.Release|x64.ActiveCfg = Release|Win32 + {076018F7-19BD-423A-ABBF-229273DA08D8}.Release|x86.ActiveCfg = Release|Win32 + {076018F7-19BD-423A-ABBF-229273DA08D8}.Release|x86.Build.0 = Release|Win32 + {1ACFFEFD-505A-41A5-ACBF-A02B7B473AA2}.Debug|Any CPU.ActiveCfg = Debug|x86 + {1ACFFEFD-505A-41A5-ACBF-A02B7B473AA2}.Debug|Any CPU.Build.0 = Debug|x86 + {1ACFFEFD-505A-41A5-ACBF-A02B7B473AA2}.Debug|x64.ActiveCfg = Debug|x86 + {1ACFFEFD-505A-41A5-ACBF-A02B7B473AA2}.Debug|x86.ActiveCfg = Debug|x86 + {1ACFFEFD-505A-41A5-ACBF-A02B7B473AA2}.Debug|x86.Build.0 = Debug|x86 + {1ACFFEFD-505A-41A5-ACBF-A02B7B473AA2}.Release|Any CPU.ActiveCfg = Release|x86 + {1ACFFEFD-505A-41A5-ACBF-A02B7B473AA2}.Release|Any CPU.Build.0 = Release|x86 + {1ACFFEFD-505A-41A5-ACBF-A02B7B473AA2}.Release|x64.ActiveCfg = Release|x86 + {1ACFFEFD-505A-41A5-ACBF-A02B7B473AA2}.Release|x86.ActiveCfg = Release|x86 + {1ACFFEFD-505A-41A5-ACBF-A02B7B473AA2}.Release|x86.Build.0 = Release|x86 + {6CF033EB-0A39-4AC6-9D41-9BD506352045}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6CF033EB-0A39-4AC6-9D41-9BD506352045}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6CF033EB-0A39-4AC6-9D41-9BD506352045}.Debug|x64.ActiveCfg = Debug|Any CPU + {6CF033EB-0A39-4AC6-9D41-9BD506352045}.Debug|x64.Build.0 = Debug|Any CPU + {6CF033EB-0A39-4AC6-9D41-9BD506352045}.Debug|x86.ActiveCfg = Debug|Any CPU + {6CF033EB-0A39-4AC6-9D41-9BD506352045}.Debug|x86.Build.0 = Debug|Any CPU + {6CF033EB-0A39-4AC6-9D41-9BD506352045}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6CF033EB-0A39-4AC6-9D41-9BD506352045}.Release|Any CPU.Build.0 = Release|Any CPU + {6CF033EB-0A39-4AC6-9D41-9BD506352045}.Release|x64.ActiveCfg = Release|Any CPU + {6CF033EB-0A39-4AC6-9D41-9BD506352045}.Release|x64.Build.0 = Release|Any CPU + {6CF033EB-0A39-4AC6-9D41-9BD506352045}.Release|x86.ActiveCfg = Release|Any CPU + {6CF033EB-0A39-4AC6-9D41-9BD506352045}.Release|x86.Build.0 = Release|Any CPU + {D5D34EC4-AF91-4B11-AC0A-FA5242AE924B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D5D34EC4-AF91-4B11-AC0A-FA5242AE924B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D5D34EC4-AF91-4B11-AC0A-FA5242AE924B}.Debug|x64.ActiveCfg = Debug|Any CPU + {D5D34EC4-AF91-4B11-AC0A-FA5242AE924B}.Debug|x64.Build.0 = Debug|Any CPU + {D5D34EC4-AF91-4B11-AC0A-FA5242AE924B}.Debug|x86.ActiveCfg = Debug|Any CPU + {D5D34EC4-AF91-4B11-AC0A-FA5242AE924B}.Debug|x86.Build.0 = Debug|Any CPU + {D5D34EC4-AF91-4B11-AC0A-FA5242AE924B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D5D34EC4-AF91-4B11-AC0A-FA5242AE924B}.Release|Any CPU.Build.0 = Release|Any CPU + {D5D34EC4-AF91-4B11-AC0A-FA5242AE924B}.Release|x64.ActiveCfg = Release|Any CPU + {D5D34EC4-AF91-4B11-AC0A-FA5242AE924B}.Release|x64.Build.0 = Release|Any CPU + {D5D34EC4-AF91-4B11-AC0A-FA5242AE924B}.Release|x86.ActiveCfg = Release|Any CPU + {D5D34EC4-AF91-4B11-AC0A-FA5242AE924B}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E4566A6B-47D0-4EA0-989A-D763AC39105D} + EndGlobalSection +EndGlobal 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 @@ + + + True + True + + \ 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 @@ +@setlocal +@pushd %~dp0 +@set _C=Release +@if /i "%1"=="debug" set _C=Debug + +:: Restore +msbuild -p:Configuration=%_C% -t:Restore || exit /b + +:: Build +msbuild -p:Configuration=%_C% src\test\WixToolsetTest.Util\WixToolsetTest.Util.csproj || exit /b + +:: Test +dotnet test -c %_C% --no-build src\test\WixToolsetTest.Util || exit /b + +:: Pack +msbuild -p:Configuration=%_C% -p:NoBuild=true -t:Pack src\wixext\WixToolset.Util.wixext.csproj || exit /b + +@popd +@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 @@ +# Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. +# +# Do NOT modify this file. Update the canonical version in Home\repo-template\src\appveyor.yml +# then update all of the repos. + +branches: + only: + - master + - develop + +image: Visual Studio 2019 + +version: 0.0.0.{build} +configuration: Release + +environment: + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + NUGET_XMLDOC_MODE: skip + +build_script: + - appveyor.cmd + +pull_requests: + do_not_increment_build_number: true + +nuget: + disable_publish_on_pr: true + +skip_branch_with_pr: true +skip_tags: true + +artifacts: +- path: build\Release\**\*.nupkg + name: nuget + +notifications: +- provider: Slack + incoming_webhook: + 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" +#include "BextBaseBundleExtension.h" + +class CWixUtilBundleExtension : public CBextBaseBundleExtension +{ +public: // IBundleExtension + virtual STDMETHODIMP Search( + __in LPCWSTR wzId, + __in LPCWSTR wzVariable + ) + { + HRESULT hr = S_OK; + + hr = UtilSearchExecute(&m_searches, wzId, wzVariable, m_pEngine); + + return hr; + } + +public: //CBextBaseBundleExtension + virtual STDMETHODIMP Initialize( + __in const BUNDLE_EXTENSION_CREATE_ARGS* pCreateArgs + ) + { + HRESULT hr = S_OK; + IXMLDOMDocument* pixdManifest = NULL; + IXMLDOMNode* pixnBundleExtension = NULL; + + hr = CBextBaseBundleExtension::Initialize(pCreateArgs); + ExitOnFailure(hr, "CBextBaseBundleExtension initialization failed."); + + hr = XmlLoadDocumentFromFile(m_sczBundleExtensionDataPath, &pixdManifest); + ExitOnFailure(hr, "Failed to load bundle extension manifest from path: %ls", m_sczBundleExtensionDataPath); + + hr = BextGetBundleExtensionDataNode(pixdManifest, UTIL_BUNDLE_EXTENSION_ID, &pixnBundleExtension); + ExitOnFailure(hr, "Failed to get BundleExtension '%ls'", UTIL_BUNDLE_EXTENSION_ID); + + hr = UtilSearchParseFromXml(&m_searches, pixnBundleExtension); + ExitOnFailure(hr, "Failed to parse searches from bundle extension manifest."); + + LExit: + ReleaseObject(pixnBundleExtension); + ReleaseObject(pixdManifest); + + return hr; + } + +public: + CWixUtilBundleExtension( + __in IBundleExtensionEngine* pEngine + ) : CBextBaseBundleExtension(pEngine) + { + m_searches = { }; + } + + ~CWixUtilBundleExtension() + { + UtilSearchUninitialize(&m_searches); + } + +private: + UTIL_SEARCHES m_searches; +}; + +HRESULT UtilBundleExtensionCreate( + __in IBundleExtensionEngine* pEngine, + __in const BUNDLE_EXTENSION_CREATE_ARGS* pArgs, + __out IBundleExtension** ppBundleExtension + ) +{ + HRESULT hr = S_OK; + CWixUtilBundleExtension* pExtension = NULL; + + pExtension = new CWixUtilBundleExtension(pEngine); + ExitOnNull(pExtension, hr, E_OUTOFMEMORY, "Failed to create new CWixUtilBundleExtension."); + + hr = pExtension->Initialize(pArgs); + ExitOnFailure(hr, "CWixUtilBundleExtension initialization failed"); + + *ppBundleExtension = pExtension; + pExtension = NULL; + +LExit: + ReleaseObject(pExtension); + return hr; +} 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 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +// constants + +#define UTIL_BUNDLE_EXTENSION_ID BUNDLE_EXTENSION_DECORATION(L"UtilBundleExtension") + + +// function declarations + +HRESULT UtilBundleExtensionCreate( + __in IBundleExtensionEngine* pEngine, + __in const BUNDLE_EXTENSION_CREATE_ARGS* pArgs, + __out IBundleExtension** ppBundleExtension + ); 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 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +#if defined(_M_ARM64) +#define BUNDLE_EXTENSION_DECORATION(f) L"Wix4" f L"_A64" +#elif defined(_M_AMD64) +#define BUNDLE_EXTENSION_DECORATION(f) L"Wix4" f L"_X64" +#elif defined(_M_ARM) +#define BUNDLE_EXTENSION_DECORATION(f) L"Wix4" f L"_ARM" +#else +#define BUNDLE_EXTENSION_DECORATION(f) L"Wix4" f L"_X86" +#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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + +// https://gist.github.com/navossoc/7572c7d82243e9f818989e2765e7793a +HRESULT DetectSHA2CodeSigning( + __out BOOL* pfSupported + ) +{ + HRESULT hr = S_OK; + HMODULE hModule = NULL; + FARPROC pfn = NULL; + DWORD er = ERROR_SUCCESS; + + hr = LoadSystemLibrary(L"wintrust.dll", &hModule); + ExitOnFailure(hr, "Failed to load wintrust.dll"); + + pfn = ::GetProcAddress(hModule, "CryptCATAdminAcquireContext2"); + if (pfn) + { + *pfSupported = TRUE; + ExitFunction1(hr = S_OK); + } + + er = ::GetLastError(); + if (er == ERROR_PROC_NOT_FOUND) + { + *pfSupported = FALSE; + ExitFunction1(hr = S_OK); + } + + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "Failed to probe for CryptCATAdminAcquireContext2 in wintrust.dll"); + +LExit: + ::FreeLibrary(hModule); + + return hr; +} + +HRESULT UtilPerformDetectSHA2CodeSigning( + __in LPCWSTR wzVariable, + __in UTIL_SEARCH* /*pSearch*/, + __in IBundleExtensionEngine* pEngine + ) +{ + HRESULT hr = S_OK; + BOOL fSupported = FALSE; + + hr = DetectSHA2CodeSigning(&fSupported); + ExitOnFailure(hr, "DetectSHA2CodeSigning failed."); + + hr = pEngine->SetVariableNumeric(wzVariable, fSupported ? 1 : 0); + ExitOnFailure(hr, "Failed to set variable '%ls'", wzVariable); + +LExit: + return hr; +} 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 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +HRESULT UtilPerformDetectSHA2CodeSigning( + __in LPCWSTR wzVariable, + __in UTIL_SEARCH* pSearch, + __in IBundleExtensionEngine* pEngine + ); \ 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#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 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +#if _WIN32_MSI < 150 +#define _WIN32_MSI 150 +#endif + +#include +#include +#include +#include + +#include + +#include + +#define MAXUINT USHRT_MAX + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "beDecor.h" +#include "utilsearch.h" +#include "detectsha2support.h" +#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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" +#include "BextBaseBundleExtensionProc.h" + +static IBundleExtension* vpBundleExtension = NULL; + +// function definitions + +extern "C" HRESULT WINAPI BundleExtensionCreate( + __in const BUNDLE_EXTENSION_CREATE_ARGS* pArgs, + __inout BUNDLE_EXTENSION_CREATE_RESULTS* pResults + ) +{ + HRESULT hr = S_OK; + IBundleExtensionEngine* pEngine = NULL; + + hr = XmlInitialize(); + ExitOnFailure(hr, "Failed to initialize XML."); + + hr = BextInitializeFromCreateArgs(pArgs, &pEngine); + ExitOnFailure(hr, "Failed to initialize bext"); + + hr = UtilBundleExtensionCreate(pEngine, pArgs, &vpBundleExtension); + BextExitOnFailure(hr, "Failed to create WixUtilBundleExtension"); + + pResults->pfnBundleExtensionProc = BextBaseBundleExtensionProc; + pResults->pvBundleExtensionProcContext = vpBundleExtension; + +LExit: + ReleaseObject(pEngine); + + return hr; +} + +extern "C" void WINAPI BundleExtensionDestroy() +{ + BextUninitialize(); + ReleaseNullObject(vpBundleExtension); + XmlUninitialize(); +} \ 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 @@ +; Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +LIBRARY "utilbe" + +EXPORTS + BundleExtensionCreate + 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 @@ + + + + + + + Debug + ARM64 + + + Release + ARM64 + + + Debug + X64 + + + Release + X64 + + + Debug + Win32 + + + Release + Win32 + + + + + {630C1EE7-2517-4A8C-83E3-DA1150308B58} + DynamicLibrary + utilbe + v142 + Unicode + utilbe.def + WiX Toolset Util BundleExtension + + + + + + + msi.lib + + + + + + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +STDMETHODIMP UtilSearchParseFromXml( + __in UTIL_SEARCHES* pSearches, + __in IXMLDOMNode* pixnBundleExtension + ) +{ + HRESULT hr = S_OK; + IXMLDOMNodeList* pixnNodes = NULL; + IXMLDOMNode* pixnNode = NULL; + DWORD cNodes = 0; + BSTR bstrNodeName = NULL; + LPWSTR scz = NULL; + + // Select Util search nodes. + hr = XmlSelectNodes(pixnBundleExtension, L"WixWindowsFeatureSearch", &pixnNodes); + ExitOnFailure(hr, "Failed to select Util search nodes."); + + // Get Util search node count. + hr = pixnNodes->get_length((long*)&cNodes); + ExitOnFailure(hr, "Failed to get Util search node count."); + + if (!cNodes) + { + ExitFunction(); + } + + // Allocate memory for searches. + pSearches->rgSearches = (UTIL_SEARCH*)MemAlloc(sizeof(UTIL_SEARCH) * cNodes, TRUE); + ExitOnNull(pSearches->rgSearches, hr, E_OUTOFMEMORY, "Failed to allocate memory for search structs."); + + pSearches->cSearches = cNodes; + + // Parse search elements. + for (DWORD i = 0; i < cNodes; ++i) + { + UTIL_SEARCH* pSearch = &pSearches->rgSearches[i]; + + hr = XmlNextElement(pixnNodes, &pixnNode, &bstrNodeName); + ExitOnFailure(hr, "Failed to get next node."); + + // @Id + hr = XmlGetAttributeEx(pixnNode, L"Id", &pSearch->sczId); + ExitOnFailure(hr, "Failed to get @Id."); + + // Read type specific attributes. + if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrNodeName, -1, L"WixWindowsFeatureSearch", -1)) + { + pSearch->Type = UTIL_SEARCH_TYPE_WINDOWS_FEATURE_SEARCH; + + // @Type + hr = XmlGetAttributeEx(pixnNode, L"Type", &scz); + ExitOnFailure(hr, "Failed to get @Type."); + + if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"sha2CodeSigning", -1)) + { + pSearch->WindowsFeatureSearch.type = UTIL_WINDOWS_FEATURE_SEARCH_TYPE_SHA2_CODE_SIGNING; + } + else + { + hr = E_INVALIDARG; + ExitOnFailure(hr, "Invalid value for @Type: %ls", scz); + } + } + else + { + hr = E_UNEXPECTED; + ExitOnFailure(hr, "Unexpected element name: %ls", bstrNodeName); + } + + // prepare next iteration + ReleaseNullObject(pixnNode); + ReleaseNullBSTR(bstrNodeName); + } + +LExit: + ReleaseStr(scz); + ReleaseBSTR(bstrNodeName); + ReleaseObject(pixnNode); + ReleaseObject(pixnNodes); + + return hr; +} + +void UtilSearchUninitialize( + __in UTIL_SEARCHES* pSearches + ) +{ + if (pSearches->rgSearches) + { + for (DWORD i = 0; i < pSearches->cSearches; ++i) + { + UTIL_SEARCH* pSearch = &pSearches->rgSearches[i]; + + ReleaseStr(pSearch->sczId); + } + MemFree(pSearches->rgSearches); + } +} + +STDMETHODIMP UtilSearchExecute( + __in UTIL_SEARCHES* pSearches, + __in LPCWSTR wzSearchId, + __in LPCWSTR wzVariable, + __in IBundleExtensionEngine* pEngine + ) +{ + HRESULT hr = S_OK; + UTIL_SEARCH* pSearch = NULL; + + hr = UtilSearchFindById(pSearches, wzSearchId, &pSearch); + ExitOnFailure(hr, "Search id '%ls' is unknown to the util extension."); + + switch (pSearch->Type) + { + case UTIL_SEARCH_TYPE_WINDOWS_FEATURE_SEARCH: + switch (pSearch->WindowsFeatureSearch.type) + { + case UTIL_WINDOWS_FEATURE_SEARCH_TYPE_SHA2_CODE_SIGNING: + hr = UtilPerformDetectSHA2CodeSigning(wzVariable, pSearch, pEngine); + break; + default: + hr = E_UNEXPECTED; + } + break; + default: + hr = E_UNEXPECTED; + } + +LExit: + return hr; +} + +STDMETHODIMP UtilSearchFindById( + __in UTIL_SEARCHES* pSearches, + __in LPCWSTR wzId, + __out UTIL_SEARCH** ppSearch + ) +{ + HRESULT hr = S_OK; + + for (DWORD i = 0; i < pSearches->cSearches; ++i) + { + UTIL_SEARCH* pSearch = &pSearches->rgSearches[i]; + + if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pSearch->sczId, -1, wzId, -1)) + { + *ppSearch = pSearch; + ExitFunction1(hr = S_OK); + } + } + + hr = E_NOTFOUND; + +LExit: + return hr; +} 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 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +// constants + +enum UTIL_SEARCH_TYPE +{ + UTIL_SEARCH_TYPE_NONE, + UTIL_SEARCH_TYPE_WINDOWS_FEATURE_SEARCH, +}; + +enum UTIL_WINDOWS_FEATURE_SEARCH_TYPE +{ + UTIL_WINDOWS_FEATURE_SEARCH_TYPE_NONE, + UTIL_WINDOWS_FEATURE_SEARCH_TYPE_SHA2_CODE_SIGNING, +}; + + +// structs + +typedef struct _UTIL_SEARCH +{ + LPWSTR sczId; + + UTIL_SEARCH_TYPE Type; + union + { + struct + { + UTIL_WINDOWS_FEATURE_SEARCH_TYPE type; + } WindowsFeatureSearch; + }; +} UTIL_SEARCH; + +typedef struct _UTIL_SEARCHES +{ + UTIL_SEARCH* rgSearches; + DWORD cSearches; +} UTIL_SEARCHES; + + +// function declarations + +STDMETHODIMP UtilSearchParseFromXml( + __in UTIL_SEARCHES* pSearches, + __in IXMLDOMNode* pixnBundleExtension + ); + +void UtilSearchUninitialize( + __in UTIL_SEARCHES* pSearches + ); + +STDMETHODIMP UtilSearchExecute( + __in UTIL_SEARCHES* pSearches, + __in LPCWSTR wzSearchId, + __in LPCWSTR wzVariable, + __in IBundleExtensionEngine* pEngine + ); + +STDMETHODIMP UtilSearchFindById( + __in UTIL_SEARCHES* pSearches, + __in LPCWSTR wzId, + __out UTIL_SEARCH** ppSearch + ); 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +/******************************************************************** +WixBroadcastSettingChange + + Send WM_SETTINGCHANGE message to all top-level windows indicating + that unspecified settings have changed. +********************************************************************/ +extern "C" UINT __stdcall WixBroadcastSettingChange( + __in MSIHANDLE hInstall + ) +{ + HRESULT hr = WcaInitialize(hInstall, "WixBroadcastSettingChange"); + ExitOnFailure(hr, "failed to initialize WixBroadcastSettingChange"); + + // best effort; ignore failures + ::SendMessageTimeoutW(HWND_BROADCAST, WM_SETTINGCHANGE, NULL, NULL, SMTO_ABORTIFHUNG, 1000, NULL); + +LExit: + return WcaFinalize(ERROR_SUCCESS); +} + + +/******************************************************************** +WixBroadcastEnvironmentChange + + Send WM_SETTINGCHANGE message to all top-level windows indicating + that environment variables have changed. +********************************************************************/ +extern "C" UINT __stdcall WixBroadcastEnvironmentChange( + __in MSIHANDLE hInstall + ) +{ + HRESULT hr = WcaInitialize(hInstall, "WixBroadcastEnvironmentChange"); + ExitOnFailure(hr, "failed to initialize WixBroadcastEnvironmentChange"); + + // best effort; ignore failures + ::SendMessageTimeoutW(HWND_BROADCAST, WM_SETTINGCHANGE, NULL, reinterpret_cast(L"Environment"), SMTO_ABORTIFHUNG, 1000, NULL); + +LExit: + return WcaFinalize(ERROR_SUCCESS); +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +/******************************************************************** +WixCheckRebootRequired - entry point for WixCheckRebootRequired Custom Action + + called as Type 1 CustomAction (binary DLL) from Windows Installer + in InstallExecuteSequence after InstallFinalize +********************************************************************/ +extern "C" UINT __stdcall WixCheckRebootRequired( + __in MSIHANDLE hInstall + ) +{ + HRESULT hr = S_OK; + DWORD er = ERROR_SUCCESS; + + hr = WcaInitialize(hInstall, "WixCheckRebootRequired"); + ExitOnFailure(hr, "failed to initialize"); + + if (WcaDidDeferredActionRequireReboot()) + { + WcaLog(LOGMSG_STANDARD, "Reboot required by deferred CustomAction."); + + er = ::MsiSetMode(hInstall, MSIRUNMODE_REBOOTATEND, TRUE); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "Failed to schedule reboot."); + } + +LExit: + + if (FAILED(hr)) + er = ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + +#define DEFAULT_PROCESS_EXIT_WAIT_TIME 5000 + +// structs +LPCWSTR wzQUERY_CLOSEAPPS = L"SELECT `Wix4CloseApplication`, `Target`, `Description`, `Condition`, `Attributes`, `Property`, `TerminateExitCode`, `Timeout` FROM `Wix4CloseApplication` ORDER BY `Sequence`"; +enum eQUERY_CLOSEAPPS { QCA_ID = 1, QCA_TARGET, QCA_DESCRIPTION, QCA_CONDITION, QCA_ATTRIBUTES, QCA_PROPERTY, QCA_TERMINATEEXITCODE, QCA_TIMEOUT }; + +// CloseApplication.Attributes +enum CLOSEAPP_ATTRIBUTES +{ + CLOSEAPP_ATTRIBUTE_NONE = 0x0, + CLOSEAPP_ATTRIBUTE_CLOSEMESSAGE = 0x1, + CLOSEAPP_ATTRIBUTE_REBOOTPROMPT = 0x2, + CLOSEAPP_ATTRIBUTE_ELEVATEDCLOSEMESSAGE = 0x4, + CLOSEAPP_ATTRIBUTE_ENDSESSIONMESSAGE = 0x8, + CLOSEAPP_ATTRIBUTE_ELEVATEDENDSESSIONMESSAGE = 0x10, + CLOSEAPP_ATTRIBUTE_TERMINATEPROCESS = 0x20, + CLOSEAPP_ATTRIBUTE_PROMPTTOCONTINUE = 0x40, +}; + +struct PROCESS_AND_MESSAGE +{ + DWORD dwProcessId; + DWORD dwMessageId; + DWORD dwTimeout; +}; + + +/****************************************************************** + EnumWindowsProc - callback function which sends message if the + current window matches the passed in process ID + +******************************************************************/ +BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) +{ + PROCESS_AND_MESSAGE* pPM = reinterpret_cast(lParam); + DWORD dwProcessId = 0; + DWORD_PTR dwResult = 0; + BOOL fQueryEndSession = WM_QUERYENDSESSION == pPM->dwMessageId; + BOOL fContinueWindowsInProcess = TRUE; // assume we will send message to all top-level windows in a process. + + ::GetWindowThreadProcessId(hwnd, &dwProcessId); + + // check if the process Id is the one we're looking for + if (dwProcessId != pPM->dwProcessId) + { + return TRUE; + } + + WcaLog(LOGMSG_VERBOSE, "Sending message to process id 0x%x", dwProcessId); + + if (::SendMessageTimeoutW(hwnd, pPM->dwMessageId, 0, fQueryEndSession ? ENDSESSION_CLOSEAPP : 0, SMTO_BLOCK, pPM->dwTimeout, &dwResult)) + { + WcaLog(LOGMSG_VERBOSE, "Result 0x%x", dwResult); + + if (fQueryEndSession) + { + // If application said it was okay to close, do that. + if (dwResult) + { + ::SendMessageTimeoutW(hwnd, WM_ENDSESSION, TRUE, ENDSESSION_CLOSEAPP, SMTO_BLOCK, pPM->dwTimeout, &dwResult); + } + else // application said don't try to close it, so don't bother sending messages to any other top-level windows. + { + fContinueWindowsInProcess = FALSE; + } + } + } + else // log result message. + { + WcaLog(LOGMSG_VERBOSE, "Failed to send message id: %u, error: 0x%x", pPM->dwMessageId, ::GetLastError()); + } + + // so we know we succeeded + ::SetLastError(ERROR_SUCCESS); + + return fContinueWindowsInProcess; +} + +/****************************************************************** + PromptToContinue - displays the prompt if the application is still + running. + +******************************************************************/ +static HRESULT PromptToContinue( + __in_z LPCWSTR wzApplication, + __in_z LPCWSTR wzPrompt + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + PMSIHANDLE hRecMessage = NULL; + DWORD *prgProcessIds = NULL; + DWORD cProcessIds = 0; + + hRecMessage = ::MsiCreateRecord(1); + ExitOnNull(hRecMessage, hr, E_OUTOFMEMORY, "Failed to create record for prompt."); + + er = ::MsiRecordSetStringW(hRecMessage, 0, wzPrompt); + ExitOnWin32Error(er, hr, "Failed to set prompt record field string"); + + do + { + hr = ProcFindAllIdsFromExeName(wzApplication, &prgProcessIds, &cProcessIds); + if (SUCCEEDED(hr) && 0 < cProcessIds) + { + er = WcaProcessMessage(static_cast(INSTALLMESSAGE_WARNING | MB_ABORTRETRYIGNORE | MB_DEFBUTTON3 | MB_ICONWARNING), hRecMessage); + if (IDABORT == er) + { + hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT); + } + else if (IDRETRY == er) + { + hr = S_FALSE; + } + else if (IDIGNORE == er) + { + hr = S_OK; + } + else + { + ExitOnWin32Error(er, hr, "Unexpected return value from prompt to continue."); + } + } + + ReleaseNullMem(prgProcessIds); + cProcessIds = 0; + } while (S_FALSE == hr); + +LExit: + ReleaseMem(prgProcessIds); + return hr; +} + +/****************************************************************** + SendProcessMessage - helper function to enumerate the top-level + windows and send to all matching a process ID. + +******************************************************************/ +void SendProcessMessage( + __in DWORD dwProcessId, + __in DWORD dwMessageId, + __in DWORD dwTimeout + ) +{ + WcaLog(LOGMSG_VERBOSE, "Attempting to send process id 0x%x message id: %u", dwProcessId, dwMessageId); + + PROCESS_AND_MESSAGE pm = { }; + pm.dwProcessId = dwProcessId; + pm.dwMessageId = dwMessageId; + pm.dwTimeout = dwTimeout; + + if (!::EnumWindows(EnumWindowsProc, reinterpret_cast(&pm))) + { + DWORD dwLastError = ::GetLastError(); + if (ERROR_SUCCESS != dwLastError) + { + WcaLog(LOGMSG_VERBOSE, "CloseApp enumeration error: 0x%x", dwLastError); + } + } +} + +/****************************************************************** + SendApplicationMessage - helper function to iterate through the + processes for the specified application and send all + applicable process Ids a message and give them time to process + the message. + +******************************************************************/ +void SendApplicationMessage( + __in LPCWSTR wzApplication, + __in DWORD dwMessageId, + __in DWORD dwTimeout + ) +{ + DWORD *prgProcessIds = NULL; + DWORD cProcessIds = 0, iProcessId; + HRESULT hr = S_OK; + + WcaLog(LOGMSG_VERBOSE, "Checking App: %ls ", wzApplication); + + hr = ProcFindAllIdsFromExeName(wzApplication, &prgProcessIds, &cProcessIds); + + if (SUCCEEDED(hr) && 0 < cProcessIds) + { + WcaLog(LOGMSG_VERBOSE, "App: %ls found running, %d processes, attempting to send message.", wzApplication, cProcessIds); + + for (iProcessId = 0; iProcessId < cProcessIds; ++iProcessId) + { + SendProcessMessage(prgProcessIds[iProcessId], dwMessageId, dwTimeout); + } + + ProcWaitForIds(prgProcessIds, cProcessIds, dwTimeout); + } + + ReleaseMem(prgProcessIds); +} + +/****************************************************************** + SetRunningProcessProperty - helper function that sets the specified + property if there are any instances of the specified executable + running. Useful to show custom UI to ask for shutdown. +******************************************************************/ +void SetRunningProcessProperty( + __in LPCWSTR wzApplication, + __in LPCWSTR wzProperty + ) +{ + DWORD *prgProcessIds = NULL; + DWORD cProcessIds = 0; + HRESULT hr = S_OK; + + WcaLog(LOGMSG_VERBOSE, "Checking App: %ls ", wzApplication); + + hr = ProcFindAllIdsFromExeName(wzApplication, &prgProcessIds, &cProcessIds); + + if (SUCCEEDED(hr) && 0 < cProcessIds) + { + WcaLog(LOGMSG_VERBOSE, "App: %ls found running, %d processes, setting '%ls' property.", wzApplication, cProcessIds, wzProperty); + WcaSetIntProperty(wzProperty, cProcessIds); + } + + ReleaseMem(prgProcessIds); +} + +/****************************************************************** + TerminateProcesses - helper function that kills the provided set of + process ids such that they return a particular exit code. +******************************************************************/ +void TerminateProcesses( + __in_ecount(cProcessIds) DWORD rgdwProcessIds[], + __in DWORD cProcessIds, + __in DWORD dwExitCode + ) +{ + for (DWORD i = 0; i < cProcessIds; ++i) + { + HANDLE hProcess = ::OpenProcess(PROCESS_TERMINATE, FALSE, rgdwProcessIds[i]); + if (hProcess) + { + ::TerminateProcess(hProcess, dwExitCode); + ::CloseHandle(hProcess); + } + } +} + +/****************************************************************** + WixCloseApplications - entry point for WixCloseApplications Custom Action + + called as Type 1 CustomAction (binary DLL) from Windows Installer + in InstallExecuteSequence before InstallFiles +******************************************************************/ +extern "C" UINT __stdcall WixCloseApplications( + __in MSIHANDLE hInstall + ) +{ + //AssertSz(FALSE, "debug WixCloseApplications"); + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + LPWSTR pwzData = NULL; + LPWSTR pwzId = NULL; + LPWSTR pwzTarget = NULL; + LPWSTR pwzDescription = NULL; + LPWSTR pwzCondition = NULL; + LPWSTR pwzProperty = NULL; + DWORD dwAttributes = 0; + DWORD dwTimeout = 0; + DWORD dwTerminateExitCode = 0; + MSICONDITION condition = MSICONDITION_NONE; + + DWORD cCloseApps = 0; + + PMSIHANDLE hView = NULL; + PMSIHANDLE hRec = NULL; + MSIHANDLE hListboxTable = NULL; + MSIHANDLE hListboxColumns = NULL; + + LPWSTR pwzCustomActionData = NULL; + //DWORD cchCustomActionData = 0; + + // + // initialize + // + hr = WcaInitialize(hInstall, "WixCloseApplications"); + ExitOnFailure(hr, "failed to initialize"); + + // + // loop through all the objects to be secured + // + hr = WcaOpenExecuteView(wzQUERY_CLOSEAPPS, &hView); + ExitOnFailure(hr, "failed to open view on Wix4CloseApplication table"); + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + hr = WcaGetRecordString(hRec, QCA_ID, &pwzId); + ExitOnFailure(hr, "failed to get id from Wix4CloseApplication table"); + + hr = WcaGetRecordString(hRec, QCA_CONDITION, &pwzCondition); + ExitOnFailure(hr, "failed to get condition from Wix4CloseApplication table"); + + if (pwzCondition && *pwzCondition) + { + condition = ::MsiEvaluateConditionW(hInstall, pwzCondition); + if (MSICONDITION_ERROR == condition) + { + hr = E_INVALIDARG; + ExitOnFailure(hr, "failed to process condition for Wix4CloseApplication '%ls'", pwzId); + } + else if (MSICONDITION_FALSE == condition) + { + continue; // skip processing this target + } + } + + hr = WcaGetRecordFormattedString(hRec, QCA_TARGET, &pwzTarget); + ExitOnFailure(hr, "failed to get target from Wix4CloseApplication table"); + + hr = WcaGetRecordFormattedString(hRec, QCA_DESCRIPTION, &pwzDescription); + ExitOnFailure(hr, "failed to get description from Wix4CloseApplication table"); + + hr = WcaGetRecordInteger(hRec, QCA_ATTRIBUTES, reinterpret_cast(&dwAttributes)); + ExitOnFailure(hr, "failed to get attributes from Wix4CloseApplication table"); + + hr = WcaGetRecordFormattedString(hRec, QCA_PROPERTY, &pwzProperty); + ExitOnFailure(hr, "failed to get property from Wix4CloseApplication table"); + + hr = WcaGetRecordInteger(hRec, QCA_TERMINATEEXITCODE, reinterpret_cast(&dwTerminateExitCode)); + if (S_FALSE == hr) + { + dwTerminateExitCode = 0; + hr = S_OK; + } + ExitOnFailure(hr, "failed to get terminate exit-code from Wix4CloseApplication table"); + + hr = WcaGetRecordInteger(hRec, QCA_TIMEOUT, reinterpret_cast(&dwTimeout)); + if (S_FALSE == hr) + { + dwTimeout = DEFAULT_PROCESS_EXIT_WAIT_TIME; + hr = S_OK; + } + ExitOnFailure(hr, "failed to get timeout from Wix4CloseApplication table"); + + // Before trying any changes to the machine, prompt if requested. + if (dwAttributes & CLOSEAPP_ATTRIBUTE_PROMPTTOCONTINUE) + { + hr = PromptToContinue(pwzTarget, pwzDescription ? pwzDescription : L""); + if (HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT) == hr) + { + // Skip error message if user canceled. + ExitFunction(); + } + ExitOnFailure(hr, "Failure while prompting user to continue to close application."); + } + + // + // send WM_CLOSE or WM_QUERYENDSESSION to currently running applications + // + if (dwAttributes & CLOSEAPP_ATTRIBUTE_CLOSEMESSAGE) + { + SendApplicationMessage(pwzTarget, WM_CLOSE, dwTimeout); + } + + if (dwAttributes & CLOSEAPP_ATTRIBUTE_ENDSESSIONMESSAGE) + { + SendApplicationMessage(pwzTarget, WM_QUERYENDSESSION, dwTimeout); + } + + // + // Pass the targets to the deferred action in case the app comes back + // even if we close it now. + // + if (dwAttributes & (CLOSEAPP_ATTRIBUTE_ELEVATEDCLOSEMESSAGE | CLOSEAPP_ATTRIBUTE_ELEVATEDENDSESSIONMESSAGE | CLOSEAPP_ATTRIBUTE_REBOOTPROMPT | CLOSEAPP_ATTRIBUTE_TERMINATEPROCESS)) + { + hr = WcaWriteStringToCaData(pwzTarget, &pwzCustomActionData); + ExitOnFailure(hr, "failed to add target data to CustomActionData"); + + hr = WcaWriteIntegerToCaData(dwAttributes, &pwzCustomActionData); + ExitOnFailure(hr, "failed to add attribute data to CustomActionData"); + + hr = WcaWriteIntegerToCaData(dwTimeout, &pwzCustomActionData); + ExitOnFailure(hr, "failed to add timeout data to CustomActionData"); + + hr = WcaWriteIntegerToCaData(dwTerminateExitCode, &pwzCustomActionData); + ExitOnFailure(hr, "failed to add timeout data to CustomActionData"); + } + + if (pwzProperty && *pwzProperty) + { + SetRunningProcessProperty(pwzTarget, pwzProperty); + } + + ++cCloseApps; + } + + // if we looped through all records all is well + if (E_NOMOREITEMS == hr) + { + hr = S_OK; + } + ExitOnFailure(hr, "failed while looping through all apps to close"); + + // + // Do the UI dance now. + // + /* + + TODO: Do this eventually + + if (cCloseApps) + { + while (TRUE) + { + for (DWORD i = 0; i < cCloseApps; ++i) + { + hr = WcaAddTempRecord(&hListboxTable, &hListboxColumns, L"ListBox", NULL, 0, 4, L"FileInUseProcess", i, target, description); + if (FAILED(hr)) + { + } + } + } + } + */ + + // + // schedule the custom action and add to progress bar + // + if (pwzCustomActionData && *pwzCustomActionData) + { + Assert(0 < cCloseApps); + + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"CloseApplicationsDeferred"), pwzCustomActionData, cCloseApps * COST_CLOSEAPP); + ExitOnFailure(hr, "failed to schedule CloseApplicationsDeferred action"); + } + +LExit: + if (hListboxColumns) + { + ::MsiCloseHandle(hListboxColumns); + } + if (hListboxTable) + { + ::MsiCloseHandle(hListboxTable); + } + + ReleaseStr(pwzCustomActionData); + ReleaseStr(pwzData); + ReleaseStr(pwzProperty); + ReleaseStr(pwzCondition); + ReleaseStr(pwzDescription); + ReleaseStr(pwzTarget); + ReleaseStr(pwzId); + + if (FAILED(hr)) + { + er = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT) == hr ? ERROR_INSTALL_USEREXIT : ERROR_INSTALL_FAILURE; + } + return WcaFinalize(er); +} + + +/****************************************************************** + WixCloseApplicationsDeferred - entry point for + WixCloseApplicationsDeferred Custom Action + called as Type 1025 CustomAction + (deferred binary DLL) + + NOTE: deferred CustomAction since it modifies the machine + NOTE: CustomActionData == wzTarget\tdwAttributes\tdwTimeout\tdwTerminateExitCode\t... +******************************************************************/ +extern "C" UINT __stdcall WixCloseApplicationsDeferred( + __in MSIHANDLE hInstall + ) +{ + //AssertSz(FALSE, "debug WixCloseApplicationsDeferred"); + HRESULT hr = S_OK; + DWORD er = ERROR_SUCCESS; + + LPWSTR pwz = NULL; + LPWSTR pwzData = NULL; + LPWSTR pwzTarget = NULL; + DWORD dwAttributes = 0; + DWORD dwTimeout = 0; + DWORD dwTerminateExitCode = 0; + + DWORD *prgProcessIds = NULL; + DWORD cProcessIds = 0; + + // + // initialize + // + hr = WcaInitialize(hInstall, "WixCloseApplicationsDeferred"); + ExitOnFailure(hr, "failed to initialize"); + + hr = WcaGetProperty(L"CustomActionData", &pwzData); + ExitOnFailure(hr, "failed to get CustomActionData"); + + WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); + + pwz = pwzData; + + // + // loop through all the passed in data + // + while (pwz && *pwz) + { + hr = WcaReadStringFromCaData(&pwz, &pwzTarget); + ExitOnFailure(hr, "failed to process target from CustomActionData"); + + hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&dwAttributes)); + ExitOnFailure(hr, "failed to process attributes from CustomActionData"); + + hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&dwTimeout)); + ExitOnFailure(hr, "failed to process timeout from CustomActionData"); + + hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&dwTerminateExitCode)); + ExitOnFailure(hr, "failed to process terminate exit code from CustomActionData"); + + WcaLog(LOGMSG_VERBOSE, "Checking for App: %ls Attributes: %d", pwzTarget, dwAttributes); + + // + // send WM_CLOSE or WM_QUERYENDSESSION to currently running applications + // + if (dwAttributes & CLOSEAPP_ATTRIBUTE_ELEVATEDCLOSEMESSAGE) + { + SendApplicationMessage(pwzTarget, WM_CLOSE, dwTimeout); + } + + if (dwAttributes & CLOSEAPP_ATTRIBUTE_ELEVATEDENDSESSIONMESSAGE) + { + SendApplicationMessage(pwzTarget, WM_QUERYENDSESSION, dwTimeout); + } + + // If we find that an app that we need closed is still runing, require a + // restart or kill the process as directed. + ProcFindAllIdsFromExeName(pwzTarget, &prgProcessIds, &cProcessIds); + if (0 < cProcessIds) + { + if (dwAttributes & CLOSEAPP_ATTRIBUTE_REBOOTPROMPT) + { + WcaLog(LOGMSG_VERBOSE, "App: %ls found running, requiring a reboot.", pwzTarget); + + WcaDeferredActionRequiresReboot(); + } + else if (dwAttributes & CLOSEAPP_ATTRIBUTE_TERMINATEPROCESS) + { + TerminateProcesses(prgProcessIds, cProcessIds, dwTerminateExitCode); + } + } + + hr = WcaProgressMessage(COST_CLOSEAPP, FALSE); + ExitOnFailure(hr, "failed to send progress message"); + } + +LExit: + ReleaseMem(prgProcessIds); + + ReleaseStr(pwzTarget); + ReleaseStr(pwzData); + + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + return WcaFinalize(er); +} 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 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +#define msierrSecureObjectsFailedCreateSD 25520 +#define msierrSecureObjectsFailedSet 25521 +#define msierrSecureObjectsUnknownType 25522 + +#define msierrXmlFileFailedRead 25530 +#define msierrXmlFileFailedOpen 25531 +#define msierrXmlFileFailedSelect 25532 +#define msierrXmlFileFailedSave 25533 + +#define msierrXmlConfigFailedRead 25540 +#define msierrXmlConfigFailedOpen 25541 +#define msierrXmlConfigFailedSelect 25542 +#define msierrXmlConfigFailedSave 25543 + +#define msierrPERFMONFailedRegisterDLL 26251 +#define msierrPERFMONFailedUnregisterDLL 26252 +#define msierrInstallPerfCounterData 26253 +#define msierrUninstallPerfCounterData 26254 + +#define msierrSMBFailedCreate 26301 +#define msierrSMBFailedDrop 26302 +#define msierrUSRFailedUserCreate 26401 +#define msierrUSRFailedUserCreatePswd 26402 +#define msierrUSRFailedUserGroupAdd 26403 +#define msierrUSRFailedUserCreateExists 26404 +#define msierrUSRFailedGrantLogonAsService 26405 + +//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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + +const UINT COST_FILEFORMATTING = 2000; + + +// +// WixSchedFormatFiles - immediate CA to schedule format files CAs +// +extern "C" UINT __stdcall WixSchedFormatFiles( + __in MSIHANDLE hInstall + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + PSCZ sczBinaryKey; + PSCZ sczFileKey; + PSCZ sczComponentKey; + PSCZ sczFormattedFile; + PSCZ sczFilePath; + PMSIHANDLE hView; + PMSIHANDLE hRec; + PSCZ sczFileContent; + PSCZ sczFormattedContent; + PSCZ sczExecCustomActionData; + PSCZ sczRollbackCustomActionData; + + LPCWSTR wzQuery = + L"SELECT `Wix4FormatFile`.`Binary_`, `Wix4FormatFile`.`File_`, `File`.`Component_` " + L"FROM `Wix4FormatFile`, `File` " + L"WHERE `Wix4FormatFile`.`File_` = `File`.`File`"; + enum eQuery { eqBinaryKey = 1, eqFileKey, eqComponentKey }; + + // initialize + hr = WcaInitialize(hInstall, "WixSchedFormatFiles"); + ExitOnFailure(hr, "Failed to initialize for WixSchedFormatFiles."); + + // query and loop through all the files + hr = WcaOpenExecuteView(wzQuery, &hView); + ExitOnFailure(hr, "Failed to open view on Wix4FormatFile table"); + + DWORD cFiles = 0; + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + ++cFiles; + + hr = WcaGetRecordString(hRec, eqBinaryKey, &sczBinaryKey); + ExitOnFailure(hr, "Failed to get Binary table key."); + + hr = WcaGetRecordString(hRec, eqFileKey, &sczFileKey); + ExitOnFailure(hr, "Failed to get File table key."); + + hr = WcaGetRecordString(hRec, eqComponentKey, &sczComponentKey); + ExitOnFailure(hr, "Failed to get Component table key."); + + // we need to know if the component's being installed, uninstalled, or reinstalled + WCA_TODO todo = WcaGetComponentToDo(sczComponentKey); + if (WCA_TODO_INSTALL == todo || WCA_TODO_REINSTALL == todo) + { + // turn the file key into the path to the target file + hr = StrAllocFormatted(&sczFormattedFile, L"[#%ls]", sczFileKey); + ExitOnFailure(hr, "Failed to format file string for file: %ls", sczFileKey); + hr = WcaGetFormattedString(sczFormattedFile, &sczFilePath); + ExitOnFailure(hr, "Failed to get path for file: %ls", sczFileKey); + + // extract binary to string + WCA_ENCODING encoding = WCA_ENCODING_UNKNOWN; + hr = WcaExtractBinaryToString(sczBinaryKey, &sczFileContent, &encoding); + ExitOnFailure(hr, "Failed to extract binary: %ls", sczBinaryKey); + + // format string + hr = WcaGetFormattedString(sczFileContent, &sczFormattedContent); + ExitOnFailure(hr, "Failed to format file content: %ls", sczFileContent); + + // write to deferred custom action data + hr = WcaWriteStringToCaData(sczFilePath, &sczExecCustomActionData); + ExitOnFailure(hr, "Failed to write deferred custom action data for file: %ls", sczFilePath); + + hr = WcaWriteIntegerToCaData(encoding, &sczExecCustomActionData); + ExitOnFailure(hr, "Failed to write deferred custom action data for encoding: %d", encoding); + + hr = WcaWriteStringToCaData(sczFormattedContent, &sczExecCustomActionData); + ExitOnFailure(hr, "Failed to write deferred custom action data for file content: %ls", sczFilePath); + + // write to rollback custom action data + hr = WcaWriteStringToCaData(sczFilePath, &sczRollbackCustomActionData); + ExitOnFailure(hr, "Failed to write rollback custom action data for file: %ls", sczFilePath); + + hr = WcaWriteIntegerToCaData(encoding, &sczRollbackCustomActionData); + ExitOnFailure(hr, "Failed to write deferred custom action data for encoding: %d", encoding); + + hr = WcaWriteStringToCaData(sczFileContent, &sczRollbackCustomActionData); + ExitOnFailure(hr, "Failed to write rollback custom action data for file content: %ls", sczFilePath); + } + } + + // reaching the end of the list is actually a good thing, not an error + if (E_NOMOREITEMS == hr) + { + hr = S_OK; + } + ExitOnFailure(hr, "Failure occurred while processing Wix4FormatFile table"); + + // schedule deferred CAs if there's anything to do + if (sczRollbackCustomActionData && *sczRollbackCustomActionData) + { + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackFormatFiles"), sczRollbackCustomActionData, cFiles * COST_FILEFORMATTING); + ExitOnFailure(hr, "Failed to schedule RollbackFormatFiles"); + } + + if (sczExecCustomActionData && *sczExecCustomActionData) + { + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecFormatFiles"), sczExecCustomActionData, cFiles * COST_FILEFORMATTING); + ExitOnFailure(hr, "Failed to schedule ExecFormatFiles"); + } + +LExit: + return WcaFinalize(er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er); +} + + +// +// WixExecFormatFiles - deferred and rollback CAs to write formatted files +// +extern "C" UINT __stdcall WixExecFormatFiles( + __in MSIHANDLE hInstall + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + PSCZ sczCustomActionData; + LPWSTR pwz = NULL; + PSCZ sczFilePath; + PSCZ sczFileContent; + LPSTR psz = NULL; + + // initialize + hr = WcaInitialize(hInstall, "WixExecFormatFiles"); + ExitOnFailure(hr, "Failed to initialize for WixExecFormatFiles."); + + hr = WcaGetProperty(L"CustomActionData", &sczCustomActionData); + ExitOnFailure(hr, "Failed to get CustomActionData."); +#ifdef _DEBUG + WcaLog(LOGMSG_STANDARD, "CustomActionData: %ls", sczCustomActionData); +#endif + + // loop through all the passed in data + pwz = sczCustomActionData; + while (pwz && *pwz) + { + // extract the custom action data + hr = WcaReadStringFromCaData(&pwz, &sczFilePath); + ExitOnFailure(hr, "Failed to read file path from custom action data"); + + WCA_ENCODING encoding = WCA_ENCODING_UNKNOWN; + hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&encoding)); + ExitOnFailure(hr, "Failed to read encoding from custom action data"); + + hr = WcaReadStringFromCaData(&pwz, &sczFileContent); + ExitOnFailure(hr, "Failed to read file content from custom action data"); + + // re-encode content + LPCBYTE pbData = NULL; + size_t cbData = 0; + switch (encoding) + { + case WCA_ENCODING_UTF_16: + pbData = reinterpret_cast(LPCWSTR(sczFileContent)); + cbData = lstrlenW(sczFileContent) * sizeof(WCHAR); + break; + + case WCA_ENCODING_UTF_8: + hr = StrAnsiAllocString(&psz, sczFileContent, 0, CP_UTF8); + ExitOnFailure(hr, "Failed to convert Unicode to UTF-8."); + pbData = reinterpret_cast(psz); + + hr = ::StringCbLengthA(psz, STRSAFE_MAX_CCH, &cbData); + ExitOnFailure(hr, "Failed to count UTF-8 bytes."); + break; + + case WCA_ENCODING_ANSI: + hr = StrAnsiAllocString(&psz, sczFileContent, 0, CP_ACP); + ExitOnFailure(hr, "Failed to convert Unicode to ANSI."); + pbData = reinterpret_cast(psz); + + hr = ::StringCbLengthA(psz, STRSAFE_MAX_CCH, &cbData); + ExitOnFailure(hr, "Failed to count UTF-8 bytes."); + break; + + default: + break; + } + +#ifdef _DEBUG + WcaLog(LOGMSG_STANDARD, "File: %ls", sczCustomActionData); + WcaLog(LOGMSG_STANDARD, "Content: %ls", sczFileContent); +#endif + + // write file and preserve modified time + FILETIME filetime; + + hr = FileGetTime(sczFilePath, NULL, NULL, &filetime); + ExitOnFailure(hr, "Failed to get modified time of file : %ls", sczFilePath); + + hr = FileWrite(sczFilePath, FILE_ATTRIBUTE_NORMAL, pbData, cbData, NULL); + ExitOnFailure(hr, "Failed to write file content: %ls", sczFilePath); + + hr = FileSetTime(sczFilePath, NULL, NULL, &filetime); + ExitOnFailure(hr, "Failed to set modified time of file : %ls", sczFilePath); + + // Tick the progress bar + hr = WcaProgressMessage(COST_FILEFORMATTING, FALSE); + ExitOnFailure(hr, "Failed to tick progress bar for file: %ls", sczFilePath); + } + +LExit: + ReleaseStr(psz); + + return WcaFinalize(er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er); +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + +// constants we'll pick up from later SDKs +#define SM_TABLETPC 86 +#define SM_MEDIACENTER 87 +#define SM_STARTER 88 +#define SM_SERVERR2 89 +#define VER_SUITE_WH_SERVER 0x00008000 + +/******************************************************************** +WixQueryOsInfo - entry point for WixQueryOsInfo custom action + + Called as Type 1 custom action (DLL from the Binary table) from + Windows Installer to set properties that identify OS information + and predefined directories +********************************************************************/ +extern "C" UINT __stdcall WixQueryOsInfo( + __in MSIHANDLE hInstall + ) +{ + HRESULT hr = S_OK; + DWORD er = ERROR_SUCCESS; + OSVERSIONINFOEXW ovix = {0}; + + hr = WcaInitialize(hInstall, "WixQueryOsInfo"); + ExitOnFailure(hr, "WixQueryOsInfo failed to initialize"); + + // identify product suites + ovix.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW); + #pragma warning(suppress: 4996) //TODO: use osutil + ::GetVersionExW(reinterpret_cast(&ovix)); + + if (VER_SUITE_SMALLBUSINESS == (ovix.wSuiteMask & VER_SUITE_SMALLBUSINESS)) + { + WcaSetIntProperty(L"WIX_SUITE_SMALLBUSINESS", 1); + } + + if (VER_SUITE_ENTERPRISE == (ovix.wSuiteMask & VER_SUITE_ENTERPRISE)) + { + WcaSetIntProperty(L"WIX_SUITE_ENTERPRISE", 1); + } + + if (VER_SUITE_BACKOFFICE == (ovix.wSuiteMask & VER_SUITE_BACKOFFICE)) + { + WcaSetIntProperty(L"WIX_SUITE_BACKOFFICE", 1); + } + + if (VER_SUITE_COMMUNICATIONS == (ovix.wSuiteMask & VER_SUITE_COMMUNICATIONS)) + { + WcaSetIntProperty(L"WIX_SUITE_COMMUNICATIONS", 1); + } + + if (VER_SUITE_TERMINAL == (ovix.wSuiteMask & VER_SUITE_TERMINAL)) + { + WcaSetIntProperty(L"WIX_SUITE_TERMINAL", 1); + } + + if (VER_SUITE_SMALLBUSINESS_RESTRICTED == (ovix.wSuiteMask & VER_SUITE_SMALLBUSINESS_RESTRICTED)) + { + WcaSetIntProperty(L"WIX_SUITE_SMALLBUSINESS_RESTRICTED", 1); + } + + if (VER_SUITE_EMBEDDEDNT == (ovix.wSuiteMask & VER_SUITE_EMBEDDEDNT)) + { + WcaSetIntProperty(L"WIX_SUITE_EMBEDDEDNT", 1); + } + + if (VER_SUITE_DATACENTER == (ovix.wSuiteMask & VER_SUITE_DATACENTER)) + { + WcaSetIntProperty(L"WIX_SUITE_DATACENTER", 1); + } + + if (VER_SUITE_SINGLEUSERTS == (ovix.wSuiteMask & VER_SUITE_SINGLEUSERTS)) + { + WcaSetIntProperty(L"WIX_SUITE_SINGLEUSERTS", 1); + } + + if (VER_SUITE_PERSONAL == (ovix.wSuiteMask & VER_SUITE_PERSONAL)) + { + WcaSetIntProperty(L"WIX_SUITE_PERSONAL", 1); + } + + if (VER_SUITE_BLADE == (ovix.wSuiteMask & VER_SUITE_BLADE)) + { + WcaSetIntProperty(L"WIX_SUITE_BLADE", 1); + } + + if (VER_SUITE_EMBEDDED_RESTRICTED == (ovix.wSuiteMask & VER_SUITE_EMBEDDED_RESTRICTED)) + { + WcaSetIntProperty(L"WIX_SUITE_EMBEDDED_RESTRICTED", 1); + } + + if (VER_SUITE_SECURITY_APPLIANCE == (ovix.wSuiteMask & VER_SUITE_SECURITY_APPLIANCE)) + { + WcaSetIntProperty(L"WIX_SUITE_SECURITY_APPLIANCE", 1); + } + + if (VER_SUITE_STORAGE_SERVER == (ovix.wSuiteMask & VER_SUITE_STORAGE_SERVER)) + { + WcaSetIntProperty(L"WIX_SUITE_STORAGE_SERVER", 1); + } + + if (VER_SUITE_COMPUTE_SERVER == (ovix.wSuiteMask & VER_SUITE_COMPUTE_SERVER)) + { + WcaSetIntProperty(L"WIX_SUITE_COMPUTE_SERVER", 1); + } + + if (VER_SUITE_WH_SERVER == (ovix.wSuiteMask & VER_SUITE_WH_SERVER)) + { + WcaSetIntProperty(L"WIX_SUITE_WH_SERVER", 1); + } + + // only for XP and later + if (5 < ovix.dwMajorVersion || (5 == ovix.dwMajorVersion && 0 < ovix.dwMinorVersion)) + { + if (::GetSystemMetrics(SM_SERVERR2)) + { + WcaSetIntProperty(L"WIX_SUITE_SERVERR2", 1); + } + + if (::GetSystemMetrics(SM_MEDIACENTER)) + { + WcaSetIntProperty(L"WIX_SUITE_MEDIACENTER", 1); + } + + if (::GetSystemMetrics(SM_STARTER)) + { + WcaSetIntProperty(L"WIX_SUITE_STARTER", 1); + } + + if (::GetSystemMetrics(SM_TABLETPC)) + { + WcaSetIntProperty(L"WIX_SUITE_TABLETPC", 1); + } + } + +LExit: + if (FAILED(hr)) + er = ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + +/******************************************************************** +WixQueryOsDirs - entry point for WixQueryOsDirs custom action + + Called as Type 1 custom action (DLL from the Binary table) from + Windows Installer to set properties that identify predefined directories +********************************************************************/ +extern "C" UINT __stdcall WixQueryOsDirs( + __in MSIHANDLE hInstall + ) +{ + HRESULT hr = S_OK; + DWORD er = ERROR_SUCCESS; + + hr = WcaInitialize(hInstall, "WixQueryOsDirs"); + ExitOnFailure(hr, "WixQueryOsDirs failed to initialize"); + + // get the paths of the CSIDLs that represent real paths and for which MSI + // doesn't yet have standard folder properties + WCHAR path[MAX_PATH]; + if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_ADMINTOOLS, NULL, SHGFP_TYPE_CURRENT, path)) + { + WcaSetProperty(L"WIX_DIR_ADMINTOOLS", path); + } + + if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_ALTSTARTUP, NULL, SHGFP_TYPE_CURRENT, path)) + { + WcaSetProperty(L"WIX_DIR_ALTSTARTUP", path); + } + + if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_CDBURN_AREA, NULL, SHGFP_TYPE_CURRENT, path)) + { + WcaSetProperty(L"WIX_DIR_CDBURN_AREA", path); + } + + if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_ADMINTOOLS, NULL, SHGFP_TYPE_CURRENT, path)) + { + WcaSetProperty(L"WIX_DIR_COMMON_ADMINTOOLS", path); + } + + if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_ALTSTARTUP, NULL, SHGFP_TYPE_CURRENT, path)) + { + WcaSetProperty(L"WIX_DIR_COMMON_ALTSTARTUP", path); + } + + if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_DOCUMENTS, NULL, SHGFP_TYPE_CURRENT, path)) + { + WcaSetProperty(L"WIX_DIR_COMMON_DOCUMENTS", path); + } + + if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_FAVORITES, NULL, SHGFP_TYPE_CURRENT, path)) + { + WcaSetProperty(L"WIX_DIR_COMMON_FAVORITES", path); + } + + if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_MUSIC, NULL, SHGFP_TYPE_CURRENT, path)) + { + WcaSetProperty(L"WIX_DIR_COMMON_MUSIC", path); + } + + if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_PICTURES, NULL, SHGFP_TYPE_CURRENT, path)) + { + WcaSetProperty(L"WIX_DIR_COMMON_PICTURES", path); + } + + if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_VIDEO, NULL, SHGFP_TYPE_CURRENT, path)) + { + WcaSetProperty(L"WIX_DIR_COMMON_VIDEO", path); + } + + if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COOKIES, NULL, SHGFP_TYPE_CURRENT, path)) + { + WcaSetProperty(L"WIX_DIR_COOKIES", path); + } + + if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_DESKTOP, NULL, SHGFP_TYPE_CURRENT, path)) + { + WcaSetProperty(L"WIX_DIR_DESKTOP", path); + } + + if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_HISTORY, NULL, SHGFP_TYPE_CURRENT, path)) + { + WcaSetProperty(L"WIX_DIR_HISTORY", path); + } + + if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_INTERNET_CACHE, NULL, SHGFP_TYPE_CURRENT, path)) + { + WcaSetProperty(L"WIX_DIR_INTERNET_CACHE", path); + } + + if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_MYMUSIC, NULL, SHGFP_TYPE_CURRENT, path)) + { + WcaSetProperty(L"WIX_DIR_MYMUSIC", path); + } + + if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_MYPICTURES, NULL, SHGFP_TYPE_CURRENT, path)) + { + WcaSetProperty(L"WIX_DIR_MYPICTURES", path); + } + + if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_MYVIDEO, NULL, SHGFP_TYPE_CURRENT, path)) + { + WcaSetProperty(L"WIX_DIR_MYVIDEO", path); + } + + if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_NETHOOD, NULL, SHGFP_TYPE_CURRENT, path)) + { + WcaSetProperty(L"WIX_DIR_NETHOOD", path); + } + + if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, path)) + { + WcaSetProperty(L"WIX_DIR_PERSONAL", path); + } + + if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_PRINTHOOD, NULL, SHGFP_TYPE_CURRENT, path)) + { + WcaSetProperty(L"WIX_DIR_PRINTHOOD", path); + } + + if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, path)) + { + WcaSetProperty(L"WIX_DIR_PROFILE", path); + } + + if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_RECENT, NULL, SHGFP_TYPE_CURRENT, path)) + { + WcaSetProperty(L"WIX_DIR_RECENT", path); + } + + if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_RESOURCES, NULL, SHGFP_TYPE_CURRENT, path)) + { + WcaSetProperty(L"WIX_DIR_RESOURCES", path); + } + +LExit: + if (FAILED(hr)) + er = ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + + +/******************************************************************** +SetPropertyWellKnownSID + + Set a property with the localized name of a well known windows SID +********************************************************************/ +static HRESULT SetPropertyWellKnownSID( + __in WELL_KNOWN_SID_TYPE sidType, + __in LPCWSTR wzPropertyName, + __in BOOL fIncludeDomainName + ) +{ + HRESULT hr = S_OK; + PSID psid = NULL; + WCHAR wzRefDomain[MAX_PATH] = {0}; + SID_NAME_USE nameUse; + DWORD refSize = MAX_PATH; + WCHAR wzName[MAX_PATH] = {0}; + LPWSTR pwzPropertyValue = NULL; + DWORD size = MAX_PATH; + + hr = AclGetWellKnownSid(sidType, &psid); + ExitOnFailure(hr, "Failed to get SID; skipping account %ls", wzPropertyName); + + if (!::LookupAccountSidW(NULL, psid, wzName, &size, wzRefDomain, &refSize, &nameUse)) + { + ExitWithLastError(hr, "Failed to look up account for SID; skipping account %ls.", wzPropertyName); + } + + if (fIncludeDomainName) + { + hr = StrAllocFormatted(&pwzPropertyValue, L"%s\\%s", wzRefDomain, wzName); + ExitOnFailure(hr, "Failed to format property value"); + + hr = WcaSetProperty(wzPropertyName, pwzPropertyValue); + ExitOnFailure(hr, "Failed write domain\\name property"); + } + else + { + hr = WcaSetProperty(wzPropertyName, wzName); + ExitOnFailure(hr, "Failed write to name-only property"); + } + +LExit: + if (NULL != psid) + { + ::LocalFree(psid); + } + ReleaseStr(pwzPropertyValue); + return hr; +} + +/******************************************************************** +WixQueryOsWellKnownSID - entry point for WixQueryOsWellKnownSID custom action + + Called as Type 1 custom action (DLL from the Binary table) from + Windows Installer to set properties with the localized names of built-in + Windows Security IDs +********************************************************************/ +extern "C" UINT __stdcall WixQueryOsWellKnownSID( + __in MSIHANDLE hInstall + ) +{ + HRESULT hr = S_OK; + DWORD er = ERROR_SUCCESS; + + hr = WcaInitialize(hInstall, "WixQueryOsWellKnownSID"); + ExitOnFailure(hr, "WixQueryOsWellKnownSID failed to initialize"); + + SetPropertyWellKnownSID(WinLocalSystemSid, L"WIX_ACCOUNT_LOCALSYSTEM", TRUE); + SetPropertyWellKnownSID(WinLocalServiceSid, L"WIX_ACCOUNT_LOCALSERVICE", TRUE); + SetPropertyWellKnownSID(WinNetworkServiceSid, L"WIX_ACCOUNT_NETWORKSERVICE", TRUE); + SetPropertyWellKnownSID(WinBuiltinAdministratorsSid, L"WIX_ACCOUNT_ADMINISTRATORS", TRUE); + SetPropertyWellKnownSID(WinBuiltinUsersSid, L"WIX_ACCOUNT_USERS", TRUE); + SetPropertyWellKnownSID(WinBuiltinGuestsSid, L"WIX_ACCOUNT_GUESTS", TRUE); + SetPropertyWellKnownSID(WinBuiltinPerfLoggingUsersSid, L"WIX_ACCOUNT_PERFLOGUSERS", TRUE); + SetPropertyWellKnownSID(WinBuiltinPerfLoggingUsersSid, L"WIX_ACCOUNT_PERFLOGUSERS_NODOMAIN", FALSE); + +LExit: + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + return WcaFinalize(er); +} + + +/******************************************************************** +DetectWDDMDriver + + Set a property if the driver on the machine is a WDDM driver. One + reliable way to detect the presence of a WDDM driver is to try and + use the Direct3DCreate9Ex() function. This method attempts that + then sets the property appropriately. +********************************************************************/ +static HRESULT DetectWDDMDriver() +{ + HRESULT hr = S_OK; + HMODULE hModule = NULL; + + // Manually load the d3d9.dll library. If the library couldn't be loaded then we obviously won't be able + // to try calling the function so just return. + hr = LoadSystemLibrary(L"d3d9.dll", &hModule); + if (E_MODNOTFOUND == hr) + { + TraceError(hr, "Unable to load DirectX APIs, skipping WDDM driver check."); + ExitFunction1(hr = S_OK); + } + ExitOnFailure(hr, "Failed to the load the existing DirectX APIs."); + + // Obtain the address of the Direct3DCreate9Ex function. If this fails we know it isn't a WDDM + // driver so just exit. + const void* Direct3DCreate9ExPtr = ::GetProcAddress(hModule, "Direct3DCreate9Ex"); + ExitOnNull(Direct3DCreate9ExPtr, hr, S_OK, "Unable to load Direct3DCreateEx function, so the driver is not a WDDM driver."); + + // At this point we know it's a WDDM driver so set the property. + hr = WcaSetIntProperty(L"WIX_WDDM_DRIVER_PRESENT", 1); + ExitOnFailure(hr, "Failed write property"); + +LExit: + if (NULL != hModule) + { + FreeLibrary(hModule); + } + + return hr; +} + +/******************************************************************** +DetectIsCompositionEnabled + + Set a property based on the return value of DwmIsCompositionEnabled(). +********************************************************************/ +static HRESULT DetectIsCompositionEnabled() +{ + HRESULT hr = S_OK; + HMODULE hModule = NULL; + BOOL compositionState = false; + + // Manually load the d3d9.dll library. If the library can't load it's likely because we are not on a Vista + // OS. Just return ok, and the property won't get set. + hr = LoadSystemLibrary(L"dwmapi.dll", &hModule); + if (E_MODNOTFOUND == hr) + { + TraceError(hr, "Unable to load Vista desktop window manager APIs, skipping Composition Enabled check."); + ExitFunction1(hr = S_OK); + } + ExitOnFailure(hr, "Failed to load the existing window manager APIs."); + + // If for some reason we can't get the function pointer that's ok, just return. + typedef HRESULT (WINAPI *DWMISCOMPOSITIONENABLEDPTR)(BOOL*); + DWMISCOMPOSITIONENABLEDPTR DwmIsCompositionEnabledPtr = (DWMISCOMPOSITIONENABLEDPTR)::GetProcAddress(hModule, "DwmIsCompositionEnabled"); + ExitOnNull(hModule, hr, S_OK, "Unable to obtain function information, skipping Composition Enabled check."); + + hr = DwmIsCompositionEnabledPtr(&compositionState); + ExitOnFailure(hr, "Failed to retrieve Composition state"); + + if (compositionState) + { + hr = WcaSetIntProperty(L"WIX_DWM_COMPOSITION_ENABLED", 1); + ExitOnFailure(hr, "Failed write property"); + } + +LExit: + if (NULL != hModule) + { + FreeLibrary(hModule); + } + return hr; +} + +/******************************************************************** +WixQueryOsDriverInfo - entry point for WixQueryOsDriverInfo custom action + + Called as Type 1 custom action (DLL from the Binary table) from + Windows Installer to set properties about drivers installed on + the target machine +********************************************************************/ +extern "C" UINT __stdcall WixQueryOsDriverInfo( + __in MSIHANDLE hInstall + ) +{ + HRESULT hr = S_OK; + DWORD er = ERROR_SUCCESS; + + hr = WcaInitialize(hInstall, "WixQueryOsDriverInfo"); + ExitOnFailure(hr, "WixQueryOsDriverInfo failed to initialize"); + + // Detect the WDDM driver status + hr = DetectWDDMDriver(); + ExitOnFailure(hr, "Failed to detect WIX_WDDM_DRIVER_PRESENT"); + + // Detect whether composition is enabled + hr = DetectIsCompositionEnabled(); + ExitOnFailure(hr, "Failed to detect WIX_DWM_COMPOSITION_ENABLED"); + +LExit: + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + return WcaFinalize(er); +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + +LPCWSTR vcsRemoveFolderExQuery = + L"SELECT `Wix4RemoveFolderEx`, `Component_`, `Property`, `InstallMode`, `WixRemoveFolderEx`.`Condition`, `Component`.`Attributes`" + L"FROM `Wix4RemoveFolderEx``,`Component` " + L"WHERE `Wix4RemoveFolderEx`.`Component_`=`Component`.`Component`"; +enum eRemoveFolderExQuery { rfqId = 1, rfqComponent, rfqProperty, rfqMode, rfqCondition, rfqComponentAttributes }; + +static HRESULT RecursePath( + __in_z LPCWSTR wzPath, + __in_z LPCWSTR wzId, + __in_z LPCWSTR wzComponent, + __in_z LPCWSTR wzProperty, + __in int iMode, + __in BOOL fDisableWow64Redirection, + __inout DWORD* pdwCounter, + __inout MSIHANDLE* phTable, + __inout MSIHANDLE* phColumns + ) +{ + HRESULT hr = S_OK; + DWORD er; + LPWSTR sczSearch = NULL; + LPWSTR sczProperty = NULL; + HANDLE hFind = INVALID_HANDLE_VALUE; + WIN32_FIND_DATAW wfd; + LPWSTR sczNext = NULL; + + if (fDisableWow64Redirection) + { + hr = WcaDisableWow64FSRedirection(); + ExitOnFailure(hr, "Custom action was told to act on a 64-bit component, but was unable to disable filesystem redirection through the Wow64 API."); + } + + // First recurse down to all the child directories. + hr = StrAllocFormatted(&sczSearch, L"%s*", wzPath); + ExitOnFailure(hr, "Failed to allocate file search string in path: %S", wzPath); + + hFind = ::FindFirstFileW(sczSearch, &wfd); + if (INVALID_HANDLE_VALUE == hFind) + { + er = ::GetLastError(); + if (ERROR_PATH_NOT_FOUND == er) + { + WcaLog(LOGMSG_STANDARD, "Search path not found: %ls; skipping", sczSearch); + ExitFunction1(hr = S_FALSE); + } + else + { + hr = HRESULT_FROM_WIN32(er); + } + ExitOnFailure(hr, "Failed to find all files in path: %S", wzPath); + } + + do + { + // Skip files and the dot directories. + 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]))) + { + continue; + } + + hr = StrAllocFormatted(&sczNext, L"%s%s\\", wzPath, wfd.cFileName); + ExitOnFailure(hr, "Failed to concat filename '%S' to string: %S", wfd.cFileName, wzPath); + + // Don't re-disable redirection; if it was necessary, we've already done it. + hr = RecursePath(sczNext, wzId, wzComponent, wzProperty, iMode, FALSE, pdwCounter, phTable, phColumns); + ExitOnFailure(hr, "Failed to recurse path: %S", sczNext); + } while (::FindNextFileW(hFind, &wfd)); + + er = ::GetLastError(); + if (ERROR_NO_MORE_FILES == er) + { + hr = S_OK; + } + else + { + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "Failed while looping through files in directory: %S", wzPath); + } + + // Finally, set a property that points at our path. + hr = StrAllocFormatted(&sczProperty, L"_%s_%u", wzProperty, *pdwCounter); + ExitOnFailure(hr, "Failed to allocate Property for RemoveFile table with property: %S.", wzProperty); + + ++(*pdwCounter); + + hr = WcaSetProperty(sczProperty, wzPath); + ExitOnFailure(hr, "Failed to set Property: %S with path: %S", sczProperty, wzPath); + + // Add the row to remove any files and another row to remove the folder. + hr = WcaAddTempRecord(phTable, phColumns, L"RemoveFile", NULL, 1, 5, L"RfxFiles", wzComponent, L"*.*", sczProperty, iMode); + ExitOnFailure(hr, "Failed to add row to remove all files for Wix4RemoveFolderEx row: %ls under path: %ls", wzId, wzPath); + + hr = WcaAddTempRecord(phTable, phColumns, L"RemoveFile", NULL, 1, 5, L"RfxFolder", wzComponent, NULL, sczProperty, iMode); + ExitOnFailure(hr, "Failed to add row to remove folder for Wix4RemoveFolderEx row: %ls under path: %ls", wzId, wzPath); + +LExit: + if (INVALID_HANDLE_VALUE != hFind) + { + ::FindClose(hFind); + } + + if (fDisableWow64Redirection) + { + WcaRevertWow64FSRedirection(); + } + + ReleaseStr(sczNext); + ReleaseStr(sczProperty); + ReleaseStr(sczSearch); + return hr; +} + +extern "C" UINT WINAPI WixRemoveFoldersEx( + __in MSIHANDLE hInstall + ) +{ + //AssertSz(FALSE, "debug WixRemoveFoldersEx"); + + HRESULT hr = S_OK; + PMSIHANDLE hView; + PMSIHANDLE hRec; + LPWSTR sczId = NULL; + LPWSTR sczComponent = NULL; + LPWSTR sczProperty = NULL; + LPWSTR sczCondition = NULL; + LPWSTR sczPath = NULL; + LPWSTR sczExpandedPath = NULL; + int iMode = 0; + int iComponentAttributes; + BOOL f64BitComponent = FALSE; + DWORD dwCounter = 0; + DWORD_PTR cchLen = 0; + MSIHANDLE hTable = NULL; + MSIHANDLE hColumns = NULL; + + hr = WcaInitialize(hInstall, "WixRemoveFoldersEx"); + ExitOnFailure(hr, "Failed to initialize WixRemoveFoldersEx."); + + WcaInitializeWow64(); + + // anything to do? + if (S_OK != WcaTableExists(L"Wix4RemoveFolderEx")) + { + WcaLog(LOGMSG_STANDARD, "Wix4RemoveFolderEx table doesn't exist, so there are no folders to remove."); + ExitFunction(); + } + + // query and loop through all the remove folders exceptions + hr = WcaOpenExecuteView(vcsRemoveFolderExQuery, &hView); + ExitOnFailure(hr, "Failed to open view on Wix4RemoveFolderEx table"); + + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + hr = WcaGetRecordString(hRec, rfqId, &sczId); + ExitOnFailure(hr, "Failed to get remove folder identity."); + + hr = WcaGetRecordString(hRec, rfqCondition, &sczCondition); + ExitOnFailure(hr, "Failed to get remove folder condition."); + + if (sczCondition && *sczCondition) + { + MSICONDITION condition = ::MsiEvaluateConditionW(hInstall, sczCondition); + if (MSICONDITION_TRUE == condition) + { + WcaLog(LOGMSG_STANDARD, "True condition for row %S: %S; processing.", sczId, sczCondition); + } + else + { + WcaLog(LOGMSG_STANDARD, "False or invalid condition for row %S: %S; skipping.", sczId, sczCondition); + continue; + } + } + + hr = WcaGetRecordString(hRec, rfqComponent, &sczComponent); + ExitOnFailure(hr, "Failed to get remove folder component."); + + hr = WcaGetRecordString(hRec, rfqProperty, &sczProperty); + ExitOnFailure(hr, "Failed to get remove folder property."); + + hr = WcaGetRecordInteger(hRec, rfqMode, &iMode); + ExitOnFailure(hr, "Failed to get remove folder mode"); + + hr = WcaGetProperty(sczProperty, &sczPath); + ExitOnFailure(hr, "Failed to resolve remove folder property: %S for row: %S", sczProperty, sczId); + + hr = WcaGetRecordInteger(hRec, rfqComponentAttributes, &iComponentAttributes); + ExitOnFailure(hr, "failed to get component attributes for row: %ls", sczId); + + f64BitComponent = iComponentAttributes & msidbComponentAttributes64bit; + + // fail early if the property isn't set as you probably don't want your installers trying to delete SystemFolder + // StringCchLengthW succeeds only if the string is zero characters plus 1 for the terminating null + hr = ::StringCchLengthW(sczPath, 1, reinterpret_cast(&cchLen)); + if (SUCCEEDED(hr)) + { + ExitOnFailure(hr = E_INVALIDARG, "Missing folder property: %S for row: %S", sczProperty, sczId); + } + + hr = PathExpand(&sczExpandedPath, sczPath, PATH_EXPAND_ENVIRONMENT); + ExitOnFailure(hr, "Failed to expand path: %S for row: %S", sczPath, sczId); + + hr = PathBackslashTerminate(&sczExpandedPath); + ExitOnFailure(hr, "Failed to backslash-terminate path: %S", sczExpandedPath); + + WcaLog(LOGMSG_STANDARD, "Recursing path: %S for row: %S.", sczExpandedPath, sczId); + hr = RecursePath(sczExpandedPath, sczId, sczComponent, sczProperty, iMode, f64BitComponent, &dwCounter, &hTable, &hColumns); + ExitOnFailure(hr, "Failed while navigating path: %S for row: %S", sczPath, sczId); + } + + // reaching the end of the list is actually a good thing, not an error + if (E_NOMOREITEMS == hr) + { + hr = S_OK; + } + ExitOnFailure(hr, "Failure occured while processing Wix4RemoveFolderEx table"); + +LExit: + WcaFinalizeWow64(); + + if (hColumns) + { + ::MsiCloseHandle(hColumns); + } + + if (hTable) + { + ::MsiCloseHandle(hTable); + } + + ReleaseStr(sczExpandedPath); + ReleaseStr(sczPath); + ReleaseStr(sczProperty); + ReleaseStr(sczComponent); + ReleaseStr(sczCondition); + ReleaseStr(sczId); + + DWORD er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + +LPCWSTR vcsRemoveRegistryKeyExQuery = + L"SELECT `Wix4RemoveRegistryKeyEx`, `Component_`, `Root`, `Key`, `InstallMode`, `Condition` FROM `Wix4RemoveRegistryKeyEx`"; +enum eRemoveRegistryKeyExQuery { rrxqId = 1, rrxqComponent, rrxqRoot, rrxqKey, rrxqMode, rrxqCondition }; + +extern "C" UINT WINAPI WixRemoveRegistryKeysEx( + __in MSIHANDLE hInstall +) +{ + //AssertSz(FALSE, "debug WixRemoveRegistryKeyEx"); + + HRESULT hr = S_OK; + PMSIHANDLE hView; + PMSIHANDLE hRec; + LPWSTR sczId = NULL; + LPWSTR sczComponent = NULL; + LPWSTR sczCondition = NULL; + LPWSTR sczKey = NULL; + int iRoot = 0; + int iMode = 0; + MSIHANDLE hTable = NULL; + MSIHANDLE hColumns = NULL; + + hr = WcaInitialize(hInstall, __FUNCTION__); + ExitOnFailure(hr, "Failed to initialize " __FUNCTION__); + + // anything to do? + if (S_OK != WcaTableExists(L"Wix4RemoveRegistryKeyEx")) + { + WcaLog(LOGMSG_STANDARD, "Wix4RemoveRegistryKeyEx table doesn't exist, so there are no registry keys to remove."); + ExitFunction(); + } + + hr = WcaOpenExecuteView(vcsRemoveRegistryKeyExQuery, &hView); + ExitOnFailure(hr, "Failed to open view on Wix4RemoveRegistryKeyEx table"); + + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + hr = WcaGetRecordString(hRec, rrxqId, &sczId); + ExitOnFailure(hr, "Failed to get Wix4RemoveRegistryKeyEx identity."); + + hr = WcaGetRecordString(hRec, rrxqCondition, &sczCondition); + ExitOnFailure(hr, "Failed to get Wix4RemoveRegistryKeyEx condition."); + + if (sczCondition && *sczCondition) + { + MSICONDITION condition = ::MsiEvaluateConditionW(hInstall, sczCondition); + if (MSICONDITION_TRUE == condition) + { + WcaLog(LOGMSG_STANDARD, "True condition for row %S: %S; processing.", sczId, sczCondition); + } + else + { + WcaLog(LOGMSG_STANDARD, "False or invalid condition for row %S: %S; skipping.", sczId, sczCondition); + continue; + } + } + + hr = WcaGetRecordString(hRec, rrxqComponent, &sczComponent); + ExitOnFailure(hr, "Failed to get Wix4RemoveRegistryKeyEx component."); + + hr = WcaGetRecordInteger(hRec, rrxqRoot, &iRoot); + ExitOnFailure(hr, "Failed to get Wix4RemoveRegistryKeyEx root."); + + hr = WcaGetRecordString(hRec, rrxqKey, &sczKey); + ExitOnFailure(hr, "Failed to get Wix4RemoveRegistryKeyEx key."); + + hr = WcaGetRecordInteger(hRec, rrxqMode, &iMode); + ExitOnFailure(hr, "Failed to get Wix4RemoveRegistryKeyEx mode."); + + switch (iMode) + { + case 1: // remove on install + WcaLog(LOGMSG_STANDARD, "Adding RemoveRegistry row: %ls/%d/%ls/-/%ls", sczId, iRoot, sczKey, sczComponent); + hr = WcaAddTempRecord(&hTable, &hColumns, L"RemoveRegistry", NULL, 0, 5, sczId, iRoot, sczKey, L"-", sczComponent); + ExitOnFailure(hr, "Failed to add RemoveRegistry row for remove-on-install Wix4RemoveRegistryKeyEx row: %ls:", sczId); + break; + case 2: // remove on uninstall + WcaLog(LOGMSG_STANDARD, "Adding Registry row: %ls/%d/%ls/-/null/%ls", sczId, iRoot, sczKey, sczComponent); + hr = WcaAddTempRecord(&hTable, &hColumns, L"Registry", NULL, 0, 6, sczId, iRoot, sczKey, L"-", NULL, sczComponent); + ExitOnFailure(hr, "Failed to add Registry row for remove-on-uninstall Wix4RemoveRegistryKeyEx row: %ls:", sczId); + break; + } + } + + // reaching the end of the list is actually a good thing, not an error + if (E_NOMOREITEMS == hr) + { + hr = S_OK; + } + ExitOnFailure(hr, "Failure occured while processing Wix4RemoveRegistryKeyEx table."); + +LExit: + if (hColumns) + { + ::MsiCloseHandle(hColumns); + } + + if (hTable) + { + ::MsiCloseHandle(hTable); + } + + ReleaseStr(sczKey); + ReleaseStr(sczComponent); + ReleaseStr(sczCondition); + ReleaseStr(sczId); + + DWORD er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" +#include + +// Include space for the terminating null. +#define CCH_SESSION_KEY CCH_RM_SESSION_KEY + 1 + +enum eRmuResourceType +{ + etInvalid, + etFilename, + etApplication, + etServiceName, + + // Mask types from Attributes. + etTypeMask = 0xf, +}; + +LPCWSTR vcsRestartResourceQuery = + L"SELECT `Wix4RestartResource`.`Wix4RestartResource`, `Wix4RestartResource`.`Component_`, `Wix4RestartResource`.`Resource`, `Wix4RestartResource`.`Attributes` " + L"FROM `Wix4RestartResource`"; +enum eRestartResourceQuery { rrqRestartResource = 1, rrqComponent, rrqResource, rrqAttributes }; + +/******************************************************************** +WixRegisterRestartResources - Immediate CA to register resources with RM. + +Enumerates components before InstallValidate and registers resources +to be restarted by Restart Manager if the component action +is anything other than None. + +Do not disable file system redirection. + +********************************************************************/ +extern "C" UINT __stdcall WixRegisterRestartResources( + __in MSIHANDLE hInstall + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + PMSIHANDLE hView = NULL; + PMSIHANDLE hRec = NULL; + + LPWSTR wzSessionKey = NULL; + size_t cchSessionKey = 0; + PRMU_SESSION pSession = NULL; + + LPWSTR wzRestartResource = NULL; + LPWSTR wzComponent = NULL; + LPWSTR wzResource = NULL; + int iAttributes = NULL; + BOOL fIsComponentNull = FALSE; + WCA_TODO todo = WCA_TODO_UNKNOWN; + int iType = etInvalid; + + hr = WcaInitialize(hInstall, "WixRegisterRestartResources"); + ExitOnFailure(hr, "Failed to initialize."); + + // Skip if the table doesn't exist. + if (S_OK != WcaTableExists(L"Wix4RestartResource")) + { + WcaLog(LOGMSG_STANDARD, "The Wix4RestartResource table does not exist; there are no resources to register with Restart Manager."); + ExitFunction(); + } + + // Get the existing Restart Manager session if available. + hr = WcaGetProperty(L"MsiRestartManagerSessionKey", &wzSessionKey); + ExitOnFailure(hr, "Failed to get the MsiRestartManagerSessionKey property."); + + hr = ::StringCchLengthW(wzSessionKey, CCH_SESSION_KEY, &cchSessionKey); + ExitOnFailure(hr, "Failed to get the MsiRestartManagerSessionKey string length."); + + // Skip if the property doesn't exist. + if (0 == cchSessionKey) + { + WcaLog(LOGMSG_STANDARD, "The MsiRestartManagerSessionKey property is not available to join."); + ExitFunction(); + } + + // Join the existing Restart Manager session if supported. + hr = RmuJoinSession(&pSession, wzSessionKey); + if (E_MODNOTFOUND == hr) + { + WcaLog(LOGMSG_STANDARD, "The Restart Manager is not supported on this platform. Skipping."); + ExitFunction1(hr = S_OK); + } + else if (FAILED(hr)) + { + WcaLog(LOGMSG_STANDARD, "Failed to join the existing Restart Manager session %ls.", wzSessionKey); + ExitFunction1(hr = S_OK); + } + + // Loop through each record in the table. + hr = WcaOpenExecuteView(vcsRestartResourceQuery, &hView); + ExitOnFailure(hr, "Failed to open a view on the RestartResource table."); + + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + hr = WcaGetRecordString(hRec, rrqRestartResource, &wzRestartResource); + ExitOnFailure(hr, "Failed to get the RestartResource field value."); + + hr = WcaGetRecordString(hRec, rrqComponent, &wzComponent); + ExitOnFailure(hr, "Failed to get the Component_ field value."); + + hr = WcaGetRecordFormattedString(hRec, rrqResource, &wzResource); + ExitOnFailure(hr, "Failed to get the Resource formatted field value."); + + hr = WcaGetRecordInteger(hRec, rrqAttributes, &iAttributes); + ExitOnFailure(hr, "Failed to get the Attributes field value."); + + fIsComponentNull = ::MsiRecordIsNull(hRec, rrqComponent); + todo = WcaGetComponentToDo(wzComponent); + + // Only register resources for components that are null, or being installed, reinstalled, or uninstalled. + if (!fIsComponentNull && WCA_TODO_UNKNOWN == todo) + { + WcaLog(LOGMSG_VERBOSE, "Skipping resource %ls.", wzRestartResource); + continue; + } + + // Get the type from Attributes and add to the Restart Manager. + iType = iAttributes & etTypeMask; + switch (iType) + { + case etFilename: + WcaLog(LOGMSG_VERBOSE, "Registering file name %ls with the Restart Manager.", wzResource); + hr = RmuAddFile(pSession, wzResource); + ExitOnFailure(hr, "Failed to register the file name with the Restart Manager session."); + break; + + case etApplication: + WcaLog(LOGMSG_VERBOSE, "Registering process name %ls with the Restart Manager.", wzResource); + hr = RmuAddProcessesByName(pSession, wzResource); + if (E_NOTFOUND == hr) + { + // ERROR_ACCESS_DENIED was returned when trying to register this process. + // Since other instances may have been registered, log a message and continue the setup rather than failing. + 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); + hr = S_OK; + } + else + { + ExitOnFailure(hr, "Failed to register the process name with the Restart Manager session."); + } + break; + + case etServiceName: + WcaLog(LOGMSG_VERBOSE, "Registering service name %ls with the Restart Manager.", wzResource); + hr = RmuAddService(pSession, wzResource); + ExitOnFailure(hr, "Failed to register the service name with the Restart Manager session."); + break; + + default: + WcaLog(LOGMSG_VERBOSE, "The resource type %d for %ls is not supported and will not be registered.", iType, wzRestartResource); + break; + } + } + + if (E_NOMOREITEMS == hr) + { + hr = S_OK; + } + ExitOnFailure(hr, "Failed while looping through all rows to register resources."); + + // Register the resources and unjoin the session. + hr = RmuEndSession(pSession); + if (FAILED(hr)) + { + WcaLog(LOGMSG_VERBOSE, "Failed to register the resources with the Restart Manager."); + ExitFunction1(hr = S_OK); + } + +LExit: + ReleaseStr(wzRestartResource); + ReleaseStr(wzComponent); + ReleaseStr(wzResource); + + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + + return WcaFinalize(er); +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + +LPCWSTR vcsTouchFileQuery = L"SELECT `Wix4TouchFile`, `Component_`, `Path`, `Attributes` FROM `Wix4TouchFile`"; +enum TOUCH_FILE_QUERY { tfqId = 1, tfqComponent, tfqPath, tfqTouchFileAttributes }; + +enum TOUCH_FILE_ATTRIBUTE +{ + TOUCH_FILE_ATTRIBUTE_ON_INSTALL = 0x01, + TOUCH_FILE_ATTRIBUTE_ON_REINSTALL = 0x02, + TOUCH_FILE_ATTRIBUTE_ON_UNINSTALL = 0x04, + TOUCH_FILE_ATTRIBUTE_64BIT = 0x10, + TOUCH_FILE_ATTRIBUTE_VITAL = 0x20 +}; + + +static BOOL SetExistingFileModifiedTime( + __in_z LPCWSTR wzId, + __in_z LPCWSTR wzPath, + __in BOOL f64Bit, + __in FILETIME* pftModified + ) +{ + HRESULT hr = S_OK; + BOOL fReenableFileSystemRedirection = FALSE; + + if (f64Bit) + { + hr = WcaDisableWow64FSRedirection(); + ExitOnFailure(hr, "Failed to disable 64-bit file system redirection to path: '%ls' for: %ls", wzPath, wzId); + + fReenableFileSystemRedirection = TRUE; + } + + hr = FileSetTime(wzPath, NULL, NULL, pftModified); + +LExit: + if (fReenableFileSystemRedirection) + { + WcaRevertWow64FSRedirection(); + } + + return SUCCEEDED(hr); +} + + +static HRESULT AddDataToCustomActionData( + __deref_inout_z LPWSTR* psczCustomActionData, + __in_z LPCWSTR wzId, + __in_z LPCWSTR wzPath, + __in int iTouchFileAttributes, + __in FILETIME ftModified + ) +{ + HRESULT hr = S_OK; + + hr = WcaWriteStringToCaData(wzId, psczCustomActionData); + ExitOnFailure(hr, "Failed to add touch file identity to custom action data."); + + hr = WcaWriteStringToCaData(wzPath, psczCustomActionData); + ExitOnFailure(hr, "Failed to add touch file path to custom action data."); + + hr = WcaWriteIntegerToCaData(iTouchFileAttributes, psczCustomActionData); + ExitOnFailure(hr, "Failed to add touch file attributes to custom action data."); + + hr = WcaWriteIntegerToCaData(ftModified.dwHighDateTime, psczCustomActionData); + ExitOnFailure(hr, "Failed to add touch file high date/time to custom action data."); + + hr = WcaWriteIntegerToCaData(ftModified.dwLowDateTime, psczCustomActionData); + ExitOnFailure(hr, "Failed to add touch file low date/time to custom action data."); + +LExit: + return hr; +} + + +static BOOL TryGetExistingFileModifiedTime( + __in_z LPCWSTR wzId, + __in_z LPCWSTR wzPath, + __in BOOL f64Bit, + __inout FILETIME* pftModified + ) +{ + HRESULT hr = S_OK; + BOOL fReenableFileSystemRedirection = FALSE; + + if (f64Bit) + { + hr = WcaDisableWow64FSRedirection(); + ExitOnFailure(hr, "Failed to disable 64-bit file system redirection to path: '%ls' for: %ls", wzPath, wzId); + + fReenableFileSystemRedirection = TRUE; + } + + hr = FileGetTime(wzPath, NULL, NULL, pftModified); + if (E_PATHNOTFOUND == hr || E_FILENOTFOUND == hr) + { + // If the file doesn't exist yet there is nothing to rollback (i.e. file will probably be removed during rollback), so + // keep the error code but don't log anything. + } + else if (FAILED(hr)) + { + WcaLog(LOGMSG_STANDARD, "Cannot access modified timestamp for file: '%ls' due to error: 0x%x. Continuing with out rollback for: %ls", wzPath, hr, wzId); + } + +LExit: + if (fReenableFileSystemRedirection) + { + WcaRevertWow64FSRedirection(); + } + + return SUCCEEDED(hr); +} + + +static HRESULT ProcessTouchFileTable( + __in BOOL fInstalling + ) +{ + HRESULT hr = S_OK; + + FILETIME ftModified = {}; + + PMSIHANDLE hView; + PMSIHANDLE hRec; + + LPWSTR sczId = NULL; + LPWSTR sczComponent = NULL; + int iTouchFileAttributes = 0; + LPWSTR sczPath = NULL; + + FILETIME ftRollbackModified = {}; + LPWSTR sczRollbackData = NULL; + LPWSTR sczExecuteData = NULL; + + if (S_OK != WcaTableExists(L"Wix4TouchFile")) + { + ExitFunction(); + } + + ::GetSystemTimeAsFileTime(&ftModified); + + hr = WcaOpenExecuteView(vcsTouchFileQuery, &hView); + ExitOnFailure(hr, "Failed to open view on Wix4TouchFile table"); + + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + hr = WcaGetRecordString(hRec, tfqId, &sczId); + ExitOnFailure(hr, "Failed to get touch file identity."); + + hr = WcaGetRecordString(hRec, tfqComponent, &sczComponent); + ExitOnFailure(hr, "Failed to get touch file component for: %ls", sczId); + + hr = WcaGetRecordInteger(hRec, tfqTouchFileAttributes, &iTouchFileAttributes); + ExitOnFailure(hr, "Failed to get touch file attributes for: %ls", sczId); + + WCA_TODO todo = WcaGetComponentToDo(sczComponent); + + BOOL fOnInstall = fInstalling && WCA_TODO_INSTALL == todo && (iTouchFileAttributes & TOUCH_FILE_ATTRIBUTE_ON_INSTALL); + BOOL fOnReinstall = fInstalling && WCA_TODO_REINSTALL == todo && (iTouchFileAttributes & TOUCH_FILE_ATTRIBUTE_ON_REINSTALL); + BOOL fOnUninstall = !fInstalling && WCA_TODO_UNINSTALL == todo && (iTouchFileAttributes & TOUCH_FILE_ATTRIBUTE_ON_UNINSTALL); + + if (fOnInstall || fOnReinstall || fOnUninstall) + { + hr = WcaGetRecordFormattedString(hRec, tfqPath, &sczPath); + ExitOnFailure(hr, "Failed to get touch file path for: %ls", sczId); + + if (TryGetExistingFileModifiedTime(sczId, sczPath, (iTouchFileAttributes & TOUCH_FILE_ATTRIBUTE_64BIT), &ftRollbackModified)) + { + hr = AddDataToCustomActionData(&sczRollbackData, sczId, sczPath, iTouchFileAttributes, ftRollbackModified); + ExitOnFailure(hr, "Failed to add to rollback custom action data for: %ls", sczId); + } + + hr = AddDataToCustomActionData(&sczExecuteData, sczId, sczPath, iTouchFileAttributes, ftModified); + ExitOnFailure(hr, "Failed to add to execute custom action data for: %ls", sczId); + } + } + + if (E_NOMOREITEMS == hr) + { + hr = S_OK; + } + ExitOnFailure(hr, "Failure occured while processing Wix4TouchFile table"); + + if (sczRollbackData) + { + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackTouchFile"), sczRollbackData, 0); + ExitOnFailure(hr, "Failed to schedule RollbackTouchFile"); + } + + if (sczExecuteData) + { + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecuteTouchFile"), sczExecuteData, 0); + ExitOnFailure(hr, "Failed to schedule ExecuteTouchFile"); + } + +LExit: + ReleaseStr(sczExecuteData); + ReleaseStr(sczRollbackData); + ReleaseStr(sczPath); + ReleaseStr(sczComponent); + ReleaseStr(sczId); + + return hr; +} + + +extern "C" UINT WINAPI WixTouchFileDuringInstall( + __in MSIHANDLE hInstall + ) +{ + //AssertSz(FALSE, "debug WixTouchFileDuringInstall"); + + HRESULT hr = S_OK; + + hr = WcaInitialize(hInstall, "WixTouchFileDuringInstall"); + ExitOnFailure(hr, "Failed to initialize WixTouchFileDuringInstall."); + + hr = ProcessTouchFileTable(TRUE); + +LExit: + DWORD er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + + +extern "C" UINT WINAPI WixTouchFileDuringUninstall( + __in MSIHANDLE hInstall + ) +{ + //AssertSz(FALSE, "debug WixTouchFileDuringUninstall"); + + HRESULT hr = S_OK; + + hr = WcaInitialize(hInstall, "WixTouchFileDuringUninstall"); + ExitOnFailure(hr, "Failed to initialize WixTouchFileDuringUninstall."); + + hr = ProcessTouchFileTable(FALSE); + +LExit: + DWORD er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + + +extern "C" UINT WINAPI WixExecuteTouchFile( + __in MSIHANDLE hInstall + ) +{ + HRESULT hr = S_OK; + + LPWSTR sczData = NULL; + LPWSTR pwz = NULL; + + LPWSTR sczId = NULL; + LPWSTR sczPath = NULL; + int iTouchFileAttributes = 0; + FILETIME ftModified = {}; + + hr = WcaInitialize(hInstall, "WixExecuteTouchFile"); + ExitOnFailure(hr, "Failed to initialize WixExecuteTouchFile."); + + hr = WcaGetProperty(L"CustomActionData", &sczData); + ExitOnFailure(hr, "Failed to get custom action data for WixExecuteTouchFile."); + + pwz = sczData; + + while (pwz && *pwz) + { + hr = WcaReadStringFromCaData(&pwz, &sczId); + ExitOnFailure(hr, "Failed to get touch file identity from custom action data."); + + hr = WcaReadStringFromCaData(&pwz, &sczPath); + ExitOnFailure(hr, "Failed to get touch file path from custom action data for: %ls", sczId); + + hr = WcaReadIntegerFromCaData(&pwz, &iTouchFileAttributes); + ExitOnFailure(hr, "Failed to get touch file attributes from custom action data for: %ls", sczId); + + hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&ftModified.dwHighDateTime)); + ExitOnFailure(hr, "Failed to get touch file high date/time from custom action data for: %ls", sczId); + + hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&ftModified.dwLowDateTime)); + ExitOnFailure(hr, "Failed to get touch file low date/time from custom action data for: %ls", sczId); + + hr = SetExistingFileModifiedTime(sczId, sczPath, (iTouchFileAttributes & TOUCH_FILE_ATTRIBUTE_64BIT), &ftModified); + if (FAILED(hr)) + { + if (iTouchFileAttributes & TOUCH_FILE_ATTRIBUTE_VITAL) + { + ExitOnFailure(hr, "Failed to touch file: '%ls' for: %ls", &sczPath, sczId); + } + else + { + WcaLog(LOGMSG_STANDARD, "Could not touch non-vital file: '%ls' for: %ls with error: 0x%x. Continuing...", sczPath, sczId, hr); + hr = S_OK; + } + } + } + +LExit: + ReleaseStr(sczPath); + ReleaseStr(sczId); + ReleaseStr(sczData); + + DWORD er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + +#define XMLCONFIG_ELEMENT 0x00000001 +#define XMLCONFIG_VALUE 0x00000002 +#define XMLCONFIG_DOCUMENT 0x00000004 +#define XMLCONFIG_CREATE 0x00000010 +#define XMLCONFIG_DELETE 0x00000020 +#define XMLCONFIG_INSTALL 0x00000100 +#define XMLCONFIG_UNINSTALL 0x00000200 +#define XMLCONFIG_PRESERVE_MODIFIED 0x00001000 + +enum eXmlAction +{ + xaUnknown = 0, + xaOpenFile, + xaOpenFilex64, + xaWriteValue, + xaWriteDocument, + xaDeleteValue, + xaCreateElement, + xaDeleteElement, +}; + +enum eXmlPreserveDate +{ + xdDontPreserve = 0, + xdPreserve +}; + +LPCWSTR vcsXmlConfigQuery = + L"SELECT `Wix4XmlConfig`.`Wix4XmlConfig`, `Wix4XmlConfig`.`File`, `Wix4XmlConfig`.`ElementId`, `Wix4XmlConfig`.`ElementPath`, `Wix4XmlConfig`.`VerifyPath`, `Wix4XmlConfig`.`Name`, " + L"`Wix4XmlConfig`.`Value`, `Wix4XmlConfig`.`Flags`, `Wix4XmlConfig`.`Component_`, `Component`.`Attributes` " + L"FROM `Wix4XmlConfig`,`Component` WHERE `Wix4XmlConfig`.`Component_`=`Component`.`Component` ORDER BY `File`, `Sequence`"; +enum eXmlConfigQuery { xfqXmlConfig = 1, xfqFile, xfqElementId, xfqElementPath, xfqVerifyPath, xfqName, xfqValue, xfqXmlFlags, xfqComponent, xfqCompAttributes }; + +struct XML_CONFIG_CHANGE +{ + WCHAR wzId[MAX_DARWIN_KEY + 1]; + + WCHAR wzComponent[MAX_DARWIN_KEY + 1]; + INSTALLSTATE isInstalled; + INSTALLSTATE isAction; + + WCHAR wzFile[MAX_PATH]; + LPWSTR pwzElementId; + LPWSTR pwzElementPath; + LPWSTR pwzVerifyPath; + WCHAR wzName[MAX_DARWIN_COLUMN]; + LPWSTR pwzValue; + BOOL fInstalledFile; + + int iXmlFlags; + int iCompAttributes; + + XML_CONFIG_CHANGE* pxfcAdditionalChanges; + int cAdditionalChanges; + + XML_CONFIG_CHANGE* pxfcPrev; + XML_CONFIG_CHANGE* pxfcNext; +}; + +static HRESULT FreeXmlConfigChangeList( + __in_opt XML_CONFIG_CHANGE* pxfcList + ) +{ + HRESULT hr = S_OK; + + XML_CONFIG_CHANGE* pxfcDelete; + while(pxfcList) + { + pxfcDelete = pxfcList; + pxfcList = pxfcList->pxfcNext; + + if (pxfcDelete->pwzElementId) + { + hr = MemFree(pxfcDelete->pwzElementId); + ExitOnFailure(hr, "failed to free xml config element id in change list item"); + } + + if (pxfcDelete->pwzElementPath) + { + hr = MemFree(pxfcDelete->pwzElementPath); + ExitOnFailure(hr, "failed to free xml config element path in change list item"); + } + + if (pxfcDelete->pwzVerifyPath) + { + hr = MemFree(pxfcDelete->pwzVerifyPath); + ExitOnFailure(hr, "failed to free xml config verify path in change list item"); + } + + if (pxfcDelete->pwzValue) + { + hr = MemFree(pxfcDelete->pwzValue); + ExitOnFailure(hr, "failed to free xml config value in change list item"); + } + + hr = MemFree(pxfcDelete); + ExitOnFailure(hr, "failed to free xml config change list item"); + } + +LExit: + return hr; +} + +static HRESULT AddXmlConfigChangeToList( + __inout XML_CONFIG_CHANGE** ppxfcHead, + __inout XML_CONFIG_CHANGE** ppxfcTail + ) +{ + Assert(ppxfcHead && ppxfcTail); + + HRESULT hr = S_OK; + + XML_CONFIG_CHANGE* pxfc = static_cast(MemAlloc(sizeof(XML_CONFIG_CHANGE), TRUE)); + ExitOnNull(pxfc, hr, E_OUTOFMEMORY, "failed to allocate memory for new xml file change list element"); + + // Add it to the end of the list + if (NULL == *ppxfcHead) + { + *ppxfcHead = pxfc; + *ppxfcTail = pxfc; + } + else + { + Assert(*ppxfcTail && (*ppxfcTail)->pxfcNext == NULL); + (*ppxfcTail)->pxfcNext = pxfc; + pxfc->pxfcPrev = *ppxfcTail; + *ppxfcTail = pxfc; + } + +LExit: + return hr; +} + + +static HRESULT ReadXmlConfigTable( + __inout XML_CONFIG_CHANGE** ppxfcHead, + __inout XML_CONFIG_CHANGE** ppxfcTail + ) +{ + Assert(ppxfcHead && ppxfcTail); + + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + PMSIHANDLE hView = NULL; + PMSIHANDLE hRec = NULL; + + LPWSTR pwzData = NULL; + + // loop through all the xml configurations + hr = WcaOpenExecuteView(vcsXmlConfigQuery, &hView); + ExitOnFailure(hr, "failed to open view on Wix4XmlConfig table"); + + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + hr = AddXmlConfigChangeToList(ppxfcHead, ppxfcTail); + ExitOnFailure(hr, "failed to add xml file change to list"); + + // Get record Id + hr = WcaGetRecordString(hRec, xfqXmlConfig, &pwzData); + ExitOnFailure(hr, "failed to get Wix4XmlConfig record Id"); + hr = StringCchCopyW((*ppxfcTail)->wzId, countof((*ppxfcTail)->wzId), pwzData); + ExitOnFailure(hr, "failed to copy Wix4XmlConfig record Id"); + + // Get component name + hr = WcaGetRecordString(hRec, xfqComponent, &pwzData); + ExitOnFailure(hr, "failed to get component name for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId); + + // Get the component's state + if (pwzData && *pwzData) + { + hr = StringCchCopyW((*ppxfcTail)->wzComponent, countof((*ppxfcTail)->wzComponent), pwzData); + ExitOnFailure(hr, "failed to copy component id"); + + er = ::MsiGetComponentStateW(WcaGetInstallHandle(), (*ppxfcTail)->wzComponent, &(*ppxfcTail)->isInstalled, &(*ppxfcTail)->isAction); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "failed to get install state for component id"); + } + + // Get the xml file + hr = WcaGetRecordFormattedString(hRec, xfqFile, &pwzData); + ExitOnFailure(hr, "failed to get xml file for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId); + hr = StringCchCopyW((*ppxfcTail)->wzFile, countof((*ppxfcTail)->wzFile), pwzData); + ExitOnFailure(hr, "failed to copy xml file path"); + + // Figure out if the file is already on the machine or if it's being installed + hr = WcaGetRecordString(hRec, xfqFile, &pwzData); + ExitOnFailure(hr, "failed to get xml file for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId); + if (NULL != wcsstr(pwzData, L"[!") || NULL != wcsstr(pwzData, L"[#")) + { + (*ppxfcTail)->fInstalledFile = TRUE; + } + + // Get the Wix4XmlConfig table flags + hr = WcaGetRecordInteger(hRec, xfqXmlFlags, &(*ppxfcTail)->iXmlFlags); + ExitOnFailure(hr, "failed to get Wix4XmlConfig flags for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId); + + // Get the Element Id + hr = WcaGetRecordFormattedString(hRec, xfqElementId, &(*ppxfcTail)->pwzElementId); + ExitOnFailure(hr, "failed to get Element Id for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId); + + // Get the Element Path + hr = WcaGetRecordFormattedString(hRec, xfqElementPath, &(*ppxfcTail)->pwzElementPath); + ExitOnFailure(hr, "failed to get Element Path for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId); + + // Get the Verify Path + hr = WcaGetRecordFormattedString(hRec, xfqVerifyPath, &(*ppxfcTail)->pwzVerifyPath); + ExitOnFailure(hr, "failed to get Verify Path for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId); + + // Get the name + hr = WcaGetRecordFormattedString(hRec, xfqName, &pwzData); + ExitOnFailure(hr, "failed to get Name for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId); + hr = StringCchCopyW((*ppxfcTail)->wzName, countof((*ppxfcTail)->wzName), pwzData); + ExitOnFailure(hr, "failed to copy name of element"); + + // Get the value + hr = WcaGetRecordFormattedString(hRec, xfqValue, &pwzData); + ExitOnFailure(hr, "failed to get Value for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId); + hr = StrAllocString(&(*ppxfcTail)->pwzValue, pwzData, 0); + ExitOnFailure(hr, "failed to allocate buffer for value"); + + // Get the component attributes + hr = WcaGetRecordInteger(hRec, xfqCompAttributes, &(*ppxfcTail)->iCompAttributes); + ExitOnFailure(hr, "failed to get component attributes for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId); + } + + // if we looped through all records all is well + if (E_NOMOREITEMS == hr) + { + hr = S_OK; + } + ExitOnFailure(hr, "failed while looping through all objects to secure"); + +LExit: + ReleaseStr(pwzData); + + return hr; +} + +static HRESULT ProcessChanges( + __inout XML_CONFIG_CHANGE** ppxfcHead + ) +{ + Assert(ppxfcHead && *ppxfcHead); + HRESULT hr = S_OK; + + XML_CONFIG_CHANGE* pxfc = NULL; + XML_CONFIG_CHANGE* pxfcNext = NULL; + XML_CONFIG_CHANGE* pxfcCheck = NULL; + int cAdditionalChanges = 0; + XML_CONFIG_CHANGE* pxfcLast = NULL; + + // If there's only one item in the list, none of this matters + if (pxfc && !pxfc->pxfcNext) + { + ExitFunction(); + } + + // Loop through the list + pxfc = *ppxfcHead; + while (pxfc) + { + // Keep track of where our next spot will be since our current node may be moved + pxfcNext = pxfc->pxfcNext; + + // With each node, check to see if it's element path matches the Id of some other node in the list + pxfcCheck = *ppxfcHead; + while (pxfcCheck) + { + if (pxfc->pwzElementId) + { + if (0 == lstrcmpW(pxfc->pwzElementId, pxfcCheck->wzId) + && 0 == pxfc->iXmlFlags + && XMLCONFIG_CREATE & pxfcCheck->iXmlFlags + && XMLCONFIG_ELEMENT & pxfcCheck->iXmlFlags) + { + // We found a match. First, take it out of the current list + if (pxfc->pxfcPrev) + { + pxfc->pxfcPrev->pxfcNext = pxfc->pxfcNext; + } + else // it was the head. Update the head + { + *ppxfcHead = pxfc->pxfcNext; + } + + if (pxfc->pxfcNext) + { + pxfc->pxfcNext->pxfcPrev = pxfc->pxfcPrev; + } + + pxfc->pxfcNext = NULL; + pxfc->pxfcPrev = NULL; + + // Now, add this node to the end of the matched node's additional changes list + if (!pxfcCheck->pxfcAdditionalChanges) + { + pxfcCheck->pxfcAdditionalChanges = pxfc; + pxfcCheck->cAdditionalChanges = 1; + } + else + { + pxfcLast = pxfcCheck->pxfcAdditionalChanges; + cAdditionalChanges = 1; + while (pxfcLast->pxfcNext) + { + pxfcLast = pxfcLast->pxfcNext; + ++cAdditionalChanges; + } + pxfcLast->pxfcNext = pxfc; + pxfc->pxfcPrev = pxfcLast; + pxfcCheck->cAdditionalChanges = ++cAdditionalChanges; + } + } + else + { + hr = E_NOTFOUND; + ExitOnRootFailure(hr, "failed to find matching ElementId: %ls", pxfc->pwzElementId); + } + } + + pxfcCheck = pxfcCheck->pxfcNext; + } + + pxfc = pxfcNext; + } + +LExit: + + return hr; +} + + +static HRESULT BeginChangeFile( + __in LPCWSTR pwzFile, + __in int iCompAttributes, + __inout LPWSTR* ppwzCustomActionData + ) +{ + Assert(pwzFile && *pwzFile && ppwzCustomActionData); + + HRESULT hr = S_OK; + BOOL fIs64Bit = iCompAttributes & msidbComponentAttributes64bit; + + LPBYTE pbData = NULL; + SIZE_T cbData = 0; + + LPWSTR pwzRollbackCustomActionData = NULL; + + if (fIs64Bit) + { + hr = WcaWriteIntegerToCaData((int)xaOpenFilex64, ppwzCustomActionData); + ExitOnFailure(hr, "failed to write 64-bit file indicator to custom action data"); + } + else + { + hr = WcaWriteIntegerToCaData((int)xaOpenFile, ppwzCustomActionData); + ExitOnFailure(hr, "failed to write file indicator to custom action data"); + } + + hr = WcaWriteStringToCaData(pwzFile, ppwzCustomActionData); + ExitOnFailure(hr, "failed to write file to custom action data: %ls", pwzFile); + + // If the file already exits, then we have to put it back the way it was on failure + if (FileExistsEx(pwzFile, NULL)) + { + hr = FileRead(&pbData, &cbData, pwzFile); + ExitOnFailure(hr, "failed to read file: %ls", pwzFile); + + // Set up the rollback for this file + hr = WcaWriteIntegerToCaData((int)fIs64Bit, &pwzRollbackCustomActionData); + ExitOnFailure(hr, "failed to write component bitness to rollback custom action data"); + + hr = WcaWriteStringToCaData(pwzFile, &pwzRollbackCustomActionData); + ExitOnFailure(hr, "failed to write file name to rollback custom action data: %ls", pwzFile); + + hr = WcaWriteStreamToCaData(pbData, cbData, &pwzRollbackCustomActionData); + ExitOnFailure(hr, "failed to write file contents to rollback custom action data."); + + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecXmlConfigRollback"), pwzRollbackCustomActionData, COST_XMLFILE); + ExitOnFailure(hr, "failed to schedule ExecXmlConfigRollback for file: %ls", pwzFile); + + ReleaseStr(pwzRollbackCustomActionData); + } +LExit: + ReleaseMem(pbData); + + return hr; +} + + +static HRESULT WriteChangeData( + __in XML_CONFIG_CHANGE* pxfc, + __in eXmlAction action, + __inout LPWSTR* ppwzCustomActionData + ) +{ + Assert(pxfc && ppwzCustomActionData); + + HRESULT hr = S_OK; + XML_CONFIG_CHANGE* pxfcAdditionalChanges = NULL; + LPCWSTR wzElementPath = pxfc->pwzElementId ? pxfc->pwzElementId : pxfc->pwzElementPath; + + hr = WcaWriteStringToCaData(wzElementPath, ppwzCustomActionData); + ExitOnFailure(hr, "failed to write ElementPath to custom action data: %ls", wzElementPath); + + hr = WcaWriteStringToCaData(pxfc->pwzVerifyPath, ppwzCustomActionData); + ExitOnFailure(hr, "failed to write VerifyPath to custom action data: %ls", pxfc->pwzVerifyPath); + + hr = WcaWriteStringToCaData(pxfc->wzName, ppwzCustomActionData); + ExitOnFailure(hr, "failed to write Name to custom action data: %ls", pxfc->wzName); + + hr = WcaWriteStringToCaData(pxfc->pwzValue, ppwzCustomActionData); + ExitOnFailure(hr, "failed to write Value to custom action data: %ls", pxfc->pwzValue); + + if (pxfc->iXmlFlags & XMLCONFIG_CREATE && pxfc->iXmlFlags & XMLCONFIG_ELEMENT && xaCreateElement == action && pxfc->pxfcAdditionalChanges) + { + hr = WcaWriteIntegerToCaData(pxfc->cAdditionalChanges, ppwzCustomActionData); + ExitOnFailure(hr, "failed to write additional changes value to custom action data"); + + pxfcAdditionalChanges = pxfc->pxfcAdditionalChanges; + while (pxfcAdditionalChanges) + { + Assert((0 == lstrcmpW(pxfcAdditionalChanges->wzComponent, pxfc->wzComponent)) && 0 == pxfcAdditionalChanges->iXmlFlags && (0 == lstrcmpW(pxfcAdditionalChanges->wzFile, pxfc->wzFile))); + + hr = WcaWriteStringToCaData(pxfcAdditionalChanges->wzName, ppwzCustomActionData); + ExitOnFailure(hr, "failed to write Name to custom action data: %ls", pxfc->wzName); + + hr = WcaWriteStringToCaData(pxfcAdditionalChanges->pwzValue, ppwzCustomActionData); + ExitOnFailure(hr, "failed to write Value to custom action data: %ls", pxfc->pwzValue); + + pxfcAdditionalChanges = pxfcAdditionalChanges->pxfcNext; + } + } + else + { + hr = WcaWriteIntegerToCaData(0, ppwzCustomActionData); + ExitOnFailure(hr, "failed to write additional changes value to custom action data"); + } + +LExit: + return hr; +} + + +/****************************************************************** + SchedXmlConfig - entry point for XmlConfig Custom Action + +********************************************************************/ +extern "C" UINT __stdcall SchedXmlConfig( + __in MSIHANDLE hInstall + ) +{ +// AssertSz(FALSE, "debug SchedXmlConfig"); + + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + LPWSTR pwzCurrentFile = NULL; + BOOL fCurrentFileChanged = FALSE; + + PMSIHANDLE hView = NULL; + PMSIHANDLE hRec = NULL; + + XML_CONFIG_CHANGE* pxfcHead = NULL; + XML_CONFIG_CHANGE* pxfcTail = NULL; // TODO: do we need this any more? + XML_CONFIG_CHANGE* pxfc = NULL; + + eXmlAction xa = xaUnknown; + eXmlPreserveDate xd; + + LPWSTR pwzCustomActionData = NULL; + + DWORD cFiles = 0; + + // initialize + hr = WcaInitialize(hInstall, "SchedXmlConfig"); + ExitOnFailure(hr, "failed to initialize"); + + hr = ReadXmlConfigTable(&pxfcHead, &pxfcTail); + MessageExitOnFailure(hr, msierrXmlConfigFailedRead, "failed to read Wix4XmlConfig table"); + + hr = ProcessChanges(&pxfcHead); + ExitOnFailure(hr, "failed to process Wix4XmlConfig changes"); + + // loop through all the xml configurations + for (pxfc = pxfcHead; pxfc; pxfc = pxfc->pxfcNext) + { + // If this is a different file, or the first file... + if (NULL == pwzCurrentFile || 0 != lstrcmpW(pwzCurrentFile, pxfc->wzFile)) + { + // Remember the file we're currently working on + hr = StrAllocString(&pwzCurrentFile, pxfc->wzFile, 0); + ExitOnFailure(hr, "failed to copy file name"); + + fCurrentFileChanged = TRUE; + } + + // + // Figure out what action to take + // + xa = xaUnknown; + + // If it's being installed or reinstalled or uninstalled and that matches + // what we are doing then calculate the right action. + if ((XMLCONFIG_INSTALL & pxfc->iXmlFlags && (WcaIsInstalling(pxfc->isInstalled, pxfc->isAction) || WcaIsReInstalling(pxfc->isInstalled, pxfc->isAction))) || + (XMLCONFIG_UNINSTALL & pxfc->iXmlFlags && WcaIsUninstalling(pxfc->isInstalled, pxfc->isAction))) + { + if (XMLCONFIG_CREATE & pxfc->iXmlFlags && XMLCONFIG_ELEMENT & pxfc->iXmlFlags) + { + xa = xaCreateElement; + } + else if (XMLCONFIG_DELETE & pxfc->iXmlFlags && XMLCONFIG_ELEMENT & pxfc->iXmlFlags) + { + xa = xaDeleteElement; + } + else if (XMLCONFIG_DELETE & pxfc->iXmlFlags && XMLCONFIG_VALUE & pxfc->iXmlFlags) + { + xa = xaDeleteValue; + } + else if (XMLCONFIG_CREATE & pxfc->iXmlFlags && XMLCONFIG_VALUE & pxfc->iXmlFlags) + { + xa = xaWriteValue; + } + else if (XMLCONFIG_CREATE & pxfc->iXmlFlags && XMLCONFIG_DOCUMENT & pxfc->iXmlFlags) + { + xa = xaWriteDocument; + } + else if (XMLCONFIG_DELETE & pxfc->iXmlFlags && XMLCONFIG_DOCUMENT & pxfc->iXmlFlags) + { + hr = E_INVALIDARG; + ExitOnFailure(hr, "Invalid flag configuration. Cannot delete a fragment node."); + } + } + + if (XMLCONFIG_PRESERVE_MODIFIED & pxfc->iXmlFlags) + { + xd = xdPreserve; + } + else + { + xd= xdDontPreserve; + } + + if (xaUnknown != xa) + { + if (fCurrentFileChanged) + { + hr = BeginChangeFile(pwzCurrentFile, pxfc->iCompAttributes, &pwzCustomActionData); + ExitOnFailure(hr, "failed to begin file change for file: %ls", pwzCurrentFile); + + fCurrentFileChanged = FALSE; + ++cFiles; + } + + hr = WcaWriteIntegerToCaData((int)xa, &pwzCustomActionData); + ExitOnFailure(hr, "failed to write action indicator custom action data"); + + hr = WcaWriteIntegerToCaData((int)xd, &pwzCustomActionData); + ExitOnFailure(hr, "failed to write Preserve Date indicator to custom action data"); + + hr = WriteChangeData(pxfc, xa, &pwzCustomActionData); + ExitOnFailure(hr, "failed to write change data"); + } + } + + // If we looped through all records all is well + if (E_NOMOREITEMS == hr) + { + hr = S_OK; + } + ExitOnFailure(hr, "failed while looping through all objects to secure"); + + // Schedule the custom action and add to progress bar + if (pwzCustomActionData && *pwzCustomActionData) + { + Assert(0 < cFiles); + + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecXmlConfig"), pwzCustomActionData, cFiles * COST_XMLFILE); + ExitOnFailure(hr, "failed to schedule ExecXmlConfig action"); + } + +LExit: + ReleaseStr(pwzCurrentFile); + ReleaseStr(pwzCustomActionData); + + FreeXmlConfigChangeList(pxfcHead); + + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + return WcaFinalize(er); +} + + +/****************************************************************** + ExecXmlConfig - entry point for XmlConfig Custom Action + +*******************************************************************/ +extern "C" UINT __stdcall ExecXmlConfig( + __in MSIHANDLE hInstall + ) +{ + //AssertSz(FALSE, "debug ExecXmlConfig"); + HRESULT hr = S_OK; + HRESULT hrOpenFailure = S_OK; + UINT er = ERROR_SUCCESS; + +#ifndef _WIN64 + BOOL fIsFSRedirectDisabled = FALSE; +#endif + BOOL fPreserveDate = FALSE; + + LPWSTR pwzCustomActionData = NULL; + LPWSTR pwzData = NULL; + LPWSTR pwzFile = NULL; + LPWSTR pwzElementPath = NULL; + LPWSTR pwzVerifyPath = NULL; + LPWSTR pwzName = NULL; + LPWSTR pwzValue = NULL; + LPWSTR pwz = NULL; + int cAdditionalChanges = 0; + + IXMLDOMDocument* pixd = NULL; + IXMLDOMNode* pixn = NULL; + IXMLDOMNode* pixnVerify = NULL; + IXMLDOMNode* pixnNewNode = NULL; + IXMLDOMNode* pixnRemovedChild = NULL; + + IXMLDOMDocument* pixdNew = NULL; + IXMLDOMElement* pixeNew = NULL; + + FILETIME ft; + + int id = IDRETRY; + + eXmlAction xa; + eXmlPreserveDate xd; + + // initialize + hr = WcaInitialize(hInstall, "ExecXmlConfig"); + ExitOnFailure(hr, "failed to initialize"); + + hr = XmlInitialize(); + ExitOnFailure(hr, "failed to initialize xml utilities"); + + hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData); + ExitOnFailure(hr, "failed to get CustomActionData"); + + WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); + + pwz = pwzCustomActionData; + + hr = WcaReadIntegerFromCaData(&pwz, (int*) &xa); + ExitOnFailure(hr, "failed to process CustomActionData"); + +#ifndef _WIN64 + // Initialize the Wow64 API - store the result in fWow64APIPresent + // If it fails, this doesn't warrant an error yet, because we only need the Wow64 API in some cases + WcaInitializeWow64(); + BOOL fIsWow64Process = WcaIsWow64Process(); +#endif + + if (xaOpenFile != xa && xaOpenFilex64 != xa) + { + ExitOnFailure(hr = E_INVALIDARG, "invalid custom action data"); + } + + // loop through all the passed in data + while (pwz && *pwz) + { + hr = WcaReadStringFromCaData(&pwz, &pwzFile); + ExitOnFailure(hr, "failed to read file name from custom action data"); + + // Default to not preserve date, preserve it if any modifications require us to + fPreserveDate = FALSE; + + // Open the file + ReleaseNullObject(pixd); + +#ifndef _WIN64 + if (xaOpenFilex64 == xa) + { + if (!fIsWow64Process) + { + hr = E_NOTIMPL; + ExitOnFailure(hr, "Custom action was told to act on a 64-bit component, but the custom action process is not running in WOW."); + } + + hr = WcaDisableWow64FSRedirection(); + ExitOnFailure(hr, "Custom action was told to act on a 64-bit component, but was unable to disable filesystem redirection through the Wow64 API."); + + fIsFSRedirectDisabled = TRUE; + } +#endif + + hr = XmlLoadDocumentFromFileEx(pwzFile, XML_LOAD_PRESERVE_WHITESPACE, &pixd); + if (FAILED(hr)) + { + // 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. + hrOpenFailure = hr; + hr = S_OK; + } + else + { + hrOpenFailure = S_OK; + } + + WcaLog(LOGMSG_VERBOSE, "Configuring Xml File: %ls", pwzFile); + + while (pwz && *pwz) + { + // If we skip past an element that has additional changes we need to strip them off the stream before + // moving on to the next element. Do that now and then restart the outer loop. + if (cAdditionalChanges > 0) + { + while (cAdditionalChanges > 0) + { + hr = WcaReadStringFromCaData(&pwz, &pwzName); + ExitOnFailure(hr, "failed to process CustomActionData"); + hr = WcaReadStringFromCaData(&pwz, &pwzValue); + ExitOnFailure(hr, "failed to process CustomActionData"); + + cAdditionalChanges--; + } + continue; + } + + hr = WcaReadIntegerFromCaData(&pwz, (int*) &xa); + ExitOnFailure(hr, "failed to process CustomActionData"); + + // Break if we need to move on to a different file + if (xaOpenFile == xa || xaOpenFilex64 == xa) + { + break; + } + + hr = WcaReadIntegerFromCaData(&pwz, (int*) &xd); + ExitOnFailure(hr, "failed to process CustomActionData"); + + if (xdPreserve == xd) + { + fPreserveDate = TRUE; + } + + // Get path, name, and value to be written + hr = WcaReadStringFromCaData(&pwz, &pwzElementPath); + ExitOnFailure(hr, "failed to process CustomActionData"); + hr = WcaReadStringFromCaData(&pwz, &pwzVerifyPath); + ExitOnFailure(hr, "failed to process CustomActionData"); + hr = WcaReadStringFromCaData(&pwz, &pwzName); + ExitOnFailure(hr, "failed to process CustomActionData"); + hr = WcaReadStringFromCaData(&pwz, &pwzValue); + ExitOnFailure(hr, "failed to process CustomActionData"); + hr = WcaReadIntegerFromCaData(&pwz, &cAdditionalChanges); + ExitOnFailure(hr, "failed to process CustomActionData"); + + // 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. + if (FAILED(hrOpenFailure)) + { + if (xaCreateElement == xa || xaWriteValue == xa || xaWriteDocument == xa) + { + MessageExitOnFailure(hr = hrOpenFailure, msierrXmlConfigFailedOpen, "failed to load XML file: %ls", pwzFile); + } + else + { + continue; + } + } + + // Select the node we're about to modify + ReleaseNullObject(pixn); + + hr = XmlSelectSingleNode(pixd, pwzElementPath, &pixn); + + // 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. + if (S_FALSE == hr) + { + if (xaCreateElement == xa || xaWriteValue == xa || xaWriteDocument == xa) + { + hr = HRESULT_FROM_WIN32(ERROR_OBJECT_NOT_FOUND); + } + else + { + hr = S_OK; + continue; + } + } + + MessageExitOnFailure(hr, msierrXmlConfigFailedSelect, "failed to find node: %ls in XML file: %ls", pwzElementPath, pwzFile); + + // Make the modification + switch (xa) + { + case xaWriteValue: + if (pwzName && *pwzName) + { + // We're setting an attribute + hr = XmlSetAttribute(pixn, pwzName, pwzValue); + ExitOnFailure(hr, "failed to set attribute: %ls to value %ls", pwzName, pwzValue); + } + else + { + // We're setting the text of the node + hr = XmlSetText(pixn, pwzValue); + ExitOnFailure(hr, "failed to set text to: %ls for element %ls. Make sure that XPath points to an element.", pwzValue, pwzElementPath); + } + break; + case xaWriteDocument: + if (NULL != pwzVerifyPath && 0 != pwzVerifyPath[0]) + { + hr = XmlSelectSingleNode(pixn, pwzVerifyPath, &pixnVerify); + if (S_OK == hr) + { + // We found the verify path which means we have no further work to do + continue; + } + ExitOnFailure(hr, "failed to query verify path: %ls", pwzVerifyPath); + } + + hr = XmlLoadDocumentEx(pwzValue, XML_LOAD_PRESERVE_WHITESPACE, &pixdNew); + ExitOnFailure(hr, "Failed to load value as document."); + + hr = pixdNew->get_documentElement(&pixeNew); + ExitOnFailure(hr, "Failed to get document element."); + + hr = pixn->appendChild(pixeNew, NULL); + ExitOnFailure(hr, "Failed to append document element on to parent element."); + + ReleaseNullObject(pixeNew); + ReleaseNullObject(pixdNew); + break; + + case xaCreateElement: + if (NULL != pwzVerifyPath && 0 != pwzVerifyPath[0]) + { + hr = XmlSelectSingleNode(pixn, pwzVerifyPath, &pixnVerify); + if (S_OK == hr) + { + // We found the verify path which means we have no further work to do + continue; + } + ExitOnFailure(hr, "failed to query verify path: %ls", pwzVerifyPath); + } + + hr = XmlCreateChild(pixn, pwzName, &pixnNewNode); + ExitOnFailure(hr, "failed to create child element: %ls", pwzName); + + if (pwzValue && *pwzValue) + { + hr = XmlSetText(pixnNewNode, pwzValue); + ExitOnFailure(hr, "failed to set text to: %ls for node: %ls", pwzValue, pwzName); + } + + while (cAdditionalChanges > 0) + { + hr = WcaReadStringFromCaData(&pwz, &pwzName); + ExitOnFailure(hr, "failed to process CustomActionData"); + hr = WcaReadStringFromCaData(&pwz, &pwzValue); + ExitOnFailure(hr, "failed to process CustomActionData"); + + // Set the additional attribute + hr = XmlSetAttribute(pixnNewNode, pwzName, pwzValue); + ExitOnFailure(hr, "failed to set attribute: %ls to value %ls", pwzName, pwzValue); + + cAdditionalChanges--; + } + + ReleaseNullObject(pixnNewNode); + break; + case xaDeleteValue: + if (pwzName && *pwzName) + { + // Delete the attribute + hr = XmlRemoveAttribute(pixn, pwzName); + ExitOnFailure(hr, "failed to remove attribute: %ls", pwzName); + } + else + { + // Clear the text value for the node + hr = XmlSetText(pixn, L""); + ExitOnFailure(hr, "failed to clear text value"); + } + break; + case xaDeleteElement: + if (NULL != pwzVerifyPath && 0 != pwzVerifyPath[0]) + { + hr = XmlSelectSingleNode(pixn, pwzVerifyPath, &pixnVerify); + if (S_OK == hr) + { + hr = pixn->removeChild(pixnVerify, &pixnRemovedChild); + ExitOnFailure(hr, "failed to remove created child element"); + + ReleaseNullObject(pixnRemovedChild); + } + else + { + WcaLog(LOGMSG_VERBOSE, "Failed to select path %ls for deleting. Skipping...", pwzVerifyPath); + hr = S_OK; + } + } + else + { + // TODO: This requires a VerifyPath to delete an element. Should we support not having one? + WcaLog(LOGMSG_VERBOSE, "No VerifyPath specified for delete element of ID: %ls", pwzElementPath); + } + break; + default: + ExitOnFailure(hr = E_UNEXPECTED, "Invalid modification specified in custom action data"); + break; + } + } + + + // Now that we've made all of the changes to this file, save it and move on to the next + if (S_OK == hrOpenFailure) + { + if (fPreserveDate) + { + hr = FileGetTime(pwzFile, NULL, NULL, &ft); + ExitOnFailure(hr, "failed to get modified time of file : %ls", pwzFile); + } + + int iSaveAttempt = 0; + + do + { + hr = XmlSaveDocument(pixd, pwzFile); + if (FAILED(hr)) + { + id = WcaErrorMessage(msierrXmlConfigFailedSave, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 1, pwzFile); + switch (id) + { + case IDABORT: + ExitOnFailure(hr, "Failed to save changes to XML file: %ls", pwzFile); + case IDRETRY: + hr = S_FALSE; // hit me, baby, one more time + break; + case IDIGNORE: + hr = S_OK; // pretend everything is okay and bail + break; + case 0: // No UI case, MsiProcessMessage returns 0 + if (STIERR_SHARING_VIOLATION == hr) + { + // Only in case of sharing violation do we retry 30 times, once a second. + if (iSaveAttempt < 30) + { + hr = S_FALSE; + ++iSaveAttempt; + WcaLog(LOGMSG_VERBOSE, "Unable to save changes to XML file: %ls, retry attempt: %x", pwzFile, iSaveAttempt); + Sleep(1000); + } + else + { + ExitOnFailure(hr, "Failed to save changes to XML file: %ls", pwzFile); + } + } + break; + default: // Unknown error + ExitOnFailure(hr, "Failed to save changes to XML file: %ls", pwzFile); + } + } + } while (S_FALSE == hr); + + if (fPreserveDate) + { + hr = FileSetTime(pwzFile, NULL, NULL, &ft); + ExitOnFailure(hr, "failed to set modified time of file : %ls", pwzFile); + } + +#ifndef _WIN64 + if (fIsFSRedirectDisabled) + { + fIsFSRedirectDisabled = FALSE; + WcaRevertWow64FSRedirection(); + } +#endif + } + } + +LExit: +#ifndef _WIN64 + // Make sure we revert FS Redirection if necessary before exiting + if (fIsFSRedirectDisabled) + { + fIsFSRedirectDisabled = FALSE; + WcaRevertWow64FSRedirection(); + } + WcaFinalizeWow64(); +#endif + + ReleaseStr(pwzCustomActionData); + ReleaseStr(pwzData); + ReleaseStr(pwzFile); + ReleaseStr(pwzElementPath); + ReleaseStr(pwzVerifyPath); + ReleaseStr(pwzName); + ReleaseStr(pwzValue); + + ReleaseObject(pixeNew); + ReleaseObject(pixdNew); + + ReleaseObject(pixn); + ReleaseObject(pixd); + ReleaseObject(pixnNewNode); + ReleaseObject(pixnRemovedChild); + + XmlUninitialize(); + + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + return WcaFinalize(er); +} + + +/****************************************************************** + ExecXmlConfigRollback - entry point for XmlConfig rollback Custom Action + +*******************************************************************/ +extern "C" UINT __stdcall ExecXmlConfigRollback( + __in MSIHANDLE hInstall + ) +{ +// AssertSz(FALSE, "debug ExecXmlConfigRollback"); + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + int iIs64Bit; +#ifndef _WIN64 + BOOL fIs64Bit = FALSE; +#endif + + LPWSTR pwzCustomActionData = NULL; + LPWSTR pwz = NULL; + LPWSTR pwzFileName = NULL; + LPBYTE pbData = NULL; + DWORD_PTR cbData = 0; + + FILETIME ft; + + HANDLE hFile = INVALID_HANDLE_VALUE; + + // initialize + hr = WcaInitialize(hInstall, "ExecXmlConfigRollback"); + ExitOnFailure(hr, "failed to initialize"); + + + hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData); + ExitOnFailure(hr, "failed to get CustomActionData"); + + WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); + + pwz = pwzCustomActionData; + + hr = WcaReadIntegerFromCaData(&pwz, &iIs64Bit); + ExitOnFailure(hr, "failed to read component bitness from custom action data"); + + hr = WcaReadStringFromCaData(&pwz, &pwzFileName); + ExitOnFailure(hr, "failed to read file name from custom action data"); + + hr = WcaReadStreamFromCaData(&pwz, &pbData, &cbData); + ExitOnFailure(hr, "failed to read file contents from custom action data"); + +#ifndef _WIN64 + fIs64Bit = (BOOL)iIs64Bit; + + if (fIs64Bit) + { + hr = WcaInitializeWow64(); + if (S_FALSE == hr) + { + hr = TYPE_E_DLLFUNCTIONNOTFOUND; + } + ExitOnFailure(hr, "failed to initialize Wow64 API"); + + if (!WcaIsWow64Process()) + { + hr = E_NOTIMPL; + ExitOnFailure(hr, "Custom action was told to rollback a 64-bit component, but the Wow64 API is unavailable."); + } + + hr = WcaDisableWow64FSRedirection(); + ExitOnFailure(hr, "Custom action was told to rollback a 64-bit component, but was unable to Disable Filesystem Redirection through the Wow64 API."); + } +#endif + + hr = FileGetTime(pwzFileName, NULL, NULL, &ft); + ExitOnFailure(hr, "Failed to get modified date of file %ls.", pwzFileName); + + // Open the file + hFile = ::CreateFileW(pwzFileName, GENERIC_WRITE, NULL, NULL, TRUNCATE_EXISTING, NULL, NULL); + ExitOnInvalidHandleWithLastError(hFile, hr, "failed to open file: %ls", pwzFileName); + + // Write out the old data + hr = FileWriteHandle(hFile, pbData, cbData); + ExitOnFailure(hr, "failed to write to file: %ls", pwzFileName); + + ReleaseFile(hFile); + + hr = FileSetTime(pwzFileName, NULL, NULL, &ft); + ExitOnFailure(hr, "Failed to set modified date of file %ls.", pwzFileName); + +LExit: + ReleaseStr(pwzCustomActionData); + ReleaseStr(pwzFileName); + + ReleaseFile(hFile); + +#ifndef _WIN64 + if (fIs64Bit) + { + WcaRevertWow64FSRedirection(); + WcaFinalizeWow64(); + } +#endif + + ReleaseMem(pbData); + + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + return WcaFinalize(er); +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + +#define XMLFILE_CREATE_ELEMENT 0x00000001 +#define XMLFILE_DELETE_VALUE 0x00000002 +#define XMLFILE_BULKWRITE_VALUE 0x00000004 + +#define XMLFILE_DONT_UNINSTALL 0x00010000 +#define XMLFILE_PRESERVE_MODIFIED 0x00001000 +#define XMLFILE_USE_XPATH 0x00000100 + +extern BOOL vfMsxml30; + +enum eXmlAction +{ + xaOpenFile = 1, + xaOpenFilex64, + xaWriteValue, + xaDeleteValue, + xaCreateElement, + xaDeleteElement, + xaBulkWriteValue, +}; + +enum eXmlPreserveDate +{ + xdDontPreserve = 0, + xdPreserve +}; + +enum eXmlSelectionLanguage +{ + xsXSLPattern = 0, + xsXPath = 1, +}; + +LPCWSTR vcsXmlFileQuery = + L"SELECT `Wix4XmlFile`.`Wix4XmlFile`, `Wix4XmlFile`.`File`, `Wix4XmlFile`.`ElementPath`, `Wix4XmlFile`.`Name`, `Wix4XmlFile`.`Value`, " + L"`Wix4XmlFile`.`Flags`, `Wix4XmlFile`.`Component_`, `Component`.`Attributes` " + L"FROM `Wix4XmlFile`,`Component` WHERE `Wix4XmlFile`.`Component_`=`Component`.`Component` ORDER BY `File`, `Sequence`"; +enum eXmlFileQuery { xfqXmlFile = 1, xfqFile, xfqXPath, xfqName, xfqValue, xfqXmlFlags, xfqComponent, xfqCompAttributes }; + +struct XML_FILE_CHANGE +{ + WCHAR wzId[MAX_DARWIN_KEY]; + + INSTALLSTATE isInstalled; + INSTALLSTATE isAction; + + WCHAR wzFile[MAX_PATH]; + LPWSTR pwzElementPath; + WCHAR wzName[MAX_DARWIN_COLUMN]; + LPWSTR pwzValue; + + int iXmlFlags; + int iCompAttributes; + + XML_FILE_CHANGE* pxfcPrev; + XML_FILE_CHANGE* pxfcNext; +}; + +//static HRESULT FreeXmlFileChangeList( +// __in XML_FILE_CHANGE* pxfcList +// ) +//{ +// HRESULT hr = S_OK; +// +// XML_FILE_CHANGE* pxfcDelete; +// while(pxfcList) +// { +// pxfcDelete = pxfcList; +// pxfcList = pxfcList->pxfcNext; +// +// ReleaseStr(pxfcDelete->pwzElementPath); +// ReleaseStr(pxfcDelete->pwzValue); +// +// hr = MemFree(pxfcDelete); +// ExitOnFailure(hr, "failed to free xml file change list item"); +// } +// +//LExit: +// return hr; +//} + +static HRESULT AddXmlFileChangeToList( + __inout XML_FILE_CHANGE** ppxfcHead, + __inout XML_FILE_CHANGE** ppxfcTail + ) +{ + Assert(ppxfcHead && ppxfcTail); + + HRESULT hr = S_OK; + + XML_FILE_CHANGE* pxfc = static_cast(MemAlloc(sizeof(XML_FILE_CHANGE), TRUE)); + ExitOnNull(pxfc, hr, E_OUTOFMEMORY, "failed to allocate memory for new xml file change list element"); + + // Add it to the end of the list + if (NULL == *ppxfcHead) + { + *ppxfcHead = pxfc; + *ppxfcTail = pxfc; + } + else + { + Assert(*ppxfcTail && (*ppxfcTail)->pxfcNext == NULL); + (*ppxfcTail)->pxfcNext = pxfc; + pxfc->pxfcPrev = *ppxfcTail; + *ppxfcTail = pxfc; + } + +LExit: + return hr; +} + + +static HRESULT ReadXmlFileTable( + __inout XML_FILE_CHANGE** ppxfcHead, + __inout XML_FILE_CHANGE** ppxfcTail + ) +{ + Assert(ppxfcHead && ppxfcTail); + + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + PMSIHANDLE hView = NULL; + PMSIHANDLE hRec = NULL; + + LPWSTR pwzData = NULL; + + // check to see if necessary tables are specified + if (S_FALSE == WcaTableExists(L"Wix4XmlFile")) + { + ExitFunction1(hr = S_FALSE); + } + + // loop through all the xml configurations + hr = WcaOpenExecuteView(vcsXmlFileQuery, &hView); + ExitOnFailure(hr, "failed to open view on Wix4XmlFile table"); + + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + hr = AddXmlFileChangeToList(ppxfcHead, ppxfcTail); + ExitOnFailure(hr, "failed to add xml file change to list"); + + // Get record Id + hr = WcaGetRecordString(hRec, xfqXmlFile, &pwzData); + ExitOnFailure(hr, "failed to get Wix4XmlFile record Id"); + hr = StringCchCopyW((*ppxfcTail)->wzId, countof((*ppxfcTail)->wzId), pwzData); + ExitOnFailure(hr, "failed to copy Wix4XmlFile record Id"); + + // Get component name + hr = WcaGetRecordString(hRec, xfqComponent, &pwzData); + ExitOnFailure(hr, "failed to get component name for Wix4XmlFile: %ls", (*ppxfcTail)->wzId); + + // Get the component's state + er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &(*ppxfcTail)->isInstalled, &(*ppxfcTail)->isAction); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "failed to get install state for Component: %ls", pwzData); + + // Get the xml file + hr = WcaGetRecordFormattedString(hRec, xfqFile, &pwzData); + ExitOnFailure(hr, "failed to get xml file for Wix4XmlFile: %ls", (*ppxfcTail)->wzId); + hr = StringCchCopyW((*ppxfcTail)->wzFile, countof((*ppxfcTail)->wzFile), pwzData); + ExitOnFailure(hr, "failed to copy xml file path"); + + // Get the Wix4XmlFile table flags + hr = WcaGetRecordInteger(hRec, xfqXmlFlags, &(*ppxfcTail)->iXmlFlags); + ExitOnFailure(hr, "failed to get Wix4XmlFile flags for Wix4XmlFile: %ls", (*ppxfcTail)->wzId); + + // Get the XPath + hr = WcaGetRecordFormattedString(hRec, xfqXPath, &(*ppxfcTail)->pwzElementPath); + ExitOnFailure(hr, "failed to get XPath for Wix4XmlFile: %ls", (*ppxfcTail)->wzId); + + // Get the name + hr = WcaGetRecordFormattedString(hRec, xfqName, &pwzData); + ExitOnFailure(hr, "failed to get Name for Wix4XmlFile: %ls", (*ppxfcTail)->wzId); + hr = StringCchCopyW((*ppxfcTail)->wzName, countof((*ppxfcTail)->wzName), pwzData); + ExitOnFailure(hr, "failed to copy name of element"); + + // Get the value + hr = WcaGetRecordFormattedString(hRec, xfqValue, &pwzData); + ExitOnFailure(hr, "failed to get Value for Wix4XmlFile: %ls", (*ppxfcTail)->wzId); + hr = StrAllocString(&(*ppxfcTail)->pwzValue, pwzData, 0); + ExitOnFailure(hr, "failed to allocate buffer for value"); + + // Get the component attributes + hr = WcaGetRecordInteger(hRec, xfqCompAttributes, &(*ppxfcTail)->iCompAttributes); + ExitOnFailure(hr, "failed to get component attributes for Wix4XmlFile: %ls", (*ppxfcTail)->wzId); + } + + // if we looped through all records all is well + if (E_NOMOREITEMS == hr) + hr = S_OK; + ExitOnFailure(hr, "failed while looping through all objects to secure"); + +LExit: + ReleaseStr(pwzData); + + return hr; +} + + +static HRESULT BeginChangeFile( + __in LPCWSTR pwzFile, + __in XML_FILE_CHANGE* pxfc, + __inout LPWSTR* ppwzCustomActionData + ) +{ + Assert(pwzFile && *pwzFile && ppwzCustomActionData); + + HRESULT hr = S_OK; + BOOL fIs64Bit = pxfc->iCompAttributes & msidbComponentAttributes64bit; + BOOL fUseXPath = pxfc->iXmlFlags & XMLFILE_USE_XPATH; + LPBYTE pbData = NULL; + SIZE_T cbData = 0; + + LPWSTR pwzRollbackCustomActionData = NULL; + + if (fIs64Bit) + { + hr = WcaWriteIntegerToCaData((int)xaOpenFilex64, ppwzCustomActionData); + ExitOnFailure(hr, "failed to write 64-bit file indicator to custom action data"); + } + else + { + hr = WcaWriteIntegerToCaData((int)xaOpenFile, ppwzCustomActionData); + ExitOnFailure(hr, "failed to write file indicator to custom action data"); + } + if (fUseXPath) + { + hr = WcaWriteIntegerToCaData((int)xsXPath, ppwzCustomActionData); + ExitOnFailure(hr, "failed to write XPath selectionlanguage indicator to custom action data"); + } + else + { + hr = WcaWriteIntegerToCaData((int)xsXSLPattern, ppwzCustomActionData); + ExitOnFailure(hr, "failed to write XSLPattern selectionlanguage indicator to custom action data"); + } + hr = WcaWriteStringToCaData(pwzFile, ppwzCustomActionData); + ExitOnFailure(hr, "failed to write file to custom action data: %ls", pwzFile); + + // If the file already exits, then we have to put it back the way it was on failure + if (FileExistsEx(pwzFile, NULL)) + { + hr = FileRead(&pbData, &cbData, pwzFile); + ExitOnFailure(hr, "failed to read file: %ls", pwzFile); + + // Set up the rollback for this file + hr = WcaWriteIntegerToCaData((int)fIs64Bit, &pwzRollbackCustomActionData); + ExitOnFailure(hr, "failed to write component bitness to rollback custom action data"); + + hr = WcaWriteStringToCaData(pwzFile, &pwzRollbackCustomActionData); + ExitOnFailure(hr, "failed to write file name to rollback custom action data: %ls", pwzFile); + + hr = WcaWriteStreamToCaData(pbData, cbData, &pwzRollbackCustomActionData); + ExitOnFailure(hr, "failed to write file contents to rollback custom action data."); + + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecXmlFileRollback"), pwzRollbackCustomActionData, COST_XMLFILE); + ExitOnFailure(hr, "failed to schedule ExecXmlFileRollback for file: %ls", pwzFile); + + ReleaseStr(pwzRollbackCustomActionData); + } +LExit: + ReleaseMem(pbData); + + return hr; +} + + +static HRESULT WriteChangeData( + __in XML_FILE_CHANGE* pxfc, + __inout LPWSTR* ppwzCustomActionData + ) +{ + Assert(pxfc && ppwzCustomActionData); + + HRESULT hr = S_OK; + + hr = WcaWriteStringToCaData(pxfc->pwzElementPath, ppwzCustomActionData); + ExitOnFailure(hr, "failed to write ElementPath to custom action data: %ls", pxfc->pwzElementPath); + + hr = WcaWriteStringToCaData(pxfc->wzName, ppwzCustomActionData); + ExitOnFailure(hr, "failed to write Name to custom action data: %ls", pxfc->wzName); + + hr = WcaWriteStringToCaData(pxfc->pwzValue, ppwzCustomActionData); + ExitOnFailure(hr, "failed to write Value to custom action data: %ls", pxfc->pwzValue); + +LExit: + return hr; +} + + +/****************************************************************** + SchedXmlFile - entry point for XmlFile Custom Action + +********************************************************************/ +extern "C" UINT __stdcall SchedXmlFile( + __in MSIHANDLE hInstall + ) +{ +// AssertSz(FALSE, "debug SchedXmlFile"); + + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + LPWSTR pwzCurrentFile = NULL; + BOOL fCurrentFileChanged = FALSE; + BOOL fCurrentUseXPath = FALSE; + + PMSIHANDLE hView = NULL; + PMSIHANDLE hRec = NULL; + + XML_FILE_CHANGE* pxfcHead = NULL; + XML_FILE_CHANGE* pxfcTail = NULL; + XML_FILE_CHANGE* pxfc = NULL; + XML_FILE_CHANGE* pxfcUninstall = NULL; + + LPWSTR pwzCustomActionData = NULL; + + DWORD cFiles = 0; + + // initialize + hr = WcaInitialize(hInstall, "SchedXmlFile"); + ExitOnFailure(hr, "failed to initialize"); + + hr = ReadXmlFileTable(&pxfcHead, &pxfcTail); + if (S_FALSE == hr) + { + WcaLog(LOGMSG_VERBOSE, "Skipping SchedXmlFile because Wix4XmlFile table not present"); + ExitFunction1(hr = S_OK); + } + + MessageExitOnFailure(hr, msierrXmlFileFailedRead, "failed to read Wix4XmlFile table"); + + // loop through all the xml configurations + for (pxfc = pxfcHead; pxfc; pxfc = pxfc->pxfcNext) + { + // If this is the first file, a different file, the last file, or the SelectionLanguage property changes... + if (NULL == pwzCurrentFile || 0 != lstrcmpW(pwzCurrentFile, pxfc->wzFile) || NULL == pxfc->pxfcNext || fCurrentUseXPath != ((XMLFILE_USE_XPATH & pxfc->iXmlFlags))) + { + // If this isn't the first file + if (NULL != pwzCurrentFile) + { + // Do the uninstall work for the current file by walking backwards through the list (so the sequence is reversed) + for (pxfcUninstall = ((NULL != pxfc->pxfcNext) ? pxfc->pxfcPrev : pxfc); pxfcUninstall && 0 == lstrcmpW(pwzCurrentFile, pxfcUninstall->wzFile) && fCurrentUseXPath == ((XMLFILE_USE_XPATH & pxfcUninstall->iXmlFlags)); pxfcUninstall = pxfcUninstall->pxfcPrev) + { + // If it's being uninstalled + if (WcaIsUninstalling(pxfcUninstall->isInstalled, pxfcUninstall->isAction)) + { + // Uninstall the change + if (!(XMLFILE_DONT_UNINSTALL & pxfcUninstall->iXmlFlags)) + { + if (!fCurrentFileChanged) + { + hr = BeginChangeFile(pwzCurrentFile, pxfcUninstall, &pwzCustomActionData); + ExitOnFailure(hr, "failed to begin file change for file: %ls", pwzCurrentFile); + + fCurrentFileChanged = TRUE; + ++cFiles; + } + if (XMLFILE_CREATE_ELEMENT & pxfcUninstall->iXmlFlags) + { + hr = WcaWriteIntegerToCaData((int)xaDeleteElement, &pwzCustomActionData); + ExitOnFailure(hr, "failed to write delete element action indicator to custom action data"); + } + else + { + hr = WcaWriteIntegerToCaData((int)xaDeleteValue, &pwzCustomActionData); + ExitOnFailure(hr, "failed to write delete value action indicator to custom action data"); + } + + if (XMLFILE_PRESERVE_MODIFIED & pxfc->iXmlFlags) + { + hr = WcaWriteIntegerToCaData((int)xdPreserve, &pwzCustomActionData); + ExitOnFailure(hr, "failed to write Preserve Date indicator to custom action data"); + } + else + { + hr = WcaWriteIntegerToCaData((int)xdDontPreserve, &pwzCustomActionData); + ExitOnFailure(hr, "failed to write Don't Preserve Date indicator to custom action data"); + } + + hr = WriteChangeData(pxfcUninstall, &pwzCustomActionData); + ExitOnFailure(hr, "failed to write uninstall change data"); + } + } + } + } + + // Remember the file we're currently working on + hr = StrAllocString(&pwzCurrentFile, pxfc->wzFile, 0); + ExitOnFailure(hr, "failed to copy file name"); + fCurrentUseXPath = (XMLFILE_USE_XPATH & pxfc->iXmlFlags); + + // We haven't changed the current file yet + fCurrentFileChanged = FALSE; + } + + // If it's being installed + if (WcaIsInstalling(pxfc->isInstalled, pxfc->isAction)) + { + if (!fCurrentFileChanged) + { + hr = BeginChangeFile(pwzCurrentFile, pxfc, &pwzCustomActionData); + ExitOnFailure(hr, "failed to begin file change for file: %ls", pwzCurrentFile); + fCurrentFileChanged = TRUE; + ++cFiles; + } + + // Install the change + if (XMLFILE_CREATE_ELEMENT & pxfc->iXmlFlags) + { + hr = WcaWriteIntegerToCaData((int)xaCreateElement, &pwzCustomActionData); + ExitOnFailure(hr, "failed to write create element action indicator to custom action data"); + } + else if (XMLFILE_DELETE_VALUE & pxfc->iXmlFlags) + { + hr = WcaWriteIntegerToCaData((int)xaDeleteValue, &pwzCustomActionData); + ExitOnFailure(hr, "failed to write delete value action indicator to custom action data"); + } + else if (XMLFILE_BULKWRITE_VALUE & pxfc->iXmlFlags) + { + hr = WcaWriteIntegerToCaData((int)xaBulkWriteValue, &pwzCustomActionData); + ExitOnFailure(hr, "failed to write builkwrite value action indicator to custom action data"); + } + else + { + hr = WcaWriteIntegerToCaData((int)xaWriteValue, &pwzCustomActionData); + ExitOnFailure(hr, "failed to write file indicator to custom action data"); + } + + if (XMLFILE_PRESERVE_MODIFIED & pxfc->iXmlFlags) + { + hr = WcaWriteIntegerToCaData((int)xdPreserve, &pwzCustomActionData); + ExitOnFailure(hr, "failed to write Preserve Date indicator to custom action data"); + } + else + { + hr = WcaWriteIntegerToCaData((int)xdDontPreserve, &pwzCustomActionData); + ExitOnFailure(hr, "failed to write Don't Preserve Date indicator to custom action data"); + } + + hr = WriteChangeData(pxfc, &pwzCustomActionData); + ExitOnFailure(hr, "failed to write change data"); + } + } + + // If we looped through all records all is well + if (E_NOMOREITEMS == hr) + hr = S_OK; + ExitOnFailure(hr, "failed while looping through all objects to secure"); + + // Schedule the custom action and add to progress bar + if (pwzCustomActionData && *pwzCustomActionData) + { + Assert(0 < cFiles); + + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecXmlFile"), pwzCustomActionData, cFiles * COST_XMLFILE); + ExitOnFailure(hr, "failed to schedule ExecXmlFile action"); + } + +LExit: + ReleaseStr(pwzCurrentFile); + ReleaseStr(pwzCustomActionData); + + return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILURE : er); +} + + +/****************************************************************** + ExecXmlFile - entry point for XmlFile Custom Action + +*******************************************************************/ +extern "C" UINT __stdcall ExecXmlFile( + __in MSIHANDLE hInstall + ) +{ +// AssertSz(FALSE, "debug ExecXmlFile"); + HRESULT hr = S_OK; + HRESULT hrOpenFailure = S_OK; + UINT er = ERROR_SUCCESS; + + BOOL fIsFSRedirectDisabled = FALSE; + BOOL fPreserveDate = FALSE; + + int id = IDRETRY; + + LPWSTR pwzCustomActionData = NULL; + LPWSTR pwzData = NULL; + LPWSTR pwzFile = NULL; + LPWSTR pwzXPath = NULL; + LPWSTR pwzName = NULL; + LPWSTR pwzValue = NULL; + LPWSTR pwz = NULL; + + IXMLDOMDocument* pixd = NULL; + IXMLDOMNode* pixn = NULL; + IXMLDOMNode* pixnNewNode = NULL; + IXMLDOMNodeList* pixNodes = NULL; + IXMLDOMDocument2 *pixdDocument2 = NULL; + + FILETIME ft; + + BSTR bstrProperty = ::SysAllocString(L"SelectionLanguage"); + ExitOnNull(bstrProperty, hr, E_OUTOFMEMORY, "failed SysAllocString"); + VARIANT varValue; + ::VariantInit(&varValue); + varValue.vt = VT_BSTR; + varValue.bstrVal = ::SysAllocString(L"XPath"); + ExitOnNull(varValue.bstrVal, hr, E_OUTOFMEMORY, "failed SysAllocString"); + eXmlAction xa; + eXmlPreserveDate xd; + eXmlSelectionLanguage xl; + + // initialize + hr = WcaInitialize(hInstall, "ExecXmlFile"); + ExitOnFailure(hr, "failed to initialize"); + + hr = XmlInitialize(); + ExitOnFailure(hr, "failed to initialize xml utilities"); + + hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData); + ExitOnFailure(hr, "failed to get CustomActionData"); + + WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); + + pwz = pwzCustomActionData; + + hr = WcaReadIntegerFromCaData(&pwz, (int*) &xa); + ExitOnFailure(hr, "failed to process CustomActionData"); + +#ifndef _WIN64 + // Initialize the Wow64 API - store the result in fWow64APIPresent + // If it fails, this doesn't warrant an error yet, because we only need the Wow64 API in some cases + WcaInitializeWow64(); + BOOL fIsWow64Process = WcaIsWow64Process(); +#endif + + if (xaOpenFile != xa && xaOpenFilex64 != xa) + ExitOnFailure(hr = E_INVALIDARG, "invalid custom action data"); + + // loop through all the passed in data + while (pwz && *pwz) + { + hr = WcaReadIntegerFromCaData(&pwz, (int*) &xl); + ExitOnFailure(hr, "failed to process CustomActionData"); + + hr = WcaReadStringFromCaData(&pwz, &pwzFile); + ExitOnFailure(hr, "failed to read file name from custom action data"); + + // Default to not preserve the modified date + fPreserveDate = FALSE; + + // Open the file + ReleaseNullObject(pixd); + + if (xaOpenFilex64 == xa) + { +#ifndef _WIN64 + if (!fIsWow64Process) + { + hr = E_NOTIMPL; + ExitOnFailure(hr, "Custom action was told to act on a 64-bit component, but the custom action process is not running in WOW."); + } + + hr = WcaDisableWow64FSRedirection(); + ExitOnFailure(hr, "Custom action was told to act on a 64-bit component, but was unable to disable filesystem redirection through the Wow64 API."); + + fIsFSRedirectDisabled = TRUE; +#endif + } + + hr = XmlLoadDocumentFromFileEx(pwzFile, XML_LOAD_PRESERVE_WHITESPACE, &pixd); + if (FAILED(hr)) + { + // 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. + hrOpenFailure = hr; + hr = S_OK; + } + else + { + hrOpenFailure = S_OK; + } + WcaLog(LOGMSG_VERBOSE, "Configuring Xml File: %ls", pwzFile); + + if (xsXPath == xl) + { + if (vfMsxml30) + { + // If we failed to open the file, don't fail immediately; just skip setting the selection language, and we'll fail later if appropriate + if (SUCCEEDED(hrOpenFailure)) + { + hr = pixd->QueryInterface(XmlUtil_IID_IXMLDOMDocument2, (void**)&pixdDocument2); + ExitOnFailure(hr, "failed in querying IXMLDOMDocument2 interface"); + hr = pixdDocument2->setProperty(bstrProperty, varValue); + ExitOnFailure(hr, "failed in setting SelectionLanguage"); + } + } + else + { + ExitOnFailure(hr = E_NOTIMPL, "Error: current MSXML version does not support xpath query."); + } + } + + while (pwz && *pwz) + { + hr = WcaReadIntegerFromCaData(&pwz, (int*) &xa); + ExitOnFailure(hr, "failed to process CustomActionData"); + + // Break if we need to move on to a different file + if (xaOpenFile == xa || xaOpenFilex64 == xa) + break; + + hr = WcaReadIntegerFromCaData(&pwz, (int*) &xd); + ExitOnFailure(hr, "failed to process CustomActionData"); + + if (xdPreserve == xd) + { + fPreserveDate = TRUE; + } + + // Get path, name, and value to be written + hr = WcaReadStringFromCaData(&pwz, &pwzXPath); + ExitOnFailure(hr, "failed to process CustomActionData"); + hr = WcaReadStringFromCaData(&pwz, &pwzName); + ExitOnFailure(hr, "failed to process CustomActionData"); + hr = WcaReadStringFromCaData(&pwz, &pwzValue); + ExitOnFailure(hr, "failed to process CustomActionData"); + + // 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. + if (FAILED(hrOpenFailure)) + { + if (xaCreateElement == xa || xaWriteValue == xa || xaBulkWriteValue == xa) + { + MessageExitOnFailure(hr = hrOpenFailure, msierrXmlFileFailedOpen, "failed to load XML file: %ls", pwzFile); + } + else + { + continue; + } + } + + // Select the node we're about to modify + ReleaseNullObject(pixn); + + if (xaBulkWriteValue == xa) + { + hr = XmlSelectNodes(pixd, pwzXPath, &pixNodes); + if (S_FALSE == hr) + { + hr = HRESULT_FROM_WIN32(ERROR_OBJECT_NOT_FOUND); + } + + MessageExitOnFailure(hr, msierrXmlFileFailedSelect, "failed to find any nodes: %ls in XML file: %ls", pwzXPath, pwzFile); + for (;;) + { + pixNodes->nextNode(&pixn); + if (NULL == pixn) + break; + + if (pwzName && *pwzName) + { + // We're setting an attribute + hr = XmlSetAttribute(pixn, pwzName, pwzValue); + ExitOnFailure(hr, "failed to set attribute: %ls to value %ls", pwzName, pwzValue); + } + else + { + // We're setting the text of the node + hr = XmlSetText(pixn, pwzValue); + ExitOnFailure(hr, "failed to set text to: %ls for element %ls. Make sure that XPath points to an element.", pwzValue, pwzXPath); + } + ReleaseNullObject(pixn); + } + } + else + { + hr = XmlSelectSingleNode(pixd, pwzXPath, &pixn); + if (S_FALSE == hr) + hr = HRESULT_FROM_WIN32(ERROR_OBJECT_NOT_FOUND); + MessageExitOnFailure(hr, msierrXmlFileFailedSelect, "failed to find node: %ls in XML file: %ls", pwzXPath, pwzFile); + + // Make the modification + if (xaWriteValue == xa) + { + if (pwzName && *pwzName) + { + // We're setting an attribute + hr = XmlSetAttribute(pixn, pwzName, pwzValue); + ExitOnFailure(hr, "failed to set attribute: %ls to value %ls", pwzName, pwzValue); + } + else + { + // We're setting the text of the node + hr = XmlSetText(pixn, pwzValue); + ExitOnFailure(hr, "failed to set text to: %ls for element %ls. Make sure that XPath points to an element.", pwzValue, pwzXPath); + } + } + else if (xaCreateElement == xa) + { + hr = XmlCreateChild(pixn, pwzName, &pixnNewNode); + ExitOnFailure(hr, "failed to create child element: %ls", pwzName); + + if (pwzValue && *pwzValue) + { + hr = XmlSetText(pixnNewNode, pwzValue); + ExitOnFailure(hr, "failed to set text to: %ls for node: %ls", pwzValue, pwzName); + } + + ReleaseNullObject(pixnNewNode); + } + else if (xaDeleteValue == xa) + { + if (pwzName && *pwzName) + { + // Delete the attribute + hr = XmlRemoveAttribute(pixn, pwzName); + ExitOnFailure(hr, "failed to remove attribute: %ls", pwzName); + } + else + { + // Clear the text value for the node + hr = XmlSetText(pixn, L""); + ExitOnFailure(hr, "failed to clear text value"); + } + } + else if (xaDeleteElement == xa) + { + // TODO: This may be a little heavy handed + hr = XmlRemoveChildren(pixn, pwzName); + ExitOnFailure(hr, "failed to delete child node: %ls", pwzName); + } + else + { + ExitOnFailure(hr = E_UNEXPECTED, "Invalid modification specified in custom action data"); + } + } + } + + // Now that we've made all of the changes to this file, save it and move on to the next + if (S_OK == hrOpenFailure) + { + if (fPreserveDate) + { + hr = FileGetTime(pwzFile, NULL, NULL, &ft); + ExitOnFailure(hr, "failed to get modified time of file : %ls", pwzFile); + } + + int iSaveAttempt = 0; + + do + { + hr = XmlSaveDocument(pixd, pwzFile); + if (FAILED(hr)) + { + id = WcaErrorMessage(msierrXmlConfigFailedSave, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 1, pwzFile); + switch (id) + { + case IDABORT: + ExitOnFailure(hr, "Failed to save changes to XML file: %ls", pwzFile); + case IDRETRY: + hr = S_FALSE; // hit me, baby, one more time + break; + case IDIGNORE: + hr = S_OK; // pretend everything is okay and bail + break; + case 0: // No UI case, MsiProcessMessage returns 0 + if (STIERR_SHARING_VIOLATION == hr) + { + // Only in case of sharing violation do we retry 30 times, once a second. + if (iSaveAttempt < 30) + { + hr = S_FALSE; + ++iSaveAttempt; + WcaLog(LOGMSG_VERBOSE, "Unable to save changes to XML file: %ls, retry attempt: %x", pwzFile, iSaveAttempt); + Sleep(1000); + } + else + { + ExitOnFailure(hr, "Failed to save changes to XML file: %ls", pwzFile); + } + } + break; + default: // Unknown error + ExitOnFailure(hr, "Failed to save changes to XML file: %ls", pwzFile); + } + } + } while (S_FALSE == hr); + + if (fPreserveDate) + { + hr = FileSetTime(pwzFile, NULL, NULL, &ft); + ExitOnFailure(hr, "failed to set modified time of file : %ls", pwzFile); + } + + if (fIsFSRedirectDisabled) + { + fIsFSRedirectDisabled = FALSE; + WcaRevertWow64FSRedirection(); + } + } + } + +LExit: + // Make sure we revert FS Redirection if necessary before exiting + if (fIsFSRedirectDisabled) + { + fIsFSRedirectDisabled = FALSE; + WcaRevertWow64FSRedirection(); + } +#ifndef _WIN64 + WcaFinalizeWow64(); +#endif + + ReleaseStr(pwzCustomActionData); + ReleaseStr(pwzData); + ReleaseStr(pwzFile); + ReleaseStr(pwzXPath); + ReleaseStr(pwzName); + ReleaseStr(pwzValue); + ReleaseBSTR(bstrProperty); + ReleaseVariant(varValue); + + ReleaseObject(pixdDocument2); + ReleaseObject(pixn); + ReleaseObject(pixd); + ReleaseObject(pixnNewNode); + ReleaseObject(pixNodes); + + XmlUninitialize(); + + return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILURE : er); +} + + +/****************************************************************** + ExecXmlFileRollback - entry point for XmlFile rollback Custom Action + +*******************************************************************/ +extern "C" UINT __stdcall ExecXmlFileRollback( + __in MSIHANDLE hInstall + ) +{ +// AssertSz(FALSE, "debug ExecXmlFileRollback"); + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + int iIs64Bit; + BOOL fIs64Bit = FALSE; + + LPWSTR pwzCustomActionData = NULL; + LPWSTR pwz = NULL; + LPWSTR pwzFileName = NULL; + LPBYTE pbData = NULL; + DWORD_PTR cbData = 0; + + FILETIME ft; + + HANDLE hFile = INVALID_HANDLE_VALUE; + + // initialize + hr = WcaInitialize(hInstall, "ExecXmlFileRollback"); + ExitOnFailure(hr, "failed to initialize"); + + + hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData); + ExitOnFailure(hr, "failed to get CustomActionData"); + + WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); + + pwz = pwzCustomActionData; + + hr = WcaReadIntegerFromCaData(&pwz, &iIs64Bit); + ExitOnFailure(hr, "failed to read component bitness from custom action data"); + + hr = WcaReadStringFromCaData(&pwz, &pwzFileName); + ExitOnFailure(hr, "failed to read file name from custom action data"); + + hr = WcaReadStreamFromCaData(&pwz, &pbData, &cbData); + ExitOnFailure(hr, "failed to read file contents from custom action data"); + +#ifndef _WIN64 + fIs64Bit = (BOOL)iIs64Bit; + + if (fIs64Bit) + { + hr = WcaInitializeWow64(); + if (S_FALSE == hr) + { + hr = TYPE_E_DLLFUNCTIONNOTFOUND; + } + ExitOnFailure(hr, "failed to initialize Wow64 API"); + + if (!WcaIsWow64Process()) + { + hr = E_NOTIMPL; + ExitOnFailure(hr, "Custom action was told to rollback a 64-bit component, but the custom action process is not running in WOW."); + } + + hr = WcaDisableWow64FSRedirection(); + ExitOnFailure(hr, "Custom action was told to rollback a 64-bit component, but was unable to Disable Filesystem Redirection through the Wow64 API."); + } +#endif + + // Always preserve the modified date on rollback + hr = FileGetTime(pwzFileName, NULL, NULL, &ft); + ExitOnFailure(hr, "Failed to get modified date of file %ls.", pwzFileName); + + // Open the file + hFile = ::CreateFileW(pwzFileName, GENERIC_WRITE, NULL, NULL, TRUNCATE_EXISTING, NULL, NULL); + ExitOnInvalidHandleWithLastError(hFile, hr, "failed to open file: %ls", pwzFileName); + + // Write out the old data + hr = FileWriteHandle(hFile, pbData, cbData); + ExitOnFailure(hr, "failed to write to file: %ls", pwzFileName); + + ReleaseFile(hFile); + + // Always preserve the modified date on rollback + hr = FileSetTime(pwzFileName, NULL, NULL, &ft); + ExitOnFailure(hr, "Failed to set modified date of file %ls.", pwzFileName); + +LExit: + ReleaseStr(pwzCustomActionData); + ReleaseStr(pwzFileName); + + ReleaseFile(hFile); + + if (fIs64Bit) + { + WcaRevertWow64FSRedirection(); + WcaFinalizeWow64(); + } + + ReleaseMem(pbData); + + return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILURE : er); +} + 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 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +#if defined(_M_ARM64) +#define CUSTOM_ACTION_DECORATION(f) L"Wix4" f L"_A64" +#elif defined(_M_AMD64) +#define CUSTOM_ACTION_DECORATION(f) L"Wix4" f L"_X64" +#elif defined(_M_ARM) +#define CUSTOM_ACTION_DECORATION(f) L"Wix4" f L"_ARM" +#else +#define CUSTOM_ACTION_DECORATION(f) L"Wix4" f L"_X86" +#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 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +const UINT COST_SECUREOBJECT = 1000; +const UINT COST_SERVICECONFIG = 1000; +const UINT COST_XMLFILE = 1000; +const UINT COST_CLOSEAPP = 500; +const 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + +/******************************************************************** +DllMain - standard entry point for all WiX custom actions + +********************************************************************/ +extern "C" BOOL WINAPI DllMain( + IN HINSTANCE hInst, + IN ULONG ulReason, + IN LPVOID) +{ + switch(ulReason) + { + case DLL_PROCESS_ATTACH: + WcaGlobalInitialize(hInst); + break; + + case DLL_PROCESS_DETACH: + WcaGlobalFinalize(); + break; + } + + return TRUE; +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +/****************************************************************** +WixExitEarlyWithSuccess - entry point for WixExitEarlyWithSuccess + custom action which does nothing except return exit code + ERROR_NO_MORE_ITEMS. The Windows Installer documentation at + http://msdn.microsoft.com/library/aa368072.aspx indicates that + this exit code is not treated as an error. This will cause a + calling application to receive a successful return code if + this custom action executes. This can be useful for backwards + compatibility when an application redistributes an MSI and + a future major upgrade is released for that MSI. It should be + conditioned on a property set by an entry in the Upgrade table + of the MSI that detects newer major upgrades of the same MSI + already installed on the system. It should be scheduled after + the FindRelatedProducts action so that the property will be + set if appropriate. +********************************************************************/ +extern "C" UINT __stdcall WixExitEarlyWithSuccess( + __in MSIHANDLE /*hInstall*/ + ) +{ + return ERROR_NO_MORE_ITEMS; +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + +LPCWSTR vcsShortcutsQuery = + L"SELECT `Component_`, `Directory_`, `Name`, `Target`, `Attributes`, `IconFile`, `IconIndex` " + L"FROM `Wix4InternetShortcut`"; +enum eShortcutsQuery { esqComponent = 1, esqDirectory, esqFilename, esqTarget, esqAttributes, esqIconFile, esqIconIndex }; +enum eShortcutsAttributes { esaLink = 0, esaURL = 1 }; + +/****************************************************************** + WixSchedInternetShortcuts - entry point + +********************************************************************/ +extern "C" UINT __stdcall WixSchedInternetShortcuts( + __in MSIHANDLE hInstall + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + UINT uiCost = 0; + + PMSIHANDLE hView = NULL; + PMSIHANDLE hRec = NULL; + + MSIHANDLE hCreateFolderTable = NULL; + MSIHANDLE hCreateFolderColumns = NULL; + + LPWSTR pwzCustomActionData = NULL; + LPWSTR pwzComponent = NULL; + LPWSTR pwzDirectory = NULL; + LPWSTR pwzFilename = NULL; + LPWSTR pwzTarget = NULL; + LPWSTR pwzShortcutPath = NULL; + int iAttr = 0; + LPWSTR pwzIconFile = NULL; + int iIconIndex = 0; + IUniformResourceLocatorW* piURL = NULL; + IShellLinkW* piShellLink = NULL; + BOOL fInitializedCom = FALSE; + + hr = WcaInitialize(hInstall, "WixSchedInternetShortcuts"); + ExitOnFailure(hr, "failed to initialize WixSchedInternetShortcuts."); + + // anything to do? + if (S_OK != WcaTableExists(L"Wix4InternetShortcut")) + { + WcaLog(LOGMSG_STANDARD, "Wix4InternetShortcut table doesn't exist, so there are no Internet shortcuts to process"); + goto LExit; + } + + // check to see if we can create a shortcut - Server Core and others may not have a shell registered. + hr = ::CoInitialize(NULL); + ExitOnFailure(hr, "failed to initialize COM"); + fInitializedCom = TRUE; + + hr = ::CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_ALL, IID_IUniformResourceLocatorW, (void**)&piURL); + if (S_OK != hr) + { + WcaLog(LOGMSG_STANDARD, "failed to create an instance of IUniformResourceLocatorW, skipping shortcut creation"); + ExitFunction1(hr = S_OK); + } + + hr = ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_ALL, IID_IShellLinkW, (void**)&piShellLink); + if (S_OK != hr) + { + WcaLog(LOGMSG_STANDARD, "failed to create an instance of IShellLinkW, skipping shortcut creation"); + ExitFunction1(hr = S_OK); + } + + // query and loop through all the shortcuts + hr = WcaOpenExecuteView(vcsShortcutsQuery, &hView); + ExitOnFailure(hr, "failed to open view on Wix4InternetShortcut table"); + + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + // read column values + hr = WcaGetRecordString(hRec, esqComponent, &pwzComponent); + ExitOnFailure(hr, "failed to get shortcut component"); + hr = WcaGetRecordString(hRec, esqDirectory, &pwzDirectory); + ExitOnFailure(hr, "failed to get shortcut directory"); + hr = WcaGetRecordString(hRec, esqFilename, &pwzFilename); + ExitOnFailure(hr, "failed to get shortcut filename"); + hr = WcaGetRecordFormattedString(hRec, esqTarget, &pwzTarget); + ExitOnFailure(hr, "failed to get shortcut target"); + hr = WcaGetRecordInteger(hRec, esqAttributes, &iAttr); + ExitOnFailure(hr, "failed to get shortcut attributes"); + hr = WcaGetRecordFormattedString(hRec, esqIconFile, &pwzIconFile); + ExitOnFailure(hr, "failed to get shortcut icon file"); + hr = WcaGetRecordInteger(hRec, esqIconIndex, &iIconIndex); + ExitOnFailure(hr, "failed to get shortcut icon index"); + + // skip processing this Wix4InternetShortcut row if the component isn't being configured + WCA_TODO todo = WcaGetComponentToDo(pwzComponent); + if (WCA_TODO_UNKNOWN == todo) + { + WcaLog(LOGMSG_VERBOSE, "Skipping shortcut for null-action component '%ls'", pwzComponent); + continue; + } + + // we need to create the directory where the shortcut is supposed to live; rather + // than doing so in our deferred custom action, use the CreateFolder table to have MSI + // make (and remove) them on our behalf (including the correct cleanup of parent directories). + MSIDBERROR dbError = MSIDBERROR_NOERROR; + WcaLog(LOGMSG_STANDARD, "Adding folder '%ls', component '%ls' to the CreateFolder table", pwzDirectory, pwzComponent); + hr = WcaAddTempRecord(&hCreateFolderTable, &hCreateFolderColumns, L"CreateFolder", &dbError, 0, 2, pwzDirectory, pwzComponent); + if (MSIDBERROR_DUPLICATEKEY == dbError) + { + WcaLog(LOGMSG_STANDARD, "Folder '%ls' already exists in the CreateFolder table; the above error is harmless", pwzDirectory); + hr = S_OK; + } + ExitOnFailure(hr, "Couldn't add temporary CreateFolder row"); + + // only if we're installing/reinstalling do we need to schedule the deferred CA + // (uninstallation is handled via permanent RemoveFile rows and temporary CreateFolder rows) + if (WCA_TODO_INSTALL == todo || WCA_TODO_REINSTALL == todo) + { + // turn the Directory_ id into a path + hr = WcaGetTargetPath(pwzDirectory, &pwzShortcutPath); + ExitOnFailure(hr, "failed to allocate string for shortcut directory"); + + // append the shortcut filename + hr = StrAllocConcat(&pwzShortcutPath, pwzFilename, 0); + ExitOnFailure(hr, "failed to allocate string for shortcut filename"); + + // write the shortcut path and target to custom action data for deferred CAs + hr = WcaWriteStringToCaData(pwzShortcutPath, &pwzCustomActionData); + ExitOnFailure(hr, "failed to write shortcut path to custom action data"); + hr = WcaWriteStringToCaData(pwzTarget, &pwzCustomActionData); + ExitOnFailure(hr, "failed to write shortcut target to custom action data"); + hr = WcaWriteIntegerToCaData(iAttr, &pwzCustomActionData); + ExitOnFailure(hr, "failed to write shortcut attributes to custom action data"); + hr = WcaWriteStringToCaData(pwzIconFile, &pwzCustomActionData); + ExitOnFailure(hr, "failed to write icon file to custom action data"); + hr = WcaWriteIntegerToCaData(iIconIndex, &pwzCustomActionData); + ExitOnFailure(hr, "failed to write icon index to custom action data"); + + uiCost += COST_INTERNETSHORTCUT; + } + } + + if (E_NOMOREITEMS == hr) + { + hr = S_OK; + } + ExitOnFailure(hr, "Failure occured while processing Wix4InternetShortcut table"); + + // if we have any shortcuts to install + if (pwzCustomActionData && *pwzCustomActionData) + { + // add cost to progress bar + hr = WcaProgressMessage(uiCost, TRUE); + ExitOnFailure(hr, "failed to extend progress bar for InternetShortcuts"); + + // provide custom action data to deferred and rollback CAs + hr = WcaSetProperty(CUSTOM_ACTION_DECORATION(L"RollbackInternetShortcuts"), pwzCustomActionData); + ExitOnFailure(hr, "failed to set WixRollbackInternetShortcuts rollback custom action data"); + hr = WcaSetProperty(CUSTOM_ACTION_DECORATION(L"CreateInternetShortcuts"), pwzCustomActionData); + ExitOnFailure(hr, "failed to set WixCreateInternetShortcuts custom action data"); + } + +LExit: + if (hCreateFolderTable) + { + ::MsiCloseHandle(hCreateFolderTable); + } + + if (hCreateFolderColumns) + { + ::MsiCloseHandle(hCreateFolderColumns); + } + + ReleaseStr(pwzCustomActionData); + ReleaseStr(pwzComponent); + ReleaseStr(pwzDirectory); + ReleaseStr(pwzFilename); + ReleaseStr(pwzTarget); + ReleaseStr(pwzShortcutPath); + ReleaseObject(piShellLink); + ReleaseObject(piURL); + + if (fInitializedCom) + { + ::CoUninitialize(); + } + + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + + + +/****************************************************************** + CreateUrl - Creates a shortcut via IUniformResourceLocatorW + +*******************************************************************/ +static HRESULT CreateUrl( + __in_z LPCWSTR wzTarget, + __in_z LPCWSTR wzShortcutPath, + __in_z_opt LPCWSTR wzIconPath, + __in int iconIndex +) +{ + HRESULT hr = S_OK; + IUniformResourceLocatorW* piURL = NULL; + IPersistFile* piPersistFile = NULL; + IPropertySetStorage* piProperties = NULL; + IPropertyStorage* piStorage = NULL; + + // create an internet shortcut object + WcaLog(LOGMSG_STANDARD, "Creating IUniformResourceLocatorW shortcut '%ls' target '%ls'", wzShortcutPath, wzTarget); + hr = ::CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_ALL, IID_IUniformResourceLocatorW, (void**)&piURL); + ExitOnFailure(hr, "failed to create an instance of IUniformResourceLocatorW"); + + // set shortcut target + hr = piURL->SetURL(wzTarget, 0); + ExitOnFailure(hr, "failed to set shortcut '%ls' target '%ls'", wzShortcutPath, wzTarget); + + if (wzIconPath) + { + WcaLog(LOGMSG_STANDARD, "Adding icon '%ls' index '%d'", wzIconPath, iconIndex); + + hr = piURL->QueryInterface(IID_IPropertySetStorage, (void **)&piProperties); + ExitOnFailure(hr, "failed to get IPropertySetStorage for shortcut '%ls'", wzShortcutPath); + + hr = piProperties->Open(FMTID_Intshcut, STGM_WRITE, &piStorage); + ExitOnFailure(hr, "failed to open storage for shortcut '%ls'", wzShortcutPath); + + PROPSPEC ppids[2] = { {PRSPEC_PROPID, PID_IS_ICONINDEX}, {PRSPEC_PROPID, PID_IS_ICONFILE} }; + PROPVARIANT ppvar[2]; + + PropVariantInit(ppvar); + PropVariantInit(ppvar + 1); + + ppvar[0].vt = VT_I4; + ppvar[0].lVal = iconIndex; + ppvar[1].vt = VT_LPWSTR; + ppvar[1].pwszVal = const_cast(wzIconPath); + + hr = piStorage->WriteMultiple(2, ppids, ppvar, 0); + ExitOnFailure(hr, "failed to write icon storage for shortcut '%ls'", wzShortcutPath); + + hr = piStorage->Commit(STGC_DEFAULT); + ExitOnFailure(hr, "failed to commit icon storage for shortcut '%ls'", wzShortcutPath); + } + + // get an IPersistFile and save the shortcut + hr = piURL->QueryInterface(IID_IPersistFile, (void**)&piPersistFile); + ExitOnFailure(hr, "failed to get IPersistFile for shortcut '%ls'", wzShortcutPath); + + hr = piPersistFile->Save(wzShortcutPath, TRUE); + ExitOnFailure(hr, "failed to save shortcut '%ls'", wzShortcutPath); + +LExit: + ReleaseObject(piPersistFile); + ReleaseObject(piURL); + ReleaseObject(piStorage); + ReleaseObject(piProperties); + + return hr; +} + +/****************************************************************** + CreateLink - Creates a shortcut via IShellLinkW + +*******************************************************************/ +static HRESULT CreateLink( + __in_z LPCWSTR wzTarget, + __in_z LPCWSTR wzShortcutPath, + __in_z_opt LPCWSTR wzIconPath, + __in int iconIndex +) +{ + HRESULT hr = S_OK; + IShellLinkW* piShellLink = NULL; + IPersistFile* piPersistFile = NULL; + + // create an internet shortcut object + WcaLog(LOGMSG_STANDARD, "Creating IShellLinkW shortcut '%ls' target '%ls'", wzShortcutPath, wzTarget); + hr = ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_ALL, IID_IShellLinkW, (void**)&piShellLink); + ExitOnFailure(hr, "failed to create an instance of IShellLinkW"); + + // set shortcut target + hr = piShellLink->SetPath(wzTarget); + ExitOnFailure(hr, "failed to set shortcut '%ls' target '%ls'", wzShortcutPath, wzTarget); + + if (wzIconPath) + { + WcaLog(LOGMSG_STANDARD, "Adding icon '%ls' index '%d'", wzIconPath, iconIndex); + hr = piShellLink->SetIconLocation(wzIconPath, iconIndex); + ExitOnFailure(hr, "failed to set icon for shortcut '%ls'", wzShortcutPath); + } + + // get an IPersistFile and save the shortcut + hr = piShellLink->QueryInterface(IID_IPersistFile, (void**)&piPersistFile); + ExitOnFailure(hr, "failed to get IPersistFile for shortcut '%ls'", wzShortcutPath); + + hr = piPersistFile->Save(wzShortcutPath, TRUE); + ExitOnFailure(hr, "failed to save shortcut '%ls'", wzShortcutPath); + +LExit: + ReleaseObject(piPersistFile); + ReleaseObject(piShellLink); + + return hr; +} + + + +/****************************************************************** + WixCreateInternetShortcuts - entry point for Internet shortcuts + custom action +*******************************************************************/ +extern "C" UINT __stdcall WixCreateInternetShortcuts( + __in MSIHANDLE hInstall + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + LPWSTR pwz = NULL; + LPWSTR pwzCustomActionData = NULL; + LPWSTR pwzTarget = NULL; + LPWSTR pwzShortcutPath = NULL; + LPWSTR pwzIconPath = NULL; + BOOL fInitializedCom = FALSE; + int iAttr = 0; + int iIconIndex = 0; + + // initialize + hr = WcaInitialize(hInstall, "WixCreateInternetShortcuts"); + ExitOnFailure(hr, "failed to initialize WixCreateInternetShortcuts"); + + hr = ::CoInitialize(NULL); + ExitOnFailure(hr, "failed to initialize COM"); + fInitializedCom = TRUE; + + // extract the custom action data + hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData); + ExitOnFailure(hr, "failed to get CustomActionData"); + + // loop through all the custom action data + pwz = pwzCustomActionData; + while (pwz && *pwz) + { + hr = WcaReadStringFromCaData(&pwz, &pwzShortcutPath); + ExitOnFailure(hr, "failed to read shortcut path from custom action data"); + hr = WcaReadStringFromCaData(&pwz, &pwzTarget); + ExitOnFailure(hr, "failed to read shortcut target from custom action data"); + hr = WcaReadIntegerFromCaData(&pwz, &iAttr); + ExitOnFailure(hr, "failed to read shortcut attributes from custom action data"); + hr = WcaReadStringFromCaData(&pwz, &pwzIconPath); + ExitOnFailure(hr, "failed to read shortcut icon path from custom action data"); + hr = WcaReadIntegerFromCaData(&pwz, &iIconIndex); + ExitOnFailure(hr, "failed to read shortcut icon index from custom action data"); + + if ((iAttr & esaURL) == esaURL) + { + hr = CreateUrl(pwzTarget, pwzShortcutPath, pwzIconPath, iIconIndex); + } + else + { + hr = CreateLink(pwzTarget, pwzShortcutPath, pwzIconPath, iIconIndex); + } + ExitOnFailure(hr, "failed to create Internet shortcut"); + + // tick the progress bar + hr = WcaProgressMessage(COST_INTERNETSHORTCUT, FALSE); + ExitOnFailure(hr, "failed to tick progress bar for shortcut: %ls", pwzShortcutPath); + } + +LExit: + ReleaseStr(pwzCustomActionData); + ReleaseStr(pwzTarget); + ReleaseStr(pwzShortcutPath); + + if (fInitializedCom) + { + ::CoUninitialize(); + } + + er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er; + return WcaFinalize(er); +} + + + +/****************************************************************** + WixRollbackInternetShortcuts - entry point for Internet shortcuts + custom action (rollback) +*******************************************************************/ +extern "C" UINT __stdcall WixRollbackInternetShortcuts( + __in MSIHANDLE hInstall + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + LPWSTR pwz = NULL; + LPWSTR pwzCustomActionData = NULL; + LPWSTR pwzShortcutPath = NULL; + int iAttr = 0; + + // initialize + hr = WcaInitialize(hInstall, "WixRemoveInternetShortcuts"); + ExitOnFailure(hr, "failed to initialize WixRemoveInternetShortcuts"); + + hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData); + ExitOnFailure(hr, "failed to get CustomActionData"); + + // loop through all the custom action data + pwz = pwzCustomActionData; + while (pwz && *pwz) + { + // extract the custom action data we're interested in + hr = WcaReadStringFromCaData(&pwz, &pwzShortcutPath); + ExitOnFailure(hr, "failed to read shortcut path from custom action data for rollback"); + + // delete file + hr = FileEnsureDelete(pwzShortcutPath); + ExitOnFailure(hr, "failed to delete file '%ls'", pwzShortcutPath); + + // skip over the shortcut target and attributes + hr = WcaReadStringFromCaData(&pwz, &pwzShortcutPath); + ExitOnFailure(hr, "failed to skip shortcut target from custom action data for rollback"); + hr = WcaReadIntegerFromCaData(&pwz, &iAttr); + ExitOnFailure(hr, "failed to read shortcut attributes from custom action data"); + } + +LExit: + ReleaseStr(pwzCustomActionData); + ReleaseStr(pwzShortcutPath); + + er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er; + return WcaFinalize(er); +} 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 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +#if _WIN32_MSI < 150 +#define _WIN32_MSI 150 +#endif + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include // NetApi32.lib +#include +#include +#include +#include + +#define MAXUINT USHRT_MAX + +#include "wcautil.h" +#include "wcawow64.h" +#include "wcawrapquery.h" +#include "aclutil.h" +#include "dirutil.h" +#include "fileutil.h" +#include "memutil.h" +#include "osutil.h" +#include "pathutil.h" +#include "procutil.h" +#include "shelutil.h" +#include "strutil.h" +#include "sczutil.h" +#include "rmutil.h" +#include "userutil.h" +#include "xmlutil.h" +#include "wiutil.h" + +#include "CustomMsiErrors.h" + +#include "sca.h" +#include "scacost.h" +#include "cost.h" +#include "scauser.h" +#include "scasmb.h" +#include "scasmbexec.h" + +#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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + +#define OUTPUT_BUFFER 1024 + +// These old "CA" prefix names are deprecated, and intended to go away in wix 4.0, only staying now for compatibility reasons +const LPCWSTR CAQUIET_TIMEOUT_PROPERTY = L"QtExecCmdTimeout"; +const LPCWSTR CAQUIET_ARGUMENTS_PROPERTY = L"QtExecCmdLine"; +const LPCWSTR CAQUIET64_ARGUMENTS_PROPERTY = L"QtExec64CmdLine"; +// end deprecated section + +// WixCA name quiet commandline argument properties +const LPCWSTR WIX_QUIET_ARGUMENTS_PROPERTY = L"WixQuietExecCmdLine"; +const LPCWSTR WIX_QUIET64_ARGUMENTS_PROPERTY = L"WixQuietExec64CmdLine"; + +// WixCA quiet timeout properties +const LPCWSTR WIX_QUIET_TIMEOUT_PROPERTY = L"WixQuietExecCmdTimeout"; +const LPCWSTR WIX_QUIET64_TIMEOUT_PROPERTY = L"WixQuietExec64CmdTimeout"; + +// WixCA silent commandline argument properties +const LPCWSTR WIX_SILENT_ARGUMENTS_PROPERTY = L"WixSilentExecCmdLine"; +const LPCWSTR WIX_SILENT64_ARGUMENTS_PROPERTY = L"WixSilentExec64CmdLine"; + +// WixCA silent timeout properties +const LPCWSTR WIX_SILENT_TIMEOUT_PROPERTY = L"WixSilentExecCmdTimeout"; +const LPCWSTR WIX_SILENT64_TIMEOUT_PROPERTY = L"WixSilentExec64CmdTimeout"; + +HRESULT BuildCommandLine( + __in LPCWSTR wzProperty, + __out LPWSTR *ppwzCommand + ) +{ + Assert(ppwzCommand); + + HRESULT hr = S_OK; + BOOL fScheduled = ::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_SCHEDULED); + BOOL fRollback = ::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK); + BOOL fCommit = ::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_COMMIT); + + if (fScheduled || fRollback || fCommit) + { + if (WcaIsPropertySet("CustomActionData")) + { + hr = WcaGetProperty( L"CustomActionData", ppwzCommand); + ExitOnFailure(hr, "Failed to get CustomActionData"); + } + } + else if (WcaIsUnicodePropertySet(wzProperty)) + { + hr = WcaGetFormattedProperty(wzProperty, ppwzCommand); + ExitOnFailure(hr, "Failed to get %ls", wzProperty); + hr = WcaSetProperty(wzProperty, L""); // clear out the property now that we've read it + ExitOnFailure(hr, "Failed to set %ls", wzProperty); + } + + if (!*ppwzCommand) + { + ExitOnFailure(hr = E_INVALIDARG, "Failed to get command line data"); + } + + if (L'"' != **ppwzCommand) + { + WcaLog(LOGMSG_STANDARD, "Command string must begin with quoted application name."); + ExitOnFailure(hr = E_INVALIDARG, "invalid command line property value"); + } + +LExit: + return hr; +} + +#define ONEMINUTE 60000 + +DWORD GetTimeout(LPCWSTR wzPropertyName) +{ + DWORD dwTimeout = ONEMINUTE; + HRESULT hr = S_OK; + + LPWSTR pwzData = NULL; + + if (WcaIsUnicodePropertySet(wzPropertyName)) + { + hr = WcaGetProperty(wzPropertyName, &pwzData); + ExitOnFailure(hr, "Failed to get %ls", wzPropertyName); + + if ((dwTimeout = (DWORD)_wtoi(pwzData)) == 0) + { + dwTimeout = ONEMINUTE; + } + } + +LExit: + ReleaseStr(pwzData); + + return dwTimeout; + +} + +HRESULT ExecCommon( + __in LPCWSTR wzArgumentsProperty, + __in LPCWSTR wzTimeoutProperty, + __in BOOL fLogCommand, + __in BOOL fLogOutput + ) +{ + HRESULT hr = S_OK; + LPWSTR pwzCommand = NULL; + DWORD dwTimeout = 0; + + hr = BuildCommandLine(wzArgumentsProperty, &pwzCommand); + ExitOnFailure(hr, "Failed to get Command Line"); + + dwTimeout = GetTimeout(wzTimeoutProperty); + + hr = QuietExec(pwzCommand, dwTimeout, fLogCommand, fLogOutput); + ExitOnFailure(hr, "QuietExec Failed"); + +LExit: + ReleaseStr(pwzCommand); + + return hr; +} + +HRESULT ExecCommon64( + __in LPCWSTR wzArgumentsProperty, + __in LPCWSTR wzTimeoutProperty, + __in BOOL fLogCommand, + __in BOOL fLogOutput + ) +{ + HRESULT hr = S_OK; + LPWSTR pwzCommand = NULL; + DWORD dwTimeout = 0; +#ifndef _WIN64 + BOOL fIsWow64Initialized = FALSE; + BOOL fRedirected = FALSE; + + hr = WcaInitializeWow64(); + if (S_FALSE == hr) + { + hr = TYPE_E_DLLFUNCTIONNOTFOUND; + } + ExitOnFailure(hr, "Failed to intialize WOW64."); + fIsWow64Initialized = TRUE; + + hr = WcaDisableWow64FSRedirection(); + ExitOnFailure(hr, "Failed to enable filesystem redirection."); + fRedirected = TRUE; +#endif + + hr = BuildCommandLine(wzArgumentsProperty, &pwzCommand); + ExitOnFailure(hr, "Failed to get Command Line"); + + dwTimeout = GetTimeout(wzTimeoutProperty); + + hr = QuietExec(pwzCommand, dwTimeout, fLogCommand, fLogOutput); + ExitOnFailure(hr, "QuietExec64 Failed"); + +LExit: + ReleaseStr(pwzCommand); + +#ifndef _WIN64 + if (fRedirected) + { + WcaRevertWow64FSRedirection(); + } + + if (fIsWow64Initialized) + { + WcaFinalizeWow64(); + } +#endif + + return hr; +} + +// These two custom actions are deprecated, and should go away in wix v4.0. WixQuietExec replaces this one, +// and is not intended to have any difference in behavior apart from CA name and property names. +extern "C" UINT __stdcall CAQuietExec( + __in MSIHANDLE hInstall + ) +{ + Assert(hInstall); + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + hr = WcaInitialize(hInstall, "CAQuietExec"); + ExitOnFailure(hr, "Failed to initialize"); + + hr = ExecCommon(CAQUIET_ARGUMENTS_PROPERTY, CAQUIET_TIMEOUT_PROPERTY, TRUE, TRUE); + ExitOnFailure(hr, "Failed in ExecCommon method"); + +LExit: + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + + return WcaFinalize(er); +} + +// 2nd deprecated custom action name, superseded by WixQuietExec64 +extern "C" UINT __stdcall CAQuietExec64( + __in MSIHANDLE hInstall + ) +{ + Assert(hInstall); + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + hr = WcaInitialize(hInstall, "CAQuietExec64"); + ExitOnFailure(hr, "Failed to initialize"); + + hr = ExecCommon64(CAQUIET64_ARGUMENTS_PROPERTY, CAQUIET_TIMEOUT_PROPERTY, TRUE, TRUE); + ExitOnFailure(hr, "Failed in ExecCommon64 method"); + +LExit: + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + + return WcaFinalize(er); +} + +extern "C" UINT __stdcall WixQuietExec( + __in MSIHANDLE hInstall + ) +{ + Assert(hInstall); + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + hr = WcaInitialize(hInstall, "WixQuietExec"); + ExitOnFailure(hr, "Failed to initialize"); + + hr = ExecCommon(WIX_QUIET_ARGUMENTS_PROPERTY, WIX_QUIET_TIMEOUT_PROPERTY, TRUE, TRUE); + ExitOnFailure(hr, "Failed in ExecCommon method"); + +LExit: + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + + return WcaFinalize(er); +} + +extern "C" UINT __stdcall WixQuietExec64( + __in MSIHANDLE hInstall + ) +{ + Assert(hInstall); + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + hr = WcaInitialize(hInstall, "WixQuietExec64"); + ExitOnFailure(hr, "Failed to initialize"); + + hr = ExecCommon64(WIX_QUIET64_ARGUMENTS_PROPERTY, WIX_QUIET64_TIMEOUT_PROPERTY, TRUE, TRUE); + ExitOnFailure(hr, "Failed in ExecCommon method"); + +LExit: + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + + return WcaFinalize(er); +} + +extern "C" UINT __stdcall WixSilentExec( + __in MSIHANDLE hInstall + ) +{ + Assert(hInstall); + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + hr = WcaInitialize(hInstall, "WixSilentExec"); + ExitOnFailure(hr, "Failed to initialize"); + + hr = ExecCommon(WIX_SILENT_ARGUMENTS_PROPERTY, WIX_SILENT_TIMEOUT_PROPERTY, FALSE, FALSE); + ExitOnFailure(hr, "Failed in ExecCommon method"); + +LExit: + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + + return WcaFinalize(er); +} + +extern "C" UINT __stdcall WixSilentExec64( + __in MSIHANDLE hInstall + ) +{ + Assert(hInstall); + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + hr = WcaInitialize(hInstall, "WixSilentExec64"); + ExitOnFailure(hr, "Failed to initialize"); + + hr = ExecCommon64(WIX_SILENT64_ARGUMENTS_PROPERTY, WIX_SILENT64_TIMEOUT_PROPERTY, FALSE, FALSE); + ExitOnFailure(hr, "Failed in ExecCommon method"); + +LExit: + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + + return WcaFinalize(er); +} 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 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +// user creation attributes definitions +enum SCAU_ATTRIBUTES +{ + SCAU_DONT_EXPIRE_PASSWRD = 0x00000001, + SCAU_PASSWD_CANT_CHANGE = 0x00000002, + SCAU_PASSWD_CHANGE_REQD_ON_LOGIN = 0x00000004, + SCAU_DISABLE_ACCOUNT = 0x00000008, + SCAU_FAIL_IF_EXISTS = 0x00000010, + SCAU_UPDATE_IF_EXISTS = 0x00000020, + SCAU_ALLOW_LOGON_AS_SERVICE = 0x00000040, + SCAU_ALLOW_LOGON_AS_BATCH = 0x00000080, + + SCAU_DONT_REMOVE_ON_UNINSTALL = 0x00000100, + SCAU_DONT_CREATE_USER = 0x00000200, + SCAU_NON_VITAL = 0x00000400, +}; \ 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 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +const UINT COST_PERFMON_REGISTER = 1000; +const UINT COST_PERFMON_UNREGISTER = 1000; + +const UINT COST_SMB_CREATESMB = 10000; +const UINT COST_SMB_DROPSMB = 5000; +const UINT COST_USER_ADD = 10000; +const UINT COST_USER_DELETE = 10000; + +const UINT COST_PERFMONMANIFEST_REGISTER = 1000; +const UINT COST_PERFMONMANIFEST_UNREGISTER = 1000; + +const UINT COST_EVENTMANIFEST_REGISTER = 1000; +const UINT COST_EVENTMANIFEST_UNREGISTER = 1000; + 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +/******************************************************************** + * CreateSmb - CUSTOM ACTION ENTRY POINT for creating fileshares + * + * Input: deferred CustomActionData - + * wzFsKey\twzShareDesc\twzFullPath\tfIntegratedAuth\twzUserName\tnPermissions\twzUserName\tnPermissions... + * + * ****************************************************************/ +extern "C" UINT __stdcall CreateSmb(MSIHANDLE hInstall) +{ +//AssertSz(0, "debug CreateSmb"); + UINT er = ERROR_SUCCESS; + HRESULT hr = S_OK; + + LPWSTR pwzData = NULL; + LPWSTR pwz = NULL; + LPWSTR pwzFsKey = NULL; + LPWSTR pwzShareDesc = NULL; + LPWSTR pwzDirectory = NULL; + int iAccessMode = 0; + DWORD nExPermissions = 0; + BOOL fIntegratedAuth; + LPWSTR pwzExUser = NULL; + SCA_SMBP ssp = {0}; + DWORD dwExUserPerms = 0; + DWORD dwCounter = 0; + SCA_SMBP_USER_PERMS* pUserPermsList = NULL; + + hr = WcaInitialize(hInstall, "CreateSmb"); + ExitOnFailure(hr, "failed to initialize"); + + hr = WcaGetProperty( L"CustomActionData", &pwzData); + ExitOnFailure(hr, "failed to get CustomActionData"); + + WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); + + pwz = pwzData; + hr = WcaReadStringFromCaData(&pwz, &pwzFsKey); // share name + ExitOnFailure(hr, "failed to read share name"); + hr = WcaReadStringFromCaData(&pwz, &pwzShareDesc); // share description + ExitOnFailure(hr, "failed to read share name"); + hr = WcaReadStringFromCaData(&pwz, &pwzDirectory); // full path to share + ExitOnFailure(hr, "failed to read share name"); + hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&fIntegratedAuth)); + ExitOnFailure(hr, "failed to read integrated authentication"); + + hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&dwExUserPerms)); + ExitOnFailure(hr, "failed to read count of permissions to set"); + if(dwExUserPerms > 0) + { + pUserPermsList = static_cast(MemAlloc(sizeof(SCA_SMBP_USER_PERMS)*dwExUserPerms, TRUE)); + ExitOnNull(pUserPermsList, hr, E_OUTOFMEMORY, "failed to allocate memory for permissions structure"); + + //Pull out all of the ExUserPerm strings + for (dwCounter = 0; dwCounter < dwExUserPerms; ++dwCounter) + { + hr = WcaReadStringFromCaData(&pwz, &pwzExUser); // user account + ExitOnFailure(hr, "failed to read user account"); + pUserPermsList[dwCounter].wzUser = pwzExUser; + pwzExUser = NULL; + + hr = WcaReadIntegerFromCaData(&pwz, &iAccessMode); + ExitOnFailure(hr, "failed to read access mode"); + pUserPermsList[dwCounter].accessMode = (ACCESS_MODE)iAccessMode; + iAccessMode = 0; + + hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&nExPermissions)); + ExitOnFailure(hr, "failed to read count of permissions"); + pUserPermsList[dwCounter].nPermissions = nExPermissions; + nExPermissions = 0; + } + } + + ssp.wzKey = pwzFsKey; + ssp.wzDescription = pwzShareDesc; + ssp.wzDirectory = pwzDirectory; + ssp.fUseIntegratedAuth = fIntegratedAuth; + ssp.dwUserPermissionCount = dwExUserPerms; + ssp.pUserPerms = pUserPermsList; + + hr = ScaEnsureSmbExists(&ssp); + MessageExitOnFailure(hr, msierrSMBFailedCreate, "failed to create share: '%ls'", pwzFsKey); + + hr = WcaProgressMessage(COST_SMB_CREATESMB, FALSE); + +LExit: + ReleaseStr(pwzFsKey); + ReleaseStr(pwzShareDesc); + ReleaseStr(pwzDirectory); + ReleaseStr(pwzData); + + if (pUserPermsList) + { + MemFree(pUserPermsList); + } + + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + return WcaFinalize(er); +} + + + +/******************************************************************** + DropSmb - CUSTOM ACTION ENTRY POINT for creating fileshares + + Input: deferred CustomActionData - wzFsKey\twzShareDesc\twzFullPath\tnPermissions\tfIntegratedAuth\twzUserName\twzPassword + + * ****************************************************************/ +extern "C" UINT __stdcall DropSmb(MSIHANDLE hInstall) +{ + //AssertSz(0, "debug DropSmb"); + UINT er = ERROR_SUCCESS; + HRESULT hr = S_OK; + + LPWSTR pwzData = NULL; + LPWSTR pwz = NULL; + LPWSTR pwzFsKey = NULL; + SCA_SMBP ssp = {0}; + + hr = WcaInitialize(hInstall, "DropSmb"); + ExitOnFailure(hr, "failed to initialize"); + + hr = WcaGetProperty( L"CustomActionData", &pwzData); + ExitOnFailure(hr, "failed to get CustomActionData"); + + WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); + + pwz = pwzData; + hr = WcaReadStringFromCaData(&pwz, &pwzFsKey); // share name + ExitOnFailure(hr, "failed to read share name"); + + ssp.wzKey = pwzFsKey; + + hr = ScaDropSmb(&ssp); + MessageExitOnFailure(hr, msierrSMBFailedDrop, "failed to delete share: '%ls'", pwzFsKey); + + hr = WcaProgressMessage(COST_SMB_DROPSMB, FALSE); + +LExit: + ReleaseStr(pwzFsKey); + ReleaseStr(pwzData); + + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + return WcaFinalize(er); +} + + +static HRESULT AddUserToGroup( + __in LPWSTR wzUser, + __in LPCWSTR wzUserDomain, + __in LPCWSTR wzGroup, + __in LPCWSTR wzGroupDomain + ) +{ + Assert(wzUser && *wzUser && wzUserDomain && wzGroup && *wzGroup && wzGroupDomain); + + HRESULT hr = S_OK; + IADsGroup *pGroup = NULL; + BSTR bstrUser = NULL; + BSTR bstrGroup = NULL; + LPCWSTR wz = NULL; + LPWSTR pwzUser = NULL; + LOCALGROUP_MEMBERS_INFO_3 lgmi; + + if (*wzGroupDomain) + { + wz = wzGroupDomain; + } + + // Try adding it to the global group first + UINT ui = ::NetGroupAddUser(wz, wzGroup, wzUser); + if (NERR_GroupNotFound == ui) + { + // Try adding it to the local group + if (wzUserDomain) + { + hr = StrAllocFormatted(&pwzUser, L"%s\\%s", wzUserDomain, wzUser); + ExitOnFailure(hr, "failed to allocate user domain string"); + } + + lgmi.lgrmi3_domainandname = (NULL == pwzUser ? wzUser : pwzUser); + ui = ::NetLocalGroupAddMembers(wz, wzGroup, 3 , reinterpret_cast(&lgmi), 1); + } + hr = HRESULT_FROM_WIN32(ui); + if (HRESULT_FROM_WIN32(ERROR_MEMBER_IN_ALIAS) == hr) // if they're already a member of the group don't report an error + hr = S_OK; + + // + // If we failed, try active directory + // + if (FAILED(hr)) + { + 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); + + hr = UserCreateADsPath(wzUserDomain, wzUser, &bstrUser); + ExitOnFailure(hr, "failed to create user ADsPath for user: %ls domain: %ls", wzUser, wzUserDomain); + + hr = UserCreateADsPath(wzGroupDomain, wzGroup, &bstrGroup); + ExitOnFailure(hr, "failed to create group ADsPath for group: %ls domain: %ls", wzGroup, wzGroupDomain); + + hr = ::ADsGetObject(bstrGroup,IID_IADsGroup, reinterpret_cast(&pGroup)); + ExitOnFailure(hr, "Failed to get group '%ls'.", reinterpret_cast(bstrGroup) ); + + hr = pGroup->Add(bstrUser); + if ((HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS) == hr) || (HRESULT_FROM_WIN32(ERROR_MEMBER_IN_ALIAS) == hr)) + hr = S_OK; + + ExitOnFailure(hr, "Failed to add user %ls to group '%ls'.", reinterpret_cast(bstrUser), reinterpret_cast(bstrGroup) ); + } + +LExit: + ReleaseObject(pGroup); + ReleaseBSTR(bstrUser); + ReleaseBSTR(bstrGroup); + + return hr; +} + +static HRESULT RemoveUserFromGroup( + __in LPWSTR wzUser, + __in LPCWSTR wzUserDomain, + __in LPCWSTR wzGroup, + __in LPCWSTR wzGroupDomain + ) +{ + Assert(wzUser && *wzUser && wzUserDomain && wzGroup && *wzGroup && wzGroupDomain); + + HRESULT hr = S_OK; + IADsGroup *pGroup = NULL; + BSTR bstrUser = NULL; + BSTR bstrGroup = NULL; + LPCWSTR wz = NULL; + LPWSTR pwzUser = NULL; + LOCALGROUP_MEMBERS_INFO_3 lgmi; + + if (*wzGroupDomain) + { + wz = wzGroupDomain; + } + + // Try removing it from the global group first + UINT ui = ::NetGroupDelUser(wz, wzGroup, wzUser); + if (NERR_GroupNotFound == ui) + { + // Try removing it from the local group + if (wzUserDomain) + { + hr = StrAllocFormatted(&pwzUser, L"%s\\%s", wzUserDomain, wzUser); + ExitOnFailure(hr, "failed to allocate user domain string"); + } + + lgmi.lgrmi3_domainandname = (NULL == pwzUser ? wzUser : pwzUser); + ui = ::NetLocalGroupDelMembers(wz, wzGroup, 3 , reinterpret_cast(&lgmi), 1); + } + hr = HRESULT_FROM_WIN32(ui); + + // + // If we failed, try active directory + // + if (FAILED(hr)) + { + 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); + + hr = UserCreateADsPath(wzUserDomain, wzUser, &bstrUser); + ExitOnFailure(hr, "failed to create user ADsPath in order to remove user: %ls domain: %ls from a group", wzUser, wzUserDomain); + + hr = UserCreateADsPath(wzGroupDomain, wzGroup, &bstrGroup); + ExitOnFailure(hr, "failed to create group ADsPath in order to remove user from group: %ls domain: %ls", wzGroup, wzGroupDomain); + + hr = ::ADsGetObject(bstrGroup,IID_IADsGroup, reinterpret_cast(&pGroup)); + ExitOnFailure(hr, "Failed to get group '%ls'.", reinterpret_cast(bstrGroup) ); + + hr = pGroup->Remove(bstrUser); + ExitOnFailure(hr, "Failed to remove user %ls from group '%ls'.", reinterpret_cast(bstrUser), reinterpret_cast(bstrGroup) ); + } + +LExit: + ReleaseObject(pGroup); + ReleaseBSTR(bstrUser); + ReleaseBSTR(bstrGroup); + + return hr; +} + + +static HRESULT GetUserHasRight( + __in LSA_HANDLE hPolicy, + __in PSID pUserSid, + __in LPWSTR wzRight, + __out BOOL* fHasRight +) +{ + HRESULT hr = S_OK; + NTSTATUS nt = 0; + LSA_UNICODE_STRING lucPrivilege = { 0 }; + PLSA_ENUMERATION_INFORMATION rgSids = NULL; + ULONG cSids = 0; + *fHasRight = FALSE; + + lucPrivilege.Buffer = wzRight; + lucPrivilege.Length = static_cast(lstrlenW(lucPrivilege.Buffer) * sizeof(WCHAR)); + lucPrivilege.MaximumLength = (lucPrivilege.Length + 1) * sizeof(WCHAR); + + nt = ::LsaEnumerateAccountsWithUserRight(hPolicy, &lucPrivilege, reinterpret_cast(&rgSids), &cSids); + hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt)); + ExitOnFailure(hr, "Failed to enumerate users for right: %ls", lucPrivilege.Buffer); + + for (DWORD i = 0; i < cSids; ++i) + { + PLSA_ENUMERATION_INFORMATION pInfo = rgSids + i; + if (::EqualSid(pUserSid, pInfo->Sid)) + { + *fHasRight = TRUE; + break; + } + } + +LExit: + if (rgSids) + { + ::LsaFreeMemory(rgSids); + } + + return hr; +} + + +static HRESULT GetExistingUserRightsAssignments( + __in_opt LPCWSTR wzDomain, + __in LPCWSTR wzName, + __inout int* iAttributes +) +{ + HRESULT hr = S_OK; + NTSTATUS nt = 0; + BOOL fHasRight = FALSE; + + LSA_HANDLE hPolicy = NULL; + LSA_OBJECT_ATTRIBUTES objectAttributes = { 0 }; + + LPWSTR pwzUser = NULL; + PSID psid = NULL; + + if (wzDomain && *wzDomain) + { + hr = StrAllocFormatted(&pwzUser, L"%s\\%s", wzDomain, wzName); + ExitOnFailure(hr, "Failed to allocate user with domain string"); + } + else + { + hr = StrAllocString(&pwzUser, wzName, 0); + ExitOnFailure(hr, "Failed to allocate string from user name."); + } + + hr = AclGetAccountSid(NULL, pwzUser, &psid); + ExitOnFailure(hr, "Failed to get SID for user: %ls", pwzUser); + + nt = ::LsaOpenPolicy(NULL, &objectAttributes, POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION, &hPolicy); + hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt)); + ExitOnFailure(hr, "Failed to open LSA policy store"); + + hr = GetUserHasRight(hPolicy, psid, L"SeServiceLogonRight", &fHasRight); + ExitOnFailure(hr, "Failed to check LogonAsService right"); + + if (fHasRight) + { + *iAttributes |= SCAU_ALLOW_LOGON_AS_SERVICE; + } + + hr = GetUserHasRight(hPolicy, psid, L"SeBatchLogonRight", &fHasRight); + ExitOnFailure(hr, "Failed to check LogonAsBatchJob right"); + + if (fHasRight) + { + *iAttributes |= SCAU_ALLOW_LOGON_AS_BATCH; + } + +LExit: + if (hPolicy) + { + ::LsaClose(hPolicy); + } + + ReleaseSid(psid); + ReleaseStr(pwzUser); + return hr; +} + + +static HRESULT ModifyUserLocalServiceRight( + __in_opt LPCWSTR wzDomain, + __in LPCWSTR wzName, + __in BOOL fAdd + ) +{ + HRESULT hr = S_OK; + NTSTATUS nt = 0; + + LPWSTR pwzUser = NULL; + PSID psid = NULL; + LSA_HANDLE hPolicy = NULL; + LSA_OBJECT_ATTRIBUTES ObjectAttributes = { 0 }; + LSA_UNICODE_STRING lucPrivilege = { 0 }; + + if (wzDomain && *wzDomain) + { + hr = StrAllocFormatted(&pwzUser, L"%s\\%s", wzDomain, wzName); + ExitOnFailure(hr, "Failed to allocate user with domain string"); + } + else + { + hr = StrAllocString(&pwzUser, wzName, 0); + ExitOnFailure(hr, "Failed to allocate string from user name."); + } + + hr = AclGetAccountSid(NULL, pwzUser, &psid); + ExitOnFailure(hr, "Failed to get SID for user: %ls", pwzUser); + + nt = ::LsaOpenPolicy(NULL, &ObjectAttributes, POLICY_ALL_ACCESS, &hPolicy); + hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt)); + ExitOnFailure(hr, "Failed to open LSA policy store."); + + lucPrivilege.Buffer = L"SeServiceLogonRight"; + lucPrivilege.Length = static_cast(lstrlenW(lucPrivilege.Buffer) * sizeof(WCHAR)); + lucPrivilege.MaximumLength = (lucPrivilege.Length + 1) * sizeof(WCHAR); + + if (fAdd) + { + nt = ::LsaAddAccountRights(hPolicy, psid, &lucPrivilege, 1); + hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt)); + ExitOnFailure(hr, "Failed to add 'logon as service' bit to user: %ls", pwzUser); + } + else + { + nt = ::LsaRemoveAccountRights(hPolicy, psid, FALSE, &lucPrivilege, 1); + hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt)); + ExitOnFailure(hr, "Failed to remove 'logon as service' bit from user: %ls", pwzUser); + } + +LExit: + if (hPolicy) + { + ::LsaClose(hPolicy); + } + + ReleaseSid(psid); + ReleaseStr(pwzUser); + return hr; +} + + +static HRESULT ModifyUserLocalBatchRight( + __in_opt LPCWSTR wzDomain, + __in LPCWSTR wzName, + __in BOOL fAdd + ) +{ + HRESULT hr = S_OK; + NTSTATUS nt = 0; + + LPWSTR pwzUser = NULL; + PSID psid = NULL; + LSA_HANDLE hPolicy = NULL; + LSA_OBJECT_ATTRIBUTES ObjectAttributes = { 0 }; + LSA_UNICODE_STRING lucPrivilege = { 0 }; + + if (wzDomain && *wzDomain) + { + hr = StrAllocFormatted(&pwzUser, L"%s\\%s", wzDomain, wzName); + ExitOnFailure(hr, "Failed to allocate user with domain string"); + } + else + { + hr = StrAllocString(&pwzUser, wzName, 0); + ExitOnFailure(hr, "Failed to allocate string from user name."); + } + + hr = AclGetAccountSid(NULL, pwzUser, &psid); + ExitOnFailure(hr, "Failed to get SID for user: %ls", pwzUser); + + nt = ::LsaOpenPolicy(NULL, &ObjectAttributes, POLICY_ALL_ACCESS, &hPolicy); + hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt)); + ExitOnFailure(hr, "Failed to open LSA policy store."); + + lucPrivilege.Buffer = L"SeBatchLogonRight"; + lucPrivilege.Length = static_cast(lstrlenW(lucPrivilege.Buffer) * sizeof(WCHAR)); + lucPrivilege.MaximumLength = (lucPrivilege.Length + 1) * sizeof(WCHAR); + + if (fAdd) + { + nt = ::LsaAddAccountRights(hPolicy, psid, &lucPrivilege, 1); + hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt)); + ExitOnFailure(hr, "Failed to add 'logon as batch job' bit to user: %ls", pwzUser); + } + else + { + nt = ::LsaRemoveAccountRights(hPolicy, psid, FALSE, &lucPrivilege, 1); + hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt)); + ExitOnFailure(hr, "Failed to remove 'logon as batch job' bit from user: %ls", pwzUser); + } + + LExit: + if (hPolicy) + { + ::LsaClose(hPolicy); + } + + ReleaseSid(psid); + ReleaseStr(pwzUser); + return hr; +} + +static void SetUserPasswordAndAttributes( + __in USER_INFO_1* puserInfo, + __in LPWSTR wzPassword, + __in int iAttributes + ) +{ + Assert(puserInfo); + + // Set the User's password + puserInfo->usri1_password = wzPassword; + + // Apply the Attributes + if (SCAU_DONT_EXPIRE_PASSWRD & iAttributes) + { + puserInfo->usri1_flags |= UF_DONT_EXPIRE_PASSWD; + } + else + { + puserInfo->usri1_flags &= ~UF_DONT_EXPIRE_PASSWD; + } + + if (SCAU_PASSWD_CANT_CHANGE & iAttributes) + { + puserInfo->usri1_flags |= UF_PASSWD_CANT_CHANGE; + } + else + { + puserInfo->usri1_flags &= ~UF_PASSWD_CANT_CHANGE; + } + + if (SCAU_DISABLE_ACCOUNT & iAttributes) + { + puserInfo->usri1_flags |= UF_ACCOUNTDISABLE; + } + else + { + puserInfo->usri1_flags &= ~UF_ACCOUNTDISABLE; + } + + if (SCAU_PASSWD_CHANGE_REQD_ON_LOGIN & iAttributes) // TODO: for some reason this doesn't work + { + puserInfo->usri1_flags |= UF_PASSWORD_EXPIRED; + } + else + { + puserInfo->usri1_flags &= ~UF_PASSWORD_EXPIRED; + } +} + + +static HRESULT RemoveUserInternal( + LPWSTR wzGroupCaData, + LPWSTR wzDomain, + LPWSTR wzName, + int iAttributes +) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + LPWSTR pwz = NULL; + LPWSTR pwzGroup = NULL; + LPWSTR pwzGroupDomain = NULL; + LPCWSTR wz = NULL; + PDOMAIN_CONTROLLER_INFOW pDomainControllerInfo = NULL; + + // + // Remove the logon as service privilege. + // + if (SCAU_ALLOW_LOGON_AS_SERVICE & iAttributes) + { + hr = ModifyUserLocalServiceRight(wzDomain, wzName, FALSE); + if (FAILED(hr)) + { + WcaLogError(hr, "Failed to remove logon as service right from user, continuing..."); + hr = S_OK; + } + } + + if (SCAU_ALLOW_LOGON_AS_BATCH & iAttributes) + { + hr = ModifyUserLocalBatchRight(wzDomain, wzName, FALSE); + if (FAILED(hr)) + { + WcaLogError(hr, "Failed to remove logon as batch job right from user, continuing..."); + hr = S_OK; + } + } + + // + // Remove the User Account if the user was created by us. + // + if (!(SCAU_DONT_CREATE_USER & iAttributes)) + { + if (wzDomain && *wzDomain) + { + er = ::DsGetDcNameW(NULL, (LPCWSTR)wzDomain, NULL, NULL, NULL, &pDomainControllerInfo); + if (RPC_S_SERVER_UNAVAILABLE == er) + { + // MSDN says, if we get the above error code, try again with the "DS_FORCE_REDISCOVERY" flag + er = ::DsGetDcNameW(NULL, (LPCWSTR)wzDomain, NULL, NULL, DS_FORCE_REDISCOVERY, &pDomainControllerInfo); + } + if (ERROR_SUCCESS == er) + { + wz = pDomainControllerInfo->DomainControllerName + 2; //Add 2 so that we don't get the \\ prefix + } + else + { + wz = wzDomain; + } + } + + er = ::NetUserDel(wz, wzName); + if (NERR_UserNotFound == er) + { + er = NERR_Success; + } + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "failed to delete user account: %ls", wzName); + } + else + { + // + // Remove the user from the groups + // + pwz = wzGroupCaData; + while (S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzGroup))) + { + hr = WcaReadStringFromCaData(&pwz, &pwzGroupDomain); + + if (FAILED(hr)) + { + WcaLogError(hr, "failed to get domain for group: %ls, continuing anyway.", pwzGroup); + } + else + { + hr = RemoveUserFromGroup(wzName, wzDomain, pwzGroup, pwzGroupDomain); + if (FAILED(hr)) + { + WcaLogError(hr, "failed to remove user: %ls from group %ls, continuing anyway.", wzName, pwzGroup); + } + } + } + + if (E_NOMOREITEMS == hr) // if there are no more items, all is well + { + hr = S_OK; + } + + ExitOnFailure(hr, "failed to get next group from which to remove user:%ls", wzName); + } + +LExit: + if (pDomainControllerInfo) + { + ::NetApiBufferFree(static_cast(pDomainControllerInfo)); + } + + return hr; +} + + +/******************************************************************** + CreateUser - CUSTOM ACTION ENTRY POINT for creating users + + Input: deferred CustomActionData - UserName\tDomain\tPassword\tAttributes\tGroupName\tDomain\tGroupName\tDomain... + * *****************************************************************/ +extern "C" UINT __stdcall CreateUser( + __in MSIHANDLE hInstall + ) +{ + //AssertSz(0, "Debug CreateUser"); + + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + LPWSTR pwzData = NULL; + LPWSTR pwz = NULL; + LPWSTR pwzName = NULL; + LPWSTR pwzDomain = NULL; + LPWSTR pwzScriptKey = NULL; + LPWSTR pwzPassword = NULL; + LPWSTR pwzGroup = NULL; + LPWSTR pwzGroupDomain = NULL; + PDOMAIN_CONTROLLER_INFOW pDomainControllerInfo = NULL; + int iAttributes = 0; + BOOL fInitializedCom = FALSE; + + WCA_CASCRIPT_HANDLE hRollbackScript = NULL; + int iOriginalAttributes = 0; + int iRollbackAttributes = 0; + + USER_INFO_1 userInfo; + USER_INFO_1* puserInfo = NULL; + DWORD dw; + LPCWSTR wz = NULL; + + hr = WcaInitialize(hInstall, "CreateUser"); + ExitOnFailure(hr, "failed to initialize"); + + hr = ::CoInitialize(NULL); + ExitOnFailure(hr, "failed to initialize COM"); + fInitializedCom = TRUE; + + hr = WcaGetProperty( L"CustomActionData", &pwzData); + ExitOnFailure(hr, "failed to get CustomActionData"); + + WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); + + // + // Read in the CustomActionData + // + pwz = pwzData; + hr = WcaReadStringFromCaData(&pwz, &pwzName); + ExitOnFailure(hr, "failed to read user name from custom action data"); + + hr = WcaReadStringFromCaData(&pwz, &pwzDomain); + ExitOnFailure(hr, "failed to read domain from custom action data"); + + hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); + ExitOnFailure(hr, "failed to read attributes from custom action data"); + + hr = WcaReadStringFromCaData(&pwz, &pwzScriptKey); + ExitOnFailure(hr, "failed to read encoding key from custom action data"); + + hr = WcaReadStringFromCaData(&pwz, &pwzPassword); + ExitOnFailure(hr, "failed to read password from custom action data"); + + // There is no rollback scheduled if the key is empty. + // Best effort to get original configuration and save it in the script so rollback can restore it. + if (*pwzScriptKey) + { + hr = WcaCaScriptCreate(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, FALSE, &hRollbackScript); + ExitOnFailure(hr, "Failed to open rollback CustomAction script."); + + iRollbackAttributes = 0; + hr = GetExistingUserRightsAssignments(pwzDomain, pwzName, &iOriginalAttributes); + if (FAILED(hr)) + { + WcaLogError(hr, "failed to get existing user rights: %ls, continuing anyway.", pwzName); + } + else + { + if (!(SCAU_ALLOW_LOGON_AS_SERVICE & iOriginalAttributes) && (SCAU_ALLOW_LOGON_AS_SERVICE & iAttributes)) + { + iRollbackAttributes |= SCAU_ALLOW_LOGON_AS_SERVICE; + } + if (!(SCAU_ALLOW_LOGON_AS_BATCH & iOriginalAttributes) && (SCAU_ALLOW_LOGON_AS_BATCH & iAttributes)) + { + iRollbackAttributes |= SCAU_ALLOW_LOGON_AS_BATCH; + } + } + + hr = WcaCaScriptWriteNumber(hRollbackScript, iRollbackAttributes); + ExitOnFailure(hr, "Failed to add data to rollback script."); + + // Nudge the system to get all our rollback data written to disk. + WcaCaScriptFlush(hRollbackScript); + } + + if (!(SCAU_DONT_CREATE_USER & iAttributes)) + { + ::ZeroMemory(&userInfo, sizeof(USER_INFO_1)); + userInfo.usri1_name = pwzName; + userInfo.usri1_priv = USER_PRIV_USER; + userInfo.usri1_flags = UF_SCRIPT; + userInfo.usri1_home_dir = NULL; + userInfo.usri1_comment = NULL; + userInfo.usri1_script_path = NULL; + + SetUserPasswordAndAttributes(&userInfo, pwzPassword, iAttributes); + + // + // Create the User + // + if (pwzDomain && *pwzDomain) + { + er = ::DsGetDcNameW( NULL, (LPCWSTR)pwzDomain, NULL, NULL, NULL, &pDomainControllerInfo ); + if (RPC_S_SERVER_UNAVAILABLE == er) + { + // MSDN says, if we get the above error code, try again with the "DS_FORCE_REDISCOVERY" flag + er = ::DsGetDcNameW( NULL, (LPCWSTR)pwzDomain, NULL, NULL, DS_FORCE_REDISCOVERY, &pDomainControllerInfo ); + } + if (ERROR_SUCCESS == er) + { + wz = pDomainControllerInfo->DomainControllerName + 2; //Add 2 so that we don't get the \\ prefix + } + else + { + wz = pwzDomain; + } + } + + er = ::NetUserAdd(wz, 1, reinterpret_cast(&userInfo), &dw); + if (NERR_UserExists == er) + { + if (SCAU_UPDATE_IF_EXISTS & iAttributes) + { + er = ::NetUserGetInfo(wz, pwzName, 1, reinterpret_cast(&puserInfo)); + if (NERR_Success == er) + { + // Change the existing user's password and attributes again then try + // to update user with this new data + SetUserPasswordAndAttributes(puserInfo, pwzPassword, iAttributes); + + er = ::NetUserSetInfo(wz, pwzName, 1, reinterpret_cast(puserInfo), &dw); + } + } + else if (!(SCAU_FAIL_IF_EXISTS & iAttributes)) + { + er = NERR_Success; + } + } + else if (NERR_PasswordTooShort == er || NERR_PasswordTooLong == er) + { + MessageExitOnFailure(hr = HRESULT_FROM_WIN32(er), msierrUSRFailedUserCreatePswd, "failed to create user: %ls due to invalid password.", pwzName); + } + MessageExitOnFailure(hr = HRESULT_FROM_WIN32(er), msierrUSRFailedUserCreate, "failed to create user: %ls", pwzName); + } + + if (SCAU_ALLOW_LOGON_AS_SERVICE & iAttributes) + { + hr = ModifyUserLocalServiceRight(pwzDomain, pwzName, TRUE); + MessageExitOnFailure(hr, msierrUSRFailedGrantLogonAsService, "Failed to grant logon as service rights to user: %ls", pwzName); + } + + if (SCAU_ALLOW_LOGON_AS_BATCH & iAttributes) + { + hr = ModifyUserLocalBatchRight(pwzDomain, pwzName, TRUE); + MessageExitOnFailure(hr, msierrUSRFailedGrantLogonAsService, "Failed to grant logon as batch job rights to user: %ls", pwzName); + } + + // + // Add the users to groups + // + while (S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzGroup))) + { + hr = WcaReadStringFromCaData(&pwz, &pwzGroupDomain); + ExitOnFailure(hr, "failed to get domain for group: %ls", pwzGroup); + + hr = AddUserToGroup(pwzName, pwzDomain, pwzGroup, pwzGroupDomain); + MessageExitOnFailure(hr, msierrUSRFailedUserGroupAdd, "failed to add user: %ls to group %ls", pwzName, pwzGroup); + } + if (E_NOMOREITEMS == hr) // if there are no more items, all is well + { + hr = S_OK; + } + ExitOnFailure(hr, "failed to get next group in which to include user:%ls", pwzName); + +LExit: + WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_PRESERVE); + + if (puserInfo) + { + ::NetApiBufferFree((LPVOID)puserInfo); + } + + if (pDomainControllerInfo) + { + ::NetApiBufferFree((LPVOID)pDomainControllerInfo); + } + + ReleaseStr(pwzData); + ReleaseStr(pwzName); + ReleaseStr(pwzDomain); + ReleaseStr(pwzScriptKey); + ReleaseStr(pwzPassword); + ReleaseStr(pwzGroup); + ReleaseStr(pwzGroupDomain); + + if (fInitializedCom) + { + ::CoUninitialize(); + } + + if (SCAU_NON_VITAL & iAttributes) + { + er = ERROR_SUCCESS; + } + else if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + + return WcaFinalize(er); +} + + +/******************************************************************** + CreateUserRollback - CUSTOM ACTION ENTRY POINT for CreateUser rollback + + * *****************************************************************/ +extern "C" UINT __stdcall CreateUserRollback( + MSIHANDLE hInstall +) +{ + //AssertSz(0, "Debug CreateUserRollback"); + + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + LPWSTR pwzData = NULL; + LPWSTR pwz = NULL; + LPWSTR pwzName = NULL; + LPWSTR pwzDomain = NULL; + LPWSTR pwzScriptKey = NULL; + int iAttributes = 0; + BOOL fInitializedCom = FALSE; + + WCA_CASCRIPT_HANDLE hRollbackScript = NULL; + LPWSTR pwzRollbackData = NULL; + int iOriginalAttributes = 0; + + hr = WcaInitialize(hInstall, "CreateUserRollback"); + ExitOnFailure(hr, "failed to initialize"); + + hr = ::CoInitialize(NULL); + ExitOnFailure(hr, "failed to initialize COM"); + fInitializedCom = TRUE; + + hr = WcaGetProperty(L"CustomActionData", &pwzData); + ExitOnFailure(hr, "failed to get CustomActionData"); + + WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); + + // + // Read in the CustomActionData + // + pwz = pwzData; + hr = WcaReadStringFromCaData(&pwz, &pwzScriptKey); + ExitOnFailure(hr, "failed to read encoding key from custom action data"); + + hr = WcaReadStringFromCaData(&pwz, &pwzName); + ExitOnFailure(hr, "failed to read name from custom action data"); + + hr = WcaReadStringFromCaData(&pwz, &pwzDomain); + ExitOnFailure(hr, "failed to read domain from custom action data"); + + hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); + ExitOnFailure(hr, "failed to read attributes from custom action data"); + + // Best effort to read original configuration from CreateUser. + hr = WcaCaScriptOpen(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, &hRollbackScript); + if (FAILED(hr)) + { + WcaLogError(hr, "Failed to open rollback CustomAction script, continuing anyway."); + } + else + { + hr = WcaCaScriptReadAsCustomActionData(hRollbackScript, &pwzRollbackData); + if (FAILED(hr)) + { + WcaLogError(hr, "Failed to read rollback script into CustomAction data, continuing anyway."); + } + else + { + WcaLog(LOGMSG_TRACEONLY, "Rollback Data: %ls", pwzRollbackData); + + pwz = pwzRollbackData; + hr = WcaReadIntegerFromCaData(&pwz, &iOriginalAttributes); + if (FAILED(hr)) + { + WcaLogError(hr, "failed to read attributes from rollback data, continuing anyway"); + } + else + { + iAttributes |= iOriginalAttributes; + } + } + } + + hr = RemoveUserInternal(pwz, pwzDomain, pwzName, iAttributes); + +LExit: + WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_DELETE); + + ReleaseStr(pwzData); + ReleaseStr(pwzName); + ReleaseStr(pwzDomain); + ReleaseStr(pwzScriptKey); + ReleaseStr(pwzRollbackData); + + if (fInitializedCom) + { + ::CoUninitialize(); + } + + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + + return WcaFinalize(er); +} + + +/******************************************************************** + RemoveUser - CUSTOM ACTION ENTRY POINT for removing users + + Input: deferred CustomActionData - Name\tDomain + * *****************************************************************/ +extern "C" UINT __stdcall RemoveUser( + MSIHANDLE hInstall +) +{ + //AssertSz(0, "Debug RemoveUser"); + + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + LPWSTR pwzData = NULL; + LPWSTR pwz = NULL; + LPWSTR pwzName = NULL; + LPWSTR pwzDomain = NULL; + int iAttributes = 0; + BOOL fInitializedCom = FALSE; + + hr = WcaInitialize(hInstall, "RemoveUser"); + ExitOnFailure(hr, "failed to initialize"); + + hr = ::CoInitialize(NULL); + ExitOnFailure(hr, "failed to initialize COM"); + fInitializedCom = TRUE; + + hr = WcaGetProperty(L"CustomActionData", &pwzData); + ExitOnFailure(hr, "failed to get CustomActionData"); + + WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); + + // + // Read in the CustomActionData + // + pwz = pwzData; + hr = WcaReadStringFromCaData(&pwz, &pwzName); + ExitOnFailure(hr, "failed to read name from custom action data"); + + hr = WcaReadStringFromCaData(&pwz, &pwzDomain); + ExitOnFailure(hr, "failed to read domain from custom action data"); + + hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); + ExitOnFailure(hr, "failed to read attributes from custom action data"); + + hr = RemoveUserInternal(pwz, pwzDomain, pwzName, iAttributes); + +LExit: + ReleaseStr(pwzData); + ReleaseStr(pwzName); + ReleaseStr(pwzDomain); + + if (fInitializedCom) + { + ::CoUninitialize(); + } + + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + + return WcaFinalize(er); +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + +LPCWSTR vcsPerfmonManifestQuery = L"SELECT `Component_`, `File`, `ResourceFileDirectory` FROM `Wix4PerfmonManifest`"; +LPCWSTR vcsEventManifestQuery = L"SELECT `Component_`, `File` FROM `Wix4EventManifest`"; +enum ePerfMonManifestQuery { pfmComponent = 1, pfmFile, pfmResourceFileDir }; +enum eEventManifestQuery { emComponent = 1, emFile}; + +BOOL IsVistaOrAbove() +{ + OSVERSIONINFO osvi; + ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + #pragma warning(suppress: 4996) //TODO: use non-deprecated function to check OS version + if (!::GetVersionEx(&osvi)) + { + return false; + } + return osvi.dwMajorVersion >= 6; +} + + +/******************************************************************** + ConfigurePerfmonManifestRegister - CUSTOM ACTION ENTRY POINT for scheduling + Perfmon counter manifest registering + +********************************************************************/ +extern "C" UINT __stdcall ConfigurePerfmonManifestRegister( + __in MSIHANDLE hInstall + ) +{ + HRESULT hr; + UINT er = ERROR_SUCCESS; + + PMSIHANDLE hView, hRec; + LPWSTR pwzData = NULL, pwzResourceFilePath = NULL, pwzFile = NULL, pwzCommand = NULL; + INSTALLSTATE isInstalled, isAction; + + hr = WcaInitialize(hInstall, "ConfigurePerfmonManifestReg"); + ExitOnFailure(hr, "Failed to initialize"); + + if (!IsVistaOrAbove()) + { + WcaLog(LOGMSG_VERBOSE, "Skipping ConfigurePerfmonManifestRegister() because the target system does not support perfmon manifest"); + ExitFunction1(hr = S_FALSE); + } + // check to see if necessary tables are specified + if (S_OK != WcaTableExists(L"Wix4PerfmonManifest")) + { + WcaLog(LOGMSG_VERBOSE, "Skipping ConfigurePerfmonManifestRegister() because Wix4PerfmonManifest table not present"); + ExitFunction1(hr = S_FALSE); + } + + hr = WcaOpenExecuteView(vcsPerfmonManifestQuery, &hView); + ExitOnFailure(hr, "failed to open view on PerfMonManifest table"); + while ((hr = WcaFetchRecord(hView, &hRec)) == S_OK) + { + // get component install state + hr = WcaGetRecordString(hRec, pfmComponent, &pwzData); + ExitOnFailure(hr, "failed to get Component for PerfMonManifest"); + er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "failed to get Component state for PerfMonManifest"); + if (!WcaIsInstalling(isInstalled, isAction)) + { + continue; + } + + hr = WcaGetRecordFormattedString(hRec, pfmFile, &pwzFile); + ExitOnFailure(hr, "failed to get File for PerfMonManifest"); + + hr = WcaGetRecordFormattedString(hRec, pfmResourceFileDir, &pwzResourceFilePath); + ExitOnFailure(hr, "failed to get ApplicationIdentity for PerfMonManifest"); + size_t iResourcePath = lstrlenW(pwzResourceFilePath); + if ( iResourcePath > 0 && *(pwzResourceFilePath + iResourcePath -1) == L'\\') + *(pwzResourceFilePath + iResourcePath -1) = 0; //remove the trailing '\' + + hr = StrAllocFormatted(&pwzCommand, L"\"unlodctr.exe\" /m:\"%s\"", pwzFile); + ExitOnFailure(hr, "failed to copy string in PerfMonManifest"); + + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackRegisterPerfmonManifest"), pwzCommand, COST_PERFMONMANIFEST_UNREGISTER); + ExitOnFailure(hr, "failed to schedule RollbackRegisterPerfmonManifest action"); + + if ( *pwzResourceFilePath ) + { + hr = StrAllocFormatted(&pwzCommand, L"\"lodctr.exe\" /m:\"%s\" \"%s\"", pwzFile, pwzResourceFilePath); + ExitOnFailure(hr, "failed to copy string in PerfMonManifest"); + } + else + { + hr = StrAllocFormatted(&pwzCommand, L"\"lodctr.exe\" /m:\"%s\"", pwzFile); + ExitOnFailure(hr, "failed to copy string in PerfMonManifest"); + } + + WcaLog(LOGMSG_VERBOSE, "RegisterPerfmonManifest's CustomActionData: '%ls'", pwzCommand); + + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RegisterPerfmonManifest"), pwzCommand, COST_PERFMONMANIFEST_REGISTER); + ExitOnFailure(hr, "failed to schedule RegisterPerfmonManifest action"); + } + + if (hr == E_NOMOREITEMS) + { + hr = S_OK; + } + ExitOnFailure(hr, "Failure while processing PerfMonManifest"); + + hr = S_OK; + +LExit: + ReleaseStr(pwzData); + ReleaseStr(pwzResourceFilePath); + ReleaseStr(pwzFile); + ReleaseStr(pwzCommand); + + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + + +/******************************************************************** + ConfigurePerfmonUninstall - CUSTOM ACTION ENTRY POINT for uninstalling + Perfmon counters + +********************************************************************/ +extern "C" UINT __stdcall ConfigurePerfmonManifestUnregister( + __in MSIHANDLE hInstall + ) +{ + HRESULT hr; + UINT er = ERROR_SUCCESS; + + PMSIHANDLE hView, hRec; + LPWSTR pwzData = NULL, pwzResourceFilePath = NULL, pwzFile = NULL, pwzCommand = NULL; + INSTALLSTATE isInstalled, isAction; + + hr = WcaInitialize(hInstall, "ConfigurePerfmonManifestUnreg"); + ExitOnFailure(hr, "Failed to initialize"); + + if (!IsVistaOrAbove()) + { + WcaLog(LOGMSG_VERBOSE, "Skipping ConfigurePerfmonManifestUnregister() because the target system does not support perfmon manifest"); + ExitFunction1(hr = S_FALSE); + } + // check to see if necessary tables are specified + if (WcaTableExists(L"Wix4PerfmonManifest") != S_OK) + { + WcaLog(LOGMSG_VERBOSE, "Skipping ConfigurePerfmonManifestUnregister() because Wix4PerfmonManifest table not present"); + ExitFunction1(hr = S_FALSE); + } + + hr = WcaOpenExecuteView(vcsPerfmonManifestQuery, &hView); + ExitOnFailure(hr, "failed to open view on Wix4PerfmonManifest table"); + while ((hr = WcaFetchRecord(hView, &hRec)) == S_OK) + { + // get component install state + hr = WcaGetRecordString(hRec, pfmComponent, &pwzData); + ExitOnFailure(hr, "failed to get Component for Wix4PerfmonManifest"); + er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "failed to get Component state for Wix4PerfmonManifest"); + if (!WcaIsUninstalling(isInstalled, isAction)) + { + continue; + } + + hr = WcaGetRecordFormattedString(hRec, pfmFile, &pwzFile); + ExitOnFailure(hr, "failed to get File for Wix4PerfmonManifest"); + + hr = WcaGetRecordFormattedString(hRec, pfmResourceFileDir, &pwzResourceFilePath); + ExitOnFailure(hr, "failed to get ApplicationIdentity for Wix4PerfmonManifest"); + size_t iResourcePath = lstrlenW(pwzResourceFilePath); + if ( iResourcePath > 0 && *(pwzResourceFilePath + iResourcePath -1) == L'\\') + *(pwzResourceFilePath + iResourcePath -1) = 0; //remove the trailing '\' + + hr = StrAllocFormatted(&pwzCommand, L"\"lodctr.exe\" /m:\"%s\" \"%s\"", pwzFile, pwzResourceFilePath); + ExitOnFailure(hr, "failed to copy string in Wix4PerfmonManifest"); + + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackUnregisterPerfmonManifest"), pwzCommand, COST_PERFMONMANIFEST_REGISTER); + ExitOnFailure(hr, "failed to schedule RollbackUnregisterPerfmonManifest action"); + + hr = StrAllocFormatted(&pwzCommand, L"\"unlodctr.exe\" /m:\"%s\"", pwzFile); + ExitOnFailure(hr, "failed to copy string in PerfMonManifest"); + + WcaLog(LOGMSG_VERBOSE, "UnRegisterPerfmonManifest's CustomActionData: '%ls'", pwzCommand); + + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"UnregisterPerfmonManifest"), pwzCommand, COST_PERFMONMANIFEST_UNREGISTER); + ExitOnFailure(hr, "failed to schedule UnregisterPerfmonManifest action"); + } + + if (hr == E_NOMOREITEMS) + { + hr = S_OK; + } + ExitOnFailure(hr, "Failure while processing PerfMonManifest"); + + hr = S_OK; + +LExit: + ReleaseStr(pwzData); + ReleaseStr(pwzResourceFilePath); + ReleaseStr(pwzFile); + ReleaseStr(pwzCommand); + + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + +/******************************************************************** + ConfigureEventManifestRegister - CUSTOM ACTION ENTRY POINT for scheduling + Event manifest registering + +********************************************************************/ +extern "C" UINT __stdcall ConfigureEventManifestRegister( + __in MSIHANDLE hInstall + ) +{ + HRESULT hr; + UINT er = ERROR_SUCCESS; + + PMSIHANDLE hView, hRec; + LPWSTR pwzData = NULL, pwzFile = NULL, pwzCommand = NULL; + INSTALLSTATE isInstalled, isAction; + + hr = WcaInitialize(hInstall, "ConfigureEventManifestReg"); + ExitOnFailure(hr, "Failed to initialize"); + + if (!IsVistaOrAbove()) + { + WcaLog(LOGMSG_VERBOSE, "Skipping ConfigureEventManifestRegister() because the target system does not support event manifest"); + ExitFunction1(hr = S_FALSE); + } + // check to see if necessary tables are specified + if (S_OK != WcaTableExists(L"Wix4EventManifest")) + { + WcaLog(LOGMSG_VERBOSE, "Skipping ConfigureEventManifestRegister() because Wix4EventManifest table not present"); + ExitFunction1(hr = S_FALSE); + } + + hr = WcaOpenExecuteView(vcsEventManifestQuery, &hView); + ExitOnFailure(hr, "failed to open view on Wix4EventManifest table"); + while ((hr = WcaFetchRecord(hView, &hRec)) == S_OK) + { + // get component install state + hr = WcaGetRecordString(hRec, emComponent, &pwzData); + ExitOnFailure(hr, "failed to get Component for Wix4EventManifest"); + er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "failed to get Component state for Wix4EventManifest"); + if (!WcaIsInstalling(isInstalled, isAction)) + { + continue; + } + + hr = WcaGetRecordFormattedString(hRec, emFile, &pwzFile); + ExitOnFailure(hr, "failed to get File for Wix4EventManifest"); + + hr = StrAllocFormatted(&pwzCommand, L"\"wevtutil.exe\" um \"%s\"", pwzFile); + ExitOnFailure(hr, "failed to copy string in Wix4EventManifest"); + + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackRegisterEventManifest"), pwzCommand, COST_PERFMONMANIFEST_UNREGISTER); + ExitOnFailure(hr, "failed to schedule RollbackRegisterEventManifest action"); + + hr = StrAllocFormatted(&pwzCommand, L"\"wevtutil.exe\" im \"%s\"", pwzFile); + ExitOnFailure(hr, "failed to copy string in Wix4EventManifest"); + WcaLog(LOGMSG_VERBOSE, "RegisterEventManifest's CustomActionData: '%ls'", pwzCommand); + + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RegisterEventManifest"), pwzCommand, COST_EVENTMANIFEST_REGISTER); + ExitOnFailure(hr, "failed to schedule RegisterEventManifest action"); + } + + if (hr == E_NOMOREITEMS) + { + hr = S_OK; + } + ExitOnFailure(hr, "Failure while processing Wix4EventManifest"); + + hr = S_OK; + +LExit: + ReleaseStr(pwzData); + ReleaseStr(pwzFile); + ReleaseStr(pwzCommand); + + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + + + +/******************************************************************** + ConfigureEventManifestRegister - CUSTOM ACTION ENTRY POINT for scheduling + Event manifest registering + +********************************************************************/ +extern "C" UINT __stdcall ConfigureEventManifestUnregister( + __in MSIHANDLE hInstall + ) +{ + HRESULT hr; + UINT er = ERROR_SUCCESS; + + PMSIHANDLE hView, hRec; + LPWSTR pwzData = NULL, pwzFile = NULL, pwzCommand = NULL; + INSTALLSTATE isInstalled, isAction; + + hr = WcaInitialize(hInstall, "ConfigureEventManifestUnreg"); + ExitOnFailure(hr, "Failed to initialize"); + + if (!IsVistaOrAbove()) + { + WcaLog(LOGMSG_VERBOSE, "Skipping ConfigureEventManifestUnregister() because the target system does not support event manifest"); + ExitFunction1(hr = S_FALSE); + } + // check to see if necessary tables are specified + if (S_OK != WcaTableExists(L"Wix4EventManifest")) + { + WcaLog(LOGMSG_VERBOSE, "Skipping ConfigureEventManifestUnregister() because Wix4EventManifest table not present"); + ExitFunction1(hr = S_FALSE); + } + + hr = WcaOpenExecuteView(vcsEventManifestQuery, &hView); + ExitOnFailure(hr, "failed to open view on Wix4EventManifest table"); + while ((hr = WcaFetchRecord(hView, &hRec)) == S_OK) + { + // get component install state + hr = WcaGetRecordString(hRec, emComponent, &pwzData); + ExitOnFailure(hr, "failed to get Component for Wix4EventManifest"); + er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "failed to get Component state for Wix4EventManifest"); + + // nothing to do on an install + // schedule the rollback action when reinstalling to re-register pre-patch manifest + if (!WcaIsUninstalling(isInstalled, isAction) && !WcaIsReInstalling(isInstalled, isAction)) + { + continue; + } + + hr = WcaGetRecordFormattedString(hRec, emFile, &pwzFile); + ExitOnFailure(hr, "failed to get File for Wix4EventManifest"); + + hr = StrAllocFormatted(&pwzCommand, L"\"wevtutil.exe\" im \"%s\"", pwzFile); + ExitOnFailure(hr, "failed to copy string in Wix4EventManifest"); + + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackUnregisterEventManifest"), pwzCommand, COST_PERFMONMANIFEST_REGISTER); + ExitOnFailure(hr, "failed to schedule RollbackUnregisterEventManifest action"); + + // no need to uninstall on a repair/patch. Register action will re-register and update the manifest. + if (!WcaIsReInstalling(isInstalled, isAction)) + { + hr = StrAllocFormatted(&pwzCommand, L"\"wevtutil.exe\" um \"%s\"", pwzFile); + ExitOnFailure(hr, "failed to copy string in Wix4EventManifest"); + WcaLog(LOGMSG_VERBOSE, "UnregisterEventManifest's CustomActionData: '%ls'", pwzCommand); + + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"UnregisterEventManifest"), pwzCommand, COST_PERFMONMANIFEST_UNREGISTER); + ExitOnFailure(hr, "failed to schedule UnregisterEventManifest action"); + } + } + + if (hr == E_NOMOREITEMS) + { + hr = S_OK; + } + ExitOnFailure(hr, "Failure while processing Wix4EventManifest"); + + hr = S_OK; + +LExit: + ReleaseStr(pwzData); + ReleaseStr(pwzFile); + ReleaseStr(pwzCommand); + + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + +LPCWSTR vcsPerfCounterDataQuery = L"SELECT `Wix4PerformanceCategory`, `Component_`, `Name`, `IniData`, `ConstantData` FROM `Wix4PerformanceCategory`"; +enum ePerfCounterDataQuery { pcdqId = 1, pcdqComponent, pcdqName, pcdqIniData, pcdqConstantData }; + +LPCWSTR vcsPerfMonQuery = L"SELECT `Component_`, `File`, `Name` FROM `Wix4Perfmon`"; +enum ePerfMonQuery { pmqComponent = 1, pmqFile, pmqName }; + + +static HRESULT ProcessPerformanceCategory( + __in MSIHANDLE hInstall, + __in BOOL fInstall + ); + + +/******************************************************************** + InstallPerfCounterData - CUSTOM ACTION ENTRY POINT for installing + Performance Counters. + +********************************************************************/ +extern "C" UINT __stdcall InstallPerfCounterData( + __in MSIHANDLE hInstall + ) +{ + // AssertSz(FALSE, "debug InstallPerfCounterData{}"); + HRESULT hr; + UINT er = ERROR_SUCCESS; + + hr = WcaInitialize(hInstall, "InstallPerfCounterData"); + ExitOnFailure(hr, "Failed to initialize InstallPerfCounterData."); + + hr = ProcessPerformanceCategory(hInstall, TRUE); + MessageExitOnFailure(hr, msierrInstallPerfCounterData, "Failed to process Wix4PerformanceCategory table."); + +LExit: + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + + +/******************************************************************** + UninstallPerfCounterData - CUSTOM ACTION ENTRY POINT for installing + Performance Counters. + +********************************************************************/ +extern "C" UINT __stdcall UninstallPerfCounterData( + __in MSIHANDLE hInstall + ) +{ + // AssertSz(FALSE, "debug UninstallPerfCounterData{}"); + HRESULT hr; + UINT er = ERROR_SUCCESS; + + hr = WcaInitialize(hInstall, "UninstallPerfCounterData"); + ExitOnFailure(hr, "Failed to initialize UninstallPerfCounterData."); + + hr = ProcessPerformanceCategory(hInstall, FALSE); + MessageExitOnFailure(hr, msierrUninstallPerfCounterData, "Failed to process Wix4PerformanceCategory table."); + +LExit: + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + + +/******************************************************************** + RegisterPerfmon - CUSTOM ACTION ENTRY POINT for installing Perfmon counters + +********************************************************************/ +extern "C" UINT __stdcall ConfigurePerfmonInstall( + __in MSIHANDLE hInstall + ) +{ +// Assert(FALSE); + HRESULT hr; + UINT er = ERROR_SUCCESS; + + PMSIHANDLE hView, hRec; + LPWSTR pwzData = NULL, pwzName = NULL, pwzFile = NULL; + INSTALLSTATE isInstalled, isAction; + + hr = WcaInitialize(hInstall, "ConfigurePerfmonInstall"); + ExitOnFailure(hr, "Failed to initialize"); + + // check to see if necessary tables are specified + if (S_OK != WcaTableExists(L"Wix4Perfmon")) + { + WcaLog(LOGMSG_VERBOSE, "Skipping RegisterPerfmon() because Wix4Perfmon table not present"); + ExitFunction1(hr = S_FALSE); + } + + hr = WcaOpenExecuteView(vcsPerfMonQuery, &hView); + ExitOnFailure(hr, "failed to open view on PerfMon table"); + while ((hr = WcaFetchRecord(hView, &hRec)) == S_OK) + { + // get component install state + hr = WcaGetRecordString(hRec, pmqComponent, &pwzData); + ExitOnFailure(hr, "failed to get Component for PerfMon"); + er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "failed to get Component state for PerfMon"); + if (!WcaIsInstalling(isInstalled, isAction)) + { + continue; + } + + hr = WcaGetRecordString(hRec, pmqName, &pwzName); + ExitOnFailure(hr, "failed to get Name for PerfMon"); + + hr = WcaGetRecordFormattedString(hRec, pmqFile, &pwzFile); + ExitOnFailure(hr, "failed to get File for PerfMon"); + + WcaLog(LOGMSG_VERBOSE, "ConfigurePerfmonInstall's CustomActionData: '%ls', '%ls'", pwzName, pwzFile); + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RegisterPerfmon"), pwzFile, COST_PERFMON_REGISTER); + ExitOnFailure(hr, "failed to schedule RegisterPerfmon action"); + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackRegisterPerfmon"), pwzName, COST_PERFMON_UNREGISTER); + ExitOnFailure(hr, "failed to schedule RollbackRegisterPerfmon action"); + } + + if (hr == E_NOMOREITEMS) + { + hr = S_OK; + } + ExitOnFailure(hr, "Failure while processing PerfMon"); + + hr = S_OK; + +LExit: + ReleaseStr(pwzData); + ReleaseStr(pwzName); + ReleaseStr(pwzFile); + + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + + +/******************************************************************** + ConfigurePerfmonUninstall - CUSTOM ACTION ENTRY POINT for uninstalling + Perfmon counters + +********************************************************************/ +extern "C" UINT __stdcall ConfigurePerfmonUninstall( + __in MSIHANDLE hInstall + ) +{ +// Assert(FALSE); + HRESULT hr; + UINT er = ERROR_SUCCESS; + + PMSIHANDLE hView, hRec; + LPWSTR pwzData = NULL, pwzName = NULL, pwzFile = NULL; + INSTALLSTATE isInstalled, isAction; + + hr = WcaInitialize(hInstall, "ConfigurePerfmonUninstall"); + ExitOnFailure(hr, "Failed to initialize"); + + // check to see if necessary tables are specified + if (WcaTableExists(L"Wix4Perfmon") != S_OK) + { + WcaLog(LOGMSG_VERBOSE, "Skipping UnregisterPerfmon() because Wix4Perfmon table not present"); + ExitFunction1(hr = S_FALSE); + } + + hr = WcaOpenExecuteView(vcsPerfMonQuery, &hView); + ExitOnFailure(hr, "failed to open view on PerfMon table"); + while ((hr = WcaFetchRecord(hView, &hRec)) == S_OK) + { + // get component install state + hr = WcaGetRecordString(hRec, pmqComponent, &pwzData); + ExitOnFailure(hr, "failed to get Component for PerfMon"); + er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "failed to get Component state for PerfMon"); + if (!WcaIsUninstalling(isInstalled, isAction)) + { + continue; + } + + hr = WcaGetRecordString(hRec, pmqName, &pwzName); + ExitOnFailure(hr, "failed to get Name for PerfMon"); + + hr = WcaGetRecordFormattedString(hRec, pmqFile, &pwzFile); + ExitOnFailure(hr, "failed to get File for PerfMon"); + + WcaLog(LOGMSG_VERBOSE, "ConfigurePerfmonUninstall's CustomActionData: '%ls', '%ls'", pwzName, pwzFile); + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"UnregisterPerfmon"), pwzName, COST_PERFMON_UNREGISTER); + ExitOnFailure(hr, "failed to schedule UnregisterPerfmon action"); + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackUnregisterPerfmon"), pwzFile, COST_PERFMON_REGISTER); + ExitOnFailure(hr, "failed to schedule RollbackUnregisterPerfmon action"); + } + + if (hr == E_NOMOREITEMS) + { + hr = S_OK; + } + ExitOnFailure(hr, "Failure while processing PerfMon"); + + hr = S_OK; + +LExit: + ReleaseStr(pwzData); + ReleaseStr(pwzName); + ReleaseStr(pwzFile); + + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + + + +static HRESULT ProcessPerformanceCategory( + __in MSIHANDLE hInstall, + __in BOOL fInstall + ) +{ + HRESULT hr = S_OK; + DWORD er = ERROR_SUCCESS; + + PMSIHANDLE hView, hRec; + LPWSTR pwzId = NULL; + LPWSTR pwzComponent = NULL; + LPWSTR pwzName = NULL; + LPWSTR pwzData = NULL; + INSTALLSTATE isInstalled, isAction; + + LPWSTR pwzCustomActionData = NULL; + + // check to see if necessary tables are specified + if (S_OK != WcaTableExists(L"Wix4PerformanceCategory")) + { + ExitFunction1(hr = S_FALSE); + } + + hr = WcaOpenExecuteView(vcsPerfCounterDataQuery, &hView); + ExitOnFailure(hr, "failed to open view on Wix4PerformanceCategory table"); + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + hr = WcaGetRecordString(hRec, pcdqId, &pwzId); + ExitOnFailure(hr, "Failed to get id for Wix4PerformanceCategory."); + + // Check to see if the Component is being installed or uninstalled + // when we are processing the same. + hr = WcaGetRecordString(hRec, pcdqComponent, &pwzComponent); + ExitOnFailure(hr, "Failed to get Component for Wix4PerformanceCategory: %ls", pwzId); + + er = ::MsiGetComponentStateW(hInstall, pwzComponent, &isInstalled, &isAction); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "Failed to get Component state for Wix4PerformanceCategory: %ls", pwzId); + + if ((fInstall && !WcaIsInstalling(isInstalled, isAction)) || + (!fInstall && !WcaIsUninstalling(isInstalled, isAction))) + { + continue; + } + + hr = WcaGetRecordString(hRec, pcdqName, &pwzName); + ExitOnFailure(hr, "Failed to get Name for Wix4PerformanceCategory: %ls", pwzId); + hr = WcaWriteStringToCaData(pwzName, &pwzCustomActionData); + ExitOnFailure(hr, "Failed to add Name to CustomActionData for Wix4PerformanceCategory: %ls", pwzId); + + hr = WcaGetRecordString(hRec, pcdqIniData, &pwzData); + ExitOnFailure(hr, "Failed to get IniData for Wix4PerformanceCategory: %ls", pwzId); + hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); + ExitOnFailure(hr, "Failed to add IniData to CustomActionData for Wix4PerformanceCategory: %ls", pwzId); + + hr = WcaGetRecordString(hRec, pcdqConstantData, &pwzData); + ExitOnFailure(hr, "Failed to get ConstantData for Wix4PerformanceCategory: %ls", pwzId); + hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); + ExitOnFailure(hr, "Failed to add ConstantData to CustomActionData for Wix4PerformanceCategory: %ls", pwzId); + } + + if (hr == E_NOMOREITEMS) + { + hr = S_OK; + } + ExitOnFailure(hr, "Failure while processing Wix4PerformanceCategory table."); + + // If there was any data built up, schedule it for execution. + if (pwzCustomActionData) + { + if (fInstall) + { + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackRegisterPerfCounterData"), pwzCustomActionData, COST_PERFMON_UNREGISTER); + ExitOnFailure(hr, "Failed to schedule RollbackRegisterPerfCounterData action for Wix4PerformanceCategory: %ls", pwzId); + + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RegisterPerfCounterData"), pwzCustomActionData, COST_PERFMON_REGISTER); + ExitOnFailure(hr, "Failed to schedule RegisterPerfCounterData action for Wix4PerformanceCategory: %ls", pwzId); + } + else + { + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackUnregisterPerfCounterData"), pwzCustomActionData, COST_PERFMON_REGISTER); + ExitOnFailure(hr, "Failed to schedule RollbackUnregisterPerfCounterData action for Wix4PerformanceCategory: %ls", pwzId); + + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"UnregisterPerfCounterData"), pwzCustomActionData, COST_PERFMON_UNREGISTER); + ExitOnFailure(hr, "Failed to schedule UnregisterPerfCounterData action for Wix4PerformanceCategory: %ls", pwzId); + } + } + +LExit: + ReleaseStr(pwzCustomActionData); + ReleaseStr(pwzData); + ReleaseStr(pwzName); + ReleaseStr(pwzComponent); + ReleaseStr(pwzId); + + return hr; +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + +typedef DWORD (STDAPICALLTYPE *PFNPERFCOUNTERTEXTSTRINGS)(LPWSTR lpCommandLine, BOOL bQuietModeArg); + +static HRESULT ExecutePerfCounterData( + __in MSIHANDLE hInstall, + __in BOOL fInstall + ); +static HRESULT CreateDataFile( + __in LPCWSTR wzTempFolder, + __in LPCWSTR wzData, + __in BOOL fIniData, + __out HANDLE *phFile, + __out_opt LPWSTR *ppwzFile + ); + + +/******************************************************************** + RegisterPerfCounterData - CUSTOM ACTION ENTRY POINT for registering + performance counters + + Input: deferred CustomActionData: wzName\twzIniData\twzConstantData\twzName\twzIniData\twzConstantData\t... +*******************************************************************/ +extern "C" UINT __stdcall RegisterPerfCounterData( + __in MSIHANDLE hInstall + ) +{ + // AssertSz(FALSE, "debug RegisterPerfCounterData()"); + HRESULT hr = S_OK; + DWORD er = ERROR_SUCCESS; + + hr = WcaInitialize(hInstall, "RegisterPerfCounterData"); + ExitOnFailure(hr, "Failed to initialize RegisterPerfCounterData."); + + hr = ExecutePerfCounterData(hInstall, TRUE); + MessageExitOnFailure(hr, msierrInstallPerfCounterData, "Failed to execute Wix4PerformanceCategory table."); + +LExit: + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + + +/******************************************************************** + UnregisterPerfCounterData - CUSTOM ACTION ENTRY POINT for registering + performance counters + + Input: deferred CustomActionData: wzName\twzIniData\twzConstantData\twzName\twzIniData\twzConstantData\t... +*******************************************************************/ +extern "C" UINT __stdcall UnregisterPerfCounterData( + __in MSIHANDLE hInstall + ) +{ + // AssertSz(FALSE, "debug UnregisterPerfCounterData()"); + HRESULT hr = S_OK; + DWORD er = ERROR_SUCCESS; + + hr = WcaInitialize(hInstall, "UnregisterPerfCounterData"); + ExitOnFailure(hr, "Failed to initialize UnregisterPerfCounterData."); + + hr = ExecutePerfCounterData(hInstall, FALSE); + MessageExitOnFailure(hr, msierrUninstallPerfCounterData, "Failed to execute Wix4PerformanceCategory table."); + +LExit: + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + + +/******************************************************************** + RegisterPerfmon - CUSTOM ACTION ENTRY POINT for registering + counters + + Input: deferred CustomActionData - + wzFile or wzName +*******************************************************************/ +extern "C" UINT __stdcall RegisterPerfmon( + __in MSIHANDLE hInstall + ) +{ +// Assert(FALSE); + UINT er = ERROR_SUCCESS; + HRESULT hr = S_OK; + LPWSTR pwzData = NULL; + + HMODULE hMod = NULL; + PFNPERFCOUNTERTEXTSTRINGS pfnPerfCounterTextString; + DWORD dwRet; + LPWSTR pwzShortPath = NULL; + DWORD cchShortPath = MAX_PATH; + DWORD cchShortPathLength = 0; + + LPWSTR pwzCommand = NULL; + + hr = WcaInitialize(hInstall, "RegisterPerfmon"); + ExitOnFailure(hr, "failed to initialize"); + + hr = WcaGetProperty(L"CustomActionData", &pwzData); + ExitOnFailure(hr, "failed to get CustomActionData"); + + WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); + + // do the perfmon registration + if (NULL == hMod) + { + hr = LoadSystemLibrary(L"loadperf.dll", &hMod); + } + ExitOnFailure(hr, "failed to load DLL for PerfMon"); + + pfnPerfCounterTextString = (PFNPERFCOUNTERTEXTSTRINGS)::GetProcAddress(hMod, "LoadPerfCounterTextStringsW"); + ExitOnNullWithLastError(pfnPerfCounterTextString, hr, "failed to get DLL function for PerfMon"); + + hr = StrAlloc(&pwzShortPath, cchShortPath); + ExitOnFailure(hr, "failed to allocate string"); + + WcaLog(LOGMSG_VERBOSE, "Converting DLL path to short format: %ls", pwzData); + cchShortPathLength = ::GetShortPathNameW(pwzData, pwzShortPath, cchShortPath); + if (cchShortPathLength > cchShortPath) + { + cchShortPath = cchShortPathLength + 1; + hr = StrAlloc(&pwzShortPath, cchShortPath); + ExitOnFailure(hr, "failed to allocate string"); + + cchShortPathLength = ::GetShortPathNameW(pwzData, pwzShortPath, cchShortPath); + } + + if (0 == cchShortPathLength) + { + ExitOnLastError(hr, "failed to get short path format of path: %ls", pwzData); + } + + hr = StrAllocFormatted(&pwzCommand, L"lodctr \"%s\"", pwzShortPath); + ExitOnFailure(hr, "failed to format lodctr string"); + + WcaLog(LOGMSG_VERBOSE, "RegisterPerfmon running command: '%ls'", pwzCommand); + dwRet = (*pfnPerfCounterTextString)(pwzCommand, TRUE); + if (dwRet != ERROR_SUCCESS && dwRet != ERROR_ALREADY_EXISTS) + { + hr = HRESULT_FROM_WIN32(dwRet); + MessageExitOnFailure(hr, msierrPERFMONFailedRegisterDLL, "failed to register with PerfMon, DLL: %ls", pwzData); + } + + hr = S_OK; +LExit: + ReleaseStr(pwzData); + + if (FAILED(hr)) + er = ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + + +extern "C" UINT __stdcall UnregisterPerfmon( + __in MSIHANDLE hInstall + ) +{ +// Assert(FALSE); + UINT er = ERROR_SUCCESS; + HRESULT hr = S_OK; + LPWSTR pwzData = NULL; + + HMODULE hMod = NULL; + PFNPERFCOUNTERTEXTSTRINGS pfnPerfCounterTextString; + DWORD dwRet; + WCHAR wz[255]; + + hr = WcaInitialize(hInstall, "UnregisterPerfmon"); + ExitOnFailure(hr, "failed to initialize"); + + hr = WcaGetProperty(L"CustomActionData", &pwzData); + ExitOnFailure(hr, "failed to get CustomActionData"); + + WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); + + // do the perfmon unregistration + hr = E_FAIL; + if (hMod == NULL) + { + hr = LoadSystemLibrary(L"loadperf.dll", &hMod); + } + ExitOnFailure(hr, "failed to load DLL for PerfMon"); + + pfnPerfCounterTextString = (PFNPERFCOUNTERTEXTSTRINGS)::GetProcAddress(hMod, "UnloadPerfCounterTextStringsW"); + ExitOnNullWithLastError(pfnPerfCounterTextString, hr, "failed to get DLL function for PerfMon"); + + hr = ::StringCchPrintfW(wz, countof(wz), L"unlodctr \"%s\"", pwzData); + ExitOnFailure(hr, "Failed to format unlodctr string with: %ls", pwzData); + WcaLog(LOGMSG_VERBOSE, "UnregisterPerfmon running command: '%ls'", wz); + dwRet = (*pfnPerfCounterTextString)(wz, TRUE); + // if the counters aren't registered, then OK to continue + if (dwRet != ERROR_SUCCESS && dwRet != ERROR_FILE_NOT_FOUND && dwRet != ERROR_BADKEY) + { + hr = HRESULT_FROM_WIN32(dwRet); + MessageExitOnFailure(hr, msierrPERFMONFailedUnregisterDLL, "failed to unregsister with PerfMon, DLL: %ls", pwzData); + } + + hr = S_OK; +LExit: + ReleaseStr(pwzData); + + if (FAILED(hr)) + er = ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + + +static HRESULT ExecutePerfCounterData( + __in MSIHANDLE /*hInstall*/, + __in BOOL fInstall + ) +{ + HRESULT hr = S_OK; + DWORD er = ERROR_SUCCESS; + + HMODULE hModule = NULL; + PFNPERFCOUNTERTEXTSTRINGS pfnPerfCounterTextString = NULL; + LPCWSTR wzPrefix = NULL; + + LPWSTR pwzCustomActionData = NULL; + LPWSTR pwz = NULL; + + LPWSTR pwzName = NULL; + LPWSTR pwzIniData = NULL; + LPWSTR pwzConstantData = NULL; + LPWSTR pwzTempFolder = NULL; + LPWSTR pwzIniFile = NULL; + LPWSTR pwzExecute = NULL; + + HANDLE hIniData = INVALID_HANDLE_VALUE; + HANDLE hConstantData = INVALID_HANDLE_VALUE; + + // Load the system performance counter helper DLL then get the appropriate + // entrypoint out of it. Fortunately, they have the same signature so we + // can use one function pointer to point to both. + hr = LoadSystemLibrary(L"loadperf.dll", &hModule); + ExitOnFailure(hr, "failed to load DLL for PerfMon"); + + if (fInstall) + { + wzPrefix = L"lodctr"; + pfnPerfCounterTextString = (PFNPERFCOUNTERTEXTSTRINGS)::GetProcAddress(hModule, "LoadPerfCounterTextStringsW"); + } + else + { + wzPrefix = L"unlodctr"; + pfnPerfCounterTextString = (PFNPERFCOUNTERTEXTSTRINGS)::GetProcAddress(hModule, "UnloadPerfCounterTextStringsW"); + } + ExitOnNullWithLastError(pfnPerfCounterTextString, hr, "Failed to get DLL function for PerfMon"); + + // Now get the CustomActionData and execute it. + hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData); + ExitOnFailure(hr, "Failed to get CustomActionData."); + + WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); + + pwz = pwzCustomActionData; + + while (S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzName))) + { + hr = WcaReadStringFromCaData(&pwz, &pwzIniData); + ExitOnFailure(hr, "Failed to read IniData from custom action data."); + + hr = WcaReadStringFromCaData(&pwz, &pwzConstantData); + ExitOnFailure(hr, "Failed to read ConstantData from custom action data."); + + if (fInstall) + { + hr = PathCreateTempDirectory(NULL, L"WIXPF%03x", 999, &pwzTempFolder); + ExitOnFailure(hr, "Failed to create temp directory."); + + hr = CreateDataFile(pwzTempFolder, pwzIniData, TRUE, &hIniData, &pwzIniFile); + ExitOnFailure(hr, "Failed to create .ini file for performance counter category: %ls", pwzName); + + hr = CreateDataFile(pwzTempFolder, pwzConstantData, FALSE, &hConstantData, NULL); + ExitOnFailure(hr, "Failed to create .h file for performance counter category: %ls", pwzName); + + hr = StrAllocFormatted(&pwzExecute, L"%s \"%s\"", wzPrefix, pwzIniFile); + ExitOnFailure(hr, "Failed to allocate string to execute."); + + // Execute the install. + er = (*pfnPerfCounterTextString)(pwzExecute, TRUE); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "Failed to execute install of performance counter category: %ls", pwzName); + + if (INVALID_HANDLE_VALUE != hIniData) + { + ::CloseHandle(hIniData); + hIniData = INVALID_HANDLE_VALUE; + } + + if (INVALID_HANDLE_VALUE != hConstantData) + { + ::CloseHandle(hConstantData); + hConstantData = INVALID_HANDLE_VALUE; + } + + DirEnsureDelete(pwzTempFolder, TRUE, TRUE); + } + else + { + hr = StrAllocFormatted(&pwzExecute, L"%s \"%s\"", wzPrefix, pwzName); + ExitOnFailure(hr, "Failed to allocate string to execute."); + + // Execute the uninstall and if the counter isn't registered then ignore + // the error since it won't hurt anything. + er = (*pfnPerfCounterTextString)(pwzExecute, TRUE); + if (ERROR_FILE_NOT_FOUND == er || ERROR_BADKEY == er) + { + er = ERROR_SUCCESS; + } + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "Failed to execute uninstall of performance counter category: %ls", pwzName); + } + } + + if (E_NOMOREITEMS == hr) // If there are no more items, all is well + { + hr = S_OK; + } + ExitOnFailure(hr, "Failed to execute all perf counter data."); + + hr = S_OK; + +LExit: + if (INVALID_HANDLE_VALUE != hIniData) + { + ::CloseHandle(hIniData); + } + + if (INVALID_HANDLE_VALUE != hConstantData) + { + ::CloseHandle(hConstantData); + } + + ReleaseStr(pwzExecute); + ReleaseStr(pwzIniFile); + ReleaseStr(pwzTempFolder); + ReleaseStr(pwzConstantData); + ReleaseStr(pwzIniData); + ReleaseStr(pwzName); + ReleaseStr(pwzCustomActionData); + + if (hModule) + { + ::FreeLibrary(hModule); + } + + return hr; +} + + +static HRESULT CreateDataFile( + __in LPCWSTR wzTempFolder, + __in LPCWSTR wzData, + __in BOOL fIniData, + __out HANDLE *phFile, + __out_opt LPWSTR *ppwzFile + ) +{ + HRESULT hr = S_OK; + HANDLE hFile = INVALID_HANDLE_VALUE; + LPWSTR pwzFile = NULL; + LPSTR pszData = NULL; + DWORD cbData = 0; + DWORD cbWritten = 0; + + // Convert the data to UTF-8 because lodctr/unloctr + // doesn't like unicode. + hr = StrAnsiAllocString(&pszData, wzData, 0, CP_UTF8); + ExitOnFailure(hr, "Failed to covert data to ANSI."); + + cbData = lstrlenA(pszData); + + // Concatenate the paths together, open the file data file + // and dump the data in there. + hr = StrAllocString(&pwzFile, wzTempFolder, 0); + ExitOnFailure(hr, "Failed to copy temp directory name."); + + hr = StrAllocConcat(&pwzFile, L"wixperf", 0); + ExitOnFailure(hr, "Failed to add name of file."); + + hr = StrAllocConcat(&pwzFile, fIniData ? L".ini" : L".h", 0); + ExitOnFailure(hr, "Failed to add extension of file."); + + hFile = ::CreateFileW(pwzFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (INVALID_HANDLE_VALUE == hFile) + { + ExitWithLastError(hr, "Failed to open new temp file: %ls", pwzFile); + } + + if (!::WriteFile(hFile, pszData, cbData, &cbWritten, NULL)) + { + ExitWithLastError(hr, "Failed to write data to new temp file: %ls", pwzFile); + } + + if (INVALID_HANDLE_VALUE != hFile) + { + ::CloseHandle(hFile); + hFile = INVALID_HANDLE_VALUE; + } + + // Return the requested values. + *phFile = hFile; + hFile = INVALID_HANDLE_VALUE; + + if (ppwzFile) + { + *ppwzFile = pwzFile; + pwzFile = NULL; + } + +LExit: + if (INVALID_HANDLE_VALUE != hFile) + { + ::CloseHandle(hFile); + } + ReleaseStr(pszData); + ReleaseStr(pwzFile); + + return hr; +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +/******************************************************************** +ConfigureSmb - CUSTOM ACTION ENTRY POINT for installing fileshare settings + +********************************************************************/ +extern "C" UINT __stdcall ConfigureSmbInstall( + __in MSIHANDLE hInstall + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + SCA_SMB* pssList = NULL; + + // initialize + hr = WcaInitialize(hInstall, "ConfigureSmbInstall"); + ExitOnFailure(hr, "Failed to initialize"); + + // check to see if necessary tables are specified + if (WcaTableExists(L"Wix4FileShare") != S_OK) + { + WcaLog(LOGMSG_VERBOSE, "Skipping SMB CustomAction, no Wix4FileShare table"); + ExitFunction1(hr = S_FALSE); + } + + hr = ScaSmbRead(&pssList); + ExitOnFailure(hr, "failed to read Wix4FileShare table"); + + hr = ScaSmbInstall(pssList); + ExitOnFailure(hr, "failed to install FileShares"); + +LExit: + if (pssList) + ScaSmbFreeList(pssList); + + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + + +/******************************************************************** +ConfigureSmb - CUSTOM ACTION ENTRY POINT for uninstalling fileshare settings + +********************************************************************/ +extern "C" UINT __stdcall ConfigureSmbUninstall( + __in MSIHANDLE hInstall + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + SCA_SMB* pssList = NULL; + + // initialize + hr = WcaInitialize(hInstall, "ConfigureSmbUninstall"); + ExitOnFailure(hr, "Failed to initialize"); + + // check to see if necessary tables are specified + if (WcaTableExists(L"Wix4FileShare") != S_OK) + { + WcaLog(LOGMSG_VERBOSE, "Skipping SMB CustomAction, no Wix4FileShare table"); + ExitFunction1(hr = S_FALSE); + } + + hr = ScaSmbRead(&pssList); + ExitOnFailure(hr, "failed to read Wix4FileShare table"); + + hr = ScaSmbUninstall(pssList); + ExitOnFailure(hr, "failed to uninstall FileShares"); + +LExit: + if (pssList) + ScaSmbFreeList(pssList); + + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + + +/******************************************************************** +ConfigureUsers - CUSTOM ACTION ENTRY POINT for installing users + +********************************************************************/ +extern "C" UINT __stdcall ConfigureUsers( + __in MSIHANDLE hInstall + ) +{ + //AssertSz(0, "Debug ConfigureUsers"); + + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + BOOL fInitializedCom = FALSE; + SCA_USER* psuList = NULL; + + // initialize + hr = WcaInitialize(hInstall, "ConfigureUsers"); + ExitOnFailure(hr, "Failed to initialize"); + + hr = ::CoInitialize(NULL); + ExitOnFailure(hr, "failed to initialize COM"); + fInitializedCom = TRUE; + + hr = ScaUserRead(&psuList); + ExitOnFailure(hr, "failed to read Wix4User table"); + + hr = ScaUserExecute(psuList); + ExitOnFailure(hr, "failed to add/remove User actions"); + +LExit: + if (psuList) + { + ScaUserFreeList(psuList); + } + + if (fInitializedCom) + { + ::CoUninitialize(); + } + + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} \ 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 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +#include "scauser.h" + +// structs +// Structure used to hold and extra user/permission pairs from the Wix4FileSharePermissions Table +struct SCA_SMB_EX_USER_PERMS +{ + int nPermissions; + ACCESS_MODE accessMode; + SCA_USER scau; + SCA_SMB_EX_USER_PERMS* pExUserPermsNext; +}; + +struct SCA_SMB // hungarian ss +{ + WCHAR wzId[MAX_DARWIN_KEY + 1]; + WCHAR wzShareName[MAX_DARWIN_KEY + 1]; + WCHAR wzDescription[MAX_DARWIN_COLUMN + 1]; + WCHAR wzComponent[MAX_DARWIN_KEY + 1]; + WCHAR wzDirectory[MAX_PATH + 1]; + + int nUserPermissionCount; + int nPermissions; + SCA_SMB_EX_USER_PERMS* pExUserPerms; + + INSTALLSTATE isInstalled, isAction; + + BOOL fUseIntegratedAuth; + BOOL fLegacyUserProvided; + struct SCA_USER scau; + + struct SCA_SMB* pssNext; +}; + + +#define RESERVED 0 + +// schedule prototypes +HRESULT ScaSmbRead(SCA_SMB** ppssList); +HRESULT ScaSmbExPermsRead(SCA_SMB* pss); +HRESULT ScaSmbUninstall(SCA_SMB* pssList); +HRESULT ScaSmbInstall(SCA_SMB* pssList); +void 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +/******************************************************************** + AllocateAcl - allocate an acl and populate it with this user and + permission information user could be user or domain\user + +********************************************************************/ +HRESULT AllocateAcl(SCA_SMBP* pssp, PACL* ppACL) +{ + HRESULT hr = S_OK; + EXPLICIT_ACCESSW* pEA = NULL; + DWORD cEA = 0; + DWORD dwCounter = 0; + + PSID psid = NULL; + LPCWSTR wzUser = NULL; + DWORD nPermissions = 0; + DWORD nErrorReturn = 0; + ACCESS_MODE accessMode = NOT_USED_ACCESS; + + cEA = pssp->dwUserPermissionCount + 1; + if (cEA >= MAXSIZE_T / sizeof(EXPLICIT_ACCESSW)) + { + ExitOnFailure(hr = E_OUTOFMEMORY, "Too many user permissions to allocate: %u", cEA); + } + + pEA = static_cast(MemAlloc(cEA * sizeof(EXPLICIT_ACCESSW), TRUE)); + ExitOnNull(pEA, hr, E_OUTOFMEMORY, "failed to allocate memory for explicit access structure"); + + // figure out how big the psid is + for (dwCounter = 0; dwCounter < pssp->dwUserPermissionCount; ++dwCounter) + { + wzUser = pssp->pUserPerms[dwCounter].wzUser; + nPermissions = pssp->pUserPerms[dwCounter].nPermissions; + accessMode = pssp->pUserPerms[dwCounter].accessMode; + // + // create the appropriate SID + // + + // figure out the right user to put into the access block + if (0 == lstrcmpW(wzUser, L"Everyone")) + { + hr = AclGetWellKnownSid(WinWorldSid, &psid); + } + else if (0 == lstrcmpW(wzUser, L"Administrators")) + { + hr = AclGetWellKnownSid(WinBuiltinAdministratorsSid, &psid); + } + else if (0 == lstrcmpW(wzUser, L"LocalSystem")) + { + hr = AclGetWellKnownSid(WinLocalSystemSid, &psid); + } + else if (0 == lstrcmpW(wzUser, L"LocalService")) + { + hr = AclGetWellKnownSid(WinLocalServiceSid, &psid); + } + else if (0 == lstrcmpW(wzUser, L"NetworkService")) + { + hr = AclGetWellKnownSid(WinNetworkServiceSid, &psid); + } + else if (0 == lstrcmpW(wzUser, L"AuthenticatedUser")) + { + hr = AclGetWellKnownSid(WinAuthenticatedUserSid, &psid); + } + else if (0 == lstrcmpW(wzUser, L"Guests")) + { + hr = AclGetWellKnownSid(WinBuiltinGuestsSid, &psid); + } + else if(0 == lstrcmpW(wzUser, L"CREATOR OWNER")) + { + hr = AclGetWellKnownSid(WinCreatorOwnerSid, &psid); + } + else + { + hr = AclGetAccountSid(NULL, wzUser, &psid); + } + ExitOnFailure(hr, "failed to get sid for account: %ls", wzUser); + + // we now have a valid pSid, fill in the EXPLICIT_ACCESS + + /* Permissions options: (see sca.sdh for defined sdl options) + #define GENERIC_READ (0x80000000L) 2147483648 + #define GENERIC_WRITE (0x40000000L) 1073741824 + #define GENERIC_EXECUTE (0x20000000L) 536870912 + #define GENERIC_ALL (0x10000000L) 268435456 + */ + pEA[dwCounter].grfAccessPermissions = nPermissions; + pEA[dwCounter].grfAccessMode = accessMode; + pEA[dwCounter].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT; +#pragma prefast(push) +#pragma prefast(disable:25029) + ::BuildTrusteeWithSidW(&(pEA[dwCounter].Trustee), psid); +#pragma prefast(pop) + } + + // create a new ACL that contains the ACE + *ppACL = NULL; +#pragma prefast(push) +#pragma prefast(disable:25029) + nErrorReturn = ::SetEntriesInAclW(dwCounter, pEA, NULL, ppACL); +#pragma prefast(pop) + ExitOnFailure(hr = HRESULT_FROM_WIN32(nErrorReturn), "failed to allocate ACL"); + +LExit: + if (psid) + { + AclFreeSid(psid); + } + + ReleaseMem(pEA); + + return hr; +} + + + +/******************************************************************** + FillShareInfo - fill the NetShareAdd data structure + +********************************************************************/ +void FillShareInfo(SHARE_INFO_502* psi, SCA_SMBP* pssp, PSECURITY_DESCRIPTOR pSD) +{ + psi->shi502_netname = pssp->wzKey; + psi->shi502_type = STYPE_DISKTREE; + psi->shi502_remark = pssp->wzDescription; + psi->shi502_permissions = 0; // not used + psi->shi502_max_uses = 0xFFFFFFFF; + psi->shi502_current_uses = 0; + psi->shi502_path = pssp->wzDirectory; + psi->shi502_passwd = NULL; // not file share perms + psi->shi502_reserved = 0; + psi->shi502_security_descriptor = pSD; +} + + + +/* NET_API_STATUS return codes +NERR_Success = 0 +NERR_DuplicateShare = 2118 +NERR_BufTooSmall = 2123 +NERR_NetNameNotFound = 2310 +NERR_RedirectedPath = 2117 +NERR_UnknownDevDir = 2116 +*/ + +/******************************************************************** + DoesShareExists - Does a share of this name exist on this computer? + +********************************************************************/ +HRESULT DoesShareExist(__in LPWSTR wzShareName) +{ + HRESULT hr = S_OK; + NET_API_STATUS s; + SHARE_INFO_502* psi = NULL; + s = ::NetShareGetInfo(NULL, wzShareName, 502, (BYTE**) &psi); + + switch (s) + { + case NERR_Success: + hr = S_OK; + break; + case NERR_NetNameNotFound: + hr = E_FILENOTFOUND; + break; + default: + WcaLogError(s, "NetShareGetInfo returned an unexpected value.", NULL); + hr = HRESULT_FROM_WIN32(s); + break; + } + + ::NetApiBufferFree(psi); + + return hr; +} + + + +/******************************************************************** + CreateShare - create the file share on this computer + +********************************************************************/ +HRESULT CreateShare(SCA_SMBP* pssp) +{ + if (!pssp || !(pssp->wzKey)) + return E_INVALIDARG; + + HRESULT hr = S_OK; + PACL pACL = NULL; + SHARE_INFO_502 si; + NET_API_STATUS s; + DWORD dwParamErr = 0; + + BOOL fShareExists = SUCCEEDED(DoesShareExist(pssp->wzKey)); + + PSECURITY_DESCRIPTOR pSD = static_cast(MemAlloc(SECURITY_DESCRIPTOR_MIN_LENGTH, TRUE)); + ExitOnNull(pSD, hr, E_OUTOFMEMORY, "Failed to allocate memory for security descriptor"); + +#pragma prefast(push) +#pragma prefast(disable:25029) + if (!::InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) +#pragma prefast(pop) + { + ExitOnLastError(hr, "failed to initialize security descriptor"); + } + + hr = AllocateAcl(pssp, &pACL); + ExitOnFailure(hr, "Failed to allocate ACL for fileshare"); + + if (NULL == pACL) + { + WcaLog(LOGMSG_VERBOSE, "Ignoring NULL DACL."); + } +#pragma prefast(push) +#pragma prefast(disable:25028) // We only call this when pACL isn't NULL, so this call is safe according to the docs + // add the ACL to the security descriptor. + else if (!::SetSecurityDescriptorDacl(pSD, TRUE, pACL, FALSE)) + { + ExitOnLastError(hr, "Failed to set security descriptor"); + } +#pragma prefast(pop) + + // all that is left is to create the share + FillShareInfo(&si, pssp, pSD); + + // Fail if the directory doesn't exist + if (!DirExists(pssp->wzDirectory, NULL)) + ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_OBJECT_NOT_FOUND), "Can't create a file share on directory that doesn't exist: %ls.", pssp->wzDirectory); + + WcaLog(LOGMSG_VERBOSE, "Creating file share on directory \'%ls\' named \'%ls\'.", pssp->wzDirectory, pssp->wzKey); + + if (!fShareExists) + { + s = ::NetShareAdd(NULL, 502, (BYTE*) &si, &dwParamErr); + WcaLog(LOGMSG_VERBOSE, "Adding a new file share."); + } + else + { + // The share exists. Write our new permissions over the top. + s = ::NetShareSetInfo(NULL, pssp->wzKey, 502, (BYTE*) &si, &dwParamErr); + WcaLog(LOGMSG_VERBOSE, "Setting permissions on existing share."); + } + + if (NERR_Success != s) + { + hr = E_FAIL; + if (!fShareExists && NERR_DuplicateShare == s) + WcaLog(LOGMSG_VERBOSE, "Duplicate error when existence check failed."); + + // error codes listed above. + ExitOnFailure(hr, "Failed to create/modify file share: Err: %d", s); + } + +LExit: + if (pACL) + { + ::LocalFree(pACL); + } + + ReleaseMem(pSD); + + return hr; +} + + +/******************************************************************** + ScaEnsureSmbExists + +********************************************************************/ +HRESULT ScaEnsureSmbExists(SCA_SMBP* pssp) +{ + HRESULT hr = S_OK; + + // create the share + hr = CreateShare(pssp); + + return hr; +} + + +// +// Delete File Shares - real work +// + +/******************************************************************** + ScaDropSmb - delete this file share from this computer + +********************************************************************/ +HRESULT ScaDropSmb(SCA_SMBP* pssp) +{ + HRESULT hr = S_OK; + NET_API_STATUS s; + + hr = DoesShareExist(pssp->wzKey); + + if (E_FILENOTFOUND == hr) + { + WcaLog(LOGMSG_VERBOSE, "Share doesn't exist, share removal skipped. (%ls)", pssp->wzKey); + ExitFunction1(hr = S_OK); + + } + + ExitOnFailure(hr, "Unable to detect share. (%ls)", pssp->wzKey); + + s = ::NetShareDel(NULL, pssp->wzKey, 0); + if (NERR_Success != s) + { + hr = E_FAIL; + ExitOnFailure(hr, "Failed to remove file share: Err: %d", s); + } + +LExit: + return hr; +} 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 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +struct SCA_SMBP_USER_PERMS +{ + DWORD nPermissions; + ACCESS_MODE accessMode; + WCHAR* wzUser; + //Not adding Password because I can't find anywhere that it is used +}; + +struct SCA_SMBP // hungarian ssp +{ + WCHAR* wzKey; + WCHAR* wzDescription; + WCHAR* wzComponent; + WCHAR* wzDirectory; // full path of the dir to share to + + DWORD dwUserPermissionCount; //Count of SCA_SMBP_EX_USER_PERMS structures + SCA_SMBP_USER_PERMS* pUserPerms; + BOOL fUseIntegratedAuth; +}; + + +HRESULT ScaEnsureSmbExists(SCA_SMBP* pssp); +HRESULT 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +/******************************************************************** + Helper functions to maintain a list of file shares to create / remove + +********************************************************************/ +SCA_SMB* NewSmb() +{ + SCA_SMB* pss = (SCA_SMB*)MemAlloc(sizeof(SCA_SMB), TRUE); + Assert(pss); + return pss; +} + + +SCA_SMB_EX_USER_PERMS* NewExUserPermsSmb() +{ + SCA_SMB_EX_USER_PERMS* pExUserPerms = (SCA_SMB_EX_USER_PERMS*)MemAlloc(sizeof(SCA_SMB_EX_USER_PERMS), TRUE); + Assert(pExUserPerms); + return pExUserPerms; +} + + +SCA_SMB* AddSmbToList(SCA_SMB* pssList, SCA_SMB* pss) +{ + if (pssList) + { + SCA_SMB* pssT = pssList; + while (pssT->pssNext) + { + pssT = pssT->pssNext; + } + + pssT->pssNext = pss; + } + else + { + pssList = pss; + } + + return pssList; +} + + +SCA_SMB_EX_USER_PERMS* AddExUserPermsSmbToList( + SCA_SMB_EX_USER_PERMS* pExUserPermsList, + SCA_SMB_EX_USER_PERMS* pExUserPerms + ) +{ + SCA_SMB_EX_USER_PERMS* pExUserPermsTemp = pExUserPermsList; + if (pExUserPermsList) + { + while (pExUserPermsTemp->pExUserPermsNext) + { + pExUserPermsTemp = pExUserPermsTemp->pExUserPermsNext; + } + + pExUserPermsTemp->pExUserPermsNext = pExUserPerms; + } + else + { + pExUserPermsList = pExUserPerms; + } + + return pExUserPermsList; +} + +void ScaSmbFreeList(SCA_SMB* pssList) +{ + SCA_SMB* pssDelete = pssList; + while (pssList) + { + pssDelete = pssList; + pssList = pssList->pssNext; + + MemFree(pssDelete); + } +} + +void ScaExUserPermsSmbFreeList(SCA_SMB_EX_USER_PERMS* pExUserPermsList) +{ + SCA_SMB_EX_USER_PERMS* pExUserPermsDelete = pExUserPermsList; + while (pExUserPermsList) + { + pExUserPermsDelete = pExUserPermsList; + pExUserPermsList = pExUserPermsList->pExUserPermsNext; + + MemFree(pExUserPermsDelete); + } +} + +// sql query constants +LPCWSTR vcsSmbQuery = L"SELECT `Wix4FileShare`, `ShareName`, `Description`, `Directory_`, " + L"`Component_`, `User_`, `Permissions` FROM `Wix4FileShare`"; + +enum eSmbQuery { + ssqFileShare = 1, + ssqShareName, + ssqDescription, + ssqDirectory, + ssqComponent, + ssqUser, + ssqPermissions + }; + + +/******************************************************************** + ScaSmbRead - read all of the information from the msi tables and + return a list of file share jobs to be done. + +********************************************************************/ +HRESULT ScaSmbRead(SCA_SMB** ppssList) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + PMSIHANDLE hView, hRec; + + LPWSTR pwzData = NULL; + + SCA_SMB* pss = NULL; + BOOL bUserPermissionsTableExists = FALSE; + + if (S_OK != WcaTableExists(L"Wix4FileShare")) + { + WcaLog(LOGMSG_VERBOSE, "Skipping ScaSmbCreateShare() - Wix4FileShare table not present"); + ExitFunction1(hr = S_FALSE); + } + + if (S_OK == WcaTableExists(L"Wix4FileSharePermissions")) + { + bUserPermissionsTableExists = TRUE; + } + else + { + WcaLog(LOGMSG_VERBOSE, "No Additional Permissions - Wix4FileSharePermissions table not present"); + } + + WcaLog(LOGMSG_VERBOSE, "Reading File Share Tables"); + + // loop through all the fileshares + hr = WcaOpenExecuteView(vcsSmbQuery, &hView); + ExitOnFailure(hr, "Failed to open view on Wix4FileShare table"); + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + pss = NewSmb(); + if (!pss) + { + hr = E_OUTOFMEMORY; + break; + } + Assert(pss); + ::ZeroMemory(pss, sizeof(*pss)); + + hr = WcaGetRecordString(hRec, ssqFileShare, &pwzData); + ExitOnFailure(hr, "Failed to get Wix4FileShare.Wix4FileShare"); + hr = ::StringCchCopyW(pss->wzId, countof(pss->wzId), pwzData); + ExitOnFailure(hr, "Failed to copy ID string to smb object"); + + hr = WcaGetRecordFormattedString(hRec, ssqShareName, &pwzData); + ExitOnFailure(hr, "Failed to get Wix4FileShare.ShareName"); + hr = ::StringCchCopyW(pss->wzShareName, countof(pss->wzShareName), pwzData); + ExitOnFailure(hr, "Failed to copy share name string to smb object"); + + hr = WcaGetRecordString(hRec, ssqComponent, &pwzData); + ExitOnFailure(hr, "Failed to get Component for Wix4FileShare: '%ls'", pss->wzShareName); + hr = ::StringCchCopyW(pss->wzComponent, countof(pss->wzComponent), pwzData); + ExitOnFailure(hr, "Failed to copy component string to smb object"); + + hr = WcaGetRecordFormattedString(hRec, ssqDescription, &pwzData); + ExitOnFailure(hr, "Failed to get Share Description for Wix4FileShare: '%ls'", pss->wzShareName); + hr = ::StringCchCopyW(pss->wzDescription, countof(pss->wzDescription), pwzData); + ExitOnFailure(hr, "Failed to copy description string to smb object"); + + // get user info from the user table + hr = WcaGetRecordFormattedString(hRec, ssqUser, &pwzData); + ExitOnFailure(hr, "Failed to get Wix4User record for Wix4FileShare: '%ls'", pss->wzShareName); + + // get component install state + er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pss->wzComponent, &pss->isInstalled, &pss->isAction); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "Failed to get Component state for Wix4FileShare"); + + // if a user was specified + if (*pwzData) + { + pss->fUseIntegratedAuth = FALSE; + pss->fLegacyUserProvided = TRUE; + hr = ScaGetUser(pwzData, &pss->scau); + ExitOnFailure(hr, "Failed to get user information for fileshare: '%ls'", pss->wzShareName); + } + else + { + pss->fLegacyUserProvided = FALSE; + // TODO: figure out whether this is useful still + //pss->fUseIntegratedAuth = TRUE; + // integrated authorization doesn't have a User record + } + + // get the share's directory + hr = WcaGetRecordString(hRec, ssqDirectory, &pwzData); + ExitOnFailure(hr, "Failed to get directory for Wix4FileShare: '%ls'", pss->wzShareName); + + WCHAR wzPath[MAX_PATH]; + DWORD dwLen; + dwLen = countof(wzPath); + // review: relevant for file shares? + if (INSTALLSTATE_SOURCE == pss->isAction) + { + er = ::MsiGetSourcePathW(WcaGetInstallHandle(), pwzData, wzPath, &dwLen); + } + else + { + er = ::MsiGetTargetPathW(WcaGetInstallHandle(), pwzData, wzPath, &dwLen); + } + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "Failed to get Source/TargetPath for Directory"); + + // If the path is to the root of a drive, then it needs a trailing backslash. + // Otherwise, it can't have a trailing backslash. + if (3 < dwLen) + { + if (wzPath[dwLen - 1] == L'\\') + { + wzPath[dwLen - 1] = 0; + } + } + else if (2 == dwLen && wzPath[1] == L':') + { + wzPath[2] = L'\\'; + wzPath[3] = 0; + } + + hr = ::StringCchCopyW(pss->wzDirectory, countof(pss->wzDirectory), wzPath); + ExitOnFailure(hr, "Failed to copy directory string to smb object"); + + hr = WcaGetRecordInteger(hRec, ssqPermissions, &pss->nPermissions); + ExitOnFailure(hr, "Failed to get Wix4FileShare.Permissions"); + + // Check to see if additional user & permissions are specified for this share + if (bUserPermissionsTableExists) + { + hr = ScaSmbExPermsRead(pss); + ExitOnFailure(hr, "Failed to get Additional File Share Permissions"); + } + + *ppssList = AddSmbToList(*ppssList, pss); + pss = NULL; // set the smb NULL so it doesn't accidentally get freed below + } + + if (E_NOMOREITEMS == hr) + { + hr = S_OK; + } + ExitOnFailure(hr, "Failure occured while processing Wix4FileShare table"); + +LExit: + // if anything was left over after an error clean it all up + if (pss) + { + ScaSmbFreeList(pss); + } + + ReleaseStr(pwzData); + + return hr; +} + + +/******************************************************************** + RetrieveSMBShareUserPermList - retrieve SMB Share's user permission list + +********************************************************************/ +HRESULT RetrieveFileShareUserPerm(SCA_SMB* pss, SCA_SMB_EX_USER_PERMS** ppExUserPermsList, DWORD *pUserPermsCount) +{ + HRESULT hr = S_OK; + SHARE_INFO_502* psi = NULL; + NET_API_STATUS s; + BOOL bValid, bDaclDefaulted; + PACL acl = NULL; + PEXPLICIT_ACCESSW pEA = NULL; + ULONG nCount = 0; + DWORD er = ERROR_SUCCESS; + PSID pSID = NULL; + DWORD nUserNameSize = MAX_DARWIN_COLUMN; + DWORD nDomainNameSize = MAX_DARWIN_COLUMN; + SID_NAME_USE peUse; + DWORD dwCounter = 0; + SCA_SMB_EX_USER_PERMS* pExUserPermsList = NULL; + DWORD dwUserPermsCount = 0; + + *pUserPermsCount = 0; + s = ::NetShareGetInfo(NULL, pss->wzShareName, 502, (LPBYTE*)&psi); + WcaLog(LOGMSG_VERBOSE, "retrieving permissions on existing file share."); + if (NERR_NetNameNotFound == s) + { + WcaLog(LOGMSG_VERBOSE, "File share has already been removed."); + ExitFunction1(hr = S_OK); + } + else if (NERR_Success != s || psi == NULL) + { + hr = E_FAIL; + ExitOnFailure(hr, "Failed to get share information with return code: %d", s); + } + if (!::GetSecurityDescriptorDacl(psi->shi502_security_descriptor, &bValid, &acl, &bDaclDefaulted) || !bValid) + { + ExitOnLastError(hr, "Failed to get acl from security descriptor"); + } + + er = ::GetExplicitEntriesFromAclW(acl, &nCount, &pEA); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "Failed to get access entries from acl for file share %ls", pss->wzShareName); + for (dwCounter = 0; dwCounter < nCount; ++dwCounter) + { + if (TRUSTEE_IS_SID == pEA[dwCounter].Trustee.TrusteeForm) + { + SCA_SMB_EX_USER_PERMS* pExUserPerms = NewExUserPermsSmb(); + ::ZeroMemory(pExUserPerms, sizeof(*pExUserPerms)); + pExUserPermsList = AddExUserPermsSmbToList(pExUserPermsList, pExUserPerms); + pSID = (PSID)(pEA[dwCounter].Trustee.ptstrName); + if (!::LookupAccountSidW(NULL, pSID, pExUserPerms->scau.wzName, &nUserNameSize, pExUserPerms->scau.wzDomain, &nDomainNameSize, &peUse)) + { + hr = E_FAIL; + ExitOnFailure(hr, "Failed to get account name from SID"); + } + pExUserPerms->nPermissions = pEA[dwCounter].grfAccessPermissions; + pExUserPerms->accessMode = pEA[dwCounter].grfAccessMode; + ++dwUserPermsCount; + nUserNameSize = MAX_DARWIN_COLUMN; + nDomainNameSize = MAX_DARWIN_COLUMN; + } + } + *ppExUserPermsList = pExUserPermsList; + *pUserPermsCount = dwUserPermsCount; + +LExit: + if (psi) + { + ::NetApiBufferFree(psi); + } + + if (pEA) + { + ::LocalFree(pEA); + } + + return hr; +} + + +/******************************************************************** + SchedCreateSmb - schedule one instance of a file share creation + +********************************************************************/ +HRESULT SchedCreateSmb(SCA_SMB* pss) +{ + HRESULT hr = S_OK; + + WCHAR wzDomainUser[255]; // "domain\user" + SCA_SMB_EX_USER_PERMS* pExUserPermsList = NULL; + int nCounter = 0; + WCHAR* pwzRollbackCustomActionData = NULL; + WCHAR* pwzCustomActionData = NULL; + + hr = WcaWriteStringToCaData(pss->wzShareName, &pwzRollbackCustomActionData); + ExitOnFailure(hr, "failed to add ShareName to CustomActionData"); + + hr = WcaWriteStringToCaData(pss->wzShareName, &pwzCustomActionData); + ExitOnFailure(hr, "failed to add ShareName to CustomActionData"); + + hr = WcaWriteStringToCaData(pss->wzDescription, &pwzCustomActionData); + ExitOnFailure(hr, "Failed to add server name to CustomActionData"); + + hr = WcaWriteStringToCaData(pss->wzDirectory, &pwzCustomActionData); + ExitOnFailure(hr, "Failed to add full path instance to CustomActionData"); + + hr = WcaWriteStringToCaData(pss->fUseIntegratedAuth ? L"1" : L"0", &pwzCustomActionData); + ExitOnFailure(hr, "Failed to add server name to CustomActionData"); + + if (pss->fLegacyUserProvided) + { + hr = WcaWriteIntegerToCaData(pss->nUserPermissionCount + 1, &pwzCustomActionData); + ExitOnFailure(hr, "Failed to add additional user permission count to CustomActionData"); + + hr = UserBuildDomainUserName(wzDomainUser, countof(wzDomainUser), pss->scau.wzName, pss->scau.wzDomain); + ExitOnFailure(hr, "Failed to build user and domain name for CustomActionData"); + hr = WcaWriteStringToCaData(wzDomainUser, &pwzCustomActionData); + ExitOnFailure(hr, "Failed to add server Domain\\UserName to CustomActionData"); + + hr = WcaWriteIntegerToCaData(pss->nPermissions, &pwzCustomActionData); + ExitOnFailure(hr, "Failed to add permissions to CustomActionData"); + } + else + { + hr = WcaWriteIntegerToCaData(pss->nUserPermissionCount, &pwzCustomActionData); + ExitOnFailure(hr, "Failed to add additional user permission count to CustomActionData"); + } + + if (pss->nUserPermissionCount > 0) + { + nCounter = 0; + for (pExUserPermsList = pss->pExUserPerms; pExUserPermsList; pExUserPermsList = pExUserPermsList->pExUserPermsNext) + { + Assert(nCounter < pss->nUserPermissionCount); + + hr = UserBuildDomainUserName(wzDomainUser, countof(wzDomainUser), pExUserPermsList->scau.wzName, pExUserPermsList->scau.wzDomain); + ExitOnFailure(hr, "Failed to build user and domain name for CustomActionData"); + hr = WcaWriteStringToCaData(wzDomainUser, &pwzCustomActionData); + ExitOnFailure(hr, "Failed to add server Domain\\UserName to CustomActionData"); + + hr = WcaWriteIntegerToCaData((int)pExUserPermsList->accessMode, &pwzCustomActionData); + ExitOnFailure(hr, "Failed to add access mode to CustomActionData"); + + hr = WcaWriteIntegerToCaData(pExUserPermsList->nPermissions, &pwzCustomActionData); + ExitOnFailure(hr, "Failed to add permissions to CustomActionData"); + ++nCounter; + } + Assert(nCounter == pss->nUserPermissionCount); + } + + // Schedule the rollback first + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"CreateSmbRollback"), pwzRollbackCustomActionData, COST_SMB_DROPSMB); + ExitOnFailure(hr, "Failed to schedule DropSmb action"); + + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"CreateSmb"), pwzCustomActionData, COST_SMB_CREATESMB); + ExitOnFailure(hr, "Failed to schedule CreateSmb action"); + +LExit: + ReleaseStr(pwzRollbackCustomActionData); + ReleaseStr(pwzCustomActionData); + + if (pExUserPermsList) + { + ScaExUserPermsSmbFreeList(pExUserPermsList); + } + + return hr; +} + + +/******************************************************************** + ScaSmbInstall - for every file share, schedule the create custom action + +********************************************************************/ +HRESULT ScaSmbInstall(SCA_SMB* pssList) +{ + HRESULT hr = S_FALSE; // assume nothing will be done + SCA_SMB* pss = NULL; + + for (pss = pssList; pss; pss = pss->pssNext) + { + // if installing this component + if (WcaIsInstalling(pss->isInstalled, pss->isAction) ) + { + hr = SchedCreateSmb(pss); + ExitOnFailure(hr, "Failed to schedule the creation of the fileshare: %ls", pss->wzShareName); + } + } + +LExit: + return hr; +} + + +/******************************************************************** + SchedDropSmb - schedule one instance of a file share removal + +********************************************************************/ +HRESULT SchedDropSmb(SCA_SMB* pss) +{ + HRESULT hr = S_OK; + + WCHAR* pwzCustomActionData = NULL; + WCHAR* pwzRollbackCustomActionData = NULL; + SCA_SMB_EX_USER_PERMS *pExUserPermsList = NULL; + SCA_SMB_EX_USER_PERMS *pExUserPerm = NULL; + WCHAR wzDomainUser[255]; // "domain\user" + DWORD dwUserPermsCount = 0; + + // roll back DropSmb + hr = WcaWriteStringToCaData(pss->wzShareName, &pwzRollbackCustomActionData); + ExitOnFailure(hr, "failed to add ShareName to CustomActionData"); + + hr = WcaWriteStringToCaData(pss->wzDescription, &pwzRollbackCustomActionData); + ExitOnFailure(hr, "Failed to add server name to CustomActionData"); + + hr = WcaWriteStringToCaData(pss->wzDirectory, &pwzRollbackCustomActionData); + ExitOnFailure(hr, "Failed to add full path instance to CustomActionData"); + + hr = WcaWriteStringToCaData(L"1", &pwzRollbackCustomActionData); + ExitOnFailure(hr, "Failed to add useintegrated flag to CustomActionData"); + + hr = RetrieveFileShareUserPerm(pss, &pExUserPermsList, &dwUserPermsCount); + ExitOnFailure(hr, "Failed to retrieve SMBShare's user permissions"); + + hr = WcaWriteIntegerToCaData((int)dwUserPermsCount, &pwzRollbackCustomActionData); + ExitOnFailure(hr, "Failed to add additional user permission count to CustomActionData"); + + for (pExUserPerm = pExUserPermsList; pExUserPerm; pExUserPerm = pExUserPerm->pExUserPermsNext) + { + hr = UserBuildDomainUserName(wzDomainUser, countof(wzDomainUser), pExUserPerm->scau.wzName, pExUserPerm->scau.wzDomain); + ExitOnFailure(hr, "Failed to build user and domain name for CustomActionData"); + hr = WcaWriteStringToCaData(wzDomainUser, &pwzRollbackCustomActionData); + ExitOnFailure(hr, "Failed to add server Domain\\UserName to CustomActionData"); + + hr = WcaWriteIntegerToCaData((int)pExUserPerm->accessMode, &pwzRollbackCustomActionData); + ExitOnFailure(hr, "Failed to add access mode to CustomActionData"); + + hr = WcaWriteIntegerToCaData(pExUserPerm->nPermissions, &pwzRollbackCustomActionData); + ExitOnFailure(hr, "Failed to add permissions to CustomActionData"); + } + + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"DropSmbRollback"), pwzRollbackCustomActionData, COST_SMB_CREATESMB); + ExitOnFailure(hr, "Failed to schedule DropSmbRollback action"); + + // DropSMB + hr = WcaWriteStringToCaData(pss->wzShareName, &pwzCustomActionData); + ExitOnFailure(hr, "failed to add ShareName to CustomActionData"); + + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"DropSmb"), pwzCustomActionData, COST_SMB_DROPSMB); + ExitOnFailure(hr, "Failed to schedule DropSmb action"); + +LExit: + ReleaseStr(pwzCustomActionData); + + if (pExUserPermsList) + { + ScaExUserPermsSmbFreeList(pExUserPermsList); + } + + return hr; + +} + + +/******************************************************************** + ScaSmbUninstall - for every file share, schedule the drop custom action + +********************************************************************/ +HRESULT ScaSmbUninstall(SCA_SMB* pssList) +{ + HRESULT hr = S_FALSE; // assume nothing will be done + SCA_SMB* pss = NULL; + + for (pss = pssList; pss; pss = pss->pssNext) + { + // if uninstalling this component + if (WcaIsUninstalling(pss->isInstalled, pss->isAction) ) + { + hr = SchedDropSmb(pss); + ExitOnFailure(hr, "Failed to remove file share %ls", pss->wzShareName); + } + } + +LExit: + return hr; +} + +LPCWSTR vcsSmbExUserPermsQuery = L"SELECT `FileShare_`,`User_`,`Permissions` " + L"FROM `Wix4FileSharePermissions` WHERE `FileShare_`=?"; + +enum eSmbUserPermsQuery { + ssupqFileShare = 1, + ssupqUser, + ssupqPermissions + +}; + + +/******************************************************************** + ScaSmbExPermsRead - for Every entry in File Permissions table add a + User Name & Permissions structure to the List + +********************************************************************/ +HRESULT ScaSmbExPermsRead(SCA_SMB* pss) +{ + HRESULT hr = S_OK; + PMSIHANDLE hView, hRec; + + LPWSTR pwzData = NULL; + SCA_SMB_EX_USER_PERMS* pExUserPermsList = pss->pExUserPerms; + SCA_SMB_EX_USER_PERMS* pExUserPerms = NULL; + int nCounter = 0; + + hRec = ::MsiCreateRecord(1); + hr = WcaSetRecordString(hRec, 1, pss->wzId); + ExitOnFailure(hr, "Failed to look up FileShare"); + + hr = WcaOpenView(vcsSmbExUserPermsQuery, &hView); + ExitOnFailure(hr, "Failed to open view on Wix4FileSharePermissions table"); + hr = WcaExecuteView(hView, hRec); + ExitOnFailure(hr, "Failed to execute view on Wix4FileSharePermissions table"); + + // loop through all User/Permissions paris returned + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + pExUserPerms = NewExUserPermsSmb(); + if (!pExUserPerms) + { + hr = E_OUTOFMEMORY; + break; + } + Assert(pExUserPerms); + ::ZeroMemory(pExUserPerms, sizeof(*pExUserPerms)); + + hr = WcaGetRecordString(hRec, ssupqUser, &pwzData); + ExitOnFailure(hr, "Failed to get Wix4FileSharePermissions.User"); + hr = ScaGetUser(pwzData, &pExUserPerms->scau); + ExitOnFailure(hr, "Failed to get user information for fileshare: '%ls'", pss->wzShareName); + + hr = WcaGetRecordInteger(hRec, ssupqPermissions, &pExUserPerms->nPermissions); + ExitOnFailure(hr, "Failed to get Wix4FileSharePermissions.Permissions"); + pExUserPerms->accessMode = SET_ACCESS; // we only support SET_ACCESS here + + pExUserPermsList = AddExUserPermsSmbToList(pExUserPermsList, pExUserPerms); + ++nCounter; + pExUserPerms = NULL; // set the smb NULL so it doesn't accidentally get freed below + } + + if (E_NOMOREITEMS == hr) + { + hr = S_OK; + pss->pExUserPerms = pExUserPermsList; + pss->nUserPermissionCount = nCounter; + } + ExitOnFailure(hr, "Failure occured while processing FileShare table"); + +LExit: + // if anything was left over after an error clean it all up + if (pExUserPerms) + { + ScaExUserPermsSmbFreeList(pExUserPerms); + } + + ReleaseStr(pwzData); + + return hr; +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + +LPCWSTR vcsUserQuery = L"SELECT `Wix4User`, `Component_`, `Name`, `Domain`, `Password` FROM `Wix4User` WHERE `Wix4User`=?"; +enum eUserQuery { vuqUser = 1, vuqComponent, vuqName, vuqDomain, vuqPassword }; + +LPCWSTR vcsGroupQuery = L"SELECT `Wix4Group`, `Component_`, `Name`, `Domain` FROM `Wix4Group` WHERE `Wix4Group`=?"; +enum eGroupQuery { vgqGroup = 1, vgqComponent, vgqName, vgqDomain }; + +LPCWSTR vcsUserGroupQuery = L"SELECT `Wix4User_`, `Wix4Group_` FROM `Wix4UserGroup` WHERE `Wix4User_`=?"; +enum eUserGroupQuery { vugqUser = 1, vugqGroup }; + +LPCWSTR vActionableQuery = L"SELECT `Wix4User`,`Component_`,`Name`,`Domain`,`Password`,`Attributes` FROM `Wix4User` WHERE `Component_` IS NOT NULL"; +enum eActionableQuery { vaqUser = 1, vaqComponent, vaqName, vaqDomain, vaqPassword, vaqAttributes }; + + +static HRESULT AddUserToList( + __inout SCA_USER** ppsuList + ); + +static HRESULT AddGroupToList( + __inout SCA_GROUP** ppsgList + ); + + +HRESULT __stdcall ScaGetUser( + __in LPCWSTR wzUser, + __out SCA_USER* pscau + ) +{ + if (!wzUser || !pscau) + { + return E_INVALIDARG; + } + + HRESULT hr = S_OK; + PMSIHANDLE hView, hRec; + + LPWSTR pwzData = NULL; + + // clear struct and bail right away if no user key was passed to search for + ::ZeroMemory(pscau, sizeof(*pscau)); + if (!*wzUser) + { + ExitFunction1(hr = S_OK); + } + + hRec = ::MsiCreateRecord(1); + hr = WcaSetRecordString(hRec, 1, wzUser); + ExitOnFailure(hr, "Failed to look up User"); + + hr = WcaOpenView(vcsUserQuery, &hView); + ExitOnFailure(hr, "Failed to open view on Wix4User table"); + hr = WcaExecuteView(hView, hRec); + ExitOnFailure(hr, "Failed to execute view on Wix4User table"); + + hr = WcaFetchSingleRecord(hView, &hRec); + if (S_OK == hr) + { + hr = WcaGetRecordString(hRec, vuqUser, &pwzData); + ExitOnFailure(hr, "Failed to get Wix4User.User"); + hr = ::StringCchCopyW(pscau->wzKey, countof(pscau->wzKey), pwzData); + ExitOnFailure(hr, "Failed to copy key string to user object"); + + hr = WcaGetRecordString(hRec, vuqComponent, &pwzData); + ExitOnFailure(hr, "Failed to get Wix4User.Component_"); + hr = ::StringCchCopyW(pscau->wzComponent, countof(pscau->wzComponent), pwzData); + ExitOnFailure(hr, "Failed to copy component string to user object"); + + hr = WcaGetRecordFormattedString(hRec, vuqName, &pwzData); + ExitOnFailure(hr, "Failed to get Wix4User.Name"); + hr = ::StringCchCopyW(pscau->wzName, countof(pscau->wzName), pwzData); + ExitOnFailure(hr, "Failed to copy name string to user object"); + + hr = WcaGetRecordFormattedString(hRec, vuqDomain, &pwzData); + ExitOnFailure(hr, "Failed to get Wix4User.Domain"); + hr = ::StringCchCopyW(pscau->wzDomain, countof(pscau->wzDomain), pwzData); + ExitOnFailure(hr, "Failed to copy domain string to user object"); + + hr = WcaGetRecordFormattedString(hRec, vuqPassword, &pwzData); + ExitOnFailure(hr, "Failed to get Wix4User.Password"); + hr = ::StringCchCopyW(pscau->wzPassword, countof(pscau->wzPassword), pwzData); + ExitOnFailure(hr, "Failed to copy password string to user object"); + } + else if (E_NOMOREITEMS == hr) + { + WcaLog(LOGMSG_STANDARD, "Error: Cannot locate Wix4User.User='%ls'", wzUser); + hr = E_FAIL; + } + else + { + ExitOnFailure(hr, "Error or found multiple matching Wix4User rows"); + } + +LExit: + ReleaseStr(pwzData); + + return hr; +} + +HRESULT __stdcall ScaGetUserDeferred( + __in LPCWSTR wzUser, + __in WCA_WRAPQUERY_HANDLE hUserQuery, + __out SCA_USER* pscau + ) +{ + if (!wzUser || !pscau) + { + return E_INVALIDARG; + } + + HRESULT hr = S_OK; + MSIHANDLE hRec, hRecTest; + + LPWSTR pwzData = NULL; + + // clear struct and bail right away if no user key was passed to search for + ::ZeroMemory(pscau, sizeof(*pscau)); + if (!*wzUser) + { + ExitFunction1(hr = S_OK); + } + + // Reset back to the first record + WcaFetchWrappedReset(hUserQuery); + + hr = WcaFetchWrappedRecordWhereString(hUserQuery, vuqUser, wzUser, &hRec); + if (S_OK == hr) + { + hr = WcaFetchWrappedRecordWhereString(hUserQuery, vuqUser, wzUser, &hRecTest); + if (S_OK == hr) + { + AssertSz(FALSE, "Found multiple matching Wix4User rows"); + } + + hr = WcaGetRecordString(hRec, vuqUser, &pwzData); + ExitOnFailure(hr, "Failed to get Wix4User.User"); + hr = ::StringCchCopyW(pscau->wzKey, countof(pscau->wzKey), pwzData); + ExitOnFailure(hr, "Failed to copy key string to user object (in deferred CA)"); + + hr = WcaGetRecordString(hRec, vuqComponent, &pwzData); + ExitOnFailure(hr, "Failed to get Wix4User.Component_"); + hr = ::StringCchCopyW(pscau->wzComponent, countof(pscau->wzComponent), pwzData); + ExitOnFailure(hr, "Failed to copy component string to user object (in deferred CA)"); + + hr = WcaGetRecordString(hRec, vuqName, &pwzData); + ExitOnFailure(hr, "Failed to get Wix4User.Name"); + hr = ::StringCchCopyW(pscau->wzName, countof(pscau->wzName), pwzData); + ExitOnFailure(hr, "Failed to copy name string to user object (in deferred CA)"); + + hr = WcaGetRecordString(hRec, vuqDomain, &pwzData); + ExitOnFailure(hr, "Failed to get Wix4User.Domain"); + hr = ::StringCchCopyW(pscau->wzDomain, countof(pscau->wzDomain), pwzData); + ExitOnFailure(hr, "Failed to copy domain string to user object (in deferred CA)"); + + hr = WcaGetRecordString(hRec, vuqPassword, &pwzData); + ExitOnFailure(hr, "Failed to get Wix4User.Password"); + hr = ::StringCchCopyW(pscau->wzPassword, countof(pscau->wzPassword), pwzData); + ExitOnFailure(hr, "Failed to copy password string to user object (in deferred CA)"); + } + else if (E_NOMOREITEMS == hr) + { + WcaLog(LOGMSG_STANDARD, "Error: Cannot locate Wix4User.User='%ls'", wzUser); + hr = E_FAIL; + } + else + { + ExitOnFailure(hr, "Error fetching single Wix4User row"); + } + +LExit: + ReleaseStr(pwzData); + + return hr; +} + + +HRESULT __stdcall ScaGetGroup( + __in LPCWSTR wzGroup, + __out SCA_GROUP* pscag + ) +{ + if (!wzGroup || !pscag) + { + return E_INVALIDARG; + } + + HRESULT hr = S_OK; + PMSIHANDLE hView, hRec; + + LPWSTR pwzData = NULL; + + hRec = ::MsiCreateRecord(1); + hr = WcaSetRecordString(hRec, 1, wzGroup); + ExitOnFailure(hr, "Failed to look up Group"); + + hr = WcaOpenView(vcsGroupQuery, &hView); + ExitOnFailure(hr, "Failed to open view on Wix4Group table"); + hr = WcaExecuteView(hView, hRec); + ExitOnFailure(hr, "Failed to execute view on Wix4Group table"); + + hr = WcaFetchSingleRecord(hView, &hRec); + if (S_OK == hr) + { + hr = WcaGetRecordString(hRec, vgqGroup, &pwzData); + ExitOnFailure(hr, "Failed to get Wix4Group.Wix4Group."); + hr = ::StringCchCopyW(pscag->wzKey, countof(pscag->wzKey), pwzData); + ExitOnFailure(hr, "Failed to copy Wix4Group.Wix4Group."); + + hr = WcaGetRecordString(hRec, vgqComponent, &pwzData); + ExitOnFailure(hr, "Failed to get Wix4Group.Component_"); + hr = ::StringCchCopyW(pscag->wzComponent, countof(pscag->wzComponent), pwzData); + ExitOnFailure(hr, "Failed to copy Wix4Group.Component_."); + + hr = WcaGetRecordFormattedString(hRec, vgqName, &pwzData); + ExitOnFailure(hr, "Failed to get Wix4Group.Name"); + hr = ::StringCchCopyW(pscag->wzName, countof(pscag->wzName), pwzData); + ExitOnFailure(hr, "Failed to copy Wix4Group.Name."); + + hr = WcaGetRecordFormattedString(hRec, vgqDomain, &pwzData); + ExitOnFailure(hr, "Failed to get Wix4Group.Domain"); + hr = ::StringCchCopyW(pscag->wzDomain, countof(pscag->wzDomain), pwzData); + ExitOnFailure(hr, "Failed to copy Wix4Group.Domain."); + } + else if (E_NOMOREITEMS == hr) + { + WcaLog(LOGMSG_STANDARD, "Error: Cannot locate Wix4Group.Wix4Group='%ls'", wzGroup); + hr = E_FAIL; + } + else + { + ExitOnFailure(hr, "Error or found multiple matching Wix4Group rows"); + } + +LExit: + ReleaseStr(pwzData); + + return hr; +} + + +void ScaUserFreeList( + __in SCA_USER* psuList + ) +{ + SCA_USER* psuDelete = psuList; + while (psuList) + { + psuDelete = psuList; + psuList = psuList->psuNext; + + ScaGroupFreeList(psuDelete->psgGroups); + MemFree(psuDelete); + } +} + + +void ScaGroupFreeList( + __in SCA_GROUP* psgList + ) +{ + SCA_GROUP* psgDelete = psgList; + while (psgList) + { + psgDelete = psgList; + psgList = psgList->psgNext; + + MemFree(psgDelete); + } +} + + +HRESULT ScaUserRead( + __out SCA_USER** ppsuList + ) +{ + //Assert(FALSE); + Assert(ppsuList); + + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + PMSIHANDLE hView, hRec, hUserRec, hUserGroupView; + + LPWSTR pwzData = NULL; + + BOOL fUserGroupExists = FALSE; + + SCA_USER *psu = NULL; + + INSTALLSTATE isInstalled, isAction; + + if (S_OK != WcaTableExists(L"Wix4User")) + { + WcaLog(LOGMSG_VERBOSE, "Wix4User Table does not exist, exiting"); + ExitFunction1(hr = S_FALSE); + } + + if (S_OK == WcaTableExists(L"Wix4UserGroup")) + { + fUserGroupExists = TRUE; + } + + // + // loop through all the users + // + hr = WcaOpenExecuteView(vActionableQuery, &hView); + ExitOnFailure(hr, "failed to open view on Wix4User table"); + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + hr = WcaGetRecordString(hRec, vaqComponent, &pwzData); + ExitOnFailure(hr, "failed to get Wix4User.Component"); + + er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &isInstalled, &isAction); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "failed to get Component state for Wix4User"); + + // don't bother if we aren't installing or uninstalling this component + if (WcaIsInstalling(isInstalled, isAction) || WcaIsUninstalling(isInstalled, isAction)) + { + // + // Add the user to the list and populate it's values + // + hr = AddUserToList(ppsuList); + ExitOnFailure(hr, "failed to add user to list"); + + psu = *ppsuList; + + psu->isInstalled = isInstalled; + psu->isAction = isAction; + hr = ::StringCchCopyW(psu->wzComponent, countof(psu->wzComponent), pwzData); + ExitOnFailure(hr, "failed to copy component name: %ls", pwzData); + + hr = WcaGetRecordString(hRec, vaqUser, &pwzData); + ExitOnFailure(hr, "failed to get Wix4User.User"); + hr = ::StringCchCopyW(psu->wzKey, countof(psu->wzKey), pwzData); + ExitOnFailure(hr, "failed to copy user key: %ls", pwzData); + + hr = WcaGetRecordFormattedString(hRec, vaqName, &pwzData); + ExitOnFailure(hr, "failed to get Wix4User.Name"); + hr = ::StringCchCopyW(psu->wzName, countof(psu->wzName), pwzData); + ExitOnFailure(hr, "failed to copy user name: %ls", pwzData); + + hr = WcaGetRecordFormattedString(hRec, vaqDomain, &pwzData); + ExitOnFailure(hr, "failed to get Wix4User.Domain"); + hr = ::StringCchCopyW(psu->wzDomain, countof(psu->wzDomain), pwzData); + ExitOnFailure(hr, "failed to copy user domain: %ls", pwzData); + + hr = WcaGetRecordFormattedString(hRec, vaqPassword, &pwzData); + ExitOnFailure(hr, "failed to get Wix4User.Password"); + hr = ::StringCchCopyW(psu->wzPassword, countof(psu->wzPassword), pwzData); + ExitOnFailure(hr, "failed to copy user password"); + + hr = WcaGetRecordInteger(hRec, vaqAttributes, &psu->iAttributes); + ExitOnFailure(hr, "failed to get Wix4User.Attributes"); + + // Check if this user is to be added to any groups + if (fUserGroupExists) + { + hUserRec = ::MsiCreateRecord(1); + hr = WcaSetRecordString(hUserRec, 1, psu->wzKey); + ExitOnFailure(hr, "Failed to create user record for querying Wix4UserGroup table"); + + hr = WcaOpenView(vcsUserGroupQuery, &hUserGroupView); + ExitOnFailure(hr, "Failed to open view on Wix4UserGroup table for user %ls", psu->wzKey); + hr = WcaExecuteView(hUserGroupView, hUserRec); + ExitOnFailure(hr, "Failed to execute view on Wix4UserGroup table for user: %ls", psu->wzKey); + + while (S_OK == (hr = WcaFetchRecord(hUserGroupView, &hRec))) + { + hr = WcaGetRecordString(hRec, vugqGroup, &pwzData); + ExitOnFailure(hr, "failed to get Wix4UserGroup.Group"); + + hr = AddGroupToList(&(psu->psgGroups)); + ExitOnFailure(hr, "failed to add group to list"); + + hr = ScaGetGroup(pwzData, psu->psgGroups); + ExitOnFailure(hr, "failed to get information for group: %ls", pwzData); + } + + if (E_NOMOREITEMS == hr) + { + hr = S_OK; + } + ExitOnFailure(hr, "failed to enumerate selected rows from Wix4UserGroup table"); + } + } + } + + if (E_NOMOREITEMS == hr) + { + hr = S_OK; + } + ExitOnFailure(hr, "failed to enumerate selected rows from Wix4User table"); + +LExit: + ReleaseStr(pwzData); + + return hr; +} + + +static HRESULT WriteGroupInfo( + __in SCA_GROUP* psgList, + __in LPWSTR *ppwzActionData + ) +{ + HRESULT hr = S_OK; + + for (SCA_GROUP* psg = psgList; psg; psg = psg->psgNext) + { + hr = WcaWriteStringToCaData(psg->wzName, ppwzActionData); + ExitOnFailure(hr, "failed to add group name to custom action data: %ls", psg->wzName); + + hr = WcaWriteStringToCaData(psg->wzDomain, ppwzActionData); + ExitOnFailure(hr, "failed to add group domain to custom action data: %ls", psg->wzDomain); + } + +LExit: + return hr; +} + + +// Behaves like WriteGroupInfo, but it filters out groups the user is currently a member of, +// because we don't want to rollback those +static HRESULT WriteGroupRollbackInfo( + __in LPCWSTR pwzName, + __in LPCWSTR pwzDomain, + __in SCA_GROUP* psgList, + __in LPWSTR *ppwzActionData + ) +{ + HRESULT hr = S_OK; + BOOL fIsMember = FALSE; + + for (SCA_GROUP* psg = psgList; psg; psg = psg->psgNext) + { + hr = UserCheckIsMember(pwzName, pwzDomain, psg->wzName, psg->wzDomain, &fIsMember); + if (FAILED(hr)) + { + 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); + hr = S_OK; + continue; + } + + // If the user is currently a member, we don't want to undo that on rollback, so skip adding + // this group record to the list of groups to rollback + if (fIsMember) + { + continue; + } + + hr = WcaWriteStringToCaData(psg->wzName, ppwzActionData); + ExitOnFailure(hr, "failed to add group name to custom action data: %ls", psg->wzName); + + hr = WcaWriteStringToCaData(psg->wzDomain, ppwzActionData); + ExitOnFailure(hr, "failed to add group domain to custom action data: %ls", psg->wzDomain); + } + +LExit: + return hr; +} + + +/* **************************************************************** +ScaUserExecute - Schedules user account creation or removal based on +component state. + +******************************************************************/ +HRESULT ScaUserExecute( + __in SCA_USER *psuList + ) +{ + HRESULT hr = S_OK; + DWORD er = 0; + PDOMAIN_CONTROLLER_INFOW pDomainControllerInfo = NULL; + + LPWSTR pwzBaseScriptKey = NULL; + DWORD cScriptKey = 0; + + USER_INFO_0 *pUserInfo = NULL; + LPWSTR pwzScriptKey = NULL; + LPWSTR pwzActionData = NULL; + LPWSTR pwzRollbackData = NULL; + + // Get the base script key for this CustomAction. + hr = WcaCaScriptCreateKey(&pwzBaseScriptKey); + ExitOnFailure(hr, "Failed to get encoding key."); + + // Loop through all the users to be configured. + for (SCA_USER *psu = psuList; psu; psu = psu->psuNext) + { + USER_EXISTS ueUserExists = USER_EXISTS_INDETERMINATE; + + // Always put the User Name and Domain plus Attributes on the front of the CustomAction + // data. Sometimes we'll add more data. + Assert(psu->wzName); + hr = WcaWriteStringToCaData(psu->wzName, &pwzActionData); + ExitOnFailure(hr, "Failed to add user name to custom action data: %ls", psu->wzName); + hr = WcaWriteStringToCaData(psu->wzDomain, &pwzActionData); + ExitOnFailure(hr, "Failed to add user domain to custom action data: %ls", psu->wzDomain); + hr = WcaWriteIntegerToCaData(psu->iAttributes, &pwzActionData); + ExitOnFailure(hr, "failed to add user attributes to custom action data for user: %ls", psu->wzKey); + + // Check to see if the user already exists since we have to be very careful when adding + // and removing users. Note: MSDN says that it is safe to call these APIs from any + // user, so we should be safe calling it during immediate mode. + er = ::NetApiBufferAllocate(sizeof(USER_INFO_0), reinterpret_cast(&pUserInfo)); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "Failed to allocate memory to check existence of user: %ls", psu->wzName); + + LPCWSTR wzDomain = psu->wzDomain; + if (wzDomain && *wzDomain) + { + er = ::DsGetDcNameW(NULL, wzDomain, NULL, NULL, NULL, &pDomainControllerInfo); + if (RPC_S_SERVER_UNAVAILABLE == er) + { + // MSDN says, if we get the above error code, try again with the "DS_FORCE_REDISCOVERY" flag + er = ::DsGetDcNameW(NULL, wzDomain, NULL, NULL, DS_FORCE_REDISCOVERY, &pDomainControllerInfo); + } + if (ERROR_SUCCESS == er) + { + wzDomain = pDomainControllerInfo->DomainControllerName + 2; //Add 2 so that we don't get the \\ prefix + } + } + + er = ::NetUserGetInfo(wzDomain, psu->wzName, 0, reinterpret_cast(pUserInfo)); + if (NERR_Success == er) + { + ueUserExists = USER_EXISTS_YES; + } + else if (NERR_UserNotFound == er) + { + ueUserExists = USER_EXISTS_NO; + } + else + { + ueUserExists = USER_EXISTS_INDETERMINATE; + hr = HRESULT_FROM_WIN32(er); + WcaLog(LOGMSG_VERBOSE, "Failed to check existence of domain: %ls, user: %ls (error code 0x%x) - continuing", wzDomain, psu->wzName, hr); + hr = S_OK; + er = ERROR_SUCCESS; + } + + if (WcaIsInstalling(psu->isInstalled, psu->isAction)) + { + // If the user exists, check to see if we are supposed to fail if user the exists before + // the install. + if (USER_EXISTS_YES == ueUserExists) + { + // Reinstalls will always fail if we don't remove the check for "fail if exists". + if (WcaIsReInstalling(psu->isInstalled, psu->isAction)) + { + psu->iAttributes &= ~SCAU_FAIL_IF_EXISTS; + } + + if ((SCAU_FAIL_IF_EXISTS & (psu->iAttributes)) && !(SCAU_UPDATE_IF_EXISTS & (psu->iAttributes))) + { + hr = HRESULT_FROM_WIN32(NERR_UserExists); + MessageExitOnFailure(hr, msierrUSRFailedUserCreateExists, "Failed to create user: %ls because user already exists.", psu->wzName); + } + } + + // Rollback only if the user already exists, we couldn't determine if the user exists, or we are going to create the user + if ((USER_EXISTS_YES == ueUserExists) || (USER_EXISTS_INDETERMINATE == ueUserExists) || !(psu->iAttributes & SCAU_DONT_CREATE_USER)) + { + ++cScriptKey; + hr = StrAllocFormatted(&pwzScriptKey, L"%ls%u", pwzBaseScriptKey, cScriptKey); + ExitOnFailure(hr, "Failed to create encoding key."); + + // Write the script key to CustomActionData for install and rollback so information can be passed to rollback. + hr = WcaWriteStringToCaData(pwzScriptKey, &pwzActionData); + ExitOnFailure(hr, "Failed to add encoding key to custom action data."); + + hr = WcaWriteStringToCaData(pwzScriptKey, &pwzRollbackData); + ExitOnFailure(hr, "Failed to add encoding key to rollback custom action data."); + + INT iRollbackUserAttributes = psu->iAttributes; + + // If the user already exists, ensure this is accounted for in rollback + if (USER_EXISTS_YES == ueUserExists) + { + iRollbackUserAttributes |= SCAU_DONT_CREATE_USER; + } + else + { + iRollbackUserAttributes &= ~SCAU_DONT_CREATE_USER; + } + + // The deferred CA determines when to rollback User Rights Assignments so these should never be set. + iRollbackUserAttributes &= ~SCAU_ALLOW_LOGON_AS_SERVICE; + iRollbackUserAttributes &= ~SCAU_ALLOW_LOGON_AS_BATCH; + + hr = WcaWriteStringToCaData(psu->wzName, &pwzRollbackData); + ExitOnFailure(hr, "Failed to add user name to rollback custom action data: %ls", psu->wzName); + hr = WcaWriteStringToCaData(psu->wzDomain, &pwzRollbackData); + ExitOnFailure(hr, "Failed to add user domain to rollback custom action data: %ls", psu->wzDomain); + hr = WcaWriteIntegerToCaData(iRollbackUserAttributes, &pwzRollbackData); + ExitOnFailure(hr, "failed to add user attributes to rollback custom action data for user: %ls", psu->wzKey); + + // If the user already exists, add relevant group information to rollback data + if (USER_EXISTS_YES == ueUserExists || USER_EXISTS_INDETERMINATE == ueUserExists) + { + hr = WriteGroupRollbackInfo(psu->wzName, psu->wzDomain, psu->psgGroups, &pwzRollbackData); + ExitOnFailure(hr, "failed to add group information to rollback custom action data"); + } + + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"CreateUserRollback"), pwzRollbackData, COST_USER_DELETE); + ExitOnFailure(hr, "failed to schedule CreateUserRollback"); + } + else + { + // Write empty script key to CustomActionData since there is no rollback. + hr = WcaWriteStringToCaData(L"", &pwzActionData); + ExitOnFailure(hr, "Failed to add empty encoding key to custom action data."); + } + + // + // Schedule the creation now. + // + hr = WcaWriteStringToCaData(psu->wzPassword, &pwzActionData); + ExitOnFailure(hr, "failed to add user password to custom action data for user: %ls", psu->wzKey); + + // Add user's group information to custom action data + hr = WriteGroupInfo(psu->psgGroups, &pwzActionData); + ExitOnFailure(hr, "failed to add group information to custom action data"); + + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"CreateUser"), pwzActionData, COST_USER_ADD); + ExitOnFailure(hr, "failed to schedule CreateUser"); + } + else if (((USER_EXISTS_YES == ueUserExists) || (USER_EXISTS_INDETERMINATE == ueUserExists)) && WcaIsUninstalling(psu->isInstalled, psu->isAction) && !(psu->iAttributes & SCAU_DONT_REMOVE_ON_UNINSTALL)) + { + // 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 + hr = WriteGroupInfo(psu->psgGroups, &pwzActionData); + ExitOnFailure(hr, "failed to add group information to custom action data"); + + // + // Schedule the removal because the user exists and we don't have any flags set + // that say, don't remove the user on uninstall. + // + // Note: We can't rollback the removal of a user which is why RemoveUser is a commit + // CustomAction. + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RemoveUser"), pwzActionData, COST_USER_DELETE); + ExitOnFailure(hr, "failed to schedule RemoveUser"); + } + + ReleaseNullStr(pwzScriptKey); + ReleaseNullStr(pwzActionData); + ReleaseNullStr(pwzRollbackData); + if (pUserInfo) + { + ::NetApiBufferFree(static_cast(pUserInfo)); + pUserInfo = NULL; + } + if (pDomainControllerInfo) + { + ::NetApiBufferFree(static_cast(pDomainControllerInfo)); + pDomainControllerInfo = NULL; + } + } + +LExit: + ReleaseStr(pwzBaseScriptKey); + ReleaseStr(pwzScriptKey); + ReleaseStr(pwzActionData); + ReleaseStr(pwzRollbackData); + if (pUserInfo) + { + ::NetApiBufferFree(static_cast(pUserInfo)); + } + if (pDomainControllerInfo) + { + ::NetApiBufferFree(static_cast(pDomainControllerInfo)); + } + + return hr; +} + + +static HRESULT AddUserToList( + __inout SCA_USER** ppsuList + ) +{ + HRESULT hr = S_OK; + SCA_USER* psu = static_cast(MemAlloc(sizeof(SCA_USER), TRUE)); + ExitOnNull(psu, hr, E_OUTOFMEMORY, "failed to allocate memory for new user list element"); + + psu->psuNext = *ppsuList; + *ppsuList = psu; + +LExit: + return hr; +} + + +static HRESULT AddGroupToList( + __inout SCA_GROUP** ppsgList + ) +{ + HRESULT hr = S_OK; + SCA_GROUP* psg = static_cast(MemAlloc(sizeof(SCA_GROUP), TRUE)); + ExitOnNull(psg, hr, E_OUTOFMEMORY, "failed to allocate memory for new group list element"); + + psg->psgNext = *ppsgList; + *ppsgList = psg; + +LExit: + return hr; +} 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 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +enum USER_EXISTS +{ + USER_EXISTS_YES, + USER_EXISTS_NO, + USER_EXISTS_INDETERMINATE +}; + +// structs +struct SCA_GROUP +{ + WCHAR wzKey[MAX_DARWIN_KEY + 1]; + WCHAR wzComponent[MAX_DARWIN_KEY + 1]; + + WCHAR wzDomain[MAX_DARWIN_COLUMN + 1]; + WCHAR wzName[MAX_DARWIN_COLUMN + 1]; + + SCA_GROUP *psgNext; +}; + +struct SCA_USER +{ + WCHAR wzKey[MAX_DARWIN_KEY + 1]; + WCHAR wzComponent[MAX_DARWIN_KEY + 1]; + INSTALLSTATE isInstalled; + INSTALLSTATE isAction; + + WCHAR wzDomain[MAX_DARWIN_COLUMN + 1]; + WCHAR wzName[MAX_DARWIN_COLUMN + 1]; + WCHAR wzPassword[MAX_DARWIN_COLUMN + 1]; + INT iAttributes; + + SCA_GROUP *psgGroups; + + SCA_USER *psuNext; +}; + + +// prototypes +HRESULT __stdcall ScaGetUser( + __in LPCWSTR wzUser, + __out SCA_USER* pscau + ); +HRESULT __stdcall ScaGetUserDeferred( + __in LPCWSTR wzUser, + __in WCA_WRAPQUERY_HANDLE hUserQuery, + __out SCA_USER* pscau + ); +HRESULT __stdcall ScaGetGroup( + __in LPCWSTR wzGroup, + __out SCA_GROUP* pscag + ); +void ScaUserFreeList( + __in SCA_USER* psuList + ); +void ScaGroupFreeList( + __in SCA_GROUP* psgList + ); +HRESULT ScaUserRead( + __inout SCA_USER** ppsuList + ); +HRESULT ScaUserExecute( + __in SCA_USER *psuList + ); 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + +// structs +LPCWSTR wzQUERY_SECUREOBJECTS = L"SELECT `Wix4SecureObject`.`Wix4SecureObject`, `Wix4SecureObject`.`Table`, `Wix4SecureObject`.`Domain`, `Wix4SecureObject`.`User`, `Wix4SecureObject`.`Attributes`, " + L"`Wix4SecureObject`.`Permission`, `Wix4SecureObject`.`Component_`, `Component`.`Attributes` FROM `Wix4SecureObject`,`Component` WHERE " + L"`Wix4SecureObject`.`Component_`=`Component`.`Component`"; +enum eQUERY_SECUREOBJECTS { QSO_SECUREOBJECT = 1, QSO_TABLE, QSO_DOMAIN, QSO_USER, QSO_ATTRIBUTES, QSO_PERMISSION, QSO_COMPONENT, QSO_COMPATTRIBUTES }; + +LPCWSTR wzQUERY_REGISTRY = L"SELECT `Registry`.`Registry`, `Registry`.`Root`, `Registry`.`Key` FROM `Registry` WHERE `Registry`.`Registry`=?"; +enum eQUERY_OBJECTCOMPONENT { QSOC_REGISTRY = 1, QSOC_REGROOT, QSOC_REGKEY }; + +LPCWSTR wzQUERY_SERVICEINSTALL = L"SELECT `ServiceInstall`.`Name` FROM `ServiceInstall` WHERE `ServiceInstall`.`ServiceInstall`=?"; +enum eQUERY_SECURESERVICEINSTALL { QSSI_NAME = 1 }; + +enum eOBJECTTYPE { OT_UNKNOWN, OT_SERVICE, OT_FOLDER, OT_FILE, OT_REGISTRY }; + +enum eSECURE_OBJECT_ATTRIBUTE +{ + SECURE_OBJECT_ATTRIBUTE_INHERITABLE = 0x1, +}; + +static eOBJECTTYPE EObjectTypeFromString( + __in LPCWSTR pwzTable + ) +{ + if (NULL == pwzTable) + { + return OT_UNKNOWN; + } + + eOBJECTTYPE eType = OT_UNKNOWN; + + // ensure we're looking at a known table + if (0 == lstrcmpW(L"ServiceInstall", pwzTable)) + { + eType = OT_SERVICE; + } + else if (0 == lstrcmpW(L"CreateFolder", pwzTable)) + { + eType = OT_FOLDER; + } + else if (0 == lstrcmpW(L"File", pwzTable)) + { + eType = OT_FILE; + } + else if (0 == lstrcmpW(L"Registry", pwzTable)) + { + eType = OT_REGISTRY; + } + + return eType; +} + +static SE_OBJECT_TYPE SEObjectTypeFromString( + __in LPCWSTR pwzTable + ) +{ + if (NULL == pwzTable) + { + return SE_UNKNOWN_OBJECT_TYPE; + } + + SE_OBJECT_TYPE objectType = SE_UNKNOWN_OBJECT_TYPE; + + if (0 == lstrcmpW(L"ServiceInstall", pwzTable)) + { + objectType = SE_SERVICE; + } + else if (0 == lstrcmpW(L"CreateFolder", pwzTable) || 0 == lstrcmpW(L"File", pwzTable)) + { + objectType = SE_FILE_OBJECT; + } + else if (0 == lstrcmpW(L"Registry", pwzTable)) + { + objectType = SE_REGISTRY_KEY; + } + else + { + // Do nothing; we'll return SE_UNKNOWN_OBJECT_TYPE, and the caller should handle the situation + } + + return objectType; +} + +static HRESULT StoreACLRollbackInfo( + __in LPWSTR pwzObject, + __in LPCWSTR pwzTable + ) +{ + HRESULT hr = S_OK; + DWORD er = ERROR_SUCCESS; + PSECURITY_DESCRIPTOR psd = NULL; + SECURITY_DESCRIPTOR_CONTROL sdc = {0}; + DWORD dwRevision = 0; + LPWSTR pwzCustomActionData = NULL; + LPWSTR pwzSecurityInfo = NULL; + + Assert(pwzObject && pwzTable); + + SE_OBJECT_TYPE objectType = SEObjectTypeFromString(const_cast (pwzTable)); + + if (SE_UNKNOWN_OBJECT_TYPE != objectType) + { + er = ::GetNamedSecurityInfoW(pwzObject, objectType, DACL_SECURITY_INFORMATION, NULL, NULL, NULL, NULL, &psd); + if (ERROR_FILE_NOT_FOUND == er || ERROR_PATH_NOT_FOUND == er || ERROR_SERVICE_DOES_NOT_EXIST == HRESULT_CODE(er)) + { + // If the file, path or service doesn't exist yet, skip rollback without a message + hr = HRESULT_FROM_WIN32(er); + ExitFunction(); + } + + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Unable to schedule rollback for object: %ls", pwzObject); + + //Need to see if DACL is protected so getting Descriptor information + if (!::GetSecurityDescriptorControl(psd, &sdc, &dwRevision)) + { + ExitOnLastError(hr, "Unable to schedule rollback for object (failed to get security descriptor control): %ls", pwzObject); + } + + // Convert the security information to a string, and write this to the custom action data + if (!::ConvertSecurityDescriptorToStringSecurityDescriptorW(psd,SDDL_REVISION_1,DACL_SECURITY_INFORMATION,&pwzSecurityInfo,NULL)) + { + hr = E_UNEXPECTED; + ExitOnFailure(hr, "Unable to schedule rollback for object (failed to convert security descriptor to a valid security descriptor string): %ls", pwzObject); + } + + hr = WcaWriteStringToCaData(pwzObject, &pwzCustomActionData); + ExitOnFailure(hr, "failed to add object data to rollback CustomActionData"); + + hr = WcaWriteStringToCaData(pwzTable, &pwzCustomActionData); + ExitOnFailure(hr, "failed to add table name to rollback CustomActionData"); + + hr = WcaWriteStringToCaData(pwzSecurityInfo, &pwzCustomActionData); + ExitOnFailure(hr, "failed to add security info data to rollback CustomActionData"); + + // Write a 1 if DACL is protected, 0 otherwise + if (sdc & SE_DACL_PROTECTED) + { + hr = WcaWriteIntegerToCaData(1,&pwzCustomActionData); + ExitOnFailure(hr, "failed to add data to rollbackCustomActionData"); + } + else + { + hr = WcaWriteIntegerToCaData(0,&pwzCustomActionData); + ExitOnFailure(hr, "failed to add data to rollback CustomActionData"); + } + + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecSecureObjectsRollback"), pwzCustomActionData, COST_SECUREOBJECT); + ExitOnFailure(hr, "failed to schedule ExecSecureObjectsRollback for item: %ls of type: %ls", pwzObject, pwzTable); + + ReleaseStr(pwzCustomActionData); + pwzCustomActionData = NULL; + + } + else + { + MessageExitOnFailure(hr = E_UNEXPECTED, msierrSecureObjectsUnknownType, "unknown object type: %ls", pwzTable); + } +LExit: + ReleaseStr(pwzCustomActionData); + + if (psd) + { + ::LocalFree(psd); + } + + return hr; +} + +static HRESULT GetTargetPath( + __in eOBJECTTYPE eType, + __in LPCWSTR pwzSecureObject, + __out LPWSTR* ppwzTargetPath + ) +{ + HRESULT hr = S_OK; + + PMSIHANDLE hView = NULL; + PMSIHANDLE hRecObject = NULL; + PMSIHANDLE hRec = NULL; + + int iRoot = 0; + int iAllUsers = 0; + LPWSTR pwzKey = NULL; + LPWSTR pwzFormattedString = NULL; + + if (OT_SERVICE == eType) + { + hr = WcaTableExists(L"ServiceInstall"); + if (S_FALSE == hr) + { + hr = E_UNEXPECTED; + } + ExitOnFailure(hr, "failed to open ServiceInstall table to secure object"); + + hr = WcaOpenView(wzQUERY_SERVICEINSTALL, &hView); + ExitOnFailure(hr, "failed to open view on ServiceInstall table"); + + // create a record that stores the object to secure + hRec = MsiCreateRecord(1); + MsiRecordSetStringW(hRec, 1, pwzSecureObject); + + // execute a view looking for the object's ServiceInstall.ServiceInstall row. + hr = WcaExecuteView(hView, hRec); + ExitOnFailure(hr, "failed to execute view on ServiceInstall table"); + hr = WcaFetchSingleRecord(hView, &hRecObject); + ExitOnFailure(hr, "failed to fetch ServiceInstall row for secure object"); + + hr = WcaGetRecordFormattedString(hRecObject, QSSI_NAME, ppwzTargetPath); + ExitOnFailure(hr, "failed to get service name for secure object: %ls", pwzSecureObject); + } + else if (OT_FOLDER == eType) + { + hr = WcaGetTargetPath(pwzSecureObject, ppwzTargetPath); + ExitOnFailure(hr, "failed to get target path for directory id: %ls", pwzSecureObject); + } + else if (OT_FILE == eType) + { + hr = StrAllocFormatted(&pwzFormattedString, L"[#%s]", pwzSecureObject); + ExitOnFailure(hr, "failed to create formatted string for securing file object: %ls", pwzSecureObject); + + hr = WcaGetFormattedString(pwzFormattedString, ppwzTargetPath); + ExitOnFailure(hr, "failed to get file path from formatted string: %ls for secure object: %ls", pwzFormattedString, pwzSecureObject); + } + else if (OT_REGISTRY == eType) + { + hr = WcaTableExists(L"Registry"); + if (S_FALSE == hr) + { + hr = E_UNEXPECTED; + } + ExitOnFailure(hr, "failed to open Registry table to secure object"); + + hr = WcaOpenView(wzQUERY_REGISTRY, &hView); + ExitOnFailure(hr, "failed to open view on Registry table"); + + // create a record that stores the object to secure + hRec = MsiCreateRecord(1); + MsiRecordSetStringW(hRec, 1, pwzSecureObject); + + // execute a view looking for the object's Registry row + hr = WcaExecuteView(hView, hRec); + ExitOnFailure(hr, "failed to execute view on Registry table"); + hr = WcaFetchSingleRecord(hView, &hRecObject); + ExitOnFailure(hr, "failed to fetch Registry row for secure object"); + + hr = WcaGetRecordInteger(hRecObject, QSOC_REGROOT, &iRoot); + ExitOnFailure(hr, "Failed to get reg key root for secure object: %ls", pwzSecureObject); + + hr = WcaGetRecordFormattedString(hRecObject, QSOC_REGKEY, &pwzKey); + ExitOnFailure(hr, "Failed to get reg key for secure object: %ls", pwzSecureObject); + + // Decode the root value + if (-1 == iRoot) + { + // They didn't specify a root so that means it's either HKCU or HKLM depending on ALLUSERS property + hr = WcaGetIntProperty(L"ALLUSERS", &iAllUsers); + ExitOnFailure(hr, "failed to get value of ALLUSERS property"); + + if (1 == iAllUsers) + { + hr = StrAllocString(ppwzTargetPath, L"MACHINE\\", 0); + ExitOnFailure(hr, "failed to allocate target registry string with HKLM root"); + } + else + { + hr = StrAllocString(ppwzTargetPath, L"CURRENT_USER\\", 0); + ExitOnFailure(hr, "failed to allocate target registry string with HKCU root"); + } + } + else if (msidbRegistryRootClassesRoot == iRoot) + { + hr = StrAllocString(ppwzTargetPath, L"CLASSES_ROOT\\", 0); + ExitOnFailure(hr, "failed to allocate target registry string with HKCR root"); + } + else if (msidbRegistryRootCurrentUser == iRoot) + { + hr = StrAllocString(ppwzTargetPath, L"CURRENT_USER\\", 0); + ExitOnFailure(hr, "failed to allocate target registry string with HKCU root"); + } + else if (msidbRegistryRootLocalMachine == iRoot) + { + hr = StrAllocString(ppwzTargetPath, L"MACHINE\\", 0); + ExitOnFailure(hr, "failed to allocate target registry string with HKLM root"); + } + else if (msidbRegistryRootUsers == iRoot) + { + hr = StrAllocString(ppwzTargetPath, L"USERS\\", 0); + ExitOnFailure(hr, "failed to allocate target registry string with HKU root"); + } + else + { + ExitOnFailure(hr = E_UNEXPECTED, "Unknown registry key root specified for secure object: '%ls' root: %d", pwzSecureObject, iRoot); + } + + hr = StrAllocConcat(ppwzTargetPath, pwzKey, 0); + ExitOnFailure(hr, "Failed to concat key: %ls for secure object: %ls", pwzKey, pwzSecureObject); + } + else + { + AssertSz(FALSE, "How did you get here?"); + ExitOnFailure(hr = E_UNEXPECTED, "Unknown secure object type: %d", eType); + } + +LExit: + ReleaseStr(pwzFormattedString); + ReleaseStr(pwzKey); + + return hr; +} + +/****************************************************************** + SchedSecureObjects - entry point for SchedSecureObjects Custom Action + + called as Type 1 CustomAction (binary DLL) from Windows Installer + in InstallExecuteSequence, to schedule ExecSecureObjects +******************************************************************/ +extern "C" UINT __stdcall SchedSecureObjects( + __in MSIHANDLE hInstall + ) +{ +// AssertSz(FALSE, "debug SchedSecureObjects"); + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + LPWSTR pwzSecureObject = NULL; + LPWSTR pwzData = NULL; + LPWSTR pwzTable = NULL; + LPWSTR pwzTargetPath = NULL; + + PMSIHANDLE hView = NULL; + PMSIHANDLE hRec = NULL; + + INSTALLSTATE isInstalled; + INSTALLSTATE isAction; + + LPWSTR pwzCustomActionData = NULL; + + DWORD cObjects = 0; + eOBJECTTYPE eType = OT_UNKNOWN; + DWORD dwAttributes = 0; + + // + // initialize + // + hr = WcaInitialize(hInstall, "SchedSecureObjects"); + ExitOnFailure(hr, "failed to initialize"); + + // anything to do? + if (S_OK != WcaTableExists(L"Wix4SecureObject")) + { + WcaLog(LOGMSG_STANDARD, "Wix4SecureObject table doesn't exist, so there are no objects to secure."); + ExitFunction(); + } + + // + // loop through all the objects to be secured + // + hr = WcaOpenExecuteView(wzQUERY_SECUREOBJECTS, &hView); + ExitOnFailure(hr, "failed to open view on Wix4SecureObject table"); + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + hr = WcaGetRecordString(hRec, QSO_TABLE, &pwzTable); + ExitOnFailure(hr, "failed to get object table"); + + eType = EObjectTypeFromString(pwzTable); + + if (OT_UNKNOWN == eType) + { + ExitOnFailure(hr = E_INVALIDARG, "unknown SecureObject.Table: %ls", pwzTable); + } + + int iCompAttributes = 0; + hr = WcaGetRecordInteger(hRec, QSO_COMPATTRIBUTES, &iCompAttributes); + ExitOnFailure(hr, "failed to get Component attributes for secure object"); + + BOOL fIs64Bit = iCompAttributes & msidbComponentAttributes64bit; + + // Only process entries in the Wix4SecureObject table whose components match the bitness of this CA +#ifdef _WIN64 + if (!fIs64Bit) + { + continue; + } +#else + if (fIs64Bit) + { + continue; + } +#endif + + // Get the object to secure + hr = WcaGetRecordString(hRec, QSO_SECUREOBJECT, &pwzSecureObject); + ExitOnFailure(hr, "failed to get name of object"); + + hr = GetTargetPath(eType, pwzSecureObject, &pwzTargetPath); + ExitOnFailure(hr, "failed to get target path of object '%ls'", pwzSecureObject); + + hr = WcaGetRecordString(hRec, QSO_COMPONENT, &pwzData); + ExitOnFailure(hr, "failed to get Component name for secure object"); + + // + // if we are installing this Component + // + er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "failed to get install state for Component: %ls", pwzData); + + if (WcaIsInstalling(isInstalled, isAction)) + { + hr = WcaWriteStringToCaData(pwzTargetPath, &pwzCustomActionData); + ExitOnFailure(hr, "failed to add data to CustomActionData"); + + // add the data to the CustomActionData + hr = WcaGetRecordString(hRec, QSO_SECUREOBJECT, &pwzData); + ExitOnFailure(hr, "failed to get name of object"); + hr = WcaWriteStringToCaData(pwzTable, &pwzCustomActionData); + ExitOnFailure(hr, "failed to add data to CustomActionData"); + + hr = WcaGetRecordFormattedString(hRec, QSO_DOMAIN, &pwzData); + ExitOnFailure(hr, "failed to get domain for user to configure object"); + hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); + ExitOnFailure(hr, "failed to add data to CustomActionData"); + + hr = WcaGetRecordFormattedString(hRec, QSO_USER, &pwzData); + ExitOnFailure(hr, "failed to get user to configure object"); + hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); + ExitOnFailure(hr, "failed to add data to CustomActionData"); + + hr = WcaGetRecordInteger(hRec, QSO_ATTRIBUTES, reinterpret_cast(&dwAttributes)); + ExitOnFailure(hr, "failed to get attributes to configure object"); + hr = WcaWriteIntegerToCaData(dwAttributes, &pwzCustomActionData); + ExitOnFailure(hr, "failed to add data to CustomActionData"); + + hr = WcaGetRecordString(hRec, QSO_PERMISSION, &pwzData); + ExitOnFailure(hr, "failed to get permission to configure object"); + hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); + ExitOnFailure(hr, "failed to add data to CustomActionData"); + + ++cObjects; + } + } + + // if we looped through all records all is well + if (E_NOMOREITEMS == hr) + hr = S_OK; + ExitOnFailure(hr, "failed while looping through all objects to secure"); + + // + // schedule the custom action and add to progress bar + // + if (pwzCustomActionData && *pwzCustomActionData) + { + Assert(0 < cObjects); + + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecSecureObjects"), pwzCustomActionData, cObjects * COST_SECUREOBJECT); + ExitOnFailure(hr, "failed to schedule ExecSecureObjects action"); + } + +LExit: + ReleaseStr(pwzSecureObject); + ReleaseStr(pwzCustomActionData); + ReleaseStr(pwzData); + ReleaseStr(pwzTable); + ReleaseStr(pwzTargetPath); + + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + return WcaFinalize(er); +} + +/****************************************************************** + SchedSecureObjectsRollback - entry point for SchedSecureObjectsRollback Custom Action + + called as Type 1 CustomAction (binary DLL) from Windows Installer + in InstallExecuteSequence before SchedSecureObjects +******************************************************************/ +extern "C" UINT __stdcall SchedSecureObjectsRollback( + __in MSIHANDLE hInstall + ) +{ +// AssertSz(FALSE, "debug SchedSecureObjectsRollback"); + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + LPWSTR pwzSecureObject = NULL; + LPWSTR pwzTable = NULL; + LPWSTR pwzTargetPath = NULL; + + PMSIHANDLE hView = NULL; + PMSIHANDLE hRec = NULL; + + LPWSTR pwzCustomActionData = NULL; + + eOBJECTTYPE eType = OT_UNKNOWN; + + // + // initialize + // + hr = WcaInitialize(hInstall, "SchedSecureObjectsRollback"); + ExitOnFailure(hr, "failed to initialize"); + + // + // loop through all the objects to be secured + // + hr = WcaOpenExecuteView(wzQUERY_SECUREOBJECTS, &hView); + ExitOnFailure(hr, "failed to open view on Wix4SecureObject table"); + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + hr = WcaGetRecordString(hRec, QSO_TABLE, &pwzTable); + ExitOnFailure(hr, "failed to get object table"); + + eType = EObjectTypeFromString(pwzTable); + + if (OT_UNKNOWN == eType) + { + ExitOnFailure(hr = E_INVALIDARG, "unknown SecureObject.Table: %ls", pwzTable); + } + + int iCompAttributes = 0; + hr = WcaGetRecordInteger(hRec, QSO_COMPATTRIBUTES, &iCompAttributes); + ExitOnFailure(hr, "failed to get Component attributes for secure object"); + + BOOL fIs64Bit = iCompAttributes & msidbComponentAttributes64bit; + + // Only process entries in the Wix4SecureObject table whose components match the bitness of this CA +#ifdef _WIN64 + if (!fIs64Bit) + { + continue; + } +#else + if (fIs64Bit) + { + continue; + } +#endif + + // get the object being secured that we are planning to schedule rollback for + hr = WcaGetRecordString(hRec, QSO_SECUREOBJECT, &pwzSecureObject); + ExitOnFailure(hr, "failed to get name of object"); + + hr = GetTargetPath(eType, pwzSecureObject, &pwzTargetPath); + ExitOnFailure(hr, "failed to get target path of object '%ls' in order to schedule rollback", pwzSecureObject); + + hr = StoreACLRollbackInfo(pwzTargetPath, pwzTable); + if (FAILED(hr)) + { + WcaLog(LOGMSG_STANDARD, "Failed to store ACL rollback information with error 0x%x - continuing", hr); + } + } + + // if we looped through all records all is well + if (E_NOMOREITEMS == hr) + { + hr = S_OK; + } + ExitOnFailure(hr, "failed while looping through all objects to schedule rollback for"); + +LExit: + ReleaseStr(pwzCustomActionData); + ReleaseStr(pwzSecureObject); + ReleaseStr(pwzTable); + ReleaseStr(pwzTargetPath); + + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + return WcaFinalize(er); +} + +/****************************************************************** + CaExecSecureObjects - entry point for SecureObjects Custom Action + called as Type 1025 CustomAction (deferred binary DLL) + + NOTE: deferred CustomAction since it modifies the machine + NOTE: CustomActionData == wzObject\twzTable\twzDomain\twzUser\tdwAttributes\tdwPermissions\t... +******************************************************************/ +extern "C" UINT __stdcall ExecSecureObjects( + __in MSIHANDLE hInstall + ) +{ +// AssertSz(FALSE, "debug ExecSecureObjects"); + HRESULT hr = S_OK; + DWORD er = ERROR_SUCCESS; + + LPWSTR pwz = NULL; + LPWSTR pwzData = NULL; + LPWSTR pwzObject = NULL; + LPWSTR pwzTable = NULL; + LPWSTR pwzDomain = NULL; + DWORD dwRevision = 0; + LPWSTR pwzUser = NULL; + DWORD dwPermissions = 0; + DWORD dwAttributes = 0; + LPWSTR pwzAccount = NULL; + PSID psid = NULL; + + EXPLICIT_ACCESSW ea = {0}; + SE_OBJECT_TYPE objectType = SE_UNKNOWN_OBJECT_TYPE; + PSECURITY_DESCRIPTOR psd = NULL; + SECURITY_DESCRIPTOR_CONTROL sdc = {0}; + SECURITY_INFORMATION si = {0}; + PACL pAclExisting = NULL; // doesn't get freed + PACL pAclNew = NULL; + + PMSIHANDLE hActionRec = ::MsiCreateRecord(1); + + // + // initialize + // + hr = WcaInitialize(hInstall, "ExecSecureObjects"); + ExitOnFailure(hr, "failed to initialize"); + + hr = WcaGetProperty(L"CustomActionData", &pwzData); + ExitOnFailure(hr, "failed to get CustomActionData"); + + WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); + + pwz = pwzData; + + // + // loop through all the passed in data + // + while (pwz && *pwz) + { + hr = WcaReadStringFromCaData(&pwz, &pwzObject); + ExitOnFailure(hr, "failed to process CustomActionData"); + + hr = WcaReadStringFromCaData(&pwz, &pwzTable); + ExitOnFailure(hr, "failed to process CustomActionData"); + hr = WcaReadStringFromCaData(&pwz, &pwzDomain); + ExitOnFailure(hr, "failed to process CustomActionData"); + hr = WcaReadStringFromCaData(&pwz, &pwzUser); + ExitOnFailure(hr, "failed to process CustomActionData"); + hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&dwAttributes)); + ExitOnFailure(hr, "failed to process CustomActionData"); + hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&dwPermissions)); + ExitOnFailure(hr, "failed to process CustomActionData"); + + WcaLog(LOGMSG_VERBOSE, "Securing Object: %ls Type: %ls User: %ls", pwzObject, pwzTable, pwzUser); + + // + // create the appropriate SID + // + + // figure out the right user to put into the access block + if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"Everyone")) + { + hr = AclGetWellKnownSid(WinWorldSid, &psid); + } + else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"Administrators")) + { + hr = AclGetWellKnownSid(WinBuiltinAdministratorsSid, &psid); + } + else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"LocalSystem")) + { + hr = AclGetWellKnownSid(WinLocalSystemSid, &psid); + } + else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"LocalService")) + { + hr = AclGetWellKnownSid(WinLocalServiceSid, &psid); + } + else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"NetworkService")) + { + hr = AclGetWellKnownSid(WinNetworkServiceSid, &psid); + } + else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"AuthenticatedUser")) + { + hr = AclGetWellKnownSid(WinAuthenticatedUserSid, &psid); + } + else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"Guests")) + { + hr = AclGetWellKnownSid(WinBuiltinGuestsSid, &psid); + } + else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"CREATOR OWNER")) + { + hr = AclGetWellKnownSid(WinCreatorOwnerSid, &psid); + } + else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"INTERACTIVE")) + { + hr = AclGetWellKnownSid(WinInteractiveSid, &psid); + } + else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"Users")) + { + hr = AclGetWellKnownSid(WinBuiltinUsersSid, &psid); + } + else + { + hr = StrAllocFormatted(&pwzAccount, L"%s%s%s", pwzDomain, *pwzDomain ? L"\\" : L"", pwzUser); + ExitOnFailure(hr, "failed to build domain user name"); + + hr = AclGetAccountSid(NULL, pwzAccount, &psid); + } + ExitOnFailure(hr, "failed to get sid for account: %ls%ls%ls", pwzDomain, *pwzDomain ? L"\\" : L"", pwzUser); + + // + // build up the explicit access + // + ea.grfAccessMode = SET_ACCESS; + + if (dwAttributes & SECURE_OBJECT_ATTRIBUTE_INHERITABLE) + { + ea.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT; + } + else + { + ea.grfInheritance = NO_INHERITANCE; + } + +#pragma prefast(push) +#pragma prefast(disable:25029) + ::BuildTrusteeWithSidW(&ea.Trustee, psid); +#pragma prefast(pop) + + objectType = SEObjectTypeFromString(const_cast (pwzTable)); + + // always add these permissions for services + // these are basic permissions that are often forgotten + if (0 == lstrcmpW(L"ServiceInstall", pwzTable)) + { + dwPermissions |= SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_INTERROGATE; + } + + ea.grfAccessPermissions = dwPermissions; + + if (SE_UNKNOWN_OBJECT_TYPE != objectType) + { + er = ::GetNamedSecurityInfoW(pwzObject, objectType, DACL_SECURITY_INFORMATION, NULL, NULL, &pAclExisting, NULL, &psd); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "failed to get security info for object: %ls", pwzObject); + + //Need to see if DACL is protected so getting Descriptor information + if (!::GetSecurityDescriptorControl(psd, &sdc, &dwRevision)) + { + ExitOnLastError(hr, "failed to get security descriptor control for object: %ls", pwzObject); + } + +#pragma prefast(push) +#pragma prefast(disable:25029) + er = ::SetEntriesInAclW(1, &ea, pAclExisting, &pAclNew); +#pragma prefast(pop) + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "failed to add ACLs for object: %ls", pwzObject); + + if (sdc & SE_DACL_PROTECTED) + { + si = DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION; + } + else + { + si = DACL_SECURITY_INFORMATION; + } + er = ::SetNamedSecurityInfoW(pwzObject, objectType, si, NULL, NULL, pAclNew, NULL); + MessageExitOnFailure(hr = HRESULT_FROM_WIN32(er), msierrSecureObjectsFailedSet, "failed to set security info for object: %ls", pwzObject); + } + else + { + MessageExitOnFailure(hr = E_UNEXPECTED, msierrSecureObjectsUnknownType, "unknown object type: %ls", pwzTable); + } + + hr = WcaProgressMessage(COST_SECUREOBJECT, FALSE); + ExitOnFailure(hr, "failed to send progress message"); + + objectType = SE_UNKNOWN_OBJECT_TYPE; + } + +LExit: + ReleaseStr(pwzUser); + ReleaseStr(pwzDomain); + ReleaseStr(pwzTable); + ReleaseStr(pwzObject); + ReleaseStr(pwzData); + ReleaseStr(pwzAccount); + + if (pAclNew) + { + ::LocalFree(pAclNew); + } + if (psd) + { + ::LocalFree(psd); + } + if (psid) + { + AclFreeSid(psid); + } + + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + return WcaFinalize(er); +} + +extern "C" UINT __stdcall ExecSecureObjectsRollback( + __in MSIHANDLE hInstall + ) +{ +// AssertSz(FALSE, "debug ExecSecureObjectsRollback"); + HRESULT hr = S_OK; + DWORD er = ERROR_SUCCESS; + + LPWSTR pwz = NULL; + LPWSTR pwzData = NULL; + LPWSTR pwzObject = NULL; + LPWSTR pwzTable = NULL; + LPWSTR pwzSecurityInfo = NULL; + + SE_OBJECT_TYPE objectType = SE_UNKNOWN_OBJECT_TYPE; + PSECURITY_DESCRIPTOR psd = NULL; + ULONG psdSize; + SECURITY_DESCRIPTOR_CONTROL sdc = {0}; + SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION; + PACL pDacl = NULL; + BOOL bDaclPresent = false; + BOOL bDaclDefaulted = false; + DWORD dwRevision = 0; + int iProtected; + + // initialize + hr = WcaInitialize(hInstall, "ExecSecureObjectsRollback"); + ExitOnFailure(hr, "failed to initialize"); + + hr = WcaGetProperty(L"CustomActionData", &pwzData); + ExitOnFailure(hr, "failed to get CustomActionData"); + + WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); + + pwz = pwzData; + + hr = WcaReadStringFromCaData(&pwz, &pwzObject); + ExitOnFailure(hr, "failed to process CustomActionData"); + + hr = WcaReadStringFromCaData(&pwz, &pwzTable); + ExitOnFailure(hr, "failed to process CustomActionData"); + + objectType = SEObjectTypeFromString(const_cast (pwzTable)); + + if (SE_UNKNOWN_OBJECT_TYPE != objectType) + { + hr = WcaReadStringFromCaData(&pwz, &pwzSecurityInfo); + ExitOnFailure(hr, "failed to process CustomActionData"); + + hr = WcaReadIntegerFromCaData(&pwz, &iProtected); + ExitOnFailure(hr, "failed to process CustomActionData"); + + if (!::ConvertStringSecurityDescriptorToSecurityDescriptorW(pwzSecurityInfo,SDDL_REVISION_1,&psd,&psdSize)) + { + ExitOnLastError(hr, "failed to convert security descriptor string to a valid security descriptor"); + } + + if (!::GetSecurityDescriptorDacl(psd,&bDaclPresent,&pDacl,&bDaclDefaulted)) + { + hr = E_UNEXPECTED; + ExitOnFailure(hr, "failed to get security descriptor's DACL - error code: %d",pwzSecurityInfo,GetLastError()); + } + + // 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. + if (!bDaclPresent) + { + hr = E_UNEXPECTED; + ExitOnFailure(hr, "security descriptor does not contain a DACL"); + } + + //Need to see if DACL is protected so getting Descriptor information + if (!::GetSecurityDescriptorControl(psd, &sdc, &dwRevision)) + { + ExitOnLastError(hr, "failed to get security descriptor control for object: %ls", pwzObject); + } + + // Write a 1 if DACL is protected, 0 otherwise + switch (iProtected) + { + case 0: + // Unnecessary to do anything - leave si to the default flags + break; + + case 1: + si = si | PROTECTED_DACL_SECURITY_INFORMATION; + break; + + default: + hr = E_UNEXPECTED; + ExitOnFailure(hr, "unrecognized value in CustomActionData"); + break; + } + + er = ::SetNamedSecurityInfoW(pwzObject, objectType, si, NULL, NULL, pDacl, NULL); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "failed to set security info for object: %ls error code: %d", pwzObject, GetLastError()); + } + else + { + MessageExitOnFailure(hr = E_UNEXPECTED, msierrSecureObjectsUnknownType, "unknown object type: %ls", pwzTable); + } + +LExit: + ReleaseStr(pwzData); + ReleaseStr(pwzObject); + ReleaseStr(pwzTable); + ReleaseStr(pwzSecurityInfo); + + if (psd) + { + ::LocalFree(psd); + } + + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + return WcaFinalize(er); +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + +// structs +LPCWSTR wzQUERY_SERVICECONFIG = L"SELECT `ServiceName`, `Component_`, `NewService`, `FirstFailureActionType`, `SecondFailureActionType`, `ThirdFailureActionType`, `ResetPeriodInDays`, `RestartServiceDelayInSeconds`, `ProgramCommandLine`, `RebootMessage` FROM `Wix4ServiceConfig`"; +enum eQUERY_SERVICECONFIG { QSC_SERVICENAME = 1, QSC_COMPONENT, QSC_NEWSERVICE, QSC_FIRSTFAILUREACTIONTYPE, QSC_SECONDFAILUREACTIONTYPE, QSC_THIRDFAILUREACTIONTYPE, QSC_RESETPERIODINDAYS, QSC_RESTARTSERVICEDELAYINSECONDS, QSC_PROGRAMCOMMANDLINE, QSC_REBOOTMESSAGE }; + +// consts +LPCWSTR c_wzActionTypeNone = L"none"; +LPCWSTR c_wzActionTypeReboot = L"reboot"; +LPCWSTR c_wzActionTypeRestart = L"restart"; +LPCWSTR c_wzActionTypeRunCommand = L"runCommand"; + +// prototypes +static SC_ACTION_TYPE GetSCActionType( + __in LPCWSTR pwzActionTypeName + ); + +static HRESULT GetSCActionTypeString( + __in SC_ACTION_TYPE type, + __out_ecount(cchActionTypeString) LPWSTR wzActionTypeString, + __in DWORD cchActionTypeString + ); + +static HRESULT GetService( + __in SC_HANDLE hSCM, + __in LPCWSTR wzService, + __in DWORD dwOpenServiceAccess, + __out SC_HANDLE* phService + ); + +static HRESULT ConfigureService( + __in SC_HANDLE hSCM, + __in SC_HANDLE hService, + __in LPCWSTR wzServiceName, + __in DWORD dwRestartServiceDelayInSeconds, + __in LPCWSTR wzFirstFailureActionType, + __in LPCWSTR wzSecondFailureActionType, + __in LPCWSTR wzThirdFailureActionType, + __in DWORD dwResetPeriodInDays, + __in LPWSTR wzRebootMessage, + __in LPWSTR wzProgramCommandLine + ); + + +/****************************************************************** +SchedServiceConfig - entry point for SchedServiceConfig Custom Action + +called as Type 1 CustomAction (binary DLL) from Windows Installer +in InstallExecuteSequence before CaExecServiceConfig +********************************************************************/ +extern "C" UINT __stdcall SchedServiceConfig( + __in MSIHANDLE hInstall + ) +{ + //AssertSz(FALSE, "debug SchedServiceConfig"); + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + LPWSTR pwzScriptKey = NULL; + LPWSTR pwzCustomActionData = NULL; + + PMSIHANDLE hView = NULL; + PMSIHANDLE hRec = NULL; + LPWSTR pwzData = NULL; + int iData = 0; + DWORD cServices = 0; + + // initialize + hr = WcaInitialize(hInstall, "SchedServiceConfig"); + ExitOnFailure(hr, "Failed to initialize."); + + // Get the script key for this CustomAction and put it on the front of the + // CustomActionData of the install action. + hr = WcaCaScriptCreateKey(&pwzScriptKey); + ExitOnFailure(hr, "Failed to get encoding key."); + + hr = WcaWriteStringToCaData(pwzScriptKey, &pwzCustomActionData); + ExitOnFailure(hr, "Failed to add encoding key to CustomActionData."); + + // Loop through all the services to be configured. + hr = WcaOpenExecuteView(wzQUERY_SERVICECONFIG, &hView); + ExitOnFailure(hr, "Failed to open view on Wix4ServiceConfig table."); + + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN; + INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN; + + // Get component name to check if we are installing it. If so + // then add the table data to the CustomActionData, otherwise + // skip it. + hr = WcaGetRecordString(hRec, QSC_COMPONENT, &pwzData); + ExitOnFailure(hr, "Failed to get component name"); + + hr = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction); + ExitOnFailure(hr = HRESULT_FROM_WIN32(hr), "Failed to get install state for Component: %ls", pwzData); + + if (WcaIsInstalling(isInstalled, isAction)) + { + // Add the data to the CustomActionData (for install). + hr = WcaGetRecordFormattedString(hRec, QSC_SERVICENAME, &pwzData); + ExitOnFailure(hr, "Failed to get name of service."); + hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); + ExitOnFailure(hr, "Failed to add name to CustomActionData."); + + hr = WcaGetRecordInteger(hRec, QSC_NEWSERVICE, &iData); + ExitOnFailure(hr, "Failed to get Wix4ServiceConfig.NewService."); + hr = WcaWriteIntegerToCaData(0 != iData, &pwzCustomActionData); + ExitOnFailure(hr, "Failed to add NewService data to CustomActionData"); + + hr = WcaGetRecordString(hRec, QSC_FIRSTFAILUREACTIONTYPE, &pwzData); + ExitOnFailure(hr, "failed to get first failure action type"); + hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); + ExitOnFailure(hr, "failed to add data to CustomActionData"); + + hr = WcaGetRecordString(hRec, QSC_SECONDFAILUREACTIONTYPE, &pwzData); + ExitOnFailure(hr, "failed to get second failure action type"); + hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); + ExitOnFailure(hr, "failed to add data to CustomActionData"); + + hr = WcaGetRecordString(hRec, QSC_THIRDFAILUREACTIONTYPE, &pwzData); + ExitOnFailure(hr, "failed to get third failure action type"); + hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); + ExitOnFailure(hr, "failed to add data to CustomActionData"); + + hr = WcaGetRecordInteger(hRec, QSC_RESETPERIODINDAYS, &iData); + if (S_FALSE == hr) // deal w/ possible null value + { + iData = 0; + } + ExitOnFailure(hr, "failed to get reset period in days between service restart attempts."); + hr = WcaWriteIntegerToCaData(iData, &pwzCustomActionData); + ExitOnFailure(hr, "failed to add data to CustomActionData"); + + hr = WcaGetRecordInteger(hRec, QSC_RESTARTSERVICEDELAYINSECONDS, &iData); + if (S_FALSE == hr) // deal w/ possible null value + { + iData = 0; + } + ExitOnFailure(hr, "failed to get server restart delay value."); + hr = WcaWriteIntegerToCaData(iData, &pwzCustomActionData); + ExitOnFailure(hr, "failed to add data to CustomActionData"); + + hr = WcaGetRecordFormattedString(hRec, QSC_PROGRAMCOMMANDLINE, &pwzData); // null value already dealt w/ properly + ExitOnFailure(hr, "failed to get command line to run on service failure."); + hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); + ExitOnFailure(hr, "failed to add data to CustomActionData"); + + hr = WcaGetRecordString(hRec, QSC_REBOOTMESSAGE, &pwzData); // null value already dealt w/ properly + ExitOnFailure(hr, "failed to get message to send to users when server reboots due to service failure."); + hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); + ExitOnFailure(hr, "failed to add data to CustomActionData"); + + ++cServices; + } + } + + // if we looped through all records all is well + if (E_NOMOREITEMS == hr) + { + hr = S_OK; + } + ExitOnFailure(hr, "failed while looping through all objects to secure"); + + // setup CustomActionData and add to progress bar for download + if (0 < cServices) + { + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackServiceConfig"), pwzScriptKey, cServices * COST_SERVICECONFIG); + ExitOnFailure(hr, "failed to schedule RollbackServiceConfig action"); + + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecServiceConfig"), pwzCustomActionData, cServices * COST_SERVICECONFIG); + ExitOnFailure(hr, "failed to schedule ExecServiceConfig action"); + } + +LExit: + ReleaseStr(pwzData); + ReleaseStr(pwzCustomActionData); + ReleaseStr(pwzScriptKey); + + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + + +/****************************************************************** +CaExecServiceConfig - entry point for ServiceConfig Custom Action. + +NOTE: deferred CustomAction since it modifies the machine +NOTE: CustomActionData == wzServiceName\tfNewService\twzFirstFailureActionType\twzSecondFailureActionType\twzThirdFailureActionType\tdwResetPeriodInDays\tdwRestartServiceDelayInSeconds\twzProgramCommandLine\twzRebootMessage\twzServiceName\tfNewService\t... +*******************************************************************/ +extern "C" UINT __stdcall ExecServiceConfig( + __in MSIHANDLE hInstall + ) +{ + //AssertSz(FALSE, "debug ExecServiceConfig"); + HRESULT hr = S_OK; + DWORD er = 0; + + LPWSTR pwzCustomActionData = NULL; + LPWSTR pwz = NULL; + + LPWSTR pwzScriptKey = NULL; + WCA_CASCRIPT_HANDLE hRollbackScript = NULL; + + LPWSTR pwzServiceName = NULL; + BOOL fNewService = FALSE; + LPWSTR pwzFirstFailureActionType = NULL; + LPWSTR pwzSecondFailureActionType = NULL; + LPWSTR pwzThirdFailureActionType = NULL; + LPWSTR pwzProgramCommandLine = NULL; + LPWSTR pwzRebootMessage = NULL; + DWORD dwResetPeriodInDays = 0; + DWORD dwRestartServiceDelayInSeconds = 0; + + LPVOID lpMsgBuf = NULL; + SC_HANDLE hSCM = NULL; + SC_HANDLE hService = NULL; + + DWORD dwRestartDelay = 0; + WCHAR wzActionName[32] = { 0 }; + + DWORD cbExistingServiceConfig = 0; + + SERVICE_FAILURE_ACTIONSW* psfa = NULL; + + // initialize + hr = WcaInitialize(hInstall, "ExecServiceConfig"); + ExitOnFailure(hr, "failed to initialize"); + + // Open the Services Control Manager up front. + hSCM = ::OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); + if (NULL == hSCM) + { + er = ::GetLastError(); + hr = HRESULT_FROM_WIN32(er); + +#pragma prefast(push) +#pragma prefast(disable:25028) + ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, er, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpMsgBuf, 0, NULL); +#pragma prefast(pop) + + ExitOnFailure(hr, "Failed to get handle to SCM. Error: %ls", (LPWSTR)lpMsgBuf); + } + + // First, get the script key out of the CustomActionData and + // use that to create the rollback script for this action. + hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData); + ExitOnFailure(hr, "failed to get CustomActionData"); + + WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); + + pwz = pwzCustomActionData; + + hr = WcaReadStringFromCaData(&pwz, &pwzScriptKey); + if (!pwzScriptKey) + { + hr = E_UNEXPECTED; + ExitOnFailure(hr, "Failed due to unexpected CustomActionData passed."); + } + ExitOnFailure(hr, "Failed to read encoding key from CustomActionData."); + + hr = WcaCaScriptCreate(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, FALSE, &hRollbackScript); + ExitOnFailure(hr, "Failed to open rollback CustomAction script."); + + // Next, loop through the rest of the CustomActionData, processing + // each service config row in turn. + while (pwz && *pwz) + { + hr = WcaReadStringFromCaData(&pwz, &pwzServiceName); + ExitOnFailure(hr, "failed to process CustomActionData"); + hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&fNewService)); + ExitOnFailure(hr, "failed to process CustomActionData"); + hr = WcaReadStringFromCaData(&pwz, &pwzFirstFailureActionType); + ExitOnFailure(hr, "failed to process CustomActionData"); + hr = WcaReadStringFromCaData(&pwz, &pwzSecondFailureActionType); + ExitOnFailure(hr, "failed to process CustomActionData"); + hr = WcaReadStringFromCaData(&pwz, &pwzThirdFailureActionType); + ExitOnFailure(hr, "failed to process CustomActionData"); + hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&dwResetPeriodInDays)); + ExitOnFailure(hr, "failed to process CustomActionData"); + hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&dwRestartServiceDelayInSeconds)); + ExitOnFailure(hr, "failed to process CustomActionData"); + hr = WcaReadStringFromCaData(&pwz, &pwzProgramCommandLine); + ExitOnFailure(hr, "failed to process CustomActionData"); + hr = WcaReadStringFromCaData(&pwz, &pwzRebootMessage); + ExitOnFailure(hr, "failed to process CustomActionData"); + + WcaLog(LOGMSG_VERBOSE, "Configuring Service: %ls", pwzServiceName); + + // Open the handle with all the permissions we might need: + // SERVICE_QUERY_CONFIG is needed for QueryServiceConfig2(). + // SERVICE_CHANGE_CONFIG is needed for ChangeServiceConfig2(). + // SERVICE_START is required in order to handle SC_ACTION_RESTART action. + hr = GetService(hSCM, pwzServiceName, SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | SERVICE_START, &hService); + ExitOnFailure(hr, "Failed to get service: %ls", pwzServiceName); + + // If we are configuring a service that existed on the machine, we need to + // read the existing service configuration and write it out to the rollback + // log so rollback can put it back if anything goes wrong. + if (!fNewService) + { + // First, read the existing service config. + if (!::QueryServiceConfig2W(hService, SERVICE_CONFIG_FAILURE_ACTIONS, NULL, 0, &cbExistingServiceConfig) && ERROR_INSUFFICIENT_BUFFER != ::GetLastError()) + { + ExitWithLastError(hr, "Failed to get current service config info."); + } + + psfa = static_cast(MemAlloc(cbExistingServiceConfig, TRUE)); + ExitOnNull(psfa, hr, E_OUTOFMEMORY, "failed to allocate memory for service failure actions."); + + if (!::QueryServiceConfig2W(hService, SERVICE_CONFIG_FAILURE_ACTIONS, (LPBYTE)psfa, cbExistingServiceConfig, &cbExistingServiceConfig)) + { + ExitOnLastError(hr, "failed to Query Service."); + } + + // Build up rollback log so we can restore service state if necessary + hr = WcaCaScriptWriteString(hRollbackScript, pwzServiceName); + ExitOnFailure(hr, "Failed to add service name to Rollback Log"); + + // If this service struct is empty, fill in default values + if (3 > psfa->cActions) + { + hr = WcaCaScriptWriteString(hRollbackScript, c_wzActionTypeNone); + ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); + + hr = WcaCaScriptWriteString(hRollbackScript, c_wzActionTypeNone); + ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); + + hr = WcaCaScriptWriteString(hRollbackScript, c_wzActionTypeNone); + ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); + } + else + { + // psfa actually had actions defined, so use the first three. + for (int i = 0; i < 3; ++i) + { + hr = GetSCActionTypeString(psfa->lpsaActions[i].Type, wzActionName, countof(wzActionName)); + ExitOnFailure(hr, "failed to query SFA object"); + + if (SC_ACTION_RESTART == psfa->lpsaActions[i].Type) + { + dwRestartDelay = psfa->lpsaActions[i].Delay / 1000; + } + + hr = WcaCaScriptWriteString(hRollbackScript, wzActionName); + ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); + } + } + + hr = WcaCaScriptWriteNumber(hRollbackScript, psfa->dwResetPeriod / (24 * 60 * 60)); + ExitOnFailure(hr, "failed to add data to CustomActionData"); + + hr = WcaCaScriptWriteNumber(hRollbackScript, dwRestartDelay); + ExitOnFailure(hr, "failed to add data to CustomActionData"); + + // Handle the null cases. + if (!psfa->lpCommand) + { + psfa->lpCommand = L""; + } + hr = WcaCaScriptWriteString(hRollbackScript, psfa->lpCommand); + ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); + + // Handle the null cases. + if (!psfa->lpRebootMsg) + { + psfa->lpRebootMsg = L""; + } + hr = WcaCaScriptWriteString(hRollbackScript, psfa->lpRebootMsg); + ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); + + // Nudge the system to get all our rollback data written to disk. + WcaCaScriptFlush(hRollbackScript); + + ReleaseNullMem(psfa); + } + + hr = ConfigureService(hSCM, hService, pwzServiceName, dwRestartServiceDelayInSeconds, pwzFirstFailureActionType, + pwzSecondFailureActionType, pwzThirdFailureActionType, dwResetPeriodInDays, pwzRebootMessage, pwzProgramCommandLine); + ExitOnFailure(hr, "Failed to configure service: %ls", pwzServiceName); + + hr = WcaProgressMessage(COST_SERVICECONFIG, FALSE); + ExitOnFailure(hr, "failed to send progress message"); + + // Per-service cleanup + ::CloseServiceHandle(hService); + hService = NULL; + dwResetPeriodInDays = 0; + dwRestartServiceDelayInSeconds = 0; + } + +LExit: + WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_PRESERVE); + + if (lpMsgBuf) + { + ::LocalFree(lpMsgBuf); + } + + if (hService) + { + ::CloseServiceHandle(hService); + } + + if (hSCM) + { + ::CloseServiceHandle(hSCM); + } + + ReleaseMem(psfa); + + ReleaseStr(pwzRebootMessage); + ReleaseStr(pwzProgramCommandLine); + ReleaseStr(pwzThirdFailureActionType); + ReleaseStr(pwzSecondFailureActionType); + ReleaseStr(pwzFirstFailureActionType); + ReleaseStr(pwzServiceName); + ReleaseStr(pwzScriptKey); + ReleaseStr(pwzCustomActionData); + + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + + +/****************************************************************** +RollbackServiceConfig - entry point for ServiceConfig rollback + Custom Action. + +NOTE: CustomActionScript Data == wzServiceName\twzFirstFailureActionType\twzSecondFailureActionType\twzThirdFailureActionType\tdwResetPeriodInDays\tdwRestartServiceDelayInSeconds\twzProgramCommandLine\twzRebootMessage\twzServiceName\t... +*******************************************************************/ +extern "C" UINT __stdcall RollbackServiceConfig( + __in MSIHANDLE hInstall + ) +{ + //AssertSz(FALSE, "debug RollbackServiceConfig"); + HRESULT hr = S_OK; + DWORD er = 0; + + LPWSTR pwzCustomActionData = NULL; + LPWSTR pwz = NULL; + + LPWSTR pwzScriptKey = NULL; + WCA_CASCRIPT_HANDLE hRollbackScript = NULL; + + LPWSTR pwzServiceName = NULL; + LPWSTR pwzFirstFailureActionType = NULL; + LPWSTR pwzSecondFailureActionType = NULL; + LPWSTR pwzThirdFailureActionType = NULL; + LPWSTR pwzProgramCommandLine = NULL; + LPWSTR pwzRebootMessage = NULL; + DWORD dwResetPeriodInDays = 0; + DWORD dwRestartServiceDelayInSeconds = 0; + + LPVOID lpMsgBuf = NULL; + SC_HANDLE hSCM = NULL; + SC_HANDLE hService = NULL; + + // initialize + hr = WcaInitialize(hInstall, "RollbackServiceConfig"); + ExitOnFailure(hr, "Failed to initialize 'RollbackServiceConfig'."); + + // Open the Services Control Manager up front. + hSCM = ::OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); + if (NULL == hSCM) + { + er = ::GetLastError(); + hr = HRESULT_FROM_WIN32(er); + +#pragma prefast(push) +#pragma prefast(disable:25028) + ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, er, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpMsgBuf, 0, NULL); +#pragma prefast(pop) + + ExitOnFailure(hr, "Failed to get handle to SCM. Error: %ls", (LPWSTR)lpMsgBuf); + + // Make sure we still abort, in case hSCM was NULL but no error was returned from GetLastError + ExitOnNull(hSCM, hr, E_POINTER, "Getting handle to SCM reported success, but no handle was returned."); + } + + // Get the script key from the CustomAction data and use it to open + // the rollback log and read the data over the CustomActionData + // because all of the information is in the script data not the + // CustomActionData. + hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData); + ExitOnFailure(hr, "failed to get CustomActionData"); + + WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); + + pwz = pwzCustomActionData; + + hr = WcaReadStringFromCaData(&pwz, &pwzScriptKey); + if (!pwzScriptKey) + { + hr = E_UNEXPECTED; + ExitOnFailure(hr, "Failed due to unexpected CustomActionData passed."); + } + ExitOnFailure(hr, "Failed to read encoding key from CustomActionData."); + + hr = WcaCaScriptOpen(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, &hRollbackScript); + ExitOnFailure(hr, "Failed to open rollback CustomAction script."); + + hr = WcaCaScriptReadAsCustomActionData(hRollbackScript, &pwzCustomActionData); + ExitOnFailure(hr, "Failed to read rollback script into CustomAction data."); + + // Loop through the script's CustomActionData, processing each + // service config in turn. + pwz = pwzCustomActionData; + while (pwz && *pwz) + { + hr = WcaReadStringFromCaData(&pwz, &pwzServiceName); + ExitOnFailure(hr, "failed to process CustomActionData"); + hr = WcaReadStringFromCaData(&pwz, &pwzFirstFailureActionType); + ExitOnFailure(hr, "failed to process CustomActionData"); + hr = WcaReadStringFromCaData(&pwz, &pwzSecondFailureActionType); + ExitOnFailure(hr, "failed to process CustomActionData"); + hr = WcaReadStringFromCaData(&pwz, &pwzThirdFailureActionType); + ExitOnFailure(hr, "failed to process CustomActionData"); + hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&dwResetPeriodInDays)); + ExitOnFailure(hr, "failed to process CustomActionData"); + hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&dwRestartServiceDelayInSeconds)); + ExitOnFailure(hr, "failed to process CustomActionData"); + hr = WcaReadStringFromCaData(&pwz, &pwzProgramCommandLine); + ExitOnFailure(hr, "failed to process CustomActionData"); + hr = WcaReadStringFromCaData(&pwz, &pwzRebootMessage); + ExitOnFailure(hr, "failed to process CustomActionData"); + + WcaLog(LOGMSG_VERBOSE, "Reconfiguring Service: %ls", pwzServiceName); + + // Open the handle with all the permissions we might need. + // SERVICE_CHANGE_CONFIG is needed for ChangeServiceConfig2(). + // SERVICE_START is required in order to handle SC_ACTION_RESTART action. + hr = GetService(hSCM, pwzServiceName, SERVICE_CHANGE_CONFIG | SERVICE_START, &hService); + ExitOnFailure(hr, "Failed to get service: %ls", pwzServiceName); + + hr = ConfigureService(hSCM, hService, pwzServiceName, dwRestartServiceDelayInSeconds, pwzFirstFailureActionType, + pwzSecondFailureActionType, pwzThirdFailureActionType, dwResetPeriodInDays, pwzRebootMessage, pwzProgramCommandLine); + ExitOnFailure(hr, "Failed to configure service: %ls", pwzServiceName); + + hr = WcaProgressMessage(COST_SERVICECONFIG, FALSE); + ExitOnFailure(hr, "failed to send progress message"); + + // Per-service cleanup + ::CloseServiceHandle(hService); + hService = NULL; + dwResetPeriodInDays = 0; + dwRestartServiceDelayInSeconds = 0; + } + +LExit: + if (lpMsgBuf) // Allocated with FormatString. + { + ::LocalFree(lpMsgBuf); + } + + if (hService) + { + ::CloseServiceHandle(hService); + } + + if (hSCM) + { + ::CloseServiceHandle(hSCM); + } + + WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_DELETE); + + ReleaseStr(pwzRebootMessage); + ReleaseStr(pwzProgramCommandLine); + ReleaseStr(pwzThirdFailureActionType); + ReleaseStr(pwzSecondFailureActionType); + ReleaseStr(pwzFirstFailureActionType); + ReleaseStr(pwzServiceName); + ReleaseStr(pwzScriptKey); + ReleaseStr(pwzCustomActionData); + + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + + +/********************************************************** +GetSCActionType - helper function to return the SC_ACTION_TYPE +for a given string matching the allowed set. +REBOOT, RESTART, RUN_COMMAND and NONE +**********************************************************/ +static SC_ACTION_TYPE GetSCActionType( + __in LPCWSTR pwzActionTypeName + ) +{ + SC_ACTION_TYPE actionType; + + // verify that action types are valid. if not, just default to NONE + if (0 == lstrcmpiW(c_wzActionTypeReboot, pwzActionTypeName)) + { + actionType = SC_ACTION_REBOOT; + } + else if (0 == lstrcmpiW(c_wzActionTypeRestart, pwzActionTypeName)) + { + actionType = SC_ACTION_RESTART; + } + else if (0 == lstrcmpiW(c_wzActionTypeRunCommand, pwzActionTypeName)) + { + actionType = SC_ACTION_RUN_COMMAND; + } + else + { + // default to none + actionType = SC_ACTION_NONE; + } + + return actionType; +} + + +static HRESULT GetSCActionTypeString( + __in SC_ACTION_TYPE type, + __out_ecount(cchActionTypeString) LPWSTR wzActionTypeString, + __in DWORD cchActionTypeString + ) +{ + HRESULT hr = S_OK; + + switch (type) + { + case SC_ACTION_REBOOT: + hr = StringCchCopyW(wzActionTypeString, cchActionTypeString, c_wzActionTypeReboot); + ExitOnFailure(hr, "Failed to copy 'reboot' into action type."); + break; + case SC_ACTION_RESTART: + hr = StringCchCopyW(wzActionTypeString, cchActionTypeString, c_wzActionTypeRestart); + ExitOnFailure(hr, "Failed to copy 'restart' into action type."); + break; + case SC_ACTION_RUN_COMMAND: + hr = StringCchCopyW(wzActionTypeString, cchActionTypeString, c_wzActionTypeRunCommand); + ExitOnFailure(hr, "Failed to copy 'runCommand' into action type."); + break; + case SC_ACTION_NONE: + hr = StringCchCopyW(wzActionTypeString, cchActionTypeString, c_wzActionTypeNone); + ExitOnFailure(hr, "Failed to copy 'none' into action type."); + break; + default: + break; + } + +LExit: + return hr; +} + + +static HRESULT GetService( + __in SC_HANDLE hSCM, + __in LPCWSTR wzService, + __in DWORD dwOpenServiceAccess, + __out SC_HANDLE* phService + ) +{ + HRESULT hr = S_OK; + DWORD er = ERROR_SUCCESS; + LPVOID lpMsgBuf = NULL; + + *phService = ::OpenServiceW(hSCM, wzService, dwOpenServiceAccess); + if (NULL == *phService) + { + er = ::GetLastError(); + hr = HRESULT_FROM_WIN32(er); + if (ERROR_SERVICE_DOES_NOT_EXIST == er) + { + ExitOnFailure(hr, "Service '%ls' does not exist on this system.", wzService); + } + else + { +#pragma prefast(push) +#pragma prefast(disable:25028) + ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, er, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpMsgBuf, 0, NULL); +#pragma prefast(pop) + + ExitOnFailure(hr, "Failed to get handle to the service '%ls'. Error: %ls", wzService, (LPWSTR)lpMsgBuf); + } + } + +LExit: + if (lpMsgBuf) // Allocated with FormatString. + { + ::LocalFree(lpMsgBuf); + } + + return hr; +} + + +static HRESULT ConfigureService( + __in SC_HANDLE /*hSCM*/, + __in SC_HANDLE hService, + __in LPCWSTR wzServiceName, + __in DWORD dwRestartServiceDelayInSeconds, + __in LPCWSTR wzFirstFailureActionType, + __in LPCWSTR wzSecondFailureActionType, + __in LPCWSTR wzThirdFailureActionType, + __in DWORD dwResetPeriodInDays, + __in LPWSTR wzRebootMessage, + __in LPWSTR wzProgramCommandLine + ) +{ + HRESULT hr = S_OK; + DWORD er = ERROR_SUCCESS; + + HANDLE hToken = NULL; + TOKEN_PRIVILEGES priv = { 0 }; + TOKEN_PRIVILEGES* pPrevPriv = NULL; + DWORD cbPrevPriv = 0; + BOOL fAdjustedPrivileges = FALSE; + + SC_ACTION actions[3]; // the UI always shows 3 actions, so we'll always do 3 + SERVICE_FAILURE_ACTIONSW sfa; + LPVOID lpMsgBuf = NULL; + + // Always get the shutdown privilege in case we need to configure service to reboot. + if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken)) + { + ExitWithLastError(hr, "Failed to get process token."); + } + + priv.PrivilegeCount = 1; + priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + if (!::LookupPrivilegeValueW(NULL, L"SeShutdownPrivilege", &priv.Privileges[0].Luid)) + { + ExitWithLastError(hr, "Failed to get shutdown privilege LUID."); + } + + cbPrevPriv = sizeof(TOKEN_PRIVILEGES); + pPrevPriv = static_cast(MemAlloc(cbPrevPriv, TRUE)); + ExitOnNull(pPrevPriv, hr, E_OUTOFMEMORY, "Failed to allocate memory for empty previous privileges."); + + if (!::AdjustTokenPrivileges(hToken, FALSE, &priv, cbPrevPriv, pPrevPriv, &cbPrevPriv)) + { + LPVOID pv = MemReAlloc(pPrevPriv, cbPrevPriv, TRUE); + ExitOnNull(pv, hr, E_OUTOFMEMORY, "Failed to allocate memory for previous privileges."); + pPrevPriv = static_cast(pv); + + if (!::AdjustTokenPrivileges(hToken, FALSE, &priv, cbPrevPriv, pPrevPriv, &cbPrevPriv)) + { + ExitWithLastError(hr, "Failed to get shutdown privilege LUID."); + } + } + + fAdjustedPrivileges = TRUE; + + // build up SC_ACTION array + // TODO: why is delay only respected when SC_ACTION_RESTART is requested? + actions[0].Type = GetSCActionType(wzFirstFailureActionType); + actions[0].Delay = 0; + if (SC_ACTION_RESTART == actions[0].Type) + { + actions[0].Delay = dwRestartServiceDelayInSeconds * 1000; // seconds to milliseconds + } + + actions[1].Type = GetSCActionType(wzSecondFailureActionType); + actions[1].Delay = 0; + if (SC_ACTION_RESTART == actions[1].Type) + { + actions[1].Delay = dwRestartServiceDelayInSeconds * 1000; // seconds to milliseconds + } + + actions[2].Type = GetSCActionType(wzThirdFailureActionType); + actions[2].Delay = 0; + if (SC_ACTION_RESTART == actions[2].Type) + { + actions[2].Delay = dwRestartServiceDelayInSeconds * 1000; // seconds to milliseconds + } + + // build up the SERVICE_FAILURE_ACTIONSW struct + sfa.dwResetPeriod = dwResetPeriodInDays * (24 * 60 * 60); // days to seconds + sfa.lpRebootMsg = wzRebootMessage; + sfa.lpCommand = wzProgramCommandLine; + sfa.cActions = countof(actions); + sfa.lpsaActions = actions; + + // Call ChangeServiceConfig2 to actually set up the failure actions + if (!::ChangeServiceConfig2W(hService, SERVICE_CONFIG_FAILURE_ACTIONS, (LPVOID)&sfa)) + { + er = ::GetLastError(); + hr = HRESULT_FROM_WIN32(er); + +#pragma prefast(push) +#pragma prefast(disable:25028) + ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, er, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpMsgBuf, 0, NULL); +#pragma prefast(pop) + + // Check if this is a service that can't be modified. + if (ERROR_CANNOT_DETECT_PROCESS_ABORT == er) + { + WcaLog(LOGMSG_STANDARD, "WARNING: Service \"%ls\" is not configurable on this server and will not be set.", wzServiceName); + } + ExitOnFailure(hr, "Cannot change service configuration. Error: %ls", (LPWSTR)lpMsgBuf); + + if (lpMsgBuf) + { + ::LocalFree(lpMsgBuf); + lpMsgBuf = NULL; + } + } + +LExit: + if (lpMsgBuf) + { + ::LocalFree(lpMsgBuf); + } + + if (fAdjustedPrivileges) + { + ::AdjustTokenPrivileges(hToken, FALSE, pPrevPriv, 0, NULL, NULL); + } + + ReleaseMem(pPrevPriv); + ReleaseHandle(hToken); + + return hr; +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + +HRESULT ShellExec( + __in LPCWSTR wzTarget, + __in BOOL fUnelevated + ) +{ + HRESULT hr = S_OK; + LPWSTR sczWorkingDirectory = NULL; + + // a reasonable working directory (not the system32 default from MSI) is the directory where the target lives + hr = PathGetDirectory(wzTarget, &sczWorkingDirectory); + ExitOnFailure(hr, "failed to get directory for target: %ls", wzTarget); + + if (!DirExists(sczWorkingDirectory, NULL)) + { + ReleaseNullStr(sczWorkingDirectory); + } + + if (fUnelevated) + { + hr = ShelExecUnelevated(wzTarget, NULL, NULL, sczWorkingDirectory, SW_SHOWDEFAULT); + ExitOnFailure(hr, "ShelExecUnelevated failed with target %ls", wzTarget); + } + else + { + HINSTANCE hinst = ::ShellExecuteW(NULL, NULL, wzTarget, NULL, sczWorkingDirectory, SW_SHOWDEFAULT); + if (hinst <= HINSTANCE(32)) + { + LONG64 code = reinterpret_cast(hinst); + switch (code) + { + case ERROR_FILE_NOT_FOUND: + hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + break; + case ERROR_PATH_NOT_FOUND: + hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); + break; + case ERROR_BAD_FORMAT: + hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT); + break; + case SE_ERR_ASSOCINCOMPLETE: + case SE_ERR_NOASSOC: + hr = HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION); + break; + case SE_ERR_DDEBUSY: + case SE_ERR_DDEFAIL: + case SE_ERR_DDETIMEOUT: + hr = HRESULT_FROM_WIN32(ERROR_DDE_FAIL); + break; + case SE_ERR_DLLNOTFOUND: + hr = HRESULT_FROM_WIN32(ERROR_DLL_NOT_FOUND); + break; + case SE_ERR_OOM: + hr = E_OUTOFMEMORY; + break; + case SE_ERR_ACCESSDENIED: + hr = E_ACCESSDENIED; + break; + default: + hr = E_FAIL; + } + + ExitOnFailure(hr, "ShellExec failed with return code %llu.", code); + } + } + + +LExit: + ReleaseStr(sczWorkingDirectory); + return hr; +} + +extern "C" UINT __stdcall WixShellExec( + __in MSIHANDLE hInstall + ) +{ + Assert(hInstall); + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + LPWSTR pwzTarget = NULL; + + hr = WcaInitialize(hInstall, "WixShellExec"); + ExitOnFailure(hr, "failed to initialize"); + + hr = WcaGetFormattedProperty(L"WixShellExecTarget", &pwzTarget); + ExitOnFailure(hr, "failed to get WixShellExecTarget"); + + WcaLog(LOGMSG_VERBOSE, "WixShellExecTarget is %ls", pwzTarget); + + if (!pwzTarget || !*pwzTarget) + { + hr = E_INVALIDARG; + ExitOnFailure(hr, "failed to get WixShellExecTarget"); + } + + hr = ShellExec(pwzTarget, FALSE); + ExitOnFailure(hr, "failed to launch target"); + +LExit: + ReleaseStr(pwzTarget); + + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + return WcaFinalize(er); +} + +extern "C" UINT __stdcall WixUnelevatedShellExec( + __in MSIHANDLE hInstall + ) +{ + Assert(hInstall); + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + LPWSTR pwzTarget = NULL; + + hr = WcaInitialize(hInstall, "WixUnelevatedShellExec"); + ExitOnFailure(hr, "failed to initialize"); + + hr = WcaGetFormattedProperty(L"WixUnelevatedShellExecTarget", &pwzTarget); + ExitOnFailure(hr, "failed to get WixUnelevatedShellExecTarget"); + + WcaLog(LOGMSG_VERBOSE, "WixUnelevatedShellExecTarget is %ls", pwzTarget); + + if (!pwzTarget || !*pwzTarget) + { + hr = E_INVALIDARG; + ExitOnFailure(hr, "failed to get WixShellExecTarget"); + } + + hr = ShellExec(pwzTarget, TRUE); + ExitOnFailure(hr, "failed to launch target"); + +LExit: + ReleaseStr(pwzTarget); + + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + return WcaFinalize(er); +} + +// +// ExtractBinary extracts the data from the Binary table row with the given ID into a file. +// +HRESULT ExtractBinary( + __in LPCWSTR wzBinaryId, + __out BYTE** pbData, + __out DWORD* pcbData + ) +{ + HRESULT hr = S_OK; + LPWSTR pwzSql = NULL; + PMSIHANDLE hView; + PMSIHANDLE hRec; + + // make sure we're not horked from the get-go + hr = WcaTableExists(L"Binary"); + if (S_OK != hr) + { + if (SUCCEEDED(hr)) + { + hr = E_UNEXPECTED; + } + ExitOnFailure(hr, "There is no Binary table."); + } + + ExitOnNull(wzBinaryId, hr, E_INVALIDARG, "Binary ID cannot be null"); + ExitOnNull(*wzBinaryId, hr, E_INVALIDARG, "Binary ID cannot be empty string"); + + hr = StrAllocFormatted(&pwzSql, L"SELECT `Data` FROM `Binary` WHERE `Name`=\'%s\'", wzBinaryId); + ExitOnFailure(hr, "Failed to allocate Binary table query."); + + hr = WcaOpenExecuteView(pwzSql, &hView); + ExitOnFailure(hr, "Failed to open view on Binary table"); + + hr = WcaFetchSingleRecord(hView, &hRec); + ExitOnFailure(hr, "Failed to retrieve request from Binary table"); + + hr = WcaGetRecordStream(hRec, 1, pbData, pcbData); + ExitOnFailure(hr, "Failed to read Binary.Data."); + +LExit: + ReleaseStr(pwzSql); + + return hr; +} + +extern "C" UINT __stdcall WixShellExecBinary( + __in MSIHANDLE hInstall + ) +{ + Assert(hInstall); + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + LPWSTR pwzBinary = NULL; + LPWSTR pwzFilename = NULL; + BYTE* pbData = NULL; + DWORD cbData = 0; + HANDLE hFile = INVALID_HANDLE_VALUE; + +#if 0 + ::MessageBoxA(0, "WixShellExecBinary", "-->> ATTACH HERE", MB_OK); +#endif + + hr = WcaInitialize(hInstall, "WixShellExecBinary"); + ExitOnFailure(hr, "failed to initialize"); + + hr = WcaGetFormattedProperty(L"WixShellExecBinaryId", &pwzBinary); + ExitOnFailure(hr, "failed to get WixShellExecBinaryId"); + + WcaLog(LOGMSG_VERBOSE, "WixShellExecBinaryId is %ls", pwzBinary); + + if (!pwzBinary || !*pwzBinary) + { + hr = E_INVALIDARG; + ExitOnFailure(hr, "failed to get WixShellExecBinaryId"); + } + + // get temporary path for extracted file + StrAlloc(&pwzFilename, MAX_PATH); + ExitOnFailure(hr, "Failed to allocate temporary path"); + ::GetTempPathW(MAX_PATH, pwzFilename); + hr = ::StringCchCatW(pwzFilename, MAX_PATH, pwzBinary); + ExitOnFailure(hr, "Failed to append filename."); + + // grab the bits + hr = ExtractBinary(pwzBinary, &pbData, &cbData); + ExitOnFailure(hr, "failed to extract binary data"); + + // write 'em to the temp file + hFile = ::CreateFileW(pwzFilename, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (INVALID_HANDLE_VALUE == hFile) + { + ExitWithLastError(hr, "Failed to open new temp file: %ls", pwzFilename); + } + + DWORD cbWritten = 0; + if (!::WriteFile(hFile, pbData, cbData, &cbWritten, NULL)) + { + ExitWithLastError(hr, "Failed to write data to new temp file: %ls", pwzFilename); + } + + // close it + ::CloseHandle(hFile); + hFile = INVALID_HANDLE_VALUE; + + // and run it + hr = ShellExec(pwzFilename, FALSE); + ExitOnFailure(hr, "failed to launch target: %ls", pwzFilename); + +LExit: + ReleaseStr(pwzBinary); + ReleaseStr(pwzFilename); + ReleaseMem(pbData); + if (INVALID_HANDLE_VALUE != hFile) + { + ::CloseHandle(hFile); + } + + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + return WcaFinalize(er); +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + +#define WIXCA_UITHREAD_CLASS_WINDOW L"WixCaMessageWindow" + +extern HMODULE g_hInstCADLL; + + +// structs + +struct UITHREAD_CONTEXT +{ + HANDLE hInitializedEvent; + HINSTANCE hInstance; + HWND hWnd; +}; + + +// internal function declarations + +static HRESULT CreateMessageWindow( + __out HWND* phWnd + ); + +static void CloseMessageWindow( + __in HWND hWnd + ); + +static DWORD WINAPI ThreadProc( + __in LPVOID pvContext + ); + +static LRESULT CALLBACK WndProc( + __in HWND hWnd, + __in UINT uMsg, + __in WPARAM wParam, + __in LPARAM lParam + ); + + +/****************************************************************** +WixFailWhenDeferred - entry point for WixFailWhenDeferred + custom action which always fails when running as a deferred + custom action (otherwise it blindly succeeds). It's useful when + testing the rollback of deferred custom actions: Schedule it + immediately after the rollback/deferred CA pair you're testing + and it will fail, causing your rollback CA to get invoked. +********************************************************************/ +extern "C" UINT __stdcall WixFailWhenDeferred( + __in MSIHANDLE hInstall + ) +{ + return ::MsiGetMode(hInstall, MSIRUNMODE_SCHEDULED) ? ERROR_INSTALL_FAILURE : ERROR_SUCCESS; +} + +/****************************************************************** +WixWaitForEvent - entry point for WixWaitForEvent custom action + which waits for either the WixWaitForEventFail or + WixWaitForEventSucceed named auto reset events. Signaling the + WixWaitForEventFail event will return ERROR_INSTALL_FAILURE or + signaling the WixWaitForEventSucceed event will return + ERROR_SUCCESS. Both events are declared in the Global\ namespace. +********************************************************************/ +extern "C" UINT __stdcall WixWaitForEvent( + __in MSIHANDLE hInstall + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + HWND hMessageWindow = NULL; + LPCWSTR wzSDDL = L"D:(A;;GA;;;WD)"; + OS_VERSION version = OS_VERSION_UNKNOWN; + DWORD dwServicePack = 0; + PSECURITY_DESCRIPTOR pSD = NULL; + SECURITY_ATTRIBUTES sa = { }; + HANDLE rghEvents[2]; + + hr = WcaInitialize(hInstall, "WixWaitForEvent"); + ExitOnFailure(hr, "Failed to initialize."); + + // Create a window to prevent shutdown requests. + hr = CreateMessageWindow(&hMessageWindow); + ExitOnFailure(hr, "Failed to create message window."); + + // If running on Vista/2008 or newer use integrity enhancements. + OsGetVersion(&version, &dwServicePack); + if (OS_VERSION_VISTA <= version) + { + // Add SACL to allow Everyone to signal from a medium integrity level. + wzSDDL = L"D:(A;;GA;;;WD)S:(ML;;NW;;;ME)"; + } + + // Create the security descriptor and attributes for the events. + if (!::ConvertStringSecurityDescriptorToSecurityDescriptorW(wzSDDL, SDDL_REVISION_1, &pSD, NULL)) + { + ExitWithLastError(hr, "Failed to create the security descriptor for the events."); + } + + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = pSD; + sa.bInheritHandle = FALSE; + + rghEvents[0] = ::CreateEventW(&sa, FALSE, FALSE, L"Global\\WixWaitForEventFail"); + ExitOnNullWithLastError(rghEvents[0], hr, "Failed to create the Global\\WixWaitForEventFail event."); + + rghEvents[1] = ::CreateEventW(&sa, FALSE, FALSE, L"Global\\WixWaitForEventSucceed"); + ExitOnNullWithLastError(rghEvents[1], hr, "Failed to create the Global\\WixWaitForEventSucceed event."); + + // Wait for either of the events to be signaled and handle accordingly. + er = ::WaitForMultipleObjects(countof(rghEvents), rghEvents, FALSE, INFINITE); + switch (er) + { + case WAIT_OBJECT_0 + 0: + er = ERROR_INSTALL_FAILURE; + break; + case WAIT_OBJECT_0 + 1: + er = ERROR_SUCCESS; + break; + default: + ExitOnWin32Error(er, hr, "Unexpected failure."); + } + +LExit: + ReleaseHandle(rghEvents[1]); + ReleaseHandle(rghEvents[0]); + + if (pSD) + { + ::LocalFree(pSD); + } + + if (hMessageWindow) + { + CloseMessageWindow(hMessageWindow); + } + + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + + return WcaFinalize(er); +} + + +// internal function definitions + +static HRESULT CreateMessageWindow( + __out HWND* phWnd + ) +{ + HRESULT hr = S_OK; + HANDLE rgWaitHandles[2] = { }; + UITHREAD_CONTEXT context = { }; + + // Create event to signal after the UI thread / window is initialized. + rgWaitHandles[0] = ::CreateEventW(NULL, TRUE, FALSE, NULL); + ExitOnNullWithLastError(rgWaitHandles[0], hr, "Failed to create initialization event."); + + // Pass necessary information to create the window. + context.hInitializedEvent = rgWaitHandles[0]; + context.hInstance = (HINSTANCE)g_hInstCADLL; + + // Create our separate UI thread. + rgWaitHandles[1] = ::CreateThread(NULL, 0, ThreadProc, &context, 0, NULL); + ExitOnNullWithLastError(rgWaitHandles[1], hr, "Failed to create the UI thread."); + + // Wait for either the thread to be initialized or the window to exit / fail prematurely. + ::WaitForMultipleObjects(countof(rgWaitHandles), rgWaitHandles, FALSE, INFINITE); + + // Pass the window back to the caller. + *phWnd = context.hWnd; + +LExit: + ReleaseHandle(rgWaitHandles[1]); + ReleaseHandle(rgWaitHandles[0]); + + return hr; +} + +static void CloseMessageWindow( + __in HWND hWnd + ) +{ + if (::IsWindow(hWnd)) + { + ::PostMessageW(hWnd, WM_CLOSE, 0, 0); + } +} + +static DWORD WINAPI ThreadProc( + __in LPVOID pvContext + ) +{ + HRESULT hr = S_OK; + UITHREAD_CONTEXT* pContext = static_cast(pvContext); + + WNDCLASSW wc = { }; + BOOL fRegistered = TRUE; + HWND hWnd = NULL; + + BOOL fRet = FALSE; + MSG msg = { }; + + wc.lpfnWndProc = WndProc; + wc.hInstance = pContext->hInstance; + wc.lpszClassName = WIXCA_UITHREAD_CLASS_WINDOW; + + if (!::RegisterClassW(&wc)) + { + ExitWithLastError(hr, "Failed to register window."); + } + + fRegistered = TRUE; + + // Create the window to handle reboots without activating it. + hWnd = ::CreateWindowExW(WS_EX_TOOLWINDOW, wc.lpszClassName, NULL, WS_POPUP | WS_VISIBLE, CW_USEDEFAULT, SW_SHOWNA, 0, 0, HWND_DESKTOP, NULL, pContext->hInstance, NULL); + ExitOnNullWithLastError(hWnd, hr, "Failed to create window."); + + // Persist the window handle and let the caller know we've initialized. + pContext->hWnd = hWnd; + ::SetEvent(pContext->hInitializedEvent); + + // Pump messages until the window is closed. + while (0 != (fRet = ::GetMessageW(&msg, NULL, 0, 0))) + { + if (-1 == fRet) + { + hr = E_UNEXPECTED; + ExitOnFailure(hr, "Unexpected return value from message pump."); + } + else if (!::IsDialogMessageW(msg.hwnd, &msg)) + { + ::TranslateMessage(&msg); + ::DispatchMessageW(&msg); + } + } + +LExit: + if (fRegistered) + { + ::UnregisterClassW(WIXCA_UITHREAD_CLASS_WINDOW, pContext->hInstance); + } + + return hr; +} + +static LRESULT CALLBACK WndProc( + __in HWND hWnd, + __in UINT uMsg, + __in WPARAM wParam, + __in LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_QUERYENDSESSION: + // Prevent the process from being shut down. + WcaLog(LOGMSG_VERBOSE, "Disallowed system request to shut down the custom action server."); + return FALSE; + + case WM_DESTROY: + ::PostQuitMessage(0); + return 0; + } + + return ::DefWindowProcW(hWnd, uMsg, wParam, lParam); +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#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 @@ +; Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +LIBRARY "utilca" + +EXPORTS +; BroadcastSettingChange.cpp + WixBroadcastSettingChange + WixBroadcastEnvironmentChange +; checkreboot.cpp + WixCheckRebootRequired +; closeapps.cpp + WixCloseApplications + WixCloseApplicationsDeferred +; exitearlywithsuccess.cpp + WixExitEarlyWithSuccess +; FormatFiles.cpp + WixSchedFormatFiles + WixExecFormatFiles +; osinfo.cpp + WixQueryOsInfo + WixQueryOsDirs + WixQueryOsWellKnownSID + WixQueryOsDriverInfo +; netshortcuts.cpp + WixSchedInternetShortcuts + WixCreateInternetShortcuts + WixRollbackInternetShortcuts +; qtexecca.cpp + CAQuietExec + CAQuietExec64 + WixQuietExec + WixQuietExec64 + WixSilentExec + WixSilentExec64 +; RemoveFoldersEx.cpp + WixRemoveFoldersEx +; RemoveRegistryKeysEx.cpp + WixRemoveRegistryKeysEx +;scaexec.cpp + RegisterPerfCounterData + UnregisterPerfCounterData + RegisterPerfmon + UnregisterPerfmon + CreateSmb + DropSmb + CreateUser + CreateUserRollback + RemoveUser +;scasched.cpp + ConfigurePerfmonInstall + ConfigurePerfmonUninstall + ConfigureSmbInstall + ConfigureSmbUninstall + ConfigureUsers + InstallPerfCounterData + UninstallPerfCounterData + ConfigurePerfmonManifestRegister + ConfigurePerfmonManifestUnregister + ConfigureEventManifestRegister + ConfigureEventManifestUnregister +; RestartManager.cpp + WixRegisterRestartResources +; secureobj.cpp + SchedSecureObjects + SchedSecureObjectsRollback + ExecSecureObjects + ExecSecureObjectsRollback +; serviceconfig.cpp + SchedServiceConfig + ExecServiceConfig + RollbackServiceConfig +; shellexecca.cpp + WixShellExec + WixShellExecBinary + WixUnelevatedShellExec +; test.cpp + WixFailWhenDeferred + WixWaitForEvent +; TouchFile.cpp + WixTouchFileDuringInstall + WixTouchFileDuringUninstall + WixExecuteTouchFile +; xmlfile.cpp + SchedXmlFile + ExecXmlFile + ExecXmlFileRollback +; xmlconfig.cpp + SchedXmlConfig + ExecXmlConfig + 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 @@ + + + + + + + Debug + ARM64 + + + Release + ARM64 + + + Debug + X64 + + + Release + X64 + + + Debug + Win32 + + + Release + Win32 + + + + + {076018F7-19BD-423A-ABBF-229273DA08D8} + DynamicLibrary + utilca + v142 + Unicode + utilca.def + WiX Toolset Util CustomAction + + + + + + + activeds.lib;adsiid.lib;msi.lib;netapi32.lib;shlwapi.lib + + + + + + + + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + + + + + \ 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 Binary files /dev/null and b/src/ext/Util/test/WixToolsetTest.Util/TestData/.Data/burn.exe 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 @@ + + + + ~TestBundle + + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 Binary files /dev/null and b/src/ext/Util/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/test.msi 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 @@ + + + + A newer version of [ProductName] is already installed. + MsiPackage + + 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 @@ + + + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + 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 @@ + + + + A newer version of [ProductName] is already installed. + MsiPackage + + 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 @@ + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + 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 @@ + + + + A newer version of [ProductName] is already installed. + MsiPackage + + 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 Binary files /dev/null and b/src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcut/Package.ico 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 @@ + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + 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 Binary files /dev/null and b/src/ext/Util/test/WixToolsetTest.Util/TestData/InternetShortcutModule/Package.ico 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 @@ + + + + A newer version of [ProductName] is already installed. + MsiPackage + + 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 @@ + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + A newer version of [ProductName] is already installed. + MsiPackage + + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + 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 @@ + + + + + + + + + + + + + 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 @@ + + + + + + + + + + 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 @@ + + + + + + + + + + + + + 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 @@ + + + + + + + + + + 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 @@ + + + + A newer version of [ProductName] is already installed. + MsiPackage + + 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 @@ + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + 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 @@ + + + + A newer version of [ProductName] is already installed. + MsiPackage + + 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 @@ + + + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + + + + + + 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolsetTest.Util +{ + using System.IO; + using System.Linq; + using WixBuildTools.TestSupport; + using WixToolset.Core.TestPackage; + using WixToolset.Data; + using WixToolset.Data.Symbols; + using WixToolset.Util; + using Xunit; + + public class UtilExtensionFixture + { + [Fact] + public void CanBuildUsingFileShare() + { + var folder = TestData.Get(@"TestData\UsingFileShare"); + var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }); + + var results = build.BuildAndQuery(Build, "Binary", "CustomAction", "Wix4FileShare", "Wix4FileSharePermissions"); + WixAssert.CompareLineByLine(new[] + { + "Binary:Wix4UtilCA_X86\t[Binary data]", + "CustomAction:Wix4ConfigureSmbInstall_X86\t1\tWix4UtilCA_X86\tConfigureSmbInstall\t", + "CustomAction:Wix4ConfigureSmbUninstall_X86\t1\tWix4UtilCA_X86\tConfigureSmbUninstall\t", + "CustomAction:Wix4CreateSmb_X86\t11265\tWix4UtilCA_X86\tCreateSmb\t", + "CustomAction:Wix4CreateSmbRollback_X86\t11585\tWix4UtilCA_X86\tDropSmb\t", + "CustomAction:Wix4DropSmb_X86\t11265\tWix4UtilCA_X86\tDropSmb\t", + "CustomAction:Wix4DropSmbRollback_X86\t11585\tWix4UtilCA_X86\tCreateSmb\t", + "Wix4FileShare:ExampleFileShare\texample\tfilF5_pLhBuF5b4N9XEo52g_hUM5Lo\tAn example file share\tINSTALLFOLDER", + "Wix4FileSharePermissions:ExampleFileShare\tEveryone\t1", + }, results.OrderBy(s => s).ToArray()); + } + + [Fact] + public void CanBuildUsingFileShareX64() + { + var folder = TestData.Get(@"TestData\UsingFileShare"); + var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }); + + var results = build.BuildAndQuery(BuildX64, "Binary", "CustomAction", "Wix4FileShare", "Wix4FileSharePermissions"); + WixAssert.CompareLineByLine(new[] + { + "Binary:Wix4UtilCA_X64\t[Binary data]", + "CustomAction:Wix4ConfigureSmbInstall_X64\t1\tWix4UtilCA_X64\tConfigureSmbInstall\t", + "CustomAction:Wix4ConfigureSmbUninstall_X64\t1\tWix4UtilCA_X64\tConfigureSmbUninstall\t", + "CustomAction:Wix4CreateSmb_X64\t11265\tWix4UtilCA_X64\tCreateSmb\t", + "CustomAction:Wix4CreateSmbRollback_X64\t11585\tWix4UtilCA_X64\tDropSmb\t", + "CustomAction:Wix4DropSmb_X64\t11265\tWix4UtilCA_X64\tDropSmb\t", + "CustomAction:Wix4DropSmbRollback_X64\t11585\tWix4UtilCA_X64\tCreateSmb\t", + "Wix4FileShare:ExampleFileShare\texample\tfilF5_pLhBuF5b4N9XEo52g_hUM5Lo\tAn example file share\tINSTALLFOLDER", + "Wix4FileSharePermissions:ExampleFileShare\tEveryone\t1", + }, results.OrderBy(s => s).ToArray()); + } + + [Fact] + public void CanBuildCloseApplication() + { + var folder = TestData.Get(@"TestData\CloseApplication"); + var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }); + + var results = build.BuildAndQuery(BuildARM64, "Binary", "CustomAction", "Wix4CloseApplication"); + WixAssert.CompareLineByLine(new[] + { + "Binary:Wix4UtilCA_A64\t[Binary data]", + "CustomAction:Wix4CheckRebootRequired_A64\t65\tWix4UtilCA_A64\tWixCheckRebootRequired\t", + "CustomAction:Wix4CloseApplications_A64\t1\tWix4UtilCA_A64\tWixCloseApplications\t", + "CustomAction:Wix4CloseApplicationsDeferred_A64\t3073\tWix4UtilCA_A64\tWixCloseApplicationsDeferred\t", + "Wix4CloseApplication:CloseMyApp\texplorer.exe\t\t\t3\t\tMYAPPISRUNNING\t\t", + }, results.OrderBy(s => s).ToArray()); + } + + [Fact] + public void CanBuildInternetShortcutInProduct() + { + var folder = TestData.Get(@"TestData\InternetShortcut"); + var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }); + + var results = build.BuildAndQuery(BuildX64, "Binary", "CustomAction", "RemoveFile", "Wix4InternetShortcut"); + WixAssert.CompareLineByLine(new[] + { + "Binary:Wix4UtilCA_X64\t[Binary data]", + "CustomAction:Wix4CreateInternetShortcuts_X64\t3073\tWix4UtilCA_X64\tWixCreateInternetShortcuts\t", + "CustomAction:Wix4RollbackInternetShortcuts_X64\t3329\tWix4UtilCA_X64\tWixRollbackInternetShortcuts\t", + "CustomAction:Wix4SchedInternetShortcuts_X64\t1\tWix4UtilCA_X64\tWixSchedInternetShortcuts\t", + "RemoveFile:uisdCsU32.1i4Hebrg1N7E194zJQ8Y\tPackage.ico\thoiptxrr.url|WiX Toolset (url).url\tINSTALLFOLDER\t2", + "RemoveFile:uisjV.q0ROZZYR3h_lkpbkZtLtPH0A\tPackage.ico\tjcxd1dwf.lnk|WiX Toolset (link).lnk\tINSTALLFOLDER\t2", + "Wix4InternetShortcut:uisdCsU32.1i4Hebrg1N7E194zJQ8Y\tPackage.ico\tINSTALLFOLDER\tWiX Toolset (url).url\thttps://wixtoolset.org\t1\t[#Package.ico]\t0", + "Wix4InternetShortcut:uisjV.q0ROZZYR3h_lkpbkZtLtPH0A\tPackage.ico\tINSTALLFOLDER\tWiX Toolset (link).lnk\thttps://wixtoolset.org\t0\t[#Package.ico]\t0", + }, results.OrderBy(s => s).ToArray()); + } + + [Fact] + public void CanBuildInternetShortcutInMergeModule() + { + var folder = TestData.Get(@"TestData\InternetShortcutModule"); + var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }, "test.msm"); + + var results = build.BuildAndQuery(BuildX64, "Binary", "CustomAction", "RemoveFile", "Wix4InternetShortcut"); + WixAssert.CompareLineByLine(new[] + { + "Binary:Wix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A\t[Binary data]", + "CustomAction:Wix4CreateInternetShortcuts_X64\t3073\tWix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A\tWixCreateInternetShortcuts\t", + "CustomAction:Wix4RollbackInternetShortcuts_X64\t3329\tWix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A\tWixRollbackInternetShortcuts\t", + "CustomAction:Wix4SchedInternetShortcuts_X64\t1\tWix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A\tWixSchedInternetShortcuts\t", + "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", + "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", + "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", + "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", + }, results.OrderBy(s => s).ToArray()); + } + + [Fact] + public void CanBuildWithPermissionEx() + { + var folder = TestData.Get(@"TestData\PermissionEx"); + var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }); + + var results = build.BuildAndQuery(BuildX64, "Wix4SecureObject"); + WixAssert.CompareLineByLine(new[] + { + "Wix4SecureObject:ExampleRegistryKey\tRegistry\t\tEveryone\t1\t268435456\tfilF5_pLhBuF5b4N9XEo52g_hUM5Lo", + "Wix4SecureObject:filF5_pLhBuF5b4N9XEo52g_hUM5Lo\tFile\t\tEveryone\t1\t268435456\tfilF5_pLhBuF5b4N9XEo52g_hUM5Lo", + "Wix4SecureObject:INSTALLFOLDER\tCreateFolder\t\tEveryone\t1\t268435456\tfilF5_pLhBuF5b4N9XEo52g_hUM5Lo", + "Wix4SecureObject:regL6DnQ9yJpDJH5OdcVji4YXsdX2c\tRegistry\t\tEveryone\t1\t268435456\tfilF5_pLhBuF5b4N9XEo52g_hUM5Lo", + "Wix4SecureObject:testsvc\tServiceInstall\t\tEveryone\t1\t268435456\tfilF5_pLhBuF5b4N9XEo52g_hUM5Lo", + }, results.OrderBy(s => s).ToArray()); + } + + [Fact] + public void CanBuildRemoveRegistryKeyExInMergeModule() + { + var folder = TestData.Get(@"TestData", "RemoveRegistryKeyEx"); + var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }, "test.msm"); + + var results = build.BuildAndQuery(BuildX64, "Binary", "CustomAction", "RemoveRegistry", "Wix4RemoveRegistryKeyEx"); + WixAssert.CompareLineByLine(new[] + { + "Binary:Wix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A\t[Binary data]", + "CustomAction:Wix4RemoveRegistryKeysEx_X64.047730A5_30FE_4A62_A520_DA9381B8226A\t65\tWix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A\tWixRemoveRegistryKeysEx\t", + "Wix4RemoveRegistryKeyEx:rrxfcDhR4HhE3v3rYiQcNtQjyahQNg.047730A5_30FE_4A62_A520_DA9381B8226A\tfilh4juyUVjoUcWWtcQmd5L07FoON4.047730A5_30FE_4A62_A520_DA9381B8226A\t2\tSOFTWARE\\Example\t1\t", + }, results.OrderBy(s => s).ToArray()); + } + + [Fact] + public void CanBuildRemoveFolderExInMergeModule() + { + var folder = TestData.Get(@"TestData\RemoveFolderEx"); + var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }, "test.msm"); + + var results = build.BuildAndQuery(BuildX64, "Binary", "CustomAction", "RemoveFile", "Wix4RemoveFolderEx"); + WixAssert.CompareLineByLine(new[] + { + "Binary:Wix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A\t[Binary data]", + "CustomAction:Wix4RemoveFoldersEx_X64.047730A5_30FE_4A62_A520_DA9381B8226A\t65\tWix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A\tWixRemoveFoldersEx\t", + "Wix4RemoveFolderEx:wrf5qCm1SE.zp8djrlk78l1IYFXsEw.047730A5_30FE_4A62_A520_DA9381B8226A\tfilh4juyUVjoUcWWtcQmd5L07FoON4.047730A5_30FE_4A62_A520_DA9381B8226A\tRemoveProp.047730A5_30FE_4A62_A520_DA9381B8226A\t3\t", + }, results.OrderBy(s => s).ToArray()); + } + + [Fact] + public void CanBuildWithEventManifest() + { + var folder = TestData.Get(@"TestData\EventManifest"); + var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }); + + var results = build.BuildAndQuery(BuildARM64, "Binary", "CustomAction", "Wix4EventManifest", "Wix4XmlFile"); + WixAssert.CompareLineByLine(new[] + { + "Binary:Wix4UtilCA_A64\t[Binary data]", + "CustomAction:Wix4ConfigureEventManifestRegister_A64\t1\tWix4UtilCA_A64\tConfigureEventManifestRegister\t", + "CustomAction:Wix4ConfigureEventManifestUnregister_A64\t1\tWix4UtilCA_A64\tConfigureEventManifestUnregister\t", + "CustomAction:Wix4ExecXmlFile_A64\t11265\tWix4UtilCA_A64\tExecXmlFile\t", + "CustomAction:Wix4ExecXmlFileRollback_A64\t11521\tWix4UtilCA_A64\tExecXmlFileRollback\t", + "CustomAction:Wix4RegisterEventManifest_A64\t3073\tWix4UtilCA_A64\tWixQuietExec\t", + "CustomAction:Wix4RollbackRegisterEventManifest_A64\t3393\tWix4UtilCA_A64\tWixQuietExec\t", + "CustomAction:Wix4RollbackUnregisterEventManifest_A64\t3329\tWix4UtilCA_A64\tWixQuietExec\t", + "CustomAction:Wix4SchedXmlFile_A64\t1\tWix4UtilCA_A64\tSchedXmlFile\t", + "CustomAction:Wix4UnregisterEventManifest_A64\t3137\tWix4UtilCA_A64\tWixQuietExec\t", + "Wix4EventManifest:Manifest.dll\t[#Manifest.dll]", + "Wix4XmlFile:Config_Manifest.dllMessageFile\t[#Manifest.dll]\t/*/*/*/*[\\[]@messageFileName[\\]]\tmessageFileName\t[Manifest.dll]\t4100\tManifest.dll\t", + "Wix4XmlFile:Config_Manifest.dllResourceFile\t[#Manifest.dll]\t/*/*/*/*[\\[]@resourceFileName[\\]]\tresourceFileName\t[Manifest.dll]\t4100\tManifest.dll\t", + }, results.OrderBy(s => s).ToArray()); + } + + [Fact] + public void CanBuildWithQueries() + { + var folder = TestData.Get(@"TestData\Queries"); + var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }); + + var results = build.BuildAndQuery(BuildARM64, "Binary", "CustomAction"); + WixAssert.CompareLineByLine(new[] + { + "Binary:Wix4UtilCA_A64\t[Binary data]", + "CustomAction:Wix4BroadcastEnvironmentChange_A64\t65\tWix4UtilCA_A64\tWixBroadcastEnvironmentChange\t", + "CustomAction:Wix4BroadcastSettingChange_A64\t65\tWix4UtilCA_A64\tWixBroadcastSettingChange\t", + "CustomAction:Wix4CheckRebootRequired_A64\t65\tWix4UtilCA_A64\tWixCheckRebootRequired\t", + "CustomAction:Wix4QueryOsDriverInfo_A64\t257\tWix4UtilCA_A64\tWixQueryOsDriverInfo\t", + "CustomAction:Wix4QueryOsInfo_A64\t257\tWix4UtilCA_A64\tWixQueryOsInfo\t", + }, results.OrderBy(s => s).ToArray()); + } + + [Fact] + public void CanBuildWithXmlConfig() + { + var folder = TestData.Get(@"TestData", "XmlConfig"); + var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }); + + var results = build.BuildAndQuery(BuildX64, "Wix4XmlConfig"); + WixAssert.CompareLineByLine(new[] + { + "Wix4XmlConfig:DelElement\t[INSTALLFOLDER]my.xml\t\t//root/sub\txxx\t\t\t289\tDel\t1", + }, results.OrderBy(s => s).ToArray()); + } + + [Fact] + public void CanBuildModuleWithXmlConfig() + { + var folder = TestData.Get(@"TestData", "XmlConfigModule"); + var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }); + + var results = build.BuildAndQuery(BuildX64, "Wix4XmlConfig"); + WixAssert.CompareLineByLine(new[] + { + "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", + "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", + }, results.OrderBy(s => s).ToArray()); + } + + [Fact] + public void CanBuildBundleWithSearches() + { + var burnStubPath = TestData.Get(@"TestData\.Data\burn.exe"); + var folder = TestData.Get(@"TestData\BundleWithSearches"); + var rootFolder = TestData.Get(); + var wixext = Path.Combine(rootFolder, "WixToolset.Util.wixext.dll"); + + using (var fs = new DisposableFileSystem()) + { + var baseFolder = fs.GetFolder(); + var intermediateFolder = Path.Combine(baseFolder, "obj"); + var bundlePath = Path.Combine(baseFolder, @"bin\test.exe"); + var baFolderPath = Path.Combine(baseFolder, "ba"); + var extractFolderPath = Path.Combine(baseFolder, "extract"); + + var result = WixRunner.Execute(new[] + { + "build", + Path.Combine(folder, "Bundle.wxs"), + "-ext", wixext, + "-loc", Path.Combine(folder, "Bundle.en-us.wxl"), + "-bindpath", Path.Combine(folder, "data"), + "-intermediateFolder", intermediateFolder, + "-o", bundlePath + }); + + result.AssertSuccess(); + + Assert.True(File.Exists(bundlePath)); +#if TODO + Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb"))); +#endif + + var extractResult = BundleExtractor.ExtractBAContainer(null, bundlePath, baFolderPath, extractFolderPath); + extractResult.AssertSuccess(); + + var bundleExtensionDatas = extractResult.SelectBundleExtensionDataNodes("/be:BundleExtensionData/be:BundleExtension[@Id='Wix4UtilBundleExtension_X86']"); + Assert.Equal(1, bundleExtensionDatas.Count); + Assert.Equal("" + + "" + + "", bundleExtensionDatas[0].GetTestXml()); + + var utilSearches = extractResult.SelectManifestNodes("/burn:BurnManifest/*[self::burn:ExtensionSearch or self::burn:FileSearch or self::burn:MsiProductSearch or self::burn:RegistrySearch]"); + Assert.Equal(5, utilSearches.Count); + Assert.Equal("", utilSearches[0].GetTestXml()); + Assert.Equal("", utilSearches[1].GetTestXml()); + Assert.Equal("", utilSearches[2].GetTestXml()); + Assert.Equal("", utilSearches[3].GetTestXml()); + Assert.Equal("", utilSearches[4].GetTestXml()); + } + } + + private static void Build(string[] args) + { + var result = WixRunner.Execute(args); + result.AssertSuccess(); + } + + private static void BuildX64(string[] args) + { + var newArgs = args.ToList(); + newArgs.Add("-platform"); + newArgs.Add("x64"); + newArgs.Add("-sw1072"); + + var result = WixRunner.Execute(newArgs.ToArray()); + result.AssertSuccess(); + } + + private static void BuildARM64(string[] args) + { + var newArgs = args.ToList(); + newArgs.Add("-platform"); + newArgs.Add("arm64"); + + var result = WixRunner.Execute(newArgs.ToArray()); + result.AssertSuccess(); + } + } +} 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 @@ + + + + + + netcoreapp3.1 + false + + + + NU1701 + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + True + + \ 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 Binary files /dev/null and b/src/ext/Util/wix.snk 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 @@ +// Captured from: C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.dll + +namespace System.Diagnostics +{ + public enum PerformanceCounterType + { + // + // Summary: + // An instantaneous counter that shows the most recently observed value in hexadecimal + // format. Used, for example, to maintain a simple count of items or operations. + NumberOfItemsHEX32 = 0, + // + // Summary: + // An instantaneous counter that shows the most recently observed value. Used, for + // example, to maintain a simple count of a very large number of items or operations. + // It is the same as NumberOfItemsHEX32 except that it uses larger fields to accommodate + // larger values. + NumberOfItemsHEX64 = 256, + // + // Summary: + // An instantaneous counter that shows the most recently observed value. Used, for + // example, to maintain a simple count of items or operations. + NumberOfItems32 = 65536, + // + // Summary: + // An instantaneous counter that shows the most recently observed value. Used, for + // example, to maintain a simple count of a very large number of items or operations. + // It is the same as NumberOfItems32 except that it uses larger fields to accommodate + // larger values. + NumberOfItems64 = 65792, + // + // Summary: + // A difference counter that shows the change in the measured attribute between + // the two most recent sample intervals. + CounterDelta32 = 4195328, + // + // Summary: + // A difference counter that shows the change in the measured attribute between + // the two most recent sample intervals. It is the same as the CounterDelta32 counter + // type except that is uses larger fields to accomodate larger values. + CounterDelta64 = 4195584, + // + // Summary: + // An average counter that shows the average number of operations completed in one + // second. When a counter of this type samples the data, each sampling interrupt + // returns one or zero. The counter data is the number of ones that were sampled. + // It measures time in units of ticks of the system performance timer. + SampleCounter = 4260864, + // + // Summary: + // An average counter designed to monitor the average length of a queue to a resource + // over time. It shows the difference between the queue lengths observed during + // the last two sample intervals divided by the duration of the interval. This type + // of counter is typically used to track the number of items that are queued or + // waiting. + CountPerTimeInterval32 = 4523008, + // + // Summary: + // An average counter that monitors the average length of a queue to a resource + // over time. Counters of this type display the difference between the queue lengths + // observed during the last two sample intervals, divided by the duration of the + // interval. This counter type is the same as CountPerTimeInterval32 except that + // it uses larger fields to accommodate larger values. This type of counter is typically + // used to track a high-volume or very large number of items that are queued or + // waiting. + CountPerTimeInterval64 = 4523264, + // + // Summary: + // A difference counter that shows the average number of operations completed during + // each second of the sample interval. Counters of this type measure time in ticks + // of the system clock. + RateOfCountsPerSecond32 = 272696320, + // + // Summary: + // A difference counter that shows the average number of operations completed during + // each second of the sample interval. Counters of this type measure time in ticks + // of the system clock. This counter type is the same as the RateOfCountsPerSecond32 + // type, but it uses larger fields to accommodate larger values to track a high-volume + // number of items or operations per second, such as a byte-transmission rate. + RateOfCountsPerSecond64 = 272696576, + // + // Summary: + // An instantaneous percentage counter that shows the ratio of a subset to its set + // as a percentage. For example, it compares the number of bytes in use on a disk + // to the total number of bytes on the disk. Counters of this type display the current + // percentage only, not an average over time. + RawFraction = 537003008, + // + // Summary: + // A percentage counter that shows the average time that a component is active as + // a percentage of the total sample time. + CounterTimer = 541132032, + // + // Summary: + // A percentage counter that shows the active time of a component as a percentage + // of the total elapsed time of the sample interval. It measures time in units of + // 100 nanoseconds (ns). Counters of this type are designed to measure the activity + // of one component at a time. + Timer100Ns = 542180608, + // + // Summary: + // A percentage counter that shows the average ratio of hits to all operations during + // the last two sample intervals. + SampleFraction = 549585920, + // + // Summary: + // A percentage counter that displays the average percentage of active time observed + // during sample interval. The value of these counters is calculated by monitoring + // the percentage of time that the service was inactive and then subtracting that + // value from 100 percent. + CounterTimerInverse = 557909248, + // + // Summary: + // A percentage counter that shows the average percentage of active time observed + // during the sample interval. + Timer100NsInverse = 558957824, + // + // Summary: + // A percentage counter that displays the active time of one or more components + // as a percentage of the total time of the sample interval. Because the numerator + // records the active time of components operating simultaneously, the resulting + // percentage can exceed 100 percent. + CounterMultiTimer = 574686464, + // + // Summary: + // A percentage counter that shows the active time of one or more components as + // a percentage of the total time of the sample interval. It measures time in 100 + // nanosecond (ns) units. + CounterMultiTimer100Ns = 575735040, + // + // Summary: + // A percentage counter that shows the active time of one or more components as + // a percentage of the total time of the sample interval. It derives the active + // time by measuring the time that the components were not active and subtracting + // the result from 100 percent by the number of objects monitored. + CounterMultiTimerInverse = 591463680, + // + // Summary: + // A percentage counter that shows the active time of one or more components as + // a percentage of the total time of the sample interval. Counters of this type + // measure time in 100 nanosecond (ns) units. They derive the active time by measuring + // the time that the components were not active and subtracting the result from + // multiplying 100 percent by the number of objects monitored. + CounterMultiTimer100NsInverse = 592512256, + // + // Summary: + // An average counter that measures the time it takes, on average, to complete a + // process or operation. Counters of this type display a ratio of the total elapsed + // time of the sample interval to the number of processes or operations completed + // during that time. This counter type measures time in ticks of the system clock. + AverageTimer32 = 805438464, + // + // Summary: + // A difference timer that shows the total time between when the component or process + // started and the time when this value is calculated. + ElapsedTime = 807666944, + // + // Summary: + // An average counter that shows how many items are processed, on average, during + // an operation. Counters of this type display a ratio of the items processed to + // the number of operations completed. The ratio is calculated by comparing the + // number of items processed during the last interval to the number of operations + // completed during the last interval. + AverageCount64 = 1073874176, + // + // Summary: + // A base counter that stores the number of sampling interrupts taken and is used + // as a denominator in the sampling fraction. The sampling fraction is the number + // of samples that were 1 (or true) for a sample interrupt. Check that this value + // is greater than zero before using it as the denominator in a calculation of SampleFraction. + SampleBase = 1073939457, + // + // Summary: + // A base counter that is used in the calculation of time or count averages, such + // as AverageTimer32 and AverageCount64. Stores the denominator for calculating + // a counter to present "time per operation" or "count per operation". + AverageBase = 1073939458, + // + // Summary: + // A base counter that stores the denominator of a counter that presents a general + // arithmetic fraction. Check that this value is greater than zero before using + // it as the denominator in a RawFraction value calculation. + RawBase = 1073939459, + // + // Summary: + // A base counter that indicates the number of items sampled. It is used as the + // denominator in the calculations to get an average among the items sampled when + // taking timings of multiple, but similar items. Used with CounterMultiTimer, CounterMultiTimerInverse, + // CounterMultiTimer100Ns, and CounterMultiTimer100NsInverse. + CounterMultiBase = 1107494144 + } +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + using WixToolset.Data; + using WixToolset.Util.Symbols; + + public static partial class UtilSymbolDefinitions + { + public static readonly IntermediateSymbolDefinition EventManifest = new IntermediateSymbolDefinition( + UtilSymbolDefinitionType.EventManifest.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(EventManifestSymbolFields.ComponentRef), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(EventManifestSymbolFields.File), IntermediateFieldType.String), + }, + typeof(EventManifestSymbol)); + } +} + +namespace WixToolset.Util.Symbols +{ + using WixToolset.Data; + + public enum EventManifestSymbolFields + { + ComponentRef, + File, + } + + public class EventManifestSymbol : IntermediateSymbol + { + public EventManifestSymbol() : base(UtilSymbolDefinitions.EventManifest, null, null) + { + } + + public EventManifestSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.EventManifest, sourceLineNumber, id) + { + } + + public IntermediateField this[EventManifestSymbolFields index] => this.Fields[(int)index]; + + public string ComponentRef + { + get => this.Fields[(int)EventManifestSymbolFields.ComponentRef].AsString(); + set => this.Set((int)EventManifestSymbolFields.ComponentRef, value); + } + + public string File + { + get => this.Fields[(int)EventManifestSymbolFields.File].AsString(); + set => this.Set((int)EventManifestSymbolFields.File, value); + } + } +} \ 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + using WixToolset.Data; + using WixToolset.Util.Symbols; + + public static partial class UtilSymbolDefinitions + { + public static readonly IntermediateSymbolDefinition FileSharePermissions = new IntermediateSymbolDefinition( + UtilSymbolDefinitionType.FileSharePermissions.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(FileSharePermissionsSymbolFields.FileShareRef), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(FileSharePermissionsSymbolFields.UserRef), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(FileSharePermissionsSymbolFields.Permissions), IntermediateFieldType.Number), + }, + typeof(FileSharePermissionsSymbol)); + } +} + +namespace WixToolset.Util.Symbols +{ + using WixToolset.Data; + + public enum FileSharePermissionsSymbolFields + { + FileShareRef, + UserRef, + Permissions, + } + + public class FileSharePermissionsSymbol : IntermediateSymbol + { + public FileSharePermissionsSymbol() : base(UtilSymbolDefinitions.FileSharePermissions, null, null) + { + } + + public FileSharePermissionsSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.FileSharePermissions, sourceLineNumber, id) + { + } + + public IntermediateField this[FileSharePermissionsSymbolFields index] => this.Fields[(int)index]; + + public string FileShareRef + { + get => this.Fields[(int)FileSharePermissionsSymbolFields.FileShareRef].AsString(); + set => this.Set((int)FileSharePermissionsSymbolFields.FileShareRef, value); + } + + public string UserRef + { + get => this.Fields[(int)FileSharePermissionsSymbolFields.UserRef].AsString(); + set => this.Set((int)FileSharePermissionsSymbolFields.UserRef, value); + } + + public int Permissions + { + get => this.Fields[(int)FileSharePermissionsSymbolFields.Permissions].AsNumber(); + set => this.Set((int)FileSharePermissionsSymbolFields.Permissions, value); + } + } +} \ 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + using WixToolset.Data; + using WixToolset.Util.Symbols; + + public static partial class UtilSymbolDefinitions + { + public static readonly IntermediateSymbolDefinition FileShare = new IntermediateSymbolDefinition( + UtilSymbolDefinitionType.FileShare.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(FileShareSymbolFields.ShareName), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(FileShareSymbolFields.ComponentRef), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(FileShareSymbolFields.Description), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(FileShareSymbolFields.DirectoryRef), IntermediateFieldType.String), + }, + typeof(FileShareSymbol)); + } +} + +namespace WixToolset.Util.Symbols +{ + using WixToolset.Data; + + public enum FileShareSymbolFields + { + ShareName, + ComponentRef, + Description, + DirectoryRef, + } + + public class FileShareSymbol : IntermediateSymbol + { + public FileShareSymbol() : base(UtilSymbolDefinitions.FileShare, null, null) + { + } + + public FileShareSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.FileShare, sourceLineNumber, id) + { + } + + public IntermediateField this[FileShareSymbolFields index] => this.Fields[(int)index]; + + public string ShareName + { + get => this.Fields[(int)FileShareSymbolFields.ShareName].AsString(); + set => this.Set((int)FileShareSymbolFields.ShareName, value); + } + + public string ComponentRef + { + get => this.Fields[(int)FileShareSymbolFields.ComponentRef].AsString(); + set => this.Set((int)FileShareSymbolFields.ComponentRef, value); + } + + public string Description + { + get => this.Fields[(int)FileShareSymbolFields.Description].AsString(); + set => this.Set((int)FileShareSymbolFields.Description, value); + } + + public string DirectoryRef + { + get => this.Fields[(int)FileShareSymbolFields.DirectoryRef].AsString(); + set => this.Set((int)FileShareSymbolFields.DirectoryRef, value); + } + } +} \ 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + using WixToolset.Data; + using WixToolset.Util.Symbols; + + public static partial class UtilSymbolDefinitions + { + public static readonly IntermediateSymbolDefinition Group = new IntermediateSymbolDefinition( + UtilSymbolDefinitionType.Group.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(GroupSymbolFields.ComponentRef), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(GroupSymbolFields.Name), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(GroupSymbolFields.Domain), IntermediateFieldType.String), + }, + typeof(GroupSymbol)); + } +} + +namespace WixToolset.Util.Symbols +{ + using WixToolset.Data; + + public enum GroupSymbolFields + { + ComponentRef, + Name, + Domain, + } + + public class GroupSymbol : IntermediateSymbol + { + public GroupSymbol() : base(UtilSymbolDefinitions.Group, null, null) + { + } + + public GroupSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.Group, sourceLineNumber, id) + { + } + + public IntermediateField this[GroupSymbolFields index] => this.Fields[(int)index]; + + public string ComponentRef + { + get => this.Fields[(int)GroupSymbolFields.ComponentRef].AsString(); + set => this.Set((int)GroupSymbolFields.ComponentRef, value); + } + + public string Name + { + get => this.Fields[(int)GroupSymbolFields.Name].AsString(); + set => this.Set((int)GroupSymbolFields.Name, value); + } + + public string Domain + { + get => this.Fields[(int)GroupSymbolFields.Domain].AsString(); + set => this.Set((int)GroupSymbolFields.Domain, value); + } + } +} \ 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + using WixToolset.Data; + using WixToolset.Util.Symbols; + + public static partial class UtilSymbolDefinitions + { + public static readonly IntermediateSymbolDefinition PerfmonManifest = new IntermediateSymbolDefinition( + UtilSymbolDefinitionType.PerfmonManifest.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(PerfmonManifestSymbolFields.ComponentRef), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(PerfmonManifestSymbolFields.File), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(PerfmonManifestSymbolFields.ResourceFileDirectory), IntermediateFieldType.String), + }, + typeof(PerfmonManifestSymbol)); + } +} + +namespace WixToolset.Util.Symbols +{ + using WixToolset.Data; + + public enum PerfmonManifestSymbolFields + { + ComponentRef, + File, + ResourceFileDirectory, + } + + public class PerfmonManifestSymbol : IntermediateSymbol + { + public PerfmonManifestSymbol() : base(UtilSymbolDefinitions.PerfmonManifest, null, null) + { + } + + public PerfmonManifestSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.PerfmonManifest, sourceLineNumber, id) + { + } + + public IntermediateField this[PerfmonManifestSymbolFields index] => this.Fields[(int)index]; + + public string ComponentRef + { + get => this.Fields[(int)PerfmonManifestSymbolFields.ComponentRef].AsString(); + set => this.Set((int)PerfmonManifestSymbolFields.ComponentRef, value); + } + + public string File + { + get => this.Fields[(int)PerfmonManifestSymbolFields.File].AsString(); + set => this.Set((int)PerfmonManifestSymbolFields.File, value); + } + + public string ResourceFileDirectory + { + get => this.Fields[(int)PerfmonManifestSymbolFields.ResourceFileDirectory].AsString(); + set => this.Set((int)PerfmonManifestSymbolFields.ResourceFileDirectory, value); + } + } +} \ 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + using WixToolset.Data; + using WixToolset.Util.Symbols; + + public static partial class UtilSymbolDefinitions + { + public static readonly IntermediateSymbolDefinition Perfmon = new IntermediateSymbolDefinition( + UtilSymbolDefinitionType.Perfmon.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(PerfmonSymbolFields.ComponentRef), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(PerfmonSymbolFields.File), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(PerfmonSymbolFields.Name), IntermediateFieldType.String), + }, + typeof(PerfmonSymbol)); + } +} + +namespace WixToolset.Util.Symbols +{ + using WixToolset.Data; + + public enum PerfmonSymbolFields + { + ComponentRef, + File, + Name, + } + + public class PerfmonSymbol : IntermediateSymbol + { + public PerfmonSymbol() : base(UtilSymbolDefinitions.Perfmon, null, null) + { + } + + public PerfmonSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.Perfmon, sourceLineNumber, id) + { + } + + public IntermediateField this[PerfmonSymbolFields index] => this.Fields[(int)index]; + + public string ComponentRef + { + get => this.Fields[(int)PerfmonSymbolFields.ComponentRef].AsString(); + set => this.Set((int)PerfmonSymbolFields.ComponentRef, value); + } + + public string File + { + get => this.Fields[(int)PerfmonSymbolFields.File].AsString(); + set => this.Set((int)PerfmonSymbolFields.File, value); + } + + public string Name + { + get => this.Fields[(int)PerfmonSymbolFields.Name].AsString(); + set => this.Set((int)PerfmonSymbolFields.Name, value); + } + } +} \ 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + using WixToolset.Data; + using WixToolset.Util.Symbols; + + public static partial class UtilSymbolDefinitions + { + public static readonly IntermediateSymbolDefinition PerformanceCategory = new IntermediateSymbolDefinition( + UtilSymbolDefinitionType.PerformanceCategory.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(PerformanceCategorySymbolFields.ComponentRef), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(PerformanceCategorySymbolFields.Name), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(PerformanceCategorySymbolFields.IniData), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(PerformanceCategorySymbolFields.ConstantData), IntermediateFieldType.String), + }, + typeof(PerformanceCategorySymbol)); + } +} + +namespace WixToolset.Util.Symbols +{ + using WixToolset.Data; + + public enum PerformanceCategorySymbolFields + { + ComponentRef, + Name, + IniData, + ConstantData, + } + + public class PerformanceCategorySymbol : IntermediateSymbol + { + public PerformanceCategorySymbol() : base(UtilSymbolDefinitions.PerformanceCategory, null, null) + { + } + + public PerformanceCategorySymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.PerformanceCategory, sourceLineNumber, id) + { + } + + public IntermediateField this[PerformanceCategorySymbolFields index] => this.Fields[(int)index]; + + public string ComponentRef + { + get => this.Fields[(int)PerformanceCategorySymbolFields.ComponentRef].AsString(); + set => this.Set((int)PerformanceCategorySymbolFields.ComponentRef, value); + } + + public string Name + { + get => this.Fields[(int)PerformanceCategorySymbolFields.Name].AsString(); + set => this.Set((int)PerformanceCategorySymbolFields.Name, value); + } + + public string IniData + { + get => this.Fields[(int)PerformanceCategorySymbolFields.IniData].AsString(); + set => this.Set((int)PerformanceCategorySymbolFields.IniData, value); + } + + public string ConstantData + { + get => this.Fields[(int)PerformanceCategorySymbolFields.ConstantData].AsString(); + set => this.Set((int)PerformanceCategorySymbolFields.ConstantData, value); + } + } +} \ 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + using WixToolset.Data; + using WixToolset.Util.Symbols; + + public static partial class UtilSymbolDefinitions + { + public static readonly IntermediateSymbolDefinition SecureObjects = new IntermediateSymbolDefinition( + UtilSymbolDefinitionType.SecureObjects.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(SecureObjectsSymbolFields.SecureObject), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(SecureObjectsSymbolFields.Table), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(SecureObjectsSymbolFields.Domain), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(SecureObjectsSymbolFields.User), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(SecureObjectsSymbolFields.Attributes), IntermediateFieldType.Number), + new IntermediateFieldDefinition(nameof(SecureObjectsSymbolFields.Permission), IntermediateFieldType.Number), + new IntermediateFieldDefinition(nameof(SecureObjectsSymbolFields.ComponentRef), IntermediateFieldType.String), + }, + typeof(SecureObjectsSymbol)); + } +} + +namespace WixToolset.Util.Symbols +{ + using System; + using WixToolset.Data; + + public enum SecureObjectsSymbolFields + { + SecureObject, + Table, + Domain, + User, + Attributes, + Permission, + ComponentRef, + } + + [Flags] + public enum WixPermissionExAttributes + { + None = 0x0, + Inheritable = 0x01 + } + + public class SecureObjectsSymbol : IntermediateSymbol + { + public SecureObjectsSymbol() : base(UtilSymbolDefinitions.SecureObjects, null, null) + { + } + + public SecureObjectsSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.SecureObjects, sourceLineNumber, id) + { + } + + public IntermediateField this[SecureObjectsSymbolFields index] => this.Fields[(int)index]; + + public string SecureObject + { + get => this.Fields[(int)SecureObjectsSymbolFields.SecureObject].AsString(); + set => this.Set((int)SecureObjectsSymbolFields.SecureObject, value); + } + + public string Table + { + get => this.Fields[(int)SecureObjectsSymbolFields.Table].AsString(); + set => this.Set((int)SecureObjectsSymbolFields.Table, value); + } + + public string Domain + { + get => this.Fields[(int)SecureObjectsSymbolFields.Domain].AsString(); + set => this.Set((int)SecureObjectsSymbolFields.Domain, value); + } + + public string User + { + get => this.Fields[(int)SecureObjectsSymbolFields.User].AsString(); + set => this.Set((int)SecureObjectsSymbolFields.User, value); + } + + public WixPermissionExAttributes Attributes + { + get => (WixPermissionExAttributes)this.Fields[(int)SecureObjectsSymbolFields.Attributes].AsNumber(); + set => this.Set((int)SecureObjectsSymbolFields.Attributes, (int)value); + } + + public int? Permission + { + get => this.Fields[(int)SecureObjectsSymbolFields.Permission].AsNullableNumber(); + set => this.Set((int)SecureObjectsSymbolFields.Permission, value); + } + + public string ComponentRef + { + get => this.Fields[(int)SecureObjectsSymbolFields.ComponentRef].AsString(); + set => this.Set((int)SecureObjectsSymbolFields.ComponentRef, value); + } + } +} \ 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + using WixToolset.Data; + using WixToolset.Util.Symbols; + + public static partial class UtilSymbolDefinitions + { + public static readonly IntermediateSymbolDefinition ServiceConfig = new IntermediateSymbolDefinition( + UtilSymbolDefinitionType.ServiceConfig.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.ServiceName), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.ComponentRef), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.NewService), IntermediateFieldType.Number), + new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.FirstFailureActionType), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.SecondFailureActionType), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.ThirdFailureActionType), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.ResetPeriodInDays), IntermediateFieldType.Number), + new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.RestartServiceDelayInSeconds), IntermediateFieldType.Number), + new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.ProgramCommandLine), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.RebootMessage), IntermediateFieldType.String), + }, + typeof(ServiceConfigSymbol)); + } +} + +namespace WixToolset.Util.Symbols +{ + using WixToolset.Data; + + public enum ServiceConfigSymbolFields + { + ServiceName, + ComponentRef, + NewService, + FirstFailureActionType, + SecondFailureActionType, + ThirdFailureActionType, + ResetPeriodInDays, + RestartServiceDelayInSeconds, + ProgramCommandLine, + RebootMessage, + } + + public class ServiceConfigSymbol : IntermediateSymbol + { + public ServiceConfigSymbol() : base(UtilSymbolDefinitions.ServiceConfig, null, null) + { + } + + public ServiceConfigSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.ServiceConfig, sourceLineNumber, id) + { + } + + public IntermediateField this[ServiceConfigSymbolFields index] => this.Fields[(int)index]; + + public string ServiceName + { + get => this.Fields[(int)ServiceConfigSymbolFields.ServiceName].AsString(); + set => this.Set((int)ServiceConfigSymbolFields.ServiceName, value); + } + + public string ComponentRef + { + get => this.Fields[(int)ServiceConfigSymbolFields.ComponentRef].AsString(); + set => this.Set((int)ServiceConfigSymbolFields.ComponentRef, value); + } + + public int NewService + { + get => this.Fields[(int)ServiceConfigSymbolFields.NewService].AsNumber(); + set => this.Set((int)ServiceConfigSymbolFields.NewService, value); + } + + public string FirstFailureActionType + { + get => this.Fields[(int)ServiceConfigSymbolFields.FirstFailureActionType].AsString(); + set => this.Set((int)ServiceConfigSymbolFields.FirstFailureActionType, value); + } + + public string SecondFailureActionType + { + get => this.Fields[(int)ServiceConfigSymbolFields.SecondFailureActionType].AsString(); + set => this.Set((int)ServiceConfigSymbolFields.SecondFailureActionType, value); + } + + public string ThirdFailureActionType + { + get => this.Fields[(int)ServiceConfigSymbolFields.ThirdFailureActionType].AsString(); + set => this.Set((int)ServiceConfigSymbolFields.ThirdFailureActionType, value); + } + + public int? ResetPeriodInDays + { + get => this.Fields[(int)ServiceConfigSymbolFields.ResetPeriodInDays].AsNullableNumber(); + set => this.Set((int)ServiceConfigSymbolFields.ResetPeriodInDays, value); + } + + public int? RestartServiceDelayInSeconds + { + get => this.Fields[(int)ServiceConfigSymbolFields.RestartServiceDelayInSeconds].AsNullableNumber(); + set => this.Set((int)ServiceConfigSymbolFields.RestartServiceDelayInSeconds, value); + } + + public string ProgramCommandLine + { + get => this.Fields[(int)ServiceConfigSymbolFields.ProgramCommandLine].AsString(); + set => this.Set((int)ServiceConfigSymbolFields.ProgramCommandLine, value); + } + + public string RebootMessage + { + get => this.Fields[(int)ServiceConfigSymbolFields.RebootMessage].AsString(); + set => this.Set((int)ServiceConfigSymbolFields.RebootMessage, value); + } + } +} \ 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + using WixToolset.Data; + using WixToolset.Util.Symbols; + + public static partial class UtilSymbolDefinitions + { + public static readonly IntermediateSymbolDefinition UserGroup = new IntermediateSymbolDefinition( + UtilSymbolDefinitionType.UserGroup.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(UserGroupSymbolFields.UserRef), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(UserGroupSymbolFields.GroupRef), IntermediateFieldType.String), + }, + typeof(UserGroupSymbol)); + } +} + +namespace WixToolset.Util.Symbols +{ + using WixToolset.Data; + + public enum UserGroupSymbolFields + { + UserRef, + GroupRef, + } + + public class UserGroupSymbol : IntermediateSymbol + { + public UserGroupSymbol() : base(UtilSymbolDefinitions.UserGroup, null, null) + { + } + + public UserGroupSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.UserGroup, sourceLineNumber, id) + { + } + + public IntermediateField this[UserGroupSymbolFields index] => this.Fields[(int)index]; + + public string UserRef + { + get => this.Fields[(int)UserGroupSymbolFields.UserRef].AsString(); + set => this.Set((int)UserGroupSymbolFields.UserRef, value); + } + + public string GroupRef + { + get => this.Fields[(int)UserGroupSymbolFields.GroupRef].AsString(); + set => this.Set((int)UserGroupSymbolFields.GroupRef, value); + } + } +} \ 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + using WixToolset.Data; + using WixToolset.Util.Symbols; + + public static partial class UtilSymbolDefinitions + { + public static readonly IntermediateSymbolDefinition User = new IntermediateSymbolDefinition( + UtilSymbolDefinitionType.User.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(UserSymbolFields.ComponentRef), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(UserSymbolFields.Name), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(UserSymbolFields.Domain), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(UserSymbolFields.Password), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(UserSymbolFields.Attributes), IntermediateFieldType.Number), + }, + typeof(UserSymbol)); + } +} + +namespace WixToolset.Util.Symbols +{ + using WixToolset.Data; + + public enum UserSymbolFields + { + ComponentRef, + Name, + Domain, + Password, + Attributes, + } + + public class UserSymbol : IntermediateSymbol + { + public UserSymbol() : base(UtilSymbolDefinitions.User, null, null) + { + } + + public UserSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.User, sourceLineNumber, id) + { + } + + public IntermediateField this[UserSymbolFields index] => this.Fields[(int)index]; + + public string ComponentRef + { + get => this.Fields[(int)UserSymbolFields.ComponentRef].AsString(); + set => this.Set((int)UserSymbolFields.ComponentRef, value); + } + + public string Name + { + get => this.Fields[(int)UserSymbolFields.Name].AsString(); + set => this.Set((int)UserSymbolFields.Name, value); + } + + public string Domain + { + get => this.Fields[(int)UserSymbolFields.Domain].AsString(); + set => this.Set((int)UserSymbolFields.Domain, value); + } + + public string Password + { + get => this.Fields[(int)UserSymbolFields.Password].AsString(); + set => this.Set((int)UserSymbolFields.Password, value); + } + + public int Attributes + { + get => this.Fields[(int)UserSymbolFields.Attributes].AsNumber(); + set => this.Set((int)UserSymbolFields.Attributes, value); + } + } +} \ 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + using System; + using WixToolset.Data; + using WixToolset.Data.Burn; + + public enum UtilSymbolDefinitionType + { + EventManifest, + FileShare, + FileSharePermissions, + Group, + Perfmon, + PerfmonManifest, + PerformanceCategory, + SecureObjects, + ServiceConfig, + User, + UserGroup, + WixCloseApplication, + WixFormatFiles, + WixInternetShortcut, + WixRemoveFolderEx, + WixRemoveRegistryKeyEx, + WixRestartResource, + WixTouchFile, + WixWindowsFeatureSearch, + XmlConfig, + XmlFile, + } + + public static partial class UtilSymbolDefinitions + { + public static readonly Version Version = new Version("4.0.0"); + + public static IntermediateSymbolDefinition ByName(string name) + { + if (!Enum.TryParse(name, out UtilSymbolDefinitionType type)) + { + return null; + } + + return ByType(type); + } + + public static IntermediateSymbolDefinition ByType(UtilSymbolDefinitionType type) + { + switch (type) + { + case UtilSymbolDefinitionType.EventManifest: + return UtilSymbolDefinitions.EventManifest; + + case UtilSymbolDefinitionType.FileShare: + return UtilSymbolDefinitions.FileShare; + + case UtilSymbolDefinitionType.FileSharePermissions: + return UtilSymbolDefinitions.FileSharePermissions; + + case UtilSymbolDefinitionType.Group: + return UtilSymbolDefinitions.Group; + + case UtilSymbolDefinitionType.Perfmon: + return UtilSymbolDefinitions.Perfmon; + + case UtilSymbolDefinitionType.PerfmonManifest: + return UtilSymbolDefinitions.PerfmonManifest; + + case UtilSymbolDefinitionType.PerformanceCategory: + return UtilSymbolDefinitions.PerformanceCategory; + + case UtilSymbolDefinitionType.SecureObjects: + return UtilSymbolDefinitions.SecureObjects; + + case UtilSymbolDefinitionType.ServiceConfig: + return UtilSymbolDefinitions.ServiceConfig; + + case UtilSymbolDefinitionType.User: + return UtilSymbolDefinitions.User; + + case UtilSymbolDefinitionType.UserGroup: + return UtilSymbolDefinitions.UserGroup; + + case UtilSymbolDefinitionType.WixCloseApplication: + return UtilSymbolDefinitions.WixCloseApplication; + + case UtilSymbolDefinitionType.WixFormatFiles: + return UtilSymbolDefinitions.WixFormatFiles; + + case UtilSymbolDefinitionType.WixInternetShortcut: + return UtilSymbolDefinitions.WixInternetShortcut; + + case UtilSymbolDefinitionType.WixRemoveFolderEx: + return UtilSymbolDefinitions.WixRemoveFolderEx; + + case UtilSymbolDefinitionType.WixRemoveRegistryKeyEx: + return UtilSymbolDefinitions.WixRemoveRegistryKeyEx; + + case UtilSymbolDefinitionType.WixRestartResource: + return UtilSymbolDefinitions.WixRestartResource; + + case UtilSymbolDefinitionType.WixTouchFile: + return UtilSymbolDefinitions.WixTouchFile; + + case UtilSymbolDefinitionType.WixWindowsFeatureSearch: + return UtilSymbolDefinitions.WixWindowsFeatureSearch; + + case UtilSymbolDefinitionType.XmlConfig: + return UtilSymbolDefinitions.XmlConfig; + + case UtilSymbolDefinitionType.XmlFile: + return UtilSymbolDefinitions.XmlFile; + + default: + throw new ArgumentOutOfRangeException(nameof(type)); + } + } + + static UtilSymbolDefinitions() + { + WixWindowsFeatureSearch.AddTag(BurnConstants.BundleExtensionSearchSymbolDefinitionTag); + } + } +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + using WixToolset.Data; + using WixToolset.Util.Symbols; + + public static partial class UtilSymbolDefinitions + { + public static readonly IntermediateSymbolDefinition WixCloseApplication = new IntermediateSymbolDefinition( + UtilSymbolDefinitionType.WixCloseApplication.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(WixCloseApplicationSymbolFields.Target), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(WixCloseApplicationSymbolFields.Description), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(WixCloseApplicationSymbolFields.Condition), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(WixCloseApplicationSymbolFields.Attributes), IntermediateFieldType.Number), + new IntermediateFieldDefinition(nameof(WixCloseApplicationSymbolFields.Sequence), IntermediateFieldType.Number), + new IntermediateFieldDefinition(nameof(WixCloseApplicationSymbolFields.Property), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(WixCloseApplicationSymbolFields.TerminateExitCode), IntermediateFieldType.Number), + new IntermediateFieldDefinition(nameof(WixCloseApplicationSymbolFields.Timeout), IntermediateFieldType.Number), + }, + typeof(WixCloseApplicationSymbol)); + } +} + +namespace WixToolset.Util.Symbols +{ + using WixToolset.Data; + + public enum WixCloseApplicationSymbolFields + { + Target, + Description, + Condition, + Attributes, + Sequence, + Property, + TerminateExitCode, + Timeout, + } + + public class WixCloseApplicationSymbol : IntermediateSymbol + { + public WixCloseApplicationSymbol() : base(UtilSymbolDefinitions.WixCloseApplication, null, null) + { + } + + public WixCloseApplicationSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.WixCloseApplication, sourceLineNumber, id) + { + } + + public IntermediateField this[WixCloseApplicationSymbolFields index] => this.Fields[(int)index]; + + public string Target + { + get => this.Fields[(int)WixCloseApplicationSymbolFields.Target].AsString(); + set => this.Set((int)WixCloseApplicationSymbolFields.Target, value); + } + + public string Description + { + get => this.Fields[(int)WixCloseApplicationSymbolFields.Description].AsString(); + set => this.Set((int)WixCloseApplicationSymbolFields.Description, value); + } + + public string Condition + { + get => this.Fields[(int)WixCloseApplicationSymbolFields.Condition].AsString(); + set => this.Set((int)WixCloseApplicationSymbolFields.Condition, value); + } + + public int Attributes + { + get => this.Fields[(int)WixCloseApplicationSymbolFields.Attributes].AsNumber(); + set => this.Set((int)WixCloseApplicationSymbolFields.Attributes, value); + } + + public int? Sequence + { + get => this.Fields[(int)WixCloseApplicationSymbolFields.Sequence].AsNullableNumber(); + set => this.Set((int)WixCloseApplicationSymbolFields.Sequence, value); + } + + public string Property + { + get => this.Fields[(int)WixCloseApplicationSymbolFields.Property].AsString(); + set => this.Set((int)WixCloseApplicationSymbolFields.Property, value); + } + + public int? TerminateExitCode + { + get => this.Fields[(int)WixCloseApplicationSymbolFields.TerminateExitCode].AsNullableNumber(); + set => this.Set((int)WixCloseApplicationSymbolFields.TerminateExitCode, value); + } + + public int? Timeout + { + get => this.Fields[(int)WixCloseApplicationSymbolFields.Timeout].AsNullableNumber(); + set => this.Set((int)WixCloseApplicationSymbolFields.Timeout, value); + } + } +} \ 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + using WixToolset.Data; + using WixToolset.Util.Symbols; + + public static partial class UtilSymbolDefinitions + { + public static readonly IntermediateSymbolDefinition WixFormatFiles = new IntermediateSymbolDefinition( + UtilSymbolDefinitionType.WixFormatFiles.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(WixFormatFilesSymbolFields.BinaryRef), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(WixFormatFilesSymbolFields.FileRef), IntermediateFieldType.String), + }, + typeof(WixFormatFilesSymbol)); + } +} + +namespace WixToolset.Util.Symbols +{ + using WixToolset.Data; + + public enum WixFormatFilesSymbolFields + { + BinaryRef, + FileRef, + } + + public class WixFormatFilesSymbol : IntermediateSymbol + { + public WixFormatFilesSymbol() : base(UtilSymbolDefinitions.WixFormatFiles, null, null) + { + } + + public WixFormatFilesSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.WixFormatFiles, sourceLineNumber, id) + { + } + + public IntermediateField this[WixFormatFilesSymbolFields index] => this.Fields[(int)index]; + + public string BinaryRef + { + get => this.Fields[(int)WixFormatFilesSymbolFields.BinaryRef].AsString(); + set => this.Set((int)WixFormatFilesSymbolFields.BinaryRef, value); + } + + public string FileRef + { + get => this.Fields[(int)WixFormatFilesSymbolFields.FileRef].AsString(); + set => this.Set((int)WixFormatFilesSymbolFields.FileRef, value); + } + } +} \ 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + using WixToolset.Data; + using WixToolset.Util.Symbols; + + public static partial class UtilSymbolDefinitions + { + public static readonly IntermediateSymbolDefinition WixInternetShortcut = new IntermediateSymbolDefinition( + UtilSymbolDefinitionType.WixInternetShortcut.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(WixInternetShortcutSymbolFields.ComponentRef), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(WixInternetShortcutSymbolFields.DirectoryRef), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(WixInternetShortcutSymbolFields.Name), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(WixInternetShortcutSymbolFields.Target), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(WixInternetShortcutSymbolFields.Attributes), IntermediateFieldType.Number), + new IntermediateFieldDefinition(nameof(WixInternetShortcutSymbolFields.IconFile), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(WixInternetShortcutSymbolFields.IconIndex), IntermediateFieldType.Number), + }, + typeof(WixInternetShortcutSymbol)); + } +} + +namespace WixToolset.Util.Symbols +{ + using WixToolset.Data; + + public enum WixInternetShortcutSymbolFields + { + ComponentRef, + DirectoryRef, + Name, + Target, + Attributes, + IconFile, + IconIndex, + } + + public class WixInternetShortcutSymbol : IntermediateSymbol + { + public WixInternetShortcutSymbol() : base(UtilSymbolDefinitions.WixInternetShortcut, null, null) + { + } + + public WixInternetShortcutSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.WixInternetShortcut, sourceLineNumber, id) + { + } + + public IntermediateField this[WixInternetShortcutSymbolFields index] => this.Fields[(int)index]; + + public string ComponentRef + { + get => this.Fields[(int)WixInternetShortcutSymbolFields.ComponentRef].AsString(); + set => this.Set((int)WixInternetShortcutSymbolFields.ComponentRef, value); + } + + public string DirectoryRef + { + get => this.Fields[(int)WixInternetShortcutSymbolFields.DirectoryRef].AsString(); + set => this.Set((int)WixInternetShortcutSymbolFields.DirectoryRef, value); + } + + public string Name + { + get => this.Fields[(int)WixInternetShortcutSymbolFields.Name].AsString(); + set => this.Set((int)WixInternetShortcutSymbolFields.Name, value); + } + + public string Target + { + get => this.Fields[(int)WixInternetShortcutSymbolFields.Target].AsString(); + set => this.Set((int)WixInternetShortcutSymbolFields.Target, value); + } + + public int Attributes + { + get => this.Fields[(int)WixInternetShortcutSymbolFields.Attributes].AsNumber(); + set => this.Set((int)WixInternetShortcutSymbolFields.Attributes, value); + } + + public string IconFile + { + get => this.Fields[(int)WixInternetShortcutSymbolFields.IconFile].AsString(); + set => this.Set((int)WixInternetShortcutSymbolFields.IconFile, value); + } + + public int? IconIndex + { + get => this.Fields[(int)WixInternetShortcutSymbolFields.IconIndex].AsNullableNumber(); + set => this.Set((int)WixInternetShortcutSymbolFields.IconIndex, value); + } + } +} \ 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + using WixToolset.Data; + using WixToolset.Util.Symbols; + + public static partial class UtilSymbolDefinitions + { + public static readonly IntermediateSymbolDefinition WixRemoveFolderEx = new IntermediateSymbolDefinition( + UtilSymbolDefinitionType.WixRemoveFolderEx.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(WixRemoveFolderExSymbolFields.ComponentRef), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(WixRemoveFolderExSymbolFields.Property), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(WixRemoveFolderExSymbolFields.InstallMode), IntermediateFieldType.Number), + new IntermediateFieldDefinition(nameof(WixRemoveFolderExSymbolFields.Condition), IntermediateFieldType.String), + }, + typeof(WixRemoveFolderExSymbol)); + } +} + +namespace WixToolset.Util.Symbols +{ + using WixToolset.Data; + + public enum WixRemoveFolderExSymbolFields + { + ComponentRef, + Property, + InstallMode, + Condition, + } + + public enum WixRemoveFolderExInstallMode + { + Install = 1, + Uninstall = 2, + Both = 3, + } + + public class WixRemoveFolderExSymbol : IntermediateSymbol + { + public WixRemoveFolderExSymbol() : base(UtilSymbolDefinitions.WixRemoveFolderEx, null, null) + { + } + + public WixRemoveFolderExSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.WixRemoveFolderEx, sourceLineNumber, id) + { + } + + public IntermediateField this[WixRemoveFolderExSymbolFields index] => this.Fields[(int)index]; + + public string ComponentRef + { + get => this.Fields[(int)WixRemoveFolderExSymbolFields.ComponentRef].AsString(); + set => this.Set((int)WixRemoveFolderExSymbolFields.ComponentRef, value); + } + + public string Property + { + get => this.Fields[(int)WixRemoveFolderExSymbolFields.Property].AsString(); + set => this.Set((int)WixRemoveFolderExSymbolFields.Property, value); + } + + public WixRemoveFolderExInstallMode InstallMode + { + get => (WixRemoveFolderExInstallMode)this.Fields[(int)WixRemoveFolderExSymbolFields.InstallMode].AsNumber(); + set => this.Set((int)WixRemoveFolderExSymbolFields.InstallMode, (int)value); + } + + public string Condition + { + get => this.Fields[(int)WixRemoveFolderExSymbolFields.Condition].AsString(); + set => this.Set((int)WixRemoveFolderExSymbolFields.Condition, value); + } + } +} \ 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + using WixToolset.Data; + using WixToolset.Util.Symbols; + + public static partial class UtilSymbolDefinitions + { + public static readonly IntermediateSymbolDefinition WixRemoveRegistryKeyEx = new IntermediateSymbolDefinition( + UtilSymbolDefinitionType.WixRemoveRegistryKeyEx.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(WixRemoveRegistryKeyExSymbolFields.ComponentRef), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(WixRemoveRegistryKeyExSymbolFields.Root), IntermediateFieldType.Number), + new IntermediateFieldDefinition(nameof(WixRemoveRegistryKeyExSymbolFields.Key), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(WixRemoveRegistryKeyExSymbolFields.InstallMode), IntermediateFieldType.Number), + new IntermediateFieldDefinition(nameof(WixRemoveRegistryKeyExSymbolFields.Condition), IntermediateFieldType.String), + }, + typeof(WixRemoveRegistryKeyExSymbol)); + } +} + +namespace WixToolset.Util.Symbols +{ + using WixToolset.Data; + using WixToolset.Data.Symbols; + + public enum WixRemoveRegistryKeyExSymbolFields + { + ComponentRef, + Root, + Key, + InstallMode, + Condition, + } + + public enum WixRemoveRegistryKeyExInstallMode + { + Install = 1, + Uninstall = 2, + } + + public class WixRemoveRegistryKeyExSymbol : IntermediateSymbol + { + public WixRemoveRegistryKeyExSymbol() : base(UtilSymbolDefinitions.WixRemoveRegistryKeyEx, null, null) + { + } + + public WixRemoveRegistryKeyExSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.WixRemoveRegistryKeyEx, sourceLineNumber, id) + { + } + + public IntermediateField this[WixRemoveRegistryKeyExSymbolFields index] => this.Fields[(int)index]; + + public string ComponentRef + { + get => this.Fields[(int)WixRemoveRegistryKeyExSymbolFields.ComponentRef].AsString(); + set => this.Set((int)WixRemoveRegistryKeyExSymbolFields.ComponentRef, value); + } + + public RegistryRootType Root + { + get => (RegistryRootType)this.Fields[(int)WixRemoveRegistryKeyExSymbolFields.Root].AsNumber(); + set => this.Set((int)WixRemoveRegistryKeyExSymbolFields.Root, (int)value); + } + + public string Key + { + get => (string)this.Fields[(int)WixRemoveRegistryKeyExSymbolFields.Key]; + set => this.Set((int)WixRemoveRegistryKeyExSymbolFields.Key, value); + } + + public WixRemoveRegistryKeyExInstallMode InstallMode + { + get => (WixRemoveRegistryKeyExInstallMode)this.Fields[(int)WixRemoveRegistryKeyExSymbolFields.InstallMode].AsNumber(); + set => this.Set((int)WixRemoveRegistryKeyExSymbolFields.InstallMode, (int)value); + } + + public string Condition + { + get => this.Fields[(int)WixRemoveRegistryKeyExSymbolFields.Condition].AsString(); + set => this.Set((int)WixRemoveRegistryKeyExSymbolFields.Condition, value); + } + } +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + using WixToolset.Data; + using WixToolset.Util.Symbols; + + public static partial class UtilSymbolDefinitions + { + public static readonly IntermediateSymbolDefinition WixRestartResource = new IntermediateSymbolDefinition( + UtilSymbolDefinitionType.WixRestartResource.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(WixRestartResourceSymbolFields.ComponentRef), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(WixRestartResourceSymbolFields.Resource), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(WixRestartResourceSymbolFields.Attributes), IntermediateFieldType.Number), + }, + typeof(WixRestartResourceSymbol)); + } +} + +namespace WixToolset.Util.Symbols +{ + using WixToolset.Data; + + public enum WixRestartResourceSymbolFields + { + ComponentRef, + Resource, + Attributes, + } + + public enum WixRestartResourceAttributes + { + Filename = 1, + ProcessName, + ServiceName, + TypeMask = 0xf, + } + + public class WixRestartResourceSymbol : IntermediateSymbol + { + public WixRestartResourceSymbol() : base(UtilSymbolDefinitions.WixRestartResource, null, null) + { + } + + public WixRestartResourceSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.WixRestartResource, sourceLineNumber, id) + { + } + + public IntermediateField this[WixRestartResourceSymbolFields index] => this.Fields[(int)index]; + + public string ComponentRef + { + get => this.Fields[(int)WixRestartResourceSymbolFields.ComponentRef].AsString(); + set => this.Set((int)WixRestartResourceSymbolFields.ComponentRef, value); + } + + public string Resource + { + get => this.Fields[(int)WixRestartResourceSymbolFields.Resource].AsString(); + set => this.Set((int)WixRestartResourceSymbolFields.Resource, value); + } + + public WixRestartResourceAttributes? Attributes + { + get => (WixRestartResourceAttributes?)this.Fields[(int)WixRestartResourceSymbolFields.Attributes].AsNullableNumber(); + set => this.Set((int)WixRestartResourceSymbolFields.Attributes, (int?)value); + } + } +} \ 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + using WixToolset.Data; + using WixToolset.Util.Symbols; + + public static partial class UtilSymbolDefinitions + { + public static readonly IntermediateSymbolDefinition WixTouchFile = new IntermediateSymbolDefinition( + UtilSymbolDefinitionType.WixTouchFile.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(WixTouchFileSymbolFields.ComponentRef), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(WixTouchFileSymbolFields.Path), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(WixTouchFileSymbolFields.Attributes), IntermediateFieldType.Number), + }, + typeof(WixTouchFileSymbol)); + } +} + +namespace WixToolset.Util.Symbols +{ + using WixToolset.Data; + + public enum WixTouchFileSymbolFields + { + ComponentRef, + Path, + Attributes, + } + + public class WixTouchFileSymbol : IntermediateSymbol + { + public WixTouchFileSymbol() : base(UtilSymbolDefinitions.WixTouchFile, null, null) + { + } + + public WixTouchFileSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.WixTouchFile, sourceLineNumber, id) + { + } + + public IntermediateField this[WixTouchFileSymbolFields index] => this.Fields[(int)index]; + + public string ComponentRef + { + get => this.Fields[(int)WixTouchFileSymbolFields.ComponentRef].AsString(); + set => this.Set((int)WixTouchFileSymbolFields.ComponentRef, value); + } + + public string Path + { + get => this.Fields[(int)WixTouchFileSymbolFields.Path].AsString(); + set => this.Set((int)WixTouchFileSymbolFields.Path, value); + } + + public int Attributes + { + get => this.Fields[(int)WixTouchFileSymbolFields.Attributes].AsNumber(); + set => this.Set((int)WixTouchFileSymbolFields.Attributes, value); + } + } +} \ 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + using WixToolset.Data; + using WixToolset.Util.Symbols; + + public static partial class UtilSymbolDefinitions + { + public static readonly IntermediateSymbolDefinition WixWindowsFeatureSearch = new IntermediateSymbolDefinition( + UtilSymbolDefinitionType.WixWindowsFeatureSearch.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(WixWindowsFeatureSearchSymbolFields.Type), IntermediateFieldType.String), + }, + typeof(WixWindowsFeatureSearchSymbol)); + } +} + +namespace WixToolset.Util.Symbols +{ + using WixToolset.Data; + + public enum WixWindowsFeatureSearchSymbolFields + { + Type, + } + + public class WixWindowsFeatureSearchSymbol : IntermediateSymbol + { + public WixWindowsFeatureSearchSymbol() : base(UtilSymbolDefinitions.WixWindowsFeatureSearch, null, null) + { + } + + public WixWindowsFeatureSearchSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.WixWindowsFeatureSearch, sourceLineNumber, id) + { + } + + public IntermediateField this[WixWindowsFeatureSearchSymbolFields index] => this.Fields[(int)index]; + + public string Type + { + get => this.Fields[(int)WixWindowsFeatureSearchSymbolFields.Type].AsString(); + set => this.Set((int)WixWindowsFeatureSearchSymbolFields.Type, value); + } + } +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + using WixToolset.Data; + using WixToolset.Util.Symbols; + + public static partial class UtilSymbolDefinitions + { + public static readonly IntermediateSymbolDefinition XmlConfig = new IntermediateSymbolDefinition( + UtilSymbolDefinitionType.XmlConfig.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.File), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.ElementId), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.ElementPath), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.VerifyPath), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.Name), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.Value), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.Flags), IntermediateFieldType.Number), + new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.ComponentRef), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.Sequence), IntermediateFieldType.Number), + }, + typeof(XmlConfigSymbol)); + } +} + +namespace WixToolset.Util.Symbols +{ + using WixToolset.Data; + + public enum XmlConfigSymbolFields + { + File, + ElementId, + ElementPath, + VerifyPath, + Name, + Value, + Flags, + ComponentRef, + Sequence, + } + + public class XmlConfigSymbol : IntermediateSymbol + { + public XmlConfigSymbol() : base(UtilSymbolDefinitions.XmlConfig, null, null) + { + } + + public XmlConfigSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.XmlConfig, sourceLineNumber, id) + { + } + + public IntermediateField this[XmlConfigSymbolFields index] => this.Fields[(int)index]; + + public string File + { + get => this.Fields[(int)XmlConfigSymbolFields.File].AsString(); + set => this.Set((int)XmlConfigSymbolFields.File, value); + } + + public string ElementId + { + get => this.Fields[(int)XmlConfigSymbolFields.ElementId].AsString(); + set => this.Set((int)XmlConfigSymbolFields.ElementId, value); + } + + public string ElementPath + { + get => this.Fields[(int)XmlConfigSymbolFields.ElementPath].AsString(); + set => this.Set((int)XmlConfigSymbolFields.ElementPath, value); + } + + public string VerifyPath + { + get => this.Fields[(int)XmlConfigSymbolFields.VerifyPath].AsString(); + set => this.Set((int)XmlConfigSymbolFields.VerifyPath, value); + } + + public string Name + { + get => this.Fields[(int)XmlConfigSymbolFields.Name].AsString(); + set => this.Set((int)XmlConfigSymbolFields.Name, value); + } + + public string Value + { + get => this.Fields[(int)XmlConfigSymbolFields.Value].AsString(); + set => this.Set((int)XmlConfigSymbolFields.Value, value); + } + + public int Flags + { + get => this.Fields[(int)XmlConfigSymbolFields.Flags].AsNumber(); + set => this.Set((int)XmlConfigSymbolFields.Flags, value); + } + + public string ComponentRef + { + get => this.Fields[(int)XmlConfigSymbolFields.ComponentRef].AsString(); + set => this.Set((int)XmlConfigSymbolFields.ComponentRef, value); + } + + public int? Sequence + { + get => this.Fields[(int)XmlConfigSymbolFields.Sequence].AsNullableNumber(); + set => this.Set((int)XmlConfigSymbolFields.Sequence, value); + } + } +} \ 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + using WixToolset.Data; + using WixToolset.Util.Symbols; + + public static partial class UtilSymbolDefinitions + { + public static readonly IntermediateSymbolDefinition XmlFile = new IntermediateSymbolDefinition( + UtilSymbolDefinitionType.XmlFile.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(XmlFileSymbolFields.File), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(XmlFileSymbolFields.ElementPath), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(XmlFileSymbolFields.Name), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(XmlFileSymbolFields.Value), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(XmlFileSymbolFields.Flags), IntermediateFieldType.Number), + new IntermediateFieldDefinition(nameof(XmlFileSymbolFields.ComponentRef), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(XmlFileSymbolFields.Sequence), IntermediateFieldType.Number), + }, + typeof(XmlFileSymbol)); + } +} + +namespace WixToolset.Util.Symbols +{ + using WixToolset.Data; + + public enum XmlFileSymbolFields + { + File, + ElementPath, + Name, + Value, + Flags, + ComponentRef, + Sequence, + } + + public class XmlFileSymbol : IntermediateSymbol + { + public XmlFileSymbol() : base(UtilSymbolDefinitions.XmlFile, null, null) + { + } + + public XmlFileSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.XmlFile, sourceLineNumber, id) + { + } + + public IntermediateField this[XmlFileSymbolFields index] => this.Fields[(int)index]; + + public string File + { + get => this.Fields[(int)XmlFileSymbolFields.File].AsString(); + set => this.Set((int)XmlFileSymbolFields.File, value); + } + + public string ElementPath + { + get => this.Fields[(int)XmlFileSymbolFields.ElementPath].AsString(); + set => this.Set((int)XmlFileSymbolFields.ElementPath, value); + } + + public string Name + { + get => this.Fields[(int)XmlFileSymbolFields.Name].AsString(); + set => this.Set((int)XmlFileSymbolFields.Name, value); + } + + public string Value + { + get => this.Fields[(int)XmlFileSymbolFields.Value].AsString(); + set => this.Set((int)XmlFileSymbolFields.Value, value); + } + + public int Flags + { + get => this.Fields[(int)XmlFileSymbolFields.Flags].AsNumber(); + set => this.Set((int)XmlFileSymbolFields.Flags, value); + } + + public string ComponentRef + { + get => this.Fields[(int)XmlFileSymbolFields.ComponentRef].AsString(); + set => this.Set((int)XmlFileSymbolFields.ComponentRef, value); + } + + public int? Sequence + { + get => this.Fields[(int)XmlFileSymbolFields.Sequence].AsNullableNumber(); + set => this.Set((int)XmlFileSymbolFields.Sequence, value); + } + } +} \ 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Globalization; + using System.Linq; + using System.Text; + using System.Text.RegularExpressions; + using System.Xml.Linq; + using WixToolset.Data; + using WixToolset.Data.Symbols; + using WixToolset.Extensibility; + using WixToolset.Extensibility.Data; + using WixToolset.Util.Symbols; + + /// + /// The compiler for the WiX Toolset Utility Extension. + /// + public sealed class UtilCompiler : BaseCompilerExtension + { + // user creation attributes definitions (from sca.h) + internal const int UserDontExpirePasswrd = 0x00000001; + internal const int UserPasswdCantChange = 0x00000002; + internal const int UserPasswdChangeReqdOnLogin = 0x00000004; + internal const int UserDisableAccount = 0x00000008; + internal const int UserFailIfExists = 0x00000010; + internal const int UserUpdateIfExists = 0x00000020; + internal const int UserLogonAsService = 0x00000040; + internal const int UserLogonAsBatchJob = 0x00000080; + + internal const int UserDontRemoveOnUninstall = 0x00000100; + internal const int UserDontCreateUser = 0x00000200; + internal const int UserNonVital = 0x00000400; + + private static readonly Regex FindPropertyBrackets = new Regex(@"\[(?!\\|\])|(? "http://wixtoolset.org/schemas/v4/wxs/util"; + + /// + /// Types of Internet shortcuts. + /// + public enum InternetShortcutType + { + /// Create a .lnk file. + Link = 0, + + /// Create a .url file. + Url, + } + + /// + /// Types of permission setting methods. + /// + private enum PermissionType + { + /// LockPermissions (normal) type permission setting. + LockPermissions, + + /// FileSharePermissions type permission setting. + FileSharePermissions, + + /// SecureObjects type permission setting. + SecureObjects, + } + + /// + /// Processes an element for the Compiler. + /// + /// Parent element of element to process. + /// Element to process. + /// Extra information about the context in which this element is being parsed. + public override void ParseElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, IDictionary context) + { + this.ParsePossibleKeyPathElement(intermediate, section, parentElement, element, context); + } + + /// + /// Processes an element for the Compiler. + /// + /// Source line number for the parent element. + /// Parent element of element to process. + /// Element to process. + /// Extra information about the context in which this element is being parsed. + public override IComponentKeyPath ParsePossibleKeyPathElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, IDictionary context) + { + IComponentKeyPath possibleKeyPath = null; + + switch (parentElement.Name.LocalName) + { + case "CreateFolder": + var createFolderId = context["DirectoryId"]; + var createFolderComponentId = context["ComponentId"]; + + // If this doesn't parse successfully, something really odd is going on, so let the exception get thrown + var createFolderWin64 = Boolean.Parse(context["Win64"]); + + switch (element.Name.LocalName) + { + case "PermissionEx": + this.ParsePermissionExElement(intermediate, section, element, createFolderId, createFolderComponentId, createFolderWin64, "CreateFolder"); + break; + default: + this.ParseHelper.UnexpectedElement(parentElement, element); + break; + } + break; + case "Component": + var componentId = context["ComponentId"]; + var directoryId = context["DirectoryId"]; + var componentWin64 = Boolean.Parse(context["Win64"]); + + switch (element.Name.LocalName) + { + case "EventSource": + possibleKeyPath = this.ParseEventSourceElement(intermediate, section, element, componentId); + break; + case "FileShare": + this.ParseFileShareElement(intermediate, section, element, componentId, directoryId); + break; + case "InternetShortcut": + this.ParseInternetShortcutElement(intermediate, section, element, componentId, directoryId); + break; + case "PerformanceCategory": + this.ParsePerformanceCategoryElement(intermediate, section, element, componentId); + break; + case "RemoveFolderEx": + this.ParseRemoveFolderExElement(intermediate, section, element, componentId); + break; + case "RemoveRegistryKey": + this.ParseRemoveRegistryKeyExElement(intermediate, section, element, componentId); + break; + case "RestartResource": + this.ParseRestartResourceElement(intermediate, section, element, componentId); + break; + case "ServiceConfig": + this.ParseServiceConfigElement(intermediate, section, element, componentId, "Component", null); + break; + case "TouchFile": + this.ParseTouchFileElement(intermediate, section, element, componentId, componentWin64); + break; + case "User": + this.ParseUserElement(intermediate, section, element, componentId); + break; + case "XmlFile": + this.ParseXmlFileElement(intermediate, section, element, componentId); + break; + case "XmlConfig": + this.ParseXmlConfigElement(intermediate, section, element, componentId, false); + break; + default: + this.ParseHelper.UnexpectedElement(parentElement, element); + break; + } + break; + case "File": + var fileId = context["FileId"]; + var fileComponentId = context["ComponentId"]; + + // If this doesn't parse successfully, something really odd is going on, so let the exception get thrown + var fileWin64 = Boolean.Parse(context["Win64"]); + + switch (element.Name.LocalName) + { + case "PerfCounter": + this.ParsePerfCounterElement(intermediate, section, element, fileComponentId, fileId); + break; + case "PermissionEx": + this.ParsePermissionExElement(intermediate, section, element, fileId, fileComponentId, fileWin64, "File"); + break; + case "PerfCounterManifest": + this.ParsePerfCounterManifestElement(intermediate, section, element, fileComponentId, fileId); + break; + case "EventManifest": + this.ParseEventManifestElement(intermediate, section, element, fileComponentId, fileId); + break; + case "FormatFile": + this.ParseFormatFileElement(intermediate, section, element, fileId, fileWin64); + break; + default: + this.ParseHelper.UnexpectedElement(parentElement, element); + break; + } + break; + case "Bundle": + case "Fragment": + case "Module": + case "Package": + switch (element.Name.LocalName) + { + case "CloseApplication": + this.ParseCloseApplicationElement(intermediate, section, element); + break; + case "Group": + this.ParseGroupElement(intermediate, section, element, null); + break; + case "RestartResource": + // Currently not supported for Bundles. + if (parentElement.Name.LocalName != "Bundle") + { + this.ParseRestartResourceElement(intermediate, section, element, null); + } + else + { + this.ParseHelper.UnexpectedElement(parentElement, element); + } + break; + case "User": + this.ParseUserElement(intermediate, section, element, null); + break; + case "BroadcastEnvironmentChange": + case "BroadcastSettingChange": + case "CheckRebootRequired": + case "ExitEarlyWithSuccess": + case "FailWhenDeferred": + case "QueryWindowsDirectories": + case "QueryWindowsDriverInfo": + case "QueryWindowsSuiteInfo": + case "QueryWindowsWellKnownSIDs": + case "WaitForEvent": + case "WaitForEventDeferred": + this.AddCustomActionReference(intermediate, section, element, parentElement); + break; + case "ComponentSearch": + case "ComponentSearchRef": + case "DirectorySearch": + case "DirectorySearchRef": + case "FileSearch": + case "FileSearchRef": + case "ProductSearch": + case "ProductSearchRef": + case "RegistrySearch": + case "RegistrySearchRef": + case "WindowsFeatureSearch": + case "WindowsFeatureSearchRef": + // These will eventually be supported under Module/Product, but are not yet. + if (parentElement.Name.LocalName == "Bundle" || parentElement.Name.LocalName == "Fragment") + { + // TODO: When these are supported by all section types, move + // these out of the nested switch and back into the surrounding one. + switch (element.Name.LocalName) + { + case "ComponentSearch": + this.ParseComponentSearchElement(intermediate, section, element); + break; + case "ComponentSearchRef": + this.ParseComponentSearchRefElement(intermediate, section, element); + break; + case "DirectorySearch": + this.ParseDirectorySearchElement(intermediate, section, element); + break; + case "DirectorySearchRef": + this.ParseWixSearchRefElement(intermediate, section, element); + break; + case "FileSearch": + this.ParseFileSearchElement(intermediate, section, element); + break; + case "FileSearchRef": + this.ParseWixSearchRefElement(intermediate, section, element); + break; + case "ProductSearch": + this.ParseProductSearchElement(intermediate, section, element); + break; + case "ProductSearchRef": + this.ParseWixSearchRefElement(intermediate, section, element); + break; + case "RegistrySearch": + this.ParseRegistrySearchElement(intermediate, section, element); + break; + case "RegistrySearchRef": + this.ParseWixSearchRefElement(intermediate, section, element); + break; + case "WindowsFeatureSearch": + this.ParseWindowsFeatureSearchElement(intermediate, section, element); + break; + case "WindowsFeatureSearchRef": + this.ParseWindowsFeatureSearchRefElement(intermediate, section, element); + break; + } + } + else + { + this.ParseHelper.UnexpectedElement(parentElement, element); + } + break; + default: + this.ParseHelper.UnexpectedElement(parentElement, element); + break; + } + break; + case "Registry": + case "RegistryKey": + case "RegistryValue": + var registryId = context["RegistryId"]; + var registryComponentId = context["ComponentId"]; + + // If this doesn't parse successfully, something really odd is going on, so let the exception get thrown + var registryWin64 = Boolean.Parse(context["Win64"]); + + switch (element.Name.LocalName) + { + case "PermissionEx": + this.ParsePermissionExElement(intermediate, section, element, registryId, registryComponentId, registryWin64, "Registry"); + break; + default: + this.ParseHelper.UnexpectedElement(parentElement, element); + break; + } + break; + case "ServiceInstall": + var serviceInstallId = context["ServiceInstallId"]; + var serviceInstallName = context["ServiceInstallName"]; + var serviceInstallComponentId = context["ServiceInstallComponentId"]; + + // If this doesn't parse successfully, something really odd is going on, so let the exception get thrown + var serviceInstallWin64 = Boolean.Parse(context["Win64"]); + + switch (element.Name.LocalName) + { + case "PermissionEx": + this.ParsePermissionExElement(intermediate, section, element, serviceInstallId, serviceInstallComponentId, serviceInstallWin64, "ServiceInstall"); + break; + case "ServiceConfig": + this.ParseServiceConfigElement(intermediate, section, element, serviceInstallComponentId, "ServiceInstall", serviceInstallName); + break; + default: + this.ParseHelper.UnexpectedElement(parentElement, element); + break; + } + break; + case "UI": + switch (element.Name.LocalName) + { + case "BroadcastEnvironmentChange": + case "BroadcastSettingChange": + case "CheckRebootRequired": + case "ExitEarlyWithSuccess": + case "FailWhenDeferred": + case "QueryWindowsDirectories": + case "QueryWindowsDriverInfo": + case "QueryWindowsSuiteInfo": + case "QueryWindowsWellKnownSIDs": + case "WaitForEvent": + case "WaitForEventDeferred": + this.AddCustomActionReference(intermediate, section, element, parentElement); + break; + } + break; + default: + this.ParseHelper.UnexpectedElement(parentElement, element); + break; + } + + return possibleKeyPath; + } + + private void AddCustomActionReference(Intermediate intermediate, IntermediateSection section, XElement element, XElement parentElement) + { + // These elements are not supported for bundles. + if (parentElement.Name.LocalName == "Bundle") + { + this.ParseHelper.UnexpectedElement(parentElement, element); + return; + } + + var customAction = element.Name.LocalName; + switch (element.Name.LocalName) + { + case "BroadcastEnvironmentChange": + case "BroadcastSettingChange": + case "CheckRebootRequired": + case "ExitEarlyWithSuccess": + case "FailWhenDeferred": + case "WaitForEvent": + case "WaitForEventDeferred": + //default: customAction = element.Name.LocalName; + break; + case "QueryWindowsDirectories": + customAction = "QueryOsDirs"; + break; + case "QueryWindowsDriverInfo": + customAction = "QueryOsDriverInfo"; + break; + case "QueryWindowsSuiteInfo": + customAction = "QueryOsInfo"; + break; + case "QueryWindowsWellKnownSIDs": + customAction = "QueryOsWellKnownSID"; + break; + } + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + // no attributes today + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + + this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4" + customAction, this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); + } + + /// + /// Parses the common search attributes shared across all searches. + /// + /// Source line number for the parent element. + /// Attribute to parse. + /// Value of the Id attribute. + /// Value of the Variable attribute. + /// Value of the Condition attribute. + /// Value of the After attribute. + private void ParseCommonSearchAttributes(SourceLineNumber sourceLineNumbers, XAttribute attrib, ref Identifier id, ref string variable, ref string condition, ref string after) + { + switch (attrib.Name.LocalName) + { + case "Id": + id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); + break; + case "Variable": + variable = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + // TODO: handle standard bundle variables + break; + case "Condition": + condition = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "After": + after = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + default: + System.Diagnostics.Debug.Assert(false); + break; + } + } + + /// + /// Parses a ComponentSearch element. + /// + /// Element to parse. + private void ParseComponentSearchElement(Intermediate intermediate, IntermediateSection section, XElement element) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + Identifier id = null; + string variable = null; + string condition = null; + string after = null; + string guid = null; + string productCode = null; + var attributes = WixComponentSearchAttributes.KeyPath; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + case "Variable": + case "Condition": + case "After": + this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after); + break; + case "Guid": + guid = this.ParseHelper.GetAttributeGuidValue(sourceLineNumbers, attrib); + break; + case "ProductCode": + productCode = this.ParseHelper.GetAttributeGuidValue(sourceLineNumbers, attrib); + break; + case "Result": + var result = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + switch (result) + { + case "directory": + attributes = WixComponentSearchAttributes.WantDirectory; + break; + case "keyPath": + attributes = WixComponentSearchAttributes.KeyPath; + break; + case "state": + attributes = WixComponentSearchAttributes.State; + break; + default: + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, result, "directory", "keyPath", "state")); + break; + } + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + if (null == guid) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Guid")); + } + + if (null == id) + { + id = this.ParseHelper.CreateIdentifier("wcs", variable, condition, after, guid, productCode, attributes.ToString()); + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + + this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, null); + + if (!this.Messaging.EncounteredError) + { + section.AddSymbol(new WixComponentSearchSymbol(sourceLineNumbers, id) + { + Guid = guid, + ProductCode = productCode, + Attributes = attributes, + }); + } + } + + /// + /// Parses a ComponentSearchRef element + /// + /// Element to parse. + private void ParseComponentSearchRefElement(Intermediate intermediate, IntermediateSection section, XElement element) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + string refId = null; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + refId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.WixComponentSearch, refId); + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + } + + /// + /// Parses a WindowsFeatureSearch element. + /// + /// Element to parse. + private void ParseWindowsFeatureSearchElement(Intermediate intermediate, IntermediateSection section, XElement element) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + Identifier id = null; + string variable = null; + string condition = null; + string after = null; + string feature = null; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + case "Variable": + case "Condition": + case "After": + this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after); + break; + case "Feature": + feature = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + switch (feature) + { + case "sha2CodeSigning": + break; + default: + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Feature", feature, "sha2CodeSigning")); + break; + } + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + if (id == null) + { + id = this.ParseHelper.CreateIdentifier("wwfs", variable, condition, after); + } + + if (feature == null) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Feature")); + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + + var bundleExtensionId = this.ParseHelper.CreateIdentifierValueFromPlatform("Wix4UtilBundleExtension", this.Context.Platform, BurnPlatforms.X86 | BurnPlatforms.X64 | BurnPlatforms.ARM64); + if (bundleExtensionId == null) + { + this.Messaging.Write(ErrorMessages.UnsupportedPlatformForElement(sourceLineNumbers, this.Context.Platform.ToString(), element.Name.LocalName)); + } + + this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, bundleExtensionId); + + if (!this.Messaging.EncounteredError) + { + section.AddSymbol(new WixWindowsFeatureSearchSymbol(sourceLineNumbers, id) + { + Type = feature, + }); + } + } + + /// + /// Parses a WindowsFeatureSearchRef element + /// + /// Element to parse. + private void ParseWindowsFeatureSearchRefElement(Intermediate intermediate, IntermediateSection section, XElement element) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + var refId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, UtilSymbolDefinitions.WixWindowsFeatureSearch, refId); + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + } + + /// + /// Parses an event source element. + /// + /// Element to parse. + /// Identifier of parent component. + private IComponentKeyPath ParseEventSourceElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + string sourceName = null; + string logName = null; + string categoryMessageFile = null; + var categoryCount = CompilerConstants.IntegerNotSet; + string eventMessageFile = null; + string parameterMessageFile = null; + int typesSupported = 0; + var isKeyPath = false; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "CategoryCount": + categoryCount = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); + break; + case "CategoryMessageFile": + categoryMessageFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "EventMessageFile": + eventMessageFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "KeyPath": + isKeyPath = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib); + break; + case "Log": + logName = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + if ("Security" == logName) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, logName, "Application", "System", "")); + } + break; + case "Name": + sourceName = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "ParameterMessageFile": + parameterMessageFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "SupportsErrors": + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + typesSupported |= 0x01; // EVENTLOG_ERROR_TYPE + } + break; + case "SupportsFailureAudits": + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + typesSupported |= 0x10; // EVENTLOG_AUDIT_FAILURE + } + break; + case "SupportsInformationals": + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + typesSupported |= 0x04; // EVENTLOG_INFORMATION_TYPE + } + break; + case "SupportsSuccessAudits": + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + typesSupported |= 0x08; // EVENTLOG_AUDIT_SUCCESS + } + break; + case "SupportsWarnings": + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + typesSupported |= 0x02; // EVENTLOG_WARNING_TYPE + } + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + if (null == sourceName) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name")); + } + + if (null == logName) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "EventLog")); + } + + if (null == eventMessageFile) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "EventMessageFile")); + } + + if (null == categoryMessageFile && 0 < categoryCount) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, element.Name.LocalName, "CategoryCount", "CategoryMessageFile")); + } + + if (null != categoryMessageFile && CompilerConstants.IntegerNotSet == categoryCount) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, element.Name.LocalName, "CategoryMessageFile", "CategoryCount")); + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + + string eventSourceKey = $@"SYSTEM\CurrentControlSet\Services\EventLog\{logName}\{sourceName}"; + var id = this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, eventSourceKey, "EventMessageFile", String.Concat("#%", eventMessageFile), componentId, false); + + if (null != categoryMessageFile) + { + this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, eventSourceKey, "CategoryMessageFile", String.Concat("#%", categoryMessageFile), componentId, false); + } + + if (CompilerConstants.IntegerNotSet != categoryCount) + { + this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, eventSourceKey, "CategoryCount", String.Concat("#", categoryCount), componentId, false); + } + + if (null != parameterMessageFile) + { + this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, eventSourceKey, "ParameterMessageFile", String.Concat("#%", parameterMessageFile), componentId, false); + } + + if (0 != typesSupported) + { + this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, eventSourceKey, "TypesSupported", String.Concat("#", typesSupported), componentId, false); + } + + var componentKeyPath = this.CreateComponentKeyPath(); + componentKeyPath.Id = id.Id; + componentKeyPath.Explicit = isKeyPath; + componentKeyPath.Type = PossibleKeyPathType.Registry; + return componentKeyPath; + } + + /// + /// Parses a close application element. + /// + /// Element to parse. + private void ParseCloseApplicationElement(Intermediate intermediate, IntermediateSection section, XElement element) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + string condition = null; + string description = null; + string target = null; + string property = null; + Identifier id = null; + int attributes = 2; // default to CLOSEAPP_ATTRIBUTE_REBOOTPROMPT enabled + var sequence = CompilerConstants.IntegerNotSet; + var terminateExitCode = CompilerConstants.IntegerNotSet; + var timeout = CompilerConstants.IntegerNotSet; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); + break; + case "Condition": + condition = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Description": + description = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Property": + property = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + break; + case "Sequence": + sequence = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); + break; + case "Timeout": + timeout = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); + break; + case "Target": + target = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "CloseMessage": + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= 1; // CLOSEAPP_ATTRIBUTE_CLOSEMESSAGE + } + else + { + attributes &= ~1; // CLOSEAPP_ATTRIBUTE_CLOSEMESSAGE + } + break; + case "EndSessionMessage": + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= 8; // CLOSEAPP_ATTRIBUTE_ENDSESSIONMESSAGE + } + else + { + attributes &= ~8; // CLOSEAPP_ATTRIBUTE_ENDSESSIONMESSAGE + } + break; + case "PromptToContinue": + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= 0x40; // CLOSEAPP_ATTRIBUTE_PROMPTTOCONTINUE + } + else + { + attributes &= ~0x40; // CLOSEAPP_ATTRIBUTE_PROMPTTOCONTINUE + } + break; + case "RebootPrompt": + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= 2; // CLOSEAPP_ATTRIBUTE_REBOOTPROMPT + } + else + { + attributes &= ~2; // CLOSEAPP_ATTRIBUTE_REBOOTPROMPT + } + break; + case "ElevatedCloseMessage": + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= 4; // CLOSEAPP_ATTRIBUTE_ELEVATEDCLOSEMESSAGE + } + else + { + attributes &= ~4; // CLOSEAPP_ATTRIBUTE_ELEVATEDCLOSEMESSAGE + } + break; + case "ElevatedEndSessionMessage": + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= 0x10; // CLOSEAPP_ATTRIBUTE_ELEVATEDENDSESSIONMESSAGE + } + else + { + attributes &= ~0x10; // CLOSEAPP_ATTRIBUTE_ELEVATEDENDSESSIONMESSAGE + } + break; + case "TerminateProcess": + terminateExitCode = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); + attributes |= 0x20; // CLOSEAPP_ATTRIBUTE_TERMINATEPROCESS + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + if (null == target) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Target")); + } + else if (null == id) + { + id = this.ParseHelper.CreateIdentifier("ca", target); + } + + if (String.IsNullOrEmpty(description) && 0x40 == (attributes & 0x40)) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeValueWithoutOtherAttribute(sourceLineNumbers, element.Name.LocalName, "PromptToContinue", "yes", "Description")); + } + + if (0x22 == (attributes & 0x22)) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "TerminateProcess", "RebootPrompt", "yes")); + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + + this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4CloseApplications", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); + + if (!this.Messaging.EncounteredError) + { + var symbol = section.AddSymbol(new WixCloseApplicationSymbol(sourceLineNumbers, id) + { + Target = target, + Description = description, + Condition = condition, + Attributes = attributes, + Property = property, + }); + if (CompilerConstants.IntegerNotSet != sequence) + { + symbol.Sequence = sequence; + } + if (CompilerConstants.IntegerNotSet != terminateExitCode) + { + symbol.TerminateExitCode = terminateExitCode; + } + if (CompilerConstants.IntegerNotSet != timeout) + { + symbol.Timeout = timeout * 1000; // make the timeout milliseconds in the table. + } + } + } + + /// + /// Parses a DirectorySearch element. + /// + /// Element to parse. + private void ParseDirectorySearchElement(Intermediate intermediate, IntermediateSection section, XElement element) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + Identifier id = null; + string variable = null; + string condition = null; + string after = null; + string path = null; + var attributes = WixFileSearchAttributes.IsDirectory; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + case "Variable": + case "Condition": + case "After": + this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after); + break; + case "Path": + path = this.ParseHelper.GetAttributeLongFilename(sourceLineNumbers, attrib, false, true); + break; + case "Result": + var result = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + switch (result) + { + case "exists": + attributes |= WixFileSearchAttributes.WantExists; + break; + default: + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, result, "exists")); + break; + } + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + if (null == path) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Path")); + } + + if (null == id) + { + id = this.ParseHelper.CreateIdentifier("wds", variable, condition, after, path, attributes.ToString()); + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + + this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, null); + + if (!this.Messaging.EncounteredError) + { + this.CreateWixFileSearchRow(section, sourceLineNumbers, id, path, attributes); + } + } + + /// + /// Parses a DirectorySearchRef, FileSearchRef, ProductSearchRef, and RegistrySearchRef elements + /// + /// Element to parse. + private void ParseWixSearchRefElement(Intermediate intermediate, IntermediateSection section, XElement node) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); + + foreach (XAttribute attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + var refId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.WixSearch, refId); + break; + default: + this.ParseHelper.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib); + } + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, node); + } + + /// + /// Parses a FileSearch element. + /// + /// Element to parse. + private void ParseFileSearchElement(Intermediate intermediate, IntermediateSection section, XElement node) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); + Identifier id = null; + string variable = null; + string condition = null; + string after = null; + string path = null; + var attributes = WixFileSearchAttributes.Default; + + foreach (var attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + case "Variable": + case "Condition": + case "After": + this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after); + break; + case "Path": + path = this.ParseHelper.GetAttributeLongFilename(sourceLineNumbers, attrib, false, true); + break; + case "Result": + string result = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + switch (result) + { + case "exists": + attributes |= WixFileSearchAttributes.WantExists; + break; + case "version": + attributes |= WixFileSearchAttributes.WantVersion; + break; + default: + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, result, "exists", "version")); + break; + } + break; + default: + this.ParseHelper.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib); + } + } + + if (null == path) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Path")); + } + + if (null == id) + { + id = this.ParseHelper.CreateIdentifier("wfs", variable, condition, after, path, attributes.ToString()); + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, node); + + this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, node.Name.LocalName, id, variable, condition, after, null); + + if (!this.Messaging.EncounteredError) + { + this.CreateWixFileSearchRow(section, sourceLineNumbers, id, path, attributes); + } + } + + /// + /// Creates a row in the WixFileSearch table. + /// + /// Source line number for the parent element. + /// Identifier of the search (key into the WixSearch table) + /// File/directory path to search for. + /// + private void CreateWixFileSearchRow(IntermediateSection section, SourceLineNumber sourceLineNumbers, Identifier id, string path, WixFileSearchAttributes attributes) + { + section.AddSymbol(new WixFileSearchSymbol(sourceLineNumbers, id) + { + Path = path, + Attributes = attributes, + }); + } + + /// + /// Parses a file share element. + /// + /// Element to parse. + /// Identifier of parent component. + /// Identifier of referred to directory. + private void ParseFileShareElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string directoryId) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + string description = null; + string name = null; + Identifier id = null; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); + break; + case "Name": + name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Description": + description = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + if (null == id) + { + id = this.ParseHelper.CreateIdentifier("ufs", componentId, name); + } + + if (null == name) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name")); + } + + if (!element.Elements().Any()) + { + this.Messaging.Write(ErrorMessages.ExpectedElement(sourceLineNumbers, element.Name.LocalName, "FileSharePermission")); + } + + foreach (var child in element.Elements()) + { + if (this.Namespace == child.Name.Namespace) + { + switch (child.Name.LocalName) + { + case "FileSharePermission": + this.ParseFileSharePermissionElement(intermediate, section, child, id); + break; + default: + this.ParseHelper.UnexpectedElement(element, child); + break; + } + } + else + { + this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child); + } + } + + this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureSmbInstall", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); + this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureSmbUninstall", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); + + if (!this.Messaging.EncounteredError) + { + section.AddSymbol(new FileShareSymbol(sourceLineNumbers, id) + { + ShareName = name, + ComponentRef = componentId, + Description = description, + DirectoryRef = directoryId, + }); + } + } + + /// + /// Parses a FileSharePermission element. + /// + /// Element to parse. + /// The identifier of the parent FileShare element. + private void ParseFileSharePermissionElement(Intermediate intermediate, IntermediateSection section, XElement element, Identifier fileShareId) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + var bits = new BitArray(32); + string user = null; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "User": + user = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, UtilSymbolDefinitions.User, user); + break; + default: + var attribValue = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib); + if (!this.TrySetBitFromName(UtilConstants.StandardPermissions, attrib.Name.LocalName, attribValue, bits, 16)) + { + if (!this.TrySetBitFromName(UtilConstants.GenericPermissions, attrib.Name.LocalName, attribValue, bits, 28)) + { + if (!this.TrySetBitFromName(UtilConstants.FolderPermissions, attrib.Name.LocalName, attribValue, bits, 0)) + { + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + } + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + var permission = this.CreateIntegerFromBitArray(bits); + + if (null == user) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "User")); + } + + if (Int32.MinValue == permission) // just GENERIC_READ, which is MSI_NULL + { + this.Messaging.Write(ErrorMessages.GenericReadNotAllowed(sourceLineNumbers)); + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + + if (!this.Messaging.EncounteredError) + { + section.AddSymbol(new FileSharePermissionsSymbol(sourceLineNumbers) + { + FileShareRef = fileShareId.Id, + UserRef = user, + Permissions = permission, + }); + } + } + + /// + /// Parses a group element. + /// + /// Node to be parsed. + /// Component Id of the parent component of this element. + private void ParseGroupElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + Identifier id = null; + string domain = null; + string name = null; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); + break; + case "Name": + name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Domain": + domain = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + if (null == id) + { + id = this.ParseHelper.CreateIdentifier("ugr", componentId, domain, name); + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + + if (!this.Messaging.EncounteredError) + { + section.AddSymbol(new GroupSymbol(sourceLineNumbers, id) + { + ComponentRef = componentId, + Name = name, + Domain = domain, + }); + } + } + + /// + /// Parses a GroupRef element + /// + /// Element to parse. + /// Required user id to be joined to the group. + private void ParseGroupRefElement(Intermediate intermediate, IntermediateSection section, XElement element, string userId) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + string groupId = null; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + groupId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, UtilSymbolDefinitions.Group, groupId); + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + + if (!this.Messaging.EncounteredError) + { + section.AddSymbol(new UserGroupSymbol(sourceLineNumbers) + { + UserRef = userId, + GroupRef = groupId, + }); + } + } + + /// + /// Parses an InternetShortcut element. + /// + /// Element to parse. + /// Identifier of parent component. + /// Default directory if none is specified on the InternetShortcut element. + private void ParseInternetShortcutElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string defaultTarget) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + Identifier id = null; + string name = null; + string target = null; + string directoryId = null; + string type = null; + string iconFile = null; + int iconIndex = 0; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Directory": + directoryId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + break; + case "Id": + id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); + break; + case "Name": + name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Target": + target = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Type": + type = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "IconFile": + iconFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "IconIndex": + iconIndex = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + // If there was no directoryId specified on the InternetShortcut element, default to the one on + // the parent component. + if (null == directoryId) + { + directoryId = defaultTarget; + } + + if (null == id) + { + id = this.ParseHelper.CreateIdentifier("uis", componentId, directoryId, name, target); + } + + // In theory this can never be the case, since InternetShortcut can only be under + // a component element, and if the Directory wasn't specified the default will come + // from the component. However, better safe than sorry, so here's a check to make sure + // it didn't wind up being null after setting it to the defaultTarget. + if (null == directoryId) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Directory")); + } + + if (null == name) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name")); + } + + if (null == target) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Target")); + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + + var shortcutType = InternetShortcutType.Link; + if (String.Equals(type, "url", StringComparison.OrdinalIgnoreCase)) + { + shortcutType = InternetShortcutType.Url; + } + + if (!this.Messaging.EncounteredError) + { + this.CreateWixInternetShortcut(section, sourceLineNumbers, componentId, directoryId, id, name, target, shortcutType, iconFile, iconIndex); + } + } + + /// + /// Creates the rows needed for WixInternetShortcut to work. + /// + /// The CompilerCore object used to create rows. + /// Source line information about the owner element. + /// Identifier of parent component. + /// Identifier of directory containing shortcut. + /// Identifier of shortcut. + /// Name of shortcut without extension. + /// Target URL of shortcut. + private void CreateWixInternetShortcut(IntermediateSection section, SourceLineNumber sourceLineNumbers, string componentId, string directoryId, Identifier shortcutId, string name, string target, InternetShortcutType type, string iconFile, int iconIndex) + { + // add the appropriate extension based on type of shortcut + name = String.Concat(name, InternetShortcutType.Url == type ? ".url" : ".lnk"); + + section.AddSymbol(new WixInternetShortcutSymbol(sourceLineNumbers, shortcutId) + { + ComponentRef = componentId, + DirectoryRef = directoryId, + Name = name, + Target = target, + Attributes = (int)type, + IconFile = iconFile, + IconIndex = iconIndex, + }); + + this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedInternetShortcuts", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); + + // make sure we have a CreateFolder table so that the immediate CA can add temporary rows to handle installation and uninstallation + this.ParseHelper.EnsureTable(section, sourceLineNumbers, "CreateFolder"); + + // use built-in MSI functionality to remove the shortcuts rather than doing so via CA + section.AddSymbol(new RemoveFileSymbol(sourceLineNumbers, shortcutId) + { + ComponentRef = componentId, + DirPropertyRef = directoryId, + OnUninstall = true, + FileName = name, + }); + } + + /// + /// Parses a performance category element. + /// + /// Element to parse. + /// Identifier of parent component. + private void ParsePerformanceCategoryElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + Identifier id = null; + string name = null; + string help = null; + var multiInstance = YesNoType.No; + int defaultLanguage = 0x09; // default to "english" + + var parsedPerformanceCounters = new List(); + + // default to managed performance counter + var library = "netfxperf.dll"; + var openEntryPoint = "OpenPerformanceData"; + var collectEntryPoint = "CollectPerformanceData"; + var closeEntryPoint = "ClosePerformanceData"; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Close": + closeEntryPoint = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Collect": + collectEntryPoint = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "DefaultLanguage": + defaultLanguage = this.GetPerformanceCounterLanguage(sourceLineNumbers, attrib); + break; + case "Help": + help = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Id": + id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); + break; + case "Library": + library = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "MultiInstance": + multiInstance = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib); + break; + case "Name": + name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Open": + openEntryPoint = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + if (null == id && null == name) + { + this.Messaging.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, element.Name.LocalName, "Id", "Name")); + } + else if (null == id) + { + id = this.ParseHelper.CreateIdentifier("upc", componentId, name); + } + else if (null == name) + { + name = id.Id; + } + + // Process the child counter elements. + foreach (var child in element.Elements()) + { + if (this.Namespace == child.Name.Namespace) + { + switch (child.Name.LocalName) + { + case "PerformanceCounter": + var counter = this.ParsePerformanceCounterElement(intermediate, section, child, defaultLanguage); + if (null != counter) + { + parsedPerformanceCounters.Add(counter); + } + break; + default: + this.ParseHelper.UnexpectedElement(element, child); + break; + } + } + else + { + this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child); + } + } + + + if (!this.Messaging.EncounteredError) + { + // Calculate the ini and h file content. + var objectName = "OBJECT_1"; + var objectLanguage = defaultLanguage.ToString("D3", CultureInfo.InvariantCulture); + + var sbIniData = new StringBuilder(); + 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); + sbIniData.AppendFormat("[text]\r\n{0}_{1}_NAME={2}\r\n", objectName, objectLanguage, name); + if (null != help) + { + sbIniData.AppendFormat("{0}_{1}_HELP={2}\r\n", objectName, objectLanguage, help); + } + + int symbolConstantsCounter = 0; + var sbSymbolicConstants = new StringBuilder(); + sbSymbolicConstants.AppendFormat("#define {0} {1}\r\n", objectName, symbolConstantsCounter); + + var sbCounterNames = new StringBuilder("[~]"); + var sbCounterTypes = new StringBuilder("[~]"); + for (int i = 0; i < parsedPerformanceCounters.Count; ++i) + { + var counter = parsedPerformanceCounters[i]; + var counterName = String.Concat("DEVICE_COUNTER_", i + 1); + + sbIniData.AppendFormat("{0}_{1}_NAME={2}\r\n", counterName, counter.Language, counter.Name); + if (null != counter.Help) + { + sbIniData.AppendFormat("{0}_{1}_HELP={2}\r\n", counterName, counter.Language, counter.Help); + } + + symbolConstantsCounter += 2; + sbSymbolicConstants.AppendFormat("#define {0} {1}\r\n", counterName, symbolConstantsCounter); + + sbCounterNames.Append(UtilCompiler.FindPropertyBrackets.Replace(counter.Name, this.EscapeProperties)); + sbCounterNames.Append("[~]"); + sbCounterTypes.Append(counter.Type); + sbCounterTypes.Append("[~]"); + } + + sbSymbolicConstants.AppendFormat("#define LAST_{0}_COUNTER_OFFSET {1}\r\n", objectName, symbolConstantsCounter); + + // Add the calculated INI and H strings to the PerformanceCategory table. + section.AddSymbol(new PerformanceCategorySymbol(sourceLineNumbers, id) + { + ComponentRef = componentId, + Name = name, + IniData = sbIniData.ToString(), + ConstantData = sbSymbolicConstants.ToString(), + }); + + // Set up the application's performance key. + var escapedName = UtilCompiler.FindPropertyBrackets.Replace(name, this.EscapeProperties); + var linkageKey = String.Format(@"SYSTEM\CurrentControlSet\Services\{0}\Linkage", escapedName); + var performanceKey = String.Format(@"SYSTEM\CurrentControlSet\Services\{0}\Performance", escapedName); + + this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, linkageKey, "Export", escapedName, componentId, false); + this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "-", null, componentId, false); + this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Library", library, componentId, false); + this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Open", openEntryPoint, componentId, false); + this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Collect", collectEntryPoint, componentId, false); + this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Close", closeEntryPoint, componentId, false); + this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "IsMultiInstance", YesNoType.Yes == multiInstance ? "#1" : "#0", componentId, false); + this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Counter Names", sbCounterNames.ToString(), componentId, false); + this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Counter Types", sbCounterTypes.ToString(), componentId, false); + } + + this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4InstallPerfCounterData", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); + this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4UninstallPerfCounterData", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); + } + + /// + /// Gets the performance counter language as a decimal number. + /// + /// Source line information about the owner element. + /// The attribute containing the value to get. + /// Numeric representation of the language as per WinNT.h. + private int GetPerformanceCounterLanguage(SourceLineNumber sourceLineNumbers, XAttribute attribute) + { + int language = 0; + if (String.Empty == attribute.Value) + { + this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName)); + } + else + { + switch (attribute.Value) + { + case "afrikaans": + language = 0x36; + break; + case "albanian": + language = 0x1c; + break; + case "arabic": + language = 0x01; + break; + case "armenian": + language = 0x2b; + break; + case "assamese": + language = 0x4d; + break; + case "azeri": + language = 0x2c; + break; + case "basque": + language = 0x2d; + break; + case "belarusian": + language = 0x23; + break; + case "bengali": + language = 0x45; + break; + case "bulgarian": + language = 0x02; + break; + case "catalan": + language = 0x03; + break; + case "chinese": + language = 0x04; + break; + case "croatian": + language = 0x1a; + break; + case "czech": + language = 0x05; + break; + case "danish": + language = 0x06; + break; + case "divehi": + language = 0x65; + break; + case "dutch": + language = 0x13; + break; + case "piglatin": + case "english": + language = 0x09; + break; + case "estonian": + language = 0x25; + break; + case "faeroese": + language = 0x38; + break; + case "farsi": + language = 0x29; + break; + case "finnish": + language = 0x0b; + break; + case "french": + language = 0x0c; + break; + case "galician": + language = 0x56; + break; + case "georgian": + language = 0x37; + break; + case "german": + language = 0x07; + break; + case "greek": + language = 0x08; + break; + case "gujarati": + language = 0x47; + break; + case "hebrew": + language = 0x0d; + break; + case "hindi": + language = 0x39; + break; + case "hungarian": + language = 0x0e; + break; + case "icelandic": + language = 0x0f; + break; + case "indonesian": + language = 0x21; + break; + case "italian": + language = 0x10; + break; + case "japanese": + language = 0x11; + break; + case "kannada": + language = 0x4b; + break; + case "kashmiri": + language = 0x60; + break; + case "kazak": + language = 0x3f; + break; + case "konkani": + language = 0x57; + break; + case "korean": + language = 0x12; + break; + case "kyrgyz": + language = 0x40; + break; + case "latvian": + language = 0x26; + break; + case "lithuanian": + language = 0x27; + break; + case "macedonian": + language = 0x2f; + break; + case "malay": + language = 0x3e; + break; + case "malayalam": + language = 0x4c; + break; + case "manipuri": + language = 0x58; + break; + case "marathi": + language = 0x4e; + break; + case "mongolian": + language = 0x50; + break; + case "nepali": + language = 0x61; + break; + case "norwegian": + language = 0x14; + break; + case "oriya": + language = 0x48; + break; + case "polish": + language = 0x15; + break; + case "portuguese": + language = 0x16; + break; + case "punjabi": + language = 0x46; + break; + case "romanian": + language = 0x18; + break; + case "russian": + language = 0x19; + break; + case "sanskrit": + language = 0x4f; + break; + case "serbian": + language = 0x1a; + break; + case "sindhi": + language = 0x59; + break; + case "slovak": + language = 0x1b; + break; + case "slovenian": + language = 0x24; + break; + case "spanish": + language = 0x0a; + break; + case "swahili": + language = 0x41; + break; + case "swedish": + language = 0x1d; + break; + case "syriac": + language = 0x5a; + break; + case "tamil": + language = 0x49; + break; + case "tatar": + language = 0x44; + break; + case "telugu": + language = 0x4a; + break; + case "thai": + language = 0x1e; + break; + case "turkish": + language = 0x1f; + break; + case "ukrainian": + language = 0x22; + break; + case "urdu": + language = 0x20; + break; + case "uzbek": + language = 0x43; + break; + case "vietnamese": + language = 0x2a; + break; + default: + this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName)); + break; + } + } + + return language; + } + + /// + /// Parses a performance counter element. + /// + /// Element to parse. + /// Default language for the performance counter. + private ParsedPerformanceCounter ParsePerformanceCounterElement(Intermediate intermediate, IntermediateSection section, XElement element, int defaultLanguage) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + ParsedPerformanceCounter parsedPerformanceCounter = null; + string name = null; + string help = null; + var type = System.Diagnostics.PerformanceCounterType.NumberOfItems32; + int language = defaultLanguage; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Help": + help = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Name": + name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Type": + type = this.GetPerformanceCounterType(sourceLineNumbers, attrib); + break; + case "Language": + language = this.GetPerformanceCounterLanguage(sourceLineNumbers, attrib); + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + if (null == name) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name")); + } + + if (null == help) + { + this.Messaging.Write(UtilWarnings.RequiredAttributeForWindowsXP(sourceLineNumbers, element.Name.LocalName, "Help")); + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + + if (!this.Messaging.EncounteredError) + { + parsedPerformanceCounter = new ParsedPerformanceCounter(name, help, type, language); + } + + return parsedPerformanceCounter; + } + + /// + /// Gets the performance counter type. + /// + /// Source line information about the owner element. + /// The attribute containing the value to get. + /// Numeric representation of the language as per WinNT.h. + private System.Diagnostics.PerformanceCounterType GetPerformanceCounterType(SourceLineNumber sourceLineNumbers, XAttribute attribute) + { + var type = System.Diagnostics.PerformanceCounterType.NumberOfItems32; + if (String.Empty == attribute.Value) + { + this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName)); + } + else + { + switch (attribute.Value) + { + case "averageBase": + type = System.Diagnostics.PerformanceCounterType.AverageBase; + break; + case "averageCount64": + type = System.Diagnostics.PerformanceCounterType.AverageCount64; + break; + case "averageTimer32": + type = System.Diagnostics.PerformanceCounterType.AverageTimer32; + break; + case "counterDelta32": + type = System.Diagnostics.PerformanceCounterType.CounterDelta32; + break; + case "counterTimerInverse": + type = System.Diagnostics.PerformanceCounterType.CounterTimerInverse; + break; + case "sampleFraction": + type = System.Diagnostics.PerformanceCounterType.SampleFraction; + break; + case "timer100Ns": + type = System.Diagnostics.PerformanceCounterType.Timer100Ns; + break; + case "counterTimer": + type = System.Diagnostics.PerformanceCounterType.CounterTimer; + break; + case "rawFraction": + type = System.Diagnostics.PerformanceCounterType.RawFraction; + break; + case "timer100NsInverse": + type = System.Diagnostics.PerformanceCounterType.Timer100NsInverse; + break; + case "counterMultiTimer": + type = System.Diagnostics.PerformanceCounterType.CounterMultiTimer; + break; + case "counterMultiTimer100Ns": + type = System.Diagnostics.PerformanceCounterType.CounterMultiTimer100Ns; + break; + case "counterMultiTimerInverse": + type = System.Diagnostics.PerformanceCounterType.CounterMultiTimerInverse; + break; + case "counterMultiTimer100NsInverse": + type = System.Diagnostics.PerformanceCounterType.CounterMultiTimer100NsInverse; + break; + case "elapsedTime": + type = System.Diagnostics.PerformanceCounterType.ElapsedTime; + break; + case "sampleBase": + type = System.Diagnostics.PerformanceCounterType.SampleBase; + break; + case "rawBase": + type = System.Diagnostics.PerformanceCounterType.RawBase; + break; + case "counterMultiBase": + type = System.Diagnostics.PerformanceCounterType.CounterMultiBase; + break; + case "rateOfCountsPerSecond64": + type = System.Diagnostics.PerformanceCounterType.RateOfCountsPerSecond64; + break; + case "rateOfCountsPerSecond32": + type = System.Diagnostics.PerformanceCounterType.RateOfCountsPerSecond32; + break; + case "countPerTimeInterval64": + type = System.Diagnostics.PerformanceCounterType.CountPerTimeInterval64; + break; + case "countPerTimeInterval32": + type = System.Diagnostics.PerformanceCounterType.CountPerTimeInterval32; + break; + case "sampleCounter": + type = System.Diagnostics.PerformanceCounterType.SampleCounter; + break; + case "counterDelta64": + type = System.Diagnostics.PerformanceCounterType.CounterDelta64; + break; + case "numberOfItems64": + type = System.Diagnostics.PerformanceCounterType.NumberOfItems64; + break; + case "numberOfItems32": + type = System.Diagnostics.PerformanceCounterType.NumberOfItems32; + break; + case "numberOfItemsHEX64": + type = System.Diagnostics.PerformanceCounterType.NumberOfItemsHEX64; + break; + case "numberOfItemsHEX32": + type = System.Diagnostics.PerformanceCounterType.NumberOfItemsHEX32; + break; + default: + this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName)); + break; + } + } + + return type; + } + + /// + /// Parses a perf counter element. + /// + /// Element to parse. + /// Identifier of parent component. + /// Identifier of referenced file. + private void ParsePerfCounterElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string fileId) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + string name = null; + + this.Messaging.Write(UtilWarnings.DeprecatedPerfCounterElement(sourceLineNumbers)); + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Name": + name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + if (null == name) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name")); + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + + if (!this.Messaging.EncounteredError) + { + section.AddSymbol(new PerfmonSymbol(sourceLineNumbers) + { + ComponentRef = componentId, + File = $"[#{fileId}]", + Name = name, + }); + } + + this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigurePerfmonInstall", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); + this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigurePerfmonUninstall", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); + } + + + /// + /// Parses a perf manifest element. + /// + /// Element to parse. + /// Identifier of parent component. + /// Identifier of referenced file. + private void ParsePerfCounterManifestElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string fileId) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + string resourceFileDirectory = null; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "ResourceFileDirectory": + resourceFileDirectory = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + + if (!this.Messaging.EncounteredError) + { + section.AddSymbol(new PerfmonManifestSymbol(sourceLineNumbers) + { + ComponentRef = componentId, + File = $"[#{fileId}]", + ResourceFileDirectory = resourceFileDirectory, + }); + } + + this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigurePerfmonManifestRegister", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); + this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigurePerfmonManifestUnregister", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); + } + + /// + /// Parses a format files element. + /// + /// Element to parse. + /// Identifier of referenced file. + /// Flag to determine whether the component is 64-bit. + private void ParseFormatFileElement(Intermediate intermediate, IntermediateSection section, XElement element, string fileId, bool win64) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + string binaryId = null; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "BinaryRef": + binaryId = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + + if (null == binaryId) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "BinaryRef")); + } + + if (!this.Messaging.EncounteredError) + { + this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedFormatFiles", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); + + section.AddSymbol(new WixFormatFilesSymbol(sourceLineNumbers) + { + BinaryRef = binaryId, + FileRef = fileId, + }); + + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.Binary, binaryId); + } + } + + /// + /// Parses a event manifest element. + /// + /// Element to parse. + /// Identifier of parent component. + /// Identifier of referenced file. + private void ParseEventManifestElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string fileId) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + string messageFile = null; + string resourceFile = null; + string parameterFile = null; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "MessageFile": + messageFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "ResourceFile": + resourceFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "ParameterFile": + parameterFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + + if (!this.Messaging.EncounteredError) + { + section.AddSymbol(new EventManifestSymbol(sourceLineNumbers) + { + ComponentRef = componentId, + File = $"[#{fileId}]", + }); + + if (null != messageFile) + { + section.AddSymbol(new XmlFileSymbol(sourceLineNumbers, new Identifier(AccessModifier.Section, $"Config_{fileId}MessageFile")) + { + File = $"[#{fileId}]", + ElementPath = "/*/*/*/*[\\[]@messageFileName[\\]]", + Name = "messageFileName", + Value = messageFile, + Flags = 4 | 0x00001000, //bulk write | preserve modified date + ComponentRef = componentId, + }); + } + if (null != parameterFile) + { + section.AddSymbol(new XmlFileSymbol(sourceLineNumbers, new Identifier(AccessModifier.Section, $"Config_{fileId}ParameterFile")) + { + File = $"[#{fileId}]", + ElementPath = "/*/*/*/*[\\[]@parameterFileName[\\]]", + Name = "parameterFileName", + Value = parameterFile, + Flags = 4 | 0x00001000, //bulk write | preserve modified date + ComponentRef = componentId, + }); + } + if (null != resourceFile) + { + section.AddSymbol(new XmlFileSymbol(sourceLineNumbers, new Identifier(AccessModifier.Section, $"Config_{fileId}ResourceFile")) + { + File = $"[#{fileId}]", + ElementPath = "/*/*/*/*[\\[]@resourceFileName[\\]]", + Name = "resourceFileName", + Value = resourceFile, + Flags = 4 | 0x00001000, //bulk write | preserve modified date + ComponentRef = componentId, + }); + } + + } + + this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureEventManifestRegister", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); + this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureEventManifestUnregister", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); + + if (null != messageFile || null != parameterFile || null != resourceFile) + { + this.AddReferenceToSchedXmlFile(sourceLineNumbers, section); + } + } + + /// + /// Parses a PermissionEx element. + /// + /// Element to parse. + /// Identifier of object to be secured. + /// Identifier of component, used to determine install state. + /// Flag to determine whether the component is 64-bit. + /// Name of table that contains objectId. + private void ParsePermissionExElement(Intermediate intermediate, IntermediateSection section, XElement element, string objectId, string componentId, bool win64, string tableName) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + var bits = new BitArray(32); + string domain = null; + string[] specialPermissions = null; + string user = null; + var attributes = WixPermissionExAttributes.Inheritable; // default to inheritable. + + var permissionType = PermissionType.SecureObjects; + + switch (tableName) + { + case "CreateFolder": + specialPermissions = UtilConstants.FolderPermissions; + break; + case "File": + specialPermissions = UtilConstants.FilePermissions; + break; + case "Registry": + specialPermissions = UtilConstants.RegistryPermissions; + if (String.IsNullOrEmpty(objectId)) + { + this.Messaging.Write(UtilErrors.InvalidRegistryObject(sourceLineNumbers, element.Parent.Name.LocalName)); + } + break; + case "ServiceInstall": + specialPermissions = UtilConstants.ServicePermissions; + permissionType = PermissionType.SecureObjects; + break; + default: + this.ParseHelper.UnexpectedElement(element.Parent, element); + break; + } + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Domain": + if (PermissionType.FileSharePermissions == permissionType) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, element.Parent.Name.LocalName)); + } + domain = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Inheritable": + if (this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) == YesNoType.No) + { + attributes &= ~WixPermissionExAttributes.Inheritable; + } + break; + case "User": + user = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + default: + var attribValue = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib); + if (!this.TrySetBitFromName(UtilConstants.StandardPermissions, attrib.Name.LocalName, attribValue, bits, 16)) + { + if (!this.TrySetBitFromName(UtilConstants.GenericPermissions, attrib.Name.LocalName, attribValue, bits, 28)) + { + if (!this.TrySetBitFromName(specialPermissions, attrib.Name.LocalName, attribValue, bits, 0)) + { + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + } + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + var permission = this.CreateIntegerFromBitArray(bits); + + if (null == user) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "User")); + } + + if (Int32.MinValue == permission) // just GENERIC_READ, which is MSI_NULL + { + this.Messaging.Write(ErrorMessages.GenericReadNotAllowed(sourceLineNumbers)); + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + + if (!this.Messaging.EncounteredError) + { + this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedSecureObjects", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); + + var id = this.ParseHelper.CreateIdentifier("sec", objectId, tableName, domain, user); + section.AddSymbol(new SecureObjectsSymbol(sourceLineNumbers, id) + { + SecureObject = objectId, + Table = tableName, + Domain = domain, + User = user, + Attributes = attributes, + Permission = permission, + ComponentRef = componentId, + }); + } + } + + /// + /// Parses a ProductSearch element. + /// + /// Element to parse. + private void ParseProductSearchElement(Intermediate intermediate, IntermediateSection section, XElement element) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + Identifier id = null; + string variable = null; + string condition = null; + string after = null; + string productCode = null; + string upgradeCode = null; + var attributes = WixProductSearchAttributes.Version; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + case "Variable": + case "Condition": + case "After": + this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after); + break; + case "ProductCode": + productCode = this.ParseHelper.GetAttributeGuidValue(sourceLineNumbers, attrib, false); + break; + case "UpgradeCode": + upgradeCode = this.ParseHelper.GetAttributeGuidValue(sourceLineNumbers, attrib, false); + break; + case "Result": + var result = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + switch (result) + { + case "version": + attributes = WixProductSearchAttributes.Version; + break; + case "language": + attributes = WixProductSearchAttributes.Language; + break; + case "state": + attributes = WixProductSearchAttributes.State; + break; + case "assignment": + attributes = WixProductSearchAttributes.Assignment; + break; + default: + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, result, "version", "language", "state", "assignment")); + break; + } + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + if (null == upgradeCode && null == productCode) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "ProductCode", "UpgradeCode", true)); + } + + if (null != upgradeCode && null != productCode) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "UpgradeCode", "ProductCode")); + } + + if (null == id) + { + id = this.ParseHelper.CreateIdentifier("wps", variable, condition, after, (productCode == null ? upgradeCode : productCode), attributes.ToString()); + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + + this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, null); + + if (!this.Messaging.EncounteredError) + { + // set an additional flag if this is an upgrade code + if (null != upgradeCode) + { + attributes |= WixProductSearchAttributes.UpgradeCode; + } + + section.AddSymbol(new WixProductSearchSymbol(sourceLineNumbers, id) + { + Guid = productCode ?? upgradeCode, + Attributes = attributes, + }); + } + } + + /// + /// Parses a RegistrySearch element. + /// + /// Element to parse. + private void ParseRegistrySearchElement(Intermediate intermediate, IntermediateSection section, XElement element) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + Identifier id = null; + string variable = null; + string condition = null; + string after = null; + RegistryRootType? root = null; + string key = null; + string value = null; + var expand = YesNoType.NotSet; + var win64 = this.Context.IsCurrentPlatform64Bit; + var attributes = WixRegistrySearchAttributes.Raw | WixRegistrySearchAttributes.WantValue; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + case "Variable": + case "Condition": + case "After": + this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after); + break; + case "Bitness": + var bitnessValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + switch (bitnessValue) + { + case "always32": + win64 = false; + break; + case "always64": + win64 = true; + break; + case "default": + case "": + break; + default: + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Name.LocalName, attrib.Name.LocalName, bitnessValue, "default", "always32", "always64")); + break; + } + break; + case "Root": + root = this.ParseHelper.GetAttributeRegistryRootValue(sourceLineNumbers, attrib, false); + break; + case "Key": + key = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Value": + value = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "ExpandEnvironmentVariables": + expand = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib); + break; + case "Format": + string format = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + switch (format) + { + case "raw": + attributes |= WixRegistrySearchAttributes.Raw; + break; + case "compatible": + attributes |= WixRegistrySearchAttributes.Compatible; + break; + default: + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, format, "raw", "compatible")); + break; + } + break; + case "Result": + var result = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + switch (result) + { + case "exists": + attributes |= WixRegistrySearchAttributes.WantExists; + break; + case "value": + attributes |= WixRegistrySearchAttributes.WantValue; + break; + default: + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, result, "exists", "value")); + break; + } + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + if (!root.HasValue) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Root")); + } + + if (null == key) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Key")); + } + + if (null == id) + { + id = this.ParseHelper.CreateIdentifier("wrs", variable, condition, after, root.ToString(), key, value, attributes.ToString()); + } + + if (expand == YesNoType.Yes) + { + if (0 != (attributes & WixRegistrySearchAttributes.WantExists)) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "ExpandEnvironmentVariables", expand.ToString(), "Result", "exists")); + } + + attributes |= WixRegistrySearchAttributes.ExpandEnvironmentVariables; + } + + if (win64) + { + attributes |= WixRegistrySearchAttributes.Win64; + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + + this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, null); + + if (!this.Messaging.EncounteredError) + { + section.AddSymbol(new WixRegistrySearchSymbol(sourceLineNumbers, id) + { + Root = root.Value, + Key = key, + Value = value, + Attributes = attributes, + }); + } + } + + /// + /// Parses a RemoveFolderEx element. + /// + /// Element to parse. + /// Identifier of parent component. + private void ParseRemoveFolderExElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + Identifier id = null; + var mode = WixRemoveFolderExInstallMode.Uninstall; + string property = null; + string condition = null; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Condition": + condition = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Id": + id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); + break; + case "On": + var onValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + if (onValue.Length == 0) + { + } + else + { + switch (onValue) + { + case "install": + mode = WixRemoveFolderExInstallMode.Install; + break; + case "uninstall": + mode = WixRemoveFolderExInstallMode.Uninstall; + break; + case "both": + mode = WixRemoveFolderExInstallMode.Both; + break; + default: + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "On", onValue, "install", "uninstall", "both")); + break; + } + } + break; + case "Property": + property = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + if (String.IsNullOrEmpty(property)) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Property")); + } + + if (id == null) + { + id = this.ParseHelper.CreateIdentifier("wrf", componentId, property, mode.ToString()); + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + + if (!this.Messaging.EncounteredError) + { + this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4RemoveFoldersEx", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); + + section.AddSymbol(new WixRemoveFolderExSymbol(sourceLineNumbers, id) + { + ComponentRef = componentId, + Property = property, + InstallMode = mode, + Condition = condition + }); + + this.ParseHelper.EnsureTable(section, sourceLineNumbers, "RemoveFile"); + } + } + + /// + /// Parses a RemoveRegistryKeyEx element. + /// + /// Element to parse. + /// Identifier of parent component. + private void ParseRemoveRegistryKeyExElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + Identifier id = null; + var mode = WixRemoveRegistryKeyExInstallMode.Uninstall; + string condition = null; + RegistryRootType? root = null; + string key = null; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Condition": + condition = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Id": + id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); + break; + case "On": + var actionValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + switch (actionValue) + { + case "": + break; + case "install": + mode = WixRemoveRegistryKeyExInstallMode.Install; + break; + case "uninstall": + mode = WixRemoveRegistryKeyExInstallMode.Uninstall; + break; + default: + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "On", actionValue, "install", "uninstall")); + break; + } + break; + case "Root": + root = this.ParseHelper.GetAttributeRegistryRootValue(sourceLineNumbers, attrib, false); + break; + case "Key": + key = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + if (!root.HasValue) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Root")); + } + + if (key == null) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Key")); + } + + if (id == null) + { + id = this.ParseHelper.CreateIdentifier("rrx", componentId, condition, root.ToString(), key, mode.ToString()); + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + + if (!this.Messaging.EncounteredError) + { + this.ParseHelper.EnsureTable(section, sourceLineNumbers, "Registry"); + this.ParseHelper.EnsureTable(section, sourceLineNumbers, "RemoveRegistry"); + this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4RemoveRegistryKeysEx", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); + + section.AddSymbol(new WixRemoveRegistryKeyExSymbol(sourceLineNumbers, id) + { + ComponentRef = componentId, + Root = root.Value, + Key = key, + InstallMode = mode, + Condition = condition + }); + } + } + + /// + /// Parses a RestartResource element. + /// + /// The element to parse. + /// The identity of the parent component. + private void ParseRestartResourceElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + Identifier id = null; + string resource = null; + WixRestartResourceAttributes? attributes = null; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); + break; + + case "Path": + resource = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + attributes = WixRestartResourceAttributes.Filename; + break; + + case "ProcessName": + resource = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + attributes = WixRestartResourceAttributes.ProcessName; + break; + + case "ServiceName": + resource = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + attributes = WixRestartResourceAttributes.ServiceName; + break; + + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + // Validate the attribute. + if (id == null) + { + id = this.ParseHelper.CreateIdentifier("wrr", componentId, resource, attributes.ToString()); + } + + if (!attributes.HasValue) + { + this.Messaging.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, element.Name.LocalName, "Path", "ProcessName", "ServiceName")); + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + + if (!this.Messaging.EncounteredError) + { + this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4RegisterRestartResources", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); + + section.AddSymbol(new WixRestartResourceSymbol(sourceLineNumbers, id) + { + ComponentRef = componentId, + Resource = resource, + Attributes = attributes, + }); + } + } + + /// + /// Parses a service configuration element. + /// + /// Element to parse. + /// Identifier of parent component. + /// Name of parent element. + /// Optional name of service + private void ParseServiceConfigElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string parentTableName, string parentTableServiceName) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + string firstFailureActionType = null; + var newService = false; + string programCommandLine = null; + string rebootMessage = null; + var resetPeriod = CompilerConstants.IntegerNotSet; + var restartServiceDelay = CompilerConstants.IntegerNotSet; + string secondFailureActionType = null; + string serviceName = null; + string thirdFailureActionType = null; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "FirstFailureActionType": + firstFailureActionType = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "ProgramCommandLine": + programCommandLine = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "RebootMessage": + rebootMessage = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "ResetPeriodInDays": + resetPeriod = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); + break; + case "RestartServiceDelayInSeconds": + restartServiceDelay = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); + break; + case "SecondFailureActionType": + secondFailureActionType = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "ServiceName": + serviceName = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "ThirdFailureActionType": + thirdFailureActionType = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + // if this element is a child of ServiceInstall then ignore the service name provided. + if ("ServiceInstall" == parentTableName) + { + // TODO: the ServiceName attribute should not be allowed in this case (the overwriting behavior may confuse users) + serviceName = parentTableServiceName; + newService = true; + } + else + { + // not a child of ServiceInstall, so ServiceName must have been provided + if (null == serviceName) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "ServiceName")); + } + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + + if (!this.Messaging.EncounteredError) + { + this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedServiceConfig", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); + + section.AddSymbol(new ServiceConfigSymbol(sourceLineNumbers) + { + ServiceName = serviceName, + ComponentRef = componentId, + NewService = newService ? 1 : 0, + FirstFailureActionType = firstFailureActionType, + SecondFailureActionType = secondFailureActionType, + ThirdFailureActionType = thirdFailureActionType, + ResetPeriodInDays = resetPeriod, + RestartServiceDelayInSeconds = restartServiceDelay, + ProgramCommandLine = programCommandLine, + RebootMessage = rebootMessage, + }); + } + } + + /// + /// Parses a touch file element. + /// + /// Element to parse. + /// Identifier of parent component. + /// Indicates whether the path is a 64-bit path. + private void ParseTouchFileElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, bool win64) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + Identifier id = null; + string path = null; + var onInstall = YesNoType.NotSet; + var onReinstall = YesNoType.NotSet; + var onUninstall = YesNoType.NotSet; + var nonvital = YesNoType.NotSet; + int attributes = 0; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); + break; + case "Path": + path = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "OnInstall": + onInstall = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib); + break; + case "OnReinstall": + onReinstall = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib); + break; + case "OnUninstall": + onUninstall = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib); + break; + case "Nonvital": + nonvital = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib); + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + if (null == path) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Path")); + } + + // If none of the scheduling actions are set, default to touching on install and reinstall. + if (YesNoType.NotSet == onInstall && YesNoType.NotSet == onReinstall && YesNoType.NotSet == onUninstall) + { + onInstall = YesNoType.Yes; + onReinstall = YesNoType.Yes; + } + + attributes |= YesNoType.Yes == onInstall ? 0x1 : 0; + attributes |= YesNoType.Yes == onReinstall ? 0x2 : 0; + attributes |= YesNoType.Yes == onUninstall ? 0x4 : 0; + attributes |= win64 ? 0x10 : 0; + attributes |= YesNoType.Yes == nonvital ? 0 : 0x20; + + if (null == id) + { + id = this.ParseHelper.CreateIdentifier("tf", path, attributes.ToString()); + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + + if (!this.Messaging.EncounteredError) + { + section.AddSymbol(new WixTouchFileSymbol(sourceLineNumbers, id) + { + ComponentRef = componentId, + Path = path, + Attributes = attributes, + }); + + this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4TouchFileDuringInstall", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); + } + } + + /// + /// Parses an user element. + /// + /// Element to parse. + /// Optional identifier of parent component. + private void ParseUserElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + Identifier id = null; + int attributes = 0; + string domain = null; + string name = null; + string password = null; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); + break; + case "CanNotChangePassword": + if (null == componentId) + { + this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); + } + + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= UserPasswdCantChange; + } + break; + case "CreateUser": + if (null == componentId) + { + this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); + } + + if (YesNoType.No == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= UserDontCreateUser; + } + break; + case "Disabled": + if (null == componentId) + { + this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); + } + + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= UserDisableAccount; + } + break; + case "Domain": + domain = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "FailIfExists": + if (null == componentId) + { + this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); + } + + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= UserFailIfExists; + } + break; + case "LogonAsService": + if (null == componentId) + { + this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); + } + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= UserLogonAsService; + } + break; + case "LogonAsBatchJob": + if (null == componentId) + { + this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); + } + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= UserLogonAsBatchJob; + } + break; + case "Name": + name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Password": + password = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "PasswordExpired": + if (null == componentId) + { + this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); + } + + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= UserPasswdChangeReqdOnLogin; + } + break; + case "PasswordNeverExpires": + if (null == componentId) + { + this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); + } + + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= UserDontExpirePasswrd; + } + break; + case "RemoveOnUninstall": + if (null == componentId) + { + this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); + } + + if (YesNoType.No == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= UserDontRemoveOnUninstall; + } + break; + case "UpdateIfExists": + if (null == componentId) + { + this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); + } + + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= UserUpdateIfExists; + } + break; + case "Vital": + if (null == componentId) + { + this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); + } + + if (YesNoType.No == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + attributes |= UserNonVital; + } + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + if (null == id) + { + id = this.ParseHelper.CreateIdentifier("usr", componentId, name); + } + + if (null == name) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name")); + } + + foreach (var child in element.Elements()) + { + if (this.Namespace == child.Name.Namespace) + { + switch (child.Name.LocalName) + { + case "GroupRef": + if (null == componentId) + { + var childSourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(child); + this.Messaging.Write(UtilErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName)); + } + + this.ParseGroupRefElement(intermediate, section, child, id.Id); + break; + default: + this.ParseHelper.UnexpectedElement(element, child); + break; + } + } + else + { + this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child); + } + } + + if (null != componentId) + { + this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureUsers", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); + } + + if (!this.Messaging.EncounteredError) + { + section.AddSymbol(new UserSymbol(sourceLineNumbers, id) + { + ComponentRef = componentId, + Name = name, + Domain = domain, + Password = password, + Attributes = attributes, + }); + } + } + + /// + /// Parses a XmlFile element. + /// + /// Element to parse. + /// Identifier of parent component. + private void ParseXmlFileElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + Identifier id = null; + string file = null; + string elementPath = null; + string name = null; + string value = null; + int sequence = -1; + int flags = 0; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Action": + var actionValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + switch (actionValue) + { + case "createElement": + flags |= 0x00000001; // XMLFILE_CREATE_ELEMENT + break; + case "deleteValue": + flags |= 0x00000002; // XMLFILE_DELETE_VALUE + break; + case "bulkSetValue": + flags |= 0x00000004; // XMLFILE_BULKWRITE_VALUE + break; + case "setValue": + // no flag for set value since it's the default + break; + default: + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Action", actionValue, "createElement", "deleteValue", "setValue", "bulkSetValue")); + break; + } + break; + case "SelectionLanguage": + string selectionLanguage = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + switch (selectionLanguage) + { + case "XPath": + flags |= 0x00000100; // XMLFILE_USE_XPATH + break; + case "XSLPattern": + // no flag for since it's the default + break; + default: + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "SelectionLanguage", selectionLanguage, "XPath", "XSLPattern")); + break; + } + break; + case "Id": + id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); + break; + case "File": + file = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "ElementPath": + elementPath = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Name": + name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Permanent": + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + flags |= 0x00010000; // XMLFILE_DONT_UNINSTALL + } + break; + case "Sequence": + sequence = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, Int16.MaxValue); + break; + case "Value": + value = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "PreserveModifiedDate": + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + flags |= 0x00001000; // XMLFILE_PRESERVE_MODIFIED + } + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + if (null == id) + { + id = this.ParseHelper.CreateIdentifier("uxf", componentId, file, elementPath, name); + } + + if (null == file) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "File")); + } + + if (null == elementPath) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "ElementPath")); + } + + if ((0x00000001 /*XMLFILE_CREATE_ELEMENT*/ & flags) != 0 && null == name) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, element.Name.LocalName, "Action", "Name")); + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + + if (!this.Messaging.EncounteredError) + { + var symbol = section.AddSymbol(new XmlFileSymbol(sourceLineNumbers, id) + { + File = file, + ElementPath = elementPath, + Name = name, + Value = value, + Flags = flags, + ComponentRef = componentId, + }); + if (-1 != sequence) + { + symbol.Sequence = sequence; + } + } + + this.AddReferenceToSchedXmlFile(sourceLineNumbers, section); + } + + /// + /// Parses a XmlConfig element. + /// + /// Element to parse. + /// Identifier of parent component. + /// Whether or not the element is nested. + private void ParseXmlConfigElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, bool nested) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + Identifier id = null; + string elementId = null; + string elementPath = null; + int flags = 0; + string file = null; + string name = null; + var sequence = CompilerConstants.IntegerNotSet; + string value = null; + string verifyPath = null; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); + break; + case "Action": + if (nested) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, element.Parent.Name.LocalName)); + } + else + { + string actionValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + switch (actionValue) + { + case "create": + flags |= 0x10; // XMLCONFIG_CREATE + break; + case "delete": + flags |= 0x20; // XMLCONFIG_DELETE + break; + default: + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, actionValue, "create", "delete")); + break; + } + } + break; + case "ElementId": + elementId = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "ElementPath": + elementPath = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "File": + file = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Name": + name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Node": + if (nested) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, element.Parent.Name.LocalName)); + } + else + { + var nodeValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + switch (nodeValue) + { + case "element": + flags |= 0x1; // XMLCONFIG_ELEMENT + break; + case "value": + flags |= 0x2; // XMLCONFIG_VALUE + break; + case "document": + flags |= 0x4; // XMLCONFIG_DOCUMENT + break; + default: + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, nodeValue, "element", "value", "document")); + break; + } + } + break; + case "On": + if (nested) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, element.Parent.Name.LocalName)); + } + else + { + var onValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + switch (onValue) + { + case "install": + flags |= 0x100; // XMLCONFIG_INSTALL + break; + case "uninstall": + flags |= 0x200; // XMLCONFIG_UNINSTALL + break; + default: + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, onValue, "install", "uninstall")); + break; + } + } + break; + case "PreserveModifiedDate": + if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) + { + flags |= 0x00001000; // XMLCONFIG_PRESERVE_MODIFIED + } + break; + case "Sequence": + sequence = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, Int16.MaxValue); + break; + case "Value": + value = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "VerifyPath": + verifyPath = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + if (null == id) + { + id = this.ParseHelper.CreateIdentifier("uxc", componentId, file, elementId, elementPath); + } + + if (null == file) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "File")); + } + + if (null == elementId && null == elementPath) + { + this.Messaging.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, element.Name.LocalName, "ElementId", "ElementPath")); + } + else if (null != elementId) + { + if (null != elementPath) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "ElementId", "ElementPath")); + } + + if (0 != flags) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, "ElementId", "Action", "Node", "On")); + } + + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, UtilSymbolDefinitions.XmlConfig, elementId); + } + + // find unexpected child elements + foreach (var child in element.Elements()) + { + if (this.Namespace == child.Name.Namespace) + { + switch (child.Name.LocalName) + { + case "XmlConfig": + if (nested) + { + this.Messaging.Write(ErrorMessages.UnexpectedElement(sourceLineNumbers, element.Name.LocalName, child.Name.LocalName)); + } + else + { + this.ParseXmlConfigElement(intermediate, section, child, componentId, true); + } + break; + default: + this.ParseHelper.UnexpectedElement(element, child); + break; + } + } + else + { + this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child); + } + } + + if (!this.Messaging.EncounteredError) + { + var symbol = section.AddSymbol(new XmlConfigSymbol(sourceLineNumbers, id) + { + File = file, + ElementId = elementId, + ElementPath = elementPath, + VerifyPath = verifyPath, + Name = name, + Value = value, + Flags = flags, + ComponentRef = componentId, + }); + + if (CompilerConstants.IntegerNotSet != sequence) + { + symbol.Sequence = sequence; + } + } + + this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedXmlConfig", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); + } + + /// + /// Match evaluator to escape properties in a string. + /// + private string EscapeProperties(Match match) + { + string escape = null; + switch (match.Value) + { + case "[": + escape = @"[\[]"; + break; + case "]": + escape = @"[\]]"; + break; + } + + return escape; + } + + private int CreateIntegerFromBitArray(BitArray bits) + { + if (32 != bits.Length) + { + 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"); + } + + var intArray = new int[1]; + bits.CopyTo(intArray, 0); + + return intArray[0]; + } + + private bool TrySetBitFromName(string[] attributeNames, string attributeName, YesNoType attributeValue, BitArray bits, int offset) + { + for (var i = 0; i < attributeNames.Length; i++) + { + if (attributeName.Equals(attributeNames[i], StringComparison.Ordinal)) + { + bits.Set(i + offset, YesNoType.Yes == attributeValue); + return true; + } + } + + return false; + } + + private void AddReferenceToSchedXmlFile(SourceLineNumber sourceLineNumbers, IntermediateSection section) + { + this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedXmlFile", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); + } + + /// + /// Private class that stores the data from a parsed PerformanceCounter element. + /// + private class ParsedPerformanceCounter + { + internal ParsedPerformanceCounter(string name, string help, System.Diagnostics.PerformanceCounterType type, int language) + { + this.Name = name; + this.Help = help; + this.Type = (int)type; + this.Language = language.ToString("D3", CultureInfo.InvariantCulture); + } + + internal string Name { get; } + + internal string Help { get; } + + internal int Type { get; } + + internal string Language { get; } + } + } +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + /// + /// Constants used by Utility Extension. + /// + internal static class UtilConstants + { + internal static readonly string[] FilePermissions = { "Read", "Write", "Append", "ReadExtendedAttributes", "WriteExtendedAttributes", "Execute", null, "ReadAttributes", "WriteAttributes" }; + internal static readonly string[] FolderPermissions = { "Read", "CreateFile", "CreateChild", "ReadExtendedAttributes", "WriteExtendedAttributes", "Traverse", "DeleteChild", "ReadAttributes", "WriteAttributes" }; + internal static readonly string[] GenericPermissions = { "GenericAll", "GenericExecute", "GenericWrite", "GenericRead" }; + internal static readonly string[] RegistryPermissions = { "Read", "Write", "CreateSubkeys", "EnumerateSubkeys", "Notify", "CreateLink" }; + internal static readonly string[] ServicePermissions = { "ServiceQueryConfig", "ServiceChangeConfig", "ServiceQueryStatus", "ServiceEnumerateDependents", "ServiceStart", "ServiceStop", "ServicePauseContinue", "ServiceInterrogate", "ServiceUserDefinedControl" }; + internal static readonly string[] StandardPermissions = { "Delete", "ReadPermission", "ChangePermission", "TakeOwnership", "Synchronize" }; + } +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Extensions +{ +#if TODO_CONSIDER_DECOMPILER + using System; + using System.IO; + using System.Text; + using System.Collections; + using System.Diagnostics; + using System.Globalization; + + using Util = WixToolset.Extensions.Serialize.Util; + using WixToolset.Data; + using WixToolset.Extensibility; + using Wix = WixToolset.Data.Serialize; + + /// + /// The decompiler for the WiX Toolset Utility Extension. + /// + public sealed class UtilDecompiler : DecompilerExtension + { + /// + /// Creates a decompiler for Utility Extension. + /// + public UtilDecompiler() + { + this.TableDefinitions = UtilExtensionData.GetExtensionTableDefinitions(); + } + + /// + /// Get the extensions library to be removed. + /// + /// Table definitions for library. + /// Library to remove from decompiled output. + public override Library GetLibraryToRemove(TableDefinitionCollection tableDefinitions) + { + return UtilExtensionData.GetExtensionLibrary(tableDefinitions); + } + + /// + /// Called at the beginning of the decompilation of a database. + /// + /// The collection of all tables. + public override void Initialize(TableIndexedCollection tables) + { + this.CleanupSecureCustomProperties(tables); + this.CleanupInternetShortcutRemoveFileTables(tables); + } + + /// + /// Decompile the SecureCustomProperties field to PropertyRefs for known extension properties. + /// + /// + /// If we've referenced any of the suite or directory properties, add + /// a PropertyRef to refer to the Property (and associated custom action) + /// from the extension's library. Then remove the property from + /// SecureCustomExtensions property so later decompilation won't create + /// new Property elements. + /// + /// The collection of all tables. + private void CleanupSecureCustomProperties(TableIndexedCollection tables) + { + Table propertyTable = tables["Property"]; + + if (null != propertyTable) + { + foreach (Row row in propertyTable.Rows) + { + if ("SecureCustomProperties" == row[0].ToString()) + { + StringBuilder remainingProperties = new StringBuilder(); + string[] secureCustomProperties = row[1].ToString().Split(';'); + foreach (string property in secureCustomProperties) + { + if (property.StartsWith("WIX_SUITE_", StringComparison.Ordinal) || property.StartsWith("WIX_DIR_", StringComparison.Ordinal) + || property.StartsWith("WIX_ACCOUNT_", StringComparison.Ordinal)) + { + Wix.PropertyRef propertyRef = new Wix.PropertyRef(); + propertyRef.Id = property; + this.Core.RootElement.AddChild(propertyRef); + } + else + { + if (0 < remainingProperties.Length) + { + remainingProperties.Append(";"); + } + remainingProperties.Append(property); + } + } + + row[1] = remainingProperties.ToString(); + break; + } + } + } + } + + /// + /// Remove RemoveFile rows that the InternetShortcut compiler extension adds for us. + /// + /// The collection of all tables. + private void CleanupInternetShortcutRemoveFileTables(TableIndexedCollection tables) + { + // index the WixInternetShortcut table + Table wixInternetShortcutTable = tables["WixInternetShortcut"]; + Hashtable wixInternetShortcuts = new Hashtable(); + if (null != wixInternetShortcutTable) + { + foreach (Row row in wixInternetShortcutTable.Rows) + { + wixInternetShortcuts.Add(row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), row); + } + } + + // remove the RemoveFile rows with primary keys that match the WixInternetShortcut table's + Table removeFileTable = tables["RemoveFile"]; + if (null != removeFileTable) + { + for (int i = removeFileTable.Rows.Count - 1; 0 <= i; i--) + { + if (null != wixInternetShortcuts[removeFileTable.Rows[i][0]]) + { + removeFileTable.Rows.RemoveAt(i); + } + } + } + } + + /// + /// Decompiles an extension table. + /// + /// The table to decompile. + public override void DecompileTable(Table table) + { + switch (table.Name) + { + case "WixCloseApplication": + this.DecompileWixCloseApplicationTable(table); + break; + case "WixRemoveFolderEx": + this.DecompileWixRemoveFolderExTable(table); + break; + case "WixRestartResource": + this.DecompileWixRestartResourceTable(table); + break; + case "FileShare": + this.DecompileFileShareTable(table); + break; + case "FileSharePermissions": + this.DecompileFileSharePermissionsTable(table); + break; + case "WixInternetShortcut": + this.DecompileWixInternetShortcutTable(table); + break; + case "Group": + this.DecompileGroupTable(table); + break; + case "Perfmon": + this.DecompilePerfmonTable(table); + break; + case "PerfmonManifest": + this.DecompilePerfmonManifestTable(table); + break; + case "EventManifest": + this.DecompileEventManifestTable(table); + break; + case "SecureObjects": + this.DecompileSecureObjectsTable(table); + break; + case "ServiceConfig": + this.DecompileServiceConfigTable(table); + break; + case "User": + this.DecompileUserTable(table); + break; + case "UserGroup": + this.DecompileUserGroupTable(table); + break; + case "XmlConfig": + this.DecompileXmlConfigTable(table); + break; + case "XmlFile": + // XmlFile decompilation has been moved to FinalizeXmlFileTable function + break; + default: + base.DecompileTable(table); + break; + } + } + + /// + /// Finalize decompilation. + /// + /// The collection of all tables. + public override void Finish(TableIndexedCollection tables) + { + this.FinalizePerfmonTable(tables); + this.FinalizePerfmonManifestTable(tables); + this.FinalizeSecureObjectsTable(tables); + this.FinalizeServiceConfigTable(tables); + this.FinalizeXmlConfigTable(tables); + this.FinalizeXmlFileTable(tables); + this.FinalizeEventManifestTable(tables); + } + + /// + /// Decompile the WixCloseApplication table. + /// + /// The table to decompile. + private void DecompileWixCloseApplicationTable(Table table) + { + foreach (Row row in table.Rows) + { + Util.CloseApplication closeApplication = new Util.CloseApplication(); + + closeApplication.Id = (string)row[0]; + + closeApplication.Target = (string)row[1]; + + if (null != row[2]) + { + closeApplication.Description = (string)row[2]; + } + + if (null != row[3]) + { + closeApplication.Content = (string)row[3]; + } + + // set defaults + closeApplication.CloseMessage = Util.YesNoType.no; + closeApplication.RebootPrompt = Util.YesNoType.yes; + closeApplication.ElevatedCloseMessage = Util.YesNoType.no; + + if (null != row[4]) + { + int attribute = (int)row[4]; + + closeApplication.CloseMessage = (0x1 == (attribute & 0x1)) ? Util.YesNoType.yes : Util.YesNoType.no; + closeApplication.RebootPrompt = (0x2 == (attribute & 0x2)) ? Util.YesNoType.yes : Util.YesNoType.no; + closeApplication.ElevatedCloseMessage = (0x4 == (attribute & 0x4)) ? Util.YesNoType.yes : Util.YesNoType.no; + } + + if (null != row[5]) + { + closeApplication.Sequence = (int)row[5]; + } + + if (null != row[6]) + { + closeApplication.Property = (string)row[6]; + } + + this.Core.RootElement.AddChild(closeApplication); + } + } + + /// + /// Decompile the WixRemoveFolderEx table. + /// + /// The table to decompile. + private void DecompileWixRemoveFolderExTable(Table table) + { + foreach (Row row in table.Rows) + { + // Set the Id even if auto-generated previously. + Util.RemoveFolderEx removeFolder = new Util.RemoveFolderEx(); + removeFolder.Id = (string)row[0]; + removeFolder.Property = (string)row[2]; + + int installMode = (int)row[3]; + switch ((UtilCompiler.WixRemoveFolderExOn)installMode) + { + case UtilCompiler.WixRemoveFolderExOn.Install: + removeFolder.On = Util.RemoveFolderEx.OnType.install; + break; + + case UtilCompiler.WixRemoveFolderExOn.Uninstall: + removeFolder.On = Util.RemoveFolderEx.OnType.uninstall; + break; + + case UtilCompiler.WixRemoveFolderExOn.Both: + removeFolder.On = Util.RemoveFolderEx.OnType.both; + break; + + default: + this.Core.OnMessage(WixWarnings.UnrepresentableColumnValue(row.SourceLineNumbers, table.Name, "InstallMode", installMode)); + break; + } + + // Add to the appropriate Component or section element. + string componentId = (string)row[1]; + Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", componentId); + if (null != component) + { + component.AddChild(removeFolder); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", componentId, "Component")); + } + } + } + + /// + /// Decompile the WixRestartResource table. + /// + /// The table to decompile. + private void DecompileWixRestartResourceTable(Table table) + { + foreach (Row row in table.Rows) + { + // Set the Id even if auto-generated previously. + Util.RestartResource restartResource = new Util.RestartResource(); + restartResource.Id = (string)row[0]; + + // Determine the resource type and set accordingly. + string resource = (string)row[2]; + int attributes = (int)row[3]; + UtilCompiler.WixRestartResourceAttributes type = (UtilCompiler.WixRestartResourceAttributes)(attributes & (int)UtilCompiler.WixRestartResourceAttributes.TypeMask); + + switch (type) + { + case UtilCompiler.WixRestartResourceAttributes.Filename: + restartResource.Path = resource; + break; + + case UtilCompiler.WixRestartResourceAttributes.ProcessName: + restartResource.ProcessName = resource; + break; + + case UtilCompiler.WixRestartResourceAttributes.ServiceName: + restartResource.ServiceName = resource; + break; + + default: + this.Core.OnMessage(WixWarnings.UnrepresentableColumnValue(row.SourceLineNumbers, table.Name, "Attributes", attributes)); + break; + } + + // Add to the appropriate Component or section element. + string componentId = (string)row[1]; + if (!String.IsNullOrEmpty(componentId)) + { + Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", componentId); + if (null != component) + { + component.AddChild(restartResource); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", componentId, "Component")); + } + } + else + { + this.Core.RootElement.AddChild(restartResource); + } + } + } + + /// + /// Decompile the FileShare table. + /// + /// The table to decompile. + private void DecompileFileShareTable(Table table) + { + foreach (Row row in table.Rows) + { + Util.FileShare fileShare = new Util.FileShare(); + + fileShare.Id = (string)row[0]; + + fileShare.Name = (string)row[1]; + + if (null != row[3]) + { + fileShare.Description = (string)row[3]; + } + + // the Directory_ column is set by the parent Component + + // the User_ and Permissions columns are deprecated + + Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[2]); + if (null != component) + { + component.AddChild(fileShare); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[2], "Component")); + } + this.Core.IndexElement(row, fileShare); + } + } + + /// + /// Decompile the FileSharePermissions table. + /// + /// The table to decompile. + private void DecompileFileSharePermissionsTable(Table table) + { + foreach (Row row in table.Rows) + { + Util.FileSharePermission fileSharePermission = new Util.FileSharePermission(); + + fileSharePermission.User = (string)row[1]; + + string[] specialPermissions = UtilConstants.FolderPermissions; + int permissions = (int)row[2]; + for (int i = 0; i < 32; i++) + { + if (0 != ((permissions >> i) & 1)) + { + string name = null; + + if (16 > i && specialPermissions.Length > i) + { + name = specialPermissions[i]; + } + else if (28 > i && UtilConstants.StandardPermissions.Length > (i - 16)) + { + name = UtilConstants.StandardPermissions[i - 16]; + } + else if (0 <= (i - 28) && UtilConstants.GenericPermissions.Length > (i - 28)) + { + name = UtilConstants.GenericPermissions[i - 28]; + } + + if (null == name) + { + this.Core.OnMessage(WixWarnings.UnknownPermission(row.SourceLineNumbers, row.Table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), i)); + } + else + { + switch (name) + { + case "ChangePermission": + fileSharePermission.ChangePermission = Util.YesNoType.yes; + break; + case "CreateChild": + fileSharePermission.CreateChild = Util.YesNoType.yes; + break; + case "CreateFile": + fileSharePermission.CreateFile = Util.YesNoType.yes; + break; + case "Delete": + fileSharePermission.Delete = Util.YesNoType.yes; + break; + case "DeleteChild": + fileSharePermission.DeleteChild = Util.YesNoType.yes; + break; + case "GenericAll": + fileSharePermission.GenericAll = Util.YesNoType.yes; + break; + case "GenericExecute": + fileSharePermission.GenericExecute = Util.YesNoType.yes; + break; + case "GenericRead": + fileSharePermission.GenericRead = Util.YesNoType.yes; + break; + case "GenericWrite": + fileSharePermission.GenericWrite = Util.YesNoType.yes; + break; + case "Read": + fileSharePermission.Read = Util.YesNoType.yes; + break; + case "ReadAttributes": + fileSharePermission.ReadAttributes = Util.YesNoType.yes; + break; + case "ReadExtendedAttributes": + fileSharePermission.ReadExtendedAttributes = Util.YesNoType.yes; + break; + case "ReadPermission": + fileSharePermission.ReadPermission = Util.YesNoType.yes; + break; + case "Synchronize": + fileSharePermission.Synchronize = Util.YesNoType.yes; + break; + case "TakeOwnership": + fileSharePermission.TakeOwnership = Util.YesNoType.yes; + break; + case "Traverse": + fileSharePermission.Traverse = Util.YesNoType.yes; + break; + case "WriteAttributes": + fileSharePermission.WriteAttributes = Util.YesNoType.yes; + break; + case "WriteExtendedAttributes": + fileSharePermission.WriteExtendedAttributes = Util.YesNoType.yes; + break; + default: + Debug.Fail(String.Format("Unknown permission '{0}'.", name)); + break; + } + } + } + } + + Util.FileShare fileShare = (Util.FileShare)this.Core.GetIndexedElement("FileShare", (string)row[0]); + if (null != fileShare) + { + fileShare.AddChild(fileSharePermission); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "FileShare_", (string)row[0], "FileShare")); + } + } + } + + /// + /// Decompile the Group table. + /// + /// The table to decompile. + private void DecompileGroupTable(Table table) + { + foreach (Row row in table.Rows) + { + Util.Group group = new Util.Group(); + + group.Id = (string)row[0]; + + if (null != row[1]) + { + this.Core.OnMessage(WixWarnings.UnrepresentableColumnValue(row.SourceLineNumbers, table.Name, "Component_", (string)row[1])); + } + + group.Name = (string)row[2]; + + if (null != row[3]) + { + group.Domain = (string)row[3]; + } + + this.Core.RootElement.AddChild(group); + } + } + + /// + /// Decompile the WixInternetShortcut table. + /// + /// The table to decompile. + private void DecompileWixInternetShortcutTable(Table table) + { + foreach (Row row in table.Rows) + { + Util.InternetShortcut internetShortcut = new Util.InternetShortcut(); + internetShortcut.Id = (string)row[0]; + internetShortcut.Directory = (string)row[2]; + // remove .lnk/.url extension because compiler extension adds it back for us + internetShortcut.Name = Path.ChangeExtension((string)row[3], null); + internetShortcut.Target = (string)row[4]; + internetShortcut.IconFile = (string)row[6]; + internetShortcut.IconIndex = (int)row[7]; + + UtilCompiler.InternetShortcutType shortcutType = (UtilCompiler.InternetShortcutType)row[5]; + switch (shortcutType) + { + case UtilCompiler.InternetShortcutType.Link: + internetShortcut.Type = Util.InternetShortcut.TypeType.link; + break; + case UtilCompiler.InternetShortcutType.Url: + internetShortcut.Type = Util.InternetShortcut.TypeType.url; + break; + } + + Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[1]); + if (null != component) + { + component.AddChild(internetShortcut); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[1], "Component")); + } + + this.Core.IndexElement(row, internetShortcut); + } + } + + /// + /// Decompile the Perfmon table. + /// + /// The table to decompile. + private void DecompilePerfmonTable(Table table) + { + foreach (Row row in table.Rows) + { + Util.PerfCounter perfCounter = new Util.PerfCounter(); + + perfCounter.Name = (string)row[2]; + + this.Core.IndexElement(row, perfCounter); + } + } + + /// + /// Decompile the PerfmonManifest table. + /// + /// The table to decompile. + private void DecompilePerfmonManifestTable(Table table) + { + foreach (Row row in table.Rows) + { + Util.PerfCounterManifest perfCounterManifest = new Util.PerfCounterManifest(); + + perfCounterManifest.ResourceFileDirectory = (string)row[2]; + + this.Core.IndexElement(row, perfCounterManifest); + } + } + + /// + /// Decompile the EventManifest table. + /// + /// The table to decompile. + private void DecompileEventManifestTable(Table table) + { + foreach (Row row in table.Rows) + { + Util.EventManifest eventManifest = new Util.EventManifest(); + this.Core.IndexElement(row, eventManifest); + } + } + + /// + /// Decompile the SecureObjects table. + /// + /// The table to decompile. + private void DecompileSecureObjectsTable(Table table) + { + foreach (Row row in table.Rows) + { + Util.PermissionEx permissionEx = new Util.PermissionEx(); + + string[] specialPermissions; + switch ((string)row[1]) + { + case "CreateFolder": + specialPermissions = UtilConstants.FolderPermissions; + break; + case "File": + specialPermissions = UtilConstants.FilePermissions; + break; + case "Registry": + specialPermissions = UtilConstants.RegistryPermissions; + break; + case "ServiceInstall": + specialPermissions = UtilConstants.ServicePermissions; + break; + default: + this.Core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, row.Table.Name, row.Fields[1].Column.Name, row[1])); + return; + } + + int permissionBits = (int)row[4]; + for (int i = 0; i < 32; i++) + { + if (0 != ((permissionBits >> i) & 1)) + { + string name = null; + + if (16 > i && specialPermissions.Length > i) + { + name = specialPermissions[i]; + } + else if (28 > i && UtilConstants.StandardPermissions.Length > (i - 16)) + { + name = UtilConstants.StandardPermissions[i - 16]; + } + else if (0 <= (i - 28) && UtilConstants.GenericPermissions.Length > (i - 28)) + { + name = UtilConstants.GenericPermissions[i - 28]; + } + + if (null == name) + { + this.Core.OnMessage(WixWarnings.UnknownPermission(row.SourceLineNumbers, row.Table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), i)); + } + else + { + switch (name) + { + case "Append": + permissionEx.Append = Util.YesNoType.yes; + break; + case "ChangePermission": + permissionEx.ChangePermission = Util.YesNoType.yes; + break; + case "CreateChild": + permissionEx.CreateChild = Util.YesNoType.yes; + break; + case "CreateFile": + permissionEx.CreateFile = Util.YesNoType.yes; + break; + case "CreateLink": + permissionEx.CreateLink = Util.YesNoType.yes; + break; + case "CreateSubkeys": + permissionEx.CreateSubkeys = Util.YesNoType.yes; + break; + case "Delete": + permissionEx.Delete = Util.YesNoType.yes; + break; + case "DeleteChild": + permissionEx.DeleteChild = Util.YesNoType.yes; + break; + case "EnumerateSubkeys": + permissionEx.EnumerateSubkeys = Util.YesNoType.yes; + break; + case "Execute": + permissionEx.Execute = Util.YesNoType.yes; + break; + case "GenericAll": + permissionEx.GenericAll = Util.YesNoType.yes; + break; + case "GenericExecute": + permissionEx.GenericExecute = Util.YesNoType.yes; + break; + case "GenericRead": + permissionEx.GenericRead = Util.YesNoType.yes; + break; + case "GenericWrite": + permissionEx.GenericWrite = Util.YesNoType.yes; + break; + case "Notify": + permissionEx.Notify = Util.YesNoType.yes; + break; + case "Read": + permissionEx.Read = Util.YesNoType.yes; + break; + case "ReadAttributes": + permissionEx.ReadAttributes = Util.YesNoType.yes; + break; + case "ReadExtendedAttributes": + permissionEx.ReadExtendedAttributes = Util.YesNoType.yes; + break; + case "ReadPermission": + permissionEx.ReadPermission = Util.YesNoType.yes; + break; + case "ServiceChangeConfig": + permissionEx.ServiceChangeConfig = Util.YesNoType.yes; + break; + case "ServiceEnumerateDependents": + permissionEx.ServiceEnumerateDependents = Util.YesNoType.yes; + break; + case "ServiceInterrogate": + permissionEx.ServiceInterrogate = Util.YesNoType.yes; + break; + case "ServicePauseContinue": + permissionEx.ServicePauseContinue = Util.YesNoType.yes; + break; + case "ServiceQueryConfig": + permissionEx.ServiceQueryConfig = Util.YesNoType.yes; + break; + case "ServiceQueryStatus": + permissionEx.ServiceQueryStatus = Util.YesNoType.yes; + break; + case "ServiceStart": + permissionEx.ServiceStart = Util.YesNoType.yes; + break; + case "ServiceStop": + permissionEx.ServiceStop = Util.YesNoType.yes; + break; + case "ServiceUserDefinedControl": + permissionEx.ServiceUserDefinedControl = Util.YesNoType.yes; + break; + case "Synchronize": + permissionEx.Synchronize = Util.YesNoType.yes; + break; + case "TakeOwnership": + permissionEx.TakeOwnership = Util.YesNoType.yes; + break; + case "Traverse": + permissionEx.Traverse = Util.YesNoType.yes; + break; + case "Write": + permissionEx.Write = Util.YesNoType.yes; + break; + case "WriteAttributes": + permissionEx.WriteAttributes = Util.YesNoType.yes; + break; + case "WriteExtendedAttributes": + permissionEx.WriteExtendedAttributes = Util.YesNoType.yes; + break; + default: + throw new InvalidOperationException(String.Format("Unknown permission attribute '{0}'.", name)); + } + } + } + } + + if (null != row[2]) + { + permissionEx.Domain = (string)row[2]; + } + + permissionEx.User = (string)row[3]; + + this.Core.IndexElement(row, permissionEx); + } + } + + /// + /// Decompile the ServiceConfig table. + /// + /// The table to decompile. + private void DecompileServiceConfigTable(Table table) + { + foreach (Row row in table.Rows) + { + Util.ServiceConfig serviceConfig = new Util.ServiceConfig(); + + serviceConfig.ServiceName = (string)row[0]; + + switch ((string)row[3]) + { + case "none": + serviceConfig.FirstFailureActionType = Util.ServiceConfig.FirstFailureActionTypeType.none; + break; + case "reboot": + serviceConfig.FirstFailureActionType = Util.ServiceConfig.FirstFailureActionTypeType.reboot; + break; + case "restart": + serviceConfig.FirstFailureActionType = Util.ServiceConfig.FirstFailureActionTypeType.restart; + break; + case "runCommand": + serviceConfig.FirstFailureActionType = Util.ServiceConfig.FirstFailureActionTypeType.runCommand; + break; + default: + this.Core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[3].Column.Name, row[3])); + break; + } + + switch ((string)row[4]) + { + case "none": + serviceConfig.SecondFailureActionType = Util.ServiceConfig.SecondFailureActionTypeType.none; + break; + case "reboot": + serviceConfig.SecondFailureActionType = Util.ServiceConfig.SecondFailureActionTypeType.reboot; + break; + case "restart": + serviceConfig.SecondFailureActionType = Util.ServiceConfig.SecondFailureActionTypeType.restart; + break; + case "runCommand": + serviceConfig.SecondFailureActionType = Util.ServiceConfig.SecondFailureActionTypeType.runCommand; + break; + default: + this.Core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4])); + break; + } + + switch ((string)row[5]) + { + case "none": + serviceConfig.ThirdFailureActionType = Util.ServiceConfig.ThirdFailureActionTypeType.none; + break; + case "reboot": + serviceConfig.ThirdFailureActionType = Util.ServiceConfig.ThirdFailureActionTypeType.reboot; + break; + case "restart": + serviceConfig.ThirdFailureActionType = Util.ServiceConfig.ThirdFailureActionTypeType.restart; + break; + case "runCommand": + serviceConfig.ThirdFailureActionType = Util.ServiceConfig.ThirdFailureActionTypeType.runCommand; + break; + default: + this.Core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[5].Column.Name, row[5])); + break; + } + + if (null != row[6]) + { + serviceConfig.ResetPeriodInDays = (int)row[6]; + } + + if (null != row[7]) + { + serviceConfig.RestartServiceDelayInSeconds = (int)row[7]; + } + + if (null != row[8]) + { + serviceConfig.ProgramCommandLine = (string)row[8]; + } + + if (null != row[9]) + { + serviceConfig.RebootMessage = (string)row[9]; + } + + this.Core.IndexElement(row, serviceConfig); + } + } + + /// + /// Decompile the User table. + /// + /// The table to decompile. + private void DecompileUserTable(Table table) + { + foreach (Row row in table.Rows) + { + Util.User user = new Util.User(); + + user.Id = (string)row[0]; + + user.Name = (string)row[2]; + + if (null != row[3]) + { + user.Domain = (string)row[3]; + } + + if (null != row[4]) + { + user.Password = (string)row[4]; + } + + if (null != row[5]) + { + int attributes = (int)row[5]; + + if (UtilCompiler.UserDontExpirePasswrd == (attributes & UtilCompiler.UserDontExpirePasswrd)) + { + user.PasswordNeverExpires = Util.YesNoType.yes; + } + + if (UtilCompiler.UserPasswdCantChange == (attributes & UtilCompiler.UserPasswdCantChange)) + { + user.CanNotChangePassword = Util.YesNoType.yes; + } + + if (UtilCompiler.UserPasswdChangeReqdOnLogin == (attributes & UtilCompiler.UserPasswdChangeReqdOnLogin)) + { + user.PasswordExpired = Util.YesNoType.yes; + } + + if (UtilCompiler.UserDisableAccount == (attributes & UtilCompiler.UserDisableAccount)) + { + user.Disabled = Util.YesNoType.yes; + } + + if (UtilCompiler.UserFailIfExists == (attributes & UtilCompiler.UserFailIfExists)) + { + user.FailIfExists = Util.YesNoType.yes; + } + + if (UtilCompiler.UserUpdateIfExists == (attributes & UtilCompiler.UserUpdateIfExists)) + { + user.UpdateIfExists = Util.YesNoType.yes; + } + + if (UtilCompiler.UserLogonAsService == (attributes & UtilCompiler.UserLogonAsService)) + { + user.LogonAsService = Util.YesNoType.yes; + } + + if (UtilCompiler.UserDontRemoveOnUninstall == (attributes & UtilCompiler.UserDontRemoveOnUninstall)) + { + user.RemoveOnUninstall = Util.YesNoType.no; + } + + if (UtilCompiler.UserDontCreateUser == (attributes & UtilCompiler.UserDontCreateUser)) + { + user.CreateUser = Util.YesNoType.no; + } + + if (UtilCompiler.UserNonVital == (attributes & UtilCompiler.UserNonVital)) + { + user.Vital = Util.YesNoType.no; + } + } + + if (null != row[1]) + { + Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[1]); + + if (null != component) + { + component.AddChild(user); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[1], "Component")); + } + } + else + { + this.Core.RootElement.AddChild(user); + } + this.Core.IndexElement(row, user); + } + } + + /// + /// Decompile the UserGroup table. + /// + /// The table to decompile. + private void DecompileUserGroupTable(Table table) + { + foreach (Row row in table.Rows) + { + Util.User user = (Util.User)this.Core.GetIndexedElement("User", (string)row[0]); + + if (null != user) + { + Util.GroupRef groupRef = new Util.GroupRef(); + + groupRef.Id = (string)row[1]; + + user.AddChild(groupRef); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Group_", (string)row[0], "Group")); + } + } + } + + /// + /// Decompile the XmlConfig table. + /// + /// The table to decompile. + private void DecompileXmlConfigTable(Table table) + { + foreach (Row row in table.Rows) + { + Util.XmlConfig xmlConfig = new Util.XmlConfig(); + + xmlConfig.Id = (string)row[0]; + + xmlConfig.File = (string)row[1]; + + xmlConfig.ElementPath = (string)row[2]; + + if (null != row[3]) + { + xmlConfig.VerifyPath = (string)row[3]; + } + + if (null != row[4]) + { + xmlConfig.Name = (string)row[4]; + } + + if (null != row[5]) + { + xmlConfig.Value = (string)row[5]; + } + + int flags = (int)row[6]; + + if (0x1 == (flags & 0x1)) + { + xmlConfig.Node = Util.XmlConfig.NodeType.element; + } + else if (0x2 == (flags & 0x2)) + { + xmlConfig.Node = Util.XmlConfig.NodeType.value; + } + else if (0x4 == (flags & 0x4)) + { + xmlConfig.Node = Util.XmlConfig.NodeType.document; + } + + if (0x10 == (flags & 0x10)) + { + xmlConfig.Action = Util.XmlConfig.ActionType.create; + } + else if (0x20 == (flags & 0x20)) + { + xmlConfig.Action = Util.XmlConfig.ActionType.delete; + } + + if (0x100 == (flags & 0x100)) + { + xmlConfig.On = Util.XmlConfig.OnType.install; + } + else if (0x200 == (flags & 0x200)) + { + xmlConfig.On = Util.XmlConfig.OnType.uninstall; + } + + if (0x00001000 == (flags & 0x00001000)) + { + xmlConfig.PreserveModifiedDate = Util.YesNoType.yes; + } + + if (null != row[8]) + { + xmlConfig.Sequence = (int)row[8]; + } + + this.Core.IndexElement(row, xmlConfig); + } + } + + /// + /// Finalize the Perfmon table. + /// + /// The collection of all tables. + /// + /// Since the PerfCounter element nests under a File element, but + /// the Perfmon table does not have a foreign key relationship with + /// the File table (instead it has a formatted string that usually + /// refers to a file row - but doesn't have to), the nesting must + /// be inferred during finalization. + /// + private void FinalizePerfmonTable(TableIndexedCollection tables) + { + Table perfmonTable = tables["Perfmon"]; + + if (null != perfmonTable) + { + foreach (Row row in perfmonTable.Rows) + { + string formattedFile = (string)row[1]; + Util.PerfCounter perfCounter = (Util.PerfCounter)this.Core.GetIndexedElement(row); + + // try to "de-format" the File column's value to determine the proper parent File element + if ((formattedFile.StartsWith("[#", StringComparison.Ordinal) || formattedFile.StartsWith("[!", StringComparison.Ordinal)) + && formattedFile.EndsWith("]", StringComparison.Ordinal)) + { + string fileId = formattedFile.Substring(2, formattedFile.Length - 3); + + Wix.File file = (Wix.File)this.Core.GetIndexedElement("File", fileId); + if (null != file) + { + file.AddChild(perfCounter); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, perfmonTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "File", formattedFile, "File")); + } + } + else + { + this.Core.OnMessage(UtilErrors.IllegalFileValueInPerfmonOrManifest(formattedFile, "Perfmon")); + } + } + } + } + + /// + /// Finalize the PerfmonManifest table. + /// + /// The collection of all tables. + private void FinalizePerfmonManifestTable(TableIndexedCollection tables) + { + Table perfmonManifestTable = tables["PerfmonManifest"]; + + if (null != perfmonManifestTable) + { + foreach (Row row in perfmonManifestTable.Rows) + { + string formattedFile = (string)row[1]; + Util.PerfCounterManifest perfCounterManifest = (Util.PerfCounterManifest)this.Core.GetIndexedElement(row); + + // try to "de-format" the File column's value to determine the proper parent File element + if ((formattedFile.StartsWith("[#", StringComparison.Ordinal) || formattedFile.StartsWith("[!", StringComparison.Ordinal)) + && formattedFile.EndsWith("]", StringComparison.Ordinal)) + { + string fileId = formattedFile.Substring(2, formattedFile.Length - 3); + + Wix.File file = (Wix.File)this.Core.GetIndexedElement("File", fileId); + if (null != file) + { + file.AddChild(perfCounterManifest); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, perfCounterManifest.ResourceFileDirectory, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "File", formattedFile, "File")); + } + } + else + { + this.Core.OnMessage(UtilErrors.IllegalFileValueInPerfmonOrManifest(formattedFile, "PerfmonManifest")); + } + } + } + } + + /// + /// Finalize the SecureObjects table. + /// + /// The collection of all tables. + /// + /// Nests the PermissionEx elements below their parent elements. There are no declared foreign + /// keys for the parents of the SecureObjects table. + /// + private void FinalizeSecureObjectsTable(TableIndexedCollection tables) + { + Table createFolderTable = tables["CreateFolder"]; + Table secureObjectsTable = tables["SecureObjects"]; + + Hashtable createFolders = new Hashtable(); + + // index the CreateFolder table because the foreign key to this table from the + // LockPermissions table is only part of the primary key of this table + if (null != createFolderTable) + { + foreach (Row row in createFolderTable.Rows) + { + Wix.CreateFolder createFolder = (Wix.CreateFolder)this.Core.GetIndexedElement(row); + string directoryId = (string)row[0]; + + if (!createFolders.Contains(directoryId)) + { + createFolders.Add(directoryId, new ArrayList()); + } + ((ArrayList)createFolders[directoryId]).Add(createFolder); + } + } + + if (null != secureObjectsTable) + { + foreach (Row row in secureObjectsTable.Rows) + { + string id = (string)row[0]; + string table = (string)row[1]; + + Util.PermissionEx permissionEx = (Util.PermissionEx)this.Core.GetIndexedElement(row); + + if ("CreateFolder" == table) + { + ArrayList createFolderElements = (ArrayList)createFolders[id]; + + if (null != createFolderElements) + { + foreach (Wix.CreateFolder createFolder in createFolderElements) + { + createFolder.AddChild(permissionEx); + } + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "SecureObjects", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "LockObject", id, table)); + } + } + else + { + Wix.IParentElement parentElement = (Wix.IParentElement)this.Core.GetIndexedElement(table, id); + + if (null != parentElement) + { + parentElement.AddChild(permissionEx); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "SecureObjects", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "LockObject", id, table)); + } + } + } + } + } + + /// + /// Finalize the ServiceConfig table. + /// + /// The collection of all tables. + /// + /// Since there is no foreign key from the ServiceName column to the + /// ServiceInstall table, this relationship must be handled late. + /// + private void FinalizeServiceConfigTable(TableIndexedCollection tables) + { + Table serviceConfigTable = tables["ServiceConfig"]; + Table serviceInstallTable = tables["ServiceInstall"]; + + Hashtable serviceInstalls = new Hashtable(); + + // index the ServiceInstall table because the foreign key used by the ServiceConfig + // table is actually the ServiceInstall.Name, not the ServiceInstall.ServiceInstall + // this is unfortunate because the service Name is not guaranteed to be unique, so + // decompiler must assume there could be multiple matches and add the ServiceConfig to each + // TODO: the Component column information should be taken into acount to accurately identify + // the correct column to use + if (null != serviceInstallTable) + { + foreach (Row row in serviceInstallTable.Rows) + { + string name = (string)row[1]; + Wix.ServiceInstall serviceInstall = (Wix.ServiceInstall)this.Core.GetIndexedElement(row); + + if (!serviceInstalls.Contains(name)) + { + serviceInstalls.Add(name, new ArrayList()); + } + + ((ArrayList)serviceInstalls[name]).Add(serviceInstall); + } + } + + if (null != serviceConfigTable) + { + foreach (Row row in serviceConfigTable.Rows) + { + Util.ServiceConfig serviceConfig = (Util.ServiceConfig)this.Core.GetIndexedElement(row); + + if (0 == (int)row[2]) + { + Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[1]); + + if (null != component) + { + component.AddChild(serviceConfig); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, serviceConfigTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[1], "Component")); + } + } + else + { + ArrayList serviceInstallElements = (ArrayList)serviceInstalls[row[0]]; + + if (null != serviceInstallElements) + { + foreach (Wix.ServiceInstall serviceInstall in serviceInstallElements) + { + serviceInstall.AddChild(serviceConfig); + } + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, serviceConfigTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "ServiceName", (string)row[0], "ServiceInstall")); + } + } + } + } + } + + /// + /// Finalize the XmlConfig table. + /// + /// Collection of all tables. + private void FinalizeXmlConfigTable(TableIndexedCollection tables) + { + Table xmlConfigTable = tables["XmlConfig"]; + + if (null != xmlConfigTable) + { + foreach (Row row in xmlConfigTable.Rows) + { + Util.XmlConfig xmlConfig = (Util.XmlConfig)this.Core.GetIndexedElement(row); + + if (null == row[6] || 0 == (int)row[6]) + { + Util.XmlConfig parentXmlConfig = (Util.XmlConfig)this.Core.GetIndexedElement("XmlConfig", (string)row[2]); + + if (null != parentXmlConfig) + { + parentXmlConfig.AddChild(xmlConfig); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, xmlConfigTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "ElementPath", (string)row[2], "XmlConfig")); + } + } + else + { + Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[7]); + + if (null != component) + { + component.AddChild(xmlConfig); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, xmlConfigTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[7], "Component")); + } + } + } + } + } + + + /// + /// Finalize the XmlFile table. + /// + /// The collection of all tables. + /// + /// Some of the XmlFile table rows are compiler generated from util:EventManifest node + /// These rows should not be appended to component. + /// + private void FinalizeXmlFileTable(TableIndexedCollection tables) + { + Table xmlFileTable = tables["XmlFile"]; + Table eventManifestTable = tables["EventManifest"]; + + if (null != xmlFileTable) + { + foreach (Row row in xmlFileTable.Rows) + { + bool bManifestGenerated = false; + string xmlFileConfigId = (string)row[0]; + if (null != eventManifestTable) + { + foreach (Row emrow in eventManifestTable.Rows) + { + string formattedFile = (string)emrow[1]; + if ((formattedFile.StartsWith("[#", StringComparison.Ordinal) || formattedFile.StartsWith("[!", StringComparison.Ordinal)) + && formattedFile.EndsWith("]", StringComparison.Ordinal)) + { + string fileId = formattedFile.Substring(2, formattedFile.Length - 3); + if (String.Equals(String.Concat("Config_", fileId, "ResourceFile"), xmlFileConfigId)) + { + Util.EventManifest eventManifest = (Util.EventManifest)this.Core.GetIndexedElement(emrow); + if (null != eventManifest) + { + eventManifest.ResourceFile = (string)row[4]; + } + bManifestGenerated = true; + } + + else if (String.Equals(String.Concat("Config_", fileId, "MessageFile"), xmlFileConfigId)) + { + Util.EventManifest eventManifest = (Util.EventManifest)this.Core.GetIndexedElement(emrow); + if (null != eventManifest) + { + eventManifest.MessageFile = (string)row[4]; + } + bManifestGenerated = true; + } + } + } + } + + if (true == bManifestGenerated) + continue; + + Util.XmlFile xmlFile = new Util.XmlFile(); + + xmlFile.Id = (string)row[0]; + xmlFile.File = (string)row[1]; + xmlFile.ElementPath = (string)row[2]; + + if (null != row[3]) + { + xmlFile.Name = (string)row[3]; + } + + if (null != row[4]) + { + xmlFile.Value = (string)row[4]; + } + + int flags = (int)row[5]; + if (0x1 == (flags & 0x1) && 0x2 == (flags & 0x2)) + { + this.Core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, xmlFileTable.Name, row.Fields[5].Column.Name, row[5])); + } + else if (0x1 == (flags & 0x1)) + { + xmlFile.Action = Util.XmlFile.ActionType.createElement; + } + else if (0x2 == (flags & 0x2)) + { + xmlFile.Action = Util.XmlFile.ActionType.deleteValue; + } + else + { + xmlFile.Action = Util.XmlFile.ActionType.setValue; + } + + if (0x100 == (flags & 0x100)) + { + xmlFile.SelectionLanguage = Util.XmlFile.SelectionLanguageType.XPath; + } + + if (0x00001000 == (flags & 0x00001000)) + { + xmlFile.PreserveModifiedDate = Util.YesNoType.yes; + } + + if (0x00010000 == (flags & 0x00010000)) + { + xmlFile.Permanent = Util.YesNoType.yes; + } + + if (null != row[7]) + { + xmlFile.Sequence = (int)row[7]; + } + + Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[6]); + + if (null != component) + { + component.AddChild(xmlFile); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, xmlFileTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[6], "Component")); + } + } + } + } + + /// + /// Finalize the eventManifest table. + /// This function must be called after FinalizeXmlFileTable + /// + /// The collection of all tables. + private void FinalizeEventManifestTable(TableIndexedCollection tables) + { + Table eventManifestTable = tables["EventManifest"]; + + if (null != eventManifestTable) + { + foreach (Row row in eventManifestTable.Rows) + { + string formattedFile = (string)row[1]; + Util.EventManifest eventManifest = (Util.EventManifest)this.Core.GetIndexedElement(row); + + // try to "de-format" the File column's value to determine the proper parent File element + if ((formattedFile.StartsWith("[#", StringComparison.Ordinal) || formattedFile.StartsWith("[!", StringComparison.Ordinal)) + && formattedFile.EndsWith("]", StringComparison.Ordinal)) + { + string fileId = formattedFile.Substring(2, formattedFile.Length - 3); + + Wix.File file = (Wix.File)this.Core.GetIndexedElement("File", fileId); + if (null != file) + { + file.AddChild(eventManifest); + } + } + else + { + this.Core.OnMessage(UtilErrors.IllegalFileValueInPerfmonOrManifest(formattedFile, "EventManifest")); + } + } + } + } + } +#endif +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + using System; + using System.Resources; + using WixToolset.Data; + + public static class UtilErrors + { + public static Message IllegalAttributeWithoutComponent(SourceLineNumber sourceLineNumbers, string elementName, string attributeName) + { + 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); + } + + public static Message IllegalElementWithoutComponent(SourceLineNumber sourceLineNumbers, string elementName) + { + 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); + } + + public static Message IllegalFileValueInPerfmonOrManifest(string file, string table) + { + 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); + } + + public static Message InvalidRegistryObject(SourceLineNumber sourceLineNumbers, string registryElementName) + { + 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); + } + + private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args) + { + return new Message(sourceLineNumber, MessageLevel.Error, (int)id, format, args); + } + + private static Message Message(SourceLineNumber sourceLineNumber, Ids id, ResourceManager resourceManager, string resourceName, params object[] args) + { + return new Message(sourceLineNumber, MessageLevel.Error, (int)id, resourceManager, resourceName, args); + } + + public enum Ids + { + IllegalAttributeWithoutComponent = 5050, + IllegalElementWithoutComponent = 5051, + IllegalFileValueInPerfmonOrManifest = 5054, + InvalidRegistryObject = 5063, + } + } +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + using WixToolset.Data; + using WixToolset.Extensibility; + + public sealed class UtilExtensionData : BaseExtensionData + { + public override string DefaultCulture => "en-US"; + + public override bool TryGetSymbolDefinitionByName(string name, out IntermediateSymbolDefinition symbolDefinition) + { + symbolDefinition = UtilSymbolDefinitions.ByName(name); + return symbolDefinition != null; + } + + public override Intermediate GetLibrary(ISymbolDefinitionCreator symbolDefinitions) + { + return Intermediate.Load(typeof(UtilExtensionData).Assembly, "WixToolset.Util.util.wixlib", symbolDefinitions); + } + } +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + using System; + using System.Collections.Generic; + using WixToolset.Extensibility; + + public class UtilExtensionFactory : BaseExtensionFactory + { + protected override IReadOnlyCollection ExtensionTypes => new[] + { + typeof(UtilCompiler), + typeof(UtilExtensionData), + typeof(UtilWindowsInstallerBackendBinderExtension), + }; + } +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + using WixToolset.Data.WindowsInstaller; + + public static class UtilTableDefinitions + { + public static readonly TableDefinition Wix4CloseApplication = new TableDefinition( + "Wix4CloseApplication", + UtilSymbolDefinitions.WixCloseApplication, + new[] + { + new ColumnDefinition("Wix4CloseApplication", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token in table.", modularizeType: ColumnModularizeType.Column), + new ColumnDefinition("Target", ColumnType.Localized, 0, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "Name of executable to ensure is closed.", modularizeType: ColumnModularizeType.Property), + 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), + new ColumnDefinition("Condition", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Condition, description: "Optional expression which skips the closing.", modularizeType: ColumnModularizeType.Condition, forceLocalizable: true), + 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."), + new ColumnDefinition("Sequence", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Unknown, minValue: 1, maxValue: 2147483647, description: "Sequence to order the closings by."), + 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), + 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."), + 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."), + }, + symbolIdIsPrimaryKey: true + ); + + public static readonly TableDefinition Wix4RemoveFolderEx = new TableDefinition( + "Wix4RemoveFolderEx", + UtilSymbolDefinitions.WixRemoveFolderEx, + new[] + { + new ColumnDefinition("Wix4RemoveFolderEx", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Identifier for the WixRemoveFolderEx row in the package.", modularizeType: ColumnModularizeType.Column), + 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), + 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), + 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."), + 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), + }, + symbolIdIsPrimaryKey: true + ); + + public static readonly TableDefinition Wix4RemoveRegistryKeyEx = new TableDefinition( + "Wix4RemoveRegistryKeyEx", + UtilSymbolDefinitions.WixRemoveRegistryKeyEx, + new[] + { + new ColumnDefinition("Wix4RemoveRegistryKeyEx", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Identifier for the Wix4RemoveRegistryKeyEx row in the package.", modularizeType: ColumnModularizeType.Column), + 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), + 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."), + new ColumnDefinition("Key", ColumnType.Localized, 255, primaryKey: false, nullable: false, ColumnCategory.RegPath, description: "The key for the registry value.", modularizeType: ColumnModularizeType.Property), + 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."), + 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), + }, + symbolIdIsPrimaryKey: true + ); + + public static readonly TableDefinition Wix4RestartResource = new TableDefinition( + "Wix4RestartResource", + UtilSymbolDefinitions.WixRestartResource, + new[] + { + new ColumnDefinition("Wix4RestartResource", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized identifier.", modularizeType: ColumnModularizeType.Column), + 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), + 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), + 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."), + }, + symbolIdIsPrimaryKey: true + ); + + public static readonly TableDefinition Wix4FileShare = new TableDefinition( + "Wix4FileShare", + UtilSymbolDefinitions.FileShare, + new[] + { + new ColumnDefinition("Wix4FileShare", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized identifier", modularizeType: ColumnModularizeType.Column), + new ColumnDefinition("ShareName", ColumnType.String, 255, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "The actual share name used"), + 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), + new ColumnDefinition("Description", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Text, description: "Description string displayed for the file share"), + 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), + }, + symbolIdIsPrimaryKey: true + ); + + public static readonly TableDefinition Wix4FileSharePermissions = new TableDefinition( + "Wix4FileSharePermissions", + UtilSymbolDefinitions.FileSharePermissions, + new[] + { + 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), + 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), + new ColumnDefinition("Permissions", ColumnType.Number, 4, primaryKey: false, nullable: false, ColumnCategory.Unknown, description: "Permissions int, as in EXPLICIT_ACCESS.grfAccessPermissions in MSDN"), + }, + symbolIdIsPrimaryKey: false + ); + + public static readonly TableDefinition Wix4Group = new TableDefinition( + "Wix4Group", + UtilSymbolDefinitions.Group, + new[] + { + new ColumnDefinition("Wix4Group", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token", modularizeType: ColumnModularizeType.Column), + 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), + new ColumnDefinition("Name", ColumnType.String, 255, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "Group name", modularizeType: ColumnModularizeType.Property), + new ColumnDefinition("Domain", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Group domain", modularizeType: ColumnModularizeType.Property), + }, + symbolIdIsPrimaryKey: true + ); + + public static readonly TableDefinition Wix4InternetShortcut = new TableDefinition( + "Wix4InternetShortcut", + UtilSymbolDefinitions.WixInternetShortcut, + new[] + { + new ColumnDefinition("Wix4InternetShortcut", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token in table.", modularizeType: ColumnModularizeType.Column), + 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), + 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), + new ColumnDefinition("Name", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Text, description: "Name used for shortcut.", modularizeType: ColumnModularizeType.Property), + new ColumnDefinition("Target", ColumnType.Localized, 0, primaryKey: false, nullable: false, ColumnCategory.Text, description: "URL target."), + new ColumnDefinition("Attributes", ColumnType.Number, 2, primaryKey: false, nullable: false, ColumnCategory.Unknown, description: "Attribute flags that control how the shortcut is created."), + new ColumnDefinition("IconFile", ColumnType.Localized, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Icon file for shortcut", modularizeType: ColumnModularizeType.Property), + new ColumnDefinition("IconIndex", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Index of the icon being referenced."), + }, + symbolIdIsPrimaryKey: true + ); + + public static readonly TableDefinition Wix4PerformanceCategory = new TableDefinition( + "Wix4PerformanceCategory", + UtilSymbolDefinitions.PerformanceCategory, + new[] + { + new ColumnDefinition("Wix4PerformanceCategory", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token in table.", modularizeType: ColumnModularizeType.Column), + 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), + new ColumnDefinition("Name", ColumnType.String, 80, primaryKey: false, nullable: false, ColumnCategory.Text, description: "Name of the performance counter category."), + new ColumnDefinition("IniData", ColumnType.Localized, 0, primaryKey: false, nullable: false, ColumnCategory.Text, description: "Data that goes into the performance counter .ini file."), + new ColumnDefinition("ConstantData", ColumnType.Localized, 0, primaryKey: false, nullable: false, ColumnCategory.Text, description: "Data that goes into the performance counter .h file."), + }, + symbolIdIsPrimaryKey: true + ); + + public static readonly TableDefinition Wix4Perfmon = new TableDefinition( + "Wix4Perfmon", + UtilSymbolDefinitions.Perfmon, + new[] + { + 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), + new ColumnDefinition("File", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Formatted, description: "Name of .INI file", modularizeType: ColumnModularizeType.Property), + new ColumnDefinition("Name", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Text, description: "Service name in registry"), + }, + symbolIdIsPrimaryKey: false + ); + + public static readonly TableDefinition Wix4PerfmonManifest = new TableDefinition( + "Wix4PerfmonManifest", + UtilSymbolDefinitions.PerfmonManifest, + new[] + { + 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), + new ColumnDefinition("File", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Formatted, description: "Name of perfmon manifest file", modularizeType: ColumnModularizeType.Property), + new ColumnDefinition("ResourceFileDirectory", ColumnType.String, 255, primaryKey: true, nullable: false, ColumnCategory.Formatted, description: "The path of the Resource File Directory"), + }, + symbolIdIsPrimaryKey: false + ); + + public static readonly TableDefinition Wix4EventManifest = new TableDefinition( + "Wix4EventManifest", + UtilSymbolDefinitions.EventManifest, + new[] + { + 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), + new ColumnDefinition("File", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Formatted, description: "Name of event manifest file", modularizeType: ColumnModularizeType.Property), + }, + symbolIdIsPrimaryKey: false + ); + + public static readonly TableDefinition Wix4SecureObject = new TableDefinition( + "Wix4SecureObject", + UtilSymbolDefinitions.SecureObjects, + new[] + { + new ColumnDefinition("Wix4SecureObject", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token in Table", modularizeType: ColumnModularizeType.Column), + new ColumnDefinition("Table", ColumnType.String, 32, primaryKey: true, nullable: false, ColumnCategory.Text, description: "Table SecureObject should be securing"), + new ColumnDefinition("Domain", ColumnType.String, 255, primaryKey: true, nullable: true, ColumnCategory.Text, description: "Domain half of user account to secure", modularizeType: ColumnModularizeType.Property), + new ColumnDefinition("User", ColumnType.String, 255, primaryKey: true, nullable: false, ColumnCategory.Text, description: "User name half of user account to secure", modularizeType: ColumnModularizeType.Property), + 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."), + new ColumnDefinition("Permission", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Unknown, minValue: -2147483647, maxValue: 2147483647, description: "Permissions to grant to User"), + 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), + }, + symbolIdIsPrimaryKey: false + ); + + public static readonly TableDefinition Wix4ServiceConfig = new TableDefinition( + "Wix4ServiceConfig", + UtilSymbolDefinitions.ServiceConfig, + new[] + { + new ColumnDefinition("ServiceName", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Formatted, description: "Primary key, non-localized token"), + 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), + 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."), + new ColumnDefinition("FirstFailureActionType", ColumnType.String, 32, primaryKey: false, nullable: false, ColumnCategory.Text, description: "First failure action type for configured service to take."), + new ColumnDefinition("SecondFailureActionType", ColumnType.String, 32, primaryKey: false, nullable: false, ColumnCategory.Text, description: "Second failure action type for configured service to take."), + new ColumnDefinition("ThirdFailureActionType", ColumnType.String, 32, primaryKey: false, nullable: false, ColumnCategory.Text, description: "Third failure action type for configured service to take."), + 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."), + 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."), + 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."), + 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."), + }, + symbolIdIsPrimaryKey: false + ); + + public static readonly TableDefinition Wix4TouchFile = new TableDefinition( + "Wix4TouchFile", + UtilSymbolDefinitions.WixTouchFile, + new[] + { + new ColumnDefinition("Wix4TouchFile", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Identifier for the Wix4TouchFile row in the package.", modularizeType: ColumnModularizeType.Column), + 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), + 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), + 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."), + }, + symbolIdIsPrimaryKey: true + ); + + public static readonly TableDefinition Wix4User = new TableDefinition( + "Wix4User", + UtilSymbolDefinitions.User, + new[] + { + new ColumnDefinition("Wix4User", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token", modularizeType: ColumnModularizeType.Column), + 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), + new ColumnDefinition("Name", ColumnType.String, 255, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "User name", modularizeType: ColumnModularizeType.Property), + new ColumnDefinition("Domain", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "User domain", modularizeType: ColumnModularizeType.Property), + new ColumnDefinition("Password", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "User password", modularizeType: ColumnModularizeType.Property), + new ColumnDefinition("Attributes", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Unknown, minValue: 0, maxValue: 65535, description: "Attributes describing how to create the user"), + }, + symbolIdIsPrimaryKey: true + ); + + public static readonly TableDefinition Wix4UserGroup = new TableDefinition( + "Wix4UserGroup", + UtilSymbolDefinitions.UserGroup, + new[] + { + 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), + 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), + }, + symbolIdIsPrimaryKey: false + ); + + public static readonly TableDefinition Wix4XmlFile = new TableDefinition( + "Wix4XmlFile", + UtilSymbolDefinitions.XmlFile, + new[] + { + new ColumnDefinition("Wix4XmlFile", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token.", modularizeType: ColumnModularizeType.Column), + 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), + new ColumnDefinition("ElementPath", ColumnType.Localized, 0, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "The .XML file element to modify.", modularizeType: ColumnModularizeType.Property), + 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), + new ColumnDefinition("Value", ColumnType.Localized, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "The value to be written.", modularizeType: ColumnModularizeType.Property), + new ColumnDefinition("Flags", ColumnType.Number, 4, primaryKey: false, nullable: false, ColumnCategory.Unknown, minValue: 0, maxValue: 70143, description: "Flags"), + 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), + new ColumnDefinition("Sequence", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Order to execute the XML modifications."), + }, + symbolIdIsPrimaryKey: true + ); + + public static readonly TableDefinition Wix4XmlConfig = new TableDefinition( + "Wix4XmlConfig", + UtilSymbolDefinitions.XmlConfig, + new[] + { + new ColumnDefinition("Wix4XmlConfig", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token.", modularizeType: ColumnModularizeType.Column), + 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), + 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), + 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), + 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), + 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), + new ColumnDefinition("Value", ColumnType.Localized, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "The value to be written.", modularizeType: ColumnModularizeType.Property), + 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"), + 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), + new ColumnDefinition("Sequence", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Order to execute the XML modifications."), + }, + symbolIdIsPrimaryKey: true + ); + + public static readonly TableDefinition Wix4FormatFile = new TableDefinition( + "Wix4FormatFile", + UtilSymbolDefinitions.WixFormatFiles, + new[] + { + 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), + 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), + }, + symbolIdIsPrimaryKey: false + ); + + public static readonly TableDefinition[] All = new[] + { + Wix4CloseApplication, + Wix4RemoveFolderEx, + Wix4RemoveRegistryKeyEx, + Wix4RestartResource, + Wix4FileShare, + Wix4FileSharePermissions, + Wix4Group, + Wix4InternetShortcut, + Wix4PerformanceCategory, + Wix4Perfmon, + Wix4PerfmonManifest, + Wix4EventManifest, + Wix4SecureObject, + Wix4ServiceConfig, + Wix4TouchFile, + Wix4User, + Wix4UserGroup, + Wix4XmlFile, + Wix4XmlConfig, + Wix4FormatFile, + }; + } +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + using System; + using System.Resources; + using WixToolset.Data; + + public static class UtilWarnings + { + public static Message DeprecatedPerfCounterElement(SourceLineNumber sourceLineNumbers) + { + return Message(sourceLineNumbers, Ids.DeprecatedPerfCounterElement, "The PerfCounter element has been deprecated. Please use the PerformanceCounter element instead."); + } + + public static Message RequiredAttributeForWindowsXP(SourceLineNumber sourceLineNumbers, string elementName, string attributeName) + { + 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); + } + + private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args) + { + return new Message(sourceLineNumber, MessageLevel.Warning, (int)id, format, args); + } + + private static Message Message(SourceLineNumber sourceLineNumber, Ids id, ResourceManager resourceManager, string resourceName, params object[] args) + { + return new Message(sourceLineNumber, MessageLevel.Warning, (int)id, resourceManager, resourceName, args); + } + + public enum Ids + { + DeprecatedPerfCounterElement = 5153, + RequiredAttributeForWindowsXP = 5154, + } + } +} 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 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Util +{ + using System.Collections.Generic; + using WixToolset.Data.WindowsInstaller; + using WixToolset.Extensibility; + + public class UtilWindowsInstallerBackendBinderExtension : BaseWindowsInstallerBackendBinderExtension + { + public override IReadOnlyCollection TableDefinitions => UtilTableDefinitions.All; + } +} 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 @@ + + + + + + netstandard2.0 + WixToolset.Util + WiX Toolset Utility Extension + WiX Toolset Util Extension + embedded + true + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + $id$ + $version$ + $title$ + $description$ + $authors$ + MS-RL + false + $copyright$ + $projectUrl$ + + + + + + + + + + + + + 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 @@ + + + + + + $(MSBuildThisFileDirectory)..\tools\WixToolset.Util.wixext.dll + + + + + 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 @@ + + + + ..\..\build\Debug\util.wixlib + + + \ 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 @@ + + + + + + + + + + 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 @@ + + + + + + + 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 @@ + + + + + + + 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 @@ + + + + + + + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + + + 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 @@ + + + + + + + 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 @@ + + + + + + + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + + Konnte den Benutzer nicht anlegen. ([2] [3] [4] [5]) + Konnte den Benutzer auf Grund eines falschen Passwortes nicht anlegen. ([2] [3] [4] [5]) + Konnte Benutzer nicht zur Gruppe hinzufügen. ([2] [3] [4] [5]) + Konnte den Benutzer nicht anlegen, da er bereits existierte. ([2] [3] [4] [5]) + + Konnte Netzwerkfreigabe nicht anlegen. ([2] [3] [4] [5]) + Konnte Netzwerkfreigabe nicht entfernen. ([2] [3] [4] [5]) + + Konnte die DLL nicht für PerfMon registrieren. ([2] [3] [4] [5]) + Konnte die DLL nicht für PerfMon deregistrieren. ([2] [3] [4] [5]) + + Konnte die Daten der Leistungsüberwachung (performance counters) nicht installieren. ([2] [3] [4] [5]) + Konnte die Daten der Leistungsüberwachung (performance counters) nicht deinstallieren. ([2] [3] [4] [5]) + + Konnte keinen Security Descriptor für [3]\[4] erstellen, System Fehler: [2] + Konnte keinen Security Descriptor für das Objekt [3] erstellen, System Fehler: [2] + Unbekannter Objekt Typ [3], System Fehler: [2] + + Beim Lesen der XML Dateien trat ein Fehler auf. + Konnte XML Datei [3] nicht öffnen, System Fehler: [2] + Konnte Knoten [3] in der XML Datei [4] nicht finden, System Fehler: [2] + Beim Speichern der Änderungen an der XML Datei [3] trat ein Fehler auf, System Fehler: [2] + + Bei der Konfiguration der XML Dateien trat ein Fehler auf. + Konnte XML Datei [3] nicht öffnen, System Fehler: [2] + Konnte Knoten [3] in der XML Datei [4] nicht finden, System Fehler: [2] + Beim Speichern der Änderungen an der XML Datei [3] trat ein Fehler auf, System Fehler: [2] + 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 @@ + + + + + Failed to create user. ([2] [3] [4] [5]) + Failed to create user due to invalid password. ([2] [3] [4] [5]) + Failed to add user to group. ([2] [3] [4] [5]) + Failed to create user because it already exists. ([2] [3] [4] [5]) + + Failed to create network share. ([2] [3] [4] [5]) + Failed to drop network share. ([2] [3] [4] [5]) + + Failed to register DLL with PerfMon. ([2] [3] [4] [5]) + Failed to unregister DLL with PerfMon. ([2] [3] [4] [5]) + + Failed to install performance counters. ([2] [3] [4] [5]) + Failed to uninstall performance counters. ([2] [3] [4] [5]) + + Failed to create security descriptor for [3]\[4], system error: [2] + Failed to set security descriptor on object [3], system error: [2] + Unknown Object Type [3], system error: [2] + + There was a failure while configuring XML files. + Failed to open XML file [3], system error: [2] + Failed to find node: [3] in XML file: [4], system error: [2] + Failed to save changes to XML file [3], system error: [2] + + There was a failure while configuring XML files. + Failed to open XML file [3], system error: [2] + Failed to find node: [3] in XML file: [4], system error: [2] + Failed to save changes to XML file [3], system error: [2] + 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 @@ + + + + La creación del usuario ha fracasado. ([2] [3] [4] [5]) + La creación del usuario ha fracasado porque la contraseña es incorrecta. ([2] [3] [4] [5]) + El aditamento del usuario al grupo ha fracasado. ([2] [3] [4] [5]) + La creación del usuario ha fracasado porque ya existe. ([2] [3] [4] [5]) + + La creación de la red compartida ha fracasado. ([2] [3] [4] [5]) + La eliminación de la red compartida ha fracasado. ([2] [3] [4] [5]) + + La inscripción al registro de la DLL con PerfMon ha fracasado. ([2] [3] [4] [5]) + La cancelación de la inscripción al registro de la DLL con PerfMon ha fracasado. ([2] [3] [4] [5]) + + La instalación de los contadores de rendimiento ha fracasado. ([2] [3] [4] [5]) + La desinstalación de los contadores de rendimiento ha fracasado. ([2] [3] [4] [5]) + + La creación de los ACLs ha fracasado por [3]\[4], error del sistema : [2] + El posicionamiento de los ACLs por el objecto [3] ha fracasado, error del sistema: [2] + Tipo de objecto no conocido [3], error del sistema: [2] + + Un problema ha aparecido durante la configuración de los ficheros XML. + Fracaso de la apertura de los ficheros XML [3], error del sistema: [2] + Fracaso de la búsqueda del nodo: [3] en el fichero XML: [4], error del sistema: [2] + Fracaso durante la salvaguardia de las modificaciones en el fichero XML [3], error del sistema: [2] + + Un problema ha aparecido durante la configuración de los ficheros XML. + Fracaso de la apertura de los ficheros XML [3], error del sistema: [2] + Fracaso de la búsqueda del nodo: [3] en el fichero XML: [4], error del sistema: [2] + Fracaso durante la salvaguardia de las modificaciones en el fichero XML [3], error del sistema: [2] + \ 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 @@ + + + + La création de l'utilisateur a échoué. ([2] [3] [4] [5]) + La création de l'utilisateur a échoué car le mot de passe est invalide. ([2] [3] [4] [5]) + L'ajout de l'utilisateur au groupe a échoué. ([2] [3] [4] [5]) + La création de l'utilisateur a échoué car il existe dejà. ([2] [3] [4] [5]) + + La création du partage reseau a échoué. ([2] [3] [4] [5]) + La suppression du partage reseau a échoué. ([2] [3] [4] [5]) + + L'inscription au registre de la DLL avec PerfMon a échoué. ([2] [3] [4] [5]) + La desinscription au registre de la DLL avec PerfMon a échoué. ([2] [3] [4] [5]) + + L'installation des compteurs de performance a échoué. ([2] [3] [4] [5]) + La desinstallation des compteurs de performance a échoué. ([2] [3] [4] [5]) + + La création des ACLs a échoué pour [3]\[4], erreur systeme: [2] + Le positionnement des ACLs pour l'objet [3] a échoué, erreur systeme: [2] + Type d'objet inconnu [3], erreur systeme: [2] + + Un problème est survenu lors de la configuration des fichiers XML. + Echec de l'ouverture des fichiers XML [3], erreur systeme: [2] + Echec de la recherche du noeud: [3] dans le fichier XML: [4], erreur systeme: [2] + Echec lors de la sauvegarde des modifications dans le fichier XML [3], erreur systeme: [2] + + Un problème est survenu lors de la configuration des fichiers XML. + Echec de l'ouverture des fichiers XML [3], erreur systeme: [2] + Echec de la recherche du noeud: [3] dans le fichier XML: [4], erreur systeme: [2] + Echec lors de la sauvegarde des modifications dans le fichier XML [3], erreur systeme: [2] + \ 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 @@ + + + + + Impossibile creare l'utente. ([2] [3] [4] [5]) + Impossibile creare l'utente perchè la password è errata. ([2] [3] [4] [5]) + Impossibile aggiungere l'utente al gruppo. ([2] [3] [4] [5]) + Impossibile creare l'utente perchè già esistente. ([2] [3] [4] [5]) + + Impossibile creare la risorsa di rete. ([2] [3] [4] [5]) + Impossibile eliminare la risorsa di rete. ([2] [3] [4] [5]) + + Impossibile registrare la DLL con PerfMon. ([2] [3] [4] [5]) + Impossibile rimuovere la registrazione della DLL con PerfMon. ([2] [3] [4] [5]) + + Impossibile installare i contatori delle prestazioni. ([2] [3] [4] [5]) + Impossibile rimuovere i contatori delle prestazioni. ([2] [3] [4] [5]) + + Impossibile creare i descrittori di sicurezza per [3]\[4], errore di sistema: [2] + Impossibile impostare i descrittori di sicurezza sull'oggetto [3], errore di sistema: [2] + Tipo di oggetto sconosciuto [3], errore di sistema: [2] + + Si è verificato un errore durante la configurazione dei file XML. + Impossibile aprire il file XML [3], errore di sistema: [2] + Impossibile trovare il nodo: [3] nel file XML: [4], errore di sistema: [2] + Impossible salvare le modifiche al file XML [3], errore di sistema: [2] + + Si è verificato un errore durante la configurazione dei file XML. + Impossibile aprire il file XML [3], errore di sistema: [2] + Impossibile trovare il nodo: [3] nel file XML: [4], errore di sistema: [2] + Impossibile salvare le modifiche al file XML [3], errore di sitema: [2] + 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 @@ + + + + + ユーザー作成に失敗しました。 ([2] [3] [4] [5]) + パスワードが無効のためユーザー作成に失敗しました。 ([2] [3] [4] [5]) + ユーザーをグループに追加でいませんでした。 ([2] [3] [4] [5]) + ユーザーが既に存在するため作成できませんでした。 ([2] [3] [4] [5]) + + ネットワーク共有の作成に失敗しました。 ([2] [3] [4] [5]) + ネットワーク共有の削除に失敗しました。 ([2] [3] [4] [5]) + + DLL を PerfMon に登録でいませんでした。 ([2] [3] [4] [5]) + DLL を PerfMon より登録解除できませんでした。 ([2] [3] [4] [5]) + + パフォーマンス カウンタをインストールできませんでした。 ([2] [3] [4] [5]) + パフォーマンス カウンタをアンインストールできませんでした。 ([2] [3] [4] [5]) + + [3]\[4] 用セキュリティ ディスクリプターを作成できませんでした、システム エラー: [2] + オブジェクト [3] 上のセキュリティ ディスクリプターを設定できませんでした、システム エラー: [2] + 不明なオブジェクト種別 [3]、システム エラー: [2] + + XML ファイル構成中に失敗しました。 + XML ファイル [3] を開けませんでした、システム エラー: [2] + XML ファイル [4] 内にノード [3] が見つかりませんでした、システム エラー: [2] + XML ファイル [3] へ変更を保存できませんでした、システム エラー: [2] + + XML ファイル構成中に失敗しました。 + XML ファイル [3] を開けませんでした、システム エラー: [2] + XML ファイル [4] 内にノード [3] が見つかりませんでした、システム エラー: [2] + XML ファイル [3] へ変更を保存できませんでした、システム エラー: [2] + 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 @@ + + + + + Falha ao criar usuário. ([2] [3] [4] [5]) + Falha ao criar usuário devido a senha inválida. ([2] [3] [4] [5]) + Falha ao adicionar o usuário ao grupo. ([2] [3] [4] [5]) + Falha ao criar o usuário, porque ele já existe. ([2] [3] [4] [5]) + Falha ao criar o compartilhamento de rede. ([2] [3] [4] [5]) + Falha ao cair compartilhamento de rede. ([2] [3] [4] [5]) + Falha ao registrar DLL com PerfMon. ([2] [3] [4] [5]) + Falha ao cancelar o registro de DLL com PerfMon. ([2] [3] [4] [5]) + Falha ao instalar contadores de desempenho. ([2] [3] [4] [5]) + Falha ao desinstalar contadores de desempenho. ([2] [3] [4] [5]) + Falha ao criar o descritor de segurança [3] \ [4], erro do sistema: [2] + Falha ao definir o descritor de segurança sobre o objeto [3], erro do sistema: [2] + Objeto Desconhecido Tipo [3], erro do sistema: [2] + Houve uma falha ao configurar arquivos XML. + Falha ao abrir o arquivo XML [3], erro do sistema: [2] + Falha ao localizar nó: [3] no arquivo XML: [4], erro do sistema: [2] + Falha ao salvar as alterações para o arquivo XML [3], erro do sistema: [2] + Houve uma falha ao configurar arquivos XML. + Falha ao abrir o arquivo XML [3], erro do sistema: [2] + Falha ao localizar nó: [3] no arquivo XML: [4], erro do sistema: [2] + Falha ao salvar as alterações para o arquivo XML [3], erro do sistema: [2] + 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 @@ + + + True + + \ 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 @@ + + + + + Library + true + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ext/global.json b/src/ext/global.json new file mode 100644 index 00000000..697f5687 --- /dev/null +++ b/src/ext/global.json @@ -0,0 +1,8 @@ +{ + "msbuild-sdks": { + "WixToolset.Sdk": "4.0.0-build-0213" + }, + "sdk": { + "allowPrerelease": false + } +} diff --git a/src/test/WixToolsetTest.Util/TestData/.Data/burn.exe b/src/test/WixToolsetTest.Util/TestData/.Data/burn.exe deleted file mode 100644 index 2a4f423f..00000000 Binary files a/src/test/WixToolsetTest.Util/TestData/.Data/burn.exe and /dev/null differ diff --git a/src/test/WixToolsetTest.Util/TestData/BundleWithSearches/Bundle.en-us.wxl b/src/test/WixToolsetTest.Util/TestData/BundleWithSearches/Bundle.en-us.wxl deleted file mode 100644 index f50a5386..00000000 --- a/src/test/WixToolsetTest.Util/TestData/BundleWithSearches/Bundle.en-us.wxl +++ /dev/null @@ -1,8 +0,0 @@ - - - - ~TestBundle - - diff --git a/src/test/WixToolsetTest.Util/TestData/BundleWithSearches/Bundle.wxs b/src/test/WixToolsetTest.Util/TestData/BundleWithSearches/Bundle.wxs deleted file mode 100644 index 7fef0725..00000000 --- a/src/test/WixToolsetTest.Util/TestData/BundleWithSearches/Bundle.wxs +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/MsiPackage/Shared.dll b/src/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/MsiPackage/Shared.dll deleted file mode 100644 index 0e461ba8..00000000 --- a/src/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/MsiPackage/Shared.dll +++ /dev/null @@ -1 +0,0 @@ -This is Shared.dll. \ No newline at end of file diff --git a/src/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/MsiPackage/test.txt b/src/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/MsiPackage/test.txt deleted file mode 100644 index 8b986220..00000000 --- a/src/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/MsiPackage/test.txt +++ /dev/null @@ -1 +0,0 @@ -This is test.txt \ No newline at end of file diff --git a/src/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/fakeba.dll b/src/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/fakeba.dll deleted file mode 100644 index 970efdf0..00000000 --- a/src/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/fakeba.dll +++ /dev/null @@ -1 +0,0 @@ -This is a fakeba.dll \ No newline at end of file diff --git a/src/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/test.msi b/src/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/test.msi deleted file mode 100644 index 0722d60e..00000000 Binary files a/src/test/WixToolsetTest.Util/TestData/BundleWithSearches/data/test.msi and /dev/null differ diff --git a/src/test/WixToolsetTest.Util/TestData/CloseApplication/Package.en-us.wxl b/src/test/WixToolsetTest.Util/TestData/CloseApplication/Package.en-us.wxl deleted file mode 100644 index 5301bb1a..00000000 --- a/src/test/WixToolsetTest.Util/TestData/CloseApplication/Package.en-us.wxl +++ /dev/null @@ -1,9 +0,0 @@ - - - - A newer version of [ProductName] is already installed. - MsiPackage - - diff --git a/src/test/WixToolsetTest.Util/TestData/CloseApplication/Package.wxs b/src/test/WixToolsetTest.Util/TestData/CloseApplication/Package.wxs deleted file mode 100644 index 8e054256..00000000 --- a/src/test/WixToolsetTest.Util/TestData/CloseApplication/Package.wxs +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Util/TestData/CloseApplication/PackageComponents.wxs b/src/test/WixToolsetTest.Util/TestData/CloseApplication/PackageComponents.wxs deleted file mode 100644 index e27b3c43..00000000 --- a/src/test/WixToolsetTest.Util/TestData/CloseApplication/PackageComponents.wxs +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/src/test/WixToolsetTest.Util/TestData/CloseApplication/example.txt b/src/test/WixToolsetTest.Util/TestData/CloseApplication/example.txt deleted file mode 100644 index 1b4ffe8a..00000000 --- a/src/test/WixToolsetTest.Util/TestData/CloseApplication/example.txt +++ /dev/null @@ -1 +0,0 @@ -This is example.txt. \ No newline at end of file diff --git a/src/test/WixToolsetTest.Util/TestData/EventManifest/Package.en-us.wxl b/src/test/WixToolsetTest.Util/TestData/EventManifest/Package.en-us.wxl deleted file mode 100644 index 5301bb1a..00000000 --- a/src/test/WixToolsetTest.Util/TestData/EventManifest/Package.en-us.wxl +++ /dev/null @@ -1,9 +0,0 @@ - - - - A newer version of [ProductName] is already installed. - MsiPackage - - diff --git a/src/test/WixToolsetTest.Util/TestData/EventManifest/Package.wxs b/src/test/WixToolsetTest.Util/TestData/EventManifest/Package.wxs deleted file mode 100644 index daae573a..00000000 --- a/src/test/WixToolsetTest.Util/TestData/EventManifest/Package.wxs +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Util/TestData/EventManifest/PackageComponents.wxs b/src/test/WixToolsetTest.Util/TestData/EventManifest/PackageComponents.wxs deleted file mode 100644 index 2ec8ce82..00000000 --- a/src/test/WixToolsetTest.Util/TestData/EventManifest/PackageComponents.wxs +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Util/TestData/EventManifest/example.txt b/src/test/WixToolsetTest.Util/TestData/EventManifest/example.txt deleted file mode 100644 index 1b4ffe8a..00000000 --- a/src/test/WixToolsetTest.Util/TestData/EventManifest/example.txt +++ /dev/null @@ -1 +0,0 @@ -This is example.txt. \ No newline at end of file diff --git a/src/test/WixToolsetTest.Util/TestData/InternetShortcut/Package.en-us.wxl b/src/test/WixToolsetTest.Util/TestData/InternetShortcut/Package.en-us.wxl deleted file mode 100644 index 5301bb1a..00000000 --- a/src/test/WixToolsetTest.Util/TestData/InternetShortcut/Package.en-us.wxl +++ /dev/null @@ -1,9 +0,0 @@ - - - - A newer version of [ProductName] is already installed. - MsiPackage - - diff --git a/src/test/WixToolsetTest.Util/TestData/InternetShortcut/Package.ico b/src/test/WixToolsetTest.Util/TestData/InternetShortcut/Package.ico deleted file mode 100644 index 53134de7..00000000 Binary files a/src/test/WixToolsetTest.Util/TestData/InternetShortcut/Package.ico and /dev/null differ diff --git a/src/test/WixToolsetTest.Util/TestData/InternetShortcut/Package.wxs b/src/test/WixToolsetTest.Util/TestData/InternetShortcut/Package.wxs deleted file mode 100644 index daae573a..00000000 --- a/src/test/WixToolsetTest.Util/TestData/InternetShortcut/Package.wxs +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Util/TestData/InternetShortcut/PackageComponents.wxs b/src/test/WixToolsetTest.Util/TestData/InternetShortcut/PackageComponents.wxs deleted file mode 100644 index 2a1b4347..00000000 --- a/src/test/WixToolsetTest.Util/TestData/InternetShortcut/PackageComponents.wxs +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Util/TestData/InternetShortcut/example.txt b/src/test/WixToolsetTest.Util/TestData/InternetShortcut/example.txt deleted file mode 100644 index 1b4ffe8a..00000000 --- a/src/test/WixToolsetTest.Util/TestData/InternetShortcut/example.txt +++ /dev/null @@ -1 +0,0 @@ -This is example.txt. \ No newline at end of file diff --git a/src/test/WixToolsetTest.Util/TestData/InternetShortcutModule/Module.wxs b/src/test/WixToolsetTest.Util/TestData/InternetShortcutModule/Module.wxs deleted file mode 100644 index 1355d42e..00000000 --- a/src/test/WixToolsetTest.Util/TestData/InternetShortcutModule/Module.wxs +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Util/TestData/InternetShortcutModule/ModuleComponents.wxs b/src/test/WixToolsetTest.Util/TestData/InternetShortcutModule/ModuleComponents.wxs deleted file mode 100644 index 2a1b4347..00000000 --- a/src/test/WixToolsetTest.Util/TestData/InternetShortcutModule/ModuleComponents.wxs +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Util/TestData/InternetShortcutModule/Package.ico b/src/test/WixToolsetTest.Util/TestData/InternetShortcutModule/Package.ico deleted file mode 100644 index 53134de7..00000000 Binary files a/src/test/WixToolsetTest.Util/TestData/InternetShortcutModule/Package.ico and /dev/null differ diff --git a/src/test/WixToolsetTest.Util/TestData/PermissionEx/Package.en-us.wxl b/src/test/WixToolsetTest.Util/TestData/PermissionEx/Package.en-us.wxl deleted file mode 100644 index 5301bb1a..00000000 --- a/src/test/WixToolsetTest.Util/TestData/PermissionEx/Package.en-us.wxl +++ /dev/null @@ -1,9 +0,0 @@ - - - - A newer version of [ProductName] is already installed. - MsiPackage - - diff --git a/src/test/WixToolsetTest.Util/TestData/PermissionEx/Package.wxs b/src/test/WixToolsetTest.Util/TestData/PermissionEx/Package.wxs deleted file mode 100644 index daae573a..00000000 --- a/src/test/WixToolsetTest.Util/TestData/PermissionEx/Package.wxs +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Util/TestData/PermissionEx/PackageComponents.wxs b/src/test/WixToolsetTest.Util/TestData/PermissionEx/PackageComponents.wxs deleted file mode 100644 index 0634d7d4..00000000 --- a/src/test/WixToolsetTest.Util/TestData/PermissionEx/PackageComponents.wxs +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Util/TestData/PermissionEx/example.txt b/src/test/WixToolsetTest.Util/TestData/PermissionEx/example.txt deleted file mode 100644 index 1b4ffe8a..00000000 --- a/src/test/WixToolsetTest.Util/TestData/PermissionEx/example.txt +++ /dev/null @@ -1 +0,0 @@ -This is example.txt. \ No newline at end of file diff --git a/src/test/WixToolsetTest.Util/TestData/Queries/Package.en-us.wxl b/src/test/WixToolsetTest.Util/TestData/Queries/Package.en-us.wxl deleted file mode 100644 index 5301bb1a..00000000 --- a/src/test/WixToolsetTest.Util/TestData/Queries/Package.en-us.wxl +++ /dev/null @@ -1,9 +0,0 @@ - - - - A newer version of [ProductName] is already installed. - MsiPackage - - diff --git a/src/test/WixToolsetTest.Util/TestData/Queries/Package.wxs b/src/test/WixToolsetTest.Util/TestData/Queries/Package.wxs deleted file mode 100644 index abf0dbb4..00000000 --- a/src/test/WixToolsetTest.Util/TestData/Queries/Package.wxs +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Util/TestData/Queries/PackageComponents.wxs b/src/test/WixToolsetTest.Util/TestData/Queries/PackageComponents.wxs deleted file mode 100644 index e27b3c43..00000000 --- a/src/test/WixToolsetTest.Util/TestData/Queries/PackageComponents.wxs +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/src/test/WixToolsetTest.Util/TestData/Queries/example.txt b/src/test/WixToolsetTest.Util/TestData/Queries/example.txt deleted file mode 100644 index 1b4ffe8a..00000000 --- a/src/test/WixToolsetTest.Util/TestData/Queries/example.txt +++ /dev/null @@ -1 +0,0 @@ -This is example.txt. \ No newline at end of file diff --git a/src/test/WixToolsetTest.Util/TestData/RemoveFolderEx/Module.wxs b/src/test/WixToolsetTest.Util/TestData/RemoveFolderEx/Module.wxs deleted file mode 100644 index 2c2be584..00000000 --- a/src/test/WixToolsetTest.Util/TestData/RemoveFolderEx/Module.wxs +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Util/TestData/RemoveFolderEx/ModuleComponents.wxs b/src/test/WixToolsetTest.Util/TestData/RemoveFolderEx/ModuleComponents.wxs deleted file mode 100644 index 236d9df0..00000000 --- a/src/test/WixToolsetTest.Util/TestData/RemoveFolderEx/ModuleComponents.wxs +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Util/TestData/RemoveRegistryKeyEx/Module.wxs b/src/test/WixToolsetTest.Util/TestData/RemoveRegistryKeyEx/Module.wxs deleted file mode 100644 index 32b246f4..00000000 --- a/src/test/WixToolsetTest.Util/TestData/RemoveRegistryKeyEx/Module.wxs +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Util/TestData/RemoveRegistryKeyEx/ModuleComponents.wxs b/src/test/WixToolsetTest.Util/TestData/RemoveRegistryKeyEx/ModuleComponents.wxs deleted file mode 100644 index 0a0c8cb6..00000000 --- a/src/test/WixToolsetTest.Util/TestData/RemoveRegistryKeyEx/ModuleComponents.wxs +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Util/TestData/UsingFileShare/Package.en-us.wxl b/src/test/WixToolsetTest.Util/TestData/UsingFileShare/Package.en-us.wxl deleted file mode 100644 index 5301bb1a..00000000 --- a/src/test/WixToolsetTest.Util/TestData/UsingFileShare/Package.en-us.wxl +++ /dev/null @@ -1,9 +0,0 @@ - - - - A newer version of [ProductName] is already installed. - MsiPackage - - diff --git a/src/test/WixToolsetTest.Util/TestData/UsingFileShare/Package.wxs b/src/test/WixToolsetTest.Util/TestData/UsingFileShare/Package.wxs deleted file mode 100644 index daae573a..00000000 --- a/src/test/WixToolsetTest.Util/TestData/UsingFileShare/Package.wxs +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Util/TestData/UsingFileShare/PackageComponents.wxs b/src/test/WixToolsetTest.Util/TestData/UsingFileShare/PackageComponents.wxs deleted file mode 100644 index 7cedbb30..00000000 --- a/src/test/WixToolsetTest.Util/TestData/UsingFileShare/PackageComponents.wxs +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Util/TestData/UsingFileShare/example.txt b/src/test/WixToolsetTest.Util/TestData/UsingFileShare/example.txt deleted file mode 100644 index 1b4ffe8a..00000000 --- a/src/test/WixToolsetTest.Util/TestData/UsingFileShare/example.txt +++ /dev/null @@ -1 +0,0 @@ -This is example.txt. \ No newline at end of file diff --git a/src/test/WixToolsetTest.Util/TestData/XmlConfig/Package.en-us.wxl b/src/test/WixToolsetTest.Util/TestData/XmlConfig/Package.en-us.wxl deleted file mode 100644 index 5301bb1a..00000000 --- a/src/test/WixToolsetTest.Util/TestData/XmlConfig/Package.en-us.wxl +++ /dev/null @@ -1,9 +0,0 @@ - - - - A newer version of [ProductName] is already installed. - MsiPackage - - diff --git a/src/test/WixToolsetTest.Util/TestData/XmlConfig/Package.wxs b/src/test/WixToolsetTest.Util/TestData/XmlConfig/Package.wxs deleted file mode 100644 index a2002634..00000000 --- a/src/test/WixToolsetTest.Util/TestData/XmlConfig/Package.wxs +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Util/TestData/XmlConfigModule/Module.wxs b/src/test/WixToolsetTest.Util/TestData/XmlConfigModule/Module.wxs deleted file mode 100644 index 29e8555b..00000000 --- a/src/test/WixToolsetTest.Util/TestData/XmlConfigModule/Module.wxs +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Util/TestData/XmlConfigModule/my.xml b/src/test/WixToolsetTest.Util/TestData/XmlConfigModule/my.xml deleted file mode 100644 index bad25217..00000000 --- a/src/test/WixToolsetTest.Util/TestData/XmlConfigModule/my.xml +++ /dev/null @@ -1 +0,0 @@ -This is my.xml file. diff --git a/src/test/WixToolsetTest.Util/UtilExtensionFixture.cs b/src/test/WixToolsetTest.Util/UtilExtensionFixture.cs deleted file mode 100644 index 883f9794..00000000 --- a/src/test/WixToolsetTest.Util/UtilExtensionFixture.cs +++ /dev/null @@ -1,317 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolsetTest.Util -{ - using System.IO; - using System.Linq; - using WixBuildTools.TestSupport; - using WixToolset.Core.TestPackage; - using WixToolset.Data; - using WixToolset.Data.Symbols; - using WixToolset.Util; - using Xunit; - - public class UtilExtensionFixture - { - [Fact] - public void CanBuildUsingFileShare() - { - var folder = TestData.Get(@"TestData\UsingFileShare"); - var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }); - - var results = build.BuildAndQuery(Build, "Binary", "CustomAction", "Wix4FileShare", "Wix4FileSharePermissions"); - WixAssert.CompareLineByLine(new[] - { - "Binary:Wix4UtilCA_X86\t[Binary data]", - "CustomAction:Wix4ConfigureSmbInstall_X86\t1\tWix4UtilCA_X86\tConfigureSmbInstall\t", - "CustomAction:Wix4ConfigureSmbUninstall_X86\t1\tWix4UtilCA_X86\tConfigureSmbUninstall\t", - "CustomAction:Wix4CreateSmb_X86\t11265\tWix4UtilCA_X86\tCreateSmb\t", - "CustomAction:Wix4CreateSmbRollback_X86\t11585\tWix4UtilCA_X86\tDropSmb\t", - "CustomAction:Wix4DropSmb_X86\t11265\tWix4UtilCA_X86\tDropSmb\t", - "CustomAction:Wix4DropSmbRollback_X86\t11585\tWix4UtilCA_X86\tCreateSmb\t", - "Wix4FileShare:ExampleFileShare\texample\tfilF5_pLhBuF5b4N9XEo52g_hUM5Lo\tAn example file share\tINSTALLFOLDER", - "Wix4FileSharePermissions:ExampleFileShare\tEveryone\t1", - }, results.OrderBy(s => s).ToArray()); - } - - [Fact] - public void CanBuildUsingFileShareX64() - { - var folder = TestData.Get(@"TestData\UsingFileShare"); - var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }); - - var results = build.BuildAndQuery(BuildX64, "Binary", "CustomAction", "Wix4FileShare", "Wix4FileSharePermissions"); - WixAssert.CompareLineByLine(new[] - { - "Binary:Wix4UtilCA_X64\t[Binary data]", - "CustomAction:Wix4ConfigureSmbInstall_X64\t1\tWix4UtilCA_X64\tConfigureSmbInstall\t", - "CustomAction:Wix4ConfigureSmbUninstall_X64\t1\tWix4UtilCA_X64\tConfigureSmbUninstall\t", - "CustomAction:Wix4CreateSmb_X64\t11265\tWix4UtilCA_X64\tCreateSmb\t", - "CustomAction:Wix4CreateSmbRollback_X64\t11585\tWix4UtilCA_X64\tDropSmb\t", - "CustomAction:Wix4DropSmb_X64\t11265\tWix4UtilCA_X64\tDropSmb\t", - "CustomAction:Wix4DropSmbRollback_X64\t11585\tWix4UtilCA_X64\tCreateSmb\t", - "Wix4FileShare:ExampleFileShare\texample\tfilF5_pLhBuF5b4N9XEo52g_hUM5Lo\tAn example file share\tINSTALLFOLDER", - "Wix4FileSharePermissions:ExampleFileShare\tEveryone\t1", - }, results.OrderBy(s => s).ToArray()); - } - - [Fact] - public void CanBuildCloseApplication() - { - var folder = TestData.Get(@"TestData\CloseApplication"); - var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }); - - var results = build.BuildAndQuery(BuildARM64, "Binary", "CustomAction", "Wix4CloseApplication"); - WixAssert.CompareLineByLine(new[] - { - "Binary:Wix4UtilCA_A64\t[Binary data]", - "CustomAction:Wix4CheckRebootRequired_A64\t65\tWix4UtilCA_A64\tWixCheckRebootRequired\t", - "CustomAction:Wix4CloseApplications_A64\t1\tWix4UtilCA_A64\tWixCloseApplications\t", - "CustomAction:Wix4CloseApplicationsDeferred_A64\t3073\tWix4UtilCA_A64\tWixCloseApplicationsDeferred\t", - "Wix4CloseApplication:CloseMyApp\texplorer.exe\t\t\t3\t\tMYAPPISRUNNING\t\t", - }, results.OrderBy(s => s).ToArray()); - } - - [Fact] - public void CanBuildInternetShortcutInProduct() - { - var folder = TestData.Get(@"TestData\InternetShortcut"); - var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }); - - var results = build.BuildAndQuery(BuildX64, "Binary", "CustomAction", "RemoveFile", "Wix4InternetShortcut"); - WixAssert.CompareLineByLine(new[] - { - "Binary:Wix4UtilCA_X64\t[Binary data]", - "CustomAction:Wix4CreateInternetShortcuts_X64\t3073\tWix4UtilCA_X64\tWixCreateInternetShortcuts\t", - "CustomAction:Wix4RollbackInternetShortcuts_X64\t3329\tWix4UtilCA_X64\tWixRollbackInternetShortcuts\t", - "CustomAction:Wix4SchedInternetShortcuts_X64\t1\tWix4UtilCA_X64\tWixSchedInternetShortcuts\t", - "RemoveFile:uisdCsU32.1i4Hebrg1N7E194zJQ8Y\tPackage.ico\thoiptxrr.url|WiX Toolset (url).url\tINSTALLFOLDER\t2", - "RemoveFile:uisjV.q0ROZZYR3h_lkpbkZtLtPH0A\tPackage.ico\tjcxd1dwf.lnk|WiX Toolset (link).lnk\tINSTALLFOLDER\t2", - "Wix4InternetShortcut:uisdCsU32.1i4Hebrg1N7E194zJQ8Y\tPackage.ico\tINSTALLFOLDER\tWiX Toolset (url).url\thttps://wixtoolset.org\t1\t[#Package.ico]\t0", - "Wix4InternetShortcut:uisjV.q0ROZZYR3h_lkpbkZtLtPH0A\tPackage.ico\tINSTALLFOLDER\tWiX Toolset (link).lnk\thttps://wixtoolset.org\t0\t[#Package.ico]\t0", - }, results.OrderBy(s => s).ToArray()); - } - - [Fact] - public void CanBuildInternetShortcutInMergeModule() - { - var folder = TestData.Get(@"TestData\InternetShortcutModule"); - var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }, "test.msm"); - - var results = build.BuildAndQuery(BuildX64, "Binary", "CustomAction", "RemoveFile", "Wix4InternetShortcut"); - WixAssert.CompareLineByLine(new[] - { - "Binary:Wix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A\t[Binary data]", - "CustomAction:Wix4CreateInternetShortcuts_X64\t3073\tWix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A\tWixCreateInternetShortcuts\t", - "CustomAction:Wix4RollbackInternetShortcuts_X64\t3329\tWix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A\tWixRollbackInternetShortcuts\t", - "CustomAction:Wix4SchedInternetShortcuts_X64\t1\tWix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A\tWixSchedInternetShortcuts\t", - "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", - "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", - "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", - "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", - }, results.OrderBy(s => s).ToArray()); - } - - [Fact] - public void CanBuildWithPermissionEx() - { - var folder = TestData.Get(@"TestData\PermissionEx"); - var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }); - - var results = build.BuildAndQuery(BuildX64, "Wix4SecureObject"); - WixAssert.CompareLineByLine(new[] - { - "Wix4SecureObject:ExampleRegistryKey\tRegistry\t\tEveryone\t1\t268435456\tfilF5_pLhBuF5b4N9XEo52g_hUM5Lo", - "Wix4SecureObject:filF5_pLhBuF5b4N9XEo52g_hUM5Lo\tFile\t\tEveryone\t1\t268435456\tfilF5_pLhBuF5b4N9XEo52g_hUM5Lo", - "Wix4SecureObject:INSTALLFOLDER\tCreateFolder\t\tEveryone\t1\t268435456\tfilF5_pLhBuF5b4N9XEo52g_hUM5Lo", - "Wix4SecureObject:regL6DnQ9yJpDJH5OdcVji4YXsdX2c\tRegistry\t\tEveryone\t1\t268435456\tfilF5_pLhBuF5b4N9XEo52g_hUM5Lo", - "Wix4SecureObject:testsvc\tServiceInstall\t\tEveryone\t1\t268435456\tfilF5_pLhBuF5b4N9XEo52g_hUM5Lo", - }, results.OrderBy(s => s).ToArray()); - } - - [Fact] - public void CanBuildRemoveRegistryKeyExInMergeModule() - { - var folder = TestData.Get(@"TestData", "RemoveRegistryKeyEx"); - var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }, "test.msm"); - - var results = build.BuildAndQuery(BuildX64, "Binary", "CustomAction", "RemoveRegistry", "Wix4RemoveRegistryKeyEx"); - WixAssert.CompareLineByLine(new[] - { - "Binary:Wix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A\t[Binary data]", - "CustomAction:Wix4RemoveRegistryKeysEx_X64.047730A5_30FE_4A62_A520_DA9381B8226A\t65\tWix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A\tWixRemoveRegistryKeysEx\t", - "Wix4RemoveRegistryKeyEx:rrxfcDhR4HhE3v3rYiQcNtQjyahQNg.047730A5_30FE_4A62_A520_DA9381B8226A\tfilh4juyUVjoUcWWtcQmd5L07FoON4.047730A5_30FE_4A62_A520_DA9381B8226A\t2\tSOFTWARE\\Example\t1\t", - }, results.OrderBy(s => s).ToArray()); - } - - [Fact] - public void CanBuildRemoveFolderExInMergeModule() - { - var folder = TestData.Get(@"TestData\RemoveFolderEx"); - var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }, "test.msm"); - - var results = build.BuildAndQuery(BuildX64, "Binary", "CustomAction", "RemoveFile", "Wix4RemoveFolderEx"); - WixAssert.CompareLineByLine(new[] - { - "Binary:Wix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A\t[Binary data]", - "CustomAction:Wix4RemoveFoldersEx_X64.047730A5_30FE_4A62_A520_DA9381B8226A\t65\tWix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A\tWixRemoveFoldersEx\t", - "Wix4RemoveFolderEx:wrf5qCm1SE.zp8djrlk78l1IYFXsEw.047730A5_30FE_4A62_A520_DA9381B8226A\tfilh4juyUVjoUcWWtcQmd5L07FoON4.047730A5_30FE_4A62_A520_DA9381B8226A\tRemoveProp.047730A5_30FE_4A62_A520_DA9381B8226A\t3\t", - }, results.OrderBy(s => s).ToArray()); - } - - [Fact] - public void CanBuildWithEventManifest() - { - var folder = TestData.Get(@"TestData\EventManifest"); - var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }); - - var results = build.BuildAndQuery(BuildARM64, "Binary", "CustomAction", "Wix4EventManifest", "Wix4XmlFile"); - WixAssert.CompareLineByLine(new[] - { - "Binary:Wix4UtilCA_A64\t[Binary data]", - "CustomAction:Wix4ConfigureEventManifestRegister_A64\t1\tWix4UtilCA_A64\tConfigureEventManifestRegister\t", - "CustomAction:Wix4ConfigureEventManifestUnregister_A64\t1\tWix4UtilCA_A64\tConfigureEventManifestUnregister\t", - "CustomAction:Wix4ExecXmlFile_A64\t11265\tWix4UtilCA_A64\tExecXmlFile\t", - "CustomAction:Wix4ExecXmlFileRollback_A64\t11521\tWix4UtilCA_A64\tExecXmlFileRollback\t", - "CustomAction:Wix4RegisterEventManifest_A64\t3073\tWix4UtilCA_A64\tWixQuietExec\t", - "CustomAction:Wix4RollbackRegisterEventManifest_A64\t3393\tWix4UtilCA_A64\tWixQuietExec\t", - "CustomAction:Wix4RollbackUnregisterEventManifest_A64\t3329\tWix4UtilCA_A64\tWixQuietExec\t", - "CustomAction:Wix4SchedXmlFile_A64\t1\tWix4UtilCA_A64\tSchedXmlFile\t", - "CustomAction:Wix4UnregisterEventManifest_A64\t3137\tWix4UtilCA_A64\tWixQuietExec\t", - "Wix4EventManifest:Manifest.dll\t[#Manifest.dll]", - "Wix4XmlFile:Config_Manifest.dllMessageFile\t[#Manifest.dll]\t/*/*/*/*[\\[]@messageFileName[\\]]\tmessageFileName\t[Manifest.dll]\t4100\tManifest.dll\t", - "Wix4XmlFile:Config_Manifest.dllResourceFile\t[#Manifest.dll]\t/*/*/*/*[\\[]@resourceFileName[\\]]\tresourceFileName\t[Manifest.dll]\t4100\tManifest.dll\t", - }, results.OrderBy(s => s).ToArray()); - } - - [Fact] - public void CanBuildWithQueries() - { - var folder = TestData.Get(@"TestData\Queries"); - var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }); - - var results = build.BuildAndQuery(BuildARM64, "Binary", "CustomAction"); - WixAssert.CompareLineByLine(new[] - { - "Binary:Wix4UtilCA_A64\t[Binary data]", - "CustomAction:Wix4BroadcastEnvironmentChange_A64\t65\tWix4UtilCA_A64\tWixBroadcastEnvironmentChange\t", - "CustomAction:Wix4BroadcastSettingChange_A64\t65\tWix4UtilCA_A64\tWixBroadcastSettingChange\t", - "CustomAction:Wix4CheckRebootRequired_A64\t65\tWix4UtilCA_A64\tWixCheckRebootRequired\t", - "CustomAction:Wix4QueryOsDriverInfo_A64\t257\tWix4UtilCA_A64\tWixQueryOsDriverInfo\t", - "CustomAction:Wix4QueryOsInfo_A64\t257\tWix4UtilCA_A64\tWixQueryOsInfo\t", - }, results.OrderBy(s => s).ToArray()); - } - - [Fact] - public void CanBuildWithXmlConfig() - { - var folder = TestData.Get(@"TestData", "XmlConfig"); - var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }); - - var results = build.BuildAndQuery(BuildX64, "Wix4XmlConfig"); - WixAssert.CompareLineByLine(new[] - { - "Wix4XmlConfig:DelElement\t[INSTALLFOLDER]my.xml\t\t//root/sub\txxx\t\t\t289\tDel\t1", - }, results.OrderBy(s => s).ToArray()); - } - - [Fact] - public void CanBuildModuleWithXmlConfig() - { - var folder = TestData.Get(@"TestData", "XmlConfigModule"); - var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }); - - var results = build.BuildAndQuery(BuildX64, "Wix4XmlConfig"); - WixAssert.CompareLineByLine(new[] - { - "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", - "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", - }, results.OrderBy(s => s).ToArray()); - } - - [Fact] - public void CanBuildBundleWithSearches() - { - var burnStubPath = TestData.Get(@"TestData\.Data\burn.exe"); - var folder = TestData.Get(@"TestData\BundleWithSearches"); - var rootFolder = TestData.Get(); - var wixext = Path.Combine(rootFolder, "WixToolset.Util.wixext.dll"); - - using (var fs = new DisposableFileSystem()) - { - var baseFolder = fs.GetFolder(); - var intermediateFolder = Path.Combine(baseFolder, "obj"); - var bundlePath = Path.Combine(baseFolder, @"bin\test.exe"); - var baFolderPath = Path.Combine(baseFolder, "ba"); - var extractFolderPath = Path.Combine(baseFolder, "extract"); - - var result = WixRunner.Execute(new[] - { - "build", - Path.Combine(folder, "Bundle.wxs"), - "-ext", wixext, - "-loc", Path.Combine(folder, "Bundle.en-us.wxl"), - "-bindpath", Path.Combine(folder, "data"), - "-intermediateFolder", intermediateFolder, - "-o", bundlePath - }); - - result.AssertSuccess(); - - Assert.True(File.Exists(bundlePath)); -#if TODO - Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb"))); -#endif - - var extractResult = BundleExtractor.ExtractBAContainer(null, bundlePath, baFolderPath, extractFolderPath); - extractResult.AssertSuccess(); - - var bundleExtensionDatas = extractResult.SelectBundleExtensionDataNodes("/be:BundleExtensionData/be:BundleExtension[@Id='Wix4UtilBundleExtension_X86']"); - Assert.Equal(1, bundleExtensionDatas.Count); - Assert.Equal("" + - "" + - "", bundleExtensionDatas[0].GetTestXml()); - - var utilSearches = extractResult.SelectManifestNodes("/burn:BurnManifest/*[self::burn:ExtensionSearch or self::burn:FileSearch or self::burn:MsiProductSearch or self::burn:RegistrySearch]"); - Assert.Equal(5, utilSearches.Count); - Assert.Equal("", utilSearches[0].GetTestXml()); - Assert.Equal("", utilSearches[1].GetTestXml()); - Assert.Equal("", utilSearches[2].GetTestXml()); - Assert.Equal("", utilSearches[3].GetTestXml()); - Assert.Equal("", utilSearches[4].GetTestXml()); - } - } - - private static void Build(string[] args) - { - var result = WixRunner.Execute(args); - result.AssertSuccess(); - } - - private static void BuildX64(string[] args) - { - var newArgs = args.ToList(); - newArgs.Add("-platform"); - newArgs.Add("x64"); - newArgs.Add("-sw1072"); - - var result = WixRunner.Execute(newArgs.ToArray()); - result.AssertSuccess(); - } - - private static void BuildARM64(string[] args) - { - var newArgs = args.ToList(); - newArgs.Add("-platform"); - newArgs.Add("arm64"); - - var result = WixRunner.Execute(newArgs.ToArray()); - result.AssertSuccess(); - } - } -} diff --git a/src/test/WixToolsetTest.Util/WixToolsetTest.Util.csproj b/src/test/WixToolsetTest.Util/WixToolsetTest.Util.csproj deleted file mode 100644 index e77ecbed..00000000 --- a/src/test/WixToolsetTest.Util/WixToolsetTest.Util.csproj +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - netcoreapp3.1 - false - - - - NU1701 - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Util/WixToolsetTest.Util.v3.ncrunchproject b/src/test/WixToolsetTest.Util/WixToolsetTest.Util.v3.ncrunchproject deleted file mode 100644 index 7b5b2139..00000000 --- a/src/test/WixToolsetTest.Util/WixToolsetTest.Util.v3.ncrunchproject +++ /dev/null @@ -1,5 +0,0 @@ - - - True - - \ No newline at end of file diff --git a/src/version.json b/src/version.json new file mode 100644 index 00000000..5f857771 --- /dev/null +++ b/src/version.json @@ -0,0 +1,11 @@ +{ + "version": "4.0", + "publicReleaseRefSpec": [ + "^refs/heads/master$" + ], + "cloudBuild": { + "buildNumber": { + "enabled": true + } + } +} diff --git a/src/wix.snk b/src/wix.snk deleted file mode 100644 index 3908a66a..00000000 Binary files a/src/wix.snk and /dev/null differ diff --git a/src/wixext/PerformanceCounterType.cs b/src/wixext/PerformanceCounterType.cs deleted file mode 100644 index 1e06efd3..00000000 --- a/src/wixext/PerformanceCounterType.cs +++ /dev/null @@ -1,192 +0,0 @@ -// Captured from: C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.dll - -namespace System.Diagnostics -{ - public enum PerformanceCounterType - { - // - // Summary: - // An instantaneous counter that shows the most recently observed value in hexadecimal - // format. Used, for example, to maintain a simple count of items or operations. - NumberOfItemsHEX32 = 0, - // - // Summary: - // An instantaneous counter that shows the most recently observed value. Used, for - // example, to maintain a simple count of a very large number of items or operations. - // It is the same as NumberOfItemsHEX32 except that it uses larger fields to accommodate - // larger values. - NumberOfItemsHEX64 = 256, - // - // Summary: - // An instantaneous counter that shows the most recently observed value. Used, for - // example, to maintain a simple count of items or operations. - NumberOfItems32 = 65536, - // - // Summary: - // An instantaneous counter that shows the most recently observed value. Used, for - // example, to maintain a simple count of a very large number of items or operations. - // It is the same as NumberOfItems32 except that it uses larger fields to accommodate - // larger values. - NumberOfItems64 = 65792, - // - // Summary: - // A difference counter that shows the change in the measured attribute between - // the two most recent sample intervals. - CounterDelta32 = 4195328, - // - // Summary: - // A difference counter that shows the change in the measured attribute between - // the two most recent sample intervals. It is the same as the CounterDelta32 counter - // type except that is uses larger fields to accomodate larger values. - CounterDelta64 = 4195584, - // - // Summary: - // An average counter that shows the average number of operations completed in one - // second. When a counter of this type samples the data, each sampling interrupt - // returns one or zero. The counter data is the number of ones that were sampled. - // It measures time in units of ticks of the system performance timer. - SampleCounter = 4260864, - // - // Summary: - // An average counter designed to monitor the average length of a queue to a resource - // over time. It shows the difference between the queue lengths observed during - // the last two sample intervals divided by the duration of the interval. This type - // of counter is typically used to track the number of items that are queued or - // waiting. - CountPerTimeInterval32 = 4523008, - // - // Summary: - // An average counter that monitors the average length of a queue to a resource - // over time. Counters of this type display the difference between the queue lengths - // observed during the last two sample intervals, divided by the duration of the - // interval. This counter type is the same as CountPerTimeInterval32 except that - // it uses larger fields to accommodate larger values. This type of counter is typically - // used to track a high-volume or very large number of items that are queued or - // waiting. - CountPerTimeInterval64 = 4523264, - // - // Summary: - // A difference counter that shows the average number of operations completed during - // each second of the sample interval. Counters of this type measure time in ticks - // of the system clock. - RateOfCountsPerSecond32 = 272696320, - // - // Summary: - // A difference counter that shows the average number of operations completed during - // each second of the sample interval. Counters of this type measure time in ticks - // of the system clock. This counter type is the same as the RateOfCountsPerSecond32 - // type, but it uses larger fields to accommodate larger values to track a high-volume - // number of items or operations per second, such as a byte-transmission rate. - RateOfCountsPerSecond64 = 272696576, - // - // Summary: - // An instantaneous percentage counter that shows the ratio of a subset to its set - // as a percentage. For example, it compares the number of bytes in use on a disk - // to the total number of bytes on the disk. Counters of this type display the current - // percentage only, not an average over time. - RawFraction = 537003008, - // - // Summary: - // A percentage counter that shows the average time that a component is active as - // a percentage of the total sample time. - CounterTimer = 541132032, - // - // Summary: - // A percentage counter that shows the active time of a component as a percentage - // of the total elapsed time of the sample interval. It measures time in units of - // 100 nanoseconds (ns). Counters of this type are designed to measure the activity - // of one component at a time. - Timer100Ns = 542180608, - // - // Summary: - // A percentage counter that shows the average ratio of hits to all operations during - // the last two sample intervals. - SampleFraction = 549585920, - // - // Summary: - // A percentage counter that displays the average percentage of active time observed - // during sample interval. The value of these counters is calculated by monitoring - // the percentage of time that the service was inactive and then subtracting that - // value from 100 percent. - CounterTimerInverse = 557909248, - // - // Summary: - // A percentage counter that shows the average percentage of active time observed - // during the sample interval. - Timer100NsInverse = 558957824, - // - // Summary: - // A percentage counter that displays the active time of one or more components - // as a percentage of the total time of the sample interval. Because the numerator - // records the active time of components operating simultaneously, the resulting - // percentage can exceed 100 percent. - CounterMultiTimer = 574686464, - // - // Summary: - // A percentage counter that shows the active time of one or more components as - // a percentage of the total time of the sample interval. It measures time in 100 - // nanosecond (ns) units. - CounterMultiTimer100Ns = 575735040, - // - // Summary: - // A percentage counter that shows the active time of one or more components as - // a percentage of the total time of the sample interval. It derives the active - // time by measuring the time that the components were not active and subtracting - // the result from 100 percent by the number of objects monitored. - CounterMultiTimerInverse = 591463680, - // - // Summary: - // A percentage counter that shows the active time of one or more components as - // a percentage of the total time of the sample interval. Counters of this type - // measure time in 100 nanosecond (ns) units. They derive the active time by measuring - // the time that the components were not active and subtracting the result from - // multiplying 100 percent by the number of objects monitored. - CounterMultiTimer100NsInverse = 592512256, - // - // Summary: - // An average counter that measures the time it takes, on average, to complete a - // process or operation. Counters of this type display a ratio of the total elapsed - // time of the sample interval to the number of processes or operations completed - // during that time. This counter type measures time in ticks of the system clock. - AverageTimer32 = 805438464, - // - // Summary: - // A difference timer that shows the total time between when the component or process - // started and the time when this value is calculated. - ElapsedTime = 807666944, - // - // Summary: - // An average counter that shows how many items are processed, on average, during - // an operation. Counters of this type display a ratio of the items processed to - // the number of operations completed. The ratio is calculated by comparing the - // number of items processed during the last interval to the number of operations - // completed during the last interval. - AverageCount64 = 1073874176, - // - // Summary: - // A base counter that stores the number of sampling interrupts taken and is used - // as a denominator in the sampling fraction. The sampling fraction is the number - // of samples that were 1 (or true) for a sample interrupt. Check that this value - // is greater than zero before using it as the denominator in a calculation of SampleFraction. - SampleBase = 1073939457, - // - // Summary: - // A base counter that is used in the calculation of time or count averages, such - // as AverageTimer32 and AverageCount64. Stores the denominator for calculating - // a counter to present "time per operation" or "count per operation". - AverageBase = 1073939458, - // - // Summary: - // A base counter that stores the denominator of a counter that presents a general - // arithmetic fraction. Check that this value is greater than zero before using - // it as the denominator in a RawFraction value calculation. - RawBase = 1073939459, - // - // Summary: - // A base counter that indicates the number of items sampled. It is used as the - // denominator in the calculations to get an average among the items sampled when - // taking timings of multiple, but similar items. Used with CounterMultiTimer, CounterMultiTimerInverse, - // CounterMultiTimer100Ns, and CounterMultiTimer100NsInverse. - CounterMultiBase = 1107494144 - } -} diff --git a/src/wixext/Symbols/EventManifestSymbol.cs b/src/wixext/Symbols/EventManifestSymbol.cs deleted file mode 100644 index ccd3c899..00000000 --- a/src/wixext/Symbols/EventManifestSymbol.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - using WixToolset.Data; - using WixToolset.Util.Symbols; - - public static partial class UtilSymbolDefinitions - { - public static readonly IntermediateSymbolDefinition EventManifest = new IntermediateSymbolDefinition( - UtilSymbolDefinitionType.EventManifest.ToString(), - new[] - { - new IntermediateFieldDefinition(nameof(EventManifestSymbolFields.ComponentRef), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(EventManifestSymbolFields.File), IntermediateFieldType.String), - }, - typeof(EventManifestSymbol)); - } -} - -namespace WixToolset.Util.Symbols -{ - using WixToolset.Data; - - public enum EventManifestSymbolFields - { - ComponentRef, - File, - } - - public class EventManifestSymbol : IntermediateSymbol - { - public EventManifestSymbol() : base(UtilSymbolDefinitions.EventManifest, null, null) - { - } - - public EventManifestSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.EventManifest, sourceLineNumber, id) - { - } - - public IntermediateField this[EventManifestSymbolFields index] => this.Fields[(int)index]; - - public string ComponentRef - { - get => this.Fields[(int)EventManifestSymbolFields.ComponentRef].AsString(); - set => this.Set((int)EventManifestSymbolFields.ComponentRef, value); - } - - public string File - { - get => this.Fields[(int)EventManifestSymbolFields.File].AsString(); - set => this.Set((int)EventManifestSymbolFields.File, value); - } - } -} \ No newline at end of file diff --git a/src/wixext/Symbols/FileSharePermissionsSymbol.cs b/src/wixext/Symbols/FileSharePermissionsSymbol.cs deleted file mode 100644 index 3db92f22..00000000 --- a/src/wixext/Symbols/FileSharePermissionsSymbol.cs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - using WixToolset.Data; - using WixToolset.Util.Symbols; - - public static partial class UtilSymbolDefinitions - { - public static readonly IntermediateSymbolDefinition FileSharePermissions = new IntermediateSymbolDefinition( - UtilSymbolDefinitionType.FileSharePermissions.ToString(), - new[] - { - new IntermediateFieldDefinition(nameof(FileSharePermissionsSymbolFields.FileShareRef), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(FileSharePermissionsSymbolFields.UserRef), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(FileSharePermissionsSymbolFields.Permissions), IntermediateFieldType.Number), - }, - typeof(FileSharePermissionsSymbol)); - } -} - -namespace WixToolset.Util.Symbols -{ - using WixToolset.Data; - - public enum FileSharePermissionsSymbolFields - { - FileShareRef, - UserRef, - Permissions, - } - - public class FileSharePermissionsSymbol : IntermediateSymbol - { - public FileSharePermissionsSymbol() : base(UtilSymbolDefinitions.FileSharePermissions, null, null) - { - } - - public FileSharePermissionsSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.FileSharePermissions, sourceLineNumber, id) - { - } - - public IntermediateField this[FileSharePermissionsSymbolFields index] => this.Fields[(int)index]; - - public string FileShareRef - { - get => this.Fields[(int)FileSharePermissionsSymbolFields.FileShareRef].AsString(); - set => this.Set((int)FileSharePermissionsSymbolFields.FileShareRef, value); - } - - public string UserRef - { - get => this.Fields[(int)FileSharePermissionsSymbolFields.UserRef].AsString(); - set => this.Set((int)FileSharePermissionsSymbolFields.UserRef, value); - } - - public int Permissions - { - get => this.Fields[(int)FileSharePermissionsSymbolFields.Permissions].AsNumber(); - set => this.Set((int)FileSharePermissionsSymbolFields.Permissions, value); - } - } -} \ No newline at end of file diff --git a/src/wixext/Symbols/FileShareSymbol.cs b/src/wixext/Symbols/FileShareSymbol.cs deleted file mode 100644 index c956ff42..00000000 --- a/src/wixext/Symbols/FileShareSymbol.cs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - using WixToolset.Data; - using WixToolset.Util.Symbols; - - public static partial class UtilSymbolDefinitions - { - public static readonly IntermediateSymbolDefinition FileShare = new IntermediateSymbolDefinition( - UtilSymbolDefinitionType.FileShare.ToString(), - new[] - { - new IntermediateFieldDefinition(nameof(FileShareSymbolFields.ShareName), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(FileShareSymbolFields.ComponentRef), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(FileShareSymbolFields.Description), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(FileShareSymbolFields.DirectoryRef), IntermediateFieldType.String), - }, - typeof(FileShareSymbol)); - } -} - -namespace WixToolset.Util.Symbols -{ - using WixToolset.Data; - - public enum FileShareSymbolFields - { - ShareName, - ComponentRef, - Description, - DirectoryRef, - } - - public class FileShareSymbol : IntermediateSymbol - { - public FileShareSymbol() : base(UtilSymbolDefinitions.FileShare, null, null) - { - } - - public FileShareSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.FileShare, sourceLineNumber, id) - { - } - - public IntermediateField this[FileShareSymbolFields index] => this.Fields[(int)index]; - - public string ShareName - { - get => this.Fields[(int)FileShareSymbolFields.ShareName].AsString(); - set => this.Set((int)FileShareSymbolFields.ShareName, value); - } - - public string ComponentRef - { - get => this.Fields[(int)FileShareSymbolFields.ComponentRef].AsString(); - set => this.Set((int)FileShareSymbolFields.ComponentRef, value); - } - - public string Description - { - get => this.Fields[(int)FileShareSymbolFields.Description].AsString(); - set => this.Set((int)FileShareSymbolFields.Description, value); - } - - public string DirectoryRef - { - get => this.Fields[(int)FileShareSymbolFields.DirectoryRef].AsString(); - set => this.Set((int)FileShareSymbolFields.DirectoryRef, value); - } - } -} \ No newline at end of file diff --git a/src/wixext/Symbols/GroupSymbol.cs b/src/wixext/Symbols/GroupSymbol.cs deleted file mode 100644 index b378db44..00000000 --- a/src/wixext/Symbols/GroupSymbol.cs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - using WixToolset.Data; - using WixToolset.Util.Symbols; - - public static partial class UtilSymbolDefinitions - { - public static readonly IntermediateSymbolDefinition Group = new IntermediateSymbolDefinition( - UtilSymbolDefinitionType.Group.ToString(), - new[] - { - new IntermediateFieldDefinition(nameof(GroupSymbolFields.ComponentRef), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(GroupSymbolFields.Name), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(GroupSymbolFields.Domain), IntermediateFieldType.String), - }, - typeof(GroupSymbol)); - } -} - -namespace WixToolset.Util.Symbols -{ - using WixToolset.Data; - - public enum GroupSymbolFields - { - ComponentRef, - Name, - Domain, - } - - public class GroupSymbol : IntermediateSymbol - { - public GroupSymbol() : base(UtilSymbolDefinitions.Group, null, null) - { - } - - public GroupSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.Group, sourceLineNumber, id) - { - } - - public IntermediateField this[GroupSymbolFields index] => this.Fields[(int)index]; - - public string ComponentRef - { - get => this.Fields[(int)GroupSymbolFields.ComponentRef].AsString(); - set => this.Set((int)GroupSymbolFields.ComponentRef, value); - } - - public string Name - { - get => this.Fields[(int)GroupSymbolFields.Name].AsString(); - set => this.Set((int)GroupSymbolFields.Name, value); - } - - public string Domain - { - get => this.Fields[(int)GroupSymbolFields.Domain].AsString(); - set => this.Set((int)GroupSymbolFields.Domain, value); - } - } -} \ No newline at end of file diff --git a/src/wixext/Symbols/PerfmonManifestSymbol.cs b/src/wixext/Symbols/PerfmonManifestSymbol.cs deleted file mode 100644 index 03fef14e..00000000 --- a/src/wixext/Symbols/PerfmonManifestSymbol.cs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - using WixToolset.Data; - using WixToolset.Util.Symbols; - - public static partial class UtilSymbolDefinitions - { - public static readonly IntermediateSymbolDefinition PerfmonManifest = new IntermediateSymbolDefinition( - UtilSymbolDefinitionType.PerfmonManifest.ToString(), - new[] - { - new IntermediateFieldDefinition(nameof(PerfmonManifestSymbolFields.ComponentRef), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(PerfmonManifestSymbolFields.File), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(PerfmonManifestSymbolFields.ResourceFileDirectory), IntermediateFieldType.String), - }, - typeof(PerfmonManifestSymbol)); - } -} - -namespace WixToolset.Util.Symbols -{ - using WixToolset.Data; - - public enum PerfmonManifestSymbolFields - { - ComponentRef, - File, - ResourceFileDirectory, - } - - public class PerfmonManifestSymbol : IntermediateSymbol - { - public PerfmonManifestSymbol() : base(UtilSymbolDefinitions.PerfmonManifest, null, null) - { - } - - public PerfmonManifestSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.PerfmonManifest, sourceLineNumber, id) - { - } - - public IntermediateField this[PerfmonManifestSymbolFields index] => this.Fields[(int)index]; - - public string ComponentRef - { - get => this.Fields[(int)PerfmonManifestSymbolFields.ComponentRef].AsString(); - set => this.Set((int)PerfmonManifestSymbolFields.ComponentRef, value); - } - - public string File - { - get => this.Fields[(int)PerfmonManifestSymbolFields.File].AsString(); - set => this.Set((int)PerfmonManifestSymbolFields.File, value); - } - - public string ResourceFileDirectory - { - get => this.Fields[(int)PerfmonManifestSymbolFields.ResourceFileDirectory].AsString(); - set => this.Set((int)PerfmonManifestSymbolFields.ResourceFileDirectory, value); - } - } -} \ No newline at end of file diff --git a/src/wixext/Symbols/PerfmonSymbol.cs b/src/wixext/Symbols/PerfmonSymbol.cs deleted file mode 100644 index 6784ebd1..00000000 --- a/src/wixext/Symbols/PerfmonSymbol.cs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - using WixToolset.Data; - using WixToolset.Util.Symbols; - - public static partial class UtilSymbolDefinitions - { - public static readonly IntermediateSymbolDefinition Perfmon = new IntermediateSymbolDefinition( - UtilSymbolDefinitionType.Perfmon.ToString(), - new[] - { - new IntermediateFieldDefinition(nameof(PerfmonSymbolFields.ComponentRef), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(PerfmonSymbolFields.File), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(PerfmonSymbolFields.Name), IntermediateFieldType.String), - }, - typeof(PerfmonSymbol)); - } -} - -namespace WixToolset.Util.Symbols -{ - using WixToolset.Data; - - public enum PerfmonSymbolFields - { - ComponentRef, - File, - Name, - } - - public class PerfmonSymbol : IntermediateSymbol - { - public PerfmonSymbol() : base(UtilSymbolDefinitions.Perfmon, null, null) - { - } - - public PerfmonSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.Perfmon, sourceLineNumber, id) - { - } - - public IntermediateField this[PerfmonSymbolFields index] => this.Fields[(int)index]; - - public string ComponentRef - { - get => this.Fields[(int)PerfmonSymbolFields.ComponentRef].AsString(); - set => this.Set((int)PerfmonSymbolFields.ComponentRef, value); - } - - public string File - { - get => this.Fields[(int)PerfmonSymbolFields.File].AsString(); - set => this.Set((int)PerfmonSymbolFields.File, value); - } - - public string Name - { - get => this.Fields[(int)PerfmonSymbolFields.Name].AsString(); - set => this.Set((int)PerfmonSymbolFields.Name, value); - } - } -} \ No newline at end of file diff --git a/src/wixext/Symbols/PerformanceCategorySymbol.cs b/src/wixext/Symbols/PerformanceCategorySymbol.cs deleted file mode 100644 index 5ecf388c..00000000 --- a/src/wixext/Symbols/PerformanceCategorySymbol.cs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - using WixToolset.Data; - using WixToolset.Util.Symbols; - - public static partial class UtilSymbolDefinitions - { - public static readonly IntermediateSymbolDefinition PerformanceCategory = new IntermediateSymbolDefinition( - UtilSymbolDefinitionType.PerformanceCategory.ToString(), - new[] - { - new IntermediateFieldDefinition(nameof(PerformanceCategorySymbolFields.ComponentRef), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(PerformanceCategorySymbolFields.Name), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(PerformanceCategorySymbolFields.IniData), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(PerformanceCategorySymbolFields.ConstantData), IntermediateFieldType.String), - }, - typeof(PerformanceCategorySymbol)); - } -} - -namespace WixToolset.Util.Symbols -{ - using WixToolset.Data; - - public enum PerformanceCategorySymbolFields - { - ComponentRef, - Name, - IniData, - ConstantData, - } - - public class PerformanceCategorySymbol : IntermediateSymbol - { - public PerformanceCategorySymbol() : base(UtilSymbolDefinitions.PerformanceCategory, null, null) - { - } - - public PerformanceCategorySymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.PerformanceCategory, sourceLineNumber, id) - { - } - - public IntermediateField this[PerformanceCategorySymbolFields index] => this.Fields[(int)index]; - - public string ComponentRef - { - get => this.Fields[(int)PerformanceCategorySymbolFields.ComponentRef].AsString(); - set => this.Set((int)PerformanceCategorySymbolFields.ComponentRef, value); - } - - public string Name - { - get => this.Fields[(int)PerformanceCategorySymbolFields.Name].AsString(); - set => this.Set((int)PerformanceCategorySymbolFields.Name, value); - } - - public string IniData - { - get => this.Fields[(int)PerformanceCategorySymbolFields.IniData].AsString(); - set => this.Set((int)PerformanceCategorySymbolFields.IniData, value); - } - - public string ConstantData - { - get => this.Fields[(int)PerformanceCategorySymbolFields.ConstantData].AsString(); - set => this.Set((int)PerformanceCategorySymbolFields.ConstantData, value); - } - } -} \ No newline at end of file diff --git a/src/wixext/Symbols/SecureObjectsSymbol.cs b/src/wixext/Symbols/SecureObjectsSymbol.cs deleted file mode 100644 index 25fc6dca..00000000 --- a/src/wixext/Symbols/SecureObjectsSymbol.cs +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - using WixToolset.Data; - using WixToolset.Util.Symbols; - - public static partial class UtilSymbolDefinitions - { - public static readonly IntermediateSymbolDefinition SecureObjects = new IntermediateSymbolDefinition( - UtilSymbolDefinitionType.SecureObjects.ToString(), - new[] - { - new IntermediateFieldDefinition(nameof(SecureObjectsSymbolFields.SecureObject), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(SecureObjectsSymbolFields.Table), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(SecureObjectsSymbolFields.Domain), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(SecureObjectsSymbolFields.User), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(SecureObjectsSymbolFields.Attributes), IntermediateFieldType.Number), - new IntermediateFieldDefinition(nameof(SecureObjectsSymbolFields.Permission), IntermediateFieldType.Number), - new IntermediateFieldDefinition(nameof(SecureObjectsSymbolFields.ComponentRef), IntermediateFieldType.String), - }, - typeof(SecureObjectsSymbol)); - } -} - -namespace WixToolset.Util.Symbols -{ - using System; - using WixToolset.Data; - - public enum SecureObjectsSymbolFields - { - SecureObject, - Table, - Domain, - User, - Attributes, - Permission, - ComponentRef, - } - - [Flags] - public enum WixPermissionExAttributes - { - None = 0x0, - Inheritable = 0x01 - } - - public class SecureObjectsSymbol : IntermediateSymbol - { - public SecureObjectsSymbol() : base(UtilSymbolDefinitions.SecureObjects, null, null) - { - } - - public SecureObjectsSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.SecureObjects, sourceLineNumber, id) - { - } - - public IntermediateField this[SecureObjectsSymbolFields index] => this.Fields[(int)index]; - - public string SecureObject - { - get => this.Fields[(int)SecureObjectsSymbolFields.SecureObject].AsString(); - set => this.Set((int)SecureObjectsSymbolFields.SecureObject, value); - } - - public string Table - { - get => this.Fields[(int)SecureObjectsSymbolFields.Table].AsString(); - set => this.Set((int)SecureObjectsSymbolFields.Table, value); - } - - public string Domain - { - get => this.Fields[(int)SecureObjectsSymbolFields.Domain].AsString(); - set => this.Set((int)SecureObjectsSymbolFields.Domain, value); - } - - public string User - { - get => this.Fields[(int)SecureObjectsSymbolFields.User].AsString(); - set => this.Set((int)SecureObjectsSymbolFields.User, value); - } - - public WixPermissionExAttributes Attributes - { - get => (WixPermissionExAttributes)this.Fields[(int)SecureObjectsSymbolFields.Attributes].AsNumber(); - set => this.Set((int)SecureObjectsSymbolFields.Attributes, (int)value); - } - - public int? Permission - { - get => this.Fields[(int)SecureObjectsSymbolFields.Permission].AsNullableNumber(); - set => this.Set((int)SecureObjectsSymbolFields.Permission, value); - } - - public string ComponentRef - { - get => this.Fields[(int)SecureObjectsSymbolFields.ComponentRef].AsString(); - set => this.Set((int)SecureObjectsSymbolFields.ComponentRef, value); - } - } -} \ No newline at end of file diff --git a/src/wixext/Symbols/ServiceConfigSymbol.cs b/src/wixext/Symbols/ServiceConfigSymbol.cs deleted file mode 100644 index 3a877f9b..00000000 --- a/src/wixext/Symbols/ServiceConfigSymbol.cs +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - using WixToolset.Data; - using WixToolset.Util.Symbols; - - public static partial class UtilSymbolDefinitions - { - public static readonly IntermediateSymbolDefinition ServiceConfig = new IntermediateSymbolDefinition( - UtilSymbolDefinitionType.ServiceConfig.ToString(), - new[] - { - new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.ServiceName), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.ComponentRef), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.NewService), IntermediateFieldType.Number), - new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.FirstFailureActionType), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.SecondFailureActionType), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.ThirdFailureActionType), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.ResetPeriodInDays), IntermediateFieldType.Number), - new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.RestartServiceDelayInSeconds), IntermediateFieldType.Number), - new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.ProgramCommandLine), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(ServiceConfigSymbolFields.RebootMessage), IntermediateFieldType.String), - }, - typeof(ServiceConfigSymbol)); - } -} - -namespace WixToolset.Util.Symbols -{ - using WixToolset.Data; - - public enum ServiceConfigSymbolFields - { - ServiceName, - ComponentRef, - NewService, - FirstFailureActionType, - SecondFailureActionType, - ThirdFailureActionType, - ResetPeriodInDays, - RestartServiceDelayInSeconds, - ProgramCommandLine, - RebootMessage, - } - - public class ServiceConfigSymbol : IntermediateSymbol - { - public ServiceConfigSymbol() : base(UtilSymbolDefinitions.ServiceConfig, null, null) - { - } - - public ServiceConfigSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.ServiceConfig, sourceLineNumber, id) - { - } - - public IntermediateField this[ServiceConfigSymbolFields index] => this.Fields[(int)index]; - - public string ServiceName - { - get => this.Fields[(int)ServiceConfigSymbolFields.ServiceName].AsString(); - set => this.Set((int)ServiceConfigSymbolFields.ServiceName, value); - } - - public string ComponentRef - { - get => this.Fields[(int)ServiceConfigSymbolFields.ComponentRef].AsString(); - set => this.Set((int)ServiceConfigSymbolFields.ComponentRef, value); - } - - public int NewService - { - get => this.Fields[(int)ServiceConfigSymbolFields.NewService].AsNumber(); - set => this.Set((int)ServiceConfigSymbolFields.NewService, value); - } - - public string FirstFailureActionType - { - get => this.Fields[(int)ServiceConfigSymbolFields.FirstFailureActionType].AsString(); - set => this.Set((int)ServiceConfigSymbolFields.FirstFailureActionType, value); - } - - public string SecondFailureActionType - { - get => this.Fields[(int)ServiceConfigSymbolFields.SecondFailureActionType].AsString(); - set => this.Set((int)ServiceConfigSymbolFields.SecondFailureActionType, value); - } - - public string ThirdFailureActionType - { - get => this.Fields[(int)ServiceConfigSymbolFields.ThirdFailureActionType].AsString(); - set => this.Set((int)ServiceConfigSymbolFields.ThirdFailureActionType, value); - } - - public int? ResetPeriodInDays - { - get => this.Fields[(int)ServiceConfigSymbolFields.ResetPeriodInDays].AsNullableNumber(); - set => this.Set((int)ServiceConfigSymbolFields.ResetPeriodInDays, value); - } - - public int? RestartServiceDelayInSeconds - { - get => this.Fields[(int)ServiceConfigSymbolFields.RestartServiceDelayInSeconds].AsNullableNumber(); - set => this.Set((int)ServiceConfigSymbolFields.RestartServiceDelayInSeconds, value); - } - - public string ProgramCommandLine - { - get => this.Fields[(int)ServiceConfigSymbolFields.ProgramCommandLine].AsString(); - set => this.Set((int)ServiceConfigSymbolFields.ProgramCommandLine, value); - } - - public string RebootMessage - { - get => this.Fields[(int)ServiceConfigSymbolFields.RebootMessage].AsString(); - set => this.Set((int)ServiceConfigSymbolFields.RebootMessage, value); - } - } -} \ No newline at end of file diff --git a/src/wixext/Symbols/UserGroupSymbol.cs b/src/wixext/Symbols/UserGroupSymbol.cs deleted file mode 100644 index c8f3998e..00000000 --- a/src/wixext/Symbols/UserGroupSymbol.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - using WixToolset.Data; - using WixToolset.Util.Symbols; - - public static partial class UtilSymbolDefinitions - { - public static readonly IntermediateSymbolDefinition UserGroup = new IntermediateSymbolDefinition( - UtilSymbolDefinitionType.UserGroup.ToString(), - new[] - { - new IntermediateFieldDefinition(nameof(UserGroupSymbolFields.UserRef), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(UserGroupSymbolFields.GroupRef), IntermediateFieldType.String), - }, - typeof(UserGroupSymbol)); - } -} - -namespace WixToolset.Util.Symbols -{ - using WixToolset.Data; - - public enum UserGroupSymbolFields - { - UserRef, - GroupRef, - } - - public class UserGroupSymbol : IntermediateSymbol - { - public UserGroupSymbol() : base(UtilSymbolDefinitions.UserGroup, null, null) - { - } - - public UserGroupSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.UserGroup, sourceLineNumber, id) - { - } - - public IntermediateField this[UserGroupSymbolFields index] => this.Fields[(int)index]; - - public string UserRef - { - get => this.Fields[(int)UserGroupSymbolFields.UserRef].AsString(); - set => this.Set((int)UserGroupSymbolFields.UserRef, value); - } - - public string GroupRef - { - get => this.Fields[(int)UserGroupSymbolFields.GroupRef].AsString(); - set => this.Set((int)UserGroupSymbolFields.GroupRef, value); - } - } -} \ No newline at end of file diff --git a/src/wixext/Symbols/UserSymbol.cs b/src/wixext/Symbols/UserSymbol.cs deleted file mode 100644 index 5f00064b..00000000 --- a/src/wixext/Symbols/UserSymbol.cs +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - using WixToolset.Data; - using WixToolset.Util.Symbols; - - public static partial class UtilSymbolDefinitions - { - public static readonly IntermediateSymbolDefinition User = new IntermediateSymbolDefinition( - UtilSymbolDefinitionType.User.ToString(), - new[] - { - new IntermediateFieldDefinition(nameof(UserSymbolFields.ComponentRef), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(UserSymbolFields.Name), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(UserSymbolFields.Domain), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(UserSymbolFields.Password), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(UserSymbolFields.Attributes), IntermediateFieldType.Number), - }, - typeof(UserSymbol)); - } -} - -namespace WixToolset.Util.Symbols -{ - using WixToolset.Data; - - public enum UserSymbolFields - { - ComponentRef, - Name, - Domain, - Password, - Attributes, - } - - public class UserSymbol : IntermediateSymbol - { - public UserSymbol() : base(UtilSymbolDefinitions.User, null, null) - { - } - - public UserSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.User, sourceLineNumber, id) - { - } - - public IntermediateField this[UserSymbolFields index] => this.Fields[(int)index]; - - public string ComponentRef - { - get => this.Fields[(int)UserSymbolFields.ComponentRef].AsString(); - set => this.Set((int)UserSymbolFields.ComponentRef, value); - } - - public string Name - { - get => this.Fields[(int)UserSymbolFields.Name].AsString(); - set => this.Set((int)UserSymbolFields.Name, value); - } - - public string Domain - { - get => this.Fields[(int)UserSymbolFields.Domain].AsString(); - set => this.Set((int)UserSymbolFields.Domain, value); - } - - public string Password - { - get => this.Fields[(int)UserSymbolFields.Password].AsString(); - set => this.Set((int)UserSymbolFields.Password, value); - } - - public int Attributes - { - get => this.Fields[(int)UserSymbolFields.Attributes].AsNumber(); - set => this.Set((int)UserSymbolFields.Attributes, value); - } - } -} \ No newline at end of file diff --git a/src/wixext/Symbols/UtilSymbolDefinitions.cs b/src/wixext/Symbols/UtilSymbolDefinitions.cs deleted file mode 100644 index 72091c3b..00000000 --- a/src/wixext/Symbols/UtilSymbolDefinitions.cs +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - using System; - using WixToolset.Data; - using WixToolset.Data.Burn; - - public enum UtilSymbolDefinitionType - { - EventManifest, - FileShare, - FileSharePermissions, - Group, - Perfmon, - PerfmonManifest, - PerformanceCategory, - SecureObjects, - ServiceConfig, - User, - UserGroup, - WixCloseApplication, - WixFormatFiles, - WixInternetShortcut, - WixRemoveFolderEx, - WixRemoveRegistryKeyEx, - WixRestartResource, - WixTouchFile, - WixWindowsFeatureSearch, - XmlConfig, - XmlFile, - } - - public static partial class UtilSymbolDefinitions - { - public static readonly Version Version = new Version("4.0.0"); - - public static IntermediateSymbolDefinition ByName(string name) - { - if (!Enum.TryParse(name, out UtilSymbolDefinitionType type)) - { - return null; - } - - return ByType(type); - } - - public static IntermediateSymbolDefinition ByType(UtilSymbolDefinitionType type) - { - switch (type) - { - case UtilSymbolDefinitionType.EventManifest: - return UtilSymbolDefinitions.EventManifest; - - case UtilSymbolDefinitionType.FileShare: - return UtilSymbolDefinitions.FileShare; - - case UtilSymbolDefinitionType.FileSharePermissions: - return UtilSymbolDefinitions.FileSharePermissions; - - case UtilSymbolDefinitionType.Group: - return UtilSymbolDefinitions.Group; - - case UtilSymbolDefinitionType.Perfmon: - return UtilSymbolDefinitions.Perfmon; - - case UtilSymbolDefinitionType.PerfmonManifest: - return UtilSymbolDefinitions.PerfmonManifest; - - case UtilSymbolDefinitionType.PerformanceCategory: - return UtilSymbolDefinitions.PerformanceCategory; - - case UtilSymbolDefinitionType.SecureObjects: - return UtilSymbolDefinitions.SecureObjects; - - case UtilSymbolDefinitionType.ServiceConfig: - return UtilSymbolDefinitions.ServiceConfig; - - case UtilSymbolDefinitionType.User: - return UtilSymbolDefinitions.User; - - case UtilSymbolDefinitionType.UserGroup: - return UtilSymbolDefinitions.UserGroup; - - case UtilSymbolDefinitionType.WixCloseApplication: - return UtilSymbolDefinitions.WixCloseApplication; - - case UtilSymbolDefinitionType.WixFormatFiles: - return UtilSymbolDefinitions.WixFormatFiles; - - case UtilSymbolDefinitionType.WixInternetShortcut: - return UtilSymbolDefinitions.WixInternetShortcut; - - case UtilSymbolDefinitionType.WixRemoveFolderEx: - return UtilSymbolDefinitions.WixRemoveFolderEx; - - case UtilSymbolDefinitionType.WixRemoveRegistryKeyEx: - return UtilSymbolDefinitions.WixRemoveRegistryKeyEx; - - case UtilSymbolDefinitionType.WixRestartResource: - return UtilSymbolDefinitions.WixRestartResource; - - case UtilSymbolDefinitionType.WixTouchFile: - return UtilSymbolDefinitions.WixTouchFile; - - case UtilSymbolDefinitionType.WixWindowsFeatureSearch: - return UtilSymbolDefinitions.WixWindowsFeatureSearch; - - case UtilSymbolDefinitionType.XmlConfig: - return UtilSymbolDefinitions.XmlConfig; - - case UtilSymbolDefinitionType.XmlFile: - return UtilSymbolDefinitions.XmlFile; - - default: - throw new ArgumentOutOfRangeException(nameof(type)); - } - } - - static UtilSymbolDefinitions() - { - WixWindowsFeatureSearch.AddTag(BurnConstants.BundleExtensionSearchSymbolDefinitionTag); - } - } -} diff --git a/src/wixext/Symbols/WixCloseApplicationSymbol.cs b/src/wixext/Symbols/WixCloseApplicationSymbol.cs deleted file mode 100644 index 0738e3e4..00000000 --- a/src/wixext/Symbols/WixCloseApplicationSymbol.cs +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - using WixToolset.Data; - using WixToolset.Util.Symbols; - - public static partial class UtilSymbolDefinitions - { - public static readonly IntermediateSymbolDefinition WixCloseApplication = new IntermediateSymbolDefinition( - UtilSymbolDefinitionType.WixCloseApplication.ToString(), - new[] - { - new IntermediateFieldDefinition(nameof(WixCloseApplicationSymbolFields.Target), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(WixCloseApplicationSymbolFields.Description), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(WixCloseApplicationSymbolFields.Condition), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(WixCloseApplicationSymbolFields.Attributes), IntermediateFieldType.Number), - new IntermediateFieldDefinition(nameof(WixCloseApplicationSymbolFields.Sequence), IntermediateFieldType.Number), - new IntermediateFieldDefinition(nameof(WixCloseApplicationSymbolFields.Property), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(WixCloseApplicationSymbolFields.TerminateExitCode), IntermediateFieldType.Number), - new IntermediateFieldDefinition(nameof(WixCloseApplicationSymbolFields.Timeout), IntermediateFieldType.Number), - }, - typeof(WixCloseApplicationSymbol)); - } -} - -namespace WixToolset.Util.Symbols -{ - using WixToolset.Data; - - public enum WixCloseApplicationSymbolFields - { - Target, - Description, - Condition, - Attributes, - Sequence, - Property, - TerminateExitCode, - Timeout, - } - - public class WixCloseApplicationSymbol : IntermediateSymbol - { - public WixCloseApplicationSymbol() : base(UtilSymbolDefinitions.WixCloseApplication, null, null) - { - } - - public WixCloseApplicationSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.WixCloseApplication, sourceLineNumber, id) - { - } - - public IntermediateField this[WixCloseApplicationSymbolFields index] => this.Fields[(int)index]; - - public string Target - { - get => this.Fields[(int)WixCloseApplicationSymbolFields.Target].AsString(); - set => this.Set((int)WixCloseApplicationSymbolFields.Target, value); - } - - public string Description - { - get => this.Fields[(int)WixCloseApplicationSymbolFields.Description].AsString(); - set => this.Set((int)WixCloseApplicationSymbolFields.Description, value); - } - - public string Condition - { - get => this.Fields[(int)WixCloseApplicationSymbolFields.Condition].AsString(); - set => this.Set((int)WixCloseApplicationSymbolFields.Condition, value); - } - - public int Attributes - { - get => this.Fields[(int)WixCloseApplicationSymbolFields.Attributes].AsNumber(); - set => this.Set((int)WixCloseApplicationSymbolFields.Attributes, value); - } - - public int? Sequence - { - get => this.Fields[(int)WixCloseApplicationSymbolFields.Sequence].AsNullableNumber(); - set => this.Set((int)WixCloseApplicationSymbolFields.Sequence, value); - } - - public string Property - { - get => this.Fields[(int)WixCloseApplicationSymbolFields.Property].AsString(); - set => this.Set((int)WixCloseApplicationSymbolFields.Property, value); - } - - public int? TerminateExitCode - { - get => this.Fields[(int)WixCloseApplicationSymbolFields.TerminateExitCode].AsNullableNumber(); - set => this.Set((int)WixCloseApplicationSymbolFields.TerminateExitCode, value); - } - - public int? Timeout - { - get => this.Fields[(int)WixCloseApplicationSymbolFields.Timeout].AsNullableNumber(); - set => this.Set((int)WixCloseApplicationSymbolFields.Timeout, value); - } - } -} \ No newline at end of file diff --git a/src/wixext/Symbols/WixFormatFilesSymbol.cs b/src/wixext/Symbols/WixFormatFilesSymbol.cs deleted file mode 100644 index 38a9b8ff..00000000 --- a/src/wixext/Symbols/WixFormatFilesSymbol.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - using WixToolset.Data; - using WixToolset.Util.Symbols; - - public static partial class UtilSymbolDefinitions - { - public static readonly IntermediateSymbolDefinition WixFormatFiles = new IntermediateSymbolDefinition( - UtilSymbolDefinitionType.WixFormatFiles.ToString(), - new[] - { - new IntermediateFieldDefinition(nameof(WixFormatFilesSymbolFields.BinaryRef), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(WixFormatFilesSymbolFields.FileRef), IntermediateFieldType.String), - }, - typeof(WixFormatFilesSymbol)); - } -} - -namespace WixToolset.Util.Symbols -{ - using WixToolset.Data; - - public enum WixFormatFilesSymbolFields - { - BinaryRef, - FileRef, - } - - public class WixFormatFilesSymbol : IntermediateSymbol - { - public WixFormatFilesSymbol() : base(UtilSymbolDefinitions.WixFormatFiles, null, null) - { - } - - public WixFormatFilesSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.WixFormatFiles, sourceLineNumber, id) - { - } - - public IntermediateField this[WixFormatFilesSymbolFields index] => this.Fields[(int)index]; - - public string BinaryRef - { - get => this.Fields[(int)WixFormatFilesSymbolFields.BinaryRef].AsString(); - set => this.Set((int)WixFormatFilesSymbolFields.BinaryRef, value); - } - - public string FileRef - { - get => this.Fields[(int)WixFormatFilesSymbolFields.FileRef].AsString(); - set => this.Set((int)WixFormatFilesSymbolFields.FileRef, value); - } - } -} \ No newline at end of file diff --git a/src/wixext/Symbols/WixInternetShortcutSymbol.cs b/src/wixext/Symbols/WixInternetShortcutSymbol.cs deleted file mode 100644 index e8265e02..00000000 --- a/src/wixext/Symbols/WixInternetShortcutSymbol.cs +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - using WixToolset.Data; - using WixToolset.Util.Symbols; - - public static partial class UtilSymbolDefinitions - { - public static readonly IntermediateSymbolDefinition WixInternetShortcut = new IntermediateSymbolDefinition( - UtilSymbolDefinitionType.WixInternetShortcut.ToString(), - new[] - { - new IntermediateFieldDefinition(nameof(WixInternetShortcutSymbolFields.ComponentRef), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(WixInternetShortcutSymbolFields.DirectoryRef), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(WixInternetShortcutSymbolFields.Name), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(WixInternetShortcutSymbolFields.Target), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(WixInternetShortcutSymbolFields.Attributes), IntermediateFieldType.Number), - new IntermediateFieldDefinition(nameof(WixInternetShortcutSymbolFields.IconFile), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(WixInternetShortcutSymbolFields.IconIndex), IntermediateFieldType.Number), - }, - typeof(WixInternetShortcutSymbol)); - } -} - -namespace WixToolset.Util.Symbols -{ - using WixToolset.Data; - - public enum WixInternetShortcutSymbolFields - { - ComponentRef, - DirectoryRef, - Name, - Target, - Attributes, - IconFile, - IconIndex, - } - - public class WixInternetShortcutSymbol : IntermediateSymbol - { - public WixInternetShortcutSymbol() : base(UtilSymbolDefinitions.WixInternetShortcut, null, null) - { - } - - public WixInternetShortcutSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.WixInternetShortcut, sourceLineNumber, id) - { - } - - public IntermediateField this[WixInternetShortcutSymbolFields index] => this.Fields[(int)index]; - - public string ComponentRef - { - get => this.Fields[(int)WixInternetShortcutSymbolFields.ComponentRef].AsString(); - set => this.Set((int)WixInternetShortcutSymbolFields.ComponentRef, value); - } - - public string DirectoryRef - { - get => this.Fields[(int)WixInternetShortcutSymbolFields.DirectoryRef].AsString(); - set => this.Set((int)WixInternetShortcutSymbolFields.DirectoryRef, value); - } - - public string Name - { - get => this.Fields[(int)WixInternetShortcutSymbolFields.Name].AsString(); - set => this.Set((int)WixInternetShortcutSymbolFields.Name, value); - } - - public string Target - { - get => this.Fields[(int)WixInternetShortcutSymbolFields.Target].AsString(); - set => this.Set((int)WixInternetShortcutSymbolFields.Target, value); - } - - public int Attributes - { - get => this.Fields[(int)WixInternetShortcutSymbolFields.Attributes].AsNumber(); - set => this.Set((int)WixInternetShortcutSymbolFields.Attributes, value); - } - - public string IconFile - { - get => this.Fields[(int)WixInternetShortcutSymbolFields.IconFile].AsString(); - set => this.Set((int)WixInternetShortcutSymbolFields.IconFile, value); - } - - public int? IconIndex - { - get => this.Fields[(int)WixInternetShortcutSymbolFields.IconIndex].AsNullableNumber(); - set => this.Set((int)WixInternetShortcutSymbolFields.IconIndex, value); - } - } -} \ No newline at end of file diff --git a/src/wixext/Symbols/WixRemoveFolderExSymbol.cs b/src/wixext/Symbols/WixRemoveFolderExSymbol.cs deleted file mode 100644 index 86352b6c..00000000 --- a/src/wixext/Symbols/WixRemoveFolderExSymbol.cs +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - using WixToolset.Data; - using WixToolset.Util.Symbols; - - public static partial class UtilSymbolDefinitions - { - public static readonly IntermediateSymbolDefinition WixRemoveFolderEx = new IntermediateSymbolDefinition( - UtilSymbolDefinitionType.WixRemoveFolderEx.ToString(), - new[] - { - new IntermediateFieldDefinition(nameof(WixRemoveFolderExSymbolFields.ComponentRef), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(WixRemoveFolderExSymbolFields.Property), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(WixRemoveFolderExSymbolFields.InstallMode), IntermediateFieldType.Number), - new IntermediateFieldDefinition(nameof(WixRemoveFolderExSymbolFields.Condition), IntermediateFieldType.String), - }, - typeof(WixRemoveFolderExSymbol)); - } -} - -namespace WixToolset.Util.Symbols -{ - using WixToolset.Data; - - public enum WixRemoveFolderExSymbolFields - { - ComponentRef, - Property, - InstallMode, - Condition, - } - - public enum WixRemoveFolderExInstallMode - { - Install = 1, - Uninstall = 2, - Both = 3, - } - - public class WixRemoveFolderExSymbol : IntermediateSymbol - { - public WixRemoveFolderExSymbol() : base(UtilSymbolDefinitions.WixRemoveFolderEx, null, null) - { - } - - public WixRemoveFolderExSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.WixRemoveFolderEx, sourceLineNumber, id) - { - } - - public IntermediateField this[WixRemoveFolderExSymbolFields index] => this.Fields[(int)index]; - - public string ComponentRef - { - get => this.Fields[(int)WixRemoveFolderExSymbolFields.ComponentRef].AsString(); - set => this.Set((int)WixRemoveFolderExSymbolFields.ComponentRef, value); - } - - public string Property - { - get => this.Fields[(int)WixRemoveFolderExSymbolFields.Property].AsString(); - set => this.Set((int)WixRemoveFolderExSymbolFields.Property, value); - } - - public WixRemoveFolderExInstallMode InstallMode - { - get => (WixRemoveFolderExInstallMode)this.Fields[(int)WixRemoveFolderExSymbolFields.InstallMode].AsNumber(); - set => this.Set((int)WixRemoveFolderExSymbolFields.InstallMode, (int)value); - } - - public string Condition - { - get => this.Fields[(int)WixRemoveFolderExSymbolFields.Condition].AsString(); - set => this.Set((int)WixRemoveFolderExSymbolFields.Condition, value); - } - } -} \ No newline at end of file diff --git a/src/wixext/Symbols/WixRemoveRegistryKeyExSymbol.cs b/src/wixext/Symbols/WixRemoveRegistryKeyExSymbol.cs deleted file mode 100644 index 8e4bd212..00000000 --- a/src/wixext/Symbols/WixRemoveRegistryKeyExSymbol.cs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - using WixToolset.Data; - using WixToolset.Util.Symbols; - - public static partial class UtilSymbolDefinitions - { - public static readonly IntermediateSymbolDefinition WixRemoveRegistryKeyEx = new IntermediateSymbolDefinition( - UtilSymbolDefinitionType.WixRemoveRegistryKeyEx.ToString(), - new[] - { - new IntermediateFieldDefinition(nameof(WixRemoveRegistryKeyExSymbolFields.ComponentRef), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(WixRemoveRegistryKeyExSymbolFields.Root), IntermediateFieldType.Number), - new IntermediateFieldDefinition(nameof(WixRemoveRegistryKeyExSymbolFields.Key), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(WixRemoveRegistryKeyExSymbolFields.InstallMode), IntermediateFieldType.Number), - new IntermediateFieldDefinition(nameof(WixRemoveRegistryKeyExSymbolFields.Condition), IntermediateFieldType.String), - }, - typeof(WixRemoveRegistryKeyExSymbol)); - } -} - -namespace WixToolset.Util.Symbols -{ - using WixToolset.Data; - using WixToolset.Data.Symbols; - - public enum WixRemoveRegistryKeyExSymbolFields - { - ComponentRef, - Root, - Key, - InstallMode, - Condition, - } - - public enum WixRemoveRegistryKeyExInstallMode - { - Install = 1, - Uninstall = 2, - } - - public class WixRemoveRegistryKeyExSymbol : IntermediateSymbol - { - public WixRemoveRegistryKeyExSymbol() : base(UtilSymbolDefinitions.WixRemoveRegistryKeyEx, null, null) - { - } - - public WixRemoveRegistryKeyExSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.WixRemoveRegistryKeyEx, sourceLineNumber, id) - { - } - - public IntermediateField this[WixRemoveRegistryKeyExSymbolFields index] => this.Fields[(int)index]; - - public string ComponentRef - { - get => this.Fields[(int)WixRemoveRegistryKeyExSymbolFields.ComponentRef].AsString(); - set => this.Set((int)WixRemoveRegistryKeyExSymbolFields.ComponentRef, value); - } - - public RegistryRootType Root - { - get => (RegistryRootType)this.Fields[(int)WixRemoveRegistryKeyExSymbolFields.Root].AsNumber(); - set => this.Set((int)WixRemoveRegistryKeyExSymbolFields.Root, (int)value); - } - - public string Key - { - get => (string)this.Fields[(int)WixRemoveRegistryKeyExSymbolFields.Key]; - set => this.Set((int)WixRemoveRegistryKeyExSymbolFields.Key, value); - } - - public WixRemoveRegistryKeyExInstallMode InstallMode - { - get => (WixRemoveRegistryKeyExInstallMode)this.Fields[(int)WixRemoveRegistryKeyExSymbolFields.InstallMode].AsNumber(); - set => this.Set((int)WixRemoveRegistryKeyExSymbolFields.InstallMode, (int)value); - } - - public string Condition - { - get => this.Fields[(int)WixRemoveRegistryKeyExSymbolFields.Condition].AsString(); - set => this.Set((int)WixRemoveRegistryKeyExSymbolFields.Condition, value); - } - } -} diff --git a/src/wixext/Symbols/WixRestartResourceSymbol.cs b/src/wixext/Symbols/WixRestartResourceSymbol.cs deleted file mode 100644 index 01b92b63..00000000 --- a/src/wixext/Symbols/WixRestartResourceSymbol.cs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - using WixToolset.Data; - using WixToolset.Util.Symbols; - - public static partial class UtilSymbolDefinitions - { - public static readonly IntermediateSymbolDefinition WixRestartResource = new IntermediateSymbolDefinition( - UtilSymbolDefinitionType.WixRestartResource.ToString(), - new[] - { - new IntermediateFieldDefinition(nameof(WixRestartResourceSymbolFields.ComponentRef), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(WixRestartResourceSymbolFields.Resource), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(WixRestartResourceSymbolFields.Attributes), IntermediateFieldType.Number), - }, - typeof(WixRestartResourceSymbol)); - } -} - -namespace WixToolset.Util.Symbols -{ - using WixToolset.Data; - - public enum WixRestartResourceSymbolFields - { - ComponentRef, - Resource, - Attributes, - } - - public enum WixRestartResourceAttributes - { - Filename = 1, - ProcessName, - ServiceName, - TypeMask = 0xf, - } - - public class WixRestartResourceSymbol : IntermediateSymbol - { - public WixRestartResourceSymbol() : base(UtilSymbolDefinitions.WixRestartResource, null, null) - { - } - - public WixRestartResourceSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.WixRestartResource, sourceLineNumber, id) - { - } - - public IntermediateField this[WixRestartResourceSymbolFields index] => this.Fields[(int)index]; - - public string ComponentRef - { - get => this.Fields[(int)WixRestartResourceSymbolFields.ComponentRef].AsString(); - set => this.Set((int)WixRestartResourceSymbolFields.ComponentRef, value); - } - - public string Resource - { - get => this.Fields[(int)WixRestartResourceSymbolFields.Resource].AsString(); - set => this.Set((int)WixRestartResourceSymbolFields.Resource, value); - } - - public WixRestartResourceAttributes? Attributes - { - get => (WixRestartResourceAttributes?)this.Fields[(int)WixRestartResourceSymbolFields.Attributes].AsNullableNumber(); - set => this.Set((int)WixRestartResourceSymbolFields.Attributes, (int?)value); - } - } -} \ No newline at end of file diff --git a/src/wixext/Symbols/WixTouchFileSymbol.cs b/src/wixext/Symbols/WixTouchFileSymbol.cs deleted file mode 100644 index 447c21ba..00000000 --- a/src/wixext/Symbols/WixTouchFileSymbol.cs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - using WixToolset.Data; - using WixToolset.Util.Symbols; - - public static partial class UtilSymbolDefinitions - { - public static readonly IntermediateSymbolDefinition WixTouchFile = new IntermediateSymbolDefinition( - UtilSymbolDefinitionType.WixTouchFile.ToString(), - new[] - { - new IntermediateFieldDefinition(nameof(WixTouchFileSymbolFields.ComponentRef), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(WixTouchFileSymbolFields.Path), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(WixTouchFileSymbolFields.Attributes), IntermediateFieldType.Number), - }, - typeof(WixTouchFileSymbol)); - } -} - -namespace WixToolset.Util.Symbols -{ - using WixToolset.Data; - - public enum WixTouchFileSymbolFields - { - ComponentRef, - Path, - Attributes, - } - - public class WixTouchFileSymbol : IntermediateSymbol - { - public WixTouchFileSymbol() : base(UtilSymbolDefinitions.WixTouchFile, null, null) - { - } - - public WixTouchFileSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.WixTouchFile, sourceLineNumber, id) - { - } - - public IntermediateField this[WixTouchFileSymbolFields index] => this.Fields[(int)index]; - - public string ComponentRef - { - get => this.Fields[(int)WixTouchFileSymbolFields.ComponentRef].AsString(); - set => this.Set((int)WixTouchFileSymbolFields.ComponentRef, value); - } - - public string Path - { - get => this.Fields[(int)WixTouchFileSymbolFields.Path].AsString(); - set => this.Set((int)WixTouchFileSymbolFields.Path, value); - } - - public int Attributes - { - get => this.Fields[(int)WixTouchFileSymbolFields.Attributes].AsNumber(); - set => this.Set((int)WixTouchFileSymbolFields.Attributes, value); - } - } -} \ No newline at end of file diff --git a/src/wixext/Symbols/WixWindowsFeatureSearchSymbol.cs b/src/wixext/Symbols/WixWindowsFeatureSearchSymbol.cs deleted file mode 100644 index 9a43692c..00000000 --- a/src/wixext/Symbols/WixWindowsFeatureSearchSymbol.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - using WixToolset.Data; - using WixToolset.Util.Symbols; - - public static partial class UtilSymbolDefinitions - { - public static readonly IntermediateSymbolDefinition WixWindowsFeatureSearch = new IntermediateSymbolDefinition( - UtilSymbolDefinitionType.WixWindowsFeatureSearch.ToString(), - new[] - { - new IntermediateFieldDefinition(nameof(WixWindowsFeatureSearchSymbolFields.Type), IntermediateFieldType.String), - }, - typeof(WixWindowsFeatureSearchSymbol)); - } -} - -namespace WixToolset.Util.Symbols -{ - using WixToolset.Data; - - public enum WixWindowsFeatureSearchSymbolFields - { - Type, - } - - public class WixWindowsFeatureSearchSymbol : IntermediateSymbol - { - public WixWindowsFeatureSearchSymbol() : base(UtilSymbolDefinitions.WixWindowsFeatureSearch, null, null) - { - } - - public WixWindowsFeatureSearchSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.WixWindowsFeatureSearch, sourceLineNumber, id) - { - } - - public IntermediateField this[WixWindowsFeatureSearchSymbolFields index] => this.Fields[(int)index]; - - public string Type - { - get => this.Fields[(int)WixWindowsFeatureSearchSymbolFields.Type].AsString(); - set => this.Set((int)WixWindowsFeatureSearchSymbolFields.Type, value); - } - } -} diff --git a/src/wixext/Symbols/XmlConfigSymbol.cs b/src/wixext/Symbols/XmlConfigSymbol.cs deleted file mode 100644 index 6503a586..00000000 --- a/src/wixext/Symbols/XmlConfigSymbol.cs +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - using WixToolset.Data; - using WixToolset.Util.Symbols; - - public static partial class UtilSymbolDefinitions - { - public static readonly IntermediateSymbolDefinition XmlConfig = new IntermediateSymbolDefinition( - UtilSymbolDefinitionType.XmlConfig.ToString(), - new[] - { - new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.File), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.ElementId), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.ElementPath), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.VerifyPath), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.Name), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.Value), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.Flags), IntermediateFieldType.Number), - new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.ComponentRef), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.Sequence), IntermediateFieldType.Number), - }, - typeof(XmlConfigSymbol)); - } -} - -namespace WixToolset.Util.Symbols -{ - using WixToolset.Data; - - public enum XmlConfigSymbolFields - { - File, - ElementId, - ElementPath, - VerifyPath, - Name, - Value, - Flags, - ComponentRef, - Sequence, - } - - public class XmlConfigSymbol : IntermediateSymbol - { - public XmlConfigSymbol() : base(UtilSymbolDefinitions.XmlConfig, null, null) - { - } - - public XmlConfigSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.XmlConfig, sourceLineNumber, id) - { - } - - public IntermediateField this[XmlConfigSymbolFields index] => this.Fields[(int)index]; - - public string File - { - get => this.Fields[(int)XmlConfigSymbolFields.File].AsString(); - set => this.Set((int)XmlConfigSymbolFields.File, value); - } - - public string ElementId - { - get => this.Fields[(int)XmlConfigSymbolFields.ElementId].AsString(); - set => this.Set((int)XmlConfigSymbolFields.ElementId, value); - } - - public string ElementPath - { - get => this.Fields[(int)XmlConfigSymbolFields.ElementPath].AsString(); - set => this.Set((int)XmlConfigSymbolFields.ElementPath, value); - } - - public string VerifyPath - { - get => this.Fields[(int)XmlConfigSymbolFields.VerifyPath].AsString(); - set => this.Set((int)XmlConfigSymbolFields.VerifyPath, value); - } - - public string Name - { - get => this.Fields[(int)XmlConfigSymbolFields.Name].AsString(); - set => this.Set((int)XmlConfigSymbolFields.Name, value); - } - - public string Value - { - get => this.Fields[(int)XmlConfigSymbolFields.Value].AsString(); - set => this.Set((int)XmlConfigSymbolFields.Value, value); - } - - public int Flags - { - get => this.Fields[(int)XmlConfigSymbolFields.Flags].AsNumber(); - set => this.Set((int)XmlConfigSymbolFields.Flags, value); - } - - public string ComponentRef - { - get => this.Fields[(int)XmlConfigSymbolFields.ComponentRef].AsString(); - set => this.Set((int)XmlConfigSymbolFields.ComponentRef, value); - } - - public int? Sequence - { - get => this.Fields[(int)XmlConfigSymbolFields.Sequence].AsNullableNumber(); - set => this.Set((int)XmlConfigSymbolFields.Sequence, value); - } - } -} \ No newline at end of file diff --git a/src/wixext/Symbols/XmlFileSymbol.cs b/src/wixext/Symbols/XmlFileSymbol.cs deleted file mode 100644 index 7d5d991b..00000000 --- a/src/wixext/Symbols/XmlFileSymbol.cs +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - using WixToolset.Data; - using WixToolset.Util.Symbols; - - public static partial class UtilSymbolDefinitions - { - public static readonly IntermediateSymbolDefinition XmlFile = new IntermediateSymbolDefinition( - UtilSymbolDefinitionType.XmlFile.ToString(), - new[] - { - new IntermediateFieldDefinition(nameof(XmlFileSymbolFields.File), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(XmlFileSymbolFields.ElementPath), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(XmlFileSymbolFields.Name), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(XmlFileSymbolFields.Value), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(XmlFileSymbolFields.Flags), IntermediateFieldType.Number), - new IntermediateFieldDefinition(nameof(XmlFileSymbolFields.ComponentRef), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(XmlFileSymbolFields.Sequence), IntermediateFieldType.Number), - }, - typeof(XmlFileSymbol)); - } -} - -namespace WixToolset.Util.Symbols -{ - using WixToolset.Data; - - public enum XmlFileSymbolFields - { - File, - ElementPath, - Name, - Value, - Flags, - ComponentRef, - Sequence, - } - - public class XmlFileSymbol : IntermediateSymbol - { - public XmlFileSymbol() : base(UtilSymbolDefinitions.XmlFile, null, null) - { - } - - public XmlFileSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.XmlFile, sourceLineNumber, id) - { - } - - public IntermediateField this[XmlFileSymbolFields index] => this.Fields[(int)index]; - - public string File - { - get => this.Fields[(int)XmlFileSymbolFields.File].AsString(); - set => this.Set((int)XmlFileSymbolFields.File, value); - } - - public string ElementPath - { - get => this.Fields[(int)XmlFileSymbolFields.ElementPath].AsString(); - set => this.Set((int)XmlFileSymbolFields.ElementPath, value); - } - - public string Name - { - get => this.Fields[(int)XmlFileSymbolFields.Name].AsString(); - set => this.Set((int)XmlFileSymbolFields.Name, value); - } - - public string Value - { - get => this.Fields[(int)XmlFileSymbolFields.Value].AsString(); - set => this.Set((int)XmlFileSymbolFields.Value, value); - } - - public int Flags - { - get => this.Fields[(int)XmlFileSymbolFields.Flags].AsNumber(); - set => this.Set((int)XmlFileSymbolFields.Flags, value); - } - - public string ComponentRef - { - get => this.Fields[(int)XmlFileSymbolFields.ComponentRef].AsString(); - set => this.Set((int)XmlFileSymbolFields.ComponentRef, value); - } - - public int? Sequence - { - get => this.Fields[(int)XmlFileSymbolFields.Sequence].AsNullableNumber(); - set => this.Set((int)XmlFileSymbolFields.Sequence, value); - } - } -} \ No newline at end of file diff --git a/src/wixext/UtilCompiler.cs b/src/wixext/UtilCompiler.cs deleted file mode 100644 index 45079150..00000000 --- a/src/wixext/UtilCompiler.cs +++ /dev/null @@ -1,3889 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - using System; - using System.Collections; - using System.Collections.Generic; - using System.Globalization; - using System.Linq; - using System.Text; - using System.Text.RegularExpressions; - using System.Xml.Linq; - using WixToolset.Data; - using WixToolset.Data.Symbols; - using WixToolset.Extensibility; - using WixToolset.Extensibility.Data; - using WixToolset.Util.Symbols; - - /// - /// The compiler for the WiX Toolset Utility Extension. - /// - public sealed class UtilCompiler : BaseCompilerExtension - { - // user creation attributes definitions (from sca.h) - internal const int UserDontExpirePasswrd = 0x00000001; - internal const int UserPasswdCantChange = 0x00000002; - internal const int UserPasswdChangeReqdOnLogin = 0x00000004; - internal const int UserDisableAccount = 0x00000008; - internal const int UserFailIfExists = 0x00000010; - internal const int UserUpdateIfExists = 0x00000020; - internal const int UserLogonAsService = 0x00000040; - internal const int UserLogonAsBatchJob = 0x00000080; - - internal const int UserDontRemoveOnUninstall = 0x00000100; - internal const int UserDontCreateUser = 0x00000200; - internal const int UserNonVital = 0x00000400; - - private static readonly Regex FindPropertyBrackets = new Regex(@"\[(?!\\|\])|(? "http://wixtoolset.org/schemas/v4/wxs/util"; - - /// - /// Types of Internet shortcuts. - /// - public enum InternetShortcutType - { - /// Create a .lnk file. - Link = 0, - - /// Create a .url file. - Url, - } - - /// - /// Types of permission setting methods. - /// - private enum PermissionType - { - /// LockPermissions (normal) type permission setting. - LockPermissions, - - /// FileSharePermissions type permission setting. - FileSharePermissions, - - /// SecureObjects type permission setting. - SecureObjects, - } - - /// - /// Processes an element for the Compiler. - /// - /// Parent element of element to process. - /// Element to process. - /// Extra information about the context in which this element is being parsed. - public override void ParseElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, IDictionary context) - { - this.ParsePossibleKeyPathElement(intermediate, section, parentElement, element, context); - } - - /// - /// Processes an element for the Compiler. - /// - /// Source line number for the parent element. - /// Parent element of element to process. - /// Element to process. - /// Extra information about the context in which this element is being parsed. - public override IComponentKeyPath ParsePossibleKeyPathElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, IDictionary context) - { - IComponentKeyPath possibleKeyPath = null; - - switch (parentElement.Name.LocalName) - { - case "CreateFolder": - var createFolderId = context["DirectoryId"]; - var createFolderComponentId = context["ComponentId"]; - - // If this doesn't parse successfully, something really odd is going on, so let the exception get thrown - var createFolderWin64 = Boolean.Parse(context["Win64"]); - - switch (element.Name.LocalName) - { - case "PermissionEx": - this.ParsePermissionExElement(intermediate, section, element, createFolderId, createFolderComponentId, createFolderWin64, "CreateFolder"); - break; - default: - this.ParseHelper.UnexpectedElement(parentElement, element); - break; - } - break; - case "Component": - var componentId = context["ComponentId"]; - var directoryId = context["DirectoryId"]; - var componentWin64 = Boolean.Parse(context["Win64"]); - - switch (element.Name.LocalName) - { - case "EventSource": - possibleKeyPath = this.ParseEventSourceElement(intermediate, section, element, componentId); - break; - case "FileShare": - this.ParseFileShareElement(intermediate, section, element, componentId, directoryId); - break; - case "InternetShortcut": - this.ParseInternetShortcutElement(intermediate, section, element, componentId, directoryId); - break; - case "PerformanceCategory": - this.ParsePerformanceCategoryElement(intermediate, section, element, componentId); - break; - case "RemoveFolderEx": - this.ParseRemoveFolderExElement(intermediate, section, element, componentId); - break; - case "RemoveRegistryKey": - this.ParseRemoveRegistryKeyExElement(intermediate, section, element, componentId); - break; - case "RestartResource": - this.ParseRestartResourceElement(intermediate, section, element, componentId); - break; - case "ServiceConfig": - this.ParseServiceConfigElement(intermediate, section, element, componentId, "Component", null); - break; - case "TouchFile": - this.ParseTouchFileElement(intermediate, section, element, componentId, componentWin64); - break; - case "User": - this.ParseUserElement(intermediate, section, element, componentId); - break; - case "XmlFile": - this.ParseXmlFileElement(intermediate, section, element, componentId); - break; - case "XmlConfig": - this.ParseXmlConfigElement(intermediate, section, element, componentId, false); - break; - default: - this.ParseHelper.UnexpectedElement(parentElement, element); - break; - } - break; - case "File": - var fileId = context["FileId"]; - var fileComponentId = context["ComponentId"]; - - // If this doesn't parse successfully, something really odd is going on, so let the exception get thrown - var fileWin64 = Boolean.Parse(context["Win64"]); - - switch (element.Name.LocalName) - { - case "PerfCounter": - this.ParsePerfCounterElement(intermediate, section, element, fileComponentId, fileId); - break; - case "PermissionEx": - this.ParsePermissionExElement(intermediate, section, element, fileId, fileComponentId, fileWin64, "File"); - break; - case "PerfCounterManifest": - this.ParsePerfCounterManifestElement(intermediate, section, element, fileComponentId, fileId); - break; - case "EventManifest": - this.ParseEventManifestElement(intermediate, section, element, fileComponentId, fileId); - break; - case "FormatFile": - this.ParseFormatFileElement(intermediate, section, element, fileId, fileWin64); - break; - default: - this.ParseHelper.UnexpectedElement(parentElement, element); - break; - } - break; - case "Bundle": - case "Fragment": - case "Module": - case "Package": - switch (element.Name.LocalName) - { - case "CloseApplication": - this.ParseCloseApplicationElement(intermediate, section, element); - break; - case "Group": - this.ParseGroupElement(intermediate, section, element, null); - break; - case "RestartResource": - // Currently not supported for Bundles. - if (parentElement.Name.LocalName != "Bundle") - { - this.ParseRestartResourceElement(intermediate, section, element, null); - } - else - { - this.ParseHelper.UnexpectedElement(parentElement, element); - } - break; - case "User": - this.ParseUserElement(intermediate, section, element, null); - break; - case "BroadcastEnvironmentChange": - case "BroadcastSettingChange": - case "CheckRebootRequired": - case "ExitEarlyWithSuccess": - case "FailWhenDeferred": - case "QueryWindowsDirectories": - case "QueryWindowsDriverInfo": - case "QueryWindowsSuiteInfo": - case "QueryWindowsWellKnownSIDs": - case "WaitForEvent": - case "WaitForEventDeferred": - this.AddCustomActionReference(intermediate, section, element, parentElement); - break; - case "ComponentSearch": - case "ComponentSearchRef": - case "DirectorySearch": - case "DirectorySearchRef": - case "FileSearch": - case "FileSearchRef": - case "ProductSearch": - case "ProductSearchRef": - case "RegistrySearch": - case "RegistrySearchRef": - case "WindowsFeatureSearch": - case "WindowsFeatureSearchRef": - // These will eventually be supported under Module/Product, but are not yet. - if (parentElement.Name.LocalName == "Bundle" || parentElement.Name.LocalName == "Fragment") - { - // TODO: When these are supported by all section types, move - // these out of the nested switch and back into the surrounding one. - switch (element.Name.LocalName) - { - case "ComponentSearch": - this.ParseComponentSearchElement(intermediate, section, element); - break; - case "ComponentSearchRef": - this.ParseComponentSearchRefElement(intermediate, section, element); - break; - case "DirectorySearch": - this.ParseDirectorySearchElement(intermediate, section, element); - break; - case "DirectorySearchRef": - this.ParseWixSearchRefElement(intermediate, section, element); - break; - case "FileSearch": - this.ParseFileSearchElement(intermediate, section, element); - break; - case "FileSearchRef": - this.ParseWixSearchRefElement(intermediate, section, element); - break; - case "ProductSearch": - this.ParseProductSearchElement(intermediate, section, element); - break; - case "ProductSearchRef": - this.ParseWixSearchRefElement(intermediate, section, element); - break; - case "RegistrySearch": - this.ParseRegistrySearchElement(intermediate, section, element); - break; - case "RegistrySearchRef": - this.ParseWixSearchRefElement(intermediate, section, element); - break; - case "WindowsFeatureSearch": - this.ParseWindowsFeatureSearchElement(intermediate, section, element); - break; - case "WindowsFeatureSearchRef": - this.ParseWindowsFeatureSearchRefElement(intermediate, section, element); - break; - } - } - else - { - this.ParseHelper.UnexpectedElement(parentElement, element); - } - break; - default: - this.ParseHelper.UnexpectedElement(parentElement, element); - break; - } - break; - case "Registry": - case "RegistryKey": - case "RegistryValue": - var registryId = context["RegistryId"]; - var registryComponentId = context["ComponentId"]; - - // If this doesn't parse successfully, something really odd is going on, so let the exception get thrown - var registryWin64 = Boolean.Parse(context["Win64"]); - - switch (element.Name.LocalName) - { - case "PermissionEx": - this.ParsePermissionExElement(intermediate, section, element, registryId, registryComponentId, registryWin64, "Registry"); - break; - default: - this.ParseHelper.UnexpectedElement(parentElement, element); - break; - } - break; - case "ServiceInstall": - var serviceInstallId = context["ServiceInstallId"]; - var serviceInstallName = context["ServiceInstallName"]; - var serviceInstallComponentId = context["ServiceInstallComponentId"]; - - // If this doesn't parse successfully, something really odd is going on, so let the exception get thrown - var serviceInstallWin64 = Boolean.Parse(context["Win64"]); - - switch (element.Name.LocalName) - { - case "PermissionEx": - this.ParsePermissionExElement(intermediate, section, element, serviceInstallId, serviceInstallComponentId, serviceInstallWin64, "ServiceInstall"); - break; - case "ServiceConfig": - this.ParseServiceConfigElement(intermediate, section, element, serviceInstallComponentId, "ServiceInstall", serviceInstallName); - break; - default: - this.ParseHelper.UnexpectedElement(parentElement, element); - break; - } - break; - case "UI": - switch (element.Name.LocalName) - { - case "BroadcastEnvironmentChange": - case "BroadcastSettingChange": - case "CheckRebootRequired": - case "ExitEarlyWithSuccess": - case "FailWhenDeferred": - case "QueryWindowsDirectories": - case "QueryWindowsDriverInfo": - case "QueryWindowsSuiteInfo": - case "QueryWindowsWellKnownSIDs": - case "WaitForEvent": - case "WaitForEventDeferred": - this.AddCustomActionReference(intermediate, section, element, parentElement); - break; - } - break; - default: - this.ParseHelper.UnexpectedElement(parentElement, element); - break; - } - - return possibleKeyPath; - } - - private void AddCustomActionReference(Intermediate intermediate, IntermediateSection section, XElement element, XElement parentElement) - { - // These elements are not supported for bundles. - if (parentElement.Name.LocalName == "Bundle") - { - this.ParseHelper.UnexpectedElement(parentElement, element); - return; - } - - var customAction = element.Name.LocalName; - switch (element.Name.LocalName) - { - case "BroadcastEnvironmentChange": - case "BroadcastSettingChange": - case "CheckRebootRequired": - case "ExitEarlyWithSuccess": - case "FailWhenDeferred": - case "WaitForEvent": - case "WaitForEventDeferred": - //default: customAction = element.Name.LocalName; - break; - case "QueryWindowsDirectories": - customAction = "QueryOsDirs"; - break; - case "QueryWindowsDriverInfo": - customAction = "QueryOsDriverInfo"; - break; - case "QueryWindowsSuiteInfo": - customAction = "QueryOsInfo"; - break; - case "QueryWindowsWellKnownSIDs": - customAction = "QueryOsWellKnownSID"; - break; - } - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - // no attributes today - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - - this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); - - this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4" + customAction, this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); - } - - /// - /// Parses the common search attributes shared across all searches. - /// - /// Source line number for the parent element. - /// Attribute to parse. - /// Value of the Id attribute. - /// Value of the Variable attribute. - /// Value of the Condition attribute. - /// Value of the After attribute. - private void ParseCommonSearchAttributes(SourceLineNumber sourceLineNumbers, XAttribute attrib, ref Identifier id, ref string variable, ref string condition, ref string after) - { - switch (attrib.Name.LocalName) - { - case "Id": - id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); - break; - case "Variable": - variable = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - // TODO: handle standard bundle variables - break; - case "Condition": - condition = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "After": - after = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - default: - System.Diagnostics.Debug.Assert(false); - break; - } - } - - /// - /// Parses a ComponentSearch element. - /// - /// Element to parse. - private void ParseComponentSearchElement(Intermediate intermediate, IntermediateSection section, XElement element) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - Identifier id = null; - string variable = null; - string condition = null; - string after = null; - string guid = null; - string productCode = null; - var attributes = WixComponentSearchAttributes.KeyPath; - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "Id": - case "Variable": - case "Condition": - case "After": - this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after); - break; - case "Guid": - guid = this.ParseHelper.GetAttributeGuidValue(sourceLineNumbers, attrib); - break; - case "ProductCode": - productCode = this.ParseHelper.GetAttributeGuidValue(sourceLineNumbers, attrib); - break; - case "Result": - var result = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - switch (result) - { - case "directory": - attributes = WixComponentSearchAttributes.WantDirectory; - break; - case "keyPath": - attributes = WixComponentSearchAttributes.KeyPath; - break; - case "state": - attributes = WixComponentSearchAttributes.State; - break; - default: - this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, result, "directory", "keyPath", "state")); - break; - } - break; - default: - this.ParseHelper.UnexpectedAttribute(element, attrib); - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - if (null == guid) - { - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Guid")); - } - - if (null == id) - { - id = this.ParseHelper.CreateIdentifier("wcs", variable, condition, after, guid, productCode, attributes.ToString()); - } - - this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); - - this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, null); - - if (!this.Messaging.EncounteredError) - { - section.AddSymbol(new WixComponentSearchSymbol(sourceLineNumbers, id) - { - Guid = guid, - ProductCode = productCode, - Attributes = attributes, - }); - } - } - - /// - /// Parses a ComponentSearchRef element - /// - /// Element to parse. - private void ParseComponentSearchRefElement(Intermediate intermediate, IntermediateSection section, XElement element) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - string refId = null; - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "Id": - refId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib); - this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.WixComponentSearch, refId); - break; - default: - this.ParseHelper.UnexpectedAttribute(element, attrib); - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); - } - - /// - /// Parses a WindowsFeatureSearch element. - /// - /// Element to parse. - private void ParseWindowsFeatureSearchElement(Intermediate intermediate, IntermediateSection section, XElement element) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - Identifier id = null; - string variable = null; - string condition = null; - string after = null; - string feature = null; - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "Id": - case "Variable": - case "Condition": - case "After": - this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after); - break; - case "Feature": - feature = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - switch (feature) - { - case "sha2CodeSigning": - break; - default: - this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Feature", feature, "sha2CodeSigning")); - break; - } - break; - default: - this.ParseHelper.UnexpectedAttribute(element, attrib); - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - if (id == null) - { - id = this.ParseHelper.CreateIdentifier("wwfs", variable, condition, after); - } - - if (feature == null) - { - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Feature")); - } - - this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); - - var bundleExtensionId = this.ParseHelper.CreateIdentifierValueFromPlatform("Wix4UtilBundleExtension", this.Context.Platform, BurnPlatforms.X86 | BurnPlatforms.X64 | BurnPlatforms.ARM64); - if (bundleExtensionId == null) - { - this.Messaging.Write(ErrorMessages.UnsupportedPlatformForElement(sourceLineNumbers, this.Context.Platform.ToString(), element.Name.LocalName)); - } - - this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, bundleExtensionId); - - if (!this.Messaging.EncounteredError) - { - section.AddSymbol(new WixWindowsFeatureSearchSymbol(sourceLineNumbers, id) - { - Type = feature, - }); - } - } - - /// - /// Parses a WindowsFeatureSearchRef element - /// - /// Element to parse. - private void ParseWindowsFeatureSearchRefElement(Intermediate intermediate, IntermediateSection section, XElement element) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "Id": - var refId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib); - this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, UtilSymbolDefinitions.WixWindowsFeatureSearch, refId); - break; - default: - this.ParseHelper.UnexpectedAttribute(element, attrib); - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); - } - - /// - /// Parses an event source element. - /// - /// Element to parse. - /// Identifier of parent component. - private IComponentKeyPath ParseEventSourceElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - string sourceName = null; - string logName = null; - string categoryMessageFile = null; - var categoryCount = CompilerConstants.IntegerNotSet; - string eventMessageFile = null; - string parameterMessageFile = null; - int typesSupported = 0; - var isKeyPath = false; - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "CategoryCount": - categoryCount = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); - break; - case "CategoryMessageFile": - categoryMessageFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "EventMessageFile": - eventMessageFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "KeyPath": - isKeyPath = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib); - break; - case "Log": - logName = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - if ("Security" == logName) - { - this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, logName, "Application", "System", "")); - } - break; - case "Name": - sourceName = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "ParameterMessageFile": - parameterMessageFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "SupportsErrors": - if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - { - typesSupported |= 0x01; // EVENTLOG_ERROR_TYPE - } - break; - case "SupportsFailureAudits": - if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - { - typesSupported |= 0x10; // EVENTLOG_AUDIT_FAILURE - } - break; - case "SupportsInformationals": - if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - { - typesSupported |= 0x04; // EVENTLOG_INFORMATION_TYPE - } - break; - case "SupportsSuccessAudits": - if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - { - typesSupported |= 0x08; // EVENTLOG_AUDIT_SUCCESS - } - break; - case "SupportsWarnings": - if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - { - typesSupported |= 0x02; // EVENTLOG_WARNING_TYPE - } - break; - default: - this.ParseHelper.UnexpectedAttribute(element, attrib); - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - if (null == sourceName) - { - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name")); - } - - if (null == logName) - { - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "EventLog")); - } - - if (null == eventMessageFile) - { - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "EventMessageFile")); - } - - if (null == categoryMessageFile && 0 < categoryCount) - { - this.Messaging.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, element.Name.LocalName, "CategoryCount", "CategoryMessageFile")); - } - - if (null != categoryMessageFile && CompilerConstants.IntegerNotSet == categoryCount) - { - this.Messaging.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, element.Name.LocalName, "CategoryMessageFile", "CategoryCount")); - } - - this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); - - string eventSourceKey = $@"SYSTEM\CurrentControlSet\Services\EventLog\{logName}\{sourceName}"; - var id = this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, eventSourceKey, "EventMessageFile", String.Concat("#%", eventMessageFile), componentId, false); - - if (null != categoryMessageFile) - { - this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, eventSourceKey, "CategoryMessageFile", String.Concat("#%", categoryMessageFile), componentId, false); - } - - if (CompilerConstants.IntegerNotSet != categoryCount) - { - this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, eventSourceKey, "CategoryCount", String.Concat("#", categoryCount), componentId, false); - } - - if (null != parameterMessageFile) - { - this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, eventSourceKey, "ParameterMessageFile", String.Concat("#%", parameterMessageFile), componentId, false); - } - - if (0 != typesSupported) - { - this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, eventSourceKey, "TypesSupported", String.Concat("#", typesSupported), componentId, false); - } - - var componentKeyPath = this.CreateComponentKeyPath(); - componentKeyPath.Id = id.Id; - componentKeyPath.Explicit = isKeyPath; - componentKeyPath.Type = PossibleKeyPathType.Registry; - return componentKeyPath; - } - - /// - /// Parses a close application element. - /// - /// Element to parse. - private void ParseCloseApplicationElement(Intermediate intermediate, IntermediateSection section, XElement element) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - string condition = null; - string description = null; - string target = null; - string property = null; - Identifier id = null; - int attributes = 2; // default to CLOSEAPP_ATTRIBUTE_REBOOTPROMPT enabled - var sequence = CompilerConstants.IntegerNotSet; - var terminateExitCode = CompilerConstants.IntegerNotSet; - var timeout = CompilerConstants.IntegerNotSet; - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "Id": - id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); - break; - case "Condition": - condition = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "Description": - description = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "Property": - property = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib); - break; - case "Sequence": - sequence = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); - break; - case "Timeout": - timeout = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); - break; - case "Target": - target = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "CloseMessage": - if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - { - attributes |= 1; // CLOSEAPP_ATTRIBUTE_CLOSEMESSAGE - } - else - { - attributes &= ~1; // CLOSEAPP_ATTRIBUTE_CLOSEMESSAGE - } - break; - case "EndSessionMessage": - if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - { - attributes |= 8; // CLOSEAPP_ATTRIBUTE_ENDSESSIONMESSAGE - } - else - { - attributes &= ~8; // CLOSEAPP_ATTRIBUTE_ENDSESSIONMESSAGE - } - break; - case "PromptToContinue": - if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - { - attributes |= 0x40; // CLOSEAPP_ATTRIBUTE_PROMPTTOCONTINUE - } - else - { - attributes &= ~0x40; // CLOSEAPP_ATTRIBUTE_PROMPTTOCONTINUE - } - break; - case "RebootPrompt": - if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - { - attributes |= 2; // CLOSEAPP_ATTRIBUTE_REBOOTPROMPT - } - else - { - attributes &= ~2; // CLOSEAPP_ATTRIBUTE_REBOOTPROMPT - } - break; - case "ElevatedCloseMessage": - if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - { - attributes |= 4; // CLOSEAPP_ATTRIBUTE_ELEVATEDCLOSEMESSAGE - } - else - { - attributes &= ~4; // CLOSEAPP_ATTRIBUTE_ELEVATEDCLOSEMESSAGE - } - break; - case "ElevatedEndSessionMessage": - if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - { - attributes |= 0x10; // CLOSEAPP_ATTRIBUTE_ELEVATEDENDSESSIONMESSAGE - } - else - { - attributes &= ~0x10; // CLOSEAPP_ATTRIBUTE_ELEVATEDENDSESSIONMESSAGE - } - break; - case "TerminateProcess": - terminateExitCode = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); - attributes |= 0x20; // CLOSEAPP_ATTRIBUTE_TERMINATEPROCESS - break; - default: - this.ParseHelper.UnexpectedAttribute(element, attrib); - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - if (null == target) - { - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Target")); - } - else if (null == id) - { - id = this.ParseHelper.CreateIdentifier("ca", target); - } - - if (String.IsNullOrEmpty(description) && 0x40 == (attributes & 0x40)) - { - this.Messaging.Write(ErrorMessages.IllegalAttributeValueWithoutOtherAttribute(sourceLineNumbers, element.Name.LocalName, "PromptToContinue", "yes", "Description")); - } - - if (0x22 == (attributes & 0x22)) - { - this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "TerminateProcess", "RebootPrompt", "yes")); - } - - this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); - - this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4CloseApplications", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); - - if (!this.Messaging.EncounteredError) - { - var symbol = section.AddSymbol(new WixCloseApplicationSymbol(sourceLineNumbers, id) - { - Target = target, - Description = description, - Condition = condition, - Attributes = attributes, - Property = property, - }); - if (CompilerConstants.IntegerNotSet != sequence) - { - symbol.Sequence = sequence; - } - if (CompilerConstants.IntegerNotSet != terminateExitCode) - { - symbol.TerminateExitCode = terminateExitCode; - } - if (CompilerConstants.IntegerNotSet != timeout) - { - symbol.Timeout = timeout * 1000; // make the timeout milliseconds in the table. - } - } - } - - /// - /// Parses a DirectorySearch element. - /// - /// Element to parse. - private void ParseDirectorySearchElement(Intermediate intermediate, IntermediateSection section, XElement element) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - Identifier id = null; - string variable = null; - string condition = null; - string after = null; - string path = null; - var attributes = WixFileSearchAttributes.IsDirectory; - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "Id": - case "Variable": - case "Condition": - case "After": - this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after); - break; - case "Path": - path = this.ParseHelper.GetAttributeLongFilename(sourceLineNumbers, attrib, false, true); - break; - case "Result": - var result = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - switch (result) - { - case "exists": - attributes |= WixFileSearchAttributes.WantExists; - break; - default: - this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, result, "exists")); - break; - } - break; - default: - this.ParseHelper.UnexpectedAttribute(element, attrib); - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - if (null == path) - { - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Path")); - } - - if (null == id) - { - id = this.ParseHelper.CreateIdentifier("wds", variable, condition, after, path, attributes.ToString()); - } - - this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); - - this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, null); - - if (!this.Messaging.EncounteredError) - { - this.CreateWixFileSearchRow(section, sourceLineNumbers, id, path, attributes); - } - } - - /// - /// Parses a DirectorySearchRef, FileSearchRef, ProductSearchRef, and RegistrySearchRef elements - /// - /// Element to parse. - private void ParseWixSearchRefElement(Intermediate intermediate, IntermediateSection section, XElement node) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); - - foreach (XAttribute attrib in node.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "Id": - var refId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib); - this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.WixSearch, refId); - break; - default: - this.ParseHelper.UnexpectedAttribute(node, attrib); - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib); - } - } - - this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, node); - } - - /// - /// Parses a FileSearch element. - /// - /// Element to parse. - private void ParseFileSearchElement(Intermediate intermediate, IntermediateSection section, XElement node) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); - Identifier id = null; - string variable = null; - string condition = null; - string after = null; - string path = null; - var attributes = WixFileSearchAttributes.Default; - - foreach (var attrib in node.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "Id": - case "Variable": - case "Condition": - case "After": - this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after); - break; - case "Path": - path = this.ParseHelper.GetAttributeLongFilename(sourceLineNumbers, attrib, false, true); - break; - case "Result": - string result = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - switch (result) - { - case "exists": - attributes |= WixFileSearchAttributes.WantExists; - break; - case "version": - attributes |= WixFileSearchAttributes.WantVersion; - break; - default: - this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, result, "exists", "version")); - break; - } - break; - default: - this.ParseHelper.UnexpectedAttribute(node, attrib); - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib); - } - } - - if (null == path) - { - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Path")); - } - - if (null == id) - { - id = this.ParseHelper.CreateIdentifier("wfs", variable, condition, after, path, attributes.ToString()); - } - - this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, node); - - this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, node.Name.LocalName, id, variable, condition, after, null); - - if (!this.Messaging.EncounteredError) - { - this.CreateWixFileSearchRow(section, sourceLineNumbers, id, path, attributes); - } - } - - /// - /// Creates a row in the WixFileSearch table. - /// - /// Source line number for the parent element. - /// Identifier of the search (key into the WixSearch table) - /// File/directory path to search for. - /// - private void CreateWixFileSearchRow(IntermediateSection section, SourceLineNumber sourceLineNumbers, Identifier id, string path, WixFileSearchAttributes attributes) - { - section.AddSymbol(new WixFileSearchSymbol(sourceLineNumbers, id) - { - Path = path, - Attributes = attributes, - }); - } - - /// - /// Parses a file share element. - /// - /// Element to parse. - /// Identifier of parent component. - /// Identifier of referred to directory. - private void ParseFileShareElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string directoryId) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - string description = null; - string name = null; - Identifier id = null; - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "Id": - id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); - break; - case "Name": - name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "Description": - description = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - default: - this.ParseHelper.UnexpectedAttribute(element, attrib); - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - if (null == id) - { - id = this.ParseHelper.CreateIdentifier("ufs", componentId, name); - } - - if (null == name) - { - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name")); - } - - if (!element.Elements().Any()) - { - this.Messaging.Write(ErrorMessages.ExpectedElement(sourceLineNumbers, element.Name.LocalName, "FileSharePermission")); - } - - foreach (var child in element.Elements()) - { - if (this.Namespace == child.Name.Namespace) - { - switch (child.Name.LocalName) - { - case "FileSharePermission": - this.ParseFileSharePermissionElement(intermediate, section, child, id); - break; - default: - this.ParseHelper.UnexpectedElement(element, child); - break; - } - } - else - { - this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child); - } - } - - this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureSmbInstall", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); - this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureSmbUninstall", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); - - if (!this.Messaging.EncounteredError) - { - section.AddSymbol(new FileShareSymbol(sourceLineNumbers, id) - { - ShareName = name, - ComponentRef = componentId, - Description = description, - DirectoryRef = directoryId, - }); - } - } - - /// - /// Parses a FileSharePermission element. - /// - /// Element to parse. - /// The identifier of the parent FileShare element. - private void ParseFileSharePermissionElement(Intermediate intermediate, IntermediateSection section, XElement element, Identifier fileShareId) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - var bits = new BitArray(32); - string user = null; - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "User": - user = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib); - this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, UtilSymbolDefinitions.User, user); - break; - default: - var attribValue = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib); - if (!this.TrySetBitFromName(UtilConstants.StandardPermissions, attrib.Name.LocalName, attribValue, bits, 16)) - { - if (!this.TrySetBitFromName(UtilConstants.GenericPermissions, attrib.Name.LocalName, attribValue, bits, 28)) - { - if (!this.TrySetBitFromName(UtilConstants.FolderPermissions, attrib.Name.LocalName, attribValue, bits, 0)) - { - this.ParseHelper.UnexpectedAttribute(element, attrib); - break; - } - } - } - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - var permission = this.CreateIntegerFromBitArray(bits); - - if (null == user) - { - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "User")); - } - - if (Int32.MinValue == permission) // just GENERIC_READ, which is MSI_NULL - { - this.Messaging.Write(ErrorMessages.GenericReadNotAllowed(sourceLineNumbers)); - } - - this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); - - if (!this.Messaging.EncounteredError) - { - section.AddSymbol(new FileSharePermissionsSymbol(sourceLineNumbers) - { - FileShareRef = fileShareId.Id, - UserRef = user, - Permissions = permission, - }); - } - } - - /// - /// Parses a group element. - /// - /// Node to be parsed. - /// Component Id of the parent component of this element. - private void ParseGroupElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - Identifier id = null; - string domain = null; - string name = null; - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "Id": - id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); - break; - case "Name": - name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "Domain": - domain = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - default: - this.ParseHelper.UnexpectedAttribute(element, attrib); - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - if (null == id) - { - id = this.ParseHelper.CreateIdentifier("ugr", componentId, domain, name); - } - - this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); - - if (!this.Messaging.EncounteredError) - { - section.AddSymbol(new GroupSymbol(sourceLineNumbers, id) - { - ComponentRef = componentId, - Name = name, - Domain = domain, - }); - } - } - - /// - /// Parses a GroupRef element - /// - /// Element to parse. - /// Required user id to be joined to the group. - private void ParseGroupRefElement(Intermediate intermediate, IntermediateSection section, XElement element, string userId) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - string groupId = null; - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "Id": - groupId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib); - this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, UtilSymbolDefinitions.Group, groupId); - break; - default: - this.ParseHelper.UnexpectedAttribute(element, attrib); - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); - - if (!this.Messaging.EncounteredError) - { - section.AddSymbol(new UserGroupSymbol(sourceLineNumbers) - { - UserRef = userId, - GroupRef = groupId, - }); - } - } - - /// - /// Parses an InternetShortcut element. - /// - /// Element to parse. - /// Identifier of parent component. - /// Default directory if none is specified on the InternetShortcut element. - private void ParseInternetShortcutElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string defaultTarget) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - Identifier id = null; - string name = null; - string target = null; - string directoryId = null; - string type = null; - string iconFile = null; - int iconIndex = 0; - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "Directory": - directoryId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib); - break; - case "Id": - id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); - break; - case "Name": - name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "Target": - target = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "Type": - type = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "IconFile": - iconFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "IconIndex": - iconIndex = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); - break; - default: - this.ParseHelper.UnexpectedAttribute(element, attrib); - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - // If there was no directoryId specified on the InternetShortcut element, default to the one on - // the parent component. - if (null == directoryId) - { - directoryId = defaultTarget; - } - - if (null == id) - { - id = this.ParseHelper.CreateIdentifier("uis", componentId, directoryId, name, target); - } - - // In theory this can never be the case, since InternetShortcut can only be under - // a component element, and if the Directory wasn't specified the default will come - // from the component. However, better safe than sorry, so here's a check to make sure - // it didn't wind up being null after setting it to the defaultTarget. - if (null == directoryId) - { - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Directory")); - } - - if (null == name) - { - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name")); - } - - if (null == target) - { - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Target")); - } - - this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); - - var shortcutType = InternetShortcutType.Link; - if (String.Equals(type, "url", StringComparison.OrdinalIgnoreCase)) - { - shortcutType = InternetShortcutType.Url; - } - - if (!this.Messaging.EncounteredError) - { - this.CreateWixInternetShortcut(section, sourceLineNumbers, componentId, directoryId, id, name, target, shortcutType, iconFile, iconIndex); - } - } - - /// - /// Creates the rows needed for WixInternetShortcut to work. - /// - /// The CompilerCore object used to create rows. - /// Source line information about the owner element. - /// Identifier of parent component. - /// Identifier of directory containing shortcut. - /// Identifier of shortcut. - /// Name of shortcut without extension. - /// Target URL of shortcut. - private void CreateWixInternetShortcut(IntermediateSection section, SourceLineNumber sourceLineNumbers, string componentId, string directoryId, Identifier shortcutId, string name, string target, InternetShortcutType type, string iconFile, int iconIndex) - { - // add the appropriate extension based on type of shortcut - name = String.Concat(name, InternetShortcutType.Url == type ? ".url" : ".lnk"); - - section.AddSymbol(new WixInternetShortcutSymbol(sourceLineNumbers, shortcutId) - { - ComponentRef = componentId, - DirectoryRef = directoryId, - Name = name, - Target = target, - Attributes = (int)type, - IconFile = iconFile, - IconIndex = iconIndex, - }); - - this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedInternetShortcuts", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); - - // make sure we have a CreateFolder table so that the immediate CA can add temporary rows to handle installation and uninstallation - this.ParseHelper.EnsureTable(section, sourceLineNumbers, "CreateFolder"); - - // use built-in MSI functionality to remove the shortcuts rather than doing so via CA - section.AddSymbol(new RemoveFileSymbol(sourceLineNumbers, shortcutId) - { - ComponentRef = componentId, - DirPropertyRef = directoryId, - OnUninstall = true, - FileName = name, - }); - } - - /// - /// Parses a performance category element. - /// - /// Element to parse. - /// Identifier of parent component. - private void ParsePerformanceCategoryElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - Identifier id = null; - string name = null; - string help = null; - var multiInstance = YesNoType.No; - int defaultLanguage = 0x09; // default to "english" - - var parsedPerformanceCounters = new List(); - - // default to managed performance counter - var library = "netfxperf.dll"; - var openEntryPoint = "OpenPerformanceData"; - var collectEntryPoint = "CollectPerformanceData"; - var closeEntryPoint = "ClosePerformanceData"; - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "Close": - closeEntryPoint = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "Collect": - collectEntryPoint = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "DefaultLanguage": - defaultLanguage = this.GetPerformanceCounterLanguage(sourceLineNumbers, attrib); - break; - case "Help": - help = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "Id": - id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); - break; - case "Library": - library = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "MultiInstance": - multiInstance = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib); - break; - case "Name": - name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "Open": - openEntryPoint = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - default: - this.ParseHelper.UnexpectedAttribute(element, attrib); - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - if (null == id && null == name) - { - this.Messaging.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, element.Name.LocalName, "Id", "Name")); - } - else if (null == id) - { - id = this.ParseHelper.CreateIdentifier("upc", componentId, name); - } - else if (null == name) - { - name = id.Id; - } - - // Process the child counter elements. - foreach (var child in element.Elements()) - { - if (this.Namespace == child.Name.Namespace) - { - switch (child.Name.LocalName) - { - case "PerformanceCounter": - var counter = this.ParsePerformanceCounterElement(intermediate, section, child, defaultLanguage); - if (null != counter) - { - parsedPerformanceCounters.Add(counter); - } - break; - default: - this.ParseHelper.UnexpectedElement(element, child); - break; - } - } - else - { - this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child); - } - } - - - if (!this.Messaging.EncounteredError) - { - // Calculate the ini and h file content. - var objectName = "OBJECT_1"; - var objectLanguage = defaultLanguage.ToString("D3", CultureInfo.InvariantCulture); - - var sbIniData = new StringBuilder(); - 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); - sbIniData.AppendFormat("[text]\r\n{0}_{1}_NAME={2}\r\n", objectName, objectLanguage, name); - if (null != help) - { - sbIniData.AppendFormat("{0}_{1}_HELP={2}\r\n", objectName, objectLanguage, help); - } - - int symbolConstantsCounter = 0; - var sbSymbolicConstants = new StringBuilder(); - sbSymbolicConstants.AppendFormat("#define {0} {1}\r\n", objectName, symbolConstantsCounter); - - var sbCounterNames = new StringBuilder("[~]"); - var sbCounterTypes = new StringBuilder("[~]"); - for (int i = 0; i < parsedPerformanceCounters.Count; ++i) - { - var counter = parsedPerformanceCounters[i]; - var counterName = String.Concat("DEVICE_COUNTER_", i + 1); - - sbIniData.AppendFormat("{0}_{1}_NAME={2}\r\n", counterName, counter.Language, counter.Name); - if (null != counter.Help) - { - sbIniData.AppendFormat("{0}_{1}_HELP={2}\r\n", counterName, counter.Language, counter.Help); - } - - symbolConstantsCounter += 2; - sbSymbolicConstants.AppendFormat("#define {0} {1}\r\n", counterName, symbolConstantsCounter); - - sbCounterNames.Append(UtilCompiler.FindPropertyBrackets.Replace(counter.Name, this.EscapeProperties)); - sbCounterNames.Append("[~]"); - sbCounterTypes.Append(counter.Type); - sbCounterTypes.Append("[~]"); - } - - sbSymbolicConstants.AppendFormat("#define LAST_{0}_COUNTER_OFFSET {1}\r\n", objectName, symbolConstantsCounter); - - // Add the calculated INI and H strings to the PerformanceCategory table. - section.AddSymbol(new PerformanceCategorySymbol(sourceLineNumbers, id) - { - ComponentRef = componentId, - Name = name, - IniData = sbIniData.ToString(), - ConstantData = sbSymbolicConstants.ToString(), - }); - - // Set up the application's performance key. - var escapedName = UtilCompiler.FindPropertyBrackets.Replace(name, this.EscapeProperties); - var linkageKey = String.Format(@"SYSTEM\CurrentControlSet\Services\{0}\Linkage", escapedName); - var performanceKey = String.Format(@"SYSTEM\CurrentControlSet\Services\{0}\Performance", escapedName); - - this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, linkageKey, "Export", escapedName, componentId, false); - this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "-", null, componentId, false); - this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Library", library, componentId, false); - this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Open", openEntryPoint, componentId, false); - this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Collect", collectEntryPoint, componentId, false); - this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Close", closeEntryPoint, componentId, false); - this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "IsMultiInstance", YesNoType.Yes == multiInstance ? "#1" : "#0", componentId, false); - this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Counter Names", sbCounterNames.ToString(), componentId, false); - this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Counter Types", sbCounterTypes.ToString(), componentId, false); - } - - this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4InstallPerfCounterData", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); - this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4UninstallPerfCounterData", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); - } - - /// - /// Gets the performance counter language as a decimal number. - /// - /// Source line information about the owner element. - /// The attribute containing the value to get. - /// Numeric representation of the language as per WinNT.h. - private int GetPerformanceCounterLanguage(SourceLineNumber sourceLineNumbers, XAttribute attribute) - { - int language = 0; - if (String.Empty == attribute.Value) - { - this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName)); - } - else - { - switch (attribute.Value) - { - case "afrikaans": - language = 0x36; - break; - case "albanian": - language = 0x1c; - break; - case "arabic": - language = 0x01; - break; - case "armenian": - language = 0x2b; - break; - case "assamese": - language = 0x4d; - break; - case "azeri": - language = 0x2c; - break; - case "basque": - language = 0x2d; - break; - case "belarusian": - language = 0x23; - break; - case "bengali": - language = 0x45; - break; - case "bulgarian": - language = 0x02; - break; - case "catalan": - language = 0x03; - break; - case "chinese": - language = 0x04; - break; - case "croatian": - language = 0x1a; - break; - case "czech": - language = 0x05; - break; - case "danish": - language = 0x06; - break; - case "divehi": - language = 0x65; - break; - case "dutch": - language = 0x13; - break; - case "piglatin": - case "english": - language = 0x09; - break; - case "estonian": - language = 0x25; - break; - case "faeroese": - language = 0x38; - break; - case "farsi": - language = 0x29; - break; - case "finnish": - language = 0x0b; - break; - case "french": - language = 0x0c; - break; - case "galician": - language = 0x56; - break; - case "georgian": - language = 0x37; - break; - case "german": - language = 0x07; - break; - case "greek": - language = 0x08; - break; - case "gujarati": - language = 0x47; - break; - case "hebrew": - language = 0x0d; - break; - case "hindi": - language = 0x39; - break; - case "hungarian": - language = 0x0e; - break; - case "icelandic": - language = 0x0f; - break; - case "indonesian": - language = 0x21; - break; - case "italian": - language = 0x10; - break; - case "japanese": - language = 0x11; - break; - case "kannada": - language = 0x4b; - break; - case "kashmiri": - language = 0x60; - break; - case "kazak": - language = 0x3f; - break; - case "konkani": - language = 0x57; - break; - case "korean": - language = 0x12; - break; - case "kyrgyz": - language = 0x40; - break; - case "latvian": - language = 0x26; - break; - case "lithuanian": - language = 0x27; - break; - case "macedonian": - language = 0x2f; - break; - case "malay": - language = 0x3e; - break; - case "malayalam": - language = 0x4c; - break; - case "manipuri": - language = 0x58; - break; - case "marathi": - language = 0x4e; - break; - case "mongolian": - language = 0x50; - break; - case "nepali": - language = 0x61; - break; - case "norwegian": - language = 0x14; - break; - case "oriya": - language = 0x48; - break; - case "polish": - language = 0x15; - break; - case "portuguese": - language = 0x16; - break; - case "punjabi": - language = 0x46; - break; - case "romanian": - language = 0x18; - break; - case "russian": - language = 0x19; - break; - case "sanskrit": - language = 0x4f; - break; - case "serbian": - language = 0x1a; - break; - case "sindhi": - language = 0x59; - break; - case "slovak": - language = 0x1b; - break; - case "slovenian": - language = 0x24; - break; - case "spanish": - language = 0x0a; - break; - case "swahili": - language = 0x41; - break; - case "swedish": - language = 0x1d; - break; - case "syriac": - language = 0x5a; - break; - case "tamil": - language = 0x49; - break; - case "tatar": - language = 0x44; - break; - case "telugu": - language = 0x4a; - break; - case "thai": - language = 0x1e; - break; - case "turkish": - language = 0x1f; - break; - case "ukrainian": - language = 0x22; - break; - case "urdu": - language = 0x20; - break; - case "uzbek": - language = 0x43; - break; - case "vietnamese": - language = 0x2a; - break; - default: - this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName)); - break; - } - } - - return language; - } - - /// - /// Parses a performance counter element. - /// - /// Element to parse. - /// Default language for the performance counter. - private ParsedPerformanceCounter ParsePerformanceCounterElement(Intermediate intermediate, IntermediateSection section, XElement element, int defaultLanguage) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - ParsedPerformanceCounter parsedPerformanceCounter = null; - string name = null; - string help = null; - var type = System.Diagnostics.PerformanceCounterType.NumberOfItems32; - int language = defaultLanguage; - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "Help": - help = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "Name": - name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "Type": - type = this.GetPerformanceCounterType(sourceLineNumbers, attrib); - break; - case "Language": - language = this.GetPerformanceCounterLanguage(sourceLineNumbers, attrib); - break; - default: - this.ParseHelper.UnexpectedAttribute(element, attrib); - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - if (null == name) - { - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name")); - } - - if (null == help) - { - this.Messaging.Write(UtilWarnings.RequiredAttributeForWindowsXP(sourceLineNumbers, element.Name.LocalName, "Help")); - } - - this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); - - if (!this.Messaging.EncounteredError) - { - parsedPerformanceCounter = new ParsedPerformanceCounter(name, help, type, language); - } - - return parsedPerformanceCounter; - } - - /// - /// Gets the performance counter type. - /// - /// Source line information about the owner element. - /// The attribute containing the value to get. - /// Numeric representation of the language as per WinNT.h. - private System.Diagnostics.PerformanceCounterType GetPerformanceCounterType(SourceLineNumber sourceLineNumbers, XAttribute attribute) - { - var type = System.Diagnostics.PerformanceCounterType.NumberOfItems32; - if (String.Empty == attribute.Value) - { - this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName)); - } - else - { - switch (attribute.Value) - { - case "averageBase": - type = System.Diagnostics.PerformanceCounterType.AverageBase; - break; - case "averageCount64": - type = System.Diagnostics.PerformanceCounterType.AverageCount64; - break; - case "averageTimer32": - type = System.Diagnostics.PerformanceCounterType.AverageTimer32; - break; - case "counterDelta32": - type = System.Diagnostics.PerformanceCounterType.CounterDelta32; - break; - case "counterTimerInverse": - type = System.Diagnostics.PerformanceCounterType.CounterTimerInverse; - break; - case "sampleFraction": - type = System.Diagnostics.PerformanceCounterType.SampleFraction; - break; - case "timer100Ns": - type = System.Diagnostics.PerformanceCounterType.Timer100Ns; - break; - case "counterTimer": - type = System.Diagnostics.PerformanceCounterType.CounterTimer; - break; - case "rawFraction": - type = System.Diagnostics.PerformanceCounterType.RawFraction; - break; - case "timer100NsInverse": - type = System.Diagnostics.PerformanceCounterType.Timer100NsInverse; - break; - case "counterMultiTimer": - type = System.Diagnostics.PerformanceCounterType.CounterMultiTimer; - break; - case "counterMultiTimer100Ns": - type = System.Diagnostics.PerformanceCounterType.CounterMultiTimer100Ns; - break; - case "counterMultiTimerInverse": - type = System.Diagnostics.PerformanceCounterType.CounterMultiTimerInverse; - break; - case "counterMultiTimer100NsInverse": - type = System.Diagnostics.PerformanceCounterType.CounterMultiTimer100NsInverse; - break; - case "elapsedTime": - type = System.Diagnostics.PerformanceCounterType.ElapsedTime; - break; - case "sampleBase": - type = System.Diagnostics.PerformanceCounterType.SampleBase; - break; - case "rawBase": - type = System.Diagnostics.PerformanceCounterType.RawBase; - break; - case "counterMultiBase": - type = System.Diagnostics.PerformanceCounterType.CounterMultiBase; - break; - case "rateOfCountsPerSecond64": - type = System.Diagnostics.PerformanceCounterType.RateOfCountsPerSecond64; - break; - case "rateOfCountsPerSecond32": - type = System.Diagnostics.PerformanceCounterType.RateOfCountsPerSecond32; - break; - case "countPerTimeInterval64": - type = System.Diagnostics.PerformanceCounterType.CountPerTimeInterval64; - break; - case "countPerTimeInterval32": - type = System.Diagnostics.PerformanceCounterType.CountPerTimeInterval32; - break; - case "sampleCounter": - type = System.Diagnostics.PerformanceCounterType.SampleCounter; - break; - case "counterDelta64": - type = System.Diagnostics.PerformanceCounterType.CounterDelta64; - break; - case "numberOfItems64": - type = System.Diagnostics.PerformanceCounterType.NumberOfItems64; - break; - case "numberOfItems32": - type = System.Diagnostics.PerformanceCounterType.NumberOfItems32; - break; - case "numberOfItemsHEX64": - type = System.Diagnostics.PerformanceCounterType.NumberOfItemsHEX64; - break; - case "numberOfItemsHEX32": - type = System.Diagnostics.PerformanceCounterType.NumberOfItemsHEX32; - break; - default: - this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName)); - break; - } - } - - return type; - } - - /// - /// Parses a perf counter element. - /// - /// Element to parse. - /// Identifier of parent component. - /// Identifier of referenced file. - private void ParsePerfCounterElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string fileId) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - string name = null; - - this.Messaging.Write(UtilWarnings.DeprecatedPerfCounterElement(sourceLineNumbers)); - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "Name": - name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - default: - this.ParseHelper.UnexpectedAttribute(element, attrib); - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - if (null == name) - { - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name")); - } - - this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); - - if (!this.Messaging.EncounteredError) - { - section.AddSymbol(new PerfmonSymbol(sourceLineNumbers) - { - ComponentRef = componentId, - File = $"[#{fileId}]", - Name = name, - }); - } - - this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigurePerfmonInstall", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); - this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigurePerfmonUninstall", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); - } - - - /// - /// Parses a perf manifest element. - /// - /// Element to parse. - /// Identifier of parent component. - /// Identifier of referenced file. - private void ParsePerfCounterManifestElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string fileId) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - string resourceFileDirectory = null; - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "ResourceFileDirectory": - resourceFileDirectory = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - default: - this.ParseHelper.UnexpectedAttribute(element, attrib); - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); - - if (!this.Messaging.EncounteredError) - { - section.AddSymbol(new PerfmonManifestSymbol(sourceLineNumbers) - { - ComponentRef = componentId, - File = $"[#{fileId}]", - ResourceFileDirectory = resourceFileDirectory, - }); - } - - this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigurePerfmonManifestRegister", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); - this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigurePerfmonManifestUnregister", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); - } - - /// - /// Parses a format files element. - /// - /// Element to parse. - /// Identifier of referenced file. - /// Flag to determine whether the component is 64-bit. - private void ParseFormatFileElement(Intermediate intermediate, IntermediateSection section, XElement element, string fileId, bool win64) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - string binaryId = null; - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "BinaryRef": - binaryId = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - default: - this.ParseHelper.UnexpectedAttribute(element, attrib); - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); - - if (null == binaryId) - { - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "BinaryRef")); - } - - if (!this.Messaging.EncounteredError) - { - this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedFormatFiles", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); - - section.AddSymbol(new WixFormatFilesSymbol(sourceLineNumbers) - { - BinaryRef = binaryId, - FileRef = fileId, - }); - - this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.Binary, binaryId); - } - } - - /// - /// Parses a event manifest element. - /// - /// Element to parse. - /// Identifier of parent component. - /// Identifier of referenced file. - private void ParseEventManifestElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string fileId) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - string messageFile = null; - string resourceFile = null; - string parameterFile = null; - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "MessageFile": - messageFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "ResourceFile": - resourceFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "ParameterFile": - parameterFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - default: - this.ParseHelper.UnexpectedAttribute(element, attrib); - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); - - if (!this.Messaging.EncounteredError) - { - section.AddSymbol(new EventManifestSymbol(sourceLineNumbers) - { - ComponentRef = componentId, - File = $"[#{fileId}]", - }); - - if (null != messageFile) - { - section.AddSymbol(new XmlFileSymbol(sourceLineNumbers, new Identifier(AccessModifier.Section, $"Config_{fileId}MessageFile")) - { - File = $"[#{fileId}]", - ElementPath = "/*/*/*/*[\\[]@messageFileName[\\]]", - Name = "messageFileName", - Value = messageFile, - Flags = 4 | 0x00001000, //bulk write | preserve modified date - ComponentRef = componentId, - }); - } - if (null != parameterFile) - { - section.AddSymbol(new XmlFileSymbol(sourceLineNumbers, new Identifier(AccessModifier.Section, $"Config_{fileId}ParameterFile")) - { - File = $"[#{fileId}]", - ElementPath = "/*/*/*/*[\\[]@parameterFileName[\\]]", - Name = "parameterFileName", - Value = parameterFile, - Flags = 4 | 0x00001000, //bulk write | preserve modified date - ComponentRef = componentId, - }); - } - if (null != resourceFile) - { - section.AddSymbol(new XmlFileSymbol(sourceLineNumbers, new Identifier(AccessModifier.Section, $"Config_{fileId}ResourceFile")) - { - File = $"[#{fileId}]", - ElementPath = "/*/*/*/*[\\[]@resourceFileName[\\]]", - Name = "resourceFileName", - Value = resourceFile, - Flags = 4 | 0x00001000, //bulk write | preserve modified date - ComponentRef = componentId, - }); - } - - } - - this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureEventManifestRegister", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); - this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureEventManifestUnregister", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); - - if (null != messageFile || null != parameterFile || null != resourceFile) - { - this.AddReferenceToSchedXmlFile(sourceLineNumbers, section); - } - } - - /// - /// Parses a PermissionEx element. - /// - /// Element to parse. - /// Identifier of object to be secured. - /// Identifier of component, used to determine install state. - /// Flag to determine whether the component is 64-bit. - /// Name of table that contains objectId. - private void ParsePermissionExElement(Intermediate intermediate, IntermediateSection section, XElement element, string objectId, string componentId, bool win64, string tableName) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - var bits = new BitArray(32); - string domain = null; - string[] specialPermissions = null; - string user = null; - var attributes = WixPermissionExAttributes.Inheritable; // default to inheritable. - - var permissionType = PermissionType.SecureObjects; - - switch (tableName) - { - case "CreateFolder": - specialPermissions = UtilConstants.FolderPermissions; - break; - case "File": - specialPermissions = UtilConstants.FilePermissions; - break; - case "Registry": - specialPermissions = UtilConstants.RegistryPermissions; - if (String.IsNullOrEmpty(objectId)) - { - this.Messaging.Write(UtilErrors.InvalidRegistryObject(sourceLineNumbers, element.Parent.Name.LocalName)); - } - break; - case "ServiceInstall": - specialPermissions = UtilConstants.ServicePermissions; - permissionType = PermissionType.SecureObjects; - break; - default: - this.ParseHelper.UnexpectedElement(element.Parent, element); - break; - } - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "Domain": - if (PermissionType.FileSharePermissions == permissionType) - { - this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, element.Parent.Name.LocalName)); - } - domain = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "Inheritable": - if (this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) == YesNoType.No) - { - attributes &= ~WixPermissionExAttributes.Inheritable; - } - break; - case "User": - user = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - default: - var attribValue = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib); - if (!this.TrySetBitFromName(UtilConstants.StandardPermissions, attrib.Name.LocalName, attribValue, bits, 16)) - { - if (!this.TrySetBitFromName(UtilConstants.GenericPermissions, attrib.Name.LocalName, attribValue, bits, 28)) - { - if (!this.TrySetBitFromName(specialPermissions, attrib.Name.LocalName, attribValue, bits, 0)) - { - this.ParseHelper.UnexpectedAttribute(element, attrib); - break; - } - } - } - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - var permission = this.CreateIntegerFromBitArray(bits); - - if (null == user) - { - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "User")); - } - - if (Int32.MinValue == permission) // just GENERIC_READ, which is MSI_NULL - { - this.Messaging.Write(ErrorMessages.GenericReadNotAllowed(sourceLineNumbers)); - } - - this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); - - if (!this.Messaging.EncounteredError) - { - this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedSecureObjects", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); - - var id = this.ParseHelper.CreateIdentifier("sec", objectId, tableName, domain, user); - section.AddSymbol(new SecureObjectsSymbol(sourceLineNumbers, id) - { - SecureObject = objectId, - Table = tableName, - Domain = domain, - User = user, - Attributes = attributes, - Permission = permission, - ComponentRef = componentId, - }); - } - } - - /// - /// Parses a ProductSearch element. - /// - /// Element to parse. - private void ParseProductSearchElement(Intermediate intermediate, IntermediateSection section, XElement element) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - Identifier id = null; - string variable = null; - string condition = null; - string after = null; - string productCode = null; - string upgradeCode = null; - var attributes = WixProductSearchAttributes.Version; - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "Id": - case "Variable": - case "Condition": - case "After": - this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after); - break; - case "ProductCode": - productCode = this.ParseHelper.GetAttributeGuidValue(sourceLineNumbers, attrib, false); - break; - case "UpgradeCode": - upgradeCode = this.ParseHelper.GetAttributeGuidValue(sourceLineNumbers, attrib, false); - break; - case "Result": - var result = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - switch (result) - { - case "version": - attributes = WixProductSearchAttributes.Version; - break; - case "language": - attributes = WixProductSearchAttributes.Language; - break; - case "state": - attributes = WixProductSearchAttributes.State; - break; - case "assignment": - attributes = WixProductSearchAttributes.Assignment; - break; - default: - this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, result, "version", "language", "state", "assignment")); - break; - } - break; - default: - this.ParseHelper.UnexpectedAttribute(element, attrib); - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - if (null == upgradeCode && null == productCode) - { - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "ProductCode", "UpgradeCode", true)); - } - - if (null != upgradeCode && null != productCode) - { - this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "UpgradeCode", "ProductCode")); - } - - if (null == id) - { - id = this.ParseHelper.CreateIdentifier("wps", variable, condition, after, (productCode == null ? upgradeCode : productCode), attributes.ToString()); - } - - this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); - - this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, null); - - if (!this.Messaging.EncounteredError) - { - // set an additional flag if this is an upgrade code - if (null != upgradeCode) - { - attributes |= WixProductSearchAttributes.UpgradeCode; - } - - section.AddSymbol(new WixProductSearchSymbol(sourceLineNumbers, id) - { - Guid = productCode ?? upgradeCode, - Attributes = attributes, - }); - } - } - - /// - /// Parses a RegistrySearch element. - /// - /// Element to parse. - private void ParseRegistrySearchElement(Intermediate intermediate, IntermediateSection section, XElement element) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - Identifier id = null; - string variable = null; - string condition = null; - string after = null; - RegistryRootType? root = null; - string key = null; - string value = null; - var expand = YesNoType.NotSet; - var win64 = this.Context.IsCurrentPlatform64Bit; - var attributes = WixRegistrySearchAttributes.Raw | WixRegistrySearchAttributes.WantValue; - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "Id": - case "Variable": - case "Condition": - case "After": - this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after); - break; - case "Bitness": - var bitnessValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - switch (bitnessValue) - { - case "always32": - win64 = false; - break; - case "always64": - win64 = true; - break; - case "default": - case "": - break; - default: - this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Name.LocalName, attrib.Name.LocalName, bitnessValue, "default", "always32", "always64")); - break; - } - break; - case "Root": - root = this.ParseHelper.GetAttributeRegistryRootValue(sourceLineNumbers, attrib, false); - break; - case "Key": - key = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "Value": - value = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "ExpandEnvironmentVariables": - expand = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib); - break; - case "Format": - string format = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - switch (format) - { - case "raw": - attributes |= WixRegistrySearchAttributes.Raw; - break; - case "compatible": - attributes |= WixRegistrySearchAttributes.Compatible; - break; - default: - this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, format, "raw", "compatible")); - break; - } - break; - case "Result": - var result = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - switch (result) - { - case "exists": - attributes |= WixRegistrySearchAttributes.WantExists; - break; - case "value": - attributes |= WixRegistrySearchAttributes.WantValue; - break; - default: - this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, result, "exists", "value")); - break; - } - break; - default: - this.ParseHelper.UnexpectedAttribute(element, attrib); - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - if (!root.HasValue) - { - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Root")); - } - - if (null == key) - { - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Key")); - } - - if (null == id) - { - id = this.ParseHelper.CreateIdentifier("wrs", variable, condition, after, root.ToString(), key, value, attributes.ToString()); - } - - if (expand == YesNoType.Yes) - { - if (0 != (attributes & WixRegistrySearchAttributes.WantExists)) - { - this.Messaging.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "ExpandEnvironmentVariables", expand.ToString(), "Result", "exists")); - } - - attributes |= WixRegistrySearchAttributes.ExpandEnvironmentVariables; - } - - if (win64) - { - attributes |= WixRegistrySearchAttributes.Win64; - } - - this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); - - this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, null); - - if (!this.Messaging.EncounteredError) - { - section.AddSymbol(new WixRegistrySearchSymbol(sourceLineNumbers, id) - { - Root = root.Value, - Key = key, - Value = value, - Attributes = attributes, - }); - } - } - - /// - /// Parses a RemoveFolderEx element. - /// - /// Element to parse. - /// Identifier of parent component. - private void ParseRemoveFolderExElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - Identifier id = null; - var mode = WixRemoveFolderExInstallMode.Uninstall; - string property = null; - string condition = null; - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "Condition": - condition = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "Id": - id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); - break; - case "On": - var onValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - if (onValue.Length == 0) - { - } - else - { - switch (onValue) - { - case "install": - mode = WixRemoveFolderExInstallMode.Install; - break; - case "uninstall": - mode = WixRemoveFolderExInstallMode.Uninstall; - break; - case "both": - mode = WixRemoveFolderExInstallMode.Both; - break; - default: - this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "On", onValue, "install", "uninstall", "both")); - break; - } - } - break; - case "Property": - property = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - default: - this.ParseHelper.UnexpectedAttribute(element, attrib); - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - if (String.IsNullOrEmpty(property)) - { - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Property")); - } - - if (id == null) - { - id = this.ParseHelper.CreateIdentifier("wrf", componentId, property, mode.ToString()); - } - - this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); - - if (!this.Messaging.EncounteredError) - { - this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4RemoveFoldersEx", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); - - section.AddSymbol(new WixRemoveFolderExSymbol(sourceLineNumbers, id) - { - ComponentRef = componentId, - Property = property, - InstallMode = mode, - Condition = condition - }); - - this.ParseHelper.EnsureTable(section, sourceLineNumbers, "RemoveFile"); - } - } - - /// - /// Parses a RemoveRegistryKeyEx element. - /// - /// Element to parse. - /// Identifier of parent component. - private void ParseRemoveRegistryKeyExElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - Identifier id = null; - var mode = WixRemoveRegistryKeyExInstallMode.Uninstall; - string condition = null; - RegistryRootType? root = null; - string key = null; - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "Condition": - condition = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "Id": - id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); - break; - case "On": - var actionValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - switch (actionValue) - { - case "": - break; - case "install": - mode = WixRemoveRegistryKeyExInstallMode.Install; - break; - case "uninstall": - mode = WixRemoveRegistryKeyExInstallMode.Uninstall; - break; - default: - this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "On", actionValue, "install", "uninstall")); - break; - } - break; - case "Root": - root = this.ParseHelper.GetAttributeRegistryRootValue(sourceLineNumbers, attrib, false); - break; - case "Key": - key = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - default: - this.ParseHelper.UnexpectedAttribute(element, attrib); - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - if (!root.HasValue) - { - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Root")); - } - - if (key == null) - { - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Key")); - } - - if (id == null) - { - id = this.ParseHelper.CreateIdentifier("rrx", componentId, condition, root.ToString(), key, mode.ToString()); - } - - this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); - - if (!this.Messaging.EncounteredError) - { - this.ParseHelper.EnsureTable(section, sourceLineNumbers, "Registry"); - this.ParseHelper.EnsureTable(section, sourceLineNumbers, "RemoveRegistry"); - this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4RemoveRegistryKeysEx", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); - - section.AddSymbol(new WixRemoveRegistryKeyExSymbol(sourceLineNumbers, id) - { - ComponentRef = componentId, - Root = root.Value, - Key = key, - InstallMode = mode, - Condition = condition - }); - } - } - - /// - /// Parses a RestartResource element. - /// - /// The element to parse. - /// The identity of the parent component. - private void ParseRestartResourceElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - Identifier id = null; - string resource = null; - WixRestartResourceAttributes? attributes = null; - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "Id": - id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); - break; - - case "Path": - resource = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - attributes = WixRestartResourceAttributes.Filename; - break; - - case "ProcessName": - resource = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - attributes = WixRestartResourceAttributes.ProcessName; - break; - - case "ServiceName": - resource = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - attributes = WixRestartResourceAttributes.ServiceName; - break; - - default: - this.ParseHelper.UnexpectedAttribute(element, attrib); - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - // Validate the attribute. - if (id == null) - { - id = this.ParseHelper.CreateIdentifier("wrr", componentId, resource, attributes.ToString()); - } - - if (!attributes.HasValue) - { - this.Messaging.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, element.Name.LocalName, "Path", "ProcessName", "ServiceName")); - } - - this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); - - if (!this.Messaging.EncounteredError) - { - this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4RegisterRestartResources", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); - - section.AddSymbol(new WixRestartResourceSymbol(sourceLineNumbers, id) - { - ComponentRef = componentId, - Resource = resource, - Attributes = attributes, - }); - } - } - - /// - /// Parses a service configuration element. - /// - /// Element to parse. - /// Identifier of parent component. - /// Name of parent element. - /// Optional name of service - private void ParseServiceConfigElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string parentTableName, string parentTableServiceName) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - string firstFailureActionType = null; - var newService = false; - string programCommandLine = null; - string rebootMessage = null; - var resetPeriod = CompilerConstants.IntegerNotSet; - var restartServiceDelay = CompilerConstants.IntegerNotSet; - string secondFailureActionType = null; - string serviceName = null; - string thirdFailureActionType = null; - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "FirstFailureActionType": - firstFailureActionType = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "ProgramCommandLine": - programCommandLine = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "RebootMessage": - rebootMessage = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "ResetPeriodInDays": - resetPeriod = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); - break; - case "RestartServiceDelayInSeconds": - restartServiceDelay = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); - break; - case "SecondFailureActionType": - secondFailureActionType = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "ServiceName": - serviceName = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "ThirdFailureActionType": - thirdFailureActionType = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - default: - this.ParseHelper.UnexpectedAttribute(element, attrib); - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - // if this element is a child of ServiceInstall then ignore the service name provided. - if ("ServiceInstall" == parentTableName) - { - // TODO: the ServiceName attribute should not be allowed in this case (the overwriting behavior may confuse users) - serviceName = parentTableServiceName; - newService = true; - } - else - { - // not a child of ServiceInstall, so ServiceName must have been provided - if (null == serviceName) - { - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "ServiceName")); - } - } - - this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); - - if (!this.Messaging.EncounteredError) - { - this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedServiceConfig", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); - - section.AddSymbol(new ServiceConfigSymbol(sourceLineNumbers) - { - ServiceName = serviceName, - ComponentRef = componentId, - NewService = newService ? 1 : 0, - FirstFailureActionType = firstFailureActionType, - SecondFailureActionType = secondFailureActionType, - ThirdFailureActionType = thirdFailureActionType, - ResetPeriodInDays = resetPeriod, - RestartServiceDelayInSeconds = restartServiceDelay, - ProgramCommandLine = programCommandLine, - RebootMessage = rebootMessage, - }); - } - } - - /// - /// Parses a touch file element. - /// - /// Element to parse. - /// Identifier of parent component. - /// Indicates whether the path is a 64-bit path. - private void ParseTouchFileElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, bool win64) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - Identifier id = null; - string path = null; - var onInstall = YesNoType.NotSet; - var onReinstall = YesNoType.NotSet; - var onUninstall = YesNoType.NotSet; - var nonvital = YesNoType.NotSet; - int attributes = 0; - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "Id": - id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); - break; - case "Path": - path = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "OnInstall": - onInstall = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib); - break; - case "OnReinstall": - onReinstall = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib); - break; - case "OnUninstall": - onUninstall = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib); - break; - case "Nonvital": - nonvital = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib); - break; - default: - this.ParseHelper.UnexpectedAttribute(element, attrib); - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - if (null == path) - { - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Path")); - } - - // If none of the scheduling actions are set, default to touching on install and reinstall. - if (YesNoType.NotSet == onInstall && YesNoType.NotSet == onReinstall && YesNoType.NotSet == onUninstall) - { - onInstall = YesNoType.Yes; - onReinstall = YesNoType.Yes; - } - - attributes |= YesNoType.Yes == onInstall ? 0x1 : 0; - attributes |= YesNoType.Yes == onReinstall ? 0x2 : 0; - attributes |= YesNoType.Yes == onUninstall ? 0x4 : 0; - attributes |= win64 ? 0x10 : 0; - attributes |= YesNoType.Yes == nonvital ? 0 : 0x20; - - if (null == id) - { - id = this.ParseHelper.CreateIdentifier("tf", path, attributes.ToString()); - } - - this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); - - if (!this.Messaging.EncounteredError) - { - section.AddSymbol(new WixTouchFileSymbol(sourceLineNumbers, id) - { - ComponentRef = componentId, - Path = path, - Attributes = attributes, - }); - - this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4TouchFileDuringInstall", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); - } - } - - /// - /// Parses an user element. - /// - /// Element to parse. - /// Optional identifier of parent component. - private void ParseUserElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - Identifier id = null; - int attributes = 0; - string domain = null; - string name = null; - string password = null; - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "Id": - id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); - break; - case "CanNotChangePassword": - if (null == componentId) - { - this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); - } - - if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - { - attributes |= UserPasswdCantChange; - } - break; - case "CreateUser": - if (null == componentId) - { - this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); - } - - if (YesNoType.No == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - { - attributes |= UserDontCreateUser; - } - break; - case "Disabled": - if (null == componentId) - { - this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); - } - - if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - { - attributes |= UserDisableAccount; - } - break; - case "Domain": - domain = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "FailIfExists": - if (null == componentId) - { - this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); - } - - if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - { - attributes |= UserFailIfExists; - } - break; - case "LogonAsService": - if (null == componentId) - { - this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); - } - if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - { - attributes |= UserLogonAsService; - } - break; - case "LogonAsBatchJob": - if (null == componentId) - { - this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); - } - if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - { - attributes |= UserLogonAsBatchJob; - } - break; - case "Name": - name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "Password": - password = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "PasswordExpired": - if (null == componentId) - { - this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); - } - - if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - { - attributes |= UserPasswdChangeReqdOnLogin; - } - break; - case "PasswordNeverExpires": - if (null == componentId) - { - this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); - } - - if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - { - attributes |= UserDontExpirePasswrd; - } - break; - case "RemoveOnUninstall": - if (null == componentId) - { - this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); - } - - if (YesNoType.No == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - { - attributes |= UserDontRemoveOnUninstall; - } - break; - case "UpdateIfExists": - if (null == componentId) - { - this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); - } - - if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - { - attributes |= UserUpdateIfExists; - } - break; - case "Vital": - if (null == componentId) - { - this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); - } - - if (YesNoType.No == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - { - attributes |= UserNonVital; - } - break; - default: - this.ParseHelper.UnexpectedAttribute(element, attrib); - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - if (null == id) - { - id = this.ParseHelper.CreateIdentifier("usr", componentId, name); - } - - if (null == name) - { - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name")); - } - - foreach (var child in element.Elements()) - { - if (this.Namespace == child.Name.Namespace) - { - switch (child.Name.LocalName) - { - case "GroupRef": - if (null == componentId) - { - var childSourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(child); - this.Messaging.Write(UtilErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName)); - } - - this.ParseGroupRefElement(intermediate, section, child, id.Id); - break; - default: - this.ParseHelper.UnexpectedElement(element, child); - break; - } - } - else - { - this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child); - } - } - - if (null != componentId) - { - this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureUsers", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); - } - - if (!this.Messaging.EncounteredError) - { - section.AddSymbol(new UserSymbol(sourceLineNumbers, id) - { - ComponentRef = componentId, - Name = name, - Domain = domain, - Password = password, - Attributes = attributes, - }); - } - } - - /// - /// Parses a XmlFile element. - /// - /// Element to parse. - /// Identifier of parent component. - private void ParseXmlFileElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - Identifier id = null; - string file = null; - string elementPath = null; - string name = null; - string value = null; - int sequence = -1; - int flags = 0; - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "Action": - var actionValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - switch (actionValue) - { - case "createElement": - flags |= 0x00000001; // XMLFILE_CREATE_ELEMENT - break; - case "deleteValue": - flags |= 0x00000002; // XMLFILE_DELETE_VALUE - break; - case "bulkSetValue": - flags |= 0x00000004; // XMLFILE_BULKWRITE_VALUE - break; - case "setValue": - // no flag for set value since it's the default - break; - default: - this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Action", actionValue, "createElement", "deleteValue", "setValue", "bulkSetValue")); - break; - } - break; - case "SelectionLanguage": - string selectionLanguage = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - switch (selectionLanguage) - { - case "XPath": - flags |= 0x00000100; // XMLFILE_USE_XPATH - break; - case "XSLPattern": - // no flag for since it's the default - break; - default: - this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "SelectionLanguage", selectionLanguage, "XPath", "XSLPattern")); - break; - } - break; - case "Id": - id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); - break; - case "File": - file = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "ElementPath": - elementPath = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "Name": - name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "Permanent": - if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - { - flags |= 0x00010000; // XMLFILE_DONT_UNINSTALL - } - break; - case "Sequence": - sequence = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, Int16.MaxValue); - break; - case "Value": - value = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "PreserveModifiedDate": - if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - { - flags |= 0x00001000; // XMLFILE_PRESERVE_MODIFIED - } - break; - default: - this.ParseHelper.UnexpectedAttribute(element, attrib); - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - if (null == id) - { - id = this.ParseHelper.CreateIdentifier("uxf", componentId, file, elementPath, name); - } - - if (null == file) - { - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "File")); - } - - if (null == elementPath) - { - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "ElementPath")); - } - - if ((0x00000001 /*XMLFILE_CREATE_ELEMENT*/ & flags) != 0 && null == name) - { - this.Messaging.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, element.Name.LocalName, "Action", "Name")); - } - - this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); - - if (!this.Messaging.EncounteredError) - { - var symbol = section.AddSymbol(new XmlFileSymbol(sourceLineNumbers, id) - { - File = file, - ElementPath = elementPath, - Name = name, - Value = value, - Flags = flags, - ComponentRef = componentId, - }); - if (-1 != sequence) - { - symbol.Sequence = sequence; - } - } - - this.AddReferenceToSchedXmlFile(sourceLineNumbers, section); - } - - /// - /// Parses a XmlConfig element. - /// - /// Element to parse. - /// Identifier of parent component. - /// Whether or not the element is nested. - private void ParseXmlConfigElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, bool nested) - { - var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); - Identifier id = null; - string elementId = null; - string elementPath = null; - int flags = 0; - string file = null; - string name = null; - var sequence = CompilerConstants.IntegerNotSet; - string value = null; - string verifyPath = null; - - foreach (var attrib in element.Attributes()) - { - if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) - { - switch (attrib.Name.LocalName) - { - case "Id": - id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); - break; - case "Action": - if (nested) - { - this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, element.Parent.Name.LocalName)); - } - else - { - string actionValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - switch (actionValue) - { - case "create": - flags |= 0x10; // XMLCONFIG_CREATE - break; - case "delete": - flags |= 0x20; // XMLCONFIG_DELETE - break; - default: - this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, actionValue, "create", "delete")); - break; - } - } - break; - case "ElementId": - elementId = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "ElementPath": - elementPath = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "File": - file = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "Name": - name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "Node": - if (nested) - { - this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, element.Parent.Name.LocalName)); - } - else - { - var nodeValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - switch (nodeValue) - { - case "element": - flags |= 0x1; // XMLCONFIG_ELEMENT - break; - case "value": - flags |= 0x2; // XMLCONFIG_VALUE - break; - case "document": - flags |= 0x4; // XMLCONFIG_DOCUMENT - break; - default: - this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, nodeValue, "element", "value", "document")); - break; - } - } - break; - case "On": - if (nested) - { - this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, element.Parent.Name.LocalName)); - } - else - { - var onValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - switch (onValue) - { - case "install": - flags |= 0x100; // XMLCONFIG_INSTALL - break; - case "uninstall": - flags |= 0x200; // XMLCONFIG_UNINSTALL - break; - default: - this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, onValue, "install", "uninstall")); - break; - } - } - break; - case "PreserveModifiedDate": - if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) - { - flags |= 0x00001000; // XMLCONFIG_PRESERVE_MODIFIED - } - break; - case "Sequence": - sequence = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, Int16.MaxValue); - break; - case "Value": - value = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - case "VerifyPath": - verifyPath = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - break; - default: - this.ParseHelper.UnexpectedAttribute(element, attrib); - break; - } - } - else - { - this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); - } - } - - if (null == id) - { - id = this.ParseHelper.CreateIdentifier("uxc", componentId, file, elementId, elementPath); - } - - if (null == file) - { - this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "File")); - } - - if (null == elementId && null == elementPath) - { - this.Messaging.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, element.Name.LocalName, "ElementId", "ElementPath")); - } - else if (null != elementId) - { - if (null != elementPath) - { - this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "ElementId", "ElementPath")); - } - - if (0 != flags) - { - this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, "ElementId", "Action", "Node", "On")); - } - - this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, UtilSymbolDefinitions.XmlConfig, elementId); - } - - // find unexpected child elements - foreach (var child in element.Elements()) - { - if (this.Namespace == child.Name.Namespace) - { - switch (child.Name.LocalName) - { - case "XmlConfig": - if (nested) - { - this.Messaging.Write(ErrorMessages.UnexpectedElement(sourceLineNumbers, element.Name.LocalName, child.Name.LocalName)); - } - else - { - this.ParseXmlConfigElement(intermediate, section, child, componentId, true); - } - break; - default: - this.ParseHelper.UnexpectedElement(element, child); - break; - } - } - else - { - this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child); - } - } - - if (!this.Messaging.EncounteredError) - { - var symbol = section.AddSymbol(new XmlConfigSymbol(sourceLineNumbers, id) - { - File = file, - ElementId = elementId, - ElementPath = elementPath, - VerifyPath = verifyPath, - Name = name, - Value = value, - Flags = flags, - ComponentRef = componentId, - }); - - if (CompilerConstants.IntegerNotSet != sequence) - { - symbol.Sequence = sequence; - } - } - - this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedXmlConfig", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); - } - - /// - /// Match evaluator to escape properties in a string. - /// - private string EscapeProperties(Match match) - { - string escape = null; - switch (match.Value) - { - case "[": - escape = @"[\[]"; - break; - case "]": - escape = @"[\]]"; - break; - } - - return escape; - } - - private int CreateIntegerFromBitArray(BitArray bits) - { - if (32 != bits.Length) - { - 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"); - } - - var intArray = new int[1]; - bits.CopyTo(intArray, 0); - - return intArray[0]; - } - - private bool TrySetBitFromName(string[] attributeNames, string attributeName, YesNoType attributeValue, BitArray bits, int offset) - { - for (var i = 0; i < attributeNames.Length; i++) - { - if (attributeName.Equals(attributeNames[i], StringComparison.Ordinal)) - { - bits.Set(i + offset, YesNoType.Yes == attributeValue); - return true; - } - } - - return false; - } - - private void AddReferenceToSchedXmlFile(SourceLineNumber sourceLineNumbers, IntermediateSection section) - { - this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedXmlFile", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); - } - - /// - /// Private class that stores the data from a parsed PerformanceCounter element. - /// - private class ParsedPerformanceCounter - { - internal ParsedPerformanceCounter(string name, string help, System.Diagnostics.PerformanceCounterType type, int language) - { - this.Name = name; - this.Help = help; - this.Type = (int)type; - this.Language = language.ToString("D3", CultureInfo.InvariantCulture); - } - - internal string Name { get; } - - internal string Help { get; } - - internal int Type { get; } - - internal string Language { get; } - } - } -} diff --git a/src/wixext/UtilConstants.cs b/src/wixext/UtilConstants.cs deleted file mode 100644 index 28ff368f..00000000 --- a/src/wixext/UtilConstants.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - /// - /// Constants used by Utility Extension. - /// - internal static class UtilConstants - { - internal static readonly string[] FilePermissions = { "Read", "Write", "Append", "ReadExtendedAttributes", "WriteExtendedAttributes", "Execute", null, "ReadAttributes", "WriteAttributes" }; - internal static readonly string[] FolderPermissions = { "Read", "CreateFile", "CreateChild", "ReadExtendedAttributes", "WriteExtendedAttributes", "Traverse", "DeleteChild", "ReadAttributes", "WriteAttributes" }; - internal static readonly string[] GenericPermissions = { "GenericAll", "GenericExecute", "GenericWrite", "GenericRead" }; - internal static readonly string[] RegistryPermissions = { "Read", "Write", "CreateSubkeys", "EnumerateSubkeys", "Notify", "CreateLink" }; - internal static readonly string[] ServicePermissions = { "ServiceQueryConfig", "ServiceChangeConfig", "ServiceQueryStatus", "ServiceEnumerateDependents", "ServiceStart", "ServiceStop", "ServicePauseContinue", "ServiceInterrogate", "ServiceUserDefinedControl" }; - internal static readonly string[] StandardPermissions = { "Delete", "ReadPermission", "ChangePermission", "TakeOwnership", "Synchronize" }; - } -} diff --git a/src/wixext/UtilDecompiler.cs b/src/wixext/UtilDecompiler.cs deleted file mode 100644 index 9ef3390f..00000000 --- a/src/wixext/UtilDecompiler.cs +++ /dev/null @@ -1,1543 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Extensions -{ -#if TODO_CONSIDER_DECOMPILER - using System; - using System.IO; - using System.Text; - using System.Collections; - using System.Diagnostics; - using System.Globalization; - - using Util = WixToolset.Extensions.Serialize.Util; - using WixToolset.Data; - using WixToolset.Extensibility; - using Wix = WixToolset.Data.Serialize; - - /// - /// The decompiler for the WiX Toolset Utility Extension. - /// - public sealed class UtilDecompiler : DecompilerExtension - { - /// - /// Creates a decompiler for Utility Extension. - /// - public UtilDecompiler() - { - this.TableDefinitions = UtilExtensionData.GetExtensionTableDefinitions(); - } - - /// - /// Get the extensions library to be removed. - /// - /// Table definitions for library. - /// Library to remove from decompiled output. - public override Library GetLibraryToRemove(TableDefinitionCollection tableDefinitions) - { - return UtilExtensionData.GetExtensionLibrary(tableDefinitions); - } - - /// - /// Called at the beginning of the decompilation of a database. - /// - /// The collection of all tables. - public override void Initialize(TableIndexedCollection tables) - { - this.CleanupSecureCustomProperties(tables); - this.CleanupInternetShortcutRemoveFileTables(tables); - } - - /// - /// Decompile the SecureCustomProperties field to PropertyRefs for known extension properties. - /// - /// - /// If we've referenced any of the suite or directory properties, add - /// a PropertyRef to refer to the Property (and associated custom action) - /// from the extension's library. Then remove the property from - /// SecureCustomExtensions property so later decompilation won't create - /// new Property elements. - /// - /// The collection of all tables. - private void CleanupSecureCustomProperties(TableIndexedCollection tables) - { - Table propertyTable = tables["Property"]; - - if (null != propertyTable) - { - foreach (Row row in propertyTable.Rows) - { - if ("SecureCustomProperties" == row[0].ToString()) - { - StringBuilder remainingProperties = new StringBuilder(); - string[] secureCustomProperties = row[1].ToString().Split(';'); - foreach (string property in secureCustomProperties) - { - if (property.StartsWith("WIX_SUITE_", StringComparison.Ordinal) || property.StartsWith("WIX_DIR_", StringComparison.Ordinal) - || property.StartsWith("WIX_ACCOUNT_", StringComparison.Ordinal)) - { - Wix.PropertyRef propertyRef = new Wix.PropertyRef(); - propertyRef.Id = property; - this.Core.RootElement.AddChild(propertyRef); - } - else - { - if (0 < remainingProperties.Length) - { - remainingProperties.Append(";"); - } - remainingProperties.Append(property); - } - } - - row[1] = remainingProperties.ToString(); - break; - } - } - } - } - - /// - /// Remove RemoveFile rows that the InternetShortcut compiler extension adds for us. - /// - /// The collection of all tables. - private void CleanupInternetShortcutRemoveFileTables(TableIndexedCollection tables) - { - // index the WixInternetShortcut table - Table wixInternetShortcutTable = tables["WixInternetShortcut"]; - Hashtable wixInternetShortcuts = new Hashtable(); - if (null != wixInternetShortcutTable) - { - foreach (Row row in wixInternetShortcutTable.Rows) - { - wixInternetShortcuts.Add(row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), row); - } - } - - // remove the RemoveFile rows with primary keys that match the WixInternetShortcut table's - Table removeFileTable = tables["RemoveFile"]; - if (null != removeFileTable) - { - for (int i = removeFileTable.Rows.Count - 1; 0 <= i; i--) - { - if (null != wixInternetShortcuts[removeFileTable.Rows[i][0]]) - { - removeFileTable.Rows.RemoveAt(i); - } - } - } - } - - /// - /// Decompiles an extension table. - /// - /// The table to decompile. - public override void DecompileTable(Table table) - { - switch (table.Name) - { - case "WixCloseApplication": - this.DecompileWixCloseApplicationTable(table); - break; - case "WixRemoveFolderEx": - this.DecompileWixRemoveFolderExTable(table); - break; - case "WixRestartResource": - this.DecompileWixRestartResourceTable(table); - break; - case "FileShare": - this.DecompileFileShareTable(table); - break; - case "FileSharePermissions": - this.DecompileFileSharePermissionsTable(table); - break; - case "WixInternetShortcut": - this.DecompileWixInternetShortcutTable(table); - break; - case "Group": - this.DecompileGroupTable(table); - break; - case "Perfmon": - this.DecompilePerfmonTable(table); - break; - case "PerfmonManifest": - this.DecompilePerfmonManifestTable(table); - break; - case "EventManifest": - this.DecompileEventManifestTable(table); - break; - case "SecureObjects": - this.DecompileSecureObjectsTable(table); - break; - case "ServiceConfig": - this.DecompileServiceConfigTable(table); - break; - case "User": - this.DecompileUserTable(table); - break; - case "UserGroup": - this.DecompileUserGroupTable(table); - break; - case "XmlConfig": - this.DecompileXmlConfigTable(table); - break; - case "XmlFile": - // XmlFile decompilation has been moved to FinalizeXmlFileTable function - break; - default: - base.DecompileTable(table); - break; - } - } - - /// - /// Finalize decompilation. - /// - /// The collection of all tables. - public override void Finish(TableIndexedCollection tables) - { - this.FinalizePerfmonTable(tables); - this.FinalizePerfmonManifestTable(tables); - this.FinalizeSecureObjectsTable(tables); - this.FinalizeServiceConfigTable(tables); - this.FinalizeXmlConfigTable(tables); - this.FinalizeXmlFileTable(tables); - this.FinalizeEventManifestTable(tables); - } - - /// - /// Decompile the WixCloseApplication table. - /// - /// The table to decompile. - private void DecompileWixCloseApplicationTable(Table table) - { - foreach (Row row in table.Rows) - { - Util.CloseApplication closeApplication = new Util.CloseApplication(); - - closeApplication.Id = (string)row[0]; - - closeApplication.Target = (string)row[1]; - - if (null != row[2]) - { - closeApplication.Description = (string)row[2]; - } - - if (null != row[3]) - { - closeApplication.Content = (string)row[3]; - } - - // set defaults - closeApplication.CloseMessage = Util.YesNoType.no; - closeApplication.RebootPrompt = Util.YesNoType.yes; - closeApplication.ElevatedCloseMessage = Util.YesNoType.no; - - if (null != row[4]) - { - int attribute = (int)row[4]; - - closeApplication.CloseMessage = (0x1 == (attribute & 0x1)) ? Util.YesNoType.yes : Util.YesNoType.no; - closeApplication.RebootPrompt = (0x2 == (attribute & 0x2)) ? Util.YesNoType.yes : Util.YesNoType.no; - closeApplication.ElevatedCloseMessage = (0x4 == (attribute & 0x4)) ? Util.YesNoType.yes : Util.YesNoType.no; - } - - if (null != row[5]) - { - closeApplication.Sequence = (int)row[5]; - } - - if (null != row[6]) - { - closeApplication.Property = (string)row[6]; - } - - this.Core.RootElement.AddChild(closeApplication); - } - } - - /// - /// Decompile the WixRemoveFolderEx table. - /// - /// The table to decompile. - private void DecompileWixRemoveFolderExTable(Table table) - { - foreach (Row row in table.Rows) - { - // Set the Id even if auto-generated previously. - Util.RemoveFolderEx removeFolder = new Util.RemoveFolderEx(); - removeFolder.Id = (string)row[0]; - removeFolder.Property = (string)row[2]; - - int installMode = (int)row[3]; - switch ((UtilCompiler.WixRemoveFolderExOn)installMode) - { - case UtilCompiler.WixRemoveFolderExOn.Install: - removeFolder.On = Util.RemoveFolderEx.OnType.install; - break; - - case UtilCompiler.WixRemoveFolderExOn.Uninstall: - removeFolder.On = Util.RemoveFolderEx.OnType.uninstall; - break; - - case UtilCompiler.WixRemoveFolderExOn.Both: - removeFolder.On = Util.RemoveFolderEx.OnType.both; - break; - - default: - this.Core.OnMessage(WixWarnings.UnrepresentableColumnValue(row.SourceLineNumbers, table.Name, "InstallMode", installMode)); - break; - } - - // Add to the appropriate Component or section element. - string componentId = (string)row[1]; - Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", componentId); - if (null != component) - { - component.AddChild(removeFolder); - } - else - { - this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", componentId, "Component")); - } - } - } - - /// - /// Decompile the WixRestartResource table. - /// - /// The table to decompile. - private void DecompileWixRestartResourceTable(Table table) - { - foreach (Row row in table.Rows) - { - // Set the Id even if auto-generated previously. - Util.RestartResource restartResource = new Util.RestartResource(); - restartResource.Id = (string)row[0]; - - // Determine the resource type and set accordingly. - string resource = (string)row[2]; - int attributes = (int)row[3]; - UtilCompiler.WixRestartResourceAttributes type = (UtilCompiler.WixRestartResourceAttributes)(attributes & (int)UtilCompiler.WixRestartResourceAttributes.TypeMask); - - switch (type) - { - case UtilCompiler.WixRestartResourceAttributes.Filename: - restartResource.Path = resource; - break; - - case UtilCompiler.WixRestartResourceAttributes.ProcessName: - restartResource.ProcessName = resource; - break; - - case UtilCompiler.WixRestartResourceAttributes.ServiceName: - restartResource.ServiceName = resource; - break; - - default: - this.Core.OnMessage(WixWarnings.UnrepresentableColumnValue(row.SourceLineNumbers, table.Name, "Attributes", attributes)); - break; - } - - // Add to the appropriate Component or section element. - string componentId = (string)row[1]; - if (!String.IsNullOrEmpty(componentId)) - { - Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", componentId); - if (null != component) - { - component.AddChild(restartResource); - } - else - { - this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", componentId, "Component")); - } - } - else - { - this.Core.RootElement.AddChild(restartResource); - } - } - } - - /// - /// Decompile the FileShare table. - /// - /// The table to decompile. - private void DecompileFileShareTable(Table table) - { - foreach (Row row in table.Rows) - { - Util.FileShare fileShare = new Util.FileShare(); - - fileShare.Id = (string)row[0]; - - fileShare.Name = (string)row[1]; - - if (null != row[3]) - { - fileShare.Description = (string)row[3]; - } - - // the Directory_ column is set by the parent Component - - // the User_ and Permissions columns are deprecated - - Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[2]); - if (null != component) - { - component.AddChild(fileShare); - } - else - { - this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[2], "Component")); - } - this.Core.IndexElement(row, fileShare); - } - } - - /// - /// Decompile the FileSharePermissions table. - /// - /// The table to decompile. - private void DecompileFileSharePermissionsTable(Table table) - { - foreach (Row row in table.Rows) - { - Util.FileSharePermission fileSharePermission = new Util.FileSharePermission(); - - fileSharePermission.User = (string)row[1]; - - string[] specialPermissions = UtilConstants.FolderPermissions; - int permissions = (int)row[2]; - for (int i = 0; i < 32; i++) - { - if (0 != ((permissions >> i) & 1)) - { - string name = null; - - if (16 > i && specialPermissions.Length > i) - { - name = specialPermissions[i]; - } - else if (28 > i && UtilConstants.StandardPermissions.Length > (i - 16)) - { - name = UtilConstants.StandardPermissions[i - 16]; - } - else if (0 <= (i - 28) && UtilConstants.GenericPermissions.Length > (i - 28)) - { - name = UtilConstants.GenericPermissions[i - 28]; - } - - if (null == name) - { - this.Core.OnMessage(WixWarnings.UnknownPermission(row.SourceLineNumbers, row.Table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), i)); - } - else - { - switch (name) - { - case "ChangePermission": - fileSharePermission.ChangePermission = Util.YesNoType.yes; - break; - case "CreateChild": - fileSharePermission.CreateChild = Util.YesNoType.yes; - break; - case "CreateFile": - fileSharePermission.CreateFile = Util.YesNoType.yes; - break; - case "Delete": - fileSharePermission.Delete = Util.YesNoType.yes; - break; - case "DeleteChild": - fileSharePermission.DeleteChild = Util.YesNoType.yes; - break; - case "GenericAll": - fileSharePermission.GenericAll = Util.YesNoType.yes; - break; - case "GenericExecute": - fileSharePermission.GenericExecute = Util.YesNoType.yes; - break; - case "GenericRead": - fileSharePermission.GenericRead = Util.YesNoType.yes; - break; - case "GenericWrite": - fileSharePermission.GenericWrite = Util.YesNoType.yes; - break; - case "Read": - fileSharePermission.Read = Util.YesNoType.yes; - break; - case "ReadAttributes": - fileSharePermission.ReadAttributes = Util.YesNoType.yes; - break; - case "ReadExtendedAttributes": - fileSharePermission.ReadExtendedAttributes = Util.YesNoType.yes; - break; - case "ReadPermission": - fileSharePermission.ReadPermission = Util.YesNoType.yes; - break; - case "Synchronize": - fileSharePermission.Synchronize = Util.YesNoType.yes; - break; - case "TakeOwnership": - fileSharePermission.TakeOwnership = Util.YesNoType.yes; - break; - case "Traverse": - fileSharePermission.Traverse = Util.YesNoType.yes; - break; - case "WriteAttributes": - fileSharePermission.WriteAttributes = Util.YesNoType.yes; - break; - case "WriteExtendedAttributes": - fileSharePermission.WriteExtendedAttributes = Util.YesNoType.yes; - break; - default: - Debug.Fail(String.Format("Unknown permission '{0}'.", name)); - break; - } - } - } - } - - Util.FileShare fileShare = (Util.FileShare)this.Core.GetIndexedElement("FileShare", (string)row[0]); - if (null != fileShare) - { - fileShare.AddChild(fileSharePermission); - } - else - { - this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "FileShare_", (string)row[0], "FileShare")); - } - } - } - - /// - /// Decompile the Group table. - /// - /// The table to decompile. - private void DecompileGroupTable(Table table) - { - foreach (Row row in table.Rows) - { - Util.Group group = new Util.Group(); - - group.Id = (string)row[0]; - - if (null != row[1]) - { - this.Core.OnMessage(WixWarnings.UnrepresentableColumnValue(row.SourceLineNumbers, table.Name, "Component_", (string)row[1])); - } - - group.Name = (string)row[2]; - - if (null != row[3]) - { - group.Domain = (string)row[3]; - } - - this.Core.RootElement.AddChild(group); - } - } - - /// - /// Decompile the WixInternetShortcut table. - /// - /// The table to decompile. - private void DecompileWixInternetShortcutTable(Table table) - { - foreach (Row row in table.Rows) - { - Util.InternetShortcut internetShortcut = new Util.InternetShortcut(); - internetShortcut.Id = (string)row[0]; - internetShortcut.Directory = (string)row[2]; - // remove .lnk/.url extension because compiler extension adds it back for us - internetShortcut.Name = Path.ChangeExtension((string)row[3], null); - internetShortcut.Target = (string)row[4]; - internetShortcut.IconFile = (string)row[6]; - internetShortcut.IconIndex = (int)row[7]; - - UtilCompiler.InternetShortcutType shortcutType = (UtilCompiler.InternetShortcutType)row[5]; - switch (shortcutType) - { - case UtilCompiler.InternetShortcutType.Link: - internetShortcut.Type = Util.InternetShortcut.TypeType.link; - break; - case UtilCompiler.InternetShortcutType.Url: - internetShortcut.Type = Util.InternetShortcut.TypeType.url; - break; - } - - Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[1]); - if (null != component) - { - component.AddChild(internetShortcut); - } - else - { - this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[1], "Component")); - } - - this.Core.IndexElement(row, internetShortcut); - } - } - - /// - /// Decompile the Perfmon table. - /// - /// The table to decompile. - private void DecompilePerfmonTable(Table table) - { - foreach (Row row in table.Rows) - { - Util.PerfCounter perfCounter = new Util.PerfCounter(); - - perfCounter.Name = (string)row[2]; - - this.Core.IndexElement(row, perfCounter); - } - } - - /// - /// Decompile the PerfmonManifest table. - /// - /// The table to decompile. - private void DecompilePerfmonManifestTable(Table table) - { - foreach (Row row in table.Rows) - { - Util.PerfCounterManifest perfCounterManifest = new Util.PerfCounterManifest(); - - perfCounterManifest.ResourceFileDirectory = (string)row[2]; - - this.Core.IndexElement(row, perfCounterManifest); - } - } - - /// - /// Decompile the EventManifest table. - /// - /// The table to decompile. - private void DecompileEventManifestTable(Table table) - { - foreach (Row row in table.Rows) - { - Util.EventManifest eventManifest = new Util.EventManifest(); - this.Core.IndexElement(row, eventManifest); - } - } - - /// - /// Decompile the SecureObjects table. - /// - /// The table to decompile. - private void DecompileSecureObjectsTable(Table table) - { - foreach (Row row in table.Rows) - { - Util.PermissionEx permissionEx = new Util.PermissionEx(); - - string[] specialPermissions; - switch ((string)row[1]) - { - case "CreateFolder": - specialPermissions = UtilConstants.FolderPermissions; - break; - case "File": - specialPermissions = UtilConstants.FilePermissions; - break; - case "Registry": - specialPermissions = UtilConstants.RegistryPermissions; - break; - case "ServiceInstall": - specialPermissions = UtilConstants.ServicePermissions; - break; - default: - this.Core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, row.Table.Name, row.Fields[1].Column.Name, row[1])); - return; - } - - int permissionBits = (int)row[4]; - for (int i = 0; i < 32; i++) - { - if (0 != ((permissionBits >> i) & 1)) - { - string name = null; - - if (16 > i && specialPermissions.Length > i) - { - name = specialPermissions[i]; - } - else if (28 > i && UtilConstants.StandardPermissions.Length > (i - 16)) - { - name = UtilConstants.StandardPermissions[i - 16]; - } - else if (0 <= (i - 28) && UtilConstants.GenericPermissions.Length > (i - 28)) - { - name = UtilConstants.GenericPermissions[i - 28]; - } - - if (null == name) - { - this.Core.OnMessage(WixWarnings.UnknownPermission(row.SourceLineNumbers, row.Table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), i)); - } - else - { - switch (name) - { - case "Append": - permissionEx.Append = Util.YesNoType.yes; - break; - case "ChangePermission": - permissionEx.ChangePermission = Util.YesNoType.yes; - break; - case "CreateChild": - permissionEx.CreateChild = Util.YesNoType.yes; - break; - case "CreateFile": - permissionEx.CreateFile = Util.YesNoType.yes; - break; - case "CreateLink": - permissionEx.CreateLink = Util.YesNoType.yes; - break; - case "CreateSubkeys": - permissionEx.CreateSubkeys = Util.YesNoType.yes; - break; - case "Delete": - permissionEx.Delete = Util.YesNoType.yes; - break; - case "DeleteChild": - permissionEx.DeleteChild = Util.YesNoType.yes; - break; - case "EnumerateSubkeys": - permissionEx.EnumerateSubkeys = Util.YesNoType.yes; - break; - case "Execute": - permissionEx.Execute = Util.YesNoType.yes; - break; - case "GenericAll": - permissionEx.GenericAll = Util.YesNoType.yes; - break; - case "GenericExecute": - permissionEx.GenericExecute = Util.YesNoType.yes; - break; - case "GenericRead": - permissionEx.GenericRead = Util.YesNoType.yes; - break; - case "GenericWrite": - permissionEx.GenericWrite = Util.YesNoType.yes; - break; - case "Notify": - permissionEx.Notify = Util.YesNoType.yes; - break; - case "Read": - permissionEx.Read = Util.YesNoType.yes; - break; - case "ReadAttributes": - permissionEx.ReadAttributes = Util.YesNoType.yes; - break; - case "ReadExtendedAttributes": - permissionEx.ReadExtendedAttributes = Util.YesNoType.yes; - break; - case "ReadPermission": - permissionEx.ReadPermission = Util.YesNoType.yes; - break; - case "ServiceChangeConfig": - permissionEx.ServiceChangeConfig = Util.YesNoType.yes; - break; - case "ServiceEnumerateDependents": - permissionEx.ServiceEnumerateDependents = Util.YesNoType.yes; - break; - case "ServiceInterrogate": - permissionEx.ServiceInterrogate = Util.YesNoType.yes; - break; - case "ServicePauseContinue": - permissionEx.ServicePauseContinue = Util.YesNoType.yes; - break; - case "ServiceQueryConfig": - permissionEx.ServiceQueryConfig = Util.YesNoType.yes; - break; - case "ServiceQueryStatus": - permissionEx.ServiceQueryStatus = Util.YesNoType.yes; - break; - case "ServiceStart": - permissionEx.ServiceStart = Util.YesNoType.yes; - break; - case "ServiceStop": - permissionEx.ServiceStop = Util.YesNoType.yes; - break; - case "ServiceUserDefinedControl": - permissionEx.ServiceUserDefinedControl = Util.YesNoType.yes; - break; - case "Synchronize": - permissionEx.Synchronize = Util.YesNoType.yes; - break; - case "TakeOwnership": - permissionEx.TakeOwnership = Util.YesNoType.yes; - break; - case "Traverse": - permissionEx.Traverse = Util.YesNoType.yes; - break; - case "Write": - permissionEx.Write = Util.YesNoType.yes; - break; - case "WriteAttributes": - permissionEx.WriteAttributes = Util.YesNoType.yes; - break; - case "WriteExtendedAttributes": - permissionEx.WriteExtendedAttributes = Util.YesNoType.yes; - break; - default: - throw new InvalidOperationException(String.Format("Unknown permission attribute '{0}'.", name)); - } - } - } - } - - if (null != row[2]) - { - permissionEx.Domain = (string)row[2]; - } - - permissionEx.User = (string)row[3]; - - this.Core.IndexElement(row, permissionEx); - } - } - - /// - /// Decompile the ServiceConfig table. - /// - /// The table to decompile. - private void DecompileServiceConfigTable(Table table) - { - foreach (Row row in table.Rows) - { - Util.ServiceConfig serviceConfig = new Util.ServiceConfig(); - - serviceConfig.ServiceName = (string)row[0]; - - switch ((string)row[3]) - { - case "none": - serviceConfig.FirstFailureActionType = Util.ServiceConfig.FirstFailureActionTypeType.none; - break; - case "reboot": - serviceConfig.FirstFailureActionType = Util.ServiceConfig.FirstFailureActionTypeType.reboot; - break; - case "restart": - serviceConfig.FirstFailureActionType = Util.ServiceConfig.FirstFailureActionTypeType.restart; - break; - case "runCommand": - serviceConfig.FirstFailureActionType = Util.ServiceConfig.FirstFailureActionTypeType.runCommand; - break; - default: - this.Core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[3].Column.Name, row[3])); - break; - } - - switch ((string)row[4]) - { - case "none": - serviceConfig.SecondFailureActionType = Util.ServiceConfig.SecondFailureActionTypeType.none; - break; - case "reboot": - serviceConfig.SecondFailureActionType = Util.ServiceConfig.SecondFailureActionTypeType.reboot; - break; - case "restart": - serviceConfig.SecondFailureActionType = Util.ServiceConfig.SecondFailureActionTypeType.restart; - break; - case "runCommand": - serviceConfig.SecondFailureActionType = Util.ServiceConfig.SecondFailureActionTypeType.runCommand; - break; - default: - this.Core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[4].Column.Name, row[4])); - break; - } - - switch ((string)row[5]) - { - case "none": - serviceConfig.ThirdFailureActionType = Util.ServiceConfig.ThirdFailureActionTypeType.none; - break; - case "reboot": - serviceConfig.ThirdFailureActionType = Util.ServiceConfig.ThirdFailureActionTypeType.reboot; - break; - case "restart": - serviceConfig.ThirdFailureActionType = Util.ServiceConfig.ThirdFailureActionTypeType.restart; - break; - case "runCommand": - serviceConfig.ThirdFailureActionType = Util.ServiceConfig.ThirdFailureActionTypeType.runCommand; - break; - default: - this.Core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[5].Column.Name, row[5])); - break; - } - - if (null != row[6]) - { - serviceConfig.ResetPeriodInDays = (int)row[6]; - } - - if (null != row[7]) - { - serviceConfig.RestartServiceDelayInSeconds = (int)row[7]; - } - - if (null != row[8]) - { - serviceConfig.ProgramCommandLine = (string)row[8]; - } - - if (null != row[9]) - { - serviceConfig.RebootMessage = (string)row[9]; - } - - this.Core.IndexElement(row, serviceConfig); - } - } - - /// - /// Decompile the User table. - /// - /// The table to decompile. - private void DecompileUserTable(Table table) - { - foreach (Row row in table.Rows) - { - Util.User user = new Util.User(); - - user.Id = (string)row[0]; - - user.Name = (string)row[2]; - - if (null != row[3]) - { - user.Domain = (string)row[3]; - } - - if (null != row[4]) - { - user.Password = (string)row[4]; - } - - if (null != row[5]) - { - int attributes = (int)row[5]; - - if (UtilCompiler.UserDontExpirePasswrd == (attributes & UtilCompiler.UserDontExpirePasswrd)) - { - user.PasswordNeverExpires = Util.YesNoType.yes; - } - - if (UtilCompiler.UserPasswdCantChange == (attributes & UtilCompiler.UserPasswdCantChange)) - { - user.CanNotChangePassword = Util.YesNoType.yes; - } - - if (UtilCompiler.UserPasswdChangeReqdOnLogin == (attributes & UtilCompiler.UserPasswdChangeReqdOnLogin)) - { - user.PasswordExpired = Util.YesNoType.yes; - } - - if (UtilCompiler.UserDisableAccount == (attributes & UtilCompiler.UserDisableAccount)) - { - user.Disabled = Util.YesNoType.yes; - } - - if (UtilCompiler.UserFailIfExists == (attributes & UtilCompiler.UserFailIfExists)) - { - user.FailIfExists = Util.YesNoType.yes; - } - - if (UtilCompiler.UserUpdateIfExists == (attributes & UtilCompiler.UserUpdateIfExists)) - { - user.UpdateIfExists = Util.YesNoType.yes; - } - - if (UtilCompiler.UserLogonAsService == (attributes & UtilCompiler.UserLogonAsService)) - { - user.LogonAsService = Util.YesNoType.yes; - } - - if (UtilCompiler.UserDontRemoveOnUninstall == (attributes & UtilCompiler.UserDontRemoveOnUninstall)) - { - user.RemoveOnUninstall = Util.YesNoType.no; - } - - if (UtilCompiler.UserDontCreateUser == (attributes & UtilCompiler.UserDontCreateUser)) - { - user.CreateUser = Util.YesNoType.no; - } - - if (UtilCompiler.UserNonVital == (attributes & UtilCompiler.UserNonVital)) - { - user.Vital = Util.YesNoType.no; - } - } - - if (null != row[1]) - { - Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[1]); - - if (null != component) - { - component.AddChild(user); - } - else - { - this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[1], "Component")); - } - } - else - { - this.Core.RootElement.AddChild(user); - } - this.Core.IndexElement(row, user); - } - } - - /// - /// Decompile the UserGroup table. - /// - /// The table to decompile. - private void DecompileUserGroupTable(Table table) - { - foreach (Row row in table.Rows) - { - Util.User user = (Util.User)this.Core.GetIndexedElement("User", (string)row[0]); - - if (null != user) - { - Util.GroupRef groupRef = new Util.GroupRef(); - - groupRef.Id = (string)row[1]; - - user.AddChild(groupRef); - } - else - { - this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Group_", (string)row[0], "Group")); - } - } - } - - /// - /// Decompile the XmlConfig table. - /// - /// The table to decompile. - private void DecompileXmlConfigTable(Table table) - { - foreach (Row row in table.Rows) - { - Util.XmlConfig xmlConfig = new Util.XmlConfig(); - - xmlConfig.Id = (string)row[0]; - - xmlConfig.File = (string)row[1]; - - xmlConfig.ElementPath = (string)row[2]; - - if (null != row[3]) - { - xmlConfig.VerifyPath = (string)row[3]; - } - - if (null != row[4]) - { - xmlConfig.Name = (string)row[4]; - } - - if (null != row[5]) - { - xmlConfig.Value = (string)row[5]; - } - - int flags = (int)row[6]; - - if (0x1 == (flags & 0x1)) - { - xmlConfig.Node = Util.XmlConfig.NodeType.element; - } - else if (0x2 == (flags & 0x2)) - { - xmlConfig.Node = Util.XmlConfig.NodeType.value; - } - else if (0x4 == (flags & 0x4)) - { - xmlConfig.Node = Util.XmlConfig.NodeType.document; - } - - if (0x10 == (flags & 0x10)) - { - xmlConfig.Action = Util.XmlConfig.ActionType.create; - } - else if (0x20 == (flags & 0x20)) - { - xmlConfig.Action = Util.XmlConfig.ActionType.delete; - } - - if (0x100 == (flags & 0x100)) - { - xmlConfig.On = Util.XmlConfig.OnType.install; - } - else if (0x200 == (flags & 0x200)) - { - xmlConfig.On = Util.XmlConfig.OnType.uninstall; - } - - if (0x00001000 == (flags & 0x00001000)) - { - xmlConfig.PreserveModifiedDate = Util.YesNoType.yes; - } - - if (null != row[8]) - { - xmlConfig.Sequence = (int)row[8]; - } - - this.Core.IndexElement(row, xmlConfig); - } - } - - /// - /// Finalize the Perfmon table. - /// - /// The collection of all tables. - /// - /// Since the PerfCounter element nests under a File element, but - /// the Perfmon table does not have a foreign key relationship with - /// the File table (instead it has a formatted string that usually - /// refers to a file row - but doesn't have to), the nesting must - /// be inferred during finalization. - /// - private void FinalizePerfmonTable(TableIndexedCollection tables) - { - Table perfmonTable = tables["Perfmon"]; - - if (null != perfmonTable) - { - foreach (Row row in perfmonTable.Rows) - { - string formattedFile = (string)row[1]; - Util.PerfCounter perfCounter = (Util.PerfCounter)this.Core.GetIndexedElement(row); - - // try to "de-format" the File column's value to determine the proper parent File element - if ((formattedFile.StartsWith("[#", StringComparison.Ordinal) || formattedFile.StartsWith("[!", StringComparison.Ordinal)) - && formattedFile.EndsWith("]", StringComparison.Ordinal)) - { - string fileId = formattedFile.Substring(2, formattedFile.Length - 3); - - Wix.File file = (Wix.File)this.Core.GetIndexedElement("File", fileId); - if (null != file) - { - file.AddChild(perfCounter); - } - else - { - this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, perfmonTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "File", formattedFile, "File")); - } - } - else - { - this.Core.OnMessage(UtilErrors.IllegalFileValueInPerfmonOrManifest(formattedFile, "Perfmon")); - } - } - } - } - - /// - /// Finalize the PerfmonManifest table. - /// - /// The collection of all tables. - private void FinalizePerfmonManifestTable(TableIndexedCollection tables) - { - Table perfmonManifestTable = tables["PerfmonManifest"]; - - if (null != perfmonManifestTable) - { - foreach (Row row in perfmonManifestTable.Rows) - { - string formattedFile = (string)row[1]; - Util.PerfCounterManifest perfCounterManifest = (Util.PerfCounterManifest)this.Core.GetIndexedElement(row); - - // try to "de-format" the File column's value to determine the proper parent File element - if ((formattedFile.StartsWith("[#", StringComparison.Ordinal) || formattedFile.StartsWith("[!", StringComparison.Ordinal)) - && formattedFile.EndsWith("]", StringComparison.Ordinal)) - { - string fileId = formattedFile.Substring(2, formattedFile.Length - 3); - - Wix.File file = (Wix.File)this.Core.GetIndexedElement("File", fileId); - if (null != file) - { - file.AddChild(perfCounterManifest); - } - else - { - this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, perfCounterManifest.ResourceFileDirectory, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "File", formattedFile, "File")); - } - } - else - { - this.Core.OnMessage(UtilErrors.IllegalFileValueInPerfmonOrManifest(formattedFile, "PerfmonManifest")); - } - } - } - } - - /// - /// Finalize the SecureObjects table. - /// - /// The collection of all tables. - /// - /// Nests the PermissionEx elements below their parent elements. There are no declared foreign - /// keys for the parents of the SecureObjects table. - /// - private void FinalizeSecureObjectsTable(TableIndexedCollection tables) - { - Table createFolderTable = tables["CreateFolder"]; - Table secureObjectsTable = tables["SecureObjects"]; - - Hashtable createFolders = new Hashtable(); - - // index the CreateFolder table because the foreign key to this table from the - // LockPermissions table is only part of the primary key of this table - if (null != createFolderTable) - { - foreach (Row row in createFolderTable.Rows) - { - Wix.CreateFolder createFolder = (Wix.CreateFolder)this.Core.GetIndexedElement(row); - string directoryId = (string)row[0]; - - if (!createFolders.Contains(directoryId)) - { - createFolders.Add(directoryId, new ArrayList()); - } - ((ArrayList)createFolders[directoryId]).Add(createFolder); - } - } - - if (null != secureObjectsTable) - { - foreach (Row row in secureObjectsTable.Rows) - { - string id = (string)row[0]; - string table = (string)row[1]; - - Util.PermissionEx permissionEx = (Util.PermissionEx)this.Core.GetIndexedElement(row); - - if ("CreateFolder" == table) - { - ArrayList createFolderElements = (ArrayList)createFolders[id]; - - if (null != createFolderElements) - { - foreach (Wix.CreateFolder createFolder in createFolderElements) - { - createFolder.AddChild(permissionEx); - } - } - else - { - this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "SecureObjects", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "LockObject", id, table)); - } - } - else - { - Wix.IParentElement parentElement = (Wix.IParentElement)this.Core.GetIndexedElement(table, id); - - if (null != parentElement) - { - parentElement.AddChild(permissionEx); - } - else - { - this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "SecureObjects", row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "LockObject", id, table)); - } - } - } - } - } - - /// - /// Finalize the ServiceConfig table. - /// - /// The collection of all tables. - /// - /// Since there is no foreign key from the ServiceName column to the - /// ServiceInstall table, this relationship must be handled late. - /// - private void FinalizeServiceConfigTable(TableIndexedCollection tables) - { - Table serviceConfigTable = tables["ServiceConfig"]; - Table serviceInstallTable = tables["ServiceInstall"]; - - Hashtable serviceInstalls = new Hashtable(); - - // index the ServiceInstall table because the foreign key used by the ServiceConfig - // table is actually the ServiceInstall.Name, not the ServiceInstall.ServiceInstall - // this is unfortunate because the service Name is not guaranteed to be unique, so - // decompiler must assume there could be multiple matches and add the ServiceConfig to each - // TODO: the Component column information should be taken into acount to accurately identify - // the correct column to use - if (null != serviceInstallTable) - { - foreach (Row row in serviceInstallTable.Rows) - { - string name = (string)row[1]; - Wix.ServiceInstall serviceInstall = (Wix.ServiceInstall)this.Core.GetIndexedElement(row); - - if (!serviceInstalls.Contains(name)) - { - serviceInstalls.Add(name, new ArrayList()); - } - - ((ArrayList)serviceInstalls[name]).Add(serviceInstall); - } - } - - if (null != serviceConfigTable) - { - foreach (Row row in serviceConfigTable.Rows) - { - Util.ServiceConfig serviceConfig = (Util.ServiceConfig)this.Core.GetIndexedElement(row); - - if (0 == (int)row[2]) - { - Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[1]); - - if (null != component) - { - component.AddChild(serviceConfig); - } - else - { - this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, serviceConfigTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[1], "Component")); - } - } - else - { - ArrayList serviceInstallElements = (ArrayList)serviceInstalls[row[0]]; - - if (null != serviceInstallElements) - { - foreach (Wix.ServiceInstall serviceInstall in serviceInstallElements) - { - serviceInstall.AddChild(serviceConfig); - } - } - else - { - this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, serviceConfigTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "ServiceName", (string)row[0], "ServiceInstall")); - } - } - } - } - } - - /// - /// Finalize the XmlConfig table. - /// - /// Collection of all tables. - private void FinalizeXmlConfigTable(TableIndexedCollection tables) - { - Table xmlConfigTable = tables["XmlConfig"]; - - if (null != xmlConfigTable) - { - foreach (Row row in xmlConfigTable.Rows) - { - Util.XmlConfig xmlConfig = (Util.XmlConfig)this.Core.GetIndexedElement(row); - - if (null == row[6] || 0 == (int)row[6]) - { - Util.XmlConfig parentXmlConfig = (Util.XmlConfig)this.Core.GetIndexedElement("XmlConfig", (string)row[2]); - - if (null != parentXmlConfig) - { - parentXmlConfig.AddChild(xmlConfig); - } - else - { - this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, xmlConfigTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "ElementPath", (string)row[2], "XmlConfig")); - } - } - else - { - Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[7]); - - if (null != component) - { - component.AddChild(xmlConfig); - } - else - { - this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, xmlConfigTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[7], "Component")); - } - } - } - } - } - - - /// - /// Finalize the XmlFile table. - /// - /// The collection of all tables. - /// - /// Some of the XmlFile table rows are compiler generated from util:EventManifest node - /// These rows should not be appended to component. - /// - private void FinalizeXmlFileTable(TableIndexedCollection tables) - { - Table xmlFileTable = tables["XmlFile"]; - Table eventManifestTable = tables["EventManifest"]; - - if (null != xmlFileTable) - { - foreach (Row row in xmlFileTable.Rows) - { - bool bManifestGenerated = false; - string xmlFileConfigId = (string)row[0]; - if (null != eventManifestTable) - { - foreach (Row emrow in eventManifestTable.Rows) - { - string formattedFile = (string)emrow[1]; - if ((formattedFile.StartsWith("[#", StringComparison.Ordinal) || formattedFile.StartsWith("[!", StringComparison.Ordinal)) - && formattedFile.EndsWith("]", StringComparison.Ordinal)) - { - string fileId = formattedFile.Substring(2, formattedFile.Length - 3); - if (String.Equals(String.Concat("Config_", fileId, "ResourceFile"), xmlFileConfigId)) - { - Util.EventManifest eventManifest = (Util.EventManifest)this.Core.GetIndexedElement(emrow); - if (null != eventManifest) - { - eventManifest.ResourceFile = (string)row[4]; - } - bManifestGenerated = true; - } - - else if (String.Equals(String.Concat("Config_", fileId, "MessageFile"), xmlFileConfigId)) - { - Util.EventManifest eventManifest = (Util.EventManifest)this.Core.GetIndexedElement(emrow); - if (null != eventManifest) - { - eventManifest.MessageFile = (string)row[4]; - } - bManifestGenerated = true; - } - } - } - } - - if (true == bManifestGenerated) - continue; - - Util.XmlFile xmlFile = new Util.XmlFile(); - - xmlFile.Id = (string)row[0]; - xmlFile.File = (string)row[1]; - xmlFile.ElementPath = (string)row[2]; - - if (null != row[3]) - { - xmlFile.Name = (string)row[3]; - } - - if (null != row[4]) - { - xmlFile.Value = (string)row[4]; - } - - int flags = (int)row[5]; - if (0x1 == (flags & 0x1) && 0x2 == (flags & 0x2)) - { - this.Core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, xmlFileTable.Name, row.Fields[5].Column.Name, row[5])); - } - else if (0x1 == (flags & 0x1)) - { - xmlFile.Action = Util.XmlFile.ActionType.createElement; - } - else if (0x2 == (flags & 0x2)) - { - xmlFile.Action = Util.XmlFile.ActionType.deleteValue; - } - else - { - xmlFile.Action = Util.XmlFile.ActionType.setValue; - } - - if (0x100 == (flags & 0x100)) - { - xmlFile.SelectionLanguage = Util.XmlFile.SelectionLanguageType.XPath; - } - - if (0x00001000 == (flags & 0x00001000)) - { - xmlFile.PreserveModifiedDate = Util.YesNoType.yes; - } - - if (0x00010000 == (flags & 0x00010000)) - { - xmlFile.Permanent = Util.YesNoType.yes; - } - - if (null != row[7]) - { - xmlFile.Sequence = (int)row[7]; - } - - Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[6]); - - if (null != component) - { - component.AddChild(xmlFile); - } - else - { - this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, xmlFileTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[6], "Component")); - } - } - } - } - - /// - /// Finalize the eventManifest table. - /// This function must be called after FinalizeXmlFileTable - /// - /// The collection of all tables. - private void FinalizeEventManifestTable(TableIndexedCollection tables) - { - Table eventManifestTable = tables["EventManifest"]; - - if (null != eventManifestTable) - { - foreach (Row row in eventManifestTable.Rows) - { - string formattedFile = (string)row[1]; - Util.EventManifest eventManifest = (Util.EventManifest)this.Core.GetIndexedElement(row); - - // try to "de-format" the File column's value to determine the proper parent File element - if ((formattedFile.StartsWith("[#", StringComparison.Ordinal) || formattedFile.StartsWith("[!", StringComparison.Ordinal)) - && formattedFile.EndsWith("]", StringComparison.Ordinal)) - { - string fileId = formattedFile.Substring(2, formattedFile.Length - 3); - - Wix.File file = (Wix.File)this.Core.GetIndexedElement("File", fileId); - if (null != file) - { - file.AddChild(eventManifest); - } - } - else - { - this.Core.OnMessage(UtilErrors.IllegalFileValueInPerfmonOrManifest(formattedFile, "EventManifest")); - } - } - } - } - } -#endif -} diff --git a/src/wixext/UtilErrors.cs b/src/wixext/UtilErrors.cs deleted file mode 100644 index b9ce1688..00000000 --- a/src/wixext/UtilErrors.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - using System; - using System.Resources; - using WixToolset.Data; - - public static class UtilErrors - { - public static Message IllegalAttributeWithoutComponent(SourceLineNumber sourceLineNumbers, string elementName, string attributeName) - { - 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); - } - - public static Message IllegalElementWithoutComponent(SourceLineNumber sourceLineNumbers, string elementName) - { - 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); - } - - public static Message IllegalFileValueInPerfmonOrManifest(string file, string table) - { - 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); - } - - public static Message InvalidRegistryObject(SourceLineNumber sourceLineNumbers, string registryElementName) - { - 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); - } - - private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args) - { - return new Message(sourceLineNumber, MessageLevel.Error, (int)id, format, args); - } - - private static Message Message(SourceLineNumber sourceLineNumber, Ids id, ResourceManager resourceManager, string resourceName, params object[] args) - { - return new Message(sourceLineNumber, MessageLevel.Error, (int)id, resourceManager, resourceName, args); - } - - public enum Ids - { - IllegalAttributeWithoutComponent = 5050, - IllegalElementWithoutComponent = 5051, - IllegalFileValueInPerfmonOrManifest = 5054, - InvalidRegistryObject = 5063, - } - } -} diff --git a/src/wixext/UtilExtensionData.cs b/src/wixext/UtilExtensionData.cs deleted file mode 100644 index d3ca3358..00000000 --- a/src/wixext/UtilExtensionData.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - using WixToolset.Data; - using WixToolset.Extensibility; - - public sealed class UtilExtensionData : BaseExtensionData - { - public override string DefaultCulture => "en-US"; - - public override bool TryGetSymbolDefinitionByName(string name, out IntermediateSymbolDefinition symbolDefinition) - { - symbolDefinition = UtilSymbolDefinitions.ByName(name); - return symbolDefinition != null; - } - - public override Intermediate GetLibrary(ISymbolDefinitionCreator symbolDefinitions) - { - return Intermediate.Load(typeof(UtilExtensionData).Assembly, "WixToolset.Util.util.wixlib", symbolDefinitions); - } - } -} diff --git a/src/wixext/UtilExtensionFactory.cs b/src/wixext/UtilExtensionFactory.cs deleted file mode 100644 index 08352813..00000000 --- a/src/wixext/UtilExtensionFactory.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - using System; - using System.Collections.Generic; - using WixToolset.Extensibility; - - public class UtilExtensionFactory : BaseExtensionFactory - { - protected override IReadOnlyCollection ExtensionTypes => new[] - { - typeof(UtilCompiler), - typeof(UtilExtensionData), - typeof(UtilWindowsInstallerBackendBinderExtension), - }; - } -} diff --git a/src/wixext/UtilTableDefinitions.cs b/src/wixext/UtilTableDefinitions.cs deleted file mode 100644 index 12f423cc..00000000 --- a/src/wixext/UtilTableDefinitions.cs +++ /dev/null @@ -1,319 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - using WixToolset.Data.WindowsInstaller; - - public static class UtilTableDefinitions - { - public static readonly TableDefinition Wix4CloseApplication = new TableDefinition( - "Wix4CloseApplication", - UtilSymbolDefinitions.WixCloseApplication, - new[] - { - new ColumnDefinition("Wix4CloseApplication", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token in table.", modularizeType: ColumnModularizeType.Column), - new ColumnDefinition("Target", ColumnType.Localized, 0, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "Name of executable to ensure is closed.", modularizeType: ColumnModularizeType.Property), - 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), - new ColumnDefinition("Condition", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Condition, description: "Optional expression which skips the closing.", modularizeType: ColumnModularizeType.Condition, forceLocalizable: true), - 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."), - new ColumnDefinition("Sequence", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Unknown, minValue: 1, maxValue: 2147483647, description: "Sequence to order the closings by."), - 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), - 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."), - 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."), - }, - symbolIdIsPrimaryKey: true - ); - - public static readonly TableDefinition Wix4RemoveFolderEx = new TableDefinition( - "Wix4RemoveFolderEx", - UtilSymbolDefinitions.WixRemoveFolderEx, - new[] - { - new ColumnDefinition("Wix4RemoveFolderEx", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Identifier for the WixRemoveFolderEx row in the package.", modularizeType: ColumnModularizeType.Column), - 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), - 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), - 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."), - 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), - }, - symbolIdIsPrimaryKey: true - ); - - public static readonly TableDefinition Wix4RemoveRegistryKeyEx = new TableDefinition( - "Wix4RemoveRegistryKeyEx", - UtilSymbolDefinitions.WixRemoveRegistryKeyEx, - new[] - { - new ColumnDefinition("Wix4RemoveRegistryKeyEx", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Identifier for the Wix4RemoveRegistryKeyEx row in the package.", modularizeType: ColumnModularizeType.Column), - 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), - 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."), - new ColumnDefinition("Key", ColumnType.Localized, 255, primaryKey: false, nullable: false, ColumnCategory.RegPath, description: "The key for the registry value.", modularizeType: ColumnModularizeType.Property), - 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."), - 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), - }, - symbolIdIsPrimaryKey: true - ); - - public static readonly TableDefinition Wix4RestartResource = new TableDefinition( - "Wix4RestartResource", - UtilSymbolDefinitions.WixRestartResource, - new[] - { - new ColumnDefinition("Wix4RestartResource", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized identifier.", modularizeType: ColumnModularizeType.Column), - 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), - 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), - 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."), - }, - symbolIdIsPrimaryKey: true - ); - - public static readonly TableDefinition Wix4FileShare = new TableDefinition( - "Wix4FileShare", - UtilSymbolDefinitions.FileShare, - new[] - { - new ColumnDefinition("Wix4FileShare", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized identifier", modularizeType: ColumnModularizeType.Column), - new ColumnDefinition("ShareName", ColumnType.String, 255, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "The actual share name used"), - 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), - new ColumnDefinition("Description", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Text, description: "Description string displayed for the file share"), - 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), - }, - symbolIdIsPrimaryKey: true - ); - - public static readonly TableDefinition Wix4FileSharePermissions = new TableDefinition( - "Wix4FileSharePermissions", - UtilSymbolDefinitions.FileSharePermissions, - new[] - { - 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), - 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), - new ColumnDefinition("Permissions", ColumnType.Number, 4, primaryKey: false, nullable: false, ColumnCategory.Unknown, description: "Permissions int, as in EXPLICIT_ACCESS.grfAccessPermissions in MSDN"), - }, - symbolIdIsPrimaryKey: false - ); - - public static readonly TableDefinition Wix4Group = new TableDefinition( - "Wix4Group", - UtilSymbolDefinitions.Group, - new[] - { - new ColumnDefinition("Wix4Group", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token", modularizeType: ColumnModularizeType.Column), - 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), - new ColumnDefinition("Name", ColumnType.String, 255, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "Group name", modularizeType: ColumnModularizeType.Property), - new ColumnDefinition("Domain", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Group domain", modularizeType: ColumnModularizeType.Property), - }, - symbolIdIsPrimaryKey: true - ); - - public static readonly TableDefinition Wix4InternetShortcut = new TableDefinition( - "Wix4InternetShortcut", - UtilSymbolDefinitions.WixInternetShortcut, - new[] - { - new ColumnDefinition("Wix4InternetShortcut", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token in table.", modularizeType: ColumnModularizeType.Column), - 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), - 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), - new ColumnDefinition("Name", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Text, description: "Name used for shortcut.", modularizeType: ColumnModularizeType.Property), - new ColumnDefinition("Target", ColumnType.Localized, 0, primaryKey: false, nullable: false, ColumnCategory.Text, description: "URL target."), - new ColumnDefinition("Attributes", ColumnType.Number, 2, primaryKey: false, nullable: false, ColumnCategory.Unknown, description: "Attribute flags that control how the shortcut is created."), - new ColumnDefinition("IconFile", ColumnType.Localized, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Icon file for shortcut", modularizeType: ColumnModularizeType.Property), - new ColumnDefinition("IconIndex", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Index of the icon being referenced."), - }, - symbolIdIsPrimaryKey: true - ); - - public static readonly TableDefinition Wix4PerformanceCategory = new TableDefinition( - "Wix4PerformanceCategory", - UtilSymbolDefinitions.PerformanceCategory, - new[] - { - new ColumnDefinition("Wix4PerformanceCategory", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token in table.", modularizeType: ColumnModularizeType.Column), - 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), - new ColumnDefinition("Name", ColumnType.String, 80, primaryKey: false, nullable: false, ColumnCategory.Text, description: "Name of the performance counter category."), - new ColumnDefinition("IniData", ColumnType.Localized, 0, primaryKey: false, nullable: false, ColumnCategory.Text, description: "Data that goes into the performance counter .ini file."), - new ColumnDefinition("ConstantData", ColumnType.Localized, 0, primaryKey: false, nullable: false, ColumnCategory.Text, description: "Data that goes into the performance counter .h file."), - }, - symbolIdIsPrimaryKey: true - ); - - public static readonly TableDefinition Wix4Perfmon = new TableDefinition( - "Wix4Perfmon", - UtilSymbolDefinitions.Perfmon, - new[] - { - 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), - new ColumnDefinition("File", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Formatted, description: "Name of .INI file", modularizeType: ColumnModularizeType.Property), - new ColumnDefinition("Name", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Text, description: "Service name in registry"), - }, - symbolIdIsPrimaryKey: false - ); - - public static readonly TableDefinition Wix4PerfmonManifest = new TableDefinition( - "Wix4PerfmonManifest", - UtilSymbolDefinitions.PerfmonManifest, - new[] - { - 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), - new ColumnDefinition("File", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Formatted, description: "Name of perfmon manifest file", modularizeType: ColumnModularizeType.Property), - new ColumnDefinition("ResourceFileDirectory", ColumnType.String, 255, primaryKey: true, nullable: false, ColumnCategory.Formatted, description: "The path of the Resource File Directory"), - }, - symbolIdIsPrimaryKey: false - ); - - public static readonly TableDefinition Wix4EventManifest = new TableDefinition( - "Wix4EventManifest", - UtilSymbolDefinitions.EventManifest, - new[] - { - 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), - new ColumnDefinition("File", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Formatted, description: "Name of event manifest file", modularizeType: ColumnModularizeType.Property), - }, - symbolIdIsPrimaryKey: false - ); - - public static readonly TableDefinition Wix4SecureObject = new TableDefinition( - "Wix4SecureObject", - UtilSymbolDefinitions.SecureObjects, - new[] - { - new ColumnDefinition("Wix4SecureObject", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token in Table", modularizeType: ColumnModularizeType.Column), - new ColumnDefinition("Table", ColumnType.String, 32, primaryKey: true, nullable: false, ColumnCategory.Text, description: "Table SecureObject should be securing"), - new ColumnDefinition("Domain", ColumnType.String, 255, primaryKey: true, nullable: true, ColumnCategory.Text, description: "Domain half of user account to secure", modularizeType: ColumnModularizeType.Property), - new ColumnDefinition("User", ColumnType.String, 255, primaryKey: true, nullable: false, ColumnCategory.Text, description: "User name half of user account to secure", modularizeType: ColumnModularizeType.Property), - 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."), - new ColumnDefinition("Permission", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Unknown, minValue: -2147483647, maxValue: 2147483647, description: "Permissions to grant to User"), - 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), - }, - symbolIdIsPrimaryKey: false - ); - - public static readonly TableDefinition Wix4ServiceConfig = new TableDefinition( - "Wix4ServiceConfig", - UtilSymbolDefinitions.ServiceConfig, - new[] - { - new ColumnDefinition("ServiceName", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Formatted, description: "Primary key, non-localized token"), - 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), - 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."), - new ColumnDefinition("FirstFailureActionType", ColumnType.String, 32, primaryKey: false, nullable: false, ColumnCategory.Text, description: "First failure action type for configured service to take."), - new ColumnDefinition("SecondFailureActionType", ColumnType.String, 32, primaryKey: false, nullable: false, ColumnCategory.Text, description: "Second failure action type for configured service to take."), - new ColumnDefinition("ThirdFailureActionType", ColumnType.String, 32, primaryKey: false, nullable: false, ColumnCategory.Text, description: "Third failure action type for configured service to take."), - 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."), - 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."), - 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."), - 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."), - }, - symbolIdIsPrimaryKey: false - ); - - public static readonly TableDefinition Wix4TouchFile = new TableDefinition( - "Wix4TouchFile", - UtilSymbolDefinitions.WixTouchFile, - new[] - { - new ColumnDefinition("Wix4TouchFile", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Identifier for the Wix4TouchFile row in the package.", modularizeType: ColumnModularizeType.Column), - 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), - 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), - 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."), - }, - symbolIdIsPrimaryKey: true - ); - - public static readonly TableDefinition Wix4User = new TableDefinition( - "Wix4User", - UtilSymbolDefinitions.User, - new[] - { - new ColumnDefinition("Wix4User", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token", modularizeType: ColumnModularizeType.Column), - 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), - new ColumnDefinition("Name", ColumnType.String, 255, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "User name", modularizeType: ColumnModularizeType.Property), - new ColumnDefinition("Domain", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "User domain", modularizeType: ColumnModularizeType.Property), - new ColumnDefinition("Password", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "User password", modularizeType: ColumnModularizeType.Property), - new ColumnDefinition("Attributes", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Unknown, minValue: 0, maxValue: 65535, description: "Attributes describing how to create the user"), - }, - symbolIdIsPrimaryKey: true - ); - - public static readonly TableDefinition Wix4UserGroup = new TableDefinition( - "Wix4UserGroup", - UtilSymbolDefinitions.UserGroup, - new[] - { - 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), - 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), - }, - symbolIdIsPrimaryKey: false - ); - - public static readonly TableDefinition Wix4XmlFile = new TableDefinition( - "Wix4XmlFile", - UtilSymbolDefinitions.XmlFile, - new[] - { - new ColumnDefinition("Wix4XmlFile", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token.", modularizeType: ColumnModularizeType.Column), - 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), - new ColumnDefinition("ElementPath", ColumnType.Localized, 0, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "The .XML file element to modify.", modularizeType: ColumnModularizeType.Property), - 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), - new ColumnDefinition("Value", ColumnType.Localized, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "The value to be written.", modularizeType: ColumnModularizeType.Property), - new ColumnDefinition("Flags", ColumnType.Number, 4, primaryKey: false, nullable: false, ColumnCategory.Unknown, minValue: 0, maxValue: 70143, description: "Flags"), - 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), - new ColumnDefinition("Sequence", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Order to execute the XML modifications."), - }, - symbolIdIsPrimaryKey: true - ); - - public static readonly TableDefinition Wix4XmlConfig = new TableDefinition( - "Wix4XmlConfig", - UtilSymbolDefinitions.XmlConfig, - new[] - { - new ColumnDefinition("Wix4XmlConfig", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token.", modularizeType: ColumnModularizeType.Column), - 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), - 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), - 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), - 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), - 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), - new ColumnDefinition("Value", ColumnType.Localized, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "The value to be written.", modularizeType: ColumnModularizeType.Property), - 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"), - 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), - new ColumnDefinition("Sequence", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Order to execute the XML modifications."), - }, - symbolIdIsPrimaryKey: true - ); - - public static readonly TableDefinition Wix4FormatFile = new TableDefinition( - "Wix4FormatFile", - UtilSymbolDefinitions.WixFormatFiles, - new[] - { - 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), - 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), - }, - symbolIdIsPrimaryKey: false - ); - - public static readonly TableDefinition[] All = new[] - { - Wix4CloseApplication, - Wix4RemoveFolderEx, - Wix4RemoveRegistryKeyEx, - Wix4RestartResource, - Wix4FileShare, - Wix4FileSharePermissions, - Wix4Group, - Wix4InternetShortcut, - Wix4PerformanceCategory, - Wix4Perfmon, - Wix4PerfmonManifest, - Wix4EventManifest, - Wix4SecureObject, - Wix4ServiceConfig, - Wix4TouchFile, - Wix4User, - Wix4UserGroup, - Wix4XmlFile, - Wix4XmlConfig, - Wix4FormatFile, - }; - } -} diff --git a/src/wixext/UtilWarnings.cs b/src/wixext/UtilWarnings.cs deleted file mode 100644 index b65abe45..00000000 --- a/src/wixext/UtilWarnings.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - using System; - using System.Resources; - using WixToolset.Data; - - public static class UtilWarnings - { - public static Message DeprecatedPerfCounterElement(SourceLineNumber sourceLineNumbers) - { - return Message(sourceLineNumbers, Ids.DeprecatedPerfCounterElement, "The PerfCounter element has been deprecated. Please use the PerformanceCounter element instead."); - } - - public static Message RequiredAttributeForWindowsXP(SourceLineNumber sourceLineNumbers, string elementName, string attributeName) - { - 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); - } - - private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args) - { - return new Message(sourceLineNumber, MessageLevel.Warning, (int)id, format, args); - } - - private static Message Message(SourceLineNumber sourceLineNumber, Ids id, ResourceManager resourceManager, string resourceName, params object[] args) - { - return new Message(sourceLineNumber, MessageLevel.Warning, (int)id, resourceManager, resourceName, args); - } - - public enum Ids - { - DeprecatedPerfCounterElement = 5153, - RequiredAttributeForWindowsXP = 5154, - } - } -} diff --git a/src/wixext/UtilWindowsInstallerBackendExtension.cs b/src/wixext/UtilWindowsInstallerBackendExtension.cs deleted file mode 100644 index bca7c700..00000000 --- a/src/wixext/UtilWindowsInstallerBackendExtension.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Util -{ - using System.Collections.Generic; - using WixToolset.Data.WindowsInstaller; - using WixToolset.Extensibility; - - public class UtilWindowsInstallerBackendBinderExtension : BaseWindowsInstallerBackendBinderExtension - { - public override IReadOnlyCollection TableDefinitions => UtilTableDefinitions.All; - } -} diff --git a/src/wixext/WixToolset.Util.wixext.csproj b/src/wixext/WixToolset.Util.wixext.csproj deleted file mode 100644 index 10fc569e..00000000 --- a/src/wixext/WixToolset.Util.wixext.csproj +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - netstandard2.0 - WixToolset.Util - WiX Toolset Utility Extension - WiX Toolset Util Extension - embedded - true - - - - - - - - - - - - - - - - - - - - diff --git a/src/wixext/WixToolset.Util.wixext.nuspec b/src/wixext/WixToolset.Util.wixext.nuspec deleted file mode 100644 index ba3eaade..00000000 --- a/src/wixext/WixToolset.Util.wixext.nuspec +++ /dev/null @@ -1,25 +0,0 @@ - - - - $id$ - $version$ - $title$ - $description$ - $authors$ - MS-RL - false - $copyright$ - $projectUrl$ - - - - - - - - - - - - - diff --git a/src/wixext/WixToolset.Util.wixext.targets b/src/wixext/WixToolset.Util.wixext.targets deleted file mode 100644 index 64dff429..00000000 --- a/src/wixext/WixToolset.Util.wixext.targets +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - $(MSBuildThisFileDirectory)..\tools\WixToolset.Util.wixext.dll - - - - - diff --git a/src/wixext/WixToolset.Util.wixext.v3.ncrunchproject b/src/wixext/WixToolset.Util.wixext.v3.ncrunchproject deleted file mode 100644 index d75e7ab3..00000000 --- a/src/wixext/WixToolset.Util.wixext.v3.ncrunchproject +++ /dev/null @@ -1,7 +0,0 @@ - - - - ..\..\build\Debug\util.wixlib - - - \ No newline at end of file diff --git a/src/wixlib/UtilBundleExtension_Platform.wxi b/src/wixlib/UtilBundleExtension_Platform.wxi deleted file mode 100644 index 379c8f57..00000000 --- a/src/wixlib/UtilBundleExtension_Platform.wxi +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/src/wixlib/UtilBundleExtension_arm64.wxs b/src/wixlib/UtilBundleExtension_arm64.wxs deleted file mode 100644 index b17be031..00000000 --- a/src/wixlib/UtilBundleExtension_arm64.wxs +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/wixlib/UtilBundleExtension_x64.wxs b/src/wixlib/UtilBundleExtension_x64.wxs deleted file mode 100644 index 96c85a5b..00000000 --- a/src/wixlib/UtilBundleExtension_x64.wxs +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/wixlib/UtilBundleExtension_x86.wxs b/src/wixlib/UtilBundleExtension_x86.wxs deleted file mode 100644 index 3b458687..00000000 --- a/src/wixlib/UtilBundleExtension_x86.wxs +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/wixlib/UtilExtension.wxs b/src/wixlib/UtilExtension.wxs deleted file mode 100644 index 0f445ab4..00000000 --- a/src/wixlib/UtilExtension.wxs +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/wixlib/UtilExtension_Platform.wxi b/src/wixlib/UtilExtension_Platform.wxi deleted file mode 100644 index 913c01b9..00000000 --- a/src/wixlib/UtilExtension_Platform.wxi +++ /dev/null @@ -1,360 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/wixlib/UtilExtension_arm64.wxs b/src/wixlib/UtilExtension_arm64.wxs deleted file mode 100644 index b9dc73b8..00000000 --- a/src/wixlib/UtilExtension_arm64.wxs +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/wixlib/UtilExtension_x64.wxs b/src/wixlib/UtilExtension_x64.wxs deleted file mode 100644 index 40cdf306..00000000 --- a/src/wixlib/UtilExtension_x64.wxs +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/wixlib/UtilExtension_x86.wxs b/src/wixlib/UtilExtension_x86.wxs deleted file mode 100644 index bd0fa562..00000000 --- a/src/wixlib/UtilExtension_x86.wxs +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/wixlib/caDecor.wxi b/src/wixlib/caDecor.wxi deleted file mode 100644 index b1711518..00000000 --- a/src/wixlib/caDecor.wxi +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/wixlib/caerr.wxi b/src/wixlib/caerr.wxi deleted file mode 100644 index ff7ec121..00000000 --- a/src/wixlib/caerr.wxi +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/wixlib/de-de.wxl b/src/wixlib/de-de.wxl deleted file mode 100644 index 65785a3b..00000000 --- a/src/wixlib/de-de.wxl +++ /dev/null @@ -1,32 +0,0 @@ - - - - - Konnte den Benutzer nicht anlegen. ([2] [3] [4] [5]) - Konnte den Benutzer auf Grund eines falschen Passwortes nicht anlegen. ([2] [3] [4] [5]) - Konnte Benutzer nicht zur Gruppe hinzufügen. ([2] [3] [4] [5]) - Konnte den Benutzer nicht anlegen, da er bereits existierte. ([2] [3] [4] [5]) - - Konnte Netzwerkfreigabe nicht anlegen. ([2] [3] [4] [5]) - Konnte Netzwerkfreigabe nicht entfernen. ([2] [3] [4] [5]) - - Konnte die DLL nicht für PerfMon registrieren. ([2] [3] [4] [5]) - Konnte die DLL nicht für PerfMon deregistrieren. ([2] [3] [4] [5]) - - Konnte die Daten der Leistungsüberwachung (performance counters) nicht installieren. ([2] [3] [4] [5]) - Konnte die Daten der Leistungsüberwachung (performance counters) nicht deinstallieren. ([2] [3] [4] [5]) - - Konnte keinen Security Descriptor für [3]\[4] erstellen, System Fehler: [2] - Konnte keinen Security Descriptor für das Objekt [3] erstellen, System Fehler: [2] - Unbekannter Objekt Typ [3], System Fehler: [2] - - Beim Lesen der XML Dateien trat ein Fehler auf. - Konnte XML Datei [3] nicht öffnen, System Fehler: [2] - Konnte Knoten [3] in der XML Datei [4] nicht finden, System Fehler: [2] - Beim Speichern der Änderungen an der XML Datei [3] trat ein Fehler auf, System Fehler: [2] - - Bei der Konfiguration der XML Dateien trat ein Fehler auf. - Konnte XML Datei [3] nicht öffnen, System Fehler: [2] - Konnte Knoten [3] in der XML Datei [4] nicht finden, System Fehler: [2] - Beim Speichern der Änderungen an der XML Datei [3] trat ein Fehler auf, System Fehler: [2] - diff --git a/src/wixlib/en-us.wxl b/src/wixlib/en-us.wxl deleted file mode 100644 index e8b146a4..00000000 --- a/src/wixlib/en-us.wxl +++ /dev/null @@ -1,32 +0,0 @@ - - - - - Failed to create user. ([2] [3] [4] [5]) - Failed to create user due to invalid password. ([2] [3] [4] [5]) - Failed to add user to group. ([2] [3] [4] [5]) - Failed to create user because it already exists. ([2] [3] [4] [5]) - - Failed to create network share. ([2] [3] [4] [5]) - Failed to drop network share. ([2] [3] [4] [5]) - - Failed to register DLL with PerfMon. ([2] [3] [4] [5]) - Failed to unregister DLL with PerfMon. ([2] [3] [4] [5]) - - Failed to install performance counters. ([2] [3] [4] [5]) - Failed to uninstall performance counters. ([2] [3] [4] [5]) - - Failed to create security descriptor for [3]\[4], system error: [2] - Failed to set security descriptor on object [3], system error: [2] - Unknown Object Type [3], system error: [2] - - There was a failure while configuring XML files. - Failed to open XML file [3], system error: [2] - Failed to find node: [3] in XML file: [4], system error: [2] - Failed to save changes to XML file [3], system error: [2] - - There was a failure while configuring XML files. - Failed to open XML file [3], system error: [2] - Failed to find node: [3] in XML file: [4], system error: [2] - Failed to save changes to XML file [3], system error: [2] - diff --git a/src/wixlib/es-es.wxl b/src/wixlib/es-es.wxl deleted file mode 100644 index ca5ab8bb..00000000 --- a/src/wixlib/es-es.wxl +++ /dev/null @@ -1,31 +0,0 @@ - - - - La creación del usuario ha fracasado. ([2] [3] [4] [5]) - La creación del usuario ha fracasado porque la contraseña es incorrecta. ([2] [3] [4] [5]) - El aditamento del usuario al grupo ha fracasado. ([2] [3] [4] [5]) - La creación del usuario ha fracasado porque ya existe. ([2] [3] [4] [5]) - - La creación de la red compartida ha fracasado. ([2] [3] [4] [5]) - La eliminación de la red compartida ha fracasado. ([2] [3] [4] [5]) - - La inscripción al registro de la DLL con PerfMon ha fracasado. ([2] [3] [4] [5]) - La cancelación de la inscripción al registro de la DLL con PerfMon ha fracasado. ([2] [3] [4] [5]) - - La instalación de los contadores de rendimiento ha fracasado. ([2] [3] [4] [5]) - La desinstalación de los contadores de rendimiento ha fracasado. ([2] [3] [4] [5]) - - La creación de los ACLs ha fracasado por [3]\[4], error del sistema : [2] - El posicionamiento de los ACLs por el objecto [3] ha fracasado, error del sistema: [2] - Tipo de objecto no conocido [3], error del sistema: [2] - - Un problema ha aparecido durante la configuración de los ficheros XML. - Fracaso de la apertura de los ficheros XML [3], error del sistema: [2] - Fracaso de la búsqueda del nodo: [3] en el fichero XML: [4], error del sistema: [2] - Fracaso durante la salvaguardia de las modificaciones en el fichero XML [3], error del sistema: [2] - - Un problema ha aparecido durante la configuración de los ficheros XML. - Fracaso de la apertura de los ficheros XML [3], error del sistema: [2] - Fracaso de la búsqueda del nodo: [3] en el fichero XML: [4], error del sistema: [2] - Fracaso durante la salvaguardia de las modificaciones en el fichero XML [3], error del sistema: [2] - \ No newline at end of file diff --git a/src/wixlib/fr-fr.wxl b/src/wixlib/fr-fr.wxl deleted file mode 100644 index ad34b56a..00000000 --- a/src/wixlib/fr-fr.wxl +++ /dev/null @@ -1,31 +0,0 @@ - - - - La création de l'utilisateur a échoué. ([2] [3] [4] [5]) - La création de l'utilisateur a échoué car le mot de passe est invalide. ([2] [3] [4] [5]) - L'ajout de l'utilisateur au groupe a échoué. ([2] [3] [4] [5]) - La création de l'utilisateur a échoué car il existe dejà. ([2] [3] [4] [5]) - - La création du partage reseau a échoué. ([2] [3] [4] [5]) - La suppression du partage reseau a échoué. ([2] [3] [4] [5]) - - L'inscription au registre de la DLL avec PerfMon a échoué. ([2] [3] [4] [5]) - La desinscription au registre de la DLL avec PerfMon a échoué. ([2] [3] [4] [5]) - - L'installation des compteurs de performance a échoué. ([2] [3] [4] [5]) - La desinstallation des compteurs de performance a échoué. ([2] [3] [4] [5]) - - La création des ACLs a échoué pour [3]\[4], erreur systeme: [2] - Le positionnement des ACLs pour l'objet [3] a échoué, erreur systeme: [2] - Type d'objet inconnu [3], erreur systeme: [2] - - Un problème est survenu lors de la configuration des fichiers XML. - Echec de l'ouverture des fichiers XML [3], erreur systeme: [2] - Echec de la recherche du noeud: [3] dans le fichier XML: [4], erreur systeme: [2] - Echec lors de la sauvegarde des modifications dans le fichier XML [3], erreur systeme: [2] - - Un problème est survenu lors de la configuration des fichiers XML. - Echec de l'ouverture des fichiers XML [3], erreur systeme: [2] - Echec de la recherche du noeud: [3] dans le fichier XML: [4], erreur systeme: [2] - Echec lors de la sauvegarde des modifications dans le fichier XML [3], erreur systeme: [2] - \ No newline at end of file diff --git a/src/wixlib/it-it.wxl b/src/wixlib/it-it.wxl deleted file mode 100644 index 8cea0a14..00000000 --- a/src/wixlib/it-it.wxl +++ /dev/null @@ -1,32 +0,0 @@ - - - - - Impossibile creare l'utente. ([2] [3] [4] [5]) - Impossibile creare l'utente perchè la password è errata. ([2] [3] [4] [5]) - Impossibile aggiungere l'utente al gruppo. ([2] [3] [4] [5]) - Impossibile creare l'utente perchè già esistente. ([2] [3] [4] [5]) - - Impossibile creare la risorsa di rete. ([2] [3] [4] [5]) - Impossibile eliminare la risorsa di rete. ([2] [3] [4] [5]) - - Impossibile registrare la DLL con PerfMon. ([2] [3] [4] [5]) - Impossibile rimuovere la registrazione della DLL con PerfMon. ([2] [3] [4] [5]) - - Impossibile installare i contatori delle prestazioni. ([2] [3] [4] [5]) - Impossibile rimuovere i contatori delle prestazioni. ([2] [3] [4] [5]) - - Impossibile creare i descrittori di sicurezza per [3]\[4], errore di sistema: [2] - Impossibile impostare i descrittori di sicurezza sull'oggetto [3], errore di sistema: [2] - Tipo di oggetto sconosciuto [3], errore di sistema: [2] - - Si è verificato un errore durante la configurazione dei file XML. - Impossibile aprire il file XML [3], errore di sistema: [2] - Impossibile trovare il nodo: [3] nel file XML: [4], errore di sistema: [2] - Impossible salvare le modifiche al file XML [3], errore di sistema: [2] - - Si è verificato un errore durante la configurazione dei file XML. - Impossibile aprire il file XML [3], errore di sistema: [2] - Impossibile trovare il nodo: [3] nel file XML: [4], errore di sistema: [2] - Impossibile salvare le modifiche al file XML [3], errore di sitema: [2] - diff --git a/src/wixlib/ja-jp.wxl b/src/wixlib/ja-jp.wxl deleted file mode 100644 index 5f5cf40d..00000000 --- a/src/wixlib/ja-jp.wxl +++ /dev/null @@ -1,32 +0,0 @@ - - - - - ユーザー作成に失敗しました。 ([2] [3] [4] [5]) - パスワードが無効のためユーザー作成に失敗しました。 ([2] [3] [4] [5]) - ユーザーをグループに追加でいませんでした。 ([2] [3] [4] [5]) - ユーザーが既に存在するため作成できませんでした。 ([2] [3] [4] [5]) - - ネットワーク共有の作成に失敗しました。 ([2] [3] [4] [5]) - ネットワーク共有の削除に失敗しました。 ([2] [3] [4] [5]) - - DLL を PerfMon に登録でいませんでした。 ([2] [3] [4] [5]) - DLL を PerfMon より登録解除できませんでした。 ([2] [3] [4] [5]) - - パフォーマンス カウンタをインストールできませんでした。 ([2] [3] [4] [5]) - パフォーマンス カウンタをアンインストールできませんでした。 ([2] [3] [4] [5]) - - [3]\[4] 用セキュリティ ディスクリプターを作成できませんでした、システム エラー: [2] - オブジェクト [3] 上のセキュリティ ディスクリプターを設定できませんでした、システム エラー: [2] - 不明なオブジェクト種別 [3]、システム エラー: [2] - - XML ファイル構成中に失敗しました。 - XML ファイル [3] を開けませんでした、システム エラー: [2] - XML ファイル [4] 内にノード [3] が見つかりませんでした、システム エラー: [2] - XML ファイル [3] へ変更を保存できませんでした、システム エラー: [2] - - XML ファイル構成中に失敗しました。 - XML ファイル [3] を開けませんでした、システム エラー: [2] - XML ファイル [4] 内にノード [3] が見つかりませんでした、システム エラー: [2] - XML ファイル [3] へ変更を保存できませんでした、システム エラー: [2] - diff --git a/src/wixlib/pt-br.wxl b/src/wixlib/pt-br.wxl deleted file mode 100644 index 3ca27dda..00000000 --- a/src/wixlib/pt-br.wxl +++ /dev/null @@ -1,26 +0,0 @@ - - - - - Falha ao criar usuário. ([2] [3] [4] [5]) - Falha ao criar usuário devido a senha inválida. ([2] [3] [4] [5]) - Falha ao adicionar o usuário ao grupo. ([2] [3] [4] [5]) - Falha ao criar o usuário, porque ele já existe. ([2] [3] [4] [5]) - Falha ao criar o compartilhamento de rede. ([2] [3] [4] [5]) - Falha ao cair compartilhamento de rede. ([2] [3] [4] [5]) - Falha ao registrar DLL com PerfMon. ([2] [3] [4] [5]) - Falha ao cancelar o registro de DLL com PerfMon. ([2] [3] [4] [5]) - Falha ao instalar contadores de desempenho. ([2] [3] [4] [5]) - Falha ao desinstalar contadores de desempenho. ([2] [3] [4] [5]) - Falha ao criar o descritor de segurança [3] \ [4], erro do sistema: [2] - Falha ao definir o descritor de segurança sobre o objeto [3], erro do sistema: [2] - Objeto Desconhecido Tipo [3], erro do sistema: [2] - Houve uma falha ao configurar arquivos XML. - Falha ao abrir o arquivo XML [3], erro do sistema: [2] - Falha ao localizar nó: [3] no arquivo XML: [4], erro do sistema: [2] - Falha ao salvar as alterações para o arquivo XML [3], erro do sistema: [2] - Houve uma falha ao configurar arquivos XML. - Falha ao abrir o arquivo XML [3], erro do sistema: [2] - Falha ao localizar nó: [3] no arquivo XML: [4], erro do sistema: [2] - Falha ao salvar as alterações para o arquivo XML [3], erro do sistema: [2] - diff --git a/src/wixlib/util.v3.ncrunchproject b/src/wixlib/util.v3.ncrunchproject deleted file mode 100644 index 319cd523..00000000 --- a/src/wixlib/util.v3.ncrunchproject +++ /dev/null @@ -1,5 +0,0 @@ - - - True - - \ No newline at end of file diff --git a/src/wixlib/util.wixproj b/src/wixlib/util.wixproj deleted file mode 100644 index 99dede7d..00000000 --- a/src/wixlib/util.wixproj +++ /dev/null @@ -1,27 +0,0 @@ - - - - - Library - true - - - - - - - - - - - - - - - - - - - - - -- cgit v1.2.3-55-g6feb