WiX 트릭과 팁


264

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

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

gui4wix.codeplex.com을 살펴보십시오
TarunG

10
건설적이지 않은 것으로 폐쇄? 나는이 질문을하면서 힙을 배웠습니다! StackOverflow와의 약간의 일관성도 좋습니다. 예 : stackoverflow.com/questions/550632/…
si618

15
그것은 '203'Ups를 얻었고, 그것의 유용성을 입증하기에 충분합니다.
TarunG

따라서 질문은 확실하고 정답이 있어야합니다. 개방형 질문은 사람들이 실제 문제에 대해 묻는 질문을 프론트 페이지에서 제거합니다. faq @Si .:이 정책은 항상 AFAIK에 있었지만 지금은 더 잘 시행됩니다. 그 질문은 거의 3 살입니다.
Jim Dagg 2016 년

충분히 공정한 Jim, 그것은 개방형 질문이며, 결정하는 것은 SO 커뮤니티에 달려 있다고 생각합니다.하지만 건설적이지 않은 것으로 닫는 것은 이상하게 보입니다. 이 질문이 유용하다는 것을 발견했습니다 (예 : goo.gl/Zqp2X ) practical, answerable questions based on actual problems that you face. FAQ 의 일부 와 잘 맞습니다 .
si618

답변:


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

프로그램 추가 / 제거에 아이콘을 추가하는 것과 관련하여 정확히 내가 찾던 것입니다. 이 세 줄을 어디에 붙입니까? 엄청나게 멋진 +1.
Everett

나는 <Package> 요소 바로 뒤에 (그리고 분명히 아래에) 배치하는 경향이 있습니다. 유효성에 대한 스키마를 살펴보십시오. wix.sourceforge.net/manual-wix3/schema_index.htm
si618

+1, 내가 +100을 할 수 있기를 바랍니다. 이것은 내가 우연히 발견 한 가장 유용한 Wix 정보입니다.
Tim Long

고마워 팀! Rob Mensching, Bob Arson, Wim Coehen 및 기타 사람들은 지식을 공유할만한 가치가 있습니다.
si618

38

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>

34

모든 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를 추적하는 데 크게 도움이된다는 것을 알았습니다.


네임 스페이스는 사용하지 않지만 ID를 추가합니다. 예를 들면 다음과 같습니다. ExamplesFeature, ChmFileComponent. 나는 내가 타이핑을 좋아하는 것
같아

25

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

배포 할 파일이 많으므로 프로젝트를 여러 개의 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 스파이더가 약간 이상해집니다.

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


우리의 설정은이 접근법과 매우 유사합니다. Products.wxs와 동등한 제품을 다양한 제품의 기본 설정으로 사용할 수 있기 때문에 좋습니다.
si618

@Peter Tate : 스파이더 감각이 정확합니다. 디렉토리 별명에 대한 내 답변을 참조하십시오.
Wim Coenen

레이아웃이 동일한 Product.wxs는 정적이며 빌드 작업 (heat.exe)은 Content.wxs 파일
timvw를

20

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

...

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


하아! 내 블로그가 아닙니다. 나도 그것을 읽었다. 그리고 위의 텍스트에 블로그 항목에 대한 링크가 있습니다. 그러나 그들은 내가했던 것과 다르게했습니다. 나는 나의 길을 더 좋아한다!!
Cheeso

1
매우 도움이 된 js에 감사드립니다! 내가 wxs에서 변경해야 할 한 가지는 내부 로 교체하는 것 WIXUI_EXITDIALOGOPTIONALCHECKBOX입니다WIXUI_EXITDIALOGOPTIONALCHECKBOX = 1 and NOT Installed<Publish>
Alexander Kojevnikov

확인란을 기본적으로 선택하는 방법이 있습니까?
Alek Davis

<속성 ID = "WIXUI_EXITDIALOGOPTIONALCHECKBOX"값 = "1"/> : 기본적으로 상자를 확인하려면,이 사용
Alek 데이비스

멋진 솔루션처럼 보이지만 어떻게 사용합니까? 내 wixproj의 <AfterBuild> 요소 안에 js를 넣을 수있는 방법이 있습니까? 또는 명령 줄에서 실행하는 것을 참조하기 때문에 빌드 후 이벤트로 더 좋습니까?이 경우 Windows에 적합한 js 명령 줄 인터프리터는 무엇입니까?
vanmelle

18

동일한 소스 파일을 사용하여 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 이상 버전이므로 확실히 살펴볼 가치가 있습니다.


MSBuild Community Tasks 참조 +1, 패키지를 좋아합니다
BozoJoe

17

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

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

어디

Package.msi
패키지 이름이며
c : \ Package.log
당신이 로그의 출력을 원하는 곳입니다

MSI 오류 코드

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


2
+1 명령 줄 대신 Wix에서 로깅을 활성화하면 훨씬 좋습니다.
si618

3
WiX는 그렇습니다. MsiLogging 속성을 설정하십시오. Windows Installer 4.0 이상에서만 지원됩니다.
Rob Mensching

"Wix 선생님"감사합니다. 확인 해봐
Terrance

17

Javascript CustomActions는 너무 쉬우므로 사용하십시오.

사람들은 자바 스크립트가 MSI CustomActions에 사용하기에 잘못된 것이라고 말했다 . 이유 : 디버그하기 어렵고 신뢰할 수 없습니다. 동의하지 않습니다. 디버깅하기가 어렵지 않으며 C ++보다 어렵지 않습니다. 그냥 다릅니다. Javascript에서 CustomActions 작성이 C ++을 사용하는 것보다 훨씬 쉽고 쉽다는 것을 알았습니다. 훨씬 더 빨리. 신뢰할 수있는만큼.

