เทคนิคและเคล็ดลับของ WiX


264

เราใช้ WiX มาระยะหนึ่งแล้วถึงแม้จะใช้งานง่าย แต่ก็ใช้งานได้ดี สิ่งที่ฉันกำลังมองหาคือคำแนะนำที่เป็นประโยชน์เกี่ยวกับ:

  • การตั้งค่าโครงการ WiX (โครงร่างการอ้างอิงรูปแบบไฟล์)
  • การรวม WiX เข้ากับโซลูชันและกระบวนการสร้าง / วางจำหน่าย
  • การกำหนดค่าโปรแกรมติดตั้งสำหรับการติดตั้งและการอัพเกรดใหม่
  • WiX ที่ดีแฮ็กที่คุณต้องการแบ่งปัน

ดู gui4wix.codeplex.com
TarunG

10
ปิดเป็นไม่สร้างสรรค์? ฉันได้เรียนรู้มากมายจากการถามคำถามนี้! ความสอดคล้องเล็กน้อยจาก StackOverflow ก็จะดี ... เช่นstackoverflow.com/questions/550632/
si618

15
มันได้อัพ '203' ซึ่งเพียงพอสำหรับการพิสูจน์ประโยชน์
TarunG

ดังนั้นคำถามต้องมีคำตอบที่ชัดเจนและถูกต้อง; คำถามปลายเปิดทำให้คำถามที่คนถามเกี่ยวกับปัญหาที่แท้จริงส่งหน้าแรก faq @Si: นโยบายนั้นอยู่ที่นั่นเสมอ AFAIK แต่ตอนนี้บังคับใช้ดีกว่า คำถามนั้นเกือบสามปี
Jim Dagg

ยุติธรรมมากพอจิมมันเป็นคำถามปลายเปิดและฉันคิดว่ามันขึ้นอยู่กับชุมชน SO ที่จะตัดสินใจ แต่ฉันต้องบอกว่าการปิดมันไม่สร้างสรรค์ดูเหมือนแปลกเพราะฉันและด้วยรูปลักษณ์ของมันคนอื่น ๆ อีกมากมาย พบว่าคำถามนี้มีประโยชน์ (เช่นgoo.gl/Zqp2X ) และเหมาะกับpractical, answerable questions based on actual problems that you faceส่วนของคำถามที่พบบ่อย
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 guru Rob Menschingได้โพสต์รายการบล็อกที่ยอดเยี่ยมซึ่งจะมีรายละเอียดมากขึ้นและแก้ไขตัวพิมพ์ขอบเมื่อคุณสมบัติถูกตั้งค่าจากบรรทัดคำสั่ง

    ตัวอย่างการใช้ 1. 2. และ 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. การสร้างไอคอนใน Add / Remove Programs

    <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 ไปยังไดเรกทอรีการใช้งาน ตัวอย่างนี้ใช้เป้าหมาย wixproj ที่เรียกมาจากเป้าหมาย 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. ใช้ความร้อนเพื่อเก็บเกี่ยวไฟล์ด้วยสัญลักษณ์แทน (*) 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ลอกเมทาดาทาการโค่นล้มการทำงานก่อนที่จะทำการเก็บเกี่ยว การ-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 คอมโพเนนต์ (หรือ wild-card *) ออก

  10. ร็อบ 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>
    

เกี่ยวกับการเพิ่มไอคอนใน Add / Remove Programs มันเป็นสิ่งที่ฉันกำลังมองหา คุณติดสามบรรทัดนี้อยู่ไหน? +1 สำหรับสุดยอดที่แท้จริง
Everett

ฉันมักจะวางพวกเขาหลังจาก (และชัดเจนด้านล่าง) องค์ประกอบ <แพคเกจ> ลองดูที่ schema เพื่อ validity 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>

ตรวจสอบว่ามีการติดตั้ง IIS 6 Metabase Compatibility บน 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>

34

เก็บ ID ทั้งหมดในเนมสเปซที่แยกต่างหาก

  • คุณสมบัติเริ่มต้นด้วยF. ตัวอย่าง: F.Documentation, F.Binaries, F.SampleCode
  • ส่วนประกอบเริ่มต้นด้วยC. Ex: C.ChmFile, C.ReleaseNotes, C.LicenseFile, C.IniFile, C.Registry
  • CustomActions เป็นCA. ตัวอย่าง: CA.LaunchHelp, CA.UpdateReadyDlg, CA.SetPropertyX
  • ไฟล์ต่างๆ Fi.
  • ไดเรกทอรีเป็น Di.
  • และอื่น ๆ

ฉันพบว่าสิ่งนี้ช่วยได้อย่างมากในการติดตามรหัสต่างๆของทุกประเภทต่าง ๆ


ฉันไม่ได้ใช้เนมสเปซ แต่ฉันต่อท้ายรหัส; ตัวอย่างเช่น: ExamplesFeature, ChmFileComponent ฉันเดาว่าฉันชอบพิมพ์ ;-)
dvdvorle

25

คำถามที่ยอดเยี่ยม ฉันชอบที่จะเห็นการปฏิบัติที่ดีที่สุดที่แสดง

ฉันมีไฟล์จำนวนมากที่ฉันแจกจ่ายดังนั้นฉันจึงตั้งค่าโครงการเป็นไฟล์ wxs หลายแหล่ง

