InstallShield实例(OnFirstUIBefore分析、安装导航优化)

昨天学了一些基本语法《InstallShield脚本语言的初识》,只是试水,今天准备写个例子,看看具体脚本的写法。

创建一个空工程

  • 我使用的是InstallShield12,因为是以研究脚本为主,所以这里当然就建一个InstallScript工程。
  • 什么也不做,直接用助手build一下。
    这里写图片描述

  • 控制台显示了build成功,并给了一个路径,顺着这个路径,能够找到打包好的setup.exe,就在项目工程中。
    这里写图片描述

  • 安装一下试试。注意此时的安装程序都出现了什么内容,我们后面要通过脚本改动的就是这些。
    这里写图片描述
    这里写图片描述
    这里写图片描述
    这里写图片描述
    这里写图片描述
    这里写图片描述
    这里写图片描述
    这里写图片描述

  • ok,记录完成。这就是在没有脚本控制下默认生成的安装程序。

  • 如果现在再次打开安装程序会发生什么呢?
    这里写图片描述

  • 答案是卸载程序。此时我点了除去,就把刚刚装的软件完美的卸载掉了。
  • 再次打开可以重新安装。
  • 整个流程已经很清晰了,下面我们对应脚本来看下这个安装流程。

分析

  • 如果此刻去看看setup.rul脚本,会发现里面是空的,没有任何脚本,难道刚才这一过程没有调用脚本吗?
  • 先说答案:否。

事件

  • 此处不得不探讨一下InstallShield事件,或者说函数了。
  • 刚刚也看到,在通常情况下,setup.rul内是不显示脚本出来的,但这不代表脚本不被执行。
  • InstallShield中内置了很多固定的函数,这些函数在特定的安装阶段被执行。
    这里写图片描述

  • 从两个下拉框中可以看到这些函数,无论在脚本中如何重写这些函数,它们的执行顺序总是固定的,就按照在下拉框中排列的顺序,从上到下执行。

  • 比如说OnFirstUIBefore函数,它是在开始安装之前被执行,负责一些准备工作。
  • 而OnBegin函数在OnFirstUIBefore的上面,说明OnBegin要优先于OnFirstUIBefore执行。实际上,OnBegin是在Setup脚本中第一个被触发。

实例

以下实例都是我在网上搜刮的,大多都是pdf中的看到然后我自己敲出来运行测试的,来源不可考证,就不备注了,还请原作者见谅。

实例1:操作系统的识别
  • 我暂时写入OnBegin事件,因为引入之后看到它完全是个空的,感觉非常适合拿来写着玩。
function OnBegin()  
string szMsg;
begin  

/*    
 * <操作系统的识别>
 * 相关变量 SYSINFO:存放本机的系统变量
 * 相关函数 AskYesNo:弹出消息窗口,用户通过按是或非来回答该窗口显示的问题
 */

    if(!SYSINFO.bIntel)then
        szMsg = "提示:该软件只能运行在Intel系列的处理器上!\n\n安装程序将终止";
        MessageBox(szMsg,SEVERE);
        abort;
    endif;
    if(SYSINFO.WIN9X.bWinMe ||
        SYSINFO.WINNT.bWinNT ||
        SYSINFO.WINNT.bWin2000)then
        szMsg = "提示:该软件只能运行在WIN9X系列上才能确保程序的正常工作!\n\n是否继续安装?";
        if(!AskYesNo(szMsg,NO))then
            abort;
        endif;
    endif; 

end;
  • build之后运行安装程序,在准备安装之后,出现了如下的画面,说明这段脚本已经起作用啦!(我本地是win7系统)
    这里写图片描述

  • 点击“是”,则正常安装;点击“否”,会退出安装。abort命令在《InstallShield脚本语言的初识》中有讲到。

  • 终于看到自己双手制造出的效果了,有点小激动,那些看不懂的知识点最后再总结,先继续找感觉,进行下一个例子!
实例2:内存容量的检测
  • 还是写在OnBegin中,之后我也会贴出全部代码,而不是只当前一个实例的片段代码。
function OnBegin()  
string szMsg,svResult;
number nvFreeMem;
begin  

/*    
 * <操作系统的识别>
 * 相关变量 SYSINFO  存放本机的系统变量
 * 相关函数 AskYesNo  弹出消息窗口,用户通过按是或非来回答该窗口显示的问题
 */
    if(!SYSINFO.bIntel)then
        szMsg = "提示:该软件只能运行在Intel系列的处理器上!\n\n安装程序将终止";
        MessageBox(szMsg,SEVERE);
        abort;
    endif; 

    if(SYSINFO.WIN9X.bWinMe ||
        SYSINFO.WINNT.bWinNT ||
        SYSINFO.WINNT.bWin2000)then
        szMsg = "提示:该软件只能运行在WIN9X系列上才能确保程序的正常工作!\n\n是否继续安装?";
        if(!AskYesNo(szMsg,NO))then
            abort;
        endif;
    endif;    


/* 
 * <内存容量的检测>    
 * 相关函数:GetSystemInfo()  返回目标系统的各种信息,
 *                            如CPU类型,磁盘容量,当前日期,当前操作系统,内存容量等   
 */
    if(GetSystemInfo(EXTENDEDMEMORY,nvFreeMem,svResult)<0)then
        MessageBox("内存检测失败,安装程序将终止!",SEVERE);
        abort;
    endif;

    if(nvFreeMem<16384)then
        szMsg = "该软件只能安装在16M以上内存的机器中。\n很遗憾,本机器可用内存不足16M!\n\n安装程序将终止!";
        MessageBox(szMsg,SEVERE);
        abort;
    endif;

end;
  • 我本机的内存肯定比16M要大,所以运行安装程序也看不出效果,所以我在测试的时候将if(nvFreeMem<16384)改成了if(nvFreeMem>16384),就可以看到如下效果了。
    这里写图片描述
实例3:客户信息
  • 回顾一下,就是我们最早创建的工程中的这一界面。
    这里写图片描述

  • 客户信息的缺省值已经被填写,而这一段内容则是来自一个很重要的事件,OnFirstUIBefore。

  • 打开OnFirstUIBefore,可以看到它和OnBegin不同,里面已经内置有很多代码。想知道这些代码都是干什么用的?一个一个试试看呗~

  • 找到下图这段代码(InstallShield版本不同可能代码不同,但是效果都是类似的)。
    这里写图片描述

  • 我先试了一下注释掉它们,发现安装程序并没有什么变化。然后我改动了它们的值。

//只改了这两个
szName = "seven";
szCompany = "mosia";
  • 安装程序就跟着变了。
    这里写图片描述

  • 顺便一提,我还改了bLicenseAccepted的值为TRUE,发现许可认证的选择默认会选择“我接受”,不禁让人想起来之前支付宝账单搞事情……总之这一项还是永远保持FALSE吧。

OnFirstUIBefore

  • 对InstallShield脚本有了一定感觉之后,我想来仔细研究一下OnFirstUIBefore这个函数。我们在Move Data前看到的所有界面都在这个函数中,想要改变这些界面,就不得不自己研究下这个函数。
  • 在这个函数中,除了开始的初始化部分,很明显后面每个分支代表一个界面。为了测试分支和界面的对应,我把每个分支中的szTitle定义为当前分支的名字,如下。
Dlg_SdWelcome:
    szTitle = "SdWelcome"; //我改动的地方
    szMsg = "";
    //{{IS_SCRIPT_TAG(Dlg_SdWelcome)
    nResult = SdWelcome( szTitle, szMsg );
    //}}IS_SCRIPT_TAG(Dlg_SdWelcome)
    if (nResult = BACK) goto Dlg_Start;
  • 然后再去执行安装程序,就可以明确的看到每个界面对应的分支了。方法虽然有点笨,但是好用~
  • 大家可以自己试一试,也可以直接看我下面的截图,省去一些时间。
    这里写图片描述
    这里写图片描述
    这里写图片描述
    这里写图片描述
    这里写图片描述
    这里写图片描述
    这里写图片描述

  • 之后来看看每个分支的代码。做一些改动。

    实例4:去掉输入公司和用户名的界面
  • 很简单的改动就能做到,完整代码如下,改动处见注释。