단 하나의 단점이 있습니다. Javascript CustomActions는 Orca를 통해 추출 할 수 있지만 C / C ++ CA는 리버스 엔지니어링이 필요합니다. 설치 관리자의 마법이 지적 재산으로 보호된다고 생각되면 스크립트를 피하는 것이 좋습니다.

스크립트를 사용하는 경우 일부 구조로 시작하면됩니다. 여기 몇 가지를 시작하십시오.


CustomAction을위한 Javascript "boilerplate"코드 :

//
// CustomActions.js 
// 
// Template for WIX Custom Actions written in Javascript.
// 
// 
// Mon, 23 Nov 2009  10:54
// 
// ===================================================================


// http://msdn.microsoft.com/en-us/library/sfw6660x(VS.85).aspx
var Buttons = {
        OkOnly           : 0,
        OkCancel         : 1,
        AbortRetryIgnore : 2,
        YesNoCancel      : 3
};

var Icons = {
        Critical         : 16,
        Question         : 32,
        Exclamation      : 48,
        Information      : 64
};

var MsgKind = {
        Error            : 0x01000000,
        Warning          : 0x02000000,
        User             : 0x03000000,
        Log              : 0x04000000
};

// http://msdn.microsoft.com/en-us/library/aa371254(VS.85).aspx
var MsiActionStatus = {
        None             : 0,
        Ok               : 1, // success
        Cancel           : 2,
        Abort            : 3,
        Retry            : 4, // aka suspend?
        Ignore           : 5  // skip remaining actions; this is not an error.
};


function MyCustomActionInJavascript_CA() {
    try {
        LogMessage("Hello from MyCustomActionInJavascript");
        // ...do work here...
        LogMessage("Goodbye from MyCustomActionInJavascript");
    }
    catch (exc1) {
        Session.Property("CA_EXCEPTION") = exc1.message ;
        LogException(exc1);
        return MsiActionStatus.Abort;
    }
    return MsiActionStatus.Ok;
}

// Pop a message box.  also spool a message into the MSI log, if it is enabled. 
function LogException(exc) {
    var record = Session.Installer.CreateRecord(0);
    record.StringData(0) = "CustomAction: Exception: 0x" + decimalToHexString(exc.number) + " : " + exc.message;
    Session.Message(MsgKind.Error + Icons.Critical + Buttons.btnOkOnly, record);
}


// spool an informational message into the MSI log, if it is enabled. 
function LogMessage(msg) {
    var record = Session.Installer.CreateRecord(0);
    record.StringData(0) = "CustomAction:: " + msg;
    Session.Message(MsgKind.Log, record);
}


// http://msdn.microsoft.com/en-us/library/d5fk67ky(VS.85).aspx
var WindowStyle = {
    Hidden : 0,
    Minimized : 1,
    Maximized : 2
};

// http://msdn.microsoft.com/en-us/library/314cz14s(v=VS.85).aspx
var OpenMode = {
    ForReading : 1,
    ForWriting : 2,
    ForAppending : 8
};

// http://msdn.microsoft.com/en-us/library/a72y2t1c(v=VS.85).aspx
var SpecialFolders = {
    WindowsFolder : 0, 
    SystemFolder :  1, 
    TemporaryFolder : 2
};

// Run a command via cmd.exe from within the MSI
function RunCmd(command)
{
    var wshell = new ActiveXObject("WScript.Shell");
    var fso = new ActiveXObject("Scripting.FileSystemObject");
    var tmpdir = fso.GetSpecialFolder(SpecialFolders.TemporaryFolder);
    var tmpFileName = fso.BuildPath(tmpdir, fso.GetTempName());

    LogMessage("shell.Run("+command+")");

    // use cmd.exe to redirect the output
    var rc = wshell.Run("%comspec% /c " + command + "> " + tmpFileName, WindowStyle.Hidden, true);
    LogMessage("shell.Run rc = "  + rc);

    // here, optionally parse the output of the command 
    if (parseOutput) {
        var textStream = fso.OpenTextFile(tmpFileName, OpenMode.ForReading);
        while (!textStream.AtEndOfStream) {
            var oneLine = textStream.ReadLine();
            var line = ParseOneLine(oneLine);
                ...
        }
        textStream.Close();
    }

    if (deleteOutput) {
        fso.DeleteFile(tmpFileName);
    }

    return {
        rc : rc,
        outputfile : (deleteOutput) ? null : tmpFileName
    };
}

그런 다음 다음과 같이 사용자 정의 조치를 등록하십시오.

<Fragment>
  <Binary Id="IisScript_CA" SourceFile="CustomActions.js" />

  <CustomAction Id="CA.MyCustomAction"
              BinaryKey="IisScript_CA"
              JScriptCall="MyCustomActionInJavascript_CA"
              Execute="immediate"
              Return="check" />
</Fragmemt>

물론 여러 사용자 지정 동작에 대해 원하는만큼 Javascript 함수를 삽입 할 수 있습니다. 한 예 : Javascript를 사용하여 IIS에서 WMI 쿼리를 수행하고 ISAPI 필터를 설치할 수있는 기존 웹 사이트 목록을 얻었습니다. 그런 다음이 목록을 사용하여 UI 순서에서 나중에 표시되는 목록 상자를 채 웁니다. 모두 매우 쉽습니다.

IIS7에는 IIS 용 WMI 공급자가 없으므로 shell.Run()appcmd.exe를 호출하여 작업을 수행하는 방법을 사용 했습니다. 쉬운.

관련 질문 : Javascript CustomActions 정보


2
+1 DTF 접근 방식이 설정하기 쉽지만 자바 스크립트도 유용 할 수 있습니다.
si618

12

Peter Tate는 이미 재사용 가능한 ComponentGroup 정의를 별도의 wix 프래그먼트로 정의 할 수있는 방법을 보여주었습니다. 이것과 관련된 몇 가지 추가 트릭 :

디렉토리 별명

