我们已经使用WiX有一段时间了,尽管人们对它的易用性有一些抱怨,但它运行得相当不错。我想要的是有用的建议:
设置WiX项目(布局、引用、文件模式) 将WiX集成到解决方案中,并构建/发布流程 为新的安装和升级配置安装程序 任何你想分享的好的WiX技巧
我们已经使用WiX有一段时间了,尽管人们对它的易用性有一些抱怨,但它运行得相当不错。我想要的是有用的建议:
设置WiX项目(布局、引用、文件模式) 将WiX集成到解决方案中,并构建/发布流程 为新的安装和升级配置安装程序 任何你想分享的好的WiX技巧
当前回答
包括COM对象:
Heat生成所有(如果不是全部)注册表项和它们所需的其他配置。喜乐!
包括托管COM对象(又名。net或c# COM对象)
在托管COM对象上使用heat将为您提供一个几乎完整的wix文档。
If you don't need the library available in the GAC (ie, globally available: MOST of the time you do not need this with your .NET assemblies anyway - you've probably done something wrong at this point if it's not intended to be a shared library) you will want to make sure to update the CodeBase registry key to be set to [#ComponentName]. If you ARE planning on installing it to the GAC (eg, you've made some new awesome common library that everyone will want to use) you must remove this entry, and add two new attributes to the File element: Assembly and KeyPath. Assembly should be set to ".net" and KeyPath should be set to "yes".
然而,某些环境(特别是带有托管内存的环境,如脚本语言)也需要访问Typelib。确保在你的打字单上运行热度并包括它。Heat将生成所有需要的注册表项。多酷啊!
其他回答
从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”(区分大小写)。
当用户按下按钮时,他/她将出现标准的选择打印机对话框,并能够从那里打印。
为COM互操作注册。net程序集,兼容x86/x64
注意:这个片段本质上与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望远镜驱动程序。
首先,我采纳了上面的建议,在一个单独的文件中创建了一些平台变量,你可以在XML中看到这些变量。
接近顶部的if-then-else部分处理x86 vs x64兼容性。我的程序集目标是“任何CPU”,所以在x64系统上,我需要注册它两次,一次在64位注册表中,一次在32位Wow6432Node区域中。if-then-else为我设置了这个,这些值稍后在foreach循环中使用。这样,我只需要编写一次注册表项(DRY原则)。
file元素指定实际安装和注册的程序集dll:
<File Id="filDriverAssembly" Source="$(var.TiGra.Astronomy.AWRDriveSystem.TargetPath)" KeyPath="yes" Vital="yes" Assembly=".net" AssemblyApplication="filDriverAssembly" />
没有什么革命性的东西,但是请注意Assembly=".net" -这个属性本身就会导致程序集被放入GAC,这不是我想要的。使用AssemblyApplication属性指向它本身只是阻止Wix将文件放入GAC的一种方法。现在Wix知道它是一个。net程序集,但是,它允许我在XML中使用某些绑定器变量,例如!(bind.assemblyFullname.filDriverAssembly)来获取程序集的全名。
修改“准备好安装了吗?”对话框(又名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?
当安装不允许卸载或重新安装且不能回滚时,执行强制重新安装。 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)
包括COM对象:
Heat生成所有(如果不是全部)注册表项和它们所需的其他配置。喜乐!
包括托管COM对象(又名。net或c# COM对象)
在托管COM对象上使用heat将为您提供一个几乎完整的wix文档。
If you don't need the library available in the GAC (ie, globally available: MOST of the time you do not need this with your .NET assemblies anyway - you've probably done something wrong at this point if it's not intended to be a shared library) you will want to make sure to update the CodeBase registry key to be set to [#ComponentName]. If you ARE planning on installing it to the GAC (eg, you've made some new awesome common library that everyone will want to use) you must remove this entry, and add two new attributes to the File element: Assembly and KeyPath. Assembly should be set to ".net" and KeyPath should be set to "yes".
然而,某些环境(特别是带有托管内存的环境,如脚本语言)也需要访问Typelib。确保在你的打字单上运行热度并包括它。Heat将生成所有需要的注册表项。多酷啊!