Search code examples
wixburn

Hide Text based on RegistrySearch in WiX Bundle


Is it possible to use a RegistrySearch in WiX bundle to hide a Text in theme? I don't have a clue about where to start. In the code below, the InstalledDotNet4 variable doesn't set the Text in time to disabled and I can't find a way to disable the Text (or change its text content).

Bundle.wxs:

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
     xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"
     xmlns:bal="http://schemas.microsoft.com/wix/BalExtension">
  <Bundle Name="My App" Version="1.0.0.0"
          Manufacturer="ACME"
          UpgradeCode="d88faa97-2197-4154-9e77-32f9ca773bd4">

  <BootstrapperApplicationRef
    Id="WixExtendedBootstrapperApplication.HyperlinkLicense">

    <Payload SourceFile="Resources/background.png" Id="myLogo" />

  </BootstrapperApplicationRef>

  <WixVariable Id="WixExtbaLicenseUrl" Value="" />
  <WixVariable Id="WixExtbaThemeXml" Value="Resources\MyTheme.xml" />
  <WixVariable Id="WixExtbaThemeWxl" Value="Resources\MyTheme.wxl" />

  <util:RegistrySearch Root="HKCU"
                       Key="Software\AnythingToCheck"
                       Value="Test" Variable="InstalledDotNet4" />

  <Chain>
     <MsiPackage Id="dotNETv4" DisplayName="My .NET v4 prerequisite"
                 SourceFile="myApp.msi" 
                 Visible="yes" 
                 InstallCondition="CheckboxDotNetv4" />
  </Chain>
</Wix>

MyTheme.xml:

<?xml version="1.0" encoding="utf-8"?>
<Theme xmlns="http://wixtoolset.org/schemas/thmutil/2010">
  <!-- Window definition -->
  <!-- Font definition -->

  <Page Name="Install">
    <Checkbox Name="CheckboxDotNet4"
              X="205" Y="126"
              Width="-100" Height="17"
              TabStop="yes" FontId="3"
              HideWhenDisabled="yes">.NET Framework 4.0</Checkbox>
    <Text Name="InstalledDotNet4"
          X="-10" Y="126"
          Width="80" Height="17"
          TabStop="no" FontId="3"
          HideWhenDisabled="yes">(Installed)</Text>
  </Page>

  <!-- More pages -->
</Theme>

Additionally, I tried to use the following code in Bundle.wxs, but that is not linked to the RegistrySearch:

<Variable Name="InstalledDotNet4State" Type="string" Value="disable" />

Solution

  • Yes, after extensive research I found it is possible to hide the Text based on a RegistrySearch. First you need to download the WiX Extended Bootstrapper Application from http://wixextba.codeplex.com/. Extract the contents and add to your project the WixBalExtensionExt.dll as shown in Bundle10.wxs example.

    Then, open the project bafunctions under folder Template bafunctions. You will need to compile this C++ library and add it to your bundle as a Payload (use the Bundle10.wxs as example).

    Then, to be able to read and hide the Text control, uncomment function OnDetectComplete() and add the following code, for example:

    STDMETHODIMP OnDetectComplete()
    {
        HRESULT hr = S_OK;
        LPWSTR sczValue = NULL;
    
    #if DEBUG
        // Show log info during debug.
        // May not be THE way to log.
        size_t i; 
        LPSTR sczValue2 = (char *) malloc(100);
    #endif
    
        BalGetStringVariable(L"InstalledDotNet4Reg", &sczValue);
        BalExitOnFailure(hr, "Failed to get variable.");
    
        if (sczValue == NULL)
        {
            BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD,
                "Failed to read null variable.");
        }
        else
        {
            if (_wtoi(sczValue))
            {
                hr = m_pEngine->SetVariableString(L"CheckboxDotNetv4State",
                    L"disable");
                BalExitOnFailure(hr, "Failed to set control state.");
                hr = m_pEngine->SetVariableNumeric(L"CheckboxDotNetv4", 0);
                BalExitOnFailure(hr, "Failed to set variable.");
            }
            else
            {
    #if DEBUG
                // Log information
                wcstombs_s(&i, sczValue2, (size_t)100, sczValue, (size_t)100);
                BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, sczValue2);
    #endif
                hr = m_pEngine->SetVariableString(L"InstalledDotNet4State",
                    L"disable");
                BalExitOnFailure(hr, "Failed to set control state.");
                }
            }
    
    LExit:
        ReleaseStr(sczValue);
    
        return hr;
    }
    

    Finally, change (or add) your RegistrySearch, this way:

    <util:RegistrySearch Root="HKLM"
        Key="SOFTWARE\Classes\Installer\Products\FCDAC0A0AD874C333A05DC1548B97920"
        Variable="InstalledDotNet4Reg" Result="exists" />