In a project I'm trying to use the WebUSB API available in Chrome to print using a Zebra LP2844 printer.
I succeeded on OSX without issues and eventually on Ubuntu and on ChromeOS thanks to this post that talked about unbinding the kernel driver so Chrome was able to access the device.
The page I'm using for this is served though https as the documentation requires it.
On Windows 10 however, I'm able to connect to the printer with navigator.usb.requestDevice as shown here
but when I call open() on the connected printer during the print routine, I keep getting the next error
Error DOMException: Access denied.
Here is the print method code:
print : async function(printString) {
let startTime = new Date().getTime();
if (!this.pairedPrinter) {
console.log("No printer connected");
return;
}
try {
if (!this.pairedPrinter.opened) {
await this.pairedPrinter.open();
}
await this.pairedPrinter.claimInterface(0);
let encoder = new TextEncoder();
const printBuffer = encoder.encode(printString);
let printResult = await this.pairedPrinter.transferOut(6, printBuffer);
await this.pairedPrinter.releaseInterface(0);
await this.pairedPrinter.close();
} catch (err) {
console.log("Error");
console.log(err);
} finally {
let endTime = new Date().getTime();
let printTime = endTime - startTime;
console.log("Print time: " + printTime + " ms");
}
}
I found a similar question here, that points to this other answer. It makes perfect sense that the default driver being installed by Windows when I plug the printer prevents Chrome from accessing it (just like Ubuntu does).
So, I implemented a custom .inf file as described here.
This is my inf file
;
;
; Installs WinUsb
;
; =================== Strings ===================
[Strings]
ManufacturerName = "Zebra"
ClassName = "Universal Serial Bus devices"
DeviceName = "Aeropost Zebra LP2844"
SourceName = "Aeropost Zebra LP2844 Install Disk"
DeviceID = "VID_0A5F&PID_0009"
DeviceGUID = "{c3bd2e26-7e03-4189-8c9d-852faf628494}"
REG_MULTI_SZ = 0x00010000
[Version]
Signature = "$Windows NT$"
Class = Printer
ClassGuid = {4d36e979-e325-11ce-bfc1-08002be10318}
Provider = %ManufacturerName%
CatalogFile = zebrawinusb.cat
DriverVer = 03/02/2018,1.0.0.0
; ========== Class definition ===========
[ClassInstall32]
AddReg = ClassInstall_AddReg
[ClassInstall_AddReg]
HKR,,,0,"Universal Serial Bus devices"
HKR,,Icon,,-20
; ========== Manufacturer/Models sections ===========
[Manufacturer]
%ManufacturerName% = Standard,NTx86
%ManufacturerName% = Standard,NTamd64
[Standard.NTx86]
%DeviceName% = USB_Install, USB\%DeviceID%
[Standard.NTamd64]
%DeviceName% = USB_Install, USB\%DeviceID%
; =================== Installation ===================
[USB_Install]
Include = winusb.inf
Needs = WINUSB.NT
[USB_Install.Services]
Include = winusb.inf
Needs = WINUSB.NT.Services
[USB_Install.Wdf]
KmdfService = WINUSB, WinUsb_Install
[WinUSB_Install]
KmdfLibraryVersion = 1.11
[USB_Install.HW]
AddReg=Dev_AddReg
[Dev_AddReg]
HKR,,DeviceInterfaceGUIDs,0x10000,%DeviceGUID%
[USB_Install.CoInstallers]
AddReg = CoInstallers_AddReg
CopyFiles = CoInstallers_CopyFiles
[CoInstallers_AddReg]
HKR,,CoInstallers32,0x00010000,"WdfCoInstaller01011.dll,WdfCoInstaller","WinUsbCoInstaller2.dll"
[CoInstallers_CopyFiles]
WinUsbCoInstaller2.dll
WdfCoInstaller01011.dll
[DestinationDirs]
; If your INF needs to copy files, you must not use the DefaultDestDir directive here.
CoInstallers_CopyFiles=11
; ================= Source Media Section =====================
[SourceDisksNames]
1 = %SourceName%
[SourceDisksFiles.x86]
WinUSBCoInstaller2.dll = 1,x86
WdfCoInstaller01011.dll = 1,x86
[SourceDisksFiles.x64]
WinUSBCoInstaller2.dll = 1,x64
WdfCoInstaller01011.dll = 1,x64
Built the driver using inf2cat, test-signed it and when I try to update the printer driver to use it, it fails with error "the file specified could not be found (0x00000002)".
setupapi.dev.log file provides no info whatsoever about which file is not being found though.
Here's the log file for the driver update process:
>>> [Device Install (DiShowUpdateDevice) - USBPRINT\ZEBRA_LP2844_\6&3295E28F&3&USB001]
>>> Section start 2018/03/02 16:14:00.023
cmd: "C:\WINDOWS\system32\mmc.exe" C:\WINDOWS\system32\devmgmt.msc
dvi: {DIF_UPDATEDRIVER_UI} 16:14:00.023
dvi: Class installer: Enter 16:14:00.023
dvi: Class installer: Exit
dvi: Default installer: Enter 16:14:00.039
dvi: Default installer: Exit
dvi: {DIF_UPDATEDRIVER_UI - exit(0xe000020e)} 16:14:00.054
ndv: {Update Driver Software Wizard - USBPRINT\ZEBRA_LP2844_\6&3295E28F&3&USB001}
dvi: {DIF_SELECTDEVICE} 16:14:05.662
dvi: Class installer: Enter 16:14:05.678
dvi: Class installer: Exit
dvi: {DIF_SELECTDEVICE - exit(0xe000020e)} 16:14:05.678
dvi: {DIF_SELECTDEVICE} 16:14:12.148
dvi: Class installer: Enter 16:14:12.148
dvi: Class installer: Exit
dvi: {DIF_SELECTDEVICE - exit(0xe000020e)} 16:14:12.163
ndv: Driver package 'C:\WINDOWS\System32\DriverStore\FileRepository\zebrawinusb.inf_amd64_ddcc3ed00fd3e8a8\zebrawinusb.inf' is already imported.
sto: {Setup Import Driver Package: c:\zebrawinusbdriver\zebrawinusb.inf} 16:14:16.158
sto: Driver package already imported as 'oem20.inf'.
sto: {Setup Import Driver Package - exit (0x00000000)} 16:14:16.180
dvi: Searching for hardware ID(s):
dvi: usbprint\zebra_lp2844_5bc4
dvi: zebra_lp2844_5bc4
dvi: Class GUID of device remains: {4d36e979-e325-11ce-bfc1-08002be10318}.
dvi: {Plug and Play Service: Device Install for USBPRINT\ZEBRA_LP2844_\6&3295E28F&3&USB001}
dvi: Driver INF Path: C:\WINDOWS\INF\oem20.inf
dvi: Driver Node Name: zebrawinusb.inf:c14ce8840c48fa1f:USB_Install:1.0.0.0:usb\vid_0a5f&pid_0009,
dvi: Driver Store Path: C:\WINDOWS\System32\DriverStore\FileRepository\zebrawinusb.inf_amd64_ddcc3ed00fd3e8a8\zebrawinusb.inf
dvi: Searching for hardware ID(s):
dvi: usbprint\zebra_lp2844_5bc4
dvi: zebra_lp2844_5bc4
dvi: Class GUID of device changed to: {4d36e979-e325-11ce-bfc1-08002be10318}.
dvi: {Core Device Install} 16:14:16.313
! pol: Selected driver node does not match this device (force-install)
dvi: {Install Device - USBPRINT\ZEBRA_LP2844_\6&3295E28F&3&USB001} 16:14:16.316
dvi: Device Status: 0x0180200a, Problem: 0x0 (0x00000000)
dvi: Parent device: USB\VID_0A5F&PID_0009\42J113802152
! dvi: Unable to determine matching device ID for oem20.inf. Error = 0xE0000228
! dvi: Unable to configure device, falling back to standard device installation.
dvi: {DIF_ALLOW_INSTALL} 16:14:16.324
dvi: Using exported function 'ClassInstall32' in module 'C:\WINDOWS\system32\ntprint.dll'.
dvi: Class installer == ntprint.dll,ClassInstall32
dvi: Class installer: Enter 16:14:16.336
dvi: Class installer: Exit
dvi: Default installer: Enter 16:14:16.340
dvi: Default installer: Exit
dvi: {DIF_ALLOW_INSTALL - exit(0xe000020e)} 16:14:16.342
dvi: {DIF_INSTALLDEVICEFILES} 16:14:16.343
dvi: Class installer: Enter 16:14:16.344
!!! dvi: Class installer: failed(0x00000002)!
dvi: {DIF_INSTALLDEVICEFILES - exit(0x00000002)} 16:14:16.383
! dvi: Queueing up error report for device install failure.
dvi: {Install Device - exit(0x00000002)} 16:14:16.383
dvi: {Core Device Install - exit(0x00000002)} 16:14:16.383
dvi: {DIF_DESTROYPRIVATEDATA} 16:14:16.383
dvi: Class installer: Enter 16:14:16.383
dvi: Class installer: Exit
dvi: Default installer: Enter 16:14:16.399
dvi: Default installer: Exit
dvi: {DIF_DESTROYPRIVATEDATA - exit(0xe000020e)} 16:14:16.399
ump: {Plug and Play Service: Device Install exit(00000002)}
!!! ndv: Device install failed for device.
ndv: {Update Driver Software Wizard exit(00000002)}
<<< Section end 2018/03/02 16:15:14.498
<<< [Exit status: FAILURE(0x00000002)]
I even tried replacing the printer driver using zadig, with the same results (Access denied error).
At this point, any assistance is highly appreciated.
UPDATE 03/05/2018
Today I managed to make my custom inf installer finish successfully, by following the next steps:
- prevent windows 10 from searching the web for drivers and installing them when I plug in the printer (view details here)
- update my custom inf installer to use the USBDevice class and the {88bae032-5a81-49f0-bc3d-a4ff138216d6} ClassGuid values
- built the driver cat file and signed it
- uninstall all drivers for the device and unplug the printer
- restart the computer
- plug the printer again. At this point, in the Device Manager, the device is detected as a Universal Serial Bus device
- finally, followed followed this instructions to update the device drivers using the one created before.
Driver installation succeeded and regedit reflects the device is now using WinUSB
Sadly, I continue getting the "DOMException: Access denied." error when I try to print from the web page... so I still need help :(
ps: this is probably the longest post on stackoverflow I know (or top 10 at least).
UPDATE 03/06/2018
As per Reilly Grant's request, I'm including the output of USBView (lsusb equivalent for windows)
[Port1] : Aeropost Zebra LP2844
Is Port User Connectable: yes
Is Port Debug Capable: no
Companion Port Number: 10
Companion Hub Symbolic Link Name: USB#ROOT_HUB30#4&4f0abe8&0&0#{f18a0e88-c30c-11d0-8815-00a0c906bed8}
Protocols Supported:
USB 1.1: yes
USB 2.0: yes
USB 3.0: no
Device Power State: PowerDeviceD0
---===>Device Information<===---
*!*ERROR: No String Descriptor for index 4!
ConnectionStatus:
Current Config Value: 0x01 -> Device Bus Speed: Full (is not SuperSpeed or higher capable)
Device Address: 0x01
Open Pipes: 2
===>Device Descriptor<===
bLength: 0x12
bDescriptorType: 0x01
bcdUSB: 0x0100
bDeviceClass: 0x07
*!*ERROR: unknown bDeviceClass 7
bDeviceSubClass: 0x01
*!*ERROR: bDeviceSubClass of 1 is invalid
bDeviceProtocol: 0x02
*!*ERROR: bDeviceProtocol of 2 is invalid
bMaxPacketSize0: 0x08 = (8) Bytes
idVendor: 0x0A5F = Zebra Technologies
idProduct: 0x0009
bcdDevice: 0x0001
iManufacturer: 0x02
*!*ERROR: No String Descriptor for index 2!
iProduct: 0x04
*!*ERROR: No String Descriptor for index 4!
iSerialNumber: 0x06
*!*ERROR: No String Descriptor for index 6!
bNumConfigurations: 0x01
---===>Open Pipes<===---
===>Endpoint Descriptor<===
bLength: 0x07
bDescriptorType: 0x05
bEndpointAddress: 0x85 -> Direction: IN - EndpointID: 5
bmAttributes: 0x02 -> Bulk Transfer Type
wMaxPacketSize: 0x0040 = 0x40 bytes
bInterval: 0x00
===>Endpoint Descriptor<===
bLength: 0x07
bDescriptorType: 0x05
bEndpointAddress: 0x06 -> Direction: OUT - EndpointID: 6
bmAttributes: 0x02 -> Bulk Transfer Type
wMaxPacketSize: 0x0040 = 0x40 bytes
bInterval: 0x00
---===>Full Configuration Descriptor<===---
===>Configuration Descriptor<===
bLength: 0x09
bDescriptorType: 0x02
wTotalLength: 0x0020 -> Validated
bNumInterfaces: 0x01
bConfigurationValue: 0x01
iConfiguration: 0x00
bmAttributes: 0xC0 -> Self Powered
-> Bus Powered
MaxPower: 0x00 = 0 mA
===>Interface Descriptor<===
bLength: 0x09
bDescriptorType: 0x04
bInterfaceNumber: 0x00
bAlternateSetting: 0x00
bNumEndpoints: 0x02
bInterfaceClass: 0x07 -> This is a Printer USB Device Interface Class
bInterfaceSubClass: 0x01
bInterfaceProtocol: 0x02
iInterface: 0x00
===>Endpoint Descriptor<===
bLength: 0x07
bDescriptorType: 0x05
bEndpointAddress: 0x85 -> Direction: IN - EndpointID: 5
bmAttributes: 0x02 -> Bulk Transfer Type
wMaxPacketSize: 0x0040 = 0x40 bytes
bInterval: 0x00
===>Endpoint Descriptor<===
bLength: 0x07
bDescriptorType: 0x05
bEndpointAddress: 0x06 -> Direction: OUT - EndpointID: 6
bmAttributes: 0x02 -> Bulk Transfer Type
wMaxPacketSize: 0x0040 = 0x40 bytes
bInterval: 0x00
Interestingly (bizarrely actually) enough, while trying to get this new information, my Google Chrome started throwing
TypeError: Cannot read property 'getDevices' of undefined
error in the console, and typing navigator.usb in the console returned undefined.
Since that didn't make any sense, I reinstalled Chrome, but the error continued
Because of that I installed Chrome Canary (where navigator.usb existed) and turns out that THE PRINTER STARTED PRINTING and the Access Denied error was gone.
I uninstalled Chrome Canary and somehow GA Chrome also worked. That was until I closed Chrome and opened it again. Then I got the "Cannot read property 'getDevices' of undefined" error again.
I noticed that deleting Chrome's User Data folder in AppData/Local/Google (the entire profile folder) makes Chrome work again, until I close it and open it again.
Perhaps something in my printing code is leaving something "held" despite I'm calling releaseInterface and close?
Any ideas now that the problem seem to have changed a bit?
lsusb -v
for this device and the error displayed in chrome://device-log when you get the "Access denied." error. – Lahdidah