mirror of
https://github.com/golang/sys.git
synced 2026-02-08 19:56:04 +03:00
All consts in errors_windows.go (except APPLICATION_ERROR) were "invented" at the start of windows port to have minimal impact on existing Go packages. No point keeping them around. Also remove Errno, since we will be using syscall.Errno everywhere anyway. LGTM=r R=golang-codereviews, r CC=golang-codereviews https://golang.org/cl/128290044
276 lines
7.8 KiB
Go
276 lines
7.8 KiB
Go
// Copyright 2011 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package windows
|
|
|
|
import (
|
|
"sync"
|
|
"sync/atomic"
|
|
"syscall"
|
|
"unsafe"
|
|
)
|
|
|
|
// DLLError describes reasons for DLL load failures.
|
|
type DLLError struct {
|
|
Err error
|
|
ObjName string
|
|
Msg string
|
|
}
|
|
|
|
func (e *DLLError) Error() string { return e.Msg }
|
|
|
|
// Implemented in runtime/syscall_windows.goc; we provide jumps to them in our assembly file.
|
|
func loadlibrary(filename *uint16) (handle uintptr, err syscall.Errno)
|
|
func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err syscall.Errno)
|
|
|
|
// A DLL implements access to a single DLL.
|
|
type DLL struct {
|
|
Name string
|
|
Handle Handle
|
|
}
|
|
|
|
// LoadDLL loads DLL file into memory.
|
|
func LoadDLL(name string) (dll *DLL, err error) {
|
|
namep, err := UTF16PtrFromString(name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
h, e := loadlibrary(namep)
|
|
if e != 0 {
|
|
return nil, &DLLError{
|
|
Err: e,
|
|
ObjName: name,
|
|
Msg: "Failed to load " + name + ": " + e.Error(),
|
|
}
|
|
}
|
|
d := &DLL{
|
|
Name: name,
|
|
Handle: Handle(h),
|
|
}
|
|
return d, nil
|
|
}
|
|
|
|
// MustLoadDLL is like LoadDLL but panics if load operation failes.
|
|
func MustLoadDLL(name string) *DLL {
|
|
d, e := LoadDLL(name)
|
|
if e != nil {
|
|
panic(e)
|
|
}
|
|
return d
|
|
}
|
|
|
|
// FindProc searches DLL d for procedure named name and returns *Proc
|
|
// if found. It returns an error if search fails.
|
|
func (d *DLL) FindProc(name string) (proc *Proc, err error) {
|
|
namep, err := BytePtrFromString(name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
a, e := getprocaddress(uintptr(d.Handle), namep)
|
|
if e != 0 {
|
|
return nil, &DLLError{
|
|
Err: e,
|
|
ObjName: name,
|
|
Msg: "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(),
|
|
}
|
|
}
|
|
p := &Proc{
|
|
Dll: d,
|
|
Name: name,
|
|
addr: a,
|
|
}
|
|
return p, nil
|
|
}
|
|
|
|
// MustFindProc is like FindProc but panics if search fails.
|
|
func (d *DLL) MustFindProc(name string) *Proc {
|
|
p, e := d.FindProc(name)
|
|
if e != nil {
|
|
panic(e)
|
|
}
|
|
return p
|
|
}
|
|
|
|
// Release unloads DLL d from memory.
|
|
func (d *DLL) Release() (err error) {
|
|
return FreeLibrary(d.Handle)
|
|
}
|
|
|
|
// A Proc implements access to a procedure inside a DLL.
|
|
type Proc struct {
|
|
Dll *DLL
|
|
Name string
|
|
addr uintptr
|
|
}
|
|
|
|
// Addr returns the address of the procedure represented by p.
|
|
// The return value can be passed to Syscall to run the procedure.
|
|
func (p *Proc) Addr() uintptr {
|
|
return p.addr
|
|
}
|
|
|
|
// Call executes procedure p with arguments a. It will panic, if more then 15 arguments
|
|
// are supplied.
|
|
//
|
|
// The returned error is always non-nil, constructed from the result of GetLastError.
|
|
// Callers must inspect the primary return value to decide whether an error occurred
|
|
// (according to the semantics of the specific function being called) before consulting
|
|
// the error. The error will be guaranteed to contain windows.Errno.
|
|
func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
|
|
switch len(a) {
|
|
case 0:
|
|
return syscall.Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0)
|
|
case 1:
|
|
return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0)
|
|
case 2:
|
|
return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0)
|
|
case 3:
|
|
return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2])
|
|
case 4:
|
|
return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
|
|
case 5:
|
|
return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
|
|
case 6:
|
|
return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
|
|
case 7:
|
|
return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0)
|
|
case 8:
|
|
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)
|
|
case 9:
|
|
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])
|
|
case 10:
|
|
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)
|
|
case 11:
|
|
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)
|
|
case 12:
|
|
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])
|
|
case 13:
|
|
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)
|
|
case 14:
|
|
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)
|
|
case 15:
|
|
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])
|
|
default:
|
|
panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
|
|
}
|
|
return
|
|
}
|
|
|
|
// A LazyDLL implements access to a single DLL.
|
|
// It will delay the load of the DLL until the first
|
|
// call to its Handle method or to one of its
|
|
// LazyProc's Addr method.
|
|
type LazyDLL struct {
|
|
mu sync.Mutex
|
|
dll *DLL // non nil once DLL is loaded
|
|
Name string
|
|
}
|
|
|
|
// Load loads DLL file d.Name into memory. It returns an error if fails.
|
|
// Load will not try to load DLL, if it is already loaded into memory.
|
|
func (d *LazyDLL) Load() error {
|
|
// Non-racy version of:
|
|
// if d.dll == nil {
|
|
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll))) == nil {
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
if d.dll == nil {
|
|
dll, e := LoadDLL(d.Name)
|
|
if e != nil {
|
|
return e
|
|
}
|
|
// Non-racy version of:
|
|
// d.dll = dll
|
|
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll)), unsafe.Pointer(dll))
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// mustLoad is like Load but panics if search fails.
|
|
func (d *LazyDLL) mustLoad() {
|
|
e := d.Load()
|
|
if e != nil {
|
|
panic(e)
|
|
}
|
|
}
|
|
|
|
// Handle returns d's module handle.
|
|
func (d *LazyDLL) Handle() uintptr {
|
|
d.mustLoad()
|
|
return uintptr(d.dll.Handle)
|
|
}
|
|
|
|
// NewProc returns a LazyProc for accessing the named procedure in the DLL d.
|
|
func (d *LazyDLL) NewProc(name string) *LazyProc {
|
|
return &LazyProc{l: d, Name: name}
|
|
}
|
|
|
|
// NewLazyDLL creates new LazyDLL associated with DLL file.
|
|
func NewLazyDLL(name string) *LazyDLL {
|
|
return &LazyDLL{Name: name}
|
|
}
|
|
|
|
// A LazyProc implements access to a procedure inside a LazyDLL.
|
|
// It delays the lookup until the Addr method is called.
|
|
type LazyProc struct {
|
|
mu sync.Mutex
|
|
Name string
|
|
l *LazyDLL
|
|
proc *Proc
|
|
}
|
|
|
|
// Find searches DLL for procedure named p.Name. It returns
|
|
// an error if search fails. Find will not search procedure,
|
|
// if it is already found and loaded into memory.
|
|
func (p *LazyProc) Find() error {
|
|
// Non-racy version of:
|
|
// if p.proc == nil {
|
|
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
if p.proc == nil {
|
|
e := p.l.Load()
|
|
if e != nil {
|
|
return e
|
|
}
|
|
proc, e := p.l.dll.FindProc(p.Name)
|
|
if e != nil {
|
|
return e
|
|
}
|
|
// Non-racy version of:
|
|
// p.proc = proc
|
|
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc))
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// mustFind is like Find but panics if search fails.
|
|
func (p *LazyProc) mustFind() {
|
|
e := p.Find()
|
|
if e != nil {
|
|
panic(e)
|
|
}
|
|
}
|
|
|
|
// Addr returns the address of the procedure represented by p.
|
|
// The return value can be passed to Syscall to run the procedure.
|
|
func (p *LazyProc) Addr() uintptr {
|
|
p.mustFind()
|
|
return p.proc.Addr()
|
|
}
|
|
|
|
// Call executes procedure p with arguments a. It will panic, if more then 15 arguments
|
|
// are supplied.
|
|
//
|
|
// The returned error is always non-nil, constructed from the result of GetLastError.
|
|
// Callers must inspect the primary return value to decide whether an error occurred
|
|
// (according to the semantics of the specific function being called) before consulting
|
|
// the error. The error will be guaranteed to contain windows.Errno.
|
|
func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
|
|
p.mustFind()
|
|
return p.proc.Call(a...)
|
|
}
|