setupapi: Set LastError on success in SetupInstallFromInfSectionW.
[wine.git] / dlls / ntdll / version.c
blob167426150760ddf954804778f2040b330201b1ad
1 /*
2 * Windows and DOS version functions
4 * Copyright 1997 Marcus Meissner
5 * Copyright 1998 Patrik Stridvall
6 * Copyright 1998, 2003 Andreas Mohr
7 * Copyright 1997, 2003 Alexandre Julliard
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <string.h>
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include "ntstatus.h"
32 #define WIN32_NO_STATUS
33 #include "windef.h"
34 #include "wine/unicode.h"
35 #include "wine/debug.h"
36 #include "ntdll_misc.h"
37 #include "ddk/wdm.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(ver);
41 typedef enum
43 WIN20, /* Windows 2.0 */
44 WIN30, /* Windows 3.0 */
45 WIN31, /* Windows 3.1 */
46 WIN95, /* Windows 95 */
47 WIN98, /* Windows 98 */
48 WINME, /* Windows Me */
49 NT351, /* Windows NT 3.51 */
50 NT40, /* Windows NT 4.0 */
51 NT2K, /* Windows 2000 */
52 WINXP, /* Windows XP */
53 WINXP64, /* Windows XP 64-bit */
54 WIN2K3, /* Windows 2003 */
55 WINVISTA,/* Windows Vista */
56 WIN2K8, /* Windows 2008 */
57 WIN2K8R2,/* Windows 2008 R2 */
58 WIN7, /* Windows 7 */
59 WIN8, /* Windows 8 */
60 WIN81, /* Windows 8.1 */
61 WIN10, /* Windows 10 */
62 NB_WINDOWS_VERSIONS
63 } WINDOWS_VERSION;
65 /* FIXME: compare values below with original and fix.
66 * An *excellent* win9x version page (ALL versions !)
67 * can be found at www.mdgx.com/ver.htm */
68 static const RTL_OSVERSIONINFOEXW VersionData[NB_WINDOWS_VERSIONS] =
70 /* WIN20 FIXME: verify values */
72 sizeof(RTL_OSVERSIONINFOEXW), 2, 0, 0, VER_PLATFORM_WIN32s,
73 {'W','i','n','3','2','s',' ','1','.','3',0},
74 0, 0, 0, 0, 0
76 /* WIN30 FIXME: verify values */
78 sizeof(RTL_OSVERSIONINFOEXW), 3, 0, 0, VER_PLATFORM_WIN32s,
79 {'W','i','n','3','2','s',' ','1','.','3',0},
80 0, 0, 0, 0, 0
82 /* WIN31 */
84 sizeof(RTL_OSVERSIONINFOEXW), 3, 10, 0, VER_PLATFORM_WIN32s,
85 {'W','i','n','3','2','s',' ','1','.','3',0},
86 0, 0, 0, 0, 0
88 /* WIN95 */
90 /* Win95: 4, 0, 0x40003B6, ""
91 * Win95sp1: 4, 0, 0x40003B6, " A " (according to doc)
92 * Win95osr2: 4, 0, 0x4000457, " B " (according to doc)
93 * Win95osr2.1: 4, 3, 0x40304BC, " B " (according to doc)
94 * Win95osr2.5: 4, 3, 0x40304BE, " C " (according to doc)
95 * Win95a/b can be discerned via regkey SubVersionNumber
97 sizeof(RTL_OSVERSIONINFOEXW), 4, 0, 0x40003B6, VER_PLATFORM_WIN32_WINDOWS,
98 {0},
99 0, 0, 0, 0, 0
101 /* WIN98 (second edition) */
103 /* Win98: 4, 10, 0x40A07CE, " " 4.10.1998
104 * Win98SE: 4, 10, 0x40A08AE, " A " 4.10.2222
106 sizeof(RTL_OSVERSIONINFOEXW), 4, 10, 0x40A08AE, VER_PLATFORM_WIN32_WINDOWS,
107 {' ','A',' ',0},
108 0, 0, 0, 0, 0
110 /* WINME */
112 sizeof(RTL_OSVERSIONINFOEXW), 4, 90, 0x45A0BB8, VER_PLATFORM_WIN32_WINDOWS,
113 {' ',0},
114 0, 0, 0, 0, 0
116 /* NT351 */
118 sizeof(RTL_OSVERSIONINFOEXW), 3, 51, 0x421, VER_PLATFORM_WIN32_NT,
119 {'S','e','r','v','i','c','e',' ','P','a','c','k',' ','5',0},
120 5, 0, 0, VER_NT_WORKSTATION, 0
122 /* NT40 */
124 sizeof(RTL_OSVERSIONINFOEXW), 4, 0, 0x565, VER_PLATFORM_WIN32_NT,
125 {'S','e','r','v','i','c','e',' ','P','a','c','k',' ','6','a',0},
126 6, 0, 0, VER_NT_WORKSTATION, 0
128 /* NT2K */
130 sizeof(RTL_OSVERSIONINFOEXW), 5, 0, 0x893, VER_PLATFORM_WIN32_NT,
131 {'S','e','r','v','i','c','e',' ','P','a','c','k',' ','4',0},
132 4, 0, 0, VER_NT_WORKSTATION, 30 /* FIXME: Great, a reserved field with a value! */
134 /* WINXP */
136 sizeof(RTL_OSVERSIONINFOEXW), 5, 1, 0xA28, VER_PLATFORM_WIN32_NT,
137 {'S','e','r','v','i','c','e',' ','P','a','c','k',' ','3',0},
138 3, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 30 /* FIXME: Great, a reserved field with a value! */
140 /* WINXP64 */
142 sizeof(RTL_OSVERSIONINFOEXW), 5, 2, 0xECE, VER_PLATFORM_WIN32_NT,
143 {'S','e','r','v','i','c','e',' ','P','a','c','k',' ','2',0},
144 2, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 0
146 /* WIN2K3 */
148 sizeof(RTL_OSVERSIONINFOEXW), 5, 2, 0xECE, VER_PLATFORM_WIN32_NT,
149 {'S','e','r','v','i','c','e',' ','P','a','c','k',' ','2',0},
150 2, 0, VER_SUITE_SINGLEUSERTS, VER_NT_SERVER, 0
152 /* WINVISTA */
154 sizeof(RTL_OSVERSIONINFOEXW), 6, 0, 0x1772, VER_PLATFORM_WIN32_NT,
155 {'S','e','r','v','i','c','e',' ','P','a','c','k',' ','2',0},
156 2, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 0
158 /* WIN2K8 */
160 sizeof(RTL_OSVERSIONINFOEXW), 6, 0, 0x1772, VER_PLATFORM_WIN32_NT,
161 {'S','e','r','v','i','c','e',' ','P','a','c','k',' ','2',0},
162 2, 0, VER_SUITE_SINGLEUSERTS, VER_NT_SERVER, 0
164 /* WIN7 */
166 sizeof(RTL_OSVERSIONINFOEXW), 6, 1, 0x1DB1, VER_PLATFORM_WIN32_NT,
167 {'S','e','r','v','i','c','e',' ','P','a','c','k',' ','1',0},
168 1, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 0
170 /* WIN2K8R2 */
172 sizeof(RTL_OSVERSIONINFOEXW), 6, 1, 0x1DB1, VER_PLATFORM_WIN32_NT,
173 {'S','e','r','v','i','c','e',' ','P','a','c','k',' ','1',0},
174 1, 0, VER_SUITE_SINGLEUSERTS, VER_NT_SERVER, 0
176 /* WIN8 */
178 sizeof(RTL_OSVERSIONINFOEXW), 6, 2, 0x23F0, VER_PLATFORM_WIN32_NT,
179 {0}, 0, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 0
181 /* WIN81 */
183 sizeof(RTL_OSVERSIONINFOEXW), 6, 3, 0x2580, VER_PLATFORM_WIN32_NT,
184 {0}, 0, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 0
186 /* WIN10 */
188 sizeof(RTL_OSVERSIONINFOEXW), 10, 0, 0x3AD7, VER_PLATFORM_WIN32_NT,
189 {0}, 0, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 0
194 static const char * const WinVersionNames[NB_WINDOWS_VERSIONS] =
195 { /* no spaces in here ! */
196 "win20", /* WIN20 */
197 "win30", /* WIN30 */
198 "win31", /* WIN31 */
199 "win95", /* WIN95 */
200 "win98", /* WIN98 */
201 "winme", /* WINME */
202 "nt351", /* NT351 */
203 "nt40", /* NT40 */
204 "win2000,win2k,nt2k,nt2000", /* NT2K */
205 "winxp", /* WINXP */
206 "winxp64", /* WINXP64 */
207 "win2003,win2k3", /* WIN2K3 */
208 "vista,winvista", /* WINVISTA*/
209 "win2008,win2k8", /* WIN2K8 */
210 "win2008r2,win2k8r2", /* WIN2K8R2 */
211 "win7", /* WIN7 */
212 "win8", /* WIN8 */
213 "win81", /* WIN81 */
214 "win10", /* WIN10 */
218 /* initialized to null so that we crash if we try to retrieve the version too early at startup */
219 static const RTL_OSVERSIONINFOEXW *current_version;
222 /**********************************************************************
223 * get_nt_registry_version
225 * Fetch the version information from the NT-style registry keys.
227 static BOOL get_nt_registry_version( RTL_OSVERSIONINFOEXW *version )
229 static const WCHAR version_keyW[] = {'M','a','c','h','i','n','e','\\',
230 'S','o','f','t','w','a','r','e','\\',
231 'M','i','c','r','o','s','o','f','t','\\',
232 'W','i','n','d','o','w','s',' ','N','T','\\',
233 'C','u','r','r','e','n','t','V','e','r','s','i','o','n',0};
234 static const WCHAR service_pack_keyW[] = {'M','a','c','h','i','n','e','\\',
235 'S','y','s','t','e','m','\\',
236 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
237 'C','o','n','t','r','o','l','\\',
238 'W','i','n','d','o','w','s',0};
239 static const WCHAR product_keyW[] = {'M','a','c','h','i','n','e','\\',
240 'S','y','s','t','e','m','\\',
241 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
242 'C','o','n','t','r','o','l','\\',
243 'P','r','o','d','u','c','t','O','p','t','i','o','n','s',0};
244 static const WCHAR CurrentBuildNumberW[] = {'C','u','r','r','e','n','t','B','u','i','l','d','N','u','m','b','e','r',0};
245 static const WCHAR CSDVersionW[] = {'C','S','D','V','e','r','s','i','o','n',0};
246 static const WCHAR CurrentVersionW[] = {'C','u','r','r','e','n','t','V','e','r','s','i','o','n',0};
247 static const WCHAR ProductTypeW[] = {'P','r','o','d','u','c','t','T','y','p','e',0};
248 static const WCHAR WinNTW[] = {'W','i','n','N','T',0};
249 static const WCHAR ServerNTW[] = {'S','e','r','v','e','r','N','T',0};
250 static const WCHAR LanmanNTW[] = {'L','a','n','m','a','n','N','T',0};
252 OBJECT_ATTRIBUTES attr;
253 UNICODE_STRING nameW, valueW;
254 HANDLE hkey, hkey2;
255 char tmp[64];
256 DWORD count;
257 BOOL ret = FALSE;
258 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)tmp;
260 attr.Length = sizeof(attr);
261 attr.RootDirectory = 0;
262 attr.ObjectName = &nameW;
263 attr.Attributes = 0;
264 attr.SecurityDescriptor = NULL;
265 attr.SecurityQualityOfService = NULL;
266 RtlInitUnicodeString( &nameW, version_keyW );
268 if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )) return FALSE;
270 memset( version, 0, sizeof(*version) );
272 RtlInitUnicodeString( &valueW, CurrentVersionW );
273 if (!NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp)-1, &count ))
275 WCHAR *p, *str = (WCHAR *)info->Data;
276 str[info->DataLength / sizeof(WCHAR)] = 0;
277 p = strchrW( str, '.' );
278 if (p)
280 *p++ = 0;
281 version->dwMinorVersion = atoiW( p );
283 version->dwMajorVersion = atoiW( str );
286 if (version->dwMajorVersion) /* we got the main version, now fetch the other fields */
288 ret = TRUE;
289 version->dwPlatformId = VER_PLATFORM_WIN32_NT;
291 /* get build number */
293 RtlInitUnicodeString( &valueW, CurrentBuildNumberW );
294 if (!NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp)-1, &count ))
296 WCHAR *str = (WCHAR *)info->Data;
297 str[info->DataLength / sizeof(WCHAR)] = 0;
298 version->dwBuildNumber = atoiW( str );
301 /* get version description */
303 RtlInitUnicodeString( &valueW, CSDVersionW );
304 if (!NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp)-1, &count ))
306 DWORD len = min( info->DataLength, sizeof(version->szCSDVersion) - sizeof(WCHAR) );
307 memcpy( version->szCSDVersion, info->Data, len );
308 version->szCSDVersion[len / sizeof(WCHAR)] = 0;
311 /* get service pack version */
313 RtlInitUnicodeString( &nameW, service_pack_keyW );
314 if (!NtOpenKey( &hkey2, KEY_ALL_ACCESS, &attr ))
316 RtlInitUnicodeString( &valueW, CSDVersionW );
317 if (!NtQueryValueKey( hkey2, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
319 if (info->DataLength >= sizeof(DWORD))
321 DWORD dw = *(DWORD *)info->Data;
322 version->wServicePackMajor = LOWORD(dw) >> 8;
323 version->wServicePackMinor = LOWORD(dw) & 0xff;
326 NtClose( hkey2 );
329 /* get product type */
331 RtlInitUnicodeString( &nameW, product_keyW );
332 if (!NtOpenKey( &hkey2, KEY_ALL_ACCESS, &attr ))
334 RtlInitUnicodeString( &valueW, ProductTypeW );
335 if (!NtQueryValueKey( hkey2, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp)-1, &count ))
337 WCHAR *str = (WCHAR *)info->Data;
338 str[info->DataLength / sizeof(WCHAR)] = 0;
339 if (!strcmpiW( str, WinNTW )) version->wProductType = VER_NT_WORKSTATION;
340 else if (!strcmpiW( str, LanmanNTW )) version->wProductType = VER_NT_DOMAIN_CONTROLLER;
341 else if (!strcmpiW( str, ServerNTW )) version->wProductType = VER_NT_SERVER;
343 NtClose( hkey2 );
346 /* FIXME: get wSuiteMask */
349 NtClose( hkey );
350 return ret;
354 /**********************************************************************
355 * get_win9x_registry_version
357 * Fetch the version information from the Win9x-style registry keys.
359 static BOOL get_win9x_registry_version( RTL_OSVERSIONINFOEXW *version )
361 static const WCHAR version_keyW[] = {'M','a','c','h','i','n','e','\\',
362 'S','o','f','t','w','a','r','e','\\',
363 'M','i','c','r','o','s','o','f','t','\\',
364 'W','i','n','d','o','w','s','\\',
365 'C','u','r','r','e','n','t','V','e','r','s','i','o','n',0};
366 static const WCHAR VersionNumberW[] = {'V','e','r','s','i','o','n','N','u','m','b','e','r',0};
367 static const WCHAR SubVersionNumberW[] = {'S','u','b','V','e','r','s','i','o','n','N','u','m','b','e','r',0};
369 OBJECT_ATTRIBUTES attr;
370 UNICODE_STRING nameW, valueW;
371 HANDLE hkey;
372 char tmp[64];
373 DWORD count;
374 BOOL ret = FALSE;
375 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)tmp;
377 attr.Length = sizeof(attr);
378 attr.RootDirectory = 0;
379 attr.ObjectName = &nameW;
380 attr.Attributes = 0;
381 attr.SecurityDescriptor = NULL;
382 attr.SecurityQualityOfService = NULL;
383 RtlInitUnicodeString( &nameW, version_keyW );
385 if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )) return FALSE;
387 memset( version, 0, sizeof(*version) );
389 RtlInitUnicodeString( &valueW, VersionNumberW );
390 if (!NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp)-1, &count ))
392 WCHAR *p, *str = (WCHAR *)info->Data;
393 str[info->DataLength / sizeof(WCHAR)] = 0;
394 p = strchrW( str, '.' );
395 if (p) *p++ = 0;
396 version->dwMajorVersion = atoiW( str );
397 if (p)
399 str = p;
400 p = strchrW( str, '.' );
401 if (p)
403 *p++ = 0;
404 version->dwBuildNumber = atoiW( p );
406 version->dwMinorVersion = atoiW( str );
408 /* build number contains version too on Win9x */
409 version->dwBuildNumber |= MAKEWORD( version->dwMinorVersion, version->dwMajorVersion ) << 16;
412 if (version->dwMajorVersion) /* we got the main version, now fetch the other fields */
414 ret = TRUE;
415 version->dwPlatformId = VER_PLATFORM_WIN32_WINDOWS;
417 RtlInitUnicodeString( &valueW, SubVersionNumberW );
418 if (!NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp)-1, &count ))
420 DWORD len = min( info->DataLength, sizeof(version->szCSDVersion) - sizeof(WCHAR) );
421 memcpy( version->szCSDVersion, info->Data, len );
422 version->szCSDVersion[len / sizeof(WCHAR)] = 0;
426 NtClose( hkey );
427 return ret;
431 /**********************************************************************
432 * parse_win_version
434 * Parse the contents of the Version key.
436 static BOOL parse_win_version( HANDLE hkey )
438 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
440 UNICODE_STRING valueW;
441 char tmp[64], buffer[50];
442 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)tmp;
443 DWORD count, len;
444 int i;
446 RtlInitUnicodeString( &valueW, VersionW );
447 if (NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
448 return FALSE;
450 RtlUnicodeToMultiByteN( buffer, sizeof(buffer)-1, &len, (WCHAR *)info->Data, info->DataLength );
451 buffer[len] = 0;
453 for (i = 0; i < NB_WINDOWS_VERSIONS; i++)
455 const char *p, *pCurr = WinVersionNames[i];
456 /* iterate through all winver aliases separated by comma */
457 do {
458 p = strchr(pCurr, ',');
459 len = p ? p - pCurr : strlen(pCurr);
460 if ( (!strncmp( pCurr, buffer, len )) && (buffer[len] == 0) )
462 current_version = &VersionData[i];
463 TRACE( "got win version %s\n", WinVersionNames[i] );
464 return TRUE;
466 pCurr = p+1;
467 } while (p);
470 MESSAGE("Invalid Windows version value '%s' specified in config file.\n", buffer );
471 MESSAGE("Valid versions are:" );
472 for (i = 0; i < NB_WINDOWS_VERSIONS; i++)
474 /* only list the first, "official" alias in case of aliases */
475 const char *pCurr = WinVersionNames[i];
476 const char *p = strchr(pCurr, ',');
477 len = (p) ? p - pCurr : strlen(pCurr);
479 MESSAGE(" '%.*s'%c", (int)len, pCurr, (i == NB_WINDOWS_VERSIONS - 1) ? '\n' : ',' );
481 return FALSE;
485 /**********************************************************************
486 * version_init
488 void version_init( const WCHAR *appname )
490 static const WCHAR configW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e',0};
491 static const WCHAR appdefaultsW[] = {'A','p','p','D','e','f','a','u','l','t','s','\\',0};
492 OBJECT_ATTRIBUTES attr;
493 UNICODE_STRING nameW;
494 HANDLE root, hkey, config_key;
495 BOOL got_win_ver = FALSE;
497 current_version = &VersionData[WIN7];
499 RtlOpenCurrentUser( KEY_ALL_ACCESS, &root );
500 attr.Length = sizeof(attr);
501 attr.RootDirectory = root;
502 attr.ObjectName = &nameW;
503 attr.Attributes = 0;
504 attr.SecurityDescriptor = NULL;
505 attr.SecurityQualityOfService = NULL;
506 RtlInitUnicodeString( &nameW, configW );
508 /* @@ Wine registry key: HKCU\Software\Wine */
509 if (NtOpenKey( &config_key, KEY_ALL_ACCESS, &attr )) config_key = 0;
510 NtClose( root );
511 if (!config_key) goto done;
513 /* open AppDefaults\\appname key */
514 if (appname && *appname)
516 const WCHAR *p;
517 WCHAR appversion[MAX_PATH+20];
519 if ((p = strrchrW( appname, '/' ))) appname = p + 1;
520 if ((p = strrchrW( appname, '\\' ))) appname = p + 1;
522 strcpyW( appversion, appdefaultsW );
523 strcatW( appversion, appname );
524 RtlInitUnicodeString( &nameW, appversion );
525 attr.RootDirectory = config_key;
527 /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe */
528 if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
530 TRACE( "getting version from %s\n", debugstr_w(appversion) );
531 got_win_ver = parse_win_version( hkey );
532 NtClose( hkey );
536 if (!got_win_ver)
538 TRACE( "getting default version\n" );
539 got_win_ver = parse_win_version( config_key );
541 NtClose( config_key );
543 done:
544 if (!got_win_ver)
546 static RTL_OSVERSIONINFOEXW registry_version;
548 TRACE( "getting registry version\n" );
549 if (get_nt_registry_version( &registry_version ) ||
550 get_win9x_registry_version( &registry_version ))
551 current_version = &registry_version;
555 NtCurrentTeb()->Peb->OSMajorVersion = current_version->dwMajorVersion;
556 NtCurrentTeb()->Peb->OSMinorVersion = current_version->dwMinorVersion;
557 NtCurrentTeb()->Peb->OSBuildNumber = current_version->dwBuildNumber;
558 NtCurrentTeb()->Peb->OSPlatformId = current_version->dwPlatformId;
560 user_shared_data->NtProductType = current_version->wProductType;
561 user_shared_data->ProductTypeIsValid = TRUE;
562 user_shared_data->NtMajorVersion = current_version->dwMajorVersion;
563 user_shared_data->NtMinorVersion = current_version->dwMinorVersion;
564 user_shared_data->SuiteMask = current_version->wSuiteMask;
566 TRACE( "got %d.%d platform %d build %x name %s service pack %d.%d product %d\n",
567 current_version->dwMajorVersion, current_version->dwMinorVersion,
568 current_version->dwPlatformId, current_version->dwBuildNumber,
569 debugstr_w(current_version->szCSDVersion),
570 current_version->wServicePackMajor, current_version->wServicePackMinor,
571 current_version->wProductType );
574 /***********************************************************************
575 * RtlGetProductInfo (NTDLL.@)
577 * Gives info about the current Windows product type, in a format compatible
578 * with the given Windows version
580 * Returns TRUE if the input is valid, FALSE otherwise
582 BOOLEAN WINAPI RtlGetProductInfo(DWORD dwOSMajorVersion, DWORD dwOSMinorVersion, DWORD dwSpMajorVersion,
583 DWORD dwSpMinorVersion, PDWORD pdwReturnedProductType)
585 TRACE("(%d, %d, %d, %d, %p)\n", dwOSMajorVersion, dwOSMinorVersion,
586 dwSpMajorVersion, dwSpMinorVersion, pdwReturnedProductType);
588 if (!pdwReturnedProductType)
589 return FALSE;
591 if (dwOSMajorVersion < 6)
593 *pdwReturnedProductType = PRODUCT_UNDEFINED;
594 return FALSE;
597 if (current_version->wProductType == VER_NT_WORKSTATION)
598 *pdwReturnedProductType = PRODUCT_ULTIMATE_N;
599 else
600 *pdwReturnedProductType = PRODUCT_STANDARD_SERVER;
602 return TRUE;
605 /***********************************************************************
606 * RtlGetVersion (NTDLL.@)
608 NTSTATUS WINAPI RtlGetVersion( RTL_OSVERSIONINFOEXW *info )
610 info->dwMajorVersion = current_version->dwMajorVersion;
611 info->dwMinorVersion = current_version->dwMinorVersion;
612 info->dwBuildNumber = current_version->dwBuildNumber;
613 info->dwPlatformId = current_version->dwPlatformId;
614 strcpyW( info->szCSDVersion, current_version->szCSDVersion );
615 if(info->dwOSVersionInfoSize == sizeof(RTL_OSVERSIONINFOEXW))
617 info->wServicePackMajor = current_version->wServicePackMajor;
618 info->wServicePackMinor = current_version->wServicePackMinor;
619 info->wSuiteMask = current_version->wSuiteMask;
620 info->wProductType = current_version->wProductType;
622 return STATUS_SUCCESS;
626 /******************************************************************************
627 * RtlGetNtVersionNumbers (NTDLL.@)
629 * Get the version numbers of the run time library.
631 * PARAMS
632 * major [O] Destination for the Major version
633 * minor [O] Destination for the Minor version
634 * build [O] Destination for the Build version
636 * RETURNS
637 * Nothing.
639 * NOTES
640 * Introduced in Windows XP (NT5.1)
642 void WINAPI RtlGetNtVersionNumbers( LPDWORD major, LPDWORD minor, LPDWORD build )
644 if (major) *major = current_version->dwMajorVersion;
645 if (minor) *minor = current_version->dwMinorVersion;
646 /* FIXME: Does anybody know the real formula? */
647 if (build) *build = (0xF0000000 | current_version->dwBuildNumber);
651 /******************************************************************************
652 * RtlGetNtProductType (NTDLL.@)
654 BOOLEAN WINAPI RtlGetNtProductType( LPDWORD type )
656 if (type) *type = current_version->wProductType;
657 return TRUE;
660 static inline UCHAR version_update_condition(UCHAR *last_condition, UCHAR condition)
662 switch (*last_condition)
664 case 0:
665 *last_condition = condition;
666 break;
667 case VER_EQUAL:
668 if (condition >= VER_EQUAL && condition <= VER_LESS_EQUAL)
670 *last_condition = condition;
671 return condition;
673 break;
674 case VER_GREATER:
675 case VER_GREATER_EQUAL:
676 if (condition >= VER_EQUAL && condition <= VER_GREATER_EQUAL)
677 return condition;
678 break;
679 case VER_LESS:
680 case VER_LESS_EQUAL:
681 if (condition == VER_EQUAL || (condition >= VER_LESS && condition <= VER_LESS_EQUAL))
682 return condition;
683 break;
685 if (!condition) *last_condition |= 0x10;
686 return *last_condition & 0xf;
689 static inline NTSTATUS version_compare_values(ULONG left, ULONG right, UCHAR condition)
691 switch (condition) {
692 case VER_EQUAL:
693 if (left != right) return STATUS_REVISION_MISMATCH;
694 break;
695 case VER_GREATER:
696 if (left <= right) return STATUS_REVISION_MISMATCH;
697 break;
698 case VER_GREATER_EQUAL:
699 if (left < right) return STATUS_REVISION_MISMATCH;
700 break;
701 case VER_LESS:
702 if (left >= right) return STATUS_REVISION_MISMATCH;
703 break;
704 case VER_LESS_EQUAL:
705 if (left > right) return STATUS_REVISION_MISMATCH;
706 break;
707 default:
708 return STATUS_REVISION_MISMATCH;
710 return STATUS_SUCCESS;
713 /******************************************************************************
714 * RtlVerifyVersionInfo (NTDLL.@)
716 NTSTATUS WINAPI RtlVerifyVersionInfo( const RTL_OSVERSIONINFOEXW *info,
717 DWORD dwTypeMask, DWORDLONG dwlConditionMask )
719 RTL_OSVERSIONINFOEXW ver;
720 NTSTATUS status;
722 TRACE("(%p,0x%x,0x%s)\n", info, dwTypeMask, wine_dbgstr_longlong(dwlConditionMask));
724 ver.dwOSVersionInfoSize = sizeof(ver);
725 if ((status = RtlGetVersion( &ver )) != STATUS_SUCCESS) return status;
727 if(!(dwTypeMask && dwlConditionMask)) return STATUS_INVALID_PARAMETER;
729 if(dwTypeMask & VER_PRODUCT_TYPE)
731 status = version_compare_values(ver.wProductType, info->wProductType, dwlConditionMask >> 7*3 & 0x07);
732 if (status != STATUS_SUCCESS)
733 return status;
735 if(dwTypeMask & VER_SUITENAME)
736 switch(dwlConditionMask >> 6*3 & 0x07)
738 case VER_AND:
739 if((info->wSuiteMask & ver.wSuiteMask) != info->wSuiteMask)
740 return STATUS_REVISION_MISMATCH;
741 break;
742 case VER_OR:
743 if(!(info->wSuiteMask & ver.wSuiteMask) && info->wSuiteMask)
744 return STATUS_REVISION_MISMATCH;
745 break;
746 default:
747 return STATUS_INVALID_PARAMETER;
749 if(dwTypeMask & VER_PLATFORMID)
751 status = version_compare_values(ver.dwPlatformId, info->dwPlatformId, dwlConditionMask >> 3*3 & 0x07);
752 if (status != STATUS_SUCCESS)
753 return status;
755 if(dwTypeMask & VER_BUILDNUMBER)
757 status = version_compare_values(ver.dwBuildNumber, info->dwBuildNumber, dwlConditionMask >> 2*3 & 0x07);
758 if (status != STATUS_SUCCESS)
759 return status;
762 if(dwTypeMask & (VER_MAJORVERSION|VER_MINORVERSION|VER_SERVICEPACKMAJOR|VER_SERVICEPACKMINOR))
764 unsigned char condition, last_condition = 0;
765 BOOLEAN do_next_check = TRUE;
767 if(dwTypeMask & VER_MAJORVERSION)
769 condition = version_update_condition(&last_condition, dwlConditionMask >> 1*3 & 0x07);
770 status = version_compare_values(ver.dwMajorVersion, info->dwMajorVersion, condition);
771 do_next_check = (ver.dwMajorVersion == info->dwMajorVersion) &&
772 ((condition >= VER_EQUAL) && (condition <= VER_LESS_EQUAL));
774 if((dwTypeMask & VER_MINORVERSION) && do_next_check)
776 condition = version_update_condition(&last_condition, dwlConditionMask >> 0*3 & 0x07);
777 status = version_compare_values(ver.dwMinorVersion, info->dwMinorVersion, condition);
778 do_next_check = (ver.dwMinorVersion == info->dwMinorVersion) &&
779 ((condition >= VER_EQUAL) && (condition <= VER_LESS_EQUAL));
781 if((dwTypeMask & VER_SERVICEPACKMAJOR) && do_next_check)
783 condition = version_update_condition(&last_condition, dwlConditionMask >> 5*3 & 0x07);
784 status = version_compare_values(ver.wServicePackMajor, info->wServicePackMajor, condition);
785 do_next_check = (ver.wServicePackMajor == info->wServicePackMajor) &&
786 ((condition >= VER_EQUAL) && (condition <= VER_LESS_EQUAL));
788 if((dwTypeMask & VER_SERVICEPACKMINOR) && do_next_check)
790 condition = version_update_condition(&last_condition, dwlConditionMask >> 4*3 & 0x07);
791 status = version_compare_values(ver.wServicePackMinor, info->wServicePackMinor, condition);
794 if (status != STATUS_SUCCESS)
795 return status;
798 return STATUS_SUCCESS;