65.9K
CodeProject 正在变化。 阅读更多。
Home

设置项目 - 安装/升级序列

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.60/5 (4投票s)

2010年10月28日

CPOL

7分钟阅读

viewsIcon

51682

downloadIcon

790

在安装/升级设置项目时,显示不同的对话框序列和文本。

引言

在分发 .NET 应用程序时,设置项目是一个非常有用的工具,因为它易于使用,并且可以跟踪应用程序正常安装和工作所需的所有库依赖项。

我们有一个简单的任务想要实现。我们的对话框安装序列是:欢迎界面、文件夹界面、确认安装界面、完成安装界面。我们想要的是,当安装新版本的产品时,安装程序需要检测是否已安装前一版本,如果是,则跳过文件夹界面,因为用户在首次安装时已经选择了安装位置,并且选择了“所有用户”还是“仅我”。我们还希望更改对话框中的所有文本,以表明安装程序正在升级而不是安装。

如何使用它

您必须在“逐步”部分的开头手动完成“设置项目更改”的第 1 至第 7 步,并将文章附带的 JavaScript 文件添加为设置项目的后期生成事件,该文件将自动执行 ORCA 演示的 MSI 更改。
PostBuildEvent="$(ProjectDir)PBE.js" "$(BuiltOuputPath)" 并设置 RemovePreviousVersions=True

如何实现

为了实现我们的目标,我们使用了设置项目本身提供的功能,以及后期生成 JavaScript,该 JavaScript 自动化了必要的 MSI 更改。

挑战之一是检测我们是正在安装还是升级 - 没有简单的参数可以告诉我们。有 [PREVIOUSVERSIONSINSTALLED],但正如某处所说,它在前一版本的卸载过程中才有意义(具有正确的值),而在安装或升级时则不然。所以我们所做的是添加一个注册表值,记住最后一个安装/升级的 [ProductCode],然后在升级运行时(升级是用相同的 [UpgradeCode] 但不同的 [ProductCode] 进行安装),将该注册表值读取到参数 [OLDPRODUCTCODE] 中,并检查 SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\[OLDPRODUCTCODE] 下是否存在具有该值的注册表项,这意味着之前安装过同一产品,换句话说,我们正在升级。

跳过 FolderForm 意味着我们必须记住用户的 TargetFolder AllUsers/JustMe 选择。这是通过在 HKLM\Software\[Manufacturer]\[UpgradeCode] 下创建注册表值来完成的(我们使用 [UpgradeCode],因为它对于安装是唯一且一致的,但您也可以使用简单的 string)来存储这些选择。
AU - 存储 AllUsers/JustMe 的选择(如果 [ALLUSERS] = "" 则为 JustMe ,否则为 AllUsers )。

最初,我们尝试仅存储参数 [FolderForm_AllUsers],该参数在 FolderForm 中根据单选按钮的选择保存 ALL 或 ME 的值,但出于某种奇怪的原因,在写入注册表值 TF - 保存 [TARGETDIR] 的阶段之前,它丢失了其值。要读取这些值用于连续升级,创建了注册表搜索 - 一个将注册表值 TF 检索到 [TARGETDIR],另一个将注册表值 AU 检索到 [REMALLUSERS]

我们不直接设置 [ALLUSERS][FolderForm_AllUsers],因为它们会被 MSI 以某种方式操作,所以即使一开始就用记住的值设置,它们也会在之后被重置并丢失其值。当使用 ORCA 查看 MSI 时,在 Parameters 表中,参数 [FolderForm_AllUsers] 被设置为 ME,并且有一个 VSDCA_FolderForm_AllUsers actionInstallUISequence 表中被调用来将其值更改为 ALL。因此,现在在升级时,我们添加了条件 [REMALLUSERS]<>"ME",这样如果用户之前选择了 ME ,这个操作将被跳过,确保 [FolderForm_AllUsers] 保持设置为 ME

跳过 FormFolder 对话框意味着我们需要一个不同于导致该对话框的表单的 NextButton 行为 - 在我们的例子中是 WelcomeForm - 以及 FormFolder 之后表单的 PreviousButton 行为 - 在我们的例子中是 ConfirmInstall 表单。

WelcomeForm NextButton 的行为由参数 [WelcomeForm_NextArgs] 决定,ConfirmInstall PreviousButton 的行为由参数 [ConfirmInstallForm_PrevArgs] 决定。定义了自定义操作,使我们能够将其更改为升级值 [WelcomeForm_NextArgs]=ConfirmInstallForm [ConfirmInstallForm_PrevArgs]="",并在 InstallUISequence 中以升级为条件的( ISOLDPRODUCTCODEINSTALLED<>"")调用这些自定义操作。

