...

Source file src/syscall/dll_windows.go

     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		"internal/syscall/windows/sysdll"
     9		"sync"
    10		"sync/atomic"
    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.go.
    24	func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
    25	func Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
    26	func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
    27	func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2 uintptr, err Errno)
    28	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)
    29	func Syscall18(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18 uintptr) (r1, r2 uintptr, err Errno)
    30	func loadlibrary(filename *uint16) (handle uintptr, err Errno)
    31	func loadsystemlibrary(filename *uint16, absoluteFilepath *uint16) (handle uintptr, err Errno)
    32	func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err Errno)
    33	
    34	// A DLL implements access to a single DLL.
    35	type DLL struct {
    36		Name   string
    37		Handle Handle
    38	}
    39	
    40	// We use this for computing the absolute path for system DLLs on systems
    41	// where SEARCH_SYSTEM32 is not available.
    42	var systemDirectoryPrefix string
    43	
    44	func init() {
    45		n := uint32(MAX_PATH)
    46		for {
    47			b := make([]uint16, n)
    48			l, e := getSystemDirectory(&b[0], n)
    49			if e != nil {
    50				panic("Unable to determine system directory: " + e.Error())
    51			}
    52			if l <= n {
    53				systemDirectoryPrefix = UTF16ToString(b[:l]) + "\\"
    54				break
    55			}
    56			n = l
    57		}
    58	}
    59	
    60	// LoadDLL loads the named DLL file into memory.
    61	//
    62	// If name is not an absolute path and is not a known system DLL used by
    63	// Go, Windows will search for the named DLL in many locations, causing
    64	// potential DLL preloading attacks.
    65	//
    66	// Use LazyDLL in golang.org/x/sys/windows for a secure way to
    67	// load system DLLs.
    68	func LoadDLL(name string) (*DLL, error) {
    69		namep, err := UTF16PtrFromString(name)
    70		if err != nil {
    71			return nil, err
    72		}
    73		var h uintptr
    74		var e Errno
    75		if sysdll.IsSystemDLL[name] {
    76			absoluteFilepathp, err := UTF16PtrFromString(systemDirectoryPrefix + name)
    77			if err != nil {
    78				return nil, err
    79			}
    80			h, e = loadsystemlibrary(namep, absoluteFilepathp)
    81		} else {
    82			h, e = loadlibrary(namep)
    83		}
    84		if e != 0 {
    85			return nil, &DLLError{
    86				Err:     e,
    87				ObjName: name,
    88				Msg:     "Failed to load " + name + ": " + e.Error(),
    89			}
    90		}
    91		d := &DLL{
    92			Name:   name,
    93			Handle: Handle(h),
    94		}
    95		return d, nil
    96	}
    97	
    98	// MustLoadDLL is like LoadDLL but panics if load operation fails.
    99	func MustLoadDLL(name string) *DLL {
   100		d, e := LoadDLL(name)
   101		if e != nil {
   102			panic(e)
   103		}
   104		return d
   105	}
   106	
   107	// FindProc searches DLL d for procedure named name and returns *Proc
   108	// if found. It returns an error if search fails.
   109	func (d *DLL) FindProc(name string) (proc *Proc, err error) {
   110		namep, err := BytePtrFromString(name)
   111		if err != nil {
   112			return nil, err
   113		}
   114		a, e := getprocaddress(uintptr(d.Handle), namep)
   115		if e != 0 {
   116			return nil, &DLLError{
   117				Err:     e,
   118				ObjName: name,
   119				Msg:     "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(),
   120			}
   121		}
   122		p := &Proc{
   123			Dll:  d,
   124			Name: name,
   125			addr: a,
   126		}
   127		return p, nil
   128	}
   129	
   130	// MustFindProc is like FindProc but panics if search fails.
   131	func (d *DLL) MustFindProc(name string) *Proc {
   132		p, e := d.FindProc(name)
   133		if e != nil {
   134			panic(e)
   135		}
   136		return p
   137	}
   138	
   139	// Release unloads DLL d from memory.
   140	func (d *DLL) Release() (err error) {
   141		return FreeLibrary(d.Handle)
   142	}
   143	
   144	// A Proc implements access to a procedure inside a DLL.
   145	type Proc struct {
   146		Dll  *DLL
   147		Name string
   148		addr uintptr
   149	}
   150	
   151	// Addr returns the address of the procedure represented by p.
   152	// The return value can be passed to Syscall to run the procedure.
   153	func (p *Proc) Addr() uintptr {
   154		return p.addr
   155	}
   156	
   157	//go:uintptrescapes
   158	
   159	// Call executes procedure p with arguments a. It will panic if more than 18 arguments
   160	// are supplied.
   161	//
   162	// The returned error is always non-nil, constructed from the result of GetLastError.
   163	// Callers must inspect the primary return value to decide whether an error occurred
   164	// (according to the semantics of the specific function being called) before consulting
   165	// the error. The error will be guaranteed to contain syscall.Errno.
   166	func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
   167		switch len(a) {
   168		case 0:
   169			return Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0)
   170		case 1:
   171			return Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0)
   172		case 2:
   173			return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0)
   174		case 3:
   175			return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2])
   176		case 4:
   177			return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
   178		case 5:
   179			return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
   180		case 6:
   181			return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
   182		case 7:
   183			return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0)
   184		case 8:
   185			return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], 0)
   186		case 9:
   187			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])
   188		case 10:
   189			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)
   190		case 11:
   191			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)
   192		case 12:
   193			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])
   194		case 13:
   195			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)
   196		case 14:
   197			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)
   198		case 15:
   199			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])
   200		case 16:
   201			return Syscall18(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], a[15], 0, 0)
   202		case 17:
   203			return Syscall18(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], a[15], a[16], 0)
   204		case 18:
   205			return Syscall18(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], a[15], a[16], a[17])
   206		default:
   207			panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
   208		}
   209	}
   210	
   211	// A LazyDLL implements access to a single DLL.
   212	// It will delay the load of the DLL until the first
   213	// call to its Handle method or to one of its
   214	// LazyProc's Addr method.
   215	//
   216	// LazyDLL is subject to the same DLL preloading attacks as documented
   217	// on LoadDLL.
   218	//
   219	// Use LazyDLL in golang.org/x/sys/windows for a secure way to
   220	// load system DLLs.
   221	type LazyDLL struct {
   222		mu   sync.Mutex
   223		dll  *DLL // non nil once DLL is loaded
   224		Name string
   225	}
   226	
   227	// Load loads DLL file d.Name into memory. It returns an error if fails.
   228	// Load will not try to load DLL, if it is already loaded into memory.
   229	func (d *LazyDLL) Load() error {
   230		// Non-racy version of:
   231		// if d.dll == nil {
   232		if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll))) == nil {
   233			d.mu.Lock()
   234			defer d.mu.Unlock()
   235			if d.dll == nil {
   236				dll, e := LoadDLL(d.Name)
   237				if e != nil {
   238					return e
   239				}
   240				// Non-racy version of:
   241				// d.dll = dll
   242				atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll)), unsafe.Pointer(dll))
   243			}
   244		}
   245		return nil
   246	}
   247	
   248	// mustLoad is like Load but panics if search fails.
   249	func (d *LazyDLL) mustLoad() {
   250		e := d.Load()
   251		if e != nil {
   252			panic(e)
   253		}
   254	}
   255	
   256	// Handle returns d's module handle.
   257	func (d *LazyDLL) Handle() uintptr {
   258		d.mustLoad()
   259		return uintptr(d.dll.Handle)
   260	}
   261	
   262	// NewProc returns a LazyProc for accessing the named procedure in the DLL d.
   263	func (d *LazyDLL) NewProc(name string) *LazyProc {
   264		return &LazyProc{l: d, Name: name}
   265	}
   266	
   267	// NewLazyDLL creates new LazyDLL associated with DLL file.
   268	func NewLazyDLL(name string) *LazyDLL {
   269		return &LazyDLL{Name: name}
   270	}
   271	
   272	// A LazyProc implements access to a procedure inside a LazyDLL.
   273	// It delays the lookup until the Addr, Call, or Find method is called.
   274	type LazyProc struct {
   275		mu   sync.Mutex
   276		Name string
   277		l    *LazyDLL
   278		proc *Proc
   279	}
   280	
   281	// Find searches DLL for procedure named p.Name. It returns
   282	// an error if search fails. Find will not search procedure,
   283	// if it is already found and loaded into memory.
   284	func (p *LazyProc) Find() error {
   285		// Non-racy version of:
   286		// if p.proc == nil {
   287		if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil {
   288			p.mu.Lock()
   289			defer p.mu.Unlock()
   290			if p.proc == nil {
   291				e := p.l.Load()
   292				if e != nil {
   293					return e
   294				}
   295				proc, e := p.l.dll.FindProc(p.Name)
   296				if e != nil {
   297					return e
   298				}
   299				// Non-racy version of:
   300				// p.proc = proc
   301				atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc))
   302			}
   303		}
   304		return nil
   305	}
   306	
   307	// mustFind is like Find but panics if search fails.
   308	func (p *LazyProc) mustFind() {
   309		e := p.Find()
   310		if e != nil {
   311			panic(e)
   312		}
   313	}
   314	
   315	// Addr returns the address of the procedure represented by p.
   316	// The return value can be passed to Syscall to run the procedure.
   317	func (p *LazyProc) Addr() uintptr {
   318		p.mustFind()
   319		return p.proc.Addr()
   320	}
   321	
   322	//go:uintptrescapes
   323	
   324	// Call executes procedure p with arguments a. See the documentation of
   325	// Proc.Call for more information.
   326	func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
   327		p.mustFind()
   328		return p.proc.Call(a...)
   329	}
   330	

View as plain text