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