function OnFirstUIBefore()
    number  nResult, nLevel, nSize, nSetupType;
    string  szTitle, szMsg, szOpt1, szOpt2, szLicenseFile;
    string  szName, szCompany, szTargetPath, szDir, szFeatures;
    BOOL    bLicenseAccepted;
begin   

    // 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 = "seven";
    szCompany = "mosia";
    bLicenseAccepted = FALSE; 

// Beginning of UI Sequence
Dlg_Start:
    nResult = 0;

Dlg_SdWelcome:
    szTitle = "SdWelcome";
    szMsg = "";
    //{{IS_SCRIPT_TAG(Dlg_SdWelcome)
    nResult = SdWelcome( szTitle, szMsg );
    //}}IS_SCRIPT_TAG(Dlg_SdWelcome)
    if (nResult = BACK) goto Dlg_Start;

Dlg_SdLicense2:
    szTitle = "SdLicense2";
    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分支
/*
Dlg_SdRegisterUser:
    szMsg = "";
    szTitle = "SdRegisterUser";
    //{{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 = "SetupType2";
    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_SdLicense2;  // 我的改动:原本是gotoDlg_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 = "SdAskDestPath2";
    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 = "SdFeatureTree";
    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 = "SdStartCopy2";
    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;
实例5:优化安装导航
  • 过程比较多,改动方法和上面类似,不一一列举了,直接放出结果。
  • 具体的效果是:去掉安装类型的选择,直接进入选择安装路径的界面;调整每个界面的顺序;删除没有用的界面。
  • 优化后的安装导航如下,方便快捷,再也没有那么多繁琐的界面了。
function OnFirstUIBefore()
    number  nResult, nLevel, nSize, nSetupType;
    string  szTitle, szMsg, szOpt1, szOpt2, szLicenseFile;
    string  szName, szCompany, szTargetPath, szDir, szFeatures;
    BOOL    bLicenseAccepted;
begin   

    // 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;

    szDir = TARGETDIR;
    bLicenseAccepted = FALSE; 

// Beginning of UI Sequence
Dlg_Start:
    nResult = 0;

Dlg_SdLicense2:
    szTitle = "SdLicense2";
    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_Start;
    else
        bLicenseAccepted = TRUE;
    endif;         

Dlg_SdWelcome:
    szTitle = "SdWelcome";
    szMsg = "";
    //{{IS_SCRIPT_TAG(Dlg_SdWelcome)
    nResult = SdWelcome( szTitle, szMsg );
    //}}IS_SCRIPT_TAG(Dlg_SdWelcome)
    if (nResult = BACK) goto Dlg_SdLicense2;

Dlg_SdAskDestPath2: 
    if (nResult = BACK) goto Dlg_SdWelcome;
    szTitle = "SdAskDestPath2";
    szMsg = "";
        //{{IS_SCRIPT_TAG(Dlg_SdAskDestPath2)   
    nResult = SdAskDestPath2( szTitle, szMsg, szDir );
        //}}IS_SCRIPT_TAG(Dlg_SdAskDestPath2)
    TARGETDIR = szDir;
    if (nResult = BACK) goto Dlg_SdWelcome;    

    // Added in 11.0 - Set appropriate StatusEx static text.
    SetStatusExStaticText( SdLoadString( IDS_IFX_STATUSEX_STATICTEXT_FIRSTUI ) );

    return 0;
end;
  • 拷贝到自己的工程中试一试吧~

今天主要是优化了下安装前导航,比较皮毛。明天继续研究更深层一些的东西,比如注册表写入。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值