Commit a72a398f authored by Juergen Schmied's avatar Juergen Schmied Committed by Alexandre Julliard

Better version autodetection.

parent 1720c985
......@@ -88,11 +88,23 @@ static const char *WinVersionNames[NB_WINDOWS_VERSIONS] =
"nt40"
};
/* if one of the following dlls is importing ntdll the windows
version autodetection switches wine to unicode (nt 3.51 or 4.0) */
static char * special_dlls[] =
{
"COMDLG32",
"COMCTL32",
"SHELL32",
"USER32",
"OLE32",
"RPCRT4",
NULL
};
/* the current version has not been autodetected but forced via cmdline */
static BOOL versionForced = FALSE;
static WINDOWS_VERSION defaultWinVersion = WIN31;
/**********************************************************************
* VERSION_ParseWinVersion
*/
......@@ -132,108 +144,150 @@ void VERSION_ParseDosVersion( const char *arg )
fprintf( stderr, "-dosver: Wrong version format. Use \"-dosver x.xx\"\n");
}
WINDOWS_VERSION VERSION_GetImageVersion(PDB *pdb)
/**********************************************************************
* VERSION_GetSystemDLLVersion
*
* This function tryes to figure out if a given (native) dll comes from
* win95/98 or winnt. Since all values in the OptionalHeader are not a
* usable hint, we test if a dll imports the ntdll.
* This is at least working for all system-dlls like comctl32, comdlg32 and
* shell32.
* If you have a better idea to figure this out...
*/
DWORD VERSION_GetSystemDLLVersion (WINE_MODREF * wm)
{
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
PE_MODREF * pem = &(wm->binfmt.pe);
if (pem->pe_import)
{
peheader = PE_HEADER(pdb->exe_modref->module);
#define OPTHD peheader->OptionalHeader
TRACE("%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("unknown subsystem version: %04x.%04x, please report.\n",
OPTHD.MajorSubsystemVersion,
OPTHD.MinorSubsystemVersion );
return defaultWinVersion;
}
#undef OPTHD
IMAGE_IMPORT_DESCRIPTOR * pe_imp;
for ( pe_imp = pem->pe_import; pe_imp->Name; pe_imp++)
{
char * name = (char*)((unsigned int)wm->module+(unsigned int)(pe_imp->Name));
TRACE("%s\n", name);
if (!lstrncmpiA(name, "ntdll", 5))
{
if (3 == PE_HEADER(wm->module)->OptionalHeader.MajorOperatingSystemVersion)
return NT351;
else
return NT40;
}
}
}
return WIN95;
}
/**********************************************************************
* VERSION_GetLinkedDllVersion
*
* Some version data (not reliable!):
* linker/OS/image/subsys
*
* Check the version of COMDLG32, SHELL32, COMCTL32 and CTL3D32.
* Not functional yet.
* x.xx/1.00/0.00/3.10 Win32s (any version ?)
* 2.39/1.00/0.00/3.10 Win32s freecell.exe (any version)
* 2.50/1.00/4.00/4.00 Win32s 1.30 winhlp32.exe
* 2.60/3.51/3.51/3.51 NT351SP5 system dlls
* 2.60/3.51/3.51/4.00 NT351SP5 comctl32 dll
* 2.xx/1.00/0.00/4.00 Win95 system files
* x.xx/4.00/0.00/4.00 Win95 most applications
* 3.10/4.00/0.00/4.00 Win98 notepad
* x.xx/5.00/5.00/4.00 Win98 system dlls
* x.xx/4.00/4.00/4.00 NT 4 most apps
* 5.12/5.00/5.00/4.00 NT4+IE5 comctl32.dll
* 5.12/5.00/5.00/4.00 Win98 calc
* x.xx/5.00/5.00/4.00 win95/win98/NT4 IE5 files
*/
DWORD VERSION_GetLinkedDllVersion(PDB *pdb)
{
WINE_MODREF *wm;
WORD VersionCounter[NB_WINDOWS_VERSIONS];
DWORD WinVersion = NB_WINDOWS_VERSIONS;
PIMAGE_OPTIONAL_HEADER ophd;
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]++;
if (!pdb->exe_modref)
{
/* winn311 progs only link to user32 */
if (pdb->modref_list && pdb->modref_list->next)
return WIN95;
return WIN31;
}
/* First check the native dlls provided. These have to be
from one windows version */
for ( wm = pdb->modref_list; wm; wm=wm->next )
{
ophd = &(PE_HEADER(wm->module)->OptionalHeader);
TRACE("%s: %02x.%02x/%02x.%02x/%02x.%02x/%02x.%02x\n",
wm->modname,
ophd->MajorLinkerVersion, ophd->MinorLinkerVersion,
ophd->MajorOperatingSystemVersion, ophd->MinorOperatingSystemVersion,
ophd->MajorImageVersion, ophd->MinorImageVersion,
ophd->MajorSubsystemVersion, ophd->MinorSubsystemVersion);
/* test if it a external dll */
if ( !(wm->flags & WINE_MODREF_INTERNAL) )
{
int i;
for (i = 0; special_dlls[i]; i++)
{
/* test if it a special dll */
if (!lstrncmpiA(wm->modname, special_dlls[i], strlen(special_dlls[i]) ))
{
DWORD DllVersion = VERSION_GetSystemDLLVersion(wm);
if (WinVersion == NB_WINDOWS_VERSIONS)
{
WinVersion = DllVersion;
}
else
{
if (WinVersion != DllVersion)
{
ERR("You mixed system dlls from different windows versions! Expect a chrash!\n");
return WIN31; /* this may let the exe exiting */
}
}
break;
}
}
}
}
if(WinVersion != NB_WINDOWS_VERSIONS) return WinVersion;
/* we are using no external system dlls, look at the exe */
ophd = &(PE_HEADER(pdb->exe_modref->module)->OptionalHeader);
TRACE("-%s: %02x.%02x/%02x.%02x/%02x.%02x/%02x.%02x\n",
pdb->exe_modref->modname,
ophd->MajorLinkerVersion, ophd->MinorLinkerVersion,
ophd->MajorOperatingSystemVersion, ophd->MinorOperatingSystemVersion,
ophd->MajorImageVersion, ophd->MinorImageVersion,
ophd->MajorSubsystemVersion, ophd->MinorSubsystemVersion);
/* special nt 3.51 */
if (3 == ophd->MajorOperatingSystemVersion && 51 == ophd->MinorOperatingSystemVersion)
{
return NT351;
}
return MAKELONG(WIN95, VersionCounter[WIN95]);
/* the MajorSubsystemVersion is the only usable singn */
if (ophd->MajorSubsystemVersion < 4)
{
if ( ophd->MajorOperatingSystemVersion == 1
&& ophd->MinorOperatingSystemVersion == 0)
{
return WIN31; /* win32s */
}
if (ophd->Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)
return NT351; /* FIXME: NT 3.1, not tested */
else
return WIN95;
}
return WIN95;
}
/**********************************************************************
* VERSION_GetVersion
*
......@@ -246,42 +300,18 @@ DWORD VERSION_GetLinkedDllVersion(PDB *pdb)
* This can happen much easier than you might think, as this function
* is called by EVERY GetVersion*() API !
*
* 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;
PDB *pdb = PROCESS_Current();
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);
if (pdb->winver == 0xffff) /* to be determined */
{
pdb->winver = VERSION_GetLinkedDllVersion(pdb);
TRACE("Autodetected: %s\n", VERSION_GetVersionName());
}
return pdb->winver;
......@@ -340,8 +370,7 @@ BOOL16 WINAPI GetVersionEx16(OSVERSIONINFO16 *v)
WINDOWS_VERSION ver = VERSION_GetVersion();
if (v->dwOSVersionInfoSize != sizeof(OSVERSIONINFO16))
{
WARN("wrong OSVERSIONINFO size from app (got: %ld, expected: %d)",
v->dwOSVersionInfoSize, sizeof(OSVERSIONINFO16));
WARN("wrong OSVERSIONINFO size from app");
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment