Home | History | Annotate | Download | only in syscall
      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.go.
     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 fails.
     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 	use(unsafe.Pointer(namep))
     76 	if e != 0 {
     77 		return nil, &DLLError{
     78 			Err:     e,
     79 			ObjName: name,
     80 			Msg:     "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(),
     81 		}
     82 	}
     83 	p := &Proc{
     84 		Dll:  d,
     85 		Name: name,
     86 		addr: a,
     87 	}
     88 	return p, nil
     89 }
     90 
     91 // MustFindProc is like FindProc but panics if search fails.
     92 func (d *DLL) MustFindProc(name string) *Proc {
     93 	p, e := d.FindProc(name)
     94 	if e != nil {
     95 		panic(e)
     96 	}
     97 	return p
     98 }
     99 
    100 // Release unloads DLL d from memory.
    101 func (d *DLL) Release() (err error) {
    102 	return FreeLibrary(d.Handle)
    103 }
    104 
    105 // A Proc implements access to a procedure inside a DLL.
    106 type Proc struct {
    107 	Dll  *DLL
    108 	Name string
    109 	addr uintptr
    110 }
    111 
    112 // Addr returns the address of the procedure represented by p.
    113 // The return value can be passed to Syscall to run the procedure.
    114 func (p *Proc) Addr() uintptr {
    115 	return p.addr
    116 }
    117 
    118 // Call executes procedure p with arguments a. It will panic, if more then 15 arguments
    119 // are supplied.
    120 //
    121 // The returned error is always non-nil, constructed from the result of GetLastError.
    122 // Callers must inspect the primary return value to decide whether an error occurred
    123 // (according to the semantics of the specific function being called) before consulting
    124 // the error. The error will be guaranteed to contain syscall.Errno.
    125 func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
    126 	switch len(a) {
    127 	case 0:
    128 		return Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0)
    129 	case 1:
    130 		return Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0)
    131 	case 2:
    132 		return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0)
    133 	case 3:
    134 		return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2])
    135 	case 4:
    136 		return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
    137 	case 5:
    138 		return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
    139 	case 6:
    140 		return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
    141 	case 7:
    142 		return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0)
    143 	case 8:
    144 		return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], 0)
    145 	case 9:
    146 		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])
    147 	case 10:
    148 		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)
    149 	case 11:
    150 		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)
    151 	case 12:
    152 		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])
    153 	case 13:
    154 		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)
    155 	case 14:
    156 		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)
    157 	case 15:
    158 		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])
    159 	default:
    160 		panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
    161 	}
    162 	return
    163 }
    164 
    165 // A LazyDLL implements access to a single DLL.
    166 // It will delay the load of the DLL until the first
    167 // call to its Handle method or to one of its
    168 // LazyProc's Addr method.
    169 type LazyDLL struct {
    170 	mu   sync.Mutex
    171 	dll  *DLL // non nil once DLL is loaded
    172 	Name string
    173 }
    174 
    175 // Load loads DLL file d.Name into memory. It returns an error if fails.
    176 // Load will not try to load DLL, if it is already loaded into memory.
    177 func (d *LazyDLL) Load() error {
    178 	// Non-racy version of:
    179 	// if d.dll == nil {
    180 	if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll))) == nil {
    181 		d.mu.Lock()
    182 		defer d.mu.Unlock()
    183 		if d.dll == nil {
    184 			dll, e := LoadDLL(d.Name)
    185 			if e != nil {
    186 				return e
    187 			}
    188 			// Non-racy version of:
    189 			// d.dll = dll
    190 			atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll)), unsafe.Pointer(dll))
    191 		}
    192 	}
    193 	return nil
    194 }
    195 
    196 // mustLoad is like Load but panics if search fails.
    197 func (d *LazyDLL) mustLoad() {
    198 	e := d.Load()
    199 	if e != nil {
    200 		panic(e)
    201 	}
    202 }
    203 
    204 // Handle returns d's module handle.
    205 func (d *LazyDLL) Handle() uintptr {
    206 	d.mustLoad()
    207 	return uintptr(d.dll.Handle)
    208 }
    209 
    210 // NewProc returns a LazyProc for accessing the named procedure in the DLL d.
    211 func (d *LazyDLL) NewProc(name string) *LazyProc {
    212 	return &LazyProc{l: d, Name: name}
    213 }
    214 
    215 // NewLazyDLL creates new LazyDLL associated with DLL file.
    216 func NewLazyDLL(name string) *LazyDLL {
    217 	return &LazyDLL{Name: name}
    218 }
    219 
    220 // A LazyProc implements access to a procedure inside a LazyDLL.
    221 // It delays the lookup until the Addr method is called.
    222 type LazyProc struct {
    223 	mu   sync.Mutex
    224 	Name string
    225 	l    *LazyDLL
    226 	proc *Proc
    227 }
    228 
    229 // Find searches DLL for procedure named p.Name. It returns
    230 // an error if search fails. Find will not search procedure,
    231 // if it is already found and loaded into memory.
    232 func (p *LazyProc) Find() error {
    233 	// Non-racy version of:
    234 	// if p.proc == nil {
    235 	if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil {
    236 		p.mu.Lock()
    237 		defer p.mu.Unlock()
    238 		if p.proc == nil {
    239 			e := p.l.Load()
    240 			if e != nil {
    241 				return e
    242 			}
    243 			proc, e := p.l.dll.FindProc(p.Name)
    244 			if e != nil {
    245 				return e
    246 			}
    247 			// Non-racy version of:
    248 			// p.proc = proc
    249 			atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc))
    250 		}
    251 	}
    252 	return nil
    253 }
    254 
    255 // mustFind is like Find but panics if search fails.
    256 func (p *LazyProc) mustFind() {
    257 	e := p.Find()
    258 	if e != nil {
    259 		panic(e)
    260 	}
    261 }
    262 
    263 // Addr returns the address of the procedure represented by p.
    264 // The return value can be passed to Syscall to run the procedure.
    265 func (p *LazyProc) Addr() uintptr {
    266 	p.mustFind()
    267 	return p.proc.Addr()
    268 }
    269 
    270 // Call executes procedure p with arguments a. It will panic, if more then 15 arguments
    271 // are supplied.
    272 //
    273 // The returned error is always non-nil, constructed from the result of GetLastError.
    274 // Callers must inspect the primary return value to decide whether an error occurred
    275 // (according to the semantics of the specific function being called) before consulting
    276 // the error. The error will be guaranteed to contain syscall.Errno.
    277 func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
    278 	p.mustFind()
    279 	return p.proc.Call(a...)
    280 }
    281