[wix] WiX 트릭과 팁

우리는 한동안 WiX를 사용해 왔으며 사용의 용이성에 대한 일반적인 그립에도 불구하고 합리적으로 잘 진행되고 있습니다. 내가 찾고있는 것은 다음에 관한 유용한 조언입니다.

  • WiX 프로젝트 설정 (레이아웃, 참조, 파일 패턴)
  • WiX를 솔루션에 통합하고 프로세스를 빌드 / 릴리스
  • 새 설치 및 업그레이드를위한 설치 프로그램 구성
  • 공유하고 싶은 좋은 WiX 해킹


답변

  1. 변수를 별도의 wxi포함 파일 에 보관하십시오 . 재사용이 가능하고 변수를 더 빨리 찾을 수 있으며 필요한 경우 외부 도구로보다 쉽게 ​​조작 할 수 있습니다.

  2. x86 및 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. 설치 위치를 레지스트리에 저장하여 업그레이드를 통해 올바른 위치를 찾으십시오. 예를 들어, 사용자가 사용자 정의 설치 디렉토리를 설정 한 경우.

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

    참고 : WiX 전문가 인 Rob Mensching훌륭한 블로그 항목 을 게시 하여 명령 줄에서 속성을 설정할 때보다 자세하게 설명하고 엣지 케이스를 수정했습니다.

    1. 및 3.를 사용하는 예

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

    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="$(var.PlatformProgramFilesFolder)">
        <Directory Id="INSTALLLOCATION" Name="$(var.InstallName)">
  4. 가장 간단한 방법은 항상 대규모 업그레이드를 수행 하는 것입니다. 단일 MSI에서 새로 설치하고 업그레이드 할 수 있기 때문입니다. UpgradeCode 는 고유 한 Guid로 고정되어 있으며 기존 제품을 업그레이드하지 않으려는 경우가 아니면 변경되지 않습니다.

    참고 : WiX 3.5에는 새로운 MajorUpgrade 요소가있어 더욱 편리합니다 .

  5. 프로그램 추가 / 제거에서 아이콘 작성

    <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. 릴리스 빌드에서는 msi 파일을 배포 디렉토리에 복사하여 설치 프로그램 버전을 지정합니다. AfterBuild 대상에서 wixproj 대상을 사용하는 예는 다음과 같습니다.

    <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. 와일드 카드 (*) Guid를 사용하여 파일을 수확하려면 열을 사용하십시오. 여러 프로젝트에서 WXS 파일을 재사용하려는 경우 유용합니다 (동일한 제품의 여러 버전에 대한 답변 참조). 예를 들어이 배치 파일은 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 

    약간의 robocopy작업이 진행되고 있습니다 . 수확하기 전에 Subversion 작업 복사본 메타 데이터를 제거합니다. -dr루트 디렉토리 참조가 아닌 기본 TARGETDIR에 비해 우리의 설치 위치로 설정되고, -var소스 디렉토리를 지정하는 변수를 작성하는 데 사용됩니다 (웹 배치 출력).

  8. 현지화에 Strings.wxl을 사용하여 시작 대화 상자 제목에 제품 버전을 포함하는 쉬운 방법입니다. (크레딧 : saschabeaumont .이 위대한 팁이 댓글에 숨겨져 추가됨)

    <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. 고통을 덜고 파일 당 하나의 구성 요소에 대한 Wim Coehen의 조언 을 따르십시오 . 또한 구성 요소 GUID를 제외 (또는 와일드 카드 *) 할 수 있습니다 .

  10. Rob Mensching은 을 검색하여 MSI 로그 파일의 문제를 신속하게 추적 할 수 있는 깔끔한 방법 입니다 value 3. 국제화에 관한 의견에 유의하십시오.

  11. 조건부 기능을 추가 할 때 기본 기능 수준을 0 (비활성화)으로 설정 한 다음 조건 수준을 원하는 값으로 설정하는 것이 더 직관적입니다. 기본 기능 레벨> = 1을 설정하면 조건 레벨을 0으로 설정하여 사용하지 않도록 설정해야합니다. 이는 조건 로직이 예상 한 것과 반대이므로 혼동 될 수 있습니다.

    <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>

답변

IIS가 설치되어 있는지 확인

<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>

Vista 6에 IIS 6 메타베이스 호환성이 설치되어 있는지 확인

<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>


답변

모든 ID를 별도의 네임 스페이스에 유지

  • 기능은 F. 예 : F.Documentation, F.Binaries, F.SampleCode로 시작합니다.
  • 구성 요소는 C. Ex : C.ChmFile, C.ReleaseNotes, C.LicenseFile, C.IniFile, C.Registry로 시작합니다.
  • CustomActions는 CA. Ex : CA.LaunchHelp, CA.UpdateReadyDlg, CA.SetPropertyX입니다.
  • 파일은 Fi.
  • 디렉토리는 Di.
  • 등등.

나는 이것이 모든 다양한 범주의 모든 다양한 ID를 추적하는 데 크게 도움이된다는 것을 알았습니다.


답변

환상적인 질문. 모범 사례가 표시되는 것을보고 싶습니다.

배포 할 파일이 많으므로 프로젝트를 여러 개의 wx 소스 파일로 설정했습니다.

기본적으로 설치 구조는 포함하지만 실제 구성 요소는 포함하지 않는 Product.wxs라고하는 최상위 소스 파일이 있습니다. 이 파일에는 여러 섹션이 있습니다.

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

나머지 .wix 파일은 Product.wxs의 기능 태그에서 참조되는 구성 요소 그룹이 포함 된 조각으로 구성됩니다. 내 프로젝트에는 배포 한 파일의 논리적 그룹이 포함되어 있습니다.

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

조각이 Product.wxs 파일 (예 : DirectoryRef)에서 이름을 참조해야하기 때문에 OO 스파이더가 약간 이상해집니다.

이것에 대한 의견을 듣고 싶습니다. 누군가도 좋은 팁이 있다면!


답변

종료 대화 상자에 확인란을 추가하여 앱 또는 도움말 파일을 시작하십시오.

<!-- 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>

이렇게하면 “표준”모양이 옳지 않습니다. 확인란은 항상 회색 배경이며 대화 상자는 흰색입니다.

대체 텍스트 http://www.dizzymonkeydesign.com/blog/misc/adding-and-customizing-dlgs-in-wix-3/images/exit_dlg_1.gif

이 문제를 해결하는 한 가지 방법 은 다른 위치의 확인란사용하여 사용자 정의 ExitDialog지정하는 것입니다. 입니다. 이것은 작동하지만 하나의 컨트롤의 색상을 변경하는 것만으로도 많은 작업처럼 보입니다. 같은 문제를 해결하는 또 다른 방법은 생성 된 MSI를 사후 처리하여 특정 CheckBox 컨트롤에 대한 Control 테이블의 X, Y 필드를 변경하는 것입니다. 자바 스크립트 코드는 다음과 같습니다.

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();

light.exe에서 MSI가 생성 된 후이 스크립트를 명령 줄 스크립트 (cscript.exe 사용)로 실행하면보다 전문적인 ExitDialog가 생성됩니다.

대체 텍스트 http://www.dizzymonkeydesign.com/blog/misc/adding-and-customizing-dlgs-in-wix-3/images/exit_dlg_2.gif


답변

동일한 소스 파일을 사용하여 Live, Test, Training, … 버전 만들기

간단히 말해서 : 각 설치 프로그램에 대해 고유 한 UpgradeCode를 작성하고 각 설치 프로그램에 대해 각 Guid의 첫 번째 문자를 자동으로 정의하고 나머지 31 개는 고유하게 유지하십시오.

전제 조건

가정

  • WiX 변수는 UpgradeCode, ProductName, InstallName을 정의하는 데 사용됩니다.
  • 이미 작동중인 설치 프로그램이 있습니다. 당신이 할 때까지 나는 이것을 시도하지 않을 것입니다.
  • 모든 구성 요소는 하나의 파일 (Components.wxs)에 보관됩니다. 이 프로세스는 파일이 여러 개인 경우 작동하지만 더 많은 작업이 필요합니다.

