-

前言

前阵子做了一个有关Installshield的OA 打包安装程序,用的版本Installshield 2010-Premier,具体功能的内容如下:

1、OA采用的是asp.net(C#)开发

2、动态发布到IIS虚拟目录(采用自定义对话框)

3、附加,分离,删除数据库

4、动态修改web.config

5、完美卸载

6、更新包制作

【安装】首先准备一个发布好的aspnet网站,然后在web.config插入标签,在app_data文件夹放入数据库文件。安装的时候会自动把文件copy到目标机器,在使用dos命令将app_data里面的文件附加到数据库,根据用户填写的数据库信息替换web.config的标签……

【更新】更新包的思路也很简单,在安装的时候会把用户填写的数据库信息存到注册表(数据库服务器,用户名,密码,虚拟目录,安装路径),用了这些信息,那么更新的时候直接把文件copy到用户安装时选择的路径就可以了,如果有数据库相关的更新,则可以使用dos命令执行数据库文件(.sql),如果有web.config的更新,则再一次动态替换web.config的标签即可。

【卸载】网站的卸载就是删除文件,分离和删除数据库,删除注册表相关键值,删除虚拟目录

接下来让我们一步一步来实现,篇幅可能有点长,请大家 pay patience,Let’s go

一、新建项目

选择All Types下面的InstallScript MSI Project,填写产品名称,保存路径,点击OK

点击OK后出来这个界面Project Assistant 项目助手,点击进去可看到有些简单描述项目的选项

Installation Designer安装设计,点击进去可看到产品的信息,安装脚本,安装界面等

切换到Installation  Designer可看到以上界面。

二、填写产品信息

填写产品的基本信息(包括产品名称,安装语言,产品的安装版本,产品编码……)

三、选择文件源

选择文件源,在DefaultComponents下面的files点击右键,选择Dynamic File Linking选择文件源(将文件源填充到components,多个components组成一个features)

点击 New Link弹出Dynamic File Link Settings对话框,点击Browse选择文件夹,然后点击OK,在点击左边对话框的确定,则完成文件源的设置

定位到Setup Design选项,可看到右边窗口有DefaultFeature和DefaultComponents

1个Feature(功能)可以拆分为多个Components(组件),1:N

1个Components可以绑定一个文件夹或者文件,1:N

在Defaultfeature右键选择Associate Components,弹出Component的列表,选择然后点击OK按钮则可以将该components添加到feature下面。

四、设置文件夹权限

功能Feature关联完Component后则可以在Application Data下面的files and folders看到关联过来的文件夹信息,可以对其进行局部调整。也可以对文件夹进行权限控制,权限设置如下:

选中文件夹,右键点击Properties属性,则弹出以下属性窗口

点击Permissions弹出以下界面

在空白处点击右键选择New,则弹出以下界面

设置文件夹的权限,点击OK完成

五、Installshield Script

默认的脚本没有任何东西,只有一句 #include "ifx.h",必须点击右边的安装函数才出来脚本。

InstallScript脚本的语法类似于C,也类似于VBScript,可以调用VB的代码。也可以调用dos命令,也可以调用exe。

选择 Before Move Data 阶段的函数 OnFirstUIBefore,可出来安装过程中对话框的代码,代码如下:

function OnFirstUIBefore()
    NUMBER nResult, nSetupType, nvSize, nUser;
    STRING szTitle, szMsg, szQuestion, svName, svCompany, szFile;
    STRING szLicenseFile;
    BOOL bCustom, bIgnore1, bIgnore2;
begin    
    // TO DO: if you want to enable background, window title, and caption bar title                                                                   
    // SetTitle( @PRODUCT_NAME, 24, WHITE );                                        
    // SetTitle( @PRODUCT_NAME, 0, BACKGROUNDCAPTION );                       
    // Enable( FULLWINDOWMODE );                           
    // Enable( BACKGROUND );                              
    // SetColor(BACKGROUND,RGB (0, 128, 128));

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

Dlg_SdWelcome:
    szTitle = "";
    szMsg   = "";
    nResult = SdWelcome(szTitle, szMsg);
    if (nResult = BACK) goto Dlg_SdWelcome;
    
    szTitle   = "";
    svName    = "";
    svCompany = "";

Dlg_SdRegisterUser:
    szMsg = "";
    szTitle = "";
    nResult = SdRegisterUser( szTitle, szMsg, svName, svCompany );
    if (nResult = BACK) goto Dlg_SdWelcome;

Dlg_SetupType:
    szTitle = "";
    szMsg   = "";
    nResult = SetupType2(szTitle, szMsg, "", nSetupType, 0);
    if (nResult = BACK) then
        goto Dlg_SdRegisterUser;
    else
        nSetupType = nResult;
        if (nSetupType != CUSTOM) then
            nvSize = 0;
            FeatureCompareSizeRequired(MEDIA, INSTALLDIR, nvSize);
            if (nvSize != 0) then      
                MessageBox(szSdStr_NotEnoughSpace, WARNING);
                goto Dlg_SetupType;
            endif;
            bCustom = FALSE;
            goto Dlg_SQL;
        else
            bCustom = TRUE;
        endif;
    endif;

Dlg_SdAskDestPath:        
    nResult = SdAskDestPath(szTitle, szMsg, INSTALLDIR, 0);
    if (nResult = BACK) goto Dlg_SetupType;

Dlg_SdFeatureTree: 
    szTitle    = "";
    szMsg      = "";
    if (nSetupType = CUSTOM) then
        nResult = SdFeatureTree(szTitle, szMsg, INSTALLDIR, "", 2);
        if (nResult = BACK) goto Dlg_SdAskDestPath;  
    endif;

Dlg_SQL:
    nResult = OnSQLLogin( nResult );
    if( nResult = BACK ) then
        if (!bCustom) then
            goto Dlg_SetupType;    
        else
            goto Dlg_SdFeatureTree;
        endif;
    endif;

Dlg_SdStartCopy:
    szTitle = "";
    szMsg   = "";
    nResult = SdStartCopy2( szTitle, szMsg );            
    
    if (nResult = BACK) then
       goto Dlg_SQL;;
    endif;

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

// setup default status
    Enable(STATUSEX);
 
    return 0;
end;

Dlg_SdWelcome:    欢迎对话框
Dlg_SdRegisterUser   注册用户对话框
Dlg_SetupType       安装类型对话框
Dlg_SdAskDestPath 选择安装目录对话框
Dlg_SdFeatureTree        功能树对话框
Dlg_SQL   sql相关对话框
Dlg_SdStartCopy 复制文件对话框
这几个是系统默认的对话框,所有对话框的生命周期基于Setup.rul脚本,也就是说需要在Setup.Rul里面设置对话框的相关脚本信息和调用对话框的构造函数。
系统默认的对话框脚本都包含在#include "ifx.h"头文件里面,如果是自定义的对话框则【后面会提到】需要引用相关对话框的脚本。

若要引用其他的对话框,则要从dialog source里面调出对话框函数

六、Dialog对话框

对话框选项位于User Interface(用户体验,简称UI)下面的Dialog(对话框)选项

鼠标悬停在对话框名称,右键,选择Edit,可看到对话框的相关信息(布局,控件,属性……Control Identifier是唯一标识列),可以修改对话框的布局和信息。

Skin则是对话框的皮肤,选中皮肤,点击Select应用该皮肤。

七、一个完整的ASP.NET打包程序

1、前言

在了解了Installshield 2010 的一些基本设置和熟悉操作界面后,给大家演示一个完整的ASP.NET打包程序,ASP.NET的安装与部署比较简单,主要是把网站发布到IIS,附加数据库,配置数据库信息(包括数据库用户,密码,服务器),修改web.config配置文件。主要功能有:

●     手动选择安装目录

●     创建和设置IIS虚拟目录

●     动态附加分离数据库

●     自动修改配置文件

●     完美卸载

2、创建IIS虚拟目录

2.1、自定义创建虚拟目录对话框

由于Installshield自身没有操作IIS的功能,那么就要借助外部程序或者windowsAPI,用程序配置 IIS 所用到的“技术”无非是 ADSI 或者 WMI 提供的组件服务程序。可以通过 Windows Host Script 来执行 JScript 或者 VBScript 脚本,也可以在 VB/Delphi 这类快速开发工具开发程序来调用,甚至可以通过浏览器中运行的 JavaScript/JScript/VBScript 以及 IIS 运行的 ASP 来调用。因为支持 IDispatch 接口,所以可以后期绑定地通过 CreateObject 或者 GetObject 方式来获取 ADSI/WMI 的特定接口。那么我们这里就简单地利用adsi来操作IIS。

由于Installshield自身没有创建虚拟目录的窗口,那么我们就简单的自己做一个自定义的窗口,窗口很简单,就只有一个文本框,用于输入虚拟目录的名称。制作过程如下:

首先先All Dialogs那里右键,弹出菜单,选择New Dialog

新建对话框向导

对话框有多种类型:

Blank Dialog 空对话框,该对话框什么都没有,连上一步,下一步的按钮都没有

NewScriptBasedDialog 普通基于脚本的对话框,带基本按钮

NewSkinnableDialog 带皮肤功能的对话框,带基本按钮

如果弹出冲突页面,直接点击SkipAll就行了。

添加完皮肤对话框后,界面如上,现在就可以对对话框进行编辑,修改对话框标题,按钮的文字,字体大小,摆置方式等。最重要的是甚至对话框的Resource identifier,这是对话框的唯一标识列。

那么现在对话框已经添加完成了,那么如何在安装的过程中显示该对话框呢?

每个对话框都有一个构造函数,那么只有调用该对话框的构造函数就行了,接下来请看怎么编写对话框的构造函数(详情按F1)。

在DefineDialog ( szDialogName, hInstance, szDLLName,nDialogID, szDialogID, nReserved, hwndOwner, lMsgLevel ); 这个函数里,最主要的参数就是第四个nDialogID(对话框ID),也就是对话框Resource identifier属性的值。那么对话框构造函数就可以这样写:

szDialogName = "SelectVirDialog";
    hInstance  = 0;
    szDLLName  = "";
    nSdDialog  = "13001"
    szDialog   = ""; 
    hwndParent = 0; 
    nResult  = DefineDialog (szDialogName, hInstance, szDLLName, nSdDialog, szDialog, 
                             hwndParent, HWND_INSTALL, 
                             DLG_MSG_STANDARD|DLG_CENTERED);    
    if ( nResult = DLG_ERR ) then
       bDone = TRUE;
       return -1;
    endif;  

这里设置了一个名字为SelectVirDialog的对话框,对话框ID为13001,其他参数可以为空或为0。那么有了构造函数,那么在Setup.rul里面就可以调用构造函数,使用对话框了。

一般为了方便管理,每个对话框都会配置一个对话框的脚本。脚本里面也就是构造函数和点击按钮的业务处理

//选择虚拟目录   
Dlg_SdSelectVirtual:
        szTitle="";
        szMsg="";
        nResult=SdSelectVirtual(szTitle,szMsg);
        if(nResult=BACK) then 
            goto Dlg_SdAskDestPath;    
        endif;
        if(nResult=NEXT && !MAINTENANCE) then
            goto Dlg_SQL;
        endif;

SdSelectVirtual也就是一个构造函数,里面封装了DefineDialog 函数和业务处理。返回的是按钮ID,BACK和NEW都是枚举值。

对话框其实处于一种死循环状态,只靠goto语句来跳出循环。具体出来的对话框界面如下:

那么如果获取用户输入的值呢?

跟对话框的原理一样,每一个控件也是有一个唯一标识列的(Control Identifier)

设置控件的值CtrlSetText(szDialogName,1204,"A8");
获取控件的值CtrlGetText(szDialogName,1204,svVituralDir);
1204是控件的Control Identifier

szDialogName是对话框的名称,跟DefineDialog第一个参数相对应。

最后一个参数则是设置和获取填充的值或变量。

// Initialize the indicator used to control the while loop. 
    bDone = FALSE;

// Loop until done. 
    while (!bDone)

// Display the dialog and return the next dialog event. 
        nId = WaitOnDialog( szDlg);

// Respond to the event. 
        switch(nId) 
        
            case DLG_INIT:
                CtrlSetText(szDialogName,1204,"A8");                              
                 // No initialization is required for this example.   
            case NEXT: 
            nId   = NEXT;
            bDone = TRUE; 
            CtrlGetText(szDialogName,1204,svVituralDir);
            //将路径写到注册表
            nRootKey = HKEY_CURRENT_USER;
            szKey = "Software\\A8";
            szClass=""; 
            //更换注册表根目录
            if (RegDBSetDefaultRoot (nRootKey) < 0) then  
                MessageBox ("First call to RegDBSetDefaultRoot failed.", SEVERE); 
            endif;
             
            //创建注册表项   
            if (RegDBKeyExist (szKey) < 0) then 
                if (RegDBCreateKeyEx (szKey, szClass) < 0) then 
                    MessageBox ("RegDBCreateKeyEx failed.", SEVERE); 
                endif; 
            endif;
            
            //创建键值对[虚拟目录,目标目录]
            RegDBSetKeyValueEx (szKey, "VirDir", REGDB_STRING, svVituralDir,-1);   
            RegDBSetKeyValueEx (szKey, "TargetDir", REGDB_STRING, TARGETDIR,-1);
            
            nExists=CreateWebSite(svVituralDir);
            if(nExists==0) then
                nId=0;
                bDone=FALSE;
            else
                nId=NEXT;
                bDone=TRUE;
            endif;
            case BACK: 
                nId    = BACK;
                bDone = TRUE;  
                
            case DLG_ERR: 
            
                SdError( -1, "MyDefineDialog" );
                nId    = -1; 
                bDone  = TRUE;   
                
            case DLG_CLOSE:   
                    SdCloseDlg( hwndDlg, nId, bDone ); 
           default: 
                if(SdIsStdButton( nId ) && SdDoStdButton( nId )) then
                    bDone = TRUE;
                endif;
        endswitch; 
    endwhile;

2.2、创建虚拟目录(使用ADSI)

设置好界面,获取到用户输入的虚拟目录名称,接下来就是创建虚拟目录了。

第一步:获取IIS的Default站点

set objW3SVC = CoGetObject("IIS://localhost/W3SVC/1/Root","");

第二步:创建虚拟目录

set objVirDir=objW3SVC.Create("IISWebVirtualDir",virtrualDir);//virtrualDir是变量
第三步:设置虚拟目录的属性

objVirDir.Path = TARGETDIR;

objVirDir.AccessRead = TRUE;

objVirDir.AccessScript = TRUE;

objVirDir.AppCreate(TRUE);

objVirDir.SetInfo();

详细代码请参考SdSelectVirtual.rul的CreateWebSite函数

3、填写数据库信息

3.1、自定义数据库对话框

数据库的对话框也需要自定义,在上面已经介绍过自定义对话框的制作方法,数据库对话框界面如下:

填写服务器信息,默认是localhost或者.都可以

填写用户名,默认一般是sa

填写密码,默认是******

3.2、验证数据库信息

bDone = FALSE;

// Loop until done. 
    while (!bDone)

// Display the dialog and return the next dialog event. 
        nId = WaitOnDialog( szDlg);

// Respond to the event. 
        switch(nId) 
        
            case DLG_INIT:
                CtrlSetText(szDialogName,REX_CTRL_ID_SERVER,"localhost");
                CtrlSetText(szDialogName,REX_CTRL_ID_USER,"");
                CtrlSetText(szDialogName,REX_CTRL_ID_PWD,"");
                 // No initialization is required for this example.

case NEXT: 
            nId   = NEXT;
            bDone = TRUE; 
                CtrlGetText(szDialogName,REX_CTRL_ID_SERVER,svServer);
                CtrlGetText(szDialogName,REX_CTRL_ID_USER,svUser);
                CtrlGetText(szDialogName,REX_CTRL_ID_PWD,svPwd);
                         Server=svServer;
                         User=svUser;
                         Pwd=svPwd; 
             //判断数据库链接是否成功(0代表链接失败,1代表链接成功) 
             szWaitTxt="正在检查数据库用户名和密码"; 
             SdShowMsg (szWaitTxt, TRUE);
             Delay(2);
             SdShowMsg (szWaitTxt, FALSE); 
             if(DB_CheckConnection(Server,"SQL Server",User,Pwd)!=1) then
                nId=0;
                bDone=FALSE;  
                MessageBox ("数据库用户名或者密码错误,请重新输入", WARNING);
                CtrlSetText(szDialogName,REX_CTRL_ID_USER,"");
                CtrlSetText(szDialogName,REX_CTRL_ID_PWD,"");
            else
                nId=NEXT;
                bDone=TRUE;     
                //将路径写到注册表
                nRootKey = HKEY_CURRENT_USER;
                szKey = "Software\\A8";
                     
                //更换注册表根目录
                if (RegDBSetDefaultRoot (nRootKey) < 0) then  
                    MessageBox ("First call to RegDBSetDefaultRoot failed.", SEVERE); 
                endif;
                     
                //创建注册表项   
                if (RegDBKeyExist (szKey) < 0) then 
                    if (RegDBCreateKeyEx (szKey, szClass) < 0) then 
                        MessageBox ("RegDBCreateKeyEx failed.", SEVERE); 
                    endif; 
                endif;    
                //添加到注册表 
                RegDBSetKeyValueEx (szKey, "Server", REGDB_STRING, Server,-1);
                RegDBSetKeyValueEx (szKey, "User", REGDB_STRING, User,-1);
                RegDBSetKeyValueEx (szKey, "Pwd", REGDB_STRING, Pwd,-1);
            endif;
            
            case BACK: 
                nId    = BACK;
                bDone = TRUE;  
                
            case DLG_ERR: 
            
                SdError( -1, "MyDefineDialog" );
                nId    = -1; 
                bDone  = TRUE;   
                
            case DLG_CLOSE:   
                    SdCloseDlg( hwndDlg, nId, bDone ); 
           default: 
                if(SdIsStdButton( nId ) && SdDoStdButton( nId )) then
                    bDone = TRUE;
                endif;
        endswitch; 
    endwhile;

DB_CheckConnection 这个函数用于验证当前用户输入的数据库信息是否正确,有关数据库的相关操作位于database.rul文件。

如果数据库的信息填写无误,那么把数据库信息写到注册表,方便以后升级使用。

4、附加数据库

在执行复制文件到目标机器后,点击Finish(完成)按钮会触发函数onend

//---------------------------------------------------------------------------
// OnEnd
//
// The OnEnd event is called at the end of the setup. This event is not
// called if the setup is aborted.
//---------------------------------------------------------------------------
function OnEnd()
begin 
if(!MAINTENANCE)then
//ConfigurateSql();
CreateDataBase(Server,User,Pwd);//Server,User,Pwd为SdCreateSql.rul的全局变量  
endif;
end;

Server,User,Pwd都是全局变量,把变量定义到最顶部跟#include同级

#include "Ifx.h"  
#include "database.rul"
 
#define REX_DIALOG_ID 13003
#define REX_CTRL_ID_SERVER 1209 //服务器
#define REX_CTRL_ID_USER 1207 //用户名
#define REX_CTRL_ID_PWD 1208 //密码

export prototype SdCreateSql(string, string); //构造函数
//prototype CreateDataBase(STRING,STRING,string);//创建数据库
prototype AlterConfigure(string);//修改web.config
string Server,User,Pwd; //全局变量

附加数据库是调用了dos命令的osql.exe,代码如下:

//创建数据库
function CreateDataBase(svSQLsvr,svSQLusr,svSQLpwd) 
    STRING szCmdLine,szWaitTxt,szCommandLine; 
    begin 
    //A8数据库
    szWaitTxt=" 正在创建A8数据库."; 
    SdShowMsg (szWaitTxt, TRUE); 
    Delay(2); 
    szCmdLine = "/U "+svSQLusr+" /P "+svSQLpwd+" /S "+svSQLsvr+" /Q \"EXEC  sp_attach_db  @dbname  =  N'A8',@filename1  = N'"+TARGETDIR ^"App_Data\\A8.mdf',@filename2  = N'"+TARGETDIR ^"App_Data\\A8_log.ldf'\""; 
    if (LaunchAppAndWait("osql.exe", szCmdLine,LAAW_OPTION_NOWAIT | LAAW_OPTION_HIDDEN) < 0) then 
        MessageBox ("数据库创建失败!请确您的系统中已安装 Microsoft SQL Server 2000. 如仍无法解决,请联系系统供应商!",SEVERE); 
    endif;  
    SdShowMsg (szWaitTxt,FALSE);  
    szWaitTxt=" 正在优化系统数据库."; 
    SdShowMsg (szWaitTxt, TRUE); 
    Delay(2); 
    szCmdLine = "/U "+svSQLusr+" /P "+svSQLpwd+" /S "+svSQLsvr+" /Q \"use A8 ; exec sp_updatestats\""; 
    if (LaunchAppAndWait("osql.exe", szCmdLine,LAAW_OPTION_NOWAIT | LAAW_OPTION_HIDDEN) < 0) then 
    MessageBox ("数据库优化失败!您可以在 sql查询分析器中执行 use dlbj ; exec sp_updatestats 完成!",SEVERE); 
    endif; 
    SdShowMsg (szWaitTxt,FALSE);  
    //打开浏览器浏览制定的网页    
    szCommandLine = ProgramFilesFolder ^ "Internet Explorer\\iexplore.exe";
    LaunchAppAndWait(szCommandLine, "http://localhost/"+svVituralDir+"/login/login.aspx", NOWAIT);

//修改配置文件
    ConfigurateSql(); 
    
end;

在这里使用了LaunchAppAndWait调用exe文件,详情请按F1

5、修改Web.Config文件

修改Web.Config文件也是在文件拷贝到目标机器的完成阶段实现。

第一步:定标签

在Web.Config文件里为每一个要替换的节点定下一个注释标签

<connectionStrings>
    <!--#constring1#-->
<add name="abc" connectionString="database=abc;server=.;uid=sa;pwd=123" providerName="System.Data.SqlClient"/>
  </connectionStrings>

<!--#constring1#-->则是一个注释标签

第二步:定位行数

根据标签就可以找到该标签下面那一个节点,代码看GetLineNum函数

//从上往下搜索某文件下面的字符串,并返回该字符串所在的行数
function NUMBER GetLineNum(szFileName,szSearchStr,isContinue)
string svReturnLine;
NUMBER nvLineNumber,nvResult;
begin 
    nvResult = FileGrep (szFileName, szSearchStr, svReturnLine, nvLineNumber,isContinue); 
    switch(nvResult) 
            case FILE_NOT_FOUND: 
            // Report error; then abort. 
            MessageBox( szFileName + " not found.", WARNING); 
            abort; 
        case FILE_LINE_LENGTH: 
            // Report error; then abort. 
            MessageBox (szFileName + "lines too long.", WARNING); 
            abort; 
        case OTHER_FAILURE: 
            // Report error; then abort. 
            MessageBox (szFileName + "Unknown failure on call to FileGrep.", WARNING); 
            abort; 
    endswitch; 
    return (nvLineNumber+1);
end ;

第三步:替换该行数据

使用FileInsertLine函数可以替换文件中的某一行。

//替换webconfig里面链接字符串,使用GetLineNum注意最后一个参数,从头开始找还是继续上次往下找
            nvLineNum=GetLineNum(ConFullDir,sConTag1,CONTINUE);
            if(FileInsertLine(ConFullDir,ConString1,nvLineNum,REPLACE)<0) then
            MessageBox ("FileInsertLine failed.", SEVERE); 
            endif; 

6、完美卸载

安装过程已经完成,接下来看如何完美卸载程序(删除文件,分离数据库,删除虚拟目录)

选择Installscript,找到你要卸载的Feature,默认是DefaultFeature,选择卸载事件,UnInstalling(卸载前)和UnInstalled(卸载后)

第一步:分离数据库

因为卸载界面已经脱离了安装的生命周期,那么所有变量都被回收了,要获取数据库信息只能从注册表获取(安装的时候已写进了注册表)

//更换注册表根目录
    if (RegDBSetDefaultRoot (nRootKey) < 0) then  
        MessageBox ("First call to RegDBSetDefaultRoot failed.", INFORMATION); 
    endif;  
    
    //从注册表取数据库和虚拟目录相关信息
    RgVirDir=GetReg("VirDir");
    RgServer=GetReg("Server");
    RgUser=GetReg("User");
    RgPwd=GetReg("Pwd");  
    //分离A8数据库   
    szWaitTxt="正在分离A8数据库";
    SdShowMsg (szWaitTxt, TRUE);  
    Delay(2);
    szCmdLine = "/U "+RgUser+" /P "+RgPwd+" /S "+RgServer+" /Q \"EXEC  sp_detach_db 'A8'";  
    if(    LaunchAppAndWait("osql.exe", szCmdLine,LAAW_OPTION_NOWAIT | LAAW_OPTION_HIDDEN) <0) then
        MessageBox ("数据库分离失败!请确您的系统中已安装 Microsoft SQL Server 2000. 如仍无法解决,请联系系统供应商!",SEVERE); 
    endif;
    SdShowMsg (szWaitTxt, FALSE);  

GetReg是一个自定义函数,参数则是注册表的键名

分离数据库还是使用dos命令下的osql.exe

删除数据库文件只能先分离,不然会有数据库质疑的字样

第二步:删除虚拟目录

//删除虚拟目录
     set objW3SVC = CoGetObject("IIS://localhost/W3SVC/1/Root", "");//获取Default站点   
     if(IsObject(objW3SVC)) then
        if(IsObject( CoGetObject("IIS://localhost/W3SVC/1/Root/"+RgVirDir+"",""))) then 
                szWaitTxt="正在删除"+RgVirDir+"虚拟目录";   
                Delay(2);
                SdShowMsg (szWaitTxt, TRUE);      
                objW3SVC.Delete("IIsWebVirtualDir",RgVirDir) ;
                SdShowMsg (szWaitTxt, FALSE);      
        endif;
     endif; 

删除虚拟目录一样使用了ADSI

第三步:停止数据库服务和删除注册表键值

//停止数据库服务SQLSERVERAGENT,MSSQLSERVER
    szCmdLine = " stop SQLSERVERAGENT";    
    if(LaunchAppAndWait("sc", szCmdLine,LAAW_OPTION_NOWAIT | LAAW_OPTION_HIDDEN)<0) then
       MessageBox ("无法停止数据库服务--SQLSERVERAGENT,请手动关闭该服务",SEVERE); 
    endif;
   
    szCmdLine=" stop MSSQLSERVER";
    if(LaunchAppAndWait("sc", szCmdLine,LAAW_OPTION_NOWAIT | LAAW_OPTION_HIDDEN) <0) then
        MessageBox ("无法停止数据库服务--MSSQLSERVER,请手动关闭该服务",SEVERE); 
    endif;  
     
     //删除完删除注册表 
     DelReg(KEY);

DelReg是自定义函数,参数是注册表的键

第四步:删除文件夹和启动数据库服务(在UnInstalled卸载后触发)

//---------------------------------------------------------------------------
// The UnInstalled event is sent after the feature DefaultFeature
// is uninstalled.
// sented after delete defaultFeature
//---------------------------------------------------------------------------
 
export prototype DefaultFeature_UnInstalled();
function DefaultFeature_UnInstalled() 
string szCmdLine;
begin
    //删除后重新启动数据库服务--MSSQLSERVER
    szCmdLine=" start MSSQLSERVER";
    if(LaunchAppAndWait("sc", szCmdLine,LAAW_OPTION_NOWAIT | LAAW_OPTION_HIDDEN) <0) then
        MessageBox ("无法启动数据库服务--MSSQLSERVER,请手动启动该服务",SEVERE); 
    endif;            
    
    //可能删除不干净,手动执行删除文件夹
    if(ExistsDir(TARGETDIR)=EXISTS ) then   
        if(DeleteDir(TARGETDIR,ALLCONTENTS) < 0) then
            MessageBox("删除失败",SEVERE)  ;
        endif;
    endif;
end;

启动数据库服务,删除文件夹。

整个卸载过程完成。

八、更新包制作

1、前言

更新包也是一个独立的InstallScript MSI Project,只不过相比于安装包少了一些步骤,更新包的原理就是从注册表读出安装时写进的信息,如:数据库服务器,用户名,密码,虚拟目录,安装路径。界面略……

直接跳过选择安装目录那个对话框,因为获取了注册表的那个安装路径了。代码如下:

Dlg_SdStartCopy:
    szTitle = "";
    szMsg   = "";
    nResult = SdStartCopy2( szTitle, szMsg );            
    if (nResult = BACK) then
       goto Dlg_SQL;;
    endif;  
    
    //获取注册表的目标路径
    TARGETDIR= GetReg("TargetDir");
    
    // Added in IS 2009 - Set appropriate StatusEx static text.
    SetStatusExStaticText( SdLoadString( IDS_IFX_STATUSEX_STATICTEXT_FIRSTUI ) );

// setup default status
    Enable(STATUSEX);
 
    return 0;
end;

2、选择更新文件

方法跟安装的时候是一样的

3、修改Product Code,每次更新都要换一个Code,要不会出现(修复,卸载,重装的操作界面)

4、运行sql语句

假如有更新sql语句,将需要运行的sql语句整理成一个文件

//---------------------------------------------------------------------------
// OnEnd
//
// The OnEnd event is called at the end of the setup. This event is not
// called if the setup is aborted.
//---------------------------------------------------------------------------
function OnEnd()  
    STRING szKey, szClass, szMsg, szTitle,szCmdLine,sqlRoot;
    string targetDir,server,user,pwd;
    NUMBER nRootKey;
begin    
if(!MAINTENANCE)then
    targetDir=  GetReg("TargetDir");
    server= GetReg("Server");
    user= GetReg("User");
    pwd= GetReg("Pwd");
    sqlRoot= targetDir+"sqlFile.sql" ;
    LongPathToQuote(sqlRoot ,TRUE);                                   
    if(Is(FILE_EXISTS,sqlRoot)) then
        szCmdLine = "/U "+user+" /P "+pwd+" /S "+server+" /i "+sqlRoot+""; 
        if (LaunchAppAndWait("osql.exe", szCmdLine,LAAW_OPTION_NOWAIT | LAAW_OPTION_HIDDEN) < 0) then 
            MessageBox ("运行sql更新文件时失败,请联系供销商!",SEVERE); 
        endif;    
    else
         MessageBox ("找不到更新的sql文件,请联系供销商!",SEVERE);  
    endif;
endif;    
end;

执行更新的sql语句也是调用dos的osql.exe文件

5、屏蔽控制面板里添加删除程序的那个安装信息

九、结束语

首先感谢Installshield技术交流群(158107742)的群主海洋女神,Kevin,单车,棕橙蓝绿……还有其他群里的朋友们。排名不分前后

如果有看不懂或者不明白的可以给我留言或者加qq群跟大家交流交流,如果想了解更专业的Installshield技术,可以阅读以下的博客:

1.论坛http://www.appinstall.cn/

2.入门http://home.cnblogs.com/Cindy_weiwei

3.提高http://home.cnblogs.com/installshield

附:由于部分资源文件涉及公司机密,仅能提供自定义对话框和数据库操作的脚本资源:/Files/magicchaiy/脚本.rar

转载于:https://www.cnblogs.com/yangzhx/p/3632504.html

ASP.NET完整打包卸载更新攻略(By Installshield 2010)【转】相关推荐

  1. Crawler之Scrapy:数据挖掘必备的scrapy框架之最完整爬取网页内容攻略

    相关文章推荐 Scrapy:Python3版本上安装数据挖掘必备的scrapy框架详细攻略(二最完整爬取网页内容信息攻略) 目录 scrapy框架之最完整爬取网页内容攻略 scrapy框架之最完整爬取 ...

  2. DataScience:风控场景之金融评分卡模型的简介、构建(逻辑回归)开发(转评分卡)、使用过程(线上实现)、完整流程之详细攻略

    DataScience:风控场景之金融评分卡模型的简介.构建(逻辑回归)&开发(转评分卡).使用过程(线上实现).完整流程之详细攻略 目录 逻辑回归之金融评分卡模型的简介.构建.开发.使用过程 ...

  3. 赛尔号7月17日服务器维护,赛尔号7月17日更新攻略汇总

    赛尔号7月17日更新攻略汇总,赛尔号7月17日更新攻略内容~终极守护,赛尔号赫尔卡星的缔造者赫尔卡降临!生当作人杰,霸王项羽耀世出世--更多精彩内容请关注4399赛尔号7月17日更新攻略吧! 缔造传奇 ...

  4. VC#打包部署全攻略之(一、添加卸载程序)

    一.在系统文件的system32文件夹下找到msiexec.exe.(c:\windows\system32\msiexec.exe)在打包项目中应用程序文件夹中添加文件msiexec.exe. 二. ...

  5. 十大常遇流氓软件完全卸载全攻略

    一.3721(现更名阿里巴巴)的卸载 1,使用"开始"-->"程序"--->"3721相关程序的卸载选项"把3721卸载了(上网 ...

  6. App渠道打包的最佳攻略,一次解决打包难题

    概述 众所周知,由于国内Android应用分发市场的众多,我们在发布App时,一般需要生成多个渠道包,上传到不同的应用市场.这些渠道包需要携带不同的渠道信息,当App和后台交互或者数据上报时,会带上各 ...

  7. ASP.NET MVC IOC 之AutoFac攻略

    转于:http://www.cnblogs.com/WeiGe/p/3871451.html 一.为什么使用AutoFac? 之前介绍了Unity和Ninject两个IOC容器,但是发现园子里用Aut ...

  8. jenkins+Xcode+蒲公英实现ipa自动打包发布全攻略

    http://www.jianshu.com/p/ed124917d6c6 蒲公英:https://www.pgyer.com/udid/ 一步快速获取 iOS 设备的 UDID 请使用 iPhone ...

  9. 赛尔号7月17日服务器维护,赛尔号07月17日更新攻略汇总 环城之光圣芒降临

    1.[能源重启大地苏醒 环城之光圣芒降临] 星空璀璨闪耀天际, 绝命时刻生机乍现. 能源重启大地苏醒, 环城之光圣芒降临! 2.[御象灵尊新皮肤 热门皮肤再返场] 御象灵尊全新皮肤, 兽灵镇煞火爆上线 ...

最新文章

  1. 批量计算多个点到一个点的距离
  2. Mysql之group by 和order by 一起用时的排序问题(亲测)
  3. DNN架构解析(收集)
  4. 深入理解 Java G1 垃圾收集器GC调优
  5. 服务器,linux系统配置端口号的坑!!!服务器防火墙配置!!!
  6. python给列表的每一项都加上特定的字符串
  7. (纯CSS)悬浮一个元素,让另一个元素改变属性
  8. 【优化布局】基于matlab遗传算法求解配电变电站布局优化问题【含Matlab源码 1317期】
  9. Linux创翼拨号上网,创翼客户端下载(网络拨号工具) v4.11.4.731 最新版_数码资源网...
  10. 使用计算机对炼钢过程,炼钢过程计算机二级系统
  11. java qua_Qua Vadis Eclipse? 第二部分
  12. 最快路由器服务器地址,路由器中radius服务器IP地址要用什么样的IP
  13. CTF比赛解析备课与教学:漏洞扫描
  14. 微信支付 postman_支付宝微信刷脸支付系统搭建服务商平台怎么做
  15. tomcat 日志报错 java.lang.UnsupportedClassVersionError: com/wlt/controller/IndexController
  16. 鼠标滑轮将物体放大缩小
  17. 工业控制系统的安全防护建议
  18. 无线衰落信道的分类方式和选择性衰落条件
  19. T7 图书和音像租赁 (10分)
  20. ArcGIS制图及出图小技巧——以土地利用图为例

热门文章

  1. html让元素纵向排列,html – 如何使元素排列到父元素的外边缘
  2. 只能输入字母的c语言程序设计教程课后答案,c语言程序设计基础教程_习题答案20120319...
  3. android小部件如何实时更新,android – 使用AlarmManager手动更新小部件
  4. linux系统怎么清理磁盘空间,LINUX系统怎么使用命令清理磁盘空间?
  5. 河马php一句话木马,一句话木马的套路
  6. java 面试题 简书_java面试题
  7. 精选30道Java笔试题解答
  8. 【数学与算法】曲线上各点的曲率kappa和倾角theta
  9. 用 JMX 检测应用程序
  10. mysql dba系统学习(5)二进制日志binlog之一