瀏覽器插件之ActiveX開發(四)

原文鏈接:http://www.cnblogs.com/qguohog/archive/2013/01/25/2876828.html

    簡單總結一下前幾篇文章的內容,《瀏覽器插件之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>
複製代碼

 

    2、使用Object標籤時如何判斷ActiveX是否已註冊

複製代碼
<script type="text/javascript">
    var objCard = document.getElementById("CardAccessor");

    if (objCard.object==null) {
        alert("CardAccessor插件未安裝!");
    }
    else{
        alert("已檢測到CardAccessor插件!");
    }
</script>
複製代碼

        另外也可以通過訪問ActiveX中的某個已知已定義的屬性來判斷插件是否已安裝,如果返回的屬性值爲undefined,則表示沒有檢測到插件。例如:

複製代碼
<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的方式則調用插件接口失敗。


=======================================================================
野文(Jasson Qian)
------------------------------------------------------
博客園:http://qguohog.cnblogs.com
CSDN:http://blog.csdn.net/sallay

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章