github.com/iDigitalFlame/xmt@v0.5.4/device/winapi/y_base_loader.go (about)

     1  //go:build windows && !altload && !crypt
     2  // +build windows,!altload,!crypt
     3  
     4  // Copyright (C) 2020 - 2023 iDigitalFlame
     5  //
     6  // This program is free software: you can redistribute it and/or modify
     7  // it under the terms of the GNU General Public License as published by
     8  // the Free Software Foundation, either version 3 of the License, or
     9  // any later version.
    10  //
    11  // This program is distributed in the hope that it will be useful,
    12  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  // GNU General Public License for more details.
    15  //
    16  // You should have received a copy of the GNU General Public License
    17  // along with this program.  If not, see <https://www.gnu.org/licenses/>.
    18  //
    19  
    20  package winapi
    21  
    22  import (
    23  	"sync"
    24  	"sync/atomic"
    25  	"syscall"
    26  )
    27  
    28  type lazyDLL struct {
    29  	_    [0]func()
    30  	name string
    31  	sync.Mutex
    32  	addr uintptr
    33  }
    34  type lazyProc struct {
    35  	_    [0]func()
    36  	dll  *lazyDLL
    37  	name string
    38  	sync.Mutex
    39  	addr uintptr
    40  }
    41  
    42  func (d *lazyDLL) free() error {
    43  	if d.addr == 0 {
    44  		return nil
    45  	}
    46  	d.Lock()
    47  	err := syscall.FreeLibrary(syscall.Handle(d.addr))
    48  	atomic.StoreUintptr(&d.addr, 0)
    49  	d.Unlock()
    50  	return err
    51  }
    52  func (d *lazyDLL) load() error {
    53  	if atomic.LoadUintptr(&d.addr) > 0 {
    54  		return nil
    55  	}
    56  	d.Lock()
    57  	var (
    58  		h   uintptr
    59  		err error
    60  	)
    61  	if (len(d.name) == 12 || len(d.name) == 14) && d.name[0] == 'k' && d.name[2] == 'r' && d.name[3] == 'n' {
    62  		if h, err = loadDLL(d.name); fallbackLoad {
    63  			if h == 0 && len(d.name) == 14 {
    64  				// NOTE(dij): The "kernelbase.dll" file was not avaliable before
    65  				//            Windows 7 so we'll redirect all KernelBase calls to
    66  				//            Kernel32. We can tell this is "kernelbase.dll" fails
    67  				//            to load.
    68  				d.name = dllKernel32.name
    69  				h, err = loadDLL(dllKernel32.name)
    70  			}
    71  		}
    72  	} else {
    73  		h, err = loadLibraryEx(d.name)
    74  	}
    75  	if h > 0 {
    76  		atomic.StoreUintptr(&d.addr, h)
    77  	}
    78  	d.Unlock()
    79  	return err
    80  }
    81  func (p *lazyProc) find() error {
    82  	if atomic.LoadUintptr(&p.addr) > 0 {
    83  		return nil
    84  	}
    85  	var err error
    86  	p.Lock()
    87  	if err = p.dll.load(); err != nil {
    88  		p.Unlock()
    89  		return err
    90  	}
    91  	var h uintptr
    92  	if h, err = findProc(p.dll.addr, p.name, p.dll.name); err == nil {
    93  		atomic.StoreUintptr(&p.addr, h)
    94  	}
    95  	p.Unlock()
    96  	return err
    97  }
    98  func (d *lazyDLL) proc(n string) *lazyProc {
    99  	return &lazyProc{name: n, dll: d}
   100  }
   101  func (d *lazyDLL) sysProc(n string) *lazyProc {
   102  	if len(d.name) != 9 && d.name[0] != 'n' && d.name[1] != 't' {
   103  		return d.proc(n)
   104  	}
   105  	p := d.proc(n)
   106  	registerSyscall(p, n, 0)
   107  	return p
   108  }