ฉันมีไฟล์ต้นฉบับระดับบนสุดที่ฉันเรียกว่า 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 นั้นประกอบด้วย Fragments ที่มี ComponentGroups ซึ่งมีการอ้างอิงในแท็กคุณสมบัติใน Product.wxs โครงการของฉันมีการจัดกลุ่มแบบลอจิคัลที่ดีของไฟล์ที่ฉันแจกจ่าย

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

นี่ไม่สมบูรณ์แบบ OO spider ของฉันรู้สึกเสียวซ่าเล็กน้อยเนื่องจากแฟรกเมนต์ต้องอ้างอิงชื่อในไฟล์ Product.wxs (เช่น DirectoryRef) แต่ฉันพบว่ามันง่ายกว่าที่จะรักษาว่าไฟล์ต้นฉบับขนาดใหญ่เพียงไฟล์เดียว

ฉันชอบที่จะได้ยินความคิดเห็นเกี่ยวกับเรื่องนี้หรือถ้าใครมีเคล็ดลับที่ดีเช่นกัน!


การตั้งค่าของเราก็คล้ายกับวิธีนี้มาก เป็นเรื่องที่ดีเพราะเราสามารถใช้ Products.wx ของเราเป็นฐานการตั้งค่าสำหรับผลิตภัณฑ์ที่หลากหลาย
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>

หากคุณทำเช่นนี้ลักษณะที่ปรากฏ "มาตรฐาน" ไม่ถูกต้องนัก ช่องทำเครื่องหมายเป็นพื้นหลังสีเทาเสมอในขณะที่กล่องโต้ตอบเป็นสีขาว:

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

วิธีหนึ่งในรอบนี้คือการระบุ ExitDialog ของคุณเองกับช่องทำเครื่องหมายที่แตกต่างกันอยู่ ใช้งานได้ แต่ดูเหมือนว่าจะเป็นงานจำนวนมากเพียงเพื่อเปลี่ยนสีของการควบคุม อีกวิธีหนึ่งในการแก้ไขสิ่งเดียวกันคือการเปลี่ยน MSI ที่สร้างขึ้นเพื่อเปลี่ยนฟิลด์ 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();

การเรียกใช้รหัสนี้เป็นสคริปต์บรรทัดคำสั่ง (ใช้ cscript.exe) หลังจากสร้าง MSI (จาก light.exe) จะสร้าง ExitDialog ที่ดูเป็นมืออาชีพมากขึ้น:

alt text 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>
อเล็กซานเด Kojevnikov

มีวิธีในการทำเครื่องหมายในช่องทำเครื่องหมายโดยค่าเริ่มต้นหรือไม่
Alek Davis

ในการตรวจสอบกล่องโดยค่าเริ่มต้นฉันใช้สิ่งนี้: <Property Id = "WIXUI_EXITDIALOGOPTIONALCHECKBOX" Value = "1" />
Alek Davis

ดูเหมือนว่าเป็นทางออกที่ดี แต่ฉันจะใช้มันได้อย่างไร มีวิธีการใส่ js ในองค์ประกอบ <AfterBuild> ใน wixproj ของฉันหรือไม่? หรือเนื่องจากคุณอ้างถึงการเรียกใช้จากบรรทัดคำสั่งจะดีกว่าเป็นเหตุการณ์ post-build ในกรณีใดล่ามบรรทัดคำสั่ง js ที่ดีสำหรับ Windows คืออะไร
vanmelle

18

การสร้างเวอร์ชันสดทดสอบการฝึกอบรม ... โดยใช้ไฟล์ต้นฉบับเดียวกัน

โดยสรุป: สร้าง UpgradeCode ที่ไม่ซ้ำกันสำหรับตัวติดตั้งแต่ละตัวและกำหนดอักขระตัวแรกของแต่ละ Guid ให้กับตัวติดตั้งแต่ละตัวโดยอัตโนมัติโดยเหลือ 31 ตัวที่เหลืออยู่

ข้อกำหนดเบื้องต้น

สมมติฐาน

  • ตัวแปร WiX ใช้เพื่อกำหนด UpgradeCode, ProductName, InstallName
  • คุณมีโปรแกรมติดตั้งที่ใช้งานได้ ฉันจะไม่ลองจนกว่าคุณจะทำ
  • ส่วนประกอบทั้งหมดของคุณจะถูกเก็บไว้ในไฟล์เดียว (Components.wxs) กระบวนการนี้จะทำงานหากคุณมีหลายไฟล์จะมีงานให้ทำอีกมาก

โครงสร้างสารบบ

  • Setup.Library
    • ไฟล์ wxs ทั้งหมด (ส่วนประกอบ, คุณสมบัติ, กล่องโต้ตอบ UI, ... )
    • Common.Config.wxi (ProductCode = "*", ProductVersion, PlatformProgramFilesFolder, ... )
  • Setup.Live (wixproj)
    • เชื่อมโยงการตั้งค่าทั้งหมดไฟล์ไลบรารีโดยใช้ "เพิ่มไฟล์ที่มีอยู่" -> "เพิ่มเป็นลิงค์" (ปุ่มลูกศรลงเล็กน้อยถัดจากปุ่มเพิ่มใน Visual Studio)
    • Config.wxi (มี UpgradeCode ที่ไม่ซ้ำกัน, ชื่อผลิตภัณฑ์, InstallName, ... )
  • ตั้งค่าทดสอบ ...
    • ตามสภาพจริง แต่ Config.wxi ได้รับการกำหนดค่าสำหรับสภาพแวดล้อมการทดสอบ

