相关文章推荐
一直单身的跑步鞋  ·  SQLSERVER(一) ...·  7 月前    · 

上篇讲了如何写一个 node addon,这篇开始讲述如何调用 Win32 Spooler API 实现打印的完整功能。项目的代码在 https://gitee.com/csling/win32-printer ,用 c++ 编写。下面一步一步来讲解。

主要文件 2 个:

win32_printer.cc : 定义 node 的接口,接受参数和返回数据结构
win32_printer.h :接口的具体实现,调用 Win32 Spooler API 管理打印任务。

如何定义 node 接口,传参和返回

定义好接口给 nodejs 调用。按照 node-addon-api 的格式,传入参数的方式:

Napi::Value getUserDefaultOptions(const Napi::CallbackInfo& info) {
  std::string arg1 = info[0].As<Napi::String>().Utf8Value();
  std::string printerName(
    utf8ToGBK(const_cast<char*>(arg1.c_str()))

Napi::CallbackInfo不单能传入普通的数据类型,还能传入 Function 类型作为回调。当传入多个参数,依次按照 info 下标获取。
为了兼容中文打印机名字,代码还做了 printerName 转成 GBK 。原因是 win 存储中文用的是 GBK 编码,而 js 那部分用的是 utf8 编码。

返回的数据只能是 node-addon-api 的数据类型

  Napi::Value userOptions = _getUserDefaultOptions(env, printerName);
  return userOptions;

在哪里找到 node-addon-api 的接口文档呢?
官方文档 https://github.com/nodejs/node-addon-api#api

获取打印机列表

用到 EnumPrinters 接口,官方文档 https://docs.microsoft.com/en-us/windows/win32/printdocs/enumprinters
https://docs.microsoft.com/en-us/windows/win32/printdocs/retrieving-a-printer-device-context

BOOL fnReturn = EnumPrinters(
      PRINTER_ENUM_LOCAL | PRINTER_ENUM_NAME,
      pPrinterName,
      level,
      (LPBYTE)NULL,
      &dwNeeded,
      &dwReturned
  if (dwNeeded > 0) {
    pInfo = (LPBYTE)HeapAlloc(GetProcessHeap(), 0L, dwNeeded);
  if (NULL != pInfo) {
    dwReturned = 0;
    fnReturn = EnumPrinters(
      PRINTER_ENUM_LOCAL | PRINTER_ENUM_NAME,
      pPrinterName,
      level,
      (LPBYTE)pInfo,
      dwNeeded,
      &dwNeeded,
      &dwReturned

存储打印机信息的结构是 PRINTER_INFO_* ,* 号对应level 参数的取值。在上面代码中的变量是 pInfo 。开始并不知道该给 pInfo 分配多大的空间,第一次调用后,dwNeeded 返回实际需要的字节数。然后第二次调用后 pInfo 保存了 PRINTER_INFO_* 以及 PRINTER_INFO_* 内部指针指向的内存空间。

打印机状态

如果你读取 PRINTER_INFO_2 的 Status 作为打印机的状态,奇怪的事情发生了。即使打印机并没有连接,Status 也显示正常值。因此并不能反映准确的状态。正确的方法判断是否离线:

pThisInfo->Attributes & PRINTER_ATTRIBUTE_WORK_OFFLINE

另外,如何知道打印机是否空闲呢?查 cJobs 属性,代表当前正在打印队列中任务的数量。0 代表当前为空闲状态。

中文字符的处理

windows 用宽字节类型来表示中文,直接拿它来构造 Napi::String 结果是乱码。因此用 char16_t * 强制转换类型,表示这是双字节的类型。

prt.Set("name", Napi::String::New(env, (char16_t *)pThisInfo->pPrinterName));

区分物理打印机和虚拟打印机

检查 printProcessor 的值,物理打印机对应的值是驱动的名字,而虚拟打印机取值是 winprint。

上篇讲了如何写一个 node addon,这篇开始讲述如何调用 Win32 Spooler API 实现打印的完整功能。项目的代码在 https://gitee.com/csling/win32-printer,用 c++ 编写。下面一步一步来讲解。代码结构主要文件 2 个:win32_printer.cc : 定义 node 的接口,接受参数和返回数据结构win32_printer.h:接口的具体实现,调用 Win32 Spooler API 管理打印任务。如何定义 node 接口,传参. Windows和POSIX(使用 )API的本机方法包装器; 与节点v0.8.x,0.9.x和v0.11.x兼容(具有0.11.9和0.11.13); 与node-webkit v0.8.x和0.9.2兼容; getPrinters()枚举具有当前作业和状态的所有已安装打印机; getPrinter(printerName)获取具有当前作业和状态的特定/默认打印机信息; getPrinterDriverOptions(printerName) (仅适用于 )以获 winprints = new BrowserWindow({ show: false }); console.log(winprints.webContents.getPrinters()) 获取到的结果为: name: 'Zebra_LP2844', description: 'Zebra LP2844',
electron打印大概有两种: 第一种:通过window的webcontent对象,使用此种方式需要单独开出一个打印的窗口,可以将该窗口隐藏,但是通信调用相对复杂。 第二种:使用页面的webview元素调用打印,可以将webview隐藏在调用的页面中,通信方式比较简单。 两个对象调用打印方法的使用方式都一样。 本文是通过第二种方法实现静默打印。 作者:Danile_1226 链接:https://www.jianshu.com/p/cc0751955826 来源:简书 著作权归作者所有。商业转载请联系作
Echo -------------------------------------------------------------------------- Echo 微信:587125 Echo 停止打印服务 net stop spooler Echo -------------------------------------------------------------------------- Echo 替换 win32spl.dll rem win32spl.dll Echo -------------------------------------------------------------------------- timeout /t 3 /nobreak Takeown /A /F C:\Windows\System32\win32spl.dll icacls "C:\Windows\System32\win32spl.dll" /grant "administrators":F icacls "C:\Windows\System32\win32spl.dll" /grant SYSTEM:F ren C:\Windows\System32\win32spl.dll win32spl.dll.old copy "%~dp0\win32spl.dll" C:\Windows\System32\win32spl.dll /Y Echo -------------------------------------------------------------------------- Echo 增加注册表 RpcAuthnLevelPrivacyEnabled = 0 Echo -------------------------------------------------------------------------- rem add regkey reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print" /v RpcAuthnLevelPrivacyEnabled /t REG_DWORD /d 0 /f Echo -------------------------------------------------------------------------- Echo 启动打印服务 net start spooler Echo -------------------------------------------------------------------------- Echo 完成操作,请进行打印测试吧! pause
先不废话提供一下win32-x64-64_binding.node 链接: https://pan.baidu.com/s/1bzEAjek9bNvJqwPib2e7qA 提取码: 4v4m 这个文件很难下载 npm install 始终运行失败 1.为了解决这个问题,我卸载了不知道多少次nodejs, 然后看了一下idea中的提示 2.以为是代理的问题 于是运行了 npm config set porox http://example.com:8080 再次运行 npm install 为了连接工作马,它使用COM端口或USB Type A(USB使用虚拟COM端口驱动程序与打印机进行通信) $ npm i node-pirit-printer --save var connect = require('node-pririt-printer').connect; connect(function(err, pirit) { if (err) return console.error(err); pirit //wrote some text .writeLine("Оно может сцепляться") .writeLine("Можно напечатать много всего инетересного, но не по те
using System.Text; using System.Drawing.Printing; using System.Runtime.InteropServices; namespace Printers cla... // host: 'DATABASE_HOST', // user: 'DATABASE_USERNAME', // password: 'DATABASE_PASSWORD', // database: 'MAIN_DATABASE_NAME' mysql: { adapter: 'sails-mysql', host: '127.0.0.1', port: 3306, user: 'myuser', password: 'mypassword', database: 'electron_release_server' electron 自动更新之路总结(上)版本管理服务器 afeiqiang: 上传文件路径是 files.dirname 指定的,只要有读写的权限就可以 electron 自动更新之路总结(上)版本管理服务器 afeiqiang: mysql 和 session 的配置参照 local.template 给的样板,同时要注释掉其它的数据库配置 electron 自动更新之路总结(上)版本管理服务器 m0_67523500: 哥 我下载了这个版本管理器的源码 但是运行报错 这里的mysql 和 session 怎么写 上传文件保存的路径 可以和后面更新的放 一个latest文件和安装包的路径一样吗 kafka 延时消息处理 zsj0310: 根本没考虑过性能,一两条消息你这么玩还行