浏览器插件之ActiveX开发(二
瀏覽器插件之ActiveX開發(二)
???? 按照上文《瀏覽器插件之ActiveX開發(一)》的步驟,能開發一個基于MFC的簡單的ActiveX控件。不過在實際操作中還是會遇到一些問題。由于對COM編程了解得很少很少,有些問題我也沒有找到很好的解決方法。
?
?????一、ActiveX需要引用其他dll的問題
????? 我們的ActiveX需要對IC卡設備進行讀寫,所以需要調用設備自帶的接口。設備廠商提供了“mwhrf_bj.lib”、“mwhrf_bj.dll”和“mwrf32.h”等接口文件。將“mwhrf_bj.lib”和“mwrf32.h”添加到項目中,ActiveX的接口方法中就可以調用接口文件中的方法了。但是在編譯時會出現“Project:error PRJ0050:未能注冊輸出。請嘗試啟用“每個用戶的重定向”,或用提升權限從命令提示窗口中注冊該組件”或“Project : error PRJ0050: Failed to register output. Please ensure you have the appropriate permissions to modify the registry”的錯誤。
???? 實際上該錯誤不是出現在編輯階段,而是出現在注冊編譯后的ocx文件時。Vs.net 2008默認在編譯成功后會自動注冊編譯后的ocx文件。右擊項目名稱,選擇“Properties”,在彈出對話框的“Configurations Properties->Linker->General”中的Register Output就可以配置編譯后是否自動注冊ocx,如下圖所示:
???????
????? 之所以注冊ocx時出錯,是因為注冊時找不到被調用的“mwhrf_bj.dll”文件。將被調用的“mwhrf_bj.dll”文件放在ocx文件相同目錄下或者其他%PATH%路徑下(如Windows文件夾或System32文件夾等),則注冊ocx時不會報錯。在vs.net開發環境中可以直接將要被調用的外部dll文件copy到Debug或Release目錄下即可,也可以在PreBuild腳本里將外部dll文件COPY到編譯目標文件夾,如:
???????
?
???????注:可參考“http://www.cnblogs.com/lidabo/archive/2012/07/16/2593604.html”文章。
?
?????二、ActiveX的調試方法
??????? 在Vs.net 2008下可以對ActiveX按如下方式進行調試:
??????? 1、準備好Demo.html文件并寫好測試程序,該頁面中需通過<object />來引用需測試的ocx控件(關于如何在html頁面中調用控件在后續文章將專門提及)。
??????? 2、在vs.net 2008中右擊項目名稱,選擇“Properties”,在彈出框中的Debugging配置頁里配置好Command和CommandArgs參數:
????????????Command:??????? 本地IE瀏覽器的路徑,如“C:\Program Files\Internet Explorer\IEXPLORE.EXE”
????????????Command?Args: 已經創建好的用于測試ocx的html文件路徑(如上面提及的Demo.html文件路徑)
????????????
??????? 3、在程序中需調試的地方設置斷點。按F5運行后vs.net將自動啟動IE并打開對應的html測試文件,在斷點處會中斷運行進入調試狀態。
?
????? 三、ActiveX的接口實現out/ref參數及返回自定義結構體數據的問題
???? 有時候ActiveX的接口方法只返回一個數據并不能滿足我們的實際要求。例如通過ActiveX的getPersons()方法返回一堆的人員信息,那必定是一個列表或數組,而且每個Person還包含姓名、性別等各種信息,這個時候返回值就相當復雜了。
???? 為了簡單起見,還是已通過ActiveX進行讀卡號來舉例。一般情況下,只要該插件提供以下接口即可滿足需求:
BSTR ReadCardNo();???? 這樣在javascript中調用該ActiveX的ReadCardNo()方法即可返回一個包含卡號的字符串。
???? 但是,僅僅提供這個接口如何來識別讀卡過程中出現的異常呢?如果讀卡操作一切正常,返回一個卡號字符串當然沒有問題。但如果讀卡過程中出現諸如讀卡設備未正確連接、卡無法識別等情況,如果將這些異常信息反饋給調用者呢?
???? 1、首先我想到的是使用ref或out參數來解決,對應C++里是OUT/RETVAL之類的參數修飾符。
???? 在.idl中定義接口為:
??????[id(1), helpstring("方法ReadCardNo")] LONG GetSheetName([out]BSTR* cardNo);
???? 對應接口原型為:
??????LONG ReadCardNo( BSTR* cardNo );
???? 這樣的話通過LONG類型的返回值來識別返回狀態,例如可以約定:
?????????? 0-讀卡成功
?????????? 1-讀卡設備未連接
?????????? 2-未找到可識別的卡
?????????? ……
????? 如果返回值為0,表示讀卡成功,讀出的卡號已通過out類型的參數cardNo傳遞給調用者。
????? 但是,javascript等腳本語言并不支持out/ref等類型的參數,函數參數也無法傳址,所以這個方案無法解決我的實際問題。
?
????? 2、如果ActiveX的接口能返回一個自定義的結構體類型數據就能滿足我們的需求了。例如我們定義一個結構體:
????????? typedef struct
?????????? {
?????????????? LONG ResultStatus,????????????? // 返回狀態? 0-讀卡成功? 1-讀卡設備未連接 3-未找到可識別的卡
?????????????? BSTR CardNo?????????????????????? // 讀卡成功時,保存讀取的卡號
?????????? } AOPResult;
??????????對應接口如果可以按如下樣子來實現就可以解決我們的問題了:
????????? AOPResult ReadCardNo();
???????? 但是,在MFC ACtiveX的接口定義中中不能直接使用自定義的數據類型的,需要用VARIANT類型來進行轉換。下面幾篇參考文章均對此有所描述:
????????? a)?http://bbs.csdn.net/topics/320146859
????????? b)?http://bbs.csdn.net/topics/20064135
????????? c)?http://www.codeproject.com/Articles/916/Using-User-Defined-Types-in-COM-ATL
????????? d)?標準MFC WinSock ActiveX控件開發實例(II)高級篇
????????? 但實現起來也不是那么容易,鑒于時間問題及我們實際需求的不迫切性,我對此沒有做過多嘗試。如果有成型實例,望請賜教。
???????
????? 3、既然在Web應用場景下ActiveX的接口一般都是供js調用,那么我們可以返回一個json類型的數據即可,如“{ status:0, cardNo:234234344634 }”。這樣ActiveX接口仍然只需返回一個BSTR的參數,只是返回值的意義變了,不是簡單的卡號,而需要ActiveX的ReadCardNo接口在內部處理時需要將返回值封裝成一個json格式的字符串返回并交由調用方解析。不過,在封裝json字符串時需要對{、}、:等特殊字符進行相應處理。
?
????? 4、對于簡單的應用場景,我們也完全可以利用ActiveX的屬性來化解此類問題。例如我們在ActiveX中定義一個屬性CardNo,這樣的話提供的接口只用簡單的返回一個狀態即可:
?????????LONG ReadCardNo()
?????? 接口返回值仍然表示狀態,如0表示讀卡成功,1表示未找到讀卡設備等等。當返回0時,讀卡成功,對應的卡號從屬性CardNo中獲取即可。
?
?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
參考資料:
ActiveX Controls( MFC )
=======================================================================
野文(Jasson Qian)
------------------------------------------------------
博客園:http://qguohog.cnblogs.com
CSDN:http://blog.csdn.net/sallay
總結
以上是生活随笔為你收集整理的浏览器插件之ActiveX开发(二的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: com接口传入、传出字符串的说明和例程
- 下一篇: 来总结一下在VC中调用COM组件的方法