WiX 3.7: 如何根据用户设置的条件在卸载时删除注册表键?

7

我需要允许用户在卸载时指定安装程序是否删除或保留注册表键。这是我的做法。 我有一个名为RemoveRegistryKey的组件,其中包含一个条件元素,如下所示:

<Component
    Id="ID"
    Guid="GUID"
    KeyPath="yes" >

    <Condition></Condition>

    <RemoveRegistryKey
        Root="HKLM"
        Key="Software\PATH_TO_KEY" 
        Action="removeOnUninstall"/>
</Component>

这似乎按预期工作。如果我将条件元素硬编码为0,则注册表键将保留,如果我将其设置为1,则注册表键将被删除。(有一个不同的组件创建此注册表键,但我将其 ForceDeleteOnUninstall 属性设置为 no 。)现在,在卸载期间,我需要通过用户输入来控制此条件。我有一个用C#编写的CA,如下所示:
[CustomAction]
public static ActionResult AskUser(Session session)
{
    MessageResult result = session.Message
    (
        InstallMessage.User +
            (int)MessageBoxIcon.Information +
            (int)MessageBoxButtons.YesNo,
            new Record { FormatString = String.Format("Delete registry key?") }
    );

    if (result == MessageResult.Yes)
        session["DELETEREGKEY"] = "1";

    return ActionResult.Success;
}

我使用以下代码安排CA执行:

<CustomAction Id="AskUserCA" BinaryKey="CA_Dll" DllEntry="AskUser" Execute="immediate" />

<InstallExecuteSequence>
    <Custom Action="AskUserCA" Before="InstallValidate">(REMOVE="ALL") AND (NOT UPGRADINGPRODUCTCODE)</Custom>
</InstallExecuteSequence>

我将RemoveRegistryKey组件的Condition元素设置为:

<Condition>DELETEREGKEY="1"</Condition>

我还尝试了DELETEREGKEY = 1和DELETEREGKEY,但即使我从CA获得提示(它出现在卸载确认对话框之后),并且我可以在日志文件中看到(当我使用日志记录时)DELETEREGKEY设置为1,无论响应是(是或否),注册表键都不会被删除。 我尝试在其他事件之前/之后安排CA,但似乎没有任何帮助。
为什么这个条件似乎总是评估为false?有没有办法让它工作?
此外,是否有更好的替代方案? 我正在考虑修改卸载对话框以添加复选框提示用户删除注册表键,但我不确定如何做到这一点。 我知道如何进行更改-修改现有对话框或添加新对话框-以执行序列(我正在使用修改后的WixUI_InstallDir序列),但我无法弄清楚如何在卸载时执行此操作。
有什么想法吗?

假如你有一个已加密的数据库连接字符串、加密密钥、一些特权用户凭证或其他敏感数据。 - Alek Davis
像本地网络连接这样的东西? 对我来说,这似乎不是自定义用户设置。 当您谈论许多计算机时,应考虑通过使用活动目录和组策略将设置共享到所有计算机。 这个设置,它会进入安装过程中吗? - coding Bott
当您拥有一个全局设置,它不是安装程序的一部分时,为什么应该由卸载程序处理?我认为根本不应该成为安装程序的一部分。创建这些设置的软件应该负责删除它们。我知道这有点困难,因为在卸载之前/期间应用程序并未运行。如果您现在说,在计算机上会留下垃圾 - 您是正确的。 - coding Bott
因为如果卸载不处理它,那么谁会呢?假设应用程序本身可以清除设置,但您认为用户在卸载应用程序之前会记得这样做吗?不会。而且它不仅仅是垃圾,而是带有敏感数据的垃圾。除非数据被使用,否则您不想将其保留。 - Alek Davis
顺便说一下,这是一个常见的卸载模式。我刚从测试系统中卸载了Chrome,并询问我是否要删除所有数据(如临时文件、cookies等),以及是否要将默认浏览器更改为IE。这些都不是由安装程序安装的,但Chrome足够负责任地清理自己的残留物。任何应用程序都应该如此。 - Alek Davis
显示剩余8条评论
3个回答

5
通常情况下,您应该在UI序列中安排对话框,而不是在执行序列中安排。如果不这样做,您将无法进行无声(非)安装。
我认为您的自定义操作(CA)运行太晚了,并且将要执行的脚本已经创建。在这种情况下,“DELETEREGKEY”未设置并计算为false-结果键保持不变。
请尝试将您的CA移动到UI序列中。

我已经尝试在UI序列中安排CA的计划(尝试了几个事件),但似乎没有帮助。我会再试一次。谢谢你提供的无声卸载提示。 - Alek Davis
嗯,我尝试在ExecuteUISequence中的CostInitialize和ExecuteAction之前和之后安排它,但我根本没有看到弹出窗口。可能是我做错了什么。我会继续挖掘。 - Alek Davis
如果您在使用 CA 时遇到问题,请尝试在 WIX 中实现对话框。只需添加另一个向导页面即可。最佳实践始终是避免使用 CA。 - coding Bott
根据这个答案,卸载以静默模式运行,因此UI序列被绕过,这就解释了为什么我的CA没有从UI序列调用:http://stackoverflow.com/a/19146375/52545 - Alek Davis
如果通过GPO进行软件部署的机会更高,那么完全同意。但是,如果没有这种情况,我就不太确定了。我的意思是,很少有用户了解它的工作原理。虽然我已经使用安装程序/wix/msi很长时间了(虽然不是我的主要工作),但ARP的行为对我来说是一个完全的启示。因此,对于大多数人来说,预期的行为可能看起来更像是软件(安装程序)的问题,而不是Windows Installer的原始设计问题。 - Alek Davis
显示剩余5条评论

1

对于用户数据和其他设置之类的项目,我过去的处理方式是在卸载时将数据留在计算机上。在安装过程中,您可以检查是否存在此类数据,如果存在,则提示用户删除或覆盖该数据。


如果用户计划重新安装软件,这种方法是可行的,但当软件被永久删除时,这不是一个好选择,特别是当设置包含一些敏感数据时,通常情况下您不想保留它们(例如,如果它是一个服务器应用程序,其中包含加密连接字符串、密码或其他您不想保留的内容)。 - Alek Davis
在这种情况下,如果你只是在卸载,那么你不能永久删除它吗?但是,如果你检测到正在进行升级,那么你可以保留它或提示用户该怎么做? - BryanJ
因为我不知道用户是永久卸载(这种情况下清理是适当的)还是暂时卸载(比如,用户想要进行干净安装,或者安装以前的版本)并希望保留配置设置以供将来使用。我不是指主要升级(这很容易),但有些情况下,您需要完全卸载,然后从头安装(例如安装以前的版本)。 - Alek Davis

0

我在这里总结一下自己的发现。

看起来在执行序列中设置属性太晚了,无法在评估条件时生效。但是将 CA 移动到 UI 序列也不是一个好选择,因为默认情况下卸载会在静默模式下运行,绕过 UI。有一种方法可以调整自定义卸载快捷方式和“添加/删除程序”(ARP) 条目,以在完整的 UI 模式下运行卸载程序,但它也带来了自己的麻烦,其中最小的问题是必须手动填充 ARP 注册表项。

我采取的方法是在执行序列期间通过编程方式简单地删除注册表键 (因此我不需要 RemoveRegistryKey 组件)。为了允许静默卸载,我还添加了命令行选项,以指定是否应删除注册表键以及是否显示提示 (如果未提供删除键开关)。默认情况下,我保留注册表键。不是非常优雅,但似乎能胜任工作。

关于修改卸载对话框的建议,请参见 WiX 3.7: How to add or update a dialog during uninstall?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接