Trik dan tips WiX

264

Kami telah menggunakan WiX untuk sementara waktu sekarang, dan meskipun mengeluh tentang kemudahan penggunaan, itu berjalan cukup baik. Yang saya cari adalah saran yang berguna mengenai:

  • Menyiapkan proyek WiX (tata letak, referensi, pola file)
  • Mengintegrasikan WiX ke dalam solusi, dan membangun / melepaskan proses
  • Mengkonfigurasi penginstal untuk penginstalan dan peningkatan baru
  • Retasan WiX apa pun yang ingin Anda bagikan
si618
sumber
lihat gui4wix.codeplex.com
TarunG
10
Ditutup sebagai tidak konstruktif? Saya telah belajar banyak dari mengajukan pertanyaan ini! Sedikit konsistensi dari StackOverflow juga akan lebih baik ... misalnya stackoverflow.com/questions/550632/…
si618
15
Itu mendapat '203' Ups, itu cukup baginya untuk membuktikan kegunaannya.
TarunG
Pertanyaan SO harus memiliki jawaban yang pasti dan benar; pertanyaan terbuka membuat pertanyaan yang diajukan orang tentang masalah aktual keluar dari halaman depan. faq @Si .: Kebijakan itu selalu ada di sana AFAIK, tetapi lebih baik diberlakukan sekarang; pertanyaan itu sudah hampir tiga tahun.
Jim Dagg
Cukup adil Jim, itu adalah pertanyaan terbuka, dan saya kira itu tergantung pada komunitas SO untuk memutuskan, tetapi saya harus mengatakan bahwa menutupnya sebagai tidak konstruktif tampak aneh, mengingat bahwa saya dan dari penampilannya, banyak orang lain telah menemukan pertanyaan ini bermanfaat (mis. goo.gl/Zqp2X ), dan sangat cocok dengan practical, answerable questions based on actual problems that you facebagian dari FAQ.
si618

Jawaban:

157
  1. Simpan variabel dalam wxifile sertakan yang terpisah . Memungkinkan penggunaan ulang, variabel lebih cepat ditemukan dan (jika perlu) memungkinkan manipulasi lebih mudah oleh alat eksternal.

  2. Tentukan variabel Platform untuk build x86 dan 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. Simpan lokasi instalasi di registri, memungkinkan peningkatan untuk menemukan lokasi yang benar. Misalnya, jika pengguna menetapkan direktori pemasangan khusus.

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

    Catatan : Guru WiX Rob Mensching telah memposting entri blog yang bagus yang lebih detail dan memperbaiki casing tepi saat properti diatur dari baris perintah.

    Contoh menggunakan 1. 2. dan 3.

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

    dan

    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="$(var.PlatformProgramFilesFolder)">
        <Directory Id="INSTALLLOCATION" Name="$(var.InstallName)">
  4. Pendekatan paling sederhana adalah selalu melakukan peningkatan besar - besaran , karena memungkinkan penginstalan baru dan peningkatan di MSI tunggal. UpgradeCode ditetapkan ke Panduan unik dan tidak akan pernah berubah, kecuali kami tidak ingin meningkatkan produk yang ada.

    Catatan : Di WiX 3.5 ada elemen MajorUpgrade baru yang membuat hidup lebih mudah !

  5. Membuat ikon di Tambah / Hapus Program

    <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. Pada rilis build, kami versi installer kami, menyalin file msi ke direktori penempatan. Contoh dari ini menggunakan target wixproj dipanggil dari target 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. Gunakan panas untuk memanen file dengan wildcard (*) Guid. Berguna jika Anda ingin menggunakan kembali file WXS di beberapa proyek (lihat jawaban saya di beberapa versi dari produk yang sama). Misalnya, file batch ini secara otomatis memanen output 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 

    Ada sedikit yang terjadi, robocopymenghapus metadata copy pekerjaan Subversion sebelum panen; yang -drreferensi direktori root diatur ke lokasi instalasi kita daripada TARGETDIR default; -vardigunakan untuk membuat variabel untuk menentukan direktori sumber (output penyebaran web).

  8. Cara mudah untuk memasukkan versi produk dalam judul dialog sambutan dengan menggunakan Strings.wxl untuk pelokalan. (Kredit: saschabeaumont . Ditambahkan sebagai tip yang bagus ini disembunyikan dalam komentar)

    <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. Selamatkan diri Anda dari rasa sakit dan ikuti saran Wim Coehen tentang satu komponen per file. Ini juga memungkinkan Anda untuk meninggalkan (atau wild-card *) komponen GUID .

  10. Rob Mensching memiliki cara yang rapi untuk melacak dengan cepat masalah dalam file log MSI dengan mencari value 3. Perhatikan komentar tentang internasionalisasi.

  11. Saat menambahkan fitur bersyarat, lebih intuitif untuk mengatur level fitur default ke 0 (dinonaktifkan) dan kemudian mengatur level kondisi ke nilai yang Anda inginkan. Jika Anda mengatur level fitur default> = 1, level kondisi harus 0 untuk menonaktifkannya, artinya logika kondisi harus berlawanan dengan apa yang Anda harapkan, yang dapat membingungkan :)

    <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>
