kernelbase/tests: Use win_skip() for missing APIs.
[wine.git] / dlls / ntdll / version.c
blob9c396598d4eb18423f1b89678255b98b92ea498e
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 <string.h>
25 #include <stdlib.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include "ntstatus.h"
29 #define WIN32_NO_STATUS
30 #include "windef.h"
31 #include "wine/debug.h"
32 #include "ntdll_misc.h"
33 #include "ddk/wdm.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(ver);
37 typedef enum
39 WIN20, /* Windows 2.0 */
40 WIN30, /* Windows 3.0 */
41 WIN31, /* Windows 3.1 */
42 WIN95, /* Windows 95 */
43 WIN98, /* Windows 98 */
44 WINME, /* Windows Me */
45 NT351, /* Windows NT 3.51 */
46 NT40, /* Windows NT 4.0 */
47 NT2K, /* Windows 2000 */
48 WINXP, /* Windows XP */
49 WINXP64, /* Windows XP 64-bit */
50 WIN2K3, /* Windows 2003 */
51 WINVISTA,/* Windows Vista */
52 WIN2K8, /* Windows 2008 */
53 WIN2K8R2,/* Windows 2008 R2 */
54 WIN7, /* Windows 7 */
55 WIN8, /* Windows 8 */
56 WIN81, /* Windows 8.1 */
57 WIN10, /* Windows 10 */
58 WIN11, /* Windows 11 */
59 NB_WINDOWS_VERSIONS
60 } WINDOWS_VERSION;
62 /* FIXME: compare values below with original and fix.
63 * An *excellent* win9x version page (ALL versions !)
64 * can be found at www.mdgx.com/ver.htm */
65 static const RTL_OSVERSIONINFOEXW VersionData[NB_WINDOWS_VERSIONS] =
67 /* WIN20 FIXME: verify values */
69 sizeof(RTL_OSVERSIONINFOEXW), 2, 0, 0, VER_PLATFORM_WIN32s,
70 L"Win32s 1.3", 0, 0, 0, 0, 0
72 /* WIN30 FIXME: verify values */
74 sizeof(RTL_OSVERSIONINFOEXW), 3, 0, 0, VER_PLATFORM_WIN32s,
75 L"Win32s 1.3", 0, 0, 0, 0, 0
77 /* WIN31 */
79 sizeof(RTL_OSVERSIONINFOEXW), 3, 10, 0, VER_PLATFORM_WIN32s,
80 L"Win32s 1.3", 0, 0, 0, 0, 0
82 /* WIN95 */
84 /* Win95: 4, 0, 0x40003B6, ""
85 * Win95sp1: 4, 0, 0x40003B6, " A " (according to doc)
86 * Win95osr2: 4, 0, 0x4000457, " B " (according to doc)
87 * Win95osr2.1: 4, 3, 0x40304BC, " B " (according to doc)
88 * Win95osr2.5: 4, 3, 0x40304BE, " C " (according to doc)
89 * Win95a/b can be discerned via regkey SubVersionNumber
91 sizeof(RTL_OSVERSIONINFOEXW), 4, 0, 0x40003B6, VER_PLATFORM_WIN32_WINDOWS,
92 L"", 0, 0, 0, 0, 0
94 /* WIN98 (second edition) */
96 /* Win98: 4, 10, 0x40A07CE, " " 4.10.1998
97 * Win98SE: 4, 10, 0x40A08AE, " A " 4.10.2222
99 sizeof(RTL_OSVERSIONINFOEXW), 4, 10, 0x40A08AE, VER_PLATFORM_WIN32_WINDOWS,
100 L" A ", 0, 0, 0, 0, 0
102 /* WINME */
104 sizeof(RTL_OSVERSIONINFOEXW), 4, 90, 0x45A0BB8, VER_PLATFORM_WIN32_WINDOWS,
105 L" ", 0, 0, 0, 0, 0
107 /* NT351 */
109 sizeof(RTL_OSVERSIONINFOEXW), 3, 51, 1057, VER_PLATFORM_WIN32_NT,
110 L"Service Pack 5", 5, 0, 0, VER_NT_WORKSTATION, 0
112 /* NT40 */
114 sizeof(RTL_OSVERSIONINFOEXW), 4, 0, 1381, VER_PLATFORM_WIN32_NT,
115 L"Service Pack 6a", 6, 0, 0, VER_NT_WORKSTATION, 0
117 /* NT2K */
119 sizeof(RTL_OSVERSIONINFOEXW), 5, 0, 2195, VER_PLATFORM_WIN32_NT,
120 L"Service Pack 4", 4, 0, 0, VER_NT_WORKSTATION,
121 30 /* FIXME: Great, a reserved field with a value! */
123 /* WINXP */
125 sizeof(RTL_OSVERSIONINFOEXW), 5, 1, 2600, VER_PLATFORM_WIN32_NT,
126 L"Service Pack 3", 3, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION,
127 30 /* FIXME: Great, a reserved field with a value! */
129 /* WINXP64 */
131 sizeof(RTL_OSVERSIONINFOEXW), 5, 2, 3790, VER_PLATFORM_WIN32_NT,
132 L"Service Pack 2", 2, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 0
134 /* WIN2K3 */
136 sizeof(RTL_OSVERSIONINFOEXW), 5, 2, 3790, VER_PLATFORM_WIN32_NT,
137 L"Service Pack 2", 2, 0, VER_SUITE_SINGLEUSERTS, VER_NT_SERVER, 0
139 /* WINVISTA */
141 sizeof(RTL_OSVERSIONINFOEXW), 6, 0, 6002, VER_PLATFORM_WIN32_NT,
142 L"Service Pack 2", 2, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 0
144 /* WIN2K8 */
146 sizeof(RTL_OSVERSIONINFOEXW), 6, 0, 6002, VER_PLATFORM_WIN32_NT,
147 L"Service Pack 2", 2, 0, VER_SUITE_SINGLEUSERTS, VER_NT_SERVER, 0
149 /* WIN7 */
151 sizeof(RTL_OSVERSIONINFOEXW), 6, 1, 7601, VER_PLATFORM_WIN32_NT,
152 L"Service Pack 1", 1, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 0
154 /* WIN2K8R2 */
156 sizeof(RTL_OSVERSIONINFOEXW), 6, 1, 7601, VER_PLATFORM_WIN32_NT,
157 L"Service Pack 1", 1, 0, VER_SUITE_SINGLEUSERTS, VER_NT_SERVER, 0
159 /* WIN8 */
161 sizeof(RTL_OSVERSIONINFOEXW), 6, 2, 9200, VER_PLATFORM_WIN32_NT,
162 L"", 0, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 0
164 /* WIN81 */
166 sizeof(RTL_OSVERSIONINFOEXW), 6, 3, 9600, VER_PLATFORM_WIN32_NT,
167 L"", 0, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 0
169 /* WIN10 */
171 sizeof(RTL_OSVERSIONINFOEXW), 10, 0, 18362, VER_PLATFORM_WIN32_NT,
172 L"", 0, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 0
174 /* WIN11 */
176 sizeof(RTL_OSVERSIONINFOEXW), 10, 0, 22000, VER_PLATFORM_WIN32_NT,
177 L"", 0, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 0
181 static const struct { WCHAR name[12]; WINDOWS_VERSION ver; } version_names[] =
183 { L"win20", WIN20 },
184 { L"win30", WIN30 },
185 { L"win31", WIN31 },
186 { L"win95", WIN95 },
187 { L"win98", WIN98 },
188 { L"winme", WINME },
189 { L"nt351", NT351 },
190 { L"nt40", NT40 },
191 { L"win2000", NT2K },
192 { L"win2k", NT2K },
193 { L"nt2k", NT2K },
194 { L"nt2000", NT2K },
195 { L"winxp", WINXP },
196 { L"winxp64", WINXP64 },
197 { L"win2003", WIN2K3 },
198 { L"win2k3", WIN2K3 },
199 { L"vista", WINVISTA },
200 { L"winvista", WINVISTA },
201 { L"win2008", WIN2K8 },
202 { L"win2k8", WIN2K8 },
203 { L"win2008r2", WIN2K8R2 },
204 { L"win2k8r2", WIN2K8R2 },
205 { L"win7", WIN7 },
206 { L"win8", WIN8 },
207 { L"win81", WIN81 },
208 { L"win10", WIN10 },
209 { L"win11", WIN11 },
213 /* initialized to null so that we crash if we try to retrieve the version too early at startup */
214 static const RTL_OSVERSIONINFOEXW *current_version;
216 static char wine_version[256];
218 /*********************************************************************
219 * wine_get_version
221 const char * CDECL wine_get_version(void)
223 return wine_version;
227 /*********************************************************************
228 * wine_get_build_id
230 const char * CDECL wine_get_build_id(void)
232 const char *p = wine_version;
233 p += strlen(p) + 1; /* skip version */
234 return p;
238 /*********************************************************************
239 * wine_get_host_version
241 void CDECL wine_get_host_version( const char **sysname, const char **release )
243 const char *p = wine_version;
244 p += strlen(p) + 1; /* skip version */
245 p += strlen(p) + 1; /* skip build id */
246 if (sysname) *sysname = p;
247 p += strlen(p) + 1;
248 if (release) *release = p;
252 /**********************************************************************
253 * get_nt_registry_version
255 * Fetch the version information from the NT-style registry keys.
257 static BOOL get_nt_registry_version( RTL_OSVERSIONINFOEXW *version )
259 OBJECT_ATTRIBUTES attr;
260 UNICODE_STRING nameW, valueW;
261 HANDLE hkey, hkey2;
262 char tmp[64];
263 DWORD count;
264 BOOL ret = FALSE;
265 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)tmp;
267 attr.Length = sizeof(attr);
268 attr.RootDirectory = 0;
269 attr.ObjectName = &nameW;
270 attr.Attributes = 0;
271 attr.SecurityDescriptor = NULL;
272 attr.SecurityQualityOfService = NULL;
273 RtlInitUnicodeString( &nameW, L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion" );
275 if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )) return FALSE;
277 memset( version, 0, sizeof(*version) );
279 RtlInitUnicodeString( &valueW, L"CurrentMajorVersionNumber" );
280 if (!NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp)-1, &count ) &&
281 info->Type == REG_DWORD)
283 version->dwMajorVersion = *(DWORD *)info->Data;
285 RtlInitUnicodeString( &valueW, L"CurrentMinorVersionNumber" );
286 if (!NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp)-1, &count ) &&
287 info->Type == REG_DWORD)
289 version->dwMinorVersion = *(DWORD *)info->Data;
291 else version->dwMajorVersion = 0;
294 if (!version->dwMajorVersion)
296 RtlInitUnicodeString( &valueW, L"CurrentVersion" );
297 if (!NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp)-1, &count ))
299 WCHAR *p, *str = (WCHAR *)info->Data;
300 str[info->DataLength / sizeof(WCHAR)] = 0;
301 p = wcschr( str, '.' );
302 if (p)
304 *p++ = 0;
305 version->dwMinorVersion = wcstoul( p, NULL, 10 );
307 version->dwMajorVersion = wcstoul( str, NULL, 10 );
311 if (version->dwMajorVersion) /* we got the main version, now fetch the other fields */
313 ret = TRUE;
314 version->dwPlatformId = VER_PLATFORM_WIN32_NT;
316 /* get build number */
318 RtlInitUnicodeString( &valueW, L"CurrentBuildNumber" );
319 if (!NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp)-1, &count ))
321 WCHAR *str = (WCHAR *)info->Data;
322 str[info->DataLength / sizeof(WCHAR)] = 0;
323 version->dwBuildNumber = wcstoul( str, NULL, 10 );
326 /* get version description */
328 RtlInitUnicodeString( &valueW, L"CSDVersion" );
329 if (!NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp)-1, &count ))
331 DWORD len = min( info->DataLength, sizeof(version->szCSDVersion) - sizeof(WCHAR) );
332 memcpy( version->szCSDVersion, info->Data, len );
333 version->szCSDVersion[len / sizeof(WCHAR)] = 0;
336 /* get service pack version */
338 RtlInitUnicodeString( &nameW, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Windows" );
339 if (!NtOpenKey( &hkey2, KEY_ALL_ACCESS, &attr ))
341 RtlInitUnicodeString( &valueW, L"CSDVersion" );
342 if (!NtQueryValueKey( hkey2, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
344 if (info->DataLength >= sizeof(DWORD))
346 DWORD dw = *(DWORD *)info->Data;
347 version->wServicePackMajor = LOWORD(dw) >> 8;
348 version->wServicePackMinor = LOWORD(dw) & 0xff;
351 NtClose( hkey2 );
354 /* get product type */
356 RtlInitUnicodeString( &nameW, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\ProductOptions" );
357 if (!NtOpenKey( &hkey2, KEY_ALL_ACCESS, &attr ))
359 RtlInitUnicodeString( &valueW, L"ProductType" );
360 if (!NtQueryValueKey( hkey2, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp)-1, &count ))
362 WCHAR *str = (WCHAR *)info->Data;
363 str[info->DataLength / sizeof(WCHAR)] = 0;
364 if (!wcsicmp( str, L"WinNT" )) version->wProductType = VER_NT_WORKSTATION;
365 else if (!wcsicmp( str, L"LanmanNT" )) version->wProductType = VER_NT_DOMAIN_CONTROLLER;
366 else if (!wcsicmp( str, L"ServerNT" )) version->wProductType = VER_NT_SERVER;
368 NtClose( hkey2 );
371 /* FIXME: get wSuiteMask */
374 NtClose( hkey );
375 return ret;
379 /**********************************************************************
380 * get_win9x_registry_version
382 * Fetch the version information from the Win9x-style registry keys.
384 static BOOL get_win9x_registry_version( RTL_OSVERSIONINFOEXW *version )
386 OBJECT_ATTRIBUTES attr;
387 UNICODE_STRING nameW, valueW;
388 HANDLE hkey;
389 char tmp[64];
390 DWORD count;
391 BOOL ret = FALSE;
392 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)tmp;
394 attr.Length = sizeof(attr);
395 attr.RootDirectory = 0;
396 attr.ObjectName = &nameW;
397 attr.Attributes = 0;
398 attr.SecurityDescriptor = NULL;
399 attr.SecurityQualityOfService = NULL;
400 RtlInitUnicodeString( &nameW, L"\\Registry\\Machine\\Software\\Microsoft\\Windows\\CurrentVersion" );
402 if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )) return FALSE;
404 memset( version, 0, sizeof(*version) );
406 RtlInitUnicodeString( &valueW, L"VersionNumber" );
407 if (!NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp)-1, &count ))
409 WCHAR *p, *str = (WCHAR *)info->Data;
410 str[info->DataLength / sizeof(WCHAR)] = 0;
411 p = wcschr( str, '.' );
412 if (p) *p++ = 0;
413 version->dwMajorVersion = wcstoul( str, NULL, 10 );
414 if (p)
416 str = p;
417 p = wcschr( str, '.' );
418 if (p)
420 *p++ = 0;
421 version->dwBuildNumber = wcstoul( p, NULL, 10 );
423 version->dwMinorVersion = wcstoul( str, NULL, 10 );
425 /* build number contains version too on Win9x */
426 version->dwBuildNumber |= MAKEWORD( version->dwMinorVersion, version->dwMajorVersion ) << 16;
429 if (version->dwMajorVersion) /* we got the main version, now fetch the other fields */
431 ret = TRUE;
432 version->dwPlatformId = VER_PLATFORM_WIN32_WINDOWS;
434 RtlInitUnicodeString( &valueW, L"SubVersionNumber" );
435 if (!NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp)-1, &count ))
437 DWORD len = min( info->DataLength, sizeof(version->szCSDVersion) - sizeof(WCHAR) );
438 memcpy( version->szCSDVersion, info->Data, len );
439 version->szCSDVersion[len / sizeof(WCHAR)] = 0;
443 NtClose( hkey );
444 return ret;
448 /**********************************************************************
449 * parse_win_version
451 * Parse the contents of the Version key.
453 static BOOL parse_win_version( HANDLE hkey )
455 UNICODE_STRING valueW;
456 WCHAR *name, tmp[64];
457 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)tmp;
458 DWORD i, count;
460 RtlInitUnicodeString( &valueW, L"Version" );
461 if (NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp) - sizeof(WCHAR), &count ))
462 return FALSE;
464 name = (WCHAR *)info->Data;
465 name[info->DataLength / sizeof(WCHAR)] = 0;
467 for (i = 0; i < ARRAY_SIZE(version_names); i++)
469 if (wcscmp( version_names[i].name, name )) continue;
470 current_version = &VersionData[version_names[i].ver];
471 TRACE( "got win version %s\n", debugstr_w(version_names[i].name) );
472 return TRUE;
475 ERR( "Invalid Windows version value %s specified in config file.\n", debugstr_w(name) );
476 return FALSE;
480 /**********************************************************************
481 * version_init
483 void version_init(void)
485 OBJECT_ATTRIBUTES attr;
486 UNICODE_STRING nameW;
487 HANDLE root, hkey, config_key;
488 BOOL got_win_ver = FALSE;
489 const WCHAR *p, *appname = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
490 WCHAR appversion[MAX_PATH+20];
492 NtQuerySystemInformation( SystemWineVersionInformation, wine_version, sizeof(wine_version), NULL );
494 current_version = &VersionData[WIN10];
496 RtlOpenCurrentUser( KEY_ALL_ACCESS, &root );
497 attr.Length = sizeof(attr);
498 attr.RootDirectory = root;
499 attr.ObjectName = &nameW;
500 attr.Attributes = 0;
501 attr.SecurityDescriptor = NULL;
502 attr.SecurityQualityOfService = NULL;
503 RtlInitUnicodeString( &nameW, L"Software\\Wine" );
505 /* @@ Wine registry key: HKCU\Software\Wine */
506 if (NtOpenKey( &config_key, KEY_ALL_ACCESS, &attr )) config_key = 0;
507 NtClose( root );
508 if (!config_key) goto done;
510 /* open AppDefaults\\appname key */
512 if ((p = wcsrchr( appname, '/' ))) appname = p + 1;
513 if ((p = wcsrchr( appname, '\\' ))) appname = p + 1;
515 wcscpy( appversion, L"AppDefaults\\" );
516 wcscat( appversion, appname );
517 RtlInitUnicodeString( &nameW, appversion );
518 attr.RootDirectory = config_key;
520 /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe */
521 if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
523 TRACE( "getting version from %s\n", debugstr_w(appversion) );
524 got_win_ver = parse_win_version( hkey );
525 NtClose( hkey );
528 if (!got_win_ver)
530 TRACE( "getting default version\n" );
531 got_win_ver = parse_win_version( config_key );
533 NtClose( config_key );
535 done:
536 if (!got_win_ver)
538 static RTL_OSVERSIONINFOEXW registry_version;
540 TRACE( "getting registry version\n" );
541 if (get_nt_registry_version( &registry_version ) ||
542 get_win9x_registry_version( &registry_version ))
543 current_version = &registry_version;
547 NtCurrentTeb()->Peb->OSMajorVersion = current_version->dwMajorVersion;
548 NtCurrentTeb()->Peb->OSMinorVersion = current_version->dwMinorVersion;
549 NtCurrentTeb()->Peb->OSBuildNumber = current_version->dwBuildNumber;
550 NtCurrentTeb()->Peb->OSPlatformId = current_version->dwPlatformId;
552 TRACE( "got %ld.%ld platform %ld build %lx name %s service pack %d.%d product %d\n",
553 current_version->dwMajorVersion, current_version->dwMinorVersion,
554 current_version->dwPlatformId, current_version->dwBuildNumber,
555 debugstr_w(current_version->szCSDVersion),
556 current_version->wServicePackMajor, current_version->wServicePackMinor,
557 current_version->wProductType );
560 /***********************************************************************
561 * RtlGetProductInfo (NTDLL.@)
563 * Gives info about the current Windows product type, in a format compatible
564 * with the given Windows version
566 * Returns TRUE if the input is valid, FALSE otherwise
568 BOOLEAN WINAPI RtlGetProductInfo(DWORD dwOSMajorVersion, DWORD dwOSMinorVersion, DWORD dwSpMajorVersion,
569 DWORD dwSpMinorVersion, PDWORD pdwReturnedProductType)
571 TRACE("(%ld, %ld, %ld, %ld, %p)\n", dwOSMajorVersion, dwOSMinorVersion,
572 dwSpMajorVersion, dwSpMinorVersion, pdwReturnedProductType);
574 if (!pdwReturnedProductType)
575 return FALSE;
577 if (dwOSMajorVersion < 6)
579 *pdwReturnedProductType = PRODUCT_UNDEFINED;
580 return FALSE;
583 if (current_version->wProductType == VER_NT_WORKSTATION)
584 *pdwReturnedProductType = PRODUCT_ULTIMATE_N;
585 else
586 *pdwReturnedProductType = PRODUCT_STANDARD_SERVER;
588 return TRUE;
591 /***********************************************************************
592 * RtlGetVersion (NTDLL.@)
594 NTSTATUS WINAPI RtlGetVersion( RTL_OSVERSIONINFOEXW *info )
596 info->dwMajorVersion = current_version->dwMajorVersion;
597 info->dwMinorVersion = current_version->dwMinorVersion;
598 info->dwBuildNumber = current_version->dwBuildNumber;
599 info->dwPlatformId = current_version->dwPlatformId;
600 wcscpy( info->szCSDVersion, current_version->szCSDVersion );
601 if(info->dwOSVersionInfoSize == sizeof(RTL_OSVERSIONINFOEXW))
603 info->wServicePackMajor = current_version->wServicePackMajor;
604 info->wServicePackMinor = current_version->wServicePackMinor;
605 info->wSuiteMask = current_version->wSuiteMask;
606 info->wProductType = current_version->wProductType;
608 return STATUS_SUCCESS;
612 /******************************************************************************
613 * RtlGetNtVersionNumbers (NTDLL.@)
615 * Get the version numbers of the run time library.
617 * PARAMS
618 * major [O] Destination for the Major version
619 * minor [O] Destination for the Minor version
620 * build [O] Destination for the Build version
622 * RETURNS
623 * Nothing.
625 * NOTES
626 * Introduced in Windows XP (NT5.1)
628 void WINAPI RtlGetNtVersionNumbers( LPDWORD major, LPDWORD minor, LPDWORD build )
630 if (major) *major = current_version->dwMajorVersion;
631 if (minor) *minor = current_version->dwMinorVersion;
632 /* FIXME: Does anybody know the real formula? */
633 if (build) *build = (0xF0000000 | current_version->dwBuildNumber);
637 /******************************************************************************
638 * RtlGetNtProductType (NTDLL.@)
640 BOOLEAN WINAPI RtlGetNtProductType( LPDWORD type )
642 if (type) *type = current_version->wProductType;
643 return TRUE;
646 static inline UCHAR version_update_condition(UCHAR *last_condition, UCHAR condition)
648 switch (*last_condition)
650 case 0:
651 *last_condition = condition;
652 break;
653 case VER_EQUAL:
654 if (condition >= VER_EQUAL && condition <= VER_LESS_EQUAL)
656 *last_condition = condition;
657 return condition;
659 break;
660 case VER_GREATER:
661 case VER_GREATER_EQUAL:
662 if (condition >= VER_EQUAL && condition <= VER_GREATER_EQUAL)
663 return condition;
664 break;
665 case VER_LESS:
666 case VER_LESS_EQUAL:
667 if (condition == VER_EQUAL || (condition >= VER_LESS && condition <= VER_LESS_EQUAL))
668 return condition;
669 break;
671 if (!condition) *last_condition |= 0x10;
672 return *last_condition & 0xf;
675 static inline NTSTATUS version_compare_values(ULONG left, ULONG right, UCHAR condition)
677 switch (condition) {
678 case VER_EQUAL:
679 if (left != right) return STATUS_REVISION_MISMATCH;
680 break;
681 case VER_GREATER:
682 if (left <= right) return STATUS_REVISION_MISMATCH;
683 break;
684 case VER_GREATER_EQUAL:
685 if (left < right) return STATUS_REVISION_MISMATCH;
686 break;
687 case VER_LESS:
688 if (left >= right) return STATUS_REVISION_MISMATCH;
689 break;
690 case VER_LESS_EQUAL:
691 if (left > right) return STATUS_REVISION_MISMATCH;
692 break;
693 default:
694 return STATUS_REVISION_MISMATCH;
696 return STATUS_SUCCESS;
699 /******************************************************************************
700 * RtlVerifyVersionInfo (NTDLL.@)
702 NTSTATUS WINAPI RtlVerifyVersionInfo( const RTL_OSVERSIONINFOEXW *info,
703 DWORD dwTypeMask, DWORDLONG dwlConditionMask )
705 RTL_OSVERSIONINFOEXW ver;
706 NTSTATUS status;
708 TRACE("(%p,0x%lx,0x%s)\n", info, dwTypeMask, wine_dbgstr_longlong(dwlConditionMask));
710 ver.dwOSVersionInfoSize = sizeof(ver);
711 if ((status = RtlGetVersion( &ver )) != STATUS_SUCCESS) return status;
713 if(!(dwTypeMask && dwlConditionMask)) return STATUS_INVALID_PARAMETER;
715 if(dwTypeMask & VER_PRODUCT_TYPE)
717 status = version_compare_values(ver.wProductType, info->wProductType, dwlConditionMask >> 7*3 & 0x07);
718 if (status != STATUS_SUCCESS)
719 return status;
721 if(dwTypeMask & VER_SUITENAME)
722 switch(dwlConditionMask >> 6*3 & 0x07)
724 case VER_AND:
725 if((info->wSuiteMask & ver.wSuiteMask) != info->wSuiteMask)
726 return STATUS_REVISION_MISMATCH;
727 break;
728 case VER_OR:
729 if(!(info->wSuiteMask & ver.wSuiteMask) && info->wSuiteMask)
730 return STATUS_REVISION_MISMATCH;
731 break;
732 default:
733 return STATUS_INVALID_PARAMETER;
735 if(dwTypeMask & VER_PLATFORMID)
737 status = version_compare_values(ver.dwPlatformId, info->dwPlatformId, dwlConditionMask >> 3*3 & 0x07);
738 if (status != STATUS_SUCCESS)
739 return status;
741 if(dwTypeMask & VER_BUILDNUMBER)
743 status = version_compare_values(ver.dwBuildNumber, info->dwBuildNumber, dwlConditionMask >> 2*3 & 0x07);
744 if (status != STATUS_SUCCESS)
745 return status;
748 if(dwTypeMask & (VER_MAJORVERSION|VER_MINORVERSION|VER_SERVICEPACKMAJOR|VER_SERVICEPACKMINOR))
750 unsigned char condition, last_condition = 0;
751 BOOLEAN do_next_check = TRUE;
753 if(dwTypeMask & VER_MAJORVERSION)
755 condition = version_update_condition(&last_condition, dwlConditionMask >> 1*3 & 0x07);
756 status = version_compare_values(ver.dwMajorVersion, info->dwMajorVersion, condition);
757 do_next_check = (ver.dwMajorVersion == info->dwMajorVersion) &&
758 ((condition >= VER_EQUAL) && (condition <= VER_LESS_EQUAL));
760 if((dwTypeMask & VER_MINORVERSION) && do_next_check)
762 condition = version_update_condition(&last_condition, dwlConditionMask >> 0*3 & 0x07);
763 status = version_compare_values(ver.dwMinorVersion, info->dwMinorVersion, condition);
764 do_next_check = (ver.dwMinorVersion == info->dwMinorVersion) &&
765 ((condition >= VER_EQUAL) && (condition <= VER_LESS_EQUAL));
767 if((dwTypeMask & VER_SERVICEPACKMAJOR) && do_next_check)
769 condition = version_update_condition(&last_condition, dwlConditionMask >> 5*3 & 0x07);
770 status = version_compare_values(ver.wServicePackMajor, info->wServicePackMajor, condition);
771 do_next_check = (ver.wServicePackMajor == info->wServicePackMajor) &&
772 ((condition >= VER_EQUAL) && (condition <= VER_LESS_EQUAL));
774 if((dwTypeMask & VER_SERVICEPACKMINOR) && do_next_check)
776 condition = version_update_condition(&last_condition, dwlConditionMask >> 4*3 & 0x07);
777 status = version_compare_values(ver.wServicePackMinor, info->wServicePackMinor, condition);
780 if (status != STATUS_SUCCESS)
781 return status;
784 return STATUS_SUCCESS;
788 /******************************************************************************
789 * VerSetConditionMask (NTDLL.@)
791 ULONGLONG WINAPI VerSetConditionMask( ULONGLONG condition_mask, DWORD type_mask, BYTE condition )
793 condition &= 0x07;
794 if (type_mask & VER_PRODUCT_TYPE) condition_mask |= condition << 7*3;
795 else if (type_mask & VER_SUITENAME) condition_mask |= condition << 6*3;
796 else if (type_mask & VER_SERVICEPACKMAJOR) condition_mask |= condition << 5*3;
797 else if (type_mask & VER_SERVICEPACKMINOR) condition_mask |= condition << 4*3;
798 else if (type_mask & VER_PLATFORMID) condition_mask |= condition << 3*3;
799 else if (type_mask & VER_BUILDNUMBER) condition_mask |= condition << 2*3;
800 else if (type_mask & VER_MAJORVERSION) condition_mask |= condition << 1*3;
801 else if (type_mask & VER_MINORVERSION) condition_mask |= condition << 0*3;
802 return condition_mask;