vendor/golang.org/x/sys/windows/dll_windows.go
changeset 265 05c40b36d3b2
equal deleted inserted replaced
264:8f478162d991 265:05c40b36d3b2
       
     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 // We need to use LoadLibrary and GetProcAddress from the Go runtime, because
       
    15 // the these symbols are loaded by the system linker and are required to
       
    16 // dynamically load additional symbols. Note that in the Go runtime, these
       
    17 // return syscall.Handle and syscall.Errno, but these are the same, in fact,
       
    18 // as windows.Handle and windows.Errno, and we intend to keep these the same.
       
    19 
       
    20 //go:linkname syscall_loadlibrary syscall.loadlibrary
       
    21 func syscall_loadlibrary(filename *uint16) (handle Handle, err Errno)
       
    22 
       
    23 //go:linkname syscall_getprocaddress syscall.getprocaddress
       
    24 func syscall_getprocaddress(handle Handle, procname *uint8) (proc uintptr, err Errno)
       
    25 
       
    26 // DLLError describes reasons for DLL load failures.
       
    27 type DLLError struct {
       
    28 	Err     error
       
    29 	ObjName string
       
    30 	Msg     string
       
    31 }
       
    32 
       
    33 func (e *DLLError) Error() string { return e.Msg }
       
    34 
       
    35 func (e *DLLError) Unwrap() error { return e.Err }
       
    36 
       
    37 // A DLL implements access to a single DLL.
       
    38 type DLL struct {
       
    39 	Name   string
       
    40 	Handle Handle
       
    41 }
       
    42 
       
    43 // LoadDLL loads DLL file into memory.
       
    44 //
       
    45 // Warning: using LoadDLL without an absolute path name is subject to
       
    46 // DLL preloading attacks. To safely load a system DLL, use LazyDLL
       
    47 // with System set to true, or use LoadLibraryEx directly.
       
    48 func LoadDLL(name string) (dll *DLL, err error) {
       
    49 	namep, err := UTF16PtrFromString(name)
       
    50 	if err != nil {
       
    51 		return nil, err
       
    52 	}
       
    53 	h, e := syscall_loadlibrary(namep)
       
    54 	if e != 0 {
       
    55 		return nil, &DLLError{
       
    56 			Err:     e,
       
    57 			ObjName: name,
       
    58 			Msg:     "Failed to load " + name + ": " + e.Error(),
       
    59 		}
       
    60 	}
       
    61 	d := &DLL{
       
    62 		Name:   name,
       
    63 		Handle: h,
       
    64 	}
       
    65 	return d, nil
       
    66 }
       
    67 
       
    68 // MustLoadDLL is like LoadDLL but panics if load operation failes.
       
    69 func MustLoadDLL(name string) *DLL {
       
    70 	d, e := LoadDLL(name)
       
    71 	if e != nil {
       
    72 		panic(e)
       
    73 	}
       
    74 	return d
       
    75 }
       
    76 
       
    77 // FindProc searches DLL d for procedure named name and returns *Proc
       
    78 // if found. It returns an error if search fails.
       
    79 func (d *DLL) FindProc(name string) (proc *Proc, err error) {
       
    80 	namep, err := BytePtrFromString(name)
       
    81 	if err != nil {
       
    82 		return nil, err
       
    83 	}
       
    84 	a, e := syscall_getprocaddress(d.Handle, namep)
       
    85 	if e != 0 {
       
    86 		return nil, &DLLError{
       
    87 			Err:     e,
       
    88 			ObjName: name,
       
    89 			Msg:     "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(),
       
    90 		}
       
    91 	}
       
    92 	p := &Proc{
       
    93 		Dll:  d,
       
    94 		Name: name,
       
    95 		addr: a,
       
    96 	}
       
    97 	return p, nil
       
    98 }
       
    99 
       
   100 // MustFindProc is like FindProc but panics if search fails.
       
   101 func (d *DLL) MustFindProc(name string) *Proc {
       
   102 	p, e := d.FindProc(name)
       
   103 	if e != nil {
       
   104 		panic(e)
       
   105 	}
       
   106 	return p
       
   107 }
       
   108 
       
   109 // FindProcByOrdinal searches DLL d for procedure by ordinal and returns *Proc
       
   110 // if found. It returns an error if search fails.
       
   111 func (d *DLL) FindProcByOrdinal(ordinal uintptr) (proc *Proc, err error) {
       
   112 	a, e := GetProcAddressByOrdinal(d.Handle, ordinal)
       
   113 	name := "#" + itoa(int(ordinal))
       
   114 	if e != nil {
       
   115 		return nil, &DLLError{
       
   116 			Err:     e,
       
   117 			ObjName: name,
       
   118 			Msg:     "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(),
       
   119 		}
       
   120 	}
       
   121 	p := &Proc{
       
   122 		Dll:  d,
       
   123 		Name: name,
       
   124 		addr: a,
       
   125 	}
       
   126 	return p, nil
       
   127 }
       
   128 
       
   129 // MustFindProcByOrdinal is like FindProcByOrdinal but panics if search fails.
       
   130 func (d *DLL) MustFindProcByOrdinal(ordinal uintptr) *Proc {
       
   131 	p, e := d.FindProcByOrdinal(ordinal)
       
   132 	if e != nil {
       
   133 		panic(e)
       
   134 	}
       
   135 	return p
       
   136 }
       
   137 
       
   138 // Release unloads DLL d from memory.
       
   139 func (d *DLL) Release() (err error) {
       
   140 	return FreeLibrary(d.Handle)
       
   141 }
       
   142 
       
   143 // A Proc implements access to a procedure inside a DLL.
       
   144 type Proc struct {
       
   145 	Dll  *DLL
       
   146 	Name string
       
   147 	addr uintptr
       
   148 }
       
   149 
       
   150 // Addr returns the address of the procedure represented by p.
       
   151 // The return value can be passed to Syscall to run the procedure.
       
   152 func (p *Proc) Addr() uintptr {
       
   153 	return p.addr
       
   154 }
       
   155 
       
   156 //go:uintptrescapes
       
   157 
       
   158 // Call executes procedure p with arguments a. It will panic, if more than 15 arguments
       
   159 // are supplied.
       
   160 //
       
   161 // The returned error is always non-nil, constructed from the result of GetLastError.
       
   162 // Callers must inspect the primary return value to decide whether an error occurred
       
   163 // (according to the semantics of the specific function being called) before consulting
       
   164 // the error. The error will be guaranteed to contain windows.Errno.
       
   165 func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
       
   166 	switch len(a) {
       
   167 	case 0:
       
   168 		return syscall.Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0)
       
   169 	case 1:
       
   170 		return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0)
       
   171 	case 2:
       
   172 		return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0)
       
   173 	case 3:
       
   174 		return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2])
       
   175 	case 4:
       
   176 		return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
       
   177 	case 5:
       
   178 		return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
       
   179 	case 6:
       
   180 		return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
       
   181 	case 7:
       
   182 		return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0)
       
   183 	case 8:
       
   184 		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)
       
   185 	case 9:
       
   186 		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])
       
   187 	case 10:
       
   188 		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)
       
   189 	case 11:
       
   190 		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)
       
   191 	case 12:
       
   192 		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])
       
   193 	case 13:
       
   194 		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)
       
   195 	case 14:
       
   196 		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)
       
   197 	case 15:
       
   198 		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])
       
   199 	default:
       
   200 		panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
       
   201 	}
       
   202 }
       
   203 
       
   204 // A LazyDLL implements access to a single DLL.
       
   205 // It will delay the load of the DLL until the first
       
   206 // call to its Handle method or to one of its
       
   207 // LazyProc's Addr method.
       
   208 type LazyDLL struct {
       
   209 	Name string
       
   210 
       
   211 	// System determines whether the DLL must be loaded from the
       
   212 	// Windows System directory, bypassing the normal DLL search
       
   213 	// path.
       
   214 	System bool
       
   215 
       
   216 	mu  sync.Mutex
       
   217 	dll *DLL // non nil once DLL is loaded
       
   218 }
       
   219 
       
   220 // Load loads DLL file d.Name into memory. It returns an error if fails.
       
   221 // Load will not try to load DLL, if it is already loaded into memory.
       
   222 func (d *LazyDLL) Load() error {
       
   223 	// Non-racy version of:
       
   224 	// if d.dll != nil {
       
   225 	if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll))) != nil {
       
   226 		return nil
       
   227 	}
       
   228 	d.mu.Lock()
       
   229 	defer d.mu.Unlock()
       
   230 	if d.dll != nil {
       
   231 		return nil
       
   232 	}
       
   233 
       
   234 	// kernel32.dll is special, since it's where LoadLibraryEx comes from.
       
   235 	// The kernel already special-cases its name, so it's always
       
   236 	// loaded from system32.
       
   237 	var dll *DLL
       
   238 	var err error
       
   239 	if d.Name == "kernel32.dll" {
       
   240 		dll, err = LoadDLL(d.Name)
       
   241 	} else {
       
   242 		dll, err = loadLibraryEx(d.Name, d.System)
       
   243 	}
       
   244 	if err != nil {
       
   245 		return err
       
   246 	}
       
   247 
       
   248 	// Non-racy version of:
       
   249 	// d.dll = dll
       
   250 	atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll)), unsafe.Pointer(dll))
       
   251 	return nil
       
   252 }
       
   253 
       
   254 // mustLoad is like Load but panics if search fails.
       
   255 func (d *LazyDLL) mustLoad() {
       
   256 	e := d.Load()
       
   257 	if e != nil {
       
   258 		panic(e)
       
   259 	}
       
   260 }
       
   261 
       
   262 // Handle returns d's module handle.
       
   263 func (d *LazyDLL) Handle() uintptr {
       
   264 	d.mustLoad()
       
   265 	return uintptr(d.dll.Handle)
       
   266 }
       
   267 
       
   268 // NewProc returns a LazyProc for accessing the named procedure in the DLL d.
       
   269 func (d *LazyDLL) NewProc(name string) *LazyProc {
       
   270 	return &LazyProc{l: d, Name: name}
       
   271 }
       
   272 
       
   273 // NewLazyDLL creates new LazyDLL associated with DLL file.
       
   274 func NewLazyDLL(name string) *LazyDLL {
       
   275 	return &LazyDLL{Name: name}
       
   276 }
       
   277 
       
   278 // NewLazySystemDLL is like NewLazyDLL, but will only
       
   279 // search Windows System directory for the DLL if name is
       
   280 // a base name (like "advapi32.dll").
       
   281 func NewLazySystemDLL(name string) *LazyDLL {
       
   282 	return &LazyDLL{Name: name, System: true}
       
   283 }
       
   284 
       
   285 // A LazyProc implements access to a procedure inside a LazyDLL.
       
   286 // It delays the lookup until the Addr method is called.
       
   287 type LazyProc struct {
       
   288 	Name string
       
   289 
       
   290 	mu   sync.Mutex
       
   291 	l    *LazyDLL
       
   292 	proc *Proc
       
   293 }
       
   294 
       
   295 // Find searches DLL for procedure named p.Name. It returns
       
   296 // an error if search fails. Find will not search procedure,
       
   297 // if it is already found and loaded into memory.
       
   298 func (p *LazyProc) Find() error {
       
   299 	// Non-racy version of:
       
   300 	// if p.proc == nil {
       
   301 	if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil {
       
   302 		p.mu.Lock()
       
   303 		defer p.mu.Unlock()
       
   304 		if p.proc == nil {
       
   305 			e := p.l.Load()
       
   306 			if e != nil {
       
   307 				return e
       
   308 			}
       
   309 			proc, e := p.l.dll.FindProc(p.Name)
       
   310 			if e != nil {
       
   311 				return e
       
   312 			}
       
   313 			// Non-racy version of:
       
   314 			// p.proc = proc
       
   315 			atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc))
       
   316 		}
       
   317 	}
       
   318 	return nil
       
   319 }
       
   320 
       
   321 // mustFind is like Find but panics if search fails.
       
   322 func (p *LazyProc) mustFind() {
       
   323 	e := p.Find()
       
   324 	if e != nil {
       
   325 		panic(e)
       
   326 	}
       
   327 }
       
   328 
       
   329 // Addr returns the address of the procedure represented by p.
       
   330 // The return value can be passed to Syscall to run the procedure.
       
   331 // It will panic if the procedure cannot be found.
       
   332 func (p *LazyProc) Addr() uintptr {
       
   333 	p.mustFind()
       
   334 	return p.proc.Addr()
       
   335 }
       
   336 
       
   337 //go:uintptrescapes
       
   338 
       
   339 // Call executes procedure p with arguments a. It will panic, if more than 15 arguments
       
   340 // are supplied. It will also panic if the procedure cannot be found.
       
   341 //
       
   342 // The returned error is always non-nil, constructed from the result of GetLastError.
       
   343 // Callers must inspect the primary return value to decide whether an error occurred
       
   344 // (according to the semantics of the specific function being called) before consulting
       
   345 // the error. The error will be guaranteed to contain windows.Errno.
       
   346 func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
       
   347 	p.mustFind()
       
   348 	return p.proc.Call(a...)
       
   349 }
       
   350 
       
   351 var canDoSearchSystem32Once struct {
       
   352 	sync.Once
       
   353 	v bool
       
   354 }
       
   355 
       
   356 func initCanDoSearchSystem32() {
       
   357 	// https://msdn.microsoft.com/en-us/library/ms684179(v=vs.85).aspx says:
       
   358 	// "Windows 7, Windows Server 2008 R2, Windows Vista, and Windows
       
   359 	// Server 2008: The LOAD_LIBRARY_SEARCH_* flags are available on
       
   360 	// systems that have KB2533623 installed. To determine whether the
       
   361 	// flags are available, use GetProcAddress to get the address of the
       
   362 	// AddDllDirectory, RemoveDllDirectory, or SetDefaultDllDirectories
       
   363 	// function. If GetProcAddress succeeds, the LOAD_LIBRARY_SEARCH_*
       
   364 	// flags can be used with LoadLibraryEx."
       
   365 	canDoSearchSystem32Once.v = (modkernel32.NewProc("AddDllDirectory").Find() == nil)
       
   366 }
       
   367 
       
   368 func canDoSearchSystem32() bool {
       
   369 	canDoSearchSystem32Once.Do(initCanDoSearchSystem32)
       
   370 	return canDoSearchSystem32Once.v
       
   371 }
       
   372 
       
   373 func isBaseName(name string) bool {
       
   374 	for _, c := range name {
       
   375 		if c == ':' || c == '/' || c == '\\' {
       
   376 			return false
       
   377 		}
       
   378 	}
       
   379 	return true
       
   380 }
       
   381 
       
   382 // loadLibraryEx wraps the Windows LoadLibraryEx function.
       
   383 //
       
   384 // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179(v=vs.85).aspx
       
   385 //
       
   386 // If name is not an absolute path, LoadLibraryEx searches for the DLL
       
   387 // in a variety of automatic locations unless constrained by flags.
       
   388 // See: https://msdn.microsoft.com/en-us/library/ff919712%28VS.85%29.aspx
       
   389 func loadLibraryEx(name string, system bool) (*DLL, error) {
       
   390 	loadDLL := name
       
   391 	var flags uintptr
       
   392 	if system {
       
   393 		if canDoSearchSystem32() {
       
   394 			flags = LOAD_LIBRARY_SEARCH_SYSTEM32
       
   395 		} else if isBaseName(name) {
       
   396 			// WindowsXP or unpatched Windows machine
       
   397 			// trying to load "foo.dll" out of the system
       
   398 			// folder, but LoadLibraryEx doesn't support
       
   399 			// that yet on their system, so emulate it.
       
   400 			systemdir, err := GetSystemDirectory()
       
   401 			if err != nil {
       
   402 				return nil, err
       
   403 			}
       
   404 			loadDLL = systemdir + "\\" + name
       
   405 		}
       
   406 	}
       
   407 	h, err := LoadLibraryEx(loadDLL, 0, flags)
       
   408 	if err != nil {
       
   409 		return nil, err
       
   410 	}
       
   411 	return &DLL{Name: name, Handle: h}, nil
       
   412 }
       
   413 
       
   414 type errString string
       
   415 
       
   416 func (s errString) Error() string { return string(s) }