rev si618
sumber
Tentang menambahkan ikon di Tambah / Hapus Program, itu PERSIS apa yang saya cari. Di mana Anda menempel tiga garis itu? +1 untuk kemegahan belaka.
Everett
Saya cenderung menempatkan mereka tepat setelah (dan jelas di bawah) elemen <Package>. Lihat skema untuk validitas wix.sourceforge.net/manual-wix3/schema_index.htm
si618
+1, seandainya saya bisa melakukan +100, ini adalah informasi Wix paling berguna yang pernah saya temukan.
Tim Long
Terima kasih Tim! Rob Mensching, Bob Arson, Wim Coehen dan lainnya pantas mendapatkan pujian karena berbagi pengetahuan mereka.
si618
38

Memeriksa apakah IIS diinstal:

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

Memeriksa apakah Kompatibilitas Metabase IIS 6 diinstal pada 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>
Simon Steele
sumber
34

Simpan semua ID di ruang nama yang terpisah

  • Fitur dimulai dengan F. Contoh: F.Documentation, F.Binaries, F.SampleCode.
  • Komponen dimulai dengan C. Mis: C.ChmFile, C.ReleaseNotes, C.LicenseFile, C.IniFile, C.Registry
  • CustomActions adalah CA. Ex: CA.LaunchHelp, CA.UpdateReadyDlg, CA.SetPropertyX
  • File adalah Fi.
  • Direktori adalah Di.
  • dan seterusnya.

Saya menemukan ini sangat membantu dalam melacak semua berbagai id di semua kategori.

Cheeso
sumber
Saya tidak menggunakan ruang nama tetapi saya menambahkan ID; misalnya: ExamplesFeature, ChmFileComponent. Saya kira saya suka mengetik ;-)
dvdvorle
25

Pertanyaan yang fantastis. Saya ingin melihat beberapa praktik terbaik ditampilkan.

Saya punya banyak file yang saya distribusikan, jadi saya mengatur proyek saya menjadi beberapa file sumber wxs.

Saya memiliki file sumber level atas yang saya sebut Product.wxs yang pada dasarnya berisi struktur untuk instalasi, tetapi bukan komponen sebenarnya. File ini memiliki beberapa bagian:

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

Sisa file .wix terdiri dari Fragmen yang berisi ComponentGroups yang direferensikan dalam tag Fitur di Product.wxs. Proyek saya berisi pengelompokan logis yang bagus dari file yang saya distribusikan

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

Ini tidak sempurna, indra laba-laba OO saya sedikit menggelitik karena fragmen-fragmen harus merujuk nama-nama dalam file Product.wxs (misalnya DirectoryRef) tetapi saya merasa lebih mudah untuk mempertahankan bahwa satu file sumber besar tunggal.

Saya ingin mendengar komentar tentang ini, atau jika ada yang punya tips bagus juga!

Peter Tate
sumber
Pengaturan kami juga sangat mirip dengan pendekatan ini. Itu bagus karena kita dapat menggunakan produk kami yang setara dengan Products.wxs sebagai pengaturan dasar kami untuk berbagai produk.
si618
@Peter Tate: indera laba-laba Anda benar. Lihat jawaban saya tentang direktori alias.
Wim Coenen
Saya mengambil pendekatan yang sama: Product.wxs dengan tata letak statis, dan tugas build (heat.exe) menghasilkan file Content.wxs saya
timvw
20

Tambahkan kotak centang ke dialog keluar untuk meluncurkan aplikasi, atau file bantuan.

...

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

Jika Anda melakukannya dengan cara ini, penampilan "standar" tidak tepat. Kotak centang selalu memiliki latar belakang abu-abu, sementara dialog berwarna putih:

alt teks http://www.dizzymonkeydesign.com/blog/misc/adding-and-customizing-dlgs-in-wix-3/images/exit_dlg_1.gif

Salah satu caranya adalah dengan menentukan ExitDialog kustom Anda sendiri, dengan kotak centang yang terletak berbeda . Ini berfungsi, tetapi sepertinya banyak pekerjaan hanya untuk mengubah warna satu kontrol. Cara lain untuk menyelesaikan hal yang sama adalah memposting proses MSI yang dihasilkan untuk mengubah bidang X, Y di tabel Control untuk kontrol kotak centang tertentu. Kode javascript terlihat seperti ini:

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

Menjalankan kode ini sebagai skrip baris perintah (menggunakan cscript.exe) setelah MSI dihasilkan (dari light.exe) akan menghasilkan ExitDialog yang terlihat lebih profesional:

alt teks http://www.dizzymonkeydesign.com/blog/misc/adding-and-customizing-dlgs-in-wix-3/images/exit_dlg_2.gif

