使用CustomAction卸载Wix的问题 [英] Problem with Wix uninstall using CustomAction

查看:63
本文介绍了使用CustomAction卸载Wix的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个非常简单的MSI,将某些文件复制到ProgramFiles目录,并在安装对以C#编写的二进制文件中找到的自定义操作的调用时进行.

在安装时,我可以轻松调用所需的任何自定义操作.例如,我创建了一个安装步骤,用户应在其中输入许可证,并在确认许可证后使用C#自定义操作中编写的逻辑针对服务器对许可证进行检查.

但是,在卸载时,每次我添加一个自定义操作(即使它只返回成功也没有执行任何操作),都会收到安装失败的错误消息.

这是我使用卸载步骤的方式:

 < InstallExecuteSequence>< Custom Action ='TestUninstallation'After ='MsiUnpublishAssemblies'> REMOVE ="ALL"</Custom></InstallExecuteSequence> 

其中TestUninstallation的定义如下:

 < CustomAction Id ="TestUninstallation" Return ="check" Execute ="deferred" Impersonate ="no" BinaryKey ="TestCustomAction" DllEntry ="Uninstall"/> 

DllEntry属性等于Uninstall,这是一种C#方法,仅返回成功.

安装完成后,我试图卸载,并在AdminUISequence中定义了具有属性OnExit的UserExit对话框.

知道我想念什么吗?

解决方案

调试 :托管代码相对易于调试(本地代码实际上甚至更容易).这里有一些指针:

  • 这是DTF打包的托管代码dll :

    请注意,这是一个嵌入了托管代码内容的本机dll.它产生了一个非常不同的函数列表,但是您仍然必须在其中找到所引用的函数名称.

    这是一个直接托管代码dll(无本地包装) :

    最后:这是直接的托管代码DLL,没有包装在本机dll外壳中.


    不可卸载的安装程序 :当自定义操作在卸载过程中崩溃或失败时,您将有摆脱安装的问题(它只是回滚而您卡住安装).有几个修复程序或解决方法.

    整体解决方案-我认为-不会使自定义操作在卸载时失败,或者至少要对它们进行条件处理,以便您可以通过在命令行中设置属性来强制卸载:

    在MSI属性表中设置: SUPPRESSERROR = 0 .然后-在需要时-在命令行上设置:

      msiexec.exe/x {PRODUCT-GUID} SUPPRESSERROR ="1" 

    在MSI内,您可以使用以下条件来执行卸载自定义操作:

      REMOVE ="ALL" AND SUPPRESSERROR ="0" 

    现在,如果SUPPRESSERROR不为0,则自定义操作将不会运行.

    有一个较旧的答案,其中有几个其他选项: Wim Coenen 提供,和我搞混了他的答案,并提出了更多建议).


    样板 :为了快速使用,让我在此处转储样板临时自定义操作测试项目.假设在同一Visual Studio解决方案中有一个名为 "CustomAction1" 的C#托管代码自定义操作项目,并且在您的WiX源中向其添加了引用-就像您已经很显然地(这是供以后当我们都忘记了问题所在并需要再次测试时:

     <?xml version ="1.0" encoding ="UTF-8"?>< Wix xmlns ="http://schemas.microsoft.com/wix/2006/wi"><产品ID ="*"名称="WiXCustomActionsTesting"语言="1033"版本="1.0.0.0"Manufacturer ="test" UpgradeCode ="PUT-GUID-HERE">< Package InstallerVersion ="200" Compressed ="yes" InstallScope ="perMachine"/>< UIRef Id ="WixUI_Mondo"/><属性ID ="SUPPRESSERROR"值="0" Secure =是"/>< MajorUpgrade DowngradeErrorMessage =已经安装了[ProductName]的较新版本."/>< MediaTemplate EmbedCab ="yes"/>< Feature Id ="ProductFeature" Title ="WiXCustomActionsTesting" Level ="1">< ComponentGroupRef Id ="ProductComponents"/></功能><!-开始​​进行自定义操作部分-><二进制ID ="CustomActions" SourceFile ="$(var.CustomAction1.TargetDir)\ $(var.CustomAction1.TargetName).CA.dll"/>< CustomAction Id ="TestUninstallation" Return ="check" Execute ="deferred" Impersonate ="no" BinaryKey ="CustomActions" DllEntry ="CustomAction1"/>< InstallUISequence></InstallUISequence>< InstallExecuteSequence>< Custom Action ='TestUninstallation'After ='InstallInitialize'></Custom></InstallExecuteSequence><!-结束自定义操作部分-></产品><片段><目录ID ="TARGETDIR"名称="SourceDir"><目录ID ="ProgramFilesFolder"><目录ID ="=" INSTALLFOLDER名称=" WiXCustomActionsTesting"/></目录></目录></片段><片段>< ComponentGroup Id ="ProductComponents" Directory ="INSTALLFOLDER"><组件>< File Source ="C:\ Projects \ MySetup \ MyApp.exe"></文件></Component></ComponentGroup></片段></Wix> 

    1. 创建WiX项目
    2. 复制粘贴代码,设置新的升级GUID
    3. 创建CustomAction项目,默认名称
    4. 从wix项目中添加对自定义操作项目的引用
    5. 添加对WiXUIExtension.dll的引用
    6. 调整组件中文件的路径
    7. 编译

    I've created a very simple MSI which copies some files to the ProgramFiles directory and while installing calling to custom actions found in a binary written in C#.

    While installing, I can easily call any custom action I want. For example I've created an installation step where the user should enter a license, and after confirming the license it is checked against a server using logic written inside C# custom action.

    But, when uninstalling, every time I add a custom action (even if it does nothing but returning Success), I get error that the installation failed.

    This is how I use the uninstalling step:

    <InstallExecuteSequence>
      <Custom Action='TestUninstallation' After='MsiUnpublishAssemblies'>REMOVE="ALL"</Custom>
    </InstallExecuteSequence>
    

    where TestUninstallation is defined as following:

    <CustomAction Id="TestUninstallation" Return="check" Execute="deferred" Impersonate="no" BinaryKey="TestCustomAction" DllEntry="Uninstall" />
    

    The property DllEntry equals Uninstall which is a C# method which only returns Success.

    After installation is completed, I'm trying to uninstall and I'm getting the UserExit dialog defined inside the AdminUISequence with the property OnExit.

    Any idea what am I missing?

    解决方案

    Debugging: Managed code is relatively easy to debug (native code is actually even easier). Here are some pointers:


    Suggestions: I think you just have a broken reference to the dll export function - in other words an erroneous dll function name / reference:

    <CustomAction Id="TestUninstallation" Return="check" Execute="deferred" Impersonate="no"
                  BinaryKey="CustomActions" DllEntry="__ERRONEOUS FUNCTION REFERENCE__" />
    

    Just check what the dll actually exports and match like this:

    <CustomAction Id="CustomAction1" BinaryKey="CustomActions" DllEntry="CustomAction1"/>
    

    As always the real McCoy is the check of the dll itself to see if you have the right function name (the below screen shot from this prior answer, recommended read).

    This is a native code C++ dll:

    This is a DTF-packaged managed code dll:

    Notice that this is a native dll with the managed code stuff embedded. It yields a very different functions list, but you still have to find the function name in there that you refer to.

    This is a straight-up managed code dll (no native wrapping):

    And finally: this is the straight-up managed code DLL without being wrapped in a native dll shell.


    Un-Uninstallable Setup: When a custom action crashes or fails during uninstallation, you will have problems getting rid of the installation (it just rolls-back and you are stuck with it installed). There are several fixes or workarounds.

    The overall fix - in my view - is to not fail custom actions on uninstall, or at least condition them so you can force an uninstall by setting a property via the command line:

    Set in MSI property table: SUPPRESSERROR = 0. Then - when needed - on the command line set:

    msiexec.exe /x {PRODUCT-GUID} SUPPRESSERROR="1"
    

    Inside the MSI you condition the uninstall custom action with:

    REMOVE="ALL" AND SUPPRESSERROR="0"
    

    Now the custom action will not run if SUPPRESSERROR is anything but 0.

    There is an older answer with several further options: I screwed up, how can I uninstall my program? (courtesy of Wim Coenen, with me messing up his answer with more suggestions).


    Boilerplate: For quick use, let me just dump a boilerplate ad-hoc custom action test project here. This assumes a C# managed code custom action project called "CustomAction1" in the same Visual Studio solution and a reference added to it in your WiX source - like you already have obviously (this is for later when we have all forgotten what the problem was and need to test again):

    <?xml version="1.0" encoding="UTF-8"?>
    <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
        <Product Id="*" Name="WiXCustomActionsTesting" Language="1033" Version="1.0.0.0"
               Manufacturer="test" UpgradeCode="PUT-GUID-HERE">
            <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
    
        <UIRef Id="WixUI_Mondo" />
        <Property Id="SUPPRESSERROR" Value="0" Secure="yes" />
    
        <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
        <MediaTemplate EmbedCab="yes" />
    
        <Feature Id="ProductFeature" Title="WiXCustomActionsTesting" Level="1">
          <ComponentGroupRef Id="ProductComponents" />
        </Feature>
    
        <!--BEGIN CUSTOM ACTION SECTION-->
    
          <Binary Id="CustomActions" SourceFile="$(var.CustomAction1.TargetDir)\$(var.CustomAction1.TargetName).CA.dll" />
          <CustomAction Id="TestUninstallation" Return="check" Execute="deferred" Impersonate="no" BinaryKey="CustomActions" DllEntry="CustomAction1" />
    
          <InstallUISequence></InstallUISequence>
    
          <InstallExecuteSequence>
            <Custom Action='TestUninstallation' After='InstallInitialize'></Custom>
          </InstallExecuteSequence>
    
        <!--END CUSTOM ACTION SECTION-->
    
      </Product>
    
        <Fragment>
            <Directory Id="TARGETDIR" Name="SourceDir">
                <Directory Id="ProgramFilesFolder">
                    <Directory Id="INSTALLFOLDER" Name="WiXCustomActionsTesting" />
                </Directory>
            </Directory>
        </Fragment>
    
      <Fragment>
    
        <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
    
          <Component>
            <File Source="C:\Projects\MySetup\MyApp.exe">
            </File>
          </Component>
    
        </ComponentGroup>
    
      </Fragment>
    </Wix>
    

    1. Create WiX project
    2. Copy paste the code, set a new Upgrade GUID
    3. Create CustomAction project, default name
    4. Add reference to custom action project from wix project
    5. Add reference to WiXUIExtension.dll
    6. Adjust path to file in component
    7. Compile

    这篇关于使用CustomAction卸载Wix的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