디렉토리 구조

  • Setup.Library
    • 모든 wx 파일 (구성 요소, 기능, UI 대화 상자 등)
    • Common.Config.wxi (ProductCode = “*”, ProductVersion, PlatformProgramFilesFolder, …)
  • Setup.Live (wixproj)
    • “기존 파일 추가”-> “링크로 추가”(Visual Studio의 추가 버튼 옆에있는 작은 아래쪽 화살표 버튼)를 사용하여 모든 Setup.Library 파일을 연결합니다.
    • Config.wxi (고유 한 UpgradeCode, ProductName, InstallName 등이 있음)
  • 설정 테스트 , …
    • 라이브에 따라 Config.wxi가 테스트 환경에 대해 구성되어 있습니다.

방법

  • Setup.Library 디렉토리를 작성하고 기존 프로젝트에서 모든 wx 및 wxi 파일 (Config.wxi 제외)을 이동하십시오.
  • 일반적인 wixproj에 따라 Setup.Live, Setup.Test 등을 작성하십시오.
  • Setup.Live 등의 wixproj에 BeforeBuild 대상을 추가하여 MSBuild 커뮤니티 작업 파일 업데이트 수행 를 수정합니다 (A는 라이브, B는 테스트, C는 교육)
  • AfterBuild 대상을 추가하여 Components.wxs Guid를 다시 0으로 되돌립니다.
  • Orca에서 각 MSI의 각 구성 요소에 수정 된 guid가 있는지 확인하십시오.
  • 원래 guid가 복원되었는지 확인하십시오.
  • 각 MSI가 올바른 제품 및 위치를 설치 (및 업그레이드)하고 있는지 확인하십시오.

Config.wxi 예

<?xml version="1.0" encoding="utf-8"?>
<Include>
<!-- Upgrade code should not change unless you want to install
     a new product and have the old product remain installed,
     that is, both products existing as separate instances. -->
<?define UpgradeCode = "YOUR-GUID-HERE" ?>

<!-- Platform specific variables -->
<?if $(var.Platform) = x64 ?>
  <!-- Product name as you want it to appear in Add/Remove Programs-->
  <?define ProductName = "Foo 64 Bit [Live]" ?>
<?else ?>
  <?define ProductName =  "Foo [Live]" ?>
<?endif ?>

<!-- Directory name used as default installation location -->
<?define InstallName = "Foo [Live]" ?>

<!-- Registry key name used to store installation location -->
<?define InstallNameKey = "FooLive" ?>

<?define VDirName = "FooLive" ?>
<?define AppPoolName = "FooLiveAppPool" ?>
<?define DbName = "BlahBlahLive" ?>
</Include>

Config.Common.wxi 예

<?xml version="1.0" encoding="utf-8"?>
<Include>
<!-- Auto-generate ProductCode for each build, release and upgrade -->
<?define ProductCode = "*" ?>

<!-- Note that 4th version (Revision) is ignored by Windows Installer -->
<?define ProductVersion = "1.0.0.0" ?>

<!-- Minimum version supported if product already installed and this is an upgrade -->
<!-- Note that 4th version (Revision) is ignored by Windows Installer -->
<?define MinimumUpgradeVersion = "0.0.0.0" ?>

<!-- Platform specific variables -->
<?if $(var.Platform) = x64 ?>
   <?define Win64 = "yes" ?>
   <?define PlatformProgramFilesFolder = "ProgramFiles64Folder" ?>
<?else ?>
   <?define Win64 = "no" ?>
   <?define PlatformProgramFilesFolder = "ProgramFilesFolder" ?>
<?endif ?>

<?define ProductManufacturer = "Foo Technologies"?>

<!-- Decimal Language ID (LCID) for the Product. Used for localization. -->
<?define ProductLanguage = "1033" ?>

<?define WebSiteName = "DefaultWebSite" ?>
<?define WebSitePort = "80" ?>

<?define DbServer = "(local)" ?>
</Include>

예제 Components.wxs

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <!-- The pre-processor variable which allows the magic to happen :) -->
  <?include $(sys.CURRENTDIR)\Config.wxi?>
  <?include ..\Setup.Library\Config.Common.wxi?>
  <Fragment Id="ComponentsFragment">
    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="$(var.PlatformProgramFilesFolder)">
        <Directory Id="INSTALLLOCATION" Name="$(var.InstallName)">
          <Component Id="ProductComponent" Guid="0XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" KeyPath="yes">
          ...