Cheeso
sumber
Ha! Bukan blog saya. Saya membacanya juga. Dan saya memiliki tautan ke entri blog dalam teks di atas. Tetapi mereka melakukannya secara berbeda dari saya. Saya suka cara saya lebih baik. !!
Cheeso
1
Terima kasih atas js, sangat membantu! Satu hal yang harus saya ubah di wxs adalah ganti WIXUI_EXITDIALOGOPTIONALCHECKBOXdengan WIXUI_EXITDIALOGOPTIONALCHECKBOX = 1 and NOT Installeddi dalam<Publish>
Alexander Kojevnikov
Apakah ada cara untuk membuat kotak centang dicentang secara default?
Alek Davis
Untuk mencentang kotak secara default, saya menggunakan ini: <Property Id = "WIXUI_EXITDIALOGOPTIONALCHECKBOX" Value = "1" />
Alek Davis
Sepertinya solusi yang bagus, tapi bagaimana cara menggunakannya? Apakah ada cara untuk meletakkan js di dalam elemen <AfterBuild> di wixproj saya? Atau karena Anda merujuk menjalankannya dari baris perintah, apakah lebih baik sebagai peristiwa pasca-pembangunan, dalam hal ini, apa penerjemah baris perintah js yang baik untuk Windows?
vanmelle
18

Membuat versi Live, Test, Training, ... menggunakan file sumber yang sama.

Singkatnya: Buat UpgradeCode unik untuk setiap pemasang dan secara otomatis tentukan karakter pertama dari masing-masing Panduan untuk setiap pemasang, meninggalkan 31 unik lainnya.

Prasyarat

Asumsi

  • Variabel WiX digunakan untuk menentukan UpgradeCode, ProductName, InstallName.
  • Anda sudah memiliki installer yang berfungsi. Saya tidak akan mencoba ini sampai Anda melakukannya.
  • Semua Komponen Anda disimpan dalam satu file (Components.wxs). Proses ini akan berfungsi jika Anda memiliki banyak file, hanya akan ada lebih banyak pekerjaan yang harus dilakukan.

Struktur Direktori

  • Pengaturan. Perpustakaan
    • Semua file wxs (Komponen, Fitur, Dialog UI, ...)
    • Common.Config.wxi (ProductCode = "*", ProductVersion, PlatformProgramFilesFolder, ...)
  • Setup.Live (wixproj)
    • Tautkan semua file Setup.Library menggunakan "Tambah File yang Ada" -> "Tambahkan Sebagai Tautan" (tombol panah bawah kecil tepat di sebelah tombol Tambahkan di Visual Studio)
    • Config.wxi (memiliki UpgradeCode, ProductName, InstallName, ...) yang unik
  • Setup . Pengujian , ...
    • sesuai langsung tetapi Config.wxi dikonfigurasi untuk lingkungan Test.

Proses

  • Buat direktori Setup.Library dan pindahkan semua file wxs dan wxi Anda (kecuali Config.wxi) dari proyek yang ada.
  • Buat Setup.Live, Setup.Test, dll sesuai dengan wixproj normal.
  • Tambahkan target BeforeBuild di wixproj di Setup.Live, dll untuk melakukan FileUpdate Tugas Komunitas MSBuild untuk memodifikasi Panduan (Saya menggunakan A untuk Live, B untuk Tes dan C untuk pelatihan)
  • Tambahkan target AfterBuild untuk mengembalikan Components.wxs Panduan kembali ke 0.
  • Verifikasi dengan Orca bahwa setiap komponen di setiap MSI memiliki panduan yang dimodifikasi.
  • Pastikan bahwa pedoman asli dipulihkan.
  • Verifikasi bahwa setiap MSI menginstal (dan meningkatkan) produk dan lokasi yang benar.

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

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

Contoh 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">
          ...

Catatan: Sekarang saya sarankan untuk tidak menyertakan atribut Guid dari Component (setara dengan *), menggunakan satu file per komponen dan mengatur file sebagai keypath. Ini menghilangkan kebutuhan untuk panggilan ModifyComponentsGuidsdan RevertComponentsGuidstarget yang ditunjukkan di bawah ini. Ini mungkin tidak mungkin untuk semua komponen Anda.

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

Pikiran terakhir

  • Proses ini juga harus berfungsi untuk membuat installer yang berbeda untuk modul gabungan yang berbeda (Live, Test, ... sebagai fitur) untuk installer yang sama. Saya menggunakan penginstal yang berbeda karena sepertinya opsi yang lebih aman, ada risiko lebih besar bahwa seseorang mungkin meningkatkan Live daripada Pelatihan jika mereka menggunakan kotak yang sama dan Anda hanya menggunakan fitur untuk berbagai modul gabungan.
  • Jika Anda menggunakan MSI Anda untuk melakukan peningkatan serta menginstal baru yaitu pendekatan hanya upgrade utama, dan Anda menyimpan lokasi instalasi Anda di registri, ingatlah untuk membuat variabel untuk nama kunci untuk setiap instalasi.
  • Kami juga membuat variabel di setiap Config.wxi untuk mengaktifkan nama direktori virtual unik, kumpulan aplikasi, nama database, dan lain-lain untuk setiap penginstal.

PEMBARUAN 1: Panduan komponen penghasil otomatis menghapus kebutuhan untuk memanggil tugas FileUpdate jika Anda membuat komponen dengan Guid = "*" untuk setiap file, mengatur file sebagai keypath.

UPDATE 2: Salah satu masalah yang kami hadapi adalah jika Anda tidak membuat komponen Guid's dan pembuatannya gagal, maka file temp perlu dihapus secara manual.

