github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/pkg/syscall/dll_windows.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package syscall 6 7 import ( 8 "sync" 9 "sync/atomic" 10 "unsafe" 11 ) 12 13 // DLLError describes reasons for DLL load failures. 14 type DLLError struct { 15 Err error 16 ObjName string 17 Msg string 18 } 19 20 func (e *DLLError) Error() string { return e.Msg } 21 22 // Implemented in ../runtime/syscall_windows.goc. 23 func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) 24 func Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) 25 func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) 26 func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2 uintptr, err Errno) 27 func Syscall15(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2 uintptr, err Errno) 28 func loadlibrary(filename *uint16) (handle uintptr, err Errno) 29 func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err Errno) 30 31 // A DLL implements access to a single DLL. 32 type DLL struct { 33 Name string 34 Handle Handle 35 } 36 37 // LoadDLL loads DLL file into memory. 38 func LoadDLL(name string) (dll *DLL, err error) { 39 namep, err := UTF16PtrFromString(name) 40 if err != nil { 41 return nil, err 42 } 43 h, e := loadlibrary(namep) 44 if e != 0 { 45 return nil, &DLLError{ 46 Err: e, 47 ObjName: name, 48 Msg: "Failed to load " + name + ": " + e.Error(), 49 } 50 } 51 d := &DLL{ 52 Name: name, 53 Handle: Handle(h), 54 } 55 return d, nil 56 } 57 58 // MustLoadDLL is like LoadDLL but panics if load operation failes. 59 func MustLoadDLL(name string) *DLL { 60 d, e := LoadDLL(name) 61 if e != nil { 62 panic(e) 63 } 64 return d 65 } 66 67 // FindProc searches DLL d for procedure named name and returns *Proc 68 // if found. It returns an error if search fails. 69 func (d *DLL) FindProc(name string) (proc *Proc, err error) { 70 namep, err := BytePtrFromString(name) 71 if err != nil { 72 return nil, err 73 } 74 a, e := getprocaddress(uintptr(d.Handle), namep) 75 if e != 0 { 76 return nil, &DLLError{ 77 Err: e, 78 ObjName: name, 79 Msg: "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(), 80 } 81 } 82 p := &Proc{ 83 Dll: d, 84 Name: name, 85 addr: a, 86 } 87 return p, nil 88 } 89 90 // MustFindProc is like FindProc but panics if search fails. 91 func (d *DLL) MustFindProc(name string) *Proc { 92 p, e := d.FindProc(name) 93 if e != nil { 94 panic(e) 95 } 96 return p 97 } 98 99 // Release unloads DLL d from memory. 100 func (d *DLL) Release() (err error) { 101 return FreeLibrary(d.Handle) 102 } 103 104 // A Proc implements access to a procedure inside a DLL. 105 type Proc struct { 106 Dll *DLL 107 Name string 108 addr uintptr 109 } 110 111 // Addr returns the address of the procedure represented by p. 112 // The return value can be passed to Syscall to run the procedure. 113 func (p *Proc) Addr() uintptr { 114 return p.addr 115 } 116 117 // Call executes procedure p with arguments a. It will panic, if more then 15 arguments 118 // are supplied. 119 // 120 // The returned error is always non-nil, constructed from the result of GetLastError. 121 // Callers must inspect the primary return value to decide whether an error occurred 122 // (according to the semantics of the specific function being called) before consulting 123 // the error. The error will be guaranteed to contain syscall.Errno. 124 func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) { 125 switch len(a) { 126 case 0: 127 return Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0) 128 case 1: 129 return Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0) 130 case 2: 131 return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0) 132 case 3: 133 return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2]) 134 case 4: 135 return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0) 136 case 5: 137 return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0) 138 case 6: 139 return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5]) 140 case 7: 141 return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0) 142 case 8: 143 return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], 0) 144 case 9: 145 return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]) 146 case 10: 147 return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], 0, 0) 148 case 11: 149 return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], 0) 150 case 12: 151 return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11]) 152 case 13: 153 return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], 0, 0) 154 case 14: 155 return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], 0) 156 case 15: 157 return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14]) 158 default: 159 panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".") 160 } 161 return 162 } 163 164 // A LazyDLL implements access to a single DLL. 165 // It will delay the load of the DLL until the first 166 // call to its Handle method or to one of its 167 // LazyProc's Addr method. 168 type LazyDLL struct { 169 mu sync.Mutex 170 dll *DLL // non nil once DLL is loaded 171 Name string 172 } 173 174 // Load loads DLL file d.Name into memory. It returns an error if fails. 175 // Load will not try to load DLL, if it is already loaded into memory. 176 func (d *LazyDLL) Load() error { 177 // Non-racy version of: 178 // if d.dll == nil { 179 if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll))) == nil { 180 d.mu.Lock() 181 defer d.mu.Unlock() 182 if d.dll == nil { 183 dll, e := LoadDLL(d.Name) 184 if e != nil { 185 return e 186 } 187 // Non-racy version of: 188 // d.dll = dll 189 atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll)), unsafe.Pointer(dll)) 190 } 191 } 192 return nil 193 } 194 195 // mustLoad is like Load but panics if search fails. 196 func (d *LazyDLL) mustLoad() { 197 e := d.Load() 198 if e != nil { 199 panic(e) 200 } 201 } 202 203 // Handle returns d's module handle. 204 func (d *LazyDLL) Handle() uintptr { 205 d.mustLoad() 206 return uintptr(d.dll.Handle) 207 } 208 209 // NewProc returns a LazyProc for accessing the named procedure in the DLL d. 210 func (d *LazyDLL) NewProc(name string) *LazyProc { 211 return &LazyProc{l: d, Name: name} 212 } 213 214 // NewLazyDLL creates new LazyDLL associated with DLL file. 215 func NewLazyDLL(name string) *LazyDLL { 216 return &LazyDLL{Name: name} 217 } 218 219 // A LazyProc implements access to a procedure inside a LazyDLL. 220 // It delays the lookup until the Addr method is called. 221 type LazyProc struct { 222 mu sync.Mutex 223 Name string 224 l *LazyDLL 225 proc *Proc 226 } 227 228 // Find searches DLL for procedure named p.Name. It returns 229 // an error if search fails. Find will not search procedure, 230 // if it is already found and loaded into memory. 231 func (p *LazyProc) Find() error { 232 // Non-racy version of: 233 // if p.proc == nil { 234 if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil { 235 p.mu.Lock() 236 defer p.mu.Unlock() 237 if p.proc == nil { 238 e := p.l.Load() 239 if e != nil { 240 return e 241 } 242 proc, e := p.l.dll.FindProc(p.Name) 243 if e != nil { 244 return e 245 } 246 // Non-racy version of: 247 // p.proc = proc 248 atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc)) 249 } 250 } 251 return nil 252 } 253 254 // mustFind is like Find but panics if search fails. 255 func (p *LazyProc) mustFind() { 256 e := p.Find() 257 if e != nil { 258 panic(e) 259 } 260 } 261 262 // Addr returns the address of the procedure represented by p. 263 // The return value can be passed to Syscall to run the procedure. 264 func (p *LazyProc) Addr() uintptr { 265 p.mustFind() 266 return p.proc.Addr() 267 } 268 269 // Call executes procedure p with arguments a. It will panic, if more then 15 arguments 270 // are supplied. 271 // 272 // The returned error is always non-nil, constructed from the result of GetLastError. 273 // Callers must inspect the primary return value to decide whether an error occurred 274 // (according to the semantics of the specific function being called) before consulting 275 // the error. The error will be guaranteed to contain syscall.Errno. 276 func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) { 277 p.mustFind() 278 return p.proc.Call(a...) 279 }