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