我们已经使用WiX有一段时间了,尽管人们对它的易用性有一些抱怨,但它运行得相当不错。我想要的是有用的建议:
设置WiX项目(布局、引用、文件模式) 将WiX集成到解决方案中,并构建/发布流程 为新的安装和升级配置安装程序 任何你想分享的好的WiX技巧
我们已经使用WiX有一段时间了,尽管人们对它的易用性有一些抱怨,但它运行得相当不错。我想要的是有用的建议:
设置WiX项目(布局、引用、文件模式) 将WiX集成到解决方案中,并构建/发布流程 为新的安装和升级配置安装程序 任何你想分享的好的WiX技巧
当前回答
从Wix3.0及更高版本打印EULA
1)当你编译你的wix源代码时,light.exe必须在命令行引用WixUIExtension.dll。为此使用命令行开关-ext。
2)如果当你在WixUIExtension.dll中添加引用时,你的项目编译失败,这很可能是因为对话框id的冲突,即你的项目使用了与WixUIExtension.dll中一些标准对话框相同的对话框id,给你的对话框提供不同的id。这是一个很普遍的问题。
3)你的许可对话框必须有id为“LicenseText”的ScrollableText控件。Wix在打印时搜索该控件的名称。
<Control Id="LicenseText" Type="ScrollableText" X="20" Y="60" Width="330" Height="160" Sunken="yes" TabSkip="no">
<Text SourceFile="License.rtf" />
</Control>
以及指向自定义动作的PushButton
<Control Type="PushButton" Id="PrintButton" Width="57" Height="17" X="19" Y="244" Text="Print">
<Publish Event="DoAction" Value="PrintEula">1</Publish>
</Control>
4)使用Id="PrintEula"定义CustomAction,如下所示:
<CustomAction Id="PrintEula" BinaryKey="WixUIWixca" DllEntry="PrintEula" Return="ignore" Execute="immediate" />
注意:BinaryKey在Wix3.0和Wix2.0中是不同的,必须准确地为“WixUIWixca”(区分大小写)。
当用户按下按钮时,他/她将出现标准的选择打印机对话框,并能够从那里打印。
其他回答
Peter Tate已经展示了如何在单独的wix片段中定义可重用的ComponentGroup定义。一些与此相关的额外技巧:
目录别名
组件组片段不需要知道主产品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”的依赖项。只要你没有任何循环依赖,它就“可以工作”。
Reusable wixlib
如果您使用lit.exe将大池-o-可重用组件编译为可重用的wixlib,则上述依赖关系图的想法效果最好。在创建应用程序设置时,可以像引用wixobj文件一样引用这个wixlib。exe链接器将自动消除没有被主产品wxs文件“拉入”的任何片段。
修复ProgressDlg,使其正确显示。
我将安装程序的字体大小从8增加到10,以使字体在高分辨率显示器上更人性化、更实用。我用这个XML魔法做到这一点:
<UI Id="MyCustomUI">
<TextStyle Id="WixUI_Font_Normal" FaceName="Tahoma" Size="10" />
<TextStyle Id="WixUI_Font_Big" FaceName="Tahoma" Size="12" />
<TextStyle Id="WixUI_Font_Bigger" FaceName="Tahoma" Size="14" />
<TextStyle Id="WixUI_Font_Title" FaceName="Tahoma" Size="12" Bold="yes" />
<Property Id="DefaultUIFont" Value="WixUI_Font_Normal" />
</UI>
但这意味着ProgressDlg将无法正常显示。这是一个显示安装进度的程序,就在最后。ActionText被剪切,因此g和j等字母的下移不显示。在后处理Javascript中,通过调整Progressdialog中各种控件的大小和位置来解决这个问题。生成MSI后运行这个脚本:
var msiOpenDatabaseModeTransact = 1;
var filespec = WScript.Arguments(0);
var installer = new ActiveXObject("WindowsInstaller.Installer");
var database = installer.OpenDatabase(filespec, msiOpenDatabaseModeTransact);
// The text on the exit dialog is too close to the title. This
// step moves the text down from Y=70 to Y=90, about one line.
sql = "UPDATE `Control` SET `Control`.`Y` = '90' " +
"WHERE `Control`.`Dialog_`='ExitDialog' AND `Control`.`Control`='Description'";
view = database.OpenView(sql);
view.Execute();
view.Close();
// The progressbar is too close to the status text on the Progress dialog.
// This step moves the progressbar down from Y=115 to Y=118, about 1/3 line.
sql = "UPDATE `Control` SET `Control`.`Y` = '118' " +
"WHERE `Control`.`Dialog_`='ProgressDlg' AND `Control`.`Control`='ProgressBar'";
view = database.OpenView(sql);
view.Execute();
view.Close();
// The StatusLabel and ActionText controls are too short on the Progress dialog,
// which means the bottom of the text is cut off. This step
// increases the height from 10 to 16.
sql = "UPDATE `Control` SET `Control`.`Height` = '16' " +
"WHERE `Control`.`Dialog_`='ProgressDlg' AND `Control`.`Control`='StatusLabel'";
view = database.OpenView(sql);
view.Execute();
view.Close();
sql = "UPDATE `Control` SET `Control`.`Height` = '16' " +
"WHERE `Control`.`Dialog_`='ProgressDlg' AND `Control`.`Control`='ActionText'";
view = database.OpenView(sql);
view.Execute();
view.Close();
database.Commit();
设置DISABLEADVTSHORTCUTS属性,强制安装程序中所有发布的快捷方式成为常规快捷方式,并且不需要包括一个虚拟的reg键作为小键盘。
<Property Id="DISABLEADVTSHORTCUTS" Value="1"/>
我认为Windows Installer 4.0或更高版本是必需的。
使用Heat.exe砸碎脸和造成“史诗Pwnage”痛苦的大安装
扩展Si的和 Robert-P关于热的回答。 翻译: (使用heat可以避免手动将单个文件输入到项目中,并且可以自动化构建,从而使整个过程更容易。) 详细介绍WiX 2.0热语法
For newer versions (not all that different from older versions but there are potentially annoying syntax changes....) go to the directory Heat is in from the cmd.exe and just type in heat but I have a example one right here for help with newer versions if needed. Adding the following to your Build Event in visual studio 2010. (Right Click 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 Generates Guids when heat is run(as in when you execute the command above) -scom Dont grab "COM files" -sreg Dont grab "Registry Files" -sfrag Dont grab "Fragments" -srd Dont grab the "root Dir" dir dir indicates you want Heat to look in a folder "$(EnviromentVariable)" The name of the variable you would add to the Preprocessor variables in the (Right click project, Go to properties) project properties->Build section where it says Define preprocessor variables (assumes visual studio 2010) Example: EnviromentVariable=C:\Project\bin\Debug;No double quotes but end with a semicolon -cg GroupVariable The ComponentGroup that will be referenced from the fragment created to the main wxs file FragmentDir The fragment directory where the output wxs fragment will be stored FileName.wxs The the name of the file Full tutorial here, So freakin helpful Part 1 Part 2
修改“准备好安装了吗?”对话框(又名VerifyReadyDlg),以提供所做选择的摘要。
它是这样的: Alt文本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连接到按钮上。在这个例子中,当从CustomizeDlg中单击Next时,CA将被触发:
<UI ...>
<Publish Dialog="CustomizeDlg" Control="Next" Event="DoAction"
Value="CA.UpdateReadyDialog" Order="1"/>
</UI>
相关SO问题:如何设置,在运行时,文本将显示在VerifyReadyDlg?