InstallShield学习笔记三:脚本(2)

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();
            else
                OnFirstUIBefore();
            endif;
        endif;

        // Move Data
        OnMoveData(); // 这里可以安装,也可以卸载组件

        if( bUpdateMode ) then
            OnUpdateUIAfter();
        else
            if ( bMaintenanceMode ) then
                OnMaintUIAfter();
            else
                OnFirstUIAfter();
            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 ) goto Dlg_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 );
    else
        SdFinish ( 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 );
    else
        szBoxTitle = @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;

效果:

 

时间: 2024-10-22 01:39:32

InstallShield学习笔记三:脚本(2)的相关文章

InstallShield学习笔记三:脚本(1)

1.工程说明 在实际应用中,有 InstallSrcipt MSI 和 InstallSrcipt 这两个工程最常用,基本上脚本是可以共用的, 但是有个不同: 在 InstallSrcipt MSI 中,安装路径可以使用 INSTALLDIR 和 TARGETDIR, 而在 InstallSrcipt 中,只能使用TARGETDIR. 这里 InstallSrcipt 说明,记录使用过程中遇到的问题. 2.License选择 在 OnFirstUIBefore中,已经为工程自定义了许可文件lic

3. 蛤蟆Python脚本学习笔记三字符串

3. 蛤蟆Python脚本学习笔记三字符串 本篇名言:"平静的湖面只有呆板的倒映,奔腾的激流才有美丽的浪花!幸福不是靠别人来布施,而是要自己去赢取!生命的意义在不断挑战自己,战胜自己!" 这个本来放在昨天的,由于昨晚又太晚了,所以就搁在这里了.赶紧看看吧. 字符串两边都用双引号或者单引号包起来.否则就使用转移符号来转移一下. 输入在一起可以直接拼接. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/48112507

JavaScript--基于对象的脚本语言学习笔记(三)

事件处理器 1.一个数据校验表单的例程 <html> <head> <title>js练习</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <script type="text/javascript"> String.prototype.trim=function(){ r

【Unity 3D】学习笔记三十四:游戏元素——常用编辑器组件

常用编辑器组件 unity的特色之一就是编辑器可视化,很多常用的功能都可以在编辑器中完成.常用的编辑器可分为两种:原有组件和拓展组件.原有组件是编辑器原生的一些功能,拓展组件是编辑器智商通过脚本拓展的新功能. 摄像机 摄像机是unity最为核心组件之一,游戏界面中显示的一切内容都得需要摄像机来照射才能显示.摄像机组件的参数如下: clear flags:背景显示内容,默认的是skybox.前提是必须在render settings 中设置天空盒子材质. background:背景显示颜色,如果没

Ajax学习笔记(三)

三.jQuery库详解 1.使用jQuery之后,javascript操作的不再是HTML元素对应的DOM对象,而是包装DOM对象的jQuery对象.js通过调用jQuery对象的方法来改变它所包装的DOM对象的属性,从而实现动态更新HTML页面. 由此可见,使用jQuery动态更新HTML页面只需以下两个步骤: (1)获取jQuery对象.jQuery对象通常是DOM对象的包装 (2)调用jQuery对象的方法来改变自身.当jQuery对象被改变时,jQuery包装的DOM对象随之改变,HTM

UE4学习笔记(三): 为什么使用C++替代UnrealScript?

原文链接: https://forums.unrealengine.com/showthread.php?2574-Why-C-for-Unreal-4&p=16252&viewfull=1#post16252 之前的三代Unreal引擎中都包括了一种叫UnrealScript的脚本语言, 用它来写游戏玩法简直太方便了, 根本不用去接触复杂的C++引擎. 尽管脚本十分受新手的欢迎, 但它却成为了创新和公布的障碍. 在Unreal引擎成长的过程中, 我们不断地踩到这种坑. 所以在2011年,

Caliburn.Micro学习笔记(三)----事件聚合IEventAggregator和 Ihandle&lt;T&gt;

Caliburn.Micro学习笔记(三)----事件聚合IEventAggregator和 Ihandle<T> 今天 说一下Caliburn.Micro的IEventAggregator和IHandle<T>分成两篇去讲这一篇写一个简单的例子 看一它的的实现和源码 下一篇用它们做一个多语言的demo 这两个是事件的订阅和广播,很强大,但用的时候要小心发生不必要的冲突. 先看一下它的实现思想 在Caliburn.Micro里EventAggregator要以单例的形式出现这样可以

OpenCV for Python 学习笔记 三

给源图像增加边界 cv2.copyMakeBorder(src,top, bottom, left, right ,borderType,value) src:源图像 top,bottem,left,right: 分别表示四个方向上边界的长度 borderType: 边界的类型 有以下几种: BORDER_REFLICATE # 直接用边界的颜色填充, aaaaaa | abcdefg | gggg BORDER_REFLECT # 倒映,abcdefg | gfedcbamn | nmabcd

NFC学习笔记——三(在windows操作系统上安装libnfc)

本篇翻译文章: 这篇文章主要是说明如何在windows操作系统上安装.配置和使用libnfc. 一.基本信息 1.操作系统: Windows Vista Home Premium SP 2 2.硬件信息: System: Dell Inspiron 1720 Processor: Intel Core 2 Duo CPU T9300 @ 2.5GHz 2.5GHz System type: 32-bit Operating System 3.所需软件: 在windows操作系统上安装软件需要下列