说明:本文档的InstallShield为6.22版本,语言:中文。操作系统为Windows2000。资源编辑工具:Microsoft Visual C ++ 6.0。修改的DLL:_isuer.dll。
此主题相关图片如下:
InstallShield允许添加自定义对话框来满足不同的需求,关于如何创建一个新的对话框资源,有很多参考资料可以查询,就不多说了。这里主要说明的有以下几个方面:
1、 如何创建具有InstallShield Wizard同样风格的对话框。
2、 如何编写脚本来控制自定义对话框上的输入和控件的有效性判断。
一、 创建具有InstallShield Wizard同样风格的对话框在安装向导中可能需要加入一些自定义的步骤,这时可能需要插入一些自定义的对话框来作为某步骤,为了能够把自定义对话框的步骤完全融入导InstallShield Wizard中,即自定义对话框要具有和InstallShield标准步骤同样的风格,下图是InstallShield某标准步骤的图片:
标准步骤示例
在上图中,已经把标准向导对话框的一些风格标注出来了:①、②、③、④,①为该步骤功能说明,并且该说明以黑体字表达;②为对该功能的补充说明;③为InstallShield的图标;④为InstallShield的标注。
那么如何在自定义对话框中实现这些特性呢?下面就对这四个特殊地方作说明:
首先,这四个地方都是一个标签控件,在VC++中表现为静态控件(CStatic)。
①处是表明该步骤功能的地方,那么如何实现黑体的风格呢?其实InstallShield内嵌的机制已经对此作了定义了。在自定义对话框上添加一个静态控件,并且设置该控件的ID为50,并且使ExtendedStyles中的Transparent属性有效,然后在Caption中写上自定义的功能。该控件的位置为(10,3)。设置了这些后,InstallShield会自动把控件中的字体改为黑体。
②处为该同样设置Extended Styles的Transparent属性有效,然后在Caption中写上补充说明。该控件的位置为(17,15)。
③处为InstallShield的图标,该图标也是用静态控件来实现的。在自定义对话框上添加一个静态控件,设置该控件的ID为1200,并且使Styles中的Simple属性有效和Extended Styles的Transparent属性有效,在Caption中填上:@10550,10551;1;0;;0,128,128。该控件的位置为(0,0),大小为(332 x 218)。设置了这些后,InstallShield会自动在该控件中加入该图标。
④处为InstallShield的标注,但是不同于普通效果。在自定义对话框上添加一个静态控件,设置该控件的ID为7,把Caption清空,并且把控件的Visible属性去掉。InstallShield会自动把该控件设置成标准效果。
在设置了以上四个地方之后,还需要在添加一个静态控件,设置该控件的ID为52,把Caption清空,位置为(0,0),大小为(332 x 218)。运行的实际效果,就和标准的安装步骤中的效果一样了。
二、根据输入控制对话框上控件的有效性
在自定义了一个对话框之后,可能需要对对话框上的控件之间的关系进行一些控制,比如当选中了某单选框后,使一些控件有效,而选中其他的单选框后,另一些控件有效等等。要实现这些功能,就需要手动编写InstallShield脚本来实现了。
下面是一个在安装向导中添加了一个自定义对话框,在该步骤中实现在安装的时候在本机器上添加一个SQL Server的数据源。图“自定义对话框效果图”是该自定义对话框的运行效果图:
此主题相关图片如下:
在该自定义对话框中,除了要完成配置SQL Server的数据源之外,还要完成其他一些辅助功能。为了在本机器上配置一个SQL Server数据源,需要输入该数据源的名称、该数据源是针对那个服务器的以及配置的是用户数据源还是系统数据源等数据,而数据库和服务器用户及口令则是完成辅助功能所需要的。只有当输入了必须的数据(如:服务器、数据库、用户名称、数据源等)之后,按钮“下一步”才能有效,为了达到这个要求,就需要对用户的输入进行判断,在InstallShield中可以用WaitOnDialog来得到当前对话框的事件。下面是完成该功能的一个完整脚本代码:
///////////////////////////////////////////////////////////////////////
// kdcis.rul
//
///////////////////////////////////////////////////////////////////////
#ifndef __KDCIS_RUL_
#define __KDCIS_RUL_
#include "winsysdll.h"
//
// Pre-defined script dialog constants
//
// ----- Attribute Dialog Controls ------
#define DLG_DSN_SQLSERVER 30001
#defineIDC_RADIO_DSN_USER 1001
#define IDC_RADIO_DSN_SYSTEM 1002
#defineIDC_EDIT_DB_ADDR 1003
#define IDC_EDIT_SQLSERVER_USER_NAME 1004
#define IDC_EDIT_SQLSERVER_USER_PWD 1005
#define IDC_EDIT_SQLSERVER_DSN 1006
#define IDC_EDIT_SQLSERVER_DB 1007
file://----------------------
// Function prototypes
file://----------------------
///////////////////////////////////////////////////////////////
// 显示配置SQLSERVER数据源对话框
// 参数:
// BOOL bFirstStep:是安装的第一步吗?
// BOOL bAllowNotSet:是否允许跳过本次设置
// BYVAL STRING szTitle:对话框的标题
///////////////////////////////////////////////////////////////
prototype BuildSQLServerDSN(BOOL, BOOL, BYVAL STRING);
///////////////////////////////////////////////////////////////
// 校验配置数据源对话框的输入有效性
// 参数:
// HWND hwndDlg:配置对话框的句柄,从CmdGetHwndDlg中得到
// BOOL bAllowNotSet:是否允许跳过本次设置
// 备注:
// CheckSQLServerDSNInputValid:对SQLSERVER数据源配置进行校验
//////////////////////////////////////////////////////////////
prototype CheckSQLServerDSNInputValid(HWND, BOOL);
file://----------------------
// Variable declaration
file://----------------------
file://----------------------
// Macro declaration
file://----------------------
#define DSN_SQLSERVER_DLG "ConfigSQLServerDSNDLG"
/*------------------------------------------------------------------------*/
/* */
/* Function: BuildSQLServerDSN */
/* */
/* Descrip: use custom sqlserver's dsn dlg to createdsn. */
/* */
/* Misc: */
/* */
/*------------------------------------------------------------------------*/
function BuildSQLServerDSN(bFirstStep, bAllowNotSet,szTitle)
BOOL bDone;
NUMBER nMessage;
STRING szSQLAddr,szSQLDB, szDBUserName, szDBUserPwd, szSQLDSN;
SHORT nDSNType;
STRING svArg[1024];
STRING svDSN,svAddr, svDB, svUID, svPWD;
NUMBER nSplitPos;
HWND hwndDlg;
BOOL bBuildResult;
SHORT wErrMsgLen;
STRINGszErrMsg[MAX_PATH + 1];
LONG dwErrCode;
begin
bDone = FALSE;
// 用EzDefineDialog定义一个对话框
nMessage =EzDefineDialog(DSN_SQLSERVER_DLG, ISUSER, "", DLG_DSN_SQLSERVER);
if(nMessage = DLG_ERR) then
MessageBox("不能进行配置SQLSERVER数据源——找不到对话框", SEVERE);
bDone = TRUE;
endif;
while(bDone = FALSE)
nMessage =WaitOnDialog(DSN_SQLSERVER_DLG);
switch(nMessage)
case DLG_INIT:
hwndDlg= CmdGetHwndDlg(DSN_SQLSERVER_DLG);
CheckSQLServerDSNInputValid(hwndDlg, bAllowNotSet);
if(bFirstStep) then
_WinSubEnableControl(hwndDlg, SD_PBUT_BACK, 0);
endif;
_WinSubSetWindowTitle(hwndDlg, szTitle);
CtrlSetState(DSN_SQLSERVER_DLG, IDC_RADIO_DSN_USER, BUTTON_CHECKED);
case DLG_ERR:
MessageBox("不能显示配置SQLSERVER数据源对话框", SEVERE);
bDone = TRUE;
case CANCEL:
bDone = TRUE;
case DLG_CLOSE:
bDone = TRUE;
caseSD_PBUT_CONTINUE:
// 调用接口添加一个dsn
// ...
CtrlGetText(DSN_SQLSERVER_DLG, IDC_EDIT_DB_ADDR, szSQLAddr);
CtrlGetText(DSN_SQLSERVER_DLG, IDC_EDIT_SQLSERVER_DB, szSQLDB);
CtrlGetText(DSN_SQLSERVER_DLG, IDC_EDIT_SQLSERVER_USER_NAME, szDBUserName);
CtrlGetText(DSN_SQLSERVER_DLG, IDC_EDIT_SQLSERVER_USER_PWD, szDBUserPwd);
CtrlGetText(DSN_SQLSERVER_DLG, IDC_EDIT_SQLSERVER_DSN, szSQLDSN);
if(StrLength(szSQLAddr) = 0) then
if(AskYesNo("没有输入服务器,是否以后进行配置?", YES) = NO) then
_WinSubFocusControl(hwndDlg, IDC_EDIT_DB_ADDR);
else
bDone = TRUE;
endif;
elseif(StrLength(szSQLDB) = 0) then
if(AskYesNo("没有输入数据库,是否以后进行配置?", YES) = NO) then
_WinSubFocusControl(hwndDlg, IDC_EDIT_SQLSERVER_DB);
else
bDone = TRUE;
endif;
elseif(StrLength(szDBUserName) = 0) then
if(AskYesNo("没有输入数据库用户,是否以后进行配置?", YES) = NO) then
_WinSubFocusControl(hwndDlg, IDC_EDIT_SQLSERVER_USER_NAME);
else
bDone = TRUE;
endif;
elseif(StrLength(szSQLDSN) = 0) then
if(AskYesNo("没有输入数据源名称,是否以后进行配置?", YES) = NO) then
_WinSubFocusControl(hwndDlg, IDC_EDIT_SQLSERVER_DSN);
else
bDone = TRUE;
endif;
else
// 已经获取了所有数据,可以调用SQLConfigDataSource添加数据源了
// 组织语句
// 注:由于DSN不保存UID和PWD,所以在Attribute中不能加入这两个
// 关键字,并且每个关键子之间用'\0'分割,由于InstallShield
// 中不支持一个字符串中间存在'\0',因此,不能直接用+连接这些
// 关键字,下面是一个变通的方法
if(CtrlGetState(DSN_SQLSERVER_DLG, IDC_RADIO_DSN_USER) = BUTTON_CHECKED) then
nDSNType = ODBC_ADD_DSN;
else
nDSNType = ODBC_ADD_SYS_DSN;
endif;
svDSN = "DSN=" + szSQLDSN;
svAddr = "SERVER=" + szSQLAddr;
svDB = "DATABASE=" + szSQLDB;
svUID = "UID=" + szDBUserName;
svPWD = "PWD=" + szDBUserPwd;
svArg = svDSN + ' ' + svAddr + ' ' + svDB;
nSplitPos = StrLength(svDSN);
svArg[nSplitPos] = '\0';
nSplitPos += StrLength(svAddr) + 1;
svArg[nSplitPos] = '\0';
nSplitPos += StrLength(svDB) + 1;
svArg[nSplitPos] = '\0';
// 调用ODBCCP32中的SQLConfigDataSource添加一个DSN
// 如果返回FALSE,表示添加失败,这时可以调用
// SQLInstallerError来得到失败的原因
bBuildResult = SQLConfigDataSource(NULL, nDSNType, "SQL Server",svArg);
if(bBuildResult) then
// 如果添加成功
bDone = TRUE;
else
// 添加失败
wErrMsgLen = MAX_PATH;
SQLInstallerError(1, &dwErrCode, szErrMsg, wErrMsgLen, &wErrMsgLen);
if(bAllowNotSet) then
szErrMsg= "配置数据源失败——" + szErrMsg + "!是否以后进行配置?";
if(AskYesNo(szErrMsg, YES) = NO) then
bDone = FALSE;
else
bDone = TRUE;
endif;
else
szErrMsg = "配置数据源失败——" + szErrMsg + "!";
MessageBox(szErrMsg, SEVERE);
endif;
endif;
endif;
case SD_PBUT_BACK:
// 上一步
bDone = TRUE;
caseSD_PBUT_EXITSETUP:
bDone = TRUE;
caseIDC_RADIO_DSN_USER:
CheckSQLServerDSNInputValid(hwndDlg, bAllowNotSet);
caseIDC_RADIO_DSN_SYSTEM:
CheckSQLServerDSNInputValid(hwndDlg, bAllowNotSet);
caseIDC_EDIT_DB_ADDR:
CheckSQLServerDSNInputValid(hwndDlg, bAllowNotSet);
caseIDC_EDIT_SQLSERVER_USER_NAME:
CheckSQLServerDSNInputValid(hwndDlg, bAllowNotSet);
caseIDC_EDIT_SQLSERVER_USER_PWD:
CheckSQLServerDSNInputValid(hwndDlg, bAllowNotSet);
caseIDC_EDIT_SQLSERVER_DSN:
CheckSQLServerDSNInputValid(hwndDlg, bAllowNotSet);
caseIDC_EDIT_SQLSERVER_DB:
CheckSQLServerDSNInputValid(hwndDlg, bAllowNotSet);
endswitch;
endwhile;
EndDialog(DSN_SQLSERVER_DLG);
ReleaseDialog(DSN_SQLSERVER_DLG);
if(nMessage = SD_PBUT_CONTINUE) then
return NEXT;
elseif(nMessage = SD_PBUT_BACK) then
return BACK;
else
Do(EXIT);
endif;
end;
/*------------------------------------------------------------------------*/
/* */
/* Function: CheckSQLServerDSNInputValid */
/* */
/* Descrip: check the input data isvalid. */
/* do not need to check the pwd ifempty */
/* Misc: */
/* */
/*------------------------------------------------------------------------*/
function CheckSQLServerDSNInputValid(hwndDlg, bAllowNotSet)
STRING szDBUserName;
STRING szSQLDB;
STRING szSQLAddr;
STRING szSQLDSN;
begin
if(bAllowNotSet) then
_WinSubEnableControl(hwndDlg, SD_PBUT_CONTINUE, 1);
return 1;
endif;
if((CtrlGetState(DSN_SQLSERVER_DLG,IDC_RADIO_DSN_USER) = BUTTON_UNCHECKED) &&
(CtrlGetState(DSN_SQLSERVER_DLG,IDC_RADIO_DSN_SYSTEM) = BUTTON_UNCHECKED)) then
_WinSubEnableControl(hwndDlg,SD_PBUT_CONTINUE, 0);
return0;
endif;
CtrlGetText(DSN_SQLSERVER_DLG,IDC_EDIT_SQLSERVER_USER_NAME, szDBUserName);
if(StrLength(szDBUserName) = 0) then
_WinSubEnableControl(hwndDlg, SD_PBUT_CONTINUE, 0);
return 0;
endif;
CtrlGetText(DSN_SQLSERVER_DLG,IDC_EDIT_SQLSERVER_DSN, szSQLDSN);
if(StrLength(szSQLDSN) = 0) then
_WinSubEnableControl(hwndDlg, SD_PBUT_CONTINUE, 0);
return 0;
else
if(!SQLValidDSN(szSQLDSN)) then
MessageBox("输入了无效的数据源名称!", INFORMATION);
_WinSubFocusControl(hwndDlg, IDC_EDIT_SQLSERVER_DSN);
return 0;
endif;
endif;
CtrlGetText(DSN_SQLSERVER_DLG,IDC_EDIT_SQLSERVER_DB, szSQLDB);
if(StrLength(szSQLDB) = 0) then
_WinSubEnableControl(hwndDlg, SD_PBUT_CONTINUE, 0);
return 0;
endif;
CtrlGetText(DSN_SQLSERVER_DLG,IDC_EDIT_DB_ADDR, szSQLAddr);
if(StrLength(szSQLAddr) = 0) then
_WinSubEnableControl(hwndDlg, SD_PBUT_CONTINUE, 0);
return 0;
endif;
_WinSubEnableControl(hwndDlg,SD_PBUT_CONTINUE, 1);
return 1;
end;
#endif // __KDCIS_RUL
//===========================================================================
// 文件:winsysdll.h
// 描述:定义系统动态库的函数原型
//
// 更新:
// 2004/02/06
//===========================================================================
#ifndef __WINSYSDLL_H__
#define __WINSYSDLL_H__
//----------------------------------------------------
//Prototype user32 DLL functions used in project.
//----------------------------------------------------
//----------------------------------------------------
//Prototype ocbccp32 DLL functions used in project.
//----------------------------------------------------
#ifndef ODBC_ADD_DSN
#defineODBC_ADD_DSN 1
#endif
#ifndef ODBC_CONFIG_DSN
#defineODBC_CONFIG_DSN 2
#endif
#ifndef ODBC_ADD_SYS_DSN
#defineODBC_ADD_SYS_DSN 4
#endif
#ifndef ODBC_CONFIG_SYS_DSN
#defineODBC_CONFIG_SYS_DSN 5
#endif
#ifndef ODBC_INSTALL_COMPLETE
#define ODBC_INSTALL_COMPLETE 2
#endif
#ifndef ODBC_INSTALL_DEIVER
#defineODBC_INSTALL_DEIVER 1
#endif
#ifndef SQL_MAX_MESAGE_LENGTH
#define SQL_MAX_MESSAGE_LENGTH 512
#endif
#ifndef SQL_SUCCESS_WITH_INFO
#define SQL_SUCCESS_WITH_INFO 1
#endif
#ifndef SQL_NO_DATA
#defineSQL_NO_DATA 100
#endif
#ifndef SQL_ERROR
#defineSQL_ERROR -1
#endif
prototype BOOLODBCCP32.SQLConfigDataSource(HWND, SHORT, BYVAL STRING, BYVAL STRING);
prototype BOOL ODBCCP32.SQLValidDSN(BYVALSTRING);
prototype BOOLODBCCP32.SQLInstallerError(SHORT, POINTER, BYREF STRING, SHORT, POINTER);
#endif // __WINSYSDLL_H__
以上是本人对在InstallShield下自定义对话框的一些心得。在建立自定义对话框的时候,还是有一些疑惑,当在自定义对话框上添加了IP地址控件之后,WaitOnDialog始终返回DLG_ERR的错误,不知道如何在自定义对话框上添加IP地址控件,至于其他的控件,则没有尝试过。
转自:http://wenku.baidu.com/link?url=3Ou7r_Wkp6cWEGvDRIzUkJ9Y9V0g0kL-Stku4ToLAkaJbuQmXKjrZLyTLt-gpBJtT76R-MqEFyYQE4tkn-G1VAggPyXzm76Omd_PGzWPuTm