กระบวนการ

  • สร้างไดเรกทอรี Setup.Library และย้ายไฟล์ wxs และ wxi ทั้งหมดของคุณ (ยกเว้น Config.wxi) จากโครงการที่มีอยู่
  • สร้าง Setup.Live, Setup.Test ฯลฯ ตามปกติ wixproj
  • เพิ่ม BeforeBuild เป้าหมายใน wixproj ใน Setup.Live ฯลฯ เพื่อดำเนินการ MSBuild Community Task FileUpdateเพื่อแก้ไข Guids (ฉันใช้ A for Live, B สำหรับการทดสอบและ C สำหรับการฝึกอบรม)
  • เพิ่มเป้าหมาย AfterBuild เพื่อเปลี่ยน Components.wxs Guids กลับเป็น 0
  • ตรวจสอบกับ Orca ว่าแต่ละองค์ประกอบใน MSI แต่ละตัวมี guid ที่แก้ไขแล้ว
  • ตรวจสอบว่ามีการเรียกคืน guids ดั้งเดิม
  • ตรวจสอบว่า 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 ออกจาก Component (เทียบเท่า*) โดยใช้หนึ่งไฟล์ต่อองค์ประกอบและตั้งค่าไฟล์เป็น keypath สิ่งนี้จะช่วยลดความจำเป็นในการโทรModifyComponentsGuidsและRevertComponentsGuidsเป้าหมายที่แสดงด้านล่าง สิ่งนี้อาจเป็นไปไม่ได้สำหรับส่วนประกอบทั้งหมดของคุณ

ตัวอย่าง 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>

ความคิดสุดท้าย

  • กระบวนการนี้ควรทำงานสำหรับการสร้างตัวติดตั้งที่แตกต่างกันสำหรับโมดูลการผสานที่แตกต่างกัน (คุณลักษณะ Live, Test, ... เป็น) สำหรับโปรแกรมติดตั้งเดียวกัน ฉันไปกับตัวติดตั้งที่แตกต่างกันเพราะมันดูเหมือนเป็นตัวเลือกที่ปลอดภัยกว่ามีความเสี่ยงมากกว่าที่คนบางคนอาจอัพเกรด Live แทนการฝึกอบรมหากพวกเขาอยู่ในกล่องเดียวกันและคุณเพียงแค่ใช้ฟีเจอร์สำหรับโมดูลผสานที่แตกต่างกัน
  • หากคุณใช้ MSI ของคุณเพื่อดำเนินการอัปเกรดรวมถึงการติดตั้งใหม่เช่นวิธีการอัพเกรดที่สำคัญเท่านั้นและคุณบันทึกตำแหน่งการติดตั้งของคุณในรีจิสทรีอย่าลืมสร้างตัวแปรสำหรับชื่อคีย์สำหรับการติดตั้งแต่ละครั้ง
  • นอกจากนี้เรายังสร้างตัวแปรในแต่ละ Config.wxi เพื่อเปิดใช้งานชื่อไดเรกทอรีเสมือน, แอพพลิเคชั่น, ชื่อฐานข้อมูล, และอื่น ๆ สำหรับโปรแกรมติดตั้งแต่ละตัว

อัปเดต 1: องค์ประกอบสร้างอัตโนมัติ Guidsลบความจำเป็นในการเรียกงาน FileUpdate ถ้าคุณสร้างส่วนประกอบด้วย Guid = "*" สำหรับแต่ละไฟล์ตั้งค่าไฟล์เป็น keypath

อัปเดต 2:หนึ่งในปัญหาที่เราพบคือถ้าคุณไม่สร้างองค์ประกอบของ Guid และการสร้างล้มเหลวอัตโนมัติไฟล์ temp จะต้องถูกลบด้วยตนเอง

ปรับปรุง 3:พบวิธีที่จะลบการพึ่งพา svn: externals และการสร้างไฟล์ชั่วคราว สิ่งนี้ทำให้กระบวนการสร้างมีความยืดหยุ่นมากขึ้น (และเป็นตัวเลือกที่ดีที่สุดหากคุณไม่สามารถใช้สัญลักษณ์แทน Guids ของคุณได้) และมีความเปราะน้อยกว่าหากมีความล้มเหลวในการสร้างในแสงหรือเทียน

อัปเดต 4:รองรับอินสแตนซ์หลายตัวที่ใช้การแปลงอินสแตนซ์อยู่ใน WiX 3.0+ แน่นอนว่ามันคุ้มค่ากับการดู


+1 สำหรับการอ้างอิงภารกิจชุมชน MSBuild รักแพ็คเกจนั้น
BozoJoe

17

การใช้บันทึกการวินิจฉัย Msi เพื่อรับข้อมูลความล้มเหลวอย่างละเอียด

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

ที่ไหน

Package.msi
เป็นชื่อของแพ็คเกจของคุณและ
C: \ Package.log
เป็นที่ที่คุณต้องการเอาต์พุตของบันทึก

รหัสข้อผิดพลาด Msi

