264 votes

Trucs et astuces WiX

Nous utilisons WiX depuis un certain temps maintenant, et malgré les critiques habituelles sur la facilité d'utilisation, cela se passe plutôt bien. Ce que je recherche, ce sont des conseils utiles concernant.. :

  • Mise en place d'un projet WiX (mise en page, références, modèles de fichiers)
  • Intégration de WiX dans les solutions et les processus de construction/réalisation.
  • Configuration des installateurs pour les nouvelles installations et les mises à niveau
  • Vous avez de bonnes astuces WiX à partager ?

157voto

Si. Points 10543
  1. Conservez les variables dans un wxi fichier d'inclusion. Permet la réutilisation, les variables sont plus rapides à trouver et (si nécessaire) permet une manipulation plus facile par un outil externe.

  2. Définir les variables de plate-forme pour les constructions x86 et x64

    <!-- Product name as you want it to appear in Add/Remove Programs-->
    <?if $(var.Platform) = x64 ?>
      <?define ProductName = "Product Name (64 bit)" ?>
      <?define Win64 = "yes" ?>
      <?define PlatformProgramFilesFolder = "ProgramFiles64Folder" ?>
    <?else ?>
      <?define ProductName = "Product Name" ?>
      <?define Win64 = "no" ?>
      <?define PlatformProgramFilesFolder = "ProgramFilesFolder" ?>
    <?endif ?>
  3. Stocke l'emplacement d'installation dans le registre, permettant aux mises à jour de trouver l'emplacement correct. Par exemple, si un utilisateur définit un répertoire d'installation personnalisé.

     <Property Id="INSTALLLOCATION">
        <RegistrySearch Id="RegistrySearch" Type="raw" Root="HKLM" Win64="$(var.Win64)"
                  Key="Software\Company\Product" Name="InstallLocation" />
     </Property>

    Note : WiX guru Rob Mensching a publié un excellent article de blog qui va plus en détail et corrige un cas limite lorsque les propriétés sont définies à partir de la ligne de commande.

    Exemples utilisant 1. 2. et 3.

    <?include $(sys.CURRENTDIR)\Config.wxi?>
    <Product ... >
      <Package InstallerVersion="200" InstallPrivileges="elevated"
               InstallScope="perMachine" Platform="$(var.Platform)"
               Compressed="yes" Description="$(var.ProductName)" />

    et

    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="$(var.PlatformProgramFilesFolder)">
        <Directory Id="INSTALLLOCATION" Name="$(var.InstallName)">
  4. L'approche la plus simple est toujours de faire améliorations importantes car il permet à la fois les nouvelles installations et les mises à niveau dans un seul MSI. Code de mise à niveau est fixé à un Guid unique et ne changera jamais, sauf si nous ne voulons pas mettre à jour le produit existant.

    Note : Dans WiX 3.5 il y a une nouvelle MajorUpgrade élément qui permet la vie encore plus facile !

  5. Création d'une icône dans Ajout/Suppression de programmes

    <Icon Id="Company.ico" SourceFile="..\Tools\Company\Images\Company.ico" />
    <Property Id="ARPPRODUCTICON" Value="Company.ico" />
    <Property Id="ARPHELPLINK" Value="http://www.example.com/" />
  6. Lors de la construction d'une version, nous versions nos installateurs, en copiant le fichier msi dans un répertoire de déploiement. Un exemple de ceci en utilisant une cible wixproj appelée depuis la cible AfterBuild :

    <Target Name="CopyToDeploy" Condition="'$(Configuration)' == 'Release'">
      <!-- Note we append AssemblyFileVersion, changing MSI file name only works with Major Upgrades -->
      <Copy SourceFiles="$(OutputPath)$(OutputName).msi" 
            DestinationFiles="..\Deploy\Setup\$(OutputName) $(AssemblyFileVersion)_$(Platform).msi" />
    </Target>
  7. Utilisez heat pour récolter des fichiers avec des jokers (*) Guid. Utile si vous souhaitez réutiliser les fichiers WXS sur plusieurs projets (voir ma réponse sur les versions multiples d'un même produit). Par exemple, ce fichier batch récolte automatiquement la sortie de RoboHelp.

    @echo off  
    robocopy ..\WebHelp "%TEMP%\WebHelpTemp\WebHelp" /E /NP /PURGE /XD .svn  
    "%WIX%bin\heat" dir "%TEMP%\WebHelp" -nologo -sfrag -suid -ag -srd -dir WebHelp -out WebHelp.wxs -cg WebHelpComponent -dr INSTALLLOCATION -var var.WebDeploySourceDir 

    Il y a un peu de choses qui se passent, robocopy supprime les métadonnées de la copie de travail de Subversion avant le moissonnage. -dr La référence au répertoire racine est fixée à notre emplacement d'installation plutôt qu'au TARGETDIR par défaut ; -var est utilisé pour créer une variable permettant de spécifier le répertoire source (sortie du déploiement web).

  8. Une façon simple d'inclure la version du produit dans le titre du dialogue de bienvenue en utilisant Strings.wxl pour la localisation. (Crédit : saschabeaumont . Ajouté car ce bon conseil est caché dans un commentaire)

    <WixLocalization Culture="en-US" xmlns="http://schemas.microsoft.com/wix/2006/localization">
        <String Id="WelcomeDlgTitle">{\WixUI_Font_Bigger}Welcome to the [ProductName] [ProductVersion] Setup Wizard</String>
    </WixLocalization>
  9. Epargnez-vous de la peine et suivez Le conseil de Wim Coehen d'un composant par fichier. Cela vous permet également de ne pas tenir compte (ou d'utiliser le joker * ) le GUID du composant .

  10. Rob Mensching a un Une manière ordonnée pour retrouver rapidement les problèmes dans les fichiers journaux MSI en recherchant les éléments suivants value 3 . Notez les commentaires concernant l'internationalisation.

  11. Lorsque vous ajoutez des fonctionnalités conditionnelles, il est plus intuitif de définir le niveau de fonctionnalité par défaut sur 0 (désactivé), puis de définir le niveau de condition sur la valeur souhaitée. Si vous définissez le niveau de la fonction par défaut >= 1, le niveau de la condition doit être égal à 0 pour la désactiver, ce qui signifie que la logique de la condition doit être à l'opposé de ce à quoi vous vous attendez, ce qui peut être déroutant :)

    <Feature Id="NewInstallFeature" Level="0" Description="New installation feature" Absent="allow">
      <Condition Level="1">NOT UPGRADEFOUND</Condition>
    </Feature>
    <Feature Id="UpgradeFeature" Level="0" Description="Upgrade feature" Absent="allow">
      <Condition Level="1">UPGRADEFOUND</Condition>
    </Feature>

38voto

Simon Steele Points 8344

Vérifier si IIS est installé :

<Property Id="IIS_MAJOR_VERSION">
    <RegistrySearch Id="CheckIISVersion" Root="HKLM" Key="SOFTWARE\Microsoft\InetStp" Name="MajorVersion" Type="raw" />
</Property>

<Condition Message="IIS must be installed">
    Installed OR IIS_MAJOR_VERSION
</Condition>

Vérifier si la compatibilité de la base de données IIS 6 est installée sur Vista+ :

<Property Id="IIS_METABASE_COMPAT">
    <RegistrySearch Id="CheckIISMetabase" Root="HKLM" Key="SOFTWARE\Microsoft\InetStp\Components" Name="ADSICompatibility" Type="raw" />
</Property>

<Condition Message="IIS 6 Metabase Compatibility feature must be installed">
    Installed OR ((VersionNT &lt; 600) OR IIS_METABASE_COMPAT)
</Condition>

34voto

Cheeso Points 87022

Gardez tous les ID dans des espaces de noms séparés

  • Les fonctionnalités commencent par F. Exemples : F.Documentation, F.Binaries, F.SampleCode.
  • Les composants commencent par C. Ex : C.ChmFile, C.ReleaseNotes, C.LicenseFile, C.IniFile, C.Registry
  • Les CustomActions sont CA. Ex : CA.LaunchHelp, CA.UpdateReadyDlg, CA.SetPropertyX
  • Les fichiers sont Fi.
  • Les annuaires sont Di.
  • et ainsi de suite.

