Source file
src/syscall/dll_windows.go
Documentation: syscall
1
2
3
4
5 package syscall
6
7 import (
8 "internal/itoa"
9 "internal/syscall/windows/sysdll"
10 "sync"
11 "sync/atomic"
12 "unsafe"
13 )
14
15
16 type DLLError struct {
17 Err error
18 ObjName string
19 Msg string
20 }
21
22 func (e *DLLError) Error() string { return e.Msg }
23
24 func (e *DLLError) Unwrap() error { return e.Err }
25
26
27
28 func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
29 func Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
30 func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
31 func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2 uintptr, err Errno)
32 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)
33 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)
34 func loadlibrary(filename *uint16) (handle uintptr, err Errno)
35 func loadsystemlibrary(filename *uint16, absoluteFilepath *uint16) (handle uintptr, err Errno)
36 func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err Errno)
37
38
39 type DLL struct {
40 Name string
41 Handle Handle
42 }
43
44
45
46 var systemDirectoryPrefix string
47
48 func init() {
49 n := uint32(MAX_PATH)
50 for {
51 b := make([]uint16, n)
52 l, e := getSystemDirectory(&b[0], n)
53 if e != nil {
54 panic("Unable to determine system directory: " + e.Error())
55 }
56 if l <= n {
57 systemDirectoryPrefix = UTF16ToString(b[:l]) + "\\"
58 break
59 }
60 n = l
61 }
62 }
63
64
65
66
67
68
69
70
71
72 func LoadDLL(name string) (*DLL, error) {
73 namep, err := UTF16PtrFromString(name)
74 if err != nil {
75 return nil, err
76 }
77 var h uintptr
78 var e Errno
79 if sysdll.IsSystemDLL[name] {
80 absoluteFilepathp, err := UTF16PtrFromString(systemDirectoryPrefix + name)
81 if err != nil {
82 return nil, err
83 }
84 h, e = loadsystemlibrary(namep, absoluteFilepathp)
85 } else {
86 h, e = loadlibrary(namep)
87 }
88 if e != 0 {
89 return nil, &DLLError{
90 Err: e,
91 ObjName: name,
92 Msg: "Failed to load " + name + ": " + e.Error(),
93 }
94 }
95 d := &DLL{
96 Name: name,
97 Handle: Handle(h),
98 }
99 return d, nil
100 }
101
102
103 func MustLoadDLL(name string) *DLL {
104 d, e := LoadDLL(name)
105 if e != nil {
106 panic(e)
107 }
108 return d
109 }
110
111
112
113 func (d *DLL) FindProc(name string) (proc *Proc, err error) {
114 namep, err := BytePtrFromString(name)
115 if err != nil {
116 return nil, err
117 }
118 a, e := getprocaddress(uintptr(d.Handle), namep)
119 if e != 0 {
120 return nil, &DLLError{
121 Err: e,
122 ObjName: name,
123 Msg: "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(),
124 }
125 }
126 p := &Proc{
127 Dll: d,
128 Name: name,
129 addr: a,
130 }
131 return p, nil
132 }
133
134
135 func (d *DLL) MustFindProc(name string) *Proc {
136 p, e := d.FindProc(name)
137 if e != nil {
138 panic(e)
139 }
140 return p
141 }
142
143
144 func (d *DLL) Release() (err error) {
145 return FreeLibrary(d.Handle)
146 }
147
148
149 type Proc struct {
150 Dll *DLL
151 Name string
152 addr uintptr
153 }
154
155
156
157 func (p *Proc) Addr() uintptr {
158 return p.addr
159 }
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178 func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
179 switch len(a) {
180 case 0:
181 return Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0)
182 case 1:
183 return Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0)
184 case 2:
185 return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0)
186 case 3:
187 return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2])
188 case 4:
189 return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
190 case 5:
191 return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
192 case 6:
193 return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
194 case 7:
195 return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0)
196 case 8:
197 return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], 0)
198 case 9:
199 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])
200 case 10:
201 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)
202 case 11:
203 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)
204 case 12:
205 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])
206 case 13:
207 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)
208 case 14:
209 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)
210 case 15:
211 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])
212 case 16:
213 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)
214 case 17:
215 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)
216 case 18:
217 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])
218 default:
219 panic("Call " + p.Name + " with too many arguments " + itoa.Itoa(len(a)) + ".")
220 }
221 }
222
223
224
225
226
227
228
229
230
231
232
233 type LazyDLL struct {
234 mu sync.Mutex
235 dll *DLL
236 Name string
237 }
238
239
240
241 func (d *LazyDLL) Load() error {
242
243
244 if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll))) == nil {
245 d.mu.Lock()
246 defer d.mu.Unlock()
247 if d.dll == nil {
248 dll, e := LoadDLL(d.Name)
249 if e != nil {
250 return e
251 }
252
253
254 atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll)), unsafe.Pointer(dll))
255 }
256 }
257 return nil
258 }
259
260
261 func (d *LazyDLL) mustLoad() {
262 e := d.Load()
263 if e != nil {
264 panic(e)
265 }
266 }
267
268
269 func (d *LazyDLL) Handle() uintptr {
270 d.mustLoad()
271 return uintptr(d.dll.Handle)
272 }
273
274
275 func (d *LazyDLL) NewProc(name string) *LazyProc {
276 return &LazyProc{l: d, Name: name}
277 }
278
279
280 func NewLazyDLL(name string) *LazyDLL {
281 return &LazyDLL{Name: name}
282 }
283
284
285
286 type LazyProc struct {
287 mu sync.Mutex
288 Name string
289 l *LazyDLL
290 proc *Proc
291 }
292
293
294
295
296 func (p *LazyProc) Find() error {
297
298
299 if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil {
300 p.mu.Lock()
301 defer p.mu.Unlock()
302 if p.proc == nil {
303 e := p.l.Load()
304 if e != nil {
305 return e
306 }
307 proc, e := p.l.dll.FindProc(p.Name)
308 if e != nil {
309 return e
310 }
311
312
313 atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc))
314 }
315 }
316 return nil
317 }
318
319
320 func (p *LazyProc) mustFind() {
321 e := p.Find()
322 if e != nil {
323 panic(e)
324 }
325 }
326
327
328
329 func (p *LazyProc) Addr() uintptr {
330 p.mustFind()
331 return p.proc.Addr()
332 }
333
334
335
336
337
338 func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
339 p.mustFind()
340 return p.proc.Call(a...)
341 }
342
View as plain text