InstallShield使用——幾個技術問題介紹
InstallShield使用——幾個技術問題介紹
1幾個技術問題介紹
1.1資料庫設定
在安裝程式中設定資料庫,有兩種方法:一種採用命令列附加資料庫檔案,一種是通過SQL Script指令碼建立資料庫,對於編寫SQL Script過於複雜,或建立資料庫時間過長時建議採用第一種方法。
1.1.1命令列附加資料庫
1.將資料庫檔案(a_data.mdf和a_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.2SQL 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 Scripts的Text Replacement頁面新增兩個替換引數,如下圖所示:
1.2InstallScirpt呼叫動態執行庫中的函式
安裝過程中有些設定是InstallShield無法做到的,需要其他的程式設計軟體實現,其他的程式設計軟體可以編寫成可執行的應用程式(EXE檔案),通過LaunchApp和LaunchAppAndWait呼叫,也可以編寫成動態執行庫(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.1Basic MSI Project工程專案
1.建立自定義窗體,可參考標準窗體的各種設定,主要是窗體Behavior的設定,下面以一個例子說明建立過程;
2.建立一個記錄登入伺服器的資訊的自定義窗體,該窗體需要錄入伺服器的IP地址、使用者名稱及口令,將錄入資訊記錄到XML檔案中;
3.如下圖所示,在User Interface的Dialogs的All Dialogs點選右鍵,選擇New Dialgo選單,進入自定義窗體嚮導;
4.選擇Blank Dialog建立一個空白窗體,重新命名NewDialog1,如ServerLogin;
5.如下圖所示選擇ServerLogin下的Chinse(Simplified)節,可設計此窗體;
6.新增三個Text Area,分別將Text屬性更改為伺服器IP:、使用者名稱:及口令:,新增三個Edit Field,分別錄入Property
Name(屬性名稱)為MY_SERVER_IP、MY_SERVER_USER及MY_SERVER_PWD,
將口令的錄入框的Password屬性的值更改為True,新增三個Push Button,分別是上一步、下一步及取消,如下圖所示:
7.如果想將此窗體插入CustomerInformation窗體與SetupType之間,可選擇CustomerInformation的Behavior的Next按鈕,如下圖所示,將Event的NewDialog的Argument更改為ServerLogin窗體;
8.選擇ServerLogin的Behavior的Next按鈕
,新增一個NewDialog事件,將Argument更改為SetupType窗體,Condition更改為1,同理在上一步按鈕中新增返回CustomerInformation窗體的事件,在取消按鈕中新增Event為SpawinDialog,Argument為CancelSetup,Condiiton為1,如下圖所示:
9.可以在Behavior and Logic中的Custom Actions and Sequences中可以看出窗體的執行順序,如下圖所示:
10.在XML File Changes節中新增記錄資訊,這裡不再詳述。
1.3.2InstallScript MIS Project工程專案
1.建立自定義窗體需要注意在InstallScript中如何呼叫自定義窗體,並將窗體的屬性複製公共屬性,下面以一個例子說明呼叫;
2.建立一個記錄登入伺服器FTP的資訊的自定義窗體,該窗體需要錄入伺服器的IP地址、FTP埠、FTP使用者名稱及口令,將錄入資訊記錄到XML檔案中;
3.在User Interface的Dialogs的All Dialogs點選右鍵,選擇New Dialgo選單,進入自定義窗體嚮導,選擇Blank
Dialog建立一個空白窗體,重新命名NewDialog1,如SdComputerInfo,編輯窗體如下圖所示:
4.在Direct Editor的Dialog中查出該窗體的ID,我建立的這個自定義窗體的ID為12011,在Direct Editor的Control中查出各控制元件的ID;
5.在Property Manager中新建四個屬性LOCALHOST、LOGINUSER、LOGINPWD、FTPPORT;
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節中新增記錄資訊,這裡不再詳述。