วิดีโอแนะนำ Wix
โอ้และวิดีโอแนะนำ Wix แบบสุ่มที่มี "Mr. WiX" Rob Mensching เป็น "ภาพใหญ่แนวความคิด" ที่เป็นประโยชน์


2
+1 มันจะดีกว่ามากถ้าเราสามารถเปิดใช้งานการบันทึกจากภายใน Wix แทนที่จะเป็นบรรทัดคำสั่ง
si618

3
WiX ทำ ตั้งค่าคุณสมบัติ MsiLogging รองรับ Windows Installer 4.0+ เท่านั้น
Rob Mensching

ขอบคุณมาก "Mr. Wix" ต้องตรวจสอบว่า
Terrance

17

ใช้ Javascript CustomActions เพราะมันง่ายมาก

มีคนบอกว่าJavascript เป็นสิ่งที่ไม่ถูกต้องที่จะใช้สำหรับ MSI CustomActions เหตุผลที่กำหนด: ยากต่อการตรวจแก้จุดบกพร่องยากที่จะทำให้เชื่อถือได้ ฉันไม่เห็นด้วย การแก้ข้อบกพร่องไม่ใช่เรื่องยากแน่นอนว่าไม่ยากกว่า C ++ มันแตกต่างกันเพียง ฉันพบว่าการเขียน CustomActions ใน Javascript นั้นง่ายมากง่ายกว่าการใช้ C ++ เร็วขึ้นมาก และเชื่อถือได้เช่นกัน

มีข้อเสียเปรียบเพียงข้อเดียว: สามารถแยก CustomActions Javascript ผ่าน Orca ในขณะที่ C / C ++ CA จะต้องใช้วิศวกรรมย้อนกลับ หากคุณคิดว่าเวทมนตร์ของผู้ติดตั้งของคุณได้รับการคุ้มครองทรัพย์สินทางปัญญาคุณจะต้องหลีกเลี่ยงสคริปต์

ถ้าคุณใช้สคริปต์คุณต้องเริ่มด้วยโครงสร้างบางอย่าง นี่คือบางส่วนเพื่อให้คุณเริ่มต้น


รหัส Javascript "boilerplate" สำหรับ 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
    };
}

จากนั้นให้ลงทะเบียนการกระทำแบบกำหนดเองด้วยสิ่งนี้:

<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 เพื่อทำแบบสอบถาม WMI บน IIS เพื่อรับรายการเว็บไซต์ที่มีอยู่ซึ่งตัวกรอง ISAPI สามารถติดตั้งได้ รายการนี้ถูกใช้เพื่อเติมกล่องรายการที่แสดงในลำดับ UI ทุกอย่างง่ายมาก

บน IIS7 ไม่มีผู้ให้บริการ WMI สำหรับ IIS ดังนั้นฉันจึงใช้shell.Run()วิธีการเรียกใช้ appcmd.exe เพื่อทำงาน ง่าย.

คำถามที่เกี่ยวข้อง: เกี่ยวกับ Javascript CustomActions


2
+1 ฉันพบว่าวิธีการ DTF นั้นง่ายต่อการติดตั้ง แต่จาวาสคริปต์ก็มีประโยชน์เช่นกัน
si618

12

Peter Tate ได้แสดงวิธีที่คุณสามารถกำหนดนิยาม ComponentGroup ที่สามารถใช้ซ้ำได้ในแฟรกเมนต์ wix แยกกัน เทคนิคเพิ่มเติมบางอย่างที่เกี่ยวข้องกับสิ่งนี้:

นามแฝงไดเรกทอรี

ส่วนกลุ่มส่วนประกอบไม่จำเป็นต้องรู้เกี่ยวกับไดเรกทอรีที่กำหนดโดยผลิตภัณฑ์หลัก wxs ในส่วนกลุ่มส่วนประกอบของคุณคุณสามารถพูดคุยเกี่ยวกับโฟลเดอร์เช่นนี้:

<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" ในการตั้งค่าของคุณเพราะเป็นการอ้างอิงโดยตรงของแอปพลิเคชันของคุณมันจะดึงกลุ่มองค์ประกอบ "A" โดยอัตโนมัติแม้ว่าผู้เขียนแอปพลิเคชันจะไม่เคยรู้ว่ามันเป็น "B" มัน "ใช้งานได้" ตราบใดที่คุณไม่มีการพึ่งพาแบบวงกลมใด ๆ

wixlib นำมาใช้ใหม่

แนวคิดกราฟการพึ่งพาดังกล่าวข้างต้นทำงานได้ดีที่สุดหากคุณรวบรวมองค์ประกอบ big-pool-o-reusable-component ลงใน wixlib ที่นำกลับมาใช้ใหม่ได้ด้วย lit.exe เมื่อสร้างการตั้งค่าแอปพลิเคชันคุณสามารถอ้างอิง wixlib นี้คล้ายกับไฟล์ wixobj ตัวเชื่อมโยง candle.exe จะกำจัดส่วนที่ไม่ได้ "ดึง" โดยอัตโนมัติโดยไฟล์ผลิตภัณฑ์หลัก wxs


12

ฉันประหลาดใจที่ไม่มีใครพูดถึงการใช้ T4 เพื่อสร้างไฟล์ WXS ระหว่างการสร้าง ผมได้เรียนรู้เกี่ยวกับเรื่องนี้โดยวิธีการของเฮนรี่ลี @ โซลูชั่นยุคใหม่