UPDATE 3: Menemukan cara untuk menghapus ketergantungan pada svn: eksternal dan pembuatan file sementara. Hal ini membuat proses pembuatan lebih tangguh (dan merupakan pilihan terbaik jika Anda tidak dapat wildcard Panduan Anda) dan kurang rapuh jika ada kegagalan membangun dalam cahaya atau lilin.

UPDATE 4: Dukungan untuk Beberapa Instans menggunakan transformasi instan ada di WiX 3.0+, pasti juga patut dilihat.

si618
sumber
+1 untuk referensi Tugas Komunitas MSBuild, suka paket itu
BozoJoe
17

Menggunakan Msi Diagnostic logging untuk mendapatkan Informasi kegagalan yang terperinci

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

Dimana

Paket.msi
adalah nama paket Anda dan
c: \ Package.log
adalah tempat Anda menginginkan output dari log

Kode Kesalahan Msi

Wix Intro Video
Oh dan Random Wix intro video yang menampilkan "Mr. WiX" Rob Mensching adalah "gambaran besar konseptual" bermanfaat.

Terrance
sumber
2
+1 Akan jauh lebih baik jika kita dapat mengaktifkan pencatatan dari dalam Wix daripada baris perintah.
si618
3
WiX tidak. Setel properti MsiLogging. Hanya didukung oleh Windows Installer 4.0+.
Rob Mensching
Terima kasih banyak "Pak Wix". Harus memeriksanya.
Terrance
17

Gunakan Javascript CustomActions karena sangat mudah

Orang-orang mengatakan bahwa Javascript adalah hal yang salah untuk digunakan untuk MSI CustomActions . Alasan yang diberikan: sulit di-debug, sulit untuk diandalkan. Saya tidak setuju. Tidak sulit untuk debug, tentu tidak lebih sulit daripada C ++. Hanya berbeda. Saya menemukan penulisan CustomActions dalam Javascript menjadi super mudah, jauh lebih mudah daripada menggunakan C ++. Lebih cepat. Dan sama andal.

Hanya ada satu kelemahan: Javascript CustomActions dapat diekstraksi melalui Orca, sedangkan C / C ++ CA akan membutuhkan rekayasa balik. Jika Anda menganggap sihir pemasang Anda sebagai properti intelektual yang dilindungi, Anda harus menghindari skrip.

Jika Anda menggunakan skrip, Anda hanya perlu mulai dengan beberapa struktur. Inilah beberapa untuk Anda mulai.


Kode Javascript "boilerplate" untuk CustomAction:

//
// 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
    };
}

Lalu, daftarkan tindakan khusus dengan sesuatu seperti ini:

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

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

Anda dapat, tentu saja, menyisipkan fungsi Javascript sebanyak yang Anda suka, untuk beberapa tindakan kustom. Salah satu contoh: Saya menggunakan Javascript untuk melakukan kueri WMI pada IIS, untuk mendapatkan daftar situs web yang ada, di mana filter ISAPI dapat diinstal. Daftar ini kemudian digunakan untuk mengisi kotak daftar yang ditampilkan kemudian dalam urutan UI. Semua sangat mudah.

Pada IIS7, tidak ada penyedia WMI untuk IIS, jadi saya menggunakan shell.Run()pendekatan untuk memanggil appcmd.exe untuk melakukan pekerjaan. Mudah.

Pertanyaan terkait: Tentang Javascript CustomActions

Cheeso
sumber
2
+1 Saya menemukan pendekatan DTF mudah diatur, tetapi javascript juga bisa bermanfaat.
si618
12

Peter Tate telah menunjukkan bagaimana Anda dapat mendefinisikan definisi ComponentGroup yang dapat digunakan kembali dalam fragmen wix yang terpisah. Beberapa trik tambahan terkait dengan ini:

Direktori Aliasing

Fragmen grup komponen tidak perlu tahu tentang direktori yang ditentukan oleh produk utama wxs. Di fragmen grup komponen Anda, Anda dapat berbicara tentang folder seperti ini:

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

Kemudian produk utama dapat alias salah satu direktori (mis. "ProductInstallFolder") seperti ini:

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

Grafik Ketergantungan

Elemen ComponentGroup dapat berisi elemen anak ComponentGroupRef. Ini bagus jika Anda memiliki kumpulan besar komponen yang dapat digunakan kembali dengan grafik ketergantungan yang kompleks di antara mereka. Anda cukup mengatur ComponentGroup di fragmennya sendiri untuk setiap komponen dan mendeklarasikan dependensi seperti ini:

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

Jika sekarang Anda mereferensikan grup komponen "B" di pengaturan Anda karena itu adalah ketergantungan langsung dari aplikasi Anda, itu akan secara otomatis menarik grup komponen "A" bahkan jika pembuat aplikasi tidak pernah menyadari bahwa itu adalah ketergantungan dari "B". Ini "hanya berfungsi" selama Anda tidak memiliki dependensi melingkar.

Wixlib dapat digunakan kembali

