2

I have an application which runs as a Word add-in. (VSTO).

It runs on many PCs all over the world. In certain cases I need to trouble shoot problems (obviously remotely) and have a reporting mechanism which tells me which Windows OS is running - I use Environment.OSVersion in .NET. At least it did until Windows 10.

There is an article on MSDN (Targeting your application for Windows) about creating an application manifest which will enable the correct version to be returned.

But my application is a DLL, not an EXE and so won't really accommodate the XML code referred to in that article.

Is there no way to just ask Windows, "What version are you? Really, I won't cry if you admit to the real version".

Or an entry in the registry or something?

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
Peter
  • 1,292
  • 4
  • 15
  • 33
  • 3
    http://stackoverflow.com/questions/18280055/check-windows-version-from-registry-c-sharp – kevintjuh93 Sep 17 '15 at 08:40
  • As an aside - why do you care what version you're running on? (Especially, as there will be different versions of Windows 10) – Rowland Shaw Sep 17 '15 at 08:43
  • I just want to be able to narrow down the situations in which errors occur. And knowing what OS does help with this. Maybe a particular error only happens on Windows 10 - it would be nice to know that. – Peter Sep 17 '15 at 08:46
  • Purely in case people find this looking for information on versions of Windows 10 via their local, friendly search engine: for Universal apps, there is a [good blog post on feature detection](http://blogs.windows.com/buildingapps/2015/09/15/dynamically-detecting-features-with-api-contracts-10-by-10/) – Rowland Shaw Sep 17 '15 at 08:52
  • Thank you Kevin Kal - that gave me what I wanted. – Peter Sep 17 '15 at 11:51

4 Answers4

1

If WMI is not an option for you, You could use the SDK counterparts of the GetVersionEx functions, RtlGetVersion. They don't lie.

If you use .NET 5.0 or Core, Environment.OSVersion reports the actual version of Windows.

I posted more detail about this as addition to the answers on this other thread: https://stackoverflow.com/a/64804643/2240196

EDIT: Added example code as requested. (You probably don't need all of it)

using System;
using System.Runtime.InteropServices;

namespace VersionHelper
{
    public static class VersionHelper
    {
        // The C(++) macro VER_SET_CONDITION mentioned in the documentation for RtlVerifyVersionInfo seems to be equivalent to the VerSetConditionMask function in kernel32.dll

        // https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-versetconditionmask
        [DllImport("kernel32.dll")]
        private static extern ulong VerSetConditionMask(ulong dwlConditionMask, uint dwTypeBitMask, byte dwConditionMask);

        // https://learn.microsoft.com/en-us/windows/win32/devnotes/rtlgetversion
        [DllImport("ntdll.dll")]
        private static extern int RtlGetVersion(ref OSVERSIONINFOW lpVersionInformation);

        [DllImport("ntdll.dll")]
        private static extern int RtlGetVersion(ref OSVERSIONINFOEXW lpVersionInformation);

        // https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-rtlverifyversioninfo
        [DllImport("ntdll.dll")]
        private static extern bool RtlVerifyVersionInfo([In] ref OSVERSIONINFOEXW lpVersionInformation, uint dwTypeMask, ulong dwlConditionMask);

        // https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-osversioninfoexw
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        private struct OSVERSIONINFOEXW
        {
            internal uint dwOSVersionInfoSize;
            internal uint dwMajorVersion;
            internal uint dwMinorVersion;
            internal uint dwBuildNumber;
            internal uint dwPlatformId;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
            internal string szCSDVersion;
            internal ushort wServicePackMajor;
            internal ushort wServicePackMinor;
            internal ushort wSuiteMask;
            internal byte wProductType;
            internal byte wReserved;
        }
        
        // https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-osversioninfow
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        private struct OSVERSIONINFOW
        {
            internal uint dwOSVersionInfoSize;
            internal uint dwMajorVersion;
            internal uint dwMinorVersion;
            internal uint dwBuildNumber;
            internal uint dwPlatformId;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
            internal string szCSDVersion;
        }

        /*
         * RTL_OSVERSIONINFOEX(A/W) and OSVERSIONINFOEX(A/W) are aliases for the same structures
         * RTL_OSVERSIONINFO(A/W) and OSVERSIONINFO(A/W) are aliases for the same structures
         * */

        // These constants initialized with corresponding definitions in
        // winnt.h (part of Windows SDK)
        // https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-ver_set_condition
        private const byte VER_EQUAL = 1;
        private const byte VER_GREATER = 2;
        private const byte VER_GREATER_EQUAL = 3;
        private const byte VER_LESS = 4;
        private const byte VER_LESS_EQUAL = 5;
        private const byte VER_AND = 6;
        private const byte VER_OR = 7;

        private const byte VER_CONDITION_MASK = 7;
        private const byte VER_NUM_BITS_PER_CONDITION_MASK = 3;

        private const uint STATUS_SUCCESS = 0x00000000;

        //
        // RtlVerifyVersionInfo() type mask bits
        //
        private const uint VER_MINORVERSION = 0x0000001;
        private const uint VER_MAJORVERSION = 0x0000002;
        private const uint VER_BUILDNUMBER = 0x0000004;
        private const uint VER_PLATFORMID = 0x0000008;
        private const uint VER_SERVICEPACKMINOR = 0x0000010;
        private const uint VER_SERVICEPACKMAJOR = 0x0000020;
        private const uint VER_SUITENAME = 0x0000040;
        private const uint VER_PRODUCT_TYPE = 0x0000080;

        // wProductType    
        // Any additional information about the system.This member can be one of the following values.
        private const byte VER_NT_DOMAIN_CONTROLLER = 0x0000002;
        private const byte VER_NT_SERVER = 0x0000003;
        private const byte VER_NT_WORKSTATION = 0x0000001;


        // You can customize this to check for the condition(s) you need using any field from the OSVERSIONINFOW struct with the corresponding VER_ and VER_<operator> constants
        public static bool IsWindowsVersionOrGreater(uint majorVersion, uint minorVersion, ushort servicePackMajor = 0, uint buildNumber = 0)
        {
            var osVerInfo = new OSVERSIONINFOEXW
            {
                dwOSVersionInfoSize = (uint) Marshal.SizeOf(typeof(OSVERSIONINFOEXW)),
                dwMajorVersion = majorVersion,
                dwMinorVersion = minorVersion,
                wServicePackMajor = servicePackMajor,
                dwBuildNumber = buildNumber
            };
            ulong versionOrGreaterMask = VerSetConditionMask(
                VerSetConditionMask(
                    VerSetConditionMask(
                        0, VER_MAJORVERSION, VER_GREATER_EQUAL),
                    VER_MINORVERSION, VER_GREATER_EQUAL),
                VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
            uint versionOrGreaterTypeMask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR;
            if (buildNumber > 0)
            {
                versionOrGreaterMask = VerSetConditionMask(versionOrGreaterMask, VER_BUILDNUMBER, VER_GREATER_EQUAL);
                versionOrGreaterTypeMask |= VER_BUILDNUMBER;
            }
            return RtlVerifyVersionInfo(ref osVerInfo, versionOrGreaterTypeMask, versionOrGreaterMask);
        }

        public static bool IsWindowsServer()
        {
            var osVerInfo = new OSVERSIONINFOEXW
            {
                dwOSVersionInfoSize = (uint) Marshal.SizeOf(typeof(OSVERSIONINFOEXW)),
                wProductType = VER_NT_WORKSTATION
            };
            ulong dwlConditionMask = VerSetConditionMask(0, VER_PRODUCT_TYPE, VER_EQUAL);
            return !RtlVerifyVersionInfo(ref osVerInfo, VER_PRODUCT_TYPE, dwlConditionMask);
        }
        
        public static int GetWindowsBuildNumber()
        {
            var osVerInfo = new OSVERSIONINFOW
            {
                dwOSVersionInfoSize = (uint) Marshal.SizeOf(typeof(OSVERSIONINFOW))
            };
            if (STATUS_SUCCESS == RtlGetVersion(ref osVerInfo)) // documented to always return STATUS_SUCCESS
                return (int)osVerInfo.dwBuildNumber;
            throw new Win32Exception("Failed to determine Windows build number.");
        }

        // Other functions replicating SDK Version Helper functions
        // https://learn.microsoft.com/en-us/windows/win32/sysinfo/version-helper-apis

        //
        // _WIN32_WINNT version constants
        //
        const ushort _WIN32_WINNT_NT4 = 0x0400;
        const ushort _WIN32_WINNT_WIN2K = 0x0500;
        const ushort _WIN32_WINNT_WINXP = 0x0501;
        const ushort _WIN32_WINNT_WS03 = 0x0502;
        const ushort _WIN32_WINNT_WIN6 = 0x0600;
        const ushort _WIN32_WINNT_VISTA = 0x0600;
        const ushort _WIN32_WINNT_WS08 = 0x0600;
        const ushort _WIN32_WINNT_LONGHORN = 0x0600;
        const ushort _WIN32_WINNT_WIN7 = 0x0601;
        const ushort _WIN32_WINNT_WIN8 = 0x0602;
        const ushort _WIN32_WINNT_WINBLUE = 0x0603;
        const ushort _WIN32_WINNT_WINTHRESHOLD = 0x0A00; 
        const ushort _WIN32_WINNT_WIN10 = 0x0A00;

        const bool FALSE = false;

        static byte LOBYTE(ushort w)
        {
            return ((byte)(w & 0xff));
        }

        static byte HIBYTE(ushort w)
        {
            return ((byte)(w >> 8 & 0xff));
        }

        public static bool
        IsWindowsXPSP1OrGreater()
        {
            return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 1);
        }

        public static bool
        IsWindowsXPSP2OrGreater()
        {
            return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 2);
        }

        public static bool
        IsWindowsXPSP3OrGreater()
        {
            return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 3);
        }

        public static bool
        IsWindowsVistaOrGreater()
        {
            return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 0);
        }

        public static bool
        IsWindowsVistaSP1OrGreater()
        {
            return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 1);
        }

        public static bool
        IsWindowsVistaSP2OrGreater()
        {
            return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 2);
        }

        public static bool
        IsWindows7OrGreater()
        {
            return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 0);
        }

        public static bool
        IsWindows7SP1OrGreater()
        {
            return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 1);
        }

        public static bool
        IsWindows8OrGreater()
        {
            return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8), LOBYTE(_WIN32_WINNT_WIN8), 0);
        }

        public static bool
        IsWindows8Point1OrGreater()
        {
            return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINBLUE), LOBYTE(_WIN32_WINNT_WINBLUE), 0);
        }

        public static bool
        IsWindows10OrGreater()
        {
            return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN10), LOBYTE(_WIN32_WINNT_WIN10), 0);
        }
    }
}
0
private String GetOSVersion()
{
    var wmiEnum = new ManagementObjectSearcher("root\\CIMV2", "SELECT Version FROM  Win32_OperatingSystem").Get().GetEnumerator();
    wmiEnum.MoveNext();
    return wmiEnum.Current.Properties["Version"].Value as String;
}

