blob: daa428c32e59f8813ef7c8a9cd21fa503b37b64a [file] [log] [blame]
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00001/*
Alexandre Julliard638f1691999-01-17 16:32:32 +00002 * Windows and DOS version functions
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00003 *
4 * Copyright 1997 Alexandre Julliard
5 * Copyright 1997 Marcus Meissner
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00006 * Copyright 1998 Patrik Stridvall
Andreas Mohr5f66b042003-04-16 23:08:33 +00007 * Copyright 1998,2003 Andreas Mohr
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00008 *
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.
13 *
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.
18 *
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +000022 */
23
Patrik Stridvall57bf4502002-08-26 21:53:24 +000024#include "config.h"
25#include "wine/port.h"
26
Alexandre Julliard03468f71998-02-15 19:40:49 +000027#include <string.h>
Alexandre Julliard638f1691999-01-17 16:32:32 +000028#include <stdlib.h>
Jeremy Whited3e22d92000-02-10 19:03:02 +000029#include <stdio.h>
30#include "windef.h"
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +000031#include "winbase.h"
Jeremy Whited3e22d92000-02-10 19:03:02 +000032#include "wingdi.h"
Marcus Meissner04c3e1d1999-02-19 10:37:02 +000033#include "winuser.h"
Patrik Stridvall9c1de6d2002-09-12 22:07:02 +000034#include "winternl.h"
Alexandre Julliard81bdcf12002-09-13 17:47:44 +000035#include "winerror.h"
Marcus Meissner04c3e1d1999-02-19 10:37:02 +000036#include "wine/winbase16.h"
Alexandre Julliardbecb9a32000-12-11 03:48:15 +000037#include "module.h"
Alexandre Julliard81bdcf12002-09-13 17:47:44 +000038#include "wine/unicode.h"
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000039#include "wine/debug.h"
Eric Pouech051f8712003-03-21 00:34:36 +000040#include "ntdll_misc.h"
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +000041
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000042WINE_DEFAULT_DEBUG_CHANNEL(ver);
Alexandre Julliardd586dc92000-08-14 14:35:01 +000043
44typedef enum
45{
Andreas Mohrcb454382000-11-27 01:39:05 +000046 WIN20, /* Windows 2.0 */
47 WIN30, /* Windows 3.0 */
48 WIN31, /* Windows 3.1 */
Alexandre Julliardd586dc92000-08-14 14:35:01 +000049 WIN95, /* Windows 95 */
50 WIN98, /* Windows 98 */
Francois Gouget4ae71952001-11-06 00:49:48 +000051 WINME, /* Windows Me */
Alexandre Julliardd586dc92000-08-14 14:35:01 +000052 NT351, /* Windows NT 3.51 */
Francois Gouget4ae71952001-11-06 00:49:48 +000053 NT40, /* Windows NT 4.0 */
Andreas Mohrcb454382000-11-27 01:39:05 +000054 NT2K, /* Windows 2000 */
Francois Gouget4ae71952001-11-06 00:49:48 +000055 WINXP, /* Windows XP */
Alexandre Julliardd586dc92000-08-14 14:35:01 +000056 NB_WINDOWS_VERSIONS
57} WINDOWS_VERSION;
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000058
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +000059typedef struct
60{
Andreas Mohr5f66b042003-04-16 23:08:33 +000061 char human_readable[32];
Vincent Béron9a624912002-05-31 23:06:46 +000062 LONG getVersion16;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +000063 LONG getVersion32;
Vincent Béron9d9cf722002-05-24 21:13:45 +000064 OSVERSIONINFOEXA getVersionEx;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +000065} VERSION_DATA;
66
Andreas Mohre6b031b2002-05-25 21:06:37 +000067/* FIXME: compare values below with original and fix.
68 * An *excellent* win9x version page (ALL versions !)
69 * can be found at members.aol.com/axcel216/ver.htm */
Alexandre Julliard638f1691999-01-17 16:32:32 +000070static VERSION_DATA VersionData[NB_WINDOWS_VERSIONS] =
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +000071{
Andreas Mohrcb454382000-11-27 01:39:05 +000072 /* WIN20 FIXME: verify values */
73 {
Andreas Mohr5f66b042003-04-16 23:08:33 +000074 "Windows 2.0",
Andreas Mohrcb454382000-11-27 01:39:05 +000075 MAKELONG( 0x0002, 0x0303 ), /* assume DOS 3.3 */
Andreas Mohre6b031b2002-05-25 21:06:37 +000076 MAKELONG( 0x0002, 0x8000 ),
Andreas Mohrcb454382000-11-27 01:39:05 +000077 {
Andreas Mohr5f66b042003-04-16 23:08:33 +000078 /* yes, sizeof(OSVERSIONINFOA) is correct here
79 * (in case of OSVERSIONINFOEXA application request,
80 * we adapt it dynamically). */
Andreas Mohrcb454382000-11-27 01:39:05 +000081 sizeof(OSVERSIONINFOA), 2, 0, 0,
Vincent Béron9d9cf722002-05-24 21:13:45 +000082 VER_PLATFORM_WIN32s, "Win32s 1.3",
83 0, 0, 0, 0, 0
Andreas Mohrcb454382000-11-27 01:39:05 +000084 }
85 },
86 /* WIN30 FIXME: verify values */
87 {
Andreas Mohr5f66b042003-04-16 23:08:33 +000088 "Windows 3.0",
Andreas Mohrcb454382000-11-27 01:39:05 +000089 MAKELONG( 0x0003, 0x0500 ), /* assume DOS 5.00 */
90 MAKELONG( 0x0003, 0x8000 ),
91 {
92 sizeof(OSVERSIONINFOA), 3, 0, 0,
Vincent Béron9d9cf722002-05-24 21:13:45 +000093 VER_PLATFORM_WIN32s, "Win32s 1.3",
94 0, 0, 0, 0, 0
Andreas Mohrcb454382000-11-27 01:39:05 +000095 }
96 },
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +000097 /* WIN31 */
98 {
Andreas Mohr5f66b042003-04-16 23:08:33 +000099 "Windows 3.1",
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000100 MAKELONG( 0x0a03, 0x0616 ), /* DOS 6.22 */
101 MAKELONG( 0x0a03, 0x8000 ),
102 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000103 sizeof(OSVERSIONINFOA), 3, 10, 0,
Vincent Béron9d9cf722002-05-24 21:13:45 +0000104 VER_PLATFORM_WIN32s, "Win32s 1.3",
105 0, 0, 0, 0, 0
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000106 }
107 },
108 /* WIN95 */
109 {
Andreas Mohr5f66b042003-04-16 23:08:33 +0000110 "Windows 95",
Marcus Meissner099c1592001-10-23 19:55:11 +0000111 0x07005F03,
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000112 0xC0000004,
Francois Gouget4ae71952001-11-06 00:49:48 +0000113 {
114 /* Win95: 4, 0, 0x40003B6, ""
115 * Win95sp1: 4, 0, 0x40003B6, " A " (according to doc)
116 * Win95osr2: 4, 0, 0x4000457, " B " (according to doc)
117 * Win95osr2.1: 4, 3, 0x40304BC, " B " (according to doc)
118 * Win95osr2.5: 4, 3, 0x40304BE, " C " (according to doc)
119 * Win95a/b can be discerned via regkey SubVersionNumber
120 * See also:
121 * http://support.microsoft.com/support/kb/articles/q158/2/38.asp
122 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000123 sizeof(OSVERSIONINFOA), 4, 0, 0x40003B6,
Vincent Béron9d9cf722002-05-24 21:13:45 +0000124 VER_PLATFORM_WIN32_WINDOWS, "",
125 0, 0, 0, 0, 0
Francois Gouget4ae71952001-11-06 00:49:48 +0000126 }
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000127 },
Andreas Mohre6b031b2002-05-25 21:06:37 +0000128 /* WIN98 (second edition) */
Ian Schmidtd736ef41999-07-18 15:33:25 +0000129 {
Andreas Mohr5f66b042003-04-16 23:08:33 +0000130 "Windows 98 SE",
Francois Gouget4ae71952001-11-06 00:49:48 +0000131 0x070A5F03,
132 0xC0000A04,
133 {
Andreas Mohre6b031b2002-05-25 21:06:37 +0000134 /* Win98: 4, 10, 0x40A07CE, " " 4.10.1998
135 * Win98SE: 4, 10, 0x40A08AE, " A " 4.10.2222
Francois Gouget4ae71952001-11-06 00:49:48 +0000136 */
Andreas Mohre6b031b2002-05-25 21:06:37 +0000137 sizeof(OSVERSIONINFOA), 4, 10, 0x40A08AE,
138 VER_PLATFORM_WIN32_WINDOWS, " A ",
Vincent Béron9d9cf722002-05-24 21:13:45 +0000139 0, 0, 0, 0, 0
Francois Gouget4ae71952001-11-06 00:49:48 +0000140 }
141 },
142 /* WINME */
143 {
Andreas Mohr5f66b042003-04-16 23:08:33 +0000144 "Windows ME",
Andreas Mohre6b031b2002-05-25 21:06:37 +0000145 0x08005F03,
Francois Gouget4ae71952001-11-06 00:49:48 +0000146 0xC0005A04,
147 {
148 sizeof(OSVERSIONINFOA), 4, 90, 0x45A0BB8,
Vincent Béron9d9cf722002-05-24 21:13:45 +0000149 VER_PLATFORM_WIN32_WINDOWS, " ",
150 0, 0, 0, 0, 0
Francois Gouget4ae71952001-11-06 00:49:48 +0000151 }
Ian Schmidtd736ef41999-07-18 15:33:25 +0000152 },
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000153 /* NT351 */
154 {
Andreas Mohr5f66b042003-04-16 23:08:33 +0000155 "Windows NT 3.51",
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000156 0x05000A03,
157 0x04213303,
158 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000159 sizeof(OSVERSIONINFOA), 3, 51, 0x421,
Vincent Béron9d9cf722002-05-24 21:13:45 +0000160 VER_PLATFORM_WIN32_NT, "Service Pack 2",
161 0, 0, 0, 0, 0
Francois Gouget4ae71952001-11-06 00:49:48 +0000162 }
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000163 },
164 /* NT40 */
165 {
Andreas Mohr5f66b042003-04-16 23:08:33 +0000166 "Windows NT 4.0",
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000167 0x05000A03,
168 0x05650004,
169 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000170 sizeof(OSVERSIONINFOA), 4, 0, 0x565,
Vincent Béron9d9cf722002-05-24 21:13:45 +0000171 VER_PLATFORM_WIN32_NT, "Service Pack 6",
172 6, 0, 0, VER_NT_WORKSTATION, 0
Andreas Mohrcb454382000-11-27 01:39:05 +0000173 }
174 },
Francois Gouget4ae71952001-11-06 00:49:48 +0000175 /* NT2K */
Andreas Mohrcb454382000-11-27 01:39:05 +0000176 {
Andreas Mohr5f66b042003-04-16 23:08:33 +0000177 "Windows 2000",
Francois Gouget4ae71952001-11-06 00:49:48 +0000178 0x05005F03,
179 0x08930005,
Andreas Mohrcb454382000-11-27 01:39:05 +0000180 {
181 sizeof(OSVERSIONINFOA), 5, 0, 0x893,
Vincent Bérond3ac4222003-04-19 02:47:56 +0000182 VER_PLATFORM_WIN32_NT, "Service Pack 3",
183 3, 0, 0, VER_NT_WORKSTATION, 30 /* FIXME: Great, a reserved field with a value! */
Francois Gouget4ae71952001-11-06 00:49:48 +0000184 }
185 },
186 /* WINXP */
187 {
Andreas Mohr5f66b042003-04-16 23:08:33 +0000188 "Windows XP",
Francois Gouget4ae71952001-11-06 00:49:48 +0000189 0x05005F03, /* Assuming DOS 5 like the other NT */
190 0x0A280105,
191 {
192 sizeof(OSVERSIONINFOA), 5, 1, 0xA28,
Vincent Bérond3ac4222003-04-19 02:47:56 +0000193 VER_PLATFORM_WIN32_NT, "Service Pack 1",
194 1, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 30 /* FIXME: Great, a reserved field with a value! */
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000195 }
196 }
197};
198
Alexandre Julliard638f1691999-01-17 16:32:32 +0000199static const char *WinVersionNames[NB_WINDOWS_VERSIONS] =
Andreas Mohrc3350c52000-11-30 01:29:45 +0000200{ /* no spaces in here ! */
Andreas Mohrcb454382000-11-27 01:39:05 +0000201 "win20",
202 "win30",
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000203 "win31",
204 "win95",
Ian Schmidtd736ef41999-07-18 15:33:25 +0000205 "win98",
Francois Gouget4ae71952001-11-06 00:49:48 +0000206 "winme",
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000207 "nt351",
Andreas Mohrcb454382000-11-27 01:39:05 +0000208 "nt40",
Francois Gouget4ae71952001-11-06 00:49:48 +0000209 "win2000,win2k,nt2k,nt2000",
210 "winxp"
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000211};
212
Juergen Schmieda72a3981999-10-31 21:38:31 +0000213/* if one of the following dlls is importing ntdll the windows
214version autodetection switches wine to unicode (nt 3.51 or 4.0) */
215static char * special_dlls[] =
216{
Alexandre Julliard1df18832002-09-06 18:37:48 +0000217 "comdlg32.dll",
218 "comctl32.dll",
219 "shell32.dll",
220 "ole32.dll",
221 "rpcrt4.dll",
Juergen Schmieda72a3981999-10-31 21:38:31 +0000222 NULL
223};
224
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000225/* the current version has not been autodetected but forced via cmdline */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000226static BOOL versionForced = FALSE;
Andreas Mohre6b031b2002-05-25 21:06:37 +0000227static WINDOWS_VERSION forcedWinVersion = WIN31; /* init value irrelevant */
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000228
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000229/**********************************************************************
Alexandre Julliard638f1691999-01-17 16:32:32 +0000230 * VERSION_ParseWinVersion
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000231 */
Alexandre Julliard8c08ceb2002-05-23 19:35:18 +0000232static void VERSION_ParseWinVersion( const char *arg )
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000233{
Andreas Mohrc3350c52000-11-30 01:29:45 +0000234 int i, len;
235 const char *pCurr, *p;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000236 for (i = 0; i < NB_WINDOWS_VERSIONS; i++)
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000237 {
Andreas Mohrc3350c52000-11-30 01:29:45 +0000238 pCurr = WinVersionNames[i];
239 /* iterate through all winver aliases separated by comma */
240 do {
241 p = strchr(pCurr, ',');
242 len = p ? (int)p - (int)pCurr : strlen(pCurr);
243 if ( (!strncmp( pCurr, arg, len )) && (arg[len] == '\0') )
244 {
Andreas Mohre6b031b2002-05-25 21:06:37 +0000245 forcedWinVersion = (WINDOWS_VERSION)i;
Andreas Mohrc3350c52000-11-30 01:29:45 +0000246 versionForced = TRUE;
247 return;
248 }
249 pCurr = p+1;
250 } while (p);
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000251 }
Alexandre Julliard8c08ceb2002-05-23 19:35:18 +0000252 MESSAGE("Invalid Windows version value '%s' specified in config file.\n", arg );
Alexandre Julliard61fece01999-06-26 19:09:08 +0000253 MESSAGE("Valid versions are:" );
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000254 for (i = 0; i < NB_WINDOWS_VERSIONS; i++)
Andreas Mohrc3350c52000-11-30 01:29:45 +0000255 {
256 /* only list the first, "official" alias in case of aliases */
257 pCurr = WinVersionNames[i];
258 p = strchr(pCurr, ',');
259 len = (p) ? (int)p - (int)pCurr : strlen(pCurr);
260
261 MESSAGE(" '%.*s'%c", len, pCurr,
262 (i == NB_WINDOWS_VERSIONS - 1) ? '\n' : ',' );
263 }
Alexandre Julliardfe085682000-03-18 21:56:10 +0000264 ExitProcess(1);
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000265}
266
267
268/**********************************************************************
Alexandre Julliard638f1691999-01-17 16:32:32 +0000269 * VERSION_ParseDosVersion
270 */
Alexandre Julliard8c08ceb2002-05-23 19:35:18 +0000271static void VERSION_ParseDosVersion( const char *arg )
Alexandre Julliard638f1691999-01-17 16:32:32 +0000272{
273 int hi, lo;
274 if (sscanf( arg, "%d.%d", &hi, &lo ) == 2)
275 {
276 VersionData[WIN31].getVersion16 =
277 MAKELONG(LOWORD(VersionData[WIN31].getVersion16),
278 (hi<<8) + lo);
279 }
280 else
Alexandre Julliardfe085682000-03-18 21:56:10 +0000281 {
Alexandre Julliard8c08ceb2002-05-23 19:35:18 +0000282 MESSAGE("Wrong format for DOS version in config file. Use \"x.xx\"\n");
Alexandre Julliardfe085682000-03-18 21:56:10 +0000283 ExitProcess(1);
284 }
Alexandre Julliard638f1691999-01-17 16:32:32 +0000285}
286
Alexandre Julliard8c08ceb2002-05-23 19:35:18 +0000287
288/**********************************************************************
Alexandre Julliard81bdcf12002-09-13 17:47:44 +0000289 * VERSION_ParseVersion
290 *
291 * Parse the contents of the Version key.
292 */
293static void VERSION_ParseVersion( HKEY hkey, BOOL *got_win_ver, BOOL *got_dos_ver )
294{
295 static const WCHAR WindowsW[] = {'W','i','n','d','o','w','s',0};
296 static const WCHAR DosW[] = {'D','O','S',0};
297
298 UNICODE_STRING valueW;
299 char tmp[64], buffer[50];
300 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)tmp;
301 DWORD count, len;
302
303 if (!*got_win_ver)
304 {
305 RtlInitUnicodeString( &valueW, WindowsW );
306 if (!NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
307 {
308 RtlUnicodeToMultiByteN( buffer, sizeof(buffer)-1, &len,
309 (WCHAR *)info->Data, info->DataLength );
310 buffer[len] = 0;
311 VERSION_ParseWinVersion( buffer );
312 TRACE( "got win version %s\n", WinVersionNames[forcedWinVersion] );
313 *got_win_ver = TRUE;
314 }
315 }
316 if (!*got_dos_ver)
317 {
318 RtlInitUnicodeString( &valueW, DosW );
319 if (!NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
320 {
321 RtlUnicodeToMultiByteN( buffer, sizeof(buffer)-1, &len,
322 (WCHAR *)info->Data, info->DataLength );
323 buffer[len] = 0;
324 VERSION_ParseDosVersion( buffer );
325 TRACE( "got dos version %lx\n", VersionData[WIN31].getVersion16 );
326 *got_dos_ver = TRUE;
327 }
328 }
329}
330
331
332/**********************************************************************
Alexandre Julliard8c08ceb2002-05-23 19:35:18 +0000333 * VERSION_Init
334 */
Alexandre Julliarda0585842003-04-20 02:46:44 +0000335void VERSION_Init( const char *appname )
Alexandre Julliard8c08ceb2002-05-23 19:35:18 +0000336{
Alexandre Julliard81bdcf12002-09-13 17:47:44 +0000337 OBJECT_ATTRIBUTES attr;
338 UNICODE_STRING nameW;
339 HKEY hkey, config_key;
Alexandre Julliard8c08ceb2002-05-23 19:35:18 +0000340 BOOL got_win_ver = FALSE, got_dos_ver = FALSE;
Alexandre Julliard81bdcf12002-09-13 17:47:44 +0000341 static const WCHAR configW[] = {'M','a','c','h','i','n','e','\\',
342 'S','o','f','t','w','a','r','e','\\',
343 'W','i','n','e','\\',
344 'W','i','n','e','\\',
345 'C','o','n','f','i','g',0};
346 static const WCHAR appdefaultsW[] = {'A','p','p','D','e','f','a','u','l','t','s','\\',0};
347 static const WCHAR versionW[] = {'\\','V','e','r','s','i','o','n',0};
Alexandre Julliard8c08ceb2002-05-23 19:35:18 +0000348
Alexandre Julliard81bdcf12002-09-13 17:47:44 +0000349 attr.Length = sizeof(attr);
350 attr.RootDirectory = 0;
351 attr.ObjectName = &nameW;
352 attr.Attributes = 0;
353 attr.SecurityDescriptor = NULL;
354 attr.SecurityQualityOfService = NULL;
355 RtlInitUnicodeString( &nameW, configW );
356
357 if (NtOpenKey( &config_key, KEY_ALL_ACCESS, &attr )) return;
358 attr.RootDirectory = config_key;
359
360 /* open AppDefaults\\appname\\Version key */
Alexandre Julliarda0585842003-04-20 02:46:44 +0000361 if (appname && *appname)
Alexandre Julliard8c08ceb2002-05-23 19:35:18 +0000362 {
Alexandre Julliarda0585842003-04-20 02:46:44 +0000363 const char *p;
364 DWORD len;
365 WCHAR appversion[MAX_PATH+20];
366
367 if ((p = strrchr( appname, '/' ))) appname = p + 1;
368 if ((p = strrchr( appname, '\\' ))) appname = p + 1;
369
370 strcpyW( appversion, appdefaultsW );
371 len = strlenW(appversion);
372 RtlMultiByteToUnicodeN( appversion + len, sizeof(appversion) - len*sizeof(WCHAR),
373 &len, appname, strlen(appname)+1 );
374 strcatW( appversion, versionW );
375 TRACE( "getting version from %s\n", debugstr_w(appversion) );
376 RtlInitUnicodeString( &nameW, appversion );
377
378 if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
379 {
380 VERSION_ParseVersion( hkey, &got_win_ver, &got_dos_ver );
381 NtClose( hkey );
382 }
383 if (got_win_ver && got_dos_ver) goto done;
Alexandre Julliard8c08ceb2002-05-23 19:35:18 +0000384 }
385
Alexandre Julliarda0585842003-04-20 02:46:44 +0000386 TRACE( "getting default version\n" );
Alexandre Julliard81bdcf12002-09-13 17:47:44 +0000387 RtlInitUnicodeString( &nameW, versionW + 1 );
388 if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
Alexandre Julliard8c08ceb2002-05-23 19:35:18 +0000389 {
Alexandre Julliard81bdcf12002-09-13 17:47:44 +0000390 VERSION_ParseVersion( hkey, &got_win_ver, &got_dos_ver );
391 NtClose( hkey );
Alexandre Julliard8c08ceb2002-05-23 19:35:18 +0000392 }
Alexandre Julliard81bdcf12002-09-13 17:47:44 +0000393
394 done:
395 NtClose( config_key );
Alexandre Julliard8c08ceb2002-05-23 19:35:18 +0000396}
397
398
Andreas Mohrcd3278b1999-06-12 14:46:54 +0000399/**********************************************************************
Juergen Schmieda72a3981999-10-31 21:38:31 +0000400 * VERSION_GetSystemDLLVersion
Andreas Mohrcd3278b1999-06-12 14:46:54 +0000401 *
Andreas Mohrcb454382000-11-27 01:39:05 +0000402 * This function tries to figure out if a given (native) dll comes from
Vincent Béron9a624912002-05-31 23:06:46 +0000403 * win95/98 or winnt. Since all values in the OptionalHeader are not a
Juergen Schmieda72a3981999-10-31 21:38:31 +0000404 * usable hint, we test if a dll imports the ntdll.
Andreas Mohrcb454382000-11-27 01:39:05 +0000405 * This is at least working for all system dlls like comctl32, comdlg32 and
Juergen Schmieda72a3981999-10-31 21:38:31 +0000406 * shell32.
407 * If you have a better idea to figure this out...
408 */
Alexandre Julliard081ee942000-08-07 04:12:41 +0000409static DWORD VERSION_GetSystemDLLVersion( HMODULE hmod )
Juergen Schmieda72a3981999-10-31 21:38:31 +0000410{
Alexandre Julliarda5dea212002-08-09 19:57:38 +0000411 DWORD size;
412 IMAGE_IMPORT_DESCRIPTOR *pe_imp;
413
414 if ((pe_imp = RtlImageDirectoryEntryToData( hmod, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
Alexandre Julliard081ee942000-08-07 04:12:41 +0000415 {
Alexandre Julliard081ee942000-08-07 04:12:41 +0000416 for ( ; pe_imp->Name; pe_imp++)
417 {
418 char * name = (char *)hmod + (unsigned int)pe_imp->Name;
Juergen Schmieda72a3981999-10-31 21:38:31 +0000419 TRACE("%s\n", name);
Vincent Béron9a624912002-05-31 23:06:46 +0000420
Alexandre Julliard081ee942000-08-07 04:12:41 +0000421 if (!strncasecmp(name, "ntdll", 5))
Juergen Schmieda72a3981999-10-31 21:38:31 +0000422 {
Alexandre Julliarda5dea212002-08-09 19:57:38 +0000423 switch(RtlImageNtHeader(hmod)->OptionalHeader.MajorOperatingSystemVersion) {
Andreas Mohre6b031b2002-05-25 21:06:37 +0000424 case 3:
425 MESSAGE("WARNING: very old native DLL (NT 3.x) used, might cause instability.\n");
426 return NT351;
427 case 4: return NT40;
428 case 5: return NT2K;
429 case 6: return WINXP;
430 default:
431 FIXME("Unknown DLL OS version, please report !!\n");
432 return WINXP;
433 }
Juergen Schmieda72a3981999-10-31 21:38:31 +0000434 }
Alexandre Julliard081ee942000-08-07 04:12:41 +0000435 }
436 }
437 return WIN95;
Juergen Schmieda72a3981999-10-31 21:38:31 +0000438}
439/**********************************************************************
440 * VERSION_GetLinkedDllVersion
441 *
442 * Some version data (not reliable!):
443 * linker/OS/image/subsys
444 *
445 * x.xx/1.00/0.00/3.10 Win32s (any version ?)
446 * 2.39/1.00/0.00/3.10 Win32s freecell.exe (any version)
Vincent Béron9a624912002-05-31 23:06:46 +0000447 * 2.50/1.00/4.00/4.00 Win32s 1.30 winhlp32.exe
448 * 2.60/3.51/3.51/3.51 NT351SP5 system dlls
Juergen Schmieda72a3981999-10-31 21:38:31 +0000449 * 2.60/3.51/3.51/4.00 NT351SP5 comctl32 dll
450 * 2.xx/1.00/0.00/4.00 Win95 system files
451 * x.xx/4.00/0.00/4.00 Win95 most applications
452 * 3.10/4.00/0.00/4.00 Win98 notepad
Andreas Mohre6b031b2002-05-25 21:06:37 +0000453 * x.xx/5.00/5.00/4.00 Win98 system dlls (e.g. comctl32.dll)
Juergen Schmieda72a3981999-10-31 21:38:31 +0000454 * x.xx/4.00/4.00/4.00 NT 4 most apps
455 * 5.12/5.00/5.00/4.00 NT4+IE5 comctl32.dll
456 * 5.12/5.00/5.00/4.00 Win98 calc
457 * x.xx/5.00/5.00/4.00 win95/win98/NT4 IE5 files
Andreas Mohrcd3278b1999-06-12 14:46:54 +0000458 */
Patrik Stridvall57bf4502002-08-26 21:53:24 +0000459static DWORD VERSION_GetLinkedDllVersion(void)
Andreas Mohrcd3278b1999-06-12 14:46:54 +0000460{
Juergen Schmieda72a3981999-10-31 21:38:31 +0000461 DWORD WinVersion = NB_WINDOWS_VERSIONS;
462 PIMAGE_OPTIONAL_HEADER ophd;
Alexandre Julliarda5dea212002-08-09 19:57:38 +0000463 IMAGE_NT_HEADERS *nt;
Eric Pouech051f8712003-03-21 00:34:36 +0000464 ULONG count, required;
465 SYSTEM_MODULE_INFORMATION* smi;
Andreas Mohrcd3278b1999-06-12 14:46:54 +0000466
Juergen Schmieda72a3981999-10-31 21:38:31 +0000467 /* First check the native dlls provided. These have to be
468 from one windows version */
Eric Pouech051f8712003-03-21 00:34:36 +0000469 smi = (SYSTEM_MODULE_INFORMATION*)&count;
470 LdrQueryProcessModuleInformation(smi, sizeof(count), &required);
471 smi = RtlAllocateHeap(ntdll_get_process_heap(), 0, required);
472 if (smi)
473 {
474 if (LdrQueryProcessModuleInformation(smi, required, NULL) == STATUS_SUCCESS)
475 {
Alexandre Julliard915a4ba2003-03-30 03:08:13 +0000476 int i, k;
Eric Pouech051f8712003-03-21 00:34:36 +0000477 for (k = 0; k < smi->ModulesCount; k++)
478 {
479 nt = RtlImageNtHeader(smi->Modules[k].ImageBaseAddress);
480 ophd = &nt->OptionalHeader;
Alexandre Julliard915a4ba2003-03-30 03:08:13 +0000481
Eric Pouech051f8712003-03-21 00:34:36 +0000482 TRACE("%s: %02x.%02x/%02x.%02x/%02x.%02x/%02x.%02x\n",
483 &smi->Modules[k].Name[smi->Modules[k].NameOffset],
484 ophd->MajorLinkerVersion, ophd->MinorLinkerVersion,
485 ophd->MajorOperatingSystemVersion, ophd->MinorOperatingSystemVersion,
486 ophd->MajorImageVersion, ophd->MinorImageVersion,
487 ophd->MajorSubsystemVersion, ophd->MinorSubsystemVersion);
Andreas Mohrcd3278b1999-06-12 14:46:54 +0000488
Alexandre Julliard915a4ba2003-03-30 03:08:13 +0000489 /* test if it is an external (native) dll */
490 if (smi->Modules[k].Flags & LDR_WINE_INTERNAL) continue;
491
Eric Pouech051f8712003-03-21 00:34:36 +0000492 for (i = 0; special_dlls[i]; i++)
493 {
494 /* test if it is a special dll */
495 if (!strcasecmp(&smi->Modules[k].Name[smi->Modules[k].NameOffset], special_dlls[i]))
496 {
497 DWORD DllVersion = VERSION_GetSystemDLLVersion(smi->Modules[k].ImageBaseAddress);
498 if (WinVersion == NB_WINDOWS_VERSIONS)
499 WinVersion = DllVersion;
500 else
501 {
502 if (WinVersion != DllVersion) {
503 ERR("You mixed system DLLs from different windows versions! Expect a crash! (%s: expected version '%s', but is '%s')\n",
504 &smi->Modules[k].Name[smi->Modules[k].NameOffset],
505 VersionData[WinVersion].getVersionEx.szCSDVersion,
506 VersionData[DllVersion].getVersionEx.szCSDVersion);
507 return WIN20; /* this may let the exe exiting */
508 }
509 }
510 break;
511 }
512 }
513 }
514 }
515 RtlFreeHeap(ntdll_get_process_heap(), 0, smi);
516 }
Vincent Béron9a624912002-05-31 23:06:46 +0000517
Juergen Schmieda72a3981999-10-31 21:38:31 +0000518 if(WinVersion != NB_WINDOWS_VERSIONS) return WinVersion;
Vincent Béron9a624912002-05-31 23:06:46 +0000519
Juergen Schmieda72a3981999-10-31 21:38:31 +0000520 /* we are using no external system dlls, look at the exe */
Alexandre Julliarda5dea212002-08-09 19:57:38 +0000521 nt = RtlImageNtHeader(GetModuleHandleA(NULL));
522 ophd = &nt->OptionalHeader;
Vincent Béron9a624912002-05-31 23:06:46 +0000523
Alexandre Julliardbecb9a32000-12-11 03:48:15 +0000524 TRACE("%02x.%02x/%02x.%02x/%02x.%02x/%02x.%02x\n",
Juergen Schmieda72a3981999-10-31 21:38:31 +0000525 ophd->MajorLinkerVersion, ophd->MinorLinkerVersion,
526 ophd->MajorOperatingSystemVersion, ophd->MinorOperatingSystemVersion,
527 ophd->MajorImageVersion, ophd->MinorImageVersion,
528 ophd->MajorSubsystemVersion, ophd->MinorSubsystemVersion);
529
530 /* special nt 3.51 */
531 if (3 == ophd->MajorOperatingSystemVersion && 51 == ophd->MinorOperatingSystemVersion)
532 {
533 return NT351;
Andreas Mohrcd3278b1999-06-12 14:46:54 +0000534 }
535
Andreas Mohrcb454382000-11-27 01:39:05 +0000536 /* the MajorSubsystemVersion is the only usable sign */
Juergen Schmieda72a3981999-10-31 21:38:31 +0000537 if (ophd->MajorSubsystemVersion < 4)
538 {
Vincent Béron9a624912002-05-31 23:06:46 +0000539 if ( ophd->MajorOperatingSystemVersion == 1
Juergen Schmieda72a3981999-10-31 21:38:31 +0000540 && ophd->MinorOperatingSystemVersion == 0)
541 {
542 return WIN31; /* win32s */
543 }
Vincent Béron9a624912002-05-31 23:06:46 +0000544
Juergen Schmieda72a3981999-10-31 21:38:31 +0000545 if (ophd->Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)
546 return NT351; /* FIXME: NT 3.1, not tested */
547 else
548 return WIN95;
Vincent Béron9a624912002-05-31 23:06:46 +0000549 }
Andreas Mohrcd3278b1999-06-12 14:46:54 +0000550
Juergen Schmieda72a3981999-10-31 21:38:31 +0000551 return WIN95;
552}
Andreas Mohrcd3278b1999-06-12 14:46:54 +0000553
Alexandre Julliard638f1691999-01-17 16:32:32 +0000554/**********************************************************************
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000555 * VERSION_GetVersion
Andreas Mohrc264f2e1999-04-25 10:54:16 +0000556 *
Andreas Mohr8670b6f1999-10-13 12:19:51 +0000557 * WARNING !!!
558 * Don't call this function too early during the Wine init,
559 * as pdb->exe_modref (required by VERSION_GetImageVersion()) might still
560 * be NULL in such cases, which causes the winver to ALWAYS be detected
561 * as WIN31.
562 * And as we cache the winver once it has been determined, this is bad.
563 * This can happen much easier than you might think, as this function
564 * is called by EVERY GetVersion*() API !
565 *
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000566 */
Alexandre Julliardd586dc92000-08-14 14:35:01 +0000567static WINDOWS_VERSION VERSION_GetVersion(void)
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000568{
Andreas Mohrb7afbd42001-10-01 20:52:37 +0000569 static WORD winver = 0xffff;
Alexandre Julliard46733de2000-08-09 22:31:24 +0000570
Alexandre Julliarda0585842003-04-20 02:46:44 +0000571 if (versionForced) return forcedWinVersion; /* user has overridden any sensible checks */
572
Andreas Mohrb7afbd42001-10-01 20:52:37 +0000573 if (winver == 0xffff) /* to be determined */
574 {
Alexandre Julliarda0585842003-04-20 02:46:44 +0000575 WINDOWS_VERSION retver = VERSION_GetLinkedDllVersion();
Alexandre Julliard8c08ceb2002-05-23 19:35:18 +0000576
Alexandre Julliarda0585842003-04-20 02:46:44 +0000577 /* cache determined value, but do not store in case of WIN31 */
578 if (retver != WIN31) winver = retver;
579 return retver;
Andreas Mohrb7afbd42001-10-01 20:52:37 +0000580 }
Andreas Mohrb7afbd42001-10-01 20:52:37 +0000581 return winver;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000582}
583
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000584
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000585/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +0000586 * GetVersion (KERNEL.3)
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000587 */
588LONG WINAPI GetVersion16(void)
589{
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000590 WINDOWS_VERSION ver = VERSION_GetVersion();
Andreas Mohr5f66b042003-04-16 23:08:33 +0000591 TRACE("<-- %s (%s)\n", VersionData[ver].human_readable, VersionData[ver].getVersionEx.szCSDVersion);
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000592 return VersionData[ver].getVersion16;
593}
594
595
596/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +0000597 * GetVersion (KERNEL32.@)
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000598 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000599LONG WINAPI GetVersion(void)
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000600{
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000601 WINDOWS_VERSION ver = VERSION_GetVersion();
Andreas Mohr5f66b042003-04-16 23:08:33 +0000602 TRACE("<-- %s (%s)\n", VersionData[ver].human_readable, VersionData[ver].getVersionEx.szCSDVersion);
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000603 return VersionData[ver].getVersion32;
604}
605
606
607/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +0000608 * GetVersionEx (KERNEL.149)
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000609 */
610BOOL16 WINAPI GetVersionEx16(OSVERSIONINFO16 *v)
611{
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000612 WINDOWS_VERSION ver = VERSION_GetVersion();
James Juran94cd0602001-05-24 18:38:49 +0000613 if (v->dwOSVersionInfoSize < sizeof(OSVERSIONINFO16))
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000614 {
James Juranb7c2f2f2001-05-09 17:09:04 +0000615 WARN("wrong OSVERSIONINFO size from app\n");
Morten Eriksen594af0d1999-08-14 15:53:07 +0000616 SetLastError(ERROR_INSUFFICIENT_BUFFER);
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000617 return FALSE;
618 }
619 v->dwMajorVersion = VersionData[ver].getVersionEx.dwMajorVersion;
620 v->dwMinorVersion = VersionData[ver].getVersionEx.dwMinorVersion;
621 v->dwBuildNumber = VersionData[ver].getVersionEx.dwBuildNumber;
622 v->dwPlatformId = VersionData[ver].getVersionEx.dwPlatformId;
623 strcpy( v->szCSDVersion, VersionData[ver].getVersionEx.szCSDVersion );
Andreas Mohr5f66b042003-04-16 23:08:33 +0000624 TRACE("<-- %s (%s)\n", VersionData[ver].human_readable, VersionData[ver].getVersionEx.szCSDVersion);
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000625 return TRUE;
626}
627
628
629/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +0000630 * GetVersionExA (KERNEL32.@)
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000631 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000632BOOL WINAPI GetVersionExA(OSVERSIONINFOA *v)
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000633{
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000634 WINDOWS_VERSION ver = VERSION_GetVersion();
Vincent Béron9d9cf722002-05-24 21:13:45 +0000635 LPOSVERSIONINFOEXA vex;
636
637 if (v->dwOSVersionInfoSize != sizeof(OSVERSIONINFOA) &&
638 v->dwOSVersionInfoSize != sizeof(OSVERSIONINFOEXA))
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000639 {
Vincent Béron9d9cf722002-05-24 21:13:45 +0000640 WARN("wrong OSVERSIONINFO size from app (got: %ld, expected: %d or %d)\n",
641 v->dwOSVersionInfoSize, sizeof(OSVERSIONINFOA),
642 sizeof(OSVERSIONINFOEXA));
Morten Eriksen594af0d1999-08-14 15:53:07 +0000643 SetLastError(ERROR_INSUFFICIENT_BUFFER);
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000644 return FALSE;
645 }
646 v->dwMajorVersion = VersionData[ver].getVersionEx.dwMajorVersion;
647 v->dwMinorVersion = VersionData[ver].getVersionEx.dwMinorVersion;
648 v->dwBuildNumber = VersionData[ver].getVersionEx.dwBuildNumber;
649 v->dwPlatformId = VersionData[ver].getVersionEx.dwPlatformId;
650 strcpy( v->szCSDVersion, VersionData[ver].getVersionEx.szCSDVersion );
Vincent Béron9d9cf722002-05-24 21:13:45 +0000651 if(v->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXA)) {
652 vex = (LPOSVERSIONINFOEXA) v;
653 vex->wServicePackMajor = VersionData[ver].getVersionEx.wServicePackMajor;
654 vex->wServicePackMinor = VersionData[ver].getVersionEx.wServicePackMinor;
655 vex->wSuiteMask = VersionData[ver].getVersionEx.wSuiteMask;
656 vex->wProductType = VersionData[ver].getVersionEx.wProductType;
657 }
Andreas Mohr5f66b042003-04-16 23:08:33 +0000658 TRACE("<-- %s (%s)\n", VersionData[ver].human_readable, VersionData[ver].getVersionEx.szCSDVersion);
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000659 return TRUE;
660}
661
662
663/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +0000664 * GetVersionExW (KERNEL32.@)
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000665 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000666BOOL WINAPI GetVersionExW(OSVERSIONINFOW *v)
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000667{
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000668 WINDOWS_VERSION ver = VERSION_GetVersion();
Vincent Béron9d9cf722002-05-24 21:13:45 +0000669 LPOSVERSIONINFOEXW vex;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000670
Vincent Béron9d9cf722002-05-24 21:13:45 +0000671 if (v->dwOSVersionInfoSize != sizeof(OSVERSIONINFOW) &&
672 v->dwOSVersionInfoSize != sizeof(OSVERSIONINFOEXW))
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000673 {
Vincent Béron9d9cf722002-05-24 21:13:45 +0000674 WARN("wrong OSVERSIONINFO size from app (got: %ld, expected: %d or %d)\n",
675 v->dwOSVersionInfoSize, sizeof(OSVERSIONINFOW),
676 sizeof(OSVERSIONINFOEXW));
Morten Eriksen594af0d1999-08-14 15:53:07 +0000677 SetLastError(ERROR_INSUFFICIENT_BUFFER);
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000678 return FALSE;
679 }
680 v->dwMajorVersion = VersionData[ver].getVersionEx.dwMajorVersion;
681 v->dwMinorVersion = VersionData[ver].getVersionEx.dwMinorVersion;
682 v->dwBuildNumber = VersionData[ver].getVersionEx.dwBuildNumber;
683 v->dwPlatformId = VersionData[ver].getVersionEx.dwPlatformId;
Alexandre Julliard24a62ab2000-11-28 22:40:56 +0000684 MultiByteToWideChar( CP_ACP, 0, VersionData[ver].getVersionEx.szCSDVersion, -1,
685 v->szCSDVersion, sizeof(v->szCSDVersion)/sizeof(WCHAR) );
Vincent Béron9d9cf722002-05-24 21:13:45 +0000686 if(v->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXW)) {
687 vex = (LPOSVERSIONINFOEXW) v;
688 vex->wServicePackMajor = VersionData[ver].getVersionEx.wServicePackMajor;
689 vex->wServicePackMinor = VersionData[ver].getVersionEx.wServicePackMinor;
690 vex->wSuiteMask = VersionData[ver].getVersionEx.wSuiteMask;
691 vex->wProductType = VersionData[ver].getVersionEx.wProductType;
692 }
Andreas Mohr5f66b042003-04-16 23:08:33 +0000693 TRACE("<-- %s (%s)\n", VersionData[ver].human_readable, VersionData[ver].getVersionEx.szCSDVersion);
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000694 return TRUE;
695}
696
697
Vincent Béron9d9cf722002-05-24 21:13:45 +0000698/******************************************************************************
699 * VerifyVersionInfoA (KERNEL32.@)
700 */
701BOOL WINAPI VerifyVersionInfoA( LPOSVERSIONINFOEXA lpVersionInfo, DWORD dwTypeMask,
702 DWORDLONG dwlConditionMask)
703{
704 OSVERSIONINFOEXW verW;
705
706 verW.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
707 verW.dwMajorVersion = lpVersionInfo->dwMajorVersion;
708 verW.dwMinorVersion = lpVersionInfo->dwMinorVersion;
709 verW.dwBuildNumber = lpVersionInfo->dwBuildNumber;
710 verW.dwPlatformId = lpVersionInfo->dwPlatformId;
711 verW.wServicePackMajor = lpVersionInfo->wServicePackMajor;
712 verW.wServicePackMinor = lpVersionInfo->wServicePackMinor;
713 verW.wSuiteMask = lpVersionInfo->wSuiteMask;
714 verW.wProductType = lpVersionInfo->wProductType;
715 verW.wReserved = lpVersionInfo->wReserved;
716
717 return VerifyVersionInfoW(&verW, dwTypeMask, dwlConditionMask);
718}
719
Juergen Schmiedc5d30532002-05-09 19:36:28 +0000720
721/******************************************************************************
722 * VerifyVersionInfoW (KERNEL32.@)
723 */
Vincent Béron9d9cf722002-05-24 21:13:45 +0000724BOOL WINAPI VerifyVersionInfoW( LPOSVERSIONINFOEXW lpVersionInfo, DWORD dwTypeMask,
Juergen Schmiedc5d30532002-05-09 19:36:28 +0000725 DWORDLONG dwlConditionMask)
726{
Vincent Béron9d9cf722002-05-24 21:13:45 +0000727 OSVERSIONINFOEXW ver;
728 BOOL res, error_set;
729
730 FIXME("(%p,%lu,%llx): Not all cases correctly implemented yet\n", lpVersionInfo, dwTypeMask, dwlConditionMask);
731 /* FIXME:
732 - Check the following special case on Windows (various versions):
733 o lp->wSuiteMask == 0 and ver.wSuiteMask != 0 and VER_AND/VER_OR
734 o lp->dwOSVersionInfoSize != sizeof(OSVERSIONINFOEXW)
735 - MSDN talks about some tests being impossible. Check what really happens.
736 */
737
738 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
739 if(!GetVersionExW((LPOSVERSIONINFOW) &ver))
740 return FALSE;
741
742 res = TRUE;
743 error_set = FALSE;
744 if(!(dwTypeMask && dwlConditionMask)) {
745 res = FALSE;
746 SetLastError(ERROR_BAD_ARGUMENTS);
747 error_set = TRUE;
748 }
749 if(dwTypeMask & VER_PRODUCT_TYPE)
750 switch(dwlConditionMask >> 7*3 & 0x07) {
751 case VER_EQUAL:
752 if(ver.wProductType != lpVersionInfo->wProductType)
753 res = FALSE;
754 break;
755 case VER_GREATER:
756 if(ver.wProductType <= lpVersionInfo->wProductType)
757 res = FALSE;
758 break;
759 case VER_GREATER_EQUAL:
760 if(ver.wProductType < lpVersionInfo->wProductType)
761 res = FALSE;
762 break;
763 case VER_LESS:
764 if(ver.wProductType >= lpVersionInfo->wProductType)
765 res = FALSE;
766 break;
767 case VER_LESS_EQUAL:
768 if(ver.wProductType > lpVersionInfo->wProductType)
769 res = FALSE;
770 break;
771 default:
772 res = FALSE;
773 SetLastError(ERROR_BAD_ARGUMENTS);
774 error_set = TRUE;
775 }
776 if(dwTypeMask & VER_SUITENAME && res)
777 switch(dwlConditionMask >> 6*3 & 0x07) {
778 case VER_AND:
779 if((lpVersionInfo->wSuiteMask & ver.wSuiteMask) != lpVersionInfo->wSuiteMask)
780 res = FALSE;
781 break;
782 case VER_OR:
783 if(!(lpVersionInfo->wSuiteMask & ver.wSuiteMask) && lpVersionInfo->wSuiteMask)
784 res = FALSE;
785 break;
786 default:
787 res = FALSE;
788 SetLastError(ERROR_BAD_ARGUMENTS);
789 error_set = TRUE;
790 }
791 if(dwTypeMask & VER_PLATFORMID && res)
792 switch(dwlConditionMask >> 3*3 & 0x07) {
793 case VER_EQUAL:
794 if(ver.dwPlatformId != lpVersionInfo->dwPlatformId)
795 res = FALSE;
796 break;
797 case VER_GREATER:
798 if(ver.dwPlatformId <= lpVersionInfo->dwPlatformId)
799 res = FALSE;
800 break;
801 case VER_GREATER_EQUAL:
802 if(ver.dwPlatformId < lpVersionInfo->dwPlatformId)
803 res = FALSE;
804 break;
805 case VER_LESS:
806 if(ver.dwPlatformId >= lpVersionInfo->dwPlatformId)
807 res = FALSE;
808 break;
809 case VER_LESS_EQUAL:
810 if(ver.dwPlatformId > lpVersionInfo->dwPlatformId)
811 res = FALSE;
812 break;
813 default:
814 res = FALSE;
815 SetLastError(ERROR_BAD_ARGUMENTS);
816 error_set = TRUE;
817 }
818 if(dwTypeMask & VER_BUILDNUMBER && res)
819 switch(dwlConditionMask >> 2*3 & 0x07) {
820 case VER_EQUAL:
821 if(ver.dwBuildNumber != lpVersionInfo->dwBuildNumber)
822 res = FALSE;
823 break;
824 case VER_GREATER:
825 if(ver.dwBuildNumber <= lpVersionInfo->dwBuildNumber)
826 res = FALSE;
827 break;
828 case VER_GREATER_EQUAL:
829 if(ver.dwBuildNumber < lpVersionInfo->dwBuildNumber)
830 res = FALSE;
831 break;
832 case VER_LESS:
833 if(ver.dwBuildNumber >= lpVersionInfo->dwBuildNumber)
834 res = FALSE;
835 break;
836 case VER_LESS_EQUAL:
837 if(ver.dwBuildNumber > lpVersionInfo->dwBuildNumber)
838 res = FALSE;
839 break;
840 default:
841 res = FALSE;
842 SetLastError(ERROR_BAD_ARGUMENTS);
843 error_set = TRUE;
844 }
845 if(dwTypeMask & VER_MAJORVERSION && res)
846 switch(dwlConditionMask >> 1*3 & 0x07) {
847 case VER_EQUAL:
848 if(ver.dwMajorVersion != lpVersionInfo->dwMajorVersion)
849 res = FALSE;
850 break;
851 case VER_GREATER:
852 if(ver.dwMajorVersion <= lpVersionInfo->dwMajorVersion)
853 res = FALSE;
854 break;
855 case VER_GREATER_EQUAL:
856 if(ver.dwMajorVersion < lpVersionInfo->dwMajorVersion)
857 res = FALSE;
858 break;
859 case VER_LESS:
860 if(ver.dwMajorVersion >= lpVersionInfo->dwMajorVersion)
861 res = FALSE;
862 break;
863 case VER_LESS_EQUAL:
864 if(ver.dwMajorVersion > lpVersionInfo->dwMajorVersion)
865 res = FALSE;
866 break;
867 default:
868 res = FALSE;
869 SetLastError(ERROR_BAD_ARGUMENTS);
870 error_set = TRUE;
871 }
872 if(dwTypeMask & VER_MINORVERSION && res)
873 switch(dwlConditionMask >> 0*3 & 0x07) {
874 case VER_EQUAL:
875 if(ver.dwMinorVersion != lpVersionInfo->dwMinorVersion)
876 res = FALSE;
877 break;
878 case VER_GREATER:
879 if(ver.dwMinorVersion <= lpVersionInfo->dwMinorVersion)
880 res = FALSE;
881 break;
882 case VER_GREATER_EQUAL:
883 if(ver.dwMinorVersion < lpVersionInfo->dwMinorVersion)
884 res = FALSE;
885 break;
886 case VER_LESS:
887 if(ver.dwMinorVersion >= lpVersionInfo->dwMinorVersion)
888 res = FALSE;
889 break;
890 case VER_LESS_EQUAL:
891 if(ver.dwMinorVersion > lpVersionInfo->dwMinorVersion)
892 res = FALSE;
893 break;
894 default:
895 res = FALSE;
896 SetLastError(ERROR_BAD_ARGUMENTS);
897 error_set = TRUE;
898 }
899 if(dwTypeMask & VER_SERVICEPACKMAJOR && res)
900 switch(dwlConditionMask >> 5*3 & 0x07) {
901 case VER_EQUAL:
902 if(ver.wServicePackMajor != lpVersionInfo->wServicePackMajor)
903 res = FALSE;
904 break;
905 case VER_GREATER:
906 if(ver.wServicePackMajor <= lpVersionInfo->wServicePackMajor)
907 res = FALSE;
908 break;
909 case VER_GREATER_EQUAL:
910 if(ver.wServicePackMajor < lpVersionInfo->wServicePackMajor)
911 res = FALSE;
912 break;
913 case VER_LESS:
914 if(ver.wServicePackMajor >= lpVersionInfo->wServicePackMajor)
915 res = FALSE;
916 break;
917 case VER_LESS_EQUAL:
918 if(ver.wServicePackMajor > lpVersionInfo->wServicePackMajor)
919 res = FALSE;
920 break;
921 default:
922 res = FALSE;
923 SetLastError(ERROR_BAD_ARGUMENTS);
924 error_set = TRUE;
925 }
926 if(dwTypeMask & VER_SERVICEPACKMINOR && res)
927 switch(dwlConditionMask >> 4*3 & 0x07) {
928 case VER_EQUAL:
929 if(ver.wServicePackMinor != lpVersionInfo->wServicePackMinor)
930 res = FALSE;
931 break;
932 case VER_GREATER:
933 if(ver.wServicePackMinor <= lpVersionInfo->wServicePackMinor)
934 res = FALSE;
935 break;
936 case VER_GREATER_EQUAL:
937 if(ver.wServicePackMinor < lpVersionInfo->wServicePackMinor)
938 res = FALSE;
939 break;
940 case VER_LESS:
941 if(ver.wServicePackMinor >= lpVersionInfo->wServicePackMinor)
942 res = FALSE;
943 break;
944 case VER_LESS_EQUAL:
945 if(ver.wServicePackMinor > lpVersionInfo->wServicePackMinor)
946 res = FALSE;
947 break;
948 default:
949 res = FALSE;
950 SetLastError(ERROR_BAD_ARGUMENTS);
951 error_set = TRUE;
952 }
953
954 if(!(res || error_set))
955 SetLastError(ERROR_OLD_WIN_VERSION);
956 return res;
Juergen Schmiedc5d30532002-05-09 19:36:28 +0000957}
958
959
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000960/***********************************************************************
961 * GetWinFlags (KERNEL.132)
962 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000963DWORD WINAPI GetWinFlags16(void)
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000964{
965 static const long cpuflags[5] =
966 { WF_CPU086, WF_CPU186, WF_CPU286, WF_CPU386, WF_CPU486 };
967 SYSTEM_INFO si;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000968 OSVERSIONINFOA ovi;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000969 DWORD result;
970
971 GetSystemInfo(&si);
972
973 /* There doesn't seem to be any Pentium flag. */
Francois Gouget6d77d3a2000-03-25 21:44:35 +0000974 result = cpuflags[min(si.wProcessorLevel, 4)] | WF_ENHANCED | WF_PMODE | WF_80x87 | WF_PAGING;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000975 if (si.wProcessorLevel >= 4) result |= WF_HASCPUID;
976 ovi.dwOSVersionInfoSize = sizeof(ovi);
Alexandre Julliarda3960291999-02-26 11:11:13 +0000977 GetVersionExA(&ovi);
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000978 if (ovi.dwPlatformId == VER_PLATFORM_WIN32_NT)
979 result |= WF_WIN32WOW; /* undocumented WF_WINNT */
980 return result;
981}
982
983
Francois Gouget5686dc02001-10-08 22:30:34 +0000984#if 0
985/* Not used at this time. This is here for documentation only */
986
987/* WINDEBUGINFO flags values */
988#define WDI_OPTIONS 0x0001
989#define WDI_FILTER 0x0002
990#define WDI_ALLOCBREAK 0x0004
991
992/* dwOptions values */
993#define DBO_CHECKHEAP 0x0001
994#define DBO_BUFFERFILL 0x0004
995#define DBO_DISABLEGPTRAPPING 0x0010
996#define DBO_CHECKFREE 0x0020
997
998#define DBO_SILENT 0x8000
999
1000#define DBO_TRACEBREAK 0x2000
1001#define DBO_WARNINGBREAK 0x1000
1002#define DBO_NOERRORBREAK 0x0800
1003#define DBO_NOFATALBREAK 0x0400
1004#define DBO_INT3BREAK 0x0100
1005
1006/* DebugOutput flags values */
1007#define DBF_TRACE 0x0000
1008#define DBF_WARNING 0x4000
1009#define DBF_ERROR 0x8000
1010#define DBF_FATAL 0xc000
1011
1012/* dwFilter values */
1013#define DBF_KERNEL 0x1000
1014#define DBF_KRN_MEMMAN 0x0001
1015#define DBF_KRN_LOADMODULE 0x0002
1016#define DBF_KRN_SEGMENTLOAD 0x0004
1017#define DBF_USER 0x0800
1018#define DBF_GDI 0x0400
1019#define DBF_MMSYSTEM 0x0040
1020#define DBF_PENWIN 0x0020
1021#define DBF_APPLICATION 0x0008
1022#define DBF_DRIVER 0x0010
1023
1024#endif /* NOLOGERROR */
1025
1026
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00001027/***********************************************************************
1028 * GetWinDebugInfo (KERNEL.355)
1029 */
Francois Gouget5686dc02001-10-08 22:30:34 +00001030BOOL16 WINAPI GetWinDebugInfo16(WINDEBUGINFO16 *lpwdi, UINT16 flags)
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00001031{
Alexandre Julliard61fece01999-06-26 19:09:08 +00001032 FIXME("(%8lx,%d): stub returning 0\n",
Alexandre Julliard54c27111998-03-29 19:44:57 +00001033 (unsigned long)lpwdi, flags);
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00001034 /* 0 means not in debugging mode/version */
1035 /* Can this type of debugging be used in wine ? */
1036 /* Constants: WDI_OPTIONS WDI_FILTER WDI_ALLOCBREAK */
1037 return 0;
1038}
1039
1040
1041/***********************************************************************
1042 * SetWinDebugInfo (KERNEL.356)
1043 */
Francois Gouget5686dc02001-10-08 22:30:34 +00001044BOOL16 WINAPI SetWinDebugInfo16(WINDEBUGINFO16 *lpwdi)
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00001045{
Alexandre Julliard61fece01999-06-26 19:09:08 +00001046 FIXME("(%8lx): stub returning 0\n", (unsigned long)lpwdi);
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00001047 /* 0 means not in debugging mode/version */
1048 /* Can this type of debugging be used in wine ? */
1049 /* Constants: WDI_OPTIONS WDI_FILTER WDI_ALLOCBREAK */
1050 return 0;
1051}
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00001052
1053
1054/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001055 * K329 (KERNEL.329)
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00001056 *
1057 * TODO:
1058 * Should fill lpBuffer only if DBO_BUFFERFILL has been set by SetWinDebugInfo()
1059 */
1060void WINAPI DebugFillBuffer(LPSTR lpBuffer, WORD wBytes)
1061{
1062 memset(lpBuffer, DBGFILL_BUFFER, wBytes);
1063}
1064
1065/***********************************************************************
1066 * DiagQuery (KERNEL.339)
1067 *
1068 * returns TRUE if Win called with "/b" (bootlog.txt)
1069 */
Patrik Stridvall57bf4502002-08-26 21:53:24 +00001070BOOL16 WINAPI DiagQuery16(void)
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00001071{
1072 /* perhaps implement a Wine "/b" command line flag sometime ? */
1073 return FALSE;
1074}
1075
1076/***********************************************************************
1077 * DiagOutput (KERNEL.340)
1078 *
1079 * writes a debug string into <windir>\bootlog.txt
1080 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001081void WINAPI DiagOutput16(LPCSTR str)
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00001082{
Alexandre Julliard54c27111998-03-29 19:44:57 +00001083 /* FIXME */
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001084 DPRINTF("DIAGOUTPUT:%s\n", debugstr_a(str));
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00001085}