hidclass.sys: Return STATUS_INVALID_USER_BUFFER if buffer_len is 0.
[wine.git] / dlls / ntdll / version.c
blob5f956d9d2e6e9dbc00fc7b5d34f1e112482e8d76
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 NB_WINDOWS_VERSIONS
59 } WINDOWS_VERSION;
61 /* FIXME: compare values below with original and fix.
62 * An *excellent* win9x version page (ALL versions !)
63 * can be found at www.mdgx.com/ver.htm */
64 static const RTL_OSVERSIONINFOEXW VersionData[NB_WINDOWS_VERSIONS] =
66 /* WIN20 FIXME: verify values */
68 sizeof(RTL_OSVERSIONINFOEXW), 2, 0, 0, VER_PLATFORM_WIN32s,
69 L"Win32s 1.3", 0, 0, 0, 0, 0
71 /* WIN30 FIXME: verify values */
73 sizeof(RTL_OSVERSIONINFOEXW), 3, 0, 0, VER_PLATFORM_WIN32s,
74 L"Win32s 1.3", 0, 0, 0, 0, 0
76 /* WIN31 */
78 sizeof(RTL_OSVERSIONINFOEXW), 3, 10, 0, VER_PLATFORM_WIN32s,
79 L"Win32s 1.3", 0, 0, 0, 0, 0
81 /* WIN95 */
83 /* Win95: 4, 0, 0x40003B6, ""
84 * Win95sp1: 4, 0, 0x40003B6, " A " (according to doc)
85 * Win95osr2: 4, 0, 0x4000457, " B " (according to doc)
86 * Win95osr2.1: 4, 3, 0x40304BC, " B " (according to doc)
87 * Win95osr2.5: 4, 3, 0x40304BE, " C " (according to doc)
88 * Win95a/b can be discerned via regkey SubVersionNumber
90 sizeof(RTL_OSVERSIONINFOEXW), 4, 0, 0x40003B6, VER_PLATFORM_WIN32_WINDOWS,
91 L"", 0, 0, 0, 0, 0
93 /* WIN98 (second edition) */
95 /* Win98: 4, 10, 0x40A07CE, " " 4.10.1998
96 * Win98SE: 4, 10, 0x40A08AE, " A " 4.10.2222
98 sizeof(RTL_OSVERSIONINFOEXW), 4, 10, 0x40A08AE, VER_PLATFORM_WIN32_WINDOWS,
99 L" A ", 0, 0, 0, 0, 0
101 /* WINME */
103 sizeof(RTL_OSVERSIONINFOEXW), 4, 90, 0x45A0BB8, VER_PLATFORM_WIN32_WINDOWS,
104 L" ", 0, 0, 0, 0, 0
106 /* NT351 */
108 sizeof(RTL_OSVERSIONINFOEXW), 3, 51, 0x421, VER_PLATFORM_WIN32_NT,
109 L"Service Pack 5", 5, 0, 0, VER_NT_WORKSTATION, 0
111 /* NT40 */
113 sizeof(RTL_OSVERSIONINFOEXW), 4, 0, 0x565, VER_PLATFORM_WIN32_NT,
114 L"Service Pack 6a", 6, 0, 0, VER_NT_WORKSTATION, 0
116 /* NT2K */
118 sizeof(RTL_OSVERSIONINFOEXW), 5, 0, 0x893, VER_PLATFORM_WIN32_NT,
119 L"Service Pack 4", 4, 0, 0, VER_NT_WORKSTATION,
120 30 /* FIXME: Great, a reserved field with a value! */
122 /* WINXP */
124 sizeof(RTL_OSVERSIONINFOEXW), 5, 1, 0xA28, VER_PLATFORM_WIN32_NT,
125 L"Service Pack 3", 3, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION,
126 30 /* FIXME: Great, a reserved field with a value! */
128 /* WINXP64 */
130 sizeof(RTL_OSVERSIONINFOEXW), 5, 2, 0xECE, VER_PLATFORM_WIN32_NT,
131 L"Service Pack 2", 2, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 0
133 /* WIN2K3 */
135 sizeof(RTL_OSVERSIONINFOEXW), 5, 2, 0xECE, VER_PLATFORM_WIN32_NT,
136 L"Service Pack 2", 2, 0, VER_SUITE_SINGLEUSERTS, VER_NT_SERVER, 0
138 /* WINVISTA */
140 sizeof(RTL_OSVERSIONINFOEXW), 6, 0, 0x1772, VER_PLATFORM_WIN32_NT,
141 L"Service Pack 2", 2, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 0
143 /* WIN2K8 */
145 sizeof(RTL_OSVERSIONINFOEXW), 6, 0, 0x1772, VER_PLATFORM_WIN32_NT,
146 L"Service Pack 2", 2, 0, VER_SUITE_SINGLEUSERTS, VER_NT_SERVER, 0
148 /* WIN7 */
150 sizeof(RTL_OSVERSIONINFOEXW), 6, 1, 0x1DB1, VER_PLATFORM_WIN32_NT,
151 L"Service Pack 1", 1, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 0
153 /* WIN2K8R2 */
155 sizeof(RTL_OSVERSIONINFOEXW), 6, 1, 0x1DB1, VER_PLATFORM_WIN32_NT,
156 L"Service Pack 1", 1, 0, VER_SUITE_SINGLEUSERTS, VER_NT_SERVER, 0
158 /* WIN8 */
160 sizeof(RTL_OSVERSIONINFOEXW), 6, 2, 0x23F0, VER_PLATFORM_WIN32_NT,
161 L"", 0, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 0
163 /* WIN81 */
165 sizeof(RTL_OSVERSIONINFOEXW), 6, 3, 0x2580, VER_PLATFORM_WIN32_NT,
166 L"", 0, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 0
168 /* WIN10 */
170 sizeof(RTL_OSVERSIONINFOEXW), 10, 0, 0x4563, VER_PLATFORM_WIN32_NT,
171 L"", 0, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 0
176 static const struct { WCHAR name[12]; WINDOWS_VERSION ver; } version_names[] =
178 { L"win20", WIN20 },
179 { L"win30", WIN30 },
180 { L"win31", WIN31 },
181 { L"win95", WIN95 },
182 { L"win98", WIN98 },
183 { L"winme", WINME },
184 { L"nt351", NT351 },
185 { L"nt40", NT40 },
186 { L"win2000", NT2K },
187 { L"win2k", NT2K },
188 { L"nt2k", NT2K },
189 { L"nt2000", NT2K },
190 { L"winxp", WINXP },
191 { L"winxp64", WINXP64 },
192 { L"win2003", WIN2K3 },
193 { L"win2k3", WIN2K3 },
194 { L"vista", WINVISTA },
195 { L"winvista", WINVISTA },
196 { L"win2008", WIN2K8 },
197 { L"win2k8", WIN2K8 },
198 { L"win2008r2", WIN2K8R2 },
199 { L"win2k8r2", WIN2K8R2 },
200 { L"win7", WIN7 },
201 { L"win8", WIN8 },
202 { L"win81", WIN81 },
203 { L"win10", WIN10 },
207 /* initialized to null so that we crash if we try to retrieve the version too early at startup */
208 static const RTL_OSVERSIONINFOEXW *current_version;
210 static char wine_version[256];
212 /*********************************************************************
213 * wine_get_version
215 const char * CDECL wine_get_version(void)
217 return wine_version;
221 /*********************************************************************
222 * wine_get_build_id
224 const char * CDECL wine_get_build_id(void)
226 const char *p = wine_version;
227 p += strlen(p) + 1; /* skip version */
228 return p;
232 /*********************************************************************
233 * wine_get_host_version
235 void CDECL wine_get_host_version( const char **sysname, const char **release )
237 const char *p = wine_version;
238 p += strlen(p) + 1; /* skip version */
239 p += strlen(p) + 1; /* skip build id */
240 if (sysname) *sysname = p;
241 p += strlen(p) + 1;
242 if (release) *release = p;
246 /**********************************************************************
247 * get_nt_registry_version
249 * Fetch the version information from the NT-style registry keys.
251 static BOOL get_nt_registry_version( RTL_OSVERSIONINFOEXW *version )
253 OBJECT_ATTRIBUTES attr;
254 UNICODE_STRING nameW, valueW;
255 HANDLE hkey, hkey2;
256 char tmp[64];
257 DWORD count;
258 BOOL ret = FALSE;
259 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)tmp;
261 attr.Length = sizeof(attr);
262 attr.RootDirectory = 0;
263 attr.ObjectName = &nameW;
264 attr.Attributes = 0;
265 attr.SecurityDescriptor = NULL;
266 attr.SecurityQualityOfService = NULL;
267 RtlInitUnicodeString( &nameW, L"Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion" );
269 if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )) return FALSE;
271 memset( version, 0, sizeof(*version) );
273 RtlInitUnicodeString( &valueW, L"CurrentVersion" );
274 if (!NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp)-1, &count ))
276 WCHAR *p, *str = (WCHAR *)info->Data;
277 str[info->DataLength / sizeof(WCHAR)] = 0;
278 p = wcschr( str, '.' );
279 if (p)
281 *p++ = 0;
282 version->dwMinorVersion = wcstoul( p, NULL, 10 );
284 version->dwMajorVersion = wcstoul( str, NULL, 10 );
287 if (version->dwMajorVersion) /* we got the main version, now fetch the other fields */
289 ret = TRUE;
290 version->dwPlatformId = VER_PLATFORM_WIN32_NT;
292 /* get build number */
294 RtlInitUnicodeString( &valueW, L"CurrentBuildNumber" );
295 if (!NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp)-1, &count ))
297 WCHAR *str = (WCHAR *)info->Data;
298 str[info->DataLength / sizeof(WCHAR)] = 0;
299 version->dwBuildNumber = wcstoul( str, NULL, 10 );
302 /* get version description */
304 RtlInitUnicodeString( &valueW, L"CSDVersion" );
305 if (!NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp)-1, &count ))
307 DWORD len = min( info->DataLength, sizeof(version->szCSDVersion) - sizeof(WCHAR) );
308 memcpy( version->szCSDVersion, info->Data, len );
309 version->szCSDVersion[len / sizeof(WCHAR)] = 0;
312 /* get service pack version */
314 RtlInitUnicodeString( &nameW, L"Machine\\System\\CurrentControlSet\\Control\\Windows" );
315 if (!NtOpenKey( &hkey2, KEY_ALL_ACCESS, &attr ))
317 RtlInitUnicodeString( &valueW, L"CSDVersion" );
318 if (!NtQueryValueKey( hkey2, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
320 if (info->DataLength >= sizeof(DWORD))
322 DWORD dw = *(DWORD *)info->Data;
323 version->wServicePackMajor = LOWORD(dw) >> 8;
324 version->wServicePackMinor = LOWORD(dw) & 0xff;
327 NtClose( hkey2 );
330 /* get product type */
332 RtlInitUnicodeString( &nameW, L"Machine\\System\\CurrentControlSet\\Control\\ProductOptions" );
333 if (!NtOpenKey( &hkey2, KEY_ALL_ACCESS, &attr ))
335 RtlInitUnicodeString( &valueW, L"ProductType" );
336 if (!NtQueryValueKey( hkey2, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp)-1, &count ))
338 WCHAR *str = (WCHAR *)info->Data;
339 str[info->DataLength / sizeof(WCHAR)] = 0;
340 if (!wcsicmp( str, L"WinNT" )) version->wProductType = VER_NT_WORKSTATION;
341 else if (!wcsicmp( str, L"LanmanNT" )) version->wProductType = VER_NT_DOMAIN_CONTROLLER;
342 else if (!wcsicmp( str, L"ServerNT" )) version->wProductType = VER_NT_SERVER;
344 NtClose( hkey2 );
347 /* FIXME: get wSuiteMask */
350 NtClose( hkey );
351 return ret;
355 /**********************************************************************
356 * get_win9x_registry_version
358 * Fetch the version information from the Win9x-style registry keys.
360 static BOOL get_win9x_registry_version( RTL_OSVERSIONINFOEXW *version )
362 OBJECT_ATTRIBUTES attr;
363 UNICODE_STRING nameW, valueW;
364 HANDLE hkey;
365 char tmp[64];
366 DWORD count;
367 BOOL ret = FALSE;
368 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)tmp;
370 attr.Length = sizeof(attr);
371 attr.RootDirectory = 0;
372 attr.ObjectName = &nameW;
373 attr.Attributes = 0;
374 attr.SecurityDescriptor = NULL;
375 attr.SecurityQualityOfService = NULL;
376 RtlInitUnicodeString( &nameW, L"Machine\\Software\\Microsoft\\Windows\\CurrentVersion" );
378 if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )) return FALSE;
380 memset( version, 0, sizeof(*version) );
382 RtlInitUnicodeString( &valueW, L"VersionNumber" );
383 if (!NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp)-1, &count ))
385 WCHAR *p, *str = (WCHAR *)info->Data;
386 str[info->DataLength / sizeof(WCHAR)] = 0;
387 p = wcschr( str, '.' );
388 if (p) *p++ = 0;
389 version->dwMajorVersion = wcstoul( str, NULL, 10 );
390 if (p)
392 str = p;
393 p = wcschr( str, '.' );
394 if (p)
396 *p++ = 0;
397 version->dwBuildNumber = wcstoul( p, NULL, 10 );
399 version->dwMinorVersion = wcstoul( str, NULL, 10 );
401 /* build number contains version too on Win9x */
402 version->dwBuildNumber |= MAKEWORD( version->dwMinorVersion, version->dwMajorVersion ) << 16;
405 if (version->dwMajorVersion) /* we got the main version, now fetch the other fields */
407 ret = TRUE;
408 version->dwPlatformId = VER_PLATFORM_WIN32_WINDOWS;
410 RtlInitUnicodeString( &valueW, L"SubVersionNumber" );
411 if (!NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp)-1, &count ))
413 DWORD len = min( info->DataLength, sizeof(version->szCSDVersion) - sizeof(WCHAR) );
414 memcpy( version->szCSDVersion, info->Data, len );
415 version->szCSDVersion[len / sizeof(WCHAR)] = 0;
419 NtClose( hkey );
420 return ret;
424 /**********************************************************************
425 * parse_win_version
427 * Parse the contents of the Version key.
429 static BOOL parse_win_version( HANDLE hkey )
431 UNICODE_STRING valueW;
432 WCHAR *name, tmp[64];
433 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)tmp;
434 DWORD i, count;
436 RtlInitUnicodeString( &valueW, L"Version" );
437 if (NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp) - sizeof(WCHAR), &count ))
438 return FALSE;
440 name = (WCHAR *)info->Data;
441 name[info->DataLength / sizeof(WCHAR)] = 0;
443 for (i = 0; i < ARRAY_SIZE(version_names); i++)
445 if (wcscmp( version_names[i].name, name )) continue;
446 current_version = &VersionData[version_names[i].ver];
447 TRACE( "got win version %s\n", debugstr_w(version_names[i].name) );
448 return TRUE;
451 ERR( "Invalid Windows version value %s specified in config file.\n", debugstr_w(name) );
452 return FALSE;
456 /**********************************************************************
457 * version_init
459 void version_init(void)
461 OBJECT_ATTRIBUTES attr;
462 UNICODE_STRING nameW;
463 HANDLE root, hkey, config_key;
464 BOOL got_win_ver = FALSE;
465 const WCHAR *p, *appname = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
466 WCHAR appversion[MAX_PATH+20];
468 NtQuerySystemInformation( SystemWineVersionInformation, wine_version, sizeof(wine_version), NULL );
470 current_version = &VersionData[WIN7];
472 RtlOpenCurrentUser( KEY_ALL_ACCESS, &root );
473 attr.Length = sizeof(attr);
474 attr.RootDirectory = root;
475 attr.ObjectName = &nameW;
476 attr.Attributes = 0;
477 attr.SecurityDescriptor = NULL;
478 attr.SecurityQualityOfService = NULL;
479 RtlInitUnicodeString( &nameW, L"Software\\Wine" );
481 /* @@ Wine registry key: HKCU\Software\Wine */
482 if (NtOpenKey( &config_key, KEY_ALL_ACCESS, &attr )) config_key = 0;
483 NtClose( root );
484 if (!config_key) goto done;
486 /* open AppDefaults\\appname key */
488 if ((p = wcsrchr( appname, '/' ))) appname = p + 1;
489 if ((p = wcsrchr( appname, '\\' ))) appname = p + 1;
491 wcscpy( appversion, L"AppDefaults\\" );
492 wcscat( appversion, appname );
493 RtlInitUnicodeString( &nameW, appversion );
494 attr.RootDirectory = config_key;
496 /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe */
497 if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
499 TRACE( "getting version from %s\n", debugstr_w(appversion) );
500 got_win_ver = parse_win_version( hkey );
501 NtClose( hkey );
504 if (!got_win_ver)
506 TRACE( "getting default version\n" );
507 got_win_ver = parse_win_version( config_key );
509 NtClose( config_key );
511 done:
512 if (!got_win_ver)
514 static RTL_OSVERSIONINFOEXW registry_version;
516 TRACE( "getting registry version\n" );
517 if (get_nt_registry_version( &registry_version ) ||
518 get_win9x_registry_version( &registry_version ))
519 current_version = &registry_version;
523 NtCurrentTeb()->Peb->OSMajorVersion = current_version->dwMajorVersion;
524 NtCurrentTeb()->Peb->OSMinorVersion = current_version->dwMinorVersion;
525 NtCurrentTeb()->Peb->OSBuildNumber = current_version->dwBuildNumber;
526 NtCurrentTeb()->Peb->OSPlatformId = current_version->dwPlatformId;
528 TRACE( "got %d.%d platform %d build %x name %s service pack %d.%d product %d\n",
529 current_version->dwMajorVersion, current_version->dwMinorVersion,
530 current_version->dwPlatformId, current_version->dwBuildNumber,
531 debugstr_w(current_version->szCSDVersion),
532 current_version->wServicePackMajor, current_version->wServicePackMinor,
533 current_version->wProductType );
536 /***********************************************************************
537 * RtlGetProductInfo (NTDLL.@)
539 * Gives info about the current Windows product type, in a format compatible
540 * with the given Windows version
542 * Returns TRUE if the input is valid, FALSE otherwise
544 BOOLEAN WINAPI RtlGetProductInfo(DWORD dwOSMajorVersion, DWORD dwOSMinorVersion, DWORD dwSpMajorVersion,
545 DWORD dwSpMinorVersion, PDWORD pdwReturnedProductType)
547 TRACE("(%d, %d, %d, %d, %p)\n", dwOSMajorVersion, dwOSMinorVersion,
548 dwSpMajorVersion, dwSpMinorVersion, pdwReturnedProductType);
550 if (!pdwReturnedProductType)
551 return FALSE;
553 if (dwOSMajorVersion < 6)
555 *pdwReturnedProductType = PRODUCT_UNDEFINED;
556 return FALSE;
559 if (current_version->wProductType == VER_NT_WORKSTATION)
560 *pdwReturnedProductType = PRODUCT_ULTIMATE_N;
561 else
562 *pdwReturnedProductType = PRODUCT_STANDARD_SERVER;
564 return TRUE;
567 /***********************************************************************
568 * RtlGetVersion (NTDLL.@)
570 NTSTATUS WINAPI RtlGetVersion( RTL_OSVERSIONINFOEXW *info )
572 info->dwMajorVersion = current_version->dwMajorVersion;
573 info->dwMinorVersion = current_version->dwMinorVersion;
574 info->dwBuildNumber = current_version->dwBuildNumber;
575 info->dwPlatformId = current_version->dwPlatformId;
576 wcscpy( info->szCSDVersion, current_version->szCSDVersion );
577 if(info->dwOSVersionInfoSize == sizeof(RTL_OSVERSIONINFOEXW))
579 info->wServicePackMajor = current_version->wServicePackMajor;
580 info->wServicePackMinor = current_version->wServicePackMinor;
581 info->wSuiteMask = current_version->wSuiteMask;
582 info->wProductType = current_version->wProductType;
584 return STATUS_SUCCESS;
588 /******************************************************************************
589 * RtlGetNtVersionNumbers (NTDLL.@)
591 * Get the version numbers of the run time library.
593 * PARAMS
594 * major [O] Destination for the Major version
595 * minor [O] Destination for the Minor version
596 * build [O] Destination for the Build version
598 * RETURNS
599 * Nothing.
601 * NOTES
602 * Introduced in Windows XP (NT5.1)
604 void WINAPI RtlGetNtVersionNumbers( LPDWORD major, LPDWORD minor, LPDWORD build )
606 if (major) *major = current_version->dwMajorVersion;
607 if (minor) *minor = current_version->dwMinorVersion;
608 /* FIXME: Does anybody know the real formula? */
609 if (build) *build = (0xF0000000 | current_version->dwBuildNumber);
613 /******************************************************************************
614 * RtlGetNtProductType (NTDLL.@)
616 BOOLEAN WINAPI RtlGetNtProductType( LPDWORD type )
618 if (type) *type = current_version->wProductType;
619 return TRUE;
622 static inline UCHAR version_update_condition(UCHAR *last_condition, UCHAR condition)
624 switch (*last_condition)
626 case 0:
627 *last_condition = condition;
628 break;
629 case VER_EQUAL:
630 if (condition >= VER_EQUAL && condition <= VER_LESS_EQUAL)
632 *last_condition = condition;
633 return condition;
635 break;
636 case VER_GREATER:
637 case VER_GREATER_EQUAL:
638 if (condition >= VER_EQUAL && condition <= VER_GREATER_EQUAL)
639 return condition;
640 break;
641 case VER_LESS:
642 case VER_LESS_EQUAL:
643 if (condition == VER_EQUAL || (condition >= VER_LESS && condition <= VER_LESS_EQUAL))
644 return condition;
645 break;
647 if (!condition) *last_condition |= 0x10;
648 return *last_condition & 0xf;
651 static inline NTSTATUS version_compare_values(ULONG left, ULONG right, UCHAR condition)
653 switch (condition) {
654 case VER_EQUAL:
655 if (left != right) return STATUS_REVISION_MISMATCH;
656 break;
657 case VER_GREATER:
658 if (left <= right) return STATUS_REVISION_MISMATCH;
659 break;
660 case VER_GREATER_EQUAL:
661 if (left < right) return STATUS_REVISION_MISMATCH;
662 break;
663 case VER_LESS:
664 if (left >= right) return STATUS_REVISION_MISMATCH;
665 break;
666 case VER_LESS_EQUAL:
667 if (left > right) return STATUS_REVISION_MISMATCH;
668 break;
669 default:
670 return STATUS_REVISION_MISMATCH;
672 return STATUS_SUCCESS;
675 /******************************************************************************
676 * RtlVerifyVersionInfo (NTDLL.@)
678 NTSTATUS WINAPI RtlVerifyVersionInfo( const RTL_OSVERSIONINFOEXW *info,
679 DWORD dwTypeMask, DWORDLONG dwlConditionMask )
681 RTL_OSVERSIONINFOEXW ver;
682 NTSTATUS status;
684 TRACE("(%p,0x%x,0x%s)\n", info, dwTypeMask, wine_dbgstr_longlong(dwlConditionMask));
686 ver.dwOSVersionInfoSize = sizeof(ver);
687 if ((status = RtlGetVersion( &ver )) != STATUS_SUCCESS) return status;
689 if(!(dwTypeMask && dwlConditionMask)) return STATUS_INVALID_PARAMETER;
691 if(dwTypeMask & VER_PRODUCT_TYPE)
693 status = version_compare_values(ver.wProductType, info->wProductType, dwlConditionMask >> 7*3 & 0x07);
694 if (status != STATUS_SUCCESS)
695 return status;
697 if(dwTypeMask & VER_SUITENAME)
698 switch(dwlConditionMask >> 6*3 & 0x07)
700 case VER_AND:
701 if((info->wSuiteMask & ver.wSuiteMask) != info->wSuiteMask)
702 return STATUS_REVISION_MISMATCH;
703 break;
704 case VER_OR:
705 if(!(info->wSuiteMask & ver.wSuiteMask) && info->wSuiteMask)
706 return STATUS_REVISION_MISMATCH;
707 break;
708 default:
709 return STATUS_INVALID_PARAMETER;
711 if(dwTypeMask & VER_PLATFORMID)
713 status = version_compare_values(ver.dwPlatformId, info->dwPlatformId, dwlConditionMask >> 3*3 & 0x07);
714 if (status != STATUS_SUCCESS)
715 return status;
717 if(dwTypeMask & VER_BUILDNUMBER)
719 status = version_compare_values(ver.dwBuildNumber, info->dwBuildNumber, dwlConditionMask >> 2*3 & 0x07);
720 if (status != STATUS_SUCCESS)
721 return status;
724 if(dwTypeMask & (VER_MAJORVERSION|VER_MINORVERSION|VER_SERVICEPACKMAJOR|VER_SERVICEPACKMINOR))
726 unsigned char condition, last_condition = 0;
727 BOOLEAN do_next_check = TRUE;
729 if(dwTypeMask & VER_MAJORVERSION)
731 condition = version_update_condition(&last_condition, dwlConditionMask >> 1*3 & 0x07);
732 status = version_compare_values(ver.dwMajorVersion, info->dwMajorVersion, condition);
733 do_next_check = (ver.dwMajorVersion == info->dwMajorVersion) &&
734 ((condition >= VER_EQUAL) && (condition <= VER_LESS_EQUAL));
736 if((dwTypeMask & VER_MINORVERSION) && do_next_check)
738 condition = version_update_condition(&last_condition, dwlConditionMask >> 0*3 & 0x07);
739 status = version_compare_values(ver.dwMinorVersion, info->dwMinorVersion, condition);
740 do_next_check = (ver.dwMinorVersion == info->dwMinorVersion) &&
741 ((condition >= VER_EQUAL) && (condition <= VER_LESS_EQUAL));
743 if((dwTypeMask & VER_SERVICEPACKMAJOR) && do_next_check)
745 condition = version_update_condition(&last_condition, dwlConditionMask >> 5*3 & 0x07);
746 status = version_compare_values(ver.wServicePackMajor, info->wServicePackMajor, condition);
747 do_next_check = (ver.wServicePackMajor == info->wServicePackMajor) &&
748 ((condition >= VER_EQUAL) && (condition <= VER_LESS_EQUAL));
750 if((dwTypeMask & VER_SERVICEPACKMINOR) && do_next_check)
752 condition = version_update_condition(&last_condition, dwlConditionMask >> 4*3 & 0x07);
753 status = version_compare_values(ver.wServicePackMinor, info->wServicePackMinor, condition);
756 if (status != STATUS_SUCCESS)
757 return status;
760 return STATUS_SUCCESS;
764 /******************************************************************************
765 * VerSetConditionMask (NTDLL.@)
767 ULONGLONG WINAPI VerSetConditionMask( ULONGLONG condition_mask, DWORD type_mask, BYTE condition )
769 condition &= 0x07;
770 if (type_mask & VER_PRODUCT_TYPE) condition_mask |= condition << 7*3;
771 else if (type_mask & VER_SUITENAME) condition_mask |= condition << 6*3;
772 else if (type_mask & VER_SERVICEPACKMAJOR) condition_mask |= condition << 5*3;
773 else if (type_mask & VER_SERVICEPACKMINOR) condition_mask |= condition << 4*3;
774 else if (type_mask & VER_PLATFORMID) condition_mask |= condition << 3*3;
775 else if (type_mask & VER_BUILDNUMBER) condition_mask |= condition << 2*3;
776 else if (type_mask & VER_MAJORVERSION) condition_mask |= condition << 1*3;
777 else if (type_mask & VER_MINORVERSION) condition_mask |= condition << 0*3;
778 return condition_mask;