1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
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
}
|