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
29 #define WIN32_NO_STATUS
31 #include "wine/debug.h"
32 #include "ntdll_misc.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(ver
);
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 */
56 WIN81
, /* Windows 8.1 */
57 WIN10
, /* Windows 10 */
58 WIN11
, /* Windows 11 */
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
79 sizeof(RTL_OSVERSIONINFOEXW
), 3, 10, 0, VER_PLATFORM_WIN32s
,
80 L
"Win32s 1.3", 0, 0, 0, 0, 0
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
,
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
104 sizeof(RTL_OSVERSIONINFOEXW
), 4, 90, 0x45A0BB8, VER_PLATFORM_WIN32_WINDOWS
,
109 sizeof(RTL_OSVERSIONINFOEXW
), 3, 51, 1057, VER_PLATFORM_WIN32_NT
,
110 L
"Service Pack 5", 5, 0, 0, VER_NT_WORKSTATION
, 0
114 sizeof(RTL_OSVERSIONINFOEXW
), 4, 0, 1381, VER_PLATFORM_WIN32_NT
,
115 L
"Service Pack 6a", 6, 0, 0, VER_NT_WORKSTATION
, 0
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! */
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! */
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
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
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
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
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
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
161 sizeof(RTL_OSVERSIONINFOEXW
), 6, 2, 9200, VER_PLATFORM_WIN32_NT
,
162 L
"", 0, 0, VER_SUITE_SINGLEUSERTS
, VER_NT_WORKSTATION
, 0
166 sizeof(RTL_OSVERSIONINFOEXW
), 6, 3, 9600, VER_PLATFORM_WIN32_NT
,
167 L
"", 0, 0, VER_SUITE_SINGLEUSERTS
, VER_NT_WORKSTATION
, 0
171 sizeof(RTL_OSVERSIONINFOEXW
), 10, 0, 18362, VER_PLATFORM_WIN32_NT
,
172 L
"", 0, 0, VER_SUITE_SINGLEUSERTS
, VER_NT_WORKSTATION
, 0
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
[] =
191 { L
"win2000", NT2K
},
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
},
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 /*********************************************************************
221 const char * CDECL
wine_get_version(void)
227 /*********************************************************************
230 const char * CDECL
wine_get_build_id(void)
232 const char *p
= wine_version
;
233 p
+= strlen(p
) + 1; /* skip version */
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
;
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
;
265 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)tmp
;
267 attr
.Length
= sizeof(attr
);
268 attr
.RootDirectory
= 0;
269 attr
.ObjectName
= &nameW
;
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
, '.' );
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 */
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;
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
;
371 /* FIXME: get wSuiteMask */
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
;
392 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)tmp
;
394 attr
.Length
= sizeof(attr
);
395 attr
.RootDirectory
= 0;
396 attr
.ObjectName
= &nameW
;
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
, '.' );
413 version
->dwMajorVersion
= wcstoul( str
, NULL
, 10 );
417 p
= wcschr( str
, '.' );
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 */
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;
448 /**********************************************************************
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
;
460 RtlInitUnicodeString( &valueW
, L
"Version" );
461 if (NtQueryValueKey( hkey
, &valueW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
) - sizeof(WCHAR
), &count
))
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
) );
475 ERR( "Invalid Windows version value %s specified in config file.\n", debugstr_w(name
) );
480 /**********************************************************************
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
;
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;
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
);
530 TRACE( "getting default version\n" );
531 got_win_ver
= parse_win_version( config_key
);
533 NtClose( config_key
);
538 static RTL_OSVERSIONINFOEXW registry_version
;
540 TRACE( "getting registry version\n" );
541 if (get_nt_registry_version( ®istry_version
) ||
542 get_win9x_registry_version( ®istry_version
))
543 current_version
= ®istry_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
)
577 if (dwOSMajorVersion
< 6)
579 *pdwReturnedProductType
= PRODUCT_UNDEFINED
;
583 if (current_version
->wProductType
== VER_NT_WORKSTATION
)
584 *pdwReturnedProductType
= PRODUCT_ULTIMATE_N
;
586 *pdwReturnedProductType
= PRODUCT_STANDARD_SERVER
;
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.
618 * major [O] Destination for the Major version
619 * minor [O] Destination for the Minor version
620 * build [O] Destination for the Build version
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
;
646 static inline UCHAR
version_update_condition(UCHAR
*last_condition
, UCHAR condition
)
648 switch (*last_condition
)
651 *last_condition
= condition
;
654 if (condition
>= VER_EQUAL
&& condition
<= VER_LESS_EQUAL
)
656 *last_condition
= condition
;
661 case VER_GREATER_EQUAL
:
662 if (condition
>= VER_EQUAL
&& condition
<= VER_GREATER_EQUAL
)
667 if (condition
== VER_EQUAL
|| (condition
>= VER_LESS
&& condition
<= VER_LESS_EQUAL
))
671 if (!condition
) *last_condition
|= 0x10;
672 return *last_condition
& 0xf;
675 static inline NTSTATUS
version_compare_values(ULONG left
, ULONG right
, UCHAR condition
)
679 if (left
!= right
) return STATUS_REVISION_MISMATCH
;
682 if (left
<= right
) return STATUS_REVISION_MISMATCH
;
684 case VER_GREATER_EQUAL
:
685 if (left
< right
) return STATUS_REVISION_MISMATCH
;
688 if (left
>= right
) return STATUS_REVISION_MISMATCH
;
691 if (left
> right
) return STATUS_REVISION_MISMATCH
;
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
;
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
)
721 if(dwTypeMask
& VER_SUITENAME
)
722 switch(dwlConditionMask
>> 6*3 & 0x07)
725 if((info
->wSuiteMask
& ver
.wSuiteMask
) != info
->wSuiteMask
)
726 return STATUS_REVISION_MISMATCH
;
729 if(!(info
->wSuiteMask
& ver
.wSuiteMask
) && info
->wSuiteMask
)
730 return STATUS_REVISION_MISMATCH
;
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
)
741 if(dwTypeMask
& VER_BUILDNUMBER
)
743 status
= version_compare_values(ver
.dwBuildNumber
, info
->dwBuildNumber
, dwlConditionMask
>> 2*3 & 0x07);
744 if (status
!= STATUS_SUCCESS
)
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
)
784 return STATUS_SUCCESS
;
788 /******************************************************************************
789 * VerSetConditionMask (NTDLL.@)
791 ULONGLONG WINAPI
VerSetConditionMask( ULONGLONG condition_mask
, DWORD type_mask
, BYTE condition
)
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
;