|
|
@@ -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
|