Gagasan grafik dependensi di atas bekerja paling baik jika Anda mengkompilasi komponen pool-o-reusable-besar ke wixlib yang dapat digunakan kembali dengan lit.exe. Saat membuat pengaturan aplikasi, Anda dapat mereferensikan wixlib ini seperti file wixobj. Linker candle.exe akan secara otomatis menghilangkan setiap fragmen yang tidak "ditarik" oleh file wxs produk utama.

Wim Coenen
sumber
12

Saya terkejut tidak ada yang disebutkan menggunakan T4 untuk menghasilkan file WXS selama membangun. Saya belajar tentang ini melalui Henry Lee @ New Age Solutions .

Pada dasarnya, Anda membuat tugas MSBuild khusus untuk mengeksekusi templat T4, dan templat tersebut menghasilkan WXS tepat sebelum proyek Wix dikompilasi. Ini memungkinkan Anda untuk (tergantung pada bagaimana Anda menerapkannya) secara otomatis menyertakan semua output majelis dari mengkompilasi solusi lain (yang berarti bahwa Anda tidak lagi harus mengedit wxs setiap kali Anda menambahkan perakitan baru).

Peter T. LaComb Jr.
sumber
2
+1 itu benar-benar bagus, saya tidak terlalu khawatir tentang majelis, tetapi proyek web kami dapat memiliki masalah dengan halaman aspx dan artefak lainnya (gambar, css) yang ditambahkan ke proyek tetapi tidak WiX.
si618
4
Untuk pengunjung masa depan, Wix 3.5 memiliki utilitas heat.exe yang melakukan pemanenan ini secara otomatis
Mrchief
@ Mcrief - Saya tidak percaya Heat mengambil rujukan yang disalin lokal - ini tampaknya direncanakan untuk 4.0. Referensi: sourceforge.net/tracker/…
Peter T. LaComb Jr
Panas tidak mengambil rakitan yang direferensikan.
tofutim
Apa saja contoh bagus menggunakan T4 untuk menghasilkan file WXS?
tofutim
12

Menggunakan Heat.exe untuk menghancurkan wajah dan menimbulkan "Epic Pwnage" pada pemasangan besar yang menyakitkan

Memperluas jawaban Si dan Robert-P tentang panas.

Terjemahan: (Menggunakan panas untuk menghindari pengetikan file individual ke dalam proyek dengan tangan dan untuk mengotomatisasi pembuatan untuk proses yang lebih mudah secara keseluruhan.)

WiX 2.0 Heat Syntax merinci

Untuk versi yang lebih baru (tidak semua yang berbeda dari versi yang lebih lama tetapi ada kemungkinan perubahan sintaks yang mengganggu ....) buka direktori Heat is in dari cmd.exe dan ketik saja heat tetapi saya punya contoh di sini untuk bantuan dengan versi yang lebih baru jika diperlukan.

Menambahkan berikut ke Build Event Anda di visual studio 2010.
(Klik kanan Project-> Properties -> Build Events-> Pre-Build Events)

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

-gg 

Menghasilkan Panduan ketika panas dijalankan (seperti ketika Anda menjalankan perintah di atas)

-sekarang 

Jangan ambil "file COM"

-reg 

Jangan ambil "File Registry"

-frag 

Jangan ambil "Fragmen"

-srd 

Jangan ambil "root Dir"

dir

dir menunjukkan Anda ingin Panas melihat dalam folder

"$ (EnviromentVariable)"

Nama variabel yang akan Anda tambahkan ke variabel Preprocessor di (proyek Klik kanan, Pergi ke properti) properti proyek-> bagian Build di mana ia mengatakan Tentukan variabel preprocessor (mengasumsikan visual studio 2010)

Contoh:
EnviromentVariable = C: \ Project \ bin \ Debug;
Tidak ada tanda kutip ganda tetapi diakhiri dengan tanda titik koma

-cg GroupVariable 

ComponentGroup yang akan direferensikan dari fragmen yang dibuat ke file wxs utama

FragmentDir

Direktori fragmen tempat fragmen wxs output akan disimpan

FileName.wxs

Nama file

Tutorial lengkapnya di sini, So freakin bermanfaat

Bagian 1 Bagian 2

Terrance
sumber
Ada alat bermanfaat lain untuk tujuan yang sedikit berbeda: Parafin ( wintellect.com/CS/blogs/jrobbins/archive/2010/03/10/4107.aspx )
ralf.w.
9

Termasuk Objek COM:

heatmenghasilkan sebagian besar (jika tidak semua) entri registri dan konfigurasi lain yang diperlukan untuk mereka. Bersuka cita!