此外,我们希望更改所有控件的文本,以说明我们是正在安装还是升级,这意味着我们想要替换的单词应该是参数,并且参数的值会根据安装或升级进行相应设置。所以我们在 Parameter 表中为我们希望在安装/升级时不同的每个单词创建了一个参数,并将其值设置为指示“安装”。创建过程允许在 CustomAction 表中更改这些参数为升级值。在升级时调用这些自定义操作以实际更改 InstallUISequence 表中的参数值,条件是 ISOLDPRODUCTCODEINSTALLED<>""。在 Control 表的 Text 字段中,将所有单词替换为参数名称,这样根据安装/升级,我们将看到相应的文本。

逐步操作

设置项目更改

  • 在本地计算机上创建注册表值 TF 以记住上次安装的 [TARGETDIR]

  • 在本地计算机上创建注册表值 AU 以记住“所有用户”/“仅我”

  • 在本地计算机上创建注册表值 PC 以记住上次安装/升级的 [ProductCode]

  • 创建注册表搜索,将 TF 值从注册表读取到变量 [TARGETDIR]

  • 创建注册表搜索,将 AU 值从注册表读取到变量 [REMALLUSERS]

    非常重要的是,第 6 步必须在第 7 步之前执行,因为第 7 步取决于第 6 步检索到的值。

  • 创建注册表搜索,将 PC 值从注册表读取到变量 [OLDPRODUCTCODE]

  • 创建注册表搜索,以检查注册表项(安装)SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\[OLDPRODUCTCODE] 是否存在,并将其写入变量 [ISOLDPRODUCTCODEINSTALLED]。这将决定我们是正在安装还是升级。

    后期生成事件对 MSI 的更改 - (如前所述,当设置为后期生成事件时,由文章附带的 JavaScript 自动完成。)

  • 使操作 VSDCA_FolderForm_AllUsers(将 [FolderForm_AllUsers] 设置为其默认值)仅在安装时发生,在升级时,值将根据从注册表 [REMALLUSERS] 中检索的值进行设置。

    根据是安装还是升级更改所有控件的文本 {对于每个我们想要更改的 string - 替换对}

  • Property 表中插入一个具有默认(安装)值的参数

  • CustomAction 表中插入一个可以将其参数设置为升级值操作

  • InstallUISequence 表中插入对自定义操作的调用,该调用在升级时(条件 ISOLDPRODUCTCODEINSTALLED<>"")实际将参数更改为升级值

  • 对于 Control 表中的每一行,在 Text 列的值中,用参数名称替换我们希望依赖于安装/升级的 string

    {结束}

    升级时删除 FolderForm

  • CustomAction 表中插入一个操作,该操作可以设置 [WelcomeForm_NextArgs] 的值(该值决定了单击 WelcomeForm 中“下一步”按钮时显示的表单(我们想跳过 Folder form)),使其成为 FolderForm 之后的表单名称,在本例中是 ConfirmInstall 表单。

  • InstallUISequence 表中插入对该自定义操作的调用,该调用在升级时(条件 ISOLDPRODUCTCODEINSTALLED<>"")实际上将 [WelcomeForm_NextArgs] 设置为 ConfirmInstall 表单。

  • CustomAction 表中插入一个操作,该操作可以设置 [ConfirmInstallForm_PrevArgs] 的值(该值决定了单击 ConfirmInstall 表单中“上一步”按钮时显示的表单(我们想跳过 FolderForm)),使其成为 FolderForm 之前的表单名称,在本例中是 WelcomeForm

  • InstallUISequence 表中插入对该自定义操作的调用,该调用在升级时(条件 ISOLDPRODUCTCODEINSTALLED<>"")实际上将 [ConfirmInstallForm_PrevArgs] 设置为 WelcomeForm

    由于我们在升级时删除了文件夹表单,但我们仍然希望当 FolderForm 的“下一步”被点击时发生的所有操作都被转移到升级时的 WelcomeForm 的“下一步”,因为其余安装过程依赖于它们,其中一个就是设置记住的“所有用户”/“仅我”的选择 {对于 ControlEvent 表中的每一行,如果 Dialog='FolderForm' Control='NextButton'}。

  • 复制相同的值,但用于 Dialog=WelcomeForm Control=NextButton 和 Condition=ISOLDPRODUCTCODEINSTALLED="" - 现在 WelcomeForm 在升级时将执行 FolderForm 在安装时执行的所有操作。

注意

JavaScript 更改仅适用于描述的安装序列 **欢迎界面、文件夹界面、确认安装界面**,但可以更改为适用于其他安装序列。另外,假设 [FolderForm_AllUsers] 参数在 MSI 的 Property 表中默认设置为 ME ,事实似乎也是如此(可以添加一个检查来设置此参数,如果不存在,以保持一致性)。

© . All rights reserved.