| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- package service
- import (
- "fmt"
- "os"
- "os/exec"
- "syscall"
- "unsafe"
- "github.com/tarm/serial"
- )
- // SerialPrinter 串口打印机
- type SerialPrinter struct {
- Port *serial.Port
- }
- func NewSerialPrinter(portName string, baudRate int) (*SerialPrinter, error) {
- if baudRate <= 0 {
- baudRate = 9600
- }
- if len(portName) < 3 || portName[:3] != "COM" {
- return nil, fmt.Errorf("非串口设备: %s", portName)
- }
- 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()
- }
- // === Windows RAW 打印机(WritePrinter API)===
- var (
- winspool = syscall.NewLazyDLL("winspool.drv")
- procOpenPrinter = winspool.NewProc("OpenPrinterW")
- procClosePrinter = winspool.NewProc("ClosePrinter")
- procStartDoc = winspool.NewProc("StartDocPrinterW")
- procStartPage = winspool.NewProc("StartPagePrinter")
- procWritePrinter = winspool.NewProc("WritePrinter")
- procEndPage = winspool.NewProc("EndPagePrinter")
- procEndDoc = winspool.NewProc("EndDocPrinter")
- )
- type PRINTER_DEFAULTS struct {
- pDatatype *uint16
- pDevMode uintptr
- DesiredAccess uint32
- }
- type DOC_INFO_1 struct {
- pDocName *uint16
- pOutputFile *uint16
- pDataType *uint16
- }
- func PrintRaw(printerName string, data []byte) error {
- namePtr, _ := syscall.UTF16PtrFromString(printerName)
- rawType, _ := syscall.UTF16PtrFromString("RAW")
- pd := PRINTER_DEFAULTS{
- pDatatype: rawType,
- pDevMode: 0,
- DesiredAccess: 0x000F0000 | 0x00000008, // PRINTER_ACCESS_USE | PRINTER_ACCESS_ADMINISTER
- }
- var handle syscall.Handle
- ret, _, _ := procOpenPrinter.Call(uintptr(unsafe.Pointer(namePtr)),
- uintptr(unsafe.Pointer(&handle)), uintptr(unsafe.Pointer(&pd)))
- if ret == 0 {
- return fmt.Errorf("OpenPrinter 失败: %s", printerName)
- }
- defer procClosePrinter.Call(uintptr(handle))
- docName, _ := syscall.UTF16PtrFromString("Parking Ticket")
- di := DOC_INFO_1{pDocName: docName, pDataType: rawType}
- procStartDoc.Call(uintptr(handle), 1, uintptr(unsafe.Pointer(&di)))
- procStartPage.Call(uintptr(handle))
- var written uint32
- procWritePrinter.Call(uintptr(handle), uintptr(unsafe.Pointer(&data[0])),
- uintptr(len(data)), uintptr(unsafe.Pointer(&written)))
- procEndPage.Call(uintptr(handle))
- procEndDoc.Call(uintptr(handle))
- return nil
- }
- // copyToPrinter 通过临时文件 + COPY /B 到打印机共享发送 RAW 数据
- func copyToPrinter(printerName string, data []byte) error {
- tmpFile, err := os.CreateTemp("", "tkt_*.bin")
- if err != nil {
- return err
- }
- tmpPath := tmpFile.Name()
- defer os.Remove(tmpPath)
- if _, err := tmpFile.Write(data); err != nil {
- tmpFile.Close()
- return err
- }
- tmpFile.Close()
- // 尝试 COPY /B file \\127.0.0.1\share_name
- // 先查共享名
- shareName := printerName
- for _, path := range []string{
- fmt.Sprintf("\\\\127.0.0.1\\%s", shareName),
- fmt.Sprintf("\\\\localhost\\%s", shareName),
- } {
- cmd := exec.Command("cmd", "/C", "copy", "/B", tmpPath, path)
- output, err := cmd.CombinedOutput()
- if err == nil {
- return nil
- }
- // 打印失败,尝试下一个
- _ = output
- }
- // 最后回退 WritePrinter API
- return PrintRaw(printerName, data)
- }
- var _ = os.Stderr
|