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 }