โดยพื้นฐานแล้วคุณสร้างงาน MSBuild ที่กำหนดเองเพื่อดำเนินการเท็มเพลต T4 และเทมเพลตนั้นจะส่งออก WXS ก่อนที่โครงการ Wix จะถูกคอมไพล์ สิ่งนี้ช่วยให้คุณ (ขึ้นอยู่กับวิธีที่คุณใช้) รวมเอาแอสเซมบลีทั้งหมดออกจากการรวบรวมโซลูชันอื่นโดยอัตโนมัติ (หมายความว่าคุณไม่จำเป็นต้องแก้ไข wxs ตลอดเวลาที่คุณเพิ่มแอสเซมบลีใหม่)


2
+1 ที่ดีจริง ๆ ฉันไม่ได้กังวลมากเกี่ยวกับแอสเซมบลี แต่โครงการเว็บของเราสามารถมีปัญหากับหน้า aspx และสิ่งประดิษฐ์อื่น ๆ (รูปภาพ, css) ที่เพิ่มเข้าไปในโครงการ แต่ไม่ใช่ WiX
si618

4
สำหรับผู้เยี่ยมชมในอนาคต Wix 3.5 มียูทิลิตีheat.exeซึ่งจะทำการเก็บเกี่ยวโดยอัตโนมัติ
Mrchief

@Mrchief - ฉันไม่เชื่อว่า Heat รับชุดอ้างอิงที่คัดลอกไว้ในเครื่อง - ดูเหมือนว่าจะมีการวางแผนสำหรับ 4.0 การอ้างอิง: sourceforge.net/tracker/…
Peter T. LaComb Jr.

ความร้อนไม่ได้รับการอ้างอิงประกอบ
tofutim

ตัวอย่างที่ดีของการใช้ T4 เพื่อสร้างไฟล์ WXS คืออะไร
tofutim

12

ใช้ Heat.exe เพื่อทุบหน้าและสร้าง "Epic Pwnage" ในการติดตั้งขนาดใหญ่อย่างเจ็บปวด

ขยายคำตอบของSiและ Robert-Pเกี่ยวกับความร้อน

การแปล: (การใช้ความร้อนเพื่อหลีกเลี่ยงการพิมพ์แต่ละไฟล์ในโครงการด้วยมือและสำหรับการสร้างอัตโนมัติสำหรับกระบวนการที่ง่ายขึ้นโดยรวม)

WiX 2.0 Heat Syntax

สำหรับรุ่นที่ใหม่กว่า (ไม่ใช่ทั้งหมดที่แตกต่างจากรุ่นเก่า แต่อาจมีการเปลี่ยนแปลงทางไวยากรณ์ที่น่ารำคาญ .... ) ไปที่ไดเรกทอรีความร้อนมาจาก cmd.exe และเพียงพิมพ์ความร้อน แต่ฉันมีตัวอย่างหนึ่งที่นี่เพื่อขอความช่วยเหลือ กับรุ่นที่ใหม่กว่าถ้าจำเป็น

