<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
  <?define Copyright = '$(var.ProductOriginalVersionString) Copyright $(var.ProductBuildYear) $(var.CompanyFullName)'?>
  <?define UpdateKeyPath = 'SOFTWARE\$(var.CompanyName)\Update'?>
  <?define InstallCommandBase='--silent --install="[ProductTag]" --installsource=enterprisemsi[OptOmahaArgs]'?>

  <Package
    Name="$(var.ProductName)"
    Language="1033"
    Codepage="1252"
    UpgradeCode="$(var.MsiUpgradeCode)"
    Version="$(var.ProductVersion)"
    Manufacturer="$(var.CompanyFullName)"
    InstallerVersion="200"
    ProductCode="$(var.MsiProductId)"
    Scope="perMachine">
    <SummaryInformation
      Description="$(var.ProductName) Installer"
      Comments='$(var.Copyright)'
      Manufacturer="$(var.CompanyFullName)"
    />

    <Upgrade Id="$(var.MsiUpgradeCode)">
      <!-- Allow same-version repair. -->
      <UpgradeVersion
        Property="UPGRADEFOUND"
        OnlyDetect="no"
        Minimum="0.0.0.0"
        IncludeMinimum="yes"
        Maximum="$(var.ProductVersion)"
        IncludeMaximum="yes"
      />

      <!-- Allow downgrade. -->
      <UpgradeVersion
        Property="NEWPRODUCTFOUND"
        OnlyDetect="no"
        Minimum="$(var.ProductVersion)"
        IncludeMinimum="no"
      />
    </Upgrade>

    <?ifdef ProductIcon ?>
      <!-- If var.ProductIcon is defined, use that as an icon in the ARP
           dialog, otherwise rely on the ARP dialog's heuristics:
           https://devblogs.microsoft.com/oldnewthing/20040709-00/?p=38493 -->
      <Icon Id="icon.ico" SourceFile="$(var.ProductIcon)"/>
      <Property Id="ARPPRODUCTICON" Value="icon.ico"/>
    <?endif?>

    <!-- ARPNOMODIFY does two things:
         1) Removes the 'Modify' button from the ARP dialog.
         2) Causes the 'Remove' command to invoke msiexec /X instead of /I
            (the intent being that WITH a Modify button, clicking either
            Modify or Remove command will launch your installer UI). -->
    <Property Id="ARPNOMODIFY" Value="1" />

    <!-- Find the uninstall string to be used for the product. Only used for
         uninstallation. -->
    <Property Id="UNINSTALLCMDLINE">
      <RegistrySearch
        Id="UninstallCmdSearch"
        Root="HKLM"
        Type="raw"
        Key="$(var.UpdateKeyPath)\ClientState\$(var.ProductGuid)"
        Name="UninstallString"
        Bitness="always32"
      />
    </Property>
    <Property Id="UNINSTALLCMDARGS">
      <RegistrySearch
        Id="UninstallArgSearch"
        Root="HKLM"
        Type="raw"
        Key="$(var.UpdateKeyPath)\ClientState\$(var.ProductGuid)"
        Name="UninstallArguments"
        Bitness="always32"
      />
    </Property>
    <Property Id="AllowDowngradeSubstitution" Value="false" />

    <!-- Allows running the `updater` with a `force-install` option. This
         force-installs the installer that is run with this switch and makes it
         the active `updater`. In addition, if the MSI is tagged, this also
         installs the application(s) that are implicitly specified in the tag.
    -->
    <Property Id="RUNFORCEINSTALL" Secure="yes" />

    <!-- Eliminates "warning LGHT1076 : ICE71: The Media table has no entries." -->
    <Media Id="1" />

    <Feature Id="Complete" Level="1" AllowAbsent="yes">
      <ComponentRef Id="ProductClientState" />
    </Feature>

    <Binary Id="$(var.ProductNameLegalIdentifier)Installer" SourceFile="$(var.StandaloneInstallerPath)" />

    <Binary Id="MsiInstallerCustomActionDll" SourceFile="$(var.MsiInstallerCADll)" />

    <CustomAction Id="NewerVersionError" Error="A newer version of the $(var.ProductName) enterprise installer is already installed." />

    <!-- Custom actions to build the ProductTag property. -->
    <CustomAction
      Id="SetProductTagProperty"
      Property="ProductTag"
      Value="appguid=$(var.ProductGuid)&amp;appname=$(var.ProductName)&amp;needsAdmin=True"
      Execute="immediate"
      Return="check"
    />
    <CustomAction
      Id="AppendCustomParamsToProductTagProperty"
      Property="ProductTag"
      Value="[ProductTag]$(var.ProductCustomParams)"
      Execute="immediate"
      Return="check"
    />
    <CustomAction
      Id="TaggedMSIOverrideProductTagProperty"
      Property="ProductTag"
      Value="[TAGSTRING]"
      Execute="immediate"
      Return="check"
    />

    <CustomAction
      Id="SetOptArgsProperty"
      Property="OptOmahaArgs"
      Value=""
      Execute="immediate"
      Return="check"
    />
    <CustomAction
      Id="AppendForceInstallToOptArgsProperty"
      Property="OptOmahaArgs"
      Value="[OptOmahaArgs] --force-install"
      Execute="immediate"
      Return="check"
    />
    <CustomAction
      Id="AppendEnterpriseToOptArgsProperty"
      Property="OptOmahaArgs"
      Value="[OptOmahaArgs] --enterprise"
      Execute="immediate"
      Return="check"
    />

    <?ifdef ProductInstallerData ?>
      <CustomAction
        Id="BuildInstallCommand"
        Property="InstallCommand"
        Value="$(var.InstallCommandBase) --appargs=&quot;appguid=$(var.ProductGuid)&amp;installerdata=$(var.ProductInstallerData)&quot;"
        Execute="immediate"
        Return="check"
      />
    <?else?>
      <CustomAction
        Id="BuildInstallCommand"
        Property="InstallCommand"
        Value="$(var.InstallCommandBase)"
        Execute="immediate"
        Return="check"
      />
    <?endif?>

    <!-- Send the ProductGuid to the ShowInstallerResultUIString custom action.
         The value is accessed through the "CustomActionData" property from
         within the action itself. -->
    <CustomAction
      Id="SetAppGuidProperty"
      Property="ShowInstallerResultUIString"
      Value="$(var.ProductGuid)"
    />

    <!-- A custom action to be executed on rollback to log and display the
         LastInstallerResultUIString. -->
    <CustomAction
      Id="ShowInstallerResultUIString"
      DllEntry="ShowInstallerResultUIString"
      Execute="rollback"
      Impersonate="no"
      BinaryRef="MsiInstallerCustomActionDll"
    />

    <!-- A custom action to be executed to extract tag information from the MSI
         package. -->
    <CustomAction
      Id="ExtractTagInfoFromInstaller"
      DllEntry="ExtractTagInfoFromInstaller"
      Execute="immediate"
      Impersonate="no"
      BinaryRef="MsiInstallerCustomActionDll"
    />

    <CustomAction
      Id="DoInstall"
      Impersonate="no"
      Execute="deferred"
      ExeCommand="[InstallCommand]"
      Return="check"
      BinaryRef="$(var.ProductNameLegalIdentifier)Installer"
    />
    <CustomAction
      Id="CallUninstaller.SetProperty"
      Property="UninstallCmd"
      Value="[UNINSTALLCMDLINE]"
      Execute="immediate"
      Return="check"
    />
    <CustomAction
      Id="CallUninstallerArgs.SetProperty"
      Property="UninstallCmdArgs"
      Value="[UNINSTALLCMDARGS]"
      Execute="immediate"
      Return="check"
    />
    <CustomAction
      Id="CallUninstaller"
      Property="UninstallCmd"
      ExeCommand="[UninstallCmdArgs] $(var.ProductUninstallerAdditionalArgs)"
      Impersonate="no"
      Execute="deferred"
      Return="check"
    />

    <!-- Set [AllowDowngradeSubstitution] to true for downgrades. -->
    <CustomAction
      Id="DoAllowDowngradeSubstitution"
      Property="AllowDowngradeSubstitution"
      Value="true"
      Execute="immediate"
      Return="check"
    />

    <InstallExecuteSequence>
      <RemoveExistingProducts After="InstallValidate" />

      <Custom Action="NewerVersionError"
        After="FindRelatedProducts"
        Condition="((RUNFORCEINSTALL = &quot;&quot;) AND NEWPRODUCTFOUND AND (ALLOWDOWNGRADE = &quot;&quot;))"
      />

      <!-- The conditions in the following custom actions trigger the action when either:
           1) This is a fresh installation, i.e.,
              "(?ProductClientState = INSTALLSTATE_ABSENT) AND ($ProductClientState = INSTALLSTATE_LOCAL)".
           OR
           2) This is an overinstall, i.e., "((?ProductClientState = INSTALLSTATE_LOCAL) AND REINSTALL)".
           `?`: is used to query whether component `ProductClientState` is currently installed.
           `$`: is used to query whether component `ProductClientState` is being installed with this MSI.
           Reference: https://learn.microsoft.com/en-us/windows/win32/msi/conditional-statement-syntax.
      -->
      <!-- Build tag property. -->
      <!-- First, read the tag from the .msi. -->
      <Custom
        Action="ExtractTagInfoFromInstaller"
        Before="SetProductTagProperty"
        Condition="((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL)"
      />
      <!-- Now start forming [ProdutTag], first with the appguid and name. -->
      <Custom
        Action="SetProductTagProperty"
        Before="AppendCustomParamsToProductTagProperty"
        Condition="((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL)"
      />
      <!-- Add on the build-time string. -->
      <Custom
        Action="AppendCustomParamsToProductTagProperty"
        Before="TaggedMSIOverrideProductTagProperty"
        Condition="((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL)"
      />
      <!-- Override the tag completely if the MSI is tagged, or if the caller
           has set the `TAGSTRING` property. Among all actions that change
           `ProductTag`, this action must be the last one before
           `BuildInstallCommand`, since this one overrides all previous
           values.-->
      <Custom
        Action="TaggedMSIOverrideProductTagProperty"
        Before="BuildInstallCommand"
        Condition="(((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL)) AND (TAGSTRING &lt;&gt; &quot;&quot;)"
      />
      <Custom
        Action="SetOptArgsProperty"
        Before="AppendForceInstallToOptArgsProperty"
        Condition="((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL)"
      />
      <Custom
        Action="AppendForceInstallToOptArgsProperty"
        Before="AppendEnterpriseToOptArgsProperty"
        Condition="(((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL)) AND (RUNFORCEINSTALL &lt;&gt; &quot;&quot;)"
      />
      <Custom
        Action="AppendEnterpriseToOptArgsProperty"
        Before="BuildInstallCommand"
        Condition="(((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL)) AND (NOGOOGLEUPDATEPING &lt;&gt; &quot;&quot;)"
      />

      <!-- Set [AllowDowngradeSubstitution] to true if downgrades are allowed. -->
      <Custom
        Action="DoAllowDowngradeSubstitution"
        Before="BuildInstallCommand"
        Condition="(((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL)) AND (ALLOWDOWNGRADE &lt;&gt; &quot;&quot;)"
      />

      <Custom
        Action="BuildInstallCommand"
        Before="SetAppGuidProperty"
        Condition="((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL)"
      />
      <Custom
        Action="SetAppGuidProperty"
        Before="ShowInstallerResultUIString"
        Condition="((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL)"
      />
      <Custom
        Action="ShowInstallerResultUIString"
        Before="DoInstall"
        Condition="((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL)"
      />

      <Custom
        Action="DoInstall"
        After="InstallFiles"
        Condition="((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL)"
      />

      <!-- The conditions in the following custom actions trigger the action when the product is
           transitioning from present locally to absent only when not performing an upgrade or
           downgrade. -->
      <Custom
        Action="CallUninstallerArgs.SetProperty"
        Before="CallUninstaller.SetProperty"
        Condition="(?ProductClientState=3) AND ($ProductClientState=2) AND NOT UPGRADINGPRODUCTCODE"
      />
      <Custom
        Action="CallUninstaller.SetProperty"
        Before="CallUninstaller"
        Condition="(?ProductClientState=3) AND ($ProductClientState=2) AND NOT UPGRADINGPRODUCTCODE"
      />
      <Custom
        Action="CallUninstaller"
        Before="RemoveFiles"
        Condition="(?ProductClientState=3) AND ($ProductClientState=2) AND NOT UPGRADINGPRODUCTCODE"
      />
      <!-- Google Update will uninstall itself if the product is the only app it
           so no need to have an uninstall operation. -->
    </InstallExecuteSequence>

    <!-- Use the ProductCode as the ComponentId since we want the latter to
         change for each version change in support of major upgrades. -->
    <Component Id="ProductClientState" Guid="$(var.MsiProductId)" Directory="TARGETDIR" Bitness="always32">
      <!-- Clear the last UI string before running the installer so we know
           that any value present upon rollback is fresh. -->
      <RemoveRegistryValue
        Key="$(var.UpdateKeyPath)\ClientState\$(var.ProductGuid)"
        Name="LastInstallerResultUIString"
        Root="HKLM"
      />
      <RemoveRegistryValue
        Key="$(var.UpdateKeyPath)"
        Name="LastInstallerResultUIString"
        Root="HKLM"
      />
      <RegistryValue
        Id="NonEmptyComponent"
        Action="write"
        Root="HKLM"
        Key="$(var.UpdateKeyPath)\ClientState\$(var.ProductGuid)"
        KeyPath="yes"
        Name="EnterpriseProduct$(var.MsiProductId)"
        Type="string"
        Value="$(var.ProductVersion)"
      />
    </Component>
  </Package>
</Wix>