구성 요소 그룹 단편은 기본 제품 wx에 의해 정의 된 디렉토리에 대해 알 필요가 없습니다. 컴포넌트 그룹 조각에서 다음과 같은 폴더에 대해 이야기 할 수 있습니다.

<DirectoryRef Id="component1InstallFolder">
...
</DirectoryRef>

그런 다음 기본 제품은 다음과 같이 해당 디렉토리 중 하나 (예 : "productInstallFolder")의 별명을 지정할 수 있습니다.

<Directory Id="productInstallFolder" Name="ProductName">
   <!-- not subfolders (because no Name attribute) but aliases for parent! -->
   <Directory Id="component1InstallFolder"/> 
   <Directory Id="component2InstallFolder"/> 
</Directory>

의존성 그래프

ComponentGroup 요소는 ComponentGroupRef 하위 요소를 포함 할 수 있습니다. 재사용 가능한 구성 요소가 많은 풀이 있고 그 사이에 복잡한 종속성 그래프가있는 경우 유용합니다. 각 구성 요소에 대해 고유 한 조각으로 ComponentGroup을 설정하고 다음과 같이 종속성을 선언합니다.

<ComponentGroup Id="B">
   <ComponentRef Id="_B" />
   <ComponentGroupRef Id="A">
</ComponentGroup>

구성 요소 그룹 "B"가 응용 프로그램의 직접적인 종속성이기 때문에 설정에서 구성 요소 그룹 "B"를 참조하는 경우, 응용 프로그램 작성자가 "B"의 종속성임을 인식하지 않아도 구성 요소 그룹 "A"를 자동으로 가져옵니다. 순환 종속성이없는 한 "작동합니다".

재사용 가능한 wixlib

위의 종속성 그래프 아이디어는 lit.exe를 사용하여 big-pool-o-reusable 구성 요소를 재사용 가능한 wixlib로 컴파일하는 경우 가장 효과적입니다. 응용 프로그램 설정을 작성할 때 wixobj 파일과 매우 유사한이 wixlib를 참조 할 수 있습니다. candle.exe 링커는 기본 제품 wxs 파일에 의해 "당겨지지 않은"조각을 자동으로 제거합니다.


12

T4를 사용하여 WXS 파일을 생성하는 것에 대해 언급 한 사람이 아무도 없습니다. 나는 New Age Solutions @ Henry Lee를 통해 이것에 대해 배웠습니다. .

기본적으로 T4 템플릿을 실행하는 사용자 지정 MSBuild 작업을 생성하면 Wix 프로젝트가 컴파일되기 직전에 해당 템플릿이 WXS를 출력합니다. 이를 통해 (어떻게 구현하는지에 따라) 다른 솔루션을 컴파일하여 모든 어셈블리 출력을 자동으로 포함 할 수 있습니다 (새 어셈블리를 추가 할 때마다 더 이상 wx를 편집 할 필요가 없음).


2
+1 정말 좋았습니다. 어셈블리에 대해별로 걱정하지 않지만 웹 프로젝트는 Wix가 아닌 프로젝트에 추가 된 aspx 페이지 및 기타 아티팩트 (이미지, CSS)에 문제가있을 수 있습니다.
si618

4
앞으로의 방문객을 위해 Wix 3.5에는 자동으로 수확 하는 유틸리티 heat.exe 가 있습니다
Mr.

@Mrchief-Heat가 로컬로 복사 된 참조 된 어셈블리를 선택한다고 생각하지 않습니다. 이것은 분명히 4.0에 대한 계획입니다. 참조 : sourceforge.net/tracker/...
피터 T. 라콤 주니어

열은 참조 된 조립품을 픽업하지 않습니다.
tofutim

T4를 사용하여 WXS 파일을 생성하는 좋은 예는 무엇입니까?
tofutim

12

Heat.exe를 사용하여 얼굴을 부수고 고통스러운 대규모 설치에서 "Epic Pwnage"를 적용

열에 대한 SiRobert-P의 답변을 확장합니다 .

번역 : (열을 사용하여 개별 파일을 프로젝트에 직접 입력하지 않고 전체적으로 더 쉬운 프로세스를위한 빌드 자동화)

WiX 2.0 Heat Syntax detail

최신 버전의 경우 (이전 버전과는 다르지만 잠재적으로 성가신 구문 변경 사항이 있습니다 ....) 디렉토리로 이동하십시오. Heat는 cmd.exe에서 있고 heat를 입력하지만 여기에 도움이 필요한 예제가 있습니다. 필요한 경우 최신 버전으로.

Visual Studio 2010에서 빌드 이벤트에 다음을 추가하십시오.
(프로젝트-> 속성-> 빌드 이벤트-> 사전 빌드 이벤트를 마우스 오른쪽 단추로 클릭하십시오 . )

$(WIX)bin\heat.exe" dir "$(EnviromentVariable)" -cg GroupVariable -gg -scom -sreg -sfrag - srd -dr INSTALLLOCATION -var env.LogicPath -out "$(FragmentDir)\FileName.wxs

-gg 

열이 실행될 때 Guid를 생성합니다 (위의 명령을 실행할 때와 동일).

-scom 

"COM 파일"을 잡지 마십시오

-sreg 

"레지스트리 파일"을 잡지 마십시오

-조각 

"Fragments"를 잡지 마십시오

-srd 

"root Dir"을 잡지 마십시오

dir

dir은 Heat가 폴더를 보길 원한다는 것을 나타냅니다.

"$ (EnviromentVariable)"

(오른쪽 클릭 프로젝트, 속성으로 이동) 프로젝트 속성-> 빌드 섹션에서 프리 프로세서 변수 정의 (Visual Studio 2010으로 가정)에서 프리 프로세서 변수에 추가 할 변수의 이름

