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  }