การเพิ่มสิ่งต่อไปนี้ใน Build Build ใน visual studio 2010
(คลิกขวาที่ 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 

สร้าง Guids เมื่อความร้อนทำงาน (เช่นเมื่อคุณรันคำสั่งด้านบน)

-scom 

อย่าคว้า "ไฟล์ COM"

-sreg 

อย่าคว้า "ไฟล์รีจิสทรี"

-sfrag 

อย่าคว้า "ชิ้นส่วน"

-srd 

อย่าคว้า "root Dir"

dir

dir หมายถึงคุณต้องการให้ Heat มองในโฟลเดอร์

"$ (EnviromentVariable)"

ชื่อของตัวแปรที่คุณจะเพิ่มให้กับตัวแปรพรีโปรเซสเซอร์ในส่วน (คลิกขวาที่โปรเจ็กต์ไปที่คุณสมบัติ) โปรเจ็กต์คุณสมบัติ -> บิวด์ส่วนที่ระบุว่ากำหนดตัวแปรพรีโปรเซสเซอร์ (ถือว่า Visual Studio 2010)

ตัวอย่าง:
EnviromentVariable = C: \ โครงการ \ bin \ Debug;
ไม่มีเครื่องหมายคำพูดคู่ แต่ลงท้ายด้วยเครื่องหมายอัฒภาค

-cg GroupVariable 

ComponentGroup ที่จะอ้างอิงจากแฟรกเมนต์ที่สร้างขึ้นไปยังไฟล์ wxs หลัก

FragmentDir

ไดเร็กทอรีแฟรกเมนต์ที่เอาต์พุตแฟรกเมนต์ wxs จะถูกเก็บไว้

FileName.wxs

ชื่อของไฟล์

แบบฝึกหัดเต็มรูปแบบที่นี่ดังนั้น freakin จึงมีประโยชน์

ส่วนที่ 1 ส่วนที่ 2


มีอีกเครื่องมือที่มีประโยชน์สำหรับวัตถุประสงค์ที่แตกต่างกันเล็กน้อย: Paraffin ( wintellect.com/CS/blogs/jrobbins/archive/2010/03/10/4107.aspx )
ralf.w

9

รวมถึงวัตถุ COM:

heatสร้างรายการรีจิสทรีและการกำหนดค่าอื่น ๆ ที่จำเป็นสำหรับพวกเขาส่วนใหญ่ (ถ้าไม่ใช่ทั้งหมด) ดีใจ!

รวมถึงวัตถุที่มีการจัดการ COM (aka,. NET หรือวัตถุ C # COM)

การใช้heatบนวัตถุ COM ที่ได้รับการจัดการจะทำให้คุณมีเอกสาร wix เกือบสมบูรณ์

หากคุณไม่ต้องการห้องสมุดที่มีอยู่ใน GAC (เช่นมีอยู่ทั่วโลก: ส่วนใหญ่คุณไม่จำเป็นต้องใช้แอสเซมบลี. NET ของคุณอยู่ดี - คุณอาจทำอะไรผิดพลาดในตอนนี้หากไม่ได้ตั้งใจให้เป็น ห้องสมุดที่ใช้ร่วมกัน) คุณจะต้องการให้แน่ใจว่าการปรับปรุงคีย์รีจิสทรีจะถูกตั้งค่าCodeBase [#ComponentName]หากคุณกำลังวางแผนในการติดตั้งไปยัง GAC (เช่นคุณได้ทำห้องสมุดทั่วไปใหม่น่ากลัวบางอย่างที่ทุกคนจะต้องการที่จะใช้งาน) คุณต้องเอารายการนี้และเพิ่มสองคุณลักษณะใหม่ในFileองค์ประกอบ: และAssembly KeyPathชุดประกอบควรตั้งค่าเป็น ".net" และKeyPathควรตั้งค่าเป็น "ใช่"

อย่างไรก็ตามบางสภาพแวดล้อม (โดยเฉพาะอย่างยิ่งสิ่งใดก็ตามที่มีหน่วยความจำที่มีการจัดการเช่นภาษาสคริปต์) จะต้องเข้าถึง Typelib ด้วยเช่นกัน ตรวจสอบให้แน่ใจว่าได้ทำงานheatกับ typelib ของคุณแล้ว 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
ใช่ แต่คุณจะต้องใช้วิธีแก้ปัญหาเพราะ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
นอกจากนี้ยังมีตัวแปรการรวบรวมเช่น $ (การกำหนดค่า) และ $ (แพลตฟอร์ม) นอกจากนี้ยังมีพวงเพิ่มเติมที่msdn.microsoft.com/en-us/library/aa302186.aspx
si618

1
@Si - เมื่อก่อนวันนี้ลิงก์นั้นไม่ทำงานอีกต่อไป ฉันไม่พบสิ่งล่าสุด
Peter M



7

การแก้ไขกล่องโต้ตอบ

หนึ่งความสามารถที่ดีในการแก้ไขกล่องโต้ตอบคือการใช้ SharpDevelop ในเวอร์ชัน 4.0.1.7090 (หรือสูงกว่า) ด้วยความช่วยเหลือของเครื่องมือนี้กล่องโต้ตอบแบบสแตนด์อโลน (ไฟล์ wxs จากแหล่ง WiX เช่น InstallDirDlg.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

แก้ไข "พร้อมที่จะติดตั้งหรือไม่" โต้ตอบ (aka VerifyReadyDlg) เพื่อให้ข้อมูลสรุปของตัวเลือกที่ทำ

ดูเหมือนว่า:
alt text http://i46.tinypic.com/s4th7t.jpg

ทำสิ่งนี้ด้วย Javascript CustomAction:


รหัส 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);
}

ประกาศ 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>

แนบ CA เข้ากับปุ่ม ในตัวอย่างนี้ CA จะเริ่มทำงานเมื่อคลิกถัดไปจาก CustomizeDlg:

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

คำถาม SO ที่เกี่ยวข้อง: ฉันจะตั้งค่าอย่างไรในขณะใช้งานข้อความที่จะแสดงใน VerifyReadyDlg


นี่ไม่ควรเป็น JScript ภาษาสคริปต์ของ windows แทนที่จะเป็นจาวาสคริปต์ในการใช้ภาษา DHTML อาจเป็นคนอวดรู้เล็กน้อย แต่อาจทำให้คนสับสนเล็กน้อย
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>

นอกจากนี้เมื่อทำการแพตช์โดยใช้หัวข้อ "Using Purely WiX" จากไฟล์วิธีใช้ WiX.chm โดยใช้โพรซีเดอร์นี้เพื่อสร้างแพตช์:

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 ของผลิตภัณฑ์ wixpdb ที่สร้างขึ้นโดยใช้ส่วนประกอบในส่วนแยกต่างหาก ดังนั้นให้แน่ใจว่าได้แยกส่วนผลิตภัณฑ์ของคุณอย่างถูกต้องก่อนที่จะส่ง


5

การพิมพ์ EULA จาก Wix3.0 และใหม่กว่า

1) เมื่อคุณคอมไพล์ซอร์สโค้ด wix ของคุณ light.exe ต้องอ้างอิง WixUIExtension.dll ในบรรทัดคำสั่ง ใช้สวิตช์บรรทัดคำสั่ง - ต่อไปสำหรับสิ่งนี้

2) ถ้าเมื่อคุณเพิ่มการอ้างอิงไปยัง WixUIExtension.dll โครงการของคุณล้มเหลวในการรวบรวมนี่เป็นไปได้มากที่สุดเนื่องจาก clashes ของ Dialog IDs นั่นคือโครงการของคุณใช้ IDs ของไดอะล็อกเดียวกันกับบางไดอะล็อกมาตรฐานใน WixUIExtension.dll ให้ ID ที่แตกต่างกับกล่องโต้ตอบของคุณ นี่เป็นปัญหาที่พบบ่อยมาก