예:
EnviromentVariable = C : \ 프로젝트 \ bin \ 디버그;
큰 따옴표는 없지만 세미콜론으로 끝납니다.

-cg Group 가변 

기본 wxs 파일로 작성된 단편에서 참조 될 ComponentGroup

조각

출력 wxs 조각이 저장 될 조각 디렉토리

FileName.wxs

파일 이름

여기에 전체 튜토리얼이 있습니다.

1 부 2 부


약간 다른 목적을위한 또 다른 유용한 도구가 있습니다 : Paraffin ( wintellect.com/CS/blogs/jrobbins/archive/2010/03/10/4107.aspx )
ralf.w.

9

COM 객체 포함 :

heat레지스트리 항목과 그에 필요한 기타 구성을 모두 (모두는 아님) 생성합니다. 가지고 있다!

관리되는 COM 개체 포함 (일명 .NET 또는 C # COM 개체)

사용하여 heat관리되는 COM 개체에 당신에게 거의 완벽한 윅스 문서를 제공 할 것입니다.

GAC에서 사용할 수있는 라이브러리가 필요하지 않은 경우 (예 : 전 세계적으로 사용 가능 : 대부분 .NET 어셈블리에서이 라이브러리가 필요하지 않은 경우) 아마도이 시점에서 의도하지 않은 무언가가 잘못되었을 수 있습니다. 공유 라이브러리) CodeBase로 설정 하려면 레지스트리 키를 업데이트해야 합니다 [#ComponentName]. GAC에 설치할 계획이라면 (예를 들어, 모든 사람이 사용할 멋진 공용 라이브러리를 새로 만든 경우)이 항목을 제거하고 File요소에 두 가지 새로운 속성을 추가해야합니다 .AssemblyKeyPath. 어셈블리는 ".net" KeyPath으로 설정하고 "yes"로 설정해야합니다.

그러나 일부 환경 (특히 스크립팅 언어와 같은 관리되는 메모리가있는 환경)은 Typelib에도 액세스해야합니다. typelib 에서 실행heat 하고 포함하십시오. heat필요한 모든 레지스트리 키를 생성합니다. 얼마나 멋진가요?


8

에 설치 C:\ProductName

일부 응용 프로그램은 C:\ProductName이와 유사 하게 설치해야 하지만 네트 설치의 예제 중 99.9 % (100 %는 아님)가에 설치됩니다 C:\Program Files\CompanyName\ProductName.

다음 코드를 사용하여 TARGETDIR속성을 C:드라이브 의 루트 ( WiX 사용자 목록 에서 가져옴) 로 설정할 수 있습니다 .

<CustomAction Id="AssignTargetDir" Property="TARGETDIR" Value="C:\" Execute="firstSequence" />
<InstallUISequence>
    <Custom Action="AssignTargetDir" Before="CostInitialize">TARGETDIR=""</Custom>
</InstallUISequence>
<InstallExecuteSequence>
    <Custom Action="AssignTargetDir" Before="CostInitialize">TARGETDIR=""</Custom>
</InstallExecuteSequence>

참고 : 기본적으로 TARGETDIR 하지 않습니다 가리 C:\! 차라리 여유 공간이 가장 많은 드라이브ROOTDRIVE루트를 가리 킵니다 ( 여기 참조 ).C: 드라이브 인 . 다른 하드 드라이브, 파티션 또는 USB 드라이브가있을 수 있습니다!

그런 다음 <Product ...>태그 아래에 평소와 같이 다음 디렉토리 태그가 필요합니다.

<Directory Id="TARGETDIR" Name="SourceDir">
    <Directory Id="APPLICATIONFOLDER" Name="$(var.ProductName)">
        <!-- your content goes here... -->
    </Directory>
</Directory>

그냥 설치하는 것이 더 간단하지 WindowsVolume않습니까?
Wim Coenen

1
예, 그러나 herehere에서 지적한 WindowsVolume것처럼 속성을 Directory(컴파일러에서 오류 / 경고를 제공하는) 속성으로 사용할 수 없으므로 해결 방법을 사용해야합니다 . 개인적으로, 나는 그 해결 방법이 혼란 스럽다는 것을 알았습니다.
gehho

7

환경 변수

Wxs 문서를 wixobj 코드로 컴파일 할 때 환경 변수를 사용하여 다양한 정보를 결정할 수 있습니다. 예를 들어 프로젝트에 포함 할 파일을 변경한다고 가정 해 보겠습니다. RELEASE_MODE라는 환경 변수가 있다고 가정 해 봅시다. MSI를 빌드하기 직전에 설정했거나 스크립트를 사용하거나 수동으로 중요하지 않습니다. Wix 소스에서 다음과 같은 작업을 수행 할 수 있습니다.

<define FILESOURCE = c:\source\output\bin\$(env.RELEASE_MODE) >

그런 다음 나중에 코드에서 즉시 사용하여 wxs 문서를 즉시 변경하십시오.

<Icon Id="myicon.ico" SourceFile="$(var.FILESOURCE)" />

1
$ (Configuration) 및 $ (Platform)과 같은 컴파일 변수도 사용할 수 있습니다. 또한 msdn.microsoft.com/en-us/library/aa302186.aspx
si618

1
@Si-오늘 전에 언젠가는 해당 링크가 더 이상 활성화되어 있지 않습니다. 최신 버전을 찾을 수 없습니다.
피터 M



7

편집 대화 상자

대화 상자를 편집하는 좋은 기능 중 하나는 버전 4.0.1.7090 이상에서 SharpDevelop를 사용하는 것입니다. 이 도구를 사용하면 독립형 대화 상자 (예 : InstallDirDlg.wxs와 같은 WiX 소스의 wxs 파일)를 디자인보기에서 열고 미리보고 편집 할 수 있습니다.


놀랍고 SharpDevelop가 이것을 지원했는지 몰랐습니다.
anton.burger

6

IIS enable32BitAppOnWin64 플래그 설정 http://trycatchfail.com/blog/post/WiX-Snippet-change-enable32BitAppOnWin64.aspx

<InstallExecuteSequence>
   <RemoveExistingProducts After="InstallFinalize" />
   <Custom Action="ConfigureAppPool" After="InstallFinalize" >
     <![CDATA[NOT Installed AND VersionNT64 >= 600]]>         
   </Custom>
</InstallExecuteSequence>

<CustomAction Id="ConfigureAppPool" Return="check" Directory="TARGETDIR" ExeCommand="[SystemFolder]inetsrv\appcmd set apppool /apppool.name:[APPPOOLNAME] /enable32BitAppOnWin64:false" />

5

"설치 준비 완료?"를 수정하십시오. 대화 상자 (일명 VerifyReadyDlg)를 사용하여 선택한 사항을 요약합니다.

다음과 같이 보입니다 :
alt text http://i46.tinypic.com/s4th7t.jpg

Javascript CustomAction으로이를 수행하십시오.


자바 스크립트 코드 :

// http://msdn.microsoft.com/en-us/library/aa372516(VS.85).aspx
var MsiViewModify = 
    {
        Refresh          : 0,
        Insert           : 1,
        Update           : 2,
        Assign           : 3,
        Replace          : 4,
        Merge            : 5,
        Delete           : 6,
        InsertTemporary  : 7,   // cannot permanently modify the MSI during install
        Validate         : 8,
        ValidateNew      : 9,
        ValidateField    : 10,
        ValidateDelete   : 11
    };


// http://msdn.microsoft.com/en-us/library/sfw6660x(VS.85).aspx
var Buttons = 
    {
        OkOnly           : 0,
        OkCancel         : 1,
        AbortRetryIgnore : 2,
        YesNoCancel      : 3
    };

var Icons= 
    {
        Critical         : 16,
        Question         : 32,
        Exclamation      : 48,
        Information      : 64
    }

var MsgKind =
    {
        Error            : 0x01000000,
        Warning          : 0x02000000,
        User             : 0x03000000,
        Log              : 0x04000000
    };

// http://msdn.microsoft.com/en-us/library/aa371254(VS.85).aspx
var MsiActionStatus = 
    {
        None             : 0,
        Ok               : 1, // success
        Cancel           : 2,
        Abort            : 3,
        Retry            : 4, // aka suspend?
        Ignore           : 5  // skip remaining actions; this is not an error.
    };

function UpdateReadyDialog_CA(sitename)
{
    try 
    {
        // can retrieve properties from the install session like this:
        var selectedWebSiteId = Session.Property("MSI_PROPERTY_HERE");

        // can retrieve requested feature install state like this:
        var fInstallRequested   = Session.FeatureRequestState("F.FeatureName");

        var text1 = "This is line 1 of text in the VerifyReadyDlg";

        var text2 = "This is the second line of custom text";

        var controlView     = Session.Database.OpenView("SELECT * FROM Control");
        controlView.Execute();

        var rec             = Session.Installer.CreateRecord(12);
        rec.StringData(1)   = "VerifyReadyDlg";    // Dialog_
        rec.StringData(2)   = "CustomVerifyText1"; // Control - can be any name
        rec.StringData(3)   = "Text";              // Type
        rec.IntegerData(4)  = 25;                  // X
        rec.IntegerData(5)  = 60;                  // Y
        rec.IntegerData(6)  = 320;                 // Width
        rec.IntegerData(7)  = 85;                  // Height
        rec.IntegerData(8)  = 2;                   // Attributes
        rec.StringData(9)   = "";                  // Property
        rec.StringData(10)  = vText1;              // Text
        rec.StringData(11)  = "";                  // Control_Next
        rec.StringData(12)  = "";                  // Help
        controlView.Modify(MsiViewModify.InsertTemporary, rec);

        rec                 = Session.Installer.CreateRecord(12);
        rec.StringData(1)   = "VerifyReadyDlg";    // Dialog_
        rec.StringData(2)   = "CustomVerifyText2"; // Control - any unique name
        rec.StringData(3)   = "Text";              // Type
        rec.IntegerData(4)  = 25;                  // X
        rec.IntegerData(5)  = 160;                 // Y
        rec.IntegerData(6)  = 320;                 // Width
        rec.IntegerData(7)  = 65;                  // Height
        rec.IntegerData(8)  = 2;                   // Attributes
        rec.StringData(9)   = "";                  // Property
        rec.StringData(10)  = text2;               // Text
        rec.StringData(11)  = "";                  // Control_Next
        rec.StringData(12)  = "";                  // Help
        controlView.Modify(MsiViewModify.InsertTemporary, rec);

        controlView.Close();
    }
    catch (exc1)
    {
        Session.Property("CA_EXCEPTION") = exc1.message ;
        LogException("UpdatePropsWithSelectedWebSite", exc1);
        return MsiActionStatus.Abort;
    }
    return MsiActionStatus.Ok;
}


function LogException(loc, exc)
{
    var record = Session.Installer.CreateRecord(0);
    record.StringData(0) = "Exception {" + loc + "}: " + exc.number + " : " + exc.message;
    Session.Message(MsgKind.Error + Icons.Critical + Buttons.btnOkOnly, record);
}

자바 스크립트 CA를 선언하십시오.

<Fragment>
  <Binary Id="IisScript_CA" SourceFile="CustomActions.js" />

  <CustomAction Id="CA.UpdateReadyDialog"
              BinaryKey="IisScript_CA"
              JScriptCall="UpdateReadyDialog_CA"
              Execute="immediate"
              Return="check" />
</Fragment>

CA를 버튼에 연결하십시오. 이 예제에서 CustomizeDlg에서 Next를 클릭하면 CA가 시작됩니다.

<UI ...>
  <Publish Dialog="CustomizeDlg" Control="Next" Event="DoAction" 
           Value="CA.UpdateReadyDialog" Order="1"/>
</UI>

관련 SO 질문 : 런타임에 VerifyReadyDlg에 표시 할 텍스트를 어떻게 설정합니까?


분명히 이것은 자바 스크립트가 DHTML 스크립팅 언어 인 JScript 윈도우 스크립팅 언어가 아니어야합니다. 아마도 약간 비관적이지만 일부 사람들에게는 약간 혼란 스러울 수 있습니다.
caveman_dick

5

개별적으로 패치 될 수있는 컴포넌트를 자체 조각 안에 넣습니다.

그것은 만드는 제품 설치 및 조각의 모든 구성 요소를 포함하는 경우, 당신은 포함해야 패치를 모두가는 모든 것을 조각의 구성 요소를. 설치 프로그램을 빌드 할 때 구성 요소 참조를 놓치면 light.exe에서 연결 오류가 발생합니다. 그러나 패치를 만들 때 조각에 단일 구성 요소 참조를 포함하면 해당 조각에서 변경된 모든 구성 요소가 패치에 표시됩니다.

이처럼 :

<Fragment>
    <DirectoryRef Id="SampleProductFolder">
        <Component Id="SampleComponent1" Guid="{C28843DA-EF08-41CC-BA75-D2B99D8A1983}" DiskId="1">
            <File Id="SampleFile1" Source=".\$(var.Version)f\Sample1.txt" />
        </Component>
    </DirectoryRef>
</Fragment>

<Fragment>
    <DirectoryRef Id="SampleProductFolder">
        <Component Id="SampleComponent2" Guid="{6CEA5599-E7B0-4D65-93AA-0F2F64402B22}" DiskId="1">
           <File Id="SampleFile2" Source=".\$(var.Version)f\Sample2.txt" />
        </Component>
    </DirectoryRef>
</Fragment>

<Fragment>
    <DirectoryRef Id="SampleProductFolder">
        <Component Id="SampleComponent3" Guid="{4030BAC9-FAB3-426B-8D1E-DC1E2F72C2FC}" DiskId="1">
           <File Id="SampleFile3" Source=".\$(var.Version)f\Sample3.txt" />
        </Component>
    </DirectoryRef>
</Fragment>

이 대신에 :

<Fragment>
    <DirectoryRef Id="SampleProductFolder">
        <Component Id="SampleComponent1" Guid="{C28843DA-EF08-41CC-BA75-D2B99D8A1983}" DiskId="1">
            <File Id="SampleFile1" Source=".\$(var.Version)\Sample1.txt" />
        </Component>

        <Component Id="SampleComponent2" Guid="{6CEA5599-E7B0-4D65-93AA-0F2F64402B22}" DiskId="1">
           <File Id="SampleFile2" Source=".\$(var.Version)\Sample2.txt" />
        </Component>

        <Component Id="SampleComponent3" Guid="{4030BAC9-FAB3-426B-8D1E-DC1E2F72C2FC}" DiskId="1">
           <File Id="SampleFile3" Source=".\$(var.Version)\Sample3.txt" />
        </Component>
    </DirectoryRef>
</Fragment>

또한 WiX.chm 도움말 파일에서 "순수하게 WiX 사용"주제를 사용하여 패치 할 때이 절차를 사용하여 패치를 생성하십시오.

torch.exe -p -xi 1.0\product.wixpdb 1.1\product.wixpdb -out patch\diff.wixmst
candle.exe patch.wxs
light.exe patch.wixobj -out patch\patch.wixmsp
pyro.exe patch\patch.wixmsp -out patch\patch.msp -t RTM patch\diff.wixmst

1.1 버전의 product.wixpdb를 구성 요소를 사용하여 별도의 조각으로 작성하는 것만으로는 충분하지 않습니다. 따라서 배송 전에 제품을 올바르게 조각화하십시오.


5

Wix3.0 이상에서 EULA 인쇄

1) wix 소스 코드를 컴파일 할 때 light.exe는 명령 행에서 WixUIExtension.dll을 참조해야합니다. 이를 위해 명령 행 스위치 -ext를 사용하십시오.

