當前位置:
首頁 > 最新 > 自定義瀏覽器下JS直接進行DLL訪問實現

自定義瀏覽器下JS直接進行DLL訪問實現

編者按

3月2日,商業地產技術架構部主管楊宏俊主講分享了「JS直接進行DLL調用」技術,該技術主要應用於第三方銀行卡支付對接,印表機、錢箱、刷卡器等外設驅動控制方面。分享之餘,楊宏俊還積極撰文、精心整理代碼與大夥作進一步探討。

01

前言

越來越多的傳統CS架構項目進行了技術升級換代變為了BS架構,但是架構的升級並未屏蔽部分的原始系統資源、硬體的訪問需求(類似於MPOS、DPOS的印表機、錢箱、刷卡、銀行支付等設備對接,會員系統的制卡場景)。這類需求對於BS項目長期以來都沒有特別好的固定技術方案,這裡分享一個新的方法,提供一種可能性,也希望能推廣形成公司的統一模式和標準。

傳統的web下對於系統資源、硬體資源訪問各瀏覽器廠商爸爸支持的方案主要有:IE的ActiveX控制項(各大網銀的支付基本都在使用)、NPAPI(網景插件介面)、PPAPI(谷歌瀏覽器插件)。

但現實的情況是,IE日漸衰落退出主流瀏覽器市場,NPAPI則因為安全原因,在Chrome45、Firefox52的各自版本後都將不再被支持,而後續版本谷歌推出的PPAPI也基本被其他瀏覽器廠商華麗麗地無視了,而且開發的許可權並不完全滿足。技術產品的發展,反而讓JS和操作系統隔河相忘,棒打鴛鴦。

02

簡介

本次分享基於上述背景的情況下,嘗試了一種特殊簡單的解決方案,最終希望得到的結果是,在web項目中,JS可以自由的訪問任何Windows的DLL(動態鏈接庫,windows的程序片段),不需要任何非JS語言開發工作。希望讓JS和操作系統談一場沒有任何干擾的戀愛。當然這可能只是一場話劇,因為它只能在我們限定的舞台(自定義瀏覽器)上才能上演。

03

認識CEF3項目

CEF3項目,即Chromium Embedded Framework項目。首先來介紹下我們搭建一個自由戀愛舞台的基礎資源。CEF,Chrome的驗證工程(相當於Chrome的爸爸),開源,工程c++開發,但是提供了C++、.net、delphi、java、python的開發工程版本。上述所有語言都可以基於這個項目開發一個自定義瀏覽器。整個工程的源碼13個G可以自行編譯和修改。也是國內chrome內核瀏覽器的代碼來源,基本國內主流瀏覽器和app內置瀏覽器內核都來源於此。

優勢:完全開源。Chrome同內核同技術,運維團隊強大,提供方法進行BOM(瀏覽器對象模型,也就是瀏覽器的功能)能力的擴展,輕量簡潔,H5支持優秀,功能版本更新較快可以使用還未發布協議草案的一些能力,基於當前項目定製的瀏覽器,可以自行選擇多進程或者單進程模式降低系統開銷,整個程序為綠色版無壓縮100M左右算是相當輕量級的瀏覽器,也支持PPAPI插件。

不足:開源項目屏蔽了商業協議mp3、mp4、flash(需要自行開啟選項編譯)。

04

JS-DLL-Plugin技術方案詳解

這是本次分享的技術核心內容,前文內容也是為此做鋪墊,幫助大家更好地理解。

「技術難點」

傳統DLL調用分為靜態調用和動態調用,都需要將DLL的介面函數進行定義生命,再將DLL進行LoadLibrary載入到內存,然後根據定義函數查找對應句柄地址進行調用。要想實現JS直接訪問DLL,就存在需要平台開發語言能動態的進行DLL的介面函數進行定義,因為需要調用各種各樣不同的DLL,但是查了很多資料未找到能實現類似能力的技術方案。

在問題將進入死胡同的時候,我們請出了一位超級大神——朱總(編者按:朱浩輝),直接繞過這個坎,完全不定義DLL的函數,從更底層彙編層進行問題解決,DLL載入入內存後,直接使用彙編將函數的所有參數放入寄存器,在使用彙報直接對介面函數句柄進行調用,從而攻破了這個技術難點讓整個方案得以繼續。

「技術方案」

基於cef的delphi工程版,開發一個完整的自定義標準瀏覽器,提供了JS對DLL的直接訪問能力,整個技術方案鏈路為JS完整定義整個DLL的訪問過程,平台開發將定義進行解釋和執行,JS和平台交互為標準能力,交互使用JSON進行數據傳輸序列化。

最終前端開發人員只需要在前端項目中檢測下瀏覽器BOM也就是windows對象是否存在HDDLL對象即可,如果存在代表是定製瀏覽器且包含當前功能,然後根據DLL放給出的介面文檔,進行DLL的調用定義,如下:

