Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ import (
"unsafe"
)

const (
PRINTER_DRIVER_XPS uint32 = 0x00000002

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/PRINTER_DRIVER_XPS uint32/PRINTER_DRIVER_XPS/

make PRINTER_DRIVER_XPS untyped. Untyped consts fit anything.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add PRINTER_DRIVER_PACKAGE_AWARE and others.

RAW = "RAW"
XPS_PASS = "XPS_PASS"

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delete both RAW and XPS_PASS. Users won't need them.

)

//go:generate go run mksyscall_windows.go -output zapi.go printer.go

type DOC_INFO_1 struct {
Expand All @@ -26,6 +32,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
Expand Down Expand Up @@ -58,6 +92,36 @@ func Default() (string, error) {
return syscall.UTF16ToString(b), nil
}

func GetDefaultPrinterType() (string, error) {
printerName, _ := Default()
return GetPrinterType(printerName)
}

func GetPrinterType(printerName string) (string, error) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of creating package function, I suggest, you add new method to Printer struct. This way new method will not need printerName parameter. You will also not need GetFeaultPrinterType function, because you could use printer.Default.... instead.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is a nice a idea !

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe instead of returning sting, this function should return more info. Maybe create

type DriverInfo struct {
...
Attributes uint32
}

, then you could do:

di, err := myprinter.DriverInfo()
if err != nil {
...
}
if di.Attributes&PRINTER_DRIVER_XPS != 0 {
...
}

We could start DriverInfo struct just with Attributes field and add more fields later as needed.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, i made the Driver info with driver name, enviroment and driver path

b := make([]byte, 1024*10)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why 10K? How large this data is (from your own experiment)? Maybe start with that instead.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, is from my experiment, in my experiment the struct has 6k from a thermal printer with generic driver from windows

n := uint32(len(b))
err := GetPrinterDriver(printerName, &b[0], n)
if err != nil {
if err != syscall.ERROR_INSUFFICIENT_BUFFER {
return "", err
}
b = make([]byte, n)
err = GetPrinterDriver(printerName, &b[0], n)
if err != nil {
return "", err
}
}
di := (*DRIVER_INFO_8)(unsafe.Pointer(&b[0]))

driverType := RAW

if di.PrinterDriverAttributes&PRINTER_DRIVER_XPS == 2 {
driverType = XPS_PASS
}

return driverType, nil
}

// ReadNames return printer names on the system
func ReadNames() ([]string, error) {
const flags = PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS
Expand Down
26 changes: 24 additions & 2 deletions zapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

package printer

import "unsafe"
import "syscall"
import (
"syscall"
"unsafe"
)

var _ unsafe.Pointer

Expand All @@ -19,6 +21,7 @@ var (
procStartPagePrinter = modwinspool.NewProc("StartPagePrinter")
procEndPagePrinter = modwinspool.NewProc("EndPagePrinter")
procEnumPrintersW = modwinspool.NewProc("EnumPrintersW")
procGetPrinterDriver = modwinspool.NewProc("GetPrinterDriverW")
)

func GetDefaultPrinter(buf *uint16, bufN *uint32) (err error) {
Expand All @@ -33,6 +36,25 @@ func GetDefaultPrinter(buf *uint16, bufN *uint32) (err error) {
return
}

func GetPrinterDriver(name string, buf *byte, bufN uint32) (err error) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is generated by running "go generate" command. Do not change it manually. This file contains all Windows API, so instead of

func GetPrinterDriver(name string, buf *byte, bufN uint32) (err error)

you want

func GetPrinterDriver(h syscall.Handle, env *uint16, level uint32, di *byte, n uint32, needed *uint32) (err error)

So if you add

//sys   GetPrinterDriver(h syscall.Handle, env *uint16, level uint32, di *byte, n uint32, needed *uint32) (err error) = winspool.GetPrinterDriver

and then run "go generate" command, you will get what you want.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont know that ! i made the change and generate the code know !

p, err := Open(name)
if err != nil {
return err
}
defer p.Close()
var needed uint32
r1, _, e1 := syscall.Syscall6(procGetPrinterDriver.Addr(), 6, uintptr(p.h), uintptr(0), uintptr(8), uintptr(unsafe.Pointer(buf)), uintptr(bufN), uintptr(unsafe.Pointer(&needed)))
if r1 == 0 {
if e1 != 0 {
err = error(e1)
panic(err)
} else {
err = syscall.EINVAL
}
}
return
}

func ClosePrinter(h syscall.Handle) (err error) {
r1, _, e1 := syscall.Syscall(procClosePrinter.Addr(), 1, uintptr(h), 0, 0)
if r1 == 0 {
Expand Down