참고 : 이제 구성 요소 *당 하나의 파일을 사용하고 파일을 키 경로로 설정하여 Guid 속성을 구성 요소 (와 동등한 )에서 제외하는 것이 좋습니다 . 이렇게하면 아래에 표시된 호출 ModifyComponentsGuidsRevertComponentsGuids대상 이 필요하지 않습니다 . 그러나 모든 구성 요소에서 가능하지는 않습니다.

Setup.Live.wixproj 예제

<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" />
<Target Name="BeforeBuild">
  <CallTarget Targets="ModifyComponentsGuids" />
</Target>
<Target Name="AfterBuild">
  <CallTarget Targets="RevertComponentsGuids" />
</Target>
<!-- Modify the first character of every Guid to create unique value for Live, Test and Training builds -->
<Target Name="ModifyComponentsGuids">
  <FileUpdate Files="..\Setup.Library\Components.wxs" Regex="Guid=&quot;([a-f]|[A-F]|\d)" ReplacementText="Guid=&quot;A" />
</Target>
<!-- Revert the first character of every Guid back to initial value -->
<Target Name="RevertComponentsGuids">
  <FileUpdate Files="..\Setup.Library\Components.wxs" Regex="Guid=&quot;([a-f]|[A-F]|\d)" ReplacementText="Guid=&quot;0" />
</Target>

마지막 생각들

  • 이 프로세스는 또한 동일한 설치 프로그램에 대해 서로 다른 병합 모듈 (라이브, 테스트 등의 기능)에 대해 다른 설치 프로그램을 작성하는 데에도 효과적입니다. 더 안전한 옵션 인 것처럼 다른 설치 프로그램을 사용했습니다. 다른 사람이 동일한 상자에 있고 다른 병합 모듈의 기능을 사용하는 경우 Training 대신 Live를 업그레이드 할 위험이 더 큽니다.
  • MSI를 사용하여 업그레이드 및 새로 설치를 수행하는 경우 (예 : 주요 업그레이드 만 접근) 레지스트리에 설치 위치를 저장하는 경우 각 설치의 키 이름에 대한 변수를 작성하십시오.
  • 또한 각 설치 프로그램마다 고유 한 가상 디렉터리 이름, 응용 프로그램 풀, 데이터베이스 이름 등을 사용할 수 있도록 각 Config.wxi에 변수를 만듭니다.

업데이트 1 : 구성 요소 자동 생성 Guids 는 각 파일에 대해 Guid = “*”를 사용하여 구성 요소를 생성하고 파일을 키 경로로 설정하면 FileUpdate 작업을 호출 할 필요가 없습니다.

업데이트 2 : 우리가 제기 한 문제 중 하나는 구성 요소 Guid를 자동 생성하지 않고 빌드가 실패하면 임시 파일을 수동으로 삭제해야한다는 것입니다.

업데이트 3 : svn : externals 및 임시 파일 생성에 대한 의존성을 제거하는 방법을 찾았습니다. 이렇게하면 빌드 프로세스가보다 탄력적이며 (Guids 와일드 카드를 사용할 수없는 경우 가장 좋은 옵션 임) 빛이나 양초에 빌드 실패가있을 경우 덜 부서지기 쉽습니다.

업데이트 4 : 인스턴스 변환을 사용 하는 다중 인스턴스 지원 은 WiX 3.0 이상 버전이므로 확실히 살펴볼 가치가 있습니다.


답변

Msi 진단 로깅을 사용하여 자세한 오류 정보 얻기


msiexec /i Package.msi /l*v c:\Package.log

어디

Package.msi

패키지 이름이며

c : \ Package.log

당신이 로그의 출력을 원하는 곳입니다

MSI 오류 코드

Wix 소개 비디오
“Mr. WiX”를 특징으로하는 Oh 및 Random Wix 소개 비디오 Rob Mensching은 “개념적으로 큰 그림”이 도움이됩니다.