diff --git a/cmd/print/print.go b/cmd/print/print.go index 078aa54..c29c377 100644 --- a/cmd/print/print.go +++ b/cmd/print/print.go @@ -41,6 +41,7 @@ func listPrinters() error { if err != nil { return err } + for i, p := range printers { s := " " if p == defaultPrinter { @@ -77,7 +78,12 @@ func printOneDocument(printerName, documentName string, lines []string) error { } defer p.Close() - err = p.StartDocument(documentName, "RAW") + dataType, err := p.PrintDataType() + if err != nil { + return err + } + + err = p.StartDocument(documentName, dataType) if err != nil { return err } diff --git a/printer.go b/printer.go index e8accc5..eaab0cb 100644 --- a/printer.go +++ b/printer.go @@ -7,9 +7,16 @@ package printer import ( "syscall" + "unicode/utf16" "unsafe" ) +const ( + PRINTER_DRIVER_XPS uint32 = 0x00000002 + RAW = "RAW" + XPS_PASS = "XPS_PASS" +) + //go:generate go run mksyscall_windows.go -output zapi.go printer.go type DOC_INFO_1 struct { @@ -26,6 +33,34 @@ type PRINTER_INFO_5 struct { TransmissionRetryTimeout uint32 } +type DRIVER_INFO_8 struct { + Version uint32 + Name *uint16 + Environment *uint16 + DriverPath *uint16 + DataFile *uint16 + ConfigFile *uint16 + HelpFile *uint16 + DependentFiles *uint16 + MonitorName *uint16 + DefaultDataType *uint16 + PreviousNames *uint16 + DriverDate syscall.Filetime + DriverVersion uint64 + MfgName *uint16 + OEMUrl *uint16 + HardwareID *uint16 + Provider *uint16 + PrintProcessor *uint16 + VendorSetup *uint16 + ColorProfiles *uint16 + InfPath *uint16 + PrinterDriverAttributes uint32 + CoreDriverDependencies *uint16 + MinInboxDriverVerDate syscall.Filetime + MinInboxDriverVerVersion uint32 +} + const ( PRINTER_ENUM_LOCAL = 2 PRINTER_ENUM_CONNECTIONS = 4 @@ -40,6 +75,21 @@ const ( //sys StartPagePrinter(h syscall.Handle) (err error) = winspool.StartPagePrinter //sys EndPagePrinter(h syscall.Handle) (err error) = winspool.EndPagePrinter //sys EnumPrinters(flags uint32, name *uint16, level uint32, buf *byte, bufN uint32, needed *uint32, returned *uint32) (err error) = winspool.EnumPrintersW +//sys GetPrinterDriver(h syscall.Handle, env *uint16, level uint32, di *byte, n uint32, needed *uint32) (err error) = winspool.GetPrinterDriverW + +func convertLPTSTRToString(ptr *uint16) string { + a := (*[1<<30 - 1]uint16)(unsafe.Pointer(ptr)) + size := 0 + for ; size < len(a); size++ { + if a[size] == uint16(0) { + break + } + } + runes := utf16.Decode(a[:size:size]) + goString := string(runes) + + return goString +} func Default() (string, error) { b := make([]uint16, 3) @@ -83,6 +133,23 @@ func ReadNames() ([]string, error) { return names, nil } +type DriverInfo struct { + Name string + Environment string + DriverPath string + Attributes uint32 +} + +func newDriverInfo(di *DRIVER_INFO_8) *DriverInfo { + var info DriverInfo + info.Attributes = di.PrinterDriverAttributes + info.Name = convertLPTSTRToString(di.Name) + info.DriverPath = convertLPTSTRToString(di.DriverPath) + info.Environment = convertLPTSTRToString(di.Environment) + + return &info +} + type Printer struct { h syscall.Handle } @@ -97,6 +164,42 @@ func Open(name string) (*Printer, error) { return &p, nil } +func (p *Printer) DriverInfo() (*DriverInfo, error) { + b := make([]byte, 1024*10) + n := uint32(len(b)) + var needed uint32 + var env uint16 = 0 + err := GetPrinterDriver(p.h, &env, 8, &b[0], n, &needed) + if err != nil { + if err != syscall.ERROR_INSUFFICIENT_BUFFER { + return nil, err + } + b = make([]byte, n) + err = GetPrinterDriver(p.h, &env, 8, &b[0], needed, &needed) + if err != nil { + return nil, err + } + } + di := (*DRIVER_INFO_8)(unsafe.Pointer(&b[0])) + + ndi := newDriverInfo(di) + + return ndi, nil +} + +func (p *Printer) PrintDataType() (string, error) { + di, err := p.DriverInfo() + if err != nil { + return "", err + } + + if di.Attributes&PRINTER_DRIVER_XPS != 0 { + return XPS_PASS, nil + } + + return RAW, nil +} + func (p *Printer) StartDocument(name, datatype string) error { d := DOC_INFO_1{ DocName: &(syscall.StringToUTF16(name))[0], diff --git a/zapi.go b/zapi.go index 923c32e..6549c96 100644 --- a/zapi.go +++ b/zapi.go @@ -19,6 +19,7 @@ var ( procStartPagePrinter = modwinspool.NewProc("StartPagePrinter") procEndPagePrinter = modwinspool.NewProc("EndPagePrinter") procEnumPrintersW = modwinspool.NewProc("EnumPrintersW") + procGetPrinterDriverW = modwinspool.NewProc("GetPrinterDriverW") ) func GetDefaultPrinter(buf *uint16, bufN *uint32) (err error) { @@ -128,3 +129,15 @@ func EnumPrinters(flags uint32, name *uint16, level uint32, buf *byte, bufN uint } return } + +func GetPrinterDriver(h syscall.Handle, env *uint16, level uint32, di *byte, n uint32, needed *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procGetPrinterDriverW.Addr(), 6, uintptr(h), uintptr(unsafe.Pointer(env)), uintptr(level), uintptr(unsafe.Pointer(di)), uintptr(n), uintptr(unsafe.Pointer(needed))) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +}