自定义操作返回错误时中断安装 [英] Interrupt installation when custom action returns error

查看:95
本文介绍了自定义操作返回错误时中断安装的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一种方法可以验证 .dll 中的密码,并且在失败时应返回错误代码。它具有以下原型:

  #define DllExport __declspec(dllexport)
extern C DllExport UINT TestPassword(MSIHANDLE hInstall);

我希望当此方法返回错误代码时(例如 ERROR_INSTALL_USEREXIT = 1602 ),整个安装过程将终止(不会执行此操作之后的其他自定义操作),但是不会。



此外,在Wix中,我有以下片段:

 < CustomAction Id ='TestPassword'BinaryKey ='TestPassword'DllEntry ='TestPassword' Execute ='immediate'
Return ='check'/>

<二进制ID = TestPassword SourceFile = DummyDll.dll />


解决方案


更新:一些有用的链接。






  • 验证MSI文件DLL :您应该检查已编译的MSI,以验证其内部是否具有正确的DLL,并具有正确的导出功能。因此;验证DLL是否已安全地放入MSI的Binary表中:


    1. 打开已编译的MSI Orca



      发布模式C ++二进制文件现在不应该依赖于任何MSVC运行时dll:





      以下是该DLL如何依赖MSVC运行时dll的屏幕快照,没有进行此调整-别介意红色图标-这是古老的依赖行者工具,不会更新适用于现代依赖关系,但可以完美显示较旧样式的依赖关系:





      请注意,调试模式DLL可能依赖于与发布模式二进制文件不同的文件。发布模式二进制文件很重要。显然永远不要分发调试模式的二进制文件!


      I have a method that verifies a password in a .dll and it should return an error code on failure. It has the following prototype:

      #define DllExport __declspec( dllexport )
      extern "C" DllExport UINT TestPassword(MSIHANDLE hInstall);
      

      I expect that when this method returns an error code (like ERROR_INSTALL_USEREXIT = 1602) the whole installation process will terminate (no other custom action following this one will be executed), but it doesn't.

      Also, in Wix I have the following fragment:

       <CustomAction Id='TestPassword' BinaryKey='TestPassword' DllEntry='TestPassword' Execute='immediate'
                    Return='check'/>
      
      <Binary Id='TestPassword' SourceFile='DummyDll.dll'/>
      

      解决方案

      UPDATE: Some helpful links.


      Suspected causes:

      Listing some suggestions at the top here.

      • 1) Wrong C++ custom action code configuration, often forgetting to create a CA.def file to define dll exports. I also always use __stdcall (MSI is an old girl).
      • 2) Wrong path to custom action dll in WiX markup (not valid dll in MSI).
      • 3) Forgot to enable checking of error codes in the WiX markup (*.WXS) and then a CA does not end the setup. This looks correct in your case (Return='check').
      • 4) Forgot to insert custom action in installation sequence.
      • There are a few more, can't think of them at the moment. Might add later... One that comes to mind is bitness problems (x86/64)...
      • File and runtime dependencies is a classic fallover cause.
        • Try to statically link whatever you can.
        • Deployment DLLs should be minimum dependencies for sure since they need to run on any system, in any language, in any state, in any OS version, et...
        • One of the few cases where static linking is really recommended and always the right choice.

      Heads-Up: Avoid Licensing In Setup? I would recommend you put the license validation in your application instead of your setup. Here are some thoughts on the matter: Installer with Online Registration for Windows Application (recommended read).


      Technical Issues:

      FileName.def: I am no C++ expert, but do you have a FileName.def file in your project to declare the exported functions for the dll? If not - add one (steps / procedure below). Make sure it is in the right format (add via Visual Studio, I think it is UTF8 without BOM). Compile and check with Dependency Walker if all exports are correct:

      Verify MSI File DLL: You should check the compiled MSI to verify it has the correct DLL inside it with the correct exports available. Hence; verify that the DLL has safely made it into the Binary table of the MSI:

      1. Open your compiled MSI with Orca (or equivalent).
      2. Binary table, double click the Data column for your DLL entry.
      3. Select "Write binary to filename" and save to desktop (or somewhere else).
      4. Use Dependency Walker (depends.exe) to verify that you have a valid DLL as illustrated in the image above. Common problem is that you see no exports at all (MyImmediateCA, MyTestFail, MyTestSuccess, etc...).
      5. Verify the file- and product versions as well in file properties.

      Error Processing: A custom action can be set to suppress errors. Your markup looks correct with the "Return attribute" set: (Return='check'). Your snippet:

      <CustomAction Id='TestPassword' BinaryKey='TestPassword' 
                    DllEntry='TestPassword' Execute='immediate' Return='check'/>
      

      Sequencing: Also check that your sequencing is OK. Altogether you need to point to the binary table DLL, declare the custom action and then also insert it into the right sequence. Mock-up WiX markup:

      <!--<Binary Id="CustomActions" SourceFile="$(var.TestDll.TargetPath)" />-->
      <Binary Id="CustomActions" SourceFile="C:\TestDll.dll" />
      
      <CustomAction Id="MyTestFail" BinaryKey="CustomActions" DllEntry="MyTestFail"/>
      <CustomAction Id="MyTestSuccess" BinaryKey="CustomActions" DllEntry="MyTestSuccess"/>
      
      <InstallExecuteSequence>
        <Custom Action="MyTestSuccess" After="CostFinalize" />
        <Custom Action="MyTestFail" After="MyTestSuccess" />
      </InstallExecuteSequence>
      


      C++ DLL: And the actual C++ DLL itself (remember the *.def file). Snippet in the bottom code segment from MSI API Custom Action Security:

      Suggested steps for Visual Studio 2017:

      1. Create new VC+ DLL Project - Dynamic-Link Library (DLL).
      2. Dump the below code in the main *.cpp file (I avoid the dllmain.cpp).
      3. Add the *.def file!
        • Right Click Source Files => Add => New Item... => Code => Module-Definition File (.def) => Any name should do... (only one def file allowed)
        • Add your export function names:

      Mock-up:

      LIBRARY
      
      EXPORTS
           MyTestFail
           MyTestSuccess
           MyImmediateCA
      

      Close and re-open file to verify if there are any format errors. Select fix if a warning appears. UTF8 without BOM required I think.

      #include "stdafx.h"
      
      #include <windows.h>
      #include <Msiquery.h>
      #pragma comment(lib, "msi.lib")
      
      UINT __stdcall MyTestFail(MSIHANDLE hInstall)
      {
          MessageBox(NULL, L"MyTestFail", L"MyTestFail", MB_OK);    
          return ERROR_INSTALL_FAILURE;
      }
      
      UINT __stdcall MyTestSuccess(MSIHANDLE hInstall)
      {
          MessageBox(NULL, L"MyTestSuccess", L"MyTestSuccess", MB_OK);    
          return ERROR_SUCCESS;
      }
      
      // I will leave in the below snippet from the MSI API - section "Custom Action Security". Above two test methods will do though... 
      UINT __stdcall MyImmediateCA(MSIHANDLE hInstall)
      {
          MessageBox(NULL, L"Test", L"Test", MB_OK);
      
          // set up information for deferred custom action called MyDeferredCA
          const TCHAR szValue[] = TEXT("data");
          UINT uiStat = ERROR_INSTALL_FAILURE;
          if (ERROR_SUCCESS == MsiSetProperty(hInstall, TEXT("MyDeferredCA"), szValue))
          {
              uiStat = MsiDoAction(hInstall, TEXT("MyDeferredCA"));
      
              // clear CustomActionData property
              if (ERROR_SUCCESS != MsiSetProperty(hInstall, TEXT("MyDeferredCA"), TEXT("")))
                  return ERROR_INSTALL_FAILURE;
          }
      
          return (uiStat == ERROR_SUCCESS) ? uiStat : ERROR_INSTALL_FAILURE;
      }
      

      Minimal Dependencies: In order to minimize dependencies you should eliminate the Visual C / C++ Runtime dependencies and any MFC dependencies (don't use MFC if you can help it for file size and performance reasons). If you use MFC, set it to use static linking - also for ATL. And finally for the C/C++ runtime, see here: Visual Studio 2010 MSVCR dependency removal? (there are better links, but all I could find that I have time for right now - just want to get this in there so it is not forgotten).

      The Release mode C++ binary should now not depend on any MSVC runtime dlls:

      Here is a screenshot of how the DLL depends on MSVC runtime dlls without this tweak - don't mind the red icons - this is the ancient dependency walker tool which is not updated for modern dependencies, but shows older-style dependencies perfectly:

      Please note that debug-mode DLLs may depend on different files than the Release mode binaries. The Release mode binaries are the ones that are important. Obviously never distribute debug-mode binaries!

      这篇关于自定义操作返回错误时中断安装的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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