2) WixUIExtension.dll에 대한 참조를 추가 할 때 프로젝트가 컴파일되지 않으면 대화 상자 ID의 충돌로 인해 발생했을 가능성이 높습니다. 즉, 프로젝트가 WixUIExtension.dll의 일부 표준 대화 상자와 동일한 대화 상자 ID를 사용하고있을 가능성이 높습니다. 대화 상자에 다른 ID를 제공하십시오. 이것은 매우 일반적인 문제입니다.

3) 라이센스 대화 상자에는 ID가 "LicenseText"인 ScrollableText 컨트롤이 있어야합니다. Wix는 인쇄 할 때 정확히이 제어 이름을 검색합니다.

<Control Id="LicenseText" Type="ScrollableText" X="20" Y="60" Width="330" Height="160" Sunken="yes" TabSkip="no">
    <Text SourceFile="License.rtf" />
</Control>

커스텀 액션을 나타내는 PushButton

<Control Type="PushButton" Id="PrintButton" Width="57" Height="17" X="19" Y="244" Text="Print">
    <Publish Event="DoAction" Value="PrintEula">1</Publish>
</Control>

4) 다음과 같이 Id = "PrintEula"를 사용하여 CustomAction을 정의하십시오.

<CustomAction Id="PrintEula" BinaryKey="WixUIWixca" DllEntry="PrintEula" Return="ignore" Execute="immediate" />

