Try to autodetect NT4.
[wine] / misc / version.c
1 /*
2  * Windows version functions
3  *
4  * Copyright 1997 Alexandre Julliard
5  * Copyright 1997 Marcus Meissner
6  * Copyright 1998 Patrik Stridvall
7  */
8
9 #include <string.h>
10 #include "windows.h"
11 #include "winbase.h"
12 #include "process.h"
13 #include "options.h"
14 #include "debug.h"
15 #include "ole.h"
16 #include "winversion.h"
17
18 typedef struct
19 {
20     LONG             getVersion16; 
21     LONG             getVersion32;
22     OSVERSIONINFO32A getVersionEx;
23 } VERSION_DATA;
24
25
26 /* FIXME: compare values below with original and fix */
27 static const VERSION_DATA VersionData[NB_WINDOWS_VERSIONS] =
28 {
29     /* WIN31 */
30     {
31         MAKELONG( 0x0a03, 0x0616 ), /* DOS 6.22 */
32         MAKELONG( 0x0a03, 0x8000 ),
33         {
34             sizeof(OSVERSIONINFO32A), 3, 10, 0,
35             VER_PLATFORM_WIN32s, "Win32s 1.3" 
36         }
37     },
38     /* WIN95 */
39     {
40         0x07005F03,
41         0xC0000004,
42         {
43             sizeof(OSVERSIONINFO32A), 4, 0, 0x40003B6,
44             VER_PLATFORM_WIN32_WINDOWS, "Win95"
45         }
46     },
47     /* NT351 */
48     {
49         0x05000A03,
50         0x04213303,
51         {
52             sizeof(OSVERSIONINFO32A), 3, 51, 0x421,
53             VER_PLATFORM_WIN32_NT, "Service Pack 2"
54         }
55     },
56     /* NT40 */
57     {
58         0x05000A03,
59         0x05650004,
60         {
61             sizeof(OSVERSIONINFO32A), 4, 0, 0x565,
62             VER_PLATFORM_WIN32_NT, "Service Pack 3"
63         }
64     }
65 };
66
67 static const char *VersionNames[NB_WINDOWS_VERSIONS] =
68 {
69     "win31",
70     "win95",
71     "nt351",
72     "nt40"
73 };
74
75 /* the current version has not been autodetected but forced via cmdline */
76 static BOOL32 versionForced = FALSE;
77 static WINDOWS_VERSION defaultVersion = WIN31;
78
79
80 /**********************************************************************
81  *         VERSION_ParseVersion
82  */
83 void VERSION_ParseVersion( char *arg )
84 {
85     int i;
86     for (i = 0; i < NB_WINDOWS_VERSIONS; i++)
87     {
88         if (!strcmp( VersionNames[i], arg ))
89         {
90             defaultVersion = (WINDOWS_VERSION)i;
91             versionForced = TRUE;
92             return;
93         }
94     }
95     MSG("Invalid winver value '%s' specified.\n", arg );
96     MSG("Valid versions are:" );
97     for (i = 0; i < NB_WINDOWS_VERSIONS; i++)
98         MSG(" '%s'%c", VersionNames[i],
99             (i == NB_WINDOWS_VERSIONS - 1) ? '\n' : ',' );
100 }
101
102
103 /**********************************************************************
104  *         VERSION_GetVersion
105  */
106 WINDOWS_VERSION VERSION_GetVersion(void)
107 {
108     PIMAGE_NT_HEADERS peheader; 
109
110     if (versionForced) /* user has overridden any sensible checks */
111         return defaultVersion;
112     if (!PROCESS_Current()->exe_modref)
113     {
114         /* HACK: if we have loaded a PE image into this address space,
115          * we are probably using thunks, so Win95 is our best bet
116          */
117         if (PROCESS_Current()->modref_list) return WIN95;
118         return WIN31; /* FIXME: hmm, look at DDB.version ? */
119     }
120     peheader = PE_HEADER(PROCESS_Current()->exe_modref->module);
121     if (peheader->OptionalHeader.MajorSubsystemVersion == 4) {
122         /* FIXME: check probably not 100% good, verify with win98 too */
123         if (peheader->OptionalHeader.MajorOperatingSystemVersion == 4)
124             return NT40;
125         return WIN95;
126     }
127     if (peheader->OptionalHeader.MajorSubsystemVersion == 3)
128     {
129         /* Win3.10 */
130         if (peheader->OptionalHeader.MinorSubsystemVersion <= 11) return WIN31;
131         /* NT 3.51 */
132         if (peheader->OptionalHeader.MinorSubsystemVersion == 50) return NT351;
133         if (peheader->OptionalHeader.MinorSubsystemVersion == 51) return NT351;
134     }
135     ERR(ver,"unknown subsystem version: %04x.%04x, please report.\n",
136         peheader->OptionalHeader.MajorSubsystemVersion,
137         peheader->OptionalHeader.MinorSubsystemVersion );
138     return defaultVersion;
139 }
140
141
142 /**********************************************************************
143  *         VERSION_GetVersionName
144  */
145 char *VERSION_GetVersionName()
146 {
147   WINDOWS_VERSION ver = VERSION_GetVersion();
148   switch(ver)
149     {
150     case WIN31:
151       return "Windows 3.1";
152     case WIN95:  
153       return "Windows 95";
154     case NT351:
155       return "Windows NT 3.51";
156     case NT40:
157       return "Windows NT 4.0";
158     default:
159       FIXME(ver,"Windows version %d not named",ver);
160       return "Windows <Unknown>";
161     }
162 }
163
164 /***********************************************************************
165  *         GetVersion16   (KERNEL.3)
166  */
167 LONG WINAPI GetVersion16(void)
168 {
169     WINDOWS_VERSION ver = VERSION_GetVersion();
170     return VersionData[ver].getVersion16;
171 }
172
173
174 /***********************************************************************
175  *         GetVersion32   (KERNEL32.427)
176  */
177 LONG WINAPI GetVersion32(void)
178 {
179     WINDOWS_VERSION ver = VERSION_GetVersion();
180     return VersionData[ver].getVersion32;
181 }
182
183
184 /***********************************************************************
185  *         GetVersionEx16   (KERNEL.149)
186  */
187 BOOL16 WINAPI GetVersionEx16(OSVERSIONINFO16 *v)
188 {
189     WINDOWS_VERSION ver = VERSION_GetVersion();
190     if (v->dwOSVersionInfoSize != sizeof(OSVERSIONINFO16))
191     {
192         WARN(ver,"wrong OSVERSIONINFO size from app");
193         return FALSE;
194     }
195     v->dwMajorVersion = VersionData[ver].getVersionEx.dwMajorVersion;
196     v->dwMinorVersion = VersionData[ver].getVersionEx.dwMinorVersion;
197     v->dwBuildNumber  = VersionData[ver].getVersionEx.dwBuildNumber;
198     v->dwPlatformId   = VersionData[ver].getVersionEx.dwPlatformId;
199     strcpy( v->szCSDVersion, VersionData[ver].getVersionEx.szCSDVersion );
200     return TRUE;
201 }
202
203
204 /***********************************************************************
205  *         GetVersionEx32A   (KERNEL32.428)
206  */
207 BOOL32 WINAPI GetVersionEx32A(OSVERSIONINFO32A *v)
208 {
209     WINDOWS_VERSION ver = VERSION_GetVersion();
210     if (v->dwOSVersionInfoSize != sizeof(OSVERSIONINFO32A))
211     {
212         WARN(ver,"wrong OSVERSIONINFO size from app");
213         return FALSE;
214     }
215     v->dwMajorVersion = VersionData[ver].getVersionEx.dwMajorVersion;
216     v->dwMinorVersion = VersionData[ver].getVersionEx.dwMinorVersion;
217     v->dwBuildNumber  = VersionData[ver].getVersionEx.dwBuildNumber;
218     v->dwPlatformId   = VersionData[ver].getVersionEx.dwPlatformId;
219     strcpy( v->szCSDVersion, VersionData[ver].getVersionEx.szCSDVersion );
220     return TRUE;
221 }
222
223
224 /***********************************************************************
225  *         GetVersionEx32W   (KERNEL32.429)
226  */
227 BOOL32 WINAPI GetVersionEx32W(OSVERSIONINFO32W *v)
228 {
229     WINDOWS_VERSION ver = VERSION_GetVersion();
230
231     if (v->dwOSVersionInfoSize!=sizeof(OSVERSIONINFO32W))
232     {
233         WARN(ver,"wrong OSVERSIONINFO size from app");
234         return FALSE;
235     }
236     v->dwMajorVersion = VersionData[ver].getVersionEx.dwMajorVersion;
237     v->dwMinorVersion = VersionData[ver].getVersionEx.dwMinorVersion;
238     v->dwBuildNumber  = VersionData[ver].getVersionEx.dwBuildNumber;
239     v->dwPlatformId   = VersionData[ver].getVersionEx.dwPlatformId;
240     lstrcpyAtoW( v->szCSDVersion, VersionData[ver].getVersionEx.szCSDVersion );
241     return TRUE;
242 }
243
244
245 /***********************************************************************
246  *          GetWinFlags   (KERNEL.132)
247  */
248 DWORD WINAPI GetWinFlags(void)
249 {
250   static const long cpuflags[5] =
251     { WF_CPU086, WF_CPU186, WF_CPU286, WF_CPU386, WF_CPU486 };
252   SYSTEM_INFO si;
253   OSVERSIONINFO32A ovi;
254   DWORD result;
255
256   GetSystemInfo(&si);
257
258   /* There doesn't seem to be any Pentium flag.  */
259   result = cpuflags[MIN (si.wProcessorLevel, 4)];
260
261   switch(Options.mode)
262   {
263   case MODE_STANDARD:
264       result |= WF_STANDARD | WF_PMODE | WF_80x87;
265       break;
266
267   case MODE_ENHANCED:
268       result |= WF_ENHANCED | WF_PMODE | WF_80x87 | WF_PAGING;
269       break;
270
271   default:
272       ERR(ver, "Unknown mode set? This shouldn't happen. Check GetWinFlags()!\n");
273       break;
274   }
275   if (si.wProcessorLevel >= 4) result |= WF_HASCPUID;
276   ovi.dwOSVersionInfoSize = sizeof(ovi);
277   GetVersionEx32A(&ovi);
278   if (ovi.dwPlatformId == VER_PLATFORM_WIN32_NT)
279       result |= WF_WIN32WOW; /* undocumented WF_WINNT */
280   return result;
281 }
282
283
284 /***********************************************************************
285  *          GetWinDebugInfo   (KERNEL.355)
286  */
287 BOOL16 WINAPI GetWinDebugInfo(WINDEBUGINFO *lpwdi, UINT16 flags)
288 {
289     FIXME(ver, "(%8lx,%d): stub returning 0\n",
290           (unsigned long)lpwdi, flags);
291     /* 0 means not in debugging mode/version */
292     /* Can this type of debugging be used in wine ? */
293     /* Constants: WDI_OPTIONS WDI_FILTER WDI_ALLOCBREAK */
294     return 0;
295 }
296
297
298 /***********************************************************************
299  *          SetWinDebugInfo   (KERNEL.356)
300  */
301 BOOL16 WINAPI SetWinDebugInfo(WINDEBUGINFO *lpwdi)
302 {
303     FIXME(ver, "(%8lx): stub returning 0\n", (unsigned long)lpwdi);
304     /* 0 means not in debugging mode/version */
305     /* Can this type of debugging be used in wine ? */
306     /* Constants: WDI_OPTIONS WDI_FILTER WDI_ALLOCBREAK */
307     return 0;
308 }
309
310
311 /***********************************************************************
312  *           DebugFillBuffer                    (KERNEL.329)
313  *
314  * TODO:
315  * Should fill lpBuffer only if DBO_BUFFERFILL has been set by SetWinDebugInfo()
316  */
317 void WINAPI DebugFillBuffer(LPSTR lpBuffer, WORD wBytes)
318 {
319         memset(lpBuffer, DBGFILL_BUFFER, wBytes);
320 }
321
322 /***********************************************************************
323  *           DiagQuery                          (KERNEL.339)
324  *
325  * returns TRUE if Win called with "/b" (bootlog.txt)
326  */
327 BOOL16 WINAPI DiagQuery()
328 {
329         /* perhaps implement a Wine "/b" command line flag sometime ? */
330         return FALSE;
331 }
332
333 /***********************************************************************
334  *           DiagOutput                         (KERNEL.340)
335  *
336  * writes a debug string into <windir>\bootlog.txt
337  */
338 void WINAPI DiagOutput(LPCSTR str)
339 {
340         /* FIXME */
341         DPRINTF("DIAGOUTPUT:%s\n", debugstr_a(str));
342 }
343
344 /***********************************************************************
345  *           OaBuildVersion           [OLEAUT32.170]
346  */
347 UINT32 WINAPI OaBuildVersion()
348 {
349     WINDOWS_VERSION ver = VERSION_GetVersion();
350
351     switch(VersionData[ver].getVersion32)
352     {
353         case 0x80000a03: /* Win 3.1 */
354                 return 0x140fd1; /* from Win32s 1.1e */
355         case 0xc0000004: /* Win 95 */
356                 return 0x0a0bd3;
357         case 0x04213303: /* NT 3.51 */
358                 return 0x0; /* FIXME */
359         case 0x05650004: /* NT 4.0 */
360                 return 0x141016;
361         default:
362                 return 0x0;
363     }
364 }
365 /***********************************************************************
366  *        VERSION_OsIsUnicode   [internal]
367  *
368  * NOTES
369  *   some functions getting sometimes LPSTR sometimes LPWSTR...
370  *
371  */
372 BOOL32 VERSION_OsIsUnicode(void)
373 {
374     switch(VERSION_GetVersion())
375     {
376     case NT351:
377     case NT40:
378         return TRUE;
379     default:
380         return FALSE;
381     }
382 }