InstallShield : 实现二次安装时的覆盖安装
来源:互联网 发布:亨利领 t恤 知乎 编辑:程序博客网 时间:2024/06/05 07:30
实验的原因
偶遇csdnerA君, 需要解决领导给他的打包需求.
需求要求:
* 二次安装时,需要检查是否有旧版安装.
* 如果有旧版安装,提示用户是否继续安装.
* 如果不继续安装,退出安装程序.
* 如果继续安装,实现覆盖安装,不让用户在UI上选择( 修改,修复,卸载).
我在2010年时,经常会用到InstallShield. 现在的打包程序是自己写的, 界面效果好, 安装程序控制灵活.
我开始建议A君自己去写安装程序. 但是A君说领导指定必须用InstallShield来打包, 晕倒啊~
A君在用InstallShield的过程中, 不知道是哪里的细节搞的不对, 不能实现覆盖安装, 也不能完全实现提示用户后的安装控制.
我今天下午和晚上就贡献给他, 为他来做这个实验. 对自己来说, 也是对技术点的复习和提高. 和他讨论的过程中, 也学到了一些他的心得.
实验做完了, 解决了他的问题, 实验结果很完美~
实现点
- 覆盖安装(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)
- 对已经安装的旧版本进行检测, 通过查InstallShield自带帮助, 翻了好久,发现可以用 MAINTENANCE 来判断
- 当用户选择安装时,直接安装. 我采用了跳过 OnMaintUIBefore() 中 SdWelcomeMaint, 直接对 nType 赋值成 REPAIR, 来实现
- 当用户选择不安装时, 在 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
- InstallShield : 实现二次安装时的覆盖安装
- InstallShield 2015 LimitedEdition VS2015打包 覆盖安装
- Installshield安装
- Installshield安装
- Installshield安装
- InstallShield升级安装的问题
- Installshield新版本安装时卸载旧版本的安装
- Installshield新版本安装时卸载旧版本的安装
- InstallShield制作安装包实现自动化
- InstallShield制作安装包实现自动化
- InstallShield制作安装包实现自动化
- installshield脚本实现windows服务安装
- Installshield工程类型 & Installshield安装程序的silent installation
- Installshield脚本中安装时RegDBCreateKeyEx的注意事项
- InstallShield安装时出现“1152:error extracting"的解决方案
- InstallShield制作带ODBC的安装软件
- InstallShield制作带ODBC的安装软件
- installshield的多安装程序制作
- HDU 2389 Rain on your Parade (二分图匹配(Hopcroft-Carp的算法模板))
- Android 打包Jar(发布SDK)常见问题及解决方案
- Android中R文件的丢失问题
- c++程序设计——实验6
- islands打炉石传说—01背包
- InstallShield : 实现二次安装时的覆盖安装
- 递归与尾递归(C语言)
- 【Android】提示Note: This element has no attached source and the Javadoc could not be found in the attac
- 第四章作业补+排序+查询
- Linux\Windows下vim配置
- BestCoder Round #41 -- (A,B)
- 根据前序和中序遍历求后序 /后序和中序求前序
- override中super的用法
- islands的难题—线段是单点更新