[置顶] InstallShield自定义对话框以及问题

前言:由于项目需要,而Installshield中的界面没有我们想要的,就需要定制一套了,也在网上看了很多资料,现在项目做的差不多了,总结一下

网上有很多Installshield高手的文章,都可以参考一下,先推荐一篇: InstallShield自定义安装界面, 是Kevin.Wan写的,主要是替换InstallShield界面的一些图片。

当然还要感谢群友的帮助,还有单车兄总结的文档,非常实用。


1. 在自定义对话框的时候,无意中看到了InstallShield的一些示例以及文件,可以参看InstallShield界面中的Tools-->InstallScript-->Stand Dialog Sampler,里面有很多内嵌的对话框,可以参看然后选择自己需要的,近似于需求的对话框。比如我们项目中需要做的是类似于AskOptions(NONEXCLUSIVE)的对话框,里面需要把上面的描述字符串都替换掉,而且需要添加新的一段话,后面会详细描述。

[置顶] InstallShield自定义对话框以及问题_第1张图片


2.  还有些示例工程也可以参照学习, 具体是在安装目录下的InstallShield\xxxx\Samples,里面有InstallScript, Sample Data, WindowsInstaller目录,我们的工程类型主要是InstallScript MSI Project,所以主要参考InstallScript目录下面的示例。主要是看Serial Number Validation Sample Project.ism这个工程,它自定义了SdCustomRegisterUserEx这个对话框,可以作参考。


3. 在InstallShield的安装目录下面,InstallShield\xxxx\Script\Isrt\src,里面有很多源代码也可以参考,参照步骤1里InstallShield里面的标准对话框,可以查看相应的源码。


4. 现在来看Serial Number Validation Sample Project.ism项目中的自定义对话框,是在脚本Custom_Password.rul中,主要函数代码如下:

