InstallShield : 实现二次安装时的覆盖安装

来源:互联网 发布:亨利领 t恤 知乎 编辑:程序博客网 时间:2024/06/05 07:30

实验的原因

偶遇csdnerA君, 需要解决领导给他的打包需求.
需求要求:
* 二次安装时,需要检查是否有旧版安装.
* 如果有旧版安装,提示用户是否继续安装.
* 如果不继续安装,退出安装程序.
* 如果继续安装,实现覆盖安装,不让用户在UI上选择( 修改,修复,卸载).

我在2010年时,经常会用到InstallShield. 现在的打包程序是自己写的, 界面效果好, 安装程序控制灵活.

我开始建议A君自己去写安装程序. 但是A君说领导指定必须用InstallShield来打包, 晕倒啊~

A君在用InstallShield的过程中, 不知道是哪里的细节搞的不对, 不能实现覆盖安装, 也不能完全实现提示用户后的安装控制.

我今天下午和晚上就贡献给他, 为他来做这个实验. 对自己来说, 也是对技术点的复习和提高. 和他讨论的过程中, 也学到了一些他的心得.

实验做完了, 解决了他的问题, 实验结果很完美~

实现点

  1. 覆盖安装(note : InstallShield本来就提供, 需要注意的是 : InstallShield工程的新版本要增加版本号,不能是原来的版本号. 打包用的PE文件版本号需要比已经安装的PE文件版本号高, 而且必须要是改前三位版本号,不能改第四位版本号. 否则不能覆盖安装. e.g. 旧PE版本号 1.0.1.0, 新版本号码不能为1.0.1.9, 可以为 9.0.1.0, 1.9.1.0, 1.0.9.0)
  2. 对已经安装的旧版本进行检测, 通过查InstallShield自带帮助, 翻了好久,发现可以用 MAINTENANCE 来判断
  3. 当用户选择安装时,直接安装. 我采用了跳过 OnMaintUIBefore() 中 SdWelcomeMaint, 直接对 nType 赋值成 REPAIR, 来实现
  4. 当用户选择不安装时, 在 OnFirstUIBefore() 和 OnMaintUIBefore() 处 abort 实现安装程序退出.

总结

  • 感觉自己查资料的能力和解决问题的能力比2010年好很多, 很欣慰~
  • InstallShield的资料, 在网上很少. 自己翻InstallShield的自带Help, 需要翻很久. 权衡后, 还是翻InstallShield自带帮助节省时间, 而且能找到具体的线索和答案.
  • InstallShield能为我们生成每个安装事件的脚本实现, 确实让用户感到贴心.

备注

实验环境 : InstallShield2010

测试工程下载

test-installShield-2015-0516-2232.rar

安装脚本实现