참고 : BinaryKey는 Wix2.0과 Wix2.0에 비해 다르며 정확히 "WixUIWixca"(대소 문자 구분) 여야합니다.

사용자가 버튼을 누르면 표준 프린터 선택 대화 상자가 표시되며 여기에서 인쇄 할 수 있습니다.


5
  • GUI의 첫 번째 화면에서 제품 버전을 어딘가에 표시합니다. 사람들은 매번 올바른 버전을 고르는 데 실수를하는 경향이 있기 때문입니다. (그리고 개발자가 연령대를 계속 검색하도록합니다.)

  • TFSBuild는 다양한 환경을위한 구성으로 변환 (.mst 파일)을 생성하도록 설정했습니다. 배포해야하는 모든 환경에 대해 알고 있습니다.

Grant Holliday의 원래 블로그 게시물이 다운되었으므로 여기에 내용을 붙여 넣었습니다.


XMLMarch 11 2008에서 MSI 변환 파일을 생성하는 MSBuild 작업

이전 글에서 MSI 변환 (* .mst) 파일을 사용하여 환경 별 구성 설정을 일반 MSI 패키지와 분리하는 방법에 대해 설명했습니다.

이는 구성에 유연성을 제공하지만 Transform 파일에는 두 가지 단점이 있습니다.

  1. 그들은 이진 형식입니다
  2. 변환 파일을 "편집"하거나 "볼"수 없습니다. 변경 사항이 무엇인지 보려면 적용하거나 다시 만들어야합니다.

