2025年InstallShield - 实现二次安装时的覆盖安装

InstallShield - 实现二次安装时的覆盖安装实验的原因 偶遇 csdnerA 君 需要解决领导给他的打包需求 需求要求 二次安装时 需要检查是否有旧版安装 如果有旧版安装 提示用户是否继续安装 如果不继续安装 退出安装程序 如果继续安装 实现覆盖安装 不让用户在 UI 上选择 修改 修复 卸载 我在 2010 年时 经常会用到 InstallShiel 现在的打包程序是自己写的 界面效果好

大家好,我是讯享网,很高兴认识大家。

实验的原因

偶遇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 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) 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 Sequence Dlg_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; 

讯享网
小讯
上一篇 2025-01-16 18:46
下一篇 2025-03-07 14:50

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/23171.html