#include "ifx.h"prototype IsProductWasInstalled(); prototype GetUnInstallExePathName(BYREF STRING); prototype RunUnInstallExe();BOOL g_bSetupNow; ///< 如果旧版程序已经安装, 记录用户选择(是否覆盖安装)function OnBegin()begin    // TODO: Perform custom initialization steps, check requirements, etc.    g_bSetupNow = TRUE;    if IsProductWasInstalled() then        if (AskYesNo("已经发现本软件已经被安装!\r\n" + "是否继续安装?", YES) = NO) then             g_bSetupNow = FALSE; ///< 用户选择不安装            // RunUnInstallExe();         endif;    endif; end;                              function IsProductWasInstalled()    BOOL bRc;begin    if (MAINTENANCE != 0) then        // 产品已经被安装过        bRc = TRUE;    else        // 产品首次被安装(还没有被安装,本次安装是首次)        bRc = FALSE;    endif;                        return bRc;end;      function GetUnInstallExePathName(strPathName)    BOOL bRc;begin                                   if (RegDBGetItem(REGDB_UNINSTALL_MODIFYPATH, strPathName) < 0) then        bRc = FALSE;    else          bRc = TRUE;    endif;    return bRc;end;        function RunUnInstallExe()    STRING strUnInstallPathName;begin/**        if (GetUnInstallExePathName(strUnInstallPathName)) then            LaunchAppAndWait(strUnInstallPathName, "", WAIT);        endif;        */        ComponentRemoveAll();end;//---------------------------------------------------------------------------                                                                        // OnFirstUIBefore//// First Install UI Sequence - Before Move Data//// The OnFirstUIBefore event is called by OnShowUI when the setup is// running in first install mode. By default this event displays UI allowing// the end user to specify installation parameters.//// Note: This event will not be called automatically in a// program...endprogram style setup.//---------------------------------------------------------------------------function OnFirstUIBefore()    number  nResult, nLevel, nSize, nSetupType;    string  szTitle, szMsg, szOpt1, szOpt2, szLicenseFile;    string  szName, szCompany, szTargetPath, szDir, szFeatures;    BOOL    bLicenseAccepted;begin       /// 不安装时的处理 : 退出安装程序                                        if (g_bSetupNow == FALSE) then        abort;    endif;    // Added in InstallShield 15 - Show an appropriate error message if    // -removeonly is specified and the product is not installed.    if( REMOVEONLY ) then        Disable( DIALOGCACHE );        szMsg = SdLoadString( IDS_IFX_ERROR_PRODUCT_NOT_INSTALLED_UNINST );        SdSubstituteProductInfo( szMsg );        MessageBox( szMsg, SEVERE );        abort;    endif;    nSetupType = COMPLETE;      szDir = TARGETDIR;    szName = "";    szCompany = "";    bLicenseAccepted = FALSE;// Beginning of UI SequenceDlg_Start:    nResult = 0;Dlg_SdWelcome:    szTitle = "";    szMsg = "";    //{{IS_SCRIPT_TAG(Dlg_SdWelcome)    nResult = SdWelcome( szTitle, szMsg );    //}}IS_SCRIPT_TAG(Dlg_SdWelcome)    if (nResult = BACK) goto Dlg_Start;Dlg_SdLicense2:    szTitle = "";    szOpt1 = "";    szOpt2 = "";    //{{IS_SCRIPT_TAG(License_File_Path)    szLicenseFile = SUPPORTDIR ^ "License.rtf";    //}}IS_SCRIPT_TAG(License_File_Path)    //{{IS_SCRIPT_TAG(Dlg_SdLicense2)    nResult = SdLicense2Ex( szTitle, szOpt1, szOpt2, szLicenseFile, bLicenseAccepted, TRUE );    //}}IS_SCRIPT_TAG(Dlg_SdLicense2)    if (nResult = BACK) then        goto Dlg_SdWelcome;    else        bLicenseAccepted = TRUE;    endif;Dlg_SdRegisterUser:    szMsg = "";    szTitle = "";    //{{IS_SCRIPT_TAG(Dlg_SdRegisterUser)       nResult = SdRegisterUser( szTitle, szMsg, szName, szCompany );    //}}IS_SCRIPT_TAG(Dlg_SdRegisterUser)    if (nResult = BACK) goto Dlg_SdLicense2;Dlg_SetupType2:       szTitle = "";    szMsg = "";    nResult = CUSTOM;    //{{IS_SCRIPT_TAG(Dlg_SetupType2)       nResult = SetupType2( szTitle, szMsg, "", nSetupType, 0 );    //}}IS_SCRIPT_TAG(Dlg_SetupType2)    if (nResult = BACK) then        goto Dlg_SdRegisterUser;    else        nSetupType = nResult;        if (nSetupType != CUSTOM) then            szTargetPath = TARGETDIR;            nSize = 0;            FeatureCompareSizeRequired( MEDIA, szTargetPath, nSize );            if (nSize != 0) then                      MessageBox( szSdStr_NotEnoughSpace, WARNING );                goto Dlg_SetupType2;            endif;        endif;       endif;Dlg_SdAskDestPath2:    if ((nResult = BACK) && (nSetupType != CUSTOM)) goto Dlg_SetupType2;    szTitle = "";    szMsg = "";    if (nSetupType = CUSTOM) then                //{{IS_SCRIPT_TAG(Dlg_SdAskDestPath2)           nResult = SdAskDestPath2( szTitle, szMsg, szDir );                //}}IS_SCRIPT_TAG(Dlg_SdAskDestPath2)        TARGETDIR = szDir;    endif;    if (nResult = BACK) goto Dlg_SetupType2;Dlg_SdFeatureTree:     if ((nResult = BACK) && (nSetupType != CUSTOM)) goto Dlg_SdAskDestPath2;    szTitle = "";    szMsg = "";    szFeatures = "";    nLevel = 2;    if (nSetupType = CUSTOM) then        //{{IS_SCRIPT_TAG(Dlg_SdFeatureTree)            nResult = SdFeatureTree( szTitle, szMsg, TARGETDIR, szFeatures, nLevel );        //}}IS_SCRIPT_TAG(Dlg_SdFeatureTree)        if (nResult = BACK) goto Dlg_SdAskDestPath2;      endif;Dlg_SQLServer:    nResult = OnSQLServerInitialize( nResult );    if( nResult = BACK ) goto Dlg_SdFeatureTree;Dlg_ObjDialogs:    nResult = ShowObjWizardPages( nResult );    if (nResult = BACK) goto Dlg_SQLServer;Dlg_SdStartCopy2:    szTitle = "";    szMsg = "";    //{{IS_SCRIPT_TAG(Dlg_SdStartCopy2)     nResult = SdStartCopy2( szTitle, szMsg );       //}}IS_SCRIPT_TAG(Dlg_SdStartCopy2)    if (nResult = BACK) goto Dlg_ObjDialogs;    // Added in 11.0 - Set appropriate StatusEx static text.    SetStatusExStaticText( SdLoadString( IDS_IFX_STATUSEX_STATICTEXT_FIRSTUI ) );    return 0;end;//---------------------------------------------------------------------------// OnMaintUIBefore//// Maintenance UI Sequence - Before Move Data//// The OnMaintUIBefore event is called by OnShowUI when the setup is// running in maintenance mode. By default this event displays UI that// allows the end user to add or remove features, repair currently// installed features or uninstall the application.//// Note: This event will not be called automatically in a// program...endprogram style setup.//---------------------------------------------------------------------------function OnMaintUIBefore()    number  nResult, nType;    string  szTitle, szMsg;begin    /// 不安装时的处理 : 退出安装程序                              if (g_bSetupNow == FALSE) then        abort;    endif;    // nType defaults to MODIFY.    nType = REPAIR; ///< 只有选修复, 才能实现覆盖安装    //Initialize SQL    OnSQLServerInitializeMaint();// Beginning of UI SequenceDlg_Start:    // Added in Version 9.5 - Support for REMOVEONLY option.    if( !REMOVEONLY ) then        // In standard mode show maintenance dialog        Disable( BACKBUTTON );           /// 不让用户选择, 直接进行"修复", 实现覆盖安装        // nType = SdWelcomeMaint( szTitle, szMsg, nType );        Enable( BACKBUTTON );        nResult = NEXT;    else        // Hide the initial progress dialog as otherwise the user can        // click on it, and hide the MessageBox.        Disable( DIALOGCACHE );        // In RemoveOnly mode, set to remove.        nType = REMOVEALL;    endif;    // Show Uninstall Confirmation Dialog    if ( nType = REMOVEALL ) then        nResult = MessageBox( SdLoadString( IFX_MAINTUI_MSG ), MB_YESNO );        if (nResult != IDYES ) then            if( REMOVEONLY ) then                // In REMOVEONLY mode, abort the setup.                abort;            else                // In non-REMOVEONLY mode, redisplay the previous dialog.                goto Dlg_Start;            endif;        endif;    endif;Dlg_SdFeatureTree:    if ( nType = MODIFY ) then        szTitle = "";        szMsg = SdLoadString( SD_STR_COMPONENT_MAINT_MSG );        nResult = SdFeatureTree( szTitle, szMsg, TARGETDIR, "", -1 );        if ( nResult = BACK ) goto Dlg_Start;    endif;Dlg_ObjDialogs:    nResult = ShowObjWizardPages( nResult );    if ( ( nResult = BACK ) && ( nType != MODIFY ) ) goto Dlg_Start;    if ( ( nResult = BACK ) && ( nType = MODIFY ) ) goto Dlg_SdFeatureTree;    switch(nType)        case REMOVEALL:            // Ensure that all previously installed features are removed.            FeatureRemoveAllInMediaAndLog();            // Added in 11.0 - Set appropriate StatusEx static text.            SetStatusExStaticText( SdLoadString( IDS_IFX_STATUSEX_STATICTEXT_MAINTUI_REMOVEALL ) );        case REPAIR:            // Changed for DevStudio 9, Disk1 files are now always updated when installed            // so when running from ADDREMOVE we need to prevent these files from being            // updated since this will result in files being updated that are locked by the setup.            // Updating these files when running from ADDREMOVE should not be needed since updates            // are not run directly from Add/Remove.            if( ADDREMOVE ) then                // Reinstall all previously installed features, except                // disk1 features.                FeatureUpdate( "" );            else                // Reinstall all previously installed features.                FeatureReinstall();            endif;            // Added in 11.0 - Set appropriate StatusEx static text.            SetStatusExStaticText( SdLoadString( IDS_IFX_STATUSEX_STATICTEXT_MAINTUI_REPAIR ) );        case MODIFY:            // Added in 11.0 - Set appropriate StatusEx static text.            SetStatusExStaticText( SdLoadString( IDS_IFX_STATUSEX_STATICTEXT_MAINTUI_MODIFY ) );    endswitch;end;//---------------------------------------------------------------------------// OnMoveData//// The OnMoveData event is called by OnShowUI to initiate the file// transfer of the setup.//// Note: This event will not be called automatically in a// program...endprogram style setup.//---------------------------------------------------------------------------function OnMoveData()number  nResult, nMediaFlags;begin    // Don't install the DISK1COMPONENT if MAINT_OPTION_NONE was specified.    if( MAINT_OPTION = MAINT_OPTION_NONE ) then        FeatureSelectItem( MEDIA, DISK1COMPONENT, FALSE );    endif;    // Updated in 11.5, disable the cancel button during file transfer unless    // this is non-maintenance mode or repair mode.    if( MAINTENANCE && ( !REINSTALLMODE || UPDATEMODE ) ) then        Disable( CANCELBUTTON );    endif;    // Show Status    // Note: Start status window at 1 in case CreateInstallationInfo call    // is lengthy.    SetStatusWindow( 1, "" );    Enable( STATUSEX );    StatusUpdate( ON, 100 );    // Create the uninstall infomation (after displaying the progress dialog)    // Don't create uninstall information if MAINT_OPTION_NONE was specified.    if( MAINT_OPTION != MAINT_OPTION_NONE ) then        CreateInstallationInfo();    endif;    // Move Data    nResult = FeatureTransferData( MEDIA );    // Moved in 11.0, Check for failure before creating uninstall key.    // Handle move data error and abort if error occured.    if( nResult < ISERR_SUCCESS ) then        OnComponentError();        abort;    endif;          // Create uninstall key, if DISK1COMPONENT was installed.    if( IFX_DISK1INSTALLED ) then        // Store text-subs for maintenance mode later, only do this when        // disk 1 is installed. Note that any text-subs that are updated after        // this call will not be remembered during maintenance mode.        FeatureSaveTarget("");        // Write uninstall information.        MaintenanceStart();        // Customize Uninstall Information        OnCustomizeUninstInfo();    endif;    // Disable Status    Disable( STATUSEX );end;
0 1
原创粉丝点击