瀏覽器外掛之ActiveX開發(四)----web頁面呼叫ActiveX
轉自:http://www.cnblogs.com/qguohog/archive/2013/01/25/2876828.html
https://blog.csdn.net/zengraoli/article/details/12078757?utm_source=blogxgwz3
簡單總結一下前幾篇文章的內容,《瀏覽器外掛之ActiveX開發(一)》簡單介紹了一下如何在Vs.net 2008下用C++開發基於MFC的ActiveX外掛,《瀏覽器外掛之ActiveX開發(二)》介紹了開發外掛時可能遇到的問題,《瀏覽器外掛之ActiveX開發(三)》介紹瞭如何註冊外掛以及如何打包成cab檔案。但是,到目前為止還沒有專門提及如何在Web頁面中呼叫外掛,本文主要針對這個問題進行展開。
一、用<Object>標籤呼叫ActiveX
1、Object標籤基本用法
在Html頁面中呼叫ActiveX外掛最簡單常用的方法是:
<object id="CardAccessor"
classid="clsid:03AD53E8-D7E7-485D-A39A-D07B37DEFBC9"
width="0"
height="0">
</object>
id屬性就不用解釋了,和html中其他元素的id一樣,是DOM樹中各元素的唯一標識。width和height表示該ActiveX在Web頁面中佔位的大小,對於僅提供介面無UI介面的ActiveX來說將其設定為0即可,因為不需要在頁面上顯示任何內容(對於需要顯示介面的ActiveX,需要在專案裡建立Dialog及寫相應邏輯,可以參考“
classid屬性在這裡是一個非常關鍵的屬性,IE正是通過他才能正確找到要呼叫的ActiveX的。每個ActiveX均有一個唯一的id來表示,這就是classid,在我們建立MFC ActiveX Control專案時Vs.net 2008就幫我們生成了這個id, 可以在程式的.idl檔案最下方找到這個ID值:
一般不建議手動修改程式中的這個uuid值,因為在xxxxCtrl.cpp檔案中也用到了這個id值,只是表現形式不一樣罷了:
控制元件註冊成功後,這個classid及控制元件檔案位置等資訊均寫入登錄檔了,如下所示:
當然,如果ActiveX還定義了其他屬性,也可以在<object>中以屬性的形式給他們賦值。
如果使用者的計算機已經註冊了該外掛(例如通過Setup.exe方式),那麼Html引用上段程式碼後就可以通過js呼叫外掛的介面和屬性了(再次提示一下,ActiveX只能在IE瀏覽器執行,也就是<object…>這段程式碼在firefox等其他瀏覽器是不能正常工作的)。
<fieldset>
<legend>Read Card No Testing</legend>
卡號:<input type="text" id="txtCardNo_Read" maxlength="32" class="txt disable" readonly />
<input type="button" id="btnRead" value=" Read CardNo " class="btn" onclick="javascript:readCardNo();" />
</fieldset>
<fieldset>
<legend>Write Card No Testing</legend>
卡號:<input type="text" id="txtCardNo_Write" maxlength="32" class="txt" />
<input type="button" id="btnWrite" value=" Write CardNo " class="btn" onclick="javascript:writeCardNo();" />
</fieldset>
<script type="text/javascript">
var txtCardNo_Read = document.getElementById("txtCardNo_Read");
var txtCardNo_Write = document.getElementById("txtCardNo_Write");
var objCard = document.getElementById("CardAccessor");
function readCardNo() {
txtCardNo_Read.value = "";
try{
var ret = objCard.ReadCardNo();
if (ret == 0) {
txtCardNo_Read.value = objCard.CardNo;
alert("讀卡成功!");
}
else {
alert("讀卡失敗!錯誤碼為:" + ret);
}
}
catch (e) {
alert(e.message)
}
}
function writeCardNo() {
var cardNo = txtCardNo_Write.value;
try {
objCard.CardNo = cardNo;
var ret = objCard.WriteCardNo();
if (ret == 0) {
alert("寫卡成功!");
}
else {
alert("寫卡失敗!錯誤碼為:" + ret);
}
}
catch (e) {
alert(e.message)
}
}
</script>
<script type="text/javascript">
var objCard = document.getElementById("CardAccessor");
if (objCard.object==null) {
alert("CardAccessor外掛未安裝!");
}
else{
alert("已檢測到CardAccessor外掛!");
}
</script>
<script type="text/javascript">
var objCard = document.getElementById("CardAccessor");
if (objCard.CardNo==undefinedl) {
alert("CardAccessor外掛未安裝!");
}
else{
alert("已檢測到CardAccessor外掛!");
}
</script>
3、如何讓IE自動下載安裝外掛並智慧升級
如果檢測到外掛沒有安裝,怎樣讓IE自動從指定位置下載外掛並自動安裝呢?很簡單,在object標籤中使用codebase屬性即可:
<object id="CardAccessor"
classid="clsid:03AD53E8-D7E7-485D-A39A-D07B37DEFBC9"
codebase="CardAccessor.cab#version=1,0,0,1"
width="0"
height="0">
</object>
codebase的值格式為“xxxxx.cab#version=1,0,0,1”。'#'前面部分為cab檔案的位置,可以是在伺服器上的絕對位置,也可以是相對位置。'#‘後面部分表示當前引用的cab包的版本號。當IE檢測到系統沒有註冊指定外掛,便從codebase指定的位置下載該cab到本地,並按照其中.inf檔案的描述將各檔案複製到指定位置並註冊指定的控制元件。(注:在實際應用中涉及簽名問題,後文再述)
即使本地已經註冊了該外掛,IE還將拿已註冊的控制元件版本號與codebase中指定的版本號相比較,如果codebase中指定的版本號大於已註冊外掛的版本號,IE仍然會從codebase指定位置下載cab包並重新註冊該外掛。
正如前面的文章所提,為方便管理,一般將cab包中需註冊的ocx檔案的版本號視同cab版本號。
當外掛或外掛依賴的檔案需要升級時,只需更新相應的檔案,並對.inf中的相應檔案版本升級(為方便管理,無論是否更新了ocx檔案,該ocx檔案的版本號也跟著升級,因為其版本號代表了整個cab),然後重新打包成cab釋出到伺服器上,並更新html中object標籤中codebase屬性值的version部分版本號。當用戶下次訪問該頁面時,IE將自動下載升級後的cab並重新註冊外掛。實際上,經過我的測試,及時伺服器上的cab包不做任何變化,只要增加codebase中version的值,對應外掛均會重新下載和註冊。
二、通過javascript的new ActiveXObject來呼叫ActiveX
如果不使用object標籤,也可以直接通過js的ActiveXObject來建立指定ActiveX的例項從而達到呼叫外掛介面的目的(IE下xmlhttpRequest的呼叫就是這個原理)。例如:
var objCard = new ActiveXObject("Uprain.CardAccessorCtrl.1");
如果外掛已經註冊,接下來就可以通過objCard來呼叫外掛介面和訪問屬性了。
ActiveXObject函式的引數為對應外掛的ProgId而非CLASSID。在專案中xxxxCtrl.cpp檔案中同樣可以找到或修改對應外掛的ProgId值,如下圖:
即IMPLEMENT_OLECREATE_EX的第二引數就表示當前外掛的ProgId,該值可以根據實際需要自行修改。實際上,在登錄檔中通過ProgId是可以找到對應的ClassId的,兩者是有關聯的:
那麼如何判斷ActiveX是否已經安裝呢?實際上如果ActiveX未安裝,通過new ActiveXObject的方式來建立外掛物件是會丟擲“Automation 伺服器不能建立物件”異常的。所以用如下方式即可:
try {
objCard = new ActiveXObject("Uprain.CardAccessorCtrl.1");
}
catch (e) {
alert("呼叫ActiveX失敗!");
}
不過,我在實際測試過程中遇到兩種情況:
1) 出現“Automation 伺服器不能建立物件”異常的並不一定就表示外掛沒安裝,也有可能是因外掛未實現初始化或指令碼安全介面,從而被IE攔截,需要調整IE“工具-選項-安全-自定義級別”中“ActiveX控制元件和外掛”部分的設定;
2) 有時候,同樣已註冊的外掛,通過object標籤引用的方式能正常呼叫介面,但通過new ActiveXObject的方式則呼叫外掛介面失敗。