3) กล่องโต้ตอบใบอนุญาตของคุณต้องมีการควบคุม ScrollableText ด้วย id "LicenseText" Wix ค้นหาชื่อของการควบคุมนี้เมื่อพิมพ์

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

และปุ่มกดซึ่งหมายถึงการกระทำที่กำหนดเอง

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

4) กำหนด CustomAction ด้วย Id = "PrintEula" เช่นนี้:

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

หมายเหตุ: BinaryKey นั้นแตกต่างกันใน Wix3.0 เทียบกับ Wix2.0 และจะต้องเป็น "WixUIWixca" ทุกประการ

เมื่อผู้ใช้กดปุ่มเขา / เธอจะถูกนำเสนอด้วยกล่องโต้ตอบเลือกเครื่องพิมพ์มาตรฐานและจะสามารถพิมพ์จากที่นั่น


5
  • เราแสดงรุ่นผลิตภัณฑ์บางแห่ง (เล็ก) ในหน้าจอแรกของ GUI เพราะคนมักจะทำผิดพลาดในการเลือกเวอร์ชั่นที่ถูกต้องทุกครั้ง (และให้นักพัฒนาซอฟต์แวร์ค้นหาเราทุกวัย .. )

  • เราได้ตั้งค่า TFSBuild เพื่อสร้างการแปลง (ไฟล์. mst) ด้วยการกำหนดค่าสำหรับสภาพแวดล้อมที่แตกต่างกันของเรา (เรารู้เกี่ยวกับสภาพแวดล้อมทั้งหมดที่เราต้องนำไปใช้)

เนื่องจากโพสต์เว็บบล็อกดั้งเดิมของ Grant Holliday ไม่ทำงานฉันจึงคัดลอกเนื้อหาที่นี่:


ภารกิจ MSBuild เพื่อสร้างไฟล์ MSI Transform จาก XMLMarch 11 2008

ในโพสต์ก่อนหน้าของฉันฉันอธิบายว่าคุณสามารถใช้ไฟล์ MSI Transform (* .mst) เพื่อแยกการตั้งค่าเฉพาะสภาพแวดล้อมออกจากแพ็คเกจ MSI ทั่วไปได้อย่างไร

แม้ว่าสิ่งนี้จะให้ระดับความยืดหยุ่นในการกำหนดค่าของคุณ แต่มีไฟล์แปลงสองด้าน:

  1. มันเป็นรูปแบบไบนารี
  2. คุณไม่สามารถ "แก้ไข" หรือ "ดู" ไฟล์แปลง คุณต้องใช้มันหรือสร้างใหม่เพื่อดูว่ามีการเปลี่ยนแปลงอะไรบ้าง

โชคดีที่เราสามารถใช้ไลบรารีวัตถุ Microsoft Windows Installer (c: windowssystem32msi.dll) เพื่อเปิด MSI“ ฐานข้อมูล” และสร้างการแปลงไฟล์

เครดิตไปอีกครั้งกับAlex Shevchuk - จาก MSI ถึง WiX - ตอนที่ 7 - การปรับแต่งการติดตั้งโดยใช้การแปลงเพื่อแสดงให้เราเห็นว่าจะบรรลุสิ่งนี้ได้อย่างไรด้วย VbScript ที่สำคัญทั้งหมดที่ฉันทำคือตัวอย่างของอเล็กซ์และใช้ Interop.WindowsInstaller.dll ฉันได้ใช้งาน MSBuild ภารกิจ MSBuild

ดาวน์โหลดซอร์สโค้ด & ตัวอย่าง transforms.xml ที่นี่ (~ 7Kb Zipped VS2008 Solution)



2
เรากำหนด WelcomeDlgTitle ใหม่ในไฟล์แปลของฉัน - ใช้งานได้ดี! <String Id = "WelcomeDlgTitle"> {\ WixUI_Font_Bigger} ยินดีต้อนรับสู่ [ProductName] [ProductVersion] ตัวช่วยสร้างการตั้งค่า </String>
saschabeaumont

5

ก่อนที่จะปรับใช้แพ็คเกจการติดตั้งฉันมักจะควบคุมเนื้อหาของมัน

มันเป็นเพียงการโทรที่บรรทัดคำสั่ง (ตามโพสต์ Terrences) บรรทัดคำสั่งเปิดและป้อน

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

สิ่งนี้จะแยกเนื้อหาแพ็คเกจไปยังส่วนย่อย 'แยก' ด้วยพา ธ ปัจจุบัน


4

แทนที่จะใช้ ORCA ใช้InstEdซึ่งเป็นเครื่องมือที่ดีสำหรับการดูตาราง MSI นอกจากนี้ยังมีความสามารถในการกระจายสองแพคเกจโดยการแปลง -> เปรียบเทียบกับ ...

