electron通过edge-js调用TSCLIB.dll 打印卡白屏或退出的解决方案
軟件版本:
閱讀坑記需謹慎,版本要看仔細。
"node":"v14.16.0", "electron": "^13.0.0", //當然本文問題和vue 沒毛線關系 "vue": "^2.6.14", //遇到坑的主角是這個 "electron-edge-js": "^14.16.1", // 打包用到是該工具是 electron-builder,我想我遇到的坑應該和打包工具沒有啥關系,但還是列出來,便于交流幾年前,直接使用IE 調用相關的插件執行打印,可,IE在win11已經找不到入口了,需要單獨設置edge瀏覽器,且使用的人,經常“不小心”重置網絡的安全,導致檢查需要遠程幫他們開啟,故此需要個桌面軟件,一次解決,永不煩人。
遇到的問題
經過查看tsc打印機官網,找到了SDK下載到入口tsc官方SDK下載地址(有些人很賤,從官網下載了資料,上傳到其他收費平臺上去“賺錢”);找到了nodejs相關的樣例。
nodejs的樣例,需要用到edge-js,但經過多日的入坑,找到的資料是使用:electron-edge-js;
用electron-edge-js參考官方的edge-js樣例,確實可以打印,但是:
如果循環打印大量數據,會卡死。
卡死的調試場景
- 渲染進程的打印頁面(組件)循環 執行(調用)tsclibnet.dll打印方法;結果:頁面卡白了。
- 我把對tsclibnet.dll是調用、循環打印,新開啟一個窗口來執行;結果,該新開的窗口,如果打印數量超過3條同樣還是卡死了。
- 放在“主進程”來執行:通過渲染進程(頁面)向主進程發送數據信息,主進程執行數據的循環實施打印,結果還是卡死。
以上是我用electron-edge-js調用tsclibnet.dll遇到的問題,我不確定是不是因為我執行打印代碼寫的太垃圾,而導致卡死,或者我對electron了解太少,垃圾代碼貼出,便于交流:
(此代碼不要直接全部復制粘貼使用,我有刪改,不保證可執行)
以上就是我執行打印,頁面卡死的代碼。
解決方法嘗試
思來想去,翻來覆去搜索資料,開啟系統任務管理器,打印的時候CPU占用突增,是不是進程資源占用不符合系統規則,系統弄死該進程呢?如何重新開啟進程?略熟悉的語言也只有js?
nodejs 好像可以開啟臨時web服務,我把數據發送到另外一個軟件上執行,對吧。且還可以打包exe可執行文件->應該可以完美解決打印:
對,可行,沒有卡死,打印流程完美按照我的想法工作;(在本地 執行 node server.js 的時候服務完全正常啟動,打印正常完美執行;)
打印執行打循環體,還是上述代碼;web 服務我用node的框架 express(完全不懂,參照網絡樣例使用)
package.json 文件
{"name": "print_exe","version": "0.0.1","description": "執行打印服務","main": "server.js","author": {"name": "programmer"},"dependencies": {// 重新自己安裝,根據自己的版本來"edge-js": "^18.4.0","express": "^4.18.1"},"pkg": {"scripts": "build/**/*.js","assets": "views/**/*","targets": ["node14-win-x64"],"outputPath": "dist"} }server.js
// 'use strict'; const fs = require('fs'); const crypto = require('crypto'); const path = require ('path'); var edge = require('edge-js'); var express = require('express'); var bodyParser = require('body-parser') var app = express();var urlencodedParser = bodyParser.urlencoded({ extended: false }); var urlencodedJsonParser = bodyParser.json(); app.use(bodyParser.urlencoded({extended: true })); app.use(express.static('./'));app.listen(5000, function () {console.log("Server Start!!");log("Server Start!!"); }) // 接受打印數據方法入口 app.post('/printing', urlencodedJsonParser, (req, res) =>{// 數據合理性驗證// 節約頁面,省去我的垃圾代碼res.json({code:0,message:'打印執行中請等待',data:null});printfile(req.body); });var openport; var setup; var about; var sendcommand; var clearbuffer; var printerfont; var barcode; var printlabel; var closeport; var sendcommand_utf8; var sendcommand_binary; var windowsfont; try {openport = edge.func({assemblyFile: 'tsclibnet.dll',typeName: 'TSCSDK.node_driver',methodName: 'openport'});setup = edge.func({assemblyFile: 'tsclibnet.dll',typeName: 'TSCSDK.node_driver',methodName: 'setup'});about = edge.func({assemblyFile: 'tsclibnet.dll',typeName: 'TSCSDK.node_driver',methodName: 'about'});sendcommand = edge.func({assemblyFile: 'tsclibnet.dll',typeName: 'TSCSDK.node_driver',methodName: 'sendcommand'});clearbuffer = edge.func({assemblyFile: 'tsclibnet.dll',typeName: 'TSCSDK.node_driver',methodName: 'clearbuffer'});printerfont = edge.func({assemblyFile: 'tsclibnet.dll',typeName: 'TSCSDK.node_driver',methodName: 'printerfont'});barcode = edge.func({assemblyFile: 'tsclibnet.dll',typeName: 'TSCSDK.node_driver',methodName: 'barcode'});printlabel = edge.func({assemblyFile: 'tsclibnet.dll',typeName: 'TSCSDK.node_driver',methodName: 'printlabel'});closeport = edge.func({assemblyFile: 'tsclibnet.dll',typeName: 'TSCSDK.node_driver',methodName: 'closeport'});sendcommand_utf8 = edge.func({assemblyFile: 'tsclibnet.dll',typeName: 'TSCSDK.node_driver',methodName: 'sendcommand_utf8'});sendcommand_binary = edge.func({assemblyFile: 'tsclibnet.dll',typeName: 'TSCSDK.node_driver',methodName: 'sendcommand_binary'});windowsfont = edge.func({assemblyFile: 'tsclibnet.dll',typeName: 'TSCSDK.node_driver',methodName: 'windowsfont'}); }catch (error) {log(error,'error'); } // 日志處理方法 function log(logContent,type='info') {//省去垃圾代碼, }/*** 執行打印* @param {Object} printData 打印數據*/ function printfile(printData){try {if (! printData.hasOwnProperty('print_name')) {throw "缺少打印機";}if (! printData.hasOwnProperty('printer_config')) {throw "缺少打印紙配置";}if (! printData.hasOwnProperty('print_data')) {throw "缺少打印數據";}const {print_name,printer_config,print_data} = printData;let {width,height,speed,consistence,sensor,spacing,offsetDistance,column} = printer_config;// 傳入的單位為cm 此處是單位處理width = width * 10;height = height * 10;spacing = spacing * 10;// 總寬 mmlet totalWidth = width * column + spacing * (column-1);// 打印紙配置數據const conf = {width: Math.ceil(totalWidth).toString(),//aheight: Math.ceil(height).toString(),//bspeed: speed.toString(),//cdensity: consistence.toString(),//dsensor: sensor.toString(),//evertical: spacing.toString(),//f verticaloffset: offsetDistance.toString(),//g};for (let i = 0; i < print_data.length; i++) {openport(print_name, true);setup(conf,true);clearbuffer('', true);sendcommand('DIRECTION 1');let reverseArr = [];print_data[i].forEach(ele => {log(ele.printVal);if (ele.type == 'text') {windowsfont(ele.printVal, true);} else if (ele.type == 'qrcode'){sendcommand(ele.printVal, true);} else if (ele.type == 'barcode'){barcode(ele.printVal, true);} else if (ele.type == 'reverse'){if (Array.isArray(ele.printVal) && ele.printVal.length > 0) {reverseArr.push.apply(reverseArr, ele.printVal);}}});if (reverseArr.length > 0) {for (let ri = 0; ri < reverseArr.length; ri++) {sendcommand(reverseArr[ri], true);}}let label_variable = { quantity: '1', copy: '1' };printlabel(label_variable, true);// 關閉打印機closeport('', true);log('打印關閉');}} catch (error) {// console.log(error);log(error,'error');} }但是!但是!打包后的exe文件的啟動錯誤問題讓我無法解決:
Error: Module did not self-register: '\\?\E:\a\node_modules\edge-js\lib\native\win32\x64\14.19.3\edge_nativeclr.node'.
打包工具是 pkg
網絡上查找了原因,說需要重新針對自己的node版本打包動態庫!不想再去研究了,項目需要使用(向老板匯報)。
最終解決方法
之前簡單了解過Python 且也嘗試過Python 調用該庫,(很早之前記錄的踩坑記 Electron-vue開發桌面應用調用TSCLIB.dll)
只是之前 通過發送命令調用Python打包的 exe 程序;這次用Python的exe啟動了一個web服務,這樣用http方式發送打印數據到該服務器即可。
打印數據結構和循環體的邏輯,和最早代碼的邏輯一致:
特別注意:Python 的 TSCLIB.dll動態庫,和nodejs的不一致,去前文給到的官方地址下載Python 的例子,另外Python樣例的動態庫參數數據類型 沒有描述,參照 java 樣例的代碼可以知道參數類型。
我遇到的問題,都寫在代碼注釋中:(我的TSCLIB.dll庫和.py在同級)
# coding=utf-8 from flask import Flask,request,json,jsonify # import ctypes from ctypes import * import logging import os import datetime from time import strftime # import chardet app = Flask(__name__)''' 是否是開發 True-開發 False-生產 ''' # develop = False # 應用執行目錄,該應用存在于調用應用下的地址 appExePath = ""@app.route('/') def hello_world():# 用于應用檢測是否可以正常訪問return 'Hello World'@app.route('/printing',methods=['POST']) def exeprint():app.logger.info('info log')p_ddata = request.get_data()data = json.loads(p_ddata)# 的數據格式完全和最開始體到代碼 data 數據格式一致print_data = data['print_data']# 打印機名printer_name = data['print_name']# 打印機相關配置printer_config = data['printer_config']column = printer_config['column']width = printer_config['width'] * 10height = printer_config['height'] * 10vertical = printer_config['spacing'] * 10totalWidth = width * column + vertical * (column-1)speed = printer_config['speed']density = printer_config['consistence']sensor = printer_config['sensor']offset = printer_config['offsetDistance']# print(totalWidth)try:path = os.getcwd()dllPath = path+"\\TSCLIB.dll"tsclibrary = CDLL(dllPath)# 如果用了 tsclibrary.setup() 來設置,好像會出錯,不執行,我不清楚是否是傳入參數的錯誤,所以我用 tsclibrary.sendcommandW() 來執行我需要的設置命令# tsclibrary.setup(str(totalWidth),str(height),str(speed),str(density),str(sensor),str(spacing),str(offset))# setup (String width,String height,String speed,String density,String sensor,String vertical,String offset); # java 的# tsclibrary.sendcommandW("DIRECTION 1")for item in print_data:tsclibrary.openportW(printer_name)tsclibrary.sendcommandW("DIRECTION 1")tsclibrary.sendcommandW("SIZE "+str(totalWidth)+" mm, "+str(height)+" mm")tsclibrary.sendcommandW("GAP "+str(vertical)+" mm, 0 mm")tsclibrary.sendcommandW("SPEED "+str(speed))tsclibrary.sendcommandW("DENSITY "+str(density))# tsclibrary.setup(str(round(totalWidth)),str(round(height)),str(round(speed)),str(round(density)),str(round(sensor)),str(round(vertical)),str(round(offset)))tsclibrary.clearbuffer()reverseList = []for pd in item:if pd['type'] == 'text':x = pd['printVal']['x']y = pd['printVal']['y']fontheight = pd['printVal']['fontheight']rotation = pd['printVal']['rotation']fontstyle = pd['printVal']['fontstyle']fontunderline = pd['printVal']['fontunderline']szFaceName = pd['printVal']['szFaceName']szFaceName = 'simhei'content = pd['printVal']['content']# 官方給的 tsclibrary.windowsfontW() 好像調用無效(打印數據好像沒傳到打印機) # tsclibrary.windowsfontW 和 tsclibrary.windowsfont 有什么區別嗎?# 還是官方給到例子太老了??# tsclibrary.windowsfontW(x,y,fontheight,rotation, fontstyle, fontunderline, szFaceName,content)#無法打印# tsclibrary.windowsfont(x,y,fontheight,rotation, fontstyle, fontunderline, szFaceName,content)#打印亂碼tsclibrary.windowsfontUnicode( x, y, fontheight, rotation, fontstyle, fontunderline, szFaceName, content)#字體為默認宋elif pd['type'] == 'qrcode':tsclibrary.sendcommandW(pd['printVal'])elif pd['type'] == 'reverse':reverseList.extend(pd['printVal'])for revCmd in reverseList:tsclibrary.sendcommandW(revCmd)# tsclibrary.sendcommand(revCmd)# tsclibrary.printlabelW("1","1")tsclibrary.printlabel("1","1")tsclibrary.closeport()except OSError as err:app.logger.warning(err)print(err)return jsonify(status="success")if __name__ == '__main__':# 日志配置 不需要的話此處可以刪now=datetime.datetime.now()logdate = now.strftime("%Y-%m-%d")handler = logging.FileHandler(logdate+'.log', encoding='UTF-8')handler.setLevel(logging.DEBUG)logging_format = logging.Formatter('%(asctime)s - %(levelname)s - %(filename)s - %(funcName)s - %(lineno)s - %(message)s')handler.setFormatter(logging_format)app.logger.addHandler(handler)# 日志配置endapp.run()Python 打印服務程序 全部代碼。
打包 exe 命令pyinstaller -F -w -i my.ico PrintServer.py 參考地址
應用程序啟動打印服務(python 打包的exe)
打包后的EXE 和 TSCLIB.dll 庫都和應用打包后的啟動exe位于同級目錄(如果要放在子目錄或者其他目錄 Python 動態庫地址,需要再處理,否則electon 無法啟動打印服務)
我的此段代碼是位于electron主js文件的最后。
try {// 啟動打印服務if (是生產) {//注意每個人的端口號可能不一樣child_process.exec('netstat -ano|findstr "5000"',(err, stdout, stderr)=>{if (stdout === "") {child_process.exec(`${homeDir}\\PrintServer.exe`,(err, stdout, stderr)=>{logger.info(`命令執行err:${err}`);logger.info(`命令執行stdout:${stdout}`);logger.info(`命令執行stderr:${stderr}`);});}else{logger.info('5000 端口被占用,或打印服務已啟動');}})}// 如果是開發,手動啟動打印服務 } catch (e) {logger.info(`命令執行異常:${e}`); }后記
記錄我的坑,便于后來者。希望我遇到的問題您能避免,且把您的解決方案留言告訴我們有共同問題的人。
總結
以上是生活随笔為你收集整理的electron通过edge-js调用TSCLIB.dll 打印卡白屏或退出的解决方案的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用计算机弹出娃娃脸,RME babyfa
- 下一篇: 《Android 应用案例开发大全(第3