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