The RtlGetNtVersionNumbers function is not documented by Microsoft.
Use RtlGetVersion instead, which is documented and available on all
supported versions of Windows.
Cq-Include-Trybots: luci.golang.try:gotip-windows-amd64-longtest,gotip-windows-arm64
Change-Id: Ibaf0e2c28e673951476c5d863a829fd166705aea
Reviewed-on: https://go-review.googlesource.com/c/go/+/571015
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
// Version returns the OS version name/number.
func Version() (string, error) {
- major, minor, patch := windows.RtlGetNtVersionNumbers()
- return fmt.Sprintf("%d.%d.%d", major, minor, patch), nil
+ info := windows.RtlGetVersion()
+ return fmt.Sprintf("%d.%d.%d", info.MajorVersion, info.MinorVersion, info.BuildNumber), nil
}
package windows
-//go:generate go run ../../../syscall/mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go security_windows.go psapi_windows.go symlink_windows.go
+//go:generate go run ../../../syscall/mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go security_windows.go psapi_windows.go symlink_windows.go version_windows.go
"unsafe"
)
+// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfow
+type _OSVERSIONINFOW struct {
+ osVersionInfoSize uint32
+ majorVersion uint32
+ minorVersion uint32
+ buildNumber uint32
+ platformId uint32
+ csdVersion [128]uint16
+}
+
+// According to documentation, RtlGetVersion function always succeeds.
+//sys rtlGetVersion(info *_OSVERSIONINFOW) = ntdll.RtlGetVersion
+
// version retrieves the major, minor, and build version numbers
-// of the current Windows OS from the RtlGetNtVersionNumbers API
-// and parse the results properly.
+// of the current Windows OS from the RtlGetVersion API.
func version() (major, minor, build uint32) {
- rtlGetNtVersionNumbers(&major, &minor, &build)
- build &= 0x7fff
- return
+ info := _OSVERSIONINFOW{}
+ info.osVersionInfoSize = uint32(unsafe.Sizeof(info))
+ rtlGetVersion(&info)
+ return info.majorVersion, info.minorVersion, info.buildNumber
}
-//go:linkname rtlGetNtVersionNumbers syscall.rtlGetNtVersionNumbers
-//go:noescape
-func rtlGetNtVersionNumbers(majorVersion *uint32, minorVersion *uint32, buildNumber *uint32)
-
var (
supportTCPKeepAliveIdle bool
supportTCPKeepAliveInterval bool
modiphlpapi = syscall.NewLazyDLL(sysdll.Add("iphlpapi.dll"))
modkernel32 = syscall.NewLazyDLL(sysdll.Add("kernel32.dll"))
modnetapi32 = syscall.NewLazyDLL(sysdll.Add("netapi32.dll"))
+ modntdll = syscall.NewLazyDLL(sysdll.Add("ntdll.dll"))
modpsapi = syscall.NewLazyDLL(sysdll.Add("psapi.dll"))
moduserenv = syscall.NewLazyDLL(sysdll.Add("userenv.dll"))
modws2_32 = syscall.NewLazyDLL(sysdll.Add("ws2_32.dll"))
procNetShareAdd = modnetapi32.NewProc("NetShareAdd")
procNetShareDel = modnetapi32.NewProc("NetShareDel")
procNetUserGetLocalGroups = modnetapi32.NewProc("NetUserGetLocalGroups")
+ procRtlGetVersion = modntdll.NewProc("RtlGetVersion")
procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo")
procCreateEnvironmentBlock = moduserenv.NewProc("CreateEnvironmentBlock")
procDestroyEnvironmentBlock = moduserenv.NewProc("DestroyEnvironmentBlock")
return
}
+func rtlGetVersion(info *_OSVERSIONINFOW) {
+ syscall.Syscall(procRtlGetVersion.Addr(), 1, uintptr(unsafe.Pointer(info)), 0, 0)
+ return
+}
+
func GetProcessMemoryInfo(handle syscall.Handle, memCounters *PROCESS_MEMORY_COUNTERS, cb uint32) (err error) {
r1, _, e1 := syscall.Syscall(procGetProcessMemoryInfo.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(memCounters)), uintptr(cb))
if r1 == 0 {
protect uint32
type_ uint32
}
+
+// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfow
+type _OSVERSIONINFOW struct {
+ osVersionInfoSize uint32
+ majorVersion uint32
+ minorVersion uint32
+ buildNumber uint32
+ platformId uint32
+ csdVersion [128]uint16
+}
_NtAssociateWaitCompletionPacket stdFunction
_NtCancelWaitCompletionPacket stdFunction
_RtlGetCurrentPeb stdFunction
- _RtlGetNtVersionNumbers stdFunction
+ _RtlGetVersion stdFunction
// These are from non-kernel32.dll, so we prefer to LoadLibraryEx them.
_timeBeginPeriod,
}
}
_RtlGetCurrentPeb = windowsFindfunc(n32, []byte("RtlGetCurrentPeb\000"))
- _RtlGetNtVersionNumbers = windowsFindfunc(n32, []byte("RtlGetNtVersionNumbers\000"))
+ _RtlGetVersion = windowsFindfunc(n32, []byte("RtlGetVersion\000"))
}
func monitorSuspendResume() {
)
// Check that we're ≥ 10.0.15063.
- var maj, min, build uint32
- stdcall3(_RtlGetNtVersionNumbers, uintptr(unsafe.Pointer(&maj)), uintptr(unsafe.Pointer(&min)), uintptr(unsafe.Pointer(&build)))
- if maj < 10 || (maj == 10 && min == 0 && build&0xffff < 15063) {
+ info := _OSVERSIONINFOW{}
+ info.osVersionInfoSize = uint32(unsafe.Sizeof(info))
+ stdcall1(_RtlGetVersion, uintptr(unsafe.Pointer(&info)))
+ if info.majorVersion < 10 || (info.majorVersion == 10 && info.minorVersion == 0 && info.buildNumber < 15063) {
return
}
//sys FreeLibrary(handle Handle) (err error)
//sys GetProcAddress(module Handle, procname string) (proc uintptr, err error)
//sys GetVersion() (ver uint32, err error)
-//sys rtlGetNtVersionNumbers(majorVersion *uint32, minorVersion *uint32, buildNumber *uint32) = ntdll.RtlGetNtVersionNumbers
//sys formatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) = FormatMessageW
//sys ExitProcess(exitcode uint32)
//sys CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) [failretval==InvalidHandle] = CreateFileW
modkernel32 = NewLazyDLL(sysdll.Add("kernel32.dll"))
modmswsock = NewLazyDLL(sysdll.Add("mswsock.dll"))
modnetapi32 = NewLazyDLL(sysdll.Add("netapi32.dll"))
- modntdll = NewLazyDLL(sysdll.Add("ntdll.dll"))
modsecur32 = NewLazyDLL(sysdll.Add("secur32.dll"))
modshell32 = NewLazyDLL(sysdll.Add("shell32.dll"))
moduserenv = NewLazyDLL(sysdll.Add("userenv.dll"))
procNetApiBufferFree = modnetapi32.NewProc("NetApiBufferFree")
procNetGetJoinInformation = modnetapi32.NewProc("NetGetJoinInformation")
procNetUserGetInfo = modnetapi32.NewProc("NetUserGetInfo")
- procRtlGetNtVersionNumbers = modntdll.NewProc("RtlGetNtVersionNumbers")
procGetUserNameExW = modsecur32.NewProc("GetUserNameExW")
procTranslateNameW = modsecur32.NewProc("TranslateNameW")
procCommandLineToArgvW = modshell32.NewProc("CommandLineToArgvW")
return
}
-func rtlGetNtVersionNumbers(majorVersion *uint32, minorVersion *uint32, buildNumber *uint32) {
- Syscall(procRtlGetNtVersionNumbers.Addr(), 3, uintptr(unsafe.Pointer(majorVersion)), uintptr(unsafe.Pointer(minorVersion)), uintptr(unsafe.Pointer(buildNumber)))
- return
-}
-
func GetUserNameEx(nameFormat uint32, nameBuffre *uint16, nSize *uint32) (err error) {
r1, _, e1 := Syscall(procGetUserNameExW.Addr(), 3, uintptr(nameFormat), uintptr(unsafe.Pointer(nameBuffre)), uintptr(unsafe.Pointer(nSize)))
if r1&0xff == 0 {