electron 使用 node-ffi 呼叫 C++ 動態連結庫(DLL)
一、為什麼需要使用DLL
- 需要使用系統 API 操作或擴充套件應用程式;
- 需要呼叫第三方的介面API,特別是與硬體裝置進行通訊,而這些介面 API 基本上都是通過 C++ 動態連結庫(DLL)實現的;
- 需要呼叫C++實現的一些複雜演算法等。
二、node-ffi 是什麼
node-ffi:Node.js Foreign Function Interface
node-ffi
is a Node.js addon for loading and calling dynamic libraries using pure JavaScript. It can be used to create bindings to native libraries without writing any C++ code. It also simplifies the augmentation of node.js with C code as it
takes care of handling the translation of types across JavaScript and C, which can add reams of boilerplate code to your otherwise simple C. See the example/factorial for an example of this use case.
WARNING: node-ffi
assumes you know what you're doing. You can pretty easily create situations where you will segfault the interpreter and unless you've got C debugger skills, you probably won't know what's going on.
上面是 node-ffi 的介紹,英語不好,就不翻譯了。
三、electron 使用 node-ffi
使用上一篇文章裡的專案,在 package.json 的 dependencies 節點上加上node-ffi 依賴:
"dependencies": { "electron": "^1.6.11", "ffi": "2.2.0" }
然後安裝缺失的 npm 包(參考之前的文章),注意,安裝 ffi npm 包之前需要安裝 python2.7,否則 ffi 會編譯總是失敗,導致安裝不成功,具體安裝參考:https://github.com/nodejs/node-gyp#installation。
安裝完成後,在 app.js 檔案第一行中新增如下程式碼:
const ffi = require('ffi')
然後執行程式,出現如下錯誤:
參考資料:https://github.com/electron/electron/blob/master/docs-translations/zh-CN/tutorial/using-native-node-modules.md,原來是需要把 ffi 重新編譯為適合 electron的模組。
開啟 nodejs 命令列視窗,先執行如下命令:
set python=python安裝路徑\python.exe
設定 python 的路徑,切換到專案目錄,然後執行如下命令:
"./node_modules/.bin/electron-rebuild" "./node_modules/ffi"
編譯完成後,執行程式,漂亮的介面終於出現了。
四、使用 ffi 呼叫 Widows API 解決一個小缺陷
上篇文章中的仿 QQ 登入介面還有一個小問題,就是滑鼠右鍵點選視窗的任意地方,都會彈出系統選單:
現在使用 ffi 呼叫 user32.dll 中的 GetSystemMenu 函式來解決這個問題,首先新建一個 user32.js 檔案,為了展示 ffi ,我多定義了幾個API函式:
const ffi = require('ffi') exports.User32 = ffi.Library('user32', { 'GetWindowLongPtrW': ['int', ['int', 'int']], 'SetWindowLongPtrW': ['int', ['int', 'int', 'long']], 'GetSystemMenu': ['int', ['int', 'bool']], 'DestroyWindow': ['bool', ['int']] });
修改 app.js 檔案,首先匯入 user32.js:
const user32 = require('./app/scripts/user32').User32
然後修改如下內容:
win.once('ready-to-show', () => { let hwnd = win.getNativeWindowHandle() //獲取視窗控制代碼。 user32.GetSystemMenu(hwnd.readUInt32LE(0), true); //禁用系統選單. win.show() })
再執行專案,系統選單就消失的無影無蹤了。
最後,所有程式碼都已經提交到了github:https://github.com/starts2000/ElectronQQLogin,歡迎獲取。