diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2019-05-01 11:14:12 +0200 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2019-05-01 11:14:12 +0200 |
commit | 2e4f8e31dad639e9e40b29552380d5ca4629d1bd (patch) | |
tree | ec8573073bf68253267ed741b60bf23b8e4554a3 /version/version_windows.go | |
parent | ui: support clipboard copying for log items (diff) | |
download | wireguard-windows-2e4f8e31dad639e9e40b29552380d5ca4629d1bd.tar.xz wireguard-windows-2e4f8e31dad639e9e40b29552380d5ca4629d1bd.zip |
version: dynamically get file version
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'version/version_windows.go')
-rw-r--r-- | version/version_windows.go | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/version/version_windows.go b/version/version_windows.go new file mode 100644 index 00000000..e567e7a0 --- /dev/null +++ b/version/version_windows.go @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. + */ + +package version + +import ( + "errors" + "fmt" + "golang.org/x/sys/windows" + "os" + "runtime" + "strings" + "unsafe" +) + +//sys GetFileVersionInfoSize(filename *uint16, zero *uint32) (size uint32, err error) = version.GetFileVersionInfoSizeW +//sys GetFileVersionInfo(filename *uint16, zero uint32, size uint32, block *byte) (err error) = version.GetFileVersionInfoW +//sys VerQueryValue(block *byte, section *uint16, value **byte, size *uint32) (err error) = version.VerQueryValueW + +type vsFixedFileInfo struct { + Signature uint32 + StrucVersion uint32 + FileVersionMS uint32 + FileVersionLS uint32 + ProductVersionMS uint32 + ProductVersionLS uint32 + FileFlagsMask uint32 + FileFlags uint32 + FileOS uint32 + FileType uint32 + FileSubtype uint32 + FileDateMS uint32 + FileDateLS uint32 +} + +const vsFixedFileInfoSignature = 0xFEEF04BD + +var cachedVersion string + +func RunningVersion() string { + if len(cachedVersion) != 0 { + return cachedVersion + } + key16 := []uint16{'\\', 0x00} + self, err := os.Executable() + if err != nil { + panic(err) + } + self16, err := windows.UTF16PtrFromString(self) + if err != nil { + panic(err) + } + var zero uint32 + size, err := GetFileVersionInfoSize(self16, &zero) + if err != nil { + panic(err) + } + buffer := make([]byte, size) + err = GetFileVersionInfo(self16, zero, size, &buffer[0]) + if err != nil { + panic(err) + } + var fixedFileInfo *vsFixedFileInfo + err = VerQueryValue(&buffer[0], &key16[0], (**byte)(unsafe.Pointer(&fixedFileInfo)), &size) + if err != nil { + panic(err) + } + if uintptr(size) < unsafe.Sizeof(vsFixedFileInfo{}) || fixedFileInfo == nil || fixedFileInfo.Signature != vsFixedFileInfoSignature { + panic(errors.New("Incorrect return of VS_FIXEDFILEINFO")) + } + version := fmt.Sprintf("%d.%d.%d.%d", (fixedFileInfo.FileVersionMS>>16)&0xffff, (fixedFileInfo.FileVersionMS>>0)&0xffff, (fixedFileInfo.FileVersionLS>>16)&0xffff, (fixedFileInfo.FileVersionLS>>0)&0xffff) + runtime.KeepAlive(buffer) // The win32 API aliases it in fixedFileInfo, but Go doesn't know that. + if strings.HasSuffix(version, ".0") { + version = version[:len(version)-2] + } + if strings.HasSuffix(version, ".0") { + version = version[:len(version)-2] + } + cachedVersion = version + return version +} |