//go:build windows package pid import ( "errors" "os" "skapp/pkg/logger" "syscall" "unsafe" ) var pidFile = "./.pid" var ( kernel32 = syscall.NewLazyDLL("kernel32.dll") procLockFileEx = kernel32.NewProc("LockFileEx") procUnlockFileEx = kernel32.NewProc("UnlockFileEx") ) const ( fileFlagNormal = 0x00000080 lockfileExclusiveLock = 0x00000002 lockfileFailImmediately = 0x00000001 ) func (p *PidLock) Lock() error { _, err := os.Stat(p.file) if err == nil { os.Exit(0) } f, err := os.OpenFile(pidFile, os.O_RDONLY|os.O_CREATE, os.ModePerm) if err != nil { logger.Log.Fatalf("启动失败 进程锁文件 .pid 创建失败") return LockFail } p.lock = f _ = f.Sync() err = TryLockEX(f) if err != nil { logger.Log.Fatal(err.Error()) return LockFail } return nil } // LockSH places a shared lock on the file. If the file is already locked, waits until the file is released. func LockSH(fp *os.File) error { r1, errNo := wlock(fp, 0x0) return isWError(r1, errNo) } // LockEX places an exclusive lock on the file. If the file is already locked, waits until the file is released. func LockEX(fp *os.File) error { r1, errNo := wlock(fp, lockfileExclusiveLock) return isWError(r1, errNo) } // TryLockSH places a shared lock on the file. If the file is already locked, returns an error immediately. func TryLockSH(fp *os.File) error { r1, errNo := wlock(fp, lockfileFailImmediately) return isWError(r1, errNo) } // TryLockEX places an exclusive lock on the file. If the file is already locked, returns an error immediately. func TryLockEX(fp *os.File) error { r1, errNo := wlock(fp, lockfileExclusiveLock|lockfileFailImmediately) return isWError(r1, errNo) } // Unlock the file. func Unlock(fp *os.File) error { r1, _, errNo := syscall.SyscallN( procUnlockFileEx.Addr(), fp.Fd(), uintptr(0), uintptr(1), uintptr(0), uintptr(unsafe.Pointer(&syscall.Overlapped{})), 0, ) return isWError(r1, errNo) } func wlock(fp *os.File, flags uintptr) (uintptr, syscall.Errno) { r1, _, errNo := syscall.SyscallN( procLockFileEx.Addr(), fp.Fd(), flags, uintptr(0), uintptr(1), uintptr(0), uintptr(unsafe.Pointer(&syscall.Overlapped{})), ) return r1, errNo } func isWError(r1 uintptr, errNo syscall.Errno) error { if r1 != 1 { if errNo != 0 { return errors.New(errNo.Error()) } else { return syscall.EINVAL } } return nil } func (p *PidLock) UnLock() { _ = Unlock(p.lock) _ = p.lock.Close() _ = os.Remove(p.file) }