3

I need to optionally pass a Bundle command line argument to an MSI. That is, if its specified on the Bundle command line, pass the value to the MSI, otherwise leave it set to the default DEFINED IN THE MSI.

In order to pass a Property to an MSI you need to use this:

<MsiProperty Name='PUBLICPROPERTY' Value='[BundleParameter]'/>

And to declare a bundle variable you need this:

<Variable Name="BundleParameter" bal:Overridable="yes" Type="string" Value="SomeValue"/>   

The result is that the PUBLICPROPERTY is ALWAYS set to a value. Either the default value of "SomeValue" or a value passed on the bundle command line.

How can you conditionally pass the MsiProperty?

RobG
  • 744
  • 6
  • 16

3 Answers3

1

I checked WiX Github and looks like this is not possible today. Once you define a MsiProperty in BURN, the value gets set and passed to the MSI regardless of whether the value is empty or not. Here is a snapshot of the code:

extern "C" HRESULT MsiEngineParsePropertiesFromXml(
    __in IXMLDOMNode* pixnPackage,
    __out BURN_MSIPROPERTY** prgProperties,
    __out DWORD* pcProperties
    )
{
    HRESULT hr = S_OK;
    IXMLDOMNodeList* pixnNodes = NULL;
    IXMLDOMNode* pixnNode = NULL;
    DWORD cNodes = 0;

    BURN_MSIPROPERTY* pProperties = NULL;

    // select property nodes
    hr = XmlSelectNodes(pixnPackage, L"MsiProperty", &pixnNodes);
    ExitOnFailure(hr, "Failed to select property nodes.");

    // get property node count
    hr = pixnNodes->get_length((long*)&cNodes);
    ExitOnFailure(hr, "Failed to get property node count.");

    if (cNodes)
    {
        // allocate memory for properties
        pProperties = (BURN_MSIPROPERTY*)MemAlloc(sizeof(BURN_MSIPROPERTY) * cNodes, TRUE);
        ExitOnNull(pProperties, hr, E_OUTOFMEMORY, "Failed to allocate memory for MSI property structs.");

        // parse property elements
        for (DWORD i = 0; i < cNodes; ++i)
        {
            BURN_MSIPROPERTY* pProperty = &pProperties[i];

            hr = XmlNextElement(pixnNodes, &pixnNode, NULL);
            ExitOnFailure(hr, "Failed to get next node.");

            // @Id
            hr = XmlGetAttributeEx(pixnNode, L"Id", &pProperty->sczId);
            ExitOnFailure(hr, "Failed to get @Id.");

            // @Value
            hr = XmlGetAttributeEx(pixnNode, L"Value", &pProperty->sczValue);
            ExitOnFailure(hr, "Failed to get @Value.");

            // @RollbackValue
            hr = XmlGetAttributeEx(pixnNode, L"RollbackValue", &pProperty->sczRollbackValue);
            if (E_NOTFOUND != hr)
            {
                ExitOnFailure(hr, "Failed to get @RollbackValue.");
            }

            // prepare next iteration
            ReleaseNullObject(pixnNode);
        }
    }

Looks like this will be a new feature in WiX4.0 as mentioned HERE

Now that being said, if you are the author of that MSI then you can check the Property value within your MSI (.wxs) file and set it to a different value if it comes up "empty" by using SetProperty.

Isaiah4110
  • 9,855
  • 1
  • 40
  • 56
0

I don't know, if there is better option, but you can add 2 MsiPackages to chain, whose will install same package, but one with MsiProperty and other without MsiProperty defined. Advantage of this aproach is that you can set InstallCondition on MsiPackage but cannot on MsiProperty.

Mischo5500
  • 796
  • 6
  • 14
0

Maybe you could make two entries for MsiPackage in the burn bundle, each with opposite install conditions. I.e. if property is filled in, then run one, otherwise, run the other one? A bit hacky, but I don't know of any other way. Not sure how this will impact the uninstall portion.