นอกจากนี้ยังมีรุ่น Plusพร้อมฟังก์ชันเพิ่มเติมอีกด้วย แต่รุ่นฟรีมีทางเลือกที่ดีสำหรับ Orca


4

การลงทะเบียนแอสเซมบลี. NET สำหรับ COM Interop ด้วยความเข้ากันได้กับ x86 / x64

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 vs x64 เป้าหมายการชุมนุมของฉัน 'ใด ๆ CPU' ดังนั้นในระบบ x64 ผมจำเป็นต้องลงทะเบียนเป็นครั้งที่สองครั้งในรีจิสทรี 64 บิตและครั้งเดียวใน 32 บิตWow6432Nodeพื้นที่ if-then-else ตั้งค่าฉันสำหรับสิ่งนี้ค่าจะถูกใช้ในการforeachวนซ้ำในภายหลัง วิธีนี้ฉันต้องเขียนรีจิสตรีคีย์หนึ่งครั้ง (หลักการ DRY)

องค์ประกอบไฟล์ระบุ 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 แต่มันช่วยให้ฉันใช้ตัวแปร binder บางอย่างภายใน XML ของฉันเช่น!(bind.assemblyFullname.filDriverAssembly)เพื่อรับชื่อเต็มของชุดประกอบ


3

ตั้งค่าDISABLEADVTSHORTCUTSคุณสมบัตินี้เพื่อบังคับใช้ทางลัดที่โฆษณาทั้งหมดในโปรแกรมติดตั้งของคุณให้กลายเป็นทางลัดปกติและคุณไม่จำเป็นต้องรวมคีย์ dummy reg เพื่อใช้เป็นพา ธ

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

ผมคิดว่าการติดตั้ง Windows 4.0 หรือสูงกว่าเป็นความต้องการ


2

มันเป็นโครงสร้างที่ดี แต่จากประสบการณ์ของฉันฉันสงสัยว่าคุณจะจัดการกับเงื่อนไขเหล่านี้ได้อย่างไร:

A. การติดตั้งของคุณทั้งหมดดูเหมือนจะลงจอดในปลายทางเดียวกัน หากผู้ใช้ต้องการติดตั้งทั้ง 3 เวอร์ชันในครั้งเดียวกระบวนการของคุณจะอนุญาต พวกเขาสามารถบอกได้อย่างชัดเจนหรือไม่ว่าเวอร์ชันของไฟล์เรียกทำงานทุกไฟล์ที่เรียกใช้

B. คุณจะจัดการกับไฟล์ใหม่ที่มีอยู่ใน TEST และ / หรือ TRAINING ได้อย่างไร แต่ยังไม่มีใน LIVE


สวัสดี Blaine, A. ไม่มีพวกเขาไม่ได้ InstallName อยู่ใน Config.wxi ซึ่งเป็นไฟล์เดียวที่ไม่ได้อ้างอิงโดย svn: externals ดังนั้นสิ่งนี้จึงไม่เหมือนใครสำหรับการติดตั้งแต่ละครั้งเช่นแต่ละผลิตภัณฑ์ นั่นเป็นเหตุผลที่เราปรับเปลี่ยน Guids สำหรับแต่ละรุ่น B. GOTO A. :) พวกเขาแยก MSI ด้วย UpgradeCode ของพวกเขาเอง
si618

1
โดยวิธีการที่ฉันเข้าใจว่าทำไมคุณตอบคำถามของฉันด้วยคำถาม แต่เมื่อคุณได้รับคะแนนตัวแทนเพียงพอโปรดย้ายคำถามของคุณไปที่ความคิดเห็นคำตอบมิฉะนั้นด้ายจะยากที่จะติดตาม
si618

2

นี่คือวิธีที่จะช่วยให้โครงการเว็บขนาดใหญ่ตรวจสอบว่าจำนวนไฟล์ที่ปรับใช้ตรงกับจำนวนไฟล์ที่สร้างใน MSI (หรือโมดูลผสาน) ฉันเพิ่งใช้งาน MSBuild ที่กำหนดเองกับแอปพลิเคชันหลักของเรา (ยังอยู่ระหว่างการพัฒนา) และมันหยิบไฟล์ที่ขาดหายไปค่อนข้างน้อยภาพส่วนใหญ่เป็นไฟล์ แต่ไฟล์จาวาสคริปต์บางตัวได้เล็ดลอดไป!

วิธีการนี้ (การดูในตารางไฟล์ของ MSI โดยการเชื่อมโยงไปยังเป้าหมาย AfterBuild ของโครงการ WiX) สามารถทำงานกับแอปพลิเคชั่นประเภทอื่นที่คุณสามารถเข้าถึงรายการไฟล์ที่ต้องการทั้งหมด


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)

2

สร้าง UI ที่มีการกระทำแบบกำหนดเองที่จะตั้งค่าตัวแปรและ UI จะปิด / เปิดใช้งานปุ่มถัดไป (หรือคล้ายกัน) ตามตัวแปรที่ตั้งค่าไว้ในการกระทำที่กำหนดเอง

ไม่ตรงไปตรงมาอย่างที่คุณคิดไม่ยากเกินไปไม่ได้บันทึกไว้ที่ไหนเลย!

การโต้ตอบ Wix กับเงื่อนไขคุณสมบัติ & การกระทำที่กำหนดเอง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.