codesoft6 编写的ceshi.lab文件
系统自带打印机Microsoft Print to PDF
代码工具类
package printer
import (
"errors"
"fmt"
"runtime"
"time"
ole "github.com/go-ole/go-ole"
"github.com/go-ole/go-ole/oleutil"
)
// Label is a struct for recv label information
// template is label abs-path, printer is printer name, cause
// printer name never dupplicate in one computer/server, so using
// printer name for the output device, quantity is for the label copy num.
type Label struct {
Template string //标签路径(绝对路径)
Printer string //打印机名称
Data map[string]string //标签内参数
Quantity int //打印份数
}
// AppWorkStation is for mult-gorounting, when you using the mult-goroutings, you
// need care about the max number of the workstation can't exceed the max num. of
// cpu core this function is limited by ole working principle. if out of the cores,
// it will cause ole object can't been close properly.
func AppWorkStation(msg chan Label, max time.Duration) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
ole.CoInitializeEx(0, ole.COINIT_MULTITHREADED)
defer ole.CoUninitialize()
app, e := newApplication()
if e != nil {
fmt.Println(e)
return
}
for {
select {
case lb := <-msg:
fmt.Println(lb)
e = app.Print(lb)
if e != nil {
fmt.Println(e)
}
case <-time.After(max):
fmt.Println("app", max.String())
app.Close()
// fmt.Println("app", max.String())
return
}
}
}
// Application is for application env.
type Application struct {
oleobj *ole.IUnknown
appInterface
}
func newApplication() (r *Application, e error) {
r = &Application{}
r.oleobj, e = oleutil.CreateObject("Lppx2.Application")
if e != nil {
return
}
lb, e := r.oleobj.QueryInterface(ole.IID_IDispatch)
if e != nil {
return
}
r.appInterface = appInterface{}
r.appInterface.oleobj = lb
r.appInterface.Documents = Documents{}
r.appInterface.Documents.oleobj = oleutil.MustGetProperty(lb, "Documents").ToIDispatch()
r.appInterface.Documents.openDocs = make(map[string]Document)
return
}
// Print is function for print a label.
func (app Application) Print(l Label) (e error) {
if d, ok := app.openDocs[l.Template]; ok {
e = d.print(l)
} else {
d, e = app.Open(l.Template)
if e != nil {
return
}
e = d.print(l)
}
return
}
// Close app self
func (app Application) Close() {
app.appInterface.close()
app.oleobj.Release()
// ole.CoUninitialize()
}
type appInterface struct {
oleobj *ole.IDispatch
Documents
}
func (appif appInterface) close() {
appif.Documents.Close()
appif.oleobj.Release()
}
// Documents is an collection object for all label document
type Documents struct {
oleobj *ole.IDispatch
openDocs map[string]Document
}
// Close all the documents in the documents objects, in ole, documents
// is a collection object, in this package implment as map to keep those
// open document.
func (docs Documents) Close() {
// release open docs
for k, v := range docs.openDocs {
if &v != nil {
v.Close()
delete(docs.openDocs, k)
}
}
// release self
docs.oleobj.Release()
}
// Open a label in `lab` path, and return a Document object
func (docs *Documents) Open(lab string) (doc Document, e error) {
t := oleutil.MustCallMethod(docs.oleobj, "open", lab, true).ToIDispatch()
if t == nil {
e = errors.New("label not exists!")
return
}
if docs.openDocs == nil {
docs.openDocs = make(map[string]Document)
}
doc = Document{}
doc.oleobj = t
doc.Variables.init(doc.oleobj)
doc.Printer.init(doc.oleobj)
docs.openDocs[lab] = doc
return
}
// Document is a label template
type Document struct {
oleobj *ole.IDispatch
Variables
Printer
}
// Close and release resources
func (doc Document) Close() {
// close open docs
doc.Printer.Close()
oleutil.MustCallMethod(doc.oleobj, "Close")
}
// Print out
func (doc Document) print(l Label) (e error) {
if doc.oleobj == nil {
e = errors.New("Docment ole object is not exists")
return
}
// switch printer
fmt.Println(doc.Printer)
e = doc.Printer.SwitchTo(l.Printer)
if e != nil {
return
}
// set parameters
for k, v := range l.Data {
i := doc.Items[k]
i.Set(v)
}
// print
_, e = oleutil.CallMethod(doc.oleobj, "PrintDocument", l.Quantity)
return
}
// Printer implement from ole
type Printer struct {
oleobject *ole.IDispatch
fullName string
//我的打印机没这两个参数
// marginLeft string
// marginTop string
}
func (p *Printer) init(obj *ole.IDispatch) {
p.oleobject = oleutil.MustGetProperty(obj, "Printer").ToIDispatch()
p.fullName = oleutil.MustGetProperty(p.oleobject, "FullName").ToString()
// p.marginLeft = oleutil.MustGetProperty(p.oleobject, "MarginLeft").ToString()
// p.marginTop = oleutil.MustGetProperty(p.oleobject, "MarginTop").ToString()
}
// SwitchTo printer with printer name
func (p *Printer) SwitchTo(prt string) (e error) {
t := oleutil.MustCallMethod(p.oleobject, "SwitchTo", prt)
if t.Val == 0 {
e = errors.New("printer not exists")
return
}
p.fullName = prt
return
}
//我的打印机没这两个参数
// // MarginLeft read printer parameter: marginleft
// func (p *Printer) MarginLeft() (r string) {
// return p.marginLeft
// }
// // SetMarginLeft set printer parameter: marginleft
// func (p *Printer) SetMarginLeft(v string) {
// oleutil.MustPutProperty(p.oleobject, "MarginLeft", v)
// }
// // MarginTop read printer parameter: margintop
// func (p *Printer) MarginTop() (r string) {
// return p.marginTop
// }
// // SetMarginTop set printer parameter: margintop
// func (p *Printer) SetMarginTop(v string) {
// oleutil.MustPutProperty(p.oleobject, "MarginTop", v)
// }
// Close self
func (p *Printer) Close() {
p.oleobject.Release()
}
// Variables including in the label. it contains several parts, form variables, free variables
// and so on, please check activex document to find details. here just implement the free
// variables.
type Variables struct {
oleobj *ole.IDispatch
Items map[string]Item
}
func (v *Variables) init(obj *ole.IDispatch) {
if v == nil {
v = &Variables{}
}
v.oleobj = oleutil.MustGetProperty(obj, "Variables").ToIDispatch()
v.Items = make(map[string]Item)
ct := int(oleutil.MustGetProperty(v.oleobj, "Count").Val)
fmt.Println(ct)
for i := 1; i <= ct; i++ {
t := oleutil.MustCallMethod(v.oleobj, "item", i).ToIDispatch()
itm := &Item{}
itm.init(t)
v.Items[itm.Name] = *itm
}
// v.FreeVariables.init(v.oleobj)
}
// FreeVariables is only using in label for now
type FreeVariables struct {
oleobj *ole.IDispatch
Items map[string]Item
}
func (fv *FreeVariables) init(obj *ole.IDispatch) {
fv.oleobj = oleutil.MustGetProperty(obj, "FreeVariables").ToIDispatch()
fv.Items = make(map[string]Item)
// variables num.
// index start from 1 not 0.
ct := int(oleutil.MustGetProperty(fv.oleobj, "Count").Val)
for i := 1; i <= ct; i++ {
t := oleutil.MustCallMethod(fv.oleobj, "item", i).ToIDispatch()
itm := &Item{}
itm.init(t)
fv.Items[itm.Name] = *itm
}
}
// Item in variables
type Item struct {
oleobj *ole.IDispatch
Name string
Value string
}
func (itm *Item) init(obj *ole.IDispatch) {
if itm == nil {
itm = &Item{}
}
itm.oleobj = obj
itm.Name = oleutil.MustGetProperty(itm.oleobj, "Name").ToString()
itm.Value = oleutil.MustGetProperty(itm.oleobj, "Value").ToString()
}
// Val is a function to read item's value
func (itm *Item) Val() string {
return itm.Value
}
// Set is using to setting item's value
func (itm *Item) Set(val string) {
oleutil.PutProperty(itm.oleobj, "Value", val)
}
测试
func main() {
lb := codesoft.Label{}
lb.Template = "D:\\ceshiPrinter\\ceshi.Lab"
lb.Quantity = 1
lb.Data = map[string]string{"VAR0": "wfugui", "VAR1": "www.wfugui.com"}
// lb.Printer = "Fax"
// lb.Printer = "Microsoft XPS Document Writer"
// lb.Printer = "Microsoft Print to PDF"
lb.Printer = "Microsoft Print to PDF"
msg := make(chan codesoft.Label, 100)
go codesoft.AppWorkStation(msg, time.Second*10)
msg <- lb
lb.Data = map[string]string{"VAR0": "zxc", "VAR1": "www.wfugui.com"}
msg <- lb
time.Sleep(time.Minute * 1)
}