#define SD_DLG_CUSTOM_REGISTERUSEREX   "SdCustomRegisterUserEx"
#define SD_NDLG_CUSTOM_REGISTERUSEREX   22002
#define SD_EDIT_CUSTOM_NAME             301
#define SD_EDIT_CUSTOM_COMPANY          302
#define SD_EDIT_CUSTOM_SERIAL_1         101
#define SD_EDIT_CUSTOM_SERIAL_2         102
#define SD_EDIT_CUSTOM_SERIAL_3         103
#define N_REQ_LENGTH_OF_SERIAL_1        6
#define N_REQ_LENGTH_OF_SERIAL_2        4
function  SdCustomRegisterUserEx ( szTitle, szMsg, svName, svCompany, svSerial_1, svSerial_2, svSerial_3  )

        STRING  szDlg, szTemp;
        BOOL    bDone;
        NUMBER  nId, nMessage, nTemp, nSdDialog, nSdCustomRegisterUserEx;
        HWND    hwndDlg, hwndControl;

        begin

           szDlg     = SD_DLG_CUSTOM_REGISTERUSEREX;
           nSdDialog = SD_NDLG_CUSTOM_REGISTERUSEREX;

          // read data produced by this dialog if user runs setup in silent mode (Setup.exe -s)
          if (MODE = SILENTMODE) then
            SdMakeName( szAppKey, szDlg, szTitle, nSdCustomRegisterUserEx );
            SilentReadData( szAppKey, "Result", DATA_NUMBER, szTemp, nId );
            if ((nId != BACK) && (nId != CANCEL)) then
               SilentReadData( szAppKey, "szName", DATA_STRING, svName, nTemp );
               SilentReadData( szAppKey, "szCompany", DATA_STRING, svCompany, nTemp );
               SilentReadData( szAppKey, "szSerial_1", DATA_STRING, svSerial_1, nTemp );
               SilentReadData( szAppKey, "szSerial_2", DATA_STRING, svSerial_2, nTemp );
               SilentReadData( szAppKey, "szSerial_3", DATA_STRING, svSerial_3, nTemp );
            endif;

            return nId;
          endif;

           // ensure general initialization is complete
           if (!bSdInit) then
              SdInit( );
           endif;

           if (EzDefineDialog( szDlg, "", "", SD_NDLG_CUSTOM_REGISTERUSEREX ) = DLG_ERR) then
               return -1;
           endif;

           // Loop in dialog until the user selects a standard button
           bDone = FALSE;

           while (!bDone)

              nId = WaitOnDialog( szDlg );

              switch(nId)
              case DLG_INIT:
                   if( szMsg != "" ) then
                       SdSetStatic( szDlg, SD_STA_MSG, szMsg );
                   endif;

                   if( ( svName = "" ) && ( svCompany = "" ) ) then
                       SdGetUserCompanyInfo( svName, svCompany );
                       SdRemoveEndSpace( svName );
                       SdRemoveEndSpace( svCompany );
                   endif;

                   CtrlSetText( szDlg, SD_EDIT_CUSTOM_NAME, svName );
                   CtrlSetText( szDlg, SD_EDIT_CUSTOM_COMPANY, svCompany );
                   CtrlSetText( szDlg, SD_EDIT_CUSTOM_SERIAL_1, svSerial_1 );
                   CtrlSetText( szDlg, SD_EDIT_CUSTOM_SERIAL_2, svSerial_2 );
                   CtrlSetText( szDlg, SD_EDIT_CUSTOM_SERIAL_3, svSerial_3 );

                   hwndDlg = CmdGetHwndDlg( szDlg );
                   SdGeneralInit( szDlg, hwndDlg, STYLE_BOLD, szSdProduct );

                   if(szTitle != "") then
                       SetWindowText(hwndDlg, szTitle);
                   endif;

                   SdCustomRegExEnableButton( hwndDlg, NEXT, svName,
                                        svCompany, svSerial_1, svSerial_2, svSerial_3 );

              case SD_EDIT_CUSTOM_NAME:
                   nMessage = CtrlGetSubCommand( szDlg );
                   if( nMessage = EDITBOX_CHANGE ) then
                       CtrlGetText( szDlg, SD_EDIT_CUSTOM_NAME, svName );
                   endif;

                   SdCustomRegExEnableButton( hwndDlg, NEXT, svName,
                                        svCompany, svSerial_1, svSerial_2, svSerial_3 );

              case SD_EDIT_CUSTOM_COMPANY:
                   nMessage = CtrlGetSubCommand( szDlg );
                   if( nMessage = EDITBOX_CHANGE ) then
                       CtrlGetText( szDlg, SD_EDIT_CUSTOM_COMPANY, svCompany );
                   endif;

                   SdCustomRegExEnableButton( hwndDlg, NEXT, svName,
                                        svCompany, svSerial_1, svSerial_2, svSerial_3 );

              case SD_EDIT_CUSTOM_SERIAL_1:
                   nMessage = CtrlGetSubCommand( szDlg );
                   if( nMessage = EDITBOX_CHANGE ) then
                       CtrlGetText( szDlg, SD_EDIT_CUSTOM_SERIAL_1, svSerial_1 );
                   endif;

                   SdCustomRegExEnableButton( hwndDlg, NEXT, svName,
                                        svCompany, svSerial_1, svSerial_2, svSerial_3 );

                   ////////////////////////////////////////////////////
                   // Two quick Windows API calls to automatically
                   // advance the user's cursor to the next edit field
                   // when the maximum number of characters is entered.
                   ////////////////////////////////////////////////////

                   if (StrLength (svSerial_1) = N_REQ_LENGTH_OF_SERIAL_1) then
                        hwndControl = GetDlgItem (hwndDlg,  SD_EDIT_CUSTOM_SERIAL_2);
                        SetFocus (hwndControl);
                   endif;

              case SD_EDIT_CUSTOM_SERIAL_2:
                   nMessage = CtrlGetSubCommand( szDlg );
                   if( nMessage = EDITBOX_CHANGE ) then
                       CtrlGetText( szDlg, SD_EDIT_CUSTOM_SERIAL_2, svSerial_2 );
                   endif;

                   SdCustomRegExEnableButton( hwndDlg, NEXT, svName,
                                        svCompany, svSerial_1, svSerial_2, svSerial_3 );

                   if (StrLength (svSerial_2) = N_REQ_LENGTH_OF_SERIAL_2) then
                        hwndControl = GetDlgItem (hwndDlg,  SD_EDIT_CUSTOM_SERIAL_3);
                        SetFocus (hwndControl);
                        endif;

              case SD_EDIT_CUSTOM_SERIAL_3:
                   nMessage = CtrlGetSubCommand( szDlg );
                   if( nMessage = EDITBOX_CHANGE ) then
                       CtrlGetText( szDlg, SD_EDIT_CUSTOM_SERIAL_3, svSerial_3 );
                   endif;

                   SdCustomRegExEnableButton( hwndDlg, NEXT, svName,
                                        svCompany, svSerial_1, svSerial_2, svSerial_3 );

              case NEXT:
                   nId    = NEXT;
                   bDone  = TRUE;

              case BACK:
                   nId    = BACK;
                   bDone  = TRUE;

              case DLG_ERR:
                   SdError( -1, "SdCustomRegisterUserEx" );
                   nId    = -1;
                   bDone  = TRUE;

              case DLG_CLOSE:
                   SdCloseDlg( hwndDlg, nId, bDone );

              default:
                   // check standard handling
                   if (SdIsStdButton( nId ) && SdDoStdButton( nId )) then
                       bDone = TRUE;
                   endif;
              endswitch;

           endwhile;

           EndDialog( szDlg );
           ReleaseDialog( szDlg );

           SdUnInit( );

           // record data produced by this dialog if user runs Setup.exe -r
           SdMakeName( szAppKey, szDlg, szTitle, nSdCustomRegisterUserEx );
           SilentWriteData( szAppKey, "szName",     DATA_STRING, svName, 0 );
           SilentWriteData( szAppKey, "szCompany",  DATA_STRING, svCompany, 0 );
           SilentWriteData( szAppKey, "szSerial_1", DATA_STRING, svSerial_1, 0 );
           SilentWriteData( szAppKey, "szSerial_2", DATA_STRING, svSerial_2, 0 );
           SilentWriteData( szAppKey, "szSerial_3", DATA_STRING, svSerial_3, 0 );
           SilentWriteData( szAppKey, "Result",     DATA_NUMBER, "", nId );

           return nId;

       end;

