-
Notifications
You must be signed in to change notification settings - Fork 80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding Get Printer Type #2
base: master
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suspect you had some problem with this code always passing "RAW" to StartDocument. What is the problem? How can I reproduce it? Can you create an issue about this problem and make this PR fix the problem? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The problem is: i had a printer that doesnt accept RAW datatype, the problem is that print only accepts XPS documents. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But what is the data that you need to write to the printer when you pass "XPS_PASS" to it? Can I send text data? Will it print properly? Does every printer that reports PRINTER_DRIVER_XPS will work with "XPS_PASS"? Are there any references to all of this somewhere on the Internet? Maybe we could just introduce another flag for the program that describes data type, and default it to "RAW" instead? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Normal string data, you can send normal text, its print properly, the driver do the work, and Yes every printer with PRINTER_DRIVER_XPS will work with XPS_PASS And yes, we can do other flag for program to describe data type and set RAW as default There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you for explaining. I will wait for you to address my other comments now. Alex |
||
if err != nil { | ||
return err | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,7 @@ package printer | |
|
||
import ( | ||
"syscall" | ||
"unicode/utf16" | ||
"unsafe" | ||
) | ||
|
||
|
@@ -74,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 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You don't need to implement that function, because it already exists. Search for syscall.UTF16ToString in net package - it will show how to do that. |
||
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) | ||
|
@@ -92,36 +108,6 @@ func Default() (string, error) { | |
return syscall.UTF16ToString(b), nil | ||
} | ||
|
||
func GetDefaultPrinterType() (string, error) { | ||
printerName, _ := Default() | ||
return GetPrinterType(printerName) | ||
} | ||
|
||
func GetPrinterType(printerName string) (string, error) { | ||
b := make([]byte, 1024*10) | ||
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 | ||
|
@@ -147,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 | ||
} | ||
|
@@ -161,6 +164,42 @@ func Open(name string) (*Printer, error) { | |
return &p, nil | ||
} | ||
|
||
func (p *Printer) DriverInfo() (*DriverInfo, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. New function needs documentation. |
||
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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are you using &env and not nil here? &end points to empty environment, while nil is default for "the current environment of the calling application and client machine". Which do we want here? |
||
if err != nil { | ||
if err != syscall.ERROR_INSUFFICIENT_BUFFER { | ||
return nil, err | ||
} | ||
b = make([]byte, n) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But b already points to buffer of n bytes. Don't you want to make bigger buffer - needed bytes big? |
||
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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can just:
and you won't need newDriverInfo function. |
||
|
||
return ndi, nil | ||
} | ||
|
||
func (p *Printer) PrintDataType() (string, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please, remove this function. The name does not explain what it does, and it is simple enough to be implemented in couple of lines of code. |
||
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], | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove blank line. Unrelated to your change.