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