@@ -59,6 +59,7 @@ static const char* inf_template[WDI_NB_DRIVERS-1] = {"winusb.inf.in", "libusb0.i
5959static const char * cat_template [WDI_NB_DRIVERS - 1 ] = {"winusb.cat.in" , "libusb0.cat.in" , "libusbk.cat.in" , "usbser.cat.in" };
6060static const char * ms_compat_id [WDI_NB_DRIVERS - 1 ] = {"MS_COMP_WINUSB" , "MS_COMP_LIBUSB0" , "MS_COMP_LIBUSBK" , "MS_COMP_USBSER" };
6161int nWindowsVersion = WINDOWS_UNDEFINED ;
62+ int nWindowsBuildNumber = -1 ;
6263char WindowsVersionStr [128 ] = "Windows " ;
6364
6465// Detect Windows version
@@ -76,27 +77,101 @@ BOOL is_x64(void)
7677 return ret ;
7778}
7879
79- // From smartmontools os_win32.cpp
80+ static const char * GetEdition (DWORD ProductType )
81+ {
82+ // From: https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getproductinfo
83+ // These values can be found in the winnt.h header.
84+ switch (ProductType ) {
85+ case 0x00000000 : return "" ; // Undefined
86+ case 0x00000001 : return "Ultimate" ;
87+ case 0x00000002 : return "Home Basic" ;
88+ case 0x00000003 : return "Home Premium" ;
89+ case 0x00000004 : return "Enterprise" ;
90+ case 0x00000005 : return "Home Basic N" ;
91+ case 0x00000006 : return "Business" ;
92+ case 0x00000007 : return "Standard Server" ;
93+ case 0x00000008 : return "Datacenter Server" ;
94+ case 0x00000009 : return "Smallbusiness Server" ;
95+ case 0x0000000A : return "Enterprise Server" ;
96+ case 0x0000000B : return "Starter" ;
97+ case 0x00000010 : return "Business N" ;
98+ case 0x00000011 : return "Web Server" ;
99+ case 0x00000012 : return "Cluster Server" ;
100+ case 0x00000013 : return "Home Server" ;
101+ case 0x0000001A : return "Home Premium N" ;
102+ case 0x0000001B : return "Enterprise N" ;
103+ case 0x0000001C : return "Ultimate N" ;
104+ case 0x00000022 : return "Home Premium Server" ;
105+ case 0x0000002F : return "Starter N" ;
106+ case 0x00000030 : return "Pro" ;
107+ case 0x00000031 : return "Pro N" ;
108+ case 0x00000042 : return "Starter E" ;
109+ case 0x00000043 : return "Home Basic E" ;
110+ case 0x00000044 : return "Premium E" ;
111+ case 0x00000045 : return "Pro E" ;
112+ case 0x00000046 : return "Enterprise E" ;
113+ case 0x00000047 : return "Ultimate E" ;
114+ case 0x00000048 : return "Enterprise Eval" ;
115+ case 0x00000054 : return "Enterprise N Eval" ;
116+ case 0x00000057 : return "Thin PC" ;
117+ case 0x0000006F : return "Core Connected" ;
118+ case 0x00000070 : return "Pro Student" ;
119+ case 0x00000071 : return "Core Connected N" ;
120+ case 0x00000072 : return "Pro Student N" ;
121+ case 0x00000073 : return "Core Connected Single Language" ;
122+ case 0x00000074 : return "Core Connected China" ;
123+ case 0x00000079 : return "Edu" ;
124+ case 0x0000007A : return "Edu N" ;
125+ case 0x0000007D : return "Enterprise S" ;
126+ case 0x0000007E : return "Enterprise S N" ;
127+ case 0x0000007F : return "Pro S" ;
128+ case 0x00000080 : return "Pro S N" ;
129+ case 0x00000081 : return "Enterprise S Eval" ;
130+ case 0x00000082 : return "Enterprise S N Eval" ;
131+ case 0x0000008A : return "Pro Single Language" ;
132+ case 0x0000008B : return "Pro China" ;
133+ case 0x0000008C : return "Enterprise Subscription" ;
134+ case 0x0000008D : return "Enterprise Subscription N" ;
135+ case 0x00000095 : return "Utility VM" ;
136+ case 0x000000A1 : return "Pro Workstation" ;
137+ case 0x000000A2 : return "Pro Workstation N" ;
138+ case 0x000000A4 : return "Pro for Education" ;
139+ case 0x000000A5 : return "Pro for Education N" ;
140+ case 0x000000AB : return "Enterprise G" ; // I swear Microsoft are just making up editions...
141+ case 0x000000AC : return "Enterprise G N" ;
142+ case 0x000000B6 : return "Core OS" ;
143+ case 0x000000B7 : return "Cloud E" ;
144+ case 0x000000B8 : return "Cloud E N" ;
145+ case 0x000000BD : return "Lite" ;
146+ case 0xABCDABCD : return "(Unlicensed)" ;
147+ default : return "(Unknown Edition)" ;
148+ }
149+ }
150+
151+ /*
152+ * Modified from smartmontools' os_win32.cpp
153+ */
80154void GetWindowsVersion (void )
81155{
82156 OSVERSIONINFOEXA vi , vi2 ;
157+ DWORD dwProductType ;
83158 const char * w = 0 ;
84159 const char * w64 = "32 bit" ;
85- char * vptr , build_number [ 10 ] = "" ;
160+ char * vptr ;
86161 size_t vlen ;
87162 unsigned major , minor ;
88163 ULONGLONG major_equal , minor_equal ;
89164 BOOL ws ;
90165
91166 nWindowsVersion = WINDOWS_UNDEFINED ;
92- safe_strcpy (WindowsVersionStr , sizeof ( WindowsVersionStr ) , "Windows Undefined" );
167+ static_strcpy (WindowsVersionStr , "Windows Undefined" );
93168
94169 memset (& vi , 0 , sizeof (vi ));
95170 vi .dwOSVersionInfoSize = sizeof (vi );
96- if (!GetVersionExA ((OSVERSIONINFOA * )& vi )) {
171+ if (!GetVersionExA ((OSVERSIONINFOA * )& vi )) {
97172 memset (& vi , 0 , sizeof (vi ));
98173 vi .dwOSVersionInfoSize = sizeof (OSVERSIONINFOA );
99- if (!GetVersionExA ((OSVERSIONINFOA * )& vi ))
174+ if (!GetVersionExA ((OSVERSIONINFOA * )& vi ))
100175 return ;
101176 }
102177
@@ -136,22 +211,30 @@ void GetWindowsVersion(void)
136211 ws = (vi .wProductType <= VER_NT_WORKSTATION );
137212 nWindowsVersion = vi .dwMajorVersion << 4 | vi .dwMinorVersion ;
138213 switch (nWindowsVersion ) {
139- case 0x61 : w = (ws ? "7" : "2008_R2" );
214+ case 0x51 : w = "XP" ;
215+ break ;
216+ case 0x52 : w = (!GetSystemMetrics (89 ) ? "Server 2003" : "Server 2003_R2" );
140217 break ;
141- case 0x62 : w = (ws ? "8 " : "2012 " );
218+ case 0x60 : w = (ws ? "Vista " : "Server 2008 " );
142219 break ;
143- case 0x63 : w = (ws ? "8.1" : "2012_R2" );
220+ case 0x61 : w = (ws ? "7" : "Server 2008_R2" );
221+ break ;
222+ case 0x62 : w = (ws ? "8" : "Server 2012" );
223+ break ;
224+ case 0x63 : w = (ws ? "8.1" : "Server 2012_R2" );
144225 break ;
145226 case 0x64 : w = (ws ? "10 (Preview 1)" : "Server 10 (Preview 1)" );
146227 break ;
147228 // Starting with Windows 10 Preview 2, the major is the same as the public-facing version
148- case 0xA0 : w = (ws ? "10" : "Server 10" );
229+ case 0xA0 : w = (ws ? ((vi .dwBuildNumber < 20000 ) ? "10" : "11" ) : ((vi .dwBuildNumber < 17763 ) ? "Server 2016" : "Server 2019" ));
230+ break ;
231+ case 0xB0 : w = (ws ? "11" : "Server 2022" );
149232 break ;
150233 default :
151- if (nWindowsVersion < 0x61 )
234+ if (nWindowsVersion < 0x51 )
152235 nWindowsVersion = WINDOWS_UNSUPPORTED ;
153236 else
154- w = "11 or later" ;
237+ w = "12 or later" ;
155238 break ;
156239 }
157240 }
@@ -160,6 +243,7 @@ void GetWindowsVersion(void)
160243 if (is_x64 ())
161244 w64 = "64-bit" ;
162245
246+ GetProductInfo (vi .dwMajorVersion , vi .dwMinorVersion , vi .wServicePackMajor , vi .wServicePackMinor , & dwProductType );
163247 vptr = & WindowsVersionStr [sizeof ("Windows " ) - 1 ];
164248 vlen = sizeof (WindowsVersionStr ) - sizeof ("Windows " ) - 1 ;
165249 if (!w )
@@ -170,19 +254,29 @@ void GetWindowsVersion(void)
170254 else if (vi .wServicePackMajor )
171255 safe_sprintf (vptr , vlen , "%s SP%u %s" , w , vi .wServicePackMajor , w64 );
172256 else
173- safe_sprintf (vptr , vlen , "%s %s" , w , w64 );
257+ safe_sprintf (vptr , vlen , "%s%s%s, %s" ,
258+ w , (dwProductType != PRODUCT_UNDEFINED ) ? " " : "" , GetEdition (dwProductType ), w64 );
174259
175- // Add the build number for Windows 8.0 and later
260+ // Add the build number (including UBR if available) for Windows 8.0 and later
261+ nWindowsBuildNumber = vi .dwBuildNumber ;
176262 if (nWindowsVersion >= 0x62 ) {
177- ReadRegistryStr (REGKEY_HKLM , "Microsoft\\Windows NT\\CurrentVersion\\CurrentBuildNumber" , build_number , sizeof (build_number ));
178- if (build_number [0 ] != 0 ) {
179- safe_strcat (WindowsVersionStr , sizeof (WindowsVersionStr ), " (Build " );
180- safe_strcat (WindowsVersionStr , sizeof (WindowsVersionStr ), build_number );
181- safe_strcat (WindowsVersionStr , sizeof (WindowsVersionStr ), ")" );
182- }
263+ HKEY hCurrentVersion ;
264+ DWORD dwType = REG_DWORD , dwSize = sizeof (DWORD ), dwUbr = 0 ;
265+ if (RegOpenKeyExA (REGKEY_HKLM , "Software\\Microsoft\\Windows NT\\CurrentVersion" ,
266+ 0 , KEY_READ , & hCurrentVersion ) == ERROR_SUCCESS ) {
267+ RegQueryValueExA (hCurrentVersion , "UBR" , NULL , & dwType , (LPBYTE )& dwUbr , & dwSize );
268+ RegCloseKey (hCurrentVersion );
269+ }
270+
271+ vptr = & WindowsVersionStr [safe_strlen (WindowsVersionStr )];
272+ vlen = sizeof (WindowsVersionStr ) - safe_strlen (WindowsVersionStr ) - 1 ;
273+ if (dwUbr != 0 )
274+ safe_sprintf (vptr , vlen , " (Build %d.%d)" , nWindowsBuildNumber , (int )dwUbr );
275+ else
276+ safe_sprintf (vptr , vlen , " (Build %d)" , nWindowsBuildNumber );
183277 }
184-
185278}
279+
186280/*
187281 * Converts a windows error to human readable string
188282 * uses retval as errorcode, or, if 0, use GetLastError()
0 commit comments