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