다행히도 Microsoft Windows Installer Object Library (c : windowssystem32msi.dll)를 사용하여 MSI“데이터베이스”를 열고 변환 파일을 만들 수 있습니다.

크레딧은 Alex Shevchuk 에게 다시갑니다 – MSI에서 WiX로 – 7 부VbScript로이를 달성하는 방법을 보여준 Transforms를 사용한 설치 사용자 정의 – . 본질적으로 내가 한 모든 것은 Alex의 예제를 취하고 Interop.WindowsInstaller.dll을 사용하여 MSBuild 작업을 구현했습니다. MSBuild 작업

여기에서 소스 코드 및 예제 transforms.xml을 다운로드 하십시오 (~ 7Kb Zipped VS2008 Solution)



2
현지화 파일에서 WelcomeDlgTitle을 재정의합니다. 훌륭하게 작동합니다! <문자열 식 "WelcomeDlgTitle"> {\ WixUI_Font_Bigger}는 [ProductName]을 [PRODUCTVERSION] 설치 프로그램을 시작합니다 마법사 </ 문자열>
saschabeaumont

5

설치 패키지를 배포하기 전에 항상 패키지의 내용을 제어합니다.

(Terrences post에 따르면) 커맨드 라인에서 간단한 호출로 커맨드 라인을 열고 입력하십시오.

msiexec /a Package.msi /qb TARGETDIR="%CD%\Extract" /l*vx "%CD\install.log%"

패키지 경로를 현재 경로와 함께 하위 디렉토리 'Extract'로 추출합니다.


4

ORCA 대신 InstEd 를 사용 하면 MSI 테이블을 볼 수 있습니다. 또한 Transform-> Compare To ...로 두 패키지를 비교할 수 있습니다.

또한 추가 기능이 포함 된 Plus 버전 을 사용할 수 있습니다. 그러나 무료 버전은 Orca를위한 좋은 대안을 제공합니다.


4

x86 / x64 호환성을 가진 COM Interop 용 .NET 어셈블리 등록

NB이 조각은 본질적으로 REGASM Assembly.dll / codebase 와 동일합니다.

이 샘플에서 몇 가지 일이 진행 중이므로 여기에 코드가 있으며 나중에 설명하겠습니다.

  <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <?include $(sys.CURRENTDIR)\Config.wxi?>
  <?if $(var.Win64) ?>
  <?define CLSIDRoots = "CLSID;Wow6432Node\CLSID"?>
  <?else ?>
  <?define CLSIDRoots = "CLSID"?>
  <?endif?>
  <!-- ASCOM Driver Assembly with related COM registrations -->
  <Fragment>
    <DirectoryRef Id="INSTALLLOCATION" />
  </Fragment>
  <Fragment>
    <ComponentGroup Id="cgAscomDriver">
      <Component Id="cmpAscomDriver" Directory="INSTALLLOCATION" Guid="{0267031F-991D-4D88-A748-00EC6604171E}">
        <File Id="filDriverAssembly" Source="$(var.TiGra.Astronomy.AWRDriveSystem.TargetPath)" KeyPath="yes" Vital="yes" Assembly=".net" AssemblyApplication="filDriverAssembly"  />
        <RegistryKey Root="HKCR" Key="$(var.DriverId)"  Action="createAndRemoveOnUninstall">
          <RegistryValue Type="string" Value="$(var.DriverTypeName)"/>
          <RegistryKey Key="CLSID">
            <RegistryValue Type="string" Value="$(var.DriverGuid)" />
          </RegistryKey>
        </RegistryKey>
        <?foreach CLSID in $(var.CLSIDRoots) ?>
        <RegistryKey Root="HKCR" Key="$(var.CLSID)" Action="none">
          <RegistryKey Key="$(var.DriverGuid)" Action="createAndRemoveOnUninstall">
            <RegistryValue Type="string" Value="$(var.DriverTypeName)"/>
            <RegistryKey Key="InprocServer32">
              <RegistryValue Type="string" Value="mscoree.dll" />
              <RegistryValue Type="string" Name="ThreadingModel" Value="Both"/>
              <RegistryValue Type="string" Name="Class" Value="$(var.DriverTypeName)"/>
              <RegistryValue Type="string" Name="Assembly" Value="!(bind.assemblyFullname.filDriverAssembly)" />
              <RegistryValue Type="string" Name="RuntimeVersion" Value="v2.0.50727"/>
              <RegistryValue Type="string" Name="CodeBase" Value="file:///[#filDriverAssembly]" />
              <RegistryKey Key="!(bind.fileVersion.filDriverAssembly)" >
                <RegistryValue Type="string" Name="Class" Value="$(var.DriverTypeName)"/>
                <RegistryValue Type="string" Name="Assembly" Value="!(bind.assemblyFullname.filDriverAssembly)" />
                <RegistryValue Type="string" Name="RuntimeVersion" Value="v2.0.50727"/>
                <RegistryValue Type="string" Name="CodeBase" Value="file:///[#filDriverAssembly]" />
              </RegistryKey>
            </RegistryKey>
            <RegistryKey Key="ProgId" Action="createAndRemoveOnUninstall">
              <RegistryValue Type="string" Value="$(var.DriverId)" />
            </RegistryKey>
            <RegistryKey Key="Implemented Categories" Action="createAndRemoveOnUninstall" >
              <RegistryKey Key="{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}" Action="createAndRemoveOnUninstall" />
            </RegistryKey>
          </RegistryKey>
        </RegistryKey>
        <?endforeach?>
      </Component>
    </ComponentGroup>
  </Fragment>
