package service import ( "fmt" "os" "syscall" "github.com/tarm/serial" ) // SerialPrinter 通用打印机接口(串口或 Windows USB) type Printer interface { Write(data []byte) error Close() error } type SerialPrinter struct { Port *serial.Port } func NewSerialPrinter(portName string, baudRate int) (*SerialPrinter, error) { if baudRate <= 0 { baudRate = 9600 } // 非 COM 端口 → 尝试 Windows 打印机路径 if len(portName) >= 3 && portName[:3] != "COM" { return nil, fmt.Errorf("非串口设备,请使用 USB 驱动安装虚拟 COM 口,或连接真实 COM 口") } c := &serial.Config{Name: portName, Baud: baudRate} port, err := serial.OpenPort(c) if err != nil { return nil, fmt.Errorf("打开串口失败 %s: %w", portName, err) } return &SerialPrinter{Port: port}, nil } func (p *SerialPrinter) Write(data []byte) error { _, err := p.Port.Write(data) return err } func (p *SerialPrinter) Close() error { return p.Port.Close() } // USBPrinter Windows USB 打印机(原生 API 发送 RAW 数据) type USBPrinter struct { handle syscall.Handle } func NewUSBPrinter(printerName string) (*USBPrinter, error) { path := fmt.Sprintf("\\\\.\\%s", printerName) pathPtr, err := syscall.UTF16PtrFromString(path) if err != nil { return nil, err } handle, err := syscall.CreateFile( pathPtr, syscall.GENERIC_WRITE, syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE, nil, syscall.OPEN_EXISTING, syscall.FILE_ATTRIBUTE_NORMAL, 0, ) if err != nil { // 尝试通过 UNC 路径 uncPath := fmt.Sprintf("\\127.0.0.1\\%s", printerName) uncPtr, _ := syscall.UTF16PtrFromString(uncPath) handle, err = syscall.CreateFile(uncPtr, syscall.GENERIC_WRITE, syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE, nil, syscall.OPEN_EXISTING, 0, 0) if err != nil { return nil, fmt.Errorf("无法打开打印机 %s: %w", printerName, err) } } return &USBPrinter{handle: handle}, nil } func (p *USBPrinter) Write(data []byte) error { var written uint32 return syscall.WriteFile(p.handle, data, &written, nil) } func (p *USBPrinter) Close() error { return syscall.CloseHandle(p.handle) } var _ = os.Stderr // keep os import