diff options
Diffstat (limited to 'vendor/golang.org/x/sys/windows/dll_windows.go')
-rw-r--r-- | vendor/golang.org/x/sys/windows/dll_windows.go | 416 |
1 files changed, 416 insertions, 0 deletions
diff --git a/vendor/golang.org/x/sys/windows/dll_windows.go b/vendor/golang.org/x/sys/windows/dll_windows.go new file mode 100644 index 0000000..115341f --- /dev/null +++ b/vendor/golang.org/x/sys/windows/dll_windows.go | |||
@@ -0,0 +1,416 @@ | |||
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 windows | ||
6 | |||
7 | import ( | ||
8 | "sync" | ||
9 | "sync/atomic" | ||
10 | "syscall" | ||
11 | "unsafe" | ||
12 | ) | ||
13 | |||
14 | // We need to use LoadLibrary and GetProcAddress from the Go runtime, because | ||
15 | // the these symbols are loaded by the system linker and are required to | ||
16 | // dynamically load additional symbols. Note that in the Go runtime, these | ||
17 | // return syscall.Handle and syscall.Errno, but these are the same, in fact, | ||
18 | // as windows.Handle and windows.Errno, and we intend to keep these the same. | ||
19 | |||
20 | //go:linkname syscall_loadlibrary syscall.loadlibrary | ||
21 | func syscall_loadlibrary(filename *uint16) (handle Handle, err Errno) | ||
22 | |||
23 | //go:linkname syscall_getprocaddress syscall.getprocaddress | ||
24 | func syscall_getprocaddress(handle Handle, procname *uint8) (proc uintptr, err Errno) | ||
25 | |||
26 | // DLLError describes reasons for DLL load failures. | ||
27 | type DLLError struct { | ||
28 | Err error | ||
29 | ObjName string | ||
30 | Msg string | ||
31 | } | ||
32 | |||
33 | func (e *DLLError) Error() string { return e.Msg } | ||
34 | |||
35 | func (e *DLLError) Unwrap() error { return e.Err } | ||
36 | |||
37 | // A DLL implements access to a single DLL. | ||
38 | type DLL struct { | ||
39 | Name string | ||
40 | Handle Handle | ||
41 | } | ||
42 | |||
43 | // LoadDLL loads DLL file into memory. | ||
44 | // | ||
45 | // Warning: using LoadDLL without an absolute path name is subject to | ||
46 | // DLL preloading attacks. To safely load a system DLL, use LazyDLL | ||
47 | // with System set to true, or use LoadLibraryEx directly. | ||
48 | func LoadDLL(name string) (dll *DLL, err error) { | ||
49 | namep, err := UTF16PtrFromString(name) | ||
50 | if err != nil { | ||
51 | return nil, err | ||
52 | } | ||
53 | h, e := syscall_loadlibrary(namep) | ||
54 | if e != 0 { | ||
55 | return nil, &DLLError{ | ||
56 | Err: e, | ||
57 | ObjName: name, | ||
58 | Msg: "Failed to load " + name + ": " + e.Error(), | ||
59 | } | ||
60 | } | ||
61 | d := &DLL{ | ||
62 | Name: name, | ||
63 | Handle: h, | ||
64 | } | ||
65 | return d, nil | ||
66 | } | ||
67 | |||
68 | // MustLoadDLL is like LoadDLL but panics if load operation failes. | ||
69 | func MustLoadDLL(name string) *DLL { | ||
70 | d, e := LoadDLL(name) | ||
71 | if e != nil { | ||
72 | panic(e) | ||
73 | } | ||
74 | return d | ||
75 | } | ||
76 | |||
77 | // FindProc searches DLL d for procedure named name and returns *Proc | ||
78 | // if found. It returns an error if search fails. | ||
79 | func (d *DLL) FindProc(name string) (proc *Proc, err error) { | ||
80 | namep, err := BytePtrFromString(name) | ||
81 | if err != nil { | ||
82 | return nil, err | ||
83 | } | ||
84 | a, e := syscall_getprocaddress(d.Handle, namep) | ||
85 | if e != 0 { | ||
86 | return nil, &DLLError{ | ||
87 | Err: e, | ||
88 | ObjName: name, | ||
89 | Msg: "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(), | ||
90 | } | ||
91 | } | ||
92 | p := &Proc{ | ||
93 | Dll: d, | ||
94 | Name: name, | ||
95 | addr: a, | ||
96 | } | ||
97 | return p, nil | ||
98 | } | ||
99 | |||
100 | // MustFindProc is like FindProc but panics if search fails. | ||
101 | func (d *DLL) MustFindProc(name string) *Proc { | ||
102 | p, e := d.FindProc(name) | ||
103 | if e != nil { | ||
104 | panic(e) | ||
105 | } | ||
106 | return p | ||
107 | } | ||
108 | |||
109 | // FindProcByOrdinal searches DLL d for procedure by ordinal and returns *Proc | ||
110 | // if found. It returns an error if search fails. | ||
111 | func (d *DLL) FindProcByOrdinal(ordinal uintptr) (proc *Proc, err error) { | ||
112 | a, e := GetProcAddressByOrdinal(d.Handle, ordinal) | ||
113 | name := "#" + itoa(int(ordinal)) | ||
114 | if e != nil { | ||
115 | return nil, &DLLError{ | ||
116 | Err: e, | ||
117 | ObjName: name, | ||
118 | Msg: "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(), | ||
119 | } | ||
120 | } | ||
121 | p := &Proc{ | ||
122 | Dll: d, | ||
123 | Name: name, | ||
124 | addr: a, | ||
125 | } | ||
126 | return p, nil | ||
127 | } | ||
128 | |||
129 | // MustFindProcByOrdinal is like FindProcByOrdinal but panics if search fails. | ||
130 | func (d *DLL) MustFindProcByOrdinal(ordinal uintptr) *Proc { | ||
131 | p, e := d.FindProcByOrdinal(ordinal) | ||
132 | if e != nil { | ||
133 | panic(e) | ||
134 | } | ||
135 | return p | ||
136 | } | ||
137 | |||
138 | // Release unloads DLL d from memory. | ||
139 | func (d *DLL) Release() (err error) { | ||
140 | return FreeLibrary(d.Handle) | ||
141 | } | ||
142 | |||
143 | // A Proc implements access to a procedure inside a DLL. | ||
144 | type Proc struct { | ||
145 | Dll *DLL | ||
146 | Name string | ||
147 | addr uintptr | ||
148 | } | ||
149 | |||
150 | // Addr returns the address of the procedure represented by p. | ||
151 | // The return value can be passed to Syscall to run the procedure. | ||
152 | func (p *Proc) Addr() uintptr { | ||
153 | return p.addr | ||
154 | } | ||
155 | |||
156 | //go:uintptrescapes | ||
157 | |||
158 | // Call executes procedure p with arguments a. It will panic, if more than 15 arguments | ||
159 | // are supplied. | ||
160 | // | ||
161 | // The returned error is always non-nil, constructed from the result of GetLastError. | ||
162 | // Callers must inspect the primary return value to decide whether an error occurred | ||
163 | // (according to the semantics of the specific function being called) before consulting | ||
164 | // the error. The error will be guaranteed to contain windows.Errno. | ||
165 | func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) { | ||
166 | switch len(a) { | ||
167 | case 0: | ||
168 | return syscall.Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0) | ||
169 | case 1: | ||
170 | return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0) | ||
171 | case 2: | ||
172 | return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0) | ||
173 | case 3: | ||
174 | return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2]) | ||
175 | case 4: | ||
176 | return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0) | ||
177 | case 5: | ||
178 | return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0) | ||
179 | case 6: | ||
180 | return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5]) | ||
181 | case 7: | ||
182 | return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0) | ||
183 | case 8: | ||
184 | return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], 0) | ||
185 | case 9: | ||
186 | return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]) | ||
187 | case 10: | ||
188 | return syscall.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) | ||
189 | case 11: | ||
190 | return syscall.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) | ||
191 | case 12: | ||
192 | return syscall.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]) | ||
193 | case 13: | ||
194 | return syscall.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) | ||
195 | case 14: | ||
196 | return syscall.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) | ||
197 | case 15: | ||
198 | return syscall.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]) | ||
199 | default: | ||
200 | panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".") | ||
201 | } | ||
202 | } | ||
203 | |||
204 | // A LazyDLL implements access to a single DLL. | ||
205 | // It will delay the load of the DLL until the first | ||
206 | // call to its Handle method or to one of its | ||
207 | // LazyProc's Addr method. | ||
208 | type LazyDLL struct { | ||
209 | Name string | ||
210 | |||
211 | // System determines whether the DLL must be loaded from the | ||
212 | // Windows System directory, bypassing the normal DLL search | ||
213 | // path. | ||
214 | System bool | ||
215 | |||
216 | mu sync.Mutex | ||
217 | dll *DLL // non nil once DLL is loaded | ||
218 | } | ||
219 | |||
220 | // Load loads DLL file d.Name into memory. It returns an error if fails. | ||
221 | // Load will not try to load DLL, if it is already loaded into memory. | ||
222 | func (d *LazyDLL) Load() error { | ||
223 | // Non-racy version of: | ||
224 | // if d.dll != nil { | ||
225 | if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll))) != nil { | ||
226 | return nil | ||
227 | } | ||
228 | d.mu.Lock() | ||
229 | defer d.mu.Unlock() | ||
230 | if d.dll != nil { | ||
231 | return nil | ||
232 | } | ||
233 | |||
234 | // kernel32.dll is special, since it's where LoadLibraryEx comes from. | ||
235 | // The kernel already special-cases its name, so it's always | ||
236 | // loaded from system32. | ||
237 | var dll *DLL | ||
238 | var err error | ||
239 | if d.Name == "kernel32.dll" { | ||
240 | dll, err = LoadDLL(d.Name) | ||
241 | } else { | ||
242 | dll, err = loadLibraryEx(d.Name, d.System) | ||
243 | } | ||
244 | if err != nil { | ||
245 | return err | ||
246 | } | ||
247 | |||
248 | // Non-racy version of: | ||
249 | // d.dll = dll | ||
250 | atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll)), unsafe.Pointer(dll)) | ||
251 | return nil | ||
252 | } | ||
253 | |||
254 | // mustLoad is like Load but panics if search fails. | ||
255 | func (d *LazyDLL) mustLoad() { | ||
256 | e := d.Load() | ||
257 | if e != nil { | ||
258 | panic(e) | ||
259 | } | ||
260 | } | ||
261 | |||
262 | // Handle returns d's module handle. | ||
263 | func (d *LazyDLL) Handle() uintptr { | ||
264 | d.mustLoad() | ||
265 | return uintptr(d.dll.Handle) | ||
266 | } | ||
267 | |||
268 | // NewProc returns a LazyProc for accessing the named procedure in the DLL d. | ||
269 | func (d *LazyDLL) NewProc(name string) *LazyProc { | ||
270 | return &LazyProc{l: d, Name: name} | ||
271 | } | ||
272 | |||
273 | // NewLazyDLL creates new LazyDLL associated with DLL file. | ||
274 | func NewLazyDLL(name string) *LazyDLL { | ||
275 | return &LazyDLL{Name: name} | ||
276 | } | ||
277 | |||
278 | // NewLazySystemDLL is like NewLazyDLL, but will only | ||
279 | // search Windows System directory for the DLL if name is | ||
280 | // a base name (like "advapi32.dll"). | ||
281 | func NewLazySystemDLL(name string) *LazyDLL { | ||
282 | return &LazyDLL{Name: name, System: true} | ||
283 | } | ||
284 | |||
285 | // A LazyProc implements access to a procedure inside a LazyDLL. | ||
286 | // It delays the lookup until the Addr method is called. | ||
287 | type LazyProc struct { | ||
288 | Name string | ||
289 | |||
290 | mu sync.Mutex | ||
291 | l *LazyDLL | ||
292 | proc *Proc | ||
293 | } | ||
294 | |||
295 | // Find searches DLL for procedure named p.Name. It returns | ||
296 | // an error if search fails. Find will not search procedure, | ||
297 | // if it is already found and loaded into memory. | ||
298 | func (p *LazyProc) Find() error { | ||
299 | // Non-racy version of: | ||
300 | // if p.proc == nil { | ||
301 | if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil { | ||
302 | p.mu.Lock() | ||
303 | defer p.mu.Unlock() | ||
304 | if p.proc == nil { | ||
305 | e := p.l.Load() | ||
306 | if e != nil { | ||
307 | return e | ||
308 | } | ||
309 | proc, e := p.l.dll.FindProc(p.Name) | ||
310 | if e != nil { | ||
311 | return e | ||
312 | } | ||
313 | // Non-racy version of: | ||
314 | // p.proc = proc | ||
315 | atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc)) | ||
316 | } | ||
317 | } | ||
318 | return nil | ||
319 | } | ||
320 | |||
321 | // mustFind is like Find but panics if search fails. | ||
322 | func (p *LazyProc) mustFind() { | ||
323 | e := p.Find() | ||
324 | if e != nil { | ||
325 | panic(e) | ||
326 | } | ||
327 | } | ||
328 | |||
329 | // Addr returns the address of the procedure represented by p. | ||
330 | // The return value can be passed to Syscall to run the procedure. | ||
331 | // It will panic if the procedure cannot be found. | ||
332 | func (p *LazyProc) Addr() uintptr { | ||
333 | p.mustFind() | ||
334 | return p.proc.Addr() | ||
335 | } | ||
336 | |||
337 | //go:uintptrescapes | ||
338 | |||
339 | // Call executes procedure p with arguments a. It will panic, if more than 15 arguments | ||
340 | // are supplied. It will also panic if the procedure cannot be found. | ||
341 | // | ||
342 | // The returned error is always non-nil, constructed from the result of GetLastError. | ||
343 | // Callers must inspect the primary return value to decide whether an error occurred | ||
344 | // (according to the semantics of the specific function being called) before consulting | ||
345 | // the error. The error will be guaranteed to contain windows.Errno. | ||
346 | func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) { | ||
347 | p.mustFind() | ||
348 | return p.proc.Call(a...) | ||
349 | } | ||
350 | |||
351 | var canDoSearchSystem32Once struct { | ||
352 | sync.Once | ||
353 | v bool | ||
354 | } | ||
355 | |||
356 | func initCanDoSearchSystem32() { | ||
357 | // https://msdn.microsoft.com/en-us/library/ms684179(v=vs.85).aspx says: | ||
358 | // "Windows 7, Windows Server 2008 R2, Windows Vista, and Windows | ||
359 | // Server 2008: The LOAD_LIBRARY_SEARCH_* flags are available on | ||
360 | // systems that have KB2533623 installed. To determine whether the | ||
361 | // flags are available, use GetProcAddress to get the address of the | ||
362 | // AddDllDirectory, RemoveDllDirectory, or SetDefaultDllDirectories | ||
363 | // function. If GetProcAddress succeeds, the LOAD_LIBRARY_SEARCH_* | ||
364 | // flags can be used with LoadLibraryEx." | ||
365 | canDoSearchSystem32Once.v = (modkernel32.NewProc("AddDllDirectory").Find() == nil) | ||
366 | } | ||
367 | |||
368 | func canDoSearchSystem32() bool { | ||
369 | canDoSearchSystem32Once.Do(initCanDoSearchSystem32) | ||
370 | return canDoSearchSystem32Once.v | ||
371 | } | ||
372 | |||
373 | func isBaseName(name string) bool { | ||
374 | for _, c := range name { | ||
375 | if c == ':' || c == '/' || c == '\\' { | ||
376 | return false | ||
377 | } | ||
378 | } | ||
379 | return true | ||
380 | } | ||
381 | |||
382 | // loadLibraryEx wraps the Windows LoadLibraryEx function. | ||
383 | // | ||
384 | // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179(v=vs.85).aspx | ||
385 | // | ||
386 | // If name is not an absolute path, LoadLibraryEx searches for the DLL | ||
387 | // in a variety of automatic locations unless constrained by flags. | ||
388 | // See: https://msdn.microsoft.com/en-us/library/ff919712%28VS.85%29.aspx | ||
389 | func loadLibraryEx(name string, system bool) (*DLL, error) { | ||
390 | loadDLL := name | ||
391 | var flags uintptr | ||
392 | if system { | ||
393 | if canDoSearchSystem32() { | ||
394 | flags = LOAD_LIBRARY_SEARCH_SYSTEM32 | ||
395 | } else if isBaseName(name) { | ||
396 | // WindowsXP or unpatched Windows machine | ||
397 | // trying to load "foo.dll" out of the system | ||
398 | // folder, but LoadLibraryEx doesn't support | ||
399 | // that yet on their system, so emulate it. | ||
400 | systemdir, err := GetSystemDirectory() | ||
401 | if err != nil { | ||
402 | return nil, err | ||
403 | } | ||
404 | loadDLL = systemdir + "\\" + name | ||
405 | } | ||
406 | } | ||
407 | h, err := LoadLibraryEx(loadDLL, 0, flags) | ||
408 | if err != nil { | ||
409 | return nil, err | ||
410 | } | ||
411 | return &DLL{Name: name, Handle: h}, nil | ||
412 | } | ||
413 | |||
414 | type errString string | ||
415 | |||
416 | func (s errString) Error() string { return string(s) } | ||