其主要是定义了一套Serial验证,需要输入正确的Serial number,才能继续下一步。上述代码主要是画出显示的对话框,对话框如下:

[置顶] InstallShield自定义对话框以及问题_第2张图片


自定义函数的功能描述以及过程,可以参考InstallShield的文档:
http://helpnet.flexerasoftware.com/installshield18helplib/Dialogs_ImplementStandard.htm
主要用到了WaitOndialog,函数说明参考InstallShield文档:
http://helpnet.flexerasoftware.com/installshield18helplib/mergedProjects/installshield18langref/LangrefWaitOnDialog.htm

其中,SD_DLG_CUSTOM_REGISTERUSEREX是dialog设计的名字,SD_NDLG_CUSTOM_REGISTERUSEREX (22002)是在User Interface->Dialogs中自定义对话框的Resource Identifier,这个必须是要再函数EzDefineDialog()中用到的;如果用错了的话,会显示不出自己定义的对话框。
还有一些定义,比如说SD_EDIT_CUSTOM_NAME(301),这个是User Name后面的输入框,它的Contorl Identifier就是301,是在User Interface->Dialogs中设置的,还有需要设置它的Other Windows Styles,这个需要参照系统中定义的空间,要不然格式会不正确。

5. 以上是自定义对话框的一些详细代码,下面附上过程中遇到的问题以及解法:
5.1 问题1:当点击右上角Close button的时候,没有响应
      解决方法:在dialog中必须添加一个Control Identifier为2的控件,否则点击是没有响应的,具体可以看网页下面Additional Information的解释 http://helpnet.flexerasoftware.com/installshield18helplib/mergedProjects/installshield18langref/LangrefWaitOnDialog.htm
 
5.2 问题2:在自定义AskOptions的时候,用字符串变量和数字变量保存了 对话框的名字以及Resource Identifier,在EzDefineDialog以及一些获得控件的函数中使用响应变量,会导致对话框显示的问题
      解决方法:直接使用define的东东,就可以了,这个不知道Installshield内部是如何实现的,也没有深究

5.3 问题3:在自定义对话框的时候,Text Area的最大长度是255,
       解决方法:分成2个Text Area显示

5.4 问题4:在用InstallShield命令行IsCmdBld.exe打包的时候,使用到了其命令行参数-z <property name>=property value,也使用了-y指定版本以及-l数字签名的目录。在-y后面又添加了一些-z参数,结果导致数字签名失败,查找好久才找到原因
       解决方法:将所有的-z参数放到-y前面,具体原因不清楚
      
5.5 问题5:在InstallShield界面中,有很多人想去掉左下角InstallShield字样,当然如果你自定义的话,是可以的
      解决方法:这个方法比较丑陋,在做的过程中,发现下面的那条横线以及InstallShield字样是去不掉的,没找到控件,于是就自己定义了一条直线直接覆盖到原来的横线,自己定义的一定要和界面一样宽;其次,使用一个空白的Text Area去覆盖掉会显示InstallShield字样的地方,然后就会去掉了。
      如果大家有好的方法,请留言说明,谢谢!


你可能感兴趣的:(自定义对话框)