| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- // Copyright 2011 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package windows
- import (
- "sync"
- "sync/atomic"
- "syscall"
- "unsafe"
- )
- // DLLError describes reasons for DLL load failures.
- type DLLError struct {
- Err error
- ObjName string
- Msg string
- }
- func (e *DLLError) Error() string { return e.Msg }
- // Implemented in runtime/syscall_windows.goc; we provide jumps to them in our assembly file.
- func loadlibrary(filename *uint16) (handle uintptr, err syscall.Errno)
- func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err syscall.Errno)
- // A DLL implements access to a single DLL.
- type DLL struct {
- Name string
- Handle Handle
- }
- // LoadDLL loads DLL file into memory.
- func LoadDLL(name string) (dll *DLL, err error) {
- namep, err := UTF16PtrFromString(name)
- if err != nil {
- return nil, err
- }
- h, e := loadlibrary(namep)
- if e != 0 {
- return nil, &DLLError{
- Err: e,
- ObjName: name,
- Msg: "Failed to load " + name + ": " + e.Error(),
- }
- }
- d := &DLL{
- Name: name,
- Handle: Handle(h),
- }
- return d, nil
- }
- // MustLoadDLL is like LoadDLL but panics if load operation failes.
- func MustLoadDLL(name string) *DLL {
- d, e := LoadDLL(name)
- if e != nil {
- panic(e)
- }
- return d
- }
- // FindProc searches DLL d for procedure named name and returns *Proc
- // if found. It returns an error if search fails.
- func (d *DLL) FindProc(name string) (proc *Proc, err error) {
- namep, err := BytePtrFromString(name)
- if err != nil {
- return nil, err
- }
- a, e := getprocaddress(uintptr(d.Handle), namep)
- if e != 0 {
- return nil, &DLLError{
- Err: e,
- ObjName: name,
- Msg: "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(),
- }
- }
- p := &Proc{
- Dll: d,
- Name: name,
- addr: a,
- }
- return p, nil
- }
- // MustFindProc is like FindProc but panics if search fails.
- func (d *DLL) MustFindProc(name string) *Proc {
- p, e := d.FindProc(name)
- if e != nil {
- panic(e)
- }
- return p
- }
- // Release unloads DLL d from memory.
- func (d *DLL) Release() (err error) {
- return FreeLibrary(d.Handle)
- }
- // A Proc implements access to a procedure inside a DLL.
- type Proc struct {
- Dll *DLL
- Name string
- addr uintptr
- }
- // Addr returns the address of the procedure represented by p.
- // The return value can be passed to Syscall to run the procedure.
- func (p *Proc) Addr() uintptr {
- return p.addr
- }
- // Call executes procedure p with arguments a. It will panic, if more then 15 arguments
- // are supplied.
- //
- // The returned error is always non-nil, constructed from the result of GetLastError.
- // Callers must inspect the primary return value to decide whether an error occurred
- // (according to the semantics of the specific function being called) before consulting
- // the error. The error will be guaranteed to contain windows.Errno.
- func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
- switch len(a) {
- case 0:
- return syscall.Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0)
- case 1:
- return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0)
- case 2:
- return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0)
- case 3:
- return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2])
- case 4:
- return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
- case 5:
- return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
- case 6:
- return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
- case 7:
- return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0)
- case 8:
- 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)
- case 9:
- 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])
- case 10:
- 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)
- case 11:
- 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)
- case 12:
- 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])
- case 13:
- 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)
- case 14:
- 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)
- case 15:
- 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])
- default:
- panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
- }
- return
- }
- // A LazyDLL implements access to a single DLL.
- // It will delay the load of the DLL until the first
- // call to its Handle method or to one of its
- // LazyProc's Addr method.
- type LazyDLL struct {
- mu sync.Mutex
- dll *DLL // non nil once DLL is loaded
- Name string
- }
- // Load loads DLL file d.Name into memory. It returns an error if fails.
- // Load will not try to load DLL, if it is already loaded into memory.
- func (d *LazyDLL) Load() error {
- // Non-racy version of:
- // if d.dll == nil {
- if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll))) == nil {
- d.mu.Lock()
- defer d.mu.Unlock()
- if d.dll == nil {
- dll, e := LoadDLL(d.Name)
- if e != nil {
- return e
- }
- // Non-racy version of:
- // d.dll = dll
- atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll)), unsafe.Pointer(dll))
- }
- }
- return nil
- }
- // mustLoad is like Load but panics if search fails.
- func (d *LazyDLL) mustLoad() {
- e := d.Load()
- if e != nil {
- panic(e)
- }
- }
- // Handle returns d's module handle.
- func (d *LazyDLL) Handle() uintptr {
- d.mustLoad()
- return uintptr(d.dll.Handle)
- }
- // NewProc returns a LazyProc for accessing the named procedure in the DLL d.
- func (d *LazyDLL) NewProc(name string) *LazyProc {
- return &LazyProc{l: d, Name: name}
- }
- // NewLazyDLL creates new LazyDLL associated with DLL file.
- func NewLazyDLL(name string) *LazyDLL {
- return &LazyDLL{Name: name}
- }
- // A LazyProc implements access to a procedure inside a LazyDLL.
- // It delays the lookup until the Addr method is called.
- type LazyProc struct {
- mu sync.Mutex
- Name string
- l *LazyDLL
- proc *Proc
- }
- // Find searches DLL for procedure named p.Name. It returns
- // an error if search fails. Find will not search procedure,
- // if it is already found and loaded into memory.
- func (p *LazyProc) Find() error {
- // Non-racy version of:
- // if p.proc == nil {
- if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil {
- p.mu.Lock()
- defer p.mu.Unlock()
- if p.proc == nil {
- e := p.l.Load()
- if e != nil {
- return e
- }
- proc, e := p.l.dll.FindProc(p.Name)
- if e != nil {
- return e
- }
- // Non-racy version of:
- // p.proc = proc
- atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc))
- }
- }
- return nil
- }
- // mustFind is like Find but panics if search fails.
- func (p *LazyProc) mustFind() {
- e := p.Find()
- if e != nil {
- panic(e)
- }
- }
- // Addr returns the address of the procedure represented by p.
- // The return value can be passed to Syscall to run the procedure.
- func (p *LazyProc) Addr() uintptr {
- p.mustFind()
- return p.proc.Addr()
- }
- // Call executes procedure p with arguments a. It will panic, if more then 15 arguments
- // are supplied.
- //
- // The returned error is always non-nil, constructed from the result of GetLastError.
- // Callers must inspect the primary return value to decide whether an error occurred
- // (according to the semantics of the specific function being called) before consulting
- // the error. The error will be guaranteed to contain windows.Errno.
- func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
- p.mustFind()
- return p.proc.Call(a...)
- }
|