aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/version/version_windows.go
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2019-05-01 11:14:12 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2019-05-01 11:14:12 +0200
commit2e4f8e31dad639e9e40b29552380d5ca4629d1bd (patch)
treeec8573073bf68253267ed741b60bf23b8e4554a3 /version/version_windows.go
parentui: support clipboard copying for log items (diff)
downloadwireguard-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.go83
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
+}