相對(duì)于開(kāi)發(fā)工作,部署顯得不是那么重要,但卻是最困難的一步,也是最后一步。
控件的部門(mén)總的說(shuō)來(lái)要完成以下幾件事,或者說(shuō)實(shí)現(xiàn)以下幾個(gè)功能:
1、客戶端第一次訪問(wèn)頁(yè)面時(shí)自動(dòng)安裝(自動(dòng)提示用戶下載).
2、有新版本發(fā)布時(shí)自動(dòng)下載最新版并安裝。
經(jīng)測(cè)試還發(fā)現(xiàn),我的2.0框架下開(kāi)發(fā)的控件,不能直接在客戶機(jī)上進(jìn)行注冊(cè)(regAsm.exe:C#開(kāi)發(fā)的ActiveX控件只能用此程序注冊(cè),而不能使用RegSvr32),不知道是不是框架版本的問(wèn)題,只能做成安裝文件。
打包成安裝文件具體的就不說(shuō)了,和打包其他項(xiàng)目一樣的步驟,但需要注意以下幾點(diǎn):
1、針對(duì)控件生成的DLL中有一個(gè)Register屬性,該屬性一定要設(shè)置為vsdraCOM,否則安裝包只會(huì)將DLL文件簡(jiǎn)單拷到你的目標(biāo)目錄下,設(shè)置該值后,安裝包才會(huì)進(jìn)行注冊(cè)表的寫(xiě)入,相當(dāng)于進(jìn)行regasm注冊(cè)。
2、還有一個(gè)屬性Permanent,看該屬性的描述說(shuō)明是說(shuō)指定該DLL文件在卸載程序時(shí)是否移除,一般性的慣性思維都是設(shè)置為true時(shí)表示在卸載程序時(shí)要移除該dll文件,但經(jīng)過(guò)測(cè)試發(fā)現(xiàn)設(shè)置為flase時(shí)才會(huì)進(jìn)行移除操作。如果不移除老版本的文件,新版本安裝時(shí)不會(huì)覆蓋原有的文件。所以此屬性顯得很重要了。
一般說(shuō)來(lái)發(fā)布OCX最常用的就是打成CAB包,該方式最簡(jiǎn)單但也最麻煩,需要搞證書(shū)。所以我就自己實(shí)現(xiàn)了一種不需要證書(shū)的發(fā)布方式(前提是要生成安裝包:XXXX.msi)。
為了實(shí)現(xiàn)自動(dòng)下載并安裝,我把MSI包又制作為自解壓包,之后文件名就變成了XXXXXXX.EXE了(這個(gè)包的制作就不多說(shuō)了,用RAR直接可以進(jìn)行壓縮,網(wǎng)上也有很多介紹),這樣當(dāng)用戶通過(guò)IE下載到本地后,IE會(huì)針對(duì)EXE類型的文件提示用戶是否要現(xiàn)在運(yùn)行,如果用戶選擇運(yùn)行,就會(huì)進(jìn)行自動(dòng)安裝了。整個(gè)實(shí)現(xiàn)原理就是如此的簡(jiǎn)單,但在簡(jiǎn)單的過(guò)程中卻有比較麻煩的步驟,讓頁(yè)面通知客房端IE下載控件的步驟就較麻煩了。
在控件所在的頁(yè)面(我用的是JSP頁(yè)面)只能使用JS腳本進(jìn)行判斷是否需要安裝控件或者開(kāi)載新版本進(jìn)行安裝。
下面我說(shuō)說(shuō)通過(guò)JS來(lái)判斷控件的問(wèn)題。需要判斷以下2個(gè)內(nèi)容:
1、判斷是否需要新安裝。
2、是否發(fā)布了新版本的判斷。
需要通過(guò)JS讀取注冊(cè)表(有這個(gè)東東注定該項(xiàng)目不能移植到非WINDOWS操作系統(tǒng)上了)下的控件的相關(guān)項(xiàng)或者鍵值。如果沒(méi)找到相應(yīng)的鍵則表示沒(méi)有進(jìn)行安裝,需要新安裝。具體判斷邏輯直接上代碼:
主函數(shù):
var lastModiDatetime = "<%=lastModiDatetime%>";//讀取的服務(wù)器上的控件文件的最后修改日期
//判斷當(dāng)前本地計(jì)算機(jī)上是否已注冊(cè)了控件。
//如果已注冊(cè)了控件,再次判斷是否是最新版本(JAVA現(xiàn)在沒(méi)有直接提供對(duì)文件版本的獲取,通過(guò)獲取文件最后修改日期來(lái)變相對(duì)比文件新舊)
//要實(shí)現(xiàn)此功能,要求每一次發(fā)布新版本控件時(shí)必須在應(yīng)用服務(wù)器上安裝并注冊(cè)最新的控件。
//并把安裝路徑下的最新RuntimeData.dll及RunData.dll和最新的安裝包:
//wellalarmruntimedata.exe(根據(jù)RuntimeDataSetup.msi制作的自解壓RAR安裝包)拷到WEB應(yīng)用程序下的petrol/cab下,拷RuntimeData.dll及RunData.dll是為了讓JAVA能夠獲取控件的最新修改日期,拷wellalarmruntimedata.exe是為了讓客戶端IE在服務(wù)器上能找到下載路徑及文件。
window.onload=function()
{
//在系統(tǒng)提示用戶是否允許交互前判斷當(dāng)前控件是否加載,通過(guò)此屬性判斷當(dāng)前是否注冊(cè)了COM組件
var isReg = true;
//通過(guò)獲取注冊(cè)表屬性得到安裝路徑
var hkey_root,hkey_path,hkey_key,path;
hkey_root="HKEY_CLASSES_ROOT"
hkey_file://\\CLSID\\{80C07FCA-841C-43C9-BD34-E9F3A6E87A85}\\InprocServer32\\">\\CLSID\\{80C07FCA-841C-43C9-BD34-E9F3A6E87A85}\\InprocServer32\\"; //80C07FCA-841C-43C9-BD34-E9F3A6E87A85就是開(kāi)發(fā)篇強(qiáng)調(diào)的控件的GUID
try
{
var RegWsh = new ActiveXObject("WScript.Shell");
hkey_key="CodeBase" ;
path = RegWsh.RegRead(hkey_root+hkey_path+hkey_key);
//獲取本地機(jī)器上的組件版本號(hào)
var assembly = RegWsh.RegRead(hkey_root+hkey_path+"Assembly");
if(assembly!=null)
{
//獲取版本號(hào)
var versionNos = assembly.split("Version=")[1];
var versionNo = versionNos.substring(0,versionNos.indexOf(","));
//查找是否注冊(cè)此版本號(hào).找到最新版本的就采用此版本的安裝路徑
try
{
var path = RegWsh.RegRead(hkey_root+hkey_path+ versionNo + "\\" + hkey_key);
}
catch(ex)
{
isReg = false;
}
}
}
catch(e){}
//注意,當(dāng)用戶不允許腳本運(yùn)行時(shí)path也是為NULL值,但只要安裝注冊(cè)了控件,不放管用戶是否同意腳本運(yùn)行,
//MWellAlm控件都會(huì)被創(chuàng)建成object
if((path==null && document.getElementById("MWellAlm")==null) || !isReg)
{
//沒(méi)有注冊(cè)此控件或者此控件已被卸載
msg.style.display = '';
ctlload.style.display = 'none';
msg.innerHTML = '本地計(jì)算機(jī)上未安裝“井場(chǎng)預(yù)警及實(shí)時(shí)數(shù)據(jù)顯示控件”或此控件已被卸載,不能正確顯示此頁(yè)面,需要下載最新的控件!<br>';
msg.innerHTML += "請(qǐng)[運(yùn)行]自動(dòng)下載的文件 或者 <a id='loadctl' href='<%=context%>/petrol/cab/wellalarmruntimedata.exe'>點(diǎn)擊下載最新顯示控件</a>";
document.getElementById("loadctl").click();
return;
}
if(path!=null && document.getElementById("MWellAlm")==null)
{
alert("當(dāng)前控件已安裝注冊(cè)但不能正確顯示,請(qǐng)關(guān)閉所有的IE瀏覽器后重試!");
return;
}
document.getElementById("MWellAlm").stop(); //調(diào)用控件的方法之一
//以下就是判斷是否發(fā)布了新版本
if(path!=null && path!="")
{
var fso = new ActiveXObject("Scripting.FileSystemObject");
var f1 = fso.GetFile(path);
//FSO獲取的文件最后修改日期是UTC格式的,JAVASCRIPT還沒(méi)有對(duì)此日期格式操作對(duì)象.所以只有轉(zhuǎn)換成字符來(lái)處理
//而且此UTC日期串與從北京時(shí)間轉(zhuǎn)換來(lái)的UTC串格式不相同
var lastDate = ""+f1.DateLastModified; //轉(zhuǎn)換成字符串
var v = new Date();
v.setTime(lastModiDatetime);
//直接通過(guò)toUTCString()的格式:Thu, 18 Dec 2008 06:46:04 UTC
//獲取的文件最后修改時(shí)間的UTC格式:Thu Dec 18 14:46:04 UTC+0800 2008
//經(jīng)測(cè)試,這2個(gè)UTC時(shí)間之前除格式不同外,在小時(shí)上還不相同。前者比后者少了8小時(shí)
//在小時(shí)上+上8小時(shí),因?yàn)檫@個(gè)UTC時(shí)間是從北京時(shí)間轉(zhuǎn)換來(lái)的
v.setHours(v.getHours()+8);
//把從北京時(shí)間轉(zhuǎn)換來(lái)的UTC時(shí)間轉(zhuǎn)換成數(shù)組,在后者中逐個(gè)匹配,都匹配上就說(shuō)明時(shí)間相等
var ds = v.toUTCString().replace(",","").split(" ");
//為了保證不出現(xiàn)左右滑動(dòng)匹配的情況(18不能與118、181匹配),在匹配項(xiàng)與被匹配項(xiàng)左右都加上一個(gè)空格
var baseUtc = " "+lastDate.replace("+0800","")+" ";
var isEqual = true;
for(var i=0; i<ds.length; i++)
{
var temp = " "+ds+" ";
if(baseUtc.indexOf(temp)==-1)
{
isEqual = false;
break;
}
}
if(!isEqual)
{
document.getElementById("MWellAlm").click();
document.getElementById("MWellAlm").clearAll();
msg.style.display = '';
ctlload.style.display = 'none';
msg.innerHTML = '本地計(jì)算機(jī)上安裝的“井場(chǎng)預(yù)警及實(shí)時(shí)數(shù)據(jù)顯示控件”不是最新版本,不能正確顯示此頁(yè)面,需要下載最新的控件!<br>';
msg.innerHTML += "請(qǐng)[運(yùn)行]自動(dòng)下載的文件 或者 <a id='loadctl' href='<%=context%>/petrol/cab/wellalarmruntimedata.exe'>點(diǎn)擊下載最新顯示控件</a>";
msg.innerHTML += '<br>注意:在安裝最新控件之前請(qǐng)保證已通過(guò)[控制面板->添加或者刪除程序]卸載了舊版本的控件!';
document.getElementById("loadctl").click();
return;
}
msg.style.display = 'none';
ctlload.style.display = '';
document.getElementById("MWellAlm").click();
document.getElementById("MWellAlm").start();
}
}
以上就是我實(shí)現(xiàn)的控件發(fā)布的全部?jī)?nèi)容。為了保證能順利發(fā)布,要求客戶端IE最好把控件所在的站點(diǎn)加為信任站點(diǎn),并調(diào)低安全限制,否則容易發(fā)生控件能顯示,但不能進(jìn)行用戶交互的情況。
以上功能全部測(cè)試通過(guò),而且現(xiàn)在項(xiàng)目中也在正常使用。
OCX技術(shù)現(xiàn)在不被人們所看好,也不被推廣,但在實(shí)際項(xiàng)目中很多時(shí)候卻不得不運(yùn)用這些雞肋技術(shù)來(lái)解決實(shí)際問(wèn)題,或者實(shí)現(xiàn)特定功能,所以很多問(wèn)題還要參考實(shí)際問(wèn)題找到合適的解決辦法。
聯(lián)系客服