| /* |
| * Windows and DOS version functions |
| * |
| * Copyright 1997 Alexandre Julliard |
| * Copyright 1997 Marcus Meissner |
| * Copyright 1998 Patrik Stridvall |
| * Copyright 1998 Andreas Mohr |
| */ |
| |
| #include <string.h> |
| #include <stdlib.h> |
| #include "winbase.h" |
| #include "winuser.h" |
| #include "wine/winbase16.h" |
| #include "process.h" |
| #include "options.h" |
| #include "debug.h" |
| #include "neexe.h" |
| #include "winversion.h" |
| |
| DEFAULT_DEBUG_CHANNEL(ver) |
| |
| typedef struct |
| { |
| LONG getVersion16; |
| LONG getVersion32; |
| OSVERSIONINFOA getVersionEx; |
| } VERSION_DATA; |
| |
| |
| /* FIXME: compare values below with original and fix */ |
| static VERSION_DATA VersionData[NB_WINDOWS_VERSIONS] = |
| { |
| /* WIN31 */ |
| { |
| MAKELONG( 0x0a03, 0x0616 ), /* DOS 6.22 */ |
| MAKELONG( 0x0a03, 0x8000 ), |
| { |
| sizeof(OSVERSIONINFOA), 3, 10, 0, |
| VER_PLATFORM_WIN32s, "Win32s 1.3" |
| } |
| }, |
| /* WIN95 */ |
| { |
| 0x07005F03, |
| 0xC0000004, |
| { |
| sizeof(OSVERSIONINFOA), 4, 0, 0x40003B6, |
| VER_PLATFORM_WIN32_WINDOWS, "Win95" |
| } |
| }, |
| /* NT351 */ |
| { |
| 0x05000A03, |
| 0x04213303, |
| { |
| sizeof(OSVERSIONINFOA), 3, 51, 0x421, |
| VER_PLATFORM_WIN32_NT, "Service Pack 2" |
| } |
| }, |
| /* NT40 */ |
| { |
| 0x05000A03, |
| 0x05650004, |
| { |
| sizeof(OSVERSIONINFOA), 4, 0, 0x565, |
| VER_PLATFORM_WIN32_NT, "Service Pack 3" |
| } |
| } |
| }; |
| |
| static const char *WinVersionNames[NB_WINDOWS_VERSIONS] = |
| { |
| "win31", |
| "win95", |
| "nt351", |
| "nt40" |
| }; |
| |
| /* the current version has not been autodetected but forced via cmdline */ |
| static BOOL versionForced = FALSE; |
| static WINDOWS_VERSION defaultWinVersion = WIN31; |
| |
| |
| /********************************************************************** |
| * VERSION_ParseWinVersion |
| */ |
| void VERSION_ParseWinVersion( const char *arg ) |
| { |
| int i; |
| for (i = 0; i < NB_WINDOWS_VERSIONS; i++) |
| { |
| if (!strcmp( WinVersionNames[i], arg )) |
| { |
| defaultWinVersion = (WINDOWS_VERSION)i; |
| versionForced = TRUE; |
| return; |
| } |
| } |
| MSG("Invalid winver value '%s' specified.\n", arg ); |
| MSG("Valid versions are:" ); |
| for (i = 0; i < NB_WINDOWS_VERSIONS; i++) |
| MSG(" '%s'%c", WinVersionNames[i], |
| (i == NB_WINDOWS_VERSIONS - 1) ? '\n' : ',' ); |
| } |
| |
| |
| /********************************************************************** |
| * VERSION_ParseDosVersion |
| */ |
| void VERSION_ParseDosVersion( const char *arg ) |
| { |
| int hi, lo; |
| if (sscanf( arg, "%d.%d", &hi, &lo ) == 2) |
| { |
| VersionData[WIN31].getVersion16 = |
| MAKELONG(LOWORD(VersionData[WIN31].getVersion16), |
| (hi<<8) + lo); |
| } |
| else |
| fprintf( stderr, "-dosver: Wrong version format. Use \"-dosver x.xx\"\n"); |
| } |
| |
| |
| WINDOWS_VERSION VERSION_GetImageVersion(PDB *pdb) |
| { |
| PIMAGE_NT_HEADERS peheader; |
| |
| if (!pdb->exe_modref) |
| { |
| /* HACK: if we have loaded a PE image into this address space, |
| * we are probably using thunks, so Win95 is our best bet |
| */ |
| if (pdb->modref_list) |
| return WIN95; |
| /* FIXME: hmm, do anything else ? |
| TDB.version doesn't help here |
| as it always holds version 3.10 */ |
| return WIN31; |
| } |
| else |
| { |
| peheader = PE_HEADER(pdb->exe_modref->module); |
| #define OPTHD peheader->OptionalHeader |
| |
| TRACE(ver, "%02x.%02x/%02x.%02x/%02x.%02x/%02x.%02x\n", |
| OPTHD.MajorLinkerVersion, |
| OPTHD.MinorLinkerVersion, |
| OPTHD.MajorOperatingSystemVersion, |
| OPTHD.MinorOperatingSystemVersion, |
| OPTHD.MajorImageVersion, |
| OPTHD.MinorImageVersion, |
| OPTHD.MajorSubsystemVersion, |
| OPTHD.MinorSubsystemVersion); |
| |
| switch (OPTHD.MajorSubsystemVersion) |
| { |
| case 4: |
| switch (OPTHD.MajorOperatingSystemVersion) |
| { |
| case 5: |
| return NT40; /* FIXME: this is NT 5, isn't it ? */ |
| case 4: |
| if ((OPTHD.MajorImageVersion == 0) && |
| (OPTHD.SectionAlignment == 4096)) |
| return WIN95; |
| else |
| return NT40; |
| case 1: |
| return WIN95; |
| default: |
| return WIN95; /* FIXME ? */ |
| } |
| case 3: |
| /* 3.1x versions */ |
| if (OPTHD.MinorSubsystemVersion <= 11) |
| { |
| if (OPTHD.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI) |
| return NT351; /* FIXME: NT 3.1 */ |
| else |
| return WIN31; |
| } |
| else |
| { |
| /* NT 3.51 */ |
| if (OPTHD.MinorSubsystemVersion == 50) |
| return NT351; |
| else |
| if (OPTHD.MinorSubsystemVersion == 51) |
| return NT351; |
| } |
| default: |
| if (OPTHD.MajorSubsystemVersion) |
| ERR(ver,"unknown subsystem version: %04x.%04x, please report.\n", |
| OPTHD.MajorSubsystemVersion, |
| OPTHD.MinorSubsystemVersion ); |
| return defaultWinVersion; |
| } |
| #undef OPTHD |
| } |
| } |
| |
| |
| /********************************************************************** |
| * |
| * Check the version of COMDLG32, SHELL32, COMCTL32 and CTL3D32. |
| * Not functional yet. |
| */ |
| DWORD VERSION_GetLinkedDllVersion(PDB *pdb) |
| { |
| WINE_MODREF *wm; |
| WORD VersionCounter[NB_WINDOWS_VERSIONS]; |
| |
| memset(VersionCounter, 0, sizeof(VersionCounter)); |
| |
| VersionCounter[WIN95] = 1; |
| for ( wm = PROCESS_Current()->modref_list; wm; wm=wm->next ) { |
| if (!(lstrncmpiA(wm->modname, "CTL3D32", 7))) |
| VersionCounter[WIN95]++; |
| } |
| |
| return MAKELONG(WIN95, VersionCounter[WIN95]); |
| } |
| |
| |
| /********************************************************************** |
| * VERSION_GetVersion |
| * |
| * Some version data: |
| * linker/OS/image/subsys Name Intended for |
| * |
| * 2.39/1.00/0.00/3.10 freecell.exe Win32s (any version) |
| * 2.55/1.00/0.00/4.00 acrord32.exe Win32s, Win95 supported (?) |
| * |
| * 2.50/1.00/4.00/4.00 winhlp32.exe Win32s 1.30 |
| * 4.20/4.00/1.00/4.00 Asuslm.exe Win95 (Aaargh !) |
| * 5.12/4.00/1.07/4.00 clikfixi.exe NT 4 (service pack files) |
| * 3.10/4.00/4.00/4.00 PLUMBING.EXE NT |
| * ?.??/4.00/97.01/4.00 sse.exe huh ?? (damn crackerz ;) |
| * 5.12/5.00/5.00/4.00 comctl32.dll NT4 / IE 5.0 |
| * 6.00/5.00/5.00/4.00 NT 4 driver update (strange numbers) |
| * |
| * Common versions: |
| * x.xx/1.00/0.00/3.10 Win32s (any version ?) |
| * 2.xx/1.00/0.00/4.00 Win95 (Microsoft/system files) |
| * x.xx/4.00/0.00/4.00 Win95 (most applications !) |
| * x.xx/4.00/4.00/4.00 NT 4 (most apps) |
| * x.xx/5.00/5.00/4.00 NT 4 newer files / NT 5 ?? |
| */ |
| WINDOWS_VERSION VERSION_GetVersion(void) |
| { |
| PDB *pdb = PROCESS_Current(); |
| DWORD DllVer; |
| |
| if (versionForced) /* user has overridden any sensible checks */ |
| return defaultWinVersion; |
| |
| if (pdb->winver == 0xffff) /* to be determined */ |
| { |
| DllVer = 0/*VERSION_GetLinkedDllVersion(pdb)*/; |
| if (HIWORD(DllVer) > 1) |
| pdb->winver = LOWORD(DllVer); |
| else |
| pdb->winver = VERSION_GetImageVersion(pdb); |
| } |
| |
| return pdb->winver; |
| } |
| |
| |
| /********************************************************************** |
| * VERSION_GetVersionName |
| */ |
| char *VERSION_GetVersionName() |
| { |
| WINDOWS_VERSION ver = VERSION_GetVersion(); |
| switch(ver) |
| { |
| case WIN31: |
| return "Windows 3.1"; |
| case WIN95: |
| return "Windows 95"; |
| case NT351: |
| return "Windows NT 3.51"; |
| case NT40: |
| return "Windows NT 4.0"; |
| default: |
| FIXME(ver,"Windows version %d not named",ver); |
| return "Windows <Unknown>"; |
| } |
| } |
| |
| /*********************************************************************** |
| * GetVersion16 (KERNEL.3) |
| */ |
| LONG WINAPI GetVersion16(void) |
| { |
| WINDOWS_VERSION ver = VERSION_GetVersion(); |
| return VersionData[ver].getVersion16; |
| } |
| |
| |
| /*********************************************************************** |
| * GetVersion32 (KERNEL32.427) |
| */ |
| LONG WINAPI GetVersion(void) |
| { |
| WINDOWS_VERSION ver = VERSION_GetVersion(); |
| return VersionData[ver].getVersion32; |
| } |
| |
| |
| /*********************************************************************** |
| * GetVersionEx16 (KERNEL.149) |
| */ |
| BOOL16 WINAPI GetVersionEx16(OSVERSIONINFO16 *v) |
| { |
| WINDOWS_VERSION ver = VERSION_GetVersion(); |
| if (v->dwOSVersionInfoSize != sizeof(OSVERSIONINFO16)) |
| { |
| WARN(ver,"wrong OSVERSIONINFO size from app"); |
| return FALSE; |
| } |
| v->dwMajorVersion = VersionData[ver].getVersionEx.dwMajorVersion; |
| v->dwMinorVersion = VersionData[ver].getVersionEx.dwMinorVersion; |
| v->dwBuildNumber = VersionData[ver].getVersionEx.dwBuildNumber; |
| v->dwPlatformId = VersionData[ver].getVersionEx.dwPlatformId; |
| strcpy( v->szCSDVersion, VersionData[ver].getVersionEx.szCSDVersion ); |
| return TRUE; |
| } |
| |
| |
| /*********************************************************************** |
| * GetVersionEx32A (KERNEL32.428) |
| */ |
| BOOL WINAPI GetVersionExA(OSVERSIONINFOA *v) |
| { |
| WINDOWS_VERSION ver = VERSION_GetVersion(); |
| if (v->dwOSVersionInfoSize != sizeof(OSVERSIONINFOA)) |
| { |
| WARN(ver,"wrong OSVERSIONINFO size from app"); |
| return FALSE; |
| } |
| v->dwMajorVersion = VersionData[ver].getVersionEx.dwMajorVersion; |
| v->dwMinorVersion = VersionData[ver].getVersionEx.dwMinorVersion; |
| v->dwBuildNumber = VersionData[ver].getVersionEx.dwBuildNumber; |
| v->dwPlatformId = VersionData[ver].getVersionEx.dwPlatformId; |
| strcpy( v->szCSDVersion, VersionData[ver].getVersionEx.szCSDVersion ); |
| return TRUE; |
| } |
| |
| |
| /*********************************************************************** |
| * GetVersionEx32W (KERNEL32.429) |
| */ |
| BOOL WINAPI GetVersionExW(OSVERSIONINFOW *v) |
| { |
| WINDOWS_VERSION ver = VERSION_GetVersion(); |
| |
| if (v->dwOSVersionInfoSize!=sizeof(OSVERSIONINFOW)) |
| { |
| WARN(ver,"wrong OSVERSIONINFO size from app"); |
| return FALSE; |
| } |
| v->dwMajorVersion = VersionData[ver].getVersionEx.dwMajorVersion; |
| v->dwMinorVersion = VersionData[ver].getVersionEx.dwMinorVersion; |
| v->dwBuildNumber = VersionData[ver].getVersionEx.dwBuildNumber; |
| v->dwPlatformId = VersionData[ver].getVersionEx.dwPlatformId; |
| lstrcpyAtoW( v->szCSDVersion, VersionData[ver].getVersionEx.szCSDVersion ); |
| return TRUE; |
| } |
| |
| |
| /*********************************************************************** |
| * GetWinFlags (KERNEL.132) |
| */ |
| DWORD WINAPI GetWinFlags16(void) |
| { |
| static const long cpuflags[5] = |
| { WF_CPU086, WF_CPU186, WF_CPU286, WF_CPU386, WF_CPU486 }; |
| SYSTEM_INFO si; |
| OSVERSIONINFOA ovi; |
| DWORD result; |
| |
| GetSystemInfo(&si); |
| |
| /* There doesn't seem to be any Pentium flag. */ |
| result = cpuflags[MIN (si.wProcessorLevel, 4)]; |
| |
| switch(Options.mode) |
| { |
| case MODE_STANDARD: |
| result |= WF_STANDARD | WF_PMODE | WF_80x87; |
| break; |
| |
| case MODE_ENHANCED: |
| result |= WF_ENHANCED | WF_PMODE | WF_80x87 | WF_PAGING; |
| break; |
| |
| default: |
| ERR(ver, "Unknown mode set? This shouldn't happen. Check GetWinFlags()!\n"); |
| break; |
| } |
| if (si.wProcessorLevel >= 4) result |= WF_HASCPUID; |
| ovi.dwOSVersionInfoSize = sizeof(ovi); |
| GetVersionExA(&ovi); |
| if (ovi.dwPlatformId == VER_PLATFORM_WIN32_NT) |
| result |= WF_WIN32WOW; /* undocumented WF_WINNT */ |
| return result; |
| } |
| |
| |
| /*********************************************************************** |
| * GetWinDebugInfo (KERNEL.355) |
| */ |
| BOOL16 WINAPI GetWinDebugInfo16(WINDEBUGINFO *lpwdi, UINT16 flags) |
| { |
| FIXME(ver, "(%8lx,%d): stub returning 0\n", |
| (unsigned long)lpwdi, flags); |
| /* 0 means not in debugging mode/version */ |
| /* Can this type of debugging be used in wine ? */ |
| /* Constants: WDI_OPTIONS WDI_FILTER WDI_ALLOCBREAK */ |
| return 0; |
| } |
| |
| |
| /*********************************************************************** |
| * SetWinDebugInfo (KERNEL.356) |
| */ |
| BOOL16 WINAPI SetWinDebugInfo16(WINDEBUGINFO *lpwdi) |
| { |
| FIXME(ver, "(%8lx): stub returning 0\n", (unsigned long)lpwdi); |
| /* 0 means not in debugging mode/version */ |
| /* Can this type of debugging be used in wine ? */ |
| /* Constants: WDI_OPTIONS WDI_FILTER WDI_ALLOCBREAK */ |
| return 0; |
| } |
| |
| |
| /*********************************************************************** |
| * DebugFillBuffer (KERNEL.329) |
| * |
| * TODO: |
| * Should fill lpBuffer only if DBO_BUFFERFILL has been set by SetWinDebugInfo() |
| */ |
| void WINAPI DebugFillBuffer(LPSTR lpBuffer, WORD wBytes) |
| { |
| memset(lpBuffer, DBGFILL_BUFFER, wBytes); |
| } |
| |
| /*********************************************************************** |
| * DiagQuery (KERNEL.339) |
| * |
| * returns TRUE if Win called with "/b" (bootlog.txt) |
| */ |
| BOOL16 WINAPI DiagQuery16() |
| { |
| /* perhaps implement a Wine "/b" command line flag sometime ? */ |
| return FALSE; |
| } |
| |
| /*********************************************************************** |
| * DiagOutput (KERNEL.340) |
| * |
| * writes a debug string into <windir>\bootlog.txt |
| */ |
| void WINAPI DiagOutput16(LPCSTR str) |
| { |
| /* FIXME */ |
| DPRINTF("DIAGOUTPUT:%s\n", debugstr_a(str)); |
| } |
| |
| /*********************************************************************** |
| * OaBuildVersion [OLEAUT32.170] |
| */ |
| UINT WINAPI OaBuildVersion() |
| { |
| WINDOWS_VERSION ver = VERSION_GetVersion(); |
| |
| FIXME(ver, "Please report to a.mohr@mailto.de if you get version error messages !\n"); |
| switch(VersionData[ver].getVersion32) |
| { |
| case 0x80000a03: /* Win 3.1 */ |
| return 0x140fd1; /* from Win32s 1.1e */ |
| case 0xc0000004: /* Win 95 */ |
| return 0x1e10a9; /* some older version: 0x0a0bd3 */ |
| case 0x04213303: /* NT 3.51 */ |
| FIXME(ver, "NT 3.51 version value unknown !\n"); |
| return 0x1e10a9; /* value borrowed from Win95 */ |
| case 0x05650004: /* NT 4.0 */ |
| return 0x141016; |
| default: |
| return 0x0; |
| } |
| } |
| /*********************************************************************** |
| * VERSION_OsIsUnicode [internal] |
| * |
| * NOTES |
| * some functions getting sometimes LPSTR sometimes LPWSTR... |
| * |
| */ |
| BOOL VERSION_OsIsUnicode(void) |
| { |
| switch(VERSION_GetVersion()) |
| { |
| case NT351: |
| case NT40: |
| return TRUE; |
| default: |
| return FALSE; |
| } |
| } |