1. 程式人生 > >瀏覽器外掛之ActiveX開發(四)----web頁面呼叫ActiveX

瀏覽器外掛之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及寫相應邏輯,可以參考“

A Complete ActiveX Web Control Tutorial”例項 )。

    classid屬性在這裡是一個非常關鍵的屬性,IE正是通過他才能正確找到要呼叫的ActiveX的。每個ActiveX均有一個唯一的id來表示,這就是classid,在我們建立MFC ActiveX Control專案時Vs.net 2008就幫我們生成了這個id, 可以在程式的.idl檔案最下方找到這個ID值:

             

image

     一般不建議手動修改程式中的這個uuid值,因為在xxxxCtrl.cpp檔案中也用到了這個id值,只是表現形式不一樣罷了:

            image

      控制元件註冊成功後,這個classid及控制元件檔案位置等資訊均寫入登錄檔了,如下所示:

            image

      當然,如果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值,如下圖:

       image

 

     即IMPLEMENT_OLECREATE_EX的第二引數就表示當前外掛的ProgId,該值可以根據實際需要自行修改。實際上,在登錄檔中通過ProgId是可以找到對應的ClassId的,兩者是有關聯的:

        image

     那麼如何判斷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的方式則呼叫外掛介面失敗。