5.设置安装模式
InstallScript MSI不足:
在InstallScript MSI中,在OnFirstUIBefore()执行完成后,即安装完成,这个时候需要做后续的操作,如写注册表等,这些操作要在OnFirstUIAfter()中执行。
如果此时点击取消,然后在此安装时,InstallShield会提示先卸载之前的安装,这个体验非常不好,而且InstallScript MSI还没有办法修改。
而在InstallScript 提供了一个逻辑条件,即OnShowUI(),这个可以自己修改安装模式,代码如下
function OnShowUI() BOOL bMaintenanceMode, bUpdateMode; string szIgnore, szTitle; begin //Enable dialog caching Enable( DIALOGCACHE ); //Determine what events to show. bUpdateMode =FALSE; bMaintenanceMode =FALSE; //Remove this to disabled update mode. if( UPDATEMODE ) then bUpdateMode =TRUE; endif; //Remove this to disable maintenance mode. if( MAINTENANCE ) then bMaintenanceMode =TRUE; endif; //Show appropriate UI //TODO: Enable if you want to enable background etc. //if ( LoadStringFromStringTable( "TITLE_MAIN", szTitle ) < ISERR_SUCCESS ) then //Load the title string. //szTitle = IFX_SETUP_TITLE; //endif; //SetTitle( szTitle, 24, WHITE ); //Enable( FULLWINDOWMODE ); //Enable( BACKGROUND ); //SetColor( BACKGROUND, RGB( 0, 128, 128 ) ); if( bUpdateMode ) then OnUpdateUIBefore(); else if( bMaintenanceMode ) then OnMaintUIBefore(); elseOnFirstUIBefore(); endif; endif; //Move Data OnMoveData(); //这里可以安装,也可以卸载组件
if( bUpdateMode ) then OnUpdateUIAfter(); else if( bMaintenanceMode ) then OnMaintUIAfter(); elseOnFirstUIAfter(); endif; endif; //Disable dialog caching Disable(DIALOGCACHE); end;
分析:
(1)可以看到可以显示有3中模式:OnUpdateUIBefore,OnMaintUIBefore,OnFirstUIBefore(对应有After),分别表示升级,维护(卸载,重安装),首次安装。
(2)OnMoveData()。这个是整个方法最重要的部分,表示数据安装或者卸载。具体使用会在后面分析。
如果我们不需要用户升级,可以将OnUpdateUIBefore()替换为OnFirstUIBefore(),OnUpdateUIAfter()替换为OnFirstUIAfter()不要删除,替换即可。修改后,即使用户安装中途取消,再次运行安装程序时,也是首次安装的状态(表现为:如果在在安装包中选择弹出语言选择框,此时这个语言选择框也会弹出。。)
6.在卸载组件中OnMoveData()的使用
在第5点中展示了使用OnMoveData,这里要说下使用过程中要注意到东西。
代码:
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;
这里最重要的是FeatureTransferData(MEDIA)这个使用。
这个方法可以查看帮助文档,安装和卸载时是不一样的。
安装:Installs features that are selected(安装只勾选的组件Feature)
卸载:Uninstalls features that are not selected and are currently installed(卸载不勾选的组件Feature)。
问题来了:
在卸载时,即调用OnMaintUIBefore()的时候,调用的是nResult = SdFeatureTree( szTitle, szMsg, TARGETDIR, "", -1 );
这样会出现的一个现象是:在卸载的时候,勾选的组件卸载不掉,不勾选的反而卸载了(这个根本原因是组件重新安装)。
(这里只贴上OnMaintUIBefore()部分代码)
Dlg_SdFeatureTree: if ( nType =MODIFY ) then szTitle = ""; szMsg =SdLoadString( SD_STR_COMPONENT_MAINT_MSG ); nResult = SdFeatureTree( szTitle, szMsg, TARGETDIR, "", -1); if ( nResult = BACK ) gotoDlg_Start; endif;
解决办法:反选组件。
使用FeatureSelectItem()来控制。思路是:如果只卸载Feature1,后台设置Feature1为不勾选状态,而将Featreu2设置为勾选状态;Feature2同理。
示例代码如下:
function OnMoveData()
number nResult, nMediaFlags;
begin
…………
//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;//只有卸载时才需要这样配置,安装不需要
if(REMOVEONLY)then //只卸载Feature1,将Feature1设置为不选状态,将Feature2设置为选中状态 if(bSelectFeature1 && !bSelectFeature2) then
FeatureSelectItem(MEDIA, "DefaultFeature\NewFeature2", TRUE); FeatureSelectItem(MEDIA, "DefaultFeature\NewFeature1", FALSE);
//只卸载Feature2,将Feature2设置为不选状态,将Feature1设置为选中状态 elseif (bSelectFeature2 && !bSelectFeature1) then
FeatureSelectItem(MEDIA, "DefaultFeature\NewFeature1", TRUE); FeatureSelectItem(MEDIA, "DefaultFeature\NewFeature2", FALSE); endif; 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; …………end;
7.运行第三方程序
在InstallShield中,提供给调用exe,bat等文件。
LaunchAppAndWait ( szProgram, szCmdLine, nOptions );
代码示例:
function OnFirstUIAfter() STRING szTitle, szMsg1, szMsg2, szOpt1, szOpt2; NUMBER bvOpt1, bvOpt2; STRING szProgram, szCmd; begin ShowObjWizardPages(NEXT); szTitle = ""; szMsg1 = ""; szMsg2 = ""; szOpt1 = ""; szOpt2 = ""; bvOpt1 =FALSE; bvOpt2 =FALSE; szProgram = WINDIR ^ "System32\PING.exe"; //szProgram = SUPPORTDIR ^ "test.bat"; //如果使用自定义的bat,需要在Support Files/Billboards中存入bat文件 szCmd = "www.baidu.com"; LaunchAppAndWait (szProgram, szCmd, LAAW_OPTION_NOWAIT|LAAW_OPTION_HIDDEN); nResult =LAAW_PARAMETERS.nLaunchResult; //{{IS_SCRIPT_TAG(Dlg_SdDinishEx) if( BATCH_INSTALL ) then SdFinishReboot ( szTitle , szMsg1 , SYS_BOOTMACHINE , szMsg2 , 0); elseSdFinish ( szTitle , szMsg1 , szMsg2 , szOpt1 , szOpt2 , bvOpt1 , bvOpt2 ); endif; //}}IS_SCRIPT_TAG(Dlg_SdDinishEx) end;
这里基本上展示了LaunchAppAndWait 的用法,重点记录的是获取返回值,这个值在bat中通过使用exit()获取返回值,如exit(-1)。
8.取消安装提示信息修改
在安装和卸载过程中,如果点击取消,此时会发现弹出的信息一模一样,默认是显示取消安装的信息。试想,在取消卸载时,提示这样的信息会让用户一头雾水。
这时候需要修改取消过程中的信息,修改OnCanceling()
原始代码:
function OnCanceling() STRING szTitle, szMsg1, szMsg2, szOpt1, szOpt2; NUMBER bvOpt1, bvOpt2; begin if (IDYES = SprintfBox(MB_YESNO|MB_ICONEXCLAMATION|MB_DEFBUTTON2, SdLoadString(SD_STR_ONCANCELING_TITLE), SdLoadString(SD_STR_ONCANCELING_CONFIRM_MSG))) then //Close the current dialog. EndCurrentDialog(); //Display Finish dialog. szTitle = ""; szMsg1 =SdLoadString( SD_STR_ONCANCELING_FINISH_MSG1 ); szMsg2 =SdLoadString( SD_STR_ONCANCELING_FINISH_MSG2 ); szOpt1 = ""; szOpt2 = ""; bvOpt1 =FALSE; bvOpt2 =FALSE; SdFinish ( szTitle, szMsg1, szMsg2 , szOpt1, szOpt2, bvOpt1, bvOpt2 ); abort; endif; end;
修改后的代码:
技巧:这里使用“@”可以获取资源文件中的信息。
修改后代码:
function OnCanceling() STRING szTitle, szMsg1, szMsg2, szOpt1, szOpt2; NUMBER bvOpt1, bvOpt2; STRING szBoxTitle, szBooxMsg; begin if(MAINTENANCE) then szBoxTitle =SdLoadString(SD_STR_ONCANCELING_TITLE); szBooxMsg =SdLoadString(SD_STR_ONCANCELING_CONFIRM_MSG); //这个与弹出框没有关系,这里呈现的地方是退出向导页面,默认是安装完成 szMsg1 =SdLoadString( SD_STR_ONCANCELING_FINISH_MSG1 ); szMsg2 =SdLoadString( SD_STR_ONCANCELING_FINISH_MSG2 ); elseszBoxTitle =@UNINSTALL_BOX_TITLE; szBooxMsg =@UNINSTALL_BOX_MSG; //这个与弹出框没有关系,这里呈现的地方是退出向导页面 szMsg1 =@UNINSTALL_TITLE; szMsg2 =@UNINSTALL_MSG; endif; if (IDYES = SprintfBox(MB_YESNO|MB_ICONEXCLAMATION|MB_DEFBUTTON2, szBoxTitle, szBooxMsg)) then //Close the current dialog. EndCurrentDialog(); //Display Finish dialog. szTitle = ""; szOpt1 = ""; szOpt2 = ""; bvOpt1 =FALSE; bvOpt2 =FALSE; SdFinish ( szTitle, szMsg1, szMsg2 , szOpt1, szOpt2, bvOpt1, bvOpt2 ); abort; endif; end;
效果: