ASP.NET完整打包卸载更新攻略(By Installshield 2010)【转】
-
前言
前陣子做了一個有關Installshield的OA 打包安裝程序,用的版本Installshield 2010-Premier,具體功能的內容如下:
1、OA采用的是asp.net(C#)開發(fā)
2、動態(tài)發(fā)布到IIS虛擬目錄(采用自定義對話框)
3、附加,分離,刪除數(shù)據(jù)庫
4、動態(tài)修改web.config
5、完美卸載
6、更新包制作
【安裝】首先準備一個發(fā)布好的aspnet網(wǎng)站,然后在web.config插入標簽,在app_data文件夾放入數(shù)據(jù)庫文件。安裝的時候會自動把文件copy到目標機器,在使用dos命令將app_data里面的文件附加到數(shù)據(jù)庫,根據(jù)用戶填寫的數(shù)據(jù)庫信息替換web.config的標簽……
【更新】更新包的思路也很簡單,在安裝的時候會把用戶填寫的數(shù)據(jù)庫信息存到注冊表(數(shù)據(jù)庫服務器,用戶名,密碼,虛擬目錄,安裝路徑),用了這些信息,那么更新的時候直接把文件copy到用戶安裝時選擇的路徑就可以了,如果有數(shù)據(jù)庫相關的更新,則可以使用dos命令執(zhí)行數(shù)據(jù)庫文件(.sql),如果有web.config的更新,則再一次動態(tài)替換web.config的標簽即可。
【卸載】網(wǎng)站的卸載就是刪除文件,分離和刪除數(shù)據(jù)庫,刪除注冊表相關鍵值,刪除虛擬目錄
接下來讓我們一步一步來實現(xiàn),篇幅可能有點長,請大家 pay patience,Let’s go
一、新建項目
?
選擇All Types下面的InstallScript MSI Project,填寫產(chǎn)品名稱,保存路徑,點擊OK
?
點擊OK后出來這個界面Project Assistant 項目助手,點擊進去可看到有些簡單描述項目的選項
Installation Designer安裝設計,點擊進去可看到產(chǎn)品的信息,安裝腳本,安裝界面等?
?
切換到Installation? Designer可看到以上界面。
二、填寫產(chǎn)品信息
?
填寫產(chǎn)品的基本信息(包括產(chǎn)品名稱,安裝語言,產(chǎn)品的安裝版本,產(chǎn)品編碼……)
三、選擇文件源
?
選擇文件源,在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關聯(lián)完Component后則可以在Application Data下面的files and folders看到關聯(lián)過來的文件夾信息,可以對其進行局部調整。也可以對文件夾進行權限控制,權限設置如下:
?
選中文件夾,右鍵點擊Properties屬性,則彈出以下屬性窗口
?
點擊Permissions彈出以下界面
?
在空白處點擊右鍵選擇New,則彈出以下界面
?
設置文件夾的權限,點擊OK完成?
?
五、Installshield Script
?
默認的腳本沒有任何東西,只有一句?#include "ifx.h",必須點擊右邊的安裝函數(shù)才出來腳本。
InstallScript腳本的語法類似于C,也類似于VBScript,可以調用VB的代碼。也可以調用dos命令,也可以調用exe。
?
選擇?Before Move Data?階段的函數(shù)?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 復制文件對話框
這幾個是系統(tǒng)默認的對話框,所有對話框的生命周期基于Setup.rul腳本,也就是說需要在Setup.Rul里面設置對話框的相關腳本信息和調用對話框的構造函數(shù)。
系統(tǒng)默認的對話框腳本都包含在#include "ifx.h"頭文件里面,如果是自定義的對話框則【后面會提到】需要引用相關對話框的腳本。
?
?
若要引用其他的對話框,則要從dialog source里面調出對話框函數(shù)
?
六、Dialog對話框
?
對話框選項位于User Interface(用戶體驗,簡稱UI)下面的Dialog(對話框)選項
?
鼠標懸停在對話框名稱,右鍵,選擇Edit,可看到對話框的相關信息(布局,控件,屬性……Control Identifier是唯一標識列),可以修改對話框的布局和信息。
?
?
Skin則是對話框的皮膚,選中皮膚,點擊Select應用該皮膚。
?
七、一個完整的ASP.NET打包程序
1、前言
在了解了Installshield 2010?的一些基本設置和熟悉操作界面后,給大家演示一個完整的ASP.NET打包程序,ASP.NET的安裝與部署比較簡單,主要是把網(wǎng)站發(fā)布到IIS,附加數(shù)據(jù)庫,配置數(shù)據(jù)庫信息(包括數(shù)據(jù)庫用戶,密碼,服務器),修改web.config配置文件。主要功能有:
●?????手動選擇安裝目錄
●?????創(chuàng)建和設置IIS虛擬目錄
●?????動態(tài)附加分離數(shù)據(jù)庫
●?????自動修改配置文件
●?????完美卸載
2、創(chuàng)建IIS虛擬目錄
2.1、自定義創(chuàng)建虛擬目錄對話框
由于Installshield自身沒有操作IIS的功能,那么就要借助外部程序或者windowsAPI,用程序配置?IIS?所用到的“技術”無非是?ADSI?或者?WMI?提供的組件服務程序。可以通過?Windows Host Script?來執(zhí)行?JScript?或者?VBScript?腳本,也可以在?VB/Delphi?這類快速開發(fā)工具開發(fā)程序來調用,甚至可以通過瀏覽器中運行的?JavaScript/JScript/VBScript?以及?IIS?運行的?ASP?來調用。因為支持?IDispatch?接口,所以可以后期綁定地通過?CreateObject?或者?GetObject?方式來獲取?ADSI/WMI?的特定接口。那么我們這里就簡單地利用adsi來操作IIS。
由于Installshield自身沒有創(chuàng)建虛擬目錄的窗口,那么我們就簡單的自己做一個自定義的窗口,窗口很簡單,就只有一個文本框,用于輸入虛擬目錄的名稱。制作過程如下:
?
首先先All Dialogs那里右鍵,彈出菜單,選擇New Dialog
?
新建對話框向導
?
對話框有多種類型:
Blank Dialog?空對話框,該對話框什么都沒有,連上一步,下一步的按鈕都沒有
NewScriptBasedDialog?普通基于腳本的對話框,帶基本按鈕
NewSkinnableDialog?帶皮膚功能的對話框,帶基本按鈕
?
如果彈出沖突頁面,直接點擊SkipAll就行了。
?
添加完皮膚對話框后,界面如上,現(xiàn)在就可以對對話框進行編輯,修改對話框標題,按鈕的文字,字體大小,擺置方式等。最重要的是甚至對話框的Resource identifier,這是對話框的唯一標識列。
那么現(xiàn)在對話框已經(jīng)添加完成了,那么如何在安裝的過程中顯示該對話框呢??
每個對話框都有一個構造函數(shù),那么只有調用該對話框的構造函數(shù)就行了,接下來請看怎么編寫對話框的構造函數(shù)(詳情按F1)。
?
在DefineDialog ( szDialogName, hInstance, szDLLName,nDialogID, szDialogID, nReserved, hwndOwner, lMsgLevel );?這個函數(shù)里,最主要的參數(shù)就是第四個nDialogID(對話框ID),也就是對話框Resource identifier屬性的值。那么對話框構造函數(shù)就可以這樣寫:
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,其他參數(shù)可以為空或為0。那么有了構造函數(shù),那么在Setup.rul里面就可以調用構造函數(shù),使用對話框了。
一般為了方便管理,每個對話框都會配置一個對話框的腳本。腳本里面也就是構造函數(shù)和點擊按鈕的業(yè)務處理
//選擇虛擬目錄???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也就是一個構造函數(shù),里面封裝了DefineDialog?函數(shù)和業(yè)務處理。返回的是按鈕ID,BACK和NEW都是枚舉值。
對話框其實處于一種死循環(huán)狀態(tài),只靠goto語句來跳出循環(huán)。具體出來的對話框界面如下:
?
那么如果獲取用戶輸入的值呢?
跟對話框的原理一樣,每一個控件也是有一個唯一標識列的(Control Identifier)
設置控件的值CtrlSetText(szDialogName,1204,"A8");
獲取控件的值CtrlGetText(szDialogName,1204,svVituralDir);
1204是控件的Control Identifier
szDialogName是對話框的名稱,跟DefineDialog第一個參數(shù)相對應。
最后一個參數(shù)則是設置和獲取填充的值或變量。
//?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;
?????????????
????????????//創(chuàng)建注冊表項???
????????????if?(RegDBKeyExist?(szKey)?<?0)?then?
????????????????if?(RegDBCreateKeyEx?(szKey,?szClass)?<?0)?then?
????????????????????MessageBox?("RegDBCreateKeyEx?failed.",?SEVERE);?
????????????????endif;?
????????????endif;
????????????
????????????//創(chuàng)建鍵值對[虛擬目錄,目標目錄]
????????????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、創(chuàng)建虛擬目錄(使用ADSI)
設置好界面,獲取到用戶輸入的虛擬目錄名稱,接下來就是創(chuàng)建虛擬目錄了。
第一步:獲取IIS的Default站點
set objW3SVC = CoGetObject("IIS://localhost/W3SVC/1/Root","");
第二步:創(chuàng)建虛擬目錄
set objVirDir=objW3SVC.Create("IISWebVirtualDir",virtrualDir);//virtrualDir是變量
第三步:設置虛擬目錄的屬性
objVirDir.Path = TARGETDIR; ??
objVirDir.AccessRead = TRUE; ??
objVirDir.AccessScript = TRUE; ??
objVirDir.AppCreate(TRUE);???
objVirDir.SetInfo();
詳細代碼請參考SdSelectVirtual.rul的CreateWebSite函數(shù)
3、填寫數(shù)據(jù)庫信息
3.1、自定義數(shù)據(jù)庫對話框
數(shù)據(jù)庫的對話框也需要自定義,在上面已經(jīng)介紹過自定義對話框的制作方法,數(shù)據(jù)庫對話框界面如下:
?
填寫服務器信息,默認是localhost或者.都可以
填寫用戶名,默認一般是sa
填寫密碼,默認是******
3.2、驗證數(shù)據(jù)庫信息
?
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;?
?????????????//判斷數(shù)據(jù)庫鏈接是否成功(0代表鏈接失敗,1代表鏈接成功)?
?????????????szWaitTxt="正在檢查數(shù)據(jù)庫用戶名和密碼";?
?????????????SdShowMsg?(szWaitTxt,?TRUE);
?????????????Delay(2);
?????????????SdShowMsg?(szWaitTxt,?FALSE);?
?????????????if(DB_CheckConnection(Server,"SQL?Server",User,Pwd)!=1)?then
????????????????nId=0;
????????????????bDone=FALSE;??
????????????????MessageBox?("數(shù)據(jù)庫用戶名或者密碼錯誤,請重新輸入",?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;
?????????????????????
????????????????//創(chuàng)建注冊表項???
????????????????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?這個函數(shù)用于驗證當前用戶輸入的數(shù)據(jù)庫信息是否正確,有關數(shù)據(jù)庫的相關操作位于database.rul文件。
如果數(shù)據(jù)庫的信息填寫無誤,那么把數(shù)據(jù)庫信息寫到注冊表,方便以后升級使用。
4、附加數(shù)據(jù)庫
?
在執(zhí)行復制文件到目標機器后,點擊Finish(完成)按鈕會觸發(fā)函數(shù)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);?//構造函數(shù)
//prototype?CreateDataBase(STRING,STRING,string);//創(chuàng)建數(shù)據(jù)庫
prototype?AlterConfigure(string);//修改web.config
string?Server,User,Pwd;?//全局變量
附加數(shù)據(jù)庫是調用了dos命令的osql.exe,代碼如下:
//創(chuàng)建數(shù)據(jù)庫function?CreateDataBase(svSQLsvr,svSQLusr,svSQLpwd)?
????STRING?szCmdLine,szWaitTxt,szCommandLine;?
????begin?
????//A8數(shù)據(jù)庫
????szWaitTxt="?正在創(chuàng)建A8數(shù)據(jù)庫.";?
????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?("數(shù)據(jù)庫創(chuàng)建失敗!請確您的系統(tǒng)中已安裝?Microsoft?SQL?Server?2000.?如仍無法解決,請聯(lián)系系統(tǒng)供應商!",SEVERE);?
????endif;??
????SdShowMsg?(szWaitTxt,FALSE);??
????szWaitTxt="?正在優(yōu)化系統(tǒng)數(shù)據(jù)庫.";?
????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?("數(shù)據(jù)庫優(yōu)化失敗!您可以在?sql查詢分析器中執(zhí)行?use?dlbj?;?exec?sp_updatestats?完成!",SEVERE);?
????endif;?
????SdShowMsg?(szWaitTxt,FALSE);??
????//打開瀏覽器瀏覽制定的網(wǎng)頁????
????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文件也是在文件拷貝到目標機器的完成階段實現(xiàn)。
第一步:定標簽
在Web.Config文件里為每一個要替換的節(jié)點定下一個注釋標簽
? <connectionStrings>
??? <!--#constring1#-->
<add name="abc" connectionString="database=abc;server=.;uid=sa;pwd=123" providerName="System.Data.SqlClient"/>
? </connectionStrings>
<!--#constring1#-->則是一個注釋標簽
第二步:定位行數(shù)
根據(jù)標簽就可以找到該標簽下面那一個節(jié)點,代碼看GetLineNum函數(shù)
//從上往下搜索某文件下面的字符串,并返回該字符串所在的行數(shù)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?;
第三步:替換該行數(shù)據(jù)
使用FileInsertLine函數(shù)可以替換文件中的某一行。
//替換webconfig里面鏈接字符串,使用GetLineNum注意最后一個參數(shù),從頭開始找還是繼續(xù)上次往下找????????????nvLineNum=GetLineNum(ConFullDir,sConTag1,CONTINUE);
????????????if(FileInsertLine(ConFullDir,ConString1,nvLineNum,REPLACE)<0)?then
????????????MessageBox?("FileInsertLine?failed.",?SEVERE);?
????????????endif;?
6、完美卸載
安裝過程已經(jīng)完成,接下來看如何完美卸載程序(刪除文件,分離數(shù)據(jù)庫,刪除虛擬目錄)
?
選擇Installscript,找到你要卸載的Feature,默認是DefaultFeature,選擇卸載事件,UnInstalling(卸載前)和UnInstalled(卸載后)
第一步:分離數(shù)據(jù)庫
因為卸載界面已經(jīng)脫離了安裝的生命周期,那么所有變量都被回收了,要獲取數(shù)據(jù)庫信息只能從注冊表獲取(安裝的時候已寫進了注冊表)
//更換注冊表根目錄????if?(RegDBSetDefaultRoot?(nRootKey)?<?0)?then??
????????MessageBox?("First?call?to?RegDBSetDefaultRoot?failed.",?INFORMATION);?
????endif;??
????
????//從注冊表取數(shù)據(jù)庫和虛擬目錄相關信息
????RgVirDir=GetReg("VirDir");
????RgServer=GetReg("Server");
????RgUser=GetReg("User");
????RgPwd=GetReg("Pwd");??
????//分離A8數(shù)據(jù)庫???
????szWaitTxt="正在分離A8數(shù)據(jù)庫";
????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?("數(shù)據(jù)庫分離失敗!請確您的系統(tǒng)中已安裝?Microsoft?SQL?Server?2000.?如仍無法解決,請聯(lián)系系統(tǒng)供應商!",SEVERE);?
????endif;
????SdShowMsg?(szWaitTxt,?FALSE);??
GetReg是一個自定義函數(shù),參數(shù)則是注冊表的鍵名
分離數(shù)據(jù)庫還是使用dos命令下的osql.exe
刪除數(shù)據(jù)庫文件只能先分離,不然會有數(shù)據(jù)庫質疑的字樣
第二步:刪除虛擬目錄
//刪除虛擬目錄?????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
第三步:停止數(shù)據(jù)庫服務和刪除注冊表鍵值
//停止數(shù)據(jù)庫服務SQLSERVERAGENT,MSSQLSERVER????szCmdLine?=?"?stop?SQLSERVERAGENT";????
????if(LaunchAppAndWait("sc",?szCmdLine,LAAW_OPTION_NOWAIT?|?LAAW_OPTION_HIDDEN)<0)?then
???????MessageBox?("無法停止數(shù)據(jù)庫服務--SQLSERVERAGENT,請手動關閉該服務",SEVERE);?
????endif;
???
????szCmdLine="?stop?MSSQLSERVER";
????if(LaunchAppAndWait("sc",?szCmdLine,LAAW_OPTION_NOWAIT?|?LAAW_OPTION_HIDDEN)?<0)?then
????????MessageBox?("無法停止數(shù)據(jù)庫服務--MSSQLSERVER,請手動關閉該服務",SEVERE);?
????endif;??
?????
?????//刪除完刪除注冊表?
?????DelReg(KEY);
DelReg是自定義函數(shù),參數(shù)是注冊表的鍵
第四步:刪除文件夾和啟動數(shù)據(jù)庫服務(在UnInstalled卸載后觸發(fā))
?
//---------------------------------------------------------------------------//?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
????//刪除后重新啟動數(shù)據(jù)庫服務--MSSQLSERVER
????szCmdLine="?start?MSSQLSERVER";
????if(LaunchAppAndWait("sc",?szCmdLine,LAAW_OPTION_NOWAIT?|?LAAW_OPTION_HIDDEN)?<0)?then
????????MessageBox?("無法啟動數(shù)據(jù)庫服務--MSSQLSERVER,請手動啟動該服務",SEVERE);?
????endif;????????????
????
????//可能刪除不干凈,手動執(zhí)行刪除文件夾
????if(ExistsDir(TARGETDIR)=EXISTS?)?then???
????????if(DeleteDir(TARGETDIR,ALLCONTENTS)?<?0)?then
????????????MessageBox("刪除失敗",SEVERE)??;
????????endif;
????endif;
end;
啟動數(shù)據(jù)庫服務,刪除文件夾。
整個卸載過程完成。
八、更新包制作
1、前言
更新包也是一個獨立的InstallScript MSI Project,只不過相比于安裝包少了一些步驟,更新包的原理就是從注冊表讀出安裝時寫進的信息,如:數(shù)據(jù)庫服務器,用戶名,密碼,虛擬目錄,安裝路徑。界面略……
直接跳過選擇安裝目錄那個對話框,因為獲取了注冊表的那個安裝路徑了。代碼如下:
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,要不會出現(xiàn)(修復,卸載,重裝的操作界面)
?
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更新文件時失敗,請聯(lián)系供銷商!",SEVERE);?
????????endif;????
????else
?????????MessageBox?("找不到更新的sql文件,請聯(lián)系供銷商!",SEVERE);??
????endif;
endif;????
end;
執(zhí)行更新的sql語句也是調用dos的osql.exe文件
5、屏蔽控制面板里添加刪除程序的那個安裝信息
九、結束語
首先感謝Installshield技術交流群(158107742)的群主海洋女神,Kevin,單車,棕橙藍綠……還有其他群里的朋友們。排名不分前后
如果有看不懂或者不明白的可以給我留言或者加qq群跟大家交流交流,如果想了解更專業(yè)的Installshield技術,可以閱讀以下的博客:
?
1.論壇http://www.appinstall.cn/
2.入門http://home.cnblogs.com/Cindy_weiwei
3.提高http://home.cnblogs.com/installshield
?
附:由于部分資源文件涉及公司機密,僅能提供自定義對話框和數(shù)據(jù)庫操作的腳本資源:/Files/magicchaiy/腳本.rar
轉載于:https://www.cnblogs.com/yangzhx/p/3632504.html
總結
以上是生活随笔為你收集整理的ASP.NET完整打包卸载更新攻略(By Installshield 2010)【转】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android中focusable属性的
- 下一篇: 事务之五:Spring @Transac