From 17b965bfe9a9a4e57fb1db914b45ef66eb3e4e22 Mon Sep 17 00:00:00 2001 From: Raul Metsma Date: Mon, 26 May 2025 10:52:16 +0300 Subject: [PATCH] Add exists option to ProductSearchResult for matching other search types (e.g. FileSearch, DirectorySearch, RegistrySearch) Signed-off-by: Raul Metsma --- .../Symbols/WixProductSearchSymbol.cs | 1 + src/burn/engine/search.cpp | 13 +++++++++++++ src/burn/engine/search.h | 1 + src/burn/test/BurnUnitTest/SearchTest.cpp | 4 ++++ src/ext/Util/wixext/UtilCompiler.cs | 5 ++++- .../WixToolset.Core.Burn/Bind/LegacySearchFacade.cs | 3 +++ src/xsd/util.xsd | 5 +++++ 7 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/api/wix/WixToolset.Data/Symbols/WixProductSearchSymbol.cs b/src/api/wix/WixToolset.Data/Symbols/WixProductSearchSymbol.cs index 99360da59..38f2af889 100644 --- a/src/api/wix/WixToolset.Data/Symbols/WixProductSearchSymbol.cs +++ b/src/api/wix/WixToolset.Data/Symbols/WixProductSearchSymbol.cs @@ -46,6 +46,7 @@ public enum WixProductSearchType Language, State, Assignment, + Exists, } public class WixProductSearchSymbol : IntermediateSymbol diff --git a/src/burn/engine/search.cpp b/src/burn/engine/search.cpp index a1b6b74af..8ebf128ea 100644 --- a/src/burn/engine/search.cpp +++ b/src/burn/engine/search.cpp @@ -334,6 +334,10 @@ extern "C" HRESULT SearchesParseFromXml( { pSearch->MsiProductSearch.Type = BURN_MSI_PRODUCT_SEARCH_TYPE_ASSIGNMENT; } + else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"exists", -1)) + { + pSearch->MsiProductSearch.Type = BURN_MSI_PRODUCT_SEARCH_TYPE_EXISTS; + } else { ExitWithRootFailure(hr, E_INVALIDARG, "Invalid value for @Type: %ls", scz); @@ -1144,6 +1148,7 @@ static HRESULT MsiProductSearch( case BURN_MSI_PRODUCT_SEARCH_TYPE_LANGUAGE: wzProperty = INSTALLPROPERTY_LANGUAGE; break; + case BURN_MSI_PRODUCT_SEARCH_TYPE_EXISTS: __fallthrough; case BURN_MSI_PRODUCT_SEARCH_TYPE_STATE: wzProperty = INSTALLPROPERTY_PRODUCTSTATE; break; @@ -1218,6 +1223,7 @@ static HRESULT MsiProductSearch( case BURN_MSI_PRODUCT_SEARCH_TYPE_LANGUAGE: // is supposed to remain empty break; + case BURN_MSI_PRODUCT_SEARCH_TYPE_EXISTS: __fallthrough; case BURN_MSI_PRODUCT_SEARCH_TYPE_STATE: value.Type = BURN_VARIANT_TYPE_NUMERIC; value.llValue = INSTALLSTATE_ABSENT; @@ -1237,6 +1243,7 @@ static HRESULT MsiProductSearch( case BURN_MSI_PRODUCT_SEARCH_TYPE_LANGUAGE: type = BURN_VARIANT_TYPE_STRING; break; + case BURN_MSI_PRODUCT_SEARCH_TYPE_EXISTS: __fallthrough; case BURN_MSI_PRODUCT_SEARCH_TYPE_STATE: __fallthrough; case BURN_MSI_PRODUCT_SEARCH_TYPE_ASSIGNMENT: type = BURN_VARIANT_TYPE_NUMERIC; @@ -1245,6 +1252,12 @@ static HRESULT MsiProductSearch( hr = BVariantChangeType(&value, type); ExitOnFailure(hr, "Failed to change value type."); + // Alter value here after value has changed to numberic type. + if (BURN_MSI_PRODUCT_SEARCH_TYPE_EXISTS == pSearch->MsiProductSearch.Type) + { + value.llValue = (value.llValue == INSTALLSTATE_ABSENT) ? 0 : 1; + } + // Set variable. hr = VariableSetVariant(pVariables, pSearch->sczVariable, &value); ExitOnFailure(hr, "Failed to set variable."); diff --git a/src/burn/engine/search.h b/src/burn/engine/search.h index 341fe1aa9..e70645c59 100644 --- a/src/burn/engine/search.h +++ b/src/burn/engine/search.h @@ -58,6 +58,7 @@ enum BURN_MSI_PRODUCT_SEARCH_TYPE BURN_MSI_PRODUCT_SEARCH_TYPE_LANGUAGE, BURN_MSI_PRODUCT_SEARCH_TYPE_STATE, BURN_MSI_PRODUCT_SEARCH_TYPE_ASSIGNMENT, + BURN_MSI_PRODUCT_SEARCH_TYPE_EXISTS, }; enum BURN_MSI_PRODUCT_SEARCH_GUID_TYPE diff --git a/src/burn/test/BurnUnitTest/SearchTest.cpp b/src/burn/test/BurnUnitTest/SearchTest.cpp index a8e397c22..e3c714cb4 100644 --- a/src/burn/test/BurnUnitTest/SearchTest.cpp +++ b/src/burn/test/BurnUnitTest/SearchTest.cpp @@ -410,6 +410,8 @@ namespace Bootstrapper L" " L" " L" " + L" " + L" " L""; // load XML document @@ -429,6 +431,8 @@ namespace Bootstrapper Assert::Equal(5ll, VariableGetNumericHelper(&variables, L"Variable4")); Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable5")); Assert::Equal(gcnew String(L"1.0.0.0"), VariableGetVersionHelper(&variables, L"Variable6")); + Assert::Equal(1ll, VariableGetNumericHelper(&variables, L"Variable7")); + Assert::Equal(0ll, VariableGetNumericHelper(&variables, L"Variable8")); } finally { diff --git a/src/ext/Util/wixext/UtilCompiler.cs b/src/ext/Util/wixext/UtilCompiler.cs index 1ad273221..919cc49b2 100644 --- a/src/ext/Util/wixext/UtilCompiler.cs +++ b/src/ext/Util/wixext/UtilCompiler.cs @@ -2736,8 +2736,11 @@ private void ParseProductSearchElement(Intermediate intermediate, IntermediateSe case "assignment": type = WixProductSearchType.Assignment; break; + case "exists": + type = WixProductSearchType.Exists; + break; default: - this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, result, "version", "language", "state", "assignment")); + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, result, "version", "language", "state", "assignment", "exists")); break; } break; diff --git a/src/wix/WixToolset.Core.Burn/Bind/LegacySearchFacade.cs b/src/wix/WixToolset.Core.Burn/Bind/LegacySearchFacade.cs index c9301fdc4..885f307e5 100644 --- a/src/wix/WixToolset.Core.Burn/Bind/LegacySearchFacade.cs +++ b/src/wix/WixToolset.Core.Burn/Bind/LegacySearchFacade.cs @@ -135,6 +135,9 @@ private void WriteProductSearchXml(XmlTextWriter writer, WixProductSearchSymbol case WixProductSearchType.Assignment: writer.WriteAttributeString("Type", "assignment"); break; + case WixProductSearchType.Exists: + writer.WriteAttributeString("Type", "exists"); + break; default: throw new NotImplementedException(); } diff --git a/src/xsd/util.xsd b/src/xsd/util.xsd index c0a9e44ae..ef3047621 100644 --- a/src/xsd/util.xsd +++ b/src/xsd/util.xsd @@ -1344,6 +1344,11 @@ Saves the version of a matching product if found; 0.0.0.0 otherwise. This is the default. + + + Saves true if a matching product entry is found; false otherwise. + +