实验的原因

偶遇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() thenif (AskYesNo("已经发现本软件已经被安装!\r\n" + "是否继续安装?", YES) = NO) then g_bSetupNow = FALSE; ///< 用户选择不安装// RunUnInstallExe(); endif;endif;
end;                              function IsProductWasInstalled()BOOL bRc;
beginif (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) thenbRc = FALSE;else  bRc = TRUE;endif;return bRc;
end;        function RunUnInstallExe()STRING strUnInstallPathName;
begin
/**if (GetUnInstallExePathName(strUnInstallPathName)) thenLaunchAppAndWait(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) thenabort;endif;// Added in InstallShield 15 - Show an appropriate error message if// -removeonly is specified and the product is not installed.if( REMOVEONLY ) thenDisable( 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 Sequence
Dlg_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) thengoto Dlg_SdWelcome;elsebLicenseAccepted = 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) thengoto Dlg_SdRegisterUser;elsenSetupType = nResult;if (nSetupType != CUSTOM) thenszTargetPath = 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) thenabort;endif;// nType defaults to MODIFY.nType = REPAIR; ///< 只有选修复, 才能实现覆盖安装//Initialize SQLOnSQLServerInitializeMaint();// Beginning of UI Sequence
Dlg_Start:// Added in Version 9.5 - Support for REMOVEONLY option.if( !REMOVEONLY ) then// In standard mode show maintenance dialogDisable( 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 Dialogif ( nType = REMOVEALL ) thennResult = MessageBox( SdLoadString( IFX_MAINTUI_MSG ), MB_YESNO );if (nResult != IDYES ) thenif( 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 ) thenszTitle = "";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 ) thenFeatureSelectItem( 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 ) ) thenDisable( 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 ) thenCreateInstallationInfo();endif;// Move DatanResult = 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 ) thenOnComponentError();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 InformationOnCustomizeUninstInfo();endif;// Disable StatusDisable( STATUSEX );end;

InstallShield : 实现二次安装时的覆盖安装相关推荐

  1. mysql5.7编译安装路径_MySQL_MySQL 5.5/5.6/5.7及以上版本安装包安装时如何选择安装路径,安装环境需求: 自从昨天安 - phpStudy...

    MySQL 5.5/5.6/5.7及以上版本安装包安装时如何选择安装路径 安装环境需求: 自从昨天安装了mysql 5.7,发现了一个问题,mysql5.6起,已经不支持2003系统了,如果安装了无法 ...

  2. [解决]尝试安装时出现“无法安装 Office(64 位或 32 位)”错误

    [解决]尝试安装时出现"无法安装 Office(64 位或 32 位)"错误 出现这种错误大概率是因为电脑安装了office 没有卸载干净. 网上比较多的方法是删除注册表编辑器中的 ...

  3. vs2015安装时无法选择安装路径解决办法

    vs2015安装时无法选择安装路径解决办法 卸载vs2015,由于卸载的不够干净,重新安装时,发现无法选择新的安装路径.这是由于还有些相关的组件没卸载,导致安装路径还得和原来一样. 解决办法: (1) ...

  4. Visual Studio二次安装时无法更改安装位置解决方案

    背景:去年年底因为一个C#项目,安装过Visual Studio,当时采用的是默认安装,即安装到C盘.最近有个VB的桌面小项目,想安装Windows开发平台负载时发现C盘剩余空间不足15G,随起了卸载 ...

  5. 尝试安装时出现“无法安装 Office(64 位或 32 位)”错误

    问题描述 如果尝试在已安装 32 位版或 64 位版 Office 的计算机上安装 64 位版或 32 位版 Office 套件或 Visio 等 Office 独立应用程序,可能会看到如下所示的错误 ...

  6. Adobe系列在安装时,出现安装程序检测到计算机重新启动的过程中可能暂停、安装失败

    1.按步骤依次打开这些文件HKEY_LOCAL_MACHINE----SYSTEM----CurrentControlSet------Control------Session Manager,找到P ...

  7. win11无法打开.bat文件、打开.bat文件闪退解决方案,星露谷smapi mod安装时,.bat安装文件一闪而过

    遇到问题 在安装星露谷smapi mod时,安装mod所需要的.bat文件打不开,用管理员身份打开文件后,.bat文件一闪而过 问题分析 环境变量没有配置好 解决方案 打开设置-系统信息-高级系统设置 ...

  8. MATLAB在安装时需要选择安装的产品

    下表整理了MATLAB 2022a绝大部分产品工具箱/应用的解释(电脑内存较小,实在无法全部安装,含泪谷歌翻译整理),可参考安装: 序号 产品 解释 1 5G Toolbox 模拟.分析和测试5G通信 ...

  9. 当前安装包签名出现异常_apk的签名异常,安装时说已安装了存在签名冲突的数据包...

    展开全部 这个很正常,那是因为你没有改过62616964757a686964616fe59b9ee7ad9431333431373235apk,你要是改过apk就会知道,改过的apk都是需要签名才可以 ...

最新文章

  1. 继承映射关系 TPH、TPT、TPCEntityFramework6.0
  2. 比特币耶稣Roger Ver:BCH是世界上最创新、最实用的加密货币之一
  3. Windows Phone 8 开发资源汇总
  4. MySQL高级 - 查询缓存 - 失效场景
  5. 六种排序算法的JavaScript实现以及总结
  6. [HDOJ5542]The Battle of Chibi(DP,树状数组)
  7. 配合OAuth2进行单设备登录拦截
  8. Dockerfile 中 配置安装 php 扩展
  9. Python与自然语言处理搭建环境
  10. 用SpringBoot集成Netty开发一个基于WebSocket的聊天室
  11. python计算天数包含几周_如何在python中计算几周内两个日期之间的差异
  12. llc变换器计算机仿真,LLC谐振变换器的参数设计
  13. 连续值特征分桶区间设置
  14. C语言递归解决水洼问题
  15. AI领域首位图灵奖得主Marvin Minsky:求索“智能”奥秘的一生 | 人物志
  16. 7-2 sdust-Java-学生成绩读取与排序 (20 分)
  17. 通过 PRTG EXE 高级监控脚本 + python 监控华为防火墙线路健康状态
  18. quartz-深度解析
  19. 【3dsmax新手入门】-实体立方八面晶体绘制
  20. mysql学校教务系统_java servlet+mysql开发的学校官网+教务系统+图书馆系统,功能完善,供参考学习...

热门文章

  1. 适用于ipad2021电容笔有哪些?高性价比的ipad电容笔推荐
  2. 什么时候可以将数字化仪用作示波器,示波器数字化仪和非示波器数字化仪有什么区别?
  3. SVD奇异值分解(标题重复率过高)
  4. three games 之 桌球
  5. 如何用人工智能帮你剪视频?
  6. mysql8 caching-s,MySQL8.0登录连接报错caching_sha2_password解决方法
  7. SQL 函数 function 讲解+代码实例
  8. 约束非线性优化:几何意义对偶形式
  9. ZKP方案衍变及对比
  10. Linux内核源代码分析经验