github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/sys/windows/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 windows
     6  
     7  import (
     8  	"sync"
     9  	"sync/atomic"
    10  	"syscall"
    11  	"unsafe"
    12  )
    13  
    14  // DLLError describes reasons for DLL load failures.
    15  type DLLError struct {
    16  	Err     error
    17  	ObjName string
    18  	Msg     string
    19  }
    20  
    21  func (e *DLLError) Error() string { return e.Msg }
    22  
    23  // Implemented in runtime/syscall_windows.goc; we provide jumps to them in our assembly file.
    24  func loadlibrary(filename *uint16) (handle uintptr, err syscall.Errno)
    25  func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err syscall.Errno)
    26  
    27  // A DLL implements access to a single DLL.
    28  type DLL struct {
    29  	Name   string
    30  	Handle Handle
    31  }
    32  
    33  // LoadDLL loads DLL file into memory.
    34  func LoadDLL(name string) (dll *DLL, err error) {
    35  	namep, err := UTF16PtrFromString(name)
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  	h, e := loadlibrary(namep)
    40  	if e != 0 {
    41  		return nil, &DLLError{
    42  			Err:     e,
    43  			ObjName: name,
    44  			Msg:     "Failed to load " + name + ": " + e.Error(),
    45  		}
    46  	}
    47  	d := &DLL{
    48  		Name:   name,
    49  		Handle: Handle(h),
    50  	}
    51  	return d, nil
    52  }
    53  
    54  // MustLoadDLL is like LoadDLL but panics if load operation failes.
    55  func MustLoadDLL(name string) *DLL {
    56  	d, e := LoadDLL(name)
    57  	if e != nil {
    58  		panic(e)
    59  	}
    60  	return d
    61  }
    62  
    63  // FindProc searches DLL d for procedure named name and returns *Proc
    64  // if found. It returns an error if search fails.
    65  func (d *DLL) FindProc(name string) (proc *Proc, err error) {
    66  	namep, err := BytePtrFromString(name)
    67  	if err != nil {
    68  		return nil, err
    69  	}
    70  	a, e := getprocaddress(uintptr(d.Handle), namep)
    71  	if e != 0 {
    72  		return nil, &DLLError{
    73  			Err:     e,
    74  			ObjName: name,
    75  			Msg:     "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(),
    76  		}
    77  	}
    78  	p := &Proc{
    79  		Dll:  d,
    80  		Name: name,
    81  		addr: a,
    82  	}
    83  	return p, nil
    84  }
    85  
    86  // MustFindProc is like FindProc but panics if search fails.
    87  func (d *DLL) MustFindProc(name string) *Proc {
    88  	p, e := d.FindProc(name)
    89  	if e != nil {
    90  		panic(e)
    91  	}
    92  	return p
    93  }
    94  
    95  // Release unloads DLL d from memory.
    96  func (d *DLL) Release() (err error) {
    97  	return FreeLibrary(d.Handle)
    98  }
    99  
   100  // A Proc implements access to a procedure inside a DLL.
   101  type Proc struct {
   102  	Dll  *DLL
   103  	Name string
   104  	addr uintptr
   105  }
   106  
   107  // Addr returns the address of the procedure represented by p.
   108  // The return value can be passed to Syscall to run the procedure.
   109  func (p *Proc) Addr() uintptr {
   110  	return p.addr
   111  }
   112  
   113  // Call executes procedure p with arguments a. It will panic, if more then 15 arguments
   114  // are supplied.
   115  //
   116  // The returned error is always non-nil, constructed from the result of GetLastError.
   117  // Callers must inspect the primary return value to decide whether an error occurred
   118  // (according to the semantics of the specific function being called) before consulting
   119  // the error. The error will be guaranteed to contain windows.Errno.
   120  func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
   121  	switch len(a) {
   122  	case 0:
   123  		return syscall.Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0)
   124  	case 1:
   125  		return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0)
   126  	case 2:
   127  		return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0)
   128  	case 3:
   129  		return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2])
   130  	case 4:
   131  		return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
   132  	case 5:
   133  		return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
   134  	case 6:
   135  		return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
   136  	case 7:
   137  		return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0)
   138  	case 8:
   139  		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)
   140  	case 9:
   141  		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])
   142  	case 10:
   143  		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)
   144  	case 11:
   145  		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)
   146  	case 12:
   147  		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])
   148  	case 13:
   149  		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)
   150  	case 14:
   151  		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)
   152  	case 15:
   153  		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])
   154  	default:
   155  		panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
   156  	}
   157  	return
   158  }
   159  
   160  // A LazyDLL implements access to a single DLL.
   161  // It will delay the load of the DLL until the first
   162  // call to its Handle method or to one of its
   163  // LazyProc's Addr method.
   164  type LazyDLL struct {
   165  	mu   sync.Mutex
   166  	dll  *DLL // non nil once DLL is loaded
   167  	Name string
   168  }
   169  
   170  // Load loads DLL file d.Name into memory. It returns an error if fails.
   171  // Load will not try to load DLL, if it is already loaded into memory.
   172  func (d *LazyDLL) Load() error {
   173  	// Non-racy version of:
   174  	// if d.dll == nil {
   175  	if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll))) == nil {
   176  		d.mu.Lock()
   177  		defer d.mu.Unlock()
   178  		if d.dll == nil {
   179  			dll, e := LoadDLL(d.Name)
   180  			if e != nil {
   181  				return e
   182  			}
   183  			// Non-racy version of:
   184  			// d.dll = dll
   185  			atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll)), unsafe.Pointer(dll))
   186  		}
   187  	}
   188  	return nil
   189  }
   190  
   191  // mustLoad is like Load but panics if search fails.
   192  func (d *LazyDLL) mustLoad() {
   193  	e := d.Load()
   194  	if e != nil {
   195  		panic(e)
   196  	}
   197  }
   198  
   199  // Handle returns d's module handle.
   200  func (d *LazyDLL) Handle() uintptr {
   201  	d.mustLoad()
   202  	return uintptr(d.dll.Handle)
   203  }
   204  
   205  // NewProc returns a LazyProc for accessing the named procedure in the DLL d.
   206  func (d *LazyDLL) NewProc(name string) *LazyProc {
   207  	return &LazyProc{l: d, Name: name}
   208  }
   209  
   210  // NewLazyDLL creates new LazyDLL associated with DLL file.
   211  func NewLazyDLL(name string) *LazyDLL {
   212  	return &LazyDLL{Name: name}
   213  }
   214  
   215  // A LazyProc implements access to a procedure inside a LazyDLL.
   216  // It delays the lookup until the Addr method is called.
   217  type LazyProc struct {
   218  	mu   sync.Mutex
   219  	Name string
   220  	l    *LazyDLL
   221  	proc *Proc
   222  }
   223  
   224  // Find searches DLL for procedure named p.Name. It returns
   225  // an error if search fails. Find will not search procedure,
   226  // if it is already found and loaded into memory.
   227  func (p *LazyProc) Find() error {
   228  	// Non-racy version of:
   229  	// if p.proc == nil {
   230  	if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil {
   231  		p.mu.Lock()
   232  		defer p.mu.Unlock()
   233  		if p.proc == nil {
   234  			e := p.l.Load()
   235  			if e != nil {
   236  				return e
   237  			}
   238  			proc, e := p.l.dll.FindProc(p.Name)
   239  			if e != nil {
   240  				return e
   241  			}
   242  			// Non-racy version of:
   243  			// p.proc = proc
   244  			atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc))
   245  		}
   246  	}
   247  	return nil
   248  }
   249  
   250  // mustFind is like Find but panics if search fails.
   251  func (p *LazyProc) mustFind() {
   252  	e := p.Find()
   253  	if e != nil {
   254  		panic(e)
   255  	}
   256  }
   257  
   258  // Addr returns the address of the procedure represented by p.
   259  // The return value can be passed to Syscall to run the procedure.
   260  func (p *LazyProc) Addr() uintptr {
   261  	p.mustFind()
   262  	return p.proc.Addr()
   263  }
   264  
   265  // Call executes procedure p with arguments a. It will panic, if more then 15 arguments
   266  // are supplied.
   267  //
   268  // The returned error is always non-nil, constructed from the result of GetLastError.
   269  // Callers must inspect the primary return value to decide whether an error occurred
   270  // (according to the semantics of the specific function being called) before consulting
   271  // the error. The error will be guaranteed to contain windows.Errno.
   272  func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
   273  	p.mustFind()
   274  	return p.proc.Call(a...)
   275  }