github.com/sagernet/sing@v0.4.0-beta.19.0.20240518125136-f67a0988a636/common/winpowrprof/event_windows.go (about)

     1  package winpowrprof
     2  
     3  // modify from https://github.com/golang/go/blob/b634f6fdcbebee23b7da709a243f3db217b64776/src/runtime/os_windows.go#L257
     4  
     5  import (
     6  	"syscall"
     7  	"unsafe"
     8  
     9  	"golang.org/x/sys/windows"
    10  )
    11  
    12  var (
    13  	modpowerprof                                 = windows.NewLazySystemDLL("powrprof.dll")
    14  	procPowerRegisterSuspendResumeNotification   = modpowerprof.NewProc("PowerRegisterSuspendResumeNotification")
    15  	procPowerUnregisterSuspendResumeNotification = modpowerprof.NewProc("PowerUnregisterSuspendResumeNotification")
    16  )
    17  
    18  const (
    19  	PBT_APMSUSPEND         uint32 = 4
    20  	PBT_APMRESUMESUSPEND   uint32 = 7
    21  	PBT_APMRESUMEAUTOMATIC uint32 = 18
    22  )
    23  
    24  const (
    25  	_DEVICE_NOTIFY_CALLBACK = 2
    26  )
    27  
    28  type _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS struct {
    29  	callback uintptr
    30  	context  uintptr
    31  }
    32  
    33  type eventListener struct {
    34  	params _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS
    35  	handle uintptr
    36  }
    37  
    38  func NewEventListener(callback func(event int)) (EventListener, error) {
    39  	if err := procPowerRegisterSuspendResumeNotification.Find(); err != nil {
    40  		return nil, err // Running on Windows 7, where we don't need it anyway.
    41  	}
    42  	if err := procPowerUnregisterSuspendResumeNotification.Find(); err != nil {
    43  		return nil, err // Running on Windows 7, where we don't need it anyway.
    44  	}
    45  
    46  	var fn interface{} = func(context uintptr, changeType uint32, setting uintptr) uintptr {
    47  		switch changeType {
    48  		case PBT_APMSUSPEND:
    49  			callback(EVENT_SUSPEND)
    50  		case PBT_APMRESUMESUSPEND:
    51  			callback(EVENT_RESUME)
    52  		case PBT_APMRESUMEAUTOMATIC:
    53  			callback(EVENT_RESUME_AUTOMATIC)
    54  		}
    55  		return 0
    56  	}
    57  	return &eventListener{
    58  		params: _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS{
    59  			callback: windows.NewCallback(fn),
    60  		},
    61  	}, nil
    62  }
    63  
    64  func (l *eventListener) Start() error {
    65  	_, _, errno := syscall.SyscallN(
    66  		procPowerRegisterSuspendResumeNotification.Addr(),
    67  		_DEVICE_NOTIFY_CALLBACK,
    68  		uintptr(unsafe.Pointer(&l.params)),
    69  		uintptr(unsafe.Pointer(&l.handle)),
    70  	)
    71  	if errno != 0 {
    72  		return errno
    73  	}
    74  	return nil
    75  }
    76  
    77  func (l *eventListener) Close() error {
    78  	_, _, errno := syscall.SyscallN(procPowerUnregisterSuspendResumeNotification.Addr(), uintptr(unsafe.Pointer(&l.handle)))
    79  	if errno != 0 {
    80  		return errno
    81  	}
    82  	return nil
    83  }