在C/S開發主導的時代,delphi無疑是windows開發的佼佼者,號稱 vb killer,隨着 java 和 C#的崛起,互聯網開發時代來到,delphi也就失去了往日的光環,雖然現在絕大部分項目工作都是java web項目,但眾所周知,web應用,要跟硬件打交道,特別是在瀏覽器中,單純的jsp或者html、js,都無法實現,由於企業應用開發少不了要與硬件對接,如考勤機(人臉識別或指紋機)、門禁機、PDA(盤點機)等等,要實現在瀏覽器中對接硬件,其中一個可行方案就是開發IE瀏覽器下的OCX插件,OCX的本質就是一個C/S程序,可以訪問瀏覽器所在電腦的資源,最常見的就是dll,通過dll操作與電腦相連的硬件。因為delphi太久沒用,而ocx插件的開發也不是經常需要,導致每次開發都要翻看 以前的項目或資料重溫技術實現,最近又有一個項目,即使用便攜式指紋機實現硬件控制集團查看薪金權限,薪資管理員除了有系統功能操作權限外,還需要到人事部登記指紋,領取指紋機,在操作工資相關功能前,進行指紋認證,認證通過才能正常操作系統,趁着這次項目,把ocx開發過程記錄下來,以備以后的不時之需,也供其他同行參考。
閑話少說,直入正題,本文提及的項目,使用delphi 7,下面從新建一個ocx項目開始,一步一步指引如何用delph 7開發一個可以在 IE 上運行的OCX插件;
一、插件ACTIVEX工程
1、啟動Delphi,點擊菜單 File->New->Other:
2、選擇【ActiveX】標簽頁,選中Active Form圖標:
注:本案例中的OCX插件有用戶交互界面,所以使用 ActiveX Form。
3、為ActiveX項目和窗體對象命名:
由上圖可見,只需修改ActiveX窗體名稱、窗體實現代碼文件名、項目名即可,其他選項默認。
點擊【ok】按鈕完成項目創建,完成創建后的界面如下圖:
4、保存項目
點擊菜單 File->Save All,在彈出的保存框,選擇一個保存的目錄,然后一直點擊【保存】即可:
至此已完成一個ActiveX項目的創建,可以點擊菜單 View->Units瀏覽delphi創建的相關代碼文件:
上面三個文件是delphi自動產生的,其概要作用是:
FingerEnrollFormImpl:Ocx的實現類,編寫代碼基本都在這個文件中進行;
OfficeOcx:項目組織文件,一般不需要手工修改,由delphi自動維護;
OfficeOcx_TLB:OCX類庫代碼文件,一般也不需要手工修改;
二、設計OCX接口方法
應用程序(本例即瀏覽器中的js代碼)通過OCX提供的接口與OCX進行交互,Delphi會自動為OCX插件創建接口,我們只需跟進實際業務需要,為OCX接口增加相應的方法即可,如本案例需要添加5個接口方法:
InitDevice:鏈接指紋機;
SetUser:設置當前登記指紋的用戶資料;
GetResult:獲取指紋登記結果,0 失敗,1成功;
GetFinger1:獲取已登記的第一枚指紋數據;(每個用戶登記兩枚指紋,此款指紋機可以將采集的指紋信息轉換成字符串,以便存儲在數據庫中)
GetFinger2:獲取已登記的第二枚指紋數據;
下面介紹如何添加接口;
1、點擊菜單 View->Type Libraly:
注:Type Libraly 是Delphi中一個很重要的工具,尤其是開發類庫這一類的項目,必不可少。
2、在彈出的對話框中,右鍵左邊目錄樹中的,然后選擇 New->Method:
3、為新的方法命名為:InitDevice,然后為方法添加參數:
4、完成以上操作后,點擊菜單欄的刷新圖標:
刷新后可查看FingerEnrollFormImpl代碼中是否已包含此方法:
注:如找不到FingerEnrollFormImpl文件,可以點擊菜單 View->Units進行選擇並打開;
5、重復2-4步驟添加其他方法,下面只列出SetUser方法截圖說明,其他方法的創建類似,記得每個方法改名和添加完參數后,要點擊刷新圖標:
5個方法創建后顯示如下:
三、為接口方法添加代碼
這一部分是常規的Delphi開發,跟OCX插件開發技術本身並沒有直接關系,所以如果使用Delphi開發OCX插件,需要有一定的Delphi開發基礎,本案例並不會細談如何使用delphi進行軟件開發,接口方法都是根據實際業務需要進行代碼開的,這里只展示OCX窗體界面最終的效果:
窗體上有一個特殊的控件:,這個控件在安裝了廠家提供的指紋機驅動程序后,可以導入到Delphi中進行使用,所以非常方便,下面順帶介紹一下如何導入操作系統中已安裝的控件:
點擊菜單 Component->Import ActiveX Control...:
在彈出的對話框中:
點擊【Install】后,可以在【ActiveX】中看到這個控件:
已安裝的第三方控件,可以像其他常規控件一下,拖拽到窗體上進行開發,非常方便!
四、編譯OCX插件
編譯之后,在項目代碼保存路徑下可以看到已生成OCX插件:
把這個OCX文件拷貝到web項目下,就可以發布了。
五、發布並訪問OCX插件:
有了以上的OCX文件,就可以將它拷貝到web項目下,在頁面中引入並使用它;
本案例為java web項目,服務器環境是tomcat 6和jdk 1.6;
1、將 FtnFingerEnrollForm.ocx 文件拷貝到web項目某目錄下,如:
注:WebRoot 為web 項目代碼根目錄;
2、新建一個jsp文件 ocxTest.jsp:
注:jsp文件的存放目錄沒有特別要求,只要tomcat啟動后,能通過IE瀏覽器訪問到即可;
jsp文件代碼如下:
<%@page language="java" contentType="text/html;charset=UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path; %> <!DOCTYPE html> <html> <head> <title>OCX插件測試</title> <script type="text/javascript"> </script> </head> <body> <object id="fingerEnroll" classid="clsid:061D3A76-B267-465A-9529-F438AADD90B9" codebase="<%=basePath%>/frame/ActiveX/FtnFingerEnrollForm.ocx#version=1,0,0,0" width="606" height="271" > </object> </body> </html>
object標簽的 classid 值來自delphi項目的 FtnFingerEnrollForm_TLB.pas:
codebase屬性值為 ocx 文件在 web 項目中的 url,#version=1,0,0,0 為 ocx 控件的版本號,可以在delphi中進行查看:
點擊菜單 Project->Options...:
3、啟動tomcat,在IE中輸入jsp文件的url:
可見OCX插件被成功加載了;
在IE中加載ActiveX插件,需要做一系列的配置,如果發布到外網使用,可能還需要證書和簽名,由於平常的項目都是企業內部的應用系統,所以一般將IE安全級別降低,並將服務器IP設置為信任站點,具體的配置可以百度一下,網上有很多相關資料。
六、調用OCX接口方法
接下來演示如何在js中調用OCX接口方法,這點很重要,如果js能調用OCX接口方法,就意味着可以在瀏覽器中操作電腦上的所有資源,這在純瀏覽器環境中是做不到的。
1、修改OCX代碼
在修改OCX代碼之前,需要修改OCX項目的一些屬性,由於HTML頁面裝載OCX插件時需要指定文件版本號,瀏覽器第一次加載之后,就算OCX代碼被修改了,但是版本號沒有改,瀏覽器是不會加載新的OCX插件的。
在Delphi中打開OCX項目,點擊菜單 Project->Options...:
參照以上紅框的選項進行設置,點擊【OK】按鈕,以后修改代碼后,點擊 Project->Build FtnFingerEnrollForm時,Delphi會自動為版本號加1,可以右鍵生成的 FtnFingerEnrollForm.ocx文件進行查看:
在Delphi中修改 GetResult 方法,簡單的返回一個數值10,返回到jsp的js腳本調用中,如果js能正確顯示該數值,證明接口調用成功。
下面是 GetResult 方法代碼:
function TFingerEnrollForm.GetResult: SYSINT; begin Result:= 10; end;
2、重新構建OCX項目,點擊菜單 Project->Build FtnFingerEnrollForm,將新生成的 FtnFingerEnrollForm.ocx 重新拷到web項目發布目錄下,覆蓋原來的文件;
3、修改jsp文件,增加一個按鈕,點擊調用 GetResult 方法,將該方法返回的值 alert 出來:
<%@page language="java" contentType="text/html;charset=UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path; %> <!DOCTYPE html> <html> <head> <title>OCX插件測試</title> <script type="text/javascript"> function testGetResult() { var ocx = document.getElementById("fingerEnroll"); if (ocx) { var i = ocx.GetResult(); alert('GetResult返回的值為:' + i); } else { alert("OCX控件裝載失敗!"); } } </script> </head> <body> <object id="fingerEnroll" classid="clsid:061D3A76-B267-465A-9529-F438AADD90B9" codebase="<%=basePath%>/frame/ActiveX/FtnFingerEnrollForm.ocx#version=1,0,0,4" width="606" height="271" ></object> <br/> <input type="button" value="test GetResult" onclick="testGetResult();"/> </body> </html>
注意 version=1,0,0,4要跟OCX文件的版本號一致;
4、在IE瀏覽器中驗證結果:
七、OCX控件最終效果測試
jsp代碼:
<%@page language="java" contentType="text/html;charset=UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path; %> <!DOCTYPE html> <html> <head> <title>OCX插件測試</title> <script type="text/javascript"> function getOcx() { return document.getElementById("fingerEnroll"); } function initDevice() { var ocx = getOcx(); var i = ocx.InitDevice(); } function setUser() { var ocx = getOcx(); ocx.SetUser(document.getElementById("userCode").value, document.getElementById("userName").value, document.getElementById("deptName").value, document.getElementById("compName").value); } function getFinger() { var ocx = getOcx(); document.getElementById("finger1").value = ocx.getFinger1(); document.getElementById("finger2").value = ocx.getFinger2(); } </script> </head> <body> <input type="button" value="連接設備" onclick="initDevice();"/> <br/> <br/> 工號:<input type="text" value="TX8888" id="userCode"/> 姓名:<input type="text" value="張三" id="userName"/> 部門:<input type="text" value="人事部" id="deptName"/> 公司:<input type="text" value="DMP" id="compName"/> <input type="button" value="寫入用戶信息" onclick="setUser();"/> <br/> <br/> <object id="fingerEnroll" classid="clsid:061D3A76-B267-465A-9529-F438AADD90B9" codebase="<%=basePath%>/frame/ActiveX/FtnFingerEnrollForm.ocx#version=1,0,0,19" width="650" height="271" ></object> <br/> <br/> <br/> <input type="button" value="讀取指紋" onclick="getFinger();"/> <br/> <br/> 指紋1: <br/> <textarea rows="3" cols="100" id="finger1"></textarea> <br/> <br/> 指紋2: <br/> <textarea rows="3" cols="100" id="finger2"></textarea> </body> </html>