InstallShield使用——几个技术问题介绍

 

InstallShield使用——几个技术问题介绍

1         几个技术问题介绍

1.1       数据库设置

在安装程序中设置数据库,有两种方法:一种采用命令行附加数据库文件,一种是通过SQL Script脚本创建数据库,对于编写SQL Script过于复杂,或创建数据库时间过长时建议采用第一种方法。

1.1.1     命令行附加数据库

1.       将数据库文件(a_data.mdfa_log.ldf)插入Support Files中;

2.       定义变量:

STRING psvSQLsvr, psvSQLusr, psvSQLpwd;

BOOL bvWindowsLogin;

3.       定义CreateDataBase函数:

prototype CreateDataBase(STRING,STRING,STRING);

4.       编写CreateDataBase函数:

function CreateDataBase(svSQLsvr,svSQLusr,svSQLpwd)

     STRING szWaitTxt,szdatabase,path,path3;

begin   

     path=TARGETDIR^"Data""a_data.MDF";

     path3=TARGETDIR^"Data""a_log.LDF";

     szWaitTxt=" 正在创建数据库....";

     SdShowMsg (szWaitTxt, TRUE);

     Delay(3);

     CopyFile(SUPPORTDIR^"a_data.MDF",path);

     CopyFile(SUPPORTDIR^"a_log.LDF",path3);

     szdatabase = "/U "+svSQLusr+" /P "+svSQLpwd+" /S "+svSQLsvr+" /Q ""exec sp_attach_db N'a' , N'"+path+"',N'"+path3+"'""";

     if (LaunchAppAndWait("osql.exe", szdatabase,WAIT)<0) then;

         MessageBox ("数据库创建失败!请确您的系统中已安装 Microsoft SQL Server 2000."n如仍无法解决,请联系系统供应商!",SEVERE);

         SdShowMsg (szWaitTxt, FALSE);

         return -1;

     endif;    

end;       

5.       获取数据库的登录信息,如果没有创建数据库的脚本,安装程序不会弹出SQL登录验证界面,需要编写代码:

Prototype number SQLLogin(); //定义登录函数

function SQLLogin ()

     number nResult, nSize;

     STRING sMessage, sTemp;

begin

     Dlg_Sql:

SQLRTInitialize2 ();              

     nResult = SQLServerSelectLogin(psvSQLsvr, psvSQLusr, psvSQLpwd, bvWindowsLogin );  

     if (nResult = BACK) return BACK;  

     nSize=MAX_PATH;

     MsiGetProperty( ISMSI_HANDLE, "IS_SQLSERVER_STATUS", sTemp, nSize );

     if(sTemp!="0") then

         nSize = _MAX_PATH;

         MsiGetProperty( ISMSI_HANDLE, "IS_SQLSERVER_STATUS_ERROR", sMessage, nSize );

         if( nSize = 0 ) then

              sMessage = SdLoadString( IDS_IFX_SQL_ERROR_LOGIN_FAILED );

         endif;

         MessageBox( sMessage, MB_OK );    

         goto Dlg_Sql;

     endif;

     return 0;

end;

6.       OnFirstUIBefore事件中调用SQLLogin函数:

Dlg_SdSQL:

nResult = SQLLogin();

if (nResult = BACK) goto Dlg_Custom;

7.       OnEnd事件中调用CreateDataBase函数:

function OnEnd()

begin    

     if !MAINTENANCE then

    CreateDataBase(psvSQLsvr,psvSQLusr,psvSQLpwd); // 创建和 优化数据库

     endif;

end;

1.1.2     SQL Script

Installation Designer中的SQL Scripts插入创建数据库的脚本即可,值得注意的是脚本中的文本替换,如果脚本中有安装前未知信息(在安装过程中输入的),如数据库的安装路径,使用软件的公司名称等等,需要使用文本替换,方法如下:

1.       创建数据库的脚本片段

CREATE DATABASE [test] ON (NAME = N'test_Data', FILENAME = N'%INSTALL_DIR%DATA"test_Data.MDF' , SIZE = 4, FILEGROWTH = 0) LOG ON (NAME = N'test_Log', FILENAME = N'%INSTALL_DIR%DATA"test_Log.LDF' , SIZE = 4, FILEGROWTH = 10%)

GO

 

use test

GO 

INSERT INTO [dbo].[use_company] ( [company _name])

     VALUES ('%MY_COMPANY_NAME%')

2.       Installation Designer中的Property Manager添加一个MY_COMPANYNAME的属性,如下图所示

3.       OnFirstUIBefore事件添加代码:

Dlg_UserInfo:              

    szMsg = "请正确输入用户名称及公司名称,以便本系统显示的信息正确!";

    nResult = SdRegisterUser(szTitle, szMsg, szUserInfo, szCompanyName);

    MsiSetProperty(ISMSI_HANDLE,"MY_COMPANYNAME", szCompanyName);

if (nResult = BACK) goto Dlg_SdLicense;

4.       Installation Designer中的SQL ScriptsText Replacement页面添加两个替换参数,如下图所示:

1.2       InstallScirpt调用动态运行库中的函数

安装过程中有些设置是InstallShield无法做到的,需要其他的编程软件实现,其他的编程软件可以编写成可执行的应用程序(EXE文件),通过LaunchAppLaunchAppAndWait调用,也可以编写成动态运行库(DLL文件),InstallShield调用其中的函数,我使用的是Borland Delphi编程软件,我编写了一个将安装文件夹设置为FTP虚拟目录的动态运行库,在InstallShield中调用。

Delphi的源代码如下:

library FtpSetup;

uses

 SysUtils, Classes, COMOBJ, Variants;

{$R *.res}

procedure FtpSet(siteName, appPath: PCHAR);stdcall;

var

 FTPSite, FTPServer, FTPRoot, FTPVDir: Variant;

 newSiteName, newAppPath:string;

begin

    newSiteName:= siteName;

    newAppPath:= appPath;

    FTPSite := CreateOleObject('IISNamespace');

    FTPSite := FTPSite.GetObject('IIsFtpService', 'localhost/MSFTPSVC');

    FTPServer := FTPSite.GetObject('IIsFtpServer', '1');

    FTPRoot := FTPServer.GetObject('IIsFtpVirtualDir', 'Root');

    FTPVDir := FTPRoot.Create('IIsFtpVirtualDir', newSiteName);

    FTPVDir.Path := newAppPath;

    FTPVDir.AccessRead := true;

    FTPVDir.AccessWrite := true;

    FTPVDir.SetInfo;

    FTPSite := Unassigned;

    FTPServer := Unassigned;

    FTPRoot := Unassigned;

    FTPVDir := Unassigned;

end;

exports

 FtpSet;

begin

end.

InstallScript脚本如下:

函数定义

prototype stdcall FtpSetup.FtpSet (POINTER,POINTER);  

调用函数

DLL_FILE= SUPPORTDIR^"FtpSetup.dll";

nResult = UseDLL (DLL_FILE);

if (nResult = 0) then

     svString1 = "drawingfile";

     svString2 = TARGETDIR^"DrawingFilePath";

     psvString1 = &svString1;

     psvString2 = &svString2;

     FtpSet(psvString1,psvString2);

     UnUseDLL (DLL_FILE);

else

 MessageBox("创建FTP服务失败,请手工设置。",SEVERE);

endif;

值得注意的是函数的编写及调用都采用stdcall方式。

1.3       自定义窗体

1.3.1     Basic MSI Project工程项目

1.       创建自定义窗体,可参考标准窗体的各种设置,主要是窗体Behavior的设置,下面以一个例子说明创建过程;

2.       创建一个记录登录服务器的信息的自定义窗体,该窗体需要录入服务器的IP地址、用户名及口令,将录入信息记录到XML文件中;

3.       如下图所示,在User InterfaceDialogsAll Dialogs点击右键,选择New Dialgo菜单,进入自定义窗体向导;

4.       选择Blank Dialog创建一个空白窗体,重命名NewDialog1,如ServerLogin

5.       如下图所示选择ServerLogin下的Chinse(Simplified)节,可设计此窗体;

6.       添加三个Text Area,分别将Text属性更改为服务器IP:、用户名:及口令:,添加三个Edit Field,分别录入Property Name(属性名称)MY_SERVER_IPMY_SERVER_USERMY_SERVER_PWD 将口令的录入框的Password属性的值更改为True,添加三个Push Button,分别是上一步、下一步及取消,如下图所示:

7.       如果想将此窗体插入CustomerInformation窗体与SetupType之间,可选择CustomerInformationBehaviorNext按钮,如下图所示,将EventNewDialogArgument更改为ServerLogin窗体;

8.       选择ServerLoginBehaviorNext按钮 ,新增一个NewDialog事件,将Argument更改为SetupType窗体,Condition更改为1,同理在上一步按钮中添加返回CustomerInformation窗体的事件,在取消按钮中添加EventSpawinDialogArgumentCancelSetupCondiiton1,如下图所示:

9.       可以在Behavior and Logic中的Custom Actions and Sequences中可以看出窗体的执行顺序,如下图所示:

10.   XML File Changes节中添加记录信息,这里不再详述。

1.3.2     InstallScript MIS Project工程项目

1.       创建自定义窗体需要注意在InstallScript中如何调用自定义窗体,并将窗体的属性复制公共属性,下面以一个例子说明调用;

2.       创建一个记录登录服务器FTP的信息的自定义窗体,该窗体需要录入服务器的IP地址、FTP端口、FTP用户名及口令,将录入信息记录到XML文件中;

3.       User InterfaceDialogsAll Dialogs点击右键,选择New Dialgo菜单,进入自定义窗体向导,选择Blank Dialog创建一个空白窗体,重命名NewDialog1,如SdComputerInfo,编辑窗体如下图所示:

4.       Direct EditorDialog中查出该窗体的ID,我创建的这个自定义窗体的ID12011,在Direct EditorControl中查出各控件的ID

5.       Property Manager中新建四个属性LOCALHOSTLOGINUSERLOGINPWDFTPPORT

6.       InstallScript中新建一个名为computerinfo.rul的脚本文件,脚本如下:

prototype SdComputerInfoDialog(string);

#define RES_DIALOG_ID     12011   // ID of custom dialog

#define RES_PBUT_NEXT         1   // ID of Next button

#define RES_PBUT_CANCEL    1310   // ID of Cancel button

#define RES_PBUT_BACK      1308   // ID of Back button

#define RES_EDITIP         1302   // ID of edit box

#define RES_EDITUSER       1304

#define RES_EDITPWD        1306

#define RES_EDITPORT       1312

function SdComputerInfoDialog(szTitle)

    STRING szDialogName, svName, svCompany;

    NUMBER nResult, nCmdValue;

    BOOL    bDone;     

    HWND    hwndDlg; 

    STRING szComputerIP, szFTPUser, szFTPPwd, szFTPPort;

    number nSize;

begin 

     szDialogName = "SdComputerInfo";

    nResult = EzDefineDialog (szDialogName, "", "", RES_DIALOG_ID);

     if (nResult < 0) then

        // Report an error; then terminate.

        MessageBox ("Error in defining dialog", SEVERE);

        abort;

    endif;

     bDone = FALSE;

    // Loop until done.

    repeat

        // Display the dialog and return the next dialog event.

        nCmdValue = WaitOnDialog (szDialogName);

        // Respond to the event.

        switch (nCmdValue)

            case DLG_CLOSE:

                // The user clicked the window's Close button.

                Do (EXIT);

            case DLG_ERR:

                MessageBox ("Unable to display dialog. Setup canceled.", SEVERE);

                abort;

            case DLG_INIT:  

             hwndDlg = CmdGetHwndDlg( szDialogName );

             SdGeneralInit( szDialogName, hwndDlg, 0, szSdProduct );

                SdSetDlgTitle(szDialogName, hwndDlg, szTitle);

                nSize=MAX_PATH;

                MsiGetProperty( ISMSI_HANDLE, "LOCALHOST", szComputerIP, nSize );

                nSize=MAX_PATH;

                MsiGetProperty( ISMSI_HANDLE, "LOGINUSER", szFTPUser, nSize ); 

                nSize=MAX_PATH;

                MsiGetProperty( ISMSI_HANDLE, "LOGINPWD", szFTPPwd, nSize );  

                nSize=MAX_PATH;

                MsiGetProperty( ISMSI_HANDLE, "FTPPORT", szFTPPort, nSize );

                CtrlSetText(szDialogName, RES_EDITIP, szComputerIP);

                CtrlSetText(szDialogName, RES_EDITUSER, szFTPUser);

                CtrlSetText(szDialogName, RES_EDITPWD, szFTPPwd);

                CtrlSetText(szDialogName, RES_EDITPORT, szFTPPort);

            case RES_PBUT_CANCEL:

                Do (EXIT);

            case RES_PBUT_BACK:

                bDone = TRUE;

            case RES_PBUT_NEXT:

                CtrlGetText (szDialogName, RES_EDITIP, szComputerIP);

                CtrlGetText (szDialogName, RES_EDITUSER, szFTPUser);

                CtrlGetText (szDialogName, RES_EDITPWD, szFTPPwd);

                CtrlGetText (szDialogName, RES_EDITPORT, szFTPPort);

             MsiSetProperty(ISMSI_HANDLE,"LOCALHOST", szComputerIP);

             MsiSetProperty(ISMSI_HANDLE,"LOGINUSER", szFTPUser);

             MsiSetProperty(ISMSI_HANDLE,"LOGINPWD", szFTPPwd);  

             MsiSetProperty(ISMSI_HANDLE,"FTPPORT", szFTPPort);

             bDone = TRUE;

        endswitch;

    until bDone;

    // Close the dialog.

    EndDialog (szDialogName);

    // Remove the dialog from memory.

    ReleaseDialog (szDialogName);

    // If dialog is closed with Next button, display name and company.

   

    if nCmdValue = RES_PBUT_NEXT then  

    return NEXT;

    else

        return BACK;

    endif;

end;

7.      OnFirstUIBefore事件中添加

Dlg_ComputerInfo:

    szTitle = "设置服务器信息";

    nResult = SdComputerInfoDialog(szTitle); 

if (nResult = BACK) goto Dlg_UserInfo;

8.       XML File Changes节中添加记录信息,这里不再详述。

posted on 2008-06-11 15:44  默默ASP.NET  阅读(10473)  评论(9编辑  收藏  举报