github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/src/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  	"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 failes.
    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  }