</Wix>

궁금한 점이 있다면 이것은 실제로 ASCOM 망원경 드라이버를위한 것 입니다.

먼저 위에서 조언을 받아 별도의 파일에 platforma 변수를 만들면 XML을 통해 흩어져있는 변수를 볼 수 있습니다.

상단 근처의 if-then-else 부분은 x86 대 x64 호환성을 처리합니다. 내 어셈블리는 'Any CPU'를 대상으로하므로 x64 시스템에서는 64 비트 레지스트리와 32 비트 Wow6432Node영역에 한 번 두 번 등록해야 합니다. if-then-else는 이것을 위해 나를 설정합니다. 값은foreach 나중에 루프 됩니다. 이 방법으로 레지스트리 키를 한 번만 작성하면됩니다 (건조한 원칙).

파일 요소는 설치 및 등록되는 실제 어셈블리 dll을 지정합니다.

<File Id="filDriverAssembly" Source="$(var.TiGra.Astronomy.AWRDriveSystem.TargetPath)" KeyPath="yes" Vital="yes" Assembly=".net" AssemblyApplication="filDriverAssembly"  />

혁명적 인 것은 없지만, Assembly=".net"이 속성만으로도 어셈블리가 GAC에 들어가게되는데 이는 내가 원하는 것이 아닙니다. AssemblyApplication속성을 사용하여 자신을 다시 가리키는 것은 Wix가 파일을 GAC에 넣는 것을 막는 방법입니다. Wix는 그것이 .net 어셈블리라는 것을 알고 있지만, XML 내에서 특정 바인더 변수를 사용 !(bind.assemblyFullname.filDriverAssembly)하여 어셈블리의 전체 이름을 얻을 수 있습니다.


3

DISABLEADVTSHORTCUTS설치 프로그램의 모든 알려진 바로 가기가 일반 바로 가기가되도록 속성을 설정하십시오 . 키 경로로 사용하기 위해 더미 reg 키를 포함하지 않아도됩니다.

<Property Id="DISABLEADVTSHORTCUTS" Value="1"/>

Windows Installer 4.0 이상이 필요 하다고 생각 합니다 .


2

좋은 구조이지만 내 경험을 바탕으로 이러한 조건을 어떻게 해결하는지 궁금합니다.

A. 모든 설치가 동일한 대상에 도착한 것으로 보입니다. 사용자가 한 번에 3 가지 버전을 모두 설치해야하는 경우 프로세스에서이를 허용합니다. 트리거하는 모든 실행 파일의 버전을 분명하게 알 수 있습니까?

B. TEST 및 / 또는 TRAINING에는 있지만 아직 LIVE에는없는 새 파일을 어떻게 처리합니까?


안녕하세요 블레인, A. 아닙니다. InstallName은 Config.wxi에 있으며 svn : externals에서 참조하지 않는 유일한 파일입니다. 따라서 이는 각 설치, 즉 각 제품마다 고유합니다. 우리가 각 버전에 대해 Guid를 수정하는 이유이기도합니다. B. GOTO A. :) 자체 MSI 코드가있는 별도의 MSI입니다.
si618

1
그건 그렇고, 왜 당신이 질문으로 내 질문에 대답했는지 이해하지만 일단 충분한 답변 포인트를 얻으면 질문을 답변 의견으로 옮기십시오. 그렇지 않으면 스레드를 따르기가 어려울 것입니다.
si618

2

다음 은 대규모 웹 프로젝트에서 배포 된 파일 수가 MSI (또는 병합 모듈)에 내장 된 파일 수와 일치하는지 확인하는 방법입니다. 방금 주요 응용 프로그램 (여전히 개발 중)에 대해 사용자 지정 MSBuild 작업을 실행했으며 대부분 누락 된 파일, 주로 이미지를 선택했지만 일부 자바 스크립트 파일이 빠져 들었습니다!

이 접근 방식 (WiX 프로젝트의 AfterBuild 대상에 연결하여 MSI의 파일 테이블로 엿보기)은 예상되는 파일의 전체 목록에 액세스 할 수있는 다른 응용 프로그램 유형에서 작동 할 수 있습니다.


2

설치가 제거 또는 재설치를 허용하지 않고 롤백되지 않는 경우 강제 재설치를 수행합니다.

어떤 이유로 든 제거되지 않는 설치를 재정의하는 데 사용되는 VBscript 스크립트.

Dim objShell
set objShell = wscript.createObject("wscript.shell")

iReturn = objShell.Run("CMD /K MsiExec.exe /I ""C:\Users\TheUser\Documents\Visual Studio 2010\Projects\InstallationTarget\HelloInstaller\bin\Debug\HelloInstaller.msi"" REINSTALLMODE=vomus REINSTALL=ALL",,True)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.