DLL定義:

//驅動介面定義,請根據第三方dll介面文檔,按次擴展插件開發規範進行定義

var dll = {

dllName: "E:/SourceCode/Mpos/windows/trunk/gmctest/KeeperClient.dll", //mposdev.getLocalPath + "KeeperClient.dll", //dll絕對路徑,會按當前地址載入

dllType: "win32", //當前未使用,後續可擴展支持Active Comm模式DLL

procName: "MisPosInterface", //驅動介面函數名,根據文檔獲取

outType: "int", //驅動要調用介面函數名的返回值數據類型

params: [ //介面函數參數定義

{

order: 0, //參數順序,暫未使用

paramName: "instr", //參數名稱,如果不是返回參數可不賦值

type: "string", //參數數據類型,因為不同語言數據類型不同,所以限定4種數據類型:int、string、float、boolean

length: 255, //參數數據長度,入參可以不管,會自動取實際數據長度

value:"測試abc123", //參數值

out: false //標記是否為返回參數

},

{

order: 1,

paramName: "outstr",

type: "string",

length: this.outStruct.memSize(),

value: null,

out: true

}

]

};

調用過程 :

var instr = JSON.stringify(dll) || "";

var outStr;

if (window.DLL) {

outStr = window.DLL.call(instr);

}

返回結果處理:

var outObj = JSON.parse(outStr);

outObj.fnResult //DLL介面函數返回值,如果調用異常失敗返回-1

outObj.fnError //調用異常或者錯誤時返回的錯誤信息,正常調用返回空或者不返回

outObj.paramResult //調用成功後返回參數的存放對象,返回參數需要根據調用定義里的返回參數的名稱來取,以上述調用定義為例:

outObj.paramResult["outstr"] //取到定義返回參數的值

特殊情況下的DLL調用:

//根據第三方文檔,定義輸入對象結構體 --內存結束符不用考慮,結構體統一處理,只需要定義數據長度即可

inStruct: new Struct({

TransType: CharArray(2),

TransAmount: CharArray(12),

InstallmentTimes: CharArray(2),

... ...

CashierNum: CharArray(15),

LongQRPay: CharArray(37),

CouponNum: CharArray(37)

}),

//根據第三方文檔,定義輸出對象結構體

outStruct: new Struct({

TransType: CharArray(2),

RspCode: CharArray(2),

... ...

Sigfre: CharArray(100),

ESignData: CharArray(1000),

Remark: CharArray(1000)

}),

inStruct.getInstream() //對已賦值結構體,模擬內存存儲模式獲取對應內存流字元串

outStruct.memSize() //獲取整個結構體要佔用的內存大小

outStruct.readFromMem(outObj.paramResult["outstr"]) //將獲取到的內存流字元串格式為JS模擬結構體

outStruct.record.TransAmount.getReal() //反格式化後的結構體獲取各屬性的值

05

基於JS-DLL-Plugin的應用案例

基於MPOS產品目前是一個運行在定製瀏覽器下的BS項目,但是因為存在每個項目都需要進行銀行卡付款對接,還需要使用瀏覽器平台開發語言開發每個項目DLL調用對接驅動,但是開發人員結構逐漸變動,delphi開發人員逐漸稀少,所以進行攻關通過此項技術屏蔽delphi開發工作量。這也是本次分享功能的初衷。

基於此技術基礎在MPOS項目上開發了一個純JS前端(在MPOS的前端框架Sencha Touch基礎上)的支付插件。動態的根據後台配置動態載入JS然後調用第三方DLL進行銀行卡支付。

上述一個簡單的JS組件項目替代原有的一個CCPAY的Delphi開發DLL來解決每個項目的銀行卡付款驅動適配。

06

延伸思考和擴展

在分享過程中,有同事提出了這個功能的核心其實在無聲明的DLL訪問,和實現好了JS和原生程序代碼的交互模型,那麼單獨把這一塊拿出來做一個輕量級的本地服務程序,通過其他協議類似http進行交互,這也是一個很好的屏蔽定製伺服器前提的方案,這是一個非常好的想法。

基於公司BS項目逐漸增多,而ERP項目其實並非面向C端的項目那樣環境無法控制多樣,我們使用場景基本固定,可以考慮推進一個標準定製瀏覽器版本,賦予我們BS版ERP更多可能性。

目前比較火的windows應用程序開發方案Elctron其實和當前我們定製瀏覽器的方案如出一則,我們也應該為當前模式定製瀏覽器+前端項目的windows應用開發形成標準方案和相關協議。

文/楊宏俊

歡迎各位留言交流

海鼎Fun

有料,有愛,有夢想

空·


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 海鼎Fun 的精彩文章:

關係型資料庫版本控制框架——Rumba RdbVersion

TAG:海鼎Fun |