push 014043c4937c940c54cd1214c96e33a3b3c8cf7d
[wine/hacks.git] / dlls / ntdll / version.c
blobe5191442c772e8146ba5d2438455a550d2847be5
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 WIN2K3, /* Windows 2003 */
54 WINVISTA,/* Windows Vista */
55 NB_WINDOWS_VERSIONS
56 } WINDOWS_VERSION;
58 /* FIXME: compare values below with original and fix.
59 * An *excellent* win9x version page (ALL versions !)
60 * can be found at www.mdgx.com/ver.htm */
61 static const RTL_OSVERSIONINFOEXW VersionData[NB_WINDOWS_VERSIONS] =
63 /* WIN20 FIXME: verify values */
65 sizeof(RTL_OSVERSIONINFOEXW), 2, 0, 0, VER_PLATFORM_WIN32s,
66 {'W','i','n','3','2','s',' ','1','.','3',0},
67 0, 0, 0, 0, 0
69 /* WIN30 FIXME: verify values */
71 sizeof(RTL_OSVERSIONINFOEXW), 3, 0, 0, VER_PLATFORM_WIN32s,
72 {'W','i','n','3','2','s',' ','1','.','3',0},
73 0, 0, 0, 0, 0
75 /* WIN31 */
77 sizeof(RTL_OSVERSIONINFOEXW), 3, 10, 0, VER_PLATFORM_WIN32s,
78 {'W','i','n','3','2','s',' ','1','.','3',0},
79 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 {0},
92 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 {' ','A',' ',0},
101 0, 0, 0, 0, 0
103 /* WINME */
105 sizeof(RTL_OSVERSIONINFOEXW), 4, 90, 0x45A0BB8, VER_PLATFORM_WIN32_WINDOWS,
106 {' ',0},
107 0, 0, 0, 0, 0
109 /* NT351 */
111 sizeof(RTL_OSVERSIONINFOEXW), 3, 51, 0x421, VER_PLATFORM_WIN32_NT,
112 {'S','e','r','v','i','c','e',' ','P','a','c','k',' ','2',0},
113 0, 0, 0, 0, 0
115 /* NT40 */
117 sizeof(RTL_OSVERSIONINFOEXW), 4, 0, 0x565, VER_PLATFORM_WIN32_NT,
118 {'S','e','r','v','i','c','e',' ','P','a','c','k',' ','6','a',0},
119 6, 0, 0, VER_NT_WORKSTATION, 0
121 /* NT2K */
123 sizeof(RTL_OSVERSIONINFOEXW), 5, 0, 0x893, VER_PLATFORM_WIN32_NT,
124 {'S','e','r','v','i','c','e',' ','P','a','c','k',' ','4',0},
125 4, 0, 0, VER_NT_WORKSTATION, 30 /* FIXME: Great, a reserved field with a value! */
127 /* WINXP */
129 sizeof(RTL_OSVERSIONINFOEXW), 5, 1, 0xA28, VER_PLATFORM_WIN32_NT,
130 {'S','e','r','v','i','c','e',' ','P','a','c','k',' ','2',0},
131 2, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 30 /* FIXME: Great, a reserved field with a value! */
133 /* WIN2K3 */
135 sizeof(RTL_OSVERSIONINFOEXW), 5, 2, 0xECE, VER_PLATFORM_WIN32_NT,
136 {'S','e','r','v','i','c','e',' ','P','a','c','k',' ','1',0},
137 1, 0, VER_SUITE_SINGLEUSERTS, VER_NT_SERVER, 0
139 /* WINVISTA */
141 sizeof(RTL_OSVERSIONINFOEXW), 6, 0, 0x1770, VER_PLATFORM_WIN32_NT,
142 {' ',0},
143 0, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 0
147 static const char * const WinVersionNames[NB_WINDOWS_VERSIONS] =
148 { /* no spaces in here ! */
149 "win20", /* WIN20 */
150 "win30", /* WIN30 */
151 "win31", /* WIN31 */
152 "win95", /* WIN95 */
153 "win98", /* WIN98 */
154 "winme", /* WINME */
155 "nt351", /* NT351 */
156 "nt40", /* NT40 */
157 "win2000,win2k,nt2k,nt2000", /* NT2K */
158 "winxp", /* WINXP */
159 "win2003,win2k3", /* WIN2K3 */
160 "vista,winvista" /* WINVISTA*/
164 /* initialized to null so that we crash if we try to retrieve the version too early at startup */
165 static const RTL_OSVERSIONINFOEXW *current_version;
168 /**********************************************************************
169 * get_nt_registry_version
171 * Fetch the version information from the NT-style registry keys.
173 static BOOL get_nt_registry_version( RTL_OSVERSIONINFOEXW *version )
175 static const WCHAR version_keyW[] = {'M','a','c','h','i','n','e','\\',
176 'S','o','f','t','w','a','r','e','\\',
177 'M','i','c','r','o','s','o','f','t','\\',
178 'W','i','n','d','o','w','s',' ','N','T','\\',
179 'C','u','r','r','e','n','t','V','e','r','s','i','o','n',0};
180 static const WCHAR service_pack_keyW[] = {'M','a','c','h','i','n','e','\\',
181 'S','y','s','t','e','m','\\',
182 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
183 'C','o','n','t','r','o','l','\\',
184 'W','i','n','d','o','w','s',0};
185 static const WCHAR product_keyW[] = {'M','a','c','h','i','n','e','\\',
186 'S','y','s','t','e','m','\\',
187 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
188 'C','o','n','t','r','o','l','\\',
189 'P','r','o','d','u','c','t','O','p','t','i','o','n','s',0};
190 static const WCHAR CurrentBuildNumberW[] = {'C','u','r','r','e','n','t','B','u','i','l','d','N','u','m','b','e','r',0};
191 static const WCHAR CSDVersionW[] = {'C','S','D','V','e','r','s','i','o','n',0};
192 static const WCHAR CurrentVersionW[] = {'C','u','r','r','e','n','t','V','e','r','s','i','o','n',0};
193 static const WCHAR ProductTypeW[] = {'P','r','o','d','u','c','t','T','y','p','e',0};
194 static const WCHAR WinNTW[] = {'W','i','n','N','T',0};
195 static const WCHAR ServerNTW[] = {'S','e','r','v','e','r','N','T',0};
196 static const WCHAR LanmanNTW[] = {'L','a','n','m','a','n','N','T',0};
198 OBJECT_ATTRIBUTES attr;
199 UNICODE_STRING nameW, valueW;
200 HANDLE hkey, hkey2;
201 char tmp[64];
202 DWORD count;
203 BOOL ret = FALSE;
204 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)tmp;
206 attr.Length = sizeof(attr);
207 attr.RootDirectory = 0;
208 attr.ObjectName = &nameW;
209 attr.Attributes = 0;
210 attr.SecurityDescriptor = NULL;
211 attr.SecurityQualityOfService = NULL;
212 RtlInitUnicodeString( &nameW, version_keyW );
214 if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )) return FALSE;
216 memset( version, 0, sizeof(*version) );
218 RtlInitUnicodeString( &valueW, CurrentVersionW );
219 if (!NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp)-1, &count ))
221 WCHAR *p, *str = (WCHAR *)info->Data;
222 str[info->DataLength / sizeof(WCHAR)] = 0;
223 p = strchrW( str, '.' );
224 if (p)
226 *p++ = 0;
227 version->dwMinorVersion = atoiW( p );
229 version->dwMajorVersion = atoiW( str );
232 if (version->dwMajorVersion) /* we got the main version, now fetch the other fields */
234 ret = TRUE;
235 version->dwPlatformId = VER_PLATFORM_WIN32_NT;
237 /* get build number */
239 RtlInitUnicodeString( &valueW, CurrentBuildNumberW );
240 if (!NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp)-1, &count ))
242 WCHAR *str = (WCHAR *)info->Data;
243 str[info->DataLength / sizeof(WCHAR)] = 0;
244 version->dwBuildNumber = atoiW( str );
247 /* get version description */
249 RtlInitUnicodeString( &valueW, CSDVersionW );
250 if (!NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp)-1, &count ))
252 DWORD len = min( info->DataLength, sizeof(version->szCSDVersion) - sizeof(WCHAR) );
253 memcpy( version->szCSDVersion, info->Data, len );
254 version->szCSDVersion[len / sizeof(WCHAR)] = 0;
257 /* get service pack version */
259 RtlInitUnicodeString( &nameW, service_pack_keyW );
260 if (!NtOpenKey( &hkey2, KEY_ALL_ACCESS, &attr ))
262 RtlInitUnicodeString( &valueW, CSDVersionW );
263 if (!NtQueryValueKey( hkey2, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
265 if (info->DataLength >= sizeof(DWORD))
267 DWORD dw = *(DWORD *)info->Data;
268 version->wServicePackMajor = LOWORD(dw) >> 8;
269 version->wServicePackMinor = LOWORD(dw) & 0xff;
272 NtClose( hkey2 );
275 /* get product type */
277 RtlInitUnicodeString( &nameW, product_keyW );
278 if (!NtOpenKey( &hkey2, KEY_ALL_ACCESS, &attr ))
280 RtlInitUnicodeString( &valueW, ProductTypeW );
281 if (!NtQueryValueKey( hkey2, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp)-1, &count ))
283 WCHAR *str = (WCHAR *)info->Data;
284 str[info->DataLength / sizeof(WCHAR)] = 0;
285 if (!strcmpiW( str, WinNTW )) version->wProductType = VER_NT_WORKSTATION;
286 else if (!strcmpiW( str, LanmanNTW )) version->wProductType = VER_NT_DOMAIN_CONTROLLER;
287 else if (!strcmpiW( str, ServerNTW )) version->wProductType = VER_NT_SERVER;
289 NtClose( hkey2 );
292 /* FIXME: get wSuiteMask */
295 NtClose( hkey );
296 return ret;
300 /**********************************************************************
301 * get_win9x_registry_version
303 * Fetch the version information from the Win9x-style registry keys.
305 static BOOL get_win9x_registry_version( RTL_OSVERSIONINFOEXW *version )
307 static const WCHAR version_keyW[] = {'M','a','c','h','i','n','e','\\',
308 'S','o','f','t','w','a','r','e','\\',
309 'M','i','c','r','o','s','o','f','t','\\',
310 'W','i','n','d','o','w','s','\\',
311 'C','u','r','r','e','n','t','V','e','r','s','i','o','n',0};
312 static const WCHAR VersionNumberW[] = {'V','e','r','s','i','o','n','N','u','m','b','e','r',0};
313 static const WCHAR SubVersionNumberW[] = {'S','u','b','V','e','r','s','i','o','n','N','u','m','b','e','r',0};
315 OBJECT_ATTRIBUTES attr;
316 UNICODE_STRING nameW, valueW;
317 HANDLE hkey;
318 char tmp[64];
319 DWORD count;
320 BOOL ret = FALSE;
321 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)tmp;
323 attr.Length = sizeof(attr);
324 attr.RootDirectory = 0;
325 attr.ObjectName = &nameW;
326 attr.Attributes = 0;
327 attr.SecurityDescriptor = NULL;
328 attr.SecurityQualityOfService = NULL;
329 RtlInitUnicodeString( &nameW, version_keyW );
331 if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )) return FALSE;
333 memset( version, 0, sizeof(*version) );
335 RtlInitUnicodeString( &valueW, VersionNumberW );
336 if (!NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp)-1, &count ))
338 WCHAR *p, *str = (WCHAR *)info->Data;
339 str[info->DataLength / sizeof(WCHAR)] = 0;
340 p = strchrW( str, '.' );
341 if (p) *p++ = 0;
342 version->dwMajorVersion = atoiW( str );
343 if (p)
345 str = p;
346 p = strchrW( str, '.' );
347 if (p)
349 *p++ = 0;
350 version->dwBuildNumber = atoiW( p );
352 version->dwMinorVersion = atoiW( str );
354 /* build number contains version too on Win9x */
355 version->dwBuildNumber |= MAKEWORD( version->dwMinorVersion, version->dwMajorVersion ) << 16;
358 if (version->dwMajorVersion) /* we got the main version, now fetch the other fields */
360 ret = TRUE;
361 version->dwPlatformId = VER_PLATFORM_WIN32_WINDOWS;
363 RtlInitUnicodeString( &valueW, SubVersionNumberW );
364 if (!NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp)-1, &count ))
366 DWORD len = min( info->DataLength, sizeof(version->szCSDVersion) - sizeof(WCHAR) );
367 memcpy( version->szCSDVersion, info->Data, len );
368 version->szCSDVersion[len / sizeof(WCHAR)] = 0;
372 NtClose( hkey );
373 return ret;
377 /**********************************************************************
378 * parse_win_version
380 * Parse the contents of the Version key.
382 static BOOL parse_win_version( HANDLE hkey )
384 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
386 UNICODE_STRING valueW;
387 char tmp[64], buffer[50];
388 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)tmp;
389 DWORD count, len;
390 int i;
392 RtlInitUnicodeString( &valueW, VersionW );
393 if (NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
394 return FALSE;
396 RtlUnicodeToMultiByteN( buffer, sizeof(buffer)-1, &len, (WCHAR *)info->Data, info->DataLength );
397 buffer[len] = 0;
399 for (i = 0; i < NB_WINDOWS_VERSIONS; i++)
401 const char *p, *pCurr = WinVersionNames[i];
402 /* iterate through all winver aliases separated by comma */
403 do {
404 p = strchr(pCurr, ',');
405 len = p ? p - pCurr : strlen(pCurr);
406 if ( (!strncmp( pCurr, buffer, len )) && (buffer[len] == 0) )
408 current_version = &VersionData[i];
409 TRACE( "got win version %s\n", WinVersionNames[i] );
410 return TRUE;
412 pCurr = p+1;
413 } while (p);
416 MESSAGE("Invalid Windows version value '%s' specified in config file.\n", buffer );
417 MESSAGE("Valid versions are:" );
418 for (i = 0; i < NB_WINDOWS_VERSIONS; i++)
420 /* only list the first, "official" alias in case of aliases */
421 const char *pCurr = WinVersionNames[i];
422 const char *p = strchr(pCurr, ',');
423 len = (p) ? p - pCurr : strlen(pCurr);
425 MESSAGE(" '%.*s'%c", (int)len, pCurr, (i == NB_WINDOWS_VERSIONS - 1) ? '\n' : ',' );
427 return FALSE;
431 /**********************************************************************
432 * version_init
434 void version_init( const WCHAR *appname )
436 static const WCHAR configW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e',0};
437 static const WCHAR appdefaultsW[] = {'A','p','p','D','e','f','a','u','l','t','s','\\',0};
439 OBJECT_ATTRIBUTES attr;
440 UNICODE_STRING nameW;
441 HANDLE root, hkey, config_key;
442 BOOL got_win_ver = FALSE;
444 current_version = &VersionData[NT2K]; /* default if nothing else is specified */
446 RtlOpenCurrentUser( KEY_ALL_ACCESS, &root );
447 attr.Length = sizeof(attr);
448 attr.RootDirectory = root;
449 attr.ObjectName = &nameW;
450 attr.Attributes = 0;
451 attr.SecurityDescriptor = NULL;
452 attr.SecurityQualityOfService = NULL;
453 RtlInitUnicodeString( &nameW, configW );
455 /* @@ Wine registry key: HKCU\Software\Wine */
456 if (NtOpenKey( &config_key, KEY_ALL_ACCESS, &attr )) config_key = 0;
457 NtClose( root );
458 if (!config_key) goto done;
460 /* open AppDefaults\\appname key */
461 if (appname && *appname)
463 const WCHAR *p;
464 WCHAR appversion[MAX_PATH+20];
466 if ((p = strrchrW( appname, '/' ))) appname = p + 1;
467 if ((p = strrchrW( appname, '\\' ))) appname = p + 1;
469 strcpyW( appversion, appdefaultsW );
470 strcatW( appversion, appname );
471 RtlInitUnicodeString( &nameW, appversion );
472 attr.RootDirectory = config_key;
474 /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe */
475 if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
477 TRACE( "getting version from %s\n", debugstr_w(appversion) );
478 got_win_ver = parse_win_version( hkey );
479 NtClose( hkey );
483 if (!got_win_ver)
485 TRACE( "getting default version\n" );
486 got_win_ver = parse_win_version( config_key );
488 NtClose( config_key );
490 done:
491 if (!got_win_ver)
493 static RTL_OSVERSIONINFOEXW registry_version;
495 TRACE( "getting registry version\n" );
496 if (get_nt_registry_version( &registry_version ) ||
497 get_win9x_registry_version( &registry_version ))
498 current_version = &registry_version;
502 NtCurrentTeb()->Peb->OSMajorVersion = current_version->dwMajorVersion;
503 NtCurrentTeb()->Peb->OSMinorVersion = current_version->dwMinorVersion;
504 NtCurrentTeb()->Peb->OSBuildNumber = current_version->dwBuildNumber;
505 NtCurrentTeb()->Peb->OSPlatformId = current_version->dwPlatformId;
507 user_shared_data->NtProductType = current_version->wProductType;
508 user_shared_data->ProductTypeIsValid = TRUE;
509 user_shared_data->MajorNtVersion = current_version->dwMajorVersion;
510 user_shared_data->MinorNtVersion = current_version->dwMinorVersion;
511 user_shared_data->MinorNtVersion = current_version->dwMinorVersion;
512 user_shared_data->SuiteMask = current_version->wSuiteMask;
514 TRACE( "got %d.%d plaform %d build %x name %s service pack %d.%d product %d\n",
515 current_version->dwMajorVersion, current_version->dwMinorVersion,
516 current_version->dwPlatformId, current_version->dwBuildNumber,
517 debugstr_w(current_version->szCSDVersion),
518 current_version->wServicePackMajor, current_version->wServicePackMinor,
519 current_version->wProductType );
523 /***********************************************************************
524 * RtlGetVersion (NTDLL.@)
526 NTSTATUS WINAPI RtlGetVersion( RTL_OSVERSIONINFOEXW *info )
528 info->dwMajorVersion = current_version->dwMajorVersion;
529 info->dwMinorVersion = current_version->dwMinorVersion;
530 info->dwBuildNumber = current_version->dwBuildNumber;
531 info->dwPlatformId = current_version->dwPlatformId;
532 strcpyW( info->szCSDVersion, current_version->szCSDVersion );
533 if(info->dwOSVersionInfoSize == sizeof(RTL_OSVERSIONINFOEXW))
535 info->wServicePackMajor = current_version->wServicePackMajor;
536 info->wServicePackMinor = current_version->wServicePackMinor;
537 info->wSuiteMask = current_version->wSuiteMask;
538 info->wProductType = current_version->wProductType;
540 return STATUS_SUCCESS;
544 /******************************************************************************
545 * RtlGetNtVersionNumbers (NTDLL.@)
547 * Get the version numbers of the run time library.
549 * PARAMS
550 * major [O] Destination for the Major version
551 * minor [O] Destination for the Minor version
552 * build [O] Destination for the Build version
554 * RETURNS
555 * Nothing.
557 * NOTES
558 * Introduced in Windows XP (NT5.1)
560 void WINAPI RtlGetNtVersionNumbers( LPDWORD major, LPDWORD minor, LPDWORD build )
562 if (major) *major = current_version->dwMajorVersion;
563 if (minor) *minor = current_version->dwMinorVersion;
564 /* FIXME: Does anybody know the real formula? */
565 if (build) *build = (0xF0000000 | current_version->dwBuildNumber);
569 /******************************************************************************
570 * RtlGetNtProductType (NTDLL.@)
572 BOOLEAN WINAPI RtlGetNtProductType( LPDWORD type )
574 if (type) *type = current_version->wProductType;
575 return TRUE;
579 static inline NTSTATUS version_compare_values(ULONG left, ULONG right, UCHAR condition)
581 switch (condition) {
582 case VER_EQUAL:
583 if (left != right) return STATUS_REVISION_MISMATCH;
584 break;
585 case VER_GREATER:
586 if (left <= right) return STATUS_REVISION_MISMATCH;
587 break;
588 case VER_GREATER_EQUAL:
589 if (left < right) return STATUS_REVISION_MISMATCH;
590 break;
591 case VER_LESS:
592 if (left >= right) return STATUS_REVISION_MISMATCH;
593 break;
594 case VER_LESS_EQUAL:
595 if (left > right) return STATUS_REVISION_MISMATCH;
596 break;
597 default:
598 return STATUS_REVISION_MISMATCH;
600 return STATUS_SUCCESS;
603 /******************************************************************************
604 * RtlVerifyVersionInfo (NTDLL.@)
606 NTSTATUS WINAPI RtlVerifyVersionInfo( const RTL_OSVERSIONINFOEXW *info,
607 DWORD dwTypeMask, DWORDLONG dwlConditionMask )
609 RTL_OSVERSIONINFOEXW ver;
610 NTSTATUS status;
612 TRACE("(%p,0x%x,0x%s)\n", info, dwTypeMask, wine_dbgstr_longlong(dwlConditionMask));
614 ver.dwOSVersionInfoSize = sizeof(ver);
615 if ((status = RtlGetVersion( &ver )) != STATUS_SUCCESS) return status;
617 if(!(dwTypeMask && dwlConditionMask)) return STATUS_INVALID_PARAMETER;
619 if(dwTypeMask & VER_PRODUCT_TYPE)
621 status = version_compare_values(ver.wProductType, info->wProductType, dwlConditionMask >> 7*3 & 0x07);
622 if (status != STATUS_SUCCESS)
623 return status;
625 if(dwTypeMask & VER_SUITENAME)
626 switch(dwlConditionMask >> 6*3 & 0x07)
628 case VER_AND:
629 if((info->wSuiteMask & ver.wSuiteMask) != info->wSuiteMask)
630 return STATUS_REVISION_MISMATCH;
631 break;
632 case VER_OR:
633 if(!(info->wSuiteMask & ver.wSuiteMask) && info->wSuiteMask)
634 return STATUS_REVISION_MISMATCH;
635 break;
636 default:
637 return STATUS_INVALID_PARAMETER;
639 if(dwTypeMask & VER_PLATFORMID)
641 status = version_compare_values(ver.dwPlatformId, info->dwPlatformId, dwlConditionMask >> 3*3 & 0x07);
642 if (status != STATUS_SUCCESS)
643 return status;
645 if(dwTypeMask & VER_BUILDNUMBER)
647 status = version_compare_values(ver.dwBuildNumber, info->dwBuildNumber, dwlConditionMask >> 2*3 & 0x07);
648 if (status != STATUS_SUCCESS)
649 return status;
652 if(dwTypeMask & (VER_MAJORVERSION|VER_MINORVERSION|VER_SERVICEPACKMAJOR|VER_SERVICEPACKMINOR))
654 unsigned char condition = 0;
655 BOOLEAN do_next_check = TRUE;
657 if(dwTypeMask & VER_MAJORVERSION)
658 condition = dwlConditionMask >> 1*3 & 0x07;
659 else if(dwTypeMask & VER_MINORVERSION)
660 condition = dwlConditionMask >> 0*3 & 0x07;
661 else if(dwTypeMask & VER_SERVICEPACKMAJOR)
662 condition = dwlConditionMask >> 5*3 & 0x07;
663 else if(dwTypeMask & VER_SERVICEPACKMINOR)
664 condition = dwlConditionMask >> 4*3 & 0x07;
666 if(dwTypeMask & VER_MAJORVERSION)
668 status = version_compare_values(ver.dwMajorVersion, info->dwMajorVersion, condition);
669 do_next_check = (ver.dwMajorVersion == info->dwMajorVersion) &&
670 ((condition != VER_EQUAL) || (status == STATUS_SUCCESS));
672 if((dwTypeMask & VER_MINORVERSION) && do_next_check)
674 status = version_compare_values(ver.dwMinorVersion, info->dwMinorVersion, condition);
675 do_next_check = (ver.dwMinorVersion == info->dwMinorVersion) &&
676 ((condition != VER_EQUAL) || (status == STATUS_SUCCESS));
678 if((dwTypeMask & VER_SERVICEPACKMAJOR) && do_next_check)
680 status = version_compare_values(ver.wServicePackMajor, info->wServicePackMajor, condition);
681 do_next_check = (ver.wServicePackMajor == info->wServicePackMajor) &&
682 ((condition != VER_EQUAL) || (status == STATUS_SUCCESS));
684 if((dwTypeMask & VER_SERVICEPACKMINOR) && do_next_check)
686 status = version_compare_values(ver.wServicePackMinor, info->wServicePackMinor, condition);
689 if (status != STATUS_SUCCESS)
690 return status;
693 return STATUS_SUCCESS;