github.com/bugfan/wireguard-go@v0.0.0-20230720020150-a7b2fa340c66/tun/wintun/dll_windows.go (about) 1 /* SPDX-License-Identifier: MIT 2 * 3 * Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved. 4 */ 5 6 package wintun 7 8 import ( 9 "fmt" 10 "sync" 11 "sync/atomic" 12 "unsafe" 13 14 "golang.org/x/sys/windows" 15 ) 16 17 func newLazyDLL(name string, onLoad func(d *lazyDLL)) *lazyDLL { 18 return &lazyDLL{Name: name, onLoad: onLoad} 19 } 20 21 func (d *lazyDLL) NewProc(name string) *lazyProc { 22 return &lazyProc{dll: d, Name: name} 23 } 24 25 type lazyProc struct { 26 Name string 27 mu sync.Mutex 28 dll *lazyDLL 29 addr uintptr 30 } 31 32 func (p *lazyProc) Find() error { 33 if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.addr))) != nil { 34 return nil 35 } 36 p.mu.Lock() 37 defer p.mu.Unlock() 38 if p.addr != 0 { 39 return nil 40 } 41 42 err := p.dll.Load() 43 if err != nil { 44 return fmt.Errorf("Error loading %v DLL: %w", p.dll.Name, err) 45 } 46 addr, err := p.nameToAddr() 47 if err != nil { 48 return fmt.Errorf("Error getting %v address: %w", p.Name, err) 49 } 50 51 atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.addr)), unsafe.Pointer(addr)) 52 return nil 53 } 54 55 func (p *lazyProc) Addr() uintptr { 56 err := p.Find() 57 if err != nil { 58 panic(err) 59 } 60 return p.addr 61 } 62 63 type lazyDLL struct { 64 Name string 65 mu sync.Mutex 66 module windows.Handle 67 onLoad func(d *lazyDLL) 68 } 69 70 func (d *lazyDLL) Load() error { 71 if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.module))) != nil { 72 return nil 73 } 74 d.mu.Lock() 75 defer d.mu.Unlock() 76 if d.module != 0 { 77 return nil 78 } 79 80 const ( 81 LOAD_LIBRARY_SEARCH_APPLICATION_DIR = 0x00000200 82 LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800 83 ) 84 module, err := windows.LoadLibraryEx(d.Name, 0, LOAD_LIBRARY_SEARCH_APPLICATION_DIR|LOAD_LIBRARY_SEARCH_SYSTEM32) 85 if err != nil { 86 return fmt.Errorf("Unable to load library: %w", err) 87 } 88 89 atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.module)), unsafe.Pointer(module)) 90 if d.onLoad != nil { 91 d.onLoad(d) 92 } 93 return nil 94 } 95 96 func (p *lazyProc) nameToAddr() (uintptr, error) { 97 return windows.GetProcAddress(p.dll.module, p.Name) 98 }