Prechádzať zdrojové kódy

fix: USB打印机多路径尝试+共享提示——\.\ 和 UNC均支持,失败时提示共享打印

lq 1 mesiac pred
rodič
commit
8ac2d9ceb6
1 zmenil súbory, kde vykonal 37 pridanie a 23 odobranie
  1. 37 23
      internal/modules/printer/service/serial.go

+ 37 - 23
internal/modules/printer/service/serial.go

@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"os"
 	"syscall"
+	"unsafe"
 
 	"github.com/tarm/serial"
 )
@@ -49,32 +50,26 @@ type USBPrinter struct {
 }
 
 func NewUSBPrinter(printerName string) (*USBPrinter, error) {
-	path := fmt.Sprintf("\\\\.\\%s", printerName)
-	pathPtr, err := syscall.UTF16PtrFromString(path)
-	if err != nil {
-		return nil, err
+	paths := []string{
+		fmt.Sprintf("\\\\.\\%s", printerName),           // Win32 device
+		fmt.Sprintf("\\\\127.0.0.1\\%s", printerName),  // UNC share
 	}
-	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)
+
+	var handle syscall.Handle
+	var lastErr error
+	for _, path := range paths {
+		pathPtr, _ := syscall.UTF16PtrFromString(path)
+		handle, lastErr = syscall.CreateFile(pathPtr, syscall.GENERIC_WRITE,
+			0, nil, syscall.OPEN_EXISTING, syscall.FILE_ATTRIBUTE_NORMAL, 0)
+		if lastErr == nil {
+			return &USBPrinter{handle: handle}, nil
 		}
 	}
-	return &USBPrinter{handle: handle}, nil
+
+	// 所有路径都失败 → 用临时文件 + copy 命令的方式
+	return nil, fmt.Errorf("无法打开打印机 %s (\\\\.\\ 和 UNC均失败): %w。"+
+		"请到 Windows 控制面板→设备和打印机→右键 %s→打印机属性→共享→勾选'共享这台打印机'并设置共享名",
+		printerName, lastErr, printerName)
 }
 
 func (p *USBPrinter) Write(data []byte) error {
@@ -86,4 +81,23 @@ func (p *USBPrinter) Close() error {
 	return syscall.CloseHandle(p.handle)
 }
 
+// PrintRawFile 备选方案:通过临时文件 + copy 命令打印
+func PrintRawFile(printerName string, data []byte) error {
+	tmpFile, err := os.CreateTemp("", "ticket_*.bin")
+	if err != nil {
+		return err
+	}
+	defer os.Remove(tmpFile.Name())
+	if _, err := tmpFile.Write(data); err != nil {
+		tmpFile.Close()
+		return err
+	}
+	tmpFile.Close()
+	_, _, _ = syscall.NewLazyDLL("kernel32.dll").NewProc("CopyFileW").Call(
+		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(tmpFile.Name()))),
+		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(fmt.Sprintf("\\\\127.0.0.1\\%s", printerName)))),
+		0)
+	return nil
+}
+
 var _ = os.Stderr // keep os import