Termasuk Objek COM yang Dikelola (alias, objek .NET atau C # COM)

Menggunakan heatpada objek COM yang dikelola akan memberi Anda dokumen wix yang hampir lengkap.

Jika Anda tidak memerlukan pustaka yang tersedia di GAC (yaitu, tersedia secara global: PALING saat Anda tidak memerlukan ini dengan rakitan .NET Anda - Anda mungkin telah melakukan kesalahan pada titik ini jika tidak dimaksudkan untuk menjadi perpustakaan bersama) Anda akan ingin memastikan untuk memperbarui CodeBasekunci registri yang akan ditetapkan [#ComponentName]. Jika Anda berencana menginstalnya ke GAC (mis., Anda telah membuat beberapa perpustakaan umum baru yang mengagumkan yang semua orang ingin gunakan), Anda harus menghapus entri ini, dan menambahkan dua atribut baru ke Fileelemen: Assemblyand KeyPath. Majelis harus diatur ke ".net" dan KeyPathharus diatur ke "ya".

Namun, beberapa lingkungan (terutama apa pun dengan memori yang dikelola seperti bahasa scripting) akan memerlukan akses ke Typelib juga. Pastikan untuk menjalankan heattypelib Anda dan sertakan. heatakan menghasilkan semua kunci registri yang diperlukan. Betapa kerennya itu?

Robert P.
sumber
8

Menginstal ke C:\ProductName

Beberapa aplikasi perlu diinstal ke C:\ProductNameatau sesuatu yang serupa, tetapi 99,9% (jika tidak 100%) dari contoh di instal bersih C:\Program Files\CompanyName\ProductName.

Kode berikut dapat digunakan untuk mengatur TARGETDIRproperti ke root C:drive (diambil dari daftar pengguna 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>

CATATAN: Secara default, TARGETDIR tidak mengarah ke C:\! Ini lebih mengarah ke ROOTDRIVEmana pada gilirannya menunjuk ke root drive dengan ruang paling bebas ( lihat di sini ) - dan ini belum tentu C:drive. Mungkin ada hard drive, partisi, atau USB drive lain!

Kemudian, di suatu tempat di bawah <Product ...>tag Anda, Anda memerlukan tag direktori berikut seperti biasa:

<Directory Id="TARGETDIR" Name="SourceDir">
    <Directory Id="APPLICATIONFOLDER" Name="$(var.ProductName)">
        <!-- your content goes here... -->
    </Directory>
</Directory>
geho
sumber
Bukankah lebih mudah untuk menginstal saja WindowsVolume?
Wim Coenen
1
Ya, tetapi Anda harus menggunakan solusi karena WindowsVolumeproperti tidak dapat digunakan sebagai Directory(kompiler memberikan kesalahan / peringatan), seperti yang ditunjukkan di sini dan di sini . Secara pribadi, saya menemukan solusi yang membingungkan.
gehho
7

Variabel Lingkungan

Saat mengkompilasi dokumen Wxs Anda ke kode wixobj, Anda dapat menggunakan variabel lingkungan untuk menentukan berbagai informasi. Misalnya, katakanlah Anda ingin mengubah file mana yang disertakan dalam proyek. Katakanlah Anda memiliki variabel lingkungan bernama RELEASE_MODE, yang Anda atur tepat sebelum Anda membangun MSI Anda (baik dengan skrip atau secara manual, itu tidak masalah) Di sumber wix Anda, Anda dapat melakukan sesuatu seperti:

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

dan kemudian dalam kode Anda, gunakan di tempat untuk dengan cepat mengubah dokumen wxs Anda, misalnya:

<Icon Id="myicon.ico" SourceFile="$(var.FILESOURCE)" />
Robert P.
sumber
1
Juga variabel kompilasi seperti $ (Konfigurasi) dan $ (Platform) tersedia. Juga banyak lagi di msdn.microsoft.com/en-us/library/aa302186.aspx
si618
1
@ Si - Beberapa saat sebelum hari ini, tautan itu tidak lagi aktif. Saya tidak dapat menemukan yang terbaru.
Peter M
7

Mengedit Dialog

Satu kemampuan yang baik untuk mengedit dialog adalah menggunakan SharpDevelop dalam versi 4.0.1.7090 (atau lebih tinggi). Dengan bantuan alat ini, dialog mandiri (file wxs dari sumber WiX seperti misalnya InstallDirDlg.wxs) dapat dibuka, dipratinjau, dan diedit dalam tampilan Desain.

pengguna432758
sumber
Luar biasa, tidak tahu SharpDevelop mendukung ini.
anton.burger
6

Mengatur flag 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" />
EdmundYeung99
sumber
5

Ubah "Siap menginstal?" dialog (alias VerifyReadyDlg) untuk memberikan ringkasan pilihan yang dibuat.

Ini terlihat seperti ini:
alt text http://i46.tinypic.com/s4th7t.jpg

Lakukan ini dengan Javascript CustomAction:


Kode Javascript:

// 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);
}

Deklarasikan Javascript CA:

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

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

Pasang CA ke tombol. Dalam contoh ini, CA dipecat ketika Berikutnya diklik dari CustomizeDlg:

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

Pertanyaan SO Terkait: Bagaimana saya bisa mengatur, saat runtime, teks yang akan ditampilkan di VerifyReadyDlg?

Cheeso
sumber
Tentunya seharusnya ini bukan JScript bahasa skrip windows daripada JavaScript bahasa skrip DHTML. Mungkin agak menyombongkan diri, tetapi bisa sedikit membingungkan bagi beberapa orang.
caveman_dick
5

Masukkan Komponen yang dapat ditambal secara terpisah di dalam Fragmen mereka sendiri

Ini berlaku untuk membuat installer produk dan tambalan bahwa jika Anda memasukkan komponen apa pun dalam sebuah fragmen, Anda harus memasukkan semua komponen dalam fragmen itu. Dalam hal membangun penginstal, jika Anda melewatkan referensi komponen, Anda akan mendapatkan kesalahan penautan dari light.exe. Namun, saat Anda membuat tambalan, jika Anda menyertakan referensi komponen tunggal dalam sebuah fragmen, maka semua komponen yang diubah dari fragmen itu akan muncul di tambalan Anda.

seperti ini:

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

alih-alih ini:

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

Juga, ketika menambal menggunakan topik "Menggunakan Murni WiX" dari file bantuan WiX.chm, menggunakan prosedur ini untuk menghasilkan tambalan:

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

tidak cukup hanya memiliki versi 1.1 dari product.wixpdb yang dibangun menggunakan komponen dalam fragmen yang terpisah. Jadi pastikan untuk memecah-mecah produk Anda dengan benar sebelum pengiriman.

Dave Andersen
sumber
5

Mencetak EULA dari Wix3.0 dan yang lebih baru

1) Ketika Anda mengkompilasi kode sumber wix Anda, light.exe harus mereferensikan WixUIExtension.dll di baris perintah. Gunakan saklar baris perintah -ext untuk ini.

2) Jika ketika Anda menambahkan referensi ke WixUIExtension.dll, proyek Anda gagal dikompilasi, ini kemungkinan besar karena perselisihan ID Dialog, yaitu proyek Anda menggunakan ID dialog yang sama dengan beberapa dialog standar di WixUIExtension.dll, berikan ID yang berbeda untuk dialog Anda. Ini masalah yang cukup umum.