Returns 6.1.7601 on my W7 system and 10.0.14393 on my Server 2016 system.

No need to add a target manifest.

MikeZ
  • 1,155
  • 1
  • 13
  • 20
-1

WMI is the best way to do this kind of stuff You can use this to retrieve OS informations :

ManagementObjectSearcher objMOS = 
       new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM  Win32_OperatingSystem");

OS.Name = ((string)objMOS["Caption"]).Trim();
OS.Version = (string)objMOS["Version"];
OS.MaxProcessCount = (uint)objMOS["MaxNumberOfProcesses"];
OS.MaxProcessRAM = (ulong)objMOS["MaxProcessMemorySize"];
OS.Architecture = (string)objMOS["OSArchitecture"];
OS.SerialNumber = (string)objMOS["SerialNumber"];
OS.Build = ((string)objMOS["BuildNumber"]).ToUint();

This can fetch the OS details for you.

Mohit S
  • 13,723
  • 6
  • 34
  • 69
  • @Mohti, your code does not work, thats all I know. My coding skills do not mather – Black Aug 18 '17 at 16:32
  • @Mohit Black is right. Your code is crap. Thanks for wasting my time and the time of everyone else who stumbled upon this. – MikeZ Jan 05 '18 at 17:27
-1

You can try GetVersionEx Win32 API.

https://msdn.microsoft.com/en-us/library/windows/desktop/ms724451(v=vs.85).aspx

Note that Windows 10 in fact is version 6.4. Ver 6.0 is Vista, 6.1 - 7, 6.2 - 8.

i486
  • 6,491
  • 4
  • 24
  • 41
  • 1
    This only works if you've got the appropriate manifest entries. Otherwise, it'll just flat-out lie and tell you that everything is Windows 8. – Mark Mar 24 '16 at 22:02