Je trouve que cela aide énormément à garder la trace de tous les différents identifiants dans toutes les différentes catégories.

25voto

Peter Tate Points 1694

Question fantastique. J'adorerais voir des exemples de meilleures pratiques.

J'ai beaucoup de fichiers que je distribue, j'ai donc configuré mon projet en plusieurs fichiers sources wxs.

J'ai un fichier source de premier niveau que j'appelle Product.wxs et qui contient essentiellement la structure de l'installation, mais pas les composants réels. Ce fichier comporte plusieurs sections :

<Product ...>
  <Package ...>
    <Media>... 
   <Condition>s ...
   <Upgrade ..>
   <Directory> 
        ...
   </Directory>
   <Feature>
      <ComponentGroupRef ... > A bunch of these that
   </Feature>
   <UI ...>
   <Property...>
   <Custom Actions...>
   <Install Sequences....
  </Package>
</Product>

Le reste des fichiers .wix est composé de fragments qui contiennent des ComponentGroups référencés dans la balise Feature du Product.wxs. Mon projet contient un regroupement logique des fichiers que je distribue.

<Fragment>
   <ComponentGroup>
     <ComponentRef>
     ....
    </ComponentGroup>
    <DirectoryRef>
      <Component... for each file
      .... 
    </DirectoryRef>
</Fragment>

Ce n'est pas parfait, mon sens de l'araignée OO me titille un peu parce que les fragments doivent faire référence à des noms dans le fichier Product.wxs (par exemple le DirectoryRef) mais je trouve cela plus facile à maintenir qu'un seul gros fichier source.

J'aimerais avoir des commentaires à ce sujet, ou si quelqu'un a de bons conseils à donner !

20voto

Cheeso Points 87022

Ajoutez une case à cocher dans la boîte de dialogue de sortie pour lancer l'application ou le fichier d'aide.

...

<!-- CA to launch the exe after install -->
<CustomAction Id          ="CA.StartAppOnExit"
              FileKey     ="YourAppExeId"
              ExeCommand  =""
              Execute     ="immediate"
              Impersonate ="yes"
              Return      ="asyncNoWait" />

<!-- CA to launch the help file -->
<CustomAction Id         ="CA.LaunchHelp"
              Directory  ="INSTALLDIR"
              ExeCommand ='[WindowsFolder]hh.exe IirfGuide.chm'
              Execute    ="immediate"
              Return     ="asyncNoWait" />

<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT"
          Value="Launch MyApp when setup exits." />

<UI>
  <Publish Dialog  ="ExitDialog"
           Control ="Finish"
           Order   ="1"
           Event   ="DoAction"
           Value   ="CA.StartAppOnExit">WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT</Publish>
</UI>

Si vous procédez de cette manière, l'apparence "standard" n'est pas tout à fait correcte. La case à cocher a toujours un fond gris, alors que la boîte de dialogue est blanche :

alt text

Une façon de contourner ce problème est de spécifier votre propre ExitDialog personnalisé, avec une case à cocher située à un endroit différent. . Cela fonctionne, mais cela semble être beaucoup de travail juste pour changer la couleur d'un contrôle. Une autre façon de résoudre le même problème consiste à post-traiter la MSI générée pour modifier les champs X et Y dans la table des contrôles pour ce contrôle CheckBox particulier. Le code javascript ressemble à ceci :

var msiOpenDatabaseModeTransact = 1;
var filespec = WScript.Arguments(0);
var installer = new ActiveXObject("WindowsInstaller.Installer");
var database = installer.OpenDatabase(filespec, msiOpenDatabaseModeTransact);
var sql = "UPDATE `Control` SET `Control`.`Height` = '18', `Control`.`Width` = '170'," +
          " `Control`.`Y`='243', `Control`.`X`='10' " +
          "WHERE `Control`.`Dialog_`='ExitDialog' AND " + 
          "  `Control`.`Control`='OptionalCheckBox'";
var view = database.OpenView(sql);
view.Execute();
view.Close();
database.Commit();

L'exécution de ce code en tant que ligne de commande script (à l'aide de cscript.exe) après la génération du MSI (à partir de light.exe) produira un ExitDialog d'aspect plus professionnel :

alt text

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X