3) Dialog lisensi Anda harus memiliki kontrol ScrollableText dengan id "LicenseText". Wix mencari persis nama kontrol ini ketika mencetak.

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

dan Tombol Tekan yang mengacu pada tindakan kustom

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

4) Tentukan CustomAction dengan Id = "PrintEula" seperti ini:

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

Catatan: BinaryKey berbeda di Wix3.0 dibandingkan dengan Wix2.0 dan harus persis "WixUIWixca" (case sensitif).

Ketika pengguna menekan tombol dia akan disajikan dengan Select Dialog Printer standar dan akan dapat mencetak dari sana.

farfareast
sumber
5
  • Kami menampilkan versi produk di suatu tempat (kecil) di layar pertama GUI. Karena orang cenderung melakukan kesalahan dalam memilih versi yang tepat setiap saat. (Dan buat kami pengembang mencari usia ..)

  • Kami telah menyiapkan TFSBuild untuk juga menghasilkan transformasi (file .mst) dengan konfigurasi untuk lingkungan kami yang berbeda. (Kami tahu semua lingkungan tempat kami perlu menerapkan).

Karena posting weblog asli oleh Grant Holliday sedang down, saya salin isinya di sini:


Tugas MSBuild untuk menghasilkan file MSI Transform dari XMLMarch 11 2008

Dalam posting saya sebelumnya saya menjelaskan bagaimana Anda dapat menggunakan file MSI Transform (* .mst) untuk memisahkan pengaturan konfigurasi khusus lingkungan dari paket MSI umum.

Meskipun ini memberikan tingkat fleksibilitas dalam konfigurasi Anda, ada dua sisi bawah dari file Transform:

  1. Mereka adalah format biner
  2. Anda tidak dapat "mengedit" atau "melihat" file transformasi. Anda harus menerapkannya atau membuat ulang untuk melihat perubahan apa yang termasuk di dalamnya.

Untungnya kita dapat menggunakan Perpustakaan Objek Pemasang Microsoft Windows (c: windowssystem32msi.dll) untuk membuka "database" MSI dan membuat file transformasi.

Kredit kembali ke Alex Shevchuk - Dari MSI ke WiX - Bagian 7 - Menyesuaikan instalasi menggunakan Transforms untuk menunjukkan kepada kita bagaimana mencapainya dengan VbScript. Pada dasarnya semua yang saya lakukan adalah mengambil contoh Alex dan menggunakan Interop.WindowsInstaller.dll Saya sudah mengimplementasikan tugas MSBuild. Tugas MSBuild

Unduh kode sumber & contoh transforms.xml di sini (~ 7Kb Zip Solusi VS2008)


Terima kasih
sumber
2
Kami mendefinisikan kembali WelcomeDlgTitle dalam file pelokalan saya - berfungsi dengan baik! <String Id = "WelcomeDlgTitle"> {\ WixUI_Font_Bigger} Selamat datang di [ProductName] [ProductVersion] Setup Wizard </String>
saschabeaumont
5

Sebelum menggunakan paket instal, saya selalu mengontrol kontennya.

Itu hanya panggilan sederhana di baris perintah (sesuai dengan posting Terrences) buka baris perintah dan masukkan

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

Ini akan mengekstrak konten paket ke subdir 'Ekstrak' dengan jalur saat ini.

tobaer
sumber
4

Alih-alih ORCA menggunakan InstEd yang merupakan alat yang baik untuk melihat tabel MSI. Juga memiliki kemampuan untuk membedakan dua paket dengan Transform -> Compare To ...

