- Disable some 'classic' debug traces (avoid useless flood of traces
[wine.git] / misc / version.c
blobdaa428c32e59f8813ef7c8a9cd21fa503b37b64a
1 /*
2 * Windows and DOS version functions
4 * Copyright 1997 Alexandre Julliard
5 * Copyright 1997 Marcus Meissner
6 * Copyright 1998 Patrik Stridvall
7 * Copyright 1998,2003 Andreas Mohr
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <string.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wingdi.h"
33 #include "winuser.h"
34 #include "winternl.h"
35 #include "winerror.h"
36 #include "wine/winbase16.h"
37 #include "module.h"
38 #include "wine/unicode.h"
39 #include "wine/debug.h"
40 #include "ntdll_misc.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(ver);
44 typedef enum
46 WIN20, /* Windows 2.0 */
47 WIN30, /* Windows 3.0 */
48 WIN31, /* Windows 3.1 */
49 WIN95, /* Windows 95 */
50 WIN98, /* Windows 98 */
51 WINME, /* Windows Me */
52 NT351, /* Windows NT 3.51 */
53 NT40, /* Windows NT 4.0 */
54 NT2K, /* Windows 2000 */
55 WINXP, /* Windows XP */
56 NB_WINDOWS_VERSIONS
57 } WINDOWS_VERSION;
59 typedef struct
61 char human_readable[32];
62 LONG getVersion16;
63 LONG getVersion32;
64 OSVERSIONINFOEXA getVersionEx;
65 } VERSION_DATA;
67 /* 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 */
70 static VERSION_DATA VersionData[NB_WINDOWS_VERSIONS] =
72 /* WIN20 FIXME: verify values */
74 "Windows 2.0",
75 MAKELONG( 0x0002, 0x0303 ), /* assume DOS 3.3 */
76 MAKELONG( 0x0002, 0x8000 ),
78 /* yes, sizeof(OSVERSIONINFOA) is correct here
79 * (in case of OSVERSIONINFOEXA application request,
80 * we adapt it dynamically). */
81 sizeof(OSVERSIONINFOA), 2, 0, 0,
82 VER_PLATFORM_WIN32s, "Win32s 1.3",
83 0, 0, 0, 0, 0
86 /* WIN30 FIXME: verify values */
88 "Windows 3.0",
89 MAKELONG( 0x0003, 0x0500 ), /* assume DOS 5.00 */
90 MAKELONG( 0x0003, 0x8000 ),
92 sizeof(OSVERSIONINFOA), 3, 0, 0,
93 VER_PLATFORM_WIN32s, "Win32s 1.3",
94 0, 0, 0, 0, 0
97 /* WIN31 */
99 "Windows 3.1",
100 MAKELONG( 0x0a03, 0x0616 ), /* DOS 6.22 */
101 MAKELONG( 0x0a03, 0x8000 ),
103 sizeof(OSVERSIONINFOA), 3, 10, 0,
104 VER_PLATFORM_WIN32s, "Win32s 1.3",
105 0, 0, 0, 0, 0
108 /* WIN95 */
110 "Windows 95",
111 0x07005F03,
112 0xC0000004,
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
123 sizeof(OSVERSIONINFOA), 4, 0, 0x40003B6,
124 VER_PLATFORM_WIN32_WINDOWS, "",
125 0, 0, 0, 0, 0
128 /* WIN98 (second edition) */
130 "Windows 98 SE",
131 0x070A5F03,
132 0xC0000A04,
134 /* Win98: 4, 10, 0x40A07CE, " " 4.10.1998
135 * Win98SE: 4, 10, 0x40A08AE, " A " 4.10.2222
137 sizeof(OSVERSIONINFOA), 4, 10, 0x40A08AE,
138 VER_PLATFORM_WIN32_WINDOWS, " A ",
139 0, 0, 0, 0, 0
142 /* WINME */
144 "Windows ME",
145 0x08005F03,
146 0xC0005A04,
148 sizeof(OSVERSIONINFOA), 4, 90, 0x45A0BB8,
149 VER_PLATFORM_WIN32_WINDOWS, " ",
150 0, 0, 0, 0, 0
153 /* NT351 */
155 "Windows NT 3.51",
156 0x05000A03,
157 0x04213303,
159 sizeof(OSVERSIONINFOA), 3, 51, 0x421,
160 VER_PLATFORM_WIN32_NT, "Service Pack 2",
161 0, 0, 0, 0, 0
164 /* NT40 */
166 "Windows NT 4.0",
167 0x05000A03,
168 0x05650004,
170 sizeof(OSVERSIONINFOA), 4, 0, 0x565,
171 VER_PLATFORM_WIN32_NT, "Service Pack 6",
172 6, 0, 0, VER_NT_WORKSTATION, 0
175 /* NT2K */
177 "Windows 2000",
178 0x05005F03,
179 0x08930005,
181 sizeof(OSVERSIONINFOA), 5, 0, 0x893,
182 VER_PLATFORM_WIN32_NT, "Service Pack 3",
183 3, 0, 0, VER_NT_WORKSTATION, 30 /* FIXME: Great, a reserved field with a value! */
186 /* WINXP */
188 "Windows XP",
189 0x05005F03, /* Assuming DOS 5 like the other NT */
190 0x0A280105,
192 sizeof(OSVERSIONINFOA), 5, 1, 0xA28,
193 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! */
199 static const char *WinVersionNames[NB_WINDOWS_VERSIONS] =
200 { /* no spaces in here ! */
201 "win20",
202 "win30",
203 "win31",
204 "win95",
205 "win98",
206 "winme",
207 "nt351",
208 "nt40",
209 "win2000,win2k,nt2k,nt2000",
210 "winxp"
213 /* if one of the following dlls is importing ntdll the windows
214 version autodetection switches wine to unicode (nt 3.51 or 4.0) */
215 static char * special_dlls[] =
217 "comdlg32.dll",
218 "comctl32.dll",
219 "shell32.dll",
220 "ole32.dll",
221 "rpcrt4.dll",
222 NULL
225 /* the current version has not been autodetected but forced via cmdline */
226 static BOOL versionForced = FALSE;
227 static WINDOWS_VERSION forcedWinVersion = WIN31; /* init value irrelevant */
229 /**********************************************************************
230 * VERSION_ParseWinVersion
232 static void VERSION_ParseWinVersion( const char *arg )
234 int i, len;
235 const char *pCurr, *p;
236 for (i = 0; i < NB_WINDOWS_VERSIONS; i++)
238 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') )
245 forcedWinVersion = (WINDOWS_VERSION)i;
246 versionForced = TRUE;
247 return;
249 pCurr = p+1;
250 } while (p);
252 MESSAGE("Invalid Windows version value '%s' specified in config file.\n", arg );
253 MESSAGE("Valid versions are:" );
254 for (i = 0; i < NB_WINDOWS_VERSIONS; i++)
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);
261 MESSAGE(" '%.*s'%c", len, pCurr,
262 (i == NB_WINDOWS_VERSIONS - 1) ? '\n' : ',' );
264 ExitProcess(1);
268 /**********************************************************************
269 * VERSION_ParseDosVersion
271 static void VERSION_ParseDosVersion( const char *arg )
273 int hi, lo;
274 if (sscanf( arg, "%d.%d", &hi, &lo ) == 2)
276 VersionData[WIN31].getVersion16 =
277 MAKELONG(LOWORD(VersionData[WIN31].getVersion16),
278 (hi<<8) + lo);
280 else
282 MESSAGE("Wrong format for DOS version in config file. Use \"x.xx\"\n");
283 ExitProcess(1);
288 /**********************************************************************
289 * VERSION_ParseVersion
291 * Parse the contents of the Version key.
293 static void VERSION_ParseVersion( HKEY hkey, BOOL *got_win_ver, BOOL *got_dos_ver )
295 static const WCHAR WindowsW[] = {'W','i','n','d','o','w','s',0};
296 static const WCHAR DosW[] = {'D','O','S',0};
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;
303 if (!*got_win_ver)
305 RtlInitUnicodeString( &valueW, WindowsW );
306 if (!NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
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;
316 if (!*got_dos_ver)
318 RtlInitUnicodeString( &valueW, DosW );
319 if (!NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp), &count ))
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;
332 /**********************************************************************
333 * VERSION_Init
335 void VERSION_Init( const char *appname )
337 OBJECT_ATTRIBUTES attr;
338 UNICODE_STRING nameW;
339 HKEY hkey, config_key;
340 BOOL got_win_ver = FALSE, got_dos_ver = FALSE;
341 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};
349 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 );
357 if (NtOpenKey( &config_key, KEY_ALL_ACCESS, &attr )) return;
358 attr.RootDirectory = config_key;
360 /* open AppDefaults\\appname\\Version key */
361 if (appname && *appname)
363 const char *p;
364 DWORD len;
365 WCHAR appversion[MAX_PATH+20];
367 if ((p = strrchr( appname, '/' ))) appname = p + 1;
368 if ((p = strrchr( appname, '\\' ))) appname = p + 1;
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 );
378 if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
380 VERSION_ParseVersion( hkey, &got_win_ver, &got_dos_ver );
381 NtClose( hkey );
383 if (got_win_ver && got_dos_ver) goto done;
386 TRACE( "getting default version\n" );
387 RtlInitUnicodeString( &nameW, versionW + 1 );
388 if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
390 VERSION_ParseVersion( hkey, &got_win_ver, &got_dos_ver );
391 NtClose( hkey );
394 done:
395 NtClose( config_key );
399 /**********************************************************************
400 * VERSION_GetSystemDLLVersion
402 * This function tries to figure out if a given (native) dll comes from
403 * win95/98 or winnt. Since all values in the OptionalHeader are not a
404 * usable hint, we test if a dll imports the ntdll.
405 * This is at least working for all system dlls like comctl32, comdlg32 and
406 * shell32.
407 * If you have a better idea to figure this out...
409 static DWORD VERSION_GetSystemDLLVersion( HMODULE hmod )
411 DWORD size;
412 IMAGE_IMPORT_DESCRIPTOR *pe_imp;
414 if ((pe_imp = RtlImageDirectoryEntryToData( hmod, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
416 for ( ; pe_imp->Name; pe_imp++)
418 char * name = (char *)hmod + (unsigned int)pe_imp->Name;
419 TRACE("%s\n", name);
421 if (!strncasecmp(name, "ntdll", 5))
423 switch(RtlImageNtHeader(hmod)->OptionalHeader.MajorOperatingSystemVersion) {
424 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;
437 return WIN95;
439 /**********************************************************************
440 * VERSION_GetLinkedDllVersion
442 * Some version data (not reliable!):
443 * linker/OS/image/subsys
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)
447 * 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
449 * 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
453 * x.xx/5.00/5.00/4.00 Win98 system dlls (e.g. comctl32.dll)
454 * 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
459 static DWORD VERSION_GetLinkedDllVersion(void)
461 DWORD WinVersion = NB_WINDOWS_VERSIONS;
462 PIMAGE_OPTIONAL_HEADER ophd;
463 IMAGE_NT_HEADERS *nt;
464 ULONG count, required;
465 SYSTEM_MODULE_INFORMATION* smi;
467 /* First check the native dlls provided. These have to be
468 from one windows version */
469 smi = (SYSTEM_MODULE_INFORMATION*)&count;
470 LdrQueryProcessModuleInformation(smi, sizeof(count), &required);
471 smi = RtlAllocateHeap(ntdll_get_process_heap(), 0, required);
472 if (smi)
474 if (LdrQueryProcessModuleInformation(smi, required, NULL) == STATUS_SUCCESS)
476 int i, k;
477 for (k = 0; k < smi->ModulesCount; k++)
479 nt = RtlImageNtHeader(smi->Modules[k].ImageBaseAddress);
480 ophd = &nt->OptionalHeader;
482 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);
489 /* test if it is an external (native) dll */
490 if (smi->Modules[k].Flags & LDR_WINE_INTERNAL) continue;
492 for (i = 0; special_dlls[i]; i++)
494 /* test if it is a special dll */
495 if (!strcasecmp(&smi->Modules[k].Name[smi->Modules[k].NameOffset], special_dlls[i]))
497 DWORD DllVersion = VERSION_GetSystemDLLVersion(smi->Modules[k].ImageBaseAddress);
498 if (WinVersion == NB_WINDOWS_VERSIONS)
499 WinVersion = DllVersion;
500 else
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 */
510 break;
515 RtlFreeHeap(ntdll_get_process_heap(), 0, smi);
518 if(WinVersion != NB_WINDOWS_VERSIONS) return WinVersion;
520 /* we are using no external system dlls, look at the exe */
521 nt = RtlImageNtHeader(GetModuleHandleA(NULL));
522 ophd = &nt->OptionalHeader;
524 TRACE("%02x.%02x/%02x.%02x/%02x.%02x/%02x.%02x\n",
525 ophd->MajorLinkerVersion, ophd->MinorLinkerVersion,
526 ophd->MajorOperatingSystemVersion, ophd->MinorOperatingSystemVersion,
527 ophd->MajorImageVersion, ophd->MinorImageVersion,
528 ophd->MajorSubsystemVersion, ophd->MinorSubsystemVersion);
530 /* special nt 3.51 */
531 if (3 == ophd->MajorOperatingSystemVersion && 51 == ophd->MinorOperatingSystemVersion)
533 return NT351;
536 /* the MajorSubsystemVersion is the only usable sign */
537 if (ophd->MajorSubsystemVersion < 4)
539 if ( ophd->MajorOperatingSystemVersion == 1
540 && ophd->MinorOperatingSystemVersion == 0)
542 return WIN31; /* win32s */
545 if (ophd->Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)
546 return NT351; /* FIXME: NT 3.1, not tested */
547 else
548 return WIN95;
551 return WIN95;
554 /**********************************************************************
555 * VERSION_GetVersion
557 * 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 !
567 static WINDOWS_VERSION VERSION_GetVersion(void)
569 static WORD winver = 0xffff;
571 if (versionForced) return forcedWinVersion; /* user has overridden any sensible checks */
573 if (winver == 0xffff) /* to be determined */
575 WINDOWS_VERSION retver = VERSION_GetLinkedDllVersion();
577 /* cache determined value, but do not store in case of WIN31 */
578 if (retver != WIN31) winver = retver;
579 return retver;
581 return winver;
585 /***********************************************************************
586 * GetVersion (KERNEL.3)
588 LONG WINAPI GetVersion16(void)
590 WINDOWS_VERSION ver = VERSION_GetVersion();
591 TRACE("<-- %s (%s)\n", VersionData[ver].human_readable, VersionData[ver].getVersionEx.szCSDVersion);
592 return VersionData[ver].getVersion16;
596 /***********************************************************************
597 * GetVersion (KERNEL32.@)
599 LONG WINAPI GetVersion(void)
601 WINDOWS_VERSION ver = VERSION_GetVersion();
602 TRACE("<-- %s (%s)\n", VersionData[ver].human_readable, VersionData[ver].getVersionEx.szCSDVersion);
603 return VersionData[ver].getVersion32;
607 /***********************************************************************
608 * GetVersionEx (KERNEL.149)
610 BOOL16 WINAPI GetVersionEx16(OSVERSIONINFO16 *v)
612 WINDOWS_VERSION ver = VERSION_GetVersion();
613 if (v->dwOSVersionInfoSize < sizeof(OSVERSIONINFO16))
615 WARN("wrong OSVERSIONINFO size from app\n");
616 SetLastError(ERROR_INSUFFICIENT_BUFFER);
617 return FALSE;
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 );
624 TRACE("<-- %s (%s)\n", VersionData[ver].human_readable, VersionData[ver].getVersionEx.szCSDVersion);
625 return TRUE;
629 /***********************************************************************
630 * GetVersionExA (KERNEL32.@)
632 BOOL WINAPI GetVersionExA(OSVERSIONINFOA *v)
634 WINDOWS_VERSION ver = VERSION_GetVersion();
635 LPOSVERSIONINFOEXA vex;
637 if (v->dwOSVersionInfoSize != sizeof(OSVERSIONINFOA) &&
638 v->dwOSVersionInfoSize != sizeof(OSVERSIONINFOEXA))
640 WARN("wrong OSVERSIONINFO size from app (got: %ld, expected: %d or %d)\n",
641 v->dwOSVersionInfoSize, sizeof(OSVERSIONINFOA),
642 sizeof(OSVERSIONINFOEXA));
643 SetLastError(ERROR_INSUFFICIENT_BUFFER);
644 return FALSE;
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 );
651 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;
658 TRACE("<-- %s (%s)\n", VersionData[ver].human_readable, VersionData[ver].getVersionEx.szCSDVersion);
659 return TRUE;
663 /***********************************************************************
664 * GetVersionExW (KERNEL32.@)
666 BOOL WINAPI GetVersionExW(OSVERSIONINFOW *v)
668 WINDOWS_VERSION ver = VERSION_GetVersion();
669 LPOSVERSIONINFOEXW vex;
671 if (v->dwOSVersionInfoSize != sizeof(OSVERSIONINFOW) &&
672 v->dwOSVersionInfoSize != sizeof(OSVERSIONINFOEXW))
674 WARN("wrong OSVERSIONINFO size from app (got: %ld, expected: %d or %d)\n",
675 v->dwOSVersionInfoSize, sizeof(OSVERSIONINFOW),
676 sizeof(OSVERSIONINFOEXW));
677 SetLastError(ERROR_INSUFFICIENT_BUFFER);
678 return FALSE;
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;
684 MultiByteToWideChar( CP_ACP, 0, VersionData[ver].getVersionEx.szCSDVersion, -1,
685 v->szCSDVersion, sizeof(v->szCSDVersion)/sizeof(WCHAR) );
686 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;
693 TRACE("<-- %s (%s)\n", VersionData[ver].human_readable, VersionData[ver].getVersionEx.szCSDVersion);
694 return TRUE;
698 /******************************************************************************
699 * VerifyVersionInfoA (KERNEL32.@)
701 BOOL WINAPI VerifyVersionInfoA( LPOSVERSIONINFOEXA lpVersionInfo, DWORD dwTypeMask,
702 DWORDLONG dwlConditionMask)
704 OSVERSIONINFOEXW verW;
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;
717 return VerifyVersionInfoW(&verW, dwTypeMask, dwlConditionMask);
721 /******************************************************************************
722 * VerifyVersionInfoW (KERNEL32.@)
724 BOOL WINAPI VerifyVersionInfoW( LPOSVERSIONINFOEXW lpVersionInfo, DWORD dwTypeMask,
725 DWORDLONG dwlConditionMask)
727 OSVERSIONINFOEXW ver;
728 BOOL res, error_set;
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.
738 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
739 if(!GetVersionExW((LPOSVERSIONINFOW) &ver))
740 return FALSE;
742 res = TRUE;
743 error_set = FALSE;
744 if(!(dwTypeMask && dwlConditionMask)) {
745 res = FALSE;
746 SetLastError(ERROR_BAD_ARGUMENTS);
747 error_set = TRUE;
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;
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;
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;
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;
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;
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;
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;
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;
954 if(!(res || error_set))
955 SetLastError(ERROR_OLD_WIN_VERSION);
956 return res;
960 /***********************************************************************
961 * GetWinFlags (KERNEL.132)
963 DWORD WINAPI GetWinFlags16(void)
965 static const long cpuflags[5] =
966 { WF_CPU086, WF_CPU186, WF_CPU286, WF_CPU386, WF_CPU486 };
967 SYSTEM_INFO si;
968 OSVERSIONINFOA ovi;
969 DWORD result;
971 GetSystemInfo(&si);
973 /* There doesn't seem to be any Pentium flag. */
974 result = cpuflags[min(si.wProcessorLevel, 4)] | WF_ENHANCED | WF_PMODE | WF_80x87 | WF_PAGING;
975 if (si.wProcessorLevel >= 4) result |= WF_HASCPUID;
976 ovi.dwOSVersionInfoSize = sizeof(ovi);
977 GetVersionExA(&ovi);
978 if (ovi.dwPlatformId == VER_PLATFORM_WIN32_NT)
979 result |= WF_WIN32WOW; /* undocumented WF_WINNT */
980 return result;
984 #if 0
985 /* Not used at this time. This is here for documentation only */
987 /* WINDEBUGINFO flags values */
988 #define WDI_OPTIONS 0x0001
989 #define WDI_FILTER 0x0002
990 #define WDI_ALLOCBREAK 0x0004
992 /* dwOptions values */
993 #define DBO_CHECKHEAP 0x0001
994 #define DBO_BUFFERFILL 0x0004
995 #define DBO_DISABLEGPTRAPPING 0x0010
996 #define DBO_CHECKFREE 0x0020
998 #define DBO_SILENT 0x8000
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
1006 /* DebugOutput flags values */
1007 #define DBF_TRACE 0x0000
1008 #define DBF_WARNING 0x4000
1009 #define DBF_ERROR 0x8000
1010 #define DBF_FATAL 0xc000
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
1024 #endif /* NOLOGERROR */
1027 /***********************************************************************
1028 * GetWinDebugInfo (KERNEL.355)
1030 BOOL16 WINAPI GetWinDebugInfo16(WINDEBUGINFO16 *lpwdi, UINT16 flags)
1032 FIXME("(%8lx,%d): stub returning 0\n",
1033 (unsigned long)lpwdi, flags);
1034 /* 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;
1041 /***********************************************************************
1042 * SetWinDebugInfo (KERNEL.356)
1044 BOOL16 WINAPI SetWinDebugInfo16(WINDEBUGINFO16 *lpwdi)
1046 FIXME("(%8lx): stub returning 0\n", (unsigned long)lpwdi);
1047 /* 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;
1054 /***********************************************************************
1055 * K329 (KERNEL.329)
1057 * TODO:
1058 * Should fill lpBuffer only if DBO_BUFFERFILL has been set by SetWinDebugInfo()
1060 void WINAPI DebugFillBuffer(LPSTR lpBuffer, WORD wBytes)
1062 memset(lpBuffer, DBGFILL_BUFFER, wBytes);
1065 /***********************************************************************
1066 * DiagQuery (KERNEL.339)
1068 * returns TRUE if Win called with "/b" (bootlog.txt)
1070 BOOL16 WINAPI DiagQuery16(void)
1072 /* perhaps implement a Wine "/b" command line flag sometime ? */
1073 return FALSE;
1076 /***********************************************************************
1077 * DiagOutput (KERNEL.340)
1079 * writes a debug string into <windir>\bootlog.txt
1081 void WINAPI DiagOutput16(LPCSTR str)
1083 /* FIXME */
1084 DPRINTF("DIAGOUTPUT:%s\n", debugstr_a(str));