Selain itu versi Plus dengan fungsionalitas tambahan tersedia. Tetapi juga versi gratisnya menawarkan alternatif yang baik untuk Orca.

user432758
sumber
4

Mendaftarkan majelis .NET untuk COM Interop dengan kompatibilitas x86 / x64

NB Fragmen ini pada dasarnya sama dengan REGASM Assembly.dll / basis kode

Beberapa hal sedang terjadi dalam sampel ini jadi inilah kodenya dan saya akan menjelaskannya setelah itu ...

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

Jika Anda bertanya-tanya, ini sebenarnya untuk Driver Teleskop ASCOM .

Pertama, saya mengambil saran dari atas dan membuat beberapa variabel platforma dalam file terpisah, Anda dapat melihat mereka yang tersebar melalui XML.

Bagian if-then-else di dekat penawaran teratas dengan kompatibilitas x86 vs x64. Perakitan saya menargetkan 'Any CPU' jadi pada sistem x64, saya harus mendaftarkannya dua kali, sekali di registri 64-bit dan sekali di area 32-bit Wow6432Node. If-then-else mengatur saya untuk ini, nilai-nilai digunakan dalam aforeach loop nanti. Dengan cara ini, saya hanya perlu menulis kunci registri sekali (prinsip KERING).

Elemen file menentukan dll perakitan yang sebenarnya sedang diinstal dan terdaftar:

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

Tidak ada yang revolusioner, tetapi perhatikan Assembly=".net"- atribut ini saja akan menyebabkan perakitan dimasukkan ke GAC, yang BUKAN apa yang saya inginkan. Menggunakan AssemblyApplicationatribut untuk menunjuk kembali ke dirinya sendiri hanyalah cara menghentikan Wix menempatkan file ke GAC. Sekarang Wix tahu itu adalah .net assembly, meskipun, itu memungkinkan saya menggunakan variabel pengikat tertentu dalam XML saya, seperti !(bind.assemblyFullname.filDriverAssembly)untuk mendapatkan nama lengkap perakitan.

Tim Long
sumber
3

Tetapkan DISABLEADVTSHORTCUTSproperti untuk memaksa semua pintasan yang diiklankan di pemasang Anda menjadi pintasan biasa, dan Anda tidak perlu menyertakan kunci reg dummy untuk digunakan sebagai keypath.

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

Saya pikir Windows Installer 4.0 atau lebih tinggi adalah persyaratan .

Dave Andersen
sumber
2

Ini struktur yang bagus tapi berdasarkan pengalaman saya, saya ingin tahu bagaimana Anda mengatasi kondisi ini:

A. Semua instal Anda tampaknya mendarat di tujuan yang sama. Jika pengguna perlu menginstal semua 3 versi sekaligus, proses Anda akan memungkinkan ini. Bisakah mereka dengan jelas mengatakan versi mana dari setiap executable yang mereka picu?

B. Bagaimana Anda menangani file baru yang ada di TEST dan / atau PELATIHAN tetapi belum di LIVE?


sumber
Hai Blaine, A. Tidak, mereka tidak. InstallName ada di Config.wxi yang merupakan satu-satunya file yang tidak dirujuk oleh svn: externals. Jadi ini unik untuk setiap pemasangan, yaitu setiap produk. Itu juga mengapa kami memodifikasi Panduan untuk setiap versi. B. GOTO A. :) Mereka memisahkan MSI dengan UpgradeCode mereka sendiri.
si618
1
Ngomong-ngomong, saya mengerti mengapa Anda menjawab pertanyaan saya dengan pertanyaan, tetapi begitu Anda mendapatkan poin rep yang cukup, harap pindahkan pertanyaan Anda ke komentar jawaban, jika tidak, utas akan sulit untuk diikuti.
si618
2

Ini dia cara untuk membantu proyek web besar memverifikasi bahwa jumlah file yang digunakan cocok dengan jumlah file yang dibangun ke dalam MSI (atau menggabungkan modul). Saya baru saja menjalankan tugas MSBuild khusus terhadap aplikasi utama kami (masih dalam pengembangan) dan mengambil beberapa file yang hilang, sebagian besar gambar, tetapi beberapa file javascript telah lolos!

Pendekatan ini (mengintip ke dalam tabel File MSI dengan menghubungkan ke target AfterBuild proyek WiX) dapat bekerja untuk tipe aplikasi lain di mana Anda memiliki akses ke daftar lengkap file yang diharapkan.

si618
sumber
2

Melakukan penginstalan paksa saat penginstalan tidak memungkinkan penghapusan atau penginstalan ulang dan tidak dibatalkan.

Skrip VBscript digunakan untuk mengganti instalasi yang tidak menghapus instalasi untuk alasan apa pun ..

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)
Terrance
sumber
2

Buat UI yang memiliki tindakan kustom yang akan mengatur variabel dan UI akan menonaktifkan / mengaktifkan tombol berikutnya (atau serupa) berdasarkan variabel yang ditetapkan dalam tindakan kustom.

Tidak semudah yang Anda kira, tidak terlalu sulit tidak didokumentasikan di mana pun!

Interaksi Wix dengan Ketentuan, Properti